Top level window transparency in newer versions of GTK

Hello,

I am trying to achieve top level window transparency/translucency, but so far with little success. I came across several recipes on the internet, but they all seem to be for outdated versions of Gtk using deprecated features.

I made a small PoC prototype in Python:

import gi

gi.require_version("Gdk", "3.0")
gi.require_version("Gtk", "3.0")

from gi.repository import Gdk
from gi.repository import Gtk


CSS = b"""
#toplevel {
    background-color: rgba(0, 0, 255, 0.5);
}
"""


def on_draw(widget, cr, data):
    context = widget.get_style_context()

    width = widget.get_allocated_width()
    height = widget.get_allocated_height()
    Gtk.render_background(context, cr, 0, 0, width, height)

    cr.set_source_rgba(1.0, 1.0, 1.0, 0.5)
    cr.rectangle(0, 0, width, height)
    cr.fill()

    return False


style_provider = Gtk.CssProvider()
style_provider.load_from_data(CSS)
Gtk.StyleContext.add_provider_for_screen(
    Gdk.Screen.get_default(), 
    style_provider,
    Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)

button1 = Gtk.Button(label="Hello, world!")
button1.set_margin_bottom(50)
button1.set_margin_top(50)

box = Gtk.Box(spacing=50)
box.pack_start(button1, True, True, 50)

window = Gtk.Window(title="transparency", name="toplevel")
window.set_app_paintable(True)
window.add(box)
window.show_all()
# window.set_opacity(0.5)
window.connect("destroy", Gtk.main_quit)
# window.connect("draw", on_draw, None)

Gtk.main()

Here’s what I tried:

  1. Using set_opacity works, but setting opacity on the top level window makes all children translucent. What I want is to have translucent background of the top level window, but fully visible children.
  2. Setting alpha in CSS through background-color only affects the shade of the background color, but the window remains fully opaque.
  3. Similarly, hooking into the draw signal and painting the background on my own only achieves different shades, while the window remains fully opaque.

What am I missing?

The answer is: I’m missing a call to set_visual method on the top level window . Sharing a minimal working example in case someone else is having this problem:

import gi

gi.require_version("Gdk", "3.0")
gi.require_version("Gtk", "3.0")

from gi.repository import Gdk
from gi.repository import Gtk


CSS = b"""
#toplevel {
    background-color: rgba(0, 255, 255, 0.5);
}
"""

style_provider = Gtk.CssProvider()
style_provider.load_from_data(CSS)

Gtk.StyleContext.add_provider_for_screen(
    Gdk.Screen.get_default(),
    style_provider,
    Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)

button1 = Gtk.Button(label="Hello, world!")
button1.set_margin_bottom(50)
button1.set_margin_top(50)

box = Gtk.Box(spacing=50)
box.pack_start(button1, True, True, 50)

window = Gtk.Window(title="Hello World", name="toplevel")
screen = window.get_screen()
visual = screen.get_rgba_visual()
window.set_visual(visual)
window.add(box)
window.show_all()
window.connect("destroy", Gtk.main_quit)

Gtk.main()
1 Like