Display a transparent animation on top of gnome

I would like to display a transparent fireworks animation on top of whatever application is currently open for a brief period of time.

(The animation will be triggered when a change in a file is detected by a Python script.)

I should be able to continue to interact and see both the application and the GUI while the animation is playing.

Is it doable? What would be the easiest way to do it?

I am on Fedora

Hi, you will likely have to create a shell extension to do it securely and in a way that allows interaction with the underlying windows. It is possible to show a fullscreen animation using GTK4 without a shell extension, but it won’t be able to pass through input without losing focus. If you have unsafe mode enabled in your shell, this (very hacky) python script may work without any modifications to show a fullscreen animated GIF:

import pydbus, cairo, gi
gi.require_version('Gtk', '4.0')
from gi.repository import GLib, Gtk, GdkPixbuf

def on_map(win):
    surface = win.get_surface()
    surface.set_input_region(cairo.Region())
    pic = Gtk.Picture()
    anim = GdkPixbuf.PixbufAnimation.new_from_file('./anim.gif')
    it = anim.get_iter(None)
    def advance():
        it.advance(None)
        pic.set_pixbuf(it.get_pixbuf())
        time = it.get_delay_time()
        if time > -1:
            GLib.timeout_add(time, advance)
        pass
    advance()
    win.set_child(pic)

def on_activate(app):
    win = Gtk.ApplicationWindow(application=app, fullscreened=True, decorated=False)
    ctx = win.get_style_context()
    css = Gtk.CssProvider()
    css.load_from_data(b"window { background: none; }")
    ctx.add_provider(css, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
    win.connect('map', on_map)
    bus = pydbus.SessionBus()
    shell = bus.get('org.gnome.Shell')
    app_id = win.get_application().get_application_id()
    shell.Eval(
            f'''(() => {{
                const id = global.window_manager.connect('map', (wm, actor) => {{
                    if (actor.meta_window.get_gtk_application_id() === "{app_id}") {{
                        actor.meta_window.make_above();
                        global.window_manager.disconnect(id);
                        GLib.source_remove(timeout);
                    }}
                }});
                const timeout = GLib.timeout_add(GLib.PRIORITY_DEFAULT, 10 * 1000, () => {{
                    global.window_manager.disconnect(id);
                    return GLib.SOURCE_REMOVE;
                }});
            }})()''')
    win.present()

app = Gtk.Application(application_id='test.Fullscreen')
app.connect('activate', on_activate)
app.run(None)

For truly safe operation from Wayland you will have to put the shell JS in an extension and use Meta.WaylandClient.

1 Like

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.