Submitted by:            Zeckma
Date:                    2026-08-01
Initial Package Version: 0.10.0
Origin:                  Diff from 0.10.0 tarball to HEAD of
                         https://github.com/WayfireWM/wayfire-plugins-extra
Upstream Status:         Upstream
Description:             Brings 0.10.0 to HEAD as there were multiple changes
                         to the plugin API over time. All of these changes
                         should land in 0.11.0 anyhow.

diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/meson.build wayfire-plugins-extra/locale/meson.build
--- wayfire-plugins-extra-0.10.0/locale/meson.build	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/meson.build	2026-08-01 16:00:35.432705142 -0600
@@ -0,0 +1,19 @@
+share_dir = join_paths(get_option('prefix'), 'share')
+wayfire_locale_dir = join_paths(share_dir, 'locale')
+
+fs = import('fs')
+
+po_files_raw = run_command('find', '.', '-name', '*.po', check : true).stdout().strip().split('\n')
+po_files = files(po_files_raw)
+
+foreach po_file : po_files
+    language = fs.name(fs.parent(fs.parent(po_file)))
+    install_path = join_paths(wayfire_locale_dir, language, 'LC_MESSAGES')
+    mo_dir = join_paths(meson.project_build_root(), 'locale', language, 'LC_MESSAGES')
+    mo_file = fs.stem(po_file) + '.mo'
+    mo_path = join_paths(mo_dir, mo_file)
+    run_command('mkdir', '-p', mo_dir, check : true)
+    run_command('msgfmt', po_file, '-o', mo_path, check : true)
+    install_data(mo_path, install_dir : install_path)
+endforeach
+
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-annotate.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-annotate.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-annotate.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-annotate.po	2026-08-01 16:00:35.432842092 -0600
@@ -0,0 +1,102 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 08:00+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:4
+msgid "Annotate"
+msgstr "Adnotare"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:5
+msgid "Draw on the output."
+msgstr "Desenează pe ecran."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:8
+msgid "Draw"
+msgstr "Desenare"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:9
+msgid "Begin drawing on workspace."
+msgstr "Începe desenarea pe birou."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:13
+msgid "Clear Workspace"
+msgstr "Ștergere birou"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:14
+msgid "Clear workspace."
+msgstr "Șterge biroul."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:18
+msgid "Stroke Color"
+msgstr "Culoarea conturului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:19
+msgid "Color used for drawing."
+msgstr "Culoarea folosită pentru desen."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:23
+msgid "Drawing Method"
+msgstr "Metoda desenului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:24
+msgid "Method used for drawing."
+msgstr "Metoda folosită pentru desen."
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:28
+msgid "Free Draw"
+msgstr "Desen liber"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:32
+msgid "Line"
+msgstr "Linie"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:36
+msgid "Rectangle"
+msgstr "Dreptunghi"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:40
+msgid "Circle"
+msgstr "Cerc"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:44
+msgid "Line Width"
+msgstr "Grosimea liniei"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:45
+msgid "Line width used for drawing."
+msgstr "Grosimea liniei folosite pentru desen."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:51
+msgid "Draw Shapes From Center"
+msgstr "Desenează formele din centru"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/annotate.xml:52
+msgid "Draw shapes from center of drag point."
+msgstr "Desenează formele centrate pe punctul tragerii."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-autorotate-iio.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-autorotate-iio.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-autorotate-iio.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-autorotate-iio.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,42 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 08:54+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/autorotate-iio.xml:4
+msgid "Auto Rotate"
+msgstr "Rotire automată"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/autorotate-iio.xml:7
+msgid "Lock Rotation"
+msgstr "Blocare rotație"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/autorotate-iio.xml:11
+msgid "Rotate Up"
+msgstr "Rotire în sus"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/autorotate-iio.xml:15
+msgid "Rotate Left"
+msgstr "Rotire la stânga"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/autorotate-iio.xml:19
+msgid "Rotate Down"
+msgstr "Rotire în jos"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/autorotate-iio.xml:23
+msgid "Rotate Right"
+msgstr "Rotire la dreapta"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-bench.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-bench.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-bench.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-bench.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,87 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 08:56+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:4
+msgid "Bench"
+msgstr "Probă de performanță"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:5
+msgid "Display fps on each output."
+msgstr "Afișează numărul de cadre pe secundă pe fiecare ecran."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:8
+msgid "Average frames"
+msgstr "Cadre pentru medie"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:9
+msgid "How many frames to average to get the FPS value."
+msgstr "Pe câte cadre să se facă media pentru a obține valoarea frecvenței cadrelor."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:14
+msgid "Position"
+msgstr "Poziție"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:15
+msgid "Position of rendering."
+msgstr "Poziția desenării."
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:19
+msgid "Top Left"
+msgstr "Stânga-sus"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:23
+msgid "Top Center"
+msgstr "Centru-sus"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:27
+msgid "Top Right"
+msgstr "Dreapta-sus"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:31
+msgid "Center Left"
+msgstr "Stânga-centru"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:35
+msgid "Center"
+msgstr "Centru"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:39
+msgid "Center Right"
+msgstr "Dreapta-centru"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:43
+msgid "Bottom Left"
+msgstr "Stânga-jos"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:47
+msgid "Bottom Center"
+msgstr "Centru-jos"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/bench.xml:51
+msgid "Bottom Right"
+msgstr "Dreapta-jos"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-crosshair.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-crosshair.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-crosshair.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-crosshair.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,42 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 08:58+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/crosshair.xml:4
+msgid "Crosshair"
+msgstr "Reticulă"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/crosshair.xml:5
+msgid "Render fullscreen mouse crosshair"
+msgstr "Desenează reticula mausului pe tot ecranul."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/crosshair.xml:8
+msgid "Line Width"
+msgstr "Grosimea liniei"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/crosshair.xml:9
+msgid "Line width of crosshair"
+msgstr "Grosimea liniei reticulei."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/crosshair.xml:14
+msgid "Line Color"
+msgstr "Culoarea liniei"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/crosshair.xml:15
+msgid "Color used for rendering crosshair"
+msgstr "Culoarea folosită pentru a desena reticula."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-extra-animations.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-extra-animations.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-extra-animations.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-extra-animations.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,207 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 12:09+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:4
+msgid "Extra Animations"
+msgstr "Animații suplimentare"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:5
+msgid "Extra animations to extend animate plugin"
+msgstr "Animații care suplimentează modulul de animații"
+
+#. (itstool) path: group/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:8
+msgid "Blinds Settings"
+msgstr "Opțiuni jaluzele"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:10
+msgid "Blinds duration"
+msgstr "Durata jaluzelelor"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:11
+msgid "Sets the duration for the blinds animation in milliseconds."
+msgstr "Stabilește durata pentru animația de jaluzele, în milisecunde."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:15
+msgid "Blinds strip height"
+msgstr "Înălțimea fâșiei de jaluzele"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:16
+msgid "Height of each blinds strip in pixels."
+msgstr "Înălțimea fiecărei fâșii a jaluzelelor, în pixeli."
+
+#. (itstool) path: group/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:22
+msgid "Helix Settings"
+msgstr "Opțiuni helix"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:24
+msgid "Helix duration"
+msgstr "Durata helixului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:25
+msgid "Sets the duration for the helix animation in milliseconds."
+msgstr "Stabilește durata pentru animația helix, în milisecunde."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:29
+msgid "Helix rotations"
+msgstr "Rotații helix"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:30
+msgid "Number of rotations for the helix animation."
+msgstr "Numărul de rotații pentru animația helix."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:35
+msgid "Helix strip height"
+msgstr "Înălțimea fâșiei de helix"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:36
+msgid "Height of each helix strip in pixels."
+msgstr "Înălțimea fiecărei fâșii a helixului, în pixeli."
+
+#. (itstool) path: group/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:42
+msgid "Shatter Settings"
+msgstr "Opțiuni spargere"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:44
+msgid "Shatter duration"
+msgstr "Durata spargerii"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:45
+msgid "Sets the duration for the shatter animation in milliseconds."
+msgstr "Stabilește durata pentru animația de spargere, în milisecunde."
+
+#. (itstool) path: group/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:50
+msgid "Vortex Settings"
+msgstr "Opțiuni vârtej"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:52
+msgid "Vortex duration"
+msgstr "Durata vârtejului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:53
+msgid "Sets the duration for the vortex animation in milliseconds."
+msgstr "Stabilește durata animației de vârtej, în milisecunde."
+
+#. (itstool) path: group/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:58
+msgid "Melt Settings"
+msgstr "Opțiuni topire"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:60
+msgid "Melt duration"
+msgstr "Durata topirii"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:61
+msgid "Sets the duration for the melt animation in milliseconds."
+msgstr "Stabilește durata animației de topire, în milisecunde."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:65
+msgid "Melt distortion factor"
+msgstr "Factor de deformare pentru topire"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:66
+msgid "Distortion factor for melt animation."
+msgstr "Stabilește factorul de deformare folosit la animația de topire."
+
+#. (itstool) path: group/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:72
+msgid "Dodge Settings"
+msgstr "Opțiuni suprapunere"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:74
+msgid "Enable Dodge"
+msgstr "Activează suprapunerea"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:75
+msgid "Enables the Dodge focus animation."
+msgstr "Activează animația de suprapunere la focalizare."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:79
+msgid "Duration"
+msgstr "Durata"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:80
+msgid "Sets the animation duration in milliseconds."
+msgstr "Stabilește durata animației, în milisecunde."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:84
+msgid "Rotate"
+msgstr "Rotire"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:85
+msgid "Rotate windows during animation."
+msgstr "Rotește ferestrele în timpul animației."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:89
+msgid "Zoom"
+msgstr "Mărire"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:90
+msgid "Slightly increase zoom for the focusing window during animation."
+msgstr "Mărește puțin fereastra ce se focalizează în animație."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:94
+msgid "Animation Direction"
+msgstr "Direcția animației"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:95
+msgid "Sets the animation direction."
+msgstr "Stabilește direcția animației."
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:98
+msgid "Cardinal"
+msgstr "Cardinală"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:102
+msgid "Diagonal"
+msgstr "Diagonală"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/extra-animations.xml:106
+msgid "Circular"
+msgstr "Circulară"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-focus-change.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-focus-change.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-focus-change.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-focus-change.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,172 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 13:10+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:4
+msgid "Focus Change"
+msgstr "Schimbare focalizare"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:7
+msgid "focus up"
+msgstr "Focalizare în sus"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:8
+msgid "move focus to the closest window above"
+msgstr "Mută focalizarea la cea mai apropiată fereastră de deasupra."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:12
+msgid "focus down"
+msgstr "Focalizare în jos"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:13
+msgid "move focus to the closest window below"
+msgstr "Mută focalizarea la cea mai apropiată fereastră de dedesubt."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:17
+msgid "focus right"
+msgstr "Focalizare la dreapta"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:18
+msgid "move focus to the closest window to the right"
+msgstr "Mută focalizarea la cea mai apropiată fereastră de la dreapta."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:22
+msgid "focus left"
+msgstr "Focalizare la stânga"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:23
+msgid "move focus to the closest window to the left"
+msgstr "Mută focalizarea la cea mai apropiată fereastră de la stânga."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:27
+msgid "upwards grace in pixels"
+msgstr "Grație în sus în pixeli"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:28
+msgid ""
+"add an amount of pixel upwards in which windows will be ignored. Can be "
+"negative"
+msgstr ""
+"Adaugă pixeli în sus în care ferestrele vor fi ignorate. Poate fi negativ."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:32
+msgid "downwards grace in pixels"
+msgstr "Grație în jos în pixeli"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:33
+msgid ""
+"add an amount of pixel downwards in which windows will be ignored. Can be "
+"negative"
+msgstr ""
+"Adaugă pixeli în jos în care ferestrele vor fi ignorate. Poate fi negativ."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:37
+msgid "rightwards grace in pixels"
+msgstr "Grație în dreapta în pixeli"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:38
+msgid ""
+"add an amount of pixel to the right in which windows will be ignored. Can be "
+"negative"
+msgstr ""
+"Adaugă pixeli în dreapta în care ferestrele vor fi ignorate. Poate fi "
+"negativ."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:42
+msgid "leftwards grace in pixels"
+msgstr "Grație în stânga în pixeli"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:43
+msgid ""
+"add an amount of pixel to the left in which windows will be ignored. Can be "
+"negative"
+msgstr ""
+"Adaugă pixeli în stânga în care ferestrele vor fi ignorate. Poate fi negativ."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:47
+msgid "ignores output boundraries"
+msgstr "Ignoră granițele ecranelor"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:48
+msgid "enables moving focus between different outputs"
+msgstr "Permite mutarea focalizării între ecrane diferite."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:52
+msgid "ignores workspace boundraries"
+msgstr "Ignoră granițele birourilor"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:53
+msgid "enables moving focus between workspaces on the same output"
+msgstr "Permite mutarea focalizării între birouri de pe același ecran."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:57
+msgid "raise window on change"
+msgstr "Ridică fereastra la schimbare"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:58
+msgid "raise the newly focused window to the top"
+msgstr "Mută fereastra nou focalizată deasupra."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:62
+msgid "scan height"
+msgstr "Înălțime scanare"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:63
+msgid ""
+"the height of the bounding box used to scan for windows to the left or "
+"right. If zero it will be the height of the view. If negative it will be the "
+"height of the view subtracted by the value"
+msgstr ""
+"Înălțimea casetei care scanează ferestre în stânga sau în dreapta. Dacă este "
+"0, va fi înălțimea ferestrei. Dacă este negativă, va fi înălțimea ferestrei "
+"minus valoarea dată."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:67
+msgid "scan width"
+msgstr "Lățime scanare"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-change.xml:68
+msgid ""
+"the width of the bounding box used to scan for window above or below. If "
+"zero it will be the width of the view. If negative it will be the width of "
+"the view subtracted by the value"
+msgstr ""
+"Lățimea casetei care scanează ferestre în sus sau în jos. Dacă este 0, va fi "
+"lățimea ferestrei. Dacă este negativă, va fi lățimea ferestrei minus "
+"valoarea dată."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-focus-steal-prevent.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-focus-steal-prevent.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-focus-steal-prevent.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-focus-steal-prevent.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,61 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 21:43+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-steal-prevent.xml:4
+msgid "Focus Stealing Prevention"
+msgstr "Prevenirea furtului de focalizare"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-steal-prevent.xml:7
+msgid "The timeout (in ms) to prevent focus stealing"
+msgstr "Timpul, în milisecunde, pentru care să se prevină furtul focalizării"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-steal-prevent.xml:8
+msgid ""
+"A timer will be reset to the timeout (in ms) on every keystroke. If the "
+"timer is active when another window would normally gain focus, the focus is "
+"reset to the window that is accepting input."
+msgstr ""
+"Un cronometru va fi reînceput până la timpul stabilit (în milisecunde) la "
+"fiecare batere a tastelor. Dacă cronometrul este activ când altă fereastră "
+"ar deveni focalizată, focalizarea este restabilită la fereastra care "
+"acceptă intrare."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-steal-prevent.xml:13
+msgid "Deny focus to views matching this criteria"
+msgstr "Refuză focalizarea ferestrelor ce satisfac criteriile"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-steal-prevent.xml:14
+msgid ""
+"If a view matches when mapped, focus is reset to the last view with focus."
+msgstr ""
+"Dacă o fereastră corespunde când i se alocă ecran, focalizarea este "
+"restabilită la ultima fereastră focalizată."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-steal-prevent.xml:18
+msgid "Cancel focus stealing prevention on these keys"
+msgstr "Anulează prevenirea furtului de focalizare la aceste taste"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/focus-steal-prevent.xml:19
+msgid ""
+"Cancel focus stealing prevention when any of these keys are pressed. The "
+"string consists of keycode names delimited by | character."
+msgstr ""
+"Anulează prevenirea furtului de focalizare când oricare dintre aceste taste "
+"este apăsată. Șirul constă din coduri de taste delimitate de caracterul |."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-follow-focus.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-follow-focus.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-follow-focus.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-follow-focus.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,87 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 21:49+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:4
+msgid "Follow Focus"
+msgstr "Urmărirea focalizării"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:7
+msgid "View focus follows mouse"
+msgstr "Focalizarea ferestrelor urmărește mausul."
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:8
+msgid ""
+"When the mouse pointer is moved, the view focus changes to the view under "
+"the pointer."
+msgstr ""
+"Când se mișcă cursorul mausului, focalizarea se acordă ferestrei de sub "
+"acesta."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:12
+msgid "Output focus follows mouse"
+msgstr "Focalizarea ecranelor urmărește mausul."
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:13
+msgid ""
+"When the mouse pointer is moved, the output focus changes to the output that "
+"the pointer is currently on."
+msgstr ""
+"Când se mișcă cursorul mausului, focalizarea se acordă ecranului de sub "
+"acesta."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:17
+msgid "Delay (in ms) before focus change will be triggered"
+msgstr "Timp de așteptare (în ms) până se declanșează schimbarea focalizării"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:18
+msgid ""
+"The delay in ms before the plugin will trigger a focus change after the "
+"movement finished."
+msgstr ""
+"Timpul de așteptare, în milisecunde, înainte ca modulul să inițieze o "
+"schimbare a focalizării după ce s-a terminat mișcarea."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:23
+msgid "Minimum cursor movement"
+msgstr "Mișcarea minimă a cursorului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:24
+msgid ""
+"The distance (x+y) the cursor should be moved at least before the plugin "
+"gets activated"
+msgstr ""
+"Distanța minimă (x+y) pentru care să se miște cursorul înainte să se "
+"activeze modului."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:29
+msgid "Raise the focused view to the top"
+msgstr "Ridică fereastra focalizată"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/follow-focus.xml:30
+msgid ""
+"If disabled the focused view will only get keyboard focus, but will not be "
+"raised to the top."
+msgstr ""
+"Dacă este dezactivată, fereastra focalizată va prelua doar focalizarea "
+"tastaturii, dar nu va fi pusă deasupra."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-force-fullscreen.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-force-fullscreen.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-force-fullscreen.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-force-fullscreen.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,67 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:16+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:4
+msgid "Fullscreen Window"
+msgstr "Fereastră pe ecran complet"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:7
+msgid "Key Toggle Fullscreen"
+msgstr "Tastă pentru comutarea ecranului complet"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:11
+msgid "Preserve Aspect Ratio"
+msgstr "Păstrează raportul de aspect"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:15
+msgid "Transparent Behind Views"
+msgstr "Transparent în spatele ferestrelor"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:19
+msgid "Skew view width by multiplying by this factor"
+msgstr "Întinde lățimea ferestrei înmulțind cu acest factor"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:25
+msgid "Skew view height by multiplying by this factor"
+msgstr "Întinde înălțimea ferestrei înmulțind cu acest factor"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:31
+msgid "Constrain Mouse Pointer"
+msgstr "Constrânge cursorul mausului"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:35
+msgid "Constraint Area"
+msgstr "Zonă de constrângere"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:36
+msgid "If constrain pointer is enabled, constrain to this area."
+msgstr "Dacă constrângerea cursorului este activată, constrânge la această zonă."
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:40
+msgid "View"
+msgstr "Fereastră"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/force-fullscreen.xml:44
+msgid "Output"
+msgstr "Ecran"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-ghost.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-ghost.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-ghost.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-ghost.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,37 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:22+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/ghost.xml:4
+msgid "Ghost Windows"
+msgstr "Ferestre fantomă"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/ghost.xml:7
+msgid "Ghosted Windows"
+msgstr "Ferestre fantomă"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/ghost.xml:8
+msgid "Automatically sets the matched windows to be click-through."
+msgstr "Face automat ca clicul să treacă prin ferestrele corespunzătoare."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/ghost.xml:12
+msgid "Toggle Ghost Window"
+msgstr "Comută fereastră fantomă"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/ghost.xml:13
+msgid "Toggles the active window being click-through to whatever is below."
+msgstr "Comută dacă clicul în fereastra activă este transmis la fereastra de dedesubt."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-hide-cursor.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-hide-cursor.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-hide-cursor.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-hide-cursor.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,46 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:24+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/hide-cursor.xml:4
+msgid "Hide Cursor"
+msgstr "Ascundere cursor"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/hide-cursor.xml:5
+msgid "A plugin that allows to toggle hide mouse cursor."
+msgstr "Un modul care permite comutarea vizibilității cursorului mausului."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/hide-cursor.xml:8
+msgid "Toggle"
+msgstr "Comutare"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/hide-cursor.xml:9
+msgid "Toggles hide mouse cursor."
+msgstr "Comută vizibilitatea cursorului mausului."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/hide-cursor.xml:13
+msgid "Delay (in ms) before cursor will be hidden"
+msgstr "Timp de așteptare (în ms) până se ascunde cursorul"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/hide-cursor.xml:14
+msgid ""
+"The delay in ms before the plugin will hide the cursor. The cursor is shown "
+"again when cursor motion happens."
+msgstr ""
+"Timpul, în milisecunde, care să se aștepte înainte ca modulul să ascundă "
+"cursorul. Cursorul este afișat din nou când se mișcă."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-join-views.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-join-views.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-join-views.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-join-views.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,17 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:25+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/join-views.xml:4
+msgid "Join Views"
+msgstr "Alăturare ferestre"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-keycolor.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-keycolor.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-keycolor.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-keycolor.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,32 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:25+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/keycolor.xml:4
+msgid "Keycolor"
+msgstr "Culoare-cheie"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/keycolor.xml:7
+msgid "Key Color"
+msgstr "Culoare-cheie"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/keycolor.xml:11
+msgid "Opacity"
+msgstr "Opacitate"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/keycolor.xml:15
+msgid "Threshold"
+msgstr "Limită"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-mag.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-mag.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-mag.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-mag.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,32 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:26+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/mag.xml:4
+msgid "Magnifier"
+msgstr "Lupă"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/mag.xml:7
+msgid "Toggle"
+msgstr "Inițiere"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/mag.xml:11
+msgid "Zoom Level"
+msgstr "Nivelul măririi"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/mag.xml:17
+msgid "Default View Height"
+msgstr "Înălțimea standard a ferestrei"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-obs.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-obs.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-obs.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-obs.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,22 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:27+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/obs.xml:4
+msgid "OBS"
+msgstr "OLS"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/obs.xml:5
+msgid "Change the opacity, brightness and saturation of windows using ipc scripts"
+msgstr "Schimbă opacitatea, luminozitatea și saturația ferestrelor folosind scripturi IPC."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-pin-view.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-pin-view.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-pin-view.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-pin-view.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,22 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:28+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/pin-view.xml:4
+msgid "Pin View"
+msgstr "Prindere fereastră"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/pin-view.xml:5
+msgid "Set a view layer, role and workspace"
+msgstr "Stabilește un strat, rol și birou pentru o fereastră."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-showrepaint.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-showrepaint.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-showrepaint.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-showrepaint.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,50 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:31+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showrepaint.xml:4
+msgid "Show Repaint"
+msgstr "Arată redesenările"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showrepaint.xml:5
+msgid "Show repainted areas on the screen."
+msgstr "Arată zonele redesenate pe ecran."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showrepaint.xml:8
+msgid "Toggle"
+msgstr "Inițiere"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showrepaint.xml:9
+msgid "Toggles the plugin state."
+msgstr "Comută starea modulului."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showrepaint.xml:13
+msgid "Reduce Flicker"
+msgstr "Redu pâlpâirea"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showrepaint.xml:14
+msgid ""
+"Reduce flicker by copying the client damage region from the last frame to "
+"the current frame. This means that only the the damage region for all "
+"surfaces of the frame are painted and the rest of the output is painted with "
+"the contents of the last frame."
+msgstr ""
+"Redu pâlpâirea copiind regiunea de pătare a clientului de la cadrul anterior "
+"la cadrul actual. Aceasta înseamnă că doar regiunea de pătare pentru fiecare "
+"suprafață a cadrului este desenată și că restul ecranului este desenat cu "
+"conținutul cadrului anterior."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-showtouch.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-showtouch.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-showtouch.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-showtouch.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,72 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:34+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:4
+msgid "Showtouch"
+msgstr "Arată atingeri"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:5
+msgid "Render touchscreen fingers"
+msgstr "Desenează degetele de pe un ecran tactil."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:8
+msgid "Finger Color"
+msgstr "Culoarea degetului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:9
+msgid "Color used for rendering finger touches"
+msgstr "Culoarea folosită pentru desenarea atingerilor cu degetul."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:13
+msgid "Center Color"
+msgstr "Culoarea centrului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:14
+msgid "Color used for rendering computed center of fingers"
+msgstr "Culoarea folosită pentru desenarea centrului calculat al degetelor."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:18
+msgid "Touch Radius"
+msgstr "Raza atingerii"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:19
+msgid "Radius used to size the finger touch point renderings"
+msgstr "Raza folosită pentru a dimensiona desenele punctelor de atingere cu degetul."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:23
+msgid "Touch Duration"
+msgstr "Durata atingerii"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:24
+msgid "Milliseconds the visual finger indicator will stay on screen"
+msgstr "Câte milisecunde să stea indicatorul vizual al degetului pe ecran"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:28
+msgid "Toggle"
+msgstr "Comutare"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/showtouch.xml:29
+msgid "Toggles the finger indicators off and on"
+msgstr "Comută afișarea indicatorilor de degete"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-view-shot.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-view-shot.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-view-shot.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-view-shot.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,52 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-10-01 10:58+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/view-shot.xml:4
+msgid "View Shot"
+msgstr "Captură fereastră"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/view-shot.xml:7
+msgid "Capture"
+msgstr "Capturează"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/view-shot.xml:8
+msgid "Captures the cursor focus view."
+msgstr "Capturează fereastra focalizată pentru cursor."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/view-shot.xml:12
+msgid "File Name"
+msgstr "Numele fișierului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/view-shot.xml:13
+msgid ""
+"C date format specifiers are repleaced by the time/date/etc. For example, %Y "
+"is replaced by the current year."
+msgstr ""
+"Specificatorii formatului de dată C sunt înlocuiți de dată/oră/etc. De "
+"exemplu, %Y este înlocuit cu anul actual."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/view-shot.xml:17
+msgid "Run Command"
+msgstr "Execută comanda"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/view-shot.xml:18
+msgid ""
+"Runs the command after the capturing. %f is replaced with the file name."
+msgstr "Execută comanda după capturare. %f este înlocuit cu numele fișierului."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-water.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-water.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-water.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-water.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,32 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 22:36+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/water.xml:4
+msgid "Water"
+msgstr "Apă"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/water.xml:5
+msgid "Water effect."
+msgstr "Efect acvatic."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/water.xml:8
+msgid "Activate"
+msgstr "Inițiere"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/water.xml:9
+msgid "Activates water effect."
+msgstr "Activează efectul acvatic."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-window-zoom.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-window-zoom.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-window-zoom.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-window-zoom.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,86 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-09-30 23:36+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:4
+msgid "Window Zoom"
+msgstr "Mărire fereastră"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:5
+msgid "A plugin to zoom windows."
+msgstr "Un modul pentru a mări ferestre."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:8
+msgid "Modifier"
+msgstr "Modificatoare"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:9
+msgid ""
+"When the modifier key is held down, you can scroll down and up to adjust the "
+"zoom of the window."
+msgstr ""
+"Când tasta modificatoare este ținută apăsată, puteți derula în sus și în jos "
+"pentru a regla gradul de mărire a ferestrei."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:13
+msgid "Zoom Step"
+msgstr "Treaptă de mărire"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:14
+msgid "Sets the zoom increment per binding action."
+msgstr "Stabilește treapta gradului de mărire pentru o acțiune de asociere."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:19
+msgid "Preserve Aspect"
+msgstr "Păstrează raportul de aspect"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:20
+msgid "Preserve the aspect ratio of the view."
+msgstr "Păstrează raportul de aspect al ferestrei."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:24
+msgid "Nearest Filtering"
+msgstr "Filtru „cel mai apropiat”"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:25
+msgid "Use GL_NEAREST instead of GL_LINEAR."
+msgstr "Folosește GL_NEAREST în locul lui GL_LINEAR."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:29
+msgid "Increment X"
+msgstr "Incrementare X"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:33
+msgid "Decrement X"
+msgstr "Decrementare X"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:37
+msgid "Increment Y"
+msgstr "Incrementare Y"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/window-zoom.xml:41
+msgid "Decrement Y"
+msgstr "Decrementare Y"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-workspace-names.po wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-workspace-names.po
--- wayfire-plugins-extra-0.10.0/locale/ro/LC_MESSAGES/wf-plugin-workspace-names.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/LC_MESSAGES/wf-plugin-workspace-names.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,181 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-29 13:01+0300\n"
+"PO-Revision-Date: 2025-10-01 10:56+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.4.2\n"
+
+#. (itstool) path: plugin/_short
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:4
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:92
+msgid "Workspace Names"
+msgstr "Nume de birou"
+
+#. (itstool) path: plugin/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:5
+msgid "Name workspaces."
+msgstr "Denumiți birourile."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:8
+msgid "Display Duration"
+msgstr "Durata de afișare"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:9
+msgid "How long the name is displayed."
+msgstr "Pentru cât timp se afișează numele."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:14
+msgid "Margin"
+msgstr "Margine"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:15
+msgid "Distance from edge of screen to indicator."
+msgstr "Distanța de la marginea ecranului la indicator."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:20
+msgid "Position"
+msgstr "Poziție"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:21
+msgid "Position of rendering."
+msgstr "Poziția desenării."
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:25
+msgid "Top Left"
+msgstr "Stânga-sus"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:29
+msgid "Top Center"
+msgstr "Centru-sus"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:33
+msgid "Top Right"
+msgstr "Dreapta-sus"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:37
+msgid "Center Left"
+msgstr "Stânga-centru"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:41
+msgid "Center"
+msgstr "Centru"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:45
+msgid "Center Right"
+msgstr "Dreapta-centru"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:49
+msgid "Bottom Left"
+msgstr "Stânga-jos"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:53
+msgid "Bottom Center"
+msgstr "Centru-jos"
+
+#. (itstool) path: desc/_name
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:57
+msgid "Bottom Right"
+msgstr "Dreapta-jos"
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:61
+msgid "Background Color"
+msgstr "Culoarea de fundal"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:62
+msgid "Background color for text."
+msgstr "Culoarea de fundal a textului."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:66
+msgid "Text Color"
+msgstr "Culoarea textului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:67
+msgid "Text color."
+msgstr "Culoarea textului."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:71
+msgid "Text Font"
+msgstr "Fontul textului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:72
+msgid "Font used for text rendering."
+msgstr "Fontul folosit pentru desenarea textului."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:76
+msgid "Show Option Names"
+msgstr "Arată numele opțiunilor"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:77
+msgid "Display option names on screen for convenience."
+msgstr "Afișează numele opțiunilor pe ecran pentru comoditate."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:81
+msgid "Show Option Values"
+msgstr "Arată valorile opțiunilor"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:82
+msgid ""
+"Display option values instead of names, when show_option_names is enabled."
+msgstr ""
+"Afișează valorile opțiunilor în locul numelor când show_option_names este "
+"activat."
+
+#. (itstool) path: option/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:86
+msgid "Background Corner Radius"
+msgstr "Raza colțurilor fundalului"
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:87
+msgid "Radius for the corners of the background."
+msgstr "Raza de folosit pentru colțurile fundalului."
+
+#. (itstool) path: option/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:93
+msgid ""
+"Names of the workspaces. By default, they will have the name Workspace #N, "
+"where #N is the workspace number."
+msgstr ""
+"Numele birourilor. În mod implicit, vor avea numele Workspace #N, unde #N "
+"este numărul biroului."
+
+#. (itstool) path: entry/_short
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:95
+msgid "Workspace Name"
+msgstr "Numele biroului"
+
+#. (itstool) path: entry/_long
+#: /home/vlad/wayfire-plugins-extra/metadata/workspace-names.xml:96
+msgid "Sets the name of the workspace"
+msgstr "Stabilește numele biroului."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/ro/wf-plugin-fisheye.po wayfire-plugins-extra/locale/ro/wf-plugin-fisheye.po
--- wayfire-plugins-extra-0.10.0/locale/ro/wf-plugin-fisheye.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/ro/wf-plugin-fisheye.po	2026-08-01 16:00:35.432890271 -0600
@@ -0,0 +1,44 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: \n"
+"POT-Creation-Date: 2025-09-18 14:55+0300\n"
+"PO-Revision-Date: 2025-09-18 18:31+0300\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: ro\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Generator: Poedit 3.7\n"
+
+#. (itstool) path: plugin/_short
+msgid "Fisheye"
+msgstr "Ochi de pește"
+
+#. (itstool) path: plugin/_long
+msgid "A plugin which provides fisheye effect."
+msgstr "Un modul care furnizează un efect de obiectiv „ochi de pește”."
+
+#. (itstool) path: option/_short
+msgid "Toggle"
+msgstr "Inițiere"
+
+#. (itstool) path: option/_long
+msgid "Toggles fisheye with the specified activator."
+msgstr "Comută ochiul de pește cu activatorul specificat."
+
+#. (itstool) path: option/_short
+msgid "Radius"
+msgstr "Rază"
+
+#. (itstool) path: option/_long
+msgid "Sets the border radius in pixels."
+msgstr "Stabilește raza colțului în pixeli."
+
+#. (itstool) path: option/_short
+msgid "Zoom"
+msgstr "Mărire"
+
+#. (itstool) path: option/_long
+msgid "Sets the zoom factor."
+msgstr "Stabilește factorul de mărire."
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-annotate.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-annotate.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-annotate.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-annotate.po	2026-08-01 16:00:35.433260551 -0600
@@ -0,0 +1,83 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Annotate"
+msgstr "标注"
+
+#. (itstool) path: plugin/_long
+msgid "Draw on the output."
+msgstr "在输出上绘制。"
+
+#. (itstool) path: option/_short
+msgid "Draw"
+msgstr "绘图"
+
+#. (itstool) path: option/_long
+msgid "Begin drawing on workspace."
+msgstr "开始在工作区上绘图。"
+
+#. (itstool) path: option/_short
+msgid "Clear Workspace"
+msgstr "清除工作区"
+
+#. (itstool) path: option/_long
+msgid "Clear workspace."
+msgstr "清除工作区。"
+
+#. (itstool) path: option/_short
+msgid "Stroke Color"
+msgstr "描边颜色"
+
+#. (itstool) path: option/_long
+msgid "Color used for drawing."
+msgstr "用于绘图的颜色。"
+
+#. (itstool) path: option/_short
+msgid "Drawing Method"
+msgstr "绘图方法"
+
+#. (itstool) path: option/_long
+msgid "Method used for drawing."
+msgstr "用于绘图的方法。"
+
+#. (itstool) path: desc/_name
+msgid "Free Draw"
+msgstr "自由绘图"
+
+#. (itstool) path: desc/_name
+msgid "Line"
+msgstr "直线"
+
+#. (itstool) path: desc/_name
+msgid "Rectangle"
+msgstr "矩形"
+
+#. (itstool) path: desc/_name
+msgid "Circle"
+msgstr "圆形"
+
+#. (itstool) path: option/_short
+msgid "Line Width"
+msgstr "线宽"
+
+#. (itstool) path: option/_long
+msgid "Line width used for drawing."
+msgstr "用于绘图的线宽。"
+
+#. (itstool) path: option/_short
+msgid "Draw Shapes From Center"
+msgstr "从中心绘制形状"
+
+#. (itstool) path: option/_long
+msgid "Draw shapes from center of drag point."
+msgstr "从拖动点的中心绘制形状。"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-autorotate-iio.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-autorotate-iio.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-autorotate-iio.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-autorotate-iio.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,35 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Auto Rotate"
+msgstr "自动旋转"
+
+#. (itstool) path: option/_short
+msgid "Lock Rotation"
+msgstr "锁定旋转"
+
+#. (itstool) path: option/_short
+msgid "Rotate Up"
+msgstr "向上旋转"
+
+#. (itstool) path: option/_short
+msgid "Rotate Left"
+msgstr "向左旋转"
+
+#. (itstool) path: option/_short
+msgid "Rotate Down"
+msgstr "向下旋转"
+
+#. (itstool) path: option/_short
+msgid "Rotate Right"
+msgstr "向右旋转"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-bench.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-bench.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-bench.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-bench.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,71 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Bench"
+msgstr "基准测试"
+
+#. (itstool) path: plugin/_long
+msgid "Display fps on each output."
+msgstr "在每个输出上显示帧率。"
+
+#. (itstool) path: option/_short
+msgid "Average frames"
+msgstr "平均帧数"
+
+#. (itstool) path: option/_long
+msgid "How many frames to average to get the FPS value."
+msgstr "计算平均帧率所用的帧数。"
+
+#. (itstool) path: option/_short
+msgid "Position"
+msgstr "位置"
+
+#. (itstool) path: option/_long
+msgid "Position of rendering."
+msgstr "渲染位置。"
+
+#. (itstool) path: desc/_name
+msgid "Top Left"
+msgstr "左上"
+
+#. (itstool) path: desc/_name
+msgid "Top Center"
+msgstr "中上"
+
+#. (itstool) path: desc/_name
+msgid "Top Right"
+msgstr "右上"
+
+#. (itstool) path: desc/_name
+msgid "Center Left"
+msgstr "左中"
+
+#. (itstool) path: desc/_name
+msgid "Center"
+msgstr "居中"
+
+#. (itstool) path: desc/_name
+msgid "Center Right"
+msgstr "右中"
+
+#. (itstool) path: desc/_name
+msgid "Bottom Left"
+msgstr "左下"
+
+#. (itstool) path: desc/_name
+msgid "Bottom Center"
+msgstr "中下"
+
+#. (itstool) path: desc/_name
+msgid "Bottom Right"
+msgstr "右下"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-crosshair.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-crosshair.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-crosshair.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-crosshair.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,35 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Crosshair"
+msgstr "十字线"
+
+#. (itstool) path: plugin/_long
+msgid "Render fullscreen mouse crosshair"
+msgstr "渲染全屏鼠标十字线"
+
+#. (itstool) path: option/_short
+msgid "Line Width"
+msgstr "线宽"
+
+#. (itstool) path: option/_long
+msgid "Line width of crosshair"
+msgstr "十字线的线宽"
+
+#. (itstool) path: option/_short
+msgid "Line Color"
+msgstr "线条颜色"
+
+#. (itstool) path: option/_long
+msgid "Color used for rendering crosshair"
+msgstr "用于渲染十字线的颜色"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-extra-animations.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-extra-animations.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-extra-animations.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-extra-animations.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,167 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Extra Animations"
+msgstr "额外动画"
+
+#. (itstool) path: plugin/_long
+msgid "Extra animations to extend animate plugin"
+msgstr "扩展 animate 插件的额外动画"
+
+#. (itstool) path: group/_short
+msgid "Blinds Settings"
+msgstr "百叶窗设置"
+
+#. (itstool) path: option/_short
+msgid "Blinds duration"
+msgstr "百叶窗持续时间"
+
+#. (itstool) path: option/_long
+msgid "Sets the duration for the blinds animation in milliseconds."
+msgstr "以毫秒为单位设置百叶窗动画的持续时间。"
+
+#. (itstool) path: option/_short
+msgid "Blinds strip height"
+msgstr "百叶窗条高"
+
+#. (itstool) path: option/_long
+msgid "Height of each blinds strip in pixels."
+msgstr "每个百叶窗条的像素高度。"
+
+#. (itstool) path: group/_short
+msgid "Helix Settings"
+msgstr "螺旋设置"
+
+#. (itstool) path: option/_short
+msgid "Helix duration"
+msgstr "螺旋持续时间"
+
+#. (itstool) path: option/_long
+msgid "Sets the duration for the helix animation in milliseconds."
+msgstr "以毫秒为单位设置螺旋动画的持续时间。"
+
+#. (itstool) path: option/_short
+msgid "Helix rotations"
+msgstr "螺旋旋转次数"
+
+#. (itstool) path: option/_long
+msgid "Number of rotations for the helix animation."
+msgstr "螺旋动画的旋转次数。"
+
+#. (itstool) path: option/_short
+msgid "Helix strip height"
+msgstr "螺旋条高"
+
+#. (itstool) path: option/_long
+msgid "Height of each helix strip in pixels."
+msgstr "每个螺旋条的像素高度。"
+
+#. (itstool) path: group/_short
+msgid "Shatter Settings"
+msgstr "破碎设置"
+
+#. (itstool) path: option/_short
+msgid "Shatter duration"
+msgstr "破碎持续时间"
+
+#. (itstool) path: option/_long
+msgid "Sets the duration for the shatter animation in milliseconds."
+msgstr "以毫秒为单位设置破碎动画的持续时间。"
+
+#. (itstool) path: group/_short
+msgid "Vortex Settings"
+msgstr "旋涡设置"
+
+#. (itstool) path: option/_short
+msgid "Vortex duration"
+msgstr "旋涡持续时间"
+
+#. (itstool) path: option/_long
+msgid "Sets the duration for the vortex animation in milliseconds."
+msgstr "以毫秒为单位设置旋涡动画的持续时间。"
+
+#. (itstool) path: group/_short
+msgid "Melt Settings"
+msgstr "融化设置"
+
+#. (itstool) path: option/_short
+msgid "Melt duration"
+msgstr "融化持续时间"
+
+#. (itstool) path: option/_long
+msgid "Sets the duration for the melt animation in milliseconds."
+msgstr "以毫秒为单位设置融化动画的持续时间。"
+
+#. (itstool) path: option/_short
+msgid "Melt distortion factor"
+msgstr "融化变形系数"
+
+#. (itstool) path: option/_long
+msgid "Distortion factor for melt animation."
+msgstr "融化动画的变形系数。"
+
+#. (itstool) path: group/_short
+msgid "Dodge Settings"
+msgstr "闪避设置"
+
+#. (itstool) path: option/_short
+msgid "Enable Dodge"
+msgstr "启用闪避"
+
+#. (itstool) path: option/_long
+msgid "Enables the Dodge focus animation."
+msgstr "启用闪避焦点动画。"
+
+#. (itstool) path: option/_short
+msgid "Duration"
+msgstr "持续时间"
+
+#. (itstool) path: option/_long
+msgid "Sets the animation duration in milliseconds."
+msgstr "以毫秒为单位设置动画持续时间。"
+
+#. (itstool) path: option/_short
+msgid "Rotate"
+msgstr "旋转"
+
+#. (itstool) path: option/_long
+msgid "Rotate windows during animation."
+msgstr "动画期间旋转窗口。"
+
+#. (itstool) path: option/_short
+msgid "Zoom"
+msgstr "缩放"
+
+#. (itstool) path: option/_long
+msgid "Slightly increase zoom for the focusing window during animation."
+msgstr "在动画期间，将焦点窗口略微放大。"
+
+#. (itstool) path: option/_short
+msgid "Animation Direction"
+msgstr "动画方向"
+
+#. (itstool) path: option/_long
+msgid "Sets the animation direction."
+msgstr "设置动画方向。"
+
+#. (itstool) path: desc/_name
+msgid "Cardinal"
+msgstr "基数"
+
+#. (itstool) path: desc/_name
+msgid "Diagonal"
+msgstr "对角"
+
+#. (itstool) path: desc/_name
+msgid "Circular"
+msgstr "圆形"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-focus-change.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-focus-change.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-focus-change.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-focus-change.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,137 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Focus Change"
+msgstr "焦点切换"
+
+#. (itstool) path: option/_short
+msgid "focus up"
+msgstr "上移焦点"
+
+#. (itstool) path: option/_long
+msgid "move focus to the closest window above"
+msgstr "将焦点移动到最靠近上方的窗口"
+
+#. (itstool) path: option/_short
+msgid "focus down"
+msgstr "下移焦点"
+
+#. (itstool) path: option/_long
+msgid "move focus to the closest window below"
+msgstr "将焦点移动到最靠近下方的窗口"
+
+#. (itstool) path: option/_short
+msgid "focus right"
+msgstr "右移焦点"
+
+#. (itstool) path: option/_long
+msgid "move focus to the closest window to the right"
+msgstr "将焦点移动到最靠近右侧的窗口"
+
+#. (itstool) path: option/_short
+msgid "focus left"
+msgstr "左移焦点"
+
+#. (itstool) path: option/_long
+msgid "move focus to the closest window to the left"
+msgstr "将焦点移动到最靠近左侧的窗口"
+
+#. (itstool) path: option/_short
+msgid "upwards grace in pixels"
+msgstr "向上容忍像素"
+
+#. (itstool) path: option/_long
+msgid ""
+"add an amount of pixel upwards in which windows will be ignored. Can be "
+"negative"
+msgstr "向上增加一定数量的像素，在此范围内将忽略窗口。可以是负值"
+
+#. (itstool) path: option/_short
+msgid "downwards grace in pixels"
+msgstr "向下容忍像素"
+
+#. (itstool) path: option/_long
+msgid ""
+"add an amount of pixel downwards in which windows will be ignored. Can be "
+"negative"
+msgstr "向下增加一定数量的像素，在此范围内将忽略窗口。可以是负值"
+
+#. (itstool) path: option/_short
+msgid "rightwards grace in pixels"
+msgstr "向右容忍像素"
+
+#. (itstool) path: option/_long
+msgid ""
+"add an amount of pixel to the right in which windows will be ignored. Can be "
+"negative"
+msgstr "向右增加一定数量的像素，在此范围内将忽略窗口。可以是负值"
+
+#. (itstool) path: option/_short
+msgid "leftwards grace in pixels"
+msgstr "向左容忍像素"
+
+#. (itstool) path: option/_long
+msgid ""
+"add an amount of pixel to the left in which windows will be ignored. Can be "
+"negative"
+msgstr "向左增加一定数量的像素，在此范围内将忽略窗口。可以是负值"
+
+#. (itstool) path: option/_short
+msgid "ignores output boundraries"
+msgstr "忽略输出边界"
+
+#. (itstool) path: option/_long
+msgid "enables moving focus between different outputs"
+msgstr "允许在不同输出之间移动焦点"
+
+#. (itstool) path: option/_short
+msgid "ignores workspace boundraries"
+msgstr "忽略工作区边界"
+
+#. (itstool) path: option/_long
+msgid "enables moving focus between workspaces on the same output"
+msgstr "允许在同一输出上的工作区之间移动焦点"
+
+#. (itstool) path: option/_short
+msgid "raise window on change"
+msgstr "切换时提升窗口"
+
+#. (itstool) path: option/_long
+msgid "raise the newly focused window to the top"
+msgstr "将新获得焦点的窗口提升到最顶层"
+
+#. (itstool) path: option/_short
+msgid "scan height"
+msgstr "扫描高度"
+
+#. (itstool) path: option/_long
+msgid ""
+"the height of the bounding box used to scan for windows to the left or "
+"right. If zero it will be the height of the view. If negative it will be the "
+"height of the view subtracted by the value"
+msgstr ""
+"用于扫描左侧或右侧窗口的边界框高度。如果为零，则为视图的高度。如果为负数，则"
+"为视图高度减去该值"
+
+#. (itstool) path: option/_short
+msgid "scan width"
+msgstr "扫描宽度"
+
+#. (itstool) path: option/_long
+msgid ""
+"the width of the bounding box used to scan for window above or below. If "
+"zero it will be the width of the view. If negative it will be the width of "
+"the view subtracted by the value"
+msgstr ""
+"用于扫描上方或下方窗口的边界框宽度。如果为零，则为视图的宽度。如果为负数，则"
+"为视图宽度减去该值"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-focus-steal-prevent.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-focus-steal-prevent.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-focus-steal-prevent.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-focus-steal-prevent.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,49 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Focus Stealing Prevention"
+msgstr "焦点防盗"
+
+#. (itstool) path: option/_short
+msgid "The timeout (in ms) to prevent focus stealing"
+msgstr "防止焦点被盗的超时（毫秒）"
+
+#. (itstool) path: option/_long
+msgid ""
+"A timer will be reset to the timeout (in ms) on every keystroke. If the "
+"timer is active when another window would normally gain focus, the focus is "
+"reset to the window that is accepting input."
+msgstr ""
+"每次按键时，计时器将重置为设定的超时（毫秒）。如果在另一个窗口通常会获得焦点"
+"时计时器处于活动状态，则焦点将重置为正在接受输入的窗口。"
+
+#. (itstool) path: option/_short
+msgid "Deny focus to views matching this criteria"
+msgstr "拒绝焦点到符合此条件的视图"
+
+#. (itstool) path: option/_long
+msgid ""
+"If a view matches when mapped, focus is reset to the last view with focus."
+msgstr "如果某个视图在映射时匹配，焦点将重置为上一个具有焦点的视图。"
+
+#. (itstool) path: option/_short
+msgid "Cancel focus stealing prevention on these keys"
+msgstr "在这些键上取消焦点防盗"
+
+#. (itstool) path: option/_long
+msgid ""
+"Cancel focus stealing prevention when any of these keys are pressed. The "
+"string consists of keycode names delimited by | character."
+msgstr ""
+"按下这些键中的任何一个时，取消焦点防盗。该字符串由用 | 字符分隔的按键码名称组"
+"成。"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-follow-focus.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-follow-focus.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-follow-focus.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-follow-focus.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,65 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Follow Focus"
+msgstr "跟随焦点"
+
+#. (itstool) path: option/_short
+msgid "View focus follows mouse"
+msgstr "视图焦点跟随鼠标"
+
+#. (itstool) path: option/_long
+msgid ""
+"When the mouse pointer is moved, the view focus changes to the view under "
+"the pointer."
+msgstr "当鼠标指针移动时，视图焦点会切换到指针下方的视图。"
+
+#. (itstool) path: option/_short
+msgid "Output focus follows mouse"
+msgstr "输出焦点跟随鼠标"
+
+#. (itstool) path: option/_long
+msgid ""
+"When the mouse pointer is moved, the output focus changes to the output that "
+"the pointer is currently on."
+msgstr "当鼠标指针移动时，输出焦点会切换到指针当前所在的输出。"
+
+#. (itstool) path: option/_short
+msgid "Delay (in ms) before focus change will be triggered"
+msgstr "焦点改变前的延迟（毫秒）"
+
+#. (itstool) path: option/_long
+msgid ""
+"The delay in ms before the plugin will trigger a focus change after the "
+"movement finished."
+msgstr "在移动结束后，插件触发焦点改变前的延迟（毫秒）。"
+
+#. (itstool) path: option/_short
+msgid "Minimum cursor movement"
+msgstr "最小光标移动"
+
+#. (itstool) path: option/_long
+msgid ""
+"The distance (x+y) the cursor should be moved at least before the plugin "
+"gets activated"
+msgstr "光标需要移动的最小距离 (x+y)，在此之后插件才会激活。"
+
+#. (itstool) path: option/_short
+msgid "Raise the focused view to the top"
+msgstr "将焦点视图提升到顶部"
+
+#. (itstool) path: option/_long
+msgid ""
+"If disabled the focused view will only get keyboard focus, but will not be "
+"raised to the top."
+msgstr "如果禁用，焦点视图将只获得键盘焦点，但不会被提升到顶部。"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-force-fullscreen.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-force-fullscreen.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-force-fullscreen.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-force-fullscreen.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,51 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Fullscreen Window"
+msgstr "全屏窗口"
+
+#. (itstool) path: option/_short
+msgid "Key Toggle Fullscreen"
+msgstr "按键切换全屏"
+
+#. (itstool) path: option/_short
+msgid "Preserve Aspect Ratio"
+msgstr "保持长宽比"
+
+#. (itstool) path: option/_short
+msgid "Transparent Behind Views"
+msgstr "视图后方透明"
+
+#. (itstool) path: option/_short
+msgid "Skew view width by multiplying by this factor"
+msgstr "通过乘以该因子来扭曲视图宽度"
+
+#. (itstool) path: option/_short
+msgid "Skew view height by multiplying by this factor"
+msgstr "通过乘以该因子来扭曲视图高度"
+
+#. (itstool) path: option/_short
+msgid "Constrain Mouse Pointer"
+msgstr "限制鼠标指针"
+
+#. (itstool) path: option/_long
+msgid "If constrain pointer is enabled, constrain to this area."
+msgstr "如果启用了限制指针，则限制在此区域。"
+
+#. (itstool) path: desc/_name
+msgid "View"
+msgstr "视图"
+
+#. (itstool) path: desc/_name
+msgid "Output"
+msgstr "输出"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-ghost.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-ghost.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-ghost.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-ghost.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,31 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Ghost Windows"
+msgstr "幽灵窗口"
+
+#. (itstool) path: option/_short
+msgid "Ghosted Windows"
+msgstr "幽灵化窗口"
+
+#. (itstool) path: option/_long
+msgid "Automatically sets the matched windows to be click-through."
+msgstr "自动将匹配的窗口设置为可穿透点击。"
+
+#. (itstool) path: option/_short
+msgid "Toggle Ghost Window"
+msgstr "切换幽灵窗口"
+
+#. (itstool) path: option/_long
+msgid "Toggles the active window being click-through to whatever is below."
+msgstr "将活动窗口切换为可穿透点击，点击会作用于下方的内容。"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-hide-cursor.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-hide-cursor.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-hide-cursor.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-hide-cursor.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,37 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Hide Cursor"
+msgstr "隐藏光标"
+
+#. (itstool) path: plugin/_long
+msgid "A plugin that allows to toggle hide mouse cursor."
+msgstr "一个允许切换隐藏鼠标光标的插件。"
+
+#. (itstool) path: option/_short
+msgid "Toggle"
+msgstr "切换"
+
+#. (itstool) path: option/_long
+msgid "Toggles hide mouse cursor."
+msgstr "切换隐藏鼠标光标。"
+
+#. (itstool) path: option/_short
+msgid "Delay (in ms) before cursor will be hidden"
+msgstr "光标隐藏前的延迟（毫秒）"
+
+#. (itstool) path: option/_long
+msgid ""
+"The delay in ms before the plugin will hide the cursor. The cursor is shown "
+"again when cursor motion happens."
+msgstr "插件隐藏光标前的延迟（毫秒）。当光标移动时，光标会再次显示。"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-join-views.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-join-views.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-join-views.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-join-views.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,15 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Join Views"
+msgstr "合并视图"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-keycolor.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-keycolor.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-keycolor.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-keycolor.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,27 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Keycolor"
+msgstr "键色"
+
+#. (itstool) path: option/_short
+msgid "Key Color"
+msgstr "键色"
+
+#. (itstool) path: option/_short
+msgid "Opacity"
+msgstr "不透明度"
+
+#. (itstool) path: option/_short
+msgid "Threshold"
+msgstr "阈值"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-mag.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-mag.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-mag.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-mag.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,27 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Magnifier"
+msgstr "放大镜"
+
+#. (itstool) path: option/_short
+msgid "Toggle"
+msgstr "切换"
+
+#. (itstool) path: option/_short
+msgid "Zoom Level"
+msgstr "缩放级别"
+
+#. (itstool) path: option/_short
+msgid "Default View Height"
+msgstr "默认视图高度"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-obs.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-obs.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-obs.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-obs.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,20 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "OBS"
+msgstr "不透明度、亮度与饱和度"
+
+#. (itstool) path: plugin/_long
+msgid ""
+"Change the opacity, brightness and saturation of windows using ipc scripts"
+msgstr "使用 ipc 脚本更改窗口的不透明度、亮度和饱和度"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-pin-view.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-pin-view.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-pin-view.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-pin-view.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,19 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Pin View"
+msgstr "固定视图"
+
+#. (itstool) path: plugin/_long
+msgid "Set a view layer, role and workspace"
+msgstr "设置视图图层、角色和工作区"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-showrepaint.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-showrepaint.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-showrepaint.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-showrepaint.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,41 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Show Repaint"
+msgstr "显示重绘"
+
+#. (itstool) path: plugin/_long
+msgid "Show repainted areas on the screen."
+msgstr "在屏幕上显示重绘区域。"
+
+#. (itstool) path: option/_short
+msgid "Toggle"
+msgstr "切换"
+
+#. (itstool) path: option/_long
+msgid "Toggles the plugin state."
+msgstr "切换插件状态。"
+
+#. (itstool) path: option/_short
+msgid "Reduce Flicker"
+msgstr "减少闪烁"
+
+#. (itstool) path: option/_long
+msgid ""
+"Reduce flicker by copying the client damage region from the last frame to "
+"the current frame. This means that only the the damage region for all "
+"surfaces of the frame are painted and the rest of the output is painted with "
+"the contents of the last frame."
+msgstr ""
+"通过将客户端损坏区域从上一帧复制到当前帧来减少闪烁。这意味着只绘制帧中所有表"
+"面的损坏区域，其余输出则用上一帧的内容绘制。"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-showtouch.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-showtouch.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-showtouch.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-showtouch.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,59 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Showtouch"
+msgstr "显示触控"
+
+#. (itstool) path: plugin/_long
+msgid "Render touchscreen fingers"
+msgstr "渲染触控笔划"
+
+#. (itstool) path: option/_short
+msgid "Finger Color"
+msgstr "手指颜色"
+
+#. (itstool) path: option/_long
+msgid "Color used for rendering finger touches"
+msgstr "用于渲染手指触控的颜色"
+
+#. (itstool) path: option/_short
+msgid "Center Color"
+msgstr "中心颜色"
+
+#. (itstool) path: option/_long
+msgid "Color used for rendering computed center of fingers"
+msgstr "用于渲染计算出的手指中心的颜色"
+
+#. (itstool) path: option/_short
+msgid "Touch Radius"
+msgstr "触控半径"
+
+#. (itstool) path: option/_long
+msgid "Radius used to size the finger touch point renderings"
+msgstr "用于调整手指触控点渲染大小的半径"
+
+#. (itstool) path: option/_short
+msgid "Touch Duration"
+msgstr "触控持续时间"
+
+#. (itstool) path: option/_long
+msgid "Milliseconds the visual finger indicator will stay on screen"
+msgstr "可视手指指示器在屏幕上停留的毫秒数"
+
+#. (itstool) path: option/_short
+msgid "Toggle"
+msgstr "切换"
+
+#. (itstool) path: option/_long
+msgid "Toggles the finger indicators off and on"
+msgstr "切换手指指示器的开启和关闭"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-view-shot.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-view-shot.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-view-shot.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-view-shot.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,42 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "View Shot"
+msgstr "视图截图"
+
+#. (itstool) path: option/_short
+msgid "Capture"
+msgstr "捕捉"
+
+#. (itstool) path: option/_long
+msgid "Captures the cursor focus view."
+msgstr "捕捉光标焦点视图。"
+
+#. (itstool) path: option/_short
+msgid "File Name"
+msgstr "文件名"
+
+#. (itstool) path: option/_long
+msgid ""
+"C date format specifiers are repleaced by the time/date/etc. For example, %Y "
+"is replaced by the current year."
+msgstr "C 日期格式说明符将被替换为时间/日期等。例如，%Y 会被替换为当前年份。"
+
+#. (itstool) path: option/_short
+msgid "Run Command"
+msgstr "运行命令"
+
+#. (itstool) path: option/_long
+msgid ""
+"Runs the command after the capturing. %f is replaced with the file name."
+msgstr "捕捉后运行命令。%f 会被替换为文件名。"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-water.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-water.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-water.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-water.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,27 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Water"
+msgstr "水"
+
+#. (itstool) path: plugin/_long
+msgid "Water effect."
+msgstr "水面效果。"
+
+#. (itstool) path: option/_short
+msgid "Activate"
+msgstr "激活"
+
+#. (itstool) path: option/_long
+msgid "Activates water effect."
+msgstr "激活水面效果。"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-window-zoom.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-window-zoom.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-window-zoom.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-window-zoom.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,69 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+msgid "Window Zoom"
+msgstr "窗口缩放"
+
+#. (itstool) path: plugin/_long
+msgid "A plugin to zoom windows."
+msgstr "一个用于缩放窗口的插件。"
+
+#. (itstool) path: option/_short
+msgid "Modifier"
+msgstr "修饰键"
+
+#. (itstool) path: option/_long
+msgid ""
+"When the modifier key is held down, you can scroll down and up to adjust the "
+"zoom of the window."
+msgstr "按住修饰键时，您可以通过上下滚动来调整窗口的缩放。"
+
+#. (itstool) path: option/_short
+msgid "Zoom Step"
+msgstr "缩放步长"
+
+#. (itstool) path: option/_long
+msgid "Sets the zoom increment per binding action."
+msgstr "设置每个绑定操作的缩放增量。"
+
+#. (itstool) path: option/_short
+msgid "Preserve Aspect"
+msgstr "保持长宽比"
+
+#. (itstool) path: option/_long
+msgid "Preserve the aspect ratio of the view."
+msgstr "保持视图的长宽比。"
+
+#. (itstool) path: option/_short
+msgid "Nearest Filtering"
+msgstr "最近邻过滤"
+
+#. (itstool) path: option/_long
+msgid "Use GL_NEAREST instead of GL_LINEAR."
+msgstr "使用 GL_NEAREST 而不是 GL_LINEAR。"
+
+#. (itstool) path: option/_short
+msgid "Increment X"
+msgstr "X 增量"
+
+#. (itstool) path: option/_short
+msgid "Decrement X"
+msgstr "X 减量"
+
+#. (itstool) path: option/_short
+msgid "Increment Y"
+msgstr "Y 增量"
+
+#. (itstool) path: option/_short
+msgid "Decrement Y"
+msgstr "Y 减量"
diff --color -Naurp wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-workspace-names.po wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-workspace-names.po
--- wayfire-plugins-extra-0.10.0/locale/zh_CN/LC_MESSAGES/wf-plugin-workspace-names.po	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/locale/zh_CN/LC_MESSAGES/wf-plugin-workspace-names.po	2026-08-01 16:00:35.433292492 -0600
@@ -0,0 +1,144 @@
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"POT-Creation-Date: 2025-09-28 22:10-0600\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: \n"
+"Language-Team: \n"
+"Language: zh_CN \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. (itstool) path: plugin/_short
+#. (itstool) path: option/_short
+msgid "Workspace Names"
+msgstr "工作区名称"
+
+#. (itstool) path: plugin/_long
+msgid "Name workspaces."
+msgstr "为工作区命名。"
+
+#. (itstool) path: option/_short
+msgid "Display Duration"
+msgstr "显示持续时间"
+
+#. (itstool) path: option/_long
+msgid "How long the name is displayed."
+msgstr "名称的显示时长。"
+
+#. (itstool) path: option/_short
+msgid "Margin"
+msgstr "边距"
+
+#. (itstool) path: option/_long
+msgid "Distance from edge of screen to indicator."
+msgstr "指示器到屏幕边缘的距离。"
+
+#. (itstool) path: option/_short
+msgid "Position"
+msgstr "位置"
+
+#. (itstool) path: option/_long
+msgid "Position of rendering."
+msgstr "渲染位置。"
+
+#. (itstool) path: desc/_name
+msgid "Top Left"
+msgstr "左上"
+
+#. (itstool) path: desc/_name
+msgid "Top Center"
+msgstr "中上"
+
+#. (itstool) path: desc/_name
+msgid "Top Right"
+msgstr "右上"
+
+#. (itstool) path: desc/_name
+msgid "Center Left"
+msgstr "左中"
+
+#. (itstool) path: desc/_name
+msgid "Center"
+msgstr "居中"
+
+#. (itstool) path: desc/_name
+msgid "Center Right"
+msgstr "右中"
+
+#. (itstool) path: desc/_name
+msgid "Bottom Left"
+msgstr "左下"
+
+#. (itstool) path: desc/_name
+msgid "Bottom Center"
+msgstr "中下"
+
+#. (itstool) path: desc/_name
+msgid "Bottom Right"
+msgstr "右下"
+
+#. (itstool) path: option/_short
+msgid "Background Color"
+msgstr "背景颜色"
+
+#. (itstool) path: option/_long
+msgid "Background color for text."
+msgstr "文本的背景颜色。"
+
+#. (itstool) path: option/_short
+msgid "Text Color"
+msgstr "文本颜色"
+
+#. (itstool) path: option/_long
+msgid "Text color."
+msgstr "文本颜色。"
+
+#. (itstool) path: option/_short
+msgid "Text Font"
+msgstr "文本字体"
+
+#. (itstool) path: option/_long
+msgid "Font used for text rendering."
+msgstr "用于文本渲染的字体。"
+
+#. (itstool) path: option/_short
+msgid "Show Option Names"
+msgstr "显示选项名称"
+
+#. (itstool) path: option/_long
+msgid "Display option names on screen for convenience."
+msgstr "在屏幕上显示选项名称以方便使用。"
+
+#. (itstool) path: option/_short
+msgid "Show Option Values"
+msgstr "显示选项值"
+
+#. (itstool) path: option/_long
+msgid ""
+"Display option values instead of names, when show_option_names is enabled."
+msgstr "当启用显示选项名称时，显示选项值而不是名称。"
+
+#. (itstool) path: option/_short
+msgid "Background Corner Radius"
+msgstr "背景圆角半径"
+
+#. (itstool) path: option/_long
+msgid "Radius for the corners of the background."
+msgstr "背景圆角的半径。"
+
+#. (itstool) path: option/_long
+msgid ""
+"Names of the workspaces. By default, they will have the name Workspace #N, "
+"where #N is the workspace number."
+msgstr ""
+"工作区的名称。默认情况下，它们的名称为“工作区 #N”，其中 #N 是工作区编号。"
+
+#. (itstool) path: entry/_short
+msgid "Workspace Name"
+msgstr "工作区名称"
+
+#. (itstool) path: entry/_long
+msgid "Sets the name of the workspace"
+msgstr "设置工作区的名称"
diff --color -Naurp wayfire-plugins-extra-0.10.0/meson.build wayfire-plugins-extra/meson.build
--- wayfire-plugins-extra-0.10.0/meson.build	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/meson.build	2026-08-01 16:00:35.433292492 -0600
@@ -2,9 +2,9 @@ project(
 	'wayfire-plugins-extra',
 	'c',
 	'cpp',
-	version: '0.10.0',
+	version: '0.11.0',
 	license: 'MIT',
-	meson_version: '>=0.51.0',
+	meson_version: '>=0.59.0',
 	default_options: [
 		'cpp_std=c++17',
 		'c_std=c11',
@@ -13,7 +13,7 @@ project(
 	],
 )
 
-wayfire = dependency('wayfire', version: '>=0.9.0')
+wayfire = dependency('wayfire', version: '>=0.11.0')
 giomm = dependency('giomm-2.4', required: false)
 wayland_protos = dependency('wayland-protocols', version: '>=1.12')
 wayland_server = dependency('wayland-server')
@@ -43,6 +43,7 @@ add_project_arguments(['-Wno-unused-para
 subdir('proto')
 subdir('src')
 subdir('metadata')
+subdir('locale')
 
 summary = [
 	'',
diff --color -Naurp wayfire-plugins-extra-0.10.0/metadata/crosshair.xml wayfire-plugins-extra/metadata/crosshair.xml
--- wayfire-plugins-extra-0.10.0/metadata/crosshair.xml	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/metadata/crosshair.xml	2026-08-01 16:00:35.433615642 -0600
@@ -4,7 +4,7 @@
 		<_short>Crosshair</_short>
 		<_long>Render fullscreen mouse crosshair</_long>
 		<category>Utility</category>
-		<option name="line_width" type="int">
+		<option name="line_width" type="double">
 			<_short>Line Width</_short>
 			<_long>Line width of crosshair</_long>
 			<default>2</default>
diff --color -Naurp wayfire-plugins-extra-0.10.0/metadata/extra-animations.xml wayfire-plugins-extra/metadata/extra-animations.xml
--- wayfire-plugins-extra-0.10.0/metadata/extra-animations.xml	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/metadata/extra-animations.xml	2026-08-01 16:00:35.433615642 -0600
@@ -68,5 +68,140 @@
 				<min>1</min>
 			</option>
 		</group>
+		<group>
+			<_short>Burn Settings</_short>
+			<option name="burn_duration" type="animation">
+				<_short>Burn duration</_short>
+				<_long>Sets the duration for the burn animation in milliseconds.</_long>
+				<default>1000ms linear</default>
+			</option>
+			<option name="burn_flame_speed" type="double">
+				<_short>Burn flame speed</_short>
+				<_long>The speed at which the flames flicker.</_long>
+				<default>7</default>
+				<min>1</min>
+				<max>100</max>
+				<precision>1</precision>
+			</option>
+			<option name="burn_flame_width" type="double">
+				<_short>Burn flame width</_short>
+				<_long>The width of the flames.</_long>
+				<default>0.7</default>
+				<min>0.01</min>
+				<max>1.0</max>
+				<precision>0.01</precision>
+			</option>
+			<option name="burn_flame_height" type="double">
+				<_short>Burn flame height</_short>
+				<_long>The height of the flames.</_long>
+				<default>0.7</default>
+				<min>0.01</min>
+				<max>1.0</max>
+				<precision>0.01</precision>
+			</option>
+			<option name="burn_flame_smoothness" type="string">
+				<_short>Smoothness</_short>
+				<_long>How much dithering to use for the flames. Softest uses the least resources while Hard uses the most.</_long>
+				<default>normal</default>
+				<desc>
+					<value>softest</value>
+					<_name>Softest</_name>
+				</desc>
+				<desc>
+					<value>soft</value>
+					<_name>Soft</_name>
+				</desc>
+				<desc>
+					<value>normal</value>
+					<_name>Normal</_name>
+				</desc>
+				<desc>
+					<value>hard</value>
+					<_name>Hard</_name>
+				</desc>
+			</option>
+			<option name="burn_flame_color" type="color">
+				<_short>Flame Color</_short>
+				<_long>Color used for rendering the flames.</_long>
+				<default>1.00 0.33 0.16 1.00</default>
+			</option>
+		</group>
+		<group>
+			<_short>Magic Carpet Settings</_short>
+			<option name="carpet_roll_duration" type="animation">
+				<_short>Roll Duration</_short>
+				<_long>Sets the duration for the magic carpet animation in milliseconds.</_long>
+				<default>1000ms linear</default>
+			</option>
+			<option name="carpet_roll_direction" type="int">
+				<_short>Roll Direction</_short>
+				<_long>Choose from where the window unrolls for open animation. Left, right, top and bottom unroll from the selected edge. Horizontal and vertical scroll unrolls from the middle, much like an ancient scroll.</_long>
+				<default>0</default>
+				<desc>
+					<value>0</value>
+					<_name>Left</_name>
+				</desc>
+				<desc>
+					<value>1</value>
+					<_name>Right</_name>
+				</desc>
+				<desc>
+					<value>2</value>
+					<_name>Top</_name>
+				</desc>
+				<desc>
+					<value>3</value>
+					<_name>Bottom</_name>
+				</desc>
+				<desc>
+					<value>4</value>
+					<_name>Horizontal Scroll</_name>
+				</desc>
+				<desc>
+					<value>5</value>
+					<_name>Vertical Scroll</_name>
+				</desc>
+			</option>
+		</group>
+		<group>
+			<_short>Dodge Settings</_short>
+			<option name="dodge_toggle" type="bool">
+				<_short>Enable Dodge</_short>
+				<_long>Enables the Dodge focus animation.</_long>
+				<default>false</default>
+			</option>
+			<option name="dodge_duration" type="animation">
+				<_short>Duration</_short>
+				<_long>Sets the animation duration in milliseconds.</_long>
+				<default>350ms linear</default>
+			</option>
+			<option name="dodge_rotate" type="bool">
+				<_short>Rotate</_short>
+				<_long>Rotate windows during animation.</_long>
+				<default>false</default>
+			</option>
+			<option name="dodge_zoom" type="bool">
+				<_short>Zoom</_short>
+				<_long>Slightly increase zoom for the focusing window during animation.</_long>
+				<default>true</default>
+			</option>
+			<option name="dodge_direction" type="string">
+				<_short>Animation Direction</_short>
+				<_long>Sets the animation direction.</_long>
+				<desc>
+					<value>cardinal</value>
+					<_name>Cardinal</_name>
+				</desc>
+				<desc>
+					<value>diagonal</value>
+					<_name>Diagonal</_name>
+				</desc>
+				<desc>
+					<value>circular</value>
+					<_name>Circular</_name>
+				</desc>
+				<default>cardinal</default>
+			</option>
+		</group>
 	</plugin>
 </wayfire>
diff --color -Naurp wayfire-plugins-extra-0.10.0/metadata/fisheye.xml wayfire-plugins-extra/metadata/fisheye.xml
--- wayfire-plugins-extra-0.10.0/metadata/fisheye.xml	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/metadata/fisheye.xml	2026-08-01 16:00:35.433615642 -0600
@@ -0,0 +1,27 @@
+<?xml version="1.0"?>
+<wayfire>
+	<plugin name="fisheye">
+		<_short>Fisheye</_short>
+		<_long>A plugin which provides fisheye effect.</_long>
+		<category>Effects</category>
+		<option name="toggle" type="activator">
+			<_short>Toggle</_short>
+			<_long>Toggles fisheye with the specified activator.</_long>
+			<default>&lt;super&gt; &lt;ctrl&gt; KEY_F</default>
+		</option>
+		<option name="radius" type="double">
+			<_short>Radius</_short>
+			<_long>Sets the border radius in pixels.</_long>
+			<default>450.0</default>
+			<min>1.0</min>
+		</option>
+		<option name="zoom" type="double">
+			<_short>Zoom</_short>
+			<_long>Sets the zoom factor.</_long>
+			<default>7.0</default>
+			<min>1.0</min>
+			<max>20.0</max>
+			<precision>0.01</precision>
+		</option>
+	</plugin>
+</wayfire>
diff --color -Naurp wayfire-plugins-extra-0.10.0/metadata/meson.build wayfire-plugins-extra/metadata/meson.build
--- wayfire-plugins-extra-0.10.0/metadata/meson.build	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/metadata/meson.build	2026-08-01 16:00:35.433615642 -0600
@@ -3,6 +3,7 @@ install_data('autorotate-iio.xml', insta
 install_data('bench.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
 install_data('crosshair.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
 install_data('extra-animations.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
+install_data('fisheye.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
 install_data('focus-change.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
 install_data('focus-steal-prevent.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
 install_data('follow-focus.xml', install_dir: wayfire.get_variable(pkgconfig: 'metadatadir'))
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/annotate.cpp wayfire-plugins-extra/src/annotate.cpp
--- wayfire-plugins-extra-0.10.0/src/annotate.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/annotate.cpp	2026-08-01 16:00:35.433615642 -0600
@@ -80,26 +80,23 @@ class simple_node_render_instance_t : pu
     node_t *self;
     damage_callback push_to_parent;
     std::shared_ptr<anno_ws_overlay> overlay, shape_overlay;
-    int *x, *y, *w, *h;
+    wf::geometry_t *geometry;
 
   public:
     simple_node_render_instance_t(node_t *self, damage_callback push_dmg,
-        int *x, int *y, int *w, int *h, std::shared_ptr<anno_ws_overlay> overlay,
+        wf::geometry_t *geometry, std::shared_ptr<anno_ws_overlay> overlay,
         std::shared_ptr<anno_ws_overlay> shape_overlay)
     {
-        this->x    = x;
-        this->y    = y;
-        this->w    = w;
-        this->h    = h;
-        this->self = self;
-        this->overlay = overlay;
+        this->geometry = geometry;
+        this->self     = self;
+        this->overlay  = overlay;
         this->shape_overlay  = shape_overlay;
         this->push_to_parent = push_dmg;
         self->connect(&on_node_damaged);
     }
 
     void schedule_instructions(std::vector<render_instruction_t>& instructions,
-        const wf::render_target_t& target, wf::region_t& damage) override
+        const wf::render_target_t& target, wf::regionf_t& damage) override
     {
         // We want to render ourselves only, the node does not have children
         instructions.push_back(render_instruction_t{
@@ -111,15 +108,15 @@ class simple_node_render_instance_t : pu
 
     void render(const wf::scene::render_instruction_t& data) override
     {
-        auto ol    = this->overlay;
-        wlr_box og = {*x, *y, *w, *h};
+        auto ol = this->overlay;
+        wf::geometry_t og = *geometry;
 
         data.pass->custom_gles_subpass([&]
         {
             wf::gles::bind_render_buffer(data.target);
             for (auto& box : data.damage)
             {
-                wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
+                wf::gles::render_target_logic_scissor(data.target, box);
                 if (ol->cr)
                 {
                     OpenGL::render_texture(wf::gles_texture_t{ol->texture->tex}, data.target, og,
@@ -139,16 +136,16 @@ class simple_node_render_instance_t : pu
 
 class simple_node_t : public node_t
 {
-    int x, y, w, h;
+    wf::geometry_t geometry;
 
   public:
     std::shared_ptr<anno_ws_overlay> overlay, shape_overlay;
     simple_node_t(int x, int y, int w, int h) : node_t(false)
     {
-        this->x = x;
-        this->y = y;
-        this->w = w;
-        this->h = h;
+        this->geometry.x     = x;
+        this->geometry.y     = y;
+        this->geometry.width = w;
+        this->geometry.height = h;
         overlay = std::make_shared<anno_ws_overlay>();
         shape_overlay = std::make_shared<anno_ws_overlay>();
     }
@@ -161,10 +158,10 @@ class simple_node_t : public node_t
         // this simple nodes does not need any transformations, so the push_damage
         // callback is just passed along.
         instances.push_back(std::make_unique<simple_node_render_instance_t>(
-            this, push_damage, &x, &y, &w, &h, overlay, shape_overlay));
+            this, push_damage, &geometry, overlay, shape_overlay));
     }
 
-    void do_push_damage(wf::region_t updated_region)
+    void do_push_damage(wf::regionf_t updated_region)
     {
         node_damage_signal ev;
         ev.region = updated_region;
@@ -174,19 +171,19 @@ class simple_node_t : public node_t
     wf::geometry_t get_bounding_box() override
     {
         // Specify whatever geometry your node has
-        return {x, y, w, h};
+        return geometry;
     }
 
     void set_position(int x, int y)
     {
-        this->x = x;
-        this->y = y;
+        this->geometry.x = x;
+        this->geometry.y = y;
     }
 
     void set_size(int w, int h)
     {
-        this->w = w;
-        this->h = h;
+        this->geometry.width  = w;
+        this->geometry.height = h;
     }
 };
 
@@ -201,7 +198,7 @@ std::shared_ptr<simple_node_t> add_simpl
 class wayfire_annotate_screen : public wf::per_output_plugin_instance_t, public wf::pointer_interaction_t
 {
     uint32_t button;
-    wlr_box last_bbox;
+    wf::geometry_t last_bbox;
     annotate_draw_method draw_method;
     wf::pointf_t grab_point, last_cursor;
     std::vector<std::vector<std::shared_ptr<simple_node_t>>> overlays;
@@ -519,15 +516,15 @@ class wayfire_annotate_screen : public w
         cairo_line_to(cr, to.x, to.y);
         cairo_stroke(cr);
 
-        wlr_box bbox;
+        wf::geometry_t bbox;
         int padding = line_width + 1;
         bbox.x     = std::min(from.x, to.x) - padding;
         bbox.y     = std::min(from.y, to.y) - padding;
-        bbox.width = abs(from.x - to.x) + padding * 2;
-        bbox.height = abs(from.y - to.y) + padding * 2;
-        get_node_overlay()->do_push_damage(wf::region_t(bbox));
+        bbox.width = std::abs(from.x - to.x) + padding * 2;
+        bbox.height = std::abs(from.y - to.y) + padding * 2;
+        get_node_overlay()->do_push_damage(wf::regionf_t(bbox));
         cairo_surface_upload_to_texture_with_damage(ol->cairo_surface, *ol->texture,
-            bbox);
+            wf::to_integer_box(bbox));
     }
 
     bool should_damage_last()
@@ -563,14 +560,14 @@ class wayfire_annotate_screen : public w
         cairo_line_to(cr, to.x, to.y);
         cairo_stroke(cr);
 
-        wlr_box bbox;
+        wf::geometry_t bbox;
         int padding = line_width + 1;
         bbox.x     = std::min(from.x, to.x) - padding;
         bbox.y     = std::min(from.y, to.y) - padding;
-        bbox.width = abs(from.x - to.x) + padding * 2;
-        bbox.height = abs(from.y - to.y) + padding * 2;
+        bbox.width = std::abs(from.x - to.x) + padding * 2;
+        bbox.height = std::abs(from.y - to.y) + padding * 2;
         output->render->damage(bbox);
-        wf::region_t damage_region{bbox};
+        wf::regionf_t damage_region{bbox};
         if (damage_last_bbox)
         {
             output->render->damage(last_bbox);
@@ -579,14 +576,14 @@ class wayfire_annotate_screen : public w
 
         damage_region &= output->get_relative_geometry();
         auto damage_extents = damage_region.get_extents();
-        wlr_box damage_box  =
+        auto damage_box     = wf::to_integer_box(wf::geometry_t
         {damage_extents.x1, damage_extents.y1, damage_extents.x2 - damage_extents.x1,
-            damage_extents.y2 - damage_extents.y1};
+            damage_extents.y2 - damage_extents.y1});
         cairo_surface_upload_to_texture_with_damage(ol->cairo_surface, *ol->texture,
             damage_box);
 
-        get_node_overlay()->do_push_damage(wf::region_t(last_bbox));
-        get_node_overlay()->do_push_damage(wf::region_t(bbox));
+        get_node_overlay()->do_push_damage(wf::regionf_t(last_bbox));
+        get_node_overlay()->do_push_damage(wf::regionf_t(bbox));
         last_bbox = bbox;
     }
 
@@ -632,14 +629,14 @@ class wayfire_annotate_screen : public w
         cairo_rectangle(cr, x, y, w, h);
         cairo_stroke(cr);
 
-        wlr_box bbox;
+        wf::geometry_t bbox;
         int padding = line_width + 1;
         bbox.x     = x - padding;
         bbox.y     = y - padding;
         bbox.width = w + padding * 2;
         bbox.height = h + padding * 2;
         output->render->damage(bbox);
-        wf::region_t damage_region{bbox};
+        wf::regionf_t damage_region{bbox};
         if (damage_last_bbox)
         {
             output->render->damage(last_bbox);
@@ -648,14 +645,14 @@ class wayfire_annotate_screen : public w
 
         damage_region &= output->get_relative_geometry();
         auto damage_extents = damage_region.get_extents();
-        wlr_box damage_box  =
+        auto damage_box     = wf::to_integer_box(wf::geometry_t
         {damage_extents.x1, damage_extents.y1, damage_extents.x2 - damage_extents.x1,
-            damage_extents.y2 - damage_extents.y1};
+            damage_extents.y2 - damage_extents.y1});
         cairo_surface_upload_to_texture_with_damage(ol->cairo_surface, *ol->texture,
             damage_box);
 
-        get_node_overlay()->do_push_damage(wf::region_t(last_bbox));
-        get_node_overlay()->do_push_damage(wf::region_t(bbox));
+        get_node_overlay()->do_push_damage(wf::regionf_t(last_bbox));
+        get_node_overlay()->do_push_damage(wf::regionf_t(bbox));
         last_bbox = bbox;
     }
 
@@ -695,14 +692,14 @@ class wayfire_annotate_screen : public w
         cairo_arc(cr, from.x, from.y, radius, 0, 2 * M_PI);
         cairo_stroke(cr);
 
-        wlr_box bbox;
+        wf::geometry_t bbox;
         int padding = line_width + 1;
         bbox.x     = (from.x - radius) - padding;
         bbox.y     = (from.y - radius) - padding;
         bbox.width = (radius * 2) + padding * 2;
         bbox.height = (radius * 2) + padding * 2;
         output->render->damage(bbox);
-        wf::region_t damage_region{bbox};
+        wf::regionf_t damage_region{bbox};
         if (damage_last_bbox)
         {
             output->render->damage(last_bbox);
@@ -711,14 +708,14 @@ class wayfire_annotate_screen : public w
 
         damage_region &= output->get_relative_geometry();
         auto damage_extents = damage_region.get_extents();
-        wlr_box damage_box  =
+        auto damage_box     = wf::to_integer_box(wf::geometry_t
         {damage_extents.x1, damage_extents.y1, damage_extents.x2 - damage_extents.x1,
-            damage_extents.y2 - damage_extents.y1};
+            damage_extents.y2 - damage_extents.y1});
         cairo_surface_upload_to_texture_with_damage(ol->cairo_surface, *ol->texture,
             damage_box);
 
-        get_node_overlay()->do_push_damage(wf::region_t(last_bbox));
-        get_node_overlay()->do_push_damage(wf::region_t(bbox));
+        get_node_overlay()->do_push_damage(wf::regionf_t(last_bbox));
+        get_node_overlay()->do_push_damage(wf::regionf_t(bbox));
         last_bbox = bbox;
     }
 
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/autorotate-iio.cpp wayfire-plugins-extra/src/autorotate-iio.cpp
--- wayfire-plugins-extra-0.10.0/src/autorotate-iio.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/autorotate-iio.cpp	2026-08-01 16:00:35.433998821 -0600
@@ -22,6 +22,7 @@ extern "C"
 {
 #include <wlr/types/wlr_cursor.h>
 #include <wlr/types/wlr_seat.h>
+#include <wayland-server-core.h>
 }
 
 using namespace Gio;
@@ -105,6 +106,12 @@ class WayfireAutorotateIIO : public wf::
     /* Transform coming from the iio-sensors, -1 means not set */
     int32_t sensor_transform = -1;
 
+    /* Debounce: pending transform waiting to be confirmed stable */
+    int32_t pending_transform = -1;
+    guint debounce_timer_id   = 0;
+    static constexpr guint DEBOUNCE_ROTATE_MS = 500;
+    static constexpr guint DEBOUNCE_NORMAL_MS = 1200;
+
     bool on_rotate_binding(int32_t target_rotation)
     {
         if (!output->can_activate_plugin(&grab_interface))
@@ -154,10 +161,18 @@ class WayfireAutorotateIIO : public wf::
         return true;
     }
 
-    wf::effect_hook_t on_frame = [=] ()
+    /* Wayland event loop timer — fires every 50ms to pump the GLib main context
+     * even when the display is idle and on_frame would not run. */
+    wl_event_source *glib_timer = nullptr;
+
+    static int glib_timer_cb(void *data)
     {
+        auto *self = static_cast<WayfireAutorotateIIO*>(data);
         Glib::MainContext::get_default()->iteration(false);
-    };
+        wl_event_source_timer_update(self->glib_timer, 50);
+        return 0;
+    }
+
     Glib::RefPtr<Glib::MainLoop> loop;
 
   public:
@@ -185,7 +200,10 @@ class WayfireAutorotateIIO : public wf::
         Gio::init();
 
         loop = Glib::MainLoop::create(true);
-        output->render->add_effect(&on_frame, wf::OUTPUT_EFFECT_PRE);
+
+        auto *evloop = wl_display_get_event_loop(wf::get_core().display);
+        glib_timer = wl_event_loop_add_timer(evloop, glib_timer_cb, this);
+        wl_event_source_timer_update(glib_timer, 50);
 
         watch_id = DBus::watch_name(DBus::BUS_TYPE_SYSTEM, "net.hadess.SensorProxy",
             sigc::mem_fun(this, &WayfireAutorotateIIO::on_iio_appeared),
@@ -210,6 +228,7 @@ class WayfireAutorotateIIO : public wf::
         iio_proxy->signal_properties_changed().connect_notify(
             sigc::mem_fun(this, &WayfireAutorotateIIO::on_properties_changed));
         iio_proxy->call_sync("ClaimAccelerometer");
+        update_orientation();
     }
 
     void on_properties_changed(
@@ -228,6 +247,11 @@ class WayfireAutorotateIIO : public wf::
 
         Glib::Variant<Glib::ustring> orientation;
         iio_proxy->get_cached_property(orientation, "AccelerometerOrientation");
+        if (!orientation)
+        {
+            return;
+        }
+
         LOGI("IIO Accelerometer orientation: %s", orientation.get().c_str());
 
         static const std::map<std::string, wl_output_transform> transform_by_name =
@@ -238,10 +262,55 @@ class WayfireAutorotateIIO : public wf::
             {"bottom-up", WL_OUTPUT_TRANSFORM_180},
         };
 
-        if (transform_by_name.count(orientation.get()))
+        if (!transform_by_name.count(orientation.get()))
         {
-            sensor_transform = transform_by_name.find(orientation.get())->second;
-            update_transform();
+            return;
+        }
+
+        int32_t new_transform = transform_by_name.find(orientation.get())->second;
+
+        bool timer_running  = (debounce_timer_id != 0);
+        bool new_is_normal  = (new_transform == WL_OUTPUT_TRANSFORM_NORMAL);
+        bool pend_is_normal = (pending_transform == WL_OUTPUT_TRANSFORM_NORMAL);
+
+        if (!timer_running)
+        {
+            if (new_transform == sensor_transform)
+            {
+                return;
+            }
+
+            pending_transform = new_transform;
+            guint delay = new_is_normal ? DEBOUNCE_NORMAL_MS : DEBOUNCE_ROTATE_MS;
+            debounce_timer_id = g_timeout_add(delay, [] (gpointer data) -> gboolean
+            {
+                auto *self = static_cast<WayfireAutorotateIIO*>(data);
+                self->debounce_timer_id = 0;
+                self->sensor_transform  = self->pending_transform;
+                self->update_transform();
+                return G_SOURCE_REMOVE;
+            }, this);
+        } else if (!pend_is_normal)
+        {
+            if (!new_is_normal)
+            {
+                pending_transform = new_transform;
+            }
+        } else
+        {
+            if (!new_is_normal)
+            {
+                g_source_remove(debounce_timer_id);
+                pending_transform = new_transform;
+                debounce_timer_id = g_timeout_add(DEBOUNCE_ROTATE_MS, [] (gpointer data) -> gboolean
+                {
+                    auto *self = static_cast<WayfireAutorotateIIO*>(data);
+                    self->debounce_timer_id = 0;
+                    self->sensor_transform  = self->pending_transform;
+                    self->update_transform();
+                    return G_SOURCE_REMOVE;
+                }, this);
+            }
         }
     }
 
@@ -259,13 +328,20 @@ class WayfireAutorotateIIO : public wf::
         output->rem_binding(&on_rotate_up);
         output->rem_binding(&on_rotate_down);
 
+        if (debounce_timer_id)
+        {
+            g_source_remove(debounce_timer_id);
+            debounce_timer_id = 0;
+        }
+
         /* If loop is NULL, autorotate was disabled for the current output */
         if (loop)
         {
             iio_proxy.reset();
             DBus::unwatch_name(watch_id);
             loop->quit();
-            output->render->rem_effect(&on_frame);
+            wl_event_source_remove(glib_timer);
+            glib_timer = nullptr;
         }
     }
 };
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/crosshair.cpp wayfire-plugins-extra/src/crosshair.cpp
--- wayfire-plugins-extra-0.10.0/src/crosshair.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/crosshair.cpp	2026-08-01 16:00:35.433998821 -0600
@@ -31,7 +31,7 @@
 
 class wayfire_crosshair : public wf::per_output_plugin_instance_t
 {
-    wf::option_wrapper_t<int> line_width{"crosshair/line_width"};
+    wf::option_wrapper_t<double> line_width{"crosshair/line_width"};
     wf::option_wrapper_t<wf::color_t> line_color{"crosshair/line_color"};
     wf::geometry_t geometry[2];
 
@@ -56,9 +56,9 @@ class wayfire_crosshair : public wf::per
         output->render->damage(geometry[1]);
 
         geometry[0] =
-            wf::geometry_t{int(oc.x - half_width), 0, line_width, og.height};
+            wf::geometry_t{oc.x - half_width, 0, line_width, og.height};
         geometry[1] =
-            wf::geometry_t{0, int(oc.y - half_width), og.width, line_width};
+            wf::geometry_t{0, oc.y - half_width, og.width, line_width};
 
         output->render->damage(geometry[0]);
         output->render->damage(geometry[1]);
@@ -68,17 +68,17 @@ class wayfire_crosshair : public wf::per
     {
         auto target_fb = output->render->get_target_framebuffer();
         auto gc = wf::get_core().get_cursor_position();
-        wf::point_t coords{(int)gc.x, (int)gc.y};
+        wf::pointf_t coords{gc.x, gc.y};
 
         if (!(output->get_layout_geometry() & coords))
         {
             return;
         }
 
-        wf::region_t region;
+        wf::regionf_t region;
         region |= geometry[0];
         region |= geometry[1];
-        region &= output->render->get_swap_damage();
+        region &= target_fb.geometry_region_from_framebuffer_region(output->render->get_swap_damage());
 
         auto alpha = wf::color_t(line_color).a;
         wf::color_t color = wf::color_t{
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/blinds.hpp wayfire-plugins-extra/src/extra-animations/blinds.hpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/blinds.hpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/extra-animations/blinds.hpp	2026-08-01 16:00:35.433998821 -0600
@@ -82,14 +82,8 @@ using namespace wf::animation;
 
 static std::string blinds_transformer_name = "animation-blinds";
 
-wf::option_wrapper_t<wf::animation_description_t> blinds_duration{"extra-animations/blinds_duration"};
 wf::option_wrapper_t<int> blinds_strip_height{"extra-animations/blinds_strip_height"};
 
-class blinds_animation_t : public duration_t
-{
-  public:
-    using duration_t::duration_t;
-};
 class blinds_transformer : public wf::scene::view_2d_transformer_t
 {
   public:
@@ -97,7 +91,7 @@ class blinds_transformer : public wf::sc
     OpenGL::program_t program;
     wf::output_t *output;
     wf::geometry_t animation_geometry;
-    blinds_animation_t progression{blinds_duration};
+    duration_t progression;
 
     class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t<transformer_base_node_t>
     {
@@ -128,7 +122,7 @@ class blinds_transformer : public wf::sc
 
         void schedule_instructions(
             std::vector<render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage) override
+            const wf::render_target_t& target, wf::regionf_t& damage) override
         {
             instructions.push_back(render_instruction_t{
                         .instance = this,
@@ -137,9 +131,9 @@ class blinds_transformer : public wf::sc
                     });
         }
 
-        void transform_damage_region(wf::region_t& damage) override
+        void transform_damage_region(wf::regionf_t& damage) override
         {
-            damage |= wf::region_t{self->animation_geometry};
+            damage |= self->animation_geometry;
         }
 
         void render(const wf::scene::render_instruction_t& data) override
@@ -163,17 +157,17 @@ class blinds_transformer : public wf::sc
                     auto y     = src_box.height - i;
                     auto inv_h = 1.0 / src_box.height;
                     uv.push_back(1.0);
-                    uv.push_back(std::max(0, y - line_height) * inv_h);
+                    uv.push_back(std::max(0.0, y - line_height) * inv_h);
                     uv.push_back(0.0);
-                    uv.push_back(std::max(0, y - line_height) * inv_h);
+                    uv.push_back(std::max(0.0, y - line_height) * inv_h);
                     uv.push_back(0.0);
                     uv.push_back(y * inv_h);
                     uv.push_back(1.0);
                     uv.push_back(y * inv_h);
                     auto x1 = src_box.width / 2.0;
                     auto x2 = -(src_box.width / 2.0);
-                    auto y1 = -(std::min(src_box.height - i, line_height) / 2.0);
-                    auto y2 = std::min(src_box.height - i, line_height) / 2.0;
+                    auto y1 = -(std::min(src_box.height - i, (double)line_height) / 2.0);
+                    auto y2 = std::min(src_box.height - i, (double)line_height) / 2.0;
                     glm::vec4 v, r;
                     glm::mat4 m(1.0);
                     m =
@@ -208,13 +202,14 @@ class blinds_transformer : public wf::sc
 
                     glm::mat4 p = glm::perspective(float(M_PI / 64.0), 1.0f, 0.1f, 100.0f);
                     glm::mat4 l = glm::lookAt(
-                        glm::vec3(0., 0., 1.0 / std::tan(float(M_PI / 64.0) / 2)),
+                        glm::vec3(0., 0., -1.0 / std::tan(float(M_PI / 64.0) / 2)),
                         glm::vec3(0., 0., 0.),
-                        glm::vec3(0., 1., 0.));
+                        glm::vec3(0., -1., 0.));
 
                     auto transform = p * l;
                     wf::auxilliary_buffer_t slice_buffer;
-                    slice_buffer.allocate({src_box.width + line_height * 2, static_cast<int32_t>(y2 - y1)});
+                    slice_buffer.allocate({static_cast<int32_t>(std::ceil(src_box.width + line_height * 2)),
+                        static_cast<int32_t>(std::ceil(y2 - y1))});
                     wf::gles::bind_render_buffer(slice_buffer.get_renderbuffer());
                     OpenGL::clear(wf::color_t{0.0, 0.0, 0.0, 0.0}, GL_COLOR_BUFFER_BIT);
                     self->program.use(wf::TEXTURE_TYPE_RGBA);
@@ -227,16 +222,17 @@ class blinds_transformer : public wf::sc
                     wf::gles_texture_t slice_tex{slice_buffer.get_texture()};
 
                     wf::gles::bind_render_buffer(data.target);
-                    for (auto box : data.damage)
-                    {
-                        wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
-                        OpenGL::render_transformed_texture(slice_tex,
-                            gl_geometry{float(src_box.x - line_height),
-                                float(src_box.y + i),
-                                float((src_box.x - line_height) + src_box.width + line_height * 2.0),
-                                float((src_box.y + i) + (y2 - y1))}, {},
-                            wf::gles::render_target_orthographic_projection(data.target), glm::vec4(1.0), 0);
-                    }
+                    /* XXX: Scissoring wrong boxes here makes only top part of effect work */
+                    // for (auto box : data.damage)
+                    // {
+                    // wf::gles::render_target_logic_scissor(data.target, box);
+                    OpenGL::render_transformed_texture(slice_tex,
+                        gl_geometry{float(src_box.x - line_height),
+                            float(src_box.y + i),
+                            float((src_box.x - line_height) + src_box.width + line_height * 2.0),
+                            float((src_box.y + i) + (y2 - y1))}, {},
+                        wf::gles::render_target_orthographic_projection(data.target), glm::vec4(1.0), 0);
+                    // }
 
                     slice_buffer.free();
                 }
@@ -244,9 +240,12 @@ class blinds_transformer : public wf::sc
         }
     };
 
-    blinds_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view)
+    blinds_transformer(wayfire_view view, wf::geometry_t bbox, wf::animation_description_t duration) :
+        wf::scene::view_2d_transformer_t(view)
     {
         this->view = view;
+        duration_t d;
+        this->progression = duration_t{wf::create_option(duration)};
         if (view->get_output())
         {
             output = view->get_output();
@@ -263,11 +262,6 @@ class blinds_transformer : public wf::sc
         });
     }
 
-    wf::geometry_t get_bounding_box() override
-    {
-        return this->animation_geometry;
-    }
-
     wf::effect_hook_t pre_hook = [=] ()
     {
         output->render->damage(animation_geometry);
@@ -316,7 +310,7 @@ class blinds_animation : public animatio
         pop_transformer(view);
         auto bbox = view->get_transformed_node()->get_bounding_box();
         auto tmgr = view->get_transformed_node();
-        auto node = std::make_shared<wf::blinds::blinds_transformer>(view, bbox);
+        auto node = std::make_shared<wf::blinds::blinds_transformer>(view, bbox, dur);
         tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, blinds_transformer_name);
         node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION);
     }
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/burn.hpp wayfire-plugins-extra/src/extra-animations/burn.hpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/burn.hpp	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/src/extra-animations/burn.hpp	2026-08-01 16:00:35.434368211 -0600
@@ -0,0 +1,451 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Scott Moreau <oreaus@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <wayfire/core.hpp>
+#include <wayfire/opengl.hpp>
+#include <wayfire/view-transform.hpp>
+#include <wayfire/util/duration.hpp>
+#include <wayfire/plugins/animate/animate.hpp>
+
+
+static const char *burn_vert_source =
+    R"(
+#version 100
+
+attribute highp vec2 position;
+attribute highp vec2 uv_in;
+
+varying highp vec2 uvpos;
+
+void main() {
+
+    gl_Position = vec4(position.xy, 0.0, 1.0);
+    uvpos = uv_in;
+}
+)";
+
+static const char *burn_frag_source =
+    R"(
+#version 100
+@builtin_ext@
+@builtin@
+
+precision highp float;
+
+varying highp vec2 uvpos;
+uniform vec2 size;
+uniform float progress;
+uniform int direction;
+uniform float flame_speed;
+uniform float flame_width;
+uniform float flame_height;
+uniform int flame_smooth_1;
+uniform int flame_smooth_2;
+uniform int flame_smooth_3;
+uniform int flame_smooth_4;
+uniform vec4 flame_color;
+
+// procedural noise from IQ
+vec2 hash( vec2 p )
+{
+    p = vec2(dot(p,vec2(127.1,311.7)),
+             dot(p,vec2(269.5,183.3)));
+    return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
+}
+
+float noise( in vec2 p )
+{
+    const float K1 = 0.366025404; // (sqrt(3) - 1) / 2;
+    const float K2 = 0.211324865; // (3 - sqrt(3)) / 6;
+
+    vec2 i = floor( p + (p.x + p.y) * K1 );
+
+    vec2 a = p - i + (i.x + i.y) * K2;
+    vec2 o = (a.x > a.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
+    vec2 b = a - o + K2;
+    vec2 c = a - 1.0 + 2.0 * K2;
+
+    vec3 h = max(0.5 - vec3(dot(a, a), dot(b, b), dot(c, c) ), 0.0);
+
+    vec3 n = h * h * h * h * vec3(dot(a, hash(i)), dot(b, hash(i + o)), dot(c, hash(i + 1.0)));
+
+    return dot(n, vec3(70.0));
+}
+
+float fbm(vec2 uv)
+{
+    float f;
+    mat2 m = mat2(1.7,  1.2, -1.2,  1.7);
+    f  = 0.5000 * noise( uv ); uv = m * uv;
+    if (flame_smooth_1 == 1)
+    {
+        f += 0.2500 * noise( uv ); uv = m * uv;
+    }
+    if (flame_smooth_2 == 1)
+    {
+        f += 0.1250 * noise( uv ); uv = m * uv;
+    }
+    if (flame_smooth_3 == 1)
+    {
+        f += 0.0625 * noise( uv ); uv = m * uv;
+    }
+    if (flame_smooth_4 == 1)
+    {
+        f += 0.0125 * noise( uv ); uv = m * uv;
+    }
+    return 0.5 + 0.3 * f;
+}
+
+void main()
+{
+    float width = size.x;
+    float height = size.y;
+    vec2 uv = vec2(uvpos.x * width * 0.02, (uvpos.y - progress) * height * 0.002);
+    vec2 q = vec2(uv.x, uv.y);
+    q.x *= (1.05 - flame_width) * 3.0;
+    q.y *= pow(0.4 / ((flame_height * 0.3) + 0.1), clamp(uvpos.y + 0.2 - progress, 0.1, 0.7) * 20.0);
+    float burn_progress = progress;
+    if (direction == 1)
+    {
+        burn_progress = 1.0 - burn_progress;
+    }
+    float T3 = burn_progress * flame_speed;
+    q.x -= 0.2;
+    q.y -= 0.1;
+    float n = fbm(q - vec2(0, T3));
+    float c = 1.0 - 12.0 * pow(max(0., length(vec2(q.x * 0.0001, q.y) * vec2(1.8 + q.y * 1.5, 0.75) ) - n * max(0.0, q.y + 0.25)), 1.2);
+    float c1 = n * c * (1.5 - pow(1.25 * uv.y, 4.0));
+    c = clamp(c, 0.0, 1.0);
+    c1 = clamp(c1, 0.0, 1.0);
+
+    float r = 1.0 / flame_color.r;
+    float g = 1.0 / flame_color.g;
+    float b = 1.0 / flame_color.b;
+
+    vec3 col = vec3(1.5 * pow(c1, r), 1.5 * pow(c1, g), 1.5 * pow(c1, b));
+
+    float a = clamp(c * (1.0 - pow(uvpos.y, 10.0)), 0.0, 1.0);
+    vec4 wfrag = get_pixel(uvpos);
+    if (uvpos.x < 0.0 || uvpos.x > 1.0 ||
+        uvpos.y < 0.0 || uvpos.y > 1.0 ||
+        uvpos.y < progress)
+    {
+        wfrag = vec4(0.0);
+    }
+    a *= clamp(progress * 10.0, 0.0, 1.0);
+    a *= 1.0 - pow(clamp(-uvpos.x * (width * 0.05), 0.0, 1.0), 0.7);
+    a *= 1.0 - pow(clamp((1.0 - (2.0 - uvpos.x)) * (width * 0.05), 0.0, 1.0), 0.7);
+    vec4 color = vec4(col * a, a);
+    gl_FragColor = color + wfrag * (1.0 - a);
+}
+)";
+
+namespace wf
+{
+namespace burn
+{
+using namespace wf::scene;
+using namespace wf::animate;
+using namespace wf::animation;
+
+static std::string burn_transformer_name = "animation-burn";
+
+wf::option_wrapper_t<double> burn_flame_speed{"extra-animations/burn_flame_speed"};
+wf::option_wrapper_t<double> burn_flame_width{"extra-animations/burn_flame_width"};
+wf::option_wrapper_t<double> burn_flame_height{"extra-animations/burn_flame_height"};
+wf::option_wrapper_t<wf::color_t> burn_flame_color{"extra-animations/burn_flame_color"};
+wf::option_wrapper_t<std::string> burn_flame_smoothness{"extra-animations/burn_flame_smoothness"};
+
+class burn_transformer : public wf::scene::view_2d_transformer_t
+{
+  public:
+    wayfire_view view;
+    wf::output_t *output;
+    OpenGL::program_t program;
+    wf::auxilliary_buffer_t buffer;
+    duration_t progression;
+
+    class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t<transformer_base_node_t>
+    {
+        wf::signal::connection_t<node_damage_signal> on_node_damaged =
+            [=] (node_damage_signal *ev)
+        {
+            push_to_parent(ev->region);
+        };
+
+        burn_transformer *self;
+        wayfire_view view;
+        damage_callback push_to_parent;
+
+      public:
+        simple_node_render_instance_t(burn_transformer *self, damage_callback push_damage,
+            wayfire_view view) : wf::scene::transformer_render_instance_t<transformer_base_node_t>(self,
+                push_damage,
+                view->get_output())
+        {
+            this->self = self;
+            this->view = view;
+            this->push_to_parent = push_damage;
+            self->connect(&on_node_damaged);
+        }
+
+        ~simple_node_render_instance_t()
+        {}
+
+        void schedule_instructions(
+            std::vector<render_instruction_t>& instructions,
+            const wf::render_target_t& target, wf::regionf_t& damage) override
+        {
+            instructions.push_back(render_instruction_t{
+                        .instance = this,
+                        .target   = target,
+                        .damage   = damage & self->get_bounding_box(),
+                    });
+        }
+
+        void transform_damage_region(wf::regionf_t& damage) override
+        {
+            damage |= self->get_bounding_box();
+        }
+
+        void render(const wf::scene::render_instruction_t& data) override
+        {
+            auto bb  = self->get_children_bounding_box();
+            auto pbb = self->get_padded_bounding_box();
+            auto tex = wf::gles_texture_t{get_texture(1.0)};
+
+            const float vertices[] = {
+                -1.0, -1.0,
+                1.0f, -1.0,
+                1.0f, 1.0f,
+                -1.0, 1.0f
+            };
+            wf::pointf_t offset1{-float(bb.x - pbb.x) / bb.width,
+                -float(pbb.height - ((bb.y - pbb.y) + bb.height)) / bb.height};
+            wf::pointf_t offset2{float(pbb.width) / bb.width + offset1.x,
+                float(pbb.height) / bb.height + offset1.y};
+            const float uv[] = {
+                float(offset1.x), float(offset2.y),
+                float(offset2.x), float(offset2.y),
+                float(offset2.x), float(offset1.y),
+                float(offset1.x), float(offset1.y),
+            };
+            auto progress = self->progression.progress();
+
+            data.pass->custom_gles_subpass([&]
+            {
+                self->buffer.allocate({int(pbb.width), int(pbb.height)});
+                wf::gles::bind_render_buffer(self->buffer.get_renderbuffer());
+                wf::gles_texture_t final_tex{self->buffer.get_texture()};
+                OpenGL::clear(wf::color_t{0.0, 0.0, 0.0, 0.0}, GL_COLOR_BUFFER_BIT);
+                self->program.use(wf::TEXTURE_TYPE_RGBA);
+                self->program.attrib_pointer("position", 2, 0, vertices);
+                self->program.attrib_pointer("uv_in", 2, 0, uv);
+                self->program.uniform2f("size", bb.width * 1.0, bb.height * 1.0);
+                self->program.uniform1f("progress", 1.0 - progress);
+                self->program.uniform1i("direction", self->progression.get_direction());
+                self->program.uniform1f("flame_speed", burn_flame_speed);
+                self->program.uniform1f("flame_width", burn_flame_width);
+                self->program.uniform1f("flame_height", burn_flame_height);
+                if (std::string(burn_flame_smoothness) == "softest")
+                {
+                    self->program.uniform1i("flame_smooth_1", 0);
+                    self->program.uniform1i("flame_smooth_2", 0);
+                    self->program.uniform1i("flame_smooth_3", 0);
+                    self->program.uniform1i("flame_smooth_4", 0);
+                } else if (std::string(burn_flame_smoothness) == "soft")
+                {
+                    self->program.uniform1i("flame_smooth_1", 0);
+                    self->program.uniform1i("flame_smooth_2", 1);
+                    self->program.uniform1i("flame_smooth_3", 1);
+                    self->program.uniform1i("flame_smooth_4", 1);
+                } else if (std::string(burn_flame_smoothness) == "hard")
+                {
+                    self->program.uniform1i("flame_smooth_1", 1);
+                    self->program.uniform1i("flame_smooth_2", 1);
+                    self->program.uniform1i("flame_smooth_3", 1);
+                    self->program.uniform1i("flame_smooth_4", 1);
+                } else // "normal"
+                {
+                    self->program.uniform1i("flame_smooth_1", 1);
+                    self->program.uniform1i("flame_smooth_2", 0);
+                    self->program.uniform1i("flame_smooth_3", 1);
+                    self->program.uniform1i("flame_smooth_4", 0);
+                }
+
+                glm::vec4 flame_color{
+                    wf::color_t(burn_flame_color).r,
+                    wf::color_t(burn_flame_color).g,
+                    wf::color_t(burn_flame_color).b,
+                    wf::color_t(burn_flame_color).a};
+                self->program.uniform4f("flame_color", flame_color);
+
+                self->program.set_active_texture(tex);
+                GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
+
+                wf::gles::bind_render_buffer(data.target);
+                for (auto box : data.damage)
+                {
+                    wf::gles::render_target_logic_scissor(data.target, box);
+                    OpenGL::render_transformed_texture(final_tex, pbb,
+                        wf::gles::render_target_orthographic_projection(data.target),
+                        glm::vec4(1.0, 1.0, 1.0, std::clamp((progress - 0.07) * 10.0, 0.0, 1.0)), 0);
+                }
+
+                GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
+                self->program.deactivate();
+                self->buffer.free();
+            });
+        }
+    };
+
+    burn_transformer(wayfire_view view, wf::geometry_t bbox,
+        wf::animation_description_t duration) : wf::scene::view_2d_transformer_t(view)
+    {
+        this->view = view;
+        this->progression = duration_t{wf::create_option(duration)};
+        if (view->get_output())
+        {
+            output = view->get_output();
+            output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
+        }
+
+        wf::gles::run_in_context([&]
+        {
+            program.compile(burn_vert_source, burn_frag_source);
+        });
+    }
+
+    wf::geometry_t get_padded_bounding_box()
+    {
+        auto box     = this->get_children_bounding_box();
+        auto padding = 50;
+        box.x     -= padding;
+        box.y     -= padding;
+        box.width += padding * 2;
+        box.height += padding * 2;
+        return box;
+    }
+
+    wf::effect_hook_t pre_hook = [=] ()
+    {
+        output->render->damage(this->get_bounding_box());
+    };
+
+    void gen_render_instances(std::vector<render_instance_uptr>& instances,
+        damage_callback push_damage, wf::output_t *shown_on) override
+    {
+        instances.push_back(std::make_unique<simple_node_render_instance_t>(
+            this, push_damage, view));
+    }
+
+    void init_animation(bool burn)
+    {
+        if (burn)
+        {
+            this->progression.reverse();
+        }
+
+        this->progression.start();
+    }
+
+    virtual ~burn_transformer()
+    {
+        if (output)
+        {
+            output->render->rem_effect(&pre_hook);
+        }
+
+        wf::gles::run_in_context_if_gles([&]
+        {
+            program.free_resources();
+        });
+    }
+};
+
+class burn_animation : public animation_base_t
+{
+    wayfire_view view;
+
+  public:
+    void init(wayfire_view view, wf::animation_description_t dur, animation_type type) override
+    {
+        this->view = view;
+        pop_transformer(view);
+        auto bbox = view->get_transformed_node()->get_bounding_box();
+        auto tmgr = view->get_transformed_node();
+        auto node = std::make_shared<burn_transformer>(view, bbox, dur);
+        tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, burn_transformer_name);
+        node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION);
+    }
+
+    void pop_transformer(wayfire_view view)
+    {
+        if (view->get_transformed_node()->get_transformer(burn_transformer_name))
+        {
+            view->get_transformed_node()->rem_transformer(burn_transformer_name);
+        }
+    }
+
+    bool step() override
+    {
+        if (!view)
+        {
+            return false;
+        }
+
+        auto tmgr = view->get_transformed_node();
+        if (!tmgr)
+        {
+            return false;
+        }
+
+        if (auto tr =
+                tmgr->get_transformer<wf::burn::burn_transformer>(burn_transformer_name))
+        {
+            auto running = tr->progression.running();
+            if (!running)
+            {
+                pop_transformer(view);
+                return false;
+            }
+
+            return running;
+        }
+
+        return false;
+    }
+
+    void reverse() override
+    {
+        if (auto tr =
+                view->get_transformed_node()->get_transformer<wf::burn::burn_transformer>(
+                    burn_transformer_name))
+        {
+            tr->progression.reverse();
+        }
+    }
+};
+}
+}
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/carpet.hpp wayfire-plugins-extra/src/extra-animations/carpet.hpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/carpet.hpp	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/src/extra-animations/carpet.hpp	2026-08-01 16:00:35.434368211 -0600
@@ -0,0 +1,584 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Scott Moreau <oreaus@gmail.com>
+ * Copyright (c) 2025 Andrew Pliatsikas <futurebytestore@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <wayfire/core.hpp>
+#include <wayfire/opengl.hpp>
+#include <wayfire/view-transform.hpp>
+#include <wayfire/util/duration.hpp>
+#include <wayfire/plugins/animate/animate.hpp>
+
+
+static const char *carpet_vert_source =
+    R"(
+#version 100
+
+attribute highp vec2 position;
+attribute highp vec2 uv_in;
+
+varying highp vec2 uvpos_var;
+
+void main() {
+
+    gl_Position = vec4(position.xy, 0.0, 1.0);
+    uvpos_var = uv_in;
+}
+)";
+
+static const char *carpet_frag_source =
+    R"(
+#version 100
+@builtin_ext@
+@builtin@
+
+precision highp float;
+
+varying highp vec2 uvpos_var;
+
+uniform float progress;
+uniform int direction;
+
+#define M_PI 3.1415926535897932384626433832795
+
+// Original single roll effect
+vec4 single_roll(vec2 uvpos_var, float progress, int direction)
+{
+    vec4 wfrag;
+    vec2 uv;
+    vec2 uvpos;
+    if (direction == 1) // right
+    {
+        uvpos = vec2(1.0 - uvpos_var.x, uvpos_var.y);
+    } else if (direction == 2) // top
+    {
+        uvpos = vec2(1.0 - uvpos_var.y, uvpos_var.x);
+    } else if (direction == 3) // bottom
+    {
+        uvpos = vec2(uvpos_var.y, uvpos_var.x);
+    } else // left
+    {
+        uvpos = uvpos_var;
+    }
+    float offset = 0.1;
+    float p = progress * 1.2 - 0.2;
+
+    // initial color (transparent)
+    wfrag = vec4(0.0);
+    // get pixel from default position if left of peel line
+    if (uvpos.x < p + offset + 0.05)
+    {
+        if (uvpos_var.x >= 0.0 && uvpos_var.x <= 1.0 &&
+            uvpos_var.y >= 0.0 && uvpos_var.y <= 1.0)
+        {
+            // sample the texture, but only if within 0-1 range to avoid clamping
+            wfrag = get_pixel(uvpos_var);
+        }
+    }
+    // back of roll
+    if (uvpos.x > p + offset + 0.05 && uvpos.x < p + offset + 0.1)
+    {
+        // trigonometric sine
+        float tsin = (uvpos.x - (p + offset + 0.05)) * 20.0;
+        // angle from arcsine
+        float angle = asin(tsin);
+        // compute x sampling coordinate
+        if (direction == 0 || direction == 1)
+        {
+            uv.x = (angle / (M_PI)) * 0.15 + p + offset + 0.05;
+        } else
+        {
+            uv.x = (uvpos.y - 0.5) * pow(cos(angle), 0.02) + 0.5;
+        }
+        // compute y sampling coordinate
+        if (direction == 2 || direction == 3)
+        {
+            uv.y = (angle / (M_PI)) * 0.15 + p + offset + 0.05;
+        } else
+        {
+            uv.y = (uvpos.y - 0.5) * pow(cos(angle), 0.02) + 0.5;
+        }
+        vec4 pfrag = vec4(0.0);
+        if (uv.x >= 0.0 && uv.x <= 1.0 &&
+            uv.y >= 0.0 && uv.y <= 1.0)
+        {
+            // sample the texture, but only if within 0-1 range to avoid clamping
+            if (direction == 1)
+            {
+                pfrag = get_pixel(vec2(1.0 - uv.x, uv.y));
+            } else if (direction == 2)
+            {
+                pfrag = get_pixel(vec2(uv.x, 1.0 - uv.y));
+            } else
+            {
+                pfrag = get_pixel(uv);
+            }
+        }
+        // store color for fragment mixing with current fragment if translucent
+        wfrag = mix(pfrag, wfrag, wfrag.a);
+    }
+    // front of roll
+    if (uvpos.x > p + offset && uvpos.x < p + offset + 0.1)
+    {
+        // trigonometric sine
+        float tsin = (uvpos.x - (p + offset + 0.1)) * 20.0 + 1.0;
+        // angle from arcsine
+        float angle = asin(tsin);
+        // compute x sampling coordinate
+        if (direction == 0 || direction == 1)
+        {
+            uv.x = (angle / (-M_PI)) * 0.1 + p + offset + 0.2;
+        } else
+        {
+            uv.x = (uvpos.y - 0.5) * 0.9 * pow(cos(angle), -0.04) + 0.5;
+        }
+        // compute y sampling coordinate
+        if (direction == 2 || direction == 3)
+        {
+            uv.y = (angle / (-M_PI)) * 0.1 + p + offset + 0.2;
+        } else
+        {
+            uv.y = (uvpos.y - 0.5) * 0.9 * pow(cos(angle), -0.04) + 0.5;
+        }
+        vec4 pfrag = vec4(0.0);
+        if (uv.x >= 0.0 && uv.x <= 1.0 &&
+            uv.y >= 0.0 && uv.y <= 1.0)
+        {
+            // sample the texture, but only if within 0-1 range to avoid clamping
+            if (direction == 1)
+            {
+                pfrag = get_pixel(vec2(1.0 - uv.x, uv.y));
+            } else if (direction == 2)
+            {
+                pfrag = get_pixel(vec2(uv.x, 1.0 - uv.y));
+            } else
+            {
+                pfrag = get_pixel(uv);
+            }
+        }
+        // compute lighting
+        pfrag = vec4(clamp(pfrag.rgb + (angle / -M_PI), 0.0, 1.0), pfrag.a);
+        // store color for fragment mixing with current fragment if translucent
+        wfrag = mix(wfrag, pfrag, pfrag.a);
+    }
+
+    return wfrag;
+}
+
+// Dual scroll effect (both sides rolling toward/from middle) by Phodius
+vec4 dual_scroll(vec2 uvpos_var, float progress, int dir)
+{
+    vec4 wfrag = vec4(0.0);
+    vec2 uv;
+    
+    float coord;
+    float other_coord;
+    
+    // dir 5 = vertical, dir 4 = horizontal
+    if (dir == 5)
+    {
+        coord = uvpos_var.y;
+        other_coord = uvpos_var.x;
+    }
+    else
+    {
+        coord = uvpos_var.x;
+        other_coord = uvpos_var.y;
+    }
+    
+    // Determine which half we're on
+    bool second_half = (coord > 0.5);
+    
+    // Map to local coordinate: 0 at middle, 1 at edge
+    float local_coord;
+    if (second_half)
+    {
+        local_coord = (coord - 0.5) * 2.0;
+    }
+    else
+    {
+        local_coord = (0.5 - coord) * 2.0;
+    }
+    
+    float offset = 0.1;
+    float p = progress * 1.2 - 0.2;
+
+    // Get pixel from default position if before peel line
+    if (local_coord < p + offset + 0.05)
+    {
+        if (uvpos_var.x >= 0.0 && uvpos_var.x <= 1.0 &&
+            uvpos_var.y >= 0.0 && uvpos_var.y <= 1.0)
+        {
+            wfrag = get_pixel(uvpos_var);
+        }
+    }
+    
+    // Back of roll
+    if (local_coord > p + offset + 0.05 && local_coord < p + offset + 0.1)
+    {
+        float tsin = (local_coord - (p + offset + 0.05)) * 20.0;
+        float angle = asin(tsin);
+        
+        float local_sample = (angle / M_PI) * 0.15 + p + offset + 0.05;
+        
+        float global_sample;
+        if (second_half)
+        {
+            global_sample = 0.5 + local_sample * 0.5;
+        }
+        else
+        {
+            global_sample = 0.5 - local_sample * 0.5;
+        }
+        
+        float perp_sample = (other_coord - 0.5) * pow(cos(angle), 0.02) + 0.5;
+        
+        if (dir == 5)
+        {
+            uv.y = global_sample;
+            uv.x = perp_sample;
+        }
+        else
+        {
+            uv.x = global_sample;
+            uv.y = perp_sample;
+        }
+        
+        vec4 pfrag = vec4(0.0);
+        if (uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0)
+        {
+            pfrag = get_pixel(uv);
+        }
+        wfrag = mix(pfrag, wfrag, wfrag.a);
+    }
+    
+    // Front of roll
+    if (local_coord > p + offset && local_coord < p + offset + 0.1)
+    {
+        float tsin = (local_coord - (p + offset + 0.1)) * 20.0 + 1.0;
+        float angle = asin(tsin);
+        
+        float local_sample = (angle / (-M_PI)) * 0.1 + p + offset + 0.2;
+        
+        float global_sample;
+        if (second_half)
+        {
+            global_sample = 0.5 + local_sample * 0.5;
+        }
+        else
+        {
+            global_sample = 0.5 - local_sample * 0.5;
+        }
+        
+        float perp_sample = (other_coord - 0.5) * 0.9 * pow(cos(angle), -0.04) + 0.5;
+        
+        if (dir == 5)
+        {
+            uv.y = global_sample;
+            uv.x = perp_sample;
+        }
+        else
+        {
+            uv.x = global_sample;
+            uv.y = perp_sample;
+        }
+        
+        vec4 pfrag = vec4(0.0);
+        if (uv.x >= 0.0 && uv.x <= 1.0 && uv.y >= 0.0 && uv.y <= 1.0)
+        {
+            pfrag = get_pixel(uv);
+        }
+        pfrag = vec4(clamp(pfrag.rgb + (angle / -M_PI), 0.0, 1.0), pfrag.a);
+        wfrag = mix(wfrag, pfrag, pfrag.a);
+    }
+    
+    return wfrag;
+}
+
+void main()
+{
+    vec4 wfrag;
+    
+    if (direction <= 3)
+    {
+        // single roll: left, right, top, bottom
+        wfrag = single_roll(uvpos_var, progress, direction);
+    }
+    else
+    {
+        // dual scroll: horizontal or vertical from middle
+        wfrag = dual_scroll(uvpos_var, progress, direction);
+    }
+
+    gl_FragColor = wfrag;
+}
+)";
+
+namespace wf
+{
+namespace carpet
+{
+using namespace wf::scene;
+using namespace wf::animate;
+using namespace wf::animation;
+
+static std::string carpet_transformer_name = "animation-carpet";
+
+wf::option_wrapper_t<int> carpet_roll_direction{"extra-animations/carpet_roll_direction"};
+
+class carpet_transformer : public wf::scene::view_2d_transformer_t
+{
+  public:
+    wayfire_view view;
+    wf::output_t *output;
+    OpenGL::program_t program;
+    wf::auxilliary_buffer_t buffer;
+    duration_t progression;
+
+    class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t<transformer_base_node_t>
+    {
+        wf::signal::connection_t<node_damage_signal> on_node_damaged =
+            [=] (node_damage_signal *ev)
+        {
+            push_to_parent(ev->region);
+        };
+
+        carpet_transformer *self;
+        wayfire_view view;
+        damage_callback push_to_parent;
+
+      public:
+        simple_node_render_instance_t(carpet_transformer *self, damage_callback push_damage,
+            wayfire_view view) : wf::scene::transformer_render_instance_t<transformer_base_node_t>(self,
+                push_damage,
+                view->get_output())
+        {
+            this->self = self;
+            this->view = view;
+            this->push_to_parent = push_damage;
+            self->connect(&on_node_damaged);
+        }
+
+        ~simple_node_render_instance_t()
+        {}
+
+        void schedule_instructions(
+            std::vector<render_instruction_t>& instructions,
+            const wf::render_target_t& target, wf::regionf_t& damage) override
+        {
+            instructions.push_back(render_instruction_t{
+                        .instance = this,
+                        .target   = target,
+                        .damage   = damage & self->get_bounding_box(),
+                    });
+        }
+
+        void transform_damage_region(wf::regionf_t& damage) override
+        {
+            damage |= self->get_bounding_box();
+        }
+
+        void render(const wf::scene::render_instruction_t& data) override
+        {
+            auto bb  = self->get_children_bounding_box();
+            auto pbb = self->get_padded_bounding_box();
+            auto tex = wf::gles_texture_t{get_texture(1.0)};
+
+            const float vertices[] = {
+                -1.0, -1.0,
+                1.0f, -1.0,
+                1.0f, 1.0f,
+                -1.0, 1.0f
+            };
+            wf::pointf_t offset1{-float(bb.x - pbb.x) / bb.width,
+                -float(pbb.height - ((bb.y - pbb.y) + bb.height)) / bb.height};
+            wf::pointf_t offset2{float(pbb.width) / bb.width + offset1.x,
+                float(pbb.height) / bb.height + offset1.y};
+            const float uv[] = {
+                float(offset1.x), float(offset2.y),
+                float(offset2.x), float(offset2.y),
+                float(offset2.x), float(offset1.y),
+                float(offset1.x), float(offset1.y),
+            };
+            auto progress = self->progression.progress();
+
+            data.pass->custom_gles_subpass([&]
+            {
+                self->buffer.allocate({int(pbb.width), int(pbb.height)});
+                wf::gles::bind_render_buffer(self->buffer.get_renderbuffer());
+                wf::gles_texture_t final_tex{self->buffer.get_texture()};
+                OpenGL::clear(wf::color_t{0.0, 0.0, 0.0, 0.0}, GL_COLOR_BUFFER_BIT);
+                self->program.use(wf::TEXTURE_TYPE_RGBA);
+                self->program.attrib_pointer("position", 2, 0, vertices);
+                self->program.attrib_pointer("uv_in", 2, 0, uv);
+                self->program.uniform1f("progress", progress);
+                self->program.uniform1i("direction", carpet_roll_direction);
+
+                self->program.set_active_texture(tex);
+                GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
+
+                wf::gles::bind_render_buffer(data.target);
+                for (auto box : data.damage)
+                {
+                    wf::gles::render_target_logic_scissor(data.target, box);
+                    OpenGL::render_transformed_texture(final_tex, pbb,
+                        wf::gles::render_target_orthographic_projection(data.target),
+                        glm::vec4(1.0, 1.0, 1.0, 1.0), 0);
+                }
+
+                GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
+                self->program.deactivate();
+                self->buffer.free();
+            });
+        }
+    };
+
+    carpet_transformer(wayfire_view view, wf::geometry_t bbox,
+        wf::animation_description_t duration) : wf::scene::view_2d_transformer_t(view)
+    {
+        this->view = view;
+        this->progression = duration_t{wf::create_option(duration)};
+        if (view->get_output())
+        {
+            output = view->get_output();
+            output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
+        }
+
+        wf::gles::run_in_context([&]
+        {
+            program.compile(carpet_vert_source, carpet_frag_source);
+        });
+    }
+
+    wf::geometry_t get_padded_bounding_box()
+    {
+        auto box     = this->get_children_bounding_box();
+        auto padding = (box.width > box.height ? box.width : box.height) * 0.07;
+        box.x     -= padding;
+        box.y     -= padding;
+        box.width += padding * 2;
+        box.height += padding * 2;
+        return box;
+    }
+
+    wf::effect_hook_t pre_hook = [=] ()
+    {
+        output->render->damage(this->get_bounding_box());
+    };
+
+    void gen_render_instances(std::vector<render_instance_uptr>& instances,
+        damage_callback push_damage, wf::output_t *shown_on) override
+    {
+        instances.push_back(std::make_unique<simple_node_render_instance_t>(
+            this, push_damage, view));
+    }
+
+    void init_animation(bool carpet)
+    {
+        if (carpet)
+        {
+            this->progression.reverse();
+        }
+
+        this->progression.start();
+    }
+
+    virtual ~carpet_transformer()
+    {
+        if (output)
+        {
+            output->render->rem_effect(&pre_hook);
+        }
+
+        wf::gles::run_in_context_if_gles([&]
+        {
+            program.free_resources();
+        });
+    }
+};
+
+class carpet_animation : public animation_base_t
+{
+    wayfire_view view;
+
+  public:
+    void init(wayfire_view view, wf::animation_description_t dur, animation_type type) override
+    {
+        this->view = view;
+        pop_transformer(view);
+        auto bbox = view->get_transformed_node()->get_bounding_box();
+        auto tmgr = view->get_transformed_node();
+        auto node = std::make_shared<carpet_transformer>(view, bbox, dur);
+        tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, carpet_transformer_name);
+        node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION);
+    }
+
+    void pop_transformer(wayfire_view view)
+    {
+        if (view->get_transformed_node()->get_transformer(carpet_transformer_name))
+        {
+            view->get_transformed_node()->rem_transformer(carpet_transformer_name);
+        }
+    }
+
+    bool step() override
+    {
+        if (!view)
+        {
+            return false;
+        }
+
+        auto tmgr = view->get_transformed_node();
+        if (!tmgr)
+        {
+            return false;
+        }
+
+        if (auto tr =
+                tmgr->get_transformer<wf::carpet::carpet_transformer>(carpet_transformer_name))
+        {
+            auto running = tr->progression.running();
+            if (!running)
+            {
+                pop_transformer(view);
+                return false;
+            }
+
+            return running;
+        }
+
+        return false;
+    }
+
+    void reverse() override
+    {
+        if (auto tr =
+                view->get_transformed_node()->get_transformer<wf::carpet::carpet_transformer>(
+                    carpet_transformer_name))
+        {
+            tr->progression.reverse();
+        }
+    }
+};
+}
+}
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/dodge.hpp wayfire-plugins-extra/src/extra-animations/dodge.hpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/dodge.hpp	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/src/extra-animations/dodge.hpp	2026-08-01 16:00:35.434368211 -0600
@@ -0,0 +1,550 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2025 Scott Moreau <oreaus@gmail.com>
+ * Copyright (c) 2025 Andrew Pliatsikas <futurebytestore@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#pragma once
+
+#include <set>
+#include <cmath>
+#include <cstdlib>
+#include <wayfire/core.hpp>
+#include <wayfire/seat.hpp>
+#include <wayfire/plugin.hpp>
+#include <wayfire/view-helpers.hpp>
+#include <wayfire/toplevel-view.hpp>
+#include <wayfire/util/duration.hpp>
+#include <wayfire/view-transform.hpp>
+#include <wayfire/render-manager.hpp>
+#include <wayfire/window-manager.hpp>
+#include <wayfire/scene-operations.hpp>
+#include <wayfire/signal-definitions.hpp>
+#include <wayfire/plugins/common/util.hpp>
+
+namespace wf
+{
+namespace dodge
+{
+static std::string dodge_transformer_name = "dodge";
+
+struct dodge_view_data
+{
+    wayfire_view view;
+    wf::geometry_t from_bb, to_bb;
+    std::shared_ptr<wf::scene::view_2d_transformer_t> transformer;
+    wf::pointf_t direction;
+};
+
+bool boxes_intersect(const wayfire_view & a, const wayfire_view & b)
+{
+    auto ao = a->get_output();
+    auto bo = b->get_output();
+    if (!ao || !bo || (ao != bo))
+    {
+        return false;
+    }
+
+    auto a_bb = wf::toplevel_cast(a)->get_geometry();
+    auto b_bb = wf::toplevel_cast(b)->get_geometry();
+    return !(b_bb.x > a_bb.x + a_bb.width ||
+        a_bb.x > b_bb.x + b_bb.width ||
+        b_bb.y > a_bb.y + a_bb.height ||
+        a_bb.y > b_bb.y + b_bb.height);
+}
+
+class wayfire_dodge
+{
+    std::vector<dodge_view_data> views_from;
+    std::list<wayfire_view> minimized_views;
+    wayfire_view view_to, last_focused_view;
+    wf::option_wrapper_t<bool> dodge_zoom{"extra-animations/dodge_zoom"};
+    wf::option_wrapper_t<bool> dodge_rotate{"extra-animations/dodge_rotate"};
+    wf::option_wrapper_t<std::string> direction{"extra-animations/dodge_direction"};
+    wf::option_wrapper_t<wf::animation_description_t> animation_duration{"extra-animations/dodge_duration"};
+    wf::animation::simple_animation_t progression{animation_duration};
+    bool view_to_focused;
+    wf::output_t *view_to_output;
+    bool hook_set = false;
+    bool view_unminimized    = false;
+    bool from_mapped_event   = false;
+    bool from_unmapped_event = false;
+    std::vector<wf::output_t*> outputs;
+
+  public:
+    void init()
+    {
+        wf::get_core().connect(&view_mapped);
+        wf::get_core().connect(&view_unmapped);
+        this->progression.set(0, 0);
+        for (auto& view : wf::get_core().get_all_views())
+        {
+            if (wf::toplevel_cast(view))
+            {
+                view->connect(&view_activated);
+                view->get_output()->connect(&view_minimize_request);
+                if (std::find_if(outputs.begin(), outputs.end(), [=] (wf::output_t*& o)
+                {
+                    return view->get_output() == o;
+                }) == outputs.end())
+                {
+                    outputs.push_back(view->get_output());
+                }
+            }
+        }
+
+        for (auto output : outputs)
+        {
+            output->connect(&view_minimize_request);
+        }
+    }
+
+    wf::signal::connection_t<wf::view_minimize_request_signal> view_minimize_request =
+        [=] (wf::view_minimize_request_signal *ev)
+    {
+        if (ev->state)
+        {
+            minimized_views.push_back(ev->view);
+        } else
+        {
+            minimized_views.remove(ev->view);
+            view_unminimized = true;
+            wf::view_activated_state_signal data;
+            data.view = ev->view;
+            view_activated.emit(&data);
+        }
+    };
+
+    wf::signal::connection_t<wf::view_activated_state_signal> view_activated =
+        [=] (wf::view_activated_state_signal *ev)
+    {
+        if (ev->view == wf::get_core().seat->get_active_view())
+        {
+            last_focused_view = wf::get_core().seat->get_active_view();
+            if (!from_mapped_event)
+            {
+                return;
+            }
+        }
+
+        if (from_unmapped_event)
+        {
+            from_unmapped_event = false;
+            return;
+        }
+
+        view_to = ev->view;
+
+        auto toplevel = wf::toplevel_cast(view_to);
+        if (!toplevel)
+        {
+            return;
+        }
+
+        if (!last_focused_view || !view_to || !view_to->is_mapped() ||
+            toplevel->parent)
+        {
+            return;
+        }
+
+        auto to_bb = toplevel->get_geometry();
+
+        if (from_mapped_event)
+        {
+            view_bring_to_front(view_to);
+        }
+
+        /* Find overlapping views */
+        std::vector<wayfire_view> overlapping_views;
+        auto all_views = wf::get_core().get_all_views();
+        std::sort(all_views.begin(), all_views.end(), [] (const wayfire_view& a, const wayfire_view& b)
+        {
+            return wf::get_focus_timestamp(a) < wf::get_focus_timestamp(b);
+        });
+        for (auto& view : all_views)
+        {
+            if (!view || !view->is_mapped())
+            {
+                continue;
+            }
+
+            toplevel = wf::toplevel_cast(view);
+            if (!toplevel)
+            {
+                continue;
+            }
+
+            if ((wf::get_focus_timestamp(view_to) < wf::get_focus_timestamp(view)) ||
+                ((from_mapped_event || view_unminimized) &&
+                 (wf::get_focus_timestamp(view_to) > wf::get_focus_timestamp(view))))
+            {
+                if ((boxes_intersect(view, view_to) || from_mapped_event ||
+                     view->get_transformed_node()->get_transformer<wf::scene::view_2d_transformer_t>(
+                         dodge_transformer_name)) &&
+                    (std::find_if(minimized_views.begin(), minimized_views.end(),
+                        [view] (const wayfire_view& v) { return v == view; }) == minimized_views.end()))
+                {
+                    overlapping_views.push_back(view);
+                    view_bring_to_front(view);
+                }
+            }
+
+            if (!from_mapped_event)
+            {
+                view_bring_to_front(view);
+            }
+        }
+
+        view_unminimized = false;
+
+        if (overlapping_views.empty())
+        {
+            return;
+        }
+
+        if (!hook_set)
+        {
+            view_to_output = view_to->get_output();
+            view_to_output->render->add_effect(&dodge_animation_hook, wf::OUTPUT_EFFECT_PRE);
+            hook_set = true;
+        }
+
+        view_to_focused = false;
+        if (!this->progression.running())
+        {
+            views_from.clear();
+            this->progression.animate(0, 1);
+        }
+
+        for (size_t i = 0; i < overlapping_views.size(); i++)
+        {
+            dodge_view_data view_data;
+            view_data.view = overlapping_views[i];
+
+            view_data.from_bb = view_data.view->get_bounding_box();
+            view_data.to_bb   = view_to->get_bounding_box();
+
+            bool view_found = false;
+            for (auto vd : views_from)
+            {
+                if (vd.view == view_data.view)
+                {
+                    view_found = true;
+                    if (dodge_rotate && from_mapped_event)
+                    {
+                        auto direction = compute_direction(view_data.from_bb, to_bb);
+                        vd.direction.x = direction.x;
+                        vd.direction.y = direction.y;
+                        vd.transformer->angle = 0.1;
+                    }
+
+                    break;
+                }
+            }
+
+            if (view_found)
+            {
+                continue;
+            }
+
+            if (auto tr =
+                    view_data.view->get_transformed_node()->get_transformer<wf::scene::view_2d_transformer_t>(
+                        dodge_transformer_name))
+            {
+                view_data.transformer = tr;
+                if (dodge_rotate && from_mapped_event)
+                {
+                    view_data.transformer->angle = 0.1;
+                }
+            } else
+            {
+                view_data.transformer = std::make_shared<wf::scene::view_2d_transformer_t>(view_data.view);
+                view_data.view->get_transformed_node()->add_transformer(view_data.transformer,
+                    wf::TRANSFORMER_2D,
+                    dodge_transformer_name);
+                auto d = compute_direction(view_data.from_bb, to_bb);
+                view_data.direction.x = d.x;
+                view_data.direction.y = d.y;
+
+                auto & x = view_data.direction.x;
+                auto & y = view_data.direction.y;
+                if ((((x < 0.001) && (x > -0.001)) && ((y < 0.001) && (y > -0.001))) || std::isnan(x) ||
+                    std::isnan(y))
+                {
+                    if ((std::string(direction) == "cardinal") || (std::string(direction) == "diagonal"))
+                    {
+                        srand(wf::get_current_time() + rand());
+                        x = (rand() % 2) * 2 - 1;
+                        srand(wf::get_current_time() + rand());
+                        y = (rand() % 2) * 2 - 1;
+                    } else if (std::string(direction) == "circular")
+                    {
+                        srand(wf::get_current_time() + rand());
+                        x = (double(rand()) / RAND_MAX) * 2.0 - 1.0;
+                        srand(wf::get_current_time() + rand());
+                        y = (double(rand()) / RAND_MAX) * 2.0 - 1.0;
+                    }
+                }
+
+                if (dodge_rotate)
+                {
+                    view_data.transformer->angle = 0.1;
+                }
+            }
+
+            views_from.push_back(view_data);
+        }
+
+        from_mapped_event = false;
+    };
+
+    wf::signal::connection_t<wf::view_mapped_signal> view_mapped =
+        [=] (wf::view_mapped_signal *ev)
+    {
+        from_mapped_event = true;
+        ev->view->connect(&view_activated);
+        if (std::find_if(outputs.begin(), outputs.end(), [=] (wf::output_t*& o)
+        {
+            return ev->view->get_output() == o;
+        }) == outputs.end())
+        {
+            ev->view->get_output()->connect(&view_minimize_request);
+            outputs.push_back(ev->view->get_output());
+        }
+    };
+
+    wf::signal::connection_t<wf::view_unmapped_signal> view_unmapped =
+        [=] (wf::view_unmapped_signal *ev)
+    {
+        from_unmapped_event = true;
+        last_focused_view   = wf::get_core().seat->get_active_view();
+        if (ev->view == view_to)
+        {
+            view_bring_to_front(view_to);
+            view_to = nullptr;
+        }
+
+        if (ev->view == last_focused_view)
+        {
+            last_focused_view = nullptr;
+        }
+
+        views_from.erase(std::remove_if(views_from.begin(), views_from.end(),
+            [ev] (const dodge_view_data& data)
+        {
+            return data.view == ev->view;
+        }), views_from.end());
+    };
+
+    double magnitude(int x, int y)
+    {
+        return std::sqrt(x * x + y * y);
+    }
+
+    wf::pointf_t compute_direction(wf::geometry_t from_bb, wf::geometry_t to_bb)
+    {
+        auto from_center = wf::pointf_t{from_bb.x + from_bb.width / 2, from_bb.y + from_bb.height / 2};
+        auto to_center   = wf::pointf_t{to_bb.x + to_bb.width / 2, to_bb.y + to_bb.height / 2};
+        auto x = double(from_center.x - to_center.x);
+        auto y = double(from_center.y - to_center.y);
+        auto m = magnitude(x, y);
+        if (m == 0)
+        {
+            return wf::pointf_t{0, 0};
+        }
+
+        x /= m;
+        y /= m;
+        if (std::string(direction) != "circular")
+        {
+            x = x * std::abs(1.0 / x);
+            y = y * std::abs(1.0 / y);
+        }
+
+        return wf::pointf_t{x, y};
+    }
+
+    void damage_views()
+    {
+        for (auto& view_data : views_from)
+        {
+            view_data.view->damage();
+        }
+
+        if (view_to)
+        {
+            view_to->damage();
+        }
+    }
+
+    void finish_animation()
+    {
+        for (auto& view : wf::get_core().get_all_views())
+        {
+            view->get_transformed_node()->rem_transformer(dodge_transformer_name);
+        }
+
+        if (hook_set)
+        {
+            view_to_output->render->rem_effect(&dodge_animation_hook);
+            hook_set = false;
+        }
+
+        views_from.clear();
+        view_to = nullptr;
+    }
+
+    bool step_animation()
+    {
+        if (!view_to)
+        {
+            return false;
+        }
+
+        double progress = progression.progress();
+        progress = (1.0 - progress) * (1.0 - progress);
+        progress = 1.0 - progress;
+
+        std::shared_ptr<wf::scene::view_2d_transformer_t> view_to_transformer;
+        if (std::find_if(minimized_views.begin(), minimized_views.end(), [&] (const wayfire_view& v)
+        {
+            return v == last_focused_view;
+        }) == minimized_views.end())
+        {
+            if (auto tr =
+                    view_to->get_transformed_node()->get_transformer<wf::scene::view_2d_transformer_t>(
+                        dodge_transformer_name))
+            {
+                view_to_transformer = tr;
+            } else
+            {
+                view_to_transformer = std::make_shared<wf::scene::view_2d_transformer_t>(view_to);
+                view_to->get_transformed_node()->add_transformer(view_to_transformer, wf::TRANSFORMER_2D,
+                    dodge_transformer_name);
+            }
+        } else
+        {
+            view_to_focused = true;
+        }
+
+        if (dodge_zoom && view_to_transformer)
+        {
+            view_to_transformer->scale_x = view_to_transformer->scale_y = 1.0 + std::sin(
+                progression.progress() * M_PI) * 0.02;
+        }
+
+        for (auto& view_data : views_from)
+        {
+            auto to_bb   = view_data.to_bb;
+            auto from_bb = view_data.from_bb;
+            double move_dist_x = std::min(from_bb.x + from_bb.width - to_bb.x,
+                to_bb.x + to_bb.width - from_bb.x);
+            double move_dist_y = std::min(from_bb.y + from_bb.height - to_bb.y,
+                to_bb.y + to_bb.height - from_bb.y);
+
+            if (dodge_zoom)
+            {
+                if (view_data.transformer->scale_x <= 1.0)
+                {
+                    view_data.transformer->scale_x = view_data.transformer->scale_y = 1.0 - std::sin(
+                        progression.progress() * M_PI) * 0.25;
+                } else
+                {
+                    view_data.transformer->scale_x = view_data.transformer->scale_y = 1.0 + std::sin(
+                        progression.progress() * M_PI) * 0.02;
+                }
+            }
+
+            if (dodge_rotate && (view_data.transformer->angle != 0.0))
+            {
+                view_data.transformer->angle = progress * M_PI * 2 * (view_data.direction.x > 0 ? 1 : -1);
+                if (view_data.transformer->angle == 0.0)
+                {
+                    view_data.transformer->angle = 0.1;
+                }
+            }
+
+            if (std::string(direction) == "cardinal")
+            {
+                if (move_dist_x < move_dist_y)
+                {
+                    move_dist_y = 0;
+                } else
+                {
+                    move_dist_x = 0;
+                }
+            } else if (std::string(direction) == "circular")
+            {
+                auto direction_x = std::abs(view_data.direction.x);
+                auto direction_y = std::abs(view_data.direction.y);
+                if (direction_x < direction_y)
+                {
+                    move_dist_x *= direction_x;
+                    auto& y = view_data.direction.y;
+                    y = y * std::abs(1.0 / y);
+                } else
+                {
+                    move_dist_y *= direction_y;
+                    auto& x = view_data.direction.x;
+                    x = x * std::abs(1.0 / x);
+                }
+            }
+
+            double move_x = move_dist_x * view_data.direction.x;
+            double move_y = move_dist_y * view_data.direction.y;
+
+            view_data.transformer->translation_x = std::sin(progress * M_PI) * move_x;
+            view_data.transformer->translation_y = std::sin(progress * M_PI) * move_y;
+        }
+
+        if ((progress > 0.5) && !view_to_focused)
+        {
+            wf::get_core().seat->focus_view(view_to);
+            view_bring_to_front(view_to);
+            view_to_focused = true;
+        }
+
+        return progression.running();
+    }
+
+    wf::effect_hook_t dodge_animation_hook = [=] ()
+    {
+        damage_views();
+        bool result = step_animation();
+        damage_views();
+
+        if (!result)
+        {
+            finish_animation();
+        }
+    };
+
+    void fini()
+    {
+        finish_animation();
+        view_mapped.disconnect();
+        view_unmapped.disconnect();
+        view_activated.disconnect();
+    }
+};
+}
+}
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/helix.hpp wayfire-plugins-extra/src/extra-animations/helix.hpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/helix.hpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/extra-animations/helix.hpp	2026-08-01 16:00:35.434368211 -0600
@@ -82,15 +82,9 @@ using namespace wf::animation;
 
 static std::string transformer_name = "animation-helix";
 
-wf::option_wrapper_t<wf::animation_description_t> helix_duration{"extra-animations/helix_duration"};
 wf::option_wrapper_t<int> helix_strip_height{"extra-animations/helix_strip_height"};
 wf::option_wrapper_t<int> helix_rotations{"extra-animations/helix_rotations"};
 
-class helix_animation_t : public duration_t
-{
-  public:
-    using duration_t::duration_t;
-};
 class helix_transformer : public wf::scene::view_2d_transformer_t
 {
   public:
@@ -98,7 +92,7 @@ class helix_transformer : public wf::sce
     OpenGL::program_t program;
     wf::output_t *output;
     wf::geometry_t animation_geometry;
-    helix_animation_t progression{helix_duration};
+    duration_t progression;
 
     class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t<transformer_base_node_t>
     {
@@ -129,7 +123,7 @@ class helix_transformer : public wf::sce
 
         void schedule_instructions(
             std::vector<render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage) override
+            const wf::render_target_t& target, wf::regionf_t& damage) override
         {
             instructions.push_back(render_instruction_t{
                         .instance = this,
@@ -138,9 +132,9 @@ class helix_transformer : public wf::sce
                     });
         }
 
-        void transform_damage_region(wf::region_t& damage) override
+        void transform_damage_region(wf::regionf_t& damage) override
         {
-            damage |= wf::region_t{self->animation_geometry};
+            damage |= self->animation_geometry;
         }
 
         void render(const wf::scene::render_instruction_t& data) override
@@ -165,9 +159,9 @@ class helix_transformer : public wf::sce
                 auto y     = src_box.height - i;
                 auto inv_h = 1.0 / src_box.height;
                 uv.push_back(0.0);
-                uv.push_back(std::max(0, y - line_height) * inv_h);
+                uv.push_back(std::max(0.0, y - line_height) * inv_h);
                 uv.push_back(1.0);
-                uv.push_back(std::max(0, y - line_height) * inv_h);
+                uv.push_back(std::max(0.0, y - line_height) * inv_h);
                 uv.push_back(0.0);
                 uv.push_back(y * inv_h);
                 uv.push_back(1.0);
@@ -175,7 +169,7 @@ class helix_transformer : public wf::sce
                 uv.push_back(0.0);
                 uv.push_back(y * inv_h);
                 uv.push_back(1.0);
-                uv.push_back(std::max(0, y - line_height) * inv_h);
+                uv.push_back(std::max(0.0, y - line_height) * inv_h);
                 glm::vec4 v, r;
                 glm::mat4 m(1.0);
                 m = glm::rotate(m, float(M_PI), glm::vec3(1.0, 0.0, 0.0));
@@ -237,7 +231,7 @@ class helix_transformer : public wf::sce
                 wf::gles::bind_render_buffer(data.target);
                 for (auto box : data.damage)
                 {
-                    wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
+                    wf::gles::render_target_logic_scissor(data.target, box);
                     self->program.use(wf::TEXTURE_TYPE_RGBA);
                     self->program.uniformMatrix4f("matrix", transform);
                     self->program.attrib_pointer("position", 3, 0, vertices.data());
@@ -249,9 +243,11 @@ class helix_transformer : public wf::sce
         }
     };
 
-    helix_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view)
+    helix_transformer(wayfire_view view, wf::geometry_t bbox,
+        wf::animation_description_t duration) : wf::scene::view_2d_transformer_t(view)
     {
         this->view = view;
+        this->progression = duration_t{wf::create_option(duration)};
         if (view->get_output())
         {
             output = view->get_output();
@@ -318,7 +314,7 @@ class helix_animation : public animation
         pop_transformer(view);
         auto bbox = view->get_transformed_node()->get_bounding_box();
         auto tmgr = view->get_transformed_node();
-        auto node = std::make_shared<wf::helix::helix_transformer>(view, bbox);
+        auto node = std::make_shared<wf::helix::helix_transformer>(view, bbox, dur);
         tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, transformer_name);
         node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION);
     }
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/melt.hpp wayfire-plugins-extra/src/extra-animations/melt.hpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/melt.hpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/extra-animations/melt.hpp	2026-08-01 16:00:35.434368211 -0600
@@ -22,9 +22,12 @@
  * SOFTWARE.
  */
 
+#include <cstdlib>
 #include <wayfire/core.hpp>
 #include <wayfire/opengl.hpp>
 #include <wayfire/view-transform.hpp>
+#include <wayfire/util/duration.hpp>
+#include <wayfire/plugins/animate/animate.hpp>
 
 
 static const char *melt_vert_source =
@@ -53,10 +56,11 @@ precision highp float;
 
 varying highp vec2 uvpos;
 uniform float time;
+uniform float random;
 uniform float distortion;
 
 float rand(vec2 n) {
-    return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
+    return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453 * random);
 }
 
 // Noise function from: https://gist.github.com/patriciogonzalezvivo/670c22f3966e662d2f83
@@ -95,22 +99,17 @@ using namespace wf::animation;
 
 static std::string melt_transformer_name = "animation-melt";
 
-wf::option_wrapper_t<wf::animation_description_t> melt_duration{"extra-animations/melt_duration"};
 wf::option_wrapper_t<int> melt_distortion_factor{"extra-animations/melt_distortion_factor"};
 
-class melt_animation_t : public duration_t
-{
-  public:
-    using duration_t::duration_t;
-};
 class melt_transformer : public wf::scene::view_2d_transformer_t
 {
   public:
     wayfire_view view;
+    float random_number;
     wf::output_t *output;
     OpenGL::program_t program;
     wf::auxilliary_buffer_t buffer;
-    melt_animation_t progression{melt_duration};
+    duration_t progression;
 
     class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t<transformer_base_node_t>
     {
@@ -141,7 +140,7 @@ class melt_transformer : public wf::scen
 
         void schedule_instructions(
             std::vector<render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage) override
+            const wf::render_target_t& target, wf::regionf_t& damage) override
         {
             instructions.push_back(render_instruction_t{
                         .instance = this,
@@ -150,14 +149,14 @@ class melt_transformer : public wf::scen
                     });
         }
 
-        void transform_damage_region(wf::region_t& damage) override
+        void transform_damage_region(wf::regionf_t& damage) override
         {
             damage |= self->get_padded_bounding_box();
         }
 
         void render(const wf::scene::render_instruction_t& data) override
         {
-            auto bb  = self->get_bounding_box();
+            auto bb  = self->get_children_bounding_box();
             auto pbb = self->get_padded_bounding_box();
             auto tex = wf::gles_texture_t{get_texture(1.0)};
 
@@ -181,7 +180,7 @@ class melt_transformer : public wf::scen
 
             data.pass->custom_gles_subpass([&]
             {
-                self->buffer.allocate({pbb.width, pbb.height});
+                self->buffer.allocate({int(pbb.width), int(pbb.height)});
                 wf::gles::bind_render_buffer(self->buffer.get_renderbuffer());
                 wf::gles_texture_t final_tex{self->buffer.get_texture()};
                 OpenGL::clear(wf::color_t{0.0, 0.0, 0.0, 0.0}, GL_COLOR_BUFFER_BIT);
@@ -189,6 +188,7 @@ class melt_transformer : public wf::scen
                 self->program.attrib_pointer("position", 2, 0, vertices);
                 self->program.attrib_pointer("uv_in", 2, 0, uv);
                 self->program.uniform1f("time", progress);
+                self->program.uniform1f("random", self->random_number);
                 self->program.uniform1f("distortion", float(melt_distortion_factor));
                 self->program.set_active_texture(tex);
                 GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
@@ -196,7 +196,7 @@ class melt_transformer : public wf::scen
                 wf::gles::bind_render_buffer(data.target);
                 for (auto box : data.damage)
                 {
-                    wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
+                    wf::gles::render_target_logic_scissor(data.target, box);
                     OpenGL::render_transformed_texture(final_tex, pbb,
                         wf::gles::render_target_orthographic_projection(data.target),
                         glm::vec4(1.0, 1.0, 1.0, 1.0 / (1.0 + pow(2.718, -(progress * 15.0 - 3.0)))), 0);
@@ -209,9 +209,11 @@ class melt_transformer : public wf::scen
         }
     };
 
-    melt_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view)
+    melt_transformer(wayfire_view view, wf::geometry_t bbox,
+        wf::animation_description_t duration) : wf::scene::view_2d_transformer_t(view)
     {
         this->view = view;
+        this->progression = duration_t{wf::create_option(duration)};
         if (view->get_output())
         {
             output = view->get_output();
@@ -222,12 +224,15 @@ class melt_transformer : public wf::scen
         {
             program.compile(melt_vert_source, melt_frag_source);
         });
+
+        srand(wf::get_current_time());
+        this->random_number = (rand() % 1000000) / 1000000.0;
     }
 
     wf::geometry_t get_padded_bounding_box()
     {
         auto box     = this->get_children_bounding_box();
-        auto padding = 100;
+        auto padding = 50;
         box.x     -= padding;
         box.y     -= padding;
         box.width += padding * 2;
@@ -282,7 +287,7 @@ class melt_animation : public animation_
         pop_transformer(view);
         auto bbox = view->get_transformed_node()->get_bounding_box();
         auto tmgr = view->get_transformed_node();
-        auto node = std::make_shared<melt_transformer>(view, bbox);
+        auto node = std::make_shared<melt_transformer>(view, bbox, dur);
         tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, melt_transformer_name);
         node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION);
     }
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/plugin.cpp wayfire-plugins-extra/src/extra-animations/plugin.cpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/plugin.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/extra-animations/plugin.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -32,10 +32,23 @@
 #include "shatter.hpp"
 #include "vortex.hpp"
 #include "melt.hpp"
+#include "dodge.hpp"
+#include "burn.hpp"
+#include "carpet.hpp"
 
 class wayfire_extra_animations : public wf::plugin_interface_t
 {
     wf::shared_data::ref_ptr_t<wf::animate::animate_effects_registry_t> effects_registry;
+    wf::option_wrapper_t<bool> dodge_toggle{"extra-animations/dodge_toggle"};
+    wf::option_wrapper_t<wf::animation_description_t> blinds_duration{"extra-animations/blinds_duration"};
+    wf::option_wrapper_t<wf::animation_description_t> helix_duration{"extra-animations/helix_duration"};
+    wf::option_wrapper_t<wf::animation_description_t> shatter_duration{"extra-animations/shatter_duration"};
+    wf::option_wrapper_t<wf::animation_description_t> vortex_duration{"extra-animations/vortex_duration"};
+    wf::option_wrapper_t<wf::animation_description_t> melt_duration{"extra-animations/melt_duration"};
+    wf::option_wrapper_t<wf::animation_description_t> burn_duration{"extra-animations/burn_duration"};
+    wf::option_wrapper_t<wf::animation_description_t> carpet_roll_duration{
+        "extra-animations/carpet_roll_duration"};
+    std::unique_ptr<wf::dodge::wayfire_dodge> dodge_plugin;
 
   public:
     void init() override
@@ -48,24 +61,47 @@ class wayfire_extra_animations : public
 
         effects_registry->register_effect("blinds", wf::animate::effect_description_t{
             .generator = [] { return std::make_unique<wf::blinds::blinds_animation>(); },
-            .default_duration = [=] { return wf::blinds::blinds_duration.value(); },
+            .default_duration = [=] { return blinds_duration.value(); },
         });
         effects_registry->register_effect("helix", wf::animate::effect_description_t{
             .generator = [] { return std::make_unique<wf::helix::helix_animation>(); },
-            .default_duration = [=] { return wf::helix::helix_duration.value(); },
+            .default_duration = [=] { return helix_duration.value(); },
         });
         effects_registry->register_effect("shatter", wf::animate::effect_description_t{
             .generator = [] { return std::make_unique<wf::shatter::shatter_animation>(); },
-            .default_duration = [=] { return wf::shatter::shatter_duration.value(); },
+            .default_duration = [=] { return shatter_duration.value(); },
         });
         effects_registry->register_effect("vortex", wf::animate::effect_description_t{
             .generator = [] { return std::make_unique<wf::vortex::vortex_animation>(); },
-            .default_duration = [=] { return wf::vortex::vortex_duration.value(); },
+            .default_duration = [=] { return vortex_duration.value(); },
         });
         effects_registry->register_effect("melt", wf::animate::effect_description_t{
             .generator = [] { return std::make_unique<wf::melt::melt_animation>(); },
-            .default_duration = [=] { return wf::melt::melt_duration.value(); },
+            .default_duration = [=] { return melt_duration.value(); },
         });
+        effects_registry->register_effect("burn", wf::animate::effect_description_t{
+            .generator = [] { return std::make_unique<wf::burn::burn_animation>(); },
+            .default_duration = [=] { return burn_duration.value(); },
+        });
+        effects_registry->register_effect("carpet", wf::animate::effect_description_t{
+            .generator = [] { return std::make_unique<wf::carpet::carpet_animation>(); },
+            .default_duration = [=] { return carpet_roll_duration.value(); },
+        });
+        dodge_toggle.set_callback([=] {dodge_option_changed();});
+        dodge_option_changed();
+    }
+
+    void dodge_option_changed()
+    {
+        if (dodge_toggle && !dodge_plugin)
+        {
+            dodge_plugin = std::make_unique<wf::dodge::wayfire_dodge>();
+            dodge_plugin->init();
+        } else if (!dodge_toggle && dodge_plugin)
+        {
+            dodge_plugin->fini();
+            dodge_plugin.reset();
+        }
     }
 
     void fini() override
@@ -75,6 +111,14 @@ class wayfire_extra_animations : public
         effects_registry->unregister_effect("shatter");
         effects_registry->unregister_effect("vortex");
         effects_registry->unregister_effect("melt");
+        effects_registry->unregister_effect("burn");
+        effects_registry->unregister_effect("carpet");
+
+        if (dodge_plugin)
+        {
+            dodge_plugin->fini();
+            dodge_plugin.reset();
+        }
     }
 };
 
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/shatter.hpp wayfire-plugins-extra/src/extra-animations/shatter.hpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/shatter.hpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/extra-animations/shatter.hpp	2026-08-01 16:00:35.434368211 -0600
@@ -89,14 +89,6 @@ using namespace wf::animation;
 
 static std::string shatter_transformer_name = "animation-shatter";
 
-wf::option_wrapper_t<wf::animation_description_t> shatter_duration{"extra-animations/shatter_duration"};
-
-class shatter_animation_t : public duration_t
-{
-  public:
-    using duration_t::duration_t;
-    timed_transition_t shatter{*this};
-};
 class shatter_transformer : public wf::scene::view_2d_transformer_t
 {
   public:
@@ -104,7 +96,7 @@ class shatter_transformer : public wf::s
     OpenGL::program_t program;
     wf::output_t *output;
     wf::geometry_t animation_geometry;
-    shatter_animation_t progression{shatter_duration};
+    duration_t progression;
     voronoi_diagram<double> vd;
     std::vector<glm::vec3> rotations;
     std::vector<boost::polygon::point_data<int>> points;
@@ -138,7 +130,7 @@ class shatter_transformer : public wf::s
 
         void schedule_instructions(
             std::vector<render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage) override
+            const wf::render_target_t& target, wf::regionf_t& damage) override
         {
             instructions.push_back(render_instruction_t{
                         .instance = this,
@@ -147,9 +139,9 @@ class shatter_transformer : public wf::s
                     });
         }
 
-        void transform_damage_region(wf::region_t& damage) override
+        void transform_damage_region(wf::regionf_t& damage) override
         {
-            damage |= wf::region_t{self->animation_geometry};
+            damage |= self->animation_geometry;
         }
 
         void render(const wf::scene::render_instruction_t& data) override
@@ -289,9 +281,11 @@ class shatter_transformer : public wf::s
         }
     };
 
-    shatter_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view)
+    shatter_transformer(wayfire_view view, wf::geometry_t bbox,
+        wf::animation_description_t duration) : wf::scene::view_2d_transformer_t(view)
     {
         this->view = view;
+        this->progression = duration_t{wf::create_option(duration)};
         if (view->get_output())
         {
             output = view->get_output();
@@ -378,7 +372,7 @@ class shatter_animation : public animati
         pop_transformer(view);
         auto bbox = view->get_transformed_node()->get_bounding_box();
         auto tmgr = view->get_transformed_node();
-        auto node = std::make_shared<shatter_transformer>(view, bbox);
+        auto node = std::make_shared<shatter_transformer>(view, bbox, dur);
         tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, shatter_transformer_name);
         node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION);
     }
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/extra-animations/vortex.hpp wayfire-plugins-extra/src/extra-animations/vortex.hpp
--- wayfire-plugins-extra-0.10.0/src/extra-animations/vortex.hpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/extra-animations/vortex.hpp	2026-08-01 16:00:35.434368211 -0600
@@ -110,13 +110,6 @@ using namespace wf::animation;
 
 static std::string vortex_transformer_name = "animation-vortex";
 
-wf::option_wrapper_t<wf::animation_description_t> vortex_duration{"extra-animations/vortex_duration"};
-
-class vortex_animation_t : public duration_t
-{
-  public:
-    using duration_t::duration_t;
-};
 class vortex_transformer : public wf::scene::view_2d_transformer_t
 {
   public:
@@ -124,7 +117,7 @@ class vortex_transformer : public wf::sc
     OpenGL::program_t program;
     wf::output_t *output;
     wf::geometry_t animation_geometry;
-    vortex_animation_t progression{vortex_duration};
+    duration_t progression;
 
     class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t<transformer_base_node_t>
     {
@@ -155,7 +148,7 @@ class vortex_transformer : public wf::sc
 
         void schedule_instructions(
             std::vector<render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage) override
+            const wf::render_target_t& target, wf::regionf_t& damage) override
         {
             instructions.push_back(render_instruction_t{
                         .instance = this,
@@ -164,9 +157,9 @@ class vortex_transformer : public wf::sc
                     });
         }
 
-        void transform_damage_region(wf::region_t& damage) override
+        void transform_damage_region(wf::regionf_t& damage) override
         {
-            damage |= wf::region_t{self->animation_geometry};
+            damage |= self->animation_geometry;
         }
 
         void render(const wf::scene::render_instruction_t& data) override
@@ -183,13 +176,13 @@ class vortex_transformer : public wf::sc
             };
 
             const float vertex_data_pos[] = {
-                1.0f * src_box.x,
-                1.0f * src_box.y + src_box.height,
-                1.0f * src_box.x + src_box.width,
-                1.0f * src_box.y + src_box.height,
-                1.0f * src_box.x + src_box.width,
-                1.0f * src_box.y,
-                1.0f * src_box.x, 1.0f * src_box.y,
+                (float)src_box.x,
+                (float)src_box.y + (float)src_box.height,
+                (float)src_box.x + (float)src_box.width,
+                (float)src_box.y + (float)src_box.height,
+                (float)src_box.x + (float)src_box.width,
+                (float)src_box.y,
+                (float)src_box.x, (float)src_box.y,
             };
 
             data.pass->custom_gles_subpass([&]
@@ -207,9 +200,11 @@ class vortex_transformer : public wf::sc
         }
     };
 
-    vortex_transformer(wayfire_view view, wf::geometry_t bbox) : wf::scene::view_2d_transformer_t(view)
+    vortex_transformer(wayfire_view view, wf::geometry_t bbox,
+        wf::animation_description_t duration) : wf::scene::view_2d_transformer_t(view)
     {
         this->view = view;
+        this->progression = duration_t{wf::create_option(duration)};
         if (view->get_output())
         {
             output = view->get_output();
@@ -223,11 +218,6 @@ class vortex_transformer : public wf::sc
         });
     }
 
-    wf::geometry_t get_bounding_box() override
-    {
-        return this->animation_geometry;
-    }
-
     wf::effect_hook_t pre_hook = [=] ()
     {
         output->render->damage(animation_geometry);
@@ -275,7 +265,7 @@ class vortex_animation : public animatio
         pop_transformer(view);
         auto bbox = view->get_transformed_node()->get_bounding_box();
         auto tmgr = view->get_transformed_node();
-        auto node = std::make_shared<vortex_transformer>(view, bbox);
+        auto node = std::make_shared<vortex_transformer>(view, bbox, dur);
         tmgr->add_transformer(node, wf::TRANSFORMER_HIGHLEVEL + 1, vortex_transformer_name);
         node->init_animation(type & WF_ANIMATE_HIDING_ANIMATION);
     }
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/fisheye.cpp wayfire-plugins-extra/src/fisheye.cpp
--- wayfire-plugins-extra-0.10.0/src/fisheye.cpp	1969-12-31 17:00:00.000000000 -0700
+++ wayfire-plugins-extra/src/fisheye.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -0,0 +1,237 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2018 Scott Moreau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <wayfire/per-output-plugin.hpp>
+#include <wayfire/output.hpp>
+#include <wayfire/opengl.hpp>
+#include <wayfire/util/duration.hpp>
+#include <wayfire/render-manager.hpp>
+
+static const char *vertex_shader =
+    R"(
+#version 100
+
+attribute highp vec2 position;
+
+void main() {
+
+    gl_Position = vec4(position.xy, 0.0, 1.0);
+}
+)";
+
+static const char *fragment_shader =
+    R"(
+#version 100
+precision highp float;
+
+uniform vec2 u_resolution;
+uniform vec2 u_mouse;
+uniform float u_radius;
+uniform float u_zoom;
+uniform sampler2D u_texture;
+
+const float PI = 3.1415926535;
+
+void main()
+{
+        float radius = u_radius;
+
+        float zoom = u_zoom;
+        float pw = 1.0 / u_resolution.x;
+        float ph = 1.0 / u_resolution.y;
+
+        vec4 p0 = vec4(u_mouse.x, u_resolution.y - u_mouse.y, 1.0 / radius, 0.0);
+        vec4 p1 = vec4(pw, ph, PI / radius, (zoom - 1.0) * zoom);
+        vec4 p2 = vec4(0, 0, -PI / 2.0, 0.0);
+
+        vec4 t0, t1, t2, t3;
+
+        vec3 tc = vec3(1.0, 0.0, 0.0);
+        vec2 uv = vec2(gl_FragCoord.x, gl_FragCoord.y);
+
+        t1 = p0.xyww - vec4(uv, 0.0, 0.0);
+        t2.x = t2.y = t2.z = t2.w = 1.0 / sqrt(dot(t1.xyz, t1.xyz));
+        t0 = t2 - p0;
+
+        t3.x = t3.y = t3.z = t3.w = 1.0 / t2.x;
+        t3 = t3 * p1.z + p2.z;
+        t3.x = t3.y = t3.z = t3.w = cos(t3.x);
+
+        t3 = t3 * p1.w;
+
+        t1 = t2 * t1;
+        t1 = t1 * t3 + vec4(uv, 0.0, 0.0);
+
+        if (t0.z < 0.0) {
+                t1.x = uv.x;
+                t1.y = uv.y;
+        }
+
+        t1 = t1 * p1 + p2;
+
+        tc = texture2D(u_texture, t1.xy).rgb;
+
+        gl_FragColor = vec4(tc, 1.0);
+}
+)";
+
+class wayfire_fisheye : public wf::per_output_plugin_instance_t
+{
+    wf::animation::simple_animation_t progression{wf::create_option<int>(300)};
+
+    float target_zoom;
+    bool active, hook_set;
+
+    wf::option_wrapper_t<double> radius{"fisheye/radius"};
+    wf::option_wrapper_t<double> zoom{"fisheye/zoom"};
+
+    OpenGL::program_t program;
+
+    wf::plugin_activation_data_t grab_interface = {
+        .name = "fisheye",
+        .capabilities = 0,
+    };
+
+  public:
+    void init() override
+    {
+        if (!wf::get_core().is_gles2())
+        {
+            const char *render_type =
+                wf::get_core().is_vulkan() ? "vulkan" : (wf::get_core().is_pixman() ? "pixman" : "unknown");
+            LOGE("fisheye: requires GLES2 support, but current renderer is ", render_type);
+            return;
+        }
+
+        wf::gles::run_in_context_if_gles([&]
+        {
+            program.set_simple(OpenGL::compile_program(vertex_shader, fragment_shader));
+        });
+
+        hook_set = active = false;
+        output->add_activator(wf::option_wrapper_t<wf::activatorbinding_t>{"fisheye/toggle"}, &toggle_cb);
+
+        target_zoom = zoom;
+        zoom.set_callback([=] ()
+        {
+            if (active)
+            {
+                this->progression.animate(zoom);
+            }
+        });
+    }
+
+    wf::activator_callback toggle_cb = [=] (auto)
+    {
+        if (!output->can_activate_plugin(&grab_interface))
+        {
+            return false;
+        }
+
+        if (active)
+        {
+            active = false;
+            progression.animate(0);
+        } else
+        {
+            active = true;
+            progression.animate(zoom);
+            if (!hook_set)
+            {
+                hook_set = true;
+                output->render->add_post(&render_hook);
+                output->render->set_redraw_always();
+            }
+        }
+
+        return true;
+    };
+
+    wf::post_hook_t render_hook = [=] (wf::auxilliary_buffer_t& source,
+                                       const wf::render_buffer_t& dest)
+    {
+        auto oc = output->get_cursor_position();
+        wf::geometry_t box = {oc.x, oc.y, 1, 1};
+        auto fb_box = output->render->get_target_framebuffer().
+            framebuffer_box_from_geometry_box(box);
+        oc.x = fb_box.x;
+        oc.y = fb_box.y;
+
+        static const float vertexData[] = {
+            -1.0f, -1.0f,
+            1.0f, -1.0f,
+            1.0f, 1.0f,
+            -1.0f, 1.0f
+        };
+
+        wf::gles::run_in_context_if_gles([&]
+        {
+            wf::gles::bind_render_buffer(dest);
+            program.use(wf::TEXTURE_TYPE_RGBA);
+            GL_CALL(glBindTexture(GL_TEXTURE_2D, wf::gles_texture_t::from_aux(source).tex_id));
+            GL_CALL(glActiveTexture(GL_TEXTURE0));
+
+            program.uniform2f("u_mouse", oc.x, dest.get_size().height - oc.y);
+            program.uniform2f("u_resolution", dest.get_size().width, dest.get_size().height);
+            program.uniform1f("u_radius", radius);
+            program.uniform1f("u_zoom", progression);
+
+            program.attrib_pointer("position", 2, 0, vertexData);
+
+            GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
+            GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
+
+            program.deactivate();
+        });
+
+        if (!active && !progression.running())
+        {
+            finalize();
+        }
+    };
+
+    void finalize()
+    {
+        output->render->rem_post(&render_hook);
+        output->render->set_redraw_always(false);
+        hook_set = false;
+    }
+
+    void fini() override
+    {
+        if (hook_set)
+        {
+            finalize();
+        }
+
+        wf::gles::run_in_context_if_gles([&]
+        {
+            program.free_resources();
+        });
+
+        output->rem_binding(&toggle_cb);
+    }
+};
+
+DECLARE_WAYFIRE_PLUGIN(wf::per_output_plugin_t<wayfire_fisheye>);
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/follow-focus.cpp wayfire-plugins-extra/src/follow-focus.cpp
--- wayfire-plugins-extra-0.10.0/src/follow-focus.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/follow-focus.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -43,7 +43,7 @@ class wayfire_follow_focus : public wf::
   private:
     wayfire_view focus_view = nullptr;
     wf::wl_timer<false> change_output_focus, change_view_focus;
-    wf::point_t last_output_coords, last_view_coords;
+    wf::pointf_t last_output_coords, last_view_coords;
 
     wf::option_wrapper_t<bool> should_change_view{"follow-focus/change_view"};
     wf::option_wrapper_t<bool> should_change_output{"follow-focus/change_output"};
@@ -67,7 +67,7 @@ class wayfire_follow_focus : public wf::
     void change_output()
     {
         auto cpf = wf::get_core().get_cursor_position();
-        wf::point_t coords{static_cast<int>(cpf.x), static_cast<int>(cpf.y)};
+        wf::pointf_t coords{cpf.x, cpf.y};
 
         if (output->get_layout_geometry() & coords && (output == focus_output))
         {
@@ -90,7 +90,7 @@ class wayfire_follow_focus : public wf::
         }
 
         auto cpf = wf::get_core().get_cursor_position();
-        wf::point_t coords{static_cast<int>(cpf.x), static_cast<int>(cpf.y)};
+        wf::pointf_t coords{cpf.x, cpf.y};
 
         if (output->get_layout_geometry() & coords && (output != focus_output))
         {
@@ -98,7 +98,7 @@ class wayfire_follow_focus : public wf::
             focus_output = output;
         }
 
-        if (abs(coords - last_output_coords) < threshold)
+        if (wf::abs(coords - last_output_coords) < threshold)
         {
             return;
         }
@@ -142,14 +142,14 @@ class wayfire_follow_focus : public wf::
         }
 
         auto cpf = wf::get_core().get_cursor_position();
-        wf::point_t coords{static_cast<int>(cpf.x), static_cast<int>(cpf.y)};
+        wf::pointf_t coords{cpf.x, cpf.y};
         if (view != focus_view)
         {
             last_view_coords = coords;
             focus_view = view;
         }
 
-        if (abs(coords - last_view_coords) < threshold)
+        if (wf::abs(coords - last_view_coords) < threshold)
         {
             return;
         }
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/force-fullscreen.cpp wayfire-plugins-extra/src/force-fullscreen.cpp
--- wayfire-plugins-extra-0.10.0/src/force-fullscreen.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/force-fullscreen.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -55,21 +55,18 @@ class simple_node_render_instance_t : pu
     node_t *self;
     wayfire_toplevel_view view;
     damage_callback push_to_parent;
-    int *x, *y, *w, *h;
-    wlr_box *transparent_box;
+    wf::geometry_t *geometry;
+    wf::geometry_t *transparent_box;
     wf::option_wrapper_t<bool> transparent_behind_views{
         "force-fullscreen/transparent_behind_views"};
 
   public:
     simple_node_render_instance_t(node_t *self, damage_callback push_damage,
-        wayfire_toplevel_view view, int *x, int *y, int *w, int *h, wlr_box *transparent_box)
+        wayfire_toplevel_view view, wf::geometry_t *geometry, wf::geometry_t *transparent_box)
     {
-        this->x    = x;
-        this->y    = y;
-        this->w    = w;
-        this->h    = h;
-        this->self = self;
-        this->view = view;
+        this->geometry = geometry;
+        this->self     = self;
+        this->view     = view;
         this->transparent_box = transparent_box;
         this->push_to_parent  = push_damage;
         self->connect(&on_node_damaged);
@@ -77,7 +74,7 @@ class simple_node_render_instance_t : pu
 
     void schedule_instructions(
         std::vector<render_instruction_t>& instructions,
-        const wf::render_target_t& target, wf::region_t& damage) override
+        const wf::render_target_t& target, wf::regionf_t& damage) override
     {
         // We want to render ourselves only, the node does not have children
         instructions.push_back(render_instruction_t{
@@ -96,7 +93,7 @@ class simple_node_render_instance_t : pu
             return;
         }
 
-        wf::region_t scissor_region{data.damage};
+        wf::regionf_t scissor_region{data.damage};
         if (transparent_behind_views)
         {
             auto bbox = *transparent_box;
@@ -104,7 +101,7 @@ class simple_node_render_instance_t : pu
             bbox.y     += 1;
             bbox.width -= 2;
             bbox.height    -= 2;
-            scissor_region ^= wf::region_t{bbox};
+            scissor_region ^= wf::regionf_t{bbox};
         }
 
         data.pass->clear(scissor_region, {0, 0, 0, 1});
@@ -114,18 +111,18 @@ class simple_node_render_instance_t : pu
 class black_border_node_t : public node_t
 {
     wayfire_toplevel_view view;
-    wlr_box transparent_box;
+    wf::geometry_t transparent_box;
 
   public:
-    int x, y, w, h;
+    wf::geometry_t geometry;
 
     black_border_node_t(wayfire_toplevel_view view, int x, int y, int w,
-        int h, wlr_box transparent_box) : node_t(false)
+        int h, wf::geometry_t transparent_box) : node_t(false)
     {
-        this->x    = x;
-        this->y    = y;
-        this->w    = w;
-        this->h    = h;
+        this->geometry.x     = x;
+        this->geometry.y     = y;
+        this->geometry.width = w;
+        this->geometry.height = h;
         this->view = view;
         this->transparent_box = transparent_box;
     }
@@ -138,13 +135,13 @@ class black_border_node_t : public node_
         // this simple nodes does not need any transformations, so the push_damage
         // callback is just passed along.
         instances.push_back(std::make_unique<simple_node_render_instance_t>(
-            this, push_damage, view, &x, &y, &w, &h, &transparent_box));
+            this, push_damage, view, &geometry, &transparent_box));
     }
 
     wf::geometry_t get_bounding_box() override
     {
         // Specify whatever geometry your node has
-        return {x, y, w, h};
+        return geometry;
     }
 };
 
@@ -156,7 +153,7 @@ class fullscreen_background
     std::shared_ptr<wf::scene::view_2d_transformer_t> transformer;
     std::shared_ptr<black_border_node_t> black_border_node;
     bool black_border = false;
-    wlr_box transformed_view_box;
+    wf::geometry_t transformed_view_box;
 
     fullscreen_background(wayfire_toplevel_view view)
     {}
@@ -216,11 +213,11 @@ class wayfire_force_fullscreen : public
                 int x = offset.x * og.width;
                 int y = offset.y * og.height;
                 b.second->transformed_view_box.x = x + w;
-                b.second->black_border_node->x   = x;
-                b.second->black_border_node->y   = y;
-                b.second->black_border_node->w   = og.width;
-                b.second->black_border_node->h   = og.height;
-                b.second->transformed_view_box.y = b.second->black_border_node->y =
+                b.second->black_border_node->geometry.x     = x;
+                b.second->black_border_node->geometry.y     = y;
+                b.second->black_border_node->geometry.width = og.width;
+                b.second->black_border_node->geometry.height = og.height;
+                b.second->transformed_view_box.y = b.second->black_border_node->geometry.y =
                     y;
             }
 
@@ -228,7 +225,7 @@ class wayfire_force_fullscreen : public
         }
     };
 
-    void ensure_subsurface(wayfire_toplevel_view view, wlr_box transformed_view_box)
+    void ensure_subsurface(wayfire_toplevel_view view, wf::geometry_t transformed_view_box)
     {
         auto pair = backgrounds.find(view);
 
@@ -289,7 +286,7 @@ class wayfire_force_fullscreen : public
             scale_x = scale_y = std::min(scale_x, scale_y);
         }
 
-        wlr_box box;
+        wf::geometry_t box;
         box.width  = std::floor(vg.width * scale_x);
         box.height = std::floor(vg.height * scale_y);
         box.x = std::ceil((og.width - box.width) / 2.0);
@@ -332,7 +329,7 @@ class wayfire_force_fullscreen : public
             return false;
         }
 
-        wlr_box saved_geometry = view->get_geometry();
+        wf::geometry_t saved_geometry = view->get_geometry();
 
         auto background = backgrounds.find(view);
         bool fullscreen = background == backgrounds.end() ? true : false;
@@ -340,7 +337,7 @@ class wayfire_force_fullscreen : public
         view->toplevel()->pending().fullscreen = fullscreen;
         wf::get_core().tx_manager->schedule_object(view->toplevel());
 
-        wlr_box undecorated_geometry = view->get_geometry();
+        wf::geometry_t undecorated_geometry = view->get_geometry();
 
         if (!fullscreen)
         {
@@ -505,7 +502,7 @@ class wayfire_force_fullscreen : public
         for (auto& b : backgrounds)
         {
             auto view = wf::get_active_view_for_output(output);
-            wlr_box box;
+            wf::geometry_t box;
 
             box    = b.second->transformed_view_box;
             box.x += og.x;
@@ -519,7 +516,8 @@ class wayfire_force_fullscreen : public
             if ((b.first == view) &&
                 !(box & wf::pointf_t{cursor.x, cursor.y}))
             {
-                wlr_box_closest_point(&box, cursor.x, cursor.y,
+                auto ibox = wf::to_integer_box(box);
+                wlr_box_closest_point(&ibox, cursor.x, cursor.y,
                     &cursor.x, &cursor.y);
                 ev->event->delta_x = ev->event->unaccel_dx =
                     cursor.x - last_cursor.x;
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/keycolor.cpp wayfire-plugins-extra/src/keycolor.cpp
--- wayfire-plugins-extra-0.10.0/src/keycolor.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/keycolor.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -130,7 +130,7 @@ class simple_node_render_instance_t : pu
 
     void schedule_instructions(
         std::vector<render_instruction_t>& instructions,
-        const wf::render_target_t& target, wf::region_t& damage) override
+        const wf::render_target_t& target, wf::regionf_t& damage) override
     {
         // We want to render ourselves only, the node does not have children
         instructions.push_back(render_instruction_t{
@@ -196,7 +196,7 @@ class simple_node_render_instance_t : pu
 
             for (const auto& box : data.damage)
             {
-                wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
+                wf::gles::render_target_logic_scissor(data.target, box);
                 GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
             }
 
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/mag.cpp wayfire-plugins-extra/src/mag.cpp
--- wayfire-plugins-extra-0.10.0/src/mag.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/mag.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -71,7 +71,8 @@ class mag_view_t : public wf::toplevel_v
                 /* Draw the inside of the rect, if we have already captured the output's contents */
                 if (view->mag_tex.get_buffer() != NULL)
                 {
-                    data.pass->add_texture({view->mag_tex.get_texture()}, data.target, geometry, data.damage);
+                    data.pass->add_texture(wf::texture_t::from_aux(
+                        view->mag_tex), data.target, geometry, data.damage);
                 }
             }
         };
@@ -296,7 +297,7 @@ class wayfire_magnifier : public wf::per
     {
         auto og = output->get_relative_geometry();
         float aspect = (float)og.width / og.height;
-        wf::geometry_t start_geometry = {100, 100, (int)(default_height * aspect), default_height};
+        wf::geometry_t start_geometry = {100, 100, default_height *aspect, (double)default_height};
         return start_geometry;
     }
 
@@ -344,7 +345,7 @@ class wayfire_magnifier : public wf::per
             glm::translate(glm::mat4(1.0), glm::vec3(0.5, 0.5, 0.0)) *
             glm::scale(glm::mat4(1.0), glm::vec3{0.5, -0.5, 1.0}) * ortho;
 
-        glm::vec4 cursor = glm::vec4(cursor_position.x, cursor_position.y, 0.0, 1.0);
+        glm::vec4 cursor = glm::vec4((int)cursor_position.x, (int)cursor_position.y, 0.0, 1.0);
         cursor = cursor_transform * cursor;
 
         float x = cursor.x;
@@ -399,10 +400,10 @@ class wayfire_magnifier : public wf::per
             zoom_box.y2  = 1.0;
         }
 
-        zoom_box.x1 *= width - 1;
-        zoom_box.x2 *= width - 1;
-        zoom_box.y1 *= height - 1;
-        zoom_box.y2 *= height - 1;
+        zoom_box.x1 *= width;
+        zoom_box.x2 *= width;
+        zoom_box.y1 *= height;
+        zoom_box.y2 *= height;
 
         /* Copy zoom_box part of the output to our own texture to be
          * read by the mag_view_t. */
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/meson.build wayfire-plugins-extra/src/meson.build
--- wayfire-plugins-extra-0.10.0/src/meson.build	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/meson.build	2026-08-01 16:00:35.434368211 -0600
@@ -16,6 +16,10 @@ crosshair = shared_module('crosshair', '
     dependencies: [wayfire],
     install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))
 
+fisheye = shared_module('fisheye', 'fisheye.cpp',
+    dependencies: [wayfire],
+    install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))
+
 focus_change = shared_module('focus-change', 'focus-change.cpp',
     dependencies: [wayfire],
     install: true, install_dir: join_paths(get_option('libdir'), 'wayfire'))
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/obs.cpp wayfire-plugins-extra/src/obs.cpp
--- wayfire-plugins-extra-0.10.0/src/obs.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/obs.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -138,7 +138,7 @@ class wf_obs : public wf::scene::view_2d
         }
 
         void schedule_instructions(std::vector<render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage) override
+            const wf::render_target_t& target, wf::regionf_t& damage) override
         {
             // We want to render ourselves only, the node does not have children
             instructions.push_back(render_instruction_t{
@@ -190,7 +190,7 @@ class wf_obs : public wf::scene::view_2d
 
                 for (const auto& box : data.damage)
                 {
-                    wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
+                    wf::gles::render_target_logic_scissor(data.target, box);
                     OpenGL::render_transformed_texture(final_tex, view_box,
                         wf::gles::render_target_orthographic_projection(data.target),
                         glm::vec4(1.0), 0);
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/showrepaint.cpp wayfire-plugins-extra/src/showrepaint.cpp
--- wayfire-plugins-extra-0.10.0/src/showrepaint.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/showrepaint.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -119,13 +119,13 @@ class wayfire_showrepaint : public wf::p
     wf::effect_hook_t overlay_hook = [=] ()
     {
         auto target_fb = output->render->get_target_framebuffer();
-        wf::region_t swap_damage = target_fb.geometry_region_from_framebuffer_region(
+        wf::regionf_t swap_damage = target_fb.geometry_region_from_framebuffer_region(
             output->render->get_swap_damage());
 
-        wf::region_t scheduled_damage = output->render->get_scheduled_damage();
-        wf::region_t output_region{target_fb.geometry};
-        wf::region_t inverted_damage;
-        wf::region_t damage;
+        wf::regionf_t scheduled_damage = output->render->get_scheduled_damage();
+        wf::regionf_t output_region{target_fb.geometry};
+        wf::regionf_t inverted_damage;
+        wf::regionf_t damage;
 
         /* Show scheduled client damage. Scheduled damage is the client damage
          * in union with last frame client damage. If this region is empty, we
@@ -167,9 +167,8 @@ class wayfire_showrepaint : public wf::p
          */
         if (last_buffer.get_size().width > 0)
         {
-            wf::texture_t texture;
-            texture.texture   = last_buffer.get_texture();
-            texture.transform = target_fb.wl_transform;
+            std::shared_ptr<wf::texture_t> texture = wf::texture_t::from_aux(last_buffer);
+            texture->set_transform(target_fb.wl_transform);
             rpass->add_texture(texture, target_fb, target_fb.geometry, inverted_damage);
         }
     };
@@ -189,8 +188,8 @@ class wayfire_showrepaint : public wf::p
          */
         auto target_fb = output->render->get_target_framebuffer();
         last_buffer.allocate(target_fb.get_size());
-        wlr_box full = wf::construct_box({0, 0}, target_fb.get_size());
-        last_buffer.get_renderbuffer().blit(target_fb, wf::geometry_to_fbox(full), full);
+        wf::geometry_t full = wf::construct_box({0, 0}, target_fb.get_size());
+        last_buffer.get_renderbuffer().blit(target_fb, full, full);
     };
 
     void fini() override
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/showtouch.cpp wayfire-plugins-extra/src/showtouch.cpp
--- wayfire-plugins-extra-0.10.0/src/showtouch.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/showtouch.cpp	2026-08-01 16:00:35.434368211 -0600
@@ -324,6 +324,7 @@ class wayfire_showtouch : public wf::per
 
         wf::gles::run_in_context([&]
         {
+            wf::gles::bind_render_buffer(dest);
             program.use(wf::TEXTURE_TYPE_RGBA);
             program.set_active_texture(tex);
 
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/window-zoom.cpp wayfire-plugins-extra/src/window-zoom.cpp
--- wayfire-plugins-extra-0.10.0/src/window-zoom.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/window-zoom.cpp	2026-08-01 16:00:35.434602314 -0600
@@ -60,14 +60,14 @@ class simple_node_render_instance_t : pu
     node_t *self;
     wayfire_toplevel_view view;
     float *scale_x, *scale_y;
-    wlr_box *transformed_view_geometry;
+    wf::geometry_t *transformed_view_geometry;
     damage_callback push_damage;
     wf::option_wrapper_t<bool> nearest_filtering{"winzoom/nearest_filtering"};
 
   public:
     simple_node_render_instance_t(transformer_base_node_t *self, damage_callback push_damage,
         wayfire_toplevel_view view, float *scale_x, float *scale_y,
-        wlr_box *transformed_view_geometry) :
+        wf::geometry_t *transformed_view_geometry) :
         transformer_render_instance_t<transformer_base_node_t>(self, push_damage,
             view->get_output())
     {
@@ -89,7 +89,7 @@ class simple_node_render_instance_t : pu
 
     void schedule_instructions(
         std::vector<render_instruction_t>& instructions,
-        const wf::render_target_t& target, wf::region_t& damage) override
+        const wf::render_target_t& target, wf::regionf_t& damage) override
     {
         // We want to render ourselves only, the node does not have children
         instructions.push_back(render_instruction_t{
@@ -99,16 +99,16 @@ class simple_node_render_instance_t : pu
                     });
     }
 
-    void transform_damage_region(wf::region_t& damage) override
+    void transform_damage_region(wf::regionf_t& damage) override
     {
         damage |= view->get_transformed_node()->get_children_bounding_box();
     }
 
-    wlr_box get_scaled_geometry()
+    wf::geometry_t get_scaled_geometry()
     {
         auto vg = view->get_geometry();
         auto midpoint = get_center(vg);
-        auto result   = wf::pointf_t{float(vg.x), float(vg.y)} - midpoint;
+        auto result   = wf::pointf_t{vg.x, vg.y} - midpoint;
         result.x *= *scale_x;
         result.y *= *scale_y;
         result   += midpoint;
@@ -123,7 +123,7 @@ class simple_node_render_instance_t : pu
     {
         auto src_tex = get_texture(1.0);
         auto scaled_geometry = get_scaled_geometry();
-        src_tex.filter_mode = nearest_filtering ? WLR_SCALE_FILTER_NEAREST : WLR_SCALE_FILTER_BILINEAR;
+        src_tex->set_filter_mode(nearest_filtering ? WLR_SCALE_FILTER_NEAREST : WLR_SCALE_FILTER_BILINEAR);
         data.pass->add_texture(src_tex, data.target, scaled_geometry, data.damage);
     }
 };
@@ -131,7 +131,7 @@ class simple_node_render_instance_t : pu
 class winzoom_t : public view_2d_transformer_t
 {
     wayfire_toplevel_view view;
-    wlr_box transformed_view_geometry;
+    wf::geometry_t transformed_view_geometry;
 
   public:
     winzoom_t(wayfire_toplevel_view view) : view_2d_transformer_t(view)
diff --color -Naurp wayfire-plugins-extra-0.10.0/src/workspace-names.cpp wayfire-plugins-extra/src/workspace-names.cpp
--- wayfire-plugins-extra-0.10.0/src/workspace-names.cpp	2025-08-11 22:03:47.000000000 -0600
+++ wayfire-plugins-extra/src/workspace-names.cpp	2026-08-01 16:00:35.434602314 -0600
@@ -1,7 +1,7 @@
 /*
  * The MIT License (MIT)
  *
- * Copyright (c) 2023 Scott Moreau
+ * Copyright (c) 2026 Scott Moreau
  *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
@@ -91,7 +91,7 @@ class simple_node_render_instance_t : pu
 
     void schedule_instructions(
         std::vector<render_instruction_t>& instructions,
-        const wf::render_target_t& target, wf::region_t& damage) override
+        const wf::render_target_t& target, wf::regionf_t& damage) override
     {
         // We want to render ourselves only, the node does not have children
         instructions.push_back(render_instruction_t{
@@ -113,7 +113,7 @@ class simple_node_render_instance_t : pu
                 wf::gles::bind_render_buffer(data.target);
                 for (auto& box : data.damage)
                 {
-                    wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
+                    wf::gles::render_target_logic_scissor(data.target, box);
                     OpenGL::render_texture(wf::gles_texture_t{workspace->texture->get_texture()},
                         data.target, g, glm::vec4(1, 1, 1, *alpha_fade), 0);
                 }
@@ -132,13 +132,20 @@ class simple_node_t : public node_t
 
   public:
     std::shared_ptr<workspace_name> workspace;
-    simple_node_t(wf::point_t offset) : node_t(false)
+    wf::point_t ws;
+    simple_node_t(wf::point_t offset, wf::point_t ws) : node_t(false)
     {
-        this->offset     = offset;
+        this->ws     = ws;
+        this->offset = offset;
         this->alpha_fade = 0.0;
         workspace = std::make_shared<workspace_name>();
     }
 
+    ~simple_node_t()
+    {
+        workspace = nullptr;
+    }
+
     void gen_render_instances(std::vector<render_instance_uptr>& instances,
         damage_callback push_damage, wf::output_t *shown_on) override
     {
@@ -150,7 +157,7 @@ class simple_node_t : public node_t
             this, push_damage, &offset, &alpha_fade, workspace));
     }
 
-    void do_push_damage(wf::region_t updated_region)
+    void do_push_damage(wf::regionf_t updated_region)
     {
         node_damage_signal ev;
         ev.region = updated_region;
@@ -164,10 +171,14 @@ class simple_node_t : public node_t
             workspace->rect.width, workspace->rect.height};
     }
 
-    void set_offset(int x, int y)
+    void set_offset(wf::point_t offset)
+    {
+        this->offset = offset;
+    }
+
+    wf::point_t get_ws()
     {
-        this->offset.x = x;
-        this->offset.y = y;
+        return this->ws;
     }
 
     void set_alpha(double alpha)
@@ -177,9 +188,9 @@ class simple_node_t : public node_t
 };
 
 std::shared_ptr<simple_node_t> add_simple_node(wf::output_t *output,
-    wf::point_t offset)
+    wf::point_t offset, wf::point_t ws)
 {
-    auto subnode = std::make_shared<simple_node_t>(offset);
+    auto subnode = std::make_shared<simple_node_t>(offset, ws);
     wf::scene::add_front(output->node_for_layer(wf::scene::layer::OVERLAY), subnode);
     return subnode;
 }
@@ -187,8 +198,7 @@ std::shared_ptr<simple_node_t> add_simpl
 class wayfire_workspace_names_output : public wf::per_output_plugin_instance_t
 {
     wf::wl_timer<false> timer;
-    bool hook_set  = false;
-    bool timed_out = false;
+    bool hook_set = false;
     std::vector<std::vector<std::shared_ptr<simple_node_t>>> workspaces;
     wf::option_wrapper_t<std::string> font{"workspace-names/font"};
     wf::option_wrapper_t<std::string> position{"workspace-names/position"};
@@ -208,76 +218,90 @@ class wayfire_workspace_names_output : p
     void init() override
     {
         alpha_fade.set(0, 0);
-        timed_out = false;
 
+        output->wset()->connect(&workspace_grid_changed);
+        output->connect(&workarea_changed);
+        output->connect(&viewport_changed);
+        output->connect(&viewport_change_request);
+        font.set_callback(option_changed);
+        position.set_callback(option_changed);
+        background_color.set_callback(option_changed);
+        text_color.set_callback(option_changed);
+        show_option_values.set_callback(option_changed);
+        show_option_names.set_callback(show_options_changed);
+
+        if (show_option_names)
+        {
+            show_options_changed();
+        }
+    }
+
+    void init_workspace_name_nodes()
+    {
         auto wsize = output->wset()->get_workspace_grid_size();
+        auto og    = output->get_relative_geometry();
         workspaces.resize(wsize.width);
         for (int x = 0; x < wsize.width; x++)
         {
             workspaces[x].resize(wsize.height);
         }
 
-        auto og = output->get_relative_geometry();
         for (int x = 0; x < wsize.width; x++)
         {
             for (int y = 0; y < wsize.height; y++)
             {
-                workspaces[x][y] = add_simple_node(output, {x *og.width,
-                    y * og.height});
+                workspaces[x][y] = add_simple_node(output, {int(x * og.width),
+                    int(y * og.height)}, {x, y});
             }
         }
+    }
 
-        output->connect(&workarea_changed);
-        output->connect(&viewport_changed);
-        font.set_callback(option_changed);
-        position.set_callback(option_changed);
-        background_color.set_callback(option_changed);
-        text_color.set_callback(option_changed);
-        show_option_names.set_callback(show_options_changed);
-
-        if (show_option_names)
-        {
-            show_options_changed();
-        } else
+    void fini_workspace_name_nodes()
+    {
+        for (auto & x : workspaces)
         {
-            update_names();
+            for (auto & workspace : x)
+            {
+                auto& wsn = workspace->workspace;
+                cairo_surface_destroy(wsn->cairo_surface);
+                cairo_destroy(wsn->cr);
+                wf::scene::remove_child(workspace);
+                workspace.reset();
+            }
         }
-
-        wf::get_core().connect(&reload_config);
     }
 
-    wf::signal::connection_t<wf::reload_config_signal> reload_config{[this] (wf::reload_config_signal *ev)
+    wf::signal::connection_t<wf::workspace_grid_changed_signal> workspace_grid_changed{[this] (wf::
+                                                                                               workspace_grid_changed_signal
+                                                                                               *ev)
         {
-            update_names();
+            deactivate();
+            init_workspace_name_nodes();
         }
     };
 
     wf::config::option_base_t::updated_callback_t show_options_changed = [=] ()
     {
-        update_names();
-
-        viewport_changed.emit(nullptr);
-
         if (show_option_names)
         {
-            timer.disconnect();
-            output->render->rem_effect(&post_hook);
+            activate();
+            update_names();
+            viewport_changed.emit(nullptr);
+            alpha_fade.animate(alpha_fade, 1);
         } else
         {
-            output->connect(&viewport_changed);
-            output->render->add_effect(&post_hook, wf::OUTPUT_EFFECT_POST);
+            alpha_fade.animate(alpha_fade, 0);
         }
 
-        alpha_fade.animate(alpha_fade, 1.0);
         output->render->damage_whole();
     };
 
-    void update_name(int x, int y)
+    void update_name(std::shared_ptr<simple_node_t> workspace)
     {
         auto section = wf::get_core().config->get_section("workspace-names");
         auto wsize   = output->wset()->get_workspace_grid_size();
-        auto wsn     = workspaces[x][y]->workspace;
-        int ws_num   = x + y * wsize.width + 1;
+        auto wsn     = workspace->workspace;
+        int ws_num   = workspace->get_ws().x + workspace->get_ws().y * wsize.width + 1;
 
         // Get the option name (key) of the target workspace
         std::string key = output->to_string() + "_workspace_" + std::to_string(ws_num);
@@ -327,13 +351,12 @@ class wayfire_workspace_names_output : p
 
     void update_names()
     {
-        auto wsize = output->wset()->get_workspace_grid_size();
-        for (int x = 0; x < wsize.width; x++)
+        for (auto & x : workspaces)
         {
-            for (int y = 0; y < wsize.height; y++)
+            for (auto & workspace : x)
             {
-                update_name(x, y);
-                update_texture(workspaces[x][y]->workspace);
+                update_name(workspace);
+                update_texture(workspace->workspace);
             }
         }
     }
@@ -400,7 +423,11 @@ class wayfire_workspace_names_output : p
 
     wf::config::option_base_t::updated_callback_t option_changed = [=] ()
     {
-        update_textures();
+        if (hook_set)
+        {
+            update_names();
+            update_textures();
+        }
     };
 
     void update_texture_position(std::shared_ptr<workspace_name> wsn)
@@ -455,6 +482,7 @@ class wayfire_workspace_names_output : p
     wf::signal::connection_t<wf::workarea_changed_signal> workarea_changed{[this] (wf::workarea_changed_signal
                                                                                    *ev)
         {
+            update_workspace_names_timeout();
             update_textures();
         }
     };
@@ -528,73 +556,68 @@ class wayfire_workspace_names_output : p
         if (alpha_fade.running())
         {
             set_alpha();
-            output->render->damage_whole();
         }
     };
 
-    wf::signal::connection_t<wf::workspace_changed_signal> viewport_changed{[this] (wf::
-                                                                                    workspace_changed_signal*
-                                                                                    ev)
-        {
-            auto wsize = output->wset()->get_workspace_grid_size();
-            auto nvp   = output->wset()->get_current_workspace();
-            auto og    = output->get_relative_geometry();
+    void update_workspace_names_timeout()
+    {
+        auto wsize = output->wset()->get_workspace_grid_size();
+        auto nvp   = output->wset()->get_current_workspace();
+        auto og    = output->get_relative_geometry();
+
+        activate();
+        update_textures();
+        update_names();
 
-            for (int x = 0; x < wsize.width; x++)
+        for (int x = 0; x < wsize.width; x++)
+        {
+            for (int y = 0; y < wsize.height; y++)
             {
-                for (int y = 0; y < wsize.height; y++)
-                {
-                    workspaces[x][y]->set_offset((x - nvp.x) * og.width,
-                        (y - nvp.y) * og.height);
-                }
+                workspaces[x][y]->set_offset({int((x - nvp.x) * og.width), int((y - nvp.y) * og.height)});
             }
+        }
 
-            output->render->damage_whole();
+        output->render->damage_whole();
 
-            activate();
+        if (show_option_names)
+        {
+            return;
+        }
 
-            if (show_option_names)
-            {
-                return;
-            }
+        alpha_fade.animate(alpha_fade, 1);
 
-            if (!alpha_fade.running())
-            {
-                if (!timer.is_connected())
-                {
-                    alpha_fade.animate(alpha_fade, 1.0);
-                }
-            } else if (timed_out)
-            {
-                timed_out = false;
-                alpha_fade.animate(alpha_fade, 1.0);
-            }
+        timer.disconnect();
+        timer.set_timeout((int)display_duration, timeout);
+    }
 
-            timer.disconnect();
-            timer.set_timeout((int)display_duration, timeout);
+    wf::signal::connection_t<wf::workspace_change_request_signal> viewport_change_request{[this] (wf::
+                                                                                                  workspace_change_request_signal
+                                                                                                  *
+                                                                                                  ev)
+        {
+            update_workspace_names_timeout();
+        }
+    };
+
+    wf::signal::connection_t<wf::workspace_changed_signal> viewport_changed{[this] (wf::
+                                                                                    workspace_changed_signal*
+                                                                                    ev)
+        {
+            update_workspace_names_timeout();
         }
     };
 
     wf::wl_timer<false>::callback_t timeout = [=] ()
     {
         output->render->damage_whole();
-        alpha_fade.animate(1.0, 0.0);
-        timed_out = true;
+        alpha_fade.animate(alpha_fade, 0);
     };
 
     wf::effect_hook_t post_hook = [=] ()
     {
-        if (!alpha_fade.running())
+        if (!alpha_fade.running() && !timer.is_connected() && !show_option_names)
         {
-            if (timed_out)
-            {
-                deactivate();
-                timed_out = false;
-                output->render->damage_whole();
-            } else if (!timer.is_connected())
-            {
-                timer.set_timeout((int)display_duration, timeout);
-            }
+            deactivate();
         } else
         {
             set_alpha();
@@ -608,6 +631,7 @@ class wayfire_workspace_names_output : p
             return;
         }
 
+        init_workspace_name_nodes();
         output->render->add_effect(&post_hook, wf::OUTPUT_EFFECT_POST);
         output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
         output->render->damage_whole();
@@ -621,6 +645,8 @@ class wayfire_workspace_names_output : p
             return;
         }
 
+        timer.disconnect();
+        fini_workspace_name_nodes();
         output->render->rem_effect(&post_hook);
         output->render->rem_effect(&pre_hook);
         hook_set = false;
@@ -629,18 +655,10 @@ class wayfire_workspace_names_output : p
     void fini() override
     {
         deactivate();
-        auto wsize = output->wset()->get_workspace_grid_size();
-        for (int x = 0; x < wsize.width; x++)
-        {
-            for (int y = 0; y < wsize.height; y++)
-            {
-                auto& wsn = workspaces[x][y]->workspace;
-                cairo_surface_destroy(wsn->cairo_surface);
-                cairo_destroy(wsn->cr);
-                wf::scene::remove_child(workspaces[x][y]);
-                workspaces[x][y].reset();
-            }
-        }
+        workspace_grid_changed.disconnect();
+        viewport_change_request.disconnect();
+        viewport_changed.disconnect();
+        workarea_changed.disconnect();
 
         output->render->damage_whole();
     }
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/filter-tiled.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/filter-tiled.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/filter-tiled.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/filter-tiled.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,45 +0,0 @@
-#!/usr/bin/python3
-
-# A simple script to apply a filter to untiled views.
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-if len(sys.argv) < 2:
-    print("Required arguments: </path/to/shader>")
-    exit(-1)
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-sock.watch()
-
-def toggle_filter(view):
-    try:
-        if view["tiled-edges"] == 0:
-            if wpe.view_has_shader(int(view["id"]))["has-shader"] is False:
-                wpe.set_view_shader(int(view["id"]), os.path.abspath(str(sys.argv[1])))
-        else:
-            if wpe.view_has_shader(int(view["id"]))["has-shader"] is True:
-                wpe.unset_view_shader(int(view["id"]))
-    except:
-        pass
-
-views = sock.list_views()
-for view in views:
-    toggle_filter(view)
-
-while True:
-    try:
-        msg = sock.read_next_event()
-        if "event" in msg and "view" in msg and (msg["view"] is not None):
-            toggle_filter(msg["view"])
-    except KeyboardInterrupt:
-        views = sock.list_views()
-        for view in views:
-            try:
-                wpe.unset_view_shader(int(view["id"]))
-            except:
-                pass
-        exit(0)
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/fs-has-shader.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/fs-has-shader.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/fs-has-shader.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/fs-has-shader.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,11 +0,0 @@
-#!/usr/bin/python3
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-
-print(f'Output {sys.argv[1]} has shader: {wpe.fs_has_shader(sys.argv[1])["has-shader"]}')
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/set-fs-shader.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/set-fs-shader.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/set-fs-shader.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/set-fs-shader.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,15 +0,0 @@
-#!/usr/bin/python3
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-if len(sys.argv) < 3:
-    print("Required arguments: <Output name> </path/to/shader>")
-    exit(-1)
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-
-wpe.set_fs_shader(str(sys.argv[1]), os.path.abspath(str(sys.argv[2])))
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/set-inactive-views.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/set-inactive-views.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/set-inactive-views.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/set-inactive-views.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,48 +0,0 @@
-#!/usr/bin/python3
-
-# A simple script to apply a shader to all views except the active view
-# When a new view is focused, the shader is applied to the previously
-# active view. It skips app-id "panel", as this is wf-panel's app-id.
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-if len(sys.argv) == 1:
-    print(f"Usage: {sys.argv[0]} /path/to/filters/shader")
-    exit(-1)
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-sock.watch(['view-focused'])
-
-def unset_view_shaders():
-    for view in sock.list_views():
-        wpe.unset_view_shader(view["id"])
-
-active_view_id = sock.get_focused_view()["id"]
-active_view_app_id = sock.get_focused_view()["app-id"]
-for view in sock.list_views():
-    view_id = view["id"]
-    if view_id != active_view_id and view["app-id"] != "panel":
-        wpe.set_view_shader(view_id, os.path.abspath(str(sys.argv[1])))
-last_active_view_id = active_view_id
-last_active_view_app_id = active_view_app_id
-
-while True:
-    try:
-        msg = sock.read_next_event()
-        if "event" in msg:
-            active_view_id = sock.get_focused_view()["id"]
-            active_view_app_id = sock.get_focused_view()["app-id"]
-            if last_active_view_id != active_view_id and last_active_view_app_id != "panel":
-                wpe.set_view_shader(last_active_view_id, os.path.abspath(str(sys.argv[1])))
-                wpe.unset_view_shader(active_view_id)
-            last_active_view_id = active_view_id
-            last_active_view_app_id = active_view_app_id
-    except KeyboardInterrupt:
-        unset_view_shaders()
-        exit(0)
-    except:
-        pass
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/set-view-shader.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/set-view-shader.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/set-view-shader.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/set-view-shader.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,15 +0,0 @@
-#!/usr/bin/python3
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-if len(sys.argv) < 3:
-    print("Required arguments: <View ID> </path/to/shader>")
-    exit(-1)
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-
-wpe.set_view_shader(int(sys.argv[1]), os.path.abspath(str(sys.argv[2])))
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/toggle-fs-shader.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/toggle-fs-shader.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/toggle-fs-shader.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/toggle-fs-shader.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,22 +0,0 @@
-#!/usr/bin/python3
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-if len(sys.argv) < 2:
-    print("Required argument: Output name")
-    exit(-1)
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-
-has_shader = wpe.fs_has_shader(str(sys.argv[1]))["has-shader"]
-
-print(f'Fullscreen {sys.argv[1]} has shader: {has_shader}')
-
-if has_shader:
-    wpe.unset_fs_shader(str(sys.argv[1]))
-else:
-    wpe.set_fs_shader(str(sys.argv[1]), os.path.abspath(os.path.join(os.path.dirname(__file__), '../shaders/crt')))
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/unset-fs-shader.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/unset-fs-shader.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/unset-fs-shader.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/unset-fs-shader.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,15 +0,0 @@
-#!/usr/bin/python3
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-if len(sys.argv) < 2:
-    print("Required argument: Output name")
-    exit(-1)
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-
-wpe.unset_fs_shader(str(sys.argv[1]))
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/unset-view-shader.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/unset-view-shader.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/unset-view-shader.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/unset-view-shader.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,11 +0,0 @@
-#!/usr/bin/python3
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-
-wpe.unset_view_shader(int(sys.argv[1]))
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/view-has-shader.py wayfire-plugins-extra/subprojects/filters/ipc-scripts/view-has-shader.py
--- wayfire-plugins-extra-0.10.0/subprojects/filters/ipc-scripts/view-has-shader.py	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/ipc-scripts/view-has-shader.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,11 +0,0 @@
-#!/usr/bin/python3
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-
-print(f'View {sys.argv[1]} has shader: {wpe.view_has_shader(int(sys.argv[1]))["has-shader"]}')
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/meson.build wayfire-plugins-extra/subprojects/filters/meson.build
--- wayfire-plugins-extra-0.10.0/subprojects/filters/meson.build	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/meson.build	1969-12-31 17:00:00.000000000 -0700
@@ -1,22 +0,0 @@
-project(
-    'filters',
-    'c',
-    'cpp',
-    version: '0.1.0',
-    license: 'MIT',
-    meson_version: '>=0.51.0',
-    default_options: [
-        'cpp_std=c++17',
-        'c_std=c11',
-    ],
-)
-
-add_project_arguments(['-DWLR_USE_UNSTABLE'], language: ['cpp', 'c'])
-add_project_arguments(['-DWAYFIRE_PLUGIN'], language: ['cpp', 'c'])
-add_project_link_arguments(['-rdynamic','-fPIC'], language:'cpp')
-
-wayfire = dependency('wayfire', version: '>=0.8.1')
-
-
-subdir('src')
-subdir('metadata')
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/metadata/filters.xml wayfire-plugins-extra/subprojects/filters/metadata/filters.xml
--- wayfire-plugins-extra-0.10.0/subprojects/filters/metadata/filters.xml	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/metadata/filters.xml	1969-12-31 17:00:00.000000000 -0700
@@ -1,8 +0,0 @@
-<?xml version="1.0"?>
-<wayfire>
-	<plugin name="filters">
-		<_short>Shader Filters</_short>
-		<_long>Apply shaders via ipc.</_long>
-		<category>Effects</category>
-	</plugin>
-</wayfire>
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/metadata/meson.build wayfire-plugins-extra/subprojects/filters/metadata/meson.build
--- wayfire-plugins-extra-0.10.0/subprojects/filters/metadata/meson.build	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/metadata/meson.build	1969-12-31 17:00:00.000000000 -0700
@@ -1 +0,0 @@
-install_data( 'filters.xml', install_dir: wayfire.get_variable( pkgconfig: 'metadatadir' ) )
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/README.md wayfire-plugins-extra/subprojects/filters/README.md
--- wayfire-plugins-extra-0.10.0/subprojects/filters/README.md	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/README.md	1969-12-31 17:00:00.000000000 -0700
@@ -1,36 +0,0 @@
-# Filters
-
-## Installation
-```
-$ meson setup build --prefix=/usr
-$ ninja -C build
-# ninja -C build install
-```
-
-## Requirements
-
-Install [pywayfire](https://github.com/WayfireWM/pywayfire) with pip.
-
-## Usage
-
-To set shader on view with view-id:
-
-`./ipc-scripts/set-view-shader.py <view-id> shaders/<shader>`
-
-To unset shader on view with view-id:
-
-`./ipc-scripts/unset-view-shader.py <view-id>`
-
-To set shader on output with output-name:
-
-`./ipc-scripts/set-fs-shader.py <output-name> shaders/<shader>`
-
-To unset shader on output with output-name:
-
-`./ipc-scripts/unset-fs-shader.py <output-name>`
-
-Hints:
-
-View ID can be obtained with [wf-info](https://github.com/soreau/wf-info).
-
-Requires ipc plugin to function.
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/blur wayfire-plugins-extra/subprojects/filters/shaders/blur
--- wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/blur	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/shaders/blur	1969-12-31 17:00:00.000000000 -0700
@@ -1,40 +0,0 @@
-#version 300 es
-@builtin_ext@
-@builtin@
-
-precision mediump float;
-
-uniform sampler2D in_tex;
-out vec4 out_color;
-in mediump vec2 uvpos;
-uniform float progress;
-
-// Shader adapted from: https://www.shadertoy.com/view/Xltfzj
-
-float PI_2 = 6.28318530718;
-
-// GAUSSIAN BLUR SETTINGS
-float directions = 32.0; // BLUR DIRECTIONS (Default 16.0 - More is better but slower)
-float quality = 3.0; // BLUR QUALITY (Default 4.0 - More is better but slower)
-float radius = 8.0; // BLUR SIZE (Radius)
-
-void main()
-{
-    ivec2 size = textureSize(in_tex, 0);
-    vec2 s = vec2(size);
-    vec2 r = radius / s;
-    vec2 uv = uvpos;
-    vec4 c = get_pixel(uv);
-    vec4 oc = c;
-
-    for (float d = 0.0; d < PI_2; d += PI_2 / directions)
-    {
-        for(float i = 1.0 / quality; i <= 1.0; i += 1.0 / quality)
-        {
-            c += get_pixel(uv + vec2(cos(d), sin(d)) * r * i);
-        }
-    }
-
-    c /= quality * directions - 15.0;
-    out_color = mix(oc, c, progress);
-}
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/border wayfire-plugins-extra/subprojects/filters/shaders/border
--- wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/border	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/shaders/border	1969-12-31 17:00:00.000000000 -0700
@@ -1,63 +0,0 @@
-#version 300 es
-@builtin_ext@
-@builtin@
-
-precision mediump float;
-
-uniform sampler2D in_tex;
-out vec4 out_color;
-in mediump vec2 uvpos;
-uniform float progress;
-
-void main()
-{
-    vec4 c = get_pixel(uvpos);
-    vec4 oc = c;
-    ivec2 size = textureSize(in_tex, 0);
-    vec2 texelSize = 1.0 / vec2(size);
-    vec4 border_color = vec4(0.0, 1.0, 0.0, 1.0);
-    float border_size = 2.0;
-    float corner_radius = 10.0;
-    float d;
-    // Sides
-    if ((uvpos.x <= (texelSize.x * border_size) || uvpos.x >= 1.0 - (texelSize.x * border_size)) && uvpos.y > (texelSize.y * corner_radius) && uvpos.y < 1.0 - (texelSize.y * corner_radius) ||
-        ((uvpos.y <= (texelSize.y * border_size) || uvpos.y >= 1.0 - (texelSize.y * border_size)) && uvpos.x > (texelSize.x * corner_radius) && uvpos.x < 1.0 - (texelSize.x * corner_radius)))
-    {
-        c = border_color;
-    } else
-    // Corners
-    if (uvpos.x <= (texelSize.x * corner_radius) && uvpos.y <= (texelSize.y * corner_radius))
-    {
-        // Bottom Left
-        d = distance(vec2(corner_radius), uvpos * vec2(size));
-        if (d - corner_radius <= 0.0 && d - (corner_radius - border_size) >= 0.0)
-        {
-            c = border_color;
-        }
-    } else if (uvpos.x >= 1.0 - (texelSize.x * corner_radius) && uvpos.y <= (texelSize.y * corner_radius))
-    {
-        // Bottom Right
-        d = distance(vec2(float(size.x) - corner_radius, corner_radius), uvpos * vec2(size));
-        if (d - corner_radius <= 0.0 && d - (corner_radius - border_size) >= 0.0)
-        {
-            c = border_color;
-        }
-    } else if (uvpos.x <= (texelSize.x * corner_radius) && uvpos.y >= 1.0 - (texelSize.y * corner_radius))
-    {
-        // Top Left
-        d = distance(vec2(corner_radius, float(size.y) - corner_radius), uvpos * vec2(size));
-        if (d - corner_radius <= 0.0 && d - (corner_radius - border_size) >= 0.0)
-        {
-            c = border_color;
-        }
-    } else if (uvpos.x >= 1.0 - (texelSize.x * corner_radius) && uvpos.y >= 1.0 - (texelSize.y * corner_radius))
-    {
-        // Top Right
-        d = distance(vec2(vec2(size) - corner_radius), uvpos * vec2(size));
-        if (d - corner_radius <= 0.0 && d - (corner_radius - border_size) >= 0.0)
-        {
-            c = border_color;
-        }
-    }
-    out_color = mix(oc, c, progress);
-}
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/crt wayfire-plugins-extra/subprojects/filters/shaders/crt
--- wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/crt	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/shaders/crt	1969-12-31 17:00:00.000000000 -0700
@@ -1,28 +0,0 @@
-#version 300 es
-@builtin_ext@
-@builtin@
-
-precision mediump float;
-
-uniform sampler2D in_tex;
-out vec4 out_color;
-in mediump vec2 uvpos;
-uniform float progress;
-
-void main()
-{
-    vec4 c = get_pixel(uvpos);
-    vec4 oc = c;
-    if (mod(gl_FragCoord.x - 0.5, 3.0) == 0.0 || mod(gl_FragCoord.y - 0.5, 3.0) == 0.0)
-    {
-        c.r *= 0.75;
-        c.g *= 0.75;
-        c.b *= 0.75;
-    } else
-    {
-        c.r *= 1.25;
-        c.g *= 1.25;
-        c.b *= 1.25;
-    }
-    out_color = mix(oc, c, progress);
-}
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/invert wayfire-plugins-extra/subprojects/filters/shaders/invert
--- wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/invert	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/shaders/invert	1969-12-31 17:00:00.000000000 -0700
@@ -1,24 +0,0 @@
-#version 300 es
-@builtin_ext@
-@builtin@
-
-precision mediump float;
-
-uniform sampler2D in_tex;
-out vec4 out_color;
-in mediump vec2 uvpos;
-uniform float progress;
-
-void main()
-{
-    vec4 c = get_pixel(uvpos);
-    vec4 oc = c;
-    // Invert
-    c.r = 1.0 - c.r;
-    c.g = 1.0 - c.g;
-    c.b = 1.0 - c.b;
-    c.r *= c.a;
-    c.g *= c.a;
-    c.b *= c.a;
-    out_color = mix(oc, c, progress);
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/monochrome wayfire-plugins-extra/subprojects/filters/shaders/monochrome
--- wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/monochrome	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/shaders/monochrome	1969-12-31 17:00:00.000000000 -0700
@@ -1,21 +0,0 @@
-#version 300 es
-@builtin_ext@
-@builtin@
-
-precision mediump float;
-
-uniform sampler2D in_tex;
-out vec4 out_color;
-in mediump vec2 uvpos;
-uniform float progress;
-
-void main()
-{
-    vec4 c = get_pixel(uvpos);
-    vec4 oc = c;
-    float color_factor = 0.0; // 1.0 = color, 0.0 = greyscale
-    // Monochrome
-    float grey = 0.21 * c.r + 0.71 * c.g + 0.07 * c.b;
-    c = vec4(c.r * color_factor + grey * (1.0 - color_factor), c.g * color_factor + grey * (1.0 - color_factor), c.b * color_factor + grey * (1.0 - color_factor), 1.0);
-    out_color = mix(oc, c, progress);
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/passthrough wayfire-plugins-extra/subprojects/filters/shaders/passthrough
--- wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/passthrough	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/shaders/passthrough	1969-12-31 17:00:00.000000000 -0700
@@ -1,19 +0,0 @@
-#version 300 es
-@builtin_ext@
-@builtin@
-
-precision mediump float;
-
-uniform sampler2D in_tex;
-out vec4 out_color;
-in mediump vec2 uvpos;
-// progress is for fade in/out
-uniform float progress;
-
-void main()
-{
-    vec4 c = get_pixel(uvpos);
-    vec4 oc = c;
-    // pointless, because the two colors are the same
-    out_color = mix(oc, c, progress);
-}
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/rounded-corners wayfire-plugins-extra/subprojects/filters/shaders/rounded-corners
--- wayfire-plugins-extra-0.10.0/subprojects/filters/shaders/rounded-corners	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/shaders/rounded-corners	1969-12-31 17:00:00.000000000 -0700
@@ -1,95 +0,0 @@
-#version 300 es
-@builtin_ext@
-@builtin@
-
-precision mediump float;
-
-uniform sampler2D in_tex;
-out vec4 out_color;
-in mediump vec2 uvpos;
-uniform float progress;
-uniform vec4 margins;
-
-void main()
-{
-    vec4 c = get_pixel(uvpos);
-    vec2 uv = uvpos;
-    vec4 m = margins;
-    vec4 oc = c;
-    vec4 shadow_color = vec4(0.0, 0.0, 0.2, 0.5);
-    ivec2 size = textureSize(in_tex, 0);
-    vec2 texelSize = 1.0 / vec2(size);
-    m.x *= texelSize.x; // left
-    m.y *= texelSize.y; // top
-    m.z *= texelSize.x; // right
-    m.w *= texelSize.y; // bottom
-    vec4 border_color = vec4(0.1, 0.1, 0.1, 1.0);
-    float border_size = 1.0;
-    float corner_radius = 15.0;
-    float shadow_radius = 12.0;
-    float d;
-    float diffuse = 1.0 / max(shadow_radius / 2.0, 1.0);
-
-    // Edges
-    if ((((uv.x >= m.x - texelSize.x * border_size && uv.x <= m.x) || (uv.x <= 1.0 - (m.z - texelSize.x * border_size) && uv.x >= 1.0 - m.z)) &&
-        (uv.y > texelSize.y * (corner_radius - border_size) + m.w && uv.y < 1.0 - texelSize.y * (corner_radius - border_size) - m.y)) ||
-        (((uv.y >= m.w - texelSize.y * border_size && uv.y <= m.w) || (uv.y <= 1.0 - (m.y - texelSize.y * border_size) && uv.y >= 1.0 - m.y)) &&
-        (uv.x > texelSize.x * (corner_radius - border_size) + m.x && uv.x < 1.0 - texelSize.x * (corner_radius - border_size) - m.z)))
-    {
-        c = border_color;
-    } else
-    // Corners
-    if (uv.x <= texelSize.x * (corner_radius - border_size) + m.x && uv.y <= texelSize.y * (corner_radius - border_size) + m.w)
-    {
-        // Bottom Left
-        d = distance(vec2(corner_radius - border_size) + vec2(margins.x, margins.w), uv * vec2(size));
-        if (d - corner_radius <= 0.0)
-        {
-            if (d - (corner_radius - border_size) >= 0.0)
-            {
-                c = border_color;
-            }
-        } else
-            c = vec4(0.0);
-    } else if (uv.x >= 1.0 - m.z - texelSize.x * (corner_radius - border_size) && uv.y <= texelSize.y * (corner_radius - border_size) + m.w)
-    {
-        // Bottom Right
-        d = distance(vec2(float(size.x) - (corner_radius - border_size) - margins.z, (corner_radius - border_size) + margins.w), uv * vec2(size));
-        if (d - corner_radius <= 0.0)
-        {
-            if (d - (corner_radius - border_size) >= 0.0)
-            {
-                c = border_color;
-            }
-        } else
-            c = vec4(0.0);
-    } else if (uv.x <= texelSize.x * (corner_radius - border_size) + m.x && uv.y >= 1.0 - texelSize.y * (corner_radius - border_size) - m.y)
-    {
-        // Top Left
-        d = distance(vec2((corner_radius - border_size) + margins.x, float(size.y) - (corner_radius - border_size) - margins.y), uv * vec2(size));
-        if (d - corner_radius <= 0.0)
-        {
-            if (d - (corner_radius - border_size) >= 0.0)
-            {
-                c = border_color;
-            }
-        } else
-            c = vec4(0.0);
-    } else if (uv.x >= 1.0 - texelSize.x * (corner_radius - border_size) - m.x && uv.y >= 1.0 - texelSize.y * (corner_radius - border_size) - m.y)
-    {
-        // Top Right
-        d = distance(vec2(vec2(size) - (corner_radius - border_size) - vec2(margins.z, margins.y)), uv * vec2(size));
-        if (d - corner_radius <= 0.0)
-        {
-            if (d - (corner_radius - border_size) >= 0.0)
-            {
-                c = border_color;
-            }
-        } else
-            c = vec4(0.0);
-    } else if (uv.x < m.x || uv.x > 1.0 - m.z || uv.y < m.w || uv.y > 1.0 - m.y)
-    {
-        c = vec4(0.0);
-    }
-    out_color = mix(oc, c, progress);
-}
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/src/filters.cpp wayfire-plugins-extra/subprojects/filters/src/filters.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/filters/src/filters.cpp	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/src/filters.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,670 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2024 Scott Moreau
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include <string>
-#include <fstream>
-#include <wayfire/core.hpp>
-#include <wayfire/view.hpp>
-#include <wayfire/plugin.hpp>
-#include <wayfire/output.hpp>
-#include <wayfire/opengl.hpp>
-#include <wayfire/util/duration.hpp>
-#include <wayfire/render-manager.hpp>
-#include <wayfire/view-transform.hpp>
-#include <wayfire/per-output-plugin.hpp>
-#include <wayfire/signal-definitions.hpp>
-#include <wayfire/plugins/ipc/ipc-helpers.hpp>
-#include <wayfire/plugins/ipc/ipc-activator.hpp>
-#include <wayfire/plugins/common/shared-core-data.hpp>
-#include <wayfire/plugins/ipc/ipc-method-repository.hpp>
-
-
-static const char *vertex_shader =
-    R"(
-#version 300 es
-
-in mediump vec2 position;
-in mediump vec2 texcoord;
-
-out mediump vec2 uvpos;
-
-uniform mat4 mvp;
-
-void main() {
-
-   gl_Position = mvp * vec4(position.xy, 0.0, 1.0);
-   uvpos = texcoord;
-}
-)";
-
-// Supplied via ipc
-// static const char *fragment_shader =
-// R"(
-// #version 100
-// @builtin_ext@
-// @builtin@
-//
-// precision mediump float;
-//
-// varying mediump vec2 uvpos;
-//
-// void main()
-// {
-// vec4 c = get_pixel(uvpos);
-// gl_FragColor = c;
-// }
-// )";
-
-static std::string pixdecor_custom_data_name = "wf-decoration-shadow-margin";
-
-class wf_shadow_margin_t : public wf::custom_data_t
-{
-  public:
-    wf::decoration_margins_t get_margins()
-    {
-        return margins;
-    }
-
-    void set_margins(wf::decoration_margins_t margins)
-    {
-        this->margins = margins;
-    }
-
-  private:
-    wf::decoration_margins_t margins = {0, 0, 0, 0};
-};
-
-namespace wf
-{
-namespace scene
-{
-namespace filters
-{
-const std::string transformer_name = "filters";
-
-class wf_filters : public wf::scene::view_2d_transformer_t
-{
-    wayfire_view view;
-    wf::output_t *output;
-    OpenGL::program_t *shader;
-    std::unique_ptr<wf::animation::simple_animation_t> fade;
-
-  public:
-    OpenGL::program_t program;
-    class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t<transformer_base_node_t>
-    {
-        wf::signal::connection_t<node_damage_signal> on_node_damaged =
-            [=] (node_damage_signal *ev)
-        {
-            push_to_parent(ev->region);
-        };
-
-        wf_filters *self;
-        wayfire_view view;
-        damage_callback push_to_parent;
-
-      public:
-        simple_node_render_instance_t(wf_filters *self, damage_callback push_damage,
-            wayfire_view view) : wf::scene::transformer_render_instance_t<transformer_base_node_t>(self,
-                push_damage,
-                view->get_output())
-        {
-            this->self = self;
-            this->view = view;
-            this->push_to_parent = push_damage;
-            self->connect(&on_node_damaged);
-        }
-
-        ~simple_node_render_instance_t()
-        {}
-
-        void schedule_instructions(
-            std::vector<render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage)
-        {
-            // We want to render ourselves only, the node does not have children
-            instructions.push_back(render_instruction_t{
-                            .instance = this,
-                            .target   = target,
-                            .damage   = damage & self->get_bounding_box(),
-                        });
-        }
-
-        void render(const wf::scene::render_instruction_t& data)
-        {
-            wlr_box fb_geom =
-                data.target.framebuffer_box_from_geometry_box(data.target.geometry);
-            auto view_box = data.target.framebuffer_box_from_geometry_box(
-                self->get_children_bounding_box());
-            view_box.x -= fb_geom.x;
-            view_box.y -= fb_geom.y;
-
-            float x = view_box.x, y = view_box.y, w = view_box.width,
-                h = view_box.height;
-
-            static const float vertexData[] = {
-                -1.0f, -1.0f,
-                1.0f, -1.0f,
-                1.0f, 1.0f,
-                -1.0f, 1.0f
-            };
-            static const float texCoords[] = {
-                0.0f, 0.0f,
-                1.0f, 0.0f,
-                1.0f, 1.0f,
-                0.0f, 1.0f
-            };
-
-            auto src_tex = wf::gles_texture_t{get_texture(1.0)};
-            data.pass->custom_gles_subpass(data.target,[&]
-            {
-                this->self->shader->use(src_tex.type);
-                this->self->shader->attrib_pointer("position", 2, 0, vertexData);
-                this->self->shader->attrib_pointer("texcoord", 2, 0, texCoords);
-                this->self->shader->uniformMatrix4f("mvp", wf::gles::output_transform(data.target));
-                this->self->shader->uniform1f("progress", *self->fade);
-                this->self->shader->uniform1i("in_tex", 0);
-
-                if (auto toplevel = wf::toplevel_cast(this->view))
-                {
-                    auto bg = view->get_surface_root_node()->get_bounding_box();
-                    auto vg = toplevel->get_geometry();
-                    auto margins =
-                        glm::vec4{vg.x - bg.x, vg.y - bg.y, bg.width - ((vg.x - bg.x) + vg.width),
-                        bg.height - ((vg.y - bg.y) + vg.height)};
-                    if (view->has_data(pixdecor_custom_data_name))
-                    {
-                        auto decoration_margins =
-                            view->get_data<wf_shadow_margin_t>(pixdecor_custom_data_name)->get_margins();
-                        margins.x += decoration_margins.left;
-                        margins.y += decoration_margins.bottom;
-                        margins.z += decoration_margins.right;
-                        margins.w += decoration_margins.top;
-                    }
-
-                    // XXX: Pad the margins if there are none, so that the shader renders on the surface
-                    if (bg == vg)
-                    {
-                        margins.x += 2.0;
-                        margins.y += 2.0;
-                        margins.z += 2.0;
-                        margins.w += 2.0;
-                    }
-
-                    this->self->shader->uniform4f("margins", margins);
-                }
-
-                GL_CALL(glActiveTexture(GL_TEXTURE0));
-                this->self->shader->set_active_texture(src_tex);
-
-                /* Render it to target */
-                wf::gles::bind_render_buffer(data.target);
-                GL_CALL(glViewport(x, y, w, h));
-
-                GL_CALL(glEnable(GL_BLEND));
-                GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
-
-                for (const auto& box : data.damage)
-                {
-                    wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
-                    GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
-                }
-
-                /* Disable stuff */
-                GL_CALL(glDisable(GL_BLEND));
-                GL_CALL(glActiveTexture(GL_TEXTURE0));
-                GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
-                GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
-
-                this->self->shader->deactivate();
-            });
-        }
-    };
-
-    wf_filters(wayfire_view view, std::string shader_path) : wf::scene::view_2d_transformer_t(view)
-    {
-        this->view   = view;
-        this->shader = &program;
-        if (view->get_output())
-        {
-            output = view->get_output();
-            output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
-        }
-
-        std::ifstream t(shader_path);
-        std::string fragment_shader((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
-        wf::gles::run_in_context([&]
-        {
-            program.compile(vertex_shader, fragment_shader);
-        });
-        fade = std::make_unique<wf::animation::simple_animation_t>(wf::create_option<int>(700));
-        fade->set(0.0, 0.0);
-        fade->animate(1.0);
-    }
-
-    void unapply()
-    {
-        fade->animate(0.0);
-    }
-
-    void pop_transformer(wayfire_view view)
-    {
-        if (view->get_transformed_node()->get_transformer(transformer_name))
-        {
-            LOGI("Removing shader and transformer.");
-            view->get_transformed_node()->rem_transformer(transformer_name);
-        }
-    }
-
-    wf::effect_hook_t pre_hook = [=] ()
-    {
-        if (fade->running())
-        {
-            for (auto & v : wf::get_core().get_all_views())
-            {
-                v->damage();
-            }
-        } else if (fade->end == 0.0)
-        {
-            pop_transformer(view);
-        }
-    };
-
-    void gen_render_instances(std::vector<render_instance_uptr>& instances,
-        damage_callback push_damage, wf::output_t *shown_on) override
-    {
-        instances.push_back(std::make_unique<simple_node_render_instance_t>(
-            this, push_damage, view));
-    }
-
-    virtual ~wf_filters()
-    {
-        wf::gles::run_in_context([&]
-        {
-            program.free_resources();
-        });
-        fade.reset();
-        if (output)
-        {
-            output->render->rem_effect(&pre_hook);
-        }
-    }
-};
-
-class wayfire_per_output_filters : public wf::per_output_plugin_instance_t
-{
-    std::unique_ptr<wf::animation::simple_animation_t> fade;
-    std::shared_ptr<OpenGL::program_t> program = nullptr;
-    wf::post_hook_t hook;
-    bool active = false;
-
-  public:
-    void init() override
-    {
-        hook = [=] (wf::auxilliary_buffer_t& aux_buf, const wf::render_buffer_t& render_buf)
-        {
-            render(aux_buf, render_buf);
-        };
-        fade = std::make_unique<wf::animation::simple_animation_t>(wf::create_option<int>(700));
-        fade->set(0.0, 0.0);
-    }
-
-    wf::effect_hook_t pre_hook = [=] ()
-    {
-        if (fade->running())
-        {
-            output->render->damage_whole();
-            for (auto & v : wf::get_core().get_all_views())
-            {
-                v->damage();
-            }
-        } else if (fade->end == 0.0)
-        {
-            output->render->rem_effect(&pre_hook);
-            output->render->rem_post(&hook);
-            output->render->damage_whole();
-            if (program)
-            {
-                wf::gles::run_in_context([&]
-                {
-                    program->free_resources();
-                });
-            }
-
-            program = nullptr;
-            active  = false;
-        }
-    };
-
-    wf::json_t set_fs_shader(std::string shader)
-    {
-        if (program)
-        {
-            wf::gles::run_in_context([&]
-            {
-                program->free_resources();
-            });
-        } else
-        {
-            program = std::make_shared<OpenGL::program_t>();
-        }
-
-        std::ifstream t(shader);
-        std::string fragment_shader((std::istreambuf_iterator<char>(t)), std::istreambuf_iterator<char>());
-        wf::gles::run_in_context([&]
-        {
-            program->compile(vertex_shader, fragment_shader);
-        });
-        if (program->get_program_id(wf::TEXTURE_TYPE_RGBA) == 0)
-        {
-            LOGE("Failed to compile fullscreen shader.");
-            output->render->rem_post(&hook);
-            program = nullptr;
-            return wf::ipc::json_error("Failed to compile fullscreen shader.");
-        }
-
-        output->render->damage_whole();
-
-        if (active)
-        {
-            LOGI("Successfully compiled and applied fullscreen shader to output: ", output->to_string());
-            return wf::ipc::json_ok();
-        }
-
-        output->render->add_post(&hook);
-        output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
-        fade->animate(1.0);
-        active = true;
-
-        LOGI("Successfully compiled and applied fullscreen shader to output: ", output->to_string());
-        return wf::ipc::json_ok();
-    }
-
-    wf::json_t unset_fs_shader()
-    {
-        fade->animate(0.0);
-        return wf::ipc::json_ok();
-    }
-
-    wf::json_t fs_has_shader()
-    {
-        auto response = wf::ipc::json_ok();
-        response["has-shader"] = active;
-        return response;
-    }
-
-    void render(wf::auxilliary_buffer_t& aux_buf, const wf::render_buffer_t& render_buf)
-    {
-        static const float vertexData[] = {
-            -1.0f, -1.0f,
-            1.0f, -1.0f,
-            1.0f, 1.0f,
-            -1.0f, 1.0f
-        };
-        static const float texCoords[] = {
-            0.0f, 1.0f,
-            1.0f, 1.0f,
-            1.0f, 0.0f,
-            0.0f, 0.0f
-        };
-
-        wf::gles::run_in_context([&]
-        {
-            /* Upload data to shader */
-            program->use(wf::TEXTURE_TYPE_RGBA);
-            program->attrib_pointer("position", 2, 0, vertexData);
-            program->attrib_pointer("texcoord", 2, 0, texCoords);
-            program->uniformMatrix4f("mvp", glm::mat4(1.0));
-            program->uniform1f("progress", *fade);
-            program->uniform1i("in_tex", 0);
-            GL_CALL(glActiveTexture(GL_TEXTURE0));
-            program->set_active_texture(wf::gles_texture_t::from_aux(aux_buf));
-
-            /* Render it to aux_buf */
-            wf::gles::bind_render_buffer(render_buf);
-            GL_CALL(glViewport(0, 0, aux_buf.get_size().width, aux_buf.get_size().height));
-
-            GL_CALL(glEnable(GL_BLEND));
-            GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
-
-            GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
-
-            /* Disable stuff */
-            GL_CALL(glDisable(GL_BLEND));
-            GL_CALL(glActiveTexture(GL_TEXTURE0));
-            GL_CALL(glBindTexture(GL_TEXTURE_2D, 0));
-            GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, 0));
-
-            program->deactivate();
-        });
-    }
-
-    void fini() override
-    {
-        output->render->rem_effect(&pre_hook);
-        output->render->rem_post(&hook);
-        output->render->damage_whole();
-        if (program)
-        {
-            wf::gles::run_in_context([&]
-            {
-                program->free_resources();
-            });
-        }
-
-        fade.reset();
-    }
-};
-
-class wayfire_filters : public wf::plugin_interface_t,
-    public wf::per_output_tracker_mixin_t<wayfire_per_output_filters>
-{
-    wf::shared_data::ref_ptr_t<wf::ipc::method_repository_t> ipc_repo;
-
-    void pop_transformer(wayfire_view view)
-    {
-        if (view->get_transformed_node()->get_transformer(transformer_name))
-        {
-            LOGI("Removing shader and transformer.");
-            view->get_transformed_node()->rem_transformer(transformer_name);
-        }
-    }
-
-    void remove_transformers()
-    {
-        for (auto& view : wf::get_core().get_all_views())
-        {
-            pop_transformer(view);
-        }
-    }
-
-  public:
-    void init() override
-    {
-        ipc_repo->register_method("wf/filters/set-view-shader", ipc_set_view_shader);
-        ipc_repo->register_method("wf/filters/unset-view-shader", ipc_unset_view_shader);
-        ipc_repo->register_method("wf/filters/view-has-shader", ipc_view_has_shader);
-        ipc_repo->register_method("wf/filters/set-fs-shader", ipc_set_fs_shader);
-        ipc_repo->register_method("wf/filters/unset-fs-shader", ipc_unset_fs_shader);
-        ipc_repo->register_method("wf/filters/fs-has-shader", ipc_fs_has_shader);
-
-        per_output_tracker_mixin_t::init_output_tracking();
-    }
-
-    void handle_new_output(wf::output_t *output) override
-    {
-        per_output_tracker_mixin_t::handle_new_output(output);
-    }
-
-    void handle_output_removed(wf::output_t *output) override
-    {
-        per_output_tracker_mixin_t::handle_output_removed(output);
-    }
-
-    std::shared_ptr<wf_filters> ensure_transformer(wayfire_view view, std::string shader_path)
-    {
-        auto tmgr = view->get_transformed_node();
-        if (tmgr->get_transformer<wf_filters>(transformer_name))
-        {
-            view->get_transformed_node()->rem_transformer(transformer_name);
-        }
-
-        auto node = std::make_shared<wf_filters>(view, shader_path);
-        tmgr->add_transformer(node, wf::TRANSFORMER_2D, transformer_name);
-
-        return tmgr->get_transformer<wf_filters>(transformer_name);
-    }
-
-    wf::ipc::method_callback ipc_set_view_shader = [=] (wf::json_t data) -> wf::json_t
-    {
-        auto view_id     = wf::ipc::json_get_uint64(data, "view-id");
-        auto shader_path = wf::ipc::json_get_string(data, "shader-path");
-
-        auto view = wf::ipc::find_view_by_id(view_id);
-        if (view)
-        {
-            auto tr = ensure_transformer(view, shader_path);
-            if (tr->program.get_program_id(wf::TEXTURE_TYPE_RGBA) == 0)
-            {
-                pop_transformer(view);
-                LOGE("Failed to compile shader.");
-                return wf::ipc::json_error("Failed to compile shader.");
-            }
-        } else
-        {
-            LOGE("Failed to find view with given id. Maybe it isn't mapped?");
-            return wf::ipc::json_error("Failed to find view with given id. Maybe it isn't mapped?");
-        }
-
-        LOGI("Successfully compiled and applied shader.");
-        view->damage();
-        return wf::ipc::json_ok();
-    };
-
-    wf::ipc::method_callback ipc_unset_view_shader = [=] (wf::json_t data) -> wf::json_t
-    {
-        auto view_id = wf::ipc::json_get_uint64(data, "view-id");
-
-        auto view = wf::ipc::find_view_by_id(view_id);
-        if (view)
-        {
-            auto tmgr = view->get_transformed_node();
-            if (auto tr = tmgr->get_transformer<wf_filters>(transformer_name))
-            {
-                tr->unapply();
-                view->damage();
-            }
-        }
-
-        return wf::ipc::json_ok();
-    };
-
-    wf::ipc::method_callback ipc_view_has_shader = [=] (wf::json_t data) -> wf::json_t
-    {
-        auto view_id = wf::ipc::json_get_uint64(data, "view-id");
-
-        auto view = wf::ipc::find_view_by_id(view_id);
-        if (!view)
-        {
-            return wf::ipc::json_error("Failed to find view with given id.");
-        }
-
-        auto tmgr     = view->get_transformed_node();
-        auto response = wf::ipc::json_ok();
-        response["has-shader"] = tmgr->get_transformer<wf::scene::node_t>(transformer_name) ? true : false;
-        return response;
-    };
-
-    wf::output_t *find_output_by_name(std::string name)
-    {
-        for (auto & output : wf::get_core().output_layout->get_outputs())
-        {
-            if (output->to_string() == name)
-            {
-                return output;
-            }
-        }
-
-        return nullptr;
-    }
-
-    wf::ipc::method_callback ipc_set_fs_shader = [=] (wf::json_t data) -> wf::json_t
-    {
-        auto output_name = wf::ipc::json_get_string(data, "output-name");
-        auto shader_path = wf::ipc::json_get_string(data, "shader-path");
-
-        auto output = find_output_by_name(output_name);
-        if (!output)
-        {
-            return wf::ipc::json_error("No such output");
-        }
-
-        return this->output_instance[output]->set_fs_shader(shader_path);
-    };
-
-    wf::ipc::method_callback ipc_unset_fs_shader = [=] (wf::json_t data) -> wf::json_t
-    {
-        auto output_name = wf::ipc::json_get_string(data, "output-name");
-
-        auto output = find_output_by_name(output_name);
-        if (!output)
-        {
-            return wf::ipc::json_error("No such output");
-        }
-
-        return this->output_instance[output]->unset_fs_shader();
-    };
-
-    wf::ipc::method_callback ipc_fs_has_shader = [=] (wf::json_t data) -> wf::json_t
-    {
-        auto output_name = wf::ipc::json_get_string(data, "output-name");
-
-        auto output = find_output_by_name(output_name);
-        if (!output)
-        {
-            return wf::ipc::json_error("No such output");
-        }
-
-        return this->output_instance[output]->fs_has_shader();
-    };
-
-    void fini() override
-    {
-        per_output_tracker_mixin_t::fini_output_tracking();
-
-        ipc_repo->unregister_method("wf/filters/set-view-shader");
-        ipc_repo->unregister_method("wf/filters/unset-view-shader");
-        ipc_repo->unregister_method("wf/filters/view-has-shader");
-        ipc_repo->unregister_method("wf/filters/set-fs-shader");
-        ipc_repo->unregister_method("wf/filters/unset-fs-shader");
-        ipc_repo->unregister_method("wf/filters/fs-has-shader");
-
-        remove_transformers();
-    }
-};
-}
-}
-}
-
-DECLARE_WAYFIRE_PLUGIN(wf::scene::filters::wayfire_filters);
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/filters/src/meson.build wayfire-plugins-extra/subprojects/filters/src/meson.build
--- wayfire-plugins-extra-0.10.0/subprojects/filters/src/meson.build	2025-07-15 06:13:43.000000000 -0600
+++ wayfire-plugins-extra/subprojects/filters/src/meson.build	1969-12-31 17:00:00.000000000 -0700
@@ -1,4 +0,0 @@
-filters = shared_module('filters', ['filters.cpp'],
-        dependencies: [wayfire],
-        install: true,
-        install_dir: join_paths(get_option('libdir'), 'wayfire'))
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/focus-request/focus-request.xml wayfire-plugins-extra/subprojects/focus-request/focus-request.xml
--- wayfire-plugins-extra-0.10.0/subprojects/focus-request/focus-request.xml	2024-03-11 00:12:33.000000000 -0600
+++ wayfire-plugins-extra/subprojects/focus-request/focus-request.xml	1969-12-31 17:00:00.000000000 -0700
@@ -1,38 +0,0 @@
-<?xml version="1.0"?>
-<wayfire>
-	<plugin name="focus-request">
-		<_short>Focus Request</_short>
-		<_long>A simple plugin to handle various focus request events of wayfire.</_long>
-		<category>Desktop</category>
-		<option name="focus_stealing_timeout" type="int">
-			<_short>The timeout (in ms) to prevent focus stealing</_short>
-			<_long>If this focus request was made within the timeout period, the focus is denied and a view_hints_changed_signal will be emitted for the requesting view. This behaviour will be over-ridden by views in auto_focus_views. If the timeout is -1, then focus-stealing will be disabled.</_long>
-			<default>1000</default>
-		</option>
-		<option name="deny_focus_views" type="string">
-			<_short>Deny focus to views matching this criteria</_short>
-			<_long>If a view matches when mapped, focus is reset to the last view with focus.</_long>
-			<default>none</default>
-		</option>
-		<option name="auto_grant_focus" type="bool">
-			<_short>Grant focus on self-request</_short>
-			<_long>Acquiesce to the view's request for focus (Gtk and Qt Shell protocols, and Xwayland views). If false, view_hints_changed_signal will be emitted.</_long>
-			<default>false</default>
-		</option>
-		<option name="auto_focus_views" type="string">
-			<_short>Grant focus unconditionally</_short>
-			<_long>Grant focus to the views with these app-ids unconditionally. This is irrespective of the request type (self or other) and focus-stealing timeout.</_long>
-			<default>none</default>
-		</option>
-		<option name="auto_focus_children" type="bool">
-			<_short>Auto-grant focus to child views</_short>
-			<_long>Grant focus to the children of the currently focused view unconditionally.</_long>
-			<default>true</default>
-		</option>
-		<option name="focus_last_demand" type="activator">
-			<_short>Focus last view with demands attention</_short>
-			<_long>Focus the last view on which demands attention was set.</_long>
-			<default>&lt;ctrl&gt; &lt;alt&gt; KEY_A</default>
-		</option>
-	</plugin>
-</wayfire>
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/focus-request/LICENSE wayfire-plugins-extra/subprojects/focus-request/LICENSE
--- wayfire-plugins-extra-0.10.0/subprojects/focus-request/LICENSE	2024-03-11 00:12:33.000000000 -0600
+++ wayfire-plugins-extra/subprojects/focus-request/LICENSE	1969-12-31 17:00:00.000000000 -0700
@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2021 WayfirePlugins
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/focus-request/meson.build wayfire-plugins-extra/subprojects/focus-request/meson.build
--- wayfire-plugins-extra-0.10.0/subprojects/focus-request/meson.build	2024-03-11 00:12:33.000000000 -0600
+++ wayfire-plugins-extra/subprojects/focus-request/meson.build	1969-12-31 17:00:00.000000000 -0700
@@ -1,26 +0,0 @@
-project(
-	'focus-request',
-	'c',
-	'cpp',
-	version: '0.1.0',
-	license: 'MIT',
-	meson_version: '>=0.51.0',
-	default_options: [
-		'cpp_std=c++17',
-		'c_std=c11',
-	],
-)
-
-add_project_arguments(['-DWLR_USE_UNSTABLE'], language: ['cpp', 'c'])
-add_project_arguments(['-DWAYFIRE_PLUGIN'], language: ['cpp', 'c'])
-add_project_link_arguments(['-rdynamic','-fPIC'], language:'cpp')
-
-wayfire = dependency('wayfire')
-
-shared_module( 'focus-request', [ 'wf-focus-request.cpp' ],
-		dependencies: wayfire,
-		install: true,
-		install_dir: join_paths(get_option('libdir'), 'wayfire')
-)
-
-install_data( 'focus-request.xml', install_dir: wayfire.get_variable( pkgconfig: 'metadatadir' ) )
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/focus-request/wf-focus-request.cpp wayfire-plugins-extra/subprojects/focus-request/wf-focus-request.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/focus-request/wf-focus-request.cpp	2024-03-11 00:12:33.000000000 -0600
+++ wayfire-plugins-extra/subprojects/focus-request/wf-focus-request.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,279 +0,0 @@
-/**
- * The MIT License (MIT)
- *
- * Copyright (c) 2021 Marcus Britanicus
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- **/
-
-#include <map>
-#include <sstream>
-#include <string>
-
-#include <wayfire/core.hpp>
-#include <wayfire/util.hpp>
-#include <wayfire/view.hpp>
-#include <wayfire/object.hpp>
-#include <wayfire/plugin.hpp>
-#include <wayfire/matcher.hpp>
-#include <wayfire/toplevel.hpp>
-#include <wayfire/view-helpers.hpp>
-#include <wayfire/toplevel-view.hpp>
-#include <wayfire/window-manager.hpp>
-#include <wayfire/signal-definitions.hpp>
-#include <wayfire/bindings-repository.hpp>
-#include <wayfire/nonstd/wlroots-full.hpp>
-
-std::string ltrim( const std::string& s ) {
-    size_t start = s.find_first_not_of( ' ' );
-
-    return (start == std::string::npos) ? "" : s.substr( start );
-}
-
-
-std::string rtrim( const std::string& s ) {
-    size_t end = s.find_last_not_of( ' ' );
-
-    return (end == std::string::npos) ? "" : s.substr( 0, end + 1 );
-}
-
-
-std::string trim( const std::string& s ) {
-    return rtrim( ltrim( s ) );
-}
-
-
-std::vector<std::string> split( const std::string& s ) {
-    std::stringstream        ss( s );
-    std::vector<std::string> list;
-
-    for ( std::string line; std::getline( ss, line, ',' );  ) {
-        list.push_back( trim( line ) );
-    }
-
-    return list;
-}
-
-
-class wayfire_focus_request : public wf::plugin_interface_t {
-    wayfire_view last_focus_view = nullptr;
-    std::vector<wayfire_view> attention_list;
-
-    wf::option_wrapper_t<wf::activatorbinding_t> focus_key{ "focus-request/focus_last_demand" };
-
-    wf::activator_callback cb =
-        [ = ] ( auto ) {
-            if ( attention_list.size() == 0 ) {
-                LOGE( "Nothing to focus" );
-                return true;
-            }
-
-            /** Take the last element */
-            wayfire_view view = attention_list.back();
-
-            if ( view == nullptr ) {
-                LOGE( "[FocusRequest] Nothing to activate." );
-                return true;
-            }
-
-            LOGE( "[FocusRequest] Activating view ", view->get_app_id(), " (", view->get_id(), ") ", view->get_title() );
-
-            /** Bring it to the front */
-            wf::get_core().default_wm->focus_raise_view( view );
-
-            LOGE( "[FocusRequest] Attention list size (before) ", attention_list.size() );
-
-            /** Remove it from the list */
-            attention_list.pop_back();
-
-            LOGE( "[FocusRequest] Attention list size (after) ", attention_list.size() );
-
-            return true;
-        };
-
-    wf::signal::connection_t<wf::view_focus_request_signal> onFocusRequested {
-        [ = ] (wf::view_focus_request_signal *ev) {
-            LOGD( "[FocusRequest] view_focus_request_signal intercepted: ", ev->view->get_app_id(), " (", ev->view->get_id(), ")" );
-            /** Cast it into a toplevel object */
-            auto toplevel = wf::toplevel_cast( ev->view );
-
-            /** Worry about this only if it's a toplevel */
-            if ( toplevel == nullptr ) {
-                return;
-            }
-
-            LOGD( "[FocusRequest] Self-request: ", ev->self_request, "; carried out: ", ev->carried_out );
-
-            /** Get the focus stealing timeout */
-            wf::option_wrapper_t<int> focus_timeout{ "focus-request/focus_stealing_timeout" };
-
-            LOGD( "[FocusRequest] FSP Timeout ", focus_timeout.value() );
-
-            /** Grant focus to these views unconditionally */
-            wf::view_matcher_t always_auto_focus{ "focus-request/auto_focus_views" };
-
-            /** If this is one of the views which always get focus */
-            if ( always_auto_focus.matches( ev->view ) ) {
-                LOGD( "[FocusRequest] Granting focus to always-view ", toplevel->get_app_id(), " (", ev->view->get_id(), ")" );
-                wf::get_core().default_wm->focus_raise_view( ev->view, true );
-
-                /** Mark this as carried out */
-                ev->carried_out = true;
-            }
-
-            /** Focus children of the current view unconditionally */
-            wf::option_wrapper_t<bool> auto_focus_children{ "focus-request/auto_focus_children" };
-
-            /** Parent of the current */
-            auto parent_view = toplevel->parent;
-
-            /** Check if this the child of the currently focused view. Grant focus if needed */
-            if ( (parent_view != nullptr) && (auto_focus_children.value() == true) ) {
-                auto current_focus = wf::get_core().get_cursor_focus_view();
-
-                if ( (current_focus != nullptr) && (parent_view == current_focus) ) {
-                    LOGD( "[FocusRequest] Granting focus to child ", toplevel->get_app_id(), " (", ev->view->get_id(), ")" );
-                    wf::get_core().default_wm->focus_raise_view( toplevel );
-
-                    /** Mark this as carried out */
-                    ev->carried_out = true;
-
-                    /** We're done here */
-                    return;
-                }
-            }
-
-            /** We're now interested only in self-requests */
-            if ( ev->self_request and not ev->carried_out ) {
-                /** We'll either deny or acquiesce this request. So mark as carried out. */
-                ev->carried_out = true;
-
-                LOGD( "[FocusRequest] Recieved focus request. ", toplevel->get_app_id(), " (", ev->view->get_id(), ")" );
-
-                /** Grant it focus automatically, or just highlight it? */
-                wf::option_wrapper_t<bool> auto_grant_focus{ "focus-request/auto_grant_focus" };
-
-                /** If the request is to be granted without ado, let's do that */
-                if ( auto_grant_focus.value() == true ) {
-                    LOGD( "[FocusRequest] Granting focus ", toplevel->get_app_id(), " (", ev->view->get_id(), ")" );
-                    wf::get_core().default_wm->focus_raise_view( toplevel );
-
-                    /** We're done here */
-                    return;
-                }
-
-                /**
-                 * None of the above applied. So set demands attention flag and emit
-                 * view_hints_changed_signal
-                 */
-                LOGD( "[FocusRequest] Setting demands-attention hint ", toplevel->get_app_id(), " (", ev->view->get_id(), ")" );
-                wf::view_hints_changed_signal hints_signal;
-                hints_signal.view = ev->view;
-                hints_signal.demands_attention = true;
-                ev->view->emit( &hints_signal );
-                wf::get_core().emit( &hints_signal );
-            }
-        }
-    };
-
-    wf::signal::connection_t<wf::view_hints_changed_signal> onViewHintsChanged {
-        [ = ] (wf::view_hints_changed_signal *ev) {
-            /** Check if the view is in the list */
-            auto it = std::find( attention_list.begin(), attention_list.end(), ev->view );
-
-            LOGE( "[FocusRequest] View hints changed ", ev->view->get_app_id(), " (", ev->view->get_id(), ") ", ev->demands_attention );
-
-            std::string appid = ev->view->get_app_id();
-            if ( ( appid.size() == 0 ) || ( appid == "nil" ) || ( appid == " " ) ) {
-                LOGE( "[FocusRequest] weird app (", ev->view->get_id(), ") ignoring." );
-                return;
-            }
-
-            /** demands_attention was set on this view */
-            if ( ev->demands_attention ) {
-                /** Current view in the list: move it to the end */
-                if ( it != attention_list.end() ) {
-                    int idx = it - attention_list.begin();
-                    std::swap( attention_list[ idx ], attention_list.back() );
-                    LOGE( "[FocusRequest] attention list size ", attention_list.size() );
-                }
-
-                /** Current view not in the list: add it to the end */
-                else {
-                    attention_list.push_back( ev->view );
-                    LOGE( "[FocusRequest] attention list size ", attention_list.size() );
-                }
-
-                ev->view->get_output()->connect( &onViewDisappeared );
-            }
-
-            /** demands_attention was removed from this view */
-            else {
-                /** Current view in the list: remove it */
-                if ( it != attention_list.end() ) {
-                    attention_list.erase( it );
-                    LOGE( "[FocusRequest] attention list size ", attention_list.size() );
-                }
-            }
-        }
-    };
-
-    wf::signal::connection_t<wf::view_disappeared_signal> onViewDisappeared {
-        [ = ] (wf::view_disappeared_signal *ev) {
-            if ( ev->view == nullptr ) {
-                return;
-            }
-
-            /** Check if the view is in the list */
-            auto it = std::find( attention_list.begin(), attention_list.end(), ev->view );
-
-            if ( it != attention_list.end() ) {
-                int idx = it - attention_list.begin();
-                LOGE( "[FocusRequest] removing view ", ev->view->get_id(), " ", ev->view->get_app_id() );
-                std::swap( attention_list[ idx ], attention_list.back() );
-                LOGE( "[FocusRequest] attention list size ", attention_list.size() );
-            }
-        }
-    };
-
-    public:
-        void init() override {
-            wf::get_core().connect( &onFocusRequested );
-            wf::get_core().connect( &onViewHintsChanged );
-
-            /** Get the currently focused view */
-            last_focus_view = wf::get_core().get_cursor_focus_view();
-
-            /** Add the binding, this first time when the plugin is init */
-            LOGE( "[FocusRequest] Adding activator" );
-
-            /** Add this to the list of bindings */
-            wf::get_core().bindings->add_activator( focus_key, &cb );
-        }
-
-        bool is_unloadable() override {
-            return true;
-        }
-
-        void fini() override {
-            wf::get_core().disconnect( &onFocusRequested );
-        }
-};
-
-DECLARE_WAYFIRE_PLUGIN( wayfire_focus_request );
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/ipc-scripts/ipc-shade-toggle.py wayfire-plugins-extra/subprojects/pixdecor/ipc-scripts/ipc-shade-toggle.py
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/ipc-scripts/ipc-shade-toggle.py	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/ipc-scripts/ipc-shade-toggle.py	1969-12-31 17:00:00.000000000 -0700
@@ -1,15 +0,0 @@
-#!/usr/bin/python3
-
-import os
-import sys
-from wayfire import WayfireSocket
-from wayfire.extra.wpe import WPE
-
-if len(sys.argv) < 2:
-    print(f"Usage: {sys.argv[0]} <view-id>")
-    exit(1)
-
-sock = WayfireSocket()
-wpe = WPE(sock)
-
-wpe.shade_toggle(int(sys.argv[1]))
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/LICENSE wayfire-plugins-extra/subprojects/pixdecor/LICENSE
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/LICENSE	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/LICENSE	1969-12-31 17:00:00.000000000 -0700
@@ -1,23 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2024 Scott Moreau
-Copyright (c) 2024 Ilia Bozhinov
-Copyright (c) 2024 Andrew Pliatsikas
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/meson.build wayfire-plugins-extra/subprojects/pixdecor/meson.build
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/meson.build	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/meson.build	1969-12-31 17:00:00.000000000 -0700
@@ -1,23 +0,0 @@
-project(
-    'pixdecor',
-    'c',
-    'cpp',
-    version: '0.1.0',
-    license: 'MIT',
-    meson_version: '>=0.51.0',
-    default_options: [
-        'cpp_std=c++17',
-        'c_std=c11',
-    ],
-)
-
-add_project_arguments(['-DWLR_USE_UNSTABLE'], language: ['cpp', 'c'])
-add_project_arguments(['-DWAYFIRE_PLUGIN'], language: ['cpp', 'c'])
-add_project_link_arguments(['-rdynamic','-fPIC'], language:'cpp')
-
-wayfire = dependency('wayfire', version: '>=0.9.0')
-
-
-subdir('src')
-subdir('metadata')
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/metadata/meson.build wayfire-plugins-extra/subprojects/pixdecor/metadata/meson.build
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/metadata/meson.build	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/metadata/meson.build	1969-12-31 17:00:00.000000000 -0700
@@ -1 +0,0 @@
-install_data( 'pixdecor.xml', install_dir: wayfire.get_variable( pkgconfig: 'metadatadir' ) )
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/metadata/pixdecor.xml wayfire-plugins-extra/subprojects/pixdecor/metadata/pixdecor.xml
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/metadata/pixdecor.xml	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/metadata/pixdecor.xml	1969-12-31 17:00:00.000000000 -0700
@@ -1,268 +0,0 @@
-<?xml version="1.0"?>
-<wayfire>
-	<plugin name="pixdecor">
-		<_short>Pix Decoration</_short>
-		<_long>A highly configurable and optionally fancy decorator plugin for wayfire.</_long>
-		<category>Effects</category>
-		<group>
-			<_short>General</_short>
-			<option name="border_size" type="int">
-				<_short>Border size</_short>
-				<_long>Sets the border size in pixels.</_long>
-				<default>5</default>
-				<min>0</min>
-			</option>
-			<option name="titlebar" type="bool">
-				<_short>Titlebar</_short>
-				<_long>Whether or not to render titlebar with title text and buttons.</_long>
-				<default>true</default>
-			</option>
-			<option name="maximized_borders" type="bool">
-				<_short>Draw borders on maximized windows</_short>
-				<_long>Whether or not to render side and bottom decorations on maximized windows.</_long>
-				<default>false</default>
-			</option>
-			<option name="maximized_shadows" type="bool">
-				<_short>Draw shadows on maximized windows</_short>
-				<_long>Whether or not to allocate space for shadows on maximized windows.</_long>
-				<default>false</default>
-			</option>
-			<option name="ignore_views" type="string">
-				<_short>Decoration disabled for specified window types</_short>
-				<_long>Disables window decoration for windows matching the specified criteria.</_long>
-				<default>none</default>
-			</option>
-			<option name="always_decorate" type="string">
-				<_short>Decoration applied for specified window types</_short>
-				<_long>Forces window decoration for windows matching the specified criteria.</_long>
-				<default>none</default>
-			</option>
-			<option name="title_font" type="string">
-				<_short>Title Font</_short>
-				<_long>Font to use for the titlebar. Uses the system font by default or if invalid.</_long>
-				<default></default>
-			</option>
-			<option name="fg_color" type="color">
-				<_short>Color when focused</_short>
-				<_long>Color of the window border when it has focus.</_long>
-				<default>0.9 0.65 0.04 1.0</default>
-			</option>
-			<option name="bg_color" type="color">
-				<_short>Color when not focused</_short>
-				<_long>Color of the window border when it does not have focus.</_long>
-				<default>0.07 0.27 0.5 0.85</default>
-			</option>
-			<option name="fg_text_color" type="color">
-				<_short>Text color when focused</_short>
-				<_long>Color of the window titlebar text when it has focus.</_long>
-				<default>1.0 1.0 1.0 1.0</default>
-			</option>
-			<option name="bg_text_color" type="color">
-				<_short>Text color when not focused</_short>
-				<_long>Color of the window titlebar text when it does not have focus.</_long>
-				<default>0.7 0.7 0.7 1.0</default>
-			</option>
-			<option name="button_color" type="color">
-				<_short>Button Color</_short>
-				<_long>Color of the minimize, maximize and close buttons.</_long>
-				<default>0.0 0.0 0.0 1.0</default>
-			</option>
-			<option name="button_line_thickness" type="double">
-				<_short>Button Line Thickness</_short>
-				<_long>The thickness used to draw the minimize, maximize and close button lines.</_long>
-				<default>0.7</default>
-				<min>0.0</min>
-			</option>
-			<option name="button_spacing" type="int">
-				<_short>Button Spacing</_short>
-				<_long>The space between each button.</_long>
-				<default>5</default>
-				<min>0</min>
-			</option>
-			<option name="button_y_offset" type="int">
-				<_short>Button Y Offset</_short>
-				<_long>Use this option to move buttons up or down.</_long>
-				<default>0</default>
-			</option>
-			<option name="button_x_offset" type="int">
-				<_short>Button X Offset</_short>
-				<_long>Use this option to move the buttons to the left or right.</_long>
-				<default>0</default>
-			</option>
-			<option name="button_minimize_image" type="string">
-				<_short>Button Minimize Image</_short>
-				<_long>The png image to use for the minimize button.</_long>
-				<default></default>
-				<hint>file</hint>
-			</option>
-			<option name="button_maximize_image" type="string">
-				<_short>Button Maximize Image</_short>
-				<_long>The png image to use for the maximize button.</_long>
-				<default></default>
-				<hint>file</hint>
-			</option>
-			<option name="button_close_image" type="string">
-				<_short>Button Close Image</_short>
-				<_long>The png image to use for the close button.</_long>
-				<default></default>
-				<hint>file</hint>
-			</option>
-			<option name="title_text_align" type="int">
-				<_short>Titlebar Text Alignment</_short>
-				<_long>Sets the alignment of the titlebar text.</_long>
-				<default>1</default>
-				<desc>
-					<value>0</value>
-					<_name>Left</_name>
-				</desc>
-				<desc>
-					<value>1</value>
-					<_name>Center</_name>
-				</desc>
-				<desc>
-					<value>2</value>
-					<_name>Right</_name>
-				</desc>
-			</option>
-			<option name="overlay_engine" type="string">
-				<_short>Overlay Engine</_short>
-				<_long>Sets the overlay engine.</_long>
-				<default>none</default>
-				<desc>
-					<value>none</value>
-					<_name>None</_name>
-				</desc>
-				<desc>
-					<value>rounded_corners</value>
-					<_name>Rounded Corners</_name>
-				</desc>
-				<desc>
-					<value>beveled_glass</value>
-					<_name>Beveled Glass</_name>
-				</desc>
-			</option>
-			<option name="effect_type" type="string">
-				<_short>Effect Type</_short>
-				<_long>Sets the effect type.</_long>
-				<default>none</default>
-				<desc>
-					<value>none</value>
-					<_name>None</_name>
-				</desc>
-				<desc>
-					<value>smoke</value>
-					<_name>Smoke</_name>
-				</desc>
-				<desc>
-					<value>ink</value>
-					<_name>Ink</_name>
-				</desc>
-				<desc>
-					<value>clouds</value>
-					<_name>Clouds</_name>
-				</desc>
-				<desc>
-					<value>halftone</value>
-					<_name>Halftone</_name>
-				</desc>
-				<desc>
-					<value>pattern</value>
-					<_name>Pattern</_name>
-				</desc>
-				<desc>
-					<value>lava</value>
-					<_name>Lava</_name>
-				</desc>
-				<desc>
-					<value>hex</value>
-					<_name>Hex</_name>
-				</desc>
-				<desc>
-					<value>zebra</value>
-					<_name>Zebra</_name>
-				</desc>
-				<desc>
-					<value>neural_network</value>
-					<_name>Neural network</_name>
-				</desc>
-				<desc>
-					<value>hexagon_maze</value>
-					<_name>Hexagon maze</_name>
-				</desc>
-				<desc>
-					<value>raymarched_truchet</value>
-					<_name>Raymarched truchet</_name>
-				</desc>
-				<desc>
-					<value>neon_pattern</value>
-					<_name>Neon pattern</_name>
-				</desc>
-				<desc>
-					<value>neon_rings</value>
-					<_name>Neon rings</_name>
-				</desc>
-				<desc>
-					<value>deco</value>
-					<_name>Deco</_name>
-				</desc>
-			</option>
-			<option name="effect_color" type="color">
-				<_short>Effect Color</_short>
-				<_long>Color of the titlebar background effect.</_long>
-				<default>0.88 0.11 0.14 1.0</default>
-			</option>
-			<option name="animate" type="bool">
-				<_short>Animate Effects</_short>
-				<_long>WARNING: Enabling this option can use lots of system resources. Enables animating and constant repainting of window decorations.</_long>
-				<default>false</default>
-			</option>
-			<option name="rounded_corner_radius" type="int">
-				<_short>Rounded Corner Radius</_short>
-				<_long>The radius for corners.</_long>
-				<default>5</default>
-				<min>0</min>
-			</option>
-			<option name="shadow_radius" type="int">
-				<_short>Shadow Radius</_short>
-				<_long>The radius for shadows.</_long>
-				<default>10</default>
-				<min>0</min>
-			</option>
-			<option name="shadow_color" type="color">
-				<_short>Shadow Color</_short>
-				<_long>Color of the drop shadows.</_long>
-				<default>0.0 0.0 0.0 0.25</default>
-			</option>
-		</group>
-		<group>
-			<_short>Shade</_short>
-			<option name="enable_shade" type="bool">
-				<_short>Enable Shade Effect</_short>
-				<_long>Use the axis binding or scroll on the titlebar of pixdecor windows to shade windows into their respective titlebars.</_long>
-				<default>true</default>
-			</option>
-			<option name="shade_duration" type="animation">
-				<_short>Shade Duration</_short>
-				<_long>The duration of the shade animation in milliseconds.</_long>
-				<default>1000ms sigmoid</default>
-				<min>0</min>
-			</option>
-			<option name="shade_modifier" type="key">
-				<_short>Shade Modifier</_short>
-				<_long>When the shade modifier key is held down, you can scroll down and up to shade and unshade the window.</_long>
-				<default>&lt;super&gt; &lt;ctrl&gt;</default>
-			</option>
-			<option name="shade_toggle" type="activator">
-				<_short>Toggle Window Shade</_short>
-				<_long>Toggles shade for the active window.</_long>
-				<default></default>
-			</option>
-			<option name="csd_titlebar_height" type="int">
-				<_short>CSD Titlebar Height</_short>
-				<_long>Because there is no way to know the client surface titlebar height, this is an option to adjust it.</_long>
-				<default>32</default>
-				<min>0</min>
-			</option>
-		</group>
-	</plugin>
-</wayfire>
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/README.md wayfire-plugins-extra/subprojects/pixdecor/README.md
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/README.md	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/README.md	1969-12-31 17:00:00.000000000 -0700
@@ -1,20 +0,0 @@
-# pixdecor
-![pixdecor](https://github.com/soreau/pixdecor/assets/1450125/af891554-8eeb-4769-b571-fa587afd8350)
-
-A highly configurable decorator plugin for wayfire, pixdecor features antialiased rounded corners with shadows and optional animated effects.
-
-## Installing
-
-Set `--prefix` to the same as the wayfire installation.
-
-```
-$ meson setup build --prefix=/usr
-$ ninja -C build
-# ninja -C build install
-```
-
-Restart wayfire.
-
-## Running
-
-Disable other decorator plugins and enable pixdecor plugin in core section of `wayfire.ini`.
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-button.cpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-button.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-button.cpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-button.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,120 +0,0 @@
-#include "deco-button.hpp"
-#include "deco-theme.hpp"
-#include <wayfire/opengl.hpp>
-#include <wayfire/plugins/common/cairo-util.hpp>
-#include <stdlib.h>
-
-#define NORMAL   1.0
-#define PRESSED  0.5
-#define HOVERED  0.25
-
-namespace wf
-{
-namespace pixdecor
-{
-button_t::button_t(pixdecor_theme_t& t, std::function<void()> damage) :
-    theme(t), damage_callback(damage)
-{}
-
-wf::dimensions_t button_t::set_button_type(button_type_t type)
-{
-    this->type = type;
-    this->hover.animate(NORMAL, NORMAL);
-    auto size = update_texture();
-    add_idle_damage();
-
-    return size;
-}
-
-button_type_t button_t::get_button_type() const
-{
-    return this->type;
-}
-
-void button_t::set_hover(bool is_hovered)
-{
-    this->is_hovered = is_hovered;
-    if (!this->is_pressed)
-    {
-        if (is_hovered)
-        {
-            this->hover.animate(HOVERED);
-        } else
-        {
-            this->hover.animate(NORMAL);
-        }
-    }
-
-    add_idle_damage();
-}
-
-/**
- * Set whether the button is pressed or not.
- * Affects appearance.
- */
-void button_t::set_pressed(bool is_pressed)
-{
-    this->is_pressed = is_pressed;
-    if (is_pressed)
-    {
-        this->hover.animate(PRESSED);
-    } else
-    {
-        this->hover.animate(is_hovered ? HOVERED : NORMAL);
-    }
-
-    add_idle_damage();
-}
-
-void button_t::render(const wf::scene::render_instruction_t& data, wf::geometry_t geometry)
-{
-    OpenGL::render_texture(wf::gles_texture_t{button_texture.get_texture()}, data.target, geometry, {1, 1, 1, this->hover},
-        OpenGL::RENDER_FLAG_CACHED);
-    data.pass->custom_gles_subpass(data.target,[&]
-    {
-        for (auto& box : data.damage)
-        {
-            wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
-            OpenGL::draw_cached();
-        }
-    });
-
-    OpenGL::clear_cached();
-
-    if (this->hover.running())
-    {
-        add_idle_damage();
-    }
-}
-
-wf::dimensions_t button_t::update_texture()
-{
-    pixdecor_theme_t::button_state_t state = {
-        .width  = 1.0 * (theme.get_font_height_px() >= LARGE_ICON_THRESHOLD ? 26 : 18),
-        .height = 1.0 * (theme.get_font_height_px() >= LARGE_ICON_THRESHOLD ? 26 : 18),
-        .border = 1.0,
-        .hover  = this->is_hovered,
-    };
-
-    auto surface = theme.get_button_surface(type, state, this->active);
-    wf::dimensions_t size{cairo_image_surface_get_width(surface), cairo_image_surface_get_height(surface)};
-
-    wf::gles::run_in_context([&]
-    {
-        this->button_texture = owned_texture_t{surface};
-    });
-
-    cairo_surface_destroy(surface);
-
-    return size;
-}
-
-void button_t::add_idle_damage()
-{
-    this->idle_damage.run_once([=] ()
-    {
-        this->damage_callback();
-    });
-}
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-button.hpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-button.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-button.hpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-button.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,98 +0,0 @@
-#pragma once
-
-#include <string>
-#include <wayfire/util.hpp>
-#include <wayfire/opengl.hpp>
-#include <wayfire/render-manager.hpp>
-#include <wayfire/util/duration.hpp>
-#include <wayfire/scene-render.hpp>
-#include <wayfire/plugins/common/cairo-util.hpp>
-
-#include <cairo.h>
-#include <pango/pango.h>
-#include <pango/pangocairo.h>
-
-namespace wf
-{
-namespace pixdecor
-{
-class pixdecor_theme_t;
-
-enum button_type_t
-{
-    BUTTON_CLOSE,
-    BUTTON_TOGGLE_MAXIMIZE,
-    BUTTON_MINIMIZE,
-};
-
-class button_t
-{
-  public:
-    /**
-     * Create a new button with the given theme.
-     * @param theme  The theme to use.
-     * @param damage_callback   A callback to execute when the button needs a
-     * repaint. Damage won't be reported while render() is being called.
-     */
-    button_t(pixdecor_theme_t& theme,
-        std::function<void()> damage_callback);
-
-    /**
-     * Set the type of the button. This will affect the displayed icon and
-     * potentially other appearance like colors.
-     */
-    wf::dimensions_t set_button_type(button_type_t type);
-
-    /** @return The type of the button */
-    button_type_t get_button_type() const;
-
-    /**
-     * Set the button hover state.
-     * Affects appearance.
-     */
-    void set_hover(bool is_hovered);
-
-    /**
-     * Set whether the button is pressed or not.
-     * Affects appearance.
-     */
-    void set_pressed(bool is_pressed);
-
-    /**
-     * Render the button on the given framebuffer at the given coordinates.
-     * Precondition: set_button_type() has been called, otherwise result is no-op
-     *
-     * @param buffer The target framebuffer
-     * @param geometry The geometry of the button, in logical coordinates
-     * @param scissor The scissor rectangle to render.
-     */
-    void render(const wf::scene::render_instruction_t& data, wf::geometry_t geometry);
-
-    pixdecor_theme_t& theme;
-    std::function<void()> damage_callback;
-
-  private:
-
-    button_type_t type;
-    wf::owned_texture_t button_texture;
-    bool active = false;
-    wf::geometry_t geometry;
-
-    /* Whether the button is currently being hovered */
-    bool is_hovered = false;
-    /* Whether the button is currently being held */
-    bool is_pressed = false;
-    /* The shade of button background to use. */
-    wf::animation::simple_animation_t hover{wf::create_option(500)};
-
-    wf::wl_idle_call idle_damage;
-    /** Damage button the next time the main loop goes idle */
-    void add_idle_damage();
-
-    /**
-     * Redraw the button surface and store it as a texture
-     */
-    wf::dimensions_t update_texture();
-};
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-effects.cpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-effects.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-effects.cpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-effects.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,2624 +0,0 @@
-/*
- * The MIT License (MIT)
- *
- * Copyright (c) 2024 Scott Moreau <oreaus@gmail.com>
- * - Ported weston-smoke to compute shader set
- * Copyright (c) 2024 Ilia Bozhinov <ammen99@gmail.com>
- * - Awesome optimizations
- * Copyright (c) 2024 Andrew Pliatsikas <futurebytestore@gmail.com>
- * - Ported effect shaders to compute
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-
-#include <wayfire/debug.hpp>
-#include <wayfire/render.hpp>
-
-#include "deco-effects.hpp"
-#include "smoke-shaders.hpp"
-
-
-namespace wf
-{
-namespace pixdecor
-{
-static std::string stitch_smoke_shader(const std::string& source)
-{
-    return smoke_header + source + effect_run_for_region_main;
-}
-
-// ported from https://www.shadertoy.com/view/WdXBW4
-static const char *render_source_clouds =
-    R"(
-#version 320 es
-precision highp float;
-precision highp image2D;
-
-layout(binding = 0, rgba32f) uniform writeonly image2D out_tex;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float current_time;
-float cloudscale=2.1;  // Added cloudscale parameter
-
-const mat2 m = mat2(1.6, 1.2, -1.2, 1.6);
-
-vec2 hash(vec2 p) {
-    p = vec2(dot(p, vec2(127.1, 311.7)), dot(p, vec2(269.5, 183.3)));
-    return -1.0 + 2.0 * fract(sin(p) * 43758.5453123);
-}
-
-float noise(vec2 p) {
-    const float K1 = 0.366025404; // (sqrt(3)-1)/2;
-    const float K2 = 0.211324865; // (3-sqrt(3))/6;
-    vec2 i = floor(p + (p.x + p.y) * K1);
-    vec2 a = p - i + (i.x + i.y) * K2;
-    vec2 o = (a.x > a.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);
-    vec2 b = a - o + K2;
-    vec2 c = a - 1.0 + 2.0 * K2;
-    vec3 h = max(0.5 - vec3(dot(a, a), dot(b, b), dot(c, c)), 0.0);
-    vec3 n = h * h * h * h * vec3(dot(a, hash(i + 0.0)), dot(b, hash(i + o)), dot(c, hash(i + 1.0)));
-    return dot(n, vec3(70.0));
-}
-
-float fbm(vec2 n) {
-    float total = 0.0, amplitude = 0.1;
-    for (int i = 0; i < 7; i++) {
-        total += noise(n) * amplitude;
-        n = m * n;
-        amplitude *= 0.4;
-    }
-    return total;
-}
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-
-    int x = pos.x;
-    int y = pos.y;
-    
-    
-      // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-    
-    vec2 uv = vec2(pos) / vec2(gl_NumWorkGroups.x * gl_WorkGroupSize.x, gl_NumWorkGroups.y * gl_WorkGroupSize.y);
-
-    float time = 0.003 * current_time;  // Time variable for animation
-
-    float cloudPattern1 = fbm(uv * 10.0 * cloudscale + time);
-    float cloudPattern2 = fbm(uv * 5.0 * cloudscale + time);
-    float cloudPattern3 = fbm(uv * 3.0 * cloudscale + time);
-
-    // Combine different cloud patterns with different weights
-    float cloudPattern = 0.5 * cloudPattern1 + 0.3 * cloudPattern2 + 0.2 * cloudPattern3;
-
-    // Ridge noise shape
-    float ridgeNoiseShape = 0.0;
-    uv *= cloudscale * 1.1;  // Adjust scale
-    float weight = 0.8;
-    for (int i = 0; i < 8; i++) {
-        ridgeNoiseShape += abs(weight * noise(uv));
-        uv = m * uv + time;
-        weight *= 0.7;
-    }
-
-    // Noise shape
-    float noiseShape = 0.0;
-    uv = vec2(pos) / vec2(gl_NumWorkGroups.x * gl_WorkGroupSize.x, gl_NumWorkGroups.y * gl_WorkGroupSize.y);
-    uv *= cloudscale * 1.1;  // Adjust scale
-    weight = 0.7;
-    for (int i = 0; i < 8; i++) {
-        noiseShape += weight * noise(uv);
-        uv = m * uv + time;
-        weight *= 0.6;
-    }
-
-    noiseShape *= ridgeNoiseShape + noiseShape;
-
-    // Noise color
-    float noiseColor = 0.0;
-    uv = vec2(pos) / vec2(gl_NumWorkGroups.x * gl_WorkGroupSize.x, gl_NumWorkGroups.y * gl_WorkGroupSize.y);
-    uv *= 2.0 * cloudscale;  // Adjust scale
-    weight = 0.4;
-    for (int i = 0; i < 7; i++) {
-        noiseColor += weight * noise(uv);
-        uv = m * uv + time;
-        weight *= 0.6;
-    }
-
-    // Noise ridge color
-    float noiseRidgeColor = 0.0;
-    uv = vec2(pos) / vec2(gl_NumWorkGroups.x * gl_WorkGroupSize.x, gl_NumWorkGroups.y * gl_WorkGroupSize.y);
-    uv *= 3.0 * cloudscale;  // Adjust scale
-    weight = 0.4;
-    for (int i = 0; i < 7; i++) {
-        noiseRidgeColor += abs(weight * noise(uv));
-        uv = m * uv + time;
-        weight *= 0.6;
-    }
-
-    noiseColor += noiseRidgeColor;
-
-    // Sky tint
-    float skytint = 0.5;
-    vec3 skyColour1 = vec3(0.1, 0.2, 0.3);
-    vec3 skyColour2 = vec3(0.4, 0.7, 1.0);
-    vec3 skycolour = mix(skyColour1, skyColour2, smoothstep(0.4, 0.6, uv.y));
-
-    // Cloud darkness
-    float clouddark = 0.5;
-
-    // Cloud Cover, Cloud Alpha
-    float cloudCover = 0.01;
-    float cloudAlpha = 2.0;
-
-    // Movement effect
-    uv = uv + time;
-
-    // Use a bright color for clouds
-    vec3 cloudColor = vec3(1.0, 1.0, 1.0); ;  // Bright white color for clouds
-
-    // Mix the cloud color with the background, considering darkness, cover, and alpha
-    vec3 finalColor = mix(skycolour, cloudColor * clouddark, cloudPattern + noiseShape + noiseColor) * (1.0 - cloudCover) + cloudColor * cloudCover;
-    finalColor = mix(skycolour, finalColor, cloudAlpha);
-
-    imageStore(out_tex, pos, vec4(finalColor, 1.0));
-}
-
-
-
-)";
-
-// ported from https://github.com/keijiro/ShaderSketches/blob/master/Fragment/Dots3.glsl
-static const char *render_source_halftone =
-    R"(
-#version 310 es
-precision highp float;
-precision highp image2D;
-
-layout(binding = 0, rgba32f) writeonly uniform highp image2D out_tex;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float time;
-
-const vec2 resolution = vec2(1280.0, 720.0);
-const float timeFactor = 0.025;
-
-float rand(vec2 uv) {
-    return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
-}
-
-vec2 rotate(vec2 p, float theta) {
-    vec2 sncs = vec2(sin(theta), cos(theta));
-    return vec2(p.x * sncs.y - p.y * sncs.x, p.x * sncs.x + p.y * sncs.y);
-}
-
-float swirl(vec2 coord, float t) {
-    float l = length(coord) / resolution.x;
-    float phi = atan(coord.y, coord.x + 1e-6);
-    return sin(l * 10.0 + phi - t * 4.0) * 0.5 + 0.5;
-}
-
-float halftone(vec2 coord, float angle, float t, float amp) {
-    coord -= resolution * 0.5;
-    float size = resolution.x / (60.0 + sin(time * timeFactor * 0.5) * 50.0);
-    vec2 uv = rotate(coord / size, angle / 180.0 * 3.14);
-    vec2 ip = floor(uv); // column, row
-    vec2 odd = vec2(0.5 * mod(ip.y, 2.0), 0.0); // odd line offset
-    vec2 cp = floor(uv - odd) + odd; // dot center
-    float d = length(uv - cp - 0.5) * size; // distance
-    float r = swirl(cp * size, t) * size * 0.5 * amp; // dot radius
-    return 1.0 - clamp(d  - r, 0.0, 1.0);
-}
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-    
-       // Extract x and y coordinates
-    int x = pos.x;
-    int y = pos.y;
-    
-    
-      // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-    
-    vec3 c1 = 1.0 - vec3(1.0, 0.0, 0.0) * halftone(vec2(pos),   0.0, time * timeFactor * 1.00, 0.7);
-    vec3 c2 = 1.0 - vec3(0.0, 1.0, 0.0) * halftone(vec2(pos),  30.0, time * timeFactor * 1.33, 0.7);
-    vec3 c3 = 1.0 - vec3(0.0, 0.0, 1.0) * halftone(vec2(pos), -30.0, time * timeFactor * 1.66, 0.7);
-    vec3 c4 = 1.0 - vec3(1.0, 1.0, 1.0) * halftone(vec2(pos),  60.0, time * timeFactor * 2.13, 0.4);
-
-    // Output the final color
-    imageStore(out_tex, pos, vec4(c1 * c2 * c3 * c4, 1.0));
-}
-)";
-
-// ported from https://www.shadertoy.com/view/WdjGRc
-static const char *render_source_lava =
-    R"(
-#version 320 es
-precision highp float;
-precision highp image2D;
-
-layout(binding = 0, rgba32f) uniform readonly image2D in_tex;
-layout(binding = 0, rgba32f) uniform writeonly image2D out_tex;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float current_time;
-
-vec3 effect(float speed, vec2 uv, float time, float scale) {
-    float t = mod(time * 0.005, 6.0);
-    float rt = 0.00000000000001 * sin(t * 0.45);
-
-    mat2 m1 = mat2(cos(rt), -sin(rt), -sin(rt), cos(rt));
-    vec2 uva = uv * m1 * scale;
-    float irt = 0.005 * cos(t * 0.05);
-    mat2 m2 = mat2(sin(irt), cos(irt), -cos(irt), sin(irt));
-
-    for (int i = 1; i < 40; i += 1) {
-        float it = float(i);
-        uva *= m2;
-        uva.y += -1.0 + (0.6 / it) * cos(t + it * uva.x + 0.5 * it) * float(mod(it, 0.5) == 0.0);
-        uva.x += 1.0 + (0.5 / it) * cos(t + it * uva.y * 0.1 / 5.0 + 0.5 * (it + 15.0));  // Adjust the scaling factor for y-coordinate
-    }
-
-    float n = 0.5;
-    float r = n + n * sin(4.0 * uva.x + t);
-    float gb = n + n * sin(3.0 * uva.y);
-    return vec3(r, gb * 0.8 * r, gb * r);
-}
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-    
-vec2 uv = vec2(pos) / vec2(1000, 2000);
-    uv = 2.0 * uv - 1.0;
-    uv *= (10.3 + 0.1 * sin(current_time * 0.01));
-
-       // Extract x and y coordinates
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-
-    
-   // uv.y -= current_time * 0.013;
-//uv.x -= current_time * 0.026;
-    vec3 col = effect(0.001, uv, current_time, 0.5);
-    // col += effect(0.5, uv * 3.0, 2.0 * current_time + 10.0, 0.5) * 0.3;
-    // col += effect(0.5, sin(current_time * 0.01) * uv * 2.0, 2.0 * current_time + 10.0, 0.5) * 0.1;
-
-    // Output the final color to the output texture
-    imageStore(out_tex, pos, vec4(col, 1.0));
-}
-)";
-
-// ported from https://github.com/keijiro/ShaderSketches/blob/master/Fragment/Eyes2.glsl
-static const char *render_source_pattern =
-    R"(
-#version 310 es
-precision highp float;
-precision highp image2D;
-
-layout(binding = 0, rgba32f) writeonly uniform highp image2D out_tex;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float time;
-
-float rand(vec2 uv)
-{
-    return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
-}
-
-vec3 hue2rgb(float h)
-{
-    h = fract(h) * 6.0 - 2.0;
-    return clamp(vec3(abs(h - 1.0) - 1.0, 2.0 - abs(h), 2.0 - abs(h - 2.0)), 0.0, 1.0);
-}
-
-vec3 eyes(vec2 coord, vec2 resolution)
-{
-    const float pi = 3.141592;
-    float t = 0.4 * time * 0.05; 
-    float aspectRatio = resolution.x / resolution.y;
-    float div = 20.0;
-    float sc = 30.0;
-
-    vec2 p = (coord - resolution / 2.0) / sc - 0.5;
-
-    // center offset
-    float dir = floor(rand(floor(p) + floor(t) * 0.11) * 4.0) * pi / 2.0;
-    vec2 offs = vec2(sin(dir), cos(dir)) * 0.6;
-    offs *= smoothstep(0.0, 0.1, fract(t));
-    offs *= smoothstep(0.4, 0.5, 1.0 - fract(t));
-
-    // circles
-    float l = length(fract(p) + offs - 0.5);
-    float rep = sin((rand(floor(p)) * 2.0 + 2.0) * t) * 4.0 + 5.0;
-    float c = (abs(0.5 - fract(l * rep + 0.5)) - 0.25) * sc / rep;
-
-    // grid lines
-    vec2 gr = (abs(0.5 - fract(p + 0.5)) - 0.05) * sc;
-    c = clamp(min(min(c, gr.x), gr.y), 0.0, 1.0);
-
-    return hue2rgb(rand(floor(p) * 0.3231)) * c;
-}
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-    vec2 resolution = vec2(float(width), float(height));
-
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-
-    vec3 color = eyes(vec2(pos), resolution);
-
-    // Output the final color
-    imageStore(out_tex, pos, vec4(color, 1.0));
-}
-
-
-)";
-
-// original (by phodius)
-static const char *render_source_hex =
-    R"(
-#version 310 es
-precision highp float;
-precision highp int;
-
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-layout(binding = 0, rgba32f) writeonly uniform highp image2D OutputImage;
-
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float iTime;
-vec2 iResolution;
-
-float rand(vec2 co) {
-    return fract(sin(dot(co.xy, vec2(12.9898, 4.1414))) * 43758.5453);
-}
-
-// Hexagon function
-vec4 hexagon(vec2 p)
-{
-    vec2 q = vec2(p.x * 2.0 * 0.5773503, p.y + p.x * 0.5773503);
-
-    vec2 pi = floor(q);
-    vec2 pf = fract(q);
-
-    float v = mod(pi.x * 9.0, 0.0);
-
-    float ca = step(1.0, v);
-    float cb = step(2.0, v);
-    vec2 ma = step(pf.xy, pf.yx);
-
-    float e = 0.0;
-    float f = length((fract(p) - 10.5) * vec2(1.0, 0.85));
-
-    return vec4(pi + ca - cb * ma, e, f);
-}
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-
-    vec2 uv = (vec2(pos) + 0.5) / float(width);
-
-    // Generate a random value
-    float randVal = rand(uv);
-
-    // Apply hexagon logic
-    vec2 p = (-float(width) + 2.0 * vec2(pos)) / float(height);
-    vec4 h = hexagon(40.0 * p + vec2(0.5 * iTime * 0.125));
-
-    float col = 0.01 + 0.15 * rand(vec2(h.xy)) * 1.0;
-    col *= 4.3 + 0.15 * sin(10.0 * h.z);
-
-    // Use hardcoded colors for shades with gradient
-    vec3 shadeColor1 = vec3(0.1, 0.1, 0.1) + 1.1 * col * h.z;   // Dark gray with gradient
-    vec3 shadeColor2 = vec3(0.4, 0.4, 0.4) + 1.1 * col;  // Gray with gradient
-    vec3 shadeColor3 = vec3(0.9, 0.9, 0.9) + 0.1 * col;  // Light gray with gradient
-
-    // Use different hardcoded colors based on the random value
-    vec3 finalColor = mix(shadeColor1, mix(shadeColor2, shadeColor3, randVal), col);
-
-    // Use imageStore instead of writing to buffer
-    imageStore(OutputImage, pos, vec4(finalColor, 1.0));
-}
-)";
-
-// ported from https://github.com/keijiro/ShaderSketches/blob/master/Fragment/Zebra.glsl
-static const char *render_source_zebra =
-    R"(
-#version 310 es
-precision highp float;
-precision highp image2D;
-
-layout(binding = 0, rgba32f) writeonly uniform highp image2D out_tex;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float time;
-const float resolutionY = 720.0; // Set to constant resolution of 720p
-const float pi = 3.14159265359;
-const float timeFactor = 0.05; // Adjust this factor to control the speed of the animation
-
-float rand(vec2 uv)
-{
-    return fract(sin(dot(uv, vec2(12.9898, 78.233))) * 43758.5453);
-}
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-    float size = resolutionY / 10.0; // cell size in pixel
-
-    vec2 p1 = vec2(pos) / size; // normalized pos
-    vec2 p2 = fract(p1) - 0.5; // relative pos from cell center
-
-    // random number
-    float rnd = dot(floor(p1), vec2(12.9898, 78.233));
-    rnd = fract(sin(rnd) * 43758.5453);
-
-    // rotation matrix
-    float phi = rnd * pi * 2.0 + time * 0.4 * timeFactor;
-    mat2 rot = mat2(cos(phi), -sin(phi), sin(phi), cos(phi));
-
-    vec2 p3 = rot * p2; // apply rotation
-    p3.y += sin(p3.x * 5.0 + time * 2.0 * timeFactor) * 0.12; // wave
-
-    float rep = fract(rnd * 13.285) * 8.0 + 2.0; // line repetition
-    float gr = fract(p3.y * rep + time * 0.8 * timeFactor); // repeating gradient
-
-    // make antialiased line by saturating the gradient
-    float c = clamp((0.25 - abs(0.5 - gr)) * size * 0.75 / rep, 0.0, 1.0);
-    c *= max(0.0, 1.0 - length(p2) * 0.6); // darken corners
-
-    vec2 bd = (0.5 - abs(p2)) * size - 2.0; // border lines
-    c *= clamp(min(bd.x, bd.y), 0.0, 1.0);
-
-    // Output the final color
-    imageStore(out_tex, pos, vec4(c, c, c, 1.0));
-}
-
-
-)";
-
-// ported from https://www.shadertoy.com/view/dlGfWV
-static const char *render_source_neural_network =
-    R"(
-
-#version 310 es
-precision highp float;
-precision highp image2D;
-
-//layout(binding = 0, rgba32f) readonly uniform highp image2D neural_network_tex;  // Use binding point 0
-layout(binding = 0, rgba32f) writeonly uniform highp image2D out_tex;  // Use binding point 1
-
-//layout(binding = 0, rgba32f) writeonly uniform highp image2D out_tex;
-
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float time;
-
-uniform vec2 iResolution;
-uniform float iTime;
-
-mat2 rotate2D(float r) {
-    float c = cos(r);
-    float s = sin(r);
-    return mat2(c, -s, s, c);
-}
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-
-    // Normalized pixel coordinates (from 0 to 1)
-    vec2 uv = (vec2(pos) - 0.5 * float(gl_NumWorkGroups.x)) / float(gl_WorkGroupSize.x);
-    
-    // Scale the uv coordinates by a factor of 8
-    uv *= 0.05;
-
-    vec3 col = vec3(0);
-    float t = 0.05 * time;
-
-    vec2 n = vec2(0), q;
-    vec2 N = vec2(0);
-    vec2 p = uv + sin(t * 0.1) / 10.0;
-    float S = 10.0;
-    mat2 m = rotate2D(1.0);
-
-    for (float j = 0.0; j < 30.0; j++) {
-        p *= m;
-        n *= m;
-        q = p * S + j + n + t;
-        n += sin(q);
-        N += cos(q) / S;
-        S *= 1.2;
-    }
-
-    col = vec3(1, 2, 4) * pow((N.x + N.y + 0.2) + 0.005 / length(N), 2.1);
-
-    imageStore(out_tex, pos, vec4(col, 1.0));
-}
-)";
-
-// Ported from https://www.shadertoy.com/view/llSyDh
-static const char *render_source_hexagon_maze =
-    R"(
-#version 320 es
-
-precision highp float;
-precision highp int;
-precision highp image2D;
-
-//layout (location = 0) out vec4 fragColor;
-layout (binding = 0, rgba32f) writeonly uniform image2D fragColor;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float iTime;
-uniform vec2 iResolution;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-
-// Interlaced variation - Interesting, but patched together in a hurry.
-//#define INTERLACING
-
-// A quick hack to get rid of the winding overlay - in order to show the maze only.
-//#define MAZE_ONLY
-
-
-
-// Helper vector. If you're doing anything that involves regular triangles or hexagons, the
-// 30-60-90 triangle will be involved in some way, which has sides of 1, sqrt(3) and 2.
-const vec2 s = vec2(1, 1.7320508);
-
-// Standard vec2 to float hash - Based on IQ's original.
-float hash21(vec2 p){ return fract(sin(dot(p, vec2(141.173, 289.927)))*43758.5453); }
-
-
-// Standard 2D rotation formula.
-mat2 r2(in float a){ float c = cos(a), s = sin(a); return mat2(c, -s, s, c); }
-
-
-// The 2D hexagonal isosuface function: If you were to render a horizontal line and one that
-// slopes at 60 degrees, mirror, then combine them, you'd arrive at the following.
-float hex(in vec2 p){
-    
-    p = abs(p);
-    
-    // Below is equivalent to:
-    //return max(p.x*.5 + p.y*.866025, p.x); 
-
-    return max(dot(p, s*.5), p.x); // Hexagon.
-    
-}
-
-// This function returns the hexagonal grid coordinate for the grid cell, and the corresponding 
-// hexagon cell ID - in the form of the central hexagonal point. That's basically all you need to 
-// produce a hexagonal grid.
-//
-// When working with 2D, I guess it's not that important to streamline this particular function.
-// However, if you need to raymarch a hexagonal grid, the number of operations tend to matter.
-// This one has minimal setup, one "floor" call, a couple of "dot" calls, a ternary operator, etc.
-// To use it to raymarch, you'd have to double up on everything - in order to deal with 
-// overlapping fields from neighboring cells, so the fewer operations the better.
-vec4 getHex(vec2 p){
-    
-    // The hexagon centers: Two sets of repeat hexagons are required to fill in the space, and
-    // the two sets are stored in a "vec4" in order to group some calculations together. The hexagon
-    // center we'll eventually use will depend upon which is closest to the current point. Since 
-    // the central hexagon point is unique, it doubles as the unique hexagon ID.
-    vec4 hC = floor(vec4(p, p - vec2(.5, 1))/s.xyxy) + .5;
-    
-    // Centering the coordinates with the hexagon centers above.
-    vec4 h = vec4(p - hC.xy*s, p - (hC.zw + .5)*s);
-    
-    // Nearest hexagon center (with respect to p) to the current point. In other words, when
-    // "h.xy" is zero, we're at the center. We're also returning the corresponding hexagon ID -
-    // in the form of the hexagonal central point. Note that a random constant has been added to 
-    // "hC.zw" to further distinguish it from "hC.xy."
-    //
-    // On a side note, I sometimes compare hex distances, but I noticed that Iomateron compared
-    // the Euclidian version, which seems neater, so I've adopted that.
-    return dot(h.xy, h.xy)<dot(h.zw, h.zw) ? vec4(h.xy, hC.xy) : vec4(h.zw, hC.zw + vec2(.5, 1));
-    
-}
-
-// Dot pattern.
-float dots(in vec2 p){
-    
-    p = abs(fract(p) - .5);
-    
-    return length(p); // Circles.
-    
-    //return (p.x + p.y)/1.5 + .035; // Diamonds.
-    
-    //return max(p.x, p.y) + .03; // Squares.
-    
-    //return max(p.x*.866025 + p.y*.5, p.y) + .01; // Hexagons.
-    
-    //return min((p.x + p.y)*.7071, max(p.x, p.y)) + .08; // Stars.
-    
-    
-}
-
-
-// Distance field for the arcs. I think it's called poloidal rotation, or something like that.
-float dfPol(vec2 p){
-     
-    return length(p); // Circular arc.
-    
-    // There's no rule that says the arcs have to be rounded. Here's a hexagonal one.
-    //return hex(p);
-    
-    // Dodecahedron.
-    //return max(hex(p), hex(r2(3.14159/6.)*p));
-    
-    // Triangle.
-    //return max(abs(p.x)*.866025 - p.y, p.y);
-    
-}
-
-
-// Truchet pattern distance field.
-float df(vec2 p, float dir){
-     
-    // Weird UV coordinates. The first entry is the Truchet distance field itself,
-    // and the second is the polar angle of the arc pixel. The extra ".1" is just a bit
-    // of mutational scaling, or something... I can't actually remember why it's there. :)
-    vec2 uv = vec2(p.x + .1, p.y);//*vec2(1, 1); // Scaling.
-    
-    // A checkered dot pattern. At present the pattern needs to have flip symmetry about
-    // the center, but I'm pretty sure regular textures could be applied with a few
-    // minor changes. Due to the triangular nature of the Truchet pattern, factors of "3"
-    // were necessary, but factors of "1.5" seemed to work too. Hence the "4.5."
-    return min(dots(uv*4.5), dots(uv*4.5 + .5)) - .3;
-    
-}
-
-
-// Polar coordinate of the arc pixel.
-float getPolarCoord(vec2 q, float dir){
-    
-    // The actual animation. You perform that before polar conversion.
-    q = r2((iTime*0.05)*dir)*q;
-    
-    // Polar angle.
-    const float aNum = 1.;
-    float a = atan(q.y, q.x);
-   
-    // Wrapping the polar angle.
-    return mod(a/3.14159, 2./aNum) - 1./aNum;
-   
-    
-}
-
-
-
-void main() {
-    vec2 iResolution = vec2(width, height);
-    ivec2 id = ivec2(gl_GlobalInvocationID.xy);
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-    vec2 fragCoord = vec2(id);
-    float res = clamp(iResolution.y, 300.0, 600.0);
-    vec2 u = (fragCoord - iResolution.xy*.5)/res;
-    vec2 sc = u*4. + s.yx*(iTime*0.05)/12.;
-    vec4 h = getHex(sc);
-    vec4 h2 = getHex(sc - 1.0 / s);
-    vec4 h3 = getHex(sc + 1.0 / s);
-    vec2 p = h.xy;
-    float eDist = hex(p);
-    float cDist = dot(p, p);
-    float rnd = hash21(h.zw);
- //float aRnd = sin(rnd*6.283 + (iTime*0.05)*1.5)*.5 + .5; // Animating the random number.
-    
-    #ifdef INTERLACING
-    // Random vec3 - used for some overlapping.
-    //vec3 lRnd = vec3(rnd*14.4 + .81, fract(rnd*21.3 + .97), fract(rnd*7.2 + .63));
-    vec3 lRnd = vec3(hash21(h.zw + .23), hash21(h.zw + .96), hash21(h.zw + .47));
-    #endif
-    
-    // It's possible to control the randomness to form some kind of repeat pattern.
-    //rnd = mod(h.z + h.w, 2.);
-    
-
-    // Redundant here, but I might need it later.
-    float dir = 1.;
-    
-
-    
-    // Storage vector.
-    vec2 q;
-    
-    
-    // If the grid cell's random ID is above a threshold, flip the Y-coordinates.
-    if(rnd>.5) p.y = -p.y;
-        
-    
-
-    // Determining the closest of the three arcs to the current point, the keeping a copy
-    // of the vector used to produce it. That way, you'll know just to render that particular
-    // decorated arc, lines, etc - instead of all three. 
-    const float r = 1.;
-    const float th = .2; // Arc thickness.
-    
-    // Arc one.
-    q = p - vec2(0, r)/s;
-    vec3 da = vec3(q, dfPol(q));
-    
-    // Arc two. "r2" could be hardcoded, but this is a relatively cheap 2D example.
-    q = r2(3.14159*2./3.)*p - vec2(0, r)/s;
-    vec3 db = vec3(q, dfPol(q));
-
-     // Arc three. 
-    q = r2(3.14159*4./3.)*p - vec2(0, r)/s;
-    vec3 dc = vec3(q, dfPol(q));
-    
-    // Compare distance fields, and return the vector used to produce the closest one.
-    vec3 q3 = da.z<db.z && da.z<dc.z? da : db.z<dc.z ? db : dc;
-    
-    
-    // TRUCHET PATTERN
-    //
-    // Set the poloidal arc radius: You can change the poloidal distance field in 
-    // the "dfPol" function to a different curve shape, but you'll need to change
-    // the radius to one of the figures below.
-    //
-    q3.z -= .57735/2. + th/2.;  // Circular and dodecahedral arc/curves.
-    //q3.z -= .5/2. + th/2.;  // Hexagon curve.
-    //q3.z -= .7071/2. + th/2.;  // Triangle curve.
-    
-    q3.z = max(q3.z, -th - q3.z); // Chop out the smaller radius. The result is an arc.
-    
-    // Store the result in "d" - only to save writing "q3.z" everywhere.
-    float d = q3.z;
-    
-    // If you'd like to see the maze by itself.
-    #ifdef MAZE_ONLY
-    d += 1e5;
-    #endif
-    
-    // Truchet border.
-    float dBord = max(d - .015, -d);
-    
-
-    
- 
-    
-    // MAZE BORDERS
-    // Producing the stright-line arc borders. Basically, we're rendering some hexagonal borders around
-    // the arcs. The result is the hexagonal maze surrounding the Truchet pattern.
-    q = q3.xy;
-    const float lnTh = .05;
-    q = abs(q);
-    
-    float arcBord = hex(q);
-    //float arcBord = length(q); // Change arc length to ".57735."
-    //float arcBord = max(hex(q), hex(r2(3.14159/6.)*q)); // Change arc length to ".57735."
-    
-    // Making the hexagonal arc.
-    float lnOuter = max(arcBord - .5, -(arcBord - .5 + lnTh)); //.57735
-    
-    
-    #ifdef INTERLACING
-    float ln = min(lnOuter, (q.y*.866025 + q.x*.5, q.x) - lnTh);
-    #else
-    float ln = min(lnOuter, arcBord - lnTh);
-    #endif
-    float lnBord = ln - .03; // Border lines to the maze border, if that makes any sense. :)
-     
-       
-    ///////
-    // The moving Truchet pattern. The polar coordinates consist of a wrapped angular coordinate,
-    // and the distance field itself.
-    float a = getPolarCoord(q3.xy, dir);
-    float d2 = df(vec2(q3.z, a), dir);
-    float dMask = smoothstep(0., .015, d);
-    vec3 bg =  mix(vec3(0, .0, .6), vec3(0, .9, .0), dot(sin(u*6. - cos(u*3.)), vec2(.4/2.)) + .4); 
-    
-    
-    
-    bg = mix(bg, bg.xzy, dot(sin(u*6. - cos(u*3.)), vec2(.4/2.)) + .4);
-    bg = mix(bg, bg.zxy, dot(sin(u*3. + cos(u*3.)), vec2(.1/2.)) + .1);
-   
-    #ifdef INTERLACING
-    // Putting in background cube lines for the interlaced version.
-    float hLines = smoothstep(0., .02, eDist - .5 + .02);
-    bg = mix(bg, vec3(0), smoothstep(0., .02, ln)*dMask*hLines);
-    #endif
-    
-    // Lines over the maze lines. Applying difference logic, depending on whether the 
-    // pattern is interlaced or not.
-    const float tr = 1.;
-
-    float eDist2 = hex(h2.xy);
-    float hLines2 = smoothstep(0., .02, eDist2 - .5 + .02);
-    #ifdef INTERLACING
-    if(rnd>.5 && lRnd.x<.5) hLines2 *= smoothstep(0., .02, ln);
-    if(lRnd.x>.5) hLines2 *= dMask;
-    #else
-    if(rnd>.5) hLines2 *= smoothstep(0., .02, ln);
-    hLines2 *= dMask;
-    #endif
-    bg = mix(bg, vec3(0), hLines2*tr);
-    
-    float eDist3 = hex(h3.xy);
-    float hLines3 = smoothstep(0., .02, eDist3 - .5 + .02);
-    #ifdef INTERLACING
-    if(rnd<=.5 && lRnd.x>.5) hLines3 *= smoothstep(0., .02, ln);
-    if(lRnd.x>.5) hLines3 *= dMask;
-    #else
-    if(rnd<=.5) hLines3 *= smoothstep(0., .02, ln);
-    hLines3 *= dMask;
-    #endif
-    bg = mix(bg, vec3(0), hLines3*tr);
-
-
-    // Using the two off-centered hex coordinates to give the background a bit of highlighting.
-    float shade = max(1.25 - dot(h2.xy, h2.xy)*2., 0.);
-    shade = min(shade, max(dot(h3.xy, h3.xy)*3. + .25, 0.));
-    bg = mix(bg, vec3(0), (1.-shade)*.5); 
-    
-    // I wanted to change the colors of everything at the last minute. It's pretty hacky, so
-    // when I'm feeling less lazy, I'll tidy it up. :)
-    vec3 dotCol = bg.zyx*vec3(1.5, .4, .4);
-    vec3 bCol = mix(bg.zyx, bg.yyy, .25);
-    bg = mix(bg.yyy, bg.zyx, .25);
-    
-    
-
-    // Under the random threshold, and we draw the lines under the Truchet pattern.
-    #ifdef INTERLACING
-    if(lRnd.x>.5){
-       bg = mix(bg, vec3(0), (1. - smoothstep(0., .015, lnBord)));
-       bg = mix(bg, bCol, (1. - smoothstep(0., .015, ln))); 
-       // Center lines.
-       bg = mix(bg, vec3(0), smoothstep(0., .02, eDist3 - .5 + .02)*tr);
-    }
-    #else
-    bg = mix(bg, vec3(0), (1. - smoothstep(0., .015, lnBord)));
-    bg = mix(bg, bCol, (1. - smoothstep(0., .015, ln)));
-    #endif
-
-
-   
-     // Apply the Truchet shadow to the background.
-    bg = mix(bg, vec3(0), (1. - smoothstep(0., .07, d))*.5);
-    
-    
-    // Place the Truchet field to the background, with some additional shading to give it a 
-    // slightly rounded, raised feel.
-    //vec3 col = mix(bg, vec3(1)*max(-d*3. + .7, 0.), (1. - dMask)*.65);
-    // Huttarl suggest slightly more shading on the snake-like pattern edges, so I added just a touch.
-    vec3 col = mix(bg, vec3(1)*max(-d*9. + .4, 0.), (1. - dMask)*.65);
-
-
-
-    
-    // Apply the moving dot pattern to the Truchet.
-    //dotCol = mix(dotCol, dotCol.xzy, dot(sin(u*3.14159*2. - cos(u.yx*3.14159*2.)*3.14159), vec2(.25)) + .5);
-    col = mix(col, vec3(0), (1. - dMask)*(1. - smoothstep(0., .02, d2)));
-    col = mix(col, dotCol, (1. - dMask)*(1. - smoothstep(0., .02, d2 + .125)));
-    
-    // Truchet border.
-    col = mix(col, vec3(0), 1. - smoothstep(0., .015, dBord));
-    
-    #ifdef INTERLACING
-    // Over the random threshold, and we draw the lines over the Truchet.
-    if(lRnd.x<=.5){
-        col = mix(col, vec3(0), (1. - smoothstep(0., .015, lnBord)));
-        col = mix(col, bCol, (1. - smoothstep(0., .015, ln)));  
-        // Center lines.
-        col = mix(col, vec3(0), smoothstep(0., .02, eDist2 - .5 + .02)*tr);
-    }
-    #endif
-
-
-        
-    
-    // Subtle vignette.
-    u = fragCoord/iResolution.xy;
-    col *= pow(16.*u.x*u.y*(1. - u.x)*(1. - u.y) , .125) + .25;
-    // Colored variation.
-    //col = mix(pow(min(vec3(1.5, 1, 1)*col, 1.), vec3(1, 3, 16)), col, 
-            //pow(16.*u.x*u.y*(1. - u.x)*(1. - u.y) , .25)*.75 + .25);    
-    
-    
-
- 
-
- 
-    
-    // Using the edge distance to produce some repeat contour lines. Standard stuff.
-    //if (rnd>.5) h.xy = -h.yx;
-    //float cont = clamp(cos(hex(h.xy)*6.283*12.)*1.5 + 1.25, 0., 1.);
-    //col = mix(col, vec3(0), (1. - smoothstep(0., .015, ln))*(smoothstep(0., .015, d))*(1.-cont)*.5);
-    
-    
- 
-    // Very basic hatch line effect.
-    float gr = dot(col, vec3(.299, .587, .114));
-    float hatch = (gr<.45)? clamp(sin((sc.x - sc.y)*3.14159*40.)*2. + 1.5, 0., 1.) : 1.;
-    float hatch2 = (gr<.25)? clamp(sin((sc.x + sc.y)*3.14159*40.)*2. + 1.5, 0., 1.) : 1.;
-
-    col *= min(hatch, hatch2)*.5 + .5;    
-    col *= clamp(sin((sc.x - sc.y)*3.14159*80.)*1.5 + .75, 0., 1.)*.25 + 1.;  
-    
- 
- 
-    vec2 u2 = fragCoord / iResolution.xy;
-    col *= pow(16.0 * u2.x * u2.y * (1.0 - u2.x) * (1.0 - u2.y), 0.125) + 0.25;
-
-    imageStore(fragColor, id, vec4(sqrt(max(col, 0.0)), 1.0));
-}
-
-
-
-)";
-
-// ported from https://www.shadertoy.com/view/4td3zj
-static const char *render_source_raymarched_truchet =
-    R"(
-#version 310 es
-
-precision highp float;
-precision highp int;
-precision highp image2D;
-
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-layout(binding = 0, rgba8) writeonly uniform image2D imageOut;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float  iTime;
-uniform vec2 iResolution;
-
-float heightMap(in vec2 p) { 
-    
-    p *= 5.;
-    
-    // Hexagonal coordinates.
-    vec2 h = vec2(p.x + p.y*.57735, p.y*1.1547);
-    
-    // Closest hexagon center.
-    vec2 f = fract(h); h -= f;
-    float c = fract((h.x + h.y)/3.);
-    h =  c<.666 ?   c<.333 ?  h  :  h + 1.  :  h  + step(f.yx, f); 
-
-    p -= vec2(h.x - h.y*.5, h.y*.8660254);
-    
-    // Rotate (flip, in this case) random hexagons. Otherwise, you'd have a bunch of circles only.
-    // Note that "h" is unique to each hexagon, so we can use it as the random ID.
-    c = fract(cos(dot(h, vec2(41, 289)))*43758.5453); // Reusing "c."
-    p -= p*step(c, .5)*2.; // Equivalent to: if (c<.5) p *= -1.;
-    
-    // Minimum squared distance to neighbors. Taking the square root after comparing, for speed.
-    // Three partitions need to be checked due to the flipping process.
-    p -= vec2(-1, 0);
-    c = dot(p, p); // Reusing "c" again.
-    p -= vec2(1.5, .8660254);
-    c = min(c, dot(p, p));
-    p -= vec2(0, -1.73205);
-    c = min(c, dot(p, p));
-    
-    return sqrt(c);
-    
-    // Wrapping the values - or folding the values over (abs(c-.5)*2., cos(c*6.283*1.), etc) - to produce 
-    // the nicely lined-up, wavy patterns. I"m perfoming this step in the "map" function. It has to do 
-    // with coloring and so forth.
-    //c = sqrt(c);
-    //c = cos(c*6.283*1.) + cos(c*6.283*2.);
-    //return (clamp(c*.6+.5, 0., 1.));
-
-}
-
-// Raymarching an XY-plane - raised a little by the hexagonal Truchet heightmap. Pretty standard.
-float map(vec3 p){
-    
-    
-    float c = heightMap(p.xy); // Height map.
-    // Wrapping, or folding the height map values over, to produce the nicely lined-up, wavy patterns.
-    c = cos(c*6.283*1.) + cos(c*6.283*2.);
-    c = (clamp(c*.6+.5, 0., 1.));
-
-    
-    // Back plane, placed at vec3(0., 0., 1.), with plane normal vec3(0., 0., -1).
-    // Adding some height to the plane from the heightmap. Not much else to it.
-    return 1. - p.z - c*.025;
-
-    
-}
-
-// The normal function with some edge detection and curvature rolled into it. Sometimes, it's possible to 
-// get away with six taps, but we need a bit of epsilon value variance here, so there's an extra six.
-vec3 getNormal(vec3 p, inout float edge, inout float crv) { 
-    
-    vec2 e = vec2(.01, 0); // Larger epsilon for greater sample spread, thus thicker edges.
-
-    // Take some distance function measurements from either side of the hit point on all three axes.
-    float d1 = map(p + e.xyy), d2 = map(p - e.xyy);
-    float d3 = map(p + e.yxy), d4 = map(p - e.yxy);
-    float d5 = map(p + e.yyx), d6 = map(p - e.yyx);
-    float d = map(p)*2.;    // The hit point itself - Doubled to cut down on calculations. See below.
-     
-    // Edges - Take a geometry measurement from either side of the hit point. Average them, then see how
-    // much the value differs from the hit point itself. Do this for X, Y and Z directions. Here, the sum
-    // is used for the overall difference, but there are other ways. Note that it's mainly sharp surface 
-    // curves that register a discernible difference.
-    edge = abs(d1 + d2 - d) + abs(d3 + d4 - d) + abs(d5 + d6 - d);
-    //edge = max(max(abs(d1 + d2 - d), abs(d3 + d4 - d)), abs(d5 + d6 - d)); // Etc.
-    
-    // Once you have an edge value, it needs to normalized, and smoothed if possible. How you 
-    // do that is up to you. This is what I came up with for now, but I might tweak it later.
-    edge = smoothstep(0., 1., sqrt(edge/e.x*2.));
-    
-    // We may as well use the six measurements to obtain a rough curvature value while we're at it.
-    crv = clamp((d1 + d2 + d3 + d4 + d5 + d6 - d*3.)*32. + .6, 0., 1.);
-    
-    // Redoing the calculations for the normal with a more precise epsilon value.
-    e = vec2(.0025, 0);
-    d1 = map(p + e.xyy), d2 = map(p - e.xyy);
-    d3 = map(p + e.yxy), d4 = map(p - e.yxy);
-    d5 = map(p + e.yyx), d6 = map(p - e.yyx); 
-    
-    
-    // Return the normal.
-    // Standard, normalized gradient mearsurement.
-    return normalize(vec3(d1 - d2, d3 - d4, d5 - d6));
-}
-
-
-
-// I keep a collection of occlusion routines... OK, that sounded really nerdy. :)
-// Anyway, I like this one. I'm assuming it's based on IQ's original.
-float calculateAO(in vec3 p, in vec3 n)
-{
-    float sca = 2., occ = 0.;
-    for(float i=0.; i<5.; i++){
-    
-        float hr = .01 + i*.5/4.;        
-        float dd = map(n * hr + p);
-        occ += (hr - dd)*sca;
-        sca *= 0.7;
-    }
-    return clamp(1.0 - occ, 0., 1.);    
-}
-
-
-/*
-// Surface bump function. Cheap, but with decent visual impact.
-float bumpSurf3D( in vec3 p){
-    
-    float c = heightMap((p.xy + p.z*.025)*6.);
-    c = cos(c*6.283*3.);
-    //c = sqrt(clamp(c+.5, 0., 1.));
-    c = (c*.5 + .5);
-    
-    return c;
-
-}
-
-// Standard function-based bump mapping function.
-vec3 dbF(in vec3 p, in vec3 nor, float bumpfactor){
-    
-    const vec2 e = vec2(0.001, 0);
-    float ref = bumpSurf3D(p);                 
-    vec3 grad = (vec3(bumpSurf3D(p - e.xyy),
-                      bumpSurf3D(p - e.yxy),
-                      bumpSurf3D(p - e.yyx) )-ref)/e.x;                     
-          
-    grad -= nor*dot(nor, grad);          
-                      
-    return normalize( nor + grad*bumpfactor );
-    
-}
-*/
-
-// Compact, self-contained version of IQ's 3D value noise function.
-float n3D(vec3 p){
-    
-    const vec3 s = vec3(7, 157, 113);
-    vec3 ip = floor(p); p -= ip; 
-    vec4 h = vec4(0., s.yz, s.y + s.z) + dot(ip, s);
-    p = p*p*(3. - 2.*p); //p *= p*p*(p*(p * 6. - 15.) + 10.);
-    h = mix(fract(sin(h)*43758.5453), fract(sin(h + s.x)*43758.5453), p.x);
-    h.xy = mix(h.xz, h.yw, p.y);
-    return mix(h.x, h.y, p.z); // Range: [0, 1].
-}
-
-// Simple environment mapping. Pass the reflected vector in and create some
-// colored noise with it. The normal is redundant here, but it can be used
-// to pass into a 3D texture mapping function to produce some interesting
-// environmental reflections.
-vec3 envMap(vec3 rd, vec3 sn){
-    
-    vec3 sRd = rd; // Save rd, just for some mixing at the end.
-    
-    // Add a time component, scale, then pass into the noise function.
-    rd.xy -= iTime*.25 *0.0125;
-    rd *= 3.;
-    
-    float c = n3D(rd)*.57 + n3D(rd*2.)*.28 + n3D(rd*4.)*.15; // Noise value.
-    c = smoothstep(0.4, 1., c); // Darken and add contast for more of a spotlight look.
-    
-    vec3 col = vec3(c, c*c, c*c*c*c); // Simple, warm coloring.
-    //vec3 col = vec3(min(c*1.5, 1.), pow(c, 2.5), pow(c, 12.)); // More color.
-    
-    // Mix in some more red to tone it down and return.
-    return mix(col, col.yzx, sRd*.25+.25); 
-    
-}
-
-
-
-// vec2 to vec2 hash.
-vec2 hash22(vec2 p) { 
-
-    // Faster, but doesn't disperse things quite as nicely as other combinations. :)
-    float n = sin(dot(p, vec2(41, 289)));
-    return fract(vec2(262144, 32768)*n)*.75 + .25; 
-    
-    // Animated.
-    //p = fract(vec2(262144, 32768)*n); 
-    //return sin( p*6.2831853 + iTime *0.0125)*.35 + .65; 
-    
-}
-
-// 2D 2nd-order Voronoi: Obviously, this is just a rehash of IQ's original. I've tidied
-// up those if-statements. Since there's less writing, it should go faster. That's how 
-// it works, right? :)
-//
-float Voronoi(in vec2 p){
-    
-    vec2 g = floor(p), o; p -= g;
-    
-    vec3 d = vec3(1); // 1.4, etc. "d.z" holds the distance comparison value.
-    
-    for(int y = -1; y <= 1; y++){
-        for(int x = -1; x <= 1; x++){
-            
-            o = vec2(x, y);
-            o += hash22(g + o) - p;
-            
-            d.z = dot(o, o); 
-            // More distance metrics.
-            //o = abs(o);
-            //d.z = max(o.x*.8666 + o.y*.5, o.y);// 
-            //d.z = max(o.x, o.y);
-            //d.z = (o.x*.7 + o.y*.7);
-            
-            d.y = max(d.x, min(d.y, d.z));
-            d.x = min(d.x, d.z); 
-                       
-        }
-    }
-    
-    return max(d.y/1.2 - d.x*1., 0.)/1.2;
-    //return d.y - d.x; // return 1.-d.x; // etc.
-    
-}
-
-
-
-void main() {
-
-    vec2 iResolution = vec2(width, height);
-    ivec2 id = ivec2(gl_GlobalInvocationID.xy);
- float tm = (iTime / 2.) * 0.0125;
- 
-
-
-    // Unit directional ray - Coyote's observation.
-    vec3 rd = normalize(vec3(2. * vec2(id) - iResolution.xy, iResolution.y));
-
-
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-
-    // Rotate the XY-plane back and forth. Note that sine and cosine are kind of rolled into one.
-    vec2 a = sin(vec2(1.570796, 0) + sin(tm / 4.) * .3);
-
-    // Fabrice's observation.
-    rd.xy = mat2(a, -a.y, a.x) * rd.xy;
-
-    // Ray origin. Moving in the X-direction to the right.
-  //  vec3 ro = vec3(tm, cos(tm / 4.), 0.);
-vec3 ro = vec3(0.0,0.0, 0.);
-    // Light position, hovering around behind the camera.
-    vec3 lp = ro + vec3(cos(tm / 2.) * .5, sin(tm / 2.) * .5, -.5);
-
-    // Standard raymarching segment. Because of the straightforward setup, not many iterations are necessary.
-    float d, t = 0.;
-    for (int j = 0; j < 32; j++) {
-        d = map(ro + rd * t); // distance to the function.
-        t += d * .7;          // Total distance from the camera to the surface.
-
-        // The plane "is" the far plane, so no far=plane break is needed.
-        if (d < 0.001)
-            break;
-    }
-
-    // Edge and curve value. Passed into, and set, during the normal calculation.
-    float edge, crv;
-
-    // Surface position, surface normal and light direction.
-    vec3 sp = ro + rd * t;
-    vec3 sn = getNormal(sp, edge, crv);
-    vec3 ld = lp - sp;
-
-    
-    // Coloring and texturing the surface.
-    //
-    // Height map.
-    float c = heightMap(sp.xy); 
-    
-    // Folding, or wrapping, the values above to produce the snake-like pattern that lines up with the randomly
-    // flipped hex cells produced by the height map.
-    vec3 fold = cos(vec3(1, 2, 4)*c*6.283);
-    
-    // Using the height map value, then wrapping it, to produce a finer grain Truchet pattern for the overlay.
-    float c2 = heightMap((sp.xy + sp.z*.025)*6.);
-    c2 = cos(c2*6.283*3.);
-    c2 = (clamp(c2+.5, 0., 1.)); 
-
-    
-    // Function based bump mapping. I prefer none in this example, but it's there if you want it.   
-    //if(temp.x>0. || temp.y>0.) sn = dbF(sp, sn, .001);
-    
-    // Surface color value.
-    vec3 oC = vec3(1);
-
-    if(fold.x>0.) oC = vec3(1, .05, .1)*c2; // Reddish pink with finer grained Truchet overlay.
-    
-    if(fold.x<0.05 && (fold.y)<0.) oC = vec3(1, .7, .45)*(c2*.25 + .75); // Lighter lined borders.
-    else if(fold.x<0.) oC = vec3(1, .8, .4)*c2; // Gold, with overlay.
-        
-    //oC *= n3D(sp*128.)*.35 + .65; // Extra fine grained noisy texturing.
-
-     
-    // Sending some greenish particle pulses through the snake-like patterns. With all the shininess going 
-    // on, this effect is a little on the subtle side.
-    float p1 = 1.0 - smoothstep(0., .1, fold.x*.5+.5); // Restrict to the snake-like path.
-    // Other path.
-    //float p2 = 1.0 - smoothstep(0., .1, cos(heightMap(sp.xy + 1. + (iTime*0.0125)/4.)*6.283)*.5+.5);
-    float p2 = 1.0 - smoothstep(0., .1, Voronoi(sp.xy*4. + vec2(tm, cos(tm/4.))));
-    p1 = (p2 + .25)*p1; // Overlap the paths.
-    oC += oC.yxz*p1*p1; // Gives a kind of electron effect. Works better with just Voronoi, but it'll do.
-    
-   
-    
-    
-    float lDist = max(length(ld), 0.001); // Light distance.
-    float atten = 1./(1. + lDist*.125); // Light attenuation.
-    
-    ld /= lDist; // Normalizing the light direction vector.
-    
-   
-    float diff = max(dot(ld, sn), 0.); // Diffuse.
-    float spec = pow(max( dot( reflect(-ld, sn), -rd ), 0.0 ), 16.); // Specular.
-    float fre = pow(clamp(dot(sn, rd) + 1., .0, 1.), 3.); // Fresnel, for some mild glow.
-    
-    // Shading. Note, there are no actual shadows. The camera is front on, so the following
-    // two functions are enough to give a shadowy appearance.
-    crv = crv*.9 + .1; // Curvature value, to darken the crevices.
-    float ao = calculateAO(sp, sn); // Ambient occlusion, for self shadowing.
-
- 
-    
-    // Combining the terms above to light the texel.
- vec3 col = oC*(diff + .5) + vec3(1., .7, .4)*spec*2. + vec3(.4, .7, 1)*fre;
-
-    
-   col += (oC*.5+.5)*envMap(reflect(rd, sn), sn)*6.; // Fake environment mapping.
- 
-    
-    // Edges.
-    col *= 1. - edge*.85; // Darker edges.   
-    
-    // Applying the shades.
-    col *= (atten*crv*ao);
-
-col *= 1.3;
- // Rough gamma correction, then write to the output buffer.
-    vec3 finalColor = sqrt(clamp(col, 0., 1.));
-    ivec2 fragCoord = ivec2(id);  // Convert to ivec2
-    imageStore(imageOut, fragCoord, vec4(finalColor, 1.0));  // Use vec4 instead of uvec4
-
-}
-)";
-
-// ported from https://www.shadertoy.com/view/mtyGWy
-static const char *render_source_neon_pattern =
-    R"(
-
- #version 310 es
-precision highp float;
-precision highp image2D;
-
-layout(binding = 0, rgba32f) uniform readonly image2D in_tex;
-layout(binding = 0, rgba32f) uniform writeonly image2D out_tex;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-//uniform float current_time;  // Assuming this is the global time variable
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float current_time; 
-
-vec3 palette(float t) {
-    vec3 a = vec3(0.5, 0.5, 0.5);
-    vec3 b = vec3(0.5, 0.5, 0.5);
-    vec3 c = vec3(1.0, 1.0, 1.0);
-    vec3 d = vec3(0.263, 0.416, 0.557);
-    return a + b * cos(6.28318 * (c * t + d));
-}
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-    
-       // Extract x and y coordinates
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-    vec2 uv = vec2(pos) / vec2(width, height);
-    vec2 uv0 = uv;
-    vec3 finalColor = vec3(0.0);
-
-    for (float i = 0.0; i < 4.0; i++) {
-        uv = fract(uv * 1.5) - 0.5;
-
-        float d = length(uv) * exp(-length(uv0));
-
-        vec3 col = palette(length(uv0) + i * 0.4 + current_time * 0.000001);
-
-        d = sin(d * 8.0 + current_time * 0.02) / 8.0;
-        d = abs(d);
-
-        d = pow(0.01 / d, 1.2);
-
-        finalColor += col * d;
-    }
-
-    // Output the final color to the output texture
-    imageStore(out_tex, pos, vec4(finalColor, 1.0));
-}
-)";
-
-// original (by phodius)
-static const char *render_source_neon_rings =
-    R"(
-#version 310 es
-precision highp float;
-precision highp image2D;
-
-layout(binding = 0, rgba32f) uniform readonly image2D in_tex;
-layout(binding = 0, rgba32f) uniform writeonly image2D out_tex;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float current_time; // Animated time
-
-#define PI 3.14159265358979323846
-#define TWO_PI 6.28318530717958647692
-
-void main() {
-   
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-    // Number of circles
-    int numCircles = 5;
-
-    // Initialize final color
-    vec3 finalColor = vec3(0.0);
-
-    for (int i = 0; i < numCircles; ++i) {
-        // Calculate UV coordinates for each circle
-        vec2 uv = vec2(pos) / vec2(width / 3, height / 3);
-
-        // Calculate polar coordinates
-        float a = atan(uv.y, uv.x);
-        float r = length(uv) * (0.2 + 0.1 * float(i));
-
-        // Map polar coordinates to UV
-        uv = vec2(a / TWO_PI, r);
-
-        // Apply horizontal movement based on time for each circle
-        float xOffset = sin(current_time * 0.02 + float(i)) * 0.2;
-        uv.x += xOffset;
-
-        // Time-dependent color
-        float xCol = (uv.x - (current_time / 300000.0)) * 3.0;
-        xCol = mod(xCol, 3.0);
-        vec3 horColour = vec3(0.25, 0.25, 0.25);
-
-        if (xCol < 1.0) {
-            horColour.r += 1.0 - xCol;
-            horColour.g += xCol;
-        } else if (xCol < 2.0) {
-            xCol -= 1.0;
-            horColour.g += 1.0 - xCol;
-            horColour.b += xCol;
-        } else {
-            xCol -= 2.0;
-            horColour.b += 1.0 - xCol;
-            horColour.r += xCol;
-        }
-
-        // Draw color beam
-        uv = (2.0 * uv) - 1.0;
-        float beamWidth = (0.7 + 0.5 * cos(uv.x * 1.0 * TWO_PI * 0.15 * clamp(floor(5.0 + 1.0 * cos(current_time)), 0.0, 1.0))) * abs(1.0 / (30.0 * uv.y));
-        vec3 horBeam = vec3(beamWidth);
-        
-        // Add the color for the current circle to the final color
-        finalColor += ((horBeam) * horColour);
-    }
-
-    // Output the final color to the output texture
-    imageStore(out_tex, pos, vec4(finalColor, 1.0));
-}
-
-
-)";
-
-// ported from https://www.shadertoy.com/view/WdjGRc
-static const char *render_source_deco =
-    R"(
-#version 320 es
-precision highp float;
-precision highp image2D;
-
-layout(binding = 0, rgba32f) uniform readonly image2D in_tex;
-layout(binding = 0, rgba32f) uniform writeonly image2D out_tex;
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-layout(location = 9) uniform float current_time;
-
-vec3 effect(float speed, vec2 uv, float time, float scale) {
-    float t = mod(time * 0.005, 6.0);
-    float rt = 0.00000000000001 * sin(t * 0.45);
-
-    mat2 m1 = mat2(cos(rt), -sin(rt), -sin(rt), cos(rt));
-    vec2 uva = uv * m1 * scale;
-    float irt = 0.005 * cos(t * 0.05);
-    mat2 m2 = mat2(sin(irt), cos(irt), -cos(irt), sin(irt));
-
-    for (int i = 1; i < 400; i += 1) {
-        float it = float(i);
-        uva *= m2;
-        uva.y += -1.0 + (0.6 / it) * cos(t + it * uva.x + 0.5 * it) * float(mod(it, 0.5) == 0.0);
-        uva.x += 1.0 + (0.5 / it) * cos(t + it * uva.y * 0.1 / 5.0 + 0.5 * (it + 15.0));  // Adjust the scaling factor for y-coordinate
-    }
-
-    float n = 0.5;
-    float r = n + n * sin(4.0 * uva.x + t);
-    float gb = n + n * sin(3.0 * uva.y);
-    return vec3(r, gb * 0.8 * r, gb * r);
-}
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-    
-    vec2 uv = vec2(pos) / vec2(width, height);
-    uv = 2.0 * uv - 1.0;
-    uv *= (10.3 + 0.1 * sin(current_time * 0.01));
-
-    int x = pos.x;
-    int y = pos.y;
-
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-
-    
-   // uv.y -= current_time * 0.013;
-//uv.x -= current_time * 0.026;
-    vec3 col = effect(0.001, uv, current_time, 0.5);
-    // col += effect(0.5, uv * 3.0, 2.0 * current_time + 10.0, 0.5) * 0.3;
-    // col += effect(0.5, sin(current_time * 0.01) * uv * 2.0, 2.0 * current_time + 10.0, 0.5) * 0.1;
-
-    // Output the final color to the output texture
-    imageStore(out_tex, pos, vec4(col, 1.0));
-}
-)";
-
-static const char *rounded_corner_overlay =
-    R"(
-#version 320 es
-
-layout(binding = 0, rgba32f) readonly uniform highp image2D in_tex;  // Use binding point 0
-layout(binding = 0, rgba32f) writeonly uniform highp image2D out_tex;  // Use binding point 0
-
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int corner_radius;
-layout(location = 8) uniform int shadow_radius;
-layout(location = 9) uniform vec4 shadow_color;
-
-void main() {
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-
-    // Check if the pixel should be drawn
-    if (pos.x >= border_size && pos.x <= (width - 1) - border_size && pos.y >= title_height && pos.y <= (height - 1) - border_size)
-    {
-        return;
-    }
-    float d;
-    vec4 c = shadow_color;
-    vec4 m = vec4(0.0);
-    vec4 s;
-    float diffuse = 1.0 / float(shadow_radius == 0 ? 1 : shadow_radius);
-    // left
-    if (pos.x < shadow_radius * 2 && pos.y >= shadow_radius * 2 && pos.y <= height - shadow_radius * 2)
-    {
-        d = distance(vec2(float(shadow_radius * 2), float(pos.y)), vec2(pos));
-        imageStore(out_tex, pos, mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0))));
-    }
-    // top left corner
-    if (pos.x < shadow_radius * 2 + corner_radius && pos.y < shadow_radius * 2 + corner_radius)
-    {
-        d = distance(vec2(float(shadow_radius * 2 + corner_radius)), vec2(pos)) - float(corner_radius);
-        s = mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0)));
-        c = imageLoad(in_tex, pos);
-        d = distance(vec2(float(shadow_radius * 2 + corner_radius)), vec2(pos));
-        imageStore(out_tex, pos, mix(c, s, clamp(d - float(corner_radius), 0.0, 1.0)));
-    }
-    // bottom left corner
-    if (pos.x < (shadow_radius * 2 + corner_radius) && pos.y > height - (shadow_radius * 2 + corner_radius))
-    {
-        d = distance(vec2(float((shadow_radius * 2 + corner_radius)), float((height - 1) - (shadow_radius * 2 + corner_radius))), vec2(pos)) - float(corner_radius);
-        s = mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0)));
-        c = imageLoad(in_tex, pos);
-        d = distance(vec2(float((shadow_radius * 2 + corner_radius)), float((height - 1) - (shadow_radius * 2 + corner_radius))), vec2(pos));
-        imageStore(out_tex, pos, mix(c, s, clamp(d - float(corner_radius), 0.0, 1.0)));
-    }
-    // top
-    if (pos.x >= shadow_radius * 2 + corner_radius && pos.x <= width - shadow_radius * 2 + corner_radius && pos.y < shadow_radius * 2)
-    {
-        d = distance(vec2(float(pos.x), float(shadow_radius * 2)), vec2(pos));
-        imageStore(out_tex, pos, mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0))));
-    }
-    // right
-    if (pos.x > (width - 1) - shadow_radius * 2 && pos.y >= shadow_radius * 2 && pos.y <= (height - 1) - shadow_radius * 2)
-    {
-        d = distance(vec2(float((width - 1) - shadow_radius * 2), float(pos.y)), vec2(pos));
-        imageStore(out_tex, pos, mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0))));
-    }
-    // top right corner
-    if (pos.x > width - (shadow_radius * 2 + corner_radius) && pos.y < (shadow_radius * 2 + corner_radius))
-    {
-        d = distance(vec2(float((width - 1) - (shadow_radius * 2 + corner_radius)), float((shadow_radius * 2 + corner_radius))), vec2(pos)) - float(corner_radius);
-        s = mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0)));
-        c = imageLoad(in_tex, pos);
-        d = distance(vec2(float((width - 1) - (shadow_radius * 2 + corner_radius)), float((shadow_radius * 2 + corner_radius))), vec2(pos));
-        imageStore(out_tex, pos, mix(c, s, clamp(d - float(corner_radius), 0.0, 1.0)));
-    }
-    // bottom right corner
-    if (pos.x > (width - 1) - (shadow_radius * 2 + corner_radius) && pos.y > (height - 1) - (shadow_radius * 2 + corner_radius))
-    {
-        d = distance(vec2(float((width - 1) - (shadow_radius * 2 + corner_radius)), float((height - 1) - (shadow_radius * 2 + corner_radius))), vec2(pos)) - float(corner_radius);
-        s = mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0)));
-        c = imageLoad(in_tex, pos);
-        d = distance(vec2(float((width - 1) - (shadow_radius * 2 + corner_radius)), float((height - 1) - (shadow_radius * 2 + corner_radius))), vec2(pos));
-        imageStore(out_tex, pos, mix(c, s, clamp(d - float(corner_radius), 0.0, 1.0)));
-    }
-    // bottom
-    if (pos.x >= (shadow_radius * 2 + corner_radius) && pos.x <= (width - 1) - (shadow_radius * 2 + corner_radius) && pos.y > (height - 1) - shadow_radius * 2)
-    {
-        d = distance(vec2(float(pos.x), float((height - 1) - shadow_radius * 2)), vec2(pos));
-        imageStore(out_tex, pos, mix(c, m, 1.0 - exp(-pow(d * diffuse, 2.0))));
-    }
-}
-
-)";
-
-static const char *beveled_glass_overlay =
-    R"(
-#version 320 es
-
-layout(binding = 0, rgba32f) readonly uniform highp image2D neural_network_tex;  // Use binding point 0
-layout(binding = 0, rgba32f) writeonly uniform highp image2D image;  // Use binding point 0
-
-layout(local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-#define MARKER_RADIUS 12.5
-#define THICCNESS 2.0
-
-
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int radius;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-
-bool isInsideTriangle(vec2 p, vec2 a, vec2 b, vec2 c) {
-    vec2 v0 = b - a;
-    vec2 v1 = c - a;
-    vec2 v2 = p - a;
-
-    float dot00 = dot(v0, v0);
-    float dot01 = dot(v0, v1);
-    float dot02 = dot(v0, v2);
-    float dot11 = dot(v1, v1);
-    float dot12 = dot(v1, v2);
-
-    float invDenom = 1.0 / (dot00 * dot11 - dot01 * dot01);
-    float u = (dot11 * dot02 - dot01 * dot12) * invDenom;
-    float v = (dot00 * dot12 - dot01 * dot02) * invDenom;
-
-    return (u >= 0.0) && (v >= 0.0) && (u + v <= 1.0);
-}
-
-
-vec4 toBezier(float delta, int i, vec4 P0, vec4 P1, vec4 P2, vec4 P3)
-{
-    float t = delta * float(i);
-    float t2 = t * t;
-    float one_minus_t = 1.0 - t;
-    float one_minus_t2 = one_minus_t * one_minus_t;
-    return (P0 * one_minus_t2 * one_minus_t + P1 * 3.0 * t * one_minus_t2 + P2 * 3.0 * t2 * one_minus_t + P3 * t2 * t);
-}
-
-float sin01(float x) {
-    return (sin(x) + 1.0) / 2.0;
-}
-
-
-
-vec4 drawCurveBenzier(vec2 p1, vec2 p2, int setCount) {
-    vec4 col = vec4(0.0);
- ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
-  float curveRadius = float(radius);
-// Draw the lines connecting the points
-
-    vec2 fragCoord = vec2(storePos);
-    for (int i = 0; i <= setCount; ++i) {
-        vec4 bezierPoint = toBezier(1.0 / float(setCount), i, vec4(p1, 0.0, 1.0), vec4(p1 + (p2 - p1) * 0.5, 0.0, 1.0), vec4(p1 + (p2 - p1) * 0.5, 0.0, 1.0), vec4(p2, 0.0, 1.0));
-        vec2 curvePoint = bezierPoint.xy / bezierPoint.w;
-        float distance = length(fragCoord - curvePoint);
-        float curveIntensity = smoothstep(0.0, THICCNESS, curveRadius - distance);
-        col.rgb += vec3(0.1, 0.1, 0.1) * curveIntensity;
-        col.a = max(col.a, curveIntensity);
-    }
-
-    return col;
-}
-
-
-
-
-vec4 drawCurve(vec2 p1, vec2 p2, int setCount) {
-    vec4 col = vec4(0.0);
-    ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
-    float curveRadius = float(radius + 1);
-    vec2 fragCoord = vec2(storePos);
-
-    float t = clamp(dot(fragCoord - p1, p2 - p1) / dot(p2 - p1, p2 - p1), 0.0, 1.0);
-    vec2 curvePoint = mix(p1, p2, t);
-
-    float distance = length(fragCoord - curvePoint);
-    float curveIntensity = smoothstep(0.0, curveRadius, curveRadius - distance);
-
-    // Calculate gradient along the line with grey to white to grey
-    vec3 gradientColor;
-
-    if (t < 0.5) {
-        gradientColor = mix(vec3(0.7), vec3(1.0), t * 2.0);
-    } else {
-        gradientColor = mix(vec3(1.0), vec3(0.7), (t - 0.5) * 2.0);
-    }
-
-    // Use the curveIntensity to interpolate between gradient colors
-    col.rgb = gradientColor * curveIntensity;
-    col.a = max(col.a, curveIntensity);
-
-    return col;
-}
-
-void main() {
-    ivec2 storePos = ivec2(gl_GlobalInvocationID.xy);
-
-    int x = storePos.x;
-    int y = storePos.y;
-    // Check if the pixel should be drawn
-    if (x >= border_size && x <= (width - 1) - border_size && y >= title_height && y <= (height - 1) - border_size)
-    {
-        return;
-    }
-    vec2 fragCoord = vec2(storePos);
-
- vec4 col = vec4(0.0);
-    float space = 15.0; 
-
-    vec2 p1 = vec2(0.0 + THICCNESS, float(height) - THICCNESS - space);
-    vec2 p2 = vec2(0.0 + THICCNESS, 0.0 + THICCNESS + space);
-
-    vec2 x1 = vec2(float(width) - THICCNESS, float(height) - THICCNESS - space);
-    vec2 x2 = vec2(float(width) - THICCNESS, 0.0 + THICCNESS + space);
-
-    vec2 y1 = vec2(0.0 + THICCNESS + space, float(height) - THICCNESS);
-    vec2 y2 = vec2(float(width) - THICCNESS - space, float(height) - THICCNESS);
-
-    vec2 z1 = vec2(0.0 + THICCNESS + space, 0.0 + THICCNESS);
-    vec2 z2 = vec2(float(width) - THICCNESS - space, 0.0 + THICCNESS);
-
- float curveRadius = float(radius);
-// Draw the lines connecting the points
-
-int setwidth = int(width);
-int setheight = int(height);
-
-
-if (setwidth<=400 && setheight<=300 ){
-    col += drawCurveBenzier(p1, p2, setheight);
-    col += drawCurveBenzier(x1, x2, setheight);
-    col += drawCurveBenzier(y1, y2, setwidth);
-    col += drawCurveBenzier(z1, z2, setwidth);
-}
-else {
-    col += drawCurve(p1, p2, setheight);
-    col += drawCurve(x1, x2, setheight);
-    col += drawCurve(y1, y2, setwidth);
-    col += drawCurve(z1, z2, setwidth);
-	}
-
-
-float INNERspace = 0.0; 
-
-
-//left
-    vec2 INNERp1 = vec2(0.0 - THICCNESS+ float(border_size), float(height)  - THICCNESS - INNERspace-float(border_size) );
-    vec2 INNERp2 = vec2(0.0 - THICCNESS+ float(border_size),0.0 - THICCNESS + INNERspace+float(border_size) +float(title_height-border_size));
-//right     
-    vec2 INNERx1 = vec2(float(width) + THICCNESS-float(border_size), float(height)- THICCNESS - INNERspace-float(border_size));
-    vec2 INNERx2 = vec2(float(width) + THICCNESS-float(border_size),0.0 - THICCNESS + INNERspace+float(border_size) +float(title_height-border_size));
-//bottom
-    vec2 INNERy1 = vec2(0.0 + THICCNESS + INNERspace+float(border_size), float(height)   + THICCNESS -float(border_size));
-    vec2 INNERy2 = vec2(float(width) - THICCNESS - INNERspace-float(border_size), float(height) + THICCNESS-float(border_size));
-//top
-   vec2 INNERz1 = vec2(0.0 +INNERspace+float(border_size), 0.0 - THICCNESS + INNERspace+float(border_size) +float(title_height-border_size));
-    vec2 INNERz2 = vec2(float(width) - THICCNESS - INNERspace-float(border_size) ,0.0 - THICCNESS + INNERspace+float(border_size) +float(title_height-border_size));
-
-
-
-if (setwidth<=400 && setheight<=300 ){
-    col += drawCurveBenzier(INNERp1, INNERp2, setheight);
-    col += drawCurveBenzier(INNERx1, INNERx2, setheight);
-    col += drawCurveBenzier(INNERy1, INNERy2, setwidth);
-    col += drawCurveBenzier(INNERz1, INNERz2, setwidth);
-}
-else{
-    col += drawCurve(INNERp1, INNERp2, setheight);
-    col += drawCurve(INNERx1, INNERx2, setheight);
-    col += drawCurve(INNERy1, INNERy2, setwidth);
-    col += drawCurve(INNERz1, INNERz2, setwidth);
-    }
-
-
-    vec2 p3 = fragCoord;
-    vec2 p12 = p2 - p1;
-    vec2 p13 = p3 - p1;
-
-    vec2 x3 = fragCoord;
-    vec2 x12 = x2 - x1;
-    vec2 x13 = x3 - x1;
-
-    vec2 y3 = fragCoord;
-    vec2 y12 = y2 - y1;
-    vec2 y13 = y3 - y1;
-
-    vec2 z3 = fragCoord;
-    vec2 z12 = z2 - z1;
-    vec2 z13 = z3 - z1;
-
-    float d = dot(p12, p13) / length(p12); // = length(p13) * cos(angle)
-    float dx = dot(x12, x13) / length(x12);
-    float dy = dot(y12, y13) / length(y12);
-    float dz = dot(z12, z13) / length(z12);
-
-    vec2 p4 = p1 + normalize(p12) * d;
-    vec2 x4 = x1 + normalize(x12) * dx;
-    vec2 y4 = y1 + normalize(y12) * dy;
-    vec2 z4 = z1 + normalize(z12) * dz;
-    
-       if (((length(p4 - p3) < THICCNESS && length(p4 - p1) <= length(p12) && length(p4 - p2) <= length(p12)) ||
-         (length(x4 - x3) < THICCNESS && length(x4 - x1) <= length(x12) && length(x4 - x2) <= length(x12))) ||
-         (length(y4 - y3) < THICCNESS && length(y4 - y1) <= length(y12) && length(y4 - y2) <= length(y12)) ||
-         (length(z4 - z3) < THICCNESS && length(z4 - z1) <= length(z12) && length(z4 - z2) <= length(z12))) { 
-        col = vec4(0.1, 0.1, 0.1, 1.0);
-    }
-    
-    
-    vec2 INNERp3 = fragCoord;
-    vec2 INNERp12 = INNERp2 - INNERp1;
-    vec2 INNERp13 = INNERp3 - INNERp1;
-
-    vec2 INNERx3 = fragCoord;
-    vec2 INNERx12 = INNERx2 - INNERx1;
-    vec2 INNERx13 = INNERx3 - INNERx1;
-
-    vec2 INNERy3 = fragCoord;
-    vec2 INNERy12 = INNERy2 - INNERy1;
-    vec2 INNERy13 = INNERy3 - INNERy1;
-
-    vec2 INNERz3 = fragCoord;
-    vec2 INNERz12 = INNERz2 - INNERz1;
-    vec2 INNERz13 = INNERz3 - INNERz1;
-
-    float INNERd = dot(INNERp12, INNERp13) / length(INNERp12); // = length(p13) * cos(angle)
-    float INNERdx = dot(INNERx12, INNERx13) / length(INNERx12);
-    float INNERdy = dot(INNERy12, INNERy13) / length(INNERy12);
-    float INNERdz = dot(INNERz12, INNERz13) / length(INNERz12);
-
-    vec2 INNERp4 = INNERp1 + normalize(INNERp12) * INNERd;
-    vec2 INNERx4 = INNERx1 + normalize(INNERx12) * INNERdx;
-    vec2 INNERy4 = INNERy1 + normalize(INNERy12) * INNERdy;
-    vec2 INNERz4 = INNERz1 + normalize(INNERz12) * INNERdz;
-    
-       if (((length(INNERp4 - INNERp3) < THICCNESS && length(INNERp4 - INNERp1) <= length(INNERp12) && length(INNERp4 - INNERp2) <= length(INNERp12)) ||
-         (length(INNERx4 - INNERx3) < THICCNESS && length(INNERx4 - INNERx1) <= length(INNERx12) && length(INNERx4 - INNERx2) <= length(INNERx12))) ||
-         (length(INNERy4 - INNERy3) < THICCNESS && length(INNERy4 - INNERy1) <= length(INNERy12) && length(INNERy4 - INNERy2) <= length(INNERy12)) ||
-         (length(INNERz4 - INNERz3) < THICCNESS && length(INNERz4 - INNERz1) <= length(INNERz12) && length(INNERz4 - INNERz2) <= length(INNERz12))) { 
-        col = vec4(0.1, 0.1, 0.1, 1.0);
-    }    
-
-    
-
-
-
-    // Draw the lines connecting the points
-       // Calculate the line segment connecting p1 and y1
-    vec2 dir = normalize(y1 - p1);
-    vec2 relPoint = fragCoord - p1;
-    float alongLine = dot(relPoint, dir);
-    float distance = length(relPoint - alongLine * dir);
-
-    // Draw the line connecting p1 and y1
-    if (distance < THICCNESS && alongLine > 0.0 && alongLine < length(y1 - p1)) {
-        col = vec4(0.1, 0.1, 0.1, 1.0);
-    }
-
-
-    
-    dir = normalize(y2 - x1);
-    relPoint = fragCoord - x1;
-     alongLine = dot(relPoint, dir);
-     distance = length(relPoint - alongLine * dir);
-
-    if (distance < THICCNESS && alongLine > 0.0 && alongLine < length(x1 - y2)) {
-        col = vec4(0.1, 0.1, 0.1, 1.0);
-    }
-
-
- dir = normalize(p2 - z1);
-    relPoint = fragCoord - z1;
-     alongLine = dot(relPoint, dir);
-     distance = length(relPoint - alongLine * dir);
-
-    if (distance < THICCNESS && alongLine > 0.0 && alongLine < length(z1 - p2)) {
-        col = vec4(0.1, 0.1, 0.1, 1.0);
-    }
-
-
-
- dir = normalize(x2 - z2);
-    relPoint = fragCoord - z2;
-     alongLine = dot(relPoint, dir);
-     distance = length(relPoint - alongLine * dir);
-
-    if (distance < THICCNESS && alongLine > 0.0 && alongLine < length(x2 - z2)) {
-        col = vec4(0.1, 0.1, 0.1, 1.0);
-    }
-    // Draw other lines...
-
-    vec2 t1 = vec2(0.0, float(height));
-    vec2 t2 = vec2(float(width), float(height));
-    vec2 t3 = vec2(-0.5, -0.5);
-    vec2 t4 = vec2(float(width), -0.5);
-
-
-   if (isInsideTriangle(fragCoord, vec2(p1.x-10.1,p1.y), t1, vec2(y1.x,y1.y+10.1))  ||
-        isInsideTriangle(fragCoord, vec2(x1.x+10.1,x1.y), t2, vec2(y2.x,y2.y+10.1))  ||
-        isInsideTriangle(fragCoord, vec2(z1.x,z1.y-2.4), t3, vec2(p2.x-3.1,p2.y-2.1)) ||
-        isInsideTriangle(fragCoord, vec2(z2.x,z2.y-5.5), t4, vec2(x2.x+3.1,x2.y)) ) {
-        col = vec4(0.0, 0.0, 0.0, 0.0);  // Set the color to fully transparent
-    } else {
-        // Apply your original logic for other regions
-
-        // Sample neural network texture
-        vec4 neuralColor = imageLoad(neural_network_tex, ivec2(fragCoord));
-        col += neuralColor;
-    }
-//z2 - x2
-
-  //    vec4 neuralColor = imageLoad(neural_network_tex, ivec2(fragCoord));
-   //     col += neuralColor;
-    // Store the final color
-    imageStore(image, storePos, col);
-}
-
-)";
-
-void setup_shader(GLuint *program, std::string source)
-{
-    auto compute_shader  = OpenGL::compile_shader(source.c_str(), GL_COMPUTE_SHADER);
-    auto compute_program = GL_CALL(glCreateProgram());
-    GL_CALL(glAttachShader(compute_program, compute_shader));
-    GL_CALL(glLinkProgram(compute_program));
-
-    int s = GL_FALSE;
-#define LENGTH 1024 * 128
-    char log[LENGTH];
-    GL_CALL(glGetProgramiv(compute_program, GL_LINK_STATUS, &s));
-    GL_CALL(glGetProgramInfoLog(compute_program, LENGTH, NULL, log));
-
-    if (s == GL_FALSE)
-    {
-        LOGE("Failed to link shader:\n", source,
-            "\nLinker output:\n", log);
-    }
-
-    GL_CALL(glDeleteShader(compute_shader));
-    *program = compute_program;
-}
-
-static void seed_random()
-{
-    timespec ts;
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-    srandom(ts.tv_nsec);
-}
-
-void smoke_t::destroy_programs()
-{
-    if (motion_program != GLuint(-1))
-    {
-        GL_CALL(glDeleteProgram(motion_program));
-        GL_CALL(glDeleteProgram(diffuse1_program));
-        GL_CALL(glDeleteProgram(diffuse2_program));
-        GL_CALL(glDeleteProgram(project1_program));
-        GL_CALL(glDeleteProgram(project2_program));
-        GL_CALL(glDeleteProgram(project3_program));
-        GL_CALL(glDeleteProgram(project4_program));
-        GL_CALL(glDeleteProgram(project5_program));
-        GL_CALL(glDeleteProgram(project6_program));
-        GL_CALL(glDeleteProgram(advect1_program));
-        GL_CALL(glDeleteProgram(advect2_program));
-    }
-
-    if (render_program != GLuint(-1))
-    {
-        GL_CALL(glDeleteProgram(render_program));
-    }
-
-    if (render_overlay_program != GLuint(-1))
-    {
-        GL_CALL(glDeleteProgram(render_overlay_program));
-    }
-
-    motion_program = diffuse1_program = diffuse2_program = project1_program =
-        project2_program     = project3_program = project4_program = project5_program =
-            project6_program = advect1_program = advect2_program = render_program =
-                render_overlay_program = GLuint(-1);
-}
-
-void smoke_t::create_programs()
-{
-    destroy_programs();
-    wf::gles::run_in_context([&]
-    {
-        if ((std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink"))
-        {
-            setup_shader(&motion_program, motion_source);
-            setup_shader(&diffuse1_program, stitch_smoke_shader(diffuse1_source));
-            setup_shader(&diffuse2_program, stitch_smoke_shader(diffuse2_source));
-            setup_shader(&project1_program, stitch_smoke_shader(project1_source));
-            setup_shader(&project2_program, stitch_smoke_shader(project2_source));
-            setup_shader(&project3_program, stitch_smoke_shader(project3_source));
-            setup_shader(&project4_program, stitch_smoke_shader(project4_source));
-            setup_shader(&project5_program, stitch_smoke_shader(project5_source));
-            setup_shader(&project6_program, stitch_smoke_shader(project6_source));
-            setup_shader(&advect1_program, stitch_smoke_shader(advect1_source));
-            setup_shader(&advect2_program, stitch_smoke_shader(advect2_source));
-            setup_shader(&render_program, std::string(render_source) + effect_run_for_region_main);
-        } else if (std::string(effect_type) == "clouds")
-        {
-            setup_shader(&render_program, render_source_clouds);
-        } else if (std::string(effect_type) == "halftone")
-        {
-            setup_shader(&render_program, render_source_halftone);
-        } else if (std::string(effect_type) == "pattern")
-        {
-            setup_shader(&render_program, render_source_pattern);
-        } else if (std::string(effect_type) == "lava")
-        {
-            setup_shader(&render_program, render_source_lava);
-        } else if (std::string(effect_type) == "hex")
-        {
-            setup_shader(&render_program, render_source_hex);
-        } else if (std::string(effect_type) == "zebra")
-        {
-            setup_shader(&render_program, render_source_zebra);
-        } else if (std::string(effect_type) == "neural_network")
-        {
-            setup_shader(&render_program, render_source_neural_network);
-        } else if (std::string(effect_type) == "hexagon_maze")
-        {
-            setup_shader(&render_program, render_source_hexagon_maze);
-        } else if (std::string(effect_type) == "raymarched_truchet")
-        {
-            setup_shader(&render_program, render_source_raymarched_truchet);
-        } else if (std::string(effect_type) == "neon_pattern")
-        {
-            setup_shader(&render_program, render_source_neon_pattern);
-        } else if (std::string(effect_type) == "neon_rings")
-        {
-            setup_shader(&render_program, render_source_neon_rings);
-        } else if (std::string(effect_type) == "deco")
-        {
-            setup_shader(&render_program, render_source_deco);
-        }
-
-        if (std::string(overlay_engine) == "rounded_corners")
-        {
-            setup_shader(&render_overlay_program, rounded_corner_overlay);
-        } else if (std::string(overlay_engine) == "beveled_glass")
-        {
-            setup_shader(&render_overlay_program, beveled_glass_overlay);
-        }
-    });
-}
-
-smoke_t::smoke_t()
-{
-    motion_program = diffuse1_program = diffuse2_program = project1_program =
-        project2_program     = project3_program = project4_program = project5_program =
-            project6_program = advect1_program = advect2_program = render_program =
-                render_overlay_program = GLuint(-1);
-
-    texture = b0u = b0v = b0d = b1u = b1v = b1d = GLuint(-1);
-
-    create_programs();
-    seed_random();
-}
-
-smoke_t::~smoke_t()
-{
-    destroy_programs();
-    destroy_textures();
-}
-
-void smoke_t::create_textures()
-{
-    GL_CALL(glGenTextures(1, &texture));
-    GL_CALL(glGenTextures(1, &b0u));
-    GL_CALL(glGenTextures(1, &b0v));
-    GL_CALL(glGenTextures(1, &b0d));
-    GL_CALL(glGenTextures(1, &b1u));
-    GL_CALL(glGenTextures(1, &b1v));
-    GL_CALL(glGenTextures(1, &b1d));
-}
-
-void smoke_t::destroy_textures()
-{
-    if (texture != GLuint(-1))
-    {
-        GL_CALL(glDeleteTextures(1, &texture));
-        texture = GLuint(-1);
-    }
-
-    if (b0u == GLuint(-1))
-    {
-        return;
-    }
-
-    GL_CALL(glDeleteTextures(1, &b0u));
-    GL_CALL(glDeleteTextures(1, &b0v));
-    GL_CALL(glDeleteTextures(1, &b0d));
-    GL_CALL(glDeleteTextures(1, &b1u));
-    GL_CALL(glDeleteTextures(1, &b1v));
-    GL_CALL(glDeleteTextures(1, &b1d));
-
-    b0u = b0v = b0d = b1u = b1v = b1d = GLuint(-1);
-}
-
-int round_up_div(int a, int b)
-{
-    return (a + b - 1) / b;
-}
-
-void smoke_t::dispatch_region(const wf::region_t& region)
-{
-    std::vector<int> values;
-
-    int max_x = 0;
-    int max_y = 0;
-
-    for (auto& box : region)
-    {
-        auto rect = wlr_box_from_pixman_box(box);
-        values.push_back(rect.x);
-        values.push_back(rect.y);
-        values.push_back(rect.width);
-        values.push_back(rect.height);
-
-        if (rect.width > rect.height)
-        {
-            values.push_back(0); // xy will not be flipped in compute shader
-            max_x = std::max(max_x, rect.width);
-            max_y = std::max(max_y, rect.height);
-        } else
-        {
-            values.push_back(1); // xy will be flipped in compute shader
-            max_x = std::max(max_x, rect.height);
-            max_y = std::max(max_y, rect.width);
-        }
-    }
-
-    if (values.size() / 5 > 4)
-    {
-        LOGE("Error: too many regions");
-        return;
-    }
-
-    GL_CALL(glUniform1iv(10, values.size(), values.data()));
-    GL_CALL(glDispatchCompute(round_up_div(max_x, 16), round_up_div(max_y, 16), values.size() / 5));
-    GL_CALL(glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT));
-}
-
-void smoke_t::run_shader_region(GLuint program, const wf::region_t & region, const wf::dimensions_t & size)
-{
-    GL_CALL(glUseProgram(program));
-    GL_CALL(glUniform1i(5, size.width));
-    GL_CALL(glUniform1i(6, size.height));
-    dispatch_region(region);
-}
-
-void smoke_t::run_shader(GLuint program, int width, int height, int title_height, int border_size, int radius)
-{
-    GL_CALL(glUseProgram(program));
-    GL_CALL(glUniform1i(1, title_height + border_size + radius * 2));
-    GL_CALL(glUniform1i(2, border_size + radius * 2));
-    GL_CALL(glUniform1i(5, width));
-    GL_CALL(glUniform1i(6, height));
-    GL_CALL(glUniform1i(9, radius * 2));
-    GL_CALL(glDispatchCompute(width / 15, height / 15, 1));
-    GL_CALL(glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT));
-}
-
-void smoke_t::recreate_textures(wf::geometry_t rectangle)
-{
-    if ((rectangle.width <= 0) || (rectangle.height <= 0))
-    {
-        return;
-    }
-
-    destroy_textures();
-    create_textures();
-
-    GL_CALL(glActiveTexture(GL_TEXTURE0 + 0));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
-    GL_CALL(glTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA32F, rectangle.width, rectangle.height));
-    if ((std::string(effect_type) != "smoke") && (std::string(effect_type) != "ink"))
-    {
-        return;
-    }
-
-    GLuint fb;
-    GL_CALL(glGenFramebuffers(1, &fb));
-    GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, fb));
-
-    wf::color_t clear_color{0, 0, 0, 0};
-    GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-        GL_TEXTURE_2D, texture, 0));
-    OpenGL::clear(clear_color, GL_COLOR_BUFFER_BIT);
-
-    GL_CALL(glActiveTexture(GL_TEXTURE0 + 1));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, b0u));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
-    GL_CALL(glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, rectangle.width, rectangle.height));
-    GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-        GL_TEXTURE_2D, b0u, 0));
-    OpenGL::clear(clear_color, GL_COLOR_BUFFER_BIT);
-    GL_CALL(glActiveTexture(GL_TEXTURE0 + 2));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, b0v));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
-    GL_CALL(glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, rectangle.width, rectangle.height));
-    GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-        GL_TEXTURE_2D, b0v, 0));
-    OpenGL::clear(clear_color, GL_COLOR_BUFFER_BIT);
-    GL_CALL(glActiveTexture(GL_TEXTURE0 + 3));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, b0d));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
-    GL_CALL(glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, rectangle.width, rectangle.height));
-    GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-        GL_TEXTURE_2D, b0d, 0));
-    OpenGL::clear(clear_color, GL_COLOR_BUFFER_BIT);
-    GL_CALL(glActiveTexture(GL_TEXTURE0 + 4));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, b1u));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
-    GL_CALL(glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, rectangle.width, rectangle.height));
-    GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-        GL_TEXTURE_2D, b1u, 0));
-    OpenGL::clear(clear_color, GL_COLOR_BUFFER_BIT);
-    GL_CALL(glActiveTexture(GL_TEXTURE0 + 5));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, b1v));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
-    GL_CALL(glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, rectangle.width, rectangle.height));
-    GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-        GL_TEXTURE_2D, b1v, 0));
-    OpenGL::clear(clear_color, GL_COLOR_BUFFER_BIT);
-    GL_CALL(glActiveTexture(GL_TEXTURE0 + 6));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, b1d));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
-    GL_CALL(glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, rectangle.width, rectangle.height));
-    GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-        GL_TEXTURE_2D, b1d, 0));
-    OpenGL::clear(clear_color, GL_COLOR_BUFFER_BIT);
-
-    GL_CALL(glDeleteFramebuffers(1, &fb));
-}
-
-void smoke_t::step_effect(const wf::scene::render_instruction_t& data, wf::geometry_t rectangle,
-    bool ink, wf::pointf_t p, wf::color_t decor_color, wf::color_t effect_color,
-    int title_height, int border_size, int shadow_radius)
-{
-    bool smoke = (std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink");
-    if ((rectangle.width <= 0) || (rectangle.height <= 0))
-    {
-        return;
-    }
-
-    int radius = shadow_radius;
-    int diffuse_iterations = 2;
-
-    wf::gles::run_in_context([&]
-    {
-        wf::gles::bind_render_buffer(data.target);
-        if ((rectangle.width != saved_width) || (rectangle.height != saved_height))
-        {
-            saved_width  = rectangle.width;
-            saved_height = rectangle.height;
-
-            recreate_textures(rectangle);
-        }
-
-        GL_CALL(glActiveTexture(GL_TEXTURE0 + 0));
-        GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
-        GL_CALL(glBindImageTexture(0, texture, 0, GL_FALSE, 0, GL_READ_WRITE, GL_RGBA32F));
-
-        const wf::geometry_t nonshadow_rect = wf::geometry_t{
-            radius* 2,
-            radius* 2,
-            rectangle.width - 4 * radius,
-            rectangle.height - 4 * radius
-        };
-
-        wf::geometry_t inner_part = {
-            border_size + radius * 2,
-            title_height + border_size + radius * 2,
-            rectangle.width - border_size * 2 - radius * 4,
-            rectangle.height - border_size * 2 - title_height - radius * 4,
-        };
-
-        wf::region_t border_region = nonshadow_rect;
-        border_region ^= inner_part;
-        border_region.expand_edges(1);
-        border_region &= nonshadow_rect;
-
-        if (smoke)
-        {
-            wf::point_t point{int(p.x), int(p.y)};
-            if ((p.x == FLT_MIN) || (p.y == FLT_MIN))
-            {
-                point.x = point.y = INT_MIN;
-            }
-
-            GL_CALL(glActiveTexture(GL_TEXTURE0 + 1));
-            GL_CALL(glBindTexture(GL_TEXTURE_2D, b0u));
-            GL_CALL(glBindImageTexture(1, b0u, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F));
-            GL_CALL(glActiveTexture(GL_TEXTURE0 + 2));
-            GL_CALL(glBindTexture(GL_TEXTURE_2D, b0v));
-            GL_CALL(glBindImageTexture(2, b0v, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F));
-            GL_CALL(glActiveTexture(GL_TEXTURE0 + 3));
-            GL_CALL(glBindTexture(GL_TEXTURE_2D, b0d));
-            GL_CALL(glBindImageTexture(3, b0d, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F));
-            GL_CALL(glActiveTexture(GL_TEXTURE0 + 4));
-            GL_CALL(glBindTexture(GL_TEXTURE_2D, b1u));
-            GL_CALL(glBindImageTexture(4, b1u, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F));
-            GL_CALL(glActiveTexture(GL_TEXTURE0 + 5));
-            GL_CALL(glBindTexture(GL_TEXTURE_2D, b1v));
-            GL_CALL(glBindImageTexture(5, b1v, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F));
-            GL_CALL(glActiveTexture(GL_TEXTURE0 + 6));
-            GL_CALL(glBindTexture(GL_TEXTURE_2D, b1d));
-            GL_CALL(glBindImageTexture(6, b1d, 0, GL_FALSE, 0, GL_READ_WRITE, GL_R32F));
-
-            if ((point.x >= radius) && (point.y >= radius))
-            {
-                GL_CALL(glUseProgram(motion_program));
-                // upload stuff
-                GL_CALL(glUniform1i(1, title_height + border_size + radius * 2));
-                GL_CALL(glUniform1i(2, border_size + radius * 2));
-                GL_CALL(glUniform1i(3, point.x));
-                GL_CALL(glUniform1i(4, point.y));
-                GL_CALL(glUniform1i(5, rectangle.width));
-                GL_CALL(glUniform1i(6, rectangle.height));
-                GL_CALL(glUniform1i(7, random()));
-                GL_CALL(glUniform1i(8, random()));
-                GL_CALL(glUniform1i(9, radius * 2));
-                GL_CALL(glDispatchCompute(1, 1, 1));
-                GL_CALL(glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT));
-            }
-
-            for (int k = 0; k < diffuse_iterations; k++)
-            {
-                run_shader_region(diffuse1_program, border_region, wf::dimensions(rectangle));
-            }
-
-            run_shader_region(project1_program, border_region, wf::dimensions(rectangle));
-            for (int k = 0; k < diffuse_iterations; k++)
-            {
-                run_shader_region(project2_program, border_region, wf::dimensions(rectangle));
-            }
-
-            run_shader_region(project3_program, border_region, wf::dimensions(rectangle));
-            run_shader_region(advect1_program, border_region, wf::dimensions(rectangle));
-            run_shader_region(project4_program, border_region, wf::dimensions(rectangle));
-            for (int k = 0; k < diffuse_iterations; k++)
-            {
-                run_shader_region(project5_program, border_region, wf::dimensions(rectangle));
-            }
-
-            run_shader_region(project6_program, border_region, wf::dimensions(rectangle));
-            for (int k = 0; k < diffuse_iterations; k++)
-            {
-                run_shader_region(diffuse2_program, border_region, wf::dimensions(rectangle));
-            }
-
-            run_shader_region(advect2_program, border_region, wf::dimensions(rectangle));
-        }
-
-        if (std::string(effect_type) != "none")
-        {
-            GL_CALL(glUseProgram(render_program));
-
-            GLfloat effect_color_f[4] =
-            {GLfloat(effect_color.r), GLfloat(effect_color.g), GLfloat(effect_color.b),
-                GLfloat(effect_color.a)};
-            GLfloat decor_color_f[4] =
-            {GLfloat(decor_color.r), GLfloat(decor_color.g), GLfloat(decor_color.b), GLfloat(decor_color.a)};
-            if (smoke)
-            {
-                GL_CALL(glUniform1i(4, ink));
-                GL_CALL(glUniform4fv(8, 1, effect_color_f));
-                GL_CALL(glUniform4fv(9, 1, decor_color_f));
-                dispatch_region(border_region);
-            } else
-            {
-                GL_CALL(glUniform1i(1, title_height + border_size + radius * 2));
-                GL_CALL(glUniform1i(2, border_size + radius * 2));
-                GL_CALL(glUniform1i(5, rectangle.width));
-                GL_CALL(glUniform1i(6, rectangle.height));
-                GL_CALL(glUniform1i(7, radius * 2));
-                GL_CALL(glUniform1f(9, effect_animate ? ((wf::get_current_time() & 0x5FFFFFFF) / 30.0) : 0.0));
-                GL_CALL(glDispatchCompute(rectangle.width / 15, rectangle.height / 15, 1));
-                GL_CALL(glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT));
-            }
-        } else if (!smoke && (std::string(overlay_engine) != "none"))
-        {
-            GLuint fb;
-            GL_CALL(glGenFramebuffers(1, &fb));
-            GL_CALL(glBindFramebuffer(GL_FRAMEBUFFER, fb));
-            GL_CALL(glActiveTexture(GL_TEXTURE0 + 0));
-            GL_CALL(glBindTexture(GL_TEXTURE_2D, texture));
-            GL_CALL(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                GL_TEXTURE_2D, texture, 0));
-            OpenGL::clear(decor_color, GL_COLOR_BUFFER_BIT);
-            GL_CALL(glDeleteFramebuffers(1, &fb));
-        }
-        if ((std::string(overlay_engine) == "rounded_corners") ||
-            (std::string(overlay_engine) == "beveled_glass"))
-        {
-            GL_CALL(glUseProgram(render_overlay_program));
-            GL_CALL(glUniform1i(1, title_height + border_size + radius * 2));
-            GL_CALL(glUniform1i(2, border_size + radius * 2));
-            GL_CALL(glUniform1i(5, rectangle.width));
-            GL_CALL(glUniform1i(6, rectangle.height));
-            GL_CALL(glUniform1i(7, rounded_corner_radius));
-            if (std::string(overlay_engine) == "rounded_corners")
-            {
-                GLfloat shadow_color_f[4] =
-                {GLfloat(wf::color_t(shadow_color).r), GLfloat(wf::color_t(shadow_color).g),
-                    GLfloat(wf::color_t(shadow_color).b), GLfloat(wf::color_t(shadow_color).a)};
-                GL_CALL(glUniform1i(8, radius));
-                GL_CALL(glUniform4fv(9, 1, shadow_color_f));
-            }
-
-            GL_CALL(glDispatchCompute(round_up_div(rectangle.width, 16), round_up_div(rectangle.height, 16), 1));
-            GL_CALL(glMemoryBarrier(GL_TEXTURE_FETCH_BARRIER_BIT));
-        }
-
-        GL_CALL(glUseProgram(0));
-    });
-}
-
-void smoke_t::render_effect(const wf::scene::render_instruction_t& data, wf::geometry_t rectangle)
-{
-    OpenGL::render_transformed_texture(wf::gles_texture_t{texture}, rectangle,
-        wf::gles::render_target_orthographic_projection(data.target), glm::vec4{1},
-        OpenGL::TEXTURE_TRANSFORM_INVERT_Y | OpenGL::RENDER_FLAG_CACHED);
-
-    data.pass->custom_gles_subpass(data.target,[&]
-    {
-        for (auto& box : data.damage)
-        {
-            wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
-            OpenGL::draw_cached();
-        }
-    });
-
-    OpenGL::clear_cached();
-}
-
-void smoke_t::effect_updated()
-{
-    create_programs();
-    wf::gles::run_in_context([&]
-    {
-        recreate_textures(wf::geometry_t{0, 0, saved_width, saved_height});
-    });
-}
-} // namespace pixdecor
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-effects.hpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-effects.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-effects.hpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-effects.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,51 +0,0 @@
-#pragma once
-#include <wayfire/option-wrapper.hpp>
-#include <wayfire/core.hpp>
-#include <wayfire/opengl.hpp>
-#include <map>
-#include <GLES3/gl32.h>
-#include <wayfire/scene-render.hpp>
-
-namespace wf
-{
-namespace pixdecor
-{
-class smoke_t
-{
-    /** background effects */
-    GLuint motion_program,
-        diffuse1_program, diffuse2_program,
-        project1_program, project2_program, project3_program,
-        project4_program, project5_program, project6_program,
-        advect1_program, advect2_program, render_program, render_overlay_program,
-        texture, b0u, b0v, b0d, b1u, b1v, b1d, neural_network_tex;
-
-    int saved_width = -1, saved_height = -1;
-
-    wf::option_wrapper_t<std::string> effect_type{"pixdecor/effect_type"};
-    wf::option_wrapper_t<std::string> overlay_engine{"pixdecor/overlay_engine"};
-    wf::option_wrapper_t<bool> effect_animate{"pixdecor/animate"};
-    wf::option_wrapper_t<int> rounded_corner_radius{"pixdecor/rounded_corner_radius"};
-    wf::option_wrapper_t<wf::color_t> shadow_color{"pixdecor/shadow_color"};
-
-  public:
-    smoke_t();
-    ~smoke_t();
-
-    void run_shader(GLuint program, int width, int height, int title_height, int border_size, int radius);
-    void run_shader_region(GLuint program, const wf::region_t & region, const wf::dimensions_t & size);
-    void dispatch_region(const wf::region_t& region);
-
-    void step_effect(const wf::scene::render_instruction_t& data, wf::geometry_t rectangle,
-        bool ink, wf::pointf_t p, wf::color_t decor_color, wf::color_t effect_color,
-        int title_height, int border_size, int shadow_radius);
-    void render_effect(const wf::scene::render_instruction_t& data, wf::geometry_t rectangle);
-    void recreate_textures(wf::geometry_t rectangle);
-    void create_programs();
-    void destroy_programs();
-    void create_textures();
-    void destroy_textures();
-    void effect_updated();
-};
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-layout.cpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-layout.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-layout.cpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-layout.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,591 +0,0 @@
-#include "deco-layout.hpp"
-#include "deco-theme.hpp"
-#include <wayfire/core.hpp>
-#include <wayfire/nonstd/reverse.hpp>
-#include <wayfire/nonstd/wlroots-full.hpp>
-#include <wayfire/toplevel.hpp>
-#include <wayfire/util.hpp>
-
-namespace wf
-{
-namespace pixdecor
-{
-/**
- * Represents an area of the decoration which reacts to input events.
- */
-decoration_area_t::decoration_area_t(decoration_area_type_t type, wf::geometry_t g)
-{
-    this->type     = type;
-    this->geometry = g;
-
-    assert(type != DECORATION_AREA_BUTTON);
-}
-
-/**
- * Initialize a new decoration area holding a button
- */
-decoration_area_t::decoration_area_t(wf::geometry_t g,
-    std::function<void(wlr_box)> damage_callback,
-    pixdecor_theme_t& theme)
-{
-    this->type     = DECORATION_AREA_BUTTON;
-    this->geometry = g;
-    this->damage_callback = damage_callback;
-
-    this->button = std::make_unique<button_t>(theme,
-        std::bind(damage_callback, g));
-}
-
-wf::geometry_t decoration_area_t::get_geometry() const
-{
-    return geometry;
-}
-
-void decoration_area_t::set_geometry(wf::geometry_t g)
-{
-    geometry = g;
-
-    if (this->type == DECORATION_AREA_BUTTON)
-    {
-        this->button = std::make_unique<button_t>(this->button->theme,
-            std::bind(this->damage_callback, g));
-    }
-}
-
-button_t& decoration_area_t::as_button()
-{
-    assert(button);
-
-    return *button;
-}
-
-decoration_area_type_t decoration_area_t::get_type() const
-{
-    return type;
-}
-
-pixdecor_layout_t::pixdecor_layout_t(pixdecor_theme_t& th,
-    std::function<void(wlr_box)> callback) :
-
-    titlebar_size(th.get_title_height()),
-    border_size(th.get_input_size()),
-    theme(th),
-    damage_callback(callback)
-{}
-
-pixdecor_layout_t::~pixdecor_layout_t()
-{
-    this->layout_areas.clear();
-}
-
-wf::geometry_t pixdecor_layout_t::create_buttons(int width, int radius)
-{
-    // read the string from settings; start at the colon and replace commas with spaces
-    wf::option_wrapper_t<int> button_spacing{"pixdecor/button_spacing"};
-    wf::option_wrapper_t<int> button_x_offset{"pixdecor/button_x_offset"};
-    wf::option_wrapper_t<int> button_y_offset{"pixdecor/button_y_offset"};
-    GSettings *settings = g_settings_new("org.gnome.desktop.wm.preferences");
-    gchar *b_layout     = g_settings_get_string(settings, "button-layout");
-    gchar *ptr = b_layout + strlen(b_layout) - 1;
-    while (ptr >= b_layout)
-    {
-        if (*ptr == ',')
-        {
-            *ptr = ' ';
-        }
-
-        if (*ptr == ':')
-        {
-            break;
-        }
-
-        ptr--;
-    }
-
-    std::string layout = (*ptr == ':') ? ptr + 1 : std::string(b_layout);
-    g_free(b_layout);
-    g_object_unref(settings);
-
-    std::stringstream stream((std::string)layout);
-    std::vector<button_type_t> buttons;
-    std::string button_name;
-    while (stream >> button_name)
-    {
-        if (button_name == "minimize")
-        {
-            buttons.push_back(BUTTON_MINIMIZE);
-        }
-
-        if (button_name == "maximize")
-        {
-            buttons.push_back(BUTTON_TOGGLE_MAXIMIZE);
-        }
-
-        if (button_name == "close")
-        {
-            buttons.push_back(BUTTON_CLOSE);
-        }
-    }
-
-    int total_width = 0;
-    int per_button  = 0;
-    int border = theme.get_border_size();
-    wf::geometry_t button_geometry;
-    button_geometry.x = (width - (maximized ? 4 : border)) + button_x_offset;
-
-    for (auto type : wf::reverse(buttons))
-    {
-        auto button_area  = std::make_unique<decoration_area_t>(button_geometry, damage_callback, theme);
-        auto surface_size = button_area->as_button().set_button_type(type);
-        button_geometry.width  = surface_size.width;
-        button_geometry.height = surface_size.height;
-        int button_padding = (theme.get_title_height() - button_geometry.height) / 2 + button_y_offset;
-        button_geometry.y = button_padding + border / 2 + (radius * 2);
-        per_button = button_geometry.width + (buttons.back() == type ? 0 : button_spacing);
-        button_geometry.x -= per_button;
-        button_area->set_geometry(button_geometry);
-        button_area->as_button().set_button_type(type);
-        this->layout_areas.push_back(std::move(button_area));
-        total_width += per_button;
-    }
-
-    total_width -= button_x_offset;
-
-    return {
-        button_geometry.x, maximized ? 4 : border + (radius * 2),
-        total_width, theme.get_title_height()
-    };
-}
-
-/** Regenerate layout using the new size */
-void pixdecor_layout_t::resize(int width, int height)
-{
-    wf::option_wrapper_t<int> shadow_radius{"pixdecor/shadow_radius"};
-    wf::option_wrapper_t<std::string> overlay_engine{"pixdecor/overlay_engine"};
-    wf::option_wrapper_t<bool> maximized_borders{"pixdecor/maximized_borders"};
-    bool rounded_corners = std::string(overlay_engine) == "rounded_corners";
-
-    int border = theme.get_border_size();
-    int radius = (rounded_corners && !maximized) ? int(shadow_radius) : 0;
-
-    this->layout_areas.clear();
-
-    if (this->theme.get_title_height() > 0)
-    {
-        auto button_geometry_expanded = create_buttons(width - (radius * 2), radius);
-
-        /* Padding around the button, allows move */
-        this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-            DECORATION_AREA_MOVE, button_geometry_expanded));
-
-        /* Titlebar dragging area (for move) */
-        wf::geometry_t title_geometry = {
-            border,
-            maximized ? 0 : border / 2 + (radius * 2),
-            /* Up to the button, but subtract the padding to the left of the
-             * title and the padding between title and button */
-            std::max(1, button_geometry_expanded.x - border),
-            theme.get_title_height() + (maximized ? 0 : border / 2 + 1),
-        };
-        this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-            DECORATION_AREA_TITLE, title_geometry));
-
-        this->cached_titlebar = {
-            border, border,
-            width - 2 * border, height - 2 * border
-        };
-    }
-
-    border = MIN_RESIZE_HANDLE_SIZE - theme.get_input_size();
-    auto inverse_border = MIN_RESIZE_HANDLE_SIZE - theme.get_border_size();
-
-    if (!maximized || maximized_borders)
-    {
-        /* Resizing edges - top */
-        wf::geometry_t border_geometry =
-        {0 + (radius * 2), -inverse_border + (radius * 2),
-            width - (radius * 4) + MIN_RESIZE_HANDLE_SIZE, border};
-        this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-            DECORATION_AREA_RESIZE_TOP, border_geometry));
-
-        /* Resizing edges - bottom */
-        border_geometry =
-        {0 + (radius * 2), (height - border + inverse_border) - (radius * 2),
-            width - (radius * 4) + MIN_RESIZE_HANDLE_SIZE, border};
-        this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-            DECORATION_AREA_RESIZE_BOTTOM, border_geometry));
-
-        /* Resizing edges - left */
-        border_geometry =
-        {-inverse_border + (radius * 2), 0 + (radius * 2), border,
-            height - (radius * 4) + MIN_RESIZE_HANDLE_SIZE};
-        this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-            DECORATION_AREA_RESIZE_LEFT, border_geometry));
-
-        /* Resizing edges - right */
-        border_geometry =
-        {(width - border + inverse_border) - (radius * 2), 0 + (radius * 2), border,
-            height - (radius * 4) + MIN_RESIZE_HANDLE_SIZE};
-        this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-            DECORATION_AREA_RESIZE_RIGHT, border_geometry));
-
-        if (rounded_corners)
-        {
-            /* Shadow - top */
-            border_geometry = {0, 0, width, radius* 2};
-            this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-                DECORATION_AREA_SHADOW, border_geometry));
-
-            /* Shadow - bottom */
-            border_geometry = {0, height - radius * 2, width, radius* 2};
-            this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-                DECORATION_AREA_SHADOW, border_geometry));
-
-            /* Shadow - left */
-            border_geometry = {0, radius* 2, radius* 2, height - radius * 4};
-            this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-                DECORATION_AREA_SHADOW, border_geometry));
-
-            /* Shadow - right */
-            border_geometry = {width - radius * 2, radius* 2, radius* 2, height - radius * 4};
-            this->layout_areas.push_back(std::make_unique<decoration_area_t>(
-                DECORATION_AREA_SHADOW, border_geometry));
-        }
-    }
-}
-
-/**
- * @return The decoration areas which need to be rendered, in top to bottom
- *  order.
- */
-std::vector<nonstd::observer_ptr<decoration_area_t>> pixdecor_layout_t::get_renderable_areas()
-{
-    std::vector<nonstd::observer_ptr<decoration_area_t>> renderable;
-    for (auto& area : layout_areas)
-    {
-        if (area->get_type() & DECORATION_AREA_RENDERABLE_BIT)
-        {
-            renderable.push_back({area});
-        }
-    }
-
-    return renderable;
-}
-
-wf::region_t pixdecor_layout_t::calculate_region() const
-{
-    wf::region_t r{};
-    for (auto& area : layout_areas)
-    {
-        auto g = area->get_geometry();
-        auto b = theme.get_input_size();
-        if (maximized && (area->get_type() & DECORATION_AREA_MOVE_BIT))
-        {
-            g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{b, b, b, b});
-        }
-
-        if (area->get_type() & DECORATION_AREA_RESIZE_BIT)
-        {
-            if (b <= MIN_RESIZE_HANDLE_SIZE)
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{b, b, b, b});
-            } else if ((area->get_type() == DECORATION_AREA_RESIZE_TOP) ||
-                       (area->get_type() == DECORATION_AREA_RESIZE_BOTTOM))
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{0, 0, b, b});
-            } else if ((area->get_type() == DECORATION_AREA_RESIZE_LEFT) ||
-                       (area->get_type() == DECORATION_AREA_RESIZE_RIGHT))
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{b, b, 0, 0});
-            }
-        }
-
-        if ((g.width > 0) && (g.height > 0))
-        {
-            r |= g;
-        }
-    }
-
-    return r;
-}
-
-wf::region_t pixdecor_layout_t::limit_region(wf::region_t & region) const
-{
-    wf::region_t out = region & this->cached_titlebar;
-    return out;
-}
-
-void pixdecor_layout_t::unset_hover(wf::point_t position)
-{
-    auto area = find_area_at(position);
-    if (area && (area->get_type() == DECORATION_AREA_BUTTON))
-    {
-        area->as_button().set_hover(false);
-    }
-}
-
-/** Handle motion event to (x, y) relative to the decoration */
-pixdecor_layout_t::action_response_t pixdecor_layout_t::handle_motion(
-    int x, int y)
-{
-    auto previous_area = find_area_at(current_input);
-    auto current_area  = find_area_at({x, y});
-
-    if (previous_area == current_area)
-    {
-        if (is_grabbed && current_area &&
-            (current_area->get_type() & DECORATION_AREA_MOVE_BIT))
-        {
-            is_grabbed = false;
-            return {DECORATION_ACTION_MOVE, 0};
-        }
-    } else
-    {
-        unset_hover(current_input);
-        if (current_area && (current_area->get_type() == DECORATION_AREA_BUTTON))
-        {
-            current_area->as_button().set_hover(true);
-        }
-    }
-
-    this->current_input = {x, y};
-    update_cursor();
-
-    return {DECORATION_ACTION_NONE, 0};
-}
-
-/**
- * Handle press or release event.
- * @param pressed Whether the event is a press(true) or release(false)
- *  event.
- * @return The action which needs to be carried out in response to this
- *  event.
- * */
-pixdecor_layout_t::action_response_t pixdecor_layout_t::handle_press_event(
-    bool pressed)
-{
-    if (pressed)
-    {
-        auto area = find_area_at(current_input);
-        if (area && (area->get_type() & DECORATION_AREA_MOVE_BIT))
-        {
-            if (timer.is_connected())
-            {
-                double_click_at_release = true;
-            } else
-            {
-                timer.set_timeout(300, [] () { return false; });
-            }
-        }
-
-        if (area && (area->get_type() & DECORATION_AREA_RESIZE_BIT))
-        {
-            return {DECORATION_ACTION_RESIZE, calculate_resize_edges()};
-        }
-
-        if (area && (area->get_type() == DECORATION_AREA_BUTTON))
-        {
-            area->as_button().set_pressed(true);
-        }
-
-        is_grabbed  = true;
-        grab_origin = current_input;
-    }
-
-    if (!pressed && double_click_at_release)
-    {
-        double_click_at_release = false;
-        return {DECORATION_ACTION_TOGGLE_MAXIMIZE, 0};
-    } else if (!pressed && is_grabbed)
-    {
-        is_grabbed = false;
-        auto begin_area = find_area_at(grab_origin);
-        auto end_area   = find_area_at(current_input);
-
-        if (begin_area && (begin_area->get_type() == DECORATION_AREA_BUTTON))
-        {
-            begin_area->as_button().set_pressed(false);
-            if (end_area && (begin_area == end_area))
-            {
-                switch (begin_area->as_button().get_button_type())
-                {
-                  case BUTTON_CLOSE:
-                    return {DECORATION_ACTION_CLOSE, 0};
-
-                  case BUTTON_TOGGLE_MAXIMIZE:
-                    return {DECORATION_ACTION_TOGGLE_MAXIMIZE, 0};
-
-                  case BUTTON_MINIMIZE:
-                    return {DECORATION_ACTION_MINIMIZE, 0};
-
-                  default:
-                    break;
-                }
-            }
-        }
-    }
-
-    return {DECORATION_ACTION_NONE, 0};
-}
-
-pixdecor_layout_t::action_response_t pixdecor_layout_t::handle_axis_event(
-    int delta)
-{
-    if (delta < 0)
-    {
-        return {DECORATION_ACTION_SHADE, 0};
-    } else
-    {
-        return {DECORATION_ACTION_UNSHADE, 0};
-    }
-}
-
-/**
- * Find the layout area at the given coordinates, if any
- * @return The layout area or null on failure
- */
-nonstd::observer_ptr<decoration_area_t> pixdecor_layout_t::find_area_at(
-    wf::point_t point)
-{
-    for (auto& area : this->layout_areas)
-    {
-        auto g = area->get_geometry();
-        auto b = theme.get_input_size();
-        if (area->get_type() & DECORATION_AREA_MOVE_BIT)
-        {
-            continue;
-        }
-
-        if (area->get_type() & DECORATION_AREA_RESIZE_BIT)
-        {
-            if (b <= MIN_RESIZE_HANDLE_SIZE)
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{b, b, b, b});
-            } else if ((area->get_type() == DECORATION_AREA_RESIZE_TOP) ||
-                       (area->get_type() == DECORATION_AREA_RESIZE_BOTTOM))
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{0, 0, b, b});
-            } else if ((area->get_type() == DECORATION_AREA_RESIZE_LEFT) ||
-                       (area->get_type() == DECORATION_AREA_RESIZE_RIGHT))
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{b, b, 0, 0});
-            }
-        }
-
-        if (maximized && (area->get_type() & DECORATION_AREA_MOVE_BIT))
-        {
-            g.height += b;
-        }
-
-        if (g & point)
-        {
-            return {area};
-        }
-    }
-
-    for (auto& area : this->layout_areas)
-    {
-        auto g = area->get_geometry();
-        auto b = theme.get_input_size();
-        if (area->get_type() & DECORATION_AREA_RESIZE_BIT)
-        {
-            continue;
-        }
-
-        if (maximized && (area->get_type() & DECORATION_AREA_MOVE_BIT))
-        {
-            g.height += b;
-        }
-
-        if (g & point)
-        {
-            return {area};
-        }
-    }
-
-    return nullptr;
-}
-
-/** Calculate resize edges based on @current_input */
-uint32_t pixdecor_layout_t::calculate_resize_edges() const
-{
-    wf::option_wrapper_t<int> shadow_radius{"pixdecor/shadow_radius"};
-    wf::option_wrapper_t<std::string> overlay_engine{"pixdecor/overlay_engine"};
-    int radius     = (std::string(overlay_engine) == "rounded_corners") ? int(shadow_radius) : 0;
-    uint32_t edges = 0;
-    for (auto& area : layout_areas)
-    {
-        auto g = area->get_geometry();
-        auto b = theme.get_input_size();
-        g.width  = g.width ?: 1;
-        g.height = g.height ?: 1;
-        if (area->get_type() & DECORATION_AREA_RESIZE_BIT)
-        {
-            if (b <= MIN_RESIZE_HANDLE_SIZE)
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{b, b, b, b});
-            } else if ((area->get_type() == DECORATION_AREA_RESIZE_TOP) ||
-                       (area->get_type() == DECORATION_AREA_RESIZE_BOTTOM))
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{0, 0, b, b});
-            } else if ((area->get_type() == DECORATION_AREA_RESIZE_LEFT) ||
-                       (area->get_type() == DECORATION_AREA_RESIZE_RIGHT))
-            {
-                g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{b, b, 0, 0});
-            }
-        }
-
-        if (((b - radius * 2) > MIN_RESIZE_HANDLE_SIZE) && (area->get_type() == DECORATION_AREA_RESIZE_TOP))
-        {
-            g.height /= 2;
-        }
-
-        if (g & this->current_input)
-        {
-            if (area->get_type() & DECORATION_AREA_RESIZE_BIT)
-            {
-                edges |= (area->get_type() & ~DECORATION_AREA_RESIZE_BIT);
-            }
-        }
-    }
-
-    return edges;
-}
-
-/** Update the cursor based on @current_input */
-void pixdecor_layout_t::update_cursor()
-{
-    uint32_t edges = calculate_resize_edges();
-    auto area = find_area_at(this->current_input);
-    if (area && (area->get_type() == DECORATION_AREA_BUTTON))
-    {
-        wf::get_core().set_cursor("default");
-        return;
-    }
-
-    auto cursor_name = edges > 0 ?
-        wlr_xcursor_get_resize_name((wlr_edges)edges) : "default";
-    wf::get_core().set_cursor(cursor_name);
-}
-
-void pixdecor_layout_t::set_maximize(bool state)
-{
-    maximized = state;
-}
-
-void pixdecor_layout_t::handle_focus_lost()
-{
-    if (is_grabbed)
-    {
-        this->is_grabbed = false;
-        auto area = find_area_at(grab_origin);
-        if (area && (area->get_type() == DECORATION_AREA_BUTTON))
-        {
-            area->as_button().set_pressed(false);
-        }
-    }
-
-    this->unset_hover(current_input);
-}
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-layout.hpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-layout.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-layout.hpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-layout.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,201 +0,0 @@
-#pragma once
-
-#include <vector>
-#include <wayfire/util.hpp>
-#include "deco-button.hpp"
-
-namespace wf
-{
-namespace pixdecor
-{
-static constexpr uint32_t DECORATION_AREA_RENDERABLE_BIT = (1 << 16);
-static constexpr uint32_t DECORATION_AREA_RESIZE_BIT     = (1 << 17);
-static constexpr uint32_t DECORATION_AREA_MOVE_BIT   = (1 << 18);
-static constexpr uint32_t DECORATION_AREA_SHADOW_BIT = (1 << 19);
-
-
-/** Different types of areas around the decoration */
-enum decoration_area_type_t
-{
-    DECORATION_AREA_MOVE          = DECORATION_AREA_MOVE_BIT,
-    DECORATION_AREA_TITLE         =
-        DECORATION_AREA_MOVE_BIT | DECORATION_AREA_RENDERABLE_BIT,
-    DECORATION_AREA_BUTTON        = DECORATION_AREA_RENDERABLE_BIT,
-    DECORATION_AREA_SHADOW        = DECORATION_AREA_SHADOW_BIT,
-    DECORATION_AREA_RESIZE_LEFT   = WLR_EDGE_LEFT | DECORATION_AREA_RESIZE_BIT,
-    DECORATION_AREA_RESIZE_RIGHT  = WLR_EDGE_RIGHT | DECORATION_AREA_RESIZE_BIT,
-    DECORATION_AREA_RESIZE_TOP    = WLR_EDGE_TOP | DECORATION_AREA_RESIZE_BIT,
-    DECORATION_AREA_RESIZE_BOTTOM = WLR_EDGE_BOTTOM | DECORATION_AREA_RESIZE_BIT,
-};
-
-/**
- * Represents an area of the decoration which reacts to input events.
- */
-struct decoration_area_t
-{
-  public:
-    /**
-     * Initialize a new decoration area with the given type and geometry
-     */
-    decoration_area_t(decoration_area_type_t type, wf::geometry_t g);
-
-    /**
-     * Initialize a new decoration area holding a button.
-     *
-     * @param g The geometry of the button.
-     * @param damage_callback Callback to execute when button needs repaint.
-     * @param theme The theme to use for the button.
-     */
-    decoration_area_t(wf::geometry_t g,
-        std::function<void(wlr_box)> damage_callback,
-        pixdecor_theme_t& theme);
-
-    /** @return The geometry of the decoration area, relative to the layout */
-    wf::geometry_t get_geometry() const;
-    void set_geometry(wf::geometry_t g);
-
-    /** @return The area's button, if the area is a button. Otherwise UB */
-    button_t& as_button();
-
-    /** @return The type of the decoration area */
-    decoration_area_type_t get_type() const;
-
-  private:
-    std::function<void(wlr_box)> damage_callback;
-    decoration_area_type_t type;
-    wf::geometry_t geometry;
-
-    /* For buttons only */
-    std::unique_ptr<button_t> button;
-};
-
-
-/**
- * Action which needs to be taken in response to an input event
- */
-enum decoration_layout_action_t
-{
-    DECORATION_ACTION_NONE            = 0,
-    /* Drag actions */
-    DECORATION_ACTION_MOVE            = 1,
-    DECORATION_ACTION_RESIZE          = 2,
-    /* Button actions */
-    DECORATION_ACTION_CLOSE           = 3,
-    DECORATION_ACTION_TOGGLE_MAXIMIZE = 4,
-    DECORATION_ACTION_MINIMIZE        = 5,
-    /* Axis actions */
-    DECORATION_ACTION_SHADE           = 6,
-    DECORATION_ACTION_UNSHADE         = 7,
-};
-
-class pixdecor_theme_t;
-/**
- * Manages the layout of the decorations, i.e positioning of the title,
- * buttons, etc.
- *
- * Also dispatches the input events to the appropriate place.
- */
-class pixdecor_layout_t
-{
-  public:
-    /**
-     * Create a new decoration layout for the given theme.
-     * When the theme changes, the decoration layout needs to be created again.
-     *
-     * @param damage_callback The function to be called when a part of the
-     * layout needs a repaint.
-     */
-    pixdecor_layout_t(pixdecor_theme_t& theme,
-        std::function<void(wlr_box)> damage_callback);
-    ~pixdecor_layout_t();
-
-    /** Regenerate layout using the new size */
-    void resize(int width, int height);
-
-    /**
-     * @return The decoration areas which need to be rendered, in top to bottom
-     *  order.
-     */
-    std::vector<nonstd::observer_ptr<decoration_area_t>> get_renderable_areas();
-
-    /** @return The combined region of all layout areas */
-    wf::region_t calculate_region() const;
-
-    /** Limit region to title bar area by region intersection
-     *  @param region to limit by title area
-     *  @return the intersection between region and the title bar area */
-    wf::region_t limit_region(wf::region_t & region) const;
-
-    struct action_response_t
-    {
-        decoration_layout_action_t action;
-        /* For resizing action, determine the edges for resize request */
-        uint32_t edges;
-    };
-
-    /** Handle motion event to (x, y) relative to the decoration */
-    action_response_t handle_motion(int x, int y);
-
-    /**
-     * Handle press or release event.
-     * @param pressed Whether the event is a press(true) or release(false)
-     *  event.
-     * @return The action which needs to be carried out in response to this
-     *  event.
-     */
-    action_response_t handle_press_event(bool pressed = true);
-
-    /**
-     * Handle axis event.
-     * @param delta The delta of the axis event denoting direction
-     * @return The action which needs to be carried out in response to this
-     *  event.
-     */
-    action_response_t handle_axis_event(int delta);
-
-    /**
-     * Handle focus lost event.
-     */
-    void handle_focus_lost();
-
-    void set_maximize(bool state);
-
-  private:
-    const int titlebar_size;
-    const int border_size;
-    pixdecor_theme_t& theme;
-    bool maximized;
-
-    std::function<void(wlr_box)> damage_callback;
-
-    std::vector<std::unique_ptr<decoration_area_t>> layout_areas;
-    wf::geometry_t cached_titlebar;
-
-    bool is_grabbed = false;
-    /* Position where the grab has started */
-    wf::point_t grab_origin;
-    /* Last position of the input */
-    wf::point_t current_input;
-    /* double-click timer */
-    wf::wl_timer<false> timer;
-    bool double_click_at_release = false;
-
-    /** Create buttons in the layout, and return their total geometry */
-    wf::geometry_t create_buttons(int width, int height);
-
-    /** Calculate resize edges based on @current_input */
-    uint32_t calculate_resize_edges() const;
-    /** Update the cursor based on @current_input */
-    void update_cursor();
-
-    /**
-     * Find the layout area at the given coordinates, if any
-     * @return The layout area or null on failure
-     */
-    nonstd::observer_ptr<decoration_area_t> find_area_at(wf::point_t point);
-
-    /** Unset hover state of hovered button at @position, if any */
-    void unset_hover(wf::point_t position);
-};
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/decoration.cpp wayfire-plugins-extra/subprojects/pixdecor/src/decoration.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/decoration.cpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/decoration.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,764 +0,0 @@
-#include <wayfire/per-output-plugin.hpp>
-#include <wayfire/view.hpp>
-#include <wayfire/workarea.hpp>
-#include <wayfire/matcher.hpp>
-#include <wayfire/workspace-set.hpp>
-#include <wayfire/output.hpp>
-#include <wayfire/signal-definitions.hpp>
-#include <wayfire/txn/transaction-manager.hpp>
-#include <wayfire/render-manager.hpp>
-
-#include "deco-subsurface.hpp"
-#include "wayfire/core.hpp"
-#include "wayfire/plugin.hpp"
-#include "wayfire/signal-provider.hpp"
-#include "wayfire/toplevel-view.hpp"
-#include "wayfire/toplevel.hpp"
-#include <sys/inotify.h>
-#include <unistd.h>
-#include <gio/gio.h>
-#include <dlfcn.h>
-#include <wayfire/bindings-repository.hpp>
-#include <wayfire/plugins/ipc/ipc-activator.hpp>
-#include "shade.hpp"
-
-namespace wf
-{
-namespace pixdecor
-{
-int handle_theme_updated(int fd, uint32_t mask, void *data)
-{
-    int bufsz = sizeof(inotify_event) + NAME_MAX + 1;
-    char buf[bufsz];
-
-    if ((mask & WL_EVENT_READABLE) == 0)
-    {
-        return 0;
-    }
-
-    if (read(fd, buf, bufsz) < 0)
-    {
-        return 0;
-    }
-
-    (*((std::function<void(void)>*)data))();
-
-    return 0;
-}
-
-class wayfire_pixdecor : public wf::plugin_interface_t
-{
-    wf::option_wrapper_t<int> border_size{"pixdecor/border_size"};
-    wf::option_wrapper_t<std::string> title_font{"pixdecor/title_font"};
-    wf::option_wrapper_t<int> title_text_align{"pixdecor/title_text_align"};
-    wf::option_wrapper_t<bool> titlebar{"pixdecor/titlebar"};
-    wf::option_wrapper_t<bool> maximized_borders{"pixdecor/maximized_borders"};
-    wf::option_wrapper_t<bool> maximized_shadows{"pixdecor/maximized_shadows"};
-    wf::option_wrapper_t<wf::color_t> fg_color{"pixdecor/fg_color"};
-    wf::option_wrapper_t<wf::color_t> bg_color{"pixdecor/bg_color"};
-    wf::option_wrapper_t<wf::color_t> fg_text_color{"pixdecor/fg_text_color"};
-    wf::option_wrapper_t<wf::color_t> bg_text_color{"pixdecor/bg_text_color"};
-    wf::option_wrapper_t<wf::color_t> button_color{"pixdecor/button_color"};
-    wf::option_wrapper_t<double> button_line_thickness{"pixdecor/button_line_thickness"};
-    wf::option_wrapper_t<int> button_spacing{"pixdecor/button_spacing"};
-    wf::option_wrapper_t<int> button_x_offset{"pixdecor/button_x_offset"};
-    wf::option_wrapper_t<int> button_y_offset{"pixdecor/button_y_offset"};
-    wf::option_wrapper_t<std::string> button_minimize_image{"pixdecor/button_minimize_image"};
-    wf::option_wrapper_t<std::string> button_maximize_image{"pixdecor/button_maximize_image"};
-    wf::option_wrapper_t<std::string> button_close_image{"pixdecor/button_close_image"};
-    wf::option_wrapper_t<std::string> ignore_views_string{"pixdecor/ignore_views"};
-    wf::option_wrapper_t<std::string> always_decorate_string{"pixdecor/always_decorate"};
-    wf::option_wrapper_t<std::string> effect_type{"pixdecor/effect_type"};
-    wf::option_wrapper_t<std::string> overlay_engine{"pixdecor/overlay_engine"};
-    wf::option_wrapper_t<bool> effect_animate{"pixdecor/animate"};
-    wf::option_wrapper_t<int> rounded_corner_radius{"pixdecor/rounded_corner_radius"};
-    wf::option_wrapper_t<int> shadow_radius{"pixdecor/shadow_radius"};
-    wf::option_wrapper_t<wf::color_t> shadow_color{"pixdecor/shadow_color"};
-    wf::view_matcher_t ignore_views{"pixdecor/ignore_views"};
-    wf::view_matcher_t always_decorate{"pixdecor/always_decorate"};
-    wf::option_wrapper_t<wf::keybinding_t> shade_modifier{"pixdecor/shade_modifier"};
-    wf::option_wrapper_t<int> csd_titlebar_height{"pixdecor/csd_titlebar_height"};
-    wf::option_wrapper_t<bool> enable_shade{"pixdecor/enable_shade"};
-    wf::ipc_activator_t pixdecor_toggle_shade{"pixdecor/shade_toggle"};
-    wf::wl_idle_call idle_update_views;
-    int inotify_fd;
-    int wd_cfg_file;
-    int wd_cfg_dir;
-    wl_event_source *evsrc;
-    std::function<void(void)> update_event;
-    wf::effect_hook_t pre_hook;
-    bool hook_set = false;
-
-    wf::axis_callback shade_axis_cb;
-
-    wf::signal::connection_t<wf::txn::new_transaction_signal> on_new_tx =
-        [=] (wf::txn::new_transaction_signal *ev)
-    {
-        // For each transaction, we need to consider what happens with participating views
-        for (const auto& obj : ev->tx->get_objects())
-        {
-            if (auto toplevel = std::dynamic_pointer_cast<wf::toplevel_t>(obj))
-            {
-                // First check whether the toplevel already has decoration
-                // In that case, we should just set the correct margins
-                if (auto deco = toplevel->get_data<simple_decorator_t>())
-                {
-                    deco->update_decoration_size();
-                    toplevel->pending().margins = deco->get_margins(toplevel->pending());
-                    continue;
-                }
-
-                // Second case: the view is already mapped, or the transaction does not map it.
-                // The view is not being decorated, so nothing to do here.
-                if (toplevel->current().mapped || !toplevel->pending().mapped)
-                {
-                    continue;
-                }
-
-                // Third case: the transaction will map the toplevel.
-                auto view = wf::find_view_for_toplevel(toplevel);
-                wf::dassert(view != nullptr, "Mapping a toplevel means there must be a corresponding view!");
-                if (should_decorate_view(view))
-                {
-                    if (auto deco = toplevel->get_data<simple_decorator_t>())
-                    {
-                        deco->update_decoration_size();
-                    }
-
-                    adjust_new_decorations(view);
-                }
-            }
-        }
-    };
-
-    wf::signal::connection_t<wf::view_decoration_state_updated_signal> on_decoration_state_changed =
-        [=] (wf::view_decoration_state_updated_signal *ev)
-    {
-        auto toplevel = wf::toplevel_cast(ev->view);
-        if (toplevel)
-        {
-            remove_decoration(toplevel);
-        }
-
-        update_view_decoration(ev->view);
-    };
-
-    // allows criteria containing maximized or floating check
-    wf::signal::connection_t<wf::view_tiled_signal> on_view_tiled =
-        [=] (wf::view_tiled_signal *ev)
-    {
-        update_view_decoration(ev->view);
-    };
-
-    wf::signal::connection_t<wf::view_app_id_changed_signal> on_app_id_changed =
-        [=] (wf::view_app_id_changed_signal *ev)
-    {
-        update_view_decoration(ev->view);
-    };
-
-    wf::signal::connection_t<wf::view_title_changed_signal> on_title_changed =
-        [=] (wf::view_title_changed_signal *ev)
-    {
-        update_view_decoration(ev->view);
-    };
-
-    wf::signal::connection_t<wf::output_added_signal> on_output_added =
-        [=] (wf::output_added_signal *ev)
-    {
-        if (effect_animate || (std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink"))
-        {
-            ev->output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
-        }
-    };
-
-    wf::signal::connection_t<wf::output_removed_signal> on_output_removed =
-        [=] (wf::output_removed_signal *ev)
-    {
-        ev->output->render->rem_effect(&pre_hook);
-    };
-
-    void pop_transformer(wayfire_view view)
-    {
-        if (view->get_transformed_node()->get_transformer(shade_transformer_name))
-        {
-            view->get_transformed_node()->rem_transformer(shade_transformer_name);
-        }
-    }
-
-    void remove_shade_transformers()
-    {
-        for (auto& view : wf::get_core().get_all_views())
-        {
-            pop_transformer(view);
-        }
-    }
-
-    std::shared_ptr<pixdecor_shade> ensure_transformer(wayfire_view view, int titlebar_height)
-    {
-        auto tmgr = view->get_transformed_node();
-        if (auto tr = tmgr->get_transformer<pixdecor_shade>(shade_transformer_name))
-        {
-            return tr;
-        }
-
-        auto node = std::make_shared<pixdecor_shade>(view, titlebar_height);
-        tmgr->add_transformer(node, wf::TRANSFORMER_2D, shade_transformer_name);
-        auto tr = tmgr->get_transformer<pixdecor_shade>(shade_transformer_name);
-
-        return tr;
-    }
-
-    void init_shade(wayfire_view view, bool shade, int titlebar_height)
-    {
-        if (!bool(enable_shade))
-        {
-            return;
-        }
-
-        if (shade)
-        {
-            if (view && view->is_mapped())
-            {
-                auto tr = ensure_transformer(view, titlebar_height);
-                tr->set_titlebar_height(titlebar_height);
-                tr->init_animation(shade);
-            }
-        } else
-        {
-            if (auto tr =
-                    view->get_transformed_node()->get_transformer<pixdecor_shade>(
-                        shade_transformer_name))
-            {
-                tr->set_titlebar_height(titlebar_height);
-                tr->init_animation(shade);
-            }
-        }
-    }
-
-  public:
-
-    void init() override
-    {
-        auto& ol = wf::get_core().output_layout;
-        ol->connect(&on_output_added);
-        ol->connect(&on_output_removed);
-        wf::get_core().connect(&on_decoration_state_changed);
-        wf::get_core().tx_manager->connect(&on_new_tx);
-        wf::get_core().connect(&on_app_id_changed);
-        wf::get_core().connect(&on_title_changed);
-        wf::get_core().connect(&on_view_tiled);
-
-        if (bool(enable_shade))
-        {
-            wf::get_core().bindings->add_axis(shade_modifier, &shade_axis_cb);
-        }
-
-        pixdecor_toggle_shade.set_handler([=] (wf::output_t *output, wayfire_view view)
-        {
-            if (!bool(enable_shade))
-            {
-                return false;
-            }
-
-            if (auto toplevel = wf::toplevel_cast(view))
-            {
-                bool direction = true;
-                auto deco = toplevel->toplevel()->get_data<simple_decorator_t>();
-                if (auto tr =
-                        view->get_transformed_node()->get_transformer<pixdecor_shade>(
-                            shade_transformer_name))
-                {
-                    direction = !tr->get_direction();
-                }
-
-                init_shade(view, direction,
-                    deco ? deco->get_titlebar_height() : csd_titlebar_height);
-                return true;
-            }
-
-            return false;
-        });
-
-        shade_axis_cb = [=] (wlr_pointer_axis_event *ev)
-        {
-            auto v = wf::get_core().get_cursor_focus_view();
-            if (ev->orientation == WL_POINTER_AXIS_VERTICAL_SCROLL)
-            {
-                if (auto toplevel = wf::toplevel_cast(v))
-                {
-                    auto deco = toplevel->toplevel()->get_data<simple_decorator_t>();
-                    init_shade(v, ev->delta < 0 ? true : false,
-                        deco ? deco->get_titlebar_height() : csd_titlebar_height);
-                    return true;
-                }
-
-                return true;
-            }
-
-            return false;
-        };
-
-        enable_shade.set_callback([=]
-        {
-            if (bool(enable_shade))
-            {
-                wf::get_core().bindings->add_axis(shade_modifier, &shade_axis_cb);
-            }
-
-            {
-                wf::get_core().bindings->rem_binding(&shade_axis_cb);
-                remove_shade_transformers();
-            }
-        });
-
-        csd_titlebar_height.set_callback([=] ()
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                if (auto tr =
-                        view->get_transformed_node()->get_transformer<pixdecor_shade>(
-                            shade_transformer_name))
-                {
-                    auto toplevel = toplevel_cast(view);
-                    if (toplevel)
-                    {
-                        if (!toplevel->toplevel()->get_data<simple_decorator_t>())
-                        {
-                            tr->set_titlebar_height(csd_titlebar_height);
-                        }
-                    }
-                }
-            }
-        });
-
-        for (auto& view : wf::get_core().get_all_views())
-        {
-            update_view_decoration(view);
-        }
-
-        border_size.set_callback([=]
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                auto toplevel = wf::toplevel_cast(view);
-                if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>())
-                {
-                    continue;
-                }
-
-                remove_decoration(toplevel);
-                adjust_new_decorations(toplevel);
-                wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-            }
-        });
-
-        fg_color.set_callback([=] { update_colors(); });
-        bg_color.set_callback([=] { update_colors(); });
-        fg_text_color.set_callback([=] { update_colors(); });
-        bg_text_color.set_callback([=] { update_colors(); });
-        ignore_views_string.set_callback([=]
-        {
-            idle_update_views.run_once([=] ()
-            {
-                for (auto& view : wf::get_core().get_all_views())
-                {
-                    auto toplevel = wf::toplevel_cast(view);
-                    if (!toplevel)
-                    {
-                        continue;
-                    }
-
-                    update_view_decoration(view);
-                }
-            });
-        });
-        always_decorate_string.set_callback([=]
-        {
-            idle_update_views.run_once([=] ()
-            {
-                for (auto& view : wf::get_core().get_all_views())
-                {
-                    auto toplevel = wf::toplevel_cast(view);
-                    if (!toplevel)
-                    {
-                        continue;
-                    }
-
-                    update_view_decoration(view);
-                }
-            });
-        });
-
-        pre_hook = [=] ()
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                auto toplevel = wf::toplevel_cast(view);
-                if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>())
-                {
-                    continue;
-                }
-
-                auto deco = toplevel->toplevel()->get_data<simple_decorator_t>();
-                deco->update_animation();
-            }
-        };
-
-        if (std::string(effect_type) != "none")
-        {
-            for (auto& o : wf::get_core().output_layout->get_outputs())
-            {
-                o->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
-            }
-
-            hook_set = true;
-        }
-
-        titlebar.set_callback([=] {option_changed_cb(false, true);});
-        effect_type.set_callback([=] {option_changed_cb(false, false);});
-        overlay_engine.set_callback([=] {option_changed_cb(true, false);recreate_frames();});
-        effect_animate.set_callback([=] {option_changed_cb(false, false);});
-        button_color.set_callback([=] {recreate_frames();});
-        button_line_thickness.set_callback([=] {recreate_frames();});
-        button_spacing.set_callback([=] {recreate_frames();});
-        button_x_offset.set_callback([=] {recreate_frames();});
-        button_y_offset.set_callback([=] {recreate_frames();});
-        button_minimize_image.set_callback([=] {recreate_frames();});
-        button_maximize_image.set_callback([=] {recreate_frames();});
-        button_close_image.set_callback([=] {recreate_frames();});
-        title_text_align.set_callback([=]
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                view->damage();
-            }
-        });
-        title_font.set_callback([=] {recreate_frames();});
-        shadow_radius.set_callback([=]
-        {
-            option_changed_cb(false, (std::string(overlay_engine) == "rounded_corners"));
-        });
-        shadow_color.set_callback([=]
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                auto toplevel = wf::toplevel_cast(view);
-                if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>())
-                {
-                    continue;
-                }
-
-                view->damage();
-            }
-        });
-        rounded_corner_radius.set_callback([=]
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                auto toplevel = wf::toplevel_cast(view);
-                if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>())
-                {
-                    continue;
-                }
-
-                view->damage();
-                wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-            }
-        });
-        maximized_borders.set_callback([=]
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                auto toplevel = wf::toplevel_cast(view);
-                if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>() ||
-                    !toplevel->pending_tiled_edges())
-                {
-                    continue;
-                }
-
-                view->damage();
-                remove_decoration(toplevel);
-                adjust_new_decorations(toplevel);
-                wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-            }
-        });
-        maximized_shadows.set_callback([=]
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                auto toplevel = wf::toplevel_cast(view);
-                if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>() ||
-                    !toplevel->pending_tiled_edges())
-                {
-                    continue;
-                }
-
-                view->damage();
-                remove_decoration(toplevel);
-                adjust_new_decorations(toplevel);
-                wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-            }
-        });
-
-        // set up the watch on the xsettings file
-        inotify_fd = inotify_init1(IN_CLOEXEC);
-        evsrc = wl_event_loop_add_fd(wf::get_core().ev_loop, inotify_fd, WL_EVENT_READABLE,
-            handle_theme_updated, &this->update_event);
-
-        // enable watches on xsettings file
-        char *conf_dir  = g_build_filename(g_get_user_config_dir(), "xsettingsd/", NULL);
-        char *conf_file = g_build_filename(conf_dir, "xsettingsd.conf", NULL);
-        wd_cfg_dir  = inotify_add_watch(inotify_fd, conf_dir, IN_CREATE);
-        wd_cfg_file = inotify_add_watch(inotify_fd, conf_file, IN_CLOSE_WRITE);
-        g_free(conf_file);
-        g_free(conf_dir);
-
-        update_event = [=] (void)
-        {
-            update_colors();
-        };
-
-        dlopen("libpangocairo-1.0.so", RTLD_LAZY);
-    }
-
-    void fini() override
-    {
-        for (auto view : wf::get_core().get_all_views())
-        {
-            if (auto toplevel = wf::toplevel_cast(view))
-            {
-                remove_decoration(toplevel);
-                wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-            }
-        }
-
-        if (hook_set)
-        {
-            for (auto& o : wf::get_core().output_layout->get_outputs())
-            {
-                o->render->rem_effect(&pre_hook);
-            }
-        }
-
-        on_output_added.disconnect();
-        on_output_removed.disconnect();
-        on_decoration_state_changed.disconnect();
-        on_new_tx.disconnect();
-        on_app_id_changed.disconnect();
-        on_title_changed.disconnect();
-
-        wf::get_core().bindings->rem_binding(&shade_axis_cb);
-        remove_shade_transformers();
-
-        wl_event_source_remove(evsrc);
-        inotify_rm_watch(inotify_fd, wd_cfg_file);
-        inotify_rm_watch(inotify_fd, wd_cfg_dir);
-        close(inotify_fd);
-    }
-
-    void recreate_frame(wayfire_toplevel_view toplevel)
-    {
-        auto deco = toplevel->toplevel()->get_data<simple_decorator_t>();
-        if (!deco)
-        {
-            return;
-        }
-
-        deco->recreate_frame();
-    }
-
-    void recreate_frames()
-    {
-        for (auto& view : wf::get_core().get_all_views())
-        {
-            auto toplevel = wf::toplevel_cast(view);
-            if (!toplevel)
-            {
-                continue;
-            }
-
-            recreate_frame(toplevel);
-        }
-    }
-
-    void option_changed_cb(bool resize_decorations, bool recreate_decorations)
-    {
-        if (effect_animate || (std::string(effect_type) == "smoke") || (std::string(effect_type) == "ink"))
-        {
-            if (!hook_set)
-            {
-                for (auto& o : wf::get_core().output_layout->get_outputs())
-                {
-                    o->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
-                }
-
-                hook_set = true;
-            }
-        } else
-        {
-            if (hook_set)
-            {
-                for (auto& o : wf::get_core().output_layout->get_outputs())
-                {
-                    o->render->rem_effect(&pre_hook);
-                }
-
-                hook_set = false;
-            }
-        }
-
-        if (recreate_decorations)
-        {
-            for (auto& view : wf::get_core().get_all_views())
-            {
-                auto toplevel = wf::toplevel_cast(view);
-                if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>())
-                {
-                    continue;
-                }
-
-                remove_decoration(toplevel);
-                adjust_new_decorations(toplevel);
-                wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-            }
-
-            return;
-        }
-
-        for (auto& view : wf::get_core().get_all_views())
-        {
-            auto toplevel = wf::toplevel_cast(view);
-            if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>())
-            {
-                continue;
-            }
-
-            view->damage();
-            toplevel->toplevel()->get_data<simple_decorator_t>()->effect_updated();
-
-            auto& pending = toplevel->toplevel()->pending();
-            if (!resize_decorations || (pending.tiled_edges != 0))
-            {
-                wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-                continue;
-            }
-
-            if (std::string(overlay_engine) == "rounded_corners")
-            {
-                pending.margins =
-                {int(shadow_radius) * 2, int(shadow_radius) * 2,
-                    int(shadow_radius) * 2, int(shadow_radius) * 2};
-                pending.geometry = wf::expand_geometry_by_margins(pending.geometry, pending.margins);
-            } else
-            {
-                pending.geometry = wf::shrink_geometry_by_margins(pending.geometry, pending.margins);
-                pending.margins  = toplevel->toplevel()->get_data<simple_decorator_t>()->get_margins(
-                    toplevel->toplevel()->pending());
-                pending.geometry = wf::expand_geometry_by_margins(pending.geometry, pending.margins);
-            }
-
-            wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-        }
-    }
-
-    void update_colors()
-    {
-        for (auto& view : wf::get_core().get_all_views())
-        {
-            auto toplevel = wf::toplevel_cast(view);
-            if (!toplevel || !toplevel->toplevel()->get_data<simple_decorator_t>())
-            {
-                continue;
-            }
-
-            auto deco = toplevel->toplevel()->get_data<simple_decorator_t>();
-            deco->update_colors();
-            view->damage();
-        }
-    }
-
-    /**
-     * Uses view_matcher_t to match whether the given view needs to be
-     * ignored for decoration
-     *
-     * @param view The view to match
-     * @return Whether the given view should be decorated?
-     */
-    bool ignore_decoration_of_view(wayfire_view view)
-    {
-        return ignore_views.matches(view);
-    }
-
-    bool should_decorate_view(wayfire_toplevel_view view)
-    {
-        return (view->should_be_decorated() && !ignore_decoration_of_view(view)) || always_decorate.matches(
-            view);
-    }
-
-    void adjust_new_decorations(wayfire_toplevel_view view)
-    {
-        auto toplevel = view->toplevel();
-
-        if (!toplevel->get_data<simple_decorator_t>())
-        {
-            toplevel->store_data(std::make_unique<simple_decorator_t>(view));
-        }
-
-        auto deco     = toplevel->get_data<simple_decorator_t>();
-        auto& pending = toplevel->pending();
-        pending.margins = deco->get_margins(pending);
-
-        if (!pending.fullscreen && !pending.tiled_edges)
-        {
-            toplevel->pending().geometry = wf::expand_geometry_by_margins(
-                toplevel->pending().geometry, pending.margins);
-        }
-    }
-
-    void remove_decoration(wayfire_toplevel_view view)
-    {
-        view->toplevel()->erase_data<simple_decorator_t>();
-        auto& pending = view->toplevel()->pending();
-        if (!pending.fullscreen && !pending.tiled_edges)
-        {
-            pending.geometry = wf::shrink_geometry_by_margins(pending.geometry, pending.margins);
-        }
-
-        pending.margins = {0, 0, 0, 0};
-
-        std::string custom_data_name = "wf-decoration-shadow-margin";
-        if (view->has_data(custom_data_name))
-        {
-            view->erase_data(custom_data_name);
-        }
-    }
-
-    void update_view_decoration(wayfire_view view)
-    {
-        if (auto toplevel = wf::toplevel_cast(view))
-        {
-            if (!toplevel)
-            {
-                return;
-            }
-
-            if (!toplevel->toplevel()->get_data<simple_decorator_t>() && (always_decorate.matches(view) ||
-                                                                          (should_decorate_view(toplevel)
-                                                                           &&
-                                                                           !ignore_views.matches(view))))
-            {
-                adjust_new_decorations(toplevel);
-            } else if ((!always_decorate.matches(view) &&
-                        (!should_decorate_view(toplevel) || ignore_views.matches(view))))
-            {
-                remove_decoration(toplevel);
-            }
-
-            wf::get_core().tx_manager->schedule_object(toplevel->toplevel());
-        }
-    }
-};
-}
-}
-
-DECLARE_WAYFIRE_PLUGIN(wf::pixdecor::wayfire_pixdecor);
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-subsurface.cpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-subsurface.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-subsurface.cpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-subsurface.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,699 +0,0 @@
-#include "wayfire/geometry.hpp"
-#include "wayfire/scene-input.hpp"
-#include "wayfire/scene-operations.hpp"
-#include "wayfire/scene-render.hpp"
-#include "wayfire/scene.hpp"
-#include "wayfire/signal-provider.hpp"
-#include "wayfire/toplevel.hpp"
-#include <memory>
-#define GLM_FORCE_RADIANS
-#include <glm/gtc/matrix_transform.hpp>
-
-#include <linux/input-event-codes.h>
-
-#include <wayfire/nonstd/wlroots.hpp>
-#include <wayfire/output.hpp>
-#include <wayfire/opengl.hpp>
-#include <wayfire/core.hpp>
-#include <wayfire/signal-definitions.hpp>
-#include <wayfire/toplevel-view.hpp>
-#include "deco-subsurface.hpp"
-#include "deco-layout.hpp"
-#include "deco-theme.hpp"
-#include <wayfire/window-manager.hpp>
-#include <wayfire/view-transform.hpp>
-#include <wayfire/txn/transaction-manager.hpp>
-#include <wayfire/scene-render.hpp>
-
-#include <wayfire/plugins/common/cairo-util.hpp>
-
-#include <cairo.h>
-#include "shade.hpp"
-
-
-namespace wf
-{
-namespace pixdecor
-{
-wf::option_wrapper_t<wf::color_t> effect_color{"pixdecor/effect_color"};
-wf::option_wrapper_t<int> shadow_radius{"pixdecor/shadow_radius"};
-wf::option_wrapper_t<bool> titlebar_opt{"pixdecor/titlebar"};
-wf::option_wrapper_t<int> csd_titlebar_height{"pixdecor/csd_titlebar_height"};
-wf::option_wrapper_t<bool> enable_shade{"pixdecor/enable_shade"};
-wf::option_wrapper_t<std::string> title_font{"pixdecor/title_font"};
-wf::option_wrapper_t<std::string> overlay_engine{"pixdecor/overlay_engine"};
-wf::option_wrapper_t<std::string> effect_type{"pixdecor/effect_type"};
-wf::option_wrapper_t<bool> maximized_borders{"pixdecor/maximized_borders"};
-wf::option_wrapper_t<bool> maximized_shadows{"pixdecor/maximized_shadows"};
-wf::option_wrapper_t<int> title_text_align{"pixdecor/title_text_align"};
-
-class simple_decoration_node_t : public wf::scene::node_t, public wf::pointer_interaction_t,
-    public wf::touch_interaction_t
-{
-    std::weak_ptr<wf::toplevel_view_interface_t> _view;
-    wf::signal::connection_t<wf::view_title_changed_signal> title_set =
-        [=] (wf::view_title_changed_signal *ev)
-    {
-        if (auto view = _view.lock())
-        {
-            view->damage();
-        }
-    };
-
-    void update_title(int width, int height, int t_width, int border, int buttons_width, double scale)
-    {
-        if (auto view = _view.lock())
-        {
-            int target_width  = width * scale;
-            int target_height = height * scale;
-
-            if ((int(title_text_align) != title_texture.title_text_align) ||
-                (view->get_title() != title_texture.current_text) ||
-                (target_width != title_texture.tex.get_size().width) ||
-                (std::string(title_font) != title_texture.title_font_string) ||
-                (target_height != title_texture.tex.get_size().height) ||
-                (view->activated != title_texture.rendered_for_activated_state))
-            {
-                auto surface = theme.render_text(view->get_title(),
-                    target_width, target_height, t_width, border, buttons_width, view->activated);
-                title_texture.tex = owned_texture_t{surface};
-                cairo_surface_destroy(surface);
-                title_texture.title_font_string = title_font;
-                title_texture.current_text     = view->get_title();
-                title_texture.title_text_align = int(title_text_align);
-                title_texture.rendered_for_activated_state = view->activated;
-            }
-        }
-    }
-
-    struct
-    {
-        wf::owned_texture_t tex;
-        std::string current_text = "";
-        bool rendered_for_activated_state = false;
-        int title_text_align = int(title_text_align);
-        std::string title_font_string = title_font;
-    } title_texture;
-
-  public:
-    pixdecor_theme_t theme;
-    pixdecor_layout_t layout;
-    wf::region_t cached_region;
-
-    wf::dimensions_t size;
-
-    int current_thickness;
-    int current_titlebar;
-    wf::pointf_t current_cursor_position;
-
-    simple_decoration_node_t(wayfire_toplevel_view view) :
-        node_t(false),
-        theme{},
-        layout{theme, [=] (wlr_box box) { wf::scene::damage_node(shared_from_this(), box + get_offset()); }}
-    {
-        this->_view = view->weak_from_this();
-        view->connect(&title_set);
-
-        // make sure to hide frame if the view is fullscreen
-        update_decoration_size();
-
-        current_cursor_position.x = current_cursor_position.y = FLT_MIN;
-    }
-
-    ~simple_decoration_node_t()
-    {
-        remove_shade_transformers();
-    }
-
-    wf::point_t get_offset()
-    {
-        auto view = _view.lock();
-        if (view && view->pending_tiled_edges() && !maximized_borders && !maximized_shadows)
-        {
-            return {0, -current_titlebar};
-        }
-
-        return {-current_thickness, -current_titlebar};
-    }
-
-    void render_title(const wf::scene::render_instruction_t& data,
-        const wf::geometry_t& geometry, int t_width, int border, int buttons_width)
-    {
-        update_title(geometry.width, geometry.height, t_width, border, buttons_width, data.target.scale);
-        OpenGL::render_texture(wf::gles_texture_t{title_texture.tex.get_texture()}, data.target, geometry,
-            glm::vec4(1.0f), OpenGL::RENDER_FLAG_CACHED);
-
-        data.pass->custom_gles_subpass(data.target,[&]
-        {
-            for (auto& box : data.damage)
-            {
-                wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
-                OpenGL::draw_cached();
-            }
-        });
-
-        OpenGL::clear_cached();
-    }
-
-    void render_region(const wf::scene::render_instruction_t& data, wf::point_t origin)
-    {
-        int border = theme.get_border_size();
-        wlr_box geometry{origin.x, origin.y, size.width, size.height};
-
-        bool activated = false;
-        bool maximized = false;
-        if (auto view = _view.lock())
-        {
-            activated = view->activated;
-            maximized = view->pending_tiled_edges();
-        }
-
-        auto renderables = layout.get_renderable_areas();
-        auto offset =
-            wf::point_t{origin.x,
-            origin.y -
-            ((maximized && (!maximized_shadows || !maximized_borders)) ? -border / 2 : border / 4)};
-
-        wf::gles::run_in_context([&]
-        {
-            wf::gles::bind_render_buffer(data.target);
-
-            theme.render_background(data, geometry, activated, current_cursor_position);
-
-            if (!titlebar_opt)
-            {
-                return;
-            }
-
-            int buttons_width = 0;
-            for (auto item : renderables)
-            {
-                if (item->get_type() != DECORATION_AREA_TITLE)
-                {
-                    buttons_width += item->get_geometry().width;
-                }
-            }
-
-            /* Draw title & buttons */
-            auto title_border = border + ((std::string(overlay_engine) == "rounded_corners" &&
-                (!maximized || maximized_shadows)) ? int(shadow_radius) * 2 : 0);
-            for (auto item : renderables)
-            {
-                if (item->get_type() == DECORATION_AREA_TITLE)
-                {
-                    render_title(data,
-                        item->get_geometry() + offset, size.width - border * 2, title_border, buttons_width);
-                } else // button
-                {
-                    item->as_button().render(data,
-                        item->get_geometry() + origin);
-                }
-            }
-        });
-    }
-
-    std::optional<wf::scene::input_node_t> find_node_at(const wf::pointf_t& at) override
-    {
-        bool maximized = false;
-        if (auto view = _view.lock())
-        {
-            maximized = view->pending_tiled_edges();
-        }
-
-        int border = theme.get_border_size();
-        int r =
-            (std::string(overlay_engine) == "rounded_corners" &&
-                (!maximized || (maximized && maximized_shadows))) ? int(shadow_radius) * 2 : 0;
-        r -= MIN_RESIZE_HANDLE_SIZE - std::min(border, MIN_RESIZE_HANDLE_SIZE);
-        wf::pointf_t local = at - wf::pointf_t{get_offset()};
-        if (auto view = _view.lock())
-        {
-            wf::geometry_t g = view->get_geometry();
-            g.x = g.y = 0;
-            g   = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{-r, -r, -r, -r});
-            wf::region_t deco_region{g};
-            g = wf::expand_geometry_by_margins(g, wf::decoration_margins_t{-border, -border, -border,
-                -theme.get_title_height() - border});
-            wf::region_t view_region{g};
-            deco_region ^= view_region;
-            if (deco_region.contains_pointf(local))
-            {
-                return wf::scene::input_node_t{
-                    .node = this,
-                    .local_coords = local,
-                };
-            }
-        }
-
-        return {};
-    }
-
-    pointer_interaction_t& pointer_interaction() override
-    {
-        return *this;
-    }
-
-    touch_interaction_t& touch_interaction() override
-    {
-        return *this;
-    }
-
-    class decoration_render_instance_t : public wf::scene::render_instance_t
-    {
-        simple_decoration_node_t *self;
-        wf::scene::damage_callback push_damage;
-
-        wf::signal::connection_t<wf::scene::node_damage_signal> on_surface_damage =
-            [=] (wf::scene::node_damage_signal *data)
-        {
-            push_damage(data->region);
-        };
-
-      public:
-        decoration_render_instance_t(simple_decoration_node_t *self, wf::scene::damage_callback push_damage)
-        {
-            this->self = self;
-            this->push_damage = push_damage;
-            self->connect(&on_surface_damage);
-        }
-
-        void schedule_instructions(std::vector<wf::scene::render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage) override
-        {
-            auto our_region = self->cached_region + self->get_offset();
-            wf::region_t our_damage = damage & our_region;
-            if (!our_damage.empty())
-            {
-                instructions.push_back(wf::scene::render_instruction_t{
-                            .instance = this,
-                            .target   = target,
-                            .damage   = std::move(our_damage),
-                        });
-            }
-        }
-
-        void render(const wf::scene::render_instruction_t& data) override
-        {
-            auto offset = self->get_offset();
-            wlr_box rectangle{offset.x, offset.y, self->size.width, self->size.height};
-            bool activated = false;
-            bool maximized = false;
-            if (auto view = self->_view.lock())
-            {
-                activated = view->activated;
-                maximized = maximized_shadows ? false : view->pending_tiled_edges();
-            }
-
-            if ((std::string(effect_type) != "none") || (std::string(overlay_engine) != "none"))
-            {
-                self->theme.smoke.step_effect(data, rectangle, std::string(effect_type) == "ink",
-                    self->current_cursor_position, self->theme.get_decor_color(activated), effect_color,
-                    self->theme.get_title_height(), self->theme.get_border_size(),
-                    (std::string(overlay_engine) == "rounded_corners" && !maximized) ? shadow_radius : 0);
-            }
-
-            self->render_region(data, offset);
-        }
-    };
-
-    void gen_render_instances(std::vector<wf::scene::render_instance_uptr>& instances,
-        wf::scene::damage_callback push_damage, wf::output_t *output = nullptr) override
-    {
-        instances.push_back(std::make_unique<decoration_render_instance_t>(this, push_damage));
-    }
-
-    wf::geometry_t get_bounding_box() override
-    {
-        return wf::construct_box(get_offset(), size);
-    }
-
-    /* wf::compositor_surface_t implementation */
-    void handle_pointer_enter(wf::pointf_t point) override
-    {
-        point -= wf::pointf_t{get_offset()};
-        layout.handle_motion(point.x, point.y);
-    }
-
-    void handle_pointer_leave() override
-    {
-        layout.handle_focus_lost();
-        current_cursor_position.x = current_cursor_position.y = FLT_MIN;
-    }
-
-    void handle_pointer_motion(wf::pointf_t to, uint32_t) override
-    {
-        to -= wf::pointf_t{get_offset()};
-        handle_action(layout.handle_motion(to.x, to.y));
-        current_cursor_position = to;
-    }
-
-    void handle_pointer_button(const wlr_pointer_button_event& ev) override
-    {
-        if (ev.button != BTN_LEFT)
-        {
-            return;
-        }
-
-        handle_action(layout.handle_press_event(ev.state == WL_POINTER_BUTTON_STATE_PRESSED));
-    }
-
-    void handle_pointer_axis(const wlr_pointer_axis_event& ev) override
-    {
-        if (ev.orientation == WL_POINTER_AXIS_VERTICAL_SCROLL)
-        {
-            handle_action(layout.handle_axis_event(ev.delta));
-        }
-    }
-
-    void pop_transformer(wayfire_view view)
-    {
-        if (view->get_transformed_node()->get_transformer(shade_transformer_name))
-        {
-            view->get_transformed_node()->rem_transformer(shade_transformer_name);
-        }
-    }
-
-    void remove_shade_transformers()
-    {
-        for (auto& view : wf::get_core().get_all_views())
-        {
-            pop_transformer(view);
-        }
-    }
-
-    std::shared_ptr<pixdecor_shade> ensure_transformer(wayfire_view view, int titlebar_height)
-    {
-        auto tmgr = view->get_transformed_node();
-        if (auto tr = tmgr->get_transformer<pixdecor_shade>(shade_transformer_name))
-        {
-            return tr;
-        }
-
-        auto node = std::make_shared<pixdecor_shade>(view, titlebar_height);
-        tmgr->add_transformer(node, wf::TRANSFORMER_2D, shade_transformer_name);
-        auto tr = tmgr->get_transformer<pixdecor_shade>(shade_transformer_name);
-
-        return tr;
-    }
-
-    void init_shade(wayfire_view view, bool shade, int titlebar_height)
-    {
-        if (!bool(enable_shade))
-        {
-            return;
-        }
-
-        if (shade)
-        {
-            if (view && view->is_mapped())
-            {
-                auto tr = ensure_transformer(view, titlebar_height);
-                tr->set_titlebar_height(titlebar_height);
-                tr->init_animation(shade);
-            }
-        } else
-        {
-            if (auto tr =
-                    view->get_transformed_node()->get_transformer<pixdecor_shade>(
-                        shade_transformer_name))
-            {
-                tr->set_titlebar_height(titlebar_height);
-                tr->init_animation(shade);
-            }
-        }
-    }
-
-    void handle_action(pixdecor_layout_t::action_response_t action)
-    {
-        if (auto view = _view.lock())
-        {
-            switch (action.action)
-            {
-              case DECORATION_ACTION_MOVE:
-                return wf::get_core().default_wm->move_request(view);
-
-              case DECORATION_ACTION_RESIZE:
-                return wf::get_core().default_wm->resize_request(view, action.edges);
-
-              case DECORATION_ACTION_CLOSE:
-                return view->close();
-
-              case DECORATION_ACTION_TOGGLE_MAXIMIZE:
-                if (view->pending_tiled_edges())
-                {
-                    return wf::get_core().default_wm->tile_request(view, 0);
-                } else
-                {
-                    return wf::get_core().default_wm->tile_request(view, wf::TILED_EDGES_ALL);
-                }
-
-                break;
-
-              case DECORATION_ACTION_SHADE:
-                init_shade(view, true, current_titlebar);
-                break;
-
-              case DECORATION_ACTION_UNSHADE:
-                init_shade(view, false, current_titlebar);
-                break;
-
-              case DECORATION_ACTION_MINIMIZE:
-                return wf::get_core().default_wm->minimize_request(view, true);
-                break;
-
-              default:
-                break;
-            }
-        }
-    }
-
-    void handle_touch_down(uint32_t time_ms, int finger_id, wf::pointf_t position) override
-    {
-        handle_touch_motion(time_ms, finger_id, position);
-        handle_action(layout.handle_press_event());
-    }
-
-    void handle_touch_up(uint32_t time_ms, int finger_id, wf::pointf_t lift_off_position) override
-    {
-        handle_action(layout.handle_press_event(false));
-        layout.handle_focus_lost();
-    }
-
-    void handle_touch_motion(uint32_t time_ms, int finger_id, wf::pointf_t position) override
-    {
-        position -= wf::pointf_t{get_offset()};
-        layout.handle_motion(position.x, position.y);
-        current_cursor_position = position;
-    }
-
-    void recreate_frame()
-    {
-        update_decoration_size();
-        if (auto view = _view.lock())
-        {
-            auto size = wf::dimensions(view->get_pending_geometry());
-            layout.resize(size.width, size.height);
-            wf::get_core().tx_manager->schedule_object(view->toplevel());
-        }
-    }
-
-    void resize(wf::dimensions_t dims)
-    {
-        if (auto view = _view.lock())
-        {
-            theme.set_maximize(view->pending_tiled_edges());
-            layout.set_maximize(maximized_shadows ? 0 : view->pending_tiled_edges());
-            view->damage();
-            size = dims;
-            layout.resize(size.width, size.height);
-            if (!view->toplevel()->current().fullscreen)
-            {
-                this->cached_region = layout.calculate_region();
-            }
-
-            view->damage();
-        }
-    }
-
-    void update_decoration_size()
-    {
-        if (auto view = _view.lock())
-        {
-            view->damage();
-            bool fullscreen = view->toplevel()->pending().fullscreen;
-            bool maximized  = view->toplevel()->pending().tiled_edges;
-            if (fullscreen)
-            {
-                current_thickness = 0;
-                current_titlebar  = 0;
-                this->cached_region.clear();
-            } else
-            {
-                int shadow_thickness = std::string(overlay_engine) == "rounded_corners" &&
-                    (!maximized || (maximized && maximized_shadows)) ? int(shadow_radius) * 2 : 0;
-
-                current_thickness = theme.get_border_size() + shadow_thickness;
-                current_titlebar  = theme.get_title_height() +
-                    ((maximized && !titlebar_opt && !maximized_borders &&
-                        !maximized_shadows) ? 0 : current_thickness);
-                this->cached_region = layout.calculate_region();
-            }
-
-            if (auto tr =
-                    view->get_transformed_node()->get_transformer<pixdecor_shade>(
-                        shade_transformer_name))
-            {
-                tr->set_titlebar_height(current_titlebar);
-            }
-
-            view->damage();
-        }
-    }
-};
-
-simple_decorator_t::simple_decorator_t(wayfire_toplevel_view view)
-{
-    this->view = view;
-    this->shadow_thickness = 0;
-    deco = std::make_shared<simple_decoration_node_t>(view);
-    deco->resize(wf::dimensions(view->get_pending_geometry()));
-    wf::scene::add_back(view->get_surface_root_node(), deco);
-
-    view->connect(&on_view_activated);
-    view->connect(&on_view_geometry_changed);
-    view->connect(&on_view_fullscreen);
-    view->connect(&on_view_tiled);
-
-    on_view_activated = [this] (auto)
-    {
-        wf::scene::damage_node(deco, deco->get_bounding_box());
-    };
-
-    on_view_geometry_changed = [this] (auto)
-    {
-        deco->resize(wf::dimensions(this->view->get_geometry()));
-        wf::get_core().tx_manager->schedule_object(this->view->toplevel());
-    };
-
-    on_view_tiled = [this] (auto)
-    {
-        deco->resize(wf::dimensions(this->view->get_geometry()));
-        wf::get_core().tx_manager->schedule_object(this->view->toplevel());
-    };
-
-    on_view_fullscreen = [this] (auto)
-    {
-        if (!this->view->toplevel()->pending().fullscreen)
-        {
-            deco->resize(wf::dimensions(this->view->get_geometry()));
-            wf::get_core().tx_manager->schedule_object(this->view->toplevel());
-        }
-    };
-}
-
-simple_decorator_t::~simple_decorator_t()
-{
-    wf::scene::remove_child(deco);
-    deco.reset();
-}
-
-int simple_decorator_t::get_titlebar_height()
-{
-    return deco->current_titlebar;
-}
-
-void simple_decorator_t::recreate_frame()
-{
-    deco->recreate_frame();
-}
-
-void simple_decorator_t::update_decoration_size()
-{
-    deco->update_decoration_size();
-}
-
-void simple_decorator_t::update_colors()
-{
-    deco->theme.update_colors();
-}
-
-void simple_decorator_t::effect_updated()
-{
-    deco->theme.smoke.effect_updated();
-}
-
-wf::decoration_margins_t simple_decorator_t::get_margins(const wf::toplevel_state_t& state)
-{
-    if (state.fullscreen)
-    {
-        return {0, 0, 0, 0};
-    }
-
-    deco->theme.set_maximize(state.tiled_edges);
-
-    this->shadow_thickness = std::string(overlay_engine) == "rounded_corners" &&
-        (!state.tiled_edges || (state.tiled_edges && maximized_shadows)) ? int(shadow_radius) * 2 : 0;
-
-    int thickness = deco->theme.get_border_size() + this->shadow_thickness;
-    int titlebar  = deco->theme.get_title_height() +
-        ((state.tiled_edges && !titlebar_opt && !maximized_borders && !maximized_shadows) ? 0 : thickness);
-    if (state.tiled_edges && !maximized_borders)
-    {
-        if (maximized_shadows)
-        {
-            if (!titlebar_opt)
-            {
-                titlebar = thickness;
-            }
-        } else
-        {
-            thickness = 0;
-        }
-    }
-
-    double shade_progress = 0.0;
-    if (auto tr =
-            view->get_transformed_node()->get_transformer<pixdecor_shade>(
-                shade_transformer_name))
-    {
-        tr->set_titlebar_height(titlebar);
-        shade_progress = tr->progression.shade;
-    }
-
-    if (view->has_data(custom_data_name))
-    {
-        view->get_data<wf_shadow_margin_t>(custom_data_name)->set_margins(
-            {shadow_thickness, shadow_thickness, shadow_thickness,
-                shadow_thickness +
-                int((view->get_geometry().height - shadow_thickness - titlebar) * shade_progress)});
-    } else
-    {
-        view->store_data(std::make_unique<wf_shadow_margin_t>(), custom_data_name);
-        view->get_data<wf_shadow_margin_t>(custom_data_name)->set_margins(
-            {shadow_thickness, shadow_thickness, shadow_thickness,
-                shadow_thickness +
-                int((view->get_geometry().height - shadow_thickness - titlebar) * shade_progress)});
-    }
-
-    return wf::decoration_margins_t{
-        .left   = thickness,
-        .right  = thickness,
-        .bottom = thickness,
-        .top    = titlebar,
-    };
-}
-
-void simple_decorator_t::update_animation()
-{
-    auto margins = get_margins(view->toplevel()->current());
-    auto bbox    = deco->get_bounding_box();
-
-    wf::region_t region;
-    region |= wlr_box{bbox.x, bbox.y, bbox.width, margins.top};
-    region |= wlr_box{bbox.x, bbox.y, margins.left, bbox.height};
-    region |= wlr_box{bbox.x, bbox.y + bbox.height - margins.bottom, bbox.width, margins.bottom};
-    region |= wlr_box{bbox.x + bbox.width - margins.right, bbox.y, margins.right, bbox.height};
-    wf::scene::damage_node(deco, region);
-}
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-subsurface.hpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-subsurface.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-subsurface.hpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-subsurface.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,62 +0,0 @@
-#ifndef DECO_SUBSURFACE_HPP
-#define DECO_SUBSURFACE_HPP
-
-#include "wayfire/object.hpp"
-#include "wayfire/toplevel.hpp"
-#include <wayfire/signal-definitions.hpp>
-#include <wayfire/toplevel-view.hpp>
-#include <wayfire/scene-render.hpp>
-
-static std::string custom_data_name = "wf-decoration-shadow-margin";
-
-class wf_shadow_margin_t : public wf::custom_data_t
-{
-  public:
-    wf::decoration_margins_t get_margins()
-    {
-        return margins;
-    }
-
-    void set_margins(wf::decoration_margins_t margins)
-    {
-        this->margins = margins;
-    }
-
-  private:
-    wf::decoration_margins_t margins = {0, 0, 0, 0};
-};
-
-namespace wf
-{
-namespace pixdecor
-{
-class simple_decoration_node_t;
-/**
- * A decorator object attached as custom data to a toplevel object.
- */
-class simple_decorator_t : public wf::custom_data_t
-{
-    wayfire_toplevel_view view;
-    std::shared_ptr<simple_decoration_node_t> deco;
-
-    wf::signal::connection_t<wf::view_activated_state_signal> on_view_activated;
-    wf::signal::connection_t<wf::view_geometry_changed_signal> on_view_geometry_changed;
-    wf::signal::connection_t<wf::view_fullscreen_signal> on_view_fullscreen;
-    wf::signal::connection_t<wf::view_tiled_signal> on_view_tiled;
-
-  public:
-    void update_colors();
-    void effect_updated();
-    void recreate_frame();
-    void update_decoration_size();
-    simple_decorator_t(wayfire_toplevel_view view);
-    ~simple_decorator_t();
-    wf::decoration_margins_t get_margins(const wf::toplevel_state_t& state);
-    int get_titlebar_height();
-    void update_animation();
-    int shadow_thickness;
-};
-}
-}
-
-#endif /* end of include guard: DECO_SUBSURFACE_HPP */
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-theme.cpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-theme.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-theme.cpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-theme.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,367 +0,0 @@
-#include "deco-theme.hpp"
-#include <wayfire/core.hpp>
-#include <wayfire/opengl.hpp>
-#include <map>
-#include <mutex>
-#include <stdlib.h>
-
-namespace wf
-{
-namespace pixdecor
-{
-wf::option_wrapper_t<int> border_size{"pixdecor/border_size"};
-wf::option_wrapper_t<bool> titlebar{"pixdecor/titlebar"};
-wf::option_wrapper_t<wf::color_t> fg_color{"pixdecor/fg_color"};
-wf::option_wrapper_t<wf::color_t> bg_color{"pixdecor/bg_color"};
-wf::option_wrapper_t<wf::color_t> fg_text_color{"pixdecor/fg_text_color"};
-wf::option_wrapper_t<wf::color_t> bg_text_color{"pixdecor/bg_text_color"};
-wf::option_wrapper_t<std::string> button_minimize_image{"pixdecor/button_minimize_image"};
-wf::option_wrapper_t<std::string> button_maximize_image{"pixdecor/button_maximize_image"};
-wf::option_wrapper_t<std::string> button_close_image{"pixdecor/button_close_image"};
-wf::option_wrapper_t<wf::color_t> button_color{"pixdecor/button_color"};
-wf::option_wrapper_t<double> button_line_thickness{"pixdecor/button_line_thickness"};
-/** Create a new theme with the default parameters */
-pixdecor_theme_t::pixdecor_theme_t()
-{
-    gs = g_settings_new("org.gnome.desktop.interface");
-
-    // read initial colours
-    update_colors();
-}
-
-pixdecor_theme_t::~pixdecor_theme_t()
-{
-    g_object_unref(gs);
-}
-
-void pixdecor_theme_t::update_colors(void)
-{
-    fg = wf::color_t(fg_color);
-    bg = wf::color_t(bg_color);
-    fg_text = wf::color_t(fg_text_color);
-    bg_text = wf::color_t(bg_text_color);
-}
-
-/**
- * @return A PangoFontDescription representing either a provided font from
- *  the Title Font option or the system font, scaled by the text-scaling-factor GSetting.
- */
-PangoFontDescription*pixdecor_theme_t::create_font_description()
-{
-    GSettings *gs = g_settings_new("org.gnome.desktop.interface");
-
-    std::string title_font_val(title_font);
-    bool using_system_font{};
-
-    if (title_font_val.empty())
-    {
-        char *font = g_settings_get_string(gs, "font-name");
-        title_font_val    = font;
-        using_system_font = true;
-        g_free(font);
-    }
-
-    PangoFontDescription *font_desc = pango_font_description_from_string(title_font_val.c_str());
-    int font_size = pango_font_description_get_size(font_desc);
-    bool font_size_absolute;
-
-    // font size will be 0 if nothing is specified - grab from system font if this is the case
-    // if the font is the system font, then just pray it works
-    if (!font_size && !using_system_font)
-    {
-        char *font = g_settings_get_string(gs, "font-name");
-        PangoFontDescription *sys_font_desc = pango_font_description_from_string(font);
-
-        font_size = pango_font_description_get_size(sys_font_desc);
-        font_size_absolute = pango_font_description_get_size_is_absolute(sys_font_desc);
-
-        pango_font_description_free(sys_font_desc);
-        g_free(font);
-    } else
-    {
-        font_size_absolute = pango_font_description_get_size_is_absolute(font_desc);
-    }
-
-    // scale the font size if we got it by text-scaling-factor
-    if (font_size)
-    {
-        double scaling_factor = g_settings_get_double(gs, "text-scaling-factor");
-        if (!scaling_factor) // should default to 1.0, but better safe than sorry
-        {
-            scaling_factor = 1.0;
-        }
-
-        if (font_size_absolute)
-        {
-            pango_font_description_set_absolute_size(font_desc, font_size * scaling_factor);
-        } else
-        {
-            pango_font_description_set_size(font_desc, font_size * scaling_factor);
-        }
-    }
-
-    g_object_unref(gs);
-    return font_desc;
-}
-
-/**
- * @return A PangoFontDescription from create_font_description(),
- *  originating from a global, internally managed instance, freeing the data upon exit.
- *  It will also be updated with changes to the Title Font option.
- */
-PangoFontDescription*pixdecor_theme_t::get_font_description()
-{
-    static std::unique_ptr<PangoFontDescription, decltype(& pango_font_description_free)> font_desc(
-        create_font_description(), &pango_font_description_free);
-
-    static std::once_flag once_flag;
-    std::call_once(once_flag, [&]
-    {
-        title_font.set_callback([&]
-        {
-            font_desc.reset(create_font_description());
-        });
-    });
-
-    return font_desc.get();
-}
-
-/** @return The available height for displaying the title */
-int pixdecor_theme_t::get_font_height_px()
-{
-    PangoFontDescription *font_desc = get_font_description();
-    int font_height = pango_font_description_get_size(font_desc);
-
-    if (!pango_font_description_get_size_is_absolute(font_desc))
-    {
-        font_height *= 4;
-        font_height /= 3;
-    }
-
-    return font_height / PANGO_SCALE;
-}
-
-int pixdecor_theme_t::get_title_height()
-{
-    int height = get_font_height_px();
-    height *= 3;
-    height /= 2;
-    height += 8;
-    if (height < MIN_BAR_HEIGHT)
-    {
-        height = MIN_BAR_HEIGHT;
-    }
-
-    return titlebar ? height + ((maximized && !maximized_borders) ? border_size : 0) : 0;
-}
-
-/** @return The available border for resizing */
-int pixdecor_theme_t::get_border_size() const
-{
-    return (!maximized_borders && maximized) ? 0 : border_size;
-}
-
-/** @return The input area for resizing */
-int pixdecor_theme_t::get_input_size() const
-{
-    return std::max(get_border_size(), MIN_RESIZE_HANDLE_SIZE);
-}
-
-wf::color_t pixdecor_theme_t::get_decor_color(bool active) const
-{
-    return active ? fg : bg;
-}
-
-void pixdecor_theme_t::set_maximize(bool state)
-{
-    maximized = state;
-}
-
-/**
- * Fill the given rectangle with the background color(s).
- *
- * @param fb The target framebuffer, must have been bound already
- * @param rectangle The rectangle to redraw.
- * @param scissor The GL scissor rectangle to use.
- * @param active Whether to use active or inactive colors
- */
-void pixdecor_theme_t::render_background(const wf::scene::render_instruction_t& data,
-    wf::geometry_t rectangle, bool active, wf::pointf_t p)
-{
-    if ((std::string(effect_type) == "none") && (std::string(overlay_engine) == "none"))
-    {
-        data.pass->custom_gles_subpass(data.target,[&]
-        {
-            for (auto& box : data.damage)
-            {
-                wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
-                OpenGL::render_rectangle(rectangle, get_decor_color(active), wf::gles::render_target_orthographic_projection(data.target));
-            }
-        });
-    } else
-    {
-        smoke.render_effect(data, rectangle);
-    }
-}
-
-/**
- * Render the given text on a cairo_surface_t with the given size.
- * The caller is responsible for freeing the memory afterwards.
- */
-cairo_surface_t*pixdecor_theme_t::render_text(std::string text,
-    int width, int height, int t_width, int border, int buttons_width, bool active)
-{
-    const auto format = CAIRO_FORMAT_ARGB32;
-    auto surface = cairo_image_surface_create(format, width, height);
-
-    if (height == 0)
-    {
-        return surface;
-    }
-
-    auto cr = cairo_create(surface);
-
-    PangoFontDescription *font_desc;
-    PangoLayout *layout;
-    int x, w, h;
-
-    // render text
-    font_desc = get_font_description();
-
-    layout = pango_cairo_create_layout(cr);
-    pango_layout_set_font_description(layout, font_desc);
-    pango_layout_set_text(layout, text.c_str(), text.size());
-    cairo_set_source_rgba(cr, active ? fg_text.r : bg_text.r, active ? fg_text.g : bg_text.g,
-        active ? fg_text.b : bg_text.b, 1);
-    pango_layout_get_pixel_size(layout, &w, &h);
-    switch (int(title_text_align))
-    {
-      // left
-      case 0:
-        x = border;
-        break;
-
-      // right
-      case 2:
-        x = t_width - (w + buttons_width + border);
-        break;
-
-      // center
-      case 1:
-      default:
-        x = (t_width - w) / 2;
-        break;
-    }
-
-    cairo_translate(cr, x, (height - h) / 2);
-    pango_cairo_show_layout(cr, layout);
-    g_object_unref(layout);
-    cairo_destroy(cr);
-
-    return surface;
-}
-
-cairo_surface_t*pixdecor_theme_t::get_button_surface(button_type_t button,
-    const button_state_t& state, bool active) const
-{
-    cairo_surface_t *button_surface = NULL;
-
-    switch (button)
-    {
-      case BUTTON_CLOSE:
-        if (!std::string(button_close_image).empty())
-        {
-            button_surface = cairo_image_surface_create_from_png(std::string(button_close_image).c_str());
-        }
-
-        break;
-
-      case BUTTON_TOGGLE_MAXIMIZE:
-        if (!std::string(button_maximize_image).empty())
-        {
-            button_surface = cairo_image_surface_create_from_png(std::string(button_maximize_image).c_str());
-        }
-
-        break;
-
-      case BUTTON_MINIMIZE:
-        if (!std::string(button_minimize_image).empty())
-        {
-            button_surface = cairo_image_surface_create_from_png(std::string(button_minimize_image).c_str());
-        }
-
-        break;
-
-      default:
-        break;
-    }
-
-    if (button_surface && (cairo_surface_status(button_surface) == CAIRO_STATUS_SUCCESS))
-    {
-        return button_surface;
-    }
-
-    auto w = state.width;
-    auto h = state.height;
-
-    button_surface = cairo_image_surface_create(
-        CAIRO_FORMAT_ARGB32, w, h);
-
-    auto cr = cairo_create(button_surface);
-    cairo_set_antialias(cr, CAIRO_ANTIALIAS_DEFAULT);
-
-    cairo_set_operator(cr, CAIRO_OPERATOR_CLEAR);
-    cairo_set_source_rgba(cr, 0, 0, 0, 0);
-    cairo_rectangle(cr, 0, 0, w, h);
-    cairo_fill(cr);
-
-    cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
-
-    /** Draw the button  */
-    cairo_set_line_cap(cr, CAIRO_LINE_CAP_ROUND);
-    cairo_set_source_rgba(cr,
-        wf::color_t(button_color).r,
-        wf::color_t(button_color).g,
-        wf::color_t(button_color).b,
-        wf::color_t(button_color).a);
-    double line_width = button_line_thickness;
-    switch (button)
-    {
-      case BUTTON_CLOSE:
-        cairo_set_line_width(cr, line_width * state.border);
-        cairo_move_to(cr, 1.0 * w / 4.0,
-            1.0 * h / 4.0);
-        cairo_line_to(cr, 3.0 * w / 4.0,
-            3.0 * h / 4.0);
-        cairo_move_to(cr, 3.0 * w / 4.0,
-            1.0 * h / 4.0);
-        cairo_line_to(cr, 1.0 * w / 4.0,
-            3.0 * h / 4.0);
-        cairo_stroke(cr);
-        break;
-
-      case BUTTON_TOGGLE_MAXIMIZE:
-        cairo_set_line_width(cr, line_width * state.border);
-        cairo_rectangle(cr, w / 4.0, h / 4.0, w / 2.0, h / 2.0);
-        cairo_stroke(cr);
-        break;
-
-      case BUTTON_MINIMIZE:
-        cairo_set_line_width(cr, line_width * state.border);
-        cairo_move_to(cr, 1.0 * w / 4.0,
-            3.0 * h / 4.0);
-        cairo_line_to(cr, 3.0 * w / 4.0,
-            3.0 * h / 4.0);
-        cairo_stroke(cr);
-        break;
-
-      default:
-        assert(false);
-    }
-
-    cairo_destroy(cr);
-
-    return button_surface;
-}
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-theme.hpp wayfire-plugins-extra/subprojects/pixdecor/src/deco-theme.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/deco-theme.hpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/deco-theme.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,102 +0,0 @@
-#pragma once
-#include <gio/gio.h>
-#include <wayfire/render-manager.hpp>
-#include "deco-button.hpp"
-#include "deco-effects.hpp"
-
-#define MIN_RESIZE_HANDLE_SIZE 5
-#define LARGE_ICON_THRESHOLD 20
-#define MIN_BAR_HEIGHT 20
-
-namespace wf
-{
-namespace pixdecor
-{
-/**
- * A  class which manages the outlook of decorations.
- * It is responsible for determining the background colors, sizes, etc.
- */
-class pixdecor_theme_t
-{
-  public:
-    wf::option_wrapper_t<std::string> title_font{"pixdecor/title_font"};
-    wf::option_wrapper_t<std::string> overlay_engine{"pixdecor/overlay_engine"};
-    wf::option_wrapper_t<std::string> effect_type{"pixdecor/effect_type"};
-    wf::option_wrapper_t<bool> maximized_borders{"pixdecor/maximized_borders"};
-    wf::option_wrapper_t<bool> maximized_shadows{"pixdecor/maximized_shadows"};
-    wf::option_wrapper_t<int> title_text_align{"pixdecor/title_text_align"};
-    /** Create a new theme with the default parameters */
-    pixdecor_theme_t();
-    ~pixdecor_theme_t();
-
-    /** @return The height of the system font in pixels */
-    int get_font_height_px();
-    /** @return The available height for displaying the title */
-    int get_title_height();
-    /** @return The available border for rendering */
-    int get_border_size() const;
-    /** @return The available border for resizing */
-    int get_input_size() const;
-    /** @return The decoration color */
-    wf::color_t get_decor_color(bool active) const;
-    PangoFontDescription *create_font_description();
-    PangoFontDescription *get_font_description();
-
-    void update_colors(void);
-
-    /**
-     * Fill the given rectangle with the background color(s).
-     *
-     * @param fb The target framebuffer, must have been bound already.
-     * @param rectangle The rectangle to redraw.
-     * @param scissor The GL scissor rectangle to use.
-     * @param active Whether to use active or inactive colors
-     */
-    void render_background(const wf::scene::render_instruction_t& data,
-        wf::geometry_t rectangle, bool active, wf::pointf_t p);
-
-    /**
-     * Render the given text on a cairo_surface_t with the given size.
-     * The caller is responsible for freeing the memory afterwards.
-     */
-    cairo_surface_t *render_text(std::string text, int width, int height, int t_width, int border,
-        int buttons_width, bool active);
-
-    struct button_state_t
-    {
-        /** Button width */
-        double width;
-        /** Button height */
-        double height;
-        /** Button outline size */
-        double border;
-        /* Hovering... */
-        bool hover;
-    };
-
-    /** background effects */
-    smoke_t smoke;
-
-    /**
-     * Get the icon for the given button.
-     * The caller is responsible for freeing the memory afterwards.
-     *
-     * @param button The button type.
-     * @param state The button state.
-     */
-    cairo_surface_t *get_button_surface(button_type_t button,
-        const button_state_t& state, bool active) const;
-
-    void set_maximize(bool state);
-
-  private:
-
-    GSettings *gs;
-    wf::color_t fg;
-    wf::color_t bg;
-    wf::color_t fg_text;
-    wf::color_t bg_text;
-    bool maximized;
-};
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/meson.build wayfire-plugins-extra/subprojects/pixdecor/src/meson.build
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/meson.build	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/meson.build	1969-12-31 17:00:00.000000000 -0700
@@ -1,5 +0,0 @@
-pixdecor = shared_module('pixdecor',
-        ['decoration.cpp', 'deco-subsurface.cpp', 'deco-button.cpp', 'deco-layout.cpp', 'deco-theme.cpp', 'deco-effects.cpp'],
-        dependencies: [wayfire],
-        install: true,
-        install_dir: join_paths(get_option('libdir'), 'wayfire'))
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/shade.hpp wayfire-plugins-extra/subprojects/pixdecor/src/shade.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/shade.hpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/shade.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,290 +0,0 @@
-#pragma once
-
-#include <wayfire/output.hpp>
-#include <wayfire/opengl.hpp>
-#include <wayfire/core.hpp>
-#include <wayfire/view-transform.hpp>
-#include <wayfire/signal-definitions.hpp>
-#include <wayfire/toplevel-view.hpp>
-#include <wayfire/window-manager.hpp>
-#include <wayfire/txn/transaction-manager.hpp>
-#include <wayfire/scene-render.hpp>
-#include <wayfire/util/duration.hpp>
-
-#include "deco-subsurface.hpp"
-
-const std::string shade_transformer_name = "pixdecor_shade";
-
-namespace wf
-{
-namespace pixdecor
-{
-using namespace wf::scene;
-using namespace wf::animation;
-class shade_animation_t : public duration_t
-{
-  public:
-    using duration_t::duration_t;
-    timed_transition_t shade{*this};
-};
-class pixdecor_shade : public wf::scene::view_2d_transformer_t
-{
-    nonstd::observer_ptr<simple_decorator_t> deco = nullptr;
-    wayfire_view view;
-    wf::output_t *output;
-    int titlebar_height;
-    wf::option_wrapper_t<wf::animation_description_t> shade_duration{"pixdecor/shade_duration"};
-
-  public:
-    bool last_direction;
-    shade_animation_t progression{shade_duration};
-    class simple_node_render_instance_t : public wf::scene::transformer_render_instance_t<transformer_base_node_t>
-    {
-        wf::signal::connection_t<node_damage_signal> on_node_damaged =
-            [=] (node_damage_signal *ev)
-        {
-            push_to_parent(ev->region);
-        };
-
-        pixdecor_shade *self;
-        wayfire_view view;
-        damage_callback push_to_parent;
-
-      public:
-        simple_node_render_instance_t(pixdecor_shade *self, damage_callback push_damage,
-            wayfire_view view) : wf::scene::transformer_render_instance_t<transformer_base_node_t>(self,
-                push_damage,
-                view->get_output())
-        {
-            this->self = self;
-            this->view = view;
-            this->push_to_parent = push_damage;
-            self->connect(&on_node_damaged);
-        }
-
-        ~simple_node_render_instance_t()
-        {}
-
-        void schedule_instructions(
-            std::vector<render_instruction_t>& instructions,
-            const wf::render_target_t& target, wf::region_t& damage)
-        {
-            // We want to render ourselves only, the node does not have children
-            instructions.push_back(render_instruction_t{
-                        .instance = this,
-                        .target   = target,
-                        .damage   = damage & self->get_bounding_box(),
-                    });
-        }
-
-        void render(const wf::scene::render_instruction_t& data)
-        {
-            auto src_box = self->get_children_bounding_box();
-            gl_geometry src_geometry = {(float)src_box.x, (float)src_box.y,
-                (float)src_box.x + src_box.width, (float)src_box.y + src_box.height};
-            auto src_tex = wf::scene::transformer_render_instance_t<transformer_base_node_t>::get_texture(
-                1.0);
-            auto shade_region = data.damage;
-            int height    = src_box.height;
-            auto titlebar = self->titlebar_height + self->get_shadow_margin();
-            src_box.y += self->titlebar_height;
-            src_box.height *= 1.0 -
-                (self->progression.shade *
-                    ((src_box.height - titlebar) / float(src_box.height)));
-            auto progress_height = src_box.height;
-            shade_region &= wf::region_t{src_box};
-            wf::gles::run_in_context([&]
-            {
-                wf::gles::bind_render_buffer(data.target);
-                data.pass->custom_gles_subpass(data.target,[&]
-                {
-                    for (const auto& box : shade_region)
-                    {
-                        wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
-                        OpenGL::render_transformed_texture(wf::gles_texture_t{src_tex},
-                        {src_geometry.x1, src_geometry.y1 - (height - progress_height), src_geometry.x2,
-                            src_geometry.y2 - (height - progress_height)}, {},
-                            wf::gles::render_target_orthographic_projection(data.target), glm::vec4(1.0), 0);
-                    }
-                });
-
-                shade_region = data.damage;
-                src_box = self->get_children_bounding_box();
-                src_box.height = self->titlebar_height;
-                shade_region  &= wf::region_t{src_box};
-                //for (const auto& box : shade_region)
-                //{
-                //    target.logic_scissor(wlr_box_from_pixman_box(box));
-                data.pass->custom_gles_subpass(data.target,[&]
-                {
-                    for (const auto& box : shade_region)
-                    {
-                        wf::gles::render_target_logic_scissor(data.target, wlr_box_from_pixman_box(box));
-                        OpenGL::render_transformed_texture(wf::gles_texture_t{src_tex}, src_geometry, {},
-                            wf::gles::render_target_orthographic_projection(data.target), glm::vec4(1.0), 0);
-                    }
-                });
-
-            });
-        }
-    };
-
-    pixdecor_shade(wayfire_view view, int titlebar_height) : wf::scene::view_2d_transformer_t(view)
-    {
-        this->view   = view;
-        this->output = view->get_output();
-        this->titlebar_height = titlebar_height;
-        this->progression.shade.set(0.0, 1.0);
-        if (output)
-        {
-            output->render->add_effect(&pre_hook, wf::OUTPUT_EFFECT_PRE);
-        }
-
-        if (auto toplevel = wf::toplevel_cast(view))
-        {
-            this->deco = toplevel->toplevel()->get_data<simple_decorator_t>();
-        }
-    }
-
-    void pop_transformer(wayfire_view view)
-    {
-        if (view->get_transformed_node()->get_transformer(shade_transformer_name))
-        {
-            view->get_transformed_node()->rem_transformer(shade_transformer_name);
-        }
-
-        if (!deco && view->has_data(custom_data_name))
-        {
-            view->erase_data(custom_data_name);
-        }
-    }
-
-    wf::effect_hook_t pre_hook = [=] ()
-    {
-        if (auto toplevel = wf::toplevel_cast(view))
-        {
-            if (deco)
-            {
-                /* SSD */
-                deco->get_margins(toplevel->toplevel()->pending());
-            } else
-            {
-                /* CSD */
-                auto bg = view->get_surface_root_node()->get_bounding_box();
-                auto vg = toplevel->get_geometry();
-                auto margins =
-                    wf::decoration_margins_t{vg.x - bg.x, vg.y - bg.y,
-                    bg.width - ((vg.x - bg.x) + vg.width), bg.height - ((vg.y - bg.y) + vg.height)};
-                if (view->has_data(custom_data_name))
-                {
-                    view->get_data<wf_shadow_margin_t>(custom_data_name)->set_margins(
-                        {0, 0, 0,
-                            int(((toplevel->get_geometry().height + margins.bottom) - titlebar_height) *
-                                progression.shade)});
-                } else
-                {
-                    view->store_data(std::make_unique<wf_shadow_margin_t>(), custom_data_name);
-                    view->get_data<wf_shadow_margin_t>(custom_data_name)->set_margins(
-                        {0, 0, 0,
-                            int(((toplevel->get_geometry().height + margins.bottom) - titlebar_height) *
-                                progression.shade)});
-                }
-            }
-        }
-
-        view->damage();
-        if (!this->progression.running() && !last_direction)
-        {
-            if (output)
-            {
-                output->render->rem_effect(&pre_hook);
-            }
-
-            pop_transformer(view);
-        }
-    };
-
-    void gen_render_instances(std::vector<render_instance_uptr>& instances,
-        damage_callback push_damage, wf::output_t *shown_on) override
-    {
-        instances.push_back(std::make_unique<simple_node_render_instance_t>(
-            this, push_damage, view));
-    }
-
-    std::optional<wf::scene::input_node_t> find_node_at(const wf::pointf_t& at) override
-    {
-        auto bbox = this->get_children_bounding_box();
-        if (((at.y - bbox.y) <
-             ((1.0 -
-               (this->progression.shade * ((bbox.height - this->titlebar_height) / float(bbox.height)))) *
-              bbox.height)) &&
-            ((at.y - bbox.y) > 0.0))
-        {
-            return floating_inner_node_t::find_node_at(at);
-        }
-
-        return {};
-    }
-
-    void init_animation(bool shade)
-    {
-        if (shade == last_direction)
-        {
-            return;
-        }
-
-        if (this->progression.running())
-        {
-            this->progression.reverse();
-        } else
-        {
-            if ((shade && !this->progression.get_direction()) ||
-                (!shade && this->progression.get_direction()))
-            {
-                this->progression.reverse();
-            }
-
-            this->progression.start();
-        }
-
-        last_direction = shade;
-    }
-
-    void set_titlebar_height(int titlebar_height)
-    {
-        this->titlebar_height = titlebar_height;
-    }
-
-    int get_shadow_margin()
-    {
-        if (deco)
-        {
-            return deco->shadow_thickness;
-        } else
-        {
-            if (auto toplevel = wf::toplevel_cast(view))
-            {
-                auto bg = view->get_surface_root_node()->get_bounding_box();
-                auto vg = toplevel->get_geometry();
-                return bg.height - ((vg.y - bg.y) + vg.height);
-            }
-        }
-
-        return 0;
-    }
-
-    bool get_direction()
-    {
-        return this->last_direction;
-    }
-
-    virtual ~pixdecor_shade()
-    {
-        if (output)
-        {
-            output->render->rem_effect(&pre_hook);
-        }
-    }
-};
-}
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/smoke-shaders.hpp wayfire-plugins-extra/subprojects/pixdecor/src/smoke-shaders.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/pixdecor/src/smoke-shaders.hpp	2025-07-13 14:56:04.000000000 -0600
+++ wayfire-plugins-extra/subprojects/pixdecor/src/smoke-shaders.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,445 +0,0 @@
-static const char *motion_source =
-    R"(
-#version 320 es
-
-precision lowp image2D;
-
-layout (binding = 1, r32f) uniform readonly image2D in_b0u;
-layout (binding = 1, r32f) uniform writeonly image2D out_b0u;
-layout (binding = 2, r32f) uniform readonly image2D in_b0v;
-layout (binding = 2, r32f) uniform writeonly image2D out_b0v;
-layout (binding = 3, r32f) uniform readonly image2D in_b0d;
-layout (binding = 3, r32f) uniform writeonly image2D out_b0d;
-layout (local_size_x = 1, local_size_y = 1, local_size_z = 1) in;
-
-layout(location = 1) uniform int title_height;
-layout(location = 2) uniform int border_size;
-layout(location = 3) uniform int px;
-layout(location = 4) uniform int py;
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 7) uniform int rand1;
-layout(location = 8) uniform int rand2;
-layout(location = 9) uniform int radius;
-
-void motion(int x, int y)
-{
-	int i, i0, i1, j, j0, j1, d = 2;
-
-	if (x - d < 1)
-		i0 = 1;
-	else
-		i0 = x - d;
-	if (i0 + 2 * d > width - 1)
-		i1 = width - 1;
-	else
-		i1 = i0 + 2 * d;
-
-	if (y - d < 1)
-		j0 = 1;
-	else
-		j0 = y - d;
-	if (j0 + 2 * d > height - 1)
-		j1 = height - 1;
-	else
-		j1 = j0 + 2 * d;
-
-	for (i = i0; i < i1; i++)
-	{
-		for (j = j0; j < j1; j++) {
-			if (i < radius || j < radius || i > (width - 1) - radius || j > (height - 1) - radius || (i > border_size && i < (width - 1) - border_size && j > (title_height - 1) && j < (height - 1) - border_size))
-			{
-				continue;
-			}
-			vec4 b0u = imageLoad(in_b0u, ivec2(i, j));
-			vec4 b0v = imageLoad(in_b0v, ivec2(i, j));
-			vec4 b0d = imageLoad(in_b0d, ivec2(i, j));
-			float u = b0u.x;
-			float v = b0v.x;
-			float d = b0d.x;
-			imageStore(out_b0u, ivec2(i, j), vec4(u + float(256 - (rand1 & 512)), 0.0, 0.0, 0.0));
-			imageStore(out_b0v, ivec2(i, j), vec4(v + float(256 - (rand2 & 512)), 0.0, 0.0, 0.0));
-			imageStore(out_b0d, ivec2(i, j), vec4(d + 1.0, 0.0, 0.0, 0.0));
-		}
-	}
-}
-
-void main()
-{
-    motion(px, py);
-}
-)";
-
-// Generic smoke shader beginning
-static const char *smoke_header =
-    R"(
-#version 320 es
-
-precision lowp image2D;
-
-layout (binding = 0, rgba32f) uniform readonly image2D in_tex;
-layout (binding = 0, rgba32f) uniform writeonly image2D out_tex;
-layout (binding = 1, r32f) uniform readonly image2D in_b0u;
-layout (binding = 1, r32f) uniform writeonly image2D out_b0u;
-layout (binding = 2, r32f) uniform readonly image2D in_b0v;
-layout (binding = 2, r32f) uniform writeonly image2D out_b0v;
-layout (binding = 3, r32f) uniform readonly image2D in_b0d;
-layout (binding = 3, r32f) uniform writeonly image2D out_b0d;
-layout (binding = 4, r32f) uniform readonly image2D in_b1u;
-layout (binding = 4, r32f) uniform writeonly image2D out_b1u;
-layout (binding = 5, r32f) uniform readonly image2D in_b1v;
-layout (binding = 5, r32f) uniform writeonly image2D out_b1v;
-layout (binding = 6, r32f) uniform readonly image2D in_b1d;
-layout (binding = 6, r32f) uniform writeonly image2D out_b1d;
-layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-layout(location = 5) uniform int width;
-layout(location = 6) uniform int height;
-layout(location = 10) uniform int regionInfo[20];
-)";
-
-// Generic main method for a compute shader which runs for a particular region
-static const char *effect_run_for_region_main =
-    R"(
-void main()
-{
-    ivec2 pos = ivec2(gl_GlobalInvocationID.xy);
-    int z = int(gl_GlobalInvocationID.z);
-
-    ivec4 myRegion = ivec4(regionInfo[z * 5], regionInfo[z * 5 + 1], regionInfo[z * 5 + 2], regionInfo[z * 5 + 3]);
-    if (regionInfo[z * 5 + 4] > 0)
-    {
-        pos = pos.yx;
-    }
-
-    if (all(lessThan(pos, myRegion.zw)))
-    {
-        pos += myRegion.xy;
-        run_pixel(pos.x, pos.y);
-    }
-})";
-
-static const char *diffuse1_source =
-    R"(
-void run_pixel(int x, int y)
-{
-	int k;
-	float t, a = 0.0002;
-
-	vec4 s = imageLoad(in_b0u, ivec2(x, y));
-	vec4 d1 = imageLoad(in_b1u, ivec2(x - 1, y));
-	vec4 d2 = imageLoad(in_b1u, ivec2(x + 1, y));
-	vec4 d3 = imageLoad(in_b1u, ivec2(x, y - 1));
-	vec4 d4 = imageLoad(in_b1u, ivec2(x, y + 1));
-	float sx = s.x;
-	float du1 = d1.x;
-	float du2 = d2.x;
-	float du3 = d3.x;
-	float du4 = d4.x;
-	float t1 = du1 + du2 + du3 + du4;
-	s = imageLoad(in_b0v, ivec2(x, y));
-	d1 = imageLoad(in_b1v, ivec2(x - 1, y));
-	d2 = imageLoad(in_b1v, ivec2(x + 1, y));
-	d3 = imageLoad(in_b1v, ivec2(x, y - 1));
-	d4 = imageLoad(in_b1v, ivec2(x, y + 1));
-	float sy = s.x;
-	du1 = d1.x;
-	du2 = d2.x;
-	du3 = d3.x;
-	du4 = d4.x;
-	float t2 = du1 + du2 + du3 + du4;
-	imageStore(out_b1u, ivec2(x, y), vec4((sx + a * t1) / (1.0 + 4.0 * a) * 0.995, 0.0, 0.0, 0.0));
-	imageStore(out_b1v, ivec2(x, y), vec4((sy + a * t2) / (1.0 + 4.0 * a) * 0.995, 0.0, 0.0, 0.0));
-}
-)";
-
-static const char *project1_source =
-    R"(
-void run_pixel(int x, int y) {
-	int k, l, s;
-	float h;
-
-	h = 1.0 / float(width);
-	s = width;
-
-	vec4 s1 = imageLoad(in_b1u, ivec2(x - 1, y));
-	vec4 s2 = imageLoad(in_b1u, ivec2(x + 1, y));
-	vec4 s3 = imageLoad(in_b1v, ivec2(x, y - 1));
-	vec4 s4 = imageLoad(in_b1v, ivec2(x, y + 1));
-	float u1 = s1.x;
-	float u2 = s2.x;
-	float v1 = s3.x;
-	float v2 = s4.x;
-	imageStore(out_b0u, ivec2(x, y), vec4(0.0, 0.0, 0.0, 0.0));
-	imageStore(out_b0v, ivec2(x, y), vec4(-0.5 * h * (u2 - u1 + v2 - v1), 0.0, 0.0, 0.0));
-}
-)";
-
-static const char *project2_source =
-    R"(
-void run_pixel(int x, int y)
-{
-	int k, l, s;
-	float h;
-
-	h = 1.0 / float(width);
-	s = width;
-
-	vec4 s0 = imageLoad(in_b0v, ivec2(x, y));
-	vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
-	vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
-	vec4 s3 = imageLoad(in_b0u, ivec2(x, y - 1));
-	vec4 s4 = imageLoad(in_b0u, ivec2(x, y + 1));
-	float u1 = s1.x;
-	float u2 = s2.x;
-	float u3 = s3.x;
-	float u4 = s4.x;
-	imageStore(out_b0u, ivec2(x, y), vec4((s0.x + u1 + u2 + u3 + u4) / 4.0, 0.0, 0.0, 0.0));
-})";
-
-static const char *project3_source =
-    R"(
-void run_pixel(int x, int y)
-{
-	int k, l, s;
-	float h;
-
-	h = 1.0 / float(width);
-	s = width;
-
-	vec4 s0x = imageLoad(in_b1u, ivec2(x, y));
-	vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
-	vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
-	vec4 s0y = imageLoad(in_b1v, ivec2(x, y));
-	vec4 s3 = imageLoad(in_b0u, ivec2(x, y - 1));
-	vec4 s4 = imageLoad(in_b0u, ivec2(x, y + 1));
-	float su = s0x.x;
-	float u1 = s1.x;
-	float u2 = s2.x;
-	float sv = s0y.x;
-	float u3 = s3.x;
-	float u4 = s4.x;
-	imageStore(out_b1u, ivec2(x, y), vec4(su - 0.5 * (u2 - u1) / h, 0.0, 0.0, 0.0));
-	imageStore(out_b1v, ivec2(x, y), vec4(sv - 0.5 * (u4 - u3) / h, 0.0, 0.0, 0.0));
-})";
-
-static const char *advect1_source =
-    R"(
-void run_pixel(int x, int y) /* b1.u, b1.v, b1.u, b0.u */
-{
-	int stride;
-	int i, j;
-	float fx, fy;
-	stride = width;
-
-	vec4 sx = imageLoad(in_b1u, ivec2(x, y));
-	vec4 sy = imageLoad(in_b1v, ivec2(x, y));
-	float ix = float(x) - sx.x;
-	float iy = float(y) - sy.x;
-	if (ix < 0.5)
-		ix = 0.5;
-	if (iy < 0.5)
-		iy = 0.5;
-	if (ix > float(width) - 1.5)
-		ix = float(width) - 1.5;
-	if (iy > float(height) - 1.5)
-		iy = float(height) - 1.5;
-	i = int(ix);
-	j = int(iy);
-	fx = ix - float(i);
-	fy = iy - float(j);
-	vec4 s0x = imageLoad(in_b1u, ivec2(i,     j));
-	vec4 s1x = imageLoad(in_b1u, ivec2(i + 1, j));
-	vec4 s2x = imageLoad(in_b1u, ivec2(i,     j + 1));
-	vec4 s3x = imageLoad(in_b1u, ivec2(i + 1, j + 1));
-	float p1 = (s0x.x * (1.0 - fx) + s1x.x * fx) * (1.0 - fy) + (s2x.x * (1.0 - fx) + s3x.x * fx) * fy;
-	imageStore(out_b0u, ivec2(x, y), vec4(p1, 0.0, 0.0, 0.0));
-	ix = float(x) - sx.x;
-	iy = float(y) - sy.x;
-	if (ix < 0.5)
-		ix = 0.5;
-	if (iy < 0.5)
-		iy = 0.5;
-	if (ix > float(width) - 1.5)
-		ix = float(width) - 1.5;
-	if (iy > float(height) - 1.5)
-		iy = float(height) - 1.5;
-	i = int(ix);
-	j = int(iy);
-	fx = ix - float(i);
-	fy = iy - float(j);
-	vec4 s0y = imageLoad(in_b1v, ivec2(i,     j));
-	vec4 s1y = imageLoad(in_b1v, ivec2(i + 1, j));
-	vec4 s2y = imageLoad(in_b1v, ivec2(i,     j + 1));
-	vec4 s3y = imageLoad(in_b1v, ivec2(i + 1, j + 1));
-	float p2 = (s0y.x * (1.0 - fx) + s1y.x * fx) * (1.0 - fy) + (s2y.x * (1.0 - fx) + s3y.x * fx) * fy;
-	imageStore(out_b0v, ivec2(x, y), vec4(p2, 0.0, 0.0, 0.0));
-})";
-
-static const char *project4_source =
-    R"(
-void run_pixel(int x, int y)
-{
-	int k, l, s;
-	float h;
-
-	h = 1.0 / float(width);
-	s = width;
-
-	vec4 s1 = imageLoad(in_b0u, ivec2(x - 1, y));
-	vec4 s2 = imageLoad(in_b0u, ivec2(x + 1, y));
-	vec4 s3 = imageLoad(in_b0v, ivec2(x, y - 1));
-	vec4 s4 = imageLoad(in_b0v, ivec2(x, y + 1));
-	float u1 = s1.x;
-	float u2 = s2.x;
-	float v1 = s3.x;
-	float v2 = s4.x;
-	imageStore(out_b1u, ivec2(x, y), vec4(0.0, 0.0, 0.0, 0.0));
-	imageStore(out_b1v, ivec2(x, y), vec4(-0.5 * h * (u2 - u1 + v2 - v1), 0.0, 0.0, 0.0));
-})";
-
-static const char *project5_source =
-    R"(
-void run_pixel(int x, int y)
-{
-	int k, l, s;
-	float h;
-
-	h = 1.0 / float(width);
-	s = width;
-
-	vec4 s0 = imageLoad(in_b1v, ivec2(x, y));
-	vec4 s1 = imageLoad(in_b1u, ivec2(x - 1, y));
-	vec4 s2 = imageLoad(in_b1u, ivec2(x + 1, y));
-	vec4 s3 = imageLoad(in_b1u, ivec2(x, y - 1));
-	vec4 s4 = imageLoad(in_b1u, ivec2(x, y + 1));
-	float u1 = s1.x;
-	float u2 = s2.x;
-	float u3 = s3.x;
-	float u4 = s4.x;
-	imageStore(out_b1u, ivec2(x, y), vec4((s0.x + u1 + u2 + u3 + u4) / 4.0, 0.0, 0.0, 0.0));
-})";
-
-static const char *project6_source =
-    R"(
-void run_pixel(int x, int y)
-{
-	int k, l, s;
-	float h;
-
-	h = 1.0 / float(width);
-	s = width;
-
-	vec4 s0x = imageLoad(in_b0u, ivec2(x, y));
-	vec4 s1 = imageLoad(in_b1u, ivec2(x - 1, y));
-	vec4 s2 = imageLoad(in_b1u, ivec2(x + 1, y));
-	vec4 s0y = imageLoad(in_b0v, ivec2(x, y));
-	vec4 s3 = imageLoad(in_b1u, ivec2(x, y - 1));
-	vec4 s4 = imageLoad(in_b1u, ivec2(x, y + 1));
-	float su = s0x.x;
-	float u1 = s1.x;
-	float u2 = s2.x;
-	float sv = s0y.x;
-	float u3 = s3.x;
-	float u4 = s4.x;
-	imageStore(out_b0u, ivec2(x, y), vec4(su - 0.5 * (u2 - u1) / h, 0.0, 0.0, 0.0));
-	imageStore(out_b0v, ivec2(x, y), vec4(sv - 0.5 * (u4 - u3) / h, 0.0, 0.0, 0.0));
-})";
-
-static const char *diffuse2_source =
-    R"(
-void run_pixel(int x, int y)
-{
-	int k, stride;
-	float t, a = 0.0002;
-	stride = width;
-
-	vec4 s = imageLoad(in_b0d, ivec2(x, y));
-	vec4 d1 = imageLoad(in_b1d, ivec2(x - 1, y));
-	vec4 d2 = imageLoad(in_b1d, ivec2(x + 1, y));
-	vec4 d3 = imageLoad(in_b1d, ivec2(x, y - 1));
-	vec4 d4 = imageLoad(in_b1d, ivec2(x, y + 1));
-	float sz = s.x;
-	float du1 = d1.x;
-	float du2 = d2.x;
-	float du3 = d3.x;
-	float du4 = d4.x;
-	t = du1 + du2 + du3 + du4;
-	imageStore(out_b1d, ivec2(x, y), vec4((sz + a * t) / (1.0 + 4.0 * a) * 0.995, 0.0, 0.0, 0.0));
-})";
-
-static const char *advect2_source =
-    R"(
-void run_pixel(int x, int y) /*b0u, b0v, b1d, b0d*/
-{
-	int stride;
-	int i, j;
-	float fx, fy;
-	stride = width;
-
-	vec4 sx = imageLoad(in_b0u, ivec2(x, y));
-	vec4 sy = imageLoad(in_b0v, ivec2(x, y));
-	float ix = float(x) - sx.x;
-	float iy = float(y) - sy.x;
-	if (ix < 0.5)
-		ix = 0.5;
-	if (iy < 0.5)
-		iy = 0.5;
-	if (ix > float(width) - 1.5)
-		ix = float(width) - 1.5;
-	if (iy > float(height) - 1.5)
-		iy = float(height) - 1.5;
-	i = int(ix);
-	j = int(iy);
-	fx = ix - float(i);
-	fy = iy - float(j);
-	vec4 s0z = imageLoad(in_b1d, ivec2(i,     j));
-	vec4 s1z = imageLoad(in_b1d, ivec2(i + 1, j));
-	vec4 s2z = imageLoad(in_b1d, ivec2(i,     j + 1));
-	vec4 s3z = imageLoad(in_b1d, ivec2(i + 1, j + 1));
-	float p1 = (s0z.x * (1.0 - fx) + s1z.x * fx) * (1.0 - fy) + (s2z.x * (1.0 - fx) + s3z.x * fx) * fy;
-	imageStore(out_b0d, ivec2(x, y), vec4(p1, 0.0, 0.0, 0.0));
-})";
-
-static const char *render_source =
-    R"(
-#version 320 es
-
-precision lowp image2D;
-
-layout (binding = 0, rgba32f) uniform writeonly image2D out_tex;
-layout (binding = 3, r32f) uniform readonly image2D in_b0d;
-layout (local_size_x = 16, local_size_y = 16, local_size_z = 1) in;
-
-layout(location = 4) uniform bool ink;
-layout(location = 8) uniform vec4 smoke_color;
-layout(location = 9) uniform vec4 decor_color;
-layout(location = 10) uniform int regionInfo[20];
-
-void run_pixel(int x, int y)
-{
-	float c, r, g, b, a;
-
-	vec4 s = imageLoad(in_b0d, ivec2(x, y));
-	c = s.x * 800.0;
-	if (c > 255.0)
-		c = 255.0;
-	a = c;
-	vec3 color;
-	if (ink)
-	{
-		if (c > 2.0)
-			color = mix(decor_color.rgb, smoke_color.rgb, clamp(a, 0.0, 1.0));
-		else
-			color = mix(decor_color.rgb, vec3(0.0, 0.0, 0.0), clamp(a, 0.0, 1.0));
-		if (c > 1.5)
-			imageStore(out_tex, ivec2(x, y), vec4(color, 1.0));
-		else
-			imageStore(out_tex, ivec2(x, y), decor_color);
-		return;
-	} else
-	{
-		color = mix(decor_color.rgb, smoke_color.rgb, clamp(a, 0.0, 1.0));
-	}
-	imageStore(out_tex, ivec2(x, y), vec4(color, decor_color.a));
-})";
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/.gitignore wayfire-plugins-extra/subprojects/wayfire-shadows/.gitignore
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/.gitignore	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/.gitignore	1969-12-31 17:00:00.000000000 -0700
@@ -1,2 +0,0 @@
-build
-.cache
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/LICENSE wayfire-plugins-extra/subprojects/wayfire-shadows/LICENSE
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/LICENSE	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/LICENSE	1969-12-31 17:00:00.000000000 -0700
@@ -1,21 +0,0 @@
-The MIT License (MIT)
-
-Copyright (c) 2021 Tim Göttlicher
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/meson.build wayfire-plugins-extra/subprojects/wayfire-shadows/meson.build
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/meson.build	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/meson.build	1969-12-31 17:00:00.000000000 -0700
@@ -1,49 +0,0 @@
-project(
-	'wayfire-plugin-winshadows',
-    'c',
-	'cpp',
-	version: '0.1',
-	license: 'MIT',
-	meson_version: '>=0.51.0',
-	default_options: [
-		'cpp_std=c++17',
-        'c_std=c11',
-		'warning_level=2',
-		'werror=false',
-	],
-)
-
-wayfire  = dependency('wayfire')
-wfconfig = dependency('wf-config')
-
-add_project_arguments(['-DWLR_USE_UNSTABLE'], language: ['cpp', 'c'])
-add_project_arguments(['-DWAYFIRE_PLUGIN'], language: ['cpp', 'c'])
-add_project_link_arguments(['-rdynamic'], language:'cpp')
-
-shadows = shared_module(
-    'winshadows', [
-        'winshadows.cpp',
-        'node.cpp',
-        'renderer.cpp',
-        'shaders.glsl.cpp',
-    ],
-
-    dependencies: [
-        wfconfig,
-        wayfire
-    ],
-
-    install: true,
-    install_dir: join_paths( get_option( 'libdir' ), 'wayfire' )
-)
-
-install_data( 'winshadows.xml', install_dir: wayfire.get_variable( pkgconfig: 'metadatadir' ) )
-
-summary = [
-	'',
-	'----------------',
-	'wayfire-plugin-winshadows @0@'.format( meson.project_version() ),
-	'----------------',
-	''
-]
-message('\n'.join(summary))
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/node.cpp wayfire-plugins-extra/subprojects/wayfire-shadows/node.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/node.cpp	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/node.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,70 +0,0 @@
-#include "node.hpp"
-
-namespace winshadows {
-
-shadow_node_t::shadow_node_t( wayfire_toplevel_view view ): wf::scene::node_t(false) {
-    this->view = view;
-    on_geometry_changed.set_callback([this] (auto) {
-        update_geometry();
-    });
-    on_activated_changed.set_callback([this] (auto) {
-        this->view->damage();
-    });
-    view->connect(&on_geometry_changed);
-    view->connect(&on_activated_changed);
-    update_geometry();
-}
-
-shadow_node_t::~shadow_node_t() {
-    view->disconnect(&on_geometry_changed);
-}
-
-wf::geometry_t shadow_node_t::get_bounding_box()  {
-    return geometry;
-}
-
-void shadow_node_t::gen_render_instances(std::vector<wf::scene::render_instance_uptr> &instances, wf::scene::damage_callback push_damage, wf::output_t *output) {
-    // define renderer
-    class shadow_render_instance_t : public wf::scene::simple_render_instance_t<shadow_node_t> {
-      public:
-        using simple_render_instance_t::simple_render_instance_t;
-        void render(const wf::scene::render_instruction_t& data ) override
-        {
-            // coordinates relative to view origin (not bounding box origin)
-            wf::point_t frame_origin = self->frame_offset;
-            wf::region_t paint_region = self->shadow_region + frame_origin;
-            paint_region &= data.damage;
-
-            for (const auto& box : paint_region)
-
-            {
-                self->shadow.render(data, frame_origin, wlr_box_from_pixman_box(box) , self->view->activated);
-            }
-            self->_was_activated = self->view->activated;
-        }
-    };
-
-    instances.push_back(std::make_unique<shadow_render_instance_t>(this, push_damage, output));
-}
-
-void shadow_node_t::update_geometry() {
-    wf::geometry_t frame_geometry = view->get_geometry();
-    shadow.resize(frame_geometry.width, frame_geometry.height);
-
-    // TODO: Check whether this can be done in a nicer/easier way
-    wf::pointf_t view_origin_f = view->get_surface_root_node()->to_global({0, 0}); 
-    wf::point_t view_origin {(int)view_origin_f.x, (int)view_origin_f.y};
-
-    // Offset between view origin and frame top left corner
-    frame_offset = wf::origin(frame_geometry) - view_origin;
-
-    // Shadow geometry is relative to the top left corner of the frame (not the view)
-    wf::geometry_t shadow_geometry = shadow.get_geometry();
-
-    // move to view-relative coordinates
-    geometry = shadow_geometry + frame_offset;
-
-    this->shadow_region = shadow.calculate_region();
-}
-
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/node.hpp wayfire-plugins-extra/subprojects/wayfire-shadows/node.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/node.hpp	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/node.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,46 +0,0 @@
-#pragma once
-
-#include <wayfire/geometry.hpp>
-#include <wayfire/scene.hpp>
-#include <wayfire/scene-render.hpp>
-#include <wayfire/core.hpp>
-#include <wayfire/signal-definitions.hpp>
-#include <wayfire/toplevel-view.hpp>
-#include "renderer.hpp"
-
-namespace winshadows {
-
-class shadow_node_t : public wf::scene::node_t {
-  private:
-    int _was_activated = 1; // used to check whether redrawing on focus is necessary
-
-    // geometry of the node relative to the view origin
-    wf::geometry_t geometry;
-
-    // offset between the node origin and the frame origin (i.e. top-left borders)
-    wf::point_t frame_offset;
-
-    wayfire_toplevel_view view;
-
-    int width = 100, height = 100;
-    wf::region_t shadow_region;
-    shadow_renderer_t shadow;
-
-    wf::signal::connection_t<wf::view_geometry_changed_signal> on_geometry_changed;
-    wf::signal::connection_t<wf::view_activated_state_signal> on_activated_changed;
-
-    void update_geometry();
-
-  public:
-    shadow_node_t(wayfire_toplevel_view view);
-
-    virtual ~shadow_node_t();
-
-    void gen_render_instances(std::vector<wf::scene::render_instance_uptr> &instances, wf::scene::damage_callback push_damage, wf::output_t *output = nullptr) override;
-
-    wf::geometry_t get_bounding_box() override;
-
-};
-
-}
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/README.md wayfire-plugins-extra/subprojects/wayfire-shadows/README.md
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/README.md	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/README.md	1969-12-31 17:00:00.000000000 -0700
@@ -1,76 +0,0 @@
-# winshadows
-
-### Window Shadows Plugin for Wayfire
-
-This is a plugin for wayfire that adds window shadows. The code was initially a
-fork of <https://gitlab.com/wayfireplugins/windecor> but only a small part of
-that remains in the code.
-
-## Screenshots
-
-By default, the plugin will add fast and nice shadows around windows that use server side decorations. Additionally there is an option to make the focused window glow.
-
-![image](https://github.com/timgott/wayfire-shadows/assets/18331942/94d27159-573c-4613-8bf6-4527502539f5)
-
-<details>
-<summary>Config used in screenshot</summary>
-
-```ini
-[decoration]
-active_color = \#7A98BA76
-border_size = 4
-inactive_color = \#20201838
-title_height = 0
-
-[winshadows]
-glow_enabled = true
-shadow_radius = 50
-vertical_offset = 10
-horizontal_offset = 5
-# remaining values are default
-
-```
-</details>
-
-## Install
-
-1. Get the sources
-   ```bash
-   git clone https://github.com/timgott/wayfire-shadows.git
-   cd wayfire-shadows
-   ```
-2. ⚠️ Switch to the backport0.7 branch if you use wayfire version 0.7 (last stable release)
-   ```bash
-   git checkout backport0.7 # (if necessary)
-   ```
-3. Configure with meson and build & install with ninja.
-   ```bash
-   meson build --buildtype=release
-   cd build
-   # meson configure --prefix=... # if wayfire is not installed in /usr/local
-   ninja
-   sudo ninja install
-   ```
-
-## Install with [wfplug](https://github.com/timgott/wfplug)
-
-As above, you have to change the branch on wayfire 0.7.
-
-```bash
-# enable wfplug
-source ~/wfplug/activate  # edit path if necessary
-
-# get plugin
-wfplug-goto-plugins
-git clone https://github.com/timgott/wayfire-shadows.git winshadows
-
-# build and install to wfplug
-wfplug-build winshadows
-```
-
-Try a testconfig with
-
-```bash
-wfplug-test winshadows bluelight
-```
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/renderer.cpp wayfire-plugins-extra/subprojects/wayfire-shadows/renderer.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/renderer.cpp	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/renderer.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,220 +0,0 @@
-#include <random>
-#include <wayfire/geometry.hpp>
-#include <wayfire/toplevel.hpp>
-#include "renderer.hpp"
-
-namespace winshadows {
-
-shadow_renderer_t::shadow_renderer_t() {
-        wf::gles::run_in_context([&]
-        {
-    generate_dither_texture();
-    recompile_shaders();
-    });
-
-    light_type_option.set_callback([this] () {
-        recompile_shaders();
-    });
-}
-
-void shadow_renderer_t::recompile_shaders() {
-        wf::gles::run_in_context([&]
-        {
-    shadow_program.free_resources();
-    shadow_glow_program.free_resources();
-
-    shadow_program.set_simple(
-        OpenGL::compile_program(shadow_vert_shader, frag_shader(light_type_option, /*no glow*/ false))
-    );
-    shadow_glow_program.set_simple(
-        OpenGL::compile_program(shadow_vert_shader, frag_shader(light_type_option, /*glow*/ true))
-    );
-
-    });
-}
-
-void shadow_renderer_t::generate_dither_texture() {
-    const int size = 32;
-    GLuint data[size*size];
-
-    std::mt19937_64 gen{std::random_device{}()};
-    std::uniform_int_distribution<GLuint> distrib;
-
-    for (int i = 0; i < size*size; i++) {
-        data[i] = distrib(gen);
-    }
-
-    GL_CALL(glGenTextures(1, &dither_texture));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, dither_texture));
-    GL_CALL(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, size, size, 0, GL_RGBA, GL_UNSIGNED_BYTE, data));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT));
-    GL_CALL(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT));
-}
-
-shadow_renderer_t::~shadow_renderer_t() {
-        wf::gles::run_in_context([&]
-        {
-    shadow_program.free_resources();
-    shadow_glow_program.free_resources();
-
-    GL_CALL(glDeleteTextures(1, &dither_texture));
-
-    });
-}
-
-void shadow_renderer_t::render(const wf::scene::render_instruction_t& data, wf::point_t window_origin, const wf::geometry_t& scissor, const bool glow) {
-    float radius = shadow_radius_option;
-
-    wf::color_t color = shadow_color_option;
-
-    // Premultiply alpha for shader
-    glm::vec4 premultiplied = {
-        color.r * color.a,
-        color.g * color.a,
-        color.b * color.a,
-        color.a
-    };
-
-    // Glow color, alpha=0 => additive blending (exploiting premultiplied alpha)
-    wf::color_t glow_color = glow_color_option;
-    glm::vec4 glow_premultiplied = {
-        glow_color.r * glow_color.a,
-        glow_color.g * glow_color.a,
-        glow_color.b * glow_color.a,
-        glow_color.a * (1.0 - glow_emissivity_option)
-    };
-
-    // Enable glow shader only when glow radius > 0 and view is focused
-    bool use_glow = (glow && is_glow_enabled());
-    OpenGL::program_t &program = 
-        use_glow ? shadow_glow_program : shadow_program;
-
-            data.pass->custom_gles_subpass(data.target,[&]
-            {
-
-                wf::gles::render_target_logic_scissor(data.target, scissor);
-    program.use(wf::TEXTURE_TYPE_RGBA);
-
-    // Compute vertex rectangle geometry
-    wf::geometry_t bounds = outer_geometry + window_origin;
-    float left = bounds.x;
-    float right = bounds.x + bounds.width;
-    float top = bounds.y;
-    float bottom = bounds.y + bounds.height;
-
-    GLfloat vertexData[] = {
-        left, bottom,
-        right, bottom,
-        right, top,
-        left, top
-    };
-
-    glm::mat4 matrix = wf::gles::render_target_orthographic_projection(data.target);
-
-    // vertex parameters
-    program.attrib_pointer("position", 2, 0, vertexData);
-    program.uniformMatrix4f("MVP", matrix);
-
-    // fragment parameters
-    program.uniform1f("radius", radius);
-    program.uniform4f("color", premultiplied);
-
-    const auto inner = window_geometry + window_origin;
-    const auto shadow_inner = shadow_projection_geometry + window_origin;
-    program.uniform2f("lower", shadow_inner.x, shadow_inner.y);
-    program.uniform2f("upper", shadow_inner.x + shadow_inner.width, shadow_inner.y + shadow_inner.height);
-
-    if (use_glow) {
-        program.uniform2f("glow_lower", inner.x, inner.y);
-        program.uniform2f("glow_upper", inner.x + inner.width, inner.y + inner.height);
-
-        program.uniform1f("glow_spread", glow_spread_option);
-        program.uniform4f("glow_color", glow_premultiplied);
-        program.uniform1f("glow_intensity",  glow_intensity_option);
-        program.uniform1f("glow_threshold",  glow_threshold_option);
-    }
-
-    // dither texture
-    program.uniform1i("dither_texture", 0);
-    GL_CALL(glActiveTexture(GL_TEXTURE0));
-    GL_CALL(glBindTexture(GL_TEXTURE_2D, dither_texture));
-
-    GL_CALL(glEnable(GL_BLEND));
-    GL_CALL(glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA));
-    GL_CALL(glDrawArrays(GL_TRIANGLE_FAN, 0, 4));
-
-    program.deactivate();
-    });
-}
-
-wf::region_t shadow_renderer_t::calculate_region() const {
-    // TODO: geometry and region depending on whether glow is active or not
-    wf::region_t region = wf::region_t(shadow_geometry) | wf::region_t(glow_geometry);
-
-    if (clip_shadow_inside) {
-        region ^= window_geometry;
-    }
-
-    return region;
-}
-
-wf::geometry_t shadow_renderer_t::get_geometry() const {
-    return outer_geometry;
-}
-
-wf::geometry_t expand_geometry(const wf::geometry_t& geometry, const int marginX, const int marginY) {
-    return {
-        geometry.x - marginX,
-        geometry.y - marginY,
-        geometry.width + marginX * 2,
-        geometry.height + marginY * 2
-    };
-}
-
-wf::geometry_t expand_geometry(const wf::geometry_t& geometry, const int margin) {
-    return expand_geometry(geometry, margin, margin);
-}
-
-wf::geometry_t inflate_geometry(const wf::geometry_t& geometry, const float inflation) {
-    int expandX = geometry.width * inflation * 0.5;
-    int expandY = geometry.height * inflation * 0.5;
-    return expand_geometry(geometry, expandX, expandY);
-}
-
-void shadow_renderer_t::resize(const int window_width, const int window_height) {
-    window_geometry = {
-        0,
-        0,
-        window_width,
-        window_height
-    };
-
-    float overscale = overscale_option / 100.0;
-    const wf::point_t offset { horizontal_offset, vertical_offset };
-    shadow_projection_geometry =
-        inflate_geometry(window_geometry, overscale) + offset;
-
-    shadow_geometry = expand_geometry(shadow_projection_geometry, shadow_radius_option);
-
-    int glow_radius = is_glow_enabled() ? glow_radius_limit_option : 0;
-    glow_geometry = expand_geometry(shadow_projection_geometry, glow_radius);
-
-    int left = std::min(shadow_geometry.x, glow_geometry.x);
-    int top = std::min(shadow_geometry.y, glow_geometry.y);
-    int right = std::max(shadow_geometry.x + shadow_geometry.width, glow_geometry.x + glow_geometry.width);
-    int bottom = std::max(shadow_geometry.y + shadow_geometry.height, glow_geometry.y + glow_geometry.height);
-    outer_geometry = {
-        left,
-        top,
-        right - left,
-        bottom - top
-    };
-}
-
-bool shadow_renderer_t::is_glow_enabled() const {
-    return glow_enabled_option && (glow_radius_limit_option > 0) && (glow_intensity_option > 0);
-}
-
-}
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/renderer.hpp wayfire-plugins-extra/subprojects/wayfire-shadows/renderer.hpp
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/renderer.hpp	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/renderer.hpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,59 +0,0 @@
-#pragma once
-#include <wayfire/option-wrapper.hpp>
-#include <wayfire/opengl.hpp>
-#include <wayfire/region.hpp>
-#include <wayfire/scene.hpp>
-#include <wayfire/scene-render.hpp>
-
-namespace winshadows {
-/**
- * A  class that can render shadows.
- * It manages the shader and calculates the necessary padding.
- */
-class shadow_renderer_t {
-    public:
-        shadow_renderer_t();
-        ~shadow_renderer_t();
-
-        void recompile_shaders();
-        void render(const wf::scene::render_instruction_t& data, wf::point_t origin, const wf::geometry_t& scissor, const bool glow);
-        void resize(const int width, const int height);
-        wf::region_t calculate_region() const;
-        wf::geometry_t get_geometry() const;
-        bool is_glow_enabled() const;
-
-    private:
-        OpenGL::program_t shadow_program;
-        OpenGL::program_t shadow_glow_program;
-        GLuint dither_texture;
-        void generate_dither_texture();
-
-        wf::geometry_t glow_geometry;
-        wf::geometry_t shadow_geometry;
-        wf::geometry_t shadow_projection_geometry; // projected window geometry
-        wf::geometry_t outer_geometry;
-        wf::geometry_t window_geometry;
-        wlr_box calculate_padding(const wf::geometry_t window_geometry) const;
-
-        wf::option_wrapper_t<wf::color_t> shadow_color_option { "winshadows/shadow_color" };
-        wf::option_wrapper_t<int> shadow_radius_option { "winshadows/shadow_radius" };
-        wf::option_wrapper_t<bool> clip_shadow_inside { "winshadows/clip_shadow_inside" };
-        wf::option_wrapper_t<int> vertical_offset { "winshadows/vertical_offset" };
-        wf::option_wrapper_t<int> horizontal_offset { "winshadows/horizontal_offset" };
-        wf::option_wrapper_t<std::string> light_type_option { "winshadows/light_type" };
-        wf::option_wrapper_t<double> overscale_option { "winshadows/overscale" };
-
-        wf::option_wrapper_t<bool> glow_enabled_option { "winshadows/glow_enabled" };
-        wf::option_wrapper_t<wf::color_t> glow_color_option { "winshadows/glow_color" };
-        wf::option_wrapper_t<double> glow_emissivity_option { "winshadows/glow_emissivity" };
-        wf::option_wrapper_t<double> glow_spread_option { "winshadows/glow_spread" };
-        wf::option_wrapper_t<double> glow_intensity_option { "winshadows/glow_intensity" };
-        wf::option_wrapper_t<double> glow_threshold_option { "winshadows/glow_threshold" };
-        wf::option_wrapper_t<int> glow_radius_limit_option { "winshadows/glow_radius_limit" };
-
-        static const std::string shadow_vert_shader;
-        const std::string frag_shader(const std::string &light_type, const bool glow);
-};
-
-}
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/shaders.glsl.cpp wayfire-plugins-extra/subprojects/wayfire-shadows/shaders.glsl.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/shaders.glsl.cpp	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/shaders.glsl.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,272 +0,0 @@
-// GLSL as cpp string constant (.glsl extension for syntax highlighting)
-#include "renderer.hpp"
-
-
-/* Vertex shader */
-
-const std::string winshadows::shadow_renderer_t::shadow_vert_shader = 
-R"(
-#version 300 es
-
-in mediump vec2 position;
-out mediump vec2 uvpos;
-
-uniform mat4 MVP;
-
-void main() {
-    gl_Position = MVP * vec4(position.xy, 0.0, 1.0);
-    uvpos = position.xy;
-})";
-
-
-
-/* Base fragment shader definitions */
-
-const std::string flag_define(const std::string& name, const bool value) {
-    return "#define " + name + " " + (value? "1" : "0") + "\n";
-}
-
-const std::string frag_header(const std::string& light_type, const bool glow) {
-    return
-      "#version 300 es\n" +
-      flag_define("CIRCULAR_SHADOW", light_type == "circular") +
-      flag_define("GAUSSIAN_SHADOW", light_type == "gaussian") +
-      flag_define("SQUARE_SHADOW", light_type == "square") +
-      flag_define("GLOW", glow);
-}
-
-// All definitions are inserted in the shader, the shader compiler will remove unused ones
-const std::string frag_body =
-R"(
-precision highp float;
-in vec2 uvpos;
-out vec4 fragColor;
-uniform vec2 lower;
-uniform vec2 upper;
-uniform vec4 color;
-
-uniform float radius;
-
-uniform sampler2D dither_texture;
-
-/* Gaussian shadow */
-
-// Adapted from http://madebyevan.com/shaders/fast-rounded-rectangle-shadows/
-// License: CC0 (http://creativecommons.org/publicdomain/zero/1.0/)
-// This approximates the error function, needed for the gaussian integral
-vec4 erf(vec4 x) {
-  vec4 s = sign(x), a = abs(x);
-  x = 1.0 + (0.278393 + (0.230389 + 0.078108 * (a * a)) * a) * a;
-  x *= x;
-  return s - s / (x * x);
-}
-
-// Computes a gaussian convolution of a box from lower to upper
-float boxGaussian(vec2 lower, vec2 upper, vec2 point, float sigma) {
-  vec4 query = vec4(lower - point, upper - point);
-  vec4 integral = 0.5 + 0.5 * erf(query * (sqrt(0.5) / sigma));
-  return (integral.z - integral.x) * (integral.w - integral.y);
-}
-
-
-/* Circular shadow */
-
-// Antiderivative of sqrt(1-x^2)
-float circleIntegral(float x) {
-  return (sqrt(1.0-x*x)*x+asin(x)) / 2.0;
-}
-
-#define M_PI 3.14159265358
-
-float circleSegment(float dist) {
-  return sqrt(1.0-dist*dist);
-}
-
-// assuming fullArea is the area of two parts of a circle cut by a horizontal stripe
-// (top and bottom are the cut lines)
-// compute the remaining area when cut vertically at right
-float circleMinusWall(float top, float bottom, float right, float fullArea) {
-  if (right <= -1.0) {
-    return fullArea; // entire circle
-  } else if (right >= 1.0) {
-    return 0.0; // nothing
-  } else {
-    // compute circle segment half width
-    float w = circleSegment(right);
-    // circle segment area
-    float segmentTop = max(top, -w);
-    float segmentBottom = min(bottom, w);
-    float area = circleIntegral(segmentBottom) - circleIntegral(segmentTop) - (segmentBottom - segmentTop) * abs(right);
-    if (right < 0.0) {
-      return fullArea - area;
-    } else {
-      return area;
-    }
-  }
-}
-
-// Circle-rectangle overlap
-// circle is at (0,0) radius 1
-// only one top-left corner of rectangle is considered (assume rectangle >> circle)
-float circleOverlap(vec2 lower, vec2 upper) {
-  // left/right half integral with vertical bounds
-  float top = max(lower.y, -1.0);
-  float bottom = min(upper.y, 1.0);
-  float inner = 2.0 * (circleIntegral(bottom) - circleIntegral(top));
-  // left/right outer integrals for horizontal bounds
-  float outerLeft = circleMinusWall(top, bottom, -lower.x, inner);
-  float outerRight = circleMinusWall(top, bottom, upper.x, inner);
-  return (inner - outerLeft - outerRight) / M_PI;
-}
-
-// Shadow of rectangle under circular area light
-float circularLightShadow(vec2 lower, vec2 upper, vec2 point, float radius) {
-  vec4 query = vec4(lower - point, upper - point) / radius;
-  return max(circleOverlap(query.st, query.pq), 0.0);
-}
-
-// Shadow of rectangle under square area light
-float squareShadow(vec2 lower, vec2 upper, vec2 point, float radius) {
-  vec2 squareLower = point - radius;
-  vec2 squareUpper = point + radius;
-  vec2 overlapLower = max(lower, squareLower);
-  vec2 overlapUpper = min(upper, squareUpper);
-  vec2 overlap = max(overlapUpper - overlapLower, 0.0);
-  float maxArea = radius * radius * 4.0;
-  return overlap.x * overlap.y / maxArea; // area
-}
-
-
-/* Glow */
-
-uniform vec4 glow_color;
-uniform float glow_spread;
-uniform vec2 glow_lower;
-uniform vec2 glow_upper;
-
-uniform float glow_intensity;
-uniform float glow_threshold;
-
-/* Inverse quartic falloff */
-
-vec2 invQrtIntegralPartial(float xmin, float xmax, vec2 y, float z) {
-  // Rectangle integral over 1/(x^2+y^2+1)^2
-  // Computed using FriCAS:
-  //   formatExpression(integrate(integrate(1/((x^2+y^2+z^2)^2), x=a..b, "noPole"), y))$Format1D
-  // Then some rewriting to make it valid glsl and simplified a bit
-
-  float a = xmin;
-  float b = xmax;
-
-  float zsqr = z*z;
-  float s1 = zsqr+a*a;
-  float s2 = zsqr+b*b;
-  vec2 s3 = zsqr+y*y;
-  float t1 = sqrt(s1);
-  float t2 = sqrt(s2);
-  vec2 t3 = sqrt(s3);
-
-  return (y*t1*t2*t3*(atan((b*t3)/(s3))-atan((a*t3)/(s3)))+(zsqr+y*y)*(b*t1*atan((y*t2)/(s2))+(-a)*t2*atan((y*t1)/(s1))))/((2.0*zsqr*(1.0+y*y*zsqr))*t1*t2);
-}
-
-float boxInvQrtFalloff(vec2 lower, vec2 upper, vec2 point, float scale) {
-  vec4 query = vec4(lower - point, upper - point) / scale;
-  vec2 integralBounds = invQrtIntegralPartial(query.x, query.z, query.yw, 1.0);
-  return (integralBounds.y - integralBounds.x);
-}
-
-
-/* Inverse square falloff, but only vertically and horizontally */
-
-float orthoInvSqrFalloff(vec2 lower, vec2 upper, vec2 point, float scale) {
-  // f = (x^2+1)^(-1)
-  // F = arctan(x)
-  vec4 query = vec4(lower - point, upper - point) / scale;
-  vec4 integral = atan(query);
-  return (integral.z - integral.x) * (integral.w - integral.y);
-}
-
-
-/* Inverse square falloff, but only 1d based on distance to window edge */
-
-float distInvSqrFalloff(vec2 lower, vec2 upper, vec2 point, float scale) {
-  vec4 offsets = vec4(lower - point, point - upper) / scale;
-  float a = max(max(offsets.x, offsets.z), 0.0);
-  float b = max(max(offsets.y, offsets.w), 0.0);
-  float dsqr = a*a + b*b;
-  float invsqr = 1.0 / (dsqr + 1.0);
-  return invsqr;//invsqr.x*invsqr.z * invsqr.y*invsqr.w;
-}
-
-
-/* Inverse square falloff integral over window edges (neon) */
-
-vec4 barInvSqrFalloffIntegral(vec4 t, vec4 d, float z) {
-  // FriCAS: integrate(1/(t^2+d^2+z^2), t)
-  vec4 rsqr = d*d+z*z;
-  vec4 r = sqrt(rsqr);
-  return atan(t * r / rsqr) / r;
-}
-
-vec4 barInvCubicFalloffIntegral(vec4 t, vec4 d, float z) {
-  // FriCAS: integrate(1/(t^2+d^2+z^2)^(3/2), t)
-  vec4 rsqr = t*t+d*d+z*z;
-  vec4 r = sqrt(rsqr);
-  return -1.0/(t*r-rsqr);
-}
-
-float edgeInvSqrGlow(vec2 lower, vec2 upper, vec2 point, float scale) {
-  // distance to edge left, top, right, bottom
-  vec4 edgeDists = vec4(lower - point, upper - point);
-  vec4 integralLower = barInvSqrFalloffIntegral(edgeDists.tsts, edgeDists, scale);
-  vec4 integralUpper = barInvSqrFalloffIntegral(edgeDists.qpqp, edgeDists, scale);
-
-  vec4 integral = integralUpper - integralLower;
-  return (integral.s + integral.t + integral.p + integral.q);
-}
-
-float lightThreshold(float x, float minThreshold) {
-    return max(x - minThreshold, 0.0);
-}
-
-vec4 dither(vec2 pos) {
-    vec2 size = vec2(textureSize(dither_texture, 0));
-    return texture(dither_texture, pos / size) / 256.0 - 0.5 / 256.0;
-}
-
-vec4 shadow_color()
-{
-#if CIRCULAR_SHADOW
-    return color * circularLightShadow(lower, upper, uvpos, radius);
-#elif SQUARE_SHADOW
-    return color * squareShadow(lower, upper, uvpos, radius);
-#else // GAUSSIAN_SHADOW
-    return color * boxGaussian(lower, upper, uvpos, radius / 2.7);
-#endif
-}
-
-/* Rectangle shadow+glow fragment shader */
-
-void main()
-{
-#if GLOW
-    float glow_value = edgeInvSqrGlow(glow_lower, glow_upper, uvpos, glow_spread), glow_neon_threshold;
-    //float glow_value = boxInvQrtFalloff(glow_lower, glow_upper, uvpos, glow_spread);
-    //float glow_value = boxGaussian(glow_lower, glow_upper, uvpos, glow_spread)
-    //float glow_value = distInvSqrFalloff(glow_lower, glow_upper, uvpos, glow_spread);
-    //float glow_value = orthoInvSqrFalloff(glow_lower, glow_upper, uvpos, glow_spread);
-    vec4 out_color =
-        shadow_color() +
-        glow_intensity * glow_color * lightThreshold(glow_value, glow_threshold);
-#else
-    vec4 out_color = shadow_color();
-#endif
-    out_color += dither(uvpos + lower*upper);
-    fragColor = out_color;
-}
-
-)";
-
-const std::string winshadows::shadow_renderer_t::frag_shader(const std::string &light_type, const bool glow) {
-    return frag_header(light_type, glow) + frag_body;
-}
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/bluelight.ini wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/bluelight.ini
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/bluelight.ini	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/bluelight.ini	1969-12-31 17:00:00.000000000 -0700
@@ -1,76 +0,0 @@
-# shadows + glow + decoration
-
-[winshadows]
-clip_shadow_inside = true
-glow_color = \#3584E4FF
-glow_enabled = true
-glow_intensity = 0.5
-glow_radius_limit = 150
-glow_spread = 8.0
-glow_threshold = 0.03
-horizontal_offset = 5
-vertical_offset = 10
-shadow_color = \#00000078
-shadow_radius = 80
-
-[decoration]
-active_color = \#7A98BA76
-border_size = 4
-inactive_color = \#20201838
-title_height = 0
-
-[core]
-
-plugins = \
-  winshadows \
-  autostart \
-  command \
-  decoration \
-  move \
-  resize \
-  place \
-  vswitch \
-  follow-focus
-
-# Close focused window.
-close_top_view = <ctrl> KEY_Q
-
-# server-side decorations to make testing decorations easier
-preferred_decoration_mode = server
-
-xwayland = false
-
-
-# Startup commands ─────────────────────────────────────────────────────────────
-[autostart]
-
-# Disable panel, dock and default background
-autostart_wf_shell = false
-
-# Background might be useful if you are testing decorations
-background = swaybg --color "\#322d3d"
-
-# Start some terminal windows for testing here!
-test1 = sh -c "alacritty || foot || gnome-terminal"
-test2 = sh -c "alacritty || foot || gnome-terminal"
-
-# Bindings ───────────────────────────────────────────────────────────────
-[command]
-
-# Start a terminal
-binding_terminal = <ctrl> KEY_ENTER
-command_terminal = sh -c "alacritty || foot || gnome-terminal"
-
-# Drag windows by holding down Super and left mouse button.
-[move]
-activate = <ctrl> BTN_LEFT
-
-# Resize them with right mouse button + Super.
-[resize]
-activate = <ctrl> BTN_RIGHT
-
-
-# Place windows randomly
-[place]
-mode = random
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/circular.ini wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/circular.ini
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/circular.ini	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/circular.ini	1969-12-31 17:00:00.000000000 -0700
@@ -1,71 +0,0 @@
-# extreme circle
-
-[winshadows]
-clip_shadow_inside = true
-glow_color = \#3584E4FF
-glow_enabled = false
-glow_intensity = 0.5
-glow_radius_limit = 150
-glow_spread = 8.0
-glow_threshold = 0.03
-horizontal_offset = 100
-vertical_offset = 100
-shadow_color = \#000000FF
-shadow_radius = 100
-light_type = circular
-
-[core]
-
-plugins = \
-  winshadows \
-  autostart \
-  command \
-  move \
-  resize \
-  place \
-  vswitch \ 
-  follow-focus
-
-# Close focused window.
-close_top_view = <ctrl> KEY_Q
-
-# server-side decorations to make testing decorations easier
-preferred_decoration_mode = server
-
-xwayland = false
-
-# Background might be useful if you are testing decorations
-background_color = \#FFFFFFFF
-
-
-# Startup commands ─────────────────────────────────────────────────────────────
-[autostart]
-
-# Disable panel, dock and default background
-autostart_wf_shell = false
-
-
-# Start some terminal windows for testing here!
-test1 = sh -c "alacritty || foot || gnome-terminal"
-#test2 = sh -c "alacritty || foot || gnome-terminal"
-
-# Bindings ───────────────────────────────────────────────────────────────
-[command]
-
-# Start a terminal
-binding_terminal = <ctrl> KEY_ENTER
-command_terminal = sh -c "alacritty || foot || gnome-terminal"
-
-# Drag windows by holding down Super and left mouse button.
-[move]
-activate = <ctrl> BTN_LEFT
-
-# Resize them with right mouse button + Super.
-[resize]
-activate = <ctrl> BTN_RIGHT
-
-
-# Place windows randomly
-[place]
-mode = center
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/decoborder.ini wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/decoborder.ini
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/decoborder.ini	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/decoborder.ini	1969-12-31 17:00:00.000000000 -0700
@@ -1,76 +0,0 @@
-# shadows + glow + decoration
-
-[winshadows]
-clip_shadow_inside = true
-glow_color = \#FF00FFFF
-glow_enabled = true
-glow_intensity = 2.5
-glow_radius_limit = 50
-glow_spread = 3.0
-glow_threshold = 0.00
-horizontal_offset = 5
-vertical_offset = 10
-shadow_color = \#000000FF
-shadow_radius = 80
-
-[decoration]
-active_color = \#FFFFFFFF
-border_size = 30
-inactive_color = \#999999FF
-title_height = 30
-
-[core]
-
-plugins = \
-  winshadows \
-  autostart \
-  command \
-  decoration \
-  move \
-  resize \
-  place \
-  vswitch \
-  follow-focus
-
-# Close focused window.
-close_top_view = <ctrl> KEY_Q
-
-# server-side decorations to make testing decorations easier
-preferred_decoration_mode = server
-
-xwayland = false
-
-
-# Startup commands ─────────────────────────────────────────────────────────────
-[autostart]
-
-# Disable panel, dock and default background
-autostart_wf_shell = false
-
-# Background might be useful if you are testing decorations
-background = swaybg --color "\#322d3d"
-
-# Start some terminal windows for testing here!
-test1 = sh -c "alacritty || foot || gnome-terminal"
-test2 = sh -c "alacritty || foot || gnome-terminal"
-
-# Bindings ───────────────────────────────────────────────────────────────
-[command]
-
-# Start a terminal
-binding_terminal = <ctrl> KEY_ENTER
-command_terminal = sh -c "alacritty || foot || gnome-terminal"
-
-# Drag windows by holding down Super and left mouse button.
-[move]
-activate = <ctrl> BTN_LEFT
-
-# Resize them with right mouse button + Super.
-[resize]
-activate = <ctrl> BTN_RIGHT
-
-
-# Place windows randomly
-[place]
-mode = random
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/gaussian.ini wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/gaussian.ini
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/gaussian.ini	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/gaussian.ini	1969-12-31 17:00:00.000000000 -0700
@@ -1,74 +0,0 @@
-# extreme gaussian
-
-[winshadows]
-clip_shadow_inside = true
-glow_color = \#3584E4FF
-glow_enabled = false
-glow_intensity = 0.5
-glow_radius_limit = 150
-glow_spread = 8.0
-glow_threshold = 0.03
-horizontal_offset = 100
-vertical_offset = 100
-shadow_color = \#000000FF
-shadow_radius = 100
-light_type = gaussian
-
-[core]
-
-plugins = \
-  winshadows \
-  autostart \
-  command \
-  move \
-  resize \
-  place \
-  vswitch \ 
-  follow-focus \
-  showrepaint
-
-# Close focused window.
-close_top_view = <ctrl> KEY_Q
-
-# server-side decorations to make testing decorations easier
-preferred_decoration_mode = server
-
-xwayland = false
-
-# Background might be useful if you are testing decorations
-background_color = \#FFFFFFFF
-
-
-# Startup commands ─────────────────────────────────────────────────────────────
-[autostart]
-
-# Disable panel, dock and default background
-autostart_wf_shell = false
-
-
-# Start some terminal windows for testing here!
-test1 = sh -c "alacritty || foot || gnome-terminal"
-#test2 = sh -c "alacritty || foot || gnome-terminal"
-
-# Bindings ───────────────────────────────────────────────────────────────
-[command]
-
-# Start a terminal
-binding_terminal = <ctrl> KEY_ENTER
-command_terminal = sh -c "alacritty || foot || gnome-terminal"
-
-# Drag windows by holding down Super and left mouse button.
-[move]
-activate = <ctrl> BTN_LEFT
-
-# Resize them with right mouse button + Super.
-[resize]
-activate = <ctrl> BTN_RIGHT
-
-
-# Place windows randomly
-[place]
-mode = center
-
-[showrepaint]
-toggle = <ctrl> KEY_R
\ No newline at end of file
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/glow.ini wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/glow.ini
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/glow.ini	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/glow.ini	1969-12-31 17:00:00.000000000 -0700
@@ -1,69 +0,0 @@
-# shadows and focus glow
-
-[winshadows]
-clip_shadow_inside = true
-glow_color = \#3584E4FF
-glow_enabled = true
-glow_intensity = 0.5
-glow_radius_limit = 150
-glow_spread = 8.0
-glow_threshold = 0.03
-horizontal_offset = 5
-vertical_offset = 10
-shadow_color = \#00000078
-shadow_radius = 80
-
-[core]
-
-plugins = \
-  winshadows \
-  autostart \
-  command \
-  move \
-  resize \
-  place \
-  vswitch \ 
-  follow-focus
-
-# Close focused window.
-close_top_view = <ctrl> KEY_Q
-
-# server-side decorations to make testing decorations easier
-preferred_decoration_mode = server
-
-xwayland = false
-
-
-# Startup commands ─────────────────────────────────────────────────────────────
-[autostart]
-
-# Disable panel, dock and default background
-autostart_wf_shell = false
-
-# Background might be useful if you are testing decorations
-background = swaybg --color "\#322d3d"
-
-# Start some terminal windows for testing here!
-test1 = sh -c "alacritty || foot || gnome-terminal"
-test2 = sh -c "alacritty || foot || gnome-terminal"
-
-# Bindings ───────────────────────────────────────────────────────────────
-[command]
-
-# Start a terminal
-binding_terminal = <ctrl> KEY_ENTER
-command_terminal = sh -c "alacritty || foot || gnome-terminal"
-
-# Drag windows by holding down Super and left mouse button.
-[move]
-activate = <ctrl> BTN_LEFT
-
-# Resize them with right mouse button + Super.
-[resize]
-activate = <ctrl> BTN_RIGHT
-
-
-# Place windows randomly
-[place]
-mode = random
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/minimal.ini wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/minimal.ini
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/minimal.ini	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/minimal.ini	1969-12-31 17:00:00.000000000 -0700
@@ -1,55 +0,0 @@
-# only shadows
-
-[core]
-
-plugins = \
-  winshadows \
-  autostart \
-  command \
-  move \
-  resize \
-  place \
-  vswitch
-
-# Close focused window.
-close_top_view = <ctrl> KEY_Q
-
-# server-side decorations to make testing decorations easier
-preferred_decoration_mode = server
-
-xwayland = false
-
-
-# Startup commands ─────────────────────────────────────────────────────────────
-[autostart]
-
-# Disable panel, dock and default background
-autostart_wf_shell = false
-
-# Background might be useful if you are testing decorations
-background = swaybg --color "\#322d3d"
-
-# Start some terminal windows for testing here!
-test1 = sh -c "alacritty || foot || gnome-terminal"
-test2 = sh -c "alacritty || foot || gnome-terminal"
-
-# Bindings ───────────────────────────────────────────────────────────────
-[command]
-
-# Start a terminal
-binding_terminal = <ctrl> KEY_ENTER
-command_terminal = sh -c "alacritty || foot || gnome-terminal"
-
-# Drag windows by holding down Super and left mouse button.
-[move]
-activate = <ctrl> BTN_LEFT
-
-# Resize them with right mouse button + Super.
-[resize]
-activate = <ctrl> BTN_RIGHT
-
-
-# Place windows randomly
-[place]
-mode = random
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/overscale.ini wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/overscale.ini
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/overscale.ini	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/overscale.ini	1969-12-31 17:00:00.000000000 -0700
@@ -1,73 +0,0 @@
-# extreme square
-
-[winshadows]
-clip_shadow_inside = true
-glow_color = \#3584E4FF
-glow_enabled = false
-glow_intensity = 0.5
-glow_radius_limit = 150
-glow_spread = 8.0
-glow_threshold = 0.03
-horizontal_offset = 20
-vertical_offset = 30
-shadow_color = \#00000080
-shadow_radius = 10
-light_type = gaussian
-overscale = 2.0
-
-[core]
-
-plugins = \
-  winshadows \
-  autostart \
-  command \
-  move \
-  resize \
-  place \
-  vswitch \ 
-  decoration \
-  follow-focus
-
-# Close focused window.
-close_top_view = <ctrl> KEY_Q
-
-# server-side decorations to make testing decorations easier
-preferred_decoration_mode = server
-
-xwayland = false
-
-# Background might be useful if you are testing decorations
-background_color = \#EEEEEEFF
-
-
-# Startup commands ─────────────────────────────────────────────────────────────
-[autostart]
-
-# Disable panel, dock and default background
-autostart_wf_shell = false
-
-
-# Start some terminal windows for testing here!
-test1 = sh -c "alacritty || foot || gnome-terminal"
-#test2 = sh -c "alacritty || foot || gnome-terminal"
-
-# Bindings ───────────────────────────────────────────────────────────────
-[command]
-
-# Start a terminal
-binding_terminal = <ctrl> KEY_ENTER
-command_terminal = sh -c "alacritty || foot || gnome-terminal"
-
-# Drag windows by holding down Super and left mouse button.
-[move]
-activate = <ctrl> BTN_LEFT
-
-# Resize them with right mouse button + Super.
-[resize]
-activate = <ctrl> BTN_RIGHT
-
-
-# Place windows randomly
-[place]
-mode = center
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/square.ini wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/square.ini
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/testconfig/square.ini	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/testconfig/square.ini	1969-12-31 17:00:00.000000000 -0700
@@ -1,71 +0,0 @@
-# extreme square
-
-[winshadows]
-clip_shadow_inside = true
-glow_color = \#3584E4FF
-glow_enabled = false
-glow_intensity = 0.5
-glow_radius_limit = 150
-glow_spread = 8.0
-glow_threshold = 0.03
-horizontal_offset = 100
-vertical_offset = 100
-shadow_color = \#000000FF
-shadow_radius = 100
-light_type = square
-
-[core]
-
-plugins = \
-  winshadows \
-  autostart \
-  command \
-  move \
-  resize \
-  place \
-  vswitch \ 
-  follow-focus
-
-# Close focused window.
-close_top_view = <ctrl> KEY_Q
-
-# server-side decorations to make testing decorations easier
-preferred_decoration_mode = server
-
-xwayland = false
-
-# Background might be useful if you are testing decorations
-background_color = \#FFFFFFFF
-
-
-# Startup commands ─────────────────────────────────────────────────────────────
-[autostart]
-
-# Disable panel, dock and default background
-autostart_wf_shell = false
-
-
-# Start some terminal windows for testing here!
-test1 = sh -c "alacritty || foot || gnome-terminal"
-#test2 = sh -c "alacritty || foot || gnome-terminal"
-
-# Bindings ───────────────────────────────────────────────────────────────
-[command]
-
-# Start a terminal
-binding_terminal = <ctrl> KEY_ENTER
-command_terminal = sh -c "alacritty || foot || gnome-terminal"
-
-# Drag windows by holding down Super and left mouse button.
-[move]
-activate = <ctrl> BTN_LEFT
-
-# Resize them with right mouse button + Super.
-[resize]
-activate = <ctrl> BTN_RIGHT
-
-
-# Place windows randomly
-[place]
-mode = center
-
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/winshadows.cpp wayfire-plugins-extra/subprojects/wayfire-shadows/winshadows.cpp
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/winshadows.cpp	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/winshadows.cpp	1969-12-31 17:00:00.000000000 -0700
@@ -1,129 +0,0 @@
-#include <wayfire/core.hpp>
-#include <wayfire/matcher.hpp>
-#include <wayfire/object.hpp>
-#include <wayfire/output.hpp>
-#include <wayfire/plugin.hpp>
-#include <wayfire/scene-operations.hpp>
-#include <wayfire/signal-definitions.hpp>
-#include <wayfire/signal-provider.hpp>
-#include <wayfire/view.hpp>
-#include <wayfire/workspace-set.hpp>
-
-#include "node.hpp"
-
-struct view_shadow_data : wf::custom_data_t {
-    view_shadow_data(std::shared_ptr<winshadows::shadow_node_t> shadow_ptr) : shadow_ptr(shadow_ptr) {};
-
-    std::shared_ptr<winshadows::shadow_node_t> shadow_ptr;
-};
-
-class wayfire_shadows : public wf::plugin_interface_t {
-    const std::string surface_data_name = "shadow_surface";
-
-    wf::view_matcher_t enabled_views{"winshadows/enabled_views"};
-    wf::option_wrapper_t<bool> include_undecorated_views{"winshadows/include_undecorated_views"};
-
-    // update new views
-    wf::signal::connection_t<wf::view_mapped_signal> on_view_mapped =
-        [=](auto *data) { update_view_decoration(data->view); };
-    // update when view enables or disables server side decoration
-    wf::signal::connection_t<wf::view_decoration_state_updated_signal> on_view_updated =
-        [=](auto *data) { update_view_decoration(data->view); };
-    // update on tile state change, such that it is possible to exclude tiled windows
-    wf::signal::connection_t<wf::view_tiled_signal> on_view_tiled =
-        [=](auto *data) { update_view_decoration(data->view); };
-
-public:
-    void init() override {
-            if (!wf::get_core().is_gles2())
-        {
-            LOGE("winshadows plugin requires GLES2 renderer!");
-            return;
-        }
-        wf::get_core().connect(&on_view_mapped);
-        wf::get_core().connect(&on_view_updated);
-        wf::get_core().connect(&on_view_tiled);
-
-        for (auto &view : wf::get_core().get_all_views()) {
-            update_view_decoration(view);
-        }
-    }
-
-    void fini() override {
-        wf::get_core().disconnect(&on_view_mapped);
-        wf::get_core().disconnect(&on_view_updated);
-        wf::get_core().disconnect(&on_view_tiled);
-
-        for (auto &view : wf::get_core().get_all_views()) {
-            deinit_view(view);
-        }
-    }
-
-    /**
-     * Checks whether the given view has server side decoration and is in
-     * the white list.
-     *
-     * @param view The view to match
-     * @return Whether the view should get a shadow.
-     */
-    bool is_view_shadow_enabled(wayfire_toplevel_view view) {
-        return enabled_views.matches(view) && (is_view_decorated(view) || include_undecorated_views);
-    }
-
-    bool is_view_decorated(wayfire_toplevel_view view) {
-        return view->should_be_decorated();
-    }
-
-    const wf::scene::floating_inner_ptr& get_shadow_root_node(wayfire_view view) const {
-        return view->get_surface_root_node();
-    }
-
-    wf::wl_idle_call idle_deactivate;
-    void update_view_decoration(wayfire_view view) {
-        auto toplevel = wf::toplevel_cast(view);
-        if (toplevel) {
-            if (is_view_shadow_enabled(toplevel)) {
-                auto shadow_data = view->get_data<view_shadow_data>(surface_data_name);
-                if (!shadow_data) {
-                    // No shadow yet, create it now.
-                    init_view(toplevel);
-                } else {
-                    // in some situations the shadow node might have been removed due to unmap, but the view is reused (including the custom data)
-                    auto shadow_root = get_shadow_root_node(view);
-                    if (shadow_data->shadow_ptr->parent() != shadow_root.get()) {
-                        wf::scene::add_back(shadow_root, shadow_data->shadow_ptr);
-                    }
-                }
-            } else {
-                deinit_view(view);
-            }
-        }
-    }
-
-    bool is_view_initialized(wayfire_view view) {
-        return view->has_data(surface_data_name);
-    }
-
-    void init_view(wayfire_toplevel_view view) {
-        // create the shadow node and add it to the view
-        auto node = std::make_shared<winshadows::shadow_node_t>(view);
-        wf::scene::add_back(get_shadow_root_node(view), node);
-
-        // store the shadow node in the view so we can remove it later
-        auto view_data = std::make_unique<view_shadow_data>(node);
-        view->store_data(std::move(view_data), surface_data_name);
-
-        view->damage();
-    }
-
-    void deinit_view(wayfire_view view) {
-        auto view_data = view->get_data<view_shadow_data>(surface_data_name);
-        if (view_data != nullptr) {
-            wf::scene::remove_child(view_data->shadow_ptr);
-            view->damage();
-            view->erase_data(surface_data_name);
-        }
-    }
-};
-
-DECLARE_WAYFIRE_PLUGIN(wayfire_shadows);
diff --color -Naurp wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/winshadows.xml wayfire-plugins-extra/subprojects/wayfire-shadows/winshadows.xml
--- wayfire-plugins-extra-0.10.0/subprojects/wayfire-shadows/winshadows.xml	2025-07-20 09:49:48.000000000 -0600
+++ wayfire-plugins-extra/subprojects/wayfire-shadows/winshadows.xml	1969-12-31 17:00:00.000000000 -0700
@@ -1,118 +0,0 @@
-<?xml version="1.0"?>
-<wayfire>
-	<plugin name="winshadows">
-		<_short>Window Shadows</_short>
-		<_long>Server Side Shadows for windows on Wayfire</_long>
-		<category>Effects</category>
-		<option name="enabled_views" type="string">
-			<_short>Decoration enabled for specified window types</_short>
-			<_long>Enables window shadows for windows matching the specified criteria.</_long>
-			<default>type is "toplevel" &amp; floating is true</default>
-		</option>
-		<option name="include_undecorated_views" type="bool">
-			<_short>Include windows that have their own decoration</_short>
-			<_long>Enables window shadows on windows that do not request server side decoration.</_long>
-			<default>false</default>
-		</option>
-		<option name="clip_shadow_inside" type="bool">
-			<_short>Clip to window rectangle</_short>
-			<_long>Do not draw inside the window rectangle. May look bad on rounded corners.</_long>
-			<default>true</default>
-		</option>
-		<group>
-			<_short>Shadow</_short>
-			<option name="shadow_color" type="color">
-				<_short>Shadow color</_short>
-				<_long>Color of the window shadow.</_long>
-				<default>#00000070</default>
-			</option>
-			<option name="shadow_radius" type="int">
-				<_short>Shadow radius</_short>
-				<_long>Sets the shadow radius in pixels.</_long>
-				<default>40</default>
-			</option>
-			<option name="vertical_offset" type="int">
-				<_short>Vertical offset</_short>
-				<_long>Number of pixels to shift the shadow by in vertical direction.</_long>
-				<default>5</default>
-			</option>
-			<option name="horizontal_offset" type="int">
-				<_short>Horizontal offset</_short>
-				<_long>Number of pixels to shift the shadow by in horizontal direction.</_long>
-				<default>0</default>
-			</option>
-			<option name="light_type" type="string">
-				<_short>Light type</_short>
-				<_long>Change the shape of the simulated light source. Square is the simplest shader, might be slightly faster.</_long>
-				<default>gaussian</default>
-				<desc>
-					<value>gaussian</value>
-					<_name>Gaussian</_name>
-				</desc>
-				<desc>
-					<value>circular</value>
-					<_name>Circular</_name>
-				</desc>
-				<desc>
-					<value>square</value>
-					<_name>Square</_name>
-				</desc>
-			</option>
-			<option name="overscale" type="double">
-				<_short>Overscale</_short>
-				<_long>Percentage to scale up the shadow rectangle, corresponding to a closer lamp. Also useful to increase contrast around the window a bit.</_long>
-				<default>1.0</default>
-				<precision>0.5</precision>
-			</option>
-		</group>
-		<group>
-			<_short>Glow</_short>
-			<_long>Make windows edges emit light when focused</_long>
-			<option name="glow_enabled" type="bool">
-				<_short>Focus glow</_short>
-				<_long>Show a glow effect around the focused window.</_long>
-				<default>false</default>
-			</option>
-			<option name="glow_intensity" type="double">
-				<_short>Glow intensity</_short>
-				<_long>Intensity of light emitted by the edges of the window (multiplies alpha of glow color). 0 to disable glow.</_long>
-				<default>0.6</default>
-				<min>0</min>
-				<precision>0.1</precision>
-			</option>
-			<option name="glow_color" type="color">
-				<_short>Glow color</_short>
-				<_long>Color of the glow of the focused window. Combine with a bright focus color for the window border decoration.</_long>
-				<default>#1C71D8FF</default>
-			</option>
-			<option name="glow_spread" type="double">
-				<_short>Glow spread</_short>
-				<_long>Corresponds to elevation of the window relative to the background. Higher elevation means that the light reaches a larger area more evenly but less intense.</_long>
-				<default>10</default>
-			</option>
-			<subgroup>
-				<_short>Advanced</_short>
-				<option name="glow_radius_limit" type="int">
-					<_short>Glow render distance limit</_short>
-					<_long>Size of area around window where glow is rendered, 0 to disable glow. Set this as small as possible, but without visibly clipping the glow effect into a rectangle. Depends on intensity, elevation and threshold (could be computed automatically).</_long>
-					<default>100</default>
-				</option>
-				<option name="glow_threshold" type="double">
-					<_short>Minimum light cutoff</_short>
-					<_long>Hide light below this threshold to avoid light spreading out too far. 0 is most realistic light spread, but increase slightly if the is lit area is too large.</_long>
-					<default>0.03</default>
-					<precision>0.005</precision>
-					<max>0.2</max>
-				</option>
-				<option name="glow_emissivity" type="double">
-					<_short>Glow blend factor</_short>
-					<_long>Controls the blending of the focus glow, 0 is normal blending, 1 is additive. Set to 0 for shadows and between 0 and 1 for glow effects.</_long>
-					<default>1.0</default>
-					<min>0.0</min>
-					<max>1.0</max>
-					<precision>0.1</precision>
-				</option>
-			</subgroup>
-		</group>
-	</plugin>
-</wayfire>
