]> git.mdlowis.com Git - proto/labwc.git/commitdiff
ssd: clean up scene management
authortokyo4j <hrak1529@gmail.com>
Wed, 13 Aug 2025 12:00:11 +0000 (21:00 +0900)
committerJohan Malm <johanmalm@users.noreply.github.com>
Thu, 28 Aug 2025 20:06:51 +0000 (21:06 +0100)
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`.

13 files changed:
include/node.h
include/ssd-internal.h
include/ssd.h
include/theme.h
src/config/rcxml.c
src/desktop.c
src/node.c
src/ssd/ssd-border.c
src/ssd/ssd-extents.c
src/ssd/ssd-part.c
src/ssd/ssd-shadow.c
src/ssd/ssd-titlebar.c
src/ssd/ssd.c

index 80d03e9f1ca32917542f5813f496de30f6a0fe61..1c012392f1babd70b5c10a4494117265c2298917 100644 (file)
@@ -7,7 +7,7 @@ struct view;
 struct lab_layer_surface;
 struct lab_layer_popup;
 struct menuitem;
-struct ssd_button;
+struct ssd_part;
 struct scaled_scene_buffer;
 
 enum node_descriptor_type {
@@ -21,7 +21,7 @@ enum node_descriptor_type {
        LAB_NODE_DESC_MENUITEM,
        LAB_NODE_DESC_TREE,
        LAB_NODE_DESC_SCALED_SCENE_BUFFER,
-       LAB_NODE_DESC_SSD_BUTTON,
+       LAB_NODE_DESC_SSD_PART,
 };
 
 struct node_descriptor {
@@ -44,7 +44,7 @@ struct node_descriptor {
  *   - LAB_NODE_DESC_LAYER_SURFACE  struct lab_layer_surface
  *   - LAB_NODE_DESC_LAYER_POPUP    struct lab_layer_popup
  *   - LAB_NODE_DESC_MENUITEM       struct menuitem
- *   - LAB_NODE_DESC_SSD_BUTTON     struct ssd_button
+ *   - LAB_NODE_DESC_SSD_PART       struct ssd_part
  */
 void node_descriptor_create(struct wlr_scene_node *scene_node,
        enum node_descriptor_type type, void *data);
@@ -77,10 +77,10 @@ struct menuitem *node_menuitem_from_node(
        struct wlr_scene_node *wlr_scene_node);
 
 /**
- * node_ssd_button_from_node - return ssd_button struct from node
+ * node_ssd_part_from_node - return ssd_part struct from node
  * @wlr_scene_node: wlr_scene_node from which to return data
  */
-struct ssd_button *node_ssd_button_from_node(
+struct ssd_part *node_ssd_part_from_node(
        struct wlr_scene_node *wlr_scene_node);
 
 /**
index 4721de756ffe9eef2e7a61b5a8a97eff20a697d0..aa20dee33e21cc76c330ca280df6a94f7d7c56df 100644 (file)
@@ -3,52 +3,53 @@
 #define LABWC_SSD_INTERNAL_H
 
 #include <wlr/util/box.h>
-#include "common/macros.h"
 #include "ssd.h"
 #include "theme.h"
 #include "view.h"
 
-#define FOR_EACH(tmp, ...) \
-{ \
-       __typeof__(tmp) _x[] = { __VA_ARGS__, NULL }; \
-       size_t _i = 0; \
-       for ((tmp) = _x[_i]; _i < ARRAY_SIZE(_x) - 1; (tmp) = _x[++_i])
-
-#define FOR_EACH_END }
-
-struct ssd_button {
-       struct view *view;
-       enum ssd_part_type type;
-       /*
-        * Bitmap of lab_button_state that represents a combination of
-        * hover/toggled/rounded states.
-        */
-       uint8_t state_set;
-       /*
-        * Image buffers for each combination of hover/toggled/rounded states.
-        * img_buffers[state_set] is displayed. Some of these can be NULL
-        * (e.g. img_buffers[LAB_BS_ROUNDED] is set only for corner buttons).
-        *
-        * When "type" is LAB_SSD_BUTTON_WINDOW_ICON, these are all NULL and
-        * window_icon is used instead.
-        */
-       struct scaled_img_buffer *img_buffers[LAB_BS_ALL + 1];
-
-       struct scaled_icon_buffer *window_icon;
-
-       struct wl_listener destroy;
-};
-
-struct ssd_sub_tree {
-       struct wlr_scene_tree *tree;
-       struct wl_list parts; /* ssd_part.link */
-};
-
 struct ssd_state_title_width {
        int width;
        bool truncated;
 };
 
+/*
+ * The scene-graph of SSD 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
+ *    +--...
+ */
 struct ssd {
        struct view *view;
        struct wlr_scene_tree *tree;
@@ -81,33 +82,49 @@ struct ssd {
                struct wlr_box geometry;
                struct ssd_state_title {
                        char *text;
-                       struct ssd_state_title_width active;
-                       struct ssd_state_title_width inactive;
+                       /* indexed by enum ssd_active_state */
+                       struct ssd_state_title_width dstates[2];
                } title;
        } state;
 
        /* An invisible area around the view which allows resizing */
-       struct ssd_sub_tree extents;
+       struct ssd_extents_scene {
+               struct wlr_scene_tree *tree;
+               struct wlr_scene_rect *top, *bottom, *left, *right;
+       } extents;
 
        /* The top of the view, containing buttons, title, .. */
-       struct {
+       struct ssd_titlebar_scene {
                int height;
                struct wlr_scene_tree *tree;
-               struct ssd_sub_tree active;
-               struct ssd_sub_tree inactive;
+               struct ssd_titlebar_subtree {
+                       struct wlr_scene_tree *tree;
+                       struct wlr_scene_buffer *corner_left;
+                       struct wlr_scene_buffer *corner_right;
+                       struct wlr_scene_buffer *bar;
+                       struct scaled_font_buffer *title;
+                       /* List of ssd_parts that represent buttons */
+                       struct wl_list buttons_left;
+                       struct wl_list buttons_right;
+               } subtrees[2]; /* indexed by enum ssd_active_state */
        } titlebar;
 
        /* Borders allow resizing as well */
-       struct {
+       struct ssd_border_scene {
                struct wlr_scene_tree *tree;
-               struct ssd_sub_tree active;
-               struct ssd_sub_tree inactive;
+               struct ssd_border_subtree {
+                       struct wlr_scene_tree *tree;
+                       struct wlr_scene_rect *top, *bottom, *left, *right;
+               } subtrees[2]; /* indexed by enum ssd_active_state */
        } border;
 
-       struct {
+       struct ssd_shadow_scene {
                struct wlr_scene_tree *tree;
-               struct ssd_sub_tree active;
-               struct ssd_sub_tree inactive;
+               struct ssd_shadow_subtree {
+                       struct wlr_scene_tree *tree;
+                       struct wlr_scene_buffer *top, *bottom, *left, *right,
+                               *top_left, *top_right, *bottom_left, *bottom_right;
+               } subtrees[2]; /* indexed by enum ssd_active_state */
        } shadow;
 
        /*
@@ -118,46 +135,61 @@ struct ssd {
        struct border margin;
 };
 
+/*
+ * ssd_part wraps a scene-node with ssd-specific information and can be
+ * accessed with node_ssd_part_from_node(wlr_scene_node *).
+ * This allows get_cursor_context() in desktop.c to see which SSD part is under
+ * the cursor.
+ */
 struct ssd_part {
        enum ssd_part_type type;
-
-       /* Buffer pointer. May be NULL */
-       struct scaled_font_buffer *buffer;
+       struct view *view;
 
        /* This part represented in scene graph */
        struct wlr_scene_node *node;
+       struct wl_listener node_destroy;
+};
 
-       struct wl_list link;
+struct ssd_part_button {
+       struct ssd_part base;
+       /*
+        * Bitmap of lab_button_state that represents a combination of
+        * hover/toggled/rounded states.
+        */
+       uint8_t state_set;
+       /*
+        * Image buffers for each combination of hover/toggled/rounded states.
+        * img_buffers[state_set] is displayed. Some of these can be NULL
+        * (e.g. img_buffers[LAB_BS_ROUNDED] is set only for corner buttons).
+        *
+        * When the type of ssd_part pointing to ssd_button is
+        * LAB_SSD_BUTTON_WINDOW_ICON, these are all NULL and window_icon is
+        * used instead.
+        */
+       struct scaled_img_buffer *img_buffers[LAB_BS_ALL + 1];
+
+       struct scaled_icon_buffer *window_icon;
+
+       struct wl_list link; /* ssd_titlebar_subtree.buttons_{left,right} */
 };
 
+/* FIXME: This structure is redundant as ssd_part contains view */
 struct ssd_hover_state {
        struct view *view;
-       struct ssd_button *button;
+       struct ssd_part_button *button;
 };
 
 struct wlr_buffer;
 struct wlr_scene_tree;
 
 /* SSD internal helpers to create various SSD elements */
-/* TODO: Replace some common args with a struct */
-struct ssd_part *add_scene_part(
-       struct wl_list *part_list, enum ssd_part_type type);
-struct ssd_part *add_scene_rect(
-       struct wl_list *list, enum ssd_part_type type,
-       struct wlr_scene_tree *parent, int width, int height, int x, int y,
-       float color[4]);
-struct ssd_part *add_scene_buffer(
-       struct wl_list *list, enum ssd_part_type type,
-       struct wlr_scene_tree *parent, struct wlr_buffer *buffer, int x, int y);
-struct ssd_part *add_scene_button(struct wl_list *part_list,
+struct ssd_part *attach_ssd_part(enum ssd_part_type type, struct view *view,
+       struct wlr_scene_node *node);
+struct ssd_part_button *attach_ssd_part_button(struct wl_list *button_parts,
        enum ssd_part_type type, struct wlr_scene_tree *parent,
-       struct lab_img *buffers[LAB_BS_ALL + 1], int x, int y,
+       struct lab_img *imgs[LAB_BS_ALL + 1], int x, int y,
        struct view *view);
-
-/* SSD internal helpers */
-struct ssd_part *ssd_get_part(
-       struct wl_list *part_list, enum ssd_part_type type);
-void ssd_destroy_parts(struct wl_list *list);
+struct ssd_part_button *button_try_from_ssd_part(struct ssd_part *part);
 
 /* SSD internal */
 void ssd_titlebar_create(struct ssd *ssd);
index cf0d3e24d677bc6908e05d14cd05f5134657cb1b..f3597f3180d0682bb39b72a59209e02a106e59a5 100644 (file)
@@ -6,6 +6,13 @@
 #include "common/edge.h"
 #include "config/types.h"
 
+enum ssd_active_state {
+       SSD_INACTIVE = 0,
+       SSD_ACTIVE = 1,
+};
+
+#define FOR_EACH_ACTIVE_STATE(active) for (active = SSD_INACTIVE; active <= SSD_ACTIVE; active++)
+
 struct wlr_cursor;
 
 /*
@@ -36,11 +43,8 @@ enum ssd_part_type {
        LAB_SSD_BUTTON,
 
        LAB_SSD_PART_TITLEBAR,
-       LAB_SSD_PART_TITLEBAR_CORNER_RIGHT,
-       LAB_SSD_PART_TITLEBAR_CORNER_LEFT,
        LAB_SSD_PART_TITLE,
 
-       /* shared by shadows, borders and extents */
        LAB_SSD_PART_CORNER_TOP_LEFT,
        LAB_SSD_PART_CORNER_TOP_RIGHT,
        LAB_SSD_PART_CORNER_BOTTOM_RIGHT,
@@ -64,8 +68,8 @@ enum ssd_part_type {
 
 /* Forward declare arguments */
 struct ssd;
-struct ssd_button;
 struct ssd_hover_state;
+struct ssd_part;
 struct view;
 struct wlr_scene;
 struct wlr_scene_node;
@@ -96,12 +100,17 @@ struct ssd_hover_state *ssd_hover_state_new(void);
 void ssd_update_button_hover(struct wlr_scene_node *node,
        struct ssd_hover_state *hover_state);
 
-enum ssd_part_type ssd_button_get_type(const struct ssd_button *button);
-struct view *ssd_button_get_view(const struct ssd_button *button);
+enum ssd_part_type ssd_part_get_type(const struct ssd_part *part);
+struct view *ssd_part_get_view(const struct ssd_part *part);
 
 /* Public SSD helpers */
-enum ssd_part_type ssd_get_part_type(const struct ssd *ssd,
-       struct wlr_scene_node *node, struct wlr_cursor *cursor);
+
+/*
+ * Returns a part type that represents a mouse context like "Top", "Left" and
+ * "TRCorner" when the cursor is on the window border or resizing handle.
+ */
+enum ssd_part_type ssd_get_resizing_type(const struct ssd *ssd,
+       struct wlr_cursor *cursor);
 enum lab_edge ssd_resize_edges(enum ssd_part_type type);
 bool ssd_part_contains(enum ssd_part_type whole, enum ssd_part_type candidate);
 enum lab_ssd_mode ssd_mode_parse(const char *mode);
index 92d4a99e3e396e9ee1547d7bfae5f9ad8483b990..68a43f2f9f9ab5146f6d5603ef1580d58bc88d1a 100644 (file)
@@ -192,6 +192,7 @@ struct theme {
        int mag_border_width;
 };
 
+/* TODO: replace with enum ssd_active_state */
 #define THEME_INACTIVE 0
 #define THEME_ACTIVE 1
 
index cbe0e81db2c62a9a38fc37a0f748ccd7522d4de4..280c0256a57ea87dfe833f2fb2efa79493e1cc36 100644 (file)
@@ -155,6 +155,7 @@ fill_section(const char *content, struct wl_list *list, uint32_t *found_buttons)
 
                assert(type != LAB_SSD_NONE);
 
+               /* We no longer need this check, but let's keep it just in case */
                if (*found_buttons & (1 << type)) {
                        wlr_log(WLR_ERROR, "ignoring duplicated button type '%s'",
                                identifier);
index a7cd86a2aab3429748924ddbf5922678ca944a0f..9eabab93d4f06c5feaf8ec26a56c02d8531ae6a9 100644 (file)
@@ -302,22 +302,30 @@ get_cursor_context(struct server *server)
                        case LAB_NODE_DESC_VIEW:
                        case LAB_NODE_DESC_XDG_POPUP:
                                ret.view = desc->data;
-                               ret.type = ssd_get_part_type(
-                                       ret.view->ssd, ret.node, cursor);
-                               if (ret.type == LAB_SSD_CLIENT) {
+                               if (ret.node->type == WLR_SCENE_NODE_BUFFER
+                                               && lab_wlr_surface_from_node(ret.node)) {
+                                       ret.type = LAB_SSD_CLIENT;
                                        ret.surface = lab_wlr_surface_from_node(ret.node);
+                               } else {
+                                       /* should never be reached */
+                                       wlr_log(WLR_ERROR, "cursor not on client or ssd");
                                }
                                return ret;
-                       case LAB_NODE_DESC_SSD_BUTTON: {
-                               /*
-                                * Always return the top scene node for SSD
-                                * buttons
-                                */
-                               struct ssd_button *button =
-                                       node_ssd_button_from_node(node);
+                       case LAB_NODE_DESC_SSD_PART: {
+                               struct ssd_part *part = node_ssd_part_from_node(node);
                                ret.node = node;
-                               ret.type = ssd_button_get_type(button);
-                               ret.view = ssd_button_get_view(button);
+                               ret.view = ssd_part_get_view(part);
+
+                               /* Detect mouse contexts like Top, Left and TRCorner */
+                               ret.type = ssd_get_resizing_type(ret.view->ssd, cursor);
+                               if (ret.type == LAB_SSD_NONE) {
+                                       /*
+                                        * Otherwise, detect mouse contexts like
+                                        * Title, Titlebar and Iconify
+                                        */
+                                       ret.type = ssd_part_get_type(part);
+                               }
+
                                return ret;
                        }
                        case LAB_NODE_DESC_LAYER_SURFACE:
index ae47044cf8e93777b01988b8ae6a4a44ccd294f3..37c63a7feb8dac622184488b339b1e56cdd70430 100644 (file)
@@ -71,13 +71,13 @@ node_menuitem_from_node(struct wlr_scene_node *wlr_scene_node)
        return (struct menuitem *)node_descriptor->data;
 }
 
-struct ssd_button *
-node_ssd_button_from_node(struct wlr_scene_node *wlr_scene_node)
+struct ssd_part *
+node_ssd_part_from_node(struct wlr_scene_node *wlr_scene_node)
 {
        assert(wlr_scene_node->data);
        struct node_descriptor *node_descriptor = wlr_scene_node->data;
-       assert(node_descriptor->type == LAB_NODE_DESC_SSD_BUTTON);
-       return (struct ssd_button *)node_descriptor->data;
+       assert(node_descriptor->type == LAB_NODE_DESC_SSD_PART);
+       return (struct ssd_part *)node_descriptor->data;
 }
 
 struct scaled_scene_buffer *
index 26216ed6a02a59fe9180e5c7526ae9a8e3bff8d5..4fff0ad4177e3c5024979136970801f1847427c1 100644 (file)
@@ -2,16 +2,13 @@
 
 #include <assert.h>
 #include <wlr/types/wlr_scene.h>
+#include "common/macros.h"
 #include "common/scene-helpers.h"
 #include "labwc.h"
 #include "ssd-internal.h"
 #include "theme.h"
 #include "view.h"
 
-#define FOR_EACH_STATE(ssd, tmp) FOR_EACH(tmp, \
-       &(ssd)->border.active, \
-       &(ssd)->border.inactive)
-
 void
 ssd_border_create(struct ssd *ssd)
 {
@@ -25,35 +22,37 @@ ssd_border_create(struct ssd *ssd)
        int full_width = width + 2 * theme->border_width;
        int corner_width = ssd_get_corner_width();
 
-       float *color;
-       struct wlr_scene_tree *parent;
-       struct ssd_sub_tree *subtree;
-       int active;
-
        ssd->border.tree = wlr_scene_tree_create(ssd->tree);
        wlr_scene_node_set_position(&ssd->border.tree->node, -theme->border_width, 0);
 
-       FOR_EACH_STATE(ssd, subtree) {
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_border_subtree *subtree = &ssd->border.subtrees[active];
                subtree->tree = wlr_scene_tree_create(ssd->border.tree);
-               parent = subtree->tree;
-               active = (subtree == &ssd->border.active) ?
-                       THEME_ACTIVE : THEME_INACTIVE;
+               struct wlr_scene_tree *parent = subtree->tree;
                wlr_scene_node_set_enabled(&parent->node, active);
-               color = theme->window[active].border_color;
-
-               wl_list_init(&subtree->parts);
-               add_scene_rect(&subtree->parts, LAB_SSD_PART_LEFT, parent,
-                       theme->border_width, height, 0, 0, color);
-               add_scene_rect(&subtree->parts, LAB_SSD_PART_RIGHT, parent,
-                       theme->border_width, height,
-                       theme->border_width + width, 0, color);
-               add_scene_rect(&subtree->parts, LAB_SSD_PART_BOTTOM, parent,
-                       full_width, theme->border_width, 0, height, color);
-               add_scene_rect(&subtree->parts, LAB_SSD_PART_TOP, parent,
-                       MAX(width - 2 * corner_width, 0), theme->border_width,
+               float *color = theme->window[active].border_color;
+
+               subtree->left = wlr_scene_rect_create(parent,
+                       theme->border_width, height, color);
+               wlr_scene_node_set_position(&subtree->left->node, 0, 0);
+
+               subtree->right = wlr_scene_rect_create(parent,
+                       theme->border_width, height, color);
+               wlr_scene_node_set_position(&subtree->right->node,
+                       theme->border_width + width, 0);
+
+               subtree->bottom = wlr_scene_rect_create(parent,
+                       full_width, theme->border_width, color);
+               wlr_scene_node_set_position(&subtree->bottom->node,
+                       0, height);
+
+               subtree->top = wlr_scene_rect_create(parent,
+                       MAX(width - 2 * corner_width, 0), theme->border_width, color);
+               wlr_scene_node_set_position(&subtree->top->node,
                        theme->border_width + corner_width,
-                       -(ssd->titlebar.height + theme->border_width), color);
-       } FOR_EACH_END
+                       -(ssd->titlebar.height + theme->border_width));
+       }
 
        if (view->maximized == VIEW_AXIS_BOTH) {
                wlr_scene_node_set_enabled(&ssd->border.tree->node, false);
@@ -129,50 +128,30 @@ ssd_border_update(struct ssd *ssd)
                ? 0
                : theme->border_width + corner_width;
 
-       struct ssd_part *part;
-       struct wlr_scene_rect *rect;
-       struct ssd_sub_tree *subtree;
-       FOR_EACH_STATE(ssd, subtree) {
-               wl_list_for_each(part, &subtree->parts, link) {
-                       rect = wlr_scene_rect_from_node(part->node);
-                       switch (part->type) {
-                       case LAB_SSD_PART_LEFT:
-                               wlr_scene_rect_set_size(rect,
-                                       theme->border_width,
-                                       side_height);
-                               wlr_scene_node_set_position(part->node,
-                                       0,
-                                       side_y);
-                               continue;
-                       case LAB_SSD_PART_RIGHT:
-                               wlr_scene_rect_set_size(rect,
-                                       theme->border_width,
-                                       side_height);
-                               wlr_scene_node_set_position(part->node,
-                                       theme->border_width + width,
-                                       side_y);
-                               continue;
-                       case LAB_SSD_PART_BOTTOM:
-                               wlr_scene_rect_set_size(rect,
-                                       full_width,
-                                       theme->border_width);
-                               wlr_scene_node_set_position(part->node,
-                                       0,
-                                       height);
-                               continue;
-                       case LAB_SSD_PART_TOP:
-                               wlr_scene_rect_set_size(rect,
-                                       top_width,
-                                       theme->border_width);
-                               wlr_scene_node_set_position(part->node,
-                                       top_x,
-                                       -(ssd->titlebar.height + theme->border_width));
-                               continue;
-                       default:
-                               continue;
-                       }
-               }
-       } FOR_EACH_END
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_border_subtree *subtree = &ssd->border.subtrees[active];
+
+               wlr_scene_rect_set_size(subtree->left,
+                       theme->border_width, side_height);
+               wlr_scene_node_set_position(&subtree->left->node,
+                       0, side_y);
+
+               wlr_scene_rect_set_size(subtree->right,
+                       theme->border_width, side_height);
+               wlr_scene_node_set_position(&subtree->right->node,
+                       theme->border_width + width, side_y);
+
+               wlr_scene_rect_set_size(subtree->bottom,
+                       full_width, theme->border_width);
+               wlr_scene_node_set_position(&subtree->bottom->node,
+                       0, height);
+
+               wlr_scene_rect_set_size(subtree->top,
+                       top_width, theme->border_width);
+               wlr_scene_node_set_position(&subtree->top->node,
+                       top_x, -(ssd->titlebar.height + theme->border_width));
+       }
 }
 
 void
@@ -181,15 +160,6 @@ ssd_border_destroy(struct ssd *ssd)
        assert(ssd);
        assert(ssd->border.tree);
 
-       struct ssd_sub_tree *subtree;
-       FOR_EACH_STATE(ssd, subtree) {
-               ssd_destroy_parts(&subtree->parts);
-               wlr_scene_node_destroy(&subtree->tree->node);
-               subtree->tree = NULL;
-       } FOR_EACH_END
-
        wlr_scene_node_destroy(&ssd->border.tree->node);
-       ssd->border.tree = NULL;
+       ssd->border = (struct ssd_border_scene){0};
 }
-
-#undef FOR_EACH_STATE
index bb3f661e237a3d3c7573c844ff194e1cf4e279f1..8a38c39eb42efbbdaef8efe4944d96915263ba0e 100644 (file)
 #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};
 }
index 317d076c6aad6869d8844c108657ac71de3fa0ac..09dbf6a12ee43a17683f64c614e24fe4feb38242 100644 (file)
 // SPDX-License-Identifier: GPL-2.0-only
 
 #include <assert.h>
-#include "buffer.h"
-#include "common/box.h"
+#include "config/rcxml.h"
 #include "common/list.h"
 #include "common/mem.h"
 #include "common/scaled-icon-buffer.h"
 #include "common/scaled-img-buffer.h"
-#include "config/rcxml.h"
-#include "labwc.h"
 #include "node.h"
 #include "ssd-internal.h"
 
 /* Internal helpers */
 static void
-handle_button_node_destroy(struct wl_listener *listener, void *data)
+handle_node_destroy(struct wl_listener *listener, void *data)
 {
-       struct ssd_button *button = wl_container_of(listener, button, destroy);
-       wl_list_remove(&button->destroy.link);
-       free(button);
+       struct ssd_part *part = wl_container_of(listener, part, node_destroy);
+       wl_list_remove(&part->node_destroy.link);
+
+       struct ssd_part_button *button = button_try_from_ssd_part(part);
+       if (button) {
+               wl_list_remove(&button->link);
+       }
+
+       free(part);
 }
 
+/* Internal API */
+
 /*
- * Create a new node_descriptor containing a link to a new ssd_button struct.
+ * Create a new node_descriptor containing a link to a new ssd_part struct.
  * Both will be destroyed automatically once the scene_node they are attached
  * to is destroyed.
  */
-static struct ssd_button *
-ssd_button_descriptor_create(struct wlr_scene_node *node)
-{
-       /* Create new ssd_button */
-       struct ssd_button *button = znew(*button);
-
-       /* Let it destroy automatically when the scene node destroys */
-       button->destroy.notify = handle_button_node_destroy;
-       wl_signal_add(&node->events.destroy, &button->destroy);
-
-       /* And finally attach the ssd_button to a node descriptor */
-       node_descriptor_create(node, LAB_NODE_DESC_SSD_BUTTON, button);
-       return button;
-}
-
-/* Internal API */
-struct ssd_part *
-add_scene_part(struct wl_list *part_list, enum ssd_part_type type)
+static void
+init_ssd_part(struct ssd_part *part, enum ssd_part_type type,
+               struct view *view, struct wlr_scene_node *node)
 {
-       struct ssd_part *part = znew(*part);
        part->type = type;
-       wl_list_append(part_list, &part->link);
-       return part;
-}
+       part->node = node;
+       part->view = view;
 
-struct ssd_part *
-add_scene_rect(struct wl_list *list, enum ssd_part_type type,
-       struct wlr_scene_tree *parent, int width, int height,
-       int x, int y, float color[4])
-{
-       assert(width >= 0 && height >= 0);
-       struct ssd_part *part = add_scene_part(list, type);
-       part->node = &wlr_scene_rect_create(
-               parent, width, height, color)->node;
-       wlr_scene_node_set_position(part->node, x, y);
-       return part;
+       node_descriptor_create(node, LAB_NODE_DESC_SSD_PART, part);
+       part->node_destroy.notify = handle_node_destroy;
+       wl_signal_add(&node->events.destroy, &part->node_destroy);
 }
 
 struct ssd_part *
-add_scene_buffer(struct wl_list *list, enum ssd_part_type type,
-       struct wlr_scene_tree *parent, struct wlr_buffer *buffer,
-       int x, int y)
+attach_ssd_part(enum ssd_part_type type, struct view *view,
+               struct wlr_scene_node *node)
 {
-       struct ssd_part *part = add_scene_part(list, type);
-       part->node = &wlr_scene_buffer_create(parent, buffer)->node;
-       wlr_scene_node_set_position(part->node, x, y);
+       assert(!ssd_part_contains(LAB_SSD_BUTTON, type));
+       struct ssd_part *part = znew(*part);
+       init_ssd_part(part, type, view, node);
        return part;
 }
 
-struct ssd_part *
-add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
+struct ssd_part_button *
+attach_ssd_part_button(struct wl_list *button_parts, enum ssd_part_type type,
                struct wlr_scene_tree *parent,
                struct lab_img *imgs[LAB_BS_ALL + 1],
                int x, int y, struct view *view)
 {
-       struct ssd_part *button_root = add_scene_part(part_list, type);
-       parent = wlr_scene_tree_create(parent);
-       button_root->node = &parent->node;
-       wlr_scene_node_set_position(button_root->node, x, y);
+       struct wlr_scene_tree *root = wlr_scene_tree_create(parent);
+       wlr_scene_node_set_position(&root->node, x, y);
 
-       struct ssd_button *button = ssd_button_descriptor_create(button_root->node);
-       button->type = type;
-       button->view = view;
+       assert(ssd_part_contains(LAB_SSD_BUTTON, type));
+       struct ssd_part_button *button = znew(*button);
+       init_ssd_part(&button->base, type, view, &root->node);
+       wl_list_append(button_parts, &button->link);
 
        /* Hitbox */
        float invisible[4] = { 0, 0, 0, 0 };
-       add_scene_rect(part_list, type, parent,
-               rc.theme->window_button_width, rc.theme->window_button_height, 0, 0,
-               invisible);
+       wlr_scene_rect_create(root, rc.theme->window_button_width,
+               rc.theme->window_button_height, invisible);
 
        /* Icons */
        int button_width = rc.theme->window_button_width;
@@ -110,14 +87,13 @@ add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
        int icon_padding = button_width / 10;
 
        if (type == LAB_SSD_BUTTON_WINDOW_ICON) {
-               struct ssd_part *icon_part = add_scene_part(part_list, type);
                struct scaled_icon_buffer *icon_buffer =
-                       scaled_icon_buffer_create(parent, view->server,
+                       scaled_icon_buffer_create(root, view->server,
                                button_width - 2 * icon_padding, button_height);
-               scaled_icon_buffer_set_view(icon_buffer, view);
                assert(icon_buffer);
-               icon_part->node = &icon_buffer->scene_buffer->node;
-               wlr_scene_node_set_position(icon_part->node, icon_padding, 0);
+               struct wlr_scene_node *icon_node = &icon_buffer->scene_buffer->node;
+               scaled_icon_buffer_set_view(icon_buffer, view);
+               wlr_scene_node_set_position(icon_node, icon_padding, 0);
                button->window_icon = icon_buffer;
        } else {
                for (uint8_t state_set = LAB_BS_DEFAULT;
@@ -125,13 +101,12 @@ add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
                        if (!imgs[state_set]) {
                                continue;
                        }
-                       struct ssd_part *icon_part = add_scene_part(part_list, type);
                        struct scaled_img_buffer *img_buffer = scaled_img_buffer_create(
-                               parent, imgs[state_set], rc.theme->window_button_width,
+                               root, imgs[state_set], rc.theme->window_button_width,
                                rc.theme->window_button_height);
                        assert(img_buffer);
-                       icon_part->node = &img_buffer->scene_buffer->node;
-                       wlr_scene_node_set_enabled(icon_part->node, false);
+                       struct wlr_scene_node *icon_node = &img_buffer->scene_buffer->node;
+                       wlr_scene_node_set_enabled(icon_node, false);
                        button->img_buffers[state_set] = img_buffer;
                }
                /* Initially show non-hover, non-toggled, unrounded variant */
@@ -139,34 +114,14 @@ add_scene_button(struct wl_list *part_list, enum ssd_part_type type,
                        &button->img_buffers[LAB_BS_DEFAULT]->scene_buffer->node, true);
        }
 
-       return button_root;
+       return button;
 }
 
-struct ssd_part *
-ssd_get_part(struct wl_list *part_list, enum ssd_part_type type)
+struct ssd_part_button *
+button_try_from_ssd_part(struct ssd_part *part)
 {
-       struct ssd_part *part;
-       wl_list_for_each(part, part_list, link) {
-               if (part->type == type) {
-                       return part;
-               }
+       if (ssd_part_contains(LAB_SSD_BUTTON, part->type)) {
+               return (struct ssd_part_button *)part;
        }
        return NULL;
 }
-
-void
-ssd_destroy_parts(struct wl_list *list)
-{
-       struct ssd_part *part, *tmp;
-       wl_list_for_each_reverse_safe(part, tmp, list, link) {
-               if (part->node) {
-                       wlr_scene_node_destroy(part->node);
-                       part->node = NULL;
-               }
-               /* part->buffer will free itself along the scene_buffer node */
-               part->buffer = NULL;
-               wl_list_remove(&part->link);
-               free(part);
-       }
-       assert(wl_list_empty(list));
-}
index c17438024e3124f412d16dbe9d402499e167b2a2..2e86c864fd82c1578e6e09e98a6bccd0528f70d5 100644 (file)
 #include "theme.h"
 #include "view.h"
 
-#define FOR_EACH_STATE(ssd, tmp) FOR_EACH(tmp, \
-       &(ssd)->shadow.active, \
-       &(ssd)->shadow.inactive)
-
 /*
  * Implements point_accepts_input for a buffer which never accepts input
  * because drop-shadows should never catch clicks!
@@ -50,12 +46,10 @@ corner_scale_crop(struct wlr_scene_buffer *buffer, int horizontal_overlap,
  * drop-shadow.
  */
 static void
-set_shadow_part_geometry(struct ssd_part *part, int width, int height,
-               int titlebar_height, int corner_size, int inset,
-               int visible_shadow_width)
+set_shadow_parts_geometry(struct ssd_shadow_subtree *subtree,
+               int width, int height, int titlebar_height, int corner_size,
+               int inset, int visible_shadow_width)
 {
-       struct wlr_scene_buffer *scene_buf =
-               wlr_scene_buffer_from_node(part->node);
        /*
         * If the shadow inset is greater than half the overall window height
         * or width (eg. because the window is shaded or because we have a
@@ -81,83 +75,69 @@ set_shadow_part_geometry(struct ssd_part *part, int width, int height,
         * the top-left and bottom-right corners one pixel wider (if the width
         * is odd) or taller (if the height is odd).
         */
-       if (part->type == LAB_SSD_PART_CORNER_TOP_LEFT
-                       || part->type == LAB_SSD_PART_CORNER_BOTTOM_RIGHT) {
-               if (horizontal_overlap > 0) {
-                       horizontal_overlap -= width % 2;
-               }
-               if (vertical_overlap > 0) {
-                       vertical_overlap -= height % 2;
-               }
+       int horizontal_overlap_downsized = horizontal_overlap;
+       if (horizontal_overlap > 0) {
+               horizontal_overlap_downsized -= width % 2;
+       }
+       int vertical_overlap_downsized = vertical_overlap;
+       if (vertical_overlap > 0) {
+               vertical_overlap_downsized -= height % 2;
        }
 
        int x;
        int y;
 
-       switch (part->type) {
-       case LAB_SSD_PART_CORNER_BOTTOM_RIGHT:
-               x = width - inset + horizontal_overlap;
-               y = -titlebar_height + height - inset + vertical_overlap;
-               wlr_scene_node_set_position(part->node, x, y);
-               corner_scale_crop(scene_buf, horizontal_overlap,
-                       vertical_overlap, corner_size);
-               break;
-       case LAB_SSD_PART_CORNER_BOTTOM_LEFT:
-               x = -visible_shadow_width;
-               y = -titlebar_height + height - inset + vertical_overlap;
-               wlr_scene_node_set_position(part->node, x, y);
-               corner_scale_crop(scene_buf, horizontal_overlap,
-                       vertical_overlap, corner_size);
-               break;
-       case LAB_SSD_PART_CORNER_TOP_LEFT:
-               x = -visible_shadow_width;
-               y = -titlebar_height - visible_shadow_width;
-               wlr_scene_node_set_position(part->node, x, y);
-               corner_scale_crop(scene_buf, horizontal_overlap,
-                       vertical_overlap, corner_size);
-               break;
-       case LAB_SSD_PART_CORNER_TOP_RIGHT:
-               x = width - inset + horizontal_overlap;
-               y = -titlebar_height - visible_shadow_width;
-               wlr_scene_node_set_position(part->node, x, y);
-               corner_scale_crop(scene_buf, horizontal_overlap,
-                       vertical_overlap, corner_size);
-               break;
-       case LAB_SSD_PART_RIGHT:
-               x = width;
-               y = -titlebar_height + inset;
-               wlr_scene_node_set_position(part->node, x, y);
-               wlr_scene_buffer_set_dest_size(
-                       scene_buf, visible_shadow_width, MAX(height - 2 * inset, 0));
-               wlr_scene_node_set_enabled(part->node, show_sides);
-               break;
-       case LAB_SSD_PART_BOTTOM:
-               x = inset;
-               y = -titlebar_height + height;
-               wlr_scene_node_set_position(part->node, x, y);
-               wlr_scene_buffer_set_dest_size(
-                       scene_buf, MAX(width - 2 * inset, 0), visible_shadow_width);
-               wlr_scene_node_set_enabled(part->node, show_topbottom);
-               break;
-       case LAB_SSD_PART_LEFT:
-               x = -visible_shadow_width;
-               y = -titlebar_height + inset;
-               wlr_scene_node_set_position(part->node, x, y);
-               wlr_scene_buffer_set_dest_size(
-                       scene_buf, visible_shadow_width, MAX(height - 2 * inset, 0));
-               wlr_scene_node_set_enabled(part->node, show_sides);
-               break;
-       case LAB_SSD_PART_TOP:
-               x = inset;
-               y = -titlebar_height - visible_shadow_width;
-               wlr_scene_node_set_position(part->node, x, y);
-               wlr_scene_buffer_set_dest_size(
-                       scene_buf, MAX(width - 2 * inset, 0), visible_shadow_width);
-               wlr_scene_node_set_enabled(part->node, show_topbottom);
-               break;
-       default:
-               break;
-       }
+       x = width - inset + horizontal_overlap_downsized;
+       y = -titlebar_height + height - inset + vertical_overlap_downsized;
+       wlr_scene_node_set_position(&subtree->bottom_right->node, x, y);
+       corner_scale_crop(subtree->bottom_right, horizontal_overlap_downsized,
+               vertical_overlap_downsized, corner_size);
+
+       x = -visible_shadow_width;
+       y = -titlebar_height + height - inset + vertical_overlap;
+       wlr_scene_node_set_position(&subtree->bottom_left->node, x, y);
+       corner_scale_crop(subtree->bottom_left, horizontal_overlap,
+               vertical_overlap, corner_size);
+
+       x = -visible_shadow_width;
+       y = -titlebar_height - visible_shadow_width;
+       wlr_scene_node_set_position(&subtree->top_left->node, x, y);
+       corner_scale_crop(subtree->top_left, horizontal_overlap_downsized,
+               vertical_overlap_downsized, corner_size);
+
+       x = width - inset + horizontal_overlap;
+       y = -titlebar_height - visible_shadow_width;
+       wlr_scene_node_set_position(&subtree->top_right->node, x, y);
+       corner_scale_crop(subtree->top_right, horizontal_overlap,
+               vertical_overlap, corner_size);
+
+       x = width;
+       y = -titlebar_height + inset;
+       wlr_scene_node_set_position(&subtree->right->node, x, y);
+       wlr_scene_buffer_set_dest_size(subtree->right,
+               visible_shadow_width, MAX(height - 2 * inset, 0));
+       wlr_scene_node_set_enabled(&subtree->right->node, show_sides);
+
+       x = inset;
+       y = -titlebar_height + height;
+       wlr_scene_node_set_position(&subtree->bottom->node, x, y);
+       wlr_scene_buffer_set_dest_size(subtree->bottom,
+               MAX(width - 2 * inset, 0), visible_shadow_width);
+       wlr_scene_node_set_enabled(&subtree->bottom->node, show_topbottom);
+
+       x = -visible_shadow_width;
+       y = -titlebar_height + inset;
+       wlr_scene_node_set_position(&subtree->left->node, x, y);
+       wlr_scene_buffer_set_dest_size(subtree->left,
+               visible_shadow_width, MAX(height - 2 * inset, 0));
+       wlr_scene_node_set_enabled(&subtree->left->node, show_sides);
+
+       x = inset;
+       y = -titlebar_height - visible_shadow_width;
+       wlr_scene_node_set_position(&subtree->top->node, x, y);
+       wlr_scene_buffer_set_dest_size(subtree->top,
+               MAX(width - 2 * inset, 0), visible_shadow_width);
+       wlr_scene_node_set_enabled(&subtree->top->node, show_topbottom);
 }
 
 static void
@@ -169,17 +149,14 @@ set_shadow_geometry(struct ssd *ssd)
        int width = view->current.width;
        int height = view_effective_height(view, false) + titlebar_height;
 
-       struct ssd_part *part;
-       struct ssd_sub_tree *subtree;
-
-       FOR_EACH_STATE(ssd, subtree) {
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_shadow_subtree *subtree = &ssd->shadow.subtrees[active];
                if (!subtree->tree) {
                        /* Looks like this type of shadow is disabled */
                        continue;
                }
 
-               int active = (subtree == &ssd->shadow.active) ?
-                       THEME_ACTIVE : THEME_INACTIVE;
                int visible_shadow_width = theme->window[active].shadow_size;
                /* inset as a proportion of shadow width */
                double inset_proportion = SSD_SHADOW_INSET;
@@ -194,23 +171,19 @@ set_shadow_geometry(struct ssd *ssd)
                int corner_size =
                        theme->window[active].shadow_corner_top->logical_height;
 
-               wl_list_for_each(part, &subtree->parts, link) {
-                       set_shadow_part_geometry(part, width, height,
-                               titlebar_height, corner_size, inset,
-                               visible_shadow_width);
-               }
-       } FOR_EACH_END
+               set_shadow_parts_geometry(subtree, width, height,
+                       titlebar_height, corner_size, inset,
+                       visible_shadow_width);
+       }
 }
 
-static void
-make_shadow(struct wl_list *parts, enum ssd_part_type type,
+static struct wlr_scene_buffer *
+make_shadow(struct view *view,
        struct wlr_scene_tree *parent, struct wlr_buffer *buf,
        enum wl_output_transform tx)
 {
-       struct ssd_part *part = add_scene_buffer(
-               parts, type, parent, buf, 0, 0);
        struct wlr_scene_buffer *scene_buf =
-               wlr_scene_buffer_from_node(part->node);
+               wlr_scene_buffer_create(parent, buf);
        wlr_scene_buffer_set_transform(scene_buf, tx);
        scene_buf->point_accepts_input = never_accepts_input;
        /*
@@ -218,6 +191,7 @@ make_shadow(struct wl_list *parts, enum ssd_part_type type,
         * pixel wide/tall. Use nearest-neighbour scaling to workaround.
         */
        scene_buf->filter_mode = WLR_SCALE_FILTER_NEAREST;
+       return scene_buf;
 }
 
 void
@@ -229,51 +203,47 @@ ssd_shadow_create(struct ssd *ssd)
        ssd->shadow.tree = wlr_scene_tree_create(ssd->tree);
 
        struct theme *theme = ssd->view->server->theme;
-       struct wlr_buffer *corner_top_buffer;
-       struct wlr_buffer *corner_bottom_buffer;
-       struct wlr_buffer *edge_buffer;
-       struct ssd_sub_tree *subtree;
-       struct wlr_scene_tree *parent;
-       int active;
+       struct view *view = ssd->view;
 
-       FOR_EACH_STATE(ssd, subtree) {
-               wl_list_init(&subtree->parts);
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_shadow_subtree *subtree = &ssd->shadow.subtrees[active];
 
                if (!rc.shadows_enabled) {
                        /* Shadows are globally disabled */
                        continue;
                }
-               active = (subtree == &ssd->shadow.active) ?
-                       THEME_ACTIVE : THEME_INACTIVE;
                if (theme->window[active].shadow_size == 0) {
                        /* Window shadows are disabled */
                        continue;
                }
 
                subtree->tree = wlr_scene_tree_create(ssd->shadow.tree);
-               parent = subtree->tree;
-               corner_top_buffer = &theme->window[active].shadow_corner_top->base;
-               corner_bottom_buffer = &theme->window[active].shadow_corner_bottom->base;
-               edge_buffer = &theme->window[active].shadow_edge->base;
-
-               make_shadow(&subtree->parts, LAB_SSD_PART_CORNER_BOTTOM_RIGHT,
-                       parent, corner_bottom_buffer, WL_OUTPUT_TRANSFORM_NORMAL);
-               make_shadow(&subtree->parts, LAB_SSD_PART_CORNER_BOTTOM_LEFT,
-                       parent, corner_bottom_buffer, WL_OUTPUT_TRANSFORM_FLIPPED);
-               make_shadow(&subtree->parts, LAB_SSD_PART_CORNER_TOP_LEFT,
-                       parent, corner_top_buffer, WL_OUTPUT_TRANSFORM_180);
-               make_shadow(&subtree->parts, LAB_SSD_PART_CORNER_TOP_RIGHT,
-                       parent, corner_top_buffer, WL_OUTPUT_TRANSFORM_FLIPPED_180);
-               make_shadow(&subtree->parts, LAB_SSD_PART_RIGHT, parent,
+               struct wlr_scene_tree *parent = subtree->tree;
+               struct wlr_buffer *corner_top_buffer =
+                       &theme->window[active].shadow_corner_top->base;
+               struct wlr_buffer *corner_bottom_buffer =
+                       &theme->window[active].shadow_corner_bottom->base;
+               struct wlr_buffer *edge_buffer =
+                       &theme->window[active].shadow_edge->base;
+
+               subtree->bottom_right = make_shadow(view, parent,
+                       corner_bottom_buffer, WL_OUTPUT_TRANSFORM_NORMAL);
+               subtree->bottom_left = make_shadow(view, parent,
+                       corner_bottom_buffer, WL_OUTPUT_TRANSFORM_FLIPPED);
+               subtree->top_left = make_shadow(view, parent,
+                       corner_top_buffer, WL_OUTPUT_TRANSFORM_180);
+               subtree->top_right = make_shadow(view, parent,
+                       corner_top_buffer, WL_OUTPUT_TRANSFORM_FLIPPED_180);
+               subtree->right = make_shadow(view, parent,
                        edge_buffer, WL_OUTPUT_TRANSFORM_NORMAL);
-               make_shadow(&subtree->parts, LAB_SSD_PART_BOTTOM, parent,
+               subtree->bottom = make_shadow(view, parent,
                        edge_buffer, WL_OUTPUT_TRANSFORM_90);
-               make_shadow(&subtree->parts, LAB_SSD_PART_LEFT, parent,
+               subtree->left = make_shadow(view, parent,
                        edge_buffer, WL_OUTPUT_TRANSFORM_180);
-               make_shadow(&subtree->parts, LAB_SSD_PART_TOP, parent,
+               subtree->top = make_shadow(view, parent,
                        edge_buffer, WL_OUTPUT_TRANSFORM_270);
-
-       } FOR_EACH_END
+       }
 
        ssd_shadow_update(ssd);
 }
@@ -310,16 +280,6 @@ ssd_shadow_destroy(struct ssd *ssd)
        assert(ssd);
        assert(ssd->shadow.tree);
 
-       struct ssd_sub_tree *subtree;
-       FOR_EACH_STATE(ssd, subtree) {
-               ssd_destroy_parts(&subtree->parts);
-               /*
-                * subtree->tree will be destroyed when its
-                * parent (ssd->shadow.tree) is destroyed.
-                */
-               subtree->tree = NULL;
-       } FOR_EACH_END
-
        wlr_scene_node_destroy(&ssd->shadow.tree->node);
-       ssd->shadow.tree = NULL;
+       ssd->shadow = (struct ssd_shadow_scene){0};
 }
index 2cd963ff172676e6047bf733a0aa3a241fea4105..fabcaf7ac69b7e3bdb02f6415ef56c427b322010 100644 (file)
 #include "theme.h"
 #include "view.h"
 
-#define FOR_EACH_STATE(ssd, tmp) FOR_EACH(tmp, \
-       &(ssd)->titlebar.active, \
-       &(ssd)->titlebar.inactive)
-
 static void set_squared_corners(struct ssd *ssd, bool enable);
 static void set_alt_button_icon(struct ssd *ssd, enum ssd_part_type type, bool enable);
 static void update_visible_buttons(struct ssd *ssd);
@@ -36,30 +32,26 @@ ssd_titlebar_create(struct ssd *ssd)
        int width = view->current.width;
        int corner_width = ssd_get_corner_width();
 
-       struct wlr_scene_tree *parent;
-       struct wlr_buffer *titlebar_fill;
-       struct wlr_buffer *corner_top_left;
-       struct wlr_buffer *corner_top_right;
-       int active;
-
        ssd->titlebar.tree = wlr_scene_tree_create(ssd->tree);
+       attach_ssd_part(LAB_SSD_PART_TITLEBAR, view, &ssd->tree->node);
 
-       struct ssd_sub_tree *subtree;
-       FOR_EACH_STATE(ssd, subtree) {
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active];
                subtree->tree = wlr_scene_tree_create(ssd->titlebar.tree);
-               parent = subtree->tree;
-               active = (subtree == &ssd->titlebar.active) ?
-                       THEME_ACTIVE : THEME_INACTIVE;
-               titlebar_fill = &theme->window[active].titlebar_fill->base;
-               corner_top_left = &theme->window[active].corner_top_left_normal->base;
-               corner_top_right = &theme->window[active].corner_top_right_normal->base;
+               struct wlr_scene_tree *parent = subtree->tree;
                wlr_scene_node_set_enabled(&parent->node, active);
                wlr_scene_node_set_position(&parent->node, 0, -theme->titlebar_height);
-               wl_list_init(&subtree->parts);
+
+               struct wlr_buffer *titlebar_fill =
+                       &theme->window[active].titlebar_fill->base;
+               struct wlr_buffer *corner_top_left =
+                       &theme->window[active].corner_top_left_normal->base;
+               struct wlr_buffer *corner_top_right =
+                       &theme->window[active].corner_top_right_normal->base;
 
                /* Background */
-               struct wlr_scene_buffer *bg_scene_buffer =
-                       wlr_scene_buffer_create(parent, titlebar_fill);
+               subtree->bar = wlr_scene_buffer_create(parent, titlebar_fill);
                /*
                 * Work around the wlroots/pixman bug that widened 1px buffer
                 * becomes translucent when bilinear filtering is used.
@@ -68,27 +60,25 @@ ssd_titlebar_create(struct ssd *ssd)
                 */
                if (wlr_renderer_is_pixman(view->server->renderer)) {
                        wlr_scene_buffer_set_filter_mode(
-                               bg_scene_buffer, WLR_SCALE_FILTER_NEAREST);
+                               subtree->bar, WLR_SCALE_FILTER_NEAREST);
                }
-               struct ssd_part *bg_part =
-                       add_scene_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
-               bg_part->node = &bg_scene_buffer->node;
-               wlr_scene_node_set_position(bg_part->node, corner_width, 0);
+               wlr_scene_node_set_position(&subtree->bar->node, corner_width, 0);
+
+               subtree->corner_left = wlr_scene_buffer_create(parent, corner_top_left);
+               wlr_scene_node_set_position(&subtree->corner_left->node,
+                       -rc.theme->border_width, -rc.theme->border_width);
 
-               add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_LEFT, parent,
-                       corner_top_left, -rc.theme->border_width, -rc.theme->border_width);
-               add_scene_buffer(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT, parent,
-                       corner_top_right, width - corner_width,
-                       -rc.theme->border_width);
+               subtree->corner_right = wlr_scene_buffer_create(parent, corner_top_right);
+               wlr_scene_node_set_position(&subtree->corner_right->node,
+                       width - corner_width, -rc.theme->border_width);
 
                /* Title */
-               struct ssd_part *title_part =
-                       add_scene_part(&subtree->parts, LAB_SSD_PART_TITLE);
-               title_part->buffer = scaled_font_buffer_create_for_titlebar(
+               subtree->title = scaled_font_buffer_create_for_titlebar(
                        subtree->tree, theme->titlebar_height,
                        theme->window[active].titlebar_pattern);
-               assert(title_part->buffer);
-               title_part->node = &title_part->buffer->scene_buffer->node;
+               assert(subtree->title);
+               attach_ssd_part(LAB_SSD_PART_TITLE,
+                       view, &subtree->title->scene_buffer->node);
 
                /* Buttons */
                struct title_button *b;
@@ -97,10 +87,13 @@ ssd_titlebar_create(struct ssd *ssd)
                /* Center vertically within titlebar */
                int y = (theme->titlebar_height - theme->window_button_height) / 2;
 
+               wl_list_init(&subtree->buttons_left);
+               wl_list_init(&subtree->buttons_right);
+
                wl_list_for_each(b, &rc.title_buttons_left, link) {
                        struct lab_img **imgs =
                                theme->window[active].button_imgs[b->type];
-                       add_scene_button(&subtree->parts, b->type, parent,
+                       attach_ssd_part_button(&subtree->buttons_left, b->type, parent,
                                imgs, x, y, view);
                        x += theme->window_button_width + theme->window_button_spacing;
                }
@@ -110,10 +103,10 @@ ssd_titlebar_create(struct ssd *ssd)
                        x -= theme->window_button_width + theme->window_button_spacing;
                        struct lab_img **imgs =
                                theme->window[active].button_imgs[b->type];
-                       add_scene_button(&subtree->parts, b->type, parent,
+                       attach_ssd_part_button(&subtree->buttons_right, b->type, parent,
                                imgs, x, y, view);
                }
-       } FOR_EACH_END
+       }
 
        update_visible_buttons(ssd);
 
@@ -140,7 +133,7 @@ ssd_titlebar_create(struct ssd *ssd)
 }
 
 static void
-update_button_state(struct ssd_button *button, enum lab_button_state state,
+update_button_state(struct ssd_part_button *button, enum lab_button_state state,
                bool enable)
 {
        if (enable) {
@@ -168,56 +161,54 @@ set_squared_corners(struct ssd *ssd, bool enable)
        int corner_width = ssd_get_corner_width();
        struct theme *theme = view->server->theme;
 
-       struct ssd_part *part;
-       struct ssd_sub_tree *subtree;
        int x = enable ? 0 : corner_width;
 
-       FOR_EACH_STATE(ssd, subtree) {
-               part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
-               wlr_scene_node_set_position(part->node, x, 0);
-               wlr_scene_buffer_set_dest_size(
-                       wlr_scene_buffer_from_node(part->node),
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active];
+
+               wlr_scene_node_set_position(&subtree->bar->node, x, 0);
+               wlr_scene_buffer_set_dest_size(subtree->bar,
                        MAX(width - 2 * x, 0), theme->titlebar_height);
 
-               part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_LEFT);
-               wlr_scene_node_set_enabled(part->node, !enable);
+               wlr_scene_node_set_enabled(&subtree->corner_left->node, !enable);
 
-               part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT);
-               wlr_scene_node_set_enabled(part->node, !enable);
+               wlr_scene_node_set_enabled(&subtree->corner_right->node, !enable);
 
                /* (Un)round the corner buttons */
-               struct title_button *title_button;
-               wl_list_for_each(title_button, &rc.title_buttons_left, link) {
-                       part = ssd_get_part(&subtree->parts, title_button->type);
-                       struct ssd_button *button = node_ssd_button_from_node(part->node);
+               struct ssd_part_button *button;
+               wl_list_for_each(button, &subtree->buttons_left, link) {
                        update_button_state(button, LAB_BS_ROUNDED, !enable);
                        break;
                }
-               wl_list_for_each_reverse(title_button, &rc.title_buttons_right, link) {
-                       part = ssd_get_part(&subtree->parts, title_button->type);
-                       struct ssd_button *button = node_ssd_button_from_node(part->node);
+               wl_list_for_each(button, &subtree->buttons_right, link) {
                        update_button_state(button, LAB_BS_ROUNDED, !enable);
                        break;
                }
-       } FOR_EACH_END
+       }
 }
 
 static void
 set_alt_button_icon(struct ssd *ssd, enum ssd_part_type type, bool enable)
 {
-       struct ssd_part *part;
-       struct ssd_button *button;
-       struct ssd_sub_tree *subtree;
-
-       FOR_EACH_STATE(ssd, subtree) {
-               part = ssd_get_part(&subtree->parts, type);
-               if (!part) {
-                       return;
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active];
+
+               struct ssd_part_button *button;
+               wl_list_for_each(button, &subtree->buttons_left, link) {
+                       if (button->base.type == type) {
+                               update_button_state(button,
+                                       LAB_BS_TOGGLED, enable);
+                       }
                }
-
-               button = node_ssd_button_from_node(part->node);
-               update_button_state(button, LAB_BS_TOGGLED, enable);
-       } FOR_EACH_END
+               wl_list_for_each(button, &subtree->buttons_right, link) {
+                       if (button->base.type == type) {
+                               update_button_state(button,
+                                       LAB_BS_TOGGLED, enable);
+                       }
+               }
+       }
 }
 
 /*
@@ -254,27 +245,25 @@ update_visible_buttons(struct ssd *ssd)
                }
        }
 
-       int button_count;
-       struct ssd_part *part;
-       struct ssd_sub_tree *subtree;
-       struct title_button *b;
-       FOR_EACH_STATE(ssd, subtree) {
-               button_count = 0;
-               wl_list_for_each(b, &rc.title_buttons_left, link) {
-                       part = ssd_get_part(&subtree->parts, b->type);
-                       wlr_scene_node_set_enabled(part->node,
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active];
+               int button_count = 0;
+
+               struct ssd_part_button *button;
+               wl_list_for_each(button, &subtree->buttons_left, link) {
+                       wlr_scene_node_set_enabled(button->base.node,
                                button_count < button_count_left);
                        button_count++;
                }
 
                button_count = 0;
-               wl_list_for_each_reverse(b, &rc.title_buttons_right, link) {
-                       part = ssd_get_part(&subtree->parts, b->type);
-                       wlr_scene_node_set_enabled(part->node,
+               wl_list_for_each(button, &subtree->buttons_right, link) {
+                       wlr_scene_node_set_enabled(button->base.node,
                                button_count < button_count_right);
                        button_count++;
                }
-       } FOR_EACH_END
+       }
 }
 
 void
@@ -318,34 +307,31 @@ ssd_titlebar_update(struct ssd *ssd)
        /* Center buttons vertically within titlebar */
        int y = (theme->titlebar_height - theme->window_button_height) / 2;
        int x;
-       struct ssd_part *part;
-       struct ssd_sub_tree *subtree;
-       struct title_button *b;
        int bg_offset = maximized || squared ? 0 : corner_width;
-       FOR_EACH_STATE(ssd, subtree) {
-               part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR);
-               wlr_scene_buffer_set_dest_size(
-                       wlr_scene_buffer_from_node(part->node),
+
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active];
+               wlr_scene_buffer_set_dest_size(subtree->bar,
                        MAX(width - bg_offset * 2, 0), theme->titlebar_height);
 
                x = theme->window_titlebar_padding_width;
-               wl_list_for_each(b, &rc.title_buttons_left, link) {
-                       part = ssd_get_part(&subtree->parts, b->type);
-                       wlr_scene_node_set_position(part->node, x, y);
+               struct ssd_part_button *button;
+               wl_list_for_each(button, &subtree->buttons_left, link) {
+                       wlr_scene_node_set_position(button->base.node, x, y);
                        x += theme->window_button_width + theme->window_button_spacing;
                }
 
                x = width - corner_width;
-               part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLEBAR_CORNER_RIGHT);
-               wlr_scene_node_set_position(part->node, x, -rc.theme->border_width);
+               wlr_scene_node_set_position(&subtree->corner_right->node,
+                       x, -rc.theme->border_width);
 
                x = width - theme->window_titlebar_padding_width + theme->window_button_spacing;
-               wl_list_for_each_reverse(b, &rc.title_buttons_right, link) {
-                       part = ssd_get_part(&subtree->parts, b->type);
+               wl_list_for_each(button, &subtree->buttons_right, link) {
                        x -= theme->window_button_width + theme->window_button_spacing;
-                       wlr_scene_node_set_position(part->node, x, y);
+                       wlr_scene_node_set_position(button->base.node, x, y);
                }
-       } FOR_EACH_END
+       }
 
        ssd_update_title(ssd);
 }
@@ -357,19 +343,9 @@ ssd_titlebar_destroy(struct ssd *ssd)
                return;
        }
 
-       struct ssd_sub_tree *subtree;
-       FOR_EACH_STATE(ssd, subtree) {
-               ssd_destroy_parts(&subtree->parts);
-               wlr_scene_node_destroy(&subtree->tree->node);
-               subtree->tree = NULL;
-       } FOR_EACH_END
-
-       if (ssd->state.title.text) {
-               zfree(ssd->state.title.text);
-       }
-
+       zfree(ssd->state.title.text);
        wlr_scene_node_destroy(&ssd->titlebar.tree->node);
-       ssd->titlebar.tree = NULL;
+       ssd->titlebar = (struct ssd_titlebar_scene){0};
 }
 
 /*
@@ -392,43 +368,40 @@ ssd_update_title_positions(struct ssd *ssd, int offset_left, int offset_right)
        int width = view->current.width;
        int title_bg_width = width - offset_left - offset_right;
 
-       int x, y;
-       int buffer_height, buffer_width;
-       struct ssd_part *part;
-       struct ssd_sub_tree *subtree;
-       FOR_EACH_STATE(ssd, subtree) {
-               part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLE);
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active];
+               struct scaled_font_buffer *title = subtree->title;
+               int x, y;
 
-               buffer_width = part->buffer ? part->buffer->width : 0;
-               buffer_height = part->buffer ? part->buffer->height : 0;
                x = offset_left;
-               y = (theme->titlebar_height - buffer_height) / 2;
+               y = (theme->titlebar_height - title->height) / 2;
 
                if (title_bg_width <= 0) {
-                       wlr_scene_node_set_enabled(part->node, false);
+                       wlr_scene_node_set_enabled(&title->scene_buffer->node, false);
                        continue;
                }
-               wlr_scene_node_set_enabled(part->node, true);
+               wlr_scene_node_set_enabled(&title->scene_buffer->node, true);
 
                if (theme->window_label_text_justify == LAB_JUSTIFY_CENTER) {
-                       if (buffer_width + MAX(offset_left, offset_right) * 2 <= width) {
+                       if (title->width + MAX(offset_left, offset_right) * 2 <= width) {
                                /* Center based on the full width */
-                               x = (width - buffer_width) / 2;
+                               x = (width - title->width) / 2;
                        } else {
                                /*
                                 * Center based on the width between the buttons.
                                 * Title jumps around once this is hit but its still
                                 * better than to hide behind the buttons on the right.
                                 */
-                               x += (title_bg_width - buffer_width) / 2;
+                               x += (title_bg_width - title->width) / 2;
                        }
                } else if (theme->window_label_text_justify == LAB_JUSTIFY_RIGHT) {
-                       x += title_bg_width - buffer_width;
+                       x += title_bg_width - title->width;
                } else if (theme->window_label_text_justify == LAB_JUSTIFY_LEFT) {
                        /* TODO: maybe add some theme x padding here? */
                }
-               wlr_scene_node_set_position(part->node, x, y);
-       } FOR_EACH_END
+               wlr_scene_node_set_position(&title->scene_buffer->node, x, y);
+       }
 }
 
 /*
@@ -438,23 +411,21 @@ ssd_update_title_positions(struct ssd *ssd, int offset_left, int offset_right)
 static void
 get_title_offsets(struct ssd *ssd, int *offset_left, int *offset_right)
 {
-       struct ssd_sub_tree *subtree = &ssd->titlebar.active;
+       struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[SSD_ACTIVE];
        int button_width = ssd->view->server->theme->window_button_width;
        int button_spacing = ssd->view->server->theme->window_button_spacing;
        int padding_width = ssd->view->server->theme->window_titlebar_padding_width;
        *offset_left = padding_width;
        *offset_right = padding_width;
 
-       struct title_button *b;
-       wl_list_for_each(b, &rc.title_buttons_left, link) {
-               struct ssd_part *part = ssd_get_part(&subtree->parts, b->type);
-               if (part->node->enabled) {
+       struct ssd_part_button *button;
+       wl_list_for_each(button, &subtree->buttons_left, link) {
+               if (button->base.node->enabled) {
                        *offset_left += button_width + button_spacing;
                }
        }
-       wl_list_for_each_reverse(b, &rc.title_buttons_right, link) {
-               struct ssd_part *part = ssd_get_part(&subtree->parts, b->type);
-               if (part->node->enabled) {
+       wl_list_for_each(button, &subtree->buttons_right, link) {
+               if (button->base.node->enabled) {
                        *offset_right += button_width + button_spacing;
                }
        }
@@ -477,24 +448,17 @@ ssd_update_title(struct ssd *ssd)
        struct ssd_state_title *state = &ssd->state.title;
        bool title_unchanged = state->text && !strcmp(title, state->text);
 
-       const float *text_color;
-       const float bg_color[4] = {0, 0, 0, 0}; /* ignored */
-       struct font *font = NULL;
-       struct ssd_part *part;
-       struct ssd_sub_tree *subtree;
-       struct ssd_state_title_width *dstate;
-       int active;
-
        int offset_left, offset_right;
        get_title_offsets(ssd, &offset_left, &offset_right);
        int title_bg_width = view->current.width - offset_left - offset_right;
 
-       FOR_EACH_STATE(ssd, subtree) {
-               active = (subtree == &ssd->titlebar.active) ?
-                       THEME_ACTIVE : THEME_INACTIVE;
-               dstate = active ? &state->active : &state->inactive;
-               text_color = theme->window[active].label_text_color;
-               font = active ?  &rc.font_activewindow : &rc.font_inactivewindow;
+       enum ssd_active_state active;
+       FOR_EACH_ACTIVE_STATE(active) {
+               struct ssd_titlebar_subtree *subtree = &ssd->titlebar.subtrees[active];
+               struct ssd_state_title_width *dstate = &state->dstates[active];
+               const float *text_color = theme->window[active].label_text_color;
+               struct font *font = active ?
+                       &rc.font_activewindow : &rc.font_inactivewindow;
 
                if (title_bg_width <= 0) {
                        dstate->truncated = true;
@@ -507,15 +471,15 @@ ssd_update_title(struct ssd *ssd)
                        continue;
                }
 
-               part = ssd_get_part(&subtree->parts, LAB_SSD_PART_TITLE);
-               scaled_font_buffer_update(part->buffer, title, title_bg_width,
-                       font, text_color, bg_color);
+               const float bg_color[4] = {0, 0, 0, 0}; /* ignored */
+               scaled_font_buffer_update(subtree->title, title,
+                       title_bg_width, font,
+                       text_color, bg_color);
 
                /* And finally update the cache */
-               dstate->width = part->buffer ? part->buffer->width : 0;
+               dstate->width = subtree->title->width;
                dstate->truncated = title_bg_width <= dstate->width;
-
-       } FOR_EACH_END
+       }
 
        if (!title_unchanged) {
                if (state->text) {
@@ -530,12 +494,13 @@ void
 ssd_update_button_hover(struct wlr_scene_node *node,
                struct ssd_hover_state *hover_state)
 {
-       struct ssd_button *button = NULL;
+       struct ssd_part_button *button = NULL;
 
        if (node && node->data) {
                struct node_descriptor *desc = node->data;
-               if (desc->type == LAB_NODE_DESC_SSD_BUTTON) {
-                       button = node_ssd_button_from_node(node);
+               if (desc->type == LAB_NODE_DESC_SSD_PART) {
+                       button = button_try_from_ssd_part(
+                                       node_ssd_part_from_node(node));
                        if (button == hover_state->button) {
                                /* Cursor is still on the same button */
                                return;
@@ -551,7 +516,7 @@ ssd_update_button_hover(struct wlr_scene_node *node,
        }
        if (button) {
                update_button_state(button, LAB_BS_HOVERD, true);
-               hover_state->view = button->view;
+               hover_state->view = button->base.view;
                hover_state->button = button;
        }
 }
@@ -566,5 +531,3 @@ ssd_should_be_squared(struct ssd *ssd)
                        || view->current.width < corner_width * 2)
                && view->maximized != VIEW_AXIS_BOTH;
 }
-
-#undef FOR_EACH_STATE
index 7a45f37ef45adbb2907458c0194b073a785eebc7..adf7c2cbc2c92b65a6fadb7a734b1a8e9db8d86f 100644 (file)
@@ -85,8 +85,8 @@ ssd_max_extents(struct view *view)
  * (generally rc.resize_corner_range, but clipped to view size) of the view
  * bounds, so check the cursor against the view here.
  */
-static enum ssd_part_type
-get_resizing_type(const struct ssd *ssd, struct wlr_cursor *cursor)
+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) {
@@ -136,75 +136,6 @@ get_resizing_type(const struct ssd *ssd, struct wlr_cursor *cursor)
        return LAB_SSD_NONE;
 }
 
-enum ssd_part_type
-ssd_get_part_type(const struct ssd *ssd, struct wlr_scene_node *node,
-               struct wlr_cursor *cursor)
-{
-       if (!node) {
-               return LAB_SSD_NONE;
-       } else if (node->type == WLR_SCENE_NODE_BUFFER
-                       && lab_wlr_surface_from_node(node)) {
-               return LAB_SSD_CLIENT;
-       } else if (!ssd) {
-               return LAB_SSD_NONE;
-       }
-
-       const struct wl_list *part_list = NULL;
-       struct wlr_scene_tree *grandparent =
-               node->parent ? node->parent->node.parent : NULL;
-       struct wlr_scene_tree *greatgrandparent =
-               grandparent ? grandparent->node.parent : NULL;
-
-       /* active titlebar */
-       if (node->parent == ssd->titlebar.active.tree) {
-               part_list = &ssd->titlebar.active.parts;
-       } else if (grandparent == ssd->titlebar.active.tree) {
-               part_list = &ssd->titlebar.active.parts;
-       } else if (greatgrandparent == ssd->titlebar.active.tree) {
-               part_list = &ssd->titlebar.active.parts;
-
-       /* extents */
-       } else if (node->parent == ssd->extents.tree) {
-               part_list = &ssd->extents.parts;
-
-       /* active border */
-       } else if (node->parent == ssd->border.active.tree) {
-               part_list = &ssd->border.active.parts;
-
-       /* inactive titlebar */
-       } else if (node->parent == ssd->titlebar.inactive.tree) {
-               part_list = &ssd->titlebar.inactive.parts;
-       } else if (grandparent == ssd->titlebar.inactive.tree) {
-               part_list = &ssd->titlebar.inactive.parts;
-       } else if (greatgrandparent == ssd->titlebar.inactive.tree) {
-               part_list = &ssd->titlebar.inactive.parts;
-
-       /* inactive border */
-       } else if (node->parent == ssd->border.inactive.tree) {
-               part_list = &ssd->border.inactive.parts;
-       }
-
-       enum ssd_part_type part_type = LAB_SSD_NONE;
-
-       if (part_list) {
-               struct ssd_part *part;
-               wl_list_for_each(part, part_list, link) {
-                       if (node == part->node) {
-                               part_type = part->type;
-                               break;
-                       }
-               }
-       }
-
-       if (part_type == LAB_SSD_NONE) {
-               return part_type;
-       }
-
-       /* Perform cursor-based context checks */
-       enum ssd_part_type resizing_type = get_resizing_type(ssd, cursor);
-       return resizing_type != LAB_SSD_NONE ? resizing_type : part_type;
-}
-
 enum lab_edge
 ssd_resize_edges(enum ssd_part_type type)
 {
@@ -238,6 +169,7 @@ ssd_create(struct view *view, bool active)
 
        ssd->view = view;
        ssd->tree = wlr_scene_tree_create(view->scene_tree);
+       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);
@@ -438,17 +370,19 @@ ssd_set_active(struct ssd *ssd, bool active)
        if (!ssd) {
                return;
        }
-       wlr_scene_node_set_enabled(&ssd->border.active.tree->node, active);
-       wlr_scene_node_set_enabled(&ssd->titlebar.active.tree->node, active);
-       if (ssd->shadow.active.tree) {
+       enum ssd_active_state active_state;
+       FOR_EACH_ACTIVE_STATE(active_state) {
                wlr_scene_node_set_enabled(
-                       &ssd->shadow.active.tree->node, active);
-       }
-       wlr_scene_node_set_enabled(&ssd->border.inactive.tree->node, !active);
-       wlr_scene_node_set_enabled(&ssd->titlebar.inactive.tree->node, !active);
-       if (ssd->shadow.inactive.tree) {
+                       &ssd->border.subtrees[active_state].tree->node,
+                       active == active_state);
                wlr_scene_node_set_enabled(
-                       &ssd->shadow.inactive.tree->node, !active);
+                       &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);
+               }
        }
 }
 
@@ -474,10 +408,7 @@ ssd_enable_keybind_inhibit_indicator(struct ssd *ssd, bool enable)
        float *color = enable
                ? rc.theme->window_toggled_keybinds_color
                : rc.theme->window[THEME_ACTIVE].border_color;
-
-       struct ssd_part *part = ssd_get_part(&ssd->border.active.parts, LAB_SSD_PART_TOP);
-       struct wlr_scene_rect *rect = wlr_scene_rect_from_node(part->node);
-       wlr_scene_rect_set_color(rect, color);
+       wlr_scene_rect_set_color(ssd->border.subtrees[SSD_ACTIVE].top, color);
 }
 
 struct ssd_hover_state *
@@ -487,15 +418,15 @@ ssd_hover_state_new(void)
 }
 
 enum ssd_part_type
-ssd_button_get_type(const struct ssd_button *button)
+ssd_part_get_type(const struct ssd_part *part)
 {
-       return button ? button->type : LAB_SSD_NONE;
+       return part ? part->type : LAB_SSD_NONE;
 }
 
 struct view *
-ssd_button_get_view(const struct ssd_button *button)
+ssd_part_get_view(const struct ssd_part *part)
 {
-       return button ? button->view : NULL;
+       return part ? part->view : NULL;
 }
 
 bool
@@ -516,16 +447,16 @@ ssd_debug_get_node_name(const struct ssd *ssd, struct wlr_scene_node *node)
        if (node == &ssd->tree->node) {
                return "view->ssd";
        }
-       if (node == &ssd->titlebar.active.tree->node) {
+       if (node == &ssd->titlebar.subtrees[SSD_ACTIVE].tree->node) {
                return "titlebar.active";
        }
-       if (node == &ssd->titlebar.inactive.tree->node) {
+       if (node == &ssd->titlebar.subtrees[SSD_INACTIVE].tree->node) {
                return "titlebar.inactive";
        }
-       if (node == &ssd->border.active.tree->node) {
+       if (node == &ssd->border.subtrees[SSD_ACTIVE].tree->node) {
                return "border.active";
        }
-       if (node == &ssd->border.inactive.tree->node) {
+       if (node == &ssd->border.subtrees[SSD_INACTIVE].tree->node) {
                return "border.inactive";
        }
        if (node == &ssd->extents.tree->node) {