Compare commits

...

58 Commits
v3 ... v5

Author SHA1 Message Date
Simon Schneegans 27fec7adea ♻️ Rename method
Deploy / Extension Bundle (push) Has been cancelled
2022-01-02 14:00:18 +01:00
Simon Schneegans 3630e461a9 📝 Tweak README 2022-01-02 13:35:40 +01:00
Simon Schneegans d14e9750cf 📝 Add list of included effects 2022-01-02 13:32:17 +01:00
Simon Schneegans d44f021348 🔀 Merge pull request #19 from Schneegans/feature/menu-button 2022-01-02 12:51:13 +01:00
Simon Schneegans 681afb4793 📝 Add changelog entry 2022-01-02 12:49:59 +01:00
Simon Schneegans 5682a5cdf8 🪲 Fix GTK3 2022-01-02 12:48:47 +01:00
Simon Schneegans 8c7e3abbeb 🎉 Add a menu button 2022-01-02 12:37:51 +01:00
Simon Schneegans 7e05588682 🔧 Tweak motto 2022-01-02 12:34:13 +01:00
Simon Schneegans 13d02da36b 🔀 Merge pull request #18 from Schneegans/feature/fix-14 2022-01-02 12:32:58 +01:00
Simon Schneegans 552dc3b0c7 📝 Fix changelog 2022-01-02 12:31:15 +01:00
Simon Schneegans 976533ccc8 🎉 Support ovierview animations in GNOME 3.36 2022-01-02 07:58:35 +01:00
Simon Schneegans 403fac3367 📝 Add changelog entry 2022-01-01 21:57:57 +01:00
Simon Schneegans b916f9677e 🔧 Do not attempt to animate window closing in the overview of GNOME 3.36 2022-01-01 21:49:31 +01:00
Simon Schneegans 4965ca8735 🔀 Merge pull request #16 from Schneegans/feature/claws 2022-01-01 21:23:12 +01:00
Simon Schneegans c9bfdc4bf9 📝 Add comment 2022-01-01 21:21:56 +01:00
Simon Schneegans 54fa765766 📝 Add changelog entry 2022-01-01 21:19:30 +01:00
Simon Schneegans 37cd1fb7cc 📝 Add plenty of comments 2022-01-01 21:18:49 +01:00
Simon Schneegans 5d845e09c1 🎨 Add claws source file 2022-01-01 20:59:21 +01:00
Simon Schneegans f758f4db82 🔧 Tweak defaults 2022-01-01 20:55:12 +01:00
Simon Schneegans b410536fc2 🎉 Make T-Rex effect configurable 2022-01-01 20:47:59 +01:00
Simon Schneegans db636a7cfe Merge branch 'main' into feature/claws 2022-01-01 20:17:51 +01:00
Simon Schneegans 8c6c1bc7bd 🪲 Fix GTK3 2022-01-01 20:16:59 +01:00
Simon Schneegans 976e713a2b 🎉 Make TV Effect color configurable 2022-01-01 20:12:41 +01:00
Simon Schneegans 7dea28a145 🔧 Reduce scaling 2022-01-01 19:51:26 +01:00
Simon Schneegans 918a12060c 🎉 Add initial T-Rex shader 2022-01-01 19:48:24 +01:00
Simon Schneegans 11a3562533 🔀 Merge pull request #15 from Schneegans/feature/tv-effect 2021-12-31 20:36:56 +01:00
Simon Schneegans 68c851c9e0 📝 Add changelog entry 2021-12-31 20:35:37 +01:00
Simon Schneegans 03db97fdda 📝 Add comments 2021-12-31 20:34:50 +01:00
Simon Schneegans 0ee171aae0 Merge branch 'main' into feature/tv-effect 2021-12-30 13:51:54 +01:00
Simon Schneegans 9c9b9657e8 🎉 Improve fire appearance 2021-12-30 13:51:14 +01:00
Simon Schneegans fdd21a44b8 🎉 Add TV Effect shader 2021-12-30 13:42:41 +01:00
Simon Schneegans cd3b91a191 🎉 Bump version number 2021-12-25 20:39:28 +01:00
Simon Schneegans 333195559d 📝 Update changelog
Deploy / Extension Bundle (push) Has been cancelled
2021-12-25 20:38:38 +01:00
Simon Schneegans b5fe644782 📝 Update changelog 2021-12-25 20:33:31 +01:00
Simon Schneegans 13201620de 🔧 Do not enable the animation for dialogs per default 2021-12-25 20:32:40 +01:00
Simon Schneegans a3711e8606 🔧 Tweak fire animation fading even more 2021-12-25 20:30:40 +01:00
Simon Schneegans 3c83f7c5bc 🔀 Merge pull request #11 from Schneegans/feature/matrix 2021-12-25 13:47:36 +01:00
Simon Schneegans cb2224ca56 🔀 Merge branch 'main' into feature/matrix 2021-12-25 13:44:18 +01:00
Simon Schneegans 49ec9d8de2 🔀 Merge pull request #10 from Schneegans/feature/dialogs 2021-12-25 13:39:18 +01:00
Simon Schneegans 9b2ef55871 🎉 Add option to also destroy dialogs 2021-12-25 13:32:15 +01:00
Simon Schneegans b0aaf402f6 💄 Tweak labels 2021-12-25 13:13:25 +01:00
Simon Schneegans aa33667cae 📝 Add note why the matrix effect is not available on GNOME 3.3x 2021-12-25 13:03:03 +01:00
Simon Schneegans c5aa8b9268 🔧 Disable matrix animation on GNOME 3.3x 2021-12-25 12:56:14 +01:00
Simon Schneegans a994a3e80d 📝 Update changelog 2021-12-24 21:16:07 +01:00
Simon Schneegans c160bb92bd 🔧 Tweak fire timing 2021-12-24 21:12:26 +01:00
Simon Schneegans d91fb2f1b4 🔧 Reduce default animation time 2021-12-24 21:11:57 +01:00
Simon Schneegans 404db45ba9 🔧 GTK3 fixes 2021-12-24 13:52:00 +01:00
Simon Schneegans 46a2f3310d 🔧 Port settings to GTK3 2021-12-24 13:22:08 +01:00
Simon Schneegans 5628545c00 📝 Add some comments 2021-12-24 13:13:56 +01:00
Simon Schneegans 9e374d04d0 🔧 Make animation type configurable 2021-12-24 13:08:45 +01:00
Simon Schneegans 32a57cc523 🎉 Make matrix effect configurable 2021-12-24 12:25:17 +01:00
Simon Schneegans ca024872db 🔧 Tweak matrix shader 2021-12-23 20:56:54 +01:00
Simon Schneegans 547db3a2b8 🎉 Add initial matrix shader 2021-12-22 21:34:03 +01:00
Simon Schneegans 75b803d523 🪲 Fix preferences dialog 2021-12-22 12:30:04 +01:00
Simon Schneegans 9f27626c72 📝 Update changelog 2021-12-22 05:56:32 +01:00
Simon Schneegans a338a2f1b2 📝 Add some comments 2021-12-22 05:54:58 +01:00
Simon Schneegans 3149371a04 🚚 Move fire shader to its own file 2021-12-22 05:40:42 +01:00
Simon Schneegans e32b11a010 🎉 Bump version number 2021-12-20 20:34:55 +01:00
25 changed files with 2145 additions and 190 deletions
+1 -1
View File
@@ -30,7 +30,7 @@ burn-my-windows@schneegans.github.com.zip: schemas/gschemas.compiled resources/b
@echo "Packing zip file..."
@rm --force burn-my-windows@schneegans.github.com.zip
@zip -r burn-my-windows@schneegans.github.com.zip -- *.js resources/burn-my-windows.gresource schemas/gschemas.compiled metadata.json LICENSE
@zip -r burn-my-windows@schneegans.github.com.zip -- *.js src/*/*.js resources/burn-my-windows.gresource schemas/gschemas.compiled metadata.json LICENSE
@#Check if the zip size is too big to be uploaded
@if [[ "$$(stat -c %s burn-my-windows@schneegans.github.com.zip)" -gt 4096000 ]]; then \
+9 -5
View File
@@ -1,8 +1,4 @@
<p align="center">
<img src ="docs/pics/teaser.gif" />
</p>
# Set your Windows on Fire!
# Set GNOME Shell on Fire!
<a href="https://github.com/Schneegans/Burn-My-Windows/actions"><img src="https://github.com/Schneegans/Burn-My-Windows/workflows/Checks/badge.svg?branch=main" /></a>
<a href="LICENSE"><img src="https://img.shields.io/badge/License-GPLv3-blue.svg?labelColor=303030" /></a>
@@ -11,6 +7,14 @@
When I released the [Desktop Cube Extension](https://github.com/Schneegans/Desktop-Cube/), many people requested to revive one of the most useless features of Linux desktop history: Setting windows on fire!
This extension is not only more useless than the cube, but it is also much more hacky. So I expect some bug! [Let's incinerate them all](https://github.com/Schneegans/Burn-My-Windows/issues)!
## Included Effects
Name | Preview
-----|--------
**Fire** <br> The classic effect inspired by Compiz. However, this is implemented using a GLSL shader and not with a particle system like in the old days. | <img src ="docs/pics/fire.gif" />
**Matrix** <br> Turn your windows into a shower of green letters! The color is actually configurable. <br><br> _Only available in GNOME Shell 40+_ | <img src ="docs/pics/matrix.gif" />
**T-Rex Attack** <br> Destroy your windows with a series of violent slashes! <br><br> _Only available in GNOME Shell 40+_ | <img src ="docs/pics/trex.gif" />
**TV-Effect** <br> This is a very simple effect to demonstrate that this extension could also be used in a more professional environment. | <img src ="docs/pics/tv.gif" />
## Installation
+7
View File
@@ -0,0 +1,7 @@
# Notes for `claws.blend`
This is the source file for `resources/img/claws.png`. To generate the image, the animation in `claws.blend` is rendered to 256 PNG files and then combined using this command:
```bash
convert *.png -average claws.png
```
Binary file not shown.
+374
View File
@@ -0,0 +1,374 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="512"
height="512"
viewBox="0 0 135.46666 135.46667"
version="1.1"
id="svg5"
inkscape:version="1.1.1 (3bf5ae0d25, 2021-09-20)"
sodipodi:docname="matrixFont.svg"
inkscape:export-filename="/home/simon/Linux-Projects/Burn-My-Windows/resources/img/matrixFont.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#000000"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="1"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="true"
units="px"
inkscape:zoom="3.2650549"
inkscape:cx="194.33058"
inkscape:cy="126.49098"
inkscape:window-width="1920"
inkscape:window-height="1131"
inkscape:window-x="0"
inkscape:window-y="32"
inkscape:window-maximized="1"
inkscape:current-layer="layer1">
<inkscape:grid
type="xygrid"
id="grid8183"
empspacing="2"
spacingx="4.2333333"
spacingy="4.2333333"
color="#cbcbff"
opacity="0.1254902"
empcolor="#ffffff"
empopacity="0.25098039" />
</sodipodi:namedview>
<defs
id="defs2">
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter972"
x="-0.014295474"
y="-0.01399304"
width="1.0285909"
height="1.0279861">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="0.78384108"
id="feGaussianBlur970" />
</filter>
<filter
inkscape:collect="always"
style="color-interpolation-filters:sRGB"
id="filter974"
x="-0.024387008"
y="-0.023871079"
width="1.048774"
height="1.0477422">
<feGaussianBlur
inkscape:collect="always"
stdDeviation="1.3371742"
id="feGaussianBlur976" />
</filter>
</defs>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1">
<text
xml:space="preserve"
style="font-weight:300;font-size:7.60522px;line-height:1.112;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Light';letter-spacing:3.89202px;opacity:1;mix-blend-mode:normal;stroke-width:0.190131;filter:url(#filter972)"
x="1.7241572"
y="6.4795361"
id="text968"
inkscape:export-filename="/home/simon/Linux-Projects/Burn-My-Windows/resources/img/text3003.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="6.4795361"
id="tspan934">ABCDEFGHIJKLMNOP</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="14.946301"
id="tspan936">QRSTUVWXYZabcdef</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="23.413067"
id="tspan938">ghijklmnopqrstuv</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="31.879831"
id="tspan940">wxyzÀÁÂÃÄÅÆÇÈÉÊË</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="40.346596"
id="tspan942">ÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="48.813362"
id="tspan944">ÝÞßàáâãäåæçèéêëì</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="57.280125"
id="tspan946">íîïðΑαΒβΓγΔδΕεΖζ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="65.746887"
id="tspan948">ΗηΘθΙιΚκΛλΜμΝνΞξ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="74.213654"
id="tspan950">ΟοΠπΡρΣσΤτΥυΦφΧχ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="82.68042"
id="tspan952">ΨψΩω1234567890Аа</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="91.147186"
id="tspan954">БбВвГгДдЕеЖжЗзИи</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="99.613953"
id="tspan956">ЙйКкЛлМмНнОоПпРр</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="108.08072"
id="tspan958">СсТтУуФфХхЦцЧчШш</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="116.54748"
id="tspan960">ЩщЬьЭэЮюЯя!&quot;#$%&amp;</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="125.01424"
id="tspan962">()*+,-/:;&lt;=&gt;?@©§</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="133.48102"
id="tspan964">[\]{|}~ªº¿®¬½¼¡¶</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="141.94777"
id="tspan966" /></text>
<text
xml:space="preserve"
style="font-weight:300;font-size:7.60522px;line-height:1.112;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Light';letter-spacing:3.89202px;opacity:1;stroke-width:0.190131"
x="1.7241572"
y="6.4795361"
id="text94444"><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="6.4795361"
id="tspan94410">ABCDEFGHIJKLMNOP</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="14.946301"
id="tspan94412">QRSTUVWXYZabcdef</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="23.413067"
id="tspan94414">ghijklmnopqrstuv</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="31.879831"
id="tspan94416">wxyzÀÁÂÃÄÅÆÇÈÉÊË</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="40.346596"
id="tspan94418">ÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="48.813362"
id="tspan94420">ÝÞßàáâãäåæçèéêëì</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="57.280125"
id="tspan94422">íîïðΑαΒβΓγΔδΕεΖζ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="65.746887"
id="tspan94424">ΗηΘθΙιΚκΛλΜμΝνΞξ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="74.213654"
id="tspan94426">ΟοΠπΡρΣσΤτΥυΦφΧχ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="82.68042"
id="tspan94428">ΨψΩω1234567890Аа</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="91.147186"
id="tspan94430">БбВвГгДдЕеЖжЗзИи</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="99.613953"
id="tspan94432">ЙйКкЛлМмНнОоПпРр</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="108.08072"
id="tspan94434">СсТтУуФфХхЦцЧчШш</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="116.54748"
id="tspan94436">ЩщЬьЭэЮюЯя!&quot;#$%&amp;</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="125.01424"
id="tspan94438">()*+,-/:;&lt;=&gt;?@©§</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="133.48102"
id="tspan94440">[\]{|}~ªº¿®¬½¼¡¶</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="141.94777"
id="tspan94442" /></text>
<text
xml:space="preserve"
style="font-weight:300;font-size:7.60522px;line-height:1.112;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Light';letter-spacing:3.89202px;opacity:1;mix-blend-mode:normal;stroke-width:0.190131;filter:url(#filter974)"
x="1.7241572"
y="6.4795361"
id="text3003"
inkscape:export-filename="/home/simon/Linux-Projects/Burn-My-Windows/resources/img/text3003.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96"><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="6.4795361"
id="tspan30643">ABCDEFGHIJKLMNOP</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="14.946301"
id="tspan40072">QRSTUVWXYZabcdef</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="23.413067"
id="tspan42210">ghijklmnopqrstuv</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="31.879831"
id="tspan43166">wxyzÀÁÂÃÄÅÆÇÈÉÊË</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="40.346596"
id="tspan43762">ÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="48.813362"
id="tspan44946">ÝÞßàáâãäåæçèéêëì</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="57.280125"
id="tspan48062">íîïðΑαΒβΓγΔδΕεΖζ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="65.746887"
id="tspan56533">ΗηΘθΙιΚκΛλΜμΝνΞξ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="74.213654"
id="tspan58635">ΟοΠπΡρΣσΤτΥυΦφΧχ</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="82.68042"
id="tspan61169">ΨψΩω1234567890Аа</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="91.147186"
id="tspan67243">БбВвГгДдЕеЖжЗзИи</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="99.613953"
id="tspan69399">ЙйКкЛлМмНнОоПпРр</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="108.08072"
id="tspan70763">СсТтУуФфХхЦцЧчШш</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="116.54748"
id="tspan72709">ЩщЬьЭэЮюЯя!&quot;#$%&amp;</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="125.01424"
id="tspan77955">()*+,-/:;&lt;=&gt;?@©§</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="133.48102"
id="tspan77957">[\]{|}~ªº¿®¬½¼¡¶</tspan><tspan
sodipodi:role="line"
style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-family:monospace;-inkscape-font-specification:monospace;fill:#ffffff;fill-opacity:1;stroke-width:0.190131"
x="1.7241572"
y="141.94777"
id="tspan75487" /></text>
<text
xml:space="preserve"
style="font-weight:300;font-size:10.5833px;line-height:1.25;font-family:'Open Sans';-inkscape-font-specification:'Open Sans Light';stroke-width:0.264583"
x="169.33333"
y="29.009251"
id="text17385"><tspan
sodipodi:role="line"
id="tspan17383"
style="stroke-width:0.264583"
x="169.33333"
y="29.009251" /></text>
</g>
</svg>

After

Width:  |  Height:  |  Size: 21 KiB

+32
View File
@@ -1,5 +1,37 @@
# Changelog of the Burn-My-Windows Extension
## [Burn My Window 5](https://github.com/schneegans/Burn-My-Windows/releases/tag/v5)
**Release Date:** TBD
#### New Features
* Added a new ridiculous close-animation: the T-Rex-Attack!
* Added a new simple close-animation: the TV-Effect!
* Added a menu to the preferences dialog with links for bug reporting and donations.
#### Other Enhancements
* The fire shader now uses a `smoothstep` to make it less blocky.
#### Bug Fixes
* Fixed a bug which messed up the overview of GNOME Shell 3.36.
## [Burn My Window 4](https://github.com/schneegans/Burn-My-Windows/releases/tag/v4)
**Release Date:** 2021-12-25
#### New Features
* Added a new Matrix shader which dissolves your windows in a shower of green letters. You can switch between the fire and the matrix shader in the settings. Sadly, this effect cannot be available under GNOME 3.3x as it was apparently impossible to set textures for a `Clutter.ShaderEffect` in GJS back then.
* Added a setting to apply the animation also for closing dialog windows.
#### Other Enhancements
* Refactored the code a lot to make it easier to add new shader effects in the future.
* Tweaked timing of the fire shader. Previously, the fire became invisible quite quickly. Due to this new animation timing, the default animation time has been reduced to 1500 ms.
## [Burn My Window 3](https://github.com/schneegans/Burn-My-Windows/releases/tag/v3)
**Release Date:** 2021-12-20
Binary file not shown.

After

Width:  |  Height:  |  Size: 949 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 625 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 936 KiB

BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 203 KiB

+86 -150
View File
@@ -13,7 +13,10 @@
'use strict';
const {Clutter} = imports.gi;
const {Clutter, Gio, Meta} = imports.gi;
const Config = imports.misc.config;
const [GS_MAJOR, GS_MINOR] = Config.PACKAGE_VERSION.split('.');
const Workspace = imports.ui.workspace.Workspace;
const WindowManager = imports.ui.windowManager.WindowManager;
@@ -21,7 +24,11 @@ const WINDOW_REPOSITIONING_DELAY = imports.ui.workspace.WINDOW_REPOSITIONING_DEL
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const utils = Me.imports.utils;
const utils = Me.imports.src.common.utils;
const FireShader = Me.imports.src.extension.FireShader.FireShader;
const MatrixShader = Me.imports.src.extension.MatrixShader.MatrixShader;
const TVEffectShader = Me.imports.src.extension.TVEffectShader.TVEffectShader;
const TRexShader = Me.imports.src.extension.TRexShader.TRexShader;
//////////////////////////////////////////////////////////////////////////////////////////
// This extensions modifies the window-close animation to look like the window was set //
@@ -38,35 +45,61 @@ class Extension {
// from GNOME Tweaks, when you log in or when the screen is unlocked.
enable() {
// Load all of our resources.
this._resources = Gio.Resource.load(Me.path + '/resources/burn-my-windows.gresource');
Gio.resources_register(this._resources);
// Store a reference to the settings object.
this._settings = ExtensionUtils.getSettings();
// We will monkey-patch these three methods. Let's store the original ones.
this._origWindowRemoved = Workspace.prototype._windowRemoved;
this._origDoRemoveWindow = Workspace.prototype._doRemoveWindow;
this._origAddWindowClone = Workspace.prototype._addWindowClone;
this._origShouldAnimateActor = WindowManager.prototype._shouldAnimateActor;
// We may also override these animation times.
this._origDestroyTime = imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME;
this._origWindowTime = imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME;
this._origDialogTime = imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME;
// Update animation times if the respective settings are changed.
const loadAnimationTimes = () => {
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME =
this._settings.get_int('destroy-animation-time');
imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME =
this._settings.get_boolean('destroy-dialogs') ?
this._settings.get_int('destroy-animation-time') :
this._origDialogTime;
};
this._settings.connect('changed::destroy-animation-time', loadAnimationTimes);
this._settings.connect('changed::destroy-dialogs', loadAnimationTimes);
loadAnimationTimes();
// We will use extensionThis to refer to the extension inside the patched methods of
// the WorkspacesView.
const extensionThis = this;
// On GNOME 3.36, the window clone's 'destroy' handler only calls _removeWindowClone
// but not _doRemoveWindow. The latter is required to trigger the repositioning of the
// overview window layout. Therefore we call this method in addition.
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/gnome-3-36/js/ui/workspace.js#L1877
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1415
if (GS_MAJOR == 3 && GS_MINOR == 36) {
Workspace.prototype._addWindowClone = function(...params) {
const [clone, overlay] = extensionThis._origAddWindowClone.apply(this, params);
clone.connect('destroy', () => this._doRemoveWindow(clone.metaWindow));
return [clone, overlay];
};
}
// These three method overrides are mega-hacky! They are only required to make the
// fire animation work in the overview. Usually, windows are not faded when closed
// from the overview (why?). With these overrides we make sure that they are actually
// faded out. To do this, _windowRemoved and _doRemoveWindow now check whether there
// is a transition ongoing (via extensionThis._shouldDestroy). If that's the case,
// they methods do nothing. Are the actors removed in the end? I hope so. The
// these methods do nothing. Are the actors removed in the end? I hope so. The
// _destroyWindow of the WindowManager sets the transitions up and should take care of
// removing the actors at the end of the transitions.
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1299
@@ -79,6 +112,7 @@ class Extension {
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/workspace.js#L1178
Workspace.prototype._doRemoveWindow = function(metaWin) {
if (extensionThis._shouldDestroy(this, metaWin)) {
utils.debug((new Error()).stack);
extensionThis._origDoRemoveWindow.apply(this, [metaWin]);
}
};
@@ -90,11 +124,11 @@ class Extension {
// whether it was called by _destroyWindow. If so, we return true. Let's see if this
// breaks stuff left and right...
// https://gitlab.gnome.org/GNOME/gnome-shell/-/blob/main/js/ui/windowManager.js#L1125
WindowManager.prototype._shouldAnimateActor = function(actor, types) {
WindowManager.prototype._shouldAnimateActor = function(...params) {
if ((new Error()).stack.split('\n')[1].includes('_destroyWindow@')) {
return true;
}
return extensionThis._origShouldAnimateActor.apply(this, [actor, types]);
return extensionThis._origShouldAnimateActor.apply(this, params);
};
// The close animation is set up in WindowManager's _destroyWindow:
@@ -106,11 +140,18 @@ class Extension {
// one, set up the window close animation. This usually fades-out the window and
// scales it a bit down. If no transition is in progress, something unexpected
// happened. We rather try not to burn the window!
const transition = actor.get_transition('opacity');
const transition = actor.get_transition('scale-y');
if (!transition) {
return;
}
// We do nothing if a dialog got closed and we should not burn them.
if (!this._settings.get_boolean('destroy-dialogs') &&
(actor.meta_window.window_type == Meta.WindowType.MODAL_DIALOG ||
actor.meta_window.window_type == Meta.WindowType.DIALOG)) {
return;
}
// If there's a transition in progress, we re-target these transitions so that the
// window is neither scaled nor faded.
const tweakTransition = (property, value) => {
@@ -125,150 +166,36 @@ class Extension {
tweakTransition('scale-x', 1);
tweakTransition('scale-y', 1);
// Instead, we add a cool fire shader to our window actor! The noise implementation
// is from https://www.shadertoy.com/view/3tcBzH (CC-BY-NC-SA).
const shader = new Clutter.ShaderEffect({
shader_type: Clutter.ShaderType.FRAGMENT_SHADER,
});
let shader = null;
// Load the gradient values from the settings. We directly inject the values in the
// GLSL code below. The shader is compiled once for each window-closing anyways. In
// the future, we my want to prevent this frequent recompilations of shaders,
// though.
const gradient = [];
for (let i = 1; i <= 5; i++) {
const color =
Clutter.Color.from_string(this._settings.get_string('fire-color-' + i))[1];
gradient.push(`vec4(${color.red / 255}, ${color.green / 255}, ${
color.blue / 255}, ${color.alpha / 255})`);
// Add a cool shader to our window actor!
const mode = this._settings.get_enum('close-animation');
if (mode == 1) {
shader = new FireShader(this._settings);
} else if (mode == 2) {
shader = new MatrixShader(this._settings);
} else if (mode == 3) {
shader = new TVEffectShader(this._settings);
tweakTransition('scale-y', 0.5);
} else if (mode == 4) {
shader = new TRexShader(this._settings);
const warp = 0.5 * this._settings.get_double('claw-scratch-warp');
tweakTransition('scale-x', 1.0 + warp);
tweakTransition('scale-y', 1.0 + warp);
}
shader.set_shader_source(`
uniform sampler2D texture;
uniform float progress;
uniform float time;
uniform int sizeX;
uniform int sizeY;
if (shader) {
actor.add_effect(shader);
// These may be configurable in the future.
const float EDGE_BLEND = 70;
const float BURN_RANGE = 0.1;
const float BURN_TIME = 0.2;
const vec2 FIRE_SCALE = vec2(400, 600) * ${
this._settings.get_double('flame-scale')};
const float FIRE_SPEED = ${this._settings.get_double('flame-movement-speed')};
float rand(vec2 co) {
return fract(sin(dot(co.xy ,vec2(12.9898,78.233))) * 43758.5453);
}
float hermite(float t) {
return t * t * (3.0 - 2.0 * t);
}
float noiseImpl(vec2 co, float frequency) {
vec2 v = vec2(co.x * frequency, co.y * frequency);
float ix1 = floor(v.x);
float iy1 = floor(v.y);
float ix2 = floor(v.x + 1.0);
float iy2 = floor(v.y + 1.0);
float fx = hermite(fract(v.x));
float fy = hermite(fract(v.y));
float fade1 = mix(rand(vec2(ix1, iy1)), rand(vec2(ix2, iy1)), fx);
float fade2 = mix(rand(vec2(ix1, iy2)), rand(vec2(ix2, iy2)), fx);
return mix(fade1, fade2, fy);
}
float pNoise(vec2 co, float freq, int steps, float persistence) {
float value = 0.0;
float ampl = 1.0;
float sum = 0.0;
for(int i=0 ; i<steps ; i++) {
sum += ampl;
value += noiseImpl(co, freq) * ampl;
freq *= 2.0;
ampl *= persistence;
}
return value / sum;
}
vec4 getFireColor(float v) {
const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8);
const vec4 colors[5] = vec4[](
${gradient[0]},
${gradient[1]},
${gradient[2]},
${gradient[3]},
${gradient[4]}
);
if (v < steps[0]) {
return colors[0];
}
for (int i=0; i<4; ++i) {
if (v <= steps[i+1]) {
return mix(colors[i], colors[i+1], vec4(v - steps[i])/(steps[i+1]-steps[i]));
}
}
return colors[4];
}
void main(void) {
float burnProgress = clamp(progress/BURN_TIME, 0, 1);
float afterBurnProgress = clamp((progress-BURN_TIME)/(1-BURN_TIME), 0, 1);
// Gradient from top to bottom.
float t = cogl_tex_coord_in[0].t * (1 - BURN_RANGE);
// Visible part of the window. Gradually dissolves towards the bottom.
float alpha = 1 - clamp((burnProgress - t) / BURN_RANGE, 0, 1);
// Get window texture.
cogl_color_out = texture2D(texture, cogl_tex_coord_in[0].st) * alpha;
// Gradient from top burning window.
float mask = clamp(t*(1-alpha)/burnProgress, 0, 1);
// Fade-out when the window burned down.
if (progress > BURN_TIME) {
mask *= mix(1, 1-t, afterBurnProgress) * pow(1-afterBurnProgress, 2);
}
// Fade at window borders.
vec2 pos = cogl_tex_coord_in[0].st * vec2(sizeX, sizeY);
mask *= clamp(pos.x / EDGE_BLEND, 0, 1);
mask *= clamp(pos.y / EDGE_BLEND, 0, 1);
mask *= clamp((sizeX - pos.x) / EDGE_BLEND, 0, 1);
mask *= clamp((sizeY - pos.y) / EDGE_BLEND, 0, 1);
vec2 firePos = pos / FIRE_SCALE;
firePos.y += time * FIRE_SPEED;
float noise = pNoise(firePos, 10.0, 5, 0.5);
// Modulate noise by mask and map to color.
vec4 color = getFireColor(noise*mask);
color.rgb *= color.a;
// cogl_color_out = vec4(mask);
cogl_color_out += color;
}
`);
actor.add_effect(shader);
// Update uniforms at each frame.
transition.connect('new-frame', (t) => {
shader.set_uniform_value('progress', t.get_progress());
shader.set_uniform_value('time', 0.001 * t.get_elapsed_time());
shader.set_uniform_value('sizeX', actor.width);
shader.set_uniform_value('sizeY', actor.height);
});
// Update uniforms at each frame.
transition.connect('new-frame', (t) => {
shader.set_uniform_value('uProgress', t.get_progress());
shader.set_uniform_value('uTime', 0.001 * t.get_elapsed_time());
shader.set_uniform_value('uSizeX', actor.width);
shader.set_uniform_value('uSizeY', actor.height);
});
}
});
}
@@ -276,28 +203,37 @@ class Extension {
// Tweaks, when you log out or when the screen locks.
disable() {
// Unregister our resources.
Gio.resources_unregister(this._resources);
// Restore the original behavior.
global.window_manager.disconnect(this._destroyConnection);
Workspace.prototype._windowRemoved = this._origWindowRemoved;
Workspace.prototype._doRemoveWindow = this._origDoRemoveWindow;
Workspace.prototype._addWindowClone = this._origAddWindowClone;
WindowManager.prototype._shouldAnimateActor = this._origShouldAnimateActor;
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = this._origDestroyTime;
imports.ui.windowManager.DESTROY_WINDOW_ANIMATION_TIME = this._origWindowTime;
imports.ui.windowManager.DIALOG_DESTROY_WINDOW_ANIMATION_TIME = this._origDialogTime;
this._settings = null;
}
// ----------------------------------------------------------------------- private stuff
// This is required to enable window-close animations in the overview. See the comment
// for Workspace.prototype._windowRemoved above for an explanation.
_shouldDestroy(workspace, metaWindow) {
const index = workspace._lookupIndex(metaWindow);
if (index == -1) {
return true;
}
const actor = workspace._windows[index]._windowActor;
if (!actor.get_transition('opacity')) {
// This was called "realWindow" in GNOME 3.36.
const GS_336 = GS_MAJOR == 3 && GS_MINOR == 36;
const actor = workspace._windows[index][GS_336 ? 'realWindow' : '_windowActor'];
if (!actor.get_transition('scale-y')) {
return true;
}
+2 -2
View File
@@ -1,6 +1,6 @@
{
"uuid": "burn-my-windows@schneegans.github.com",
"description": "Disintegrate your apps the old-school way.",
"description": "Disintegrate your apps with style.",
"name": "Burn My Windows",
"gettext-domain": "burn-my-windows",
"settings-schema": "org.gnome.shell.extensions.burn-my-windows",
@@ -11,5 +11,5 @@
"41"
],
"url": "https://github.com/Schneegans/Burn-My-Windows",
"version": 3
"version": 5
}
+83 -22
View File
@@ -17,7 +17,7 @@ const {Gio, Gtk, Gdk} = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const utils = Me.imports.utils;
const utils = Me.imports.src.common.utils;
//////////////////////////////////////////////////////////////////////////////////////////
// For now, the preferences dialog of this extension is very simple. In the future, if //
@@ -34,7 +34,7 @@ var PreferencesDialog = class PreferencesDialog {
// Load the user interface file.
this._builder = new Gtk.Builder();
this._builder.add_from_resource(`/ui/${utils.gtk4() ? 'gtk4' : 'gtk3'}.ui`);
this._builder.add_from_resource(`/ui/${utils.isGTK4() ? 'gtk4' : 'gtk3'}.ui`);
// This is our top-level widget which we will return later.
this._widget = this._builder.get_object('settings-widget');
@@ -43,7 +43,9 @@ var PreferencesDialog = class PreferencesDialog {
this._settings = ExtensionUtils.getSettings();
// Bind all properties.
this._bindCombobox('close-animation');
this._bindAdjustment('destroy-animation-time');
this._bindSwitch('destroy-dialogs');
this._bindAdjustment('flame-movement-speed');
this._bindAdjustment('flame-scale');
this._bindColorButton('fire-color-1');
@@ -51,8 +53,17 @@ var PreferencesDialog = class PreferencesDialog {
this._bindColorButton('fire-color-3');
this._bindColorButton('fire-color-4');
this._bindColorButton('fire-color-5');
this._bindAdjustment('matrix-scale');
this._bindAdjustment('matrix-randomness');
this._bindColorButton('matrix-trail-color');
this._bindColorButton('matrix-tip-color');
this._bindColorButton('tv-effect-color');
this._bindColorButton('claw-scratch-color');
this._bindAdjustment('claw-scratch-scale');
this._bindAdjustment('claw-scratch-count');
this._bindAdjustment('claw-scratch-warp');
// The fire-gradient-reset button needs to by bound explicitly.
// The fire-gradient-reset button needs to be bound explicitly.
this._builder.get_object('reset-fire-colors').connect('clicked', () => {
this._settings.reset('fire-color-1');
this._settings.reset('fire-color-2');
@@ -64,6 +75,36 @@ var PreferencesDialog = class PreferencesDialog {
// Initialize the fire-preset dropdown.
this._createFirePresets();
// Add a menu to the title bar of the preferences dialog.
this._widget.connect('realize', (widget) => {
const window = utils.isGTK4() ? widget.get_root() : widget.get_toplevel();
// Show the version number in the title bar.
window.set_title(`Burn-My-Windows ${Me.metadata.version}`);
// Add the menu.
const menu = this._builder.get_object('menu-button');
window.get_titlebar().pack_end(menu);
// Populate the actions.
const group = Gio.SimpleActionGroup.new();
const addAction = (name, uri) => {
const action = Gio.SimpleAction.new(name, null);
action.connect('activate', () => Gtk.show_uri(null, uri, Gdk.CURRENT_TIME));
group.add_action(action);
};
addAction('homepage', 'https://github.com/Schneegans/Burn-My-Windows');
addAction('bugs', 'https://github.com/Schneegans/Burn-My-Windows/issues');
addAction(
'donate-paypal',
'https://www.paypal.com/donate/?hosted_button_id=3F7UFL8KLVPXE');
addAction('donate-github', 'https://github.com/sponsors/Schneegans');
window.insert_action_group('prefs', group);
});
// As we do not have something like a destructor, we just listen for the destroy
// signal of our main widget.
this._widget.connect('destroy', () => {
@@ -72,7 +113,7 @@ var PreferencesDialog = class PreferencesDialog {
});
// Show the widgets on GTK3.
if (!utils.gtk4()) {
if (!utils.isGTK4()) {
this._widget.show_all();
}
}
@@ -86,6 +127,12 @@ var PreferencesDialog = class PreferencesDialog {
// ----------------------------------------------------------------------- private stuff
// Connects a Gtk.ComboBox (or anything else which has an 'active-id' property) to a
// settings key. It also binds the corresponding reset button.
_bindCombobox(settingsKey) {
this._bind(settingsKey, 'active-id');
}
// Connects a Gtk.Adjustment (or anything else which has a 'value' property) to a
// settings key. It also binds the corresponding reset button.
_bindAdjustment(settingsKey) {
@@ -99,36 +146,50 @@ var PreferencesDialog = class PreferencesDialog {
}
// Colors are stored as strings like 'rgb(1, 0.5, 0)'. As Gio.Settings.bind_with_mapping
// is not available yet, we need to do the color conversion manually.
// is not available yet, we need to do the color conversion manually. It also binds the
// corresponding reset button.
_bindColorButton(settingsKey) {
const button = this._builder.get_object(settingsKey);
// Update the settings when the color is modified.
button.connect('color-set', () => {
this._settings.set_string(settingsKey, button.get_rgba().to_string());
});
if (button) {
// Update the button state when the settings change.
const settingSignalHandler = () => {
const rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string(settingsKey));
button.rgba = rgba;
};
// Update the settings when the color is modified.
button.connect('color-set', () => {
this._settings.set_string(settingsKey, button.get_rgba().to_string());
});
this._settings.connect('changed::' + settingsKey, settingSignalHandler);
// Update the button state when the settings change.
const settingSignalHandler = () => {
const rgba = new Gdk.RGBA();
rgba.parse(this._settings.get_string(settingsKey));
button.rgba = rgba;
};
// Initialize the button with the state in the settings.
settingSignalHandler();
this._settings.connect('changed::' + settingsKey, settingSignalHandler);
// Initialize the button with the state in the settings.
settingSignalHandler();
}
this._bindResetButton(settingsKey);
}
// Connects any widget's property to a settings key. The widget must have the same ID as
// the settings key. It also binds the corresponding reset button.
_bind(settingsKey, property) {
this._settings.bind(
settingsKey, this._builder.get_object(settingsKey), property,
Gio.SettingsBindFlags.DEFAULT);
const object = this._builder.get_object(settingsKey);
if (object) {
this._settings.bind(settingsKey, object, property, Gio.SettingsBindFlags.DEFAULT);
}
this._bindResetButton(settingsKey);
}
// Searches for a reset button for the given settings key and make it reset the settings
// key when clicked.
_bindResetButton(settingsKey) {
const resetButton = this._builder.get_object('reset-' + settingsKey);
if (resetButton) {
resetButton.connect('clicked', () => {
@@ -219,7 +280,7 @@ var PreferencesDialog = class PreferencesDialog {
this._builder.get_object('fire-preset-button').set_menu_model(menu);
const root = utils.gtk4() ? widget.get_root() : widget.get_toplevel();
const root = utils.isGTK4() ? widget.get_root() : widget.get_toplevel();
root.insert_action_group(groupName, group);
});
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 230 KiB

+245 -4
View File
@@ -2,6 +2,61 @@
<interface domain="desktop-cube">
<requires lib="gtk" version="3.0" />
<object class="GtkListStore" id="animation-mode-list">
<columns>
<column type="gchararray" />
<column type="gchararray" />
</columns>
<data>
<row>
<col id="0">Fire</col>
<col id="1">fire</col>
</row>
<row>
<col id="0">TV Effect</col>
<col id="1">tv</col>
</row>
</data>
</object>
<menu id="main-menu">
<section>
<item>
<attribute name="label" translatable="yes">Visit Homepage</attribute>
<attribute name="action">prefs.homepage</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Report a Bug</attribute>
<attribute name="action">prefs.bugs</attribute>
</item>
</section>
<section>
<submenu>
<attribute name="label" translatable="yes">Donate</attribute>
<item>
<attribute name="label" translatable="yes">Via PayPal</attribute>
<attribute name="action">prefs.donate-paypal</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Via GitHub</attribute>
<attribute name="action">prefs.donate-github</attribute>
</item>
</submenu>
</section>
</menu>
<object class="GtkMenuButton" id="menu-button">
<property name="menu-model">main-menu</property>
<property name="visible">1</property>
<child>
<object class="GtkImage">
<property name="icon-name">open-menu-symbolic</property>
<property name="visible">1</property>
<property name="icon-size">1</property>
</object>
</child>
</object>
<object class="GtkAdjustment" id="destroy-animation-time">
<property name="upper">10000</property>
<property name="lower">500</property>
@@ -23,6 +78,20 @@
<property name="page-increment">0.1</property>
</object>
<object class="GtkAdjustment" id="matrix-scale">
<property name="upper">50</property>
<property name="lower">5</property>
<property name="step-increment">1</property>
<property name="page-increment">5</property>
</object>
<object class="GtkAdjustment" id="matrix-randomness">
<property name="upper">1</property>
<property name="lower">0</property>
<property name="step-increment">0.01</property>
<property name="page-increment">0.1</property>
</object>
<object class="GtkScrolledWindow" id="settings-widget">
<property name="hscrollbar-policy">never</property>
<property name="min-content-height">200</property>
@@ -57,6 +126,58 @@
<object class="GtkListBox">
<property name="selection-mode">none</property>
<child>
<object class="GtkListBoxRow">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Close Window Animation</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkComboBox" id="close-animation">
<property name="valign">center</property>
<property name="model">animation-mode-list</property>
<property name="id_column">1</property>
<property name="active_id">fire</property>
<child>
<object class="GtkCellRendererText" />
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="reset-close-animation">
<child>
<object class="GtkImage">
<property name="icon-name">edit-clear-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="margin-start">10</property>
@@ -106,6 +227,50 @@
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Also Burn Dialogs</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkSwitch" id="destroy-dialogs">
<property name="halign">end</property>
<property name="valign">center</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-destroy-dialogs">
<child>
<object class="GtkImage">
<property name="icon-name">edit-clear-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
@@ -118,7 +283,7 @@
<property name="margin-bottom">10</property>
<child>
<object class="GtkLabel">
<property name="label">Fire Options</property>
<property name="label">Fire Animation Options</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<style>
@@ -171,7 +336,7 @@
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Flame Scale</property>
<property name="label" translatable="yes">Scale</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
@@ -220,7 +385,7 @@
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Flame Movement Speed</property>
<property name="label" translatable="yes">Speed</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
@@ -270,7 +435,7 @@
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Fire Gradient</property>
<property name="label" translatable="yes">Gradient</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
@@ -332,6 +497,82 @@
</object>
</child>
<child>
<object class="GtkBox">
<property name="margin-top">30</property>
<property name="margin-bottom">10</property>
<child>
<object class="GtkLabel">
<property name="label">TV Effect Options</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<style>
<class name="title-4" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkFrame">
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<style>
<class name="rich-list" />
</style>
<child>
<object class="GtkListBoxRow">
<property name="margin-start">10</property>
<property name="margin-end">10</property>
<property name="margin-top">10</property>
<property name="margin-bottom">10</property>
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<property name="spacing">8</property>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Color</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkColorButton" id="tv-effect-color">
<property name="use_alpha">1</property>
<property name="show_editor">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-tv-effect-color">
<child>
<object class="GtkImage">
<property name="icon-name">edit-clear-symbolic</property>
<property name="icon-size">1</property>
</object>
</child>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
+601 -4
View File
@@ -2,6 +2,62 @@
<interface domain="desktop-cube">
<requires lib="gtk" version="4.0" />
<object class="GtkListStore" id="animation-mode-list">
<columns>
<column type="gchararray" />
<column type="gchararray" />
</columns>
<data>
<row>
<col id="0">Fire</col>
<col id="1">fire</col>
</row>
<row>
<col id="0">Matrix</col>
<col id="1">matrix</col>
</row>
<row>
<col id="0">TV Effect</col>
<col id="1">tv</col>
</row>
<row>
<col id="0">T-Rex Attack</col>
<col id="1">trex</col>
</row>
</data>
</object>
<menu id="main-menu">
<section>
<item>
<attribute name="label" translatable="yes">Visit Homepage</attribute>
<attribute name="action">prefs.homepage</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Report a Bug</attribute>
<attribute name="action">prefs.bugs</attribute>
</item>
</section>
<section>
<submenu>
<attribute name="label" translatable="yes">Donate</attribute>
<item>
<attribute name="label" translatable="yes">Via PayPal</attribute>
<attribute name="action">prefs.donate-paypal</attribute>
</item>
<item>
<attribute name="label" translatable="yes">Via GitHub</attribute>
<attribute name="action">prefs.donate-github</attribute>
</item>
</submenu>
</section>
</menu>
<object class="GtkMenuButton" id="menu-button">
<property name="menu-model">main-menu</property>
<property name="icon-name">open-menu-symbolic</property>
</object>
<object class="GtkScrolledWindow" id="settings-widget">
<property name="hscrollbar-policy">never</property>
<property name="min-content-height">200</property>
@@ -42,6 +98,48 @@
</style>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Close Window Animation</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkComboBox" id="close-animation">
<property name="valign">center</property>
<property name="model">animation-mode-list</property>
<property name="id_column">1</property>
<property name="active_id">fire</property>
<child>
<object class="GtkCellRendererText" />
<attributes>
<attribute name="text">0</attribute>
</attributes>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="reset-close-animation">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
@@ -88,6 +186,40 @@
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Also Burn Dialogs</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkSwitch" id="destroy-dialogs">
<property name="halign">end</property>
<property name="valign">center</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-destroy-dialogs">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
@@ -100,7 +232,7 @@
<property name="margin-bottom">10</property>
<child>
<object class="GtkLabel">
<property name="label">Fire Options</property>
<property name="label">Fire Animation Options</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<style>
@@ -134,7 +266,7 @@
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Flame Scale</property>
<property name="label" translatable="yes">Scale</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
@@ -180,7 +312,7 @@
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Flame Movement Speed</property>
<property name="label" translatable="yes">Speed</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
@@ -226,7 +358,7 @@
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Fire Gradient</property>
<property name="label" translatable="yes">Gradient</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
@@ -283,6 +415,471 @@
</object>
</child>
<child>
<object class="GtkBox">
<property name="margin-top">30</property>
<property name="margin-bottom">10</property>
<child>
<object class="GtkLabel">
<property name="label">Matrix Animation Options</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<style>
<class name="title-4" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkFrame">
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<property name="show-separators">1</property>
<style>
<class name="rich-list" />
</style>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Scale</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkScale">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="draw-value">1</property>
<property name="digits">0</property>
<property name="value-pos">left</property>
<property name="width-request">300</property>
<property name="adjustment">
<object class="GtkAdjustment" id="matrix-scale">
<property name="upper">50</property>
<property name="lower">5</property>
<property name="step-increment">1</property>
<property name="page-increment">5</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-matrix-scale">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Randomness</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkScale">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="draw-value">1</property>
<property name="digits">2</property>
<property name="value-pos">left</property>
<property name="width-request">300</property>
<property name="adjustment">
<object class="GtkAdjustment" id="matrix-randomness">
<property name="upper">1.0</property>
<property name="lower">0.0</property>
<property name="step-increment">0.01</property>
<property name="page-increment">0.1</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-matrix-randomness">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Trail Color</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkColorButton" id="matrix-trail-color">
<property name="use_alpha">0</property>
<property name="show_editor">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-matrix-trail-color">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Tip Color</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkColorButton" id="matrix-tip-color">
<property name="use_alpha">0</property>
<property name="show_editor">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-matrix-tip-color">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="margin-top">30</property>
<property name="margin-bottom">10</property>
<child>
<object class="GtkLabel">
<property name="label">T-Rex Attack Options</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<style>
<class name="title-4" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkFrame">
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<property name="show-separators">1</property>
<style>
<class name="rich-list" />
</style>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Claw Scratch Scale</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkScale">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="draw-value">1</property>
<property name="digits">1</property>
<property name="value-pos">left</property>
<property name="width-request">300</property>
<property name="adjustment">
<object class="GtkAdjustment" id="claw-scratch-scale">
<property name="upper">10</property>
<property name="lower">0.1</property>
<property name="step-increment">0.1</property>
<property name="page-increment">1</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-claw-scratch-scale">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Claw Scratch Count</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkScale">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="draw-value">1</property>
<property name="digits">0</property>
<property name="value-pos">left</property>
<property name="width-request">300</property>
<property name="adjustment">
<object class="GtkAdjustment" id="claw-scratch-count">
<property name="upper">50</property>
<property name="lower">1</property>
<property name="step-increment">1</property>
<property name="page-increment">10</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-claw-scratch-count">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Warp Effect</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkScale">
<property name="halign">end</property>
<property name="valign">center</property>
<property name="draw-value">1</property>
<property name="digits">2</property>
<property name="value-pos">left</property>
<property name="width-request">300</property>
<property name="adjustment">
<object class="GtkAdjustment" id="claw-scratch-warp">
<property name="upper">1</property>
<property name="lower">0</property>
<property name="step-increment">0.01</property>
<property name="page-increment">0.1</property>
</object>
</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-claw-scratch-warp">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Flash Color</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkColorButton" id="claw-scratch-color">
<property name="use_alpha">1</property>
<property name="show_editor">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-claw-scratch-color">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
<child>
<object class="GtkBox">
<property name="margin-top">30</property>
<property name="margin-bottom">10</property>
<child>
<object class="GtkLabel">
<property name="label">TV Effect Options</property>
<property name="xalign">0</property>
<property name="hexpand">1</property>
<style>
<class name="title-4" />
</style>
</object>
</child>
</object>
</child>
<child>
<object class="GtkFrame">
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<property name="show-separators">1</property>
<style>
<class name="rich-list" />
</style>
<child>
<object class="GtkListBoxRow">
<property name="activatable">0</property>
<child>
<object class="GtkBox">
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">Color</property>
<property name="xalign">0</property>
<property name="halign">start</property>
<property name="valign">center</property>
<property name="hexpand">1</property>
</object>
</child>
<child>
<object class="GtkColorButton" id="tv-effect-color">
<property name="use_alpha">0</property>
<property name="show_editor">1</property>
</object>
</child>
<child>
<object class="GtkButton" id="reset-tv-effect-color">
<property name="icon-name">edit-clear-symbolic</property>
<property name="tooltip-text">Reset to Default Value</property>
<style>
<class name="flat" />
</style>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
@@ -1,14 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<schemalist>
<enum id='org.gnome.shell.extensions.burn-my-windows.AnimationType'>
<value value='1' nick='fire' />
<value value='2' nick='matrix' />
<value value='3' nick='tv' />
<value value='4' nick='trex' />
</enum>
<schema path="/org/gnome/shell/extensions/burn-my-windows/" id="org.gnome.shell.extensions.burn-my-windows">
<key name="close-animation" enum="org.gnome.shell.extensions.burn-my-windows.AnimationType">
<default>"fire"</default>
<summary>Close Animation</summary>
<description>The animation used for window closing.</description>
</key>
<key name="destroy-animation-time" type="i">
<default>2000</default>
<default>1500</default>
<summary>Destroy Animation Time</summary>
<description>The time it takes to burn the windows.</description>
</key>
<key name="destroy-dialogs" type="b">
<default>false</default>
<summary>Destroy Dialogs</summary>
<description>Set to true to burn dialogs as well.</description>
</key>
<key name="flame-movement-speed" type="d">
<default>0.5</default>
<summary>Flame Movement Speed</summary>
@@ -51,6 +71,64 @@
<description>The fifth color of the fire gradient.</description>
</key>
<key name="matrix-scale" type="i">
<default>20</default>
<summary>Matrix Scale</summary>
<description>The size of the matrix letters.</description>
</key>
<key name="matrix-randomness" type="d">
<default>1.0</default>
<summary>Matrix Randomness</summary>
<description>The randomness of the matrix effect.</description>
</key>
<key name="matrix-tip-color" type="s">
<default>"rgb(255, 255, 255)"</default>
<summary>Matrix Tip Color</summary>
<description>The color of the matrix trail tips.</description>
</key>
<key name="matrix-trail-color" type="s">
<default>"rgb(25, 255, 89)"</default>
<summary>Matrix Trail Color</summary>
<description>The color matrix trails.</description>
</key>
<key name="tv-effect-color" type="s">
<default>"rgb(255, 255, 255)"</default>
<summary>TV Effect Color</summary>
<description>The color of the TV effect.</description>
</key>
<key name="claw-scratch-color" type="s">
<default>"rgb(170, 0, 0)"</default>
<summary>Claw Scratch Color</summary>
<description>The color of the claw scratches.</description>
</key>
<key name="claw-scratch-scale" type="d">
<default>1.0</default>
<summary>Claw Scratch Scale</summary>
<description>Size of the claw scratches.</description>
</key>
<key name="claw-scratch-warp" type="d">
<default>0.15</default>
<summary>Claw Scratch Warp</summary>
<description>Intensity of the claw scratch warp effect.</description>
</key>
<key name="claw-scratch-count" type="i">
<default>5</default>
<summary>Claw Scratch Count</summary>
<description>Number of claw scratches drawn on top of each other.</description>
</key>
</schema>
</schemalist>
+1 -1
View File
@@ -39,6 +39,6 @@ function debug(message) {
}
// This method simply returns true if we are currently using GTK4.
function gtk4() {
function isGTK4() {
return Gtk.get_major_version() == 4;
}
+150
View File
@@ -0,0 +1,150 @@
//////////////////////////////////////////////////////////////////////////////////////////
// ) ( //
// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
// |__/ //
// Copyright (c) 2021 Simon Schneegans //
// Released under the GPLv3 or later. See LICENSE file for details. //
//////////////////////////////////////////////////////////////////////////////////////////
'use strict';
const {Clutter, GObject} = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const shaderSnippets = Me.imports.src.extension.shaderSnippets;
//////////////////////////////////////////////////////////////////////////////////////////
// The FireShader uses a procedural gray-scale noise texture. This texture is moved //
// vertically over time and mapped to a configurable color gradient. It is faded to //
// transparency towards the edges of the window. In addition, there are a couple of //
// moving gradients which fade-in or fade-out the fire effect. //
//////////////////////////////////////////////////////////////////////////////////////////
var FireShader = GObject.registerClass({Properties: {}, Signals: {}},
class FireShader extends Clutter.ShaderEffect {
_init(settings) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
// Load the gradient values from the settings. We directly inject the values in the
// GLSL code below. The shader is compiled once for each window-closing anyways. In
// the future, we may want to prevent this frequent recompilations of shaders,
// though.
const gradient = [];
for (let i = 1; i <= 5; i++) {
const color = Clutter.Color.from_string(settings.get_string('fire-color-' + i))[1];
gradient.push(`vec4(${color.red / 255}, ${color.green / 255}, ${
color.blue / 255}, ${color.alpha / 255})`);
}
this.set_shader_source(`
// Inject some common shader snippets.
${shaderSnippets.standardUniforms()}
${shaderSnippets.noise()}
// These may be configurable in the future.
const float EDGE_FADE = 70;
const float FADE_WIDTH = 0.1;
const float HIDE_TIME = 0.4;
const vec2 FIRE_SCALE = vec2(400, 600) * ${settings.get_double('flame-scale')};
const float FIRE_SPEED = ${settings.get_double('flame-movement-speed')};
// This maps the input value from [0..1] to a color from the gradient.
vec4 getFireColor(float v) {
const float steps[5] = float[](0.0, 0.2, 0.35, 0.5, 0.8);
const vec4 colors[5] = vec4[](
${gradient[0]},
${gradient[1]},
${gradient[2]},
${gradient[3]},
${gradient[4]}
);
if (v < steps[0]) {
return colors[0];
}
for (int i=0; i<4; ++i) {
if (v <= steps[i+1]) {
return mix(colors[i], colors[i+1], vec4(v -
steps[i])/(steps[i+1]-steps[i]));
}
}
return colors[4];
}
// This method requires the uniforms from standardUniforms() to be available.
// It returns two values: The first is an alpha value which can be used for the window
// texture. This gradually dissolves the window from top to bottom. The second can be used
// to mask any effect, it will be most opaque where the window is currently fading and
// gradually dissolve to zero over time.
// hideTime: A value in [0..1]. It determines the percentage of the animation which
// is spent for hiding the window. 1-hideTime will be spent thereafter for
// dissolving the effect mask.
// fadeWidth: The relative size of the window-hiding gradient in [0..1].
// edgeFadeWidth: The pixel width of the effect fading range at the edges of the window.
vec2 effectMask(float hideTime, float fadeWidth, float edgeFadeWidth) {
float burnProgress = clamp(uProgress/hideTime, 0, 1);
float afterBurnProgress = clamp((uProgress-hideTime)/(1-hideTime), 0, 1);
// Gradient from top to bottom.
float t = cogl_tex_coord_in[0].t * (1 - fadeWidth);
// Visible part of the window. Gradually dissolves towards the bottom.
float windowMask = 1 - clamp((burnProgress - t) / fadeWidth, 0, 1);
// Gradient from top burning window.
float effectMask = clamp(t*(1-windowMask)/burnProgress, 0, 1);
// Fade-out when the window burned down.
if (uProgress > hideTime) {
float fade = sqrt(1-afterBurnProgress*afterBurnProgress);
effectMask *= mix(1, 1-t, afterBurnProgress) * fade;
}
// Fade at window borders.
vec2 pos = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY);
effectMask *= smoothstep(0, 1, clamp(pos.x / edgeFadeWidth, 0, 1));
effectMask *= smoothstep(0, 1, clamp(pos.y / edgeFadeWidth, 0, 1));
effectMask *= smoothstep(0, 1, clamp((uSizeX - pos.x) / edgeFadeWidth, 0, 1));
effectMask *= smoothstep(0, 1, clamp((uSizeY - pos.y) / edgeFadeWidth, 0, 1));
return vec2(windowMask, effectMask);
}
void main() {
// Get a noise value which moves vertically in time.
vec2 uv = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY) / FIRE_SCALE;
uv.y += uTime * FIRE_SPEED;
float noise = perlinNoise(uv, 10.0, 5, 0.5);
// Modulate noise by effect mask.
vec2 effectMask = effectMask(HIDE_TIME, FADE_WIDTH, EDGE_FADE);
noise *= effectMask.y;
// Map noise value to color.
vec4 fire = getFireColor(noise);
fire.rgb *= fire.a;
// Get the window texture and fade it according to the effect mask.
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * effectMask.x;
// Add the fire to the window.
cogl_color_out += fire;
// These are pretty useful for understanding how this works.
// cogl_color_out = vec4(vec3(noise), 1);
// cogl_color_out = vec4(vec3(effectMask.x), 1);
// cogl_color_out = vec4(vec3(effectMask.y), 1);
}
`);
};
});
+145
View File
@@ -0,0 +1,145 @@
//////////////////////////////////////////////////////////////////////////////////////////
// ) ( //
// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
// |__/ //
// Copyright (c) 2021 Simon Schneegans //
// Released under the GPLv3 or later. See LICENSE file for details. //
//////////////////////////////////////////////////////////////////////////////////////////
'use strict';
const {Clutter, GObject, GdkPixbuf, Cogl} = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const shaderSnippets = Me.imports.src.extension.shaderSnippets;
//////////////////////////////////////////////////////////////////////////////////////////
// The MatrixShader multiplies a grid of random letters with some gradients which are //
// moving from top to bottom. The speed of the moving gradients is chosen randomly. //
// Also, there is a random delay making the gradients not drop all at the same time. //
// This effect is not available on GNOME 3.3x, due to the limitation described in the //
// documentation of vfunc_paint_target further down in this file. //
//////////////////////////////////////////////////////////////////////////////////////////
var MatrixShader = GObject.registerClass({Properties: {}, Signals: {}},
class MatrixShader extends Clutter.ShaderEffect {
_init(settings) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
// Load the font texture. As the shader is re-created for each window animation, this
// texture is also re-created each time. This could be improved in the future!
const fontData = GdkPixbuf.Pixbuf.new_from_resource('/img/matrixFont.png');
this._fontTexture = new Clutter.Image();
this._fontTexture.set_data(
fontData.get_pixels(),
fontData.has_alpha ? Cogl.PixelFormat.RGBA_8888 : Cogl.PixelFormat.RGB_888,
fontData.width, fontData.height, fontData.rowstride);
const trailColor =
Clutter.Color.from_string(settings.get_string('matrix-trail-color'))[1];
const tipColor =
Clutter.Color.from_string(settings.get_string('matrix-tip-color'))[1];
// This is partially based on https://www.shadertoy.com/view/ldccW4 (CC-BY-NC-SA).
this.set_shader_source(`
// Inject some common shader snippets.
${shaderSnippets.standardUniforms()}
${shaderSnippets.noise()}
uniform sampler2D uFontTexture;
// These may be configurable in the future.
const float EDGE_FADE = 30;
const float FADE_WIDTH = 150;
const float TRAIL_LENGTH = 0.2;
const float FINAL_FADE_START_TIME = 0.8;
const float LETTER_TILES = 16.0;
const float LETTER_SIZE = ${settings.get_int('matrix-scale')};
const float LETTER_FLICKER_SPEED = 2.0;
const float RANDOMNESS = ${settings.get_double('matrix-randomness')};
// This returns a flickering grid of random letters.
float getText(vec2 fragCoord) {
vec2 pixelCoords = fragCoord * vec2(uSizeX, uSizeY);
vec2 uv = mod(pixelCoords.xy, LETTER_SIZE)/LETTER_SIZE;
vec2 block = pixelCoords/LETTER_SIZE - uv;
// Choose random letter.
uv += floor(rand2(floor(rand(block)*vec2(12.9898,78.233) + LETTER_FLICKER_SPEED*uTime + 42.254))*LETTER_TILES);
return texture2D(uFontTexture, uv/LETTER_TILES).r;
}
// This returns two values: The first are gradients for the "raindrops" which move
// from top to bottom. This is used for fading the letters. The second value is set
// to one below each drop and to zero above it. This second value is used for fading
// the window texture.
vec2 getRain(vec2 fragCoord) {
vec2 coords = fragCoord * vec2(uSizeX, uSizeY);
coords.x -= mod(coords.x, LETTER_SIZE);
float delay = fract(sin(coords.x)*78.233) * mix(0.0, 1.0, RANDOMNESS);
float speed = fract(cos(coords.x)*12.989) * mix(0.0, 0.3, RANDOMNESS) + 1.5;
float distToDrop = (uProgress*2-delay)*speed - fragCoord.y;
float rainAlpha = distToDrop >= 0 ? exp(-distToDrop/TRAIL_LENGTH) : 0;
float windowAlpha = 1 - clamp(uSizeY*distToDrop, 0, FADE_WIDTH) / FADE_WIDTH;
return vec2(rainAlpha, windowAlpha);
}
void main() {
// Get a cool matrix effect. See comments for those methods above.
vec2 rain = getRain(cogl_tex_coord_in[0].st);
float text = getText(cogl_tex_coord_in[0].st);
// Get the window texture and fade it according to the effect mask.
cogl_color_out = texture2D(uTexture, cogl_tex_coord_in[0].st) * rain.y;
// This is used to fade out the remaining trails in the end.
float finalFade = 1-clamp((uProgress-FINAL_FADE_START_TIME)/
(1-FINAL_FADE_START_TIME), 0, 1);
float rainAlpha = finalFade * rain.x;
// Fade at window borders.
vec2 pos = cogl_tex_coord_in[0].st * vec2(uSizeX, uSizeY);
rainAlpha *= clamp(pos.x / EDGE_FADE, 0, 1);
rainAlpha *= clamp(pos.y / EDGE_FADE, 0, 1);
rainAlpha *= clamp((uSizeX - pos.x) / EDGE_FADE, 0, 1);
rainAlpha *= clamp((uSizeY - pos.y) / EDGE_FADE, 0, 1);
// Add the matrix effect to the window.
vec3 trailColor = vec3(${trailColor.red / 255},
${trailColor.green / 255},
${trailColor.blue / 255});
vec3 tipColor = vec3(${tipColor.red / 255},
${tipColor.green / 255},
${tipColor.blue / 255});
cogl_color_out.rgb += mix(trailColor, tipColor, min(1, pow(rainAlpha+0.1, 4))) * rainAlpha * text;
// These are pretty useful for understanding how this works.
// cogl_color_out = vec4(vec3(text), 1);
// cogl_color_out = vec4(vec3(rain.x), 1);
// cogl_color_out = vec4(vec3(rain.y), 1);
}
`);
};
// This is overridden to bind the font texture for drawing. Sadly, this seems to be
// impossible under GNOME 3.3x as this.get_pipeline() is not available. It was called
// get_target() back then but this is not wrapped in GJS.
// https://gitlab.gnome.org/GNOME/mutter/-/blob/gnome-3-36/clutter/clutter/clutter-offscreen-effect.c#L598
vfunc_paint_target(node, paint_context) {
const pipeline = this.get_pipeline();
pipeline.set_layer_texture(1, this._fontTexture.get_texture());
this.set_uniform_value('uFontTexture', 1);
super.vfunc_paint_target(node, paint_context);
}
});
+157
View File
@@ -0,0 +1,157 @@
//////////////////////////////////////////////////////////////////////////////////////////
// ) ( //
// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
// |__/ //
// Copyright (c) 2021 Simon Schneegans //
// Released under the GPLv3 or later. See LICENSE file for details. //
//////////////////////////////////////////////////////////////////////////////////////////
'use strict';
const {Clutter, GObject, GdkPixbuf, Cogl} = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const shaderSnippets = Me.imports.src.extension.shaderSnippets;
//////////////////////////////////////////////////////////////////////////////////////////
// This effect tears your windows apart with a series of violent scratches! //
// This effect is not available on GNOME 3.3x, due to the limitation described in the //
// documentation of vfunc_paint_target further down in this file. //
//////////////////////////////////////////////////////////////////////////////////////////
var TRexShader = GObject.registerClass({Properties: {}, Signals: {}},
class TRexShader extends Clutter.ShaderEffect {
_init(settings) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
// Load the claw texture. As the shader is re-created for each window animation, this
// texture is also re-created each time. This could be improved in the future!
// See assets/README.md for how this texture was created.
const clawData = GdkPixbuf.Pixbuf.new_from_resource('/img/claws.png');
this._clawTexture = new Clutter.Image();
this._clawTexture.set_data(
clawData.get_pixels(), Cogl.PixelFormat.RGB_888, clawData.width, clawData.height,
clawData.rowstride);
const color = Clutter.Color.from_string(settings.get_string('claw-scratch-color'))[1];
this.set_shader_source(`
// Inject some common shader snippets.
${shaderSnippets.standardUniforms()}
${shaderSnippets.noise()}
// See assets/README.md for how this texture was created.
uniform sampler2D uClawTexture;
const vec2 SEED = vec2(${Math.random()}, ${Math.random()});
const float CLAW_SIZE = ${settings.get_double('claw-scratch-scale')};
const float NUM_CLAWS = ${settings.get_int('claw-scratch-count')};
const float WARP_INTENSITY = 1.0 + ${settings.get_double('claw-scratch-warp')};
const float FLASH_INTENSITY = 0.1;
const float MAX_SPAWN_TIME = 0.5; // Scratches will only start in the first half of the animation.
const float FF_TIME = 0.5; // Relative time for the final fade to transparency.
// This method generates a grid of randomly rotated, slightly shifted and scaled
// UV squares. It returns the texture coords of the UV square at the given actor
// coordinates. If these do not fall into one of the UV grids, the coordinates of
// the closest UV grid will be clamped and returned.
vec2 getClawUV(vec2 texCoords, float gridScale, vec2 seed) {
// Shift coordinates by a random offset and make sure the have a 1:1 aspect ratio.
vec2 coords = texCoords + rand2(seed);
coords *= uSizeX < uSizeY ? vec2(1.0, 1.0 * uSizeY / uSizeX) : vec2(1.0 * uSizeX / uSizeY, 1.0);
// Apply global scale.
coords *= gridScale;
// Get grid cell coordinates in [0..1].
vec2 cellUV = mod(coords, vec2(1));
// This is unique for each cell.
vec2 cellID = coords-cellUV + vec2(362.456);
// Add random rotation, scale and offset to each grid cell.
float scale = mix(0.8, 1.0, rand(cellID*seed*134.451));
float offsetX = mix(0.0, 1.0 - scale, rand(cellID*seed*54.4129));
float offsetY = mix(0.0, 1.0 - scale, rand(cellID*seed*25.3089));
float rotation = mix(0.0, 2.0 * 3.141, rand(cellID*seed*2.99837));
cellUV -= vec2(offsetX, offsetY);
cellUV /= scale;
cellUV -= 0.5;
cellUV = vec2(cellUV.x * cos(rotation) - cellUV.y * sin(rotation),
cellUV.x * sin(rotation) + cellUV.y * cos(rotation));
cellUV += 0.5;
// Clamp resulting coordinates.
return clamp(cellUV, vec2(0), vec2(1));
}
void main() {
// Warp the texture coordinates to create a blow-up effect.
vec2 coords = cogl_tex_coord_in[0].st * 2.0 - 1.0;
float dist = length(coords);
coords = (coords/dist * pow(dist, WARP_INTENSITY)) * 0.5 + 0.5;
coords = mix(cogl_tex_coord_in[0].st, coords, uProgress);
// Accumulate several random scratches. The color in the scratch map refers to the
// relative time when the respective part will become invisible. Therefore we can
// add a value to make the scratch appear later.
float scratchMap = 1.0;
for (int i=0; i<NUM_CLAWS; ++i) {
vec2 uv = getClawUV(coords, 1.0/CLAW_SIZE, SEED*(i+1));
float delay = i/NUM_CLAWS * MAX_SPAWN_TIME;
scratchMap = min(scratchMap, clamp(texture2D(uClawTexture, uv).r + delay, 0, 1));
}
// Get the window texture. We shift the texture lookup by the local derivative of
// the claw texture in order to mimic some folding distortion.
vec2 offset = vec2(dFdx(scratchMap), dFdy(scratchMap)) * uProgress * 0.5;
cogl_color_out = texture2D(uTexture, coords + offset);
// Hide scratched out parts.
cogl_color_out *= (scratchMap > uProgress ? 1 : 0);
// Add colorful flashes.
float flashIntensity = 1.0 / FLASH_INTENSITY * (scratchMap - uProgress) + 1;
if (flashIntensity < 0 || flashIntensity >= 1) {
flashIntensity = 0;
}
vec3 flashColor = vec3(${color.red / 255},
${color.green / 255},
${color.blue / 255}) * ${color.alpha / 255};
cogl_color_out.rgb += flashIntensity * mix(flashColor, vec3(0), uProgress);
// Fade out the remaining shards.
float fade = smoothstep(0, 1, 1 - clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1));
cogl_color_out *= fade;
// These are pretty useful for understanding how this works.
// cogl_color_out = vec4(vec3(flashIntensity), 1);
// cogl_color_out = vec4(vec3(scratchMap), 1);
}
`);
};
// This is overridden to bind the claw texture for drawing. Sadly, this seems to be
// impossible under GNOME 3.3x as this.get_pipeline() is not available. It was called
// get_target() back then but this is not wrapped in GJS.
// https://gitlab.gnome.org/GNOME/mutter/-/blob/gnome-3-36/clutter/clutter/clutter-offscreen-effect.c#L598
vfunc_paint_target(node, paint_context) {
const pipeline = this.get_pipeline();
pipeline.set_layer_texture(1, this._clawTexture.get_texture());
this.set_uniform_value('uClawTexture', 1);
super.vfunc_paint_target(node, paint_context);
}
});
+90
View File
@@ -0,0 +1,90 @@
//////////////////////////////////////////////////////////////////////////////////////////
// ) ( //
// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
// |__/ //
// Copyright (c) 2021 Simon Schneegans //
// Released under the GPLv3 or later. See LICENSE file for details. //
//////////////////////////////////////////////////////////////////////////////////////////
'use strict';
const {Clutter, GObject} = imports.gi;
const ExtensionUtils = imports.misc.extensionUtils;
const Me = imports.misc.extensionUtils.getCurrentExtension();
const shaderSnippets = Me.imports.src.extension.shaderSnippets;
//////////////////////////////////////////////////////////////////////////////////////////
// The TVEffectShader hides the actor by making it first transparent from top and //
// bottom towards the middle and then hiding the resulting line from left and right //
// towards the center. //
//////////////////////////////////////////////////////////////////////////////////////////
var TVEffectShader = GObject.registerClass(
{Properties: {}, Signals: {}}, class TVEffectShader extends Clutter.ShaderEffect {
_init(settings) {
super._init({shader_type: Clutter.ShaderType.FRAGMENT_SHADER});
const color =
Clutter.Color.from_string(settings.get_string('tv-effect-color'))[1];
this.set_shader_source(`
// Inject some common shader snippets.
${shaderSnippets.standardUniforms()}
const float BLUR_WIDTH = 0.01; // Width of the gradients.
const float TB_TIME = 0.7; // Relative time for the top/bottom animation.
const float LR_TIME = 0.4; // Relative time for the left/right animation.
const float LR_DELAY = 0.6; // Delay after which the left/right animation starts.
const float FF_TIME = 0.2; // Relative time for the final fade to transparency.
void main() {
// All of these are in [0..1] during the different stages of the animation.
// tb refers to the top-bottom animation.
// lr refers to the left-right animation.
// ff refers to the final fade animation.
float tbProgress = smoothstep(0, 1, clamp(uProgress/TB_TIME, 0, 1));
float lrProgress = smoothstep(0, 1, clamp((uProgress - LR_DELAY)/LR_TIME, 0, 1));
float ffProgress = smoothstep(0, 1, clamp((uProgress - 1.0 + FF_TIME)/FF_TIME, 0, 1));
// This is a top-center-bottom gradient in [0..1..0]
float tb = cogl_tex_coord_in[0].t * 2;
tb = tb < 1 ? tb : 2 - tb;
// This is a left-center-right gradient in [0..1..0]
float lr = cogl_tex_coord_in[0].s * 2;
lr = lr < 1 ? lr : 2 - lr;
// Combine the progress values with the gradients to create the alpha masks.
float tbMask = 1 - smoothstep(0, 1, clamp((tbProgress - tb) / BLUR_WIDTH, 0, 1));
float lrMask = 1 - smoothstep(0, 1, clamp((lrProgress - lr) / BLUR_WIDTH, 0, 1));
float ffMask = 1 - smoothstep(0, 1, ffProgress);
// Assemble the final alpha value.
float mask = tbMask * lrMask * ffMask;
vec4 windowColor = texture2D(uTexture, cogl_tex_coord_in[0].st);
vec4 effectColor = vec4(${color.red / 255},
${color.green / 255},
${color.blue / 255}, 1.0) * windowColor.a;
windowColor.rgb = mix(windowColor.rgb, effectColor.rgb, smoothstep(0, 1, uProgress));
cogl_color_out = windowColor * mask;
// These are pretty useful for understanding how this works.
// cogl_color_out = vec4(vec3(tbMask), 1);
// cogl_color_out = vec4(vec3(lrMask), 1);
// cogl_color_out = vec4(vec3(ffMask), 1);
// cogl_color_out = vec4(vec3(mask), 1);
}
`);
};
});
+83
View File
@@ -0,0 +1,83 @@
//////////////////////////////////////////////////////////////////////////////////////////
// ) ( //
// ( /( ( ( ) ( ( ( ( )\ ) ( ( //
// )\()) ))\ )( ( ( )\ ) )\))( )\ ( (()/( ( )\))( ( //
// ((_)\ /((_|()\ )\ ) )\ '(()/( ((_)()((_) )\ ) ((_)))\((_)()\ )\ //
// | |(_|_))( ((_)_(_/( _((_)) )(_)) _(()((_|_)_(_/( _| |((_)(()((_|(_) //
// | '_ \ || | '_| ' \)) | ' \()| || | \ V V / | ' \)) _` / _ \ V V (_-< //
// |_.__/\_,_|_| |_||_| |_|_|_| \_, | \_/\_/|_|_||_|\__,_\___/\_/\_//__/ //
// |__/ //
// Copyright (c) 2021 Simon Schneegans //
// Released under the GPLv3 or later. See LICENSE file for details. //
//////////////////////////////////////////////////////////////////////////////////////////
'use strict';
//////////////////////////////////////////////////////////////////////////////////////////
// These functions return strings which can be injected to GLSL shader code. //
//////////////////////////////////////////////////////////////////////////////////////////
// These should be included in every shader.
// uTexture: Contains the texture of the window.
// uProgress: A value which transitions from 0 to 1 during the entire animation.
// uTime: A steadily increasing value in seconds.
// uSizeX: The horizontal size of uTexture in pixels.
// uSizeY: The vertical size of uTexture in pixels.
function standardUniforms() {
return `
uniform sampler2D uTexture;
uniform float uProgress;
uniform float uTime;
uniform int uSizeX;
uniform int uSizeY;
`;
}
// The noise implementation is from https://www.shadertoy.com/view/3tcBzH (CC-BY-NC-SA).
function noise() {
return `
float rand(vec2 co) {
return fract(sin(dot(co.xy, vec2(12.9898,78.233))) * 43758.5453);
}
vec2 rand2(vec2 co) {
return vec2(rand(co), rand(co + vec2(12.9898,78.233)));
}
float hermite(float t) {
return t * t * (3.0 - 2.0 * t);
}
float noiseImpl(vec2 co, float frequency) {
vec2 v = vec2(co.x * frequency, co.y * frequency);
float ix1 = floor(v.x);
float iy1 = floor(v.y);
float ix2 = floor(v.x + 1.0);
float iy2 = floor(v.y + 1.0);
float fx = hermite(fract(v.x));
float fy = hermite(fract(v.y));
float fade1 = mix(rand(vec2(ix1, iy1)), rand(vec2(ix2, iy1)), fx);
float fade2 = mix(rand(vec2(ix1, iy2)), rand(vec2(ix2, iy2)), fx);
return mix(fade1, fade2, fy);
}
float perlinNoise(vec2 co, float freq, int steps, float persistence) {
float value = 0.0;
float ampl = 1.0;
float sum = 0.0;
for(int i=0 ; i<steps ; i++) {
sum += ampl;
value += noiseImpl(co, freq) * ampl;
freq *= 2.0;
ampl *= persistence;
}
return value / sum;
}
`;
}