-
Notifications
You must be signed in to change notification settings - Fork 221
Description
Wayfire version
0.11.0-3c9a7712 (Jan 22 2026) branch master wlroots-0.19.2
Describe the bug
First I thought it was a bug in pygobject then I tested in gnome and some compositors which didnt present the same issue, so it seems related to Wayfire.
When using a button to open a menu (the Gtk4 Popover), the system correctly manages hover states under normal conditions: if you move the mouse away from the button, the highlight disappears, and if you click the button a second time to close the menu, the state resets properly.
The bug occurs specifically when you click any area outside both the button and the popover (such as clicking into a web browser or onto the desktop) to dismiss the menu. In this case, the menu closes instantly, but the button stays highlighted in its "Hover" or "Active" state even though the mouse is no longer near it.
Steps to Reproduce:
Open the popover.
Click in any view outside the popover
import sys
import gi
gi.require_version("Gtk", "4.0")
gi.require_version("Gtk4LayerShell", "1.0")
from gi.repository import Gtk, Gdk, Gtk4LayerShell, GLib
CSS_DATA = b"""
.reporting-button {
background-color: #242424;
color: white;
padding: 10px;
border: 2px solid transparent;
transition: all 200ms;
}
/* Very visible hover state */
.reporting-button:hover {
background-color: #005fb8;
border-color: #00aff0;
}
/* Extreme visibility for the active/stuck state */
.reporting-button:active,
.reporting-button:checked,
.reporting-button:hovered-stuck {
background-color: #ff0055 !format;
color: white;
border: 4px solid #ffffff;
box-shadow: 0 0 20px #ff0055;
}
/* GTK internal state mapping */
button:hover { background: #005fb8; }
button:active { background: #ff0055; }
"""
class LayerShellReproduction(Gtk.Application):
def __init__(self):
super().__init__(application_id="org.waypanel.report.stuckstate")
def do_activate(self):
# Apply the CSS
provider = Gtk.CssProvider()
provider.load_from_data(CSS_DATA)
Gtk.StyleContext.add_provider_for_display(
Gdk.Display.get_default(),
provider,
Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION
)
win = Gtk.ApplicationWindow(application=self)
# Layer Shell Init
Gtk4LayerShell.init_for_window(win)
Gtk4LayerShell.set_layer(win, Gtk4LayerShell.Layer.TOP)
Gtk4LayerShell.set_anchor(win, Gtk4LayerShell.Edge.TOP, True)
Gtk4LayerShell.set_keyboard_mode(win, Gtk4LayerShell.KeyboardMode.ON_DEMAND)
# The Button
btn = Gtk.Button(label="REPRODUCE: CLICK THEN CLICK OUTSIDE")
btn.add_css_class("reporting-button")
btn.set_halign(Gtk.Align.CENTER)
btn.set_margin_all(20)
# The Popover
popover = Gtk.Popover()
popover.set_parent(btn)
popover.set_child(Gtk.Label(label="Now click your Web Browser\nor any other window."))
btn.connect("clicked", lambda _: popover.popup())
# Console Monitor
def monitor_flags():
flags = btn.get_state_flags()
hover = bool(flags & Gtk.StateFlags.HOVER)
active = bool(flags & Gtk.StateFlags.ACTIVE)
if hover or active:
print(f"REPORT DATA - Hover: {hover}, Active: {active} (STUCK)")
return True
GLib.timeout_add(500, monitor_flags)
win.set_child(btn)
win.present()
if __name__ == "__main__":
app = LayerShellReproduction()
app.run(sys.argv)
Screenshots / Videos / Stacktrace
whatisgoingon.mp4
Additional context
[workarounds]
app_id_mode = "stock"
all_dialogs_modal = true
dynamic_repaint_delay = false
disable_primary_selection = false
discard_command_output = true
enable_input_method_v2 = false
enable_opaque_region_damage_optimizations = false
enable_so_unloading = false
focus_main_surface_instead_of_popup = false
force_frame_sync = false
force_preferred_decoration_mode = false
max_buffer_size = 16000
remove_output_limits = false
use_external_output_configuration = false