summaryrefslogtreecommitdiff
path: root/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/popup/message_stacks.js
diff options
context:
space:
mode:
authorNippy <nippy@Nippy-Mac-mini.local>2026-10-09 17:23:53 +0200
committerNippy <nippy@Nippy-Mac-mini.local>2026-10-09 17:23:53 +0200
commit9d5be1660d8f74038ebed3d74fdbc809e43787ae (patch)
tree4cb46c3765be87ca4c5219f2f714425d7dfddb56 /raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/popup/message_stacks.js
parentdeb4b8a9c407832c35100a643bd7a592589c9679 (diff)
downloadRaveOS-PKGBUILD-9d5be1660d8f74038ebed3d74fdbc809e43787ae.tar.gz
RaveOS-PKGBUILD-9d5be1660d8f74038ebed3d74fdbc809e43787ae.zip
gnome fix
Diffstat (limited to 'raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/popup/message_stacks.js')
-rw-r--r--raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/popup/message_stacks.js571
1 files changed, 571 insertions, 0 deletions
diff --git a/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/popup/message_stacks.js b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/popup/message_stacks.js
new file mode 100644
index 0000000..cc4af30
--- /dev/null
+++ b/raveos-gnome-theme/theme-data/extensions/installed/blur-my-shell@aunetx/components/popup/message_stacks.js
@@ -0,0 +1,571 @@
+import GLib from 'gi://GLib';
+
+const STACKED_PSEUDO_CLASSES = ['second-in-stack', 'lower-in-stack'];
+const MESSAGE_CONTAINER_STYLE_CLASSES = ['message-list', 'message-view', 'message-notification-group'];
+const INTERNAL_STYLE_CLASSES = ['bms-popup-blurred-widget', 'bms-popup-backgroundgroup'];
+const INTERNAL_NAMES = ['bms-popup-blurred-widget', 'bms-popup-backgroundgroup'];
+
+export const PopupBlurMessageStacks = class PopupBlurMessageStacks {
+ constructor(connections) {
+ this.connections = connections;
+ this.containers = new Set();
+ this.groups = new Set();
+ this.messages = new Set();
+ this.queued_actors = new WeakSet();
+ this.watched_actors = new WeakSet();
+ this.destroyed_actors = new WeakSet();
+ this.bms_clipped = new WeakSet();
+ this.group_connections = new Map();
+ this.update_ids = new Map();
+ this.original_opacity = new WeakMap();
+ this.original_message_opacity = new WeakMap();
+ this.enabled = false;
+ }
+
+ enable() {
+ this.enabled = true;
+ }
+
+ track_container(container) {
+ if (!container || this.containers.has(container))
+ return;
+ if (!this.watch_actor(container))
+ return;
+
+ this.containers.add(container);
+ this.scan(container);
+
+ this.connect(
+ container,
+ 'child-added',
+ (_, child) => {
+ this.queue_scan(child);
+ this.queue_update_all();
+ }
+ );
+
+ this.connect(
+ container,
+ 'child-removed',
+ () => this.queue_update_all()
+ );
+ }
+
+ queue_scan(actor) {
+ if (this.is_internal_actor(actor) || !this.watch_actor(actor) || this.queued_actors.has(actor))
+ return;
+
+ this.queued_actors.add(actor);
+ this.scan(actor);
+ this.queued_actors.delete(actor);
+ }
+
+ scan(actor, seen = new WeakSet()) {
+ if (this.is_internal_actor(actor) || !this.watch_actor(actor) || seen.has(actor))
+ return;
+
+ seen.add(actor);
+
+ if (this.has_any_style_class(actor, MESSAGE_CONTAINER_STYLE_CLASSES))
+ this.track_container(actor);
+
+ if (this.has_style_class(actor, 'message-notification-group'))
+ this.track_group(actor);
+
+ if (this.has_style_class(actor, 'message'))
+ this.track_message(actor);
+
+ this.get_children(actor).forEach(child => this.scan(child, seen));
+
+ const child = this.get_child(actor);
+ if (child)
+ this.scan(child, seen);
+ }
+
+ track_message(message) {
+ if (this.is_internal_actor(message) || !this.watch_actor(message) || this.messages.has(message))
+ return;
+
+ this.messages.add(message);
+ this.update_message(message);
+
+ this.connect(
+ message,
+ 'style-changed',
+ () => this.queue_update_message(message)
+ );
+
+ this.connect(
+ message,
+ 'notify::pseudo-class',
+ () => this.queue_update_message(message)
+ );
+
+ this.connect(
+ message,
+ 'notify::allocation',
+ () => this.queue_update_message(message)
+ );
+
+ this.connect(
+ message,
+ 'destroy',
+ () => {
+ this.cancel_update(message);
+ this.remove_stack_mask(message);
+ this.messages.delete(message);
+ }
+ );
+ }
+
+ track_group(group) {
+ if (!this.watch_actor(group) || this.groups.has(group))
+ return;
+
+ this.groups.add(group);
+ this.update_group_header(group);
+
+ this.connect(
+ group,
+ 'notify::expanded',
+ () => this.update_all()
+ );
+
+ this.connect(
+ group,
+ 'notify::allocation',
+ () => this.update_group_header(group)
+ );
+
+ if (group.layout_manager) {
+ const lm = group.layout_manager;
+ const id = lm.connect('notify::expansion', () => {
+ this.update_group_header(group);
+ this.update_group_messages(group);
+ });
+ this.group_connections.set(group, { lm, id });
+ }
+ }
+
+ untrack_group(group) {
+ if (this.group_connections.has(group)) {
+ const { lm, id } = this.group_connections.get(group);
+ lm.disconnect(id);
+ this.group_connections.delete(group);
+ }
+ this.groups.delete(group);
+ }
+
+ update_all() {
+ this.groups.forEach(group => {
+ this.update_group_header(group);
+ this.update_group_messages(group);
+ });
+ this.messages.forEach(message => {
+ if (!this.get_message_group(message))
+ this.update_message(message);
+ });
+ }
+
+ update_group_header(group) {
+ if (!this.watch_actor(group))
+ return;
+
+ const header = group._headerBox;
+ if (!header)
+ return;
+
+ const expansion = group.layout_manager?.expansion ?? (group.expanded ? 1 : 0);
+ const target_opacity = this.enabled ? Math.round(expansion * 255) : 255;
+
+ header.opacity = target_opacity;
+ }
+
+ get_group_messages(group) {
+ const list = [];
+ const find_messages = actor => {
+ if (this.has_style_class(actor, 'message')) {
+ list.push(actor);
+ return;
+ }
+ this.get_children(actor).forEach(find_messages);
+ };
+ find_messages(group);
+ return list;
+ }
+
+ update_group_messages(group) {
+ if (!this.enabled || !this.watch_actor(group))
+ return;
+
+ const expansion = group.layout_manager?.expansion ?? (group.expanded ? 1.0 : 0.0);
+ const messages = this.get_group_messages(group);
+
+ messages.forEach((message, index) => {
+ this.update_message_with_expansion(message, index, expansion, group);
+ });
+ }
+
+ queue_update_all() {
+ this.messages.forEach(message => this.queue_update_message(message));
+ }
+
+ queue_update_message(message) {
+ if (this.update_ids.has(message))
+ return;
+
+ const id = GLib.idle_add(GLib.PRIORITY_DEFAULT_IDLE, () => {
+ this.update_ids.delete(message);
+
+ if (this.enabled && this.messages.has(message))
+ this.update_message(message);
+
+ return GLib.SOURCE_REMOVE;
+ });
+
+ this.update_ids.set(message, id);
+ }
+
+ update_message(message) {
+ if (!this.enabled) {
+ this.remove_stack_mask(message);
+ return;
+ }
+
+ const group = this.get_message_group(message);
+ if (group) {
+ const expansion = group.layout_manager?.expansion ?? (group.expanded ? 1.0 : 0.0);
+ const index = this.get_message_index_in_group(message);
+ this.update_message_with_expansion(message, index >= 0 ? index : 0, expansion, group);
+ } else {
+ const is_expanded = this.is_in_expanded_group(message);
+ if (this.is_stacked(message) && !is_expanded) {
+ this.apply_stack_mask(message);
+ this.hide_message_content(message);
+ this.restore_message_opacity(message);
+ } else {
+ this.remove_stack_mask(message);
+ }
+ }
+ }
+
+ update_message_with_expansion(message, index, expansion, group) {
+ if (!this.enabled || !this.watch_actor(message))
+ return;
+
+ const is_stacked = this.is_stacked(message) || index > 0;
+
+ if (!is_stacked) {
+ this.remove_stack_mask(message);
+ return;
+ }
+
+ if (expansion >= 0.99) {
+ this.remove_stack_mask(message);
+ return;
+ }
+
+ if (expansion <= 0.01) {
+ this.apply_stack_mask(message);
+ this.hide_message_content(message);
+ this.restore_message_opacity(message);
+ return;
+ }
+
+ // 0.01 < expansion < 0.99: Animating unravel / collapse
+ const height = message.height || message.get_height() || 0;
+ const width = message.width || message.get_width() || 0;
+
+ if (height <= 0 || width <= 0)
+ return;
+
+ const base_edge = (index === 1) ? 10 : (index === 2 ? 7 : 0);
+ const visible_edge = Math.round(base_edge + (height - base_edge) * expansion);
+ const clip_y = Math.max(0, height - visible_edge);
+
+ message.set_clip(0, clip_y, width, visible_edge);
+ this.bms_clipped.add(message);
+
+ // Staggered opacity progress for cards so they smoothly fade in as they unravel
+ const stagger_start = Math.min(0.8, index * 0.04);
+ const progress = Math.min(1.0, Math.max(0.0, (expansion - stagger_start) / (1.0 - stagger_start)));
+ const target_alpha = Math.round(255 * progress);
+
+ this.set_child_opacity(message, target_alpha);
+
+ if (index >= 3) {
+ this.set_message_opacity(message, target_alpha);
+ } else {
+ this.restore_message_opacity(message);
+ }
+ }
+
+ apply_stack_mask(message) {
+ if (!this.watch_actor(message))
+ return;
+
+ const height = message.height || message.get_height() || 0;
+ const width = message.width || message.get_width() || 0;
+
+ if (height <= 0 || width <= 0)
+ return;
+
+ const index = this.get_message_index_in_group(message);
+
+ if (index === 1) {
+ // 2nd card: tight visible strip of 10px (matches exact 10px bottom offset below card 1)
+ const visible_edge = 10;
+ const clip_y = Math.max(0, height - visible_edge);
+ message.set_clip(0, clip_y, width, visible_edge);
+ this.bms_clipped.add(message);
+ } else if (index === 2) {
+ // 3rd card: tight visible strip of 7px (matches exact 7px bottom offset below card 2)
+ const visible_edge = 7;
+ const clip_y = Math.max(0, height - visible_edge);
+ message.set_clip(0, clip_y, width, visible_edge);
+ this.bms_clipped.add(message);
+ } else if (index >= 3) {
+ // 4th+ cards: hidden when collapsed so they don't stack behind card 3
+ message.set_clip(0, height, width, 0);
+ this.bms_clipped.add(message);
+ } else {
+ // Fallback by pseudo class
+ const is_second = this.has_pseudo_class(message, 'second-in-stack');
+ const visible_edge = is_second ? 10 : 6;
+ const clip_y = Math.max(0, height - visible_edge);
+ message.set_clip(0, clip_y, width, visible_edge);
+ this.bms_clipped.add(message);
+ }
+ }
+
+ remove_stack_mask(message) {
+ if (!message || this.destroyed_actors.has(message))
+ return;
+
+ if (this.bms_clipped.has(message)) {
+ message.remove_clip();
+ this.bms_clipped.delete(message);
+ }
+
+ this.restore_message_content(message);
+ this.restore_message_opacity(message);
+ }
+
+ set_child_opacity(message, opacity) {
+ const child = this.get_child(message);
+ if (!child)
+ return;
+
+ if (!this.original_opacity.has(child))
+ this.original_opacity.set(child, child.opacity ?? 255);
+
+ child.opacity = opacity;
+ }
+
+ hide_message_content(message) {
+ this.set_child_opacity(message, 0);
+ }
+
+ restore_message_content(message) {
+ const child = this.get_child(message);
+ if (!child)
+ return;
+
+ if (this.original_opacity.has(child)) {
+ child.opacity = this.original_opacity.get(child);
+ this.original_opacity.delete(child);
+ }
+ }
+
+ set_message_opacity(message, opacity) {
+ if (!this.watch_actor(message))
+ return;
+
+ if (!this.original_message_opacity.has(message))
+ this.original_message_opacity.set(message, message.opacity ?? 255);
+
+ message.opacity = opacity;
+ }
+
+ restore_message_opacity(message) {
+ if (!message || this.destroyed_actors.has(message))
+ return;
+
+ if (this.original_message_opacity.has(message)) {
+ message.opacity = this.original_message_opacity.get(message);
+ this.original_message_opacity.delete(message);
+ }
+ }
+
+ get_message_index_in_group(message) {
+ const group = this.get_message_group(message);
+ if (!group)
+ return -1;
+
+ const list = [];
+ const find_messages = actor => {
+ if (this.has_style_class(actor, 'message')) {
+ list.push(actor);
+ return;
+ }
+ actor.get_children().forEach(find_messages);
+ };
+ find_messages(group);
+ return list.indexOf(message);
+ }
+
+ has_pseudo_class(actor, pseudo_class) {
+ if (!actor || this.destroyed_actors.has(actor))
+ return false;
+
+ if (actor.has_style_pseudo_class)
+ return actor.has_style_pseudo_class(pseudo_class);
+
+ if (actor.get_style_pseudo_class)
+ return (actor.get_style_pseudo_class() ?? '').split(/\s+/).includes(pseudo_class);
+
+ return false;
+ }
+
+ get_message_group(message) {
+ let actor = message ? message.get_parent() : null;
+
+ while (actor && !this.destroyed_actors.has(actor)) {
+ if (this.has_style_class(actor, 'message-notification-group'))
+ return actor;
+ actor = actor.get_parent();
+ }
+ return null;
+ }
+
+ is_in_expanded_group(message) {
+ let actor = message ? message.get_parent() : null;
+
+ while (actor && !this.destroyed_actors.has(actor)) {
+ if (
+ this.has_style_class(actor, 'message-notification-group')
+ && actor.expanded
+ )
+ return true;
+ actor = actor.get_parent();
+ }
+
+ return false;
+ }
+
+ is_stacked(message) {
+ if (!message || this.destroyed_actors.has(message))
+ return false;
+ return STACKED_PSEUDO_CLASSES.some(pseudo_class => {
+ if (message.has_style_pseudo_class)
+ return message.has_style_pseudo_class(pseudo_class);
+
+ if (message.get_style_pseudo_class)
+ return (message.get_style_pseudo_class() ?? '').split(/\s+/).includes(pseudo_class);
+
+ return false;
+ });
+ }
+
+ has_any_style_class(actor, style_classes) {
+ return style_classes.some(style_class => this.has_style_class(actor, style_class));
+ }
+
+ is_internal_actor(actor) {
+ if (!actor)
+ return false;
+
+ if (this.has_any_style_class(actor, INTERNAL_STYLE_CLASSES))
+ return true;
+
+ if (this.destroyed_actors.has(actor))
+ return false;
+
+ return INTERNAL_NAMES.includes(actor.name ?? actor.get_name());
+ }
+
+ has_style_class(actor, style_class) {
+ if (!actor || this.destroyed_actors.has(actor))
+ return false;
+
+ if (actor.has_style_class_name)
+ return actor.has_style_class_name(style_class);
+
+ if (actor.get_style_class_name)
+ return (actor.get_style_class_name() ?? '').split(/\s+/).includes(style_class);
+
+ return false;
+ }
+
+ watch_actor(actor) {
+ if (!actor || this.destroyed_actors.has(actor))
+ return false;
+ if (this.watched_actors.has(actor))
+ return true;
+
+ this.connections.connect(actor, 'destroy', () => {
+ this.destroyed_actors.add(actor);
+ this.containers.delete(actor);
+ if (this.groups.has(actor)) {
+ this.untrack_group(actor);
+ }
+ this.messages.delete(actor);
+ this.cancel_update(actor);
+ });
+
+ this.watched_actors.add(actor);
+ return true;
+ }
+
+ get_children(actor) {
+ if (this.is_internal_actor(actor) || !this.watch_actor(actor))
+ return [];
+
+ return actor.get_children();
+ }
+
+ get_child(actor) {
+ if (!this.watch_actor(actor))
+ return null;
+
+ return (actor.get_child ? actor.get_child() : actor.child) || null;
+ }
+
+ cancel_update(message) {
+ const id = this.update_ids.get(message);
+ if (!id)
+ return;
+
+ GLib.source_remove(id);
+ this.update_ids.delete(message);
+ }
+
+ connect(actor, signal, handler) {
+ this.connections.connect(actor, signal, handler);
+ }
+
+ disable() {
+ this.update_ids.forEach(id => GLib.source_remove(id));
+ this.update_ids.clear();
+ this.messages.forEach(message => this.remove_stack_mask(message));
+ this.groups.forEach(group => {
+ if (group._headerBox) {
+ group._headerBox.opacity = 255;
+ }
+ this.untrack_group(group);
+ });
+ this.group_connections.forEach(({ lm, id }) => {
+ lm.disconnect(id);
+ });
+ this.group_connections.clear();
+ this.messages.clear();
+ this.groups.clear();
+ this.containers.clear();
+ this.watched_actors = new WeakSet();
+ this.destroyed_actors = new WeakSet();
+ this.bms_clipped = new WeakSet();
+ this.original_opacity = new WeakMap();
+ this.original_message_opacity = new WeakMap();
+ this.enabled = false;
+ }
+};