68 lines
3 KiB
Diff
68 lines
3 KiB
Diff
--- a/scene.c
|
|
+++ b/scene.c
|
|
@@ -57,0 +58 @@
|
|
+ bool active; // Private sidecar only: no installed tree/node ABI change.
|
|
@@ -62 +63 @@
|
|
-static struct scene_tree_clip *scene_tree_clip_find(struct wlr_scene_tree *tree) {
|
|
+static struct scene_tree_clip *scene_tree_clip_storage(struct wlr_scene_tree *tree) {
|
|
@@ -66,0 +68,8 @@
|
|
+}
|
|
+
|
|
+// WHY: reservation must survive clip removal to make later admission allocation-free.
|
|
+// CONTRACT: inactive reservations are absent to render/hit/get callers.
|
|
+// INVARIANT: lookup never exposes an uninitialized clip rectangle.
|
|
+static struct scene_tree_clip *scene_tree_clip_find(struct wlr_scene_tree *tree) {
|
|
+ struct scene_tree_clip *entry = scene_tree_clip_storage(tree);
|
|
+ return entry && entry->active ? entry : NULL;
|
|
@@ -286,0 +296,5 @@
|
|
+ // WHY: failure must occur before tree publication to parent scene children.
|
|
+ // CONTRACT: both tree and reservation are acquired before scene_tree_init.
|
|
+ // INVARIANT: failed reservation frees unpublished tree, no listener attached.
|
|
+ struct scene_tree_clip *entry = calloc(1, sizeof(*entry));
|
|
+ if (!entry) { free(tree); return NULL; }
|
|
@@ -287,0 +302,5 @@
|
|
+ entry->tree = tree;
|
|
+ entry->destroy.notify = scene_tree_clip_destroy;
|
|
+ wl_signal_add(&tree->node.events.destroy, &entry->destroy);
|
|
+ entry->next = scene_tree_clips;
|
|
+ scene_tree_clips = entry;
|
|
@@ -984,29 +1003,10 @@
|
|
- // CONTRACT: tree is required; a supplied box is copied and must have
|
|
- // nonnegative dimensions. NULL removes the entry, while a zero box masks.
|
|
- assert(tree);
|
|
- assert(!clip || (clip->width >= 0 && clip->height >= 0));
|
|
- struct scene_tree_clip *entry = scene_tree_clip_find(tree);
|
|
- if (!clip && !entry) return;
|
|
- if (clip && entry && memcmp(&entry->box, clip, sizeof(*clip)) == 0) return;
|
|
- wlr_log(WLR_INFO, "SPIKE_CLIP tree=%p rect=%d,%d %dx%d",
|
|
- (void *)tree, clip ? clip->x : 0, clip ? clip->y : 0,
|
|
- clip ? clip->width : 0, clip ? clip->height : 0);
|
|
- if (clip && !entry) {
|
|
- entry = calloc(1, sizeof(*entry));
|
|
- // WHY: this void API cannot report an uninstalled mandatory clip.
|
|
- // CONTRACT/INVARIANT: allocation failure must never expose unclipped content.
|
|
- if (!entry) {
|
|
- wlr_log(WLR_ERROR, "Failed to allocate mandatory scene tree clip");
|
|
- abort();
|
|
- }
|
|
- entry->tree = tree;
|
|
- entry->destroy.notify = scene_tree_clip_destroy;
|
|
- wl_signal_add(&tree->node.events.destroy, &entry->destroy);
|
|
- entry->next = scene_tree_clips;
|
|
- scene_tree_clips = entry;
|
|
- }
|
|
- if (clip) {
|
|
- entry->box = *clip;
|
|
- } else {
|
|
- scene_tree_clip_remove(entry);
|
|
- }
|
|
+ // WHY: no heap allocation may occur when exposing an existing tree.
|
|
+ // CONTRACT: trees must come from the private reservation-aware create path.
|
|
+ // INVARIANT: NULL deactivates but never releases the reservation.
|
|
+ assert(tree && (!clip || (clip->width >= 0 && clip->height >= 0)));
|
|
+ struct scene_tree_clip *entry = scene_tree_clip_storage(tree);
|
|
+ assert(entry);
|
|
+ if (!clip && !entry->active) return;
|
|
+ if (clip && entry->active && memcmp(&entry->box, clip, sizeof(*clip)) == 0) return;
|
|
+ entry->active = clip != NULL;
|
|
+ if (clip) entry->box = *clip;
|