From 256da8dfb5fc30ff8ac6405ef66bbc1880e01e30 Mon Sep 17 00:00:00 2001 From: Will Norris Date: Fri, 20 Dec 2024 09:11:04 -0800 Subject: [PATCH] cmd/systray: remove new menu delay on KDE The new menu delay added to fix libdbusmenu systrays causes problems with KDE. Given the state of wildly varying systray implementations, I suspect we may need more desktop-specific hacks, so I'm setting this up to accommodate that. Updates #1708 Updates #14431 Change-Id: Ia101a4a3005adb9118051b3416f5a64a4a45987d Signed-off-by: Will Norris --- cmd/systray/systray.go | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/cmd/systray/systray.go b/cmd/systray/systray.go index 504ca5b8c..5b20ddde4 100644 --- a/cmd/systray/systray.go +++ b/cmd/systray/systray.go @@ -14,6 +14,7 @@ import ( "log" "net/http" "os" + "runtime" "strings" "sync" "time" @@ -32,6 +33,10 @@ var ( chState chan ipn.State // tailscale state changes appIcon *os.File + + // newMenuDelay is the amount of time to sleep after creating a new menu, + // but before adding items to it. This works around a bug in some dbus implementations. + newMenuDelay time.Duration ) func main() { @@ -55,6 +60,30 @@ type Menu struct { eventCancel func() // cancel eventLoop } +func init() { + if runtime.GOOS != "linux" { + // so far, these tweaks are only needed on Linux + return + } + + desktop := strings.ToLower(os.Getenv("XDG_CURRENT_DESKTOP")) + switch desktop { + case "kde": + // KDE doesn't need a delay, and actually won't render submenus + // if we delay for more than about 400µs. + newMenuDelay = 0 + default: + // Add a slight delay to ensure the menu is created before adding items. + // + // Systray implementations that use libdbusmenu sometimes process messages out of order, + // resulting in errors such as: + // (waybar:153009): LIBDBUSMENU-GTK-WARNING **: 18:07:11.551: Children but no menu, someone's been naughty with their 'children-display' property: 'submenu' + // + // See also: https://github.com/fyne-io/systray/issues/12 + newMenuDelay = 100 * time.Millisecond + } +} + func onReady() { log.Printf("starting") ctx := context.Background() @@ -124,13 +153,7 @@ func (menu *Menu) rebuild(state state) { } accounts := systray.AddMenuItem(account, "") setRemoteIcon(accounts, state.curProfile.UserProfile.ProfilePicURL) - // The dbus message about this menu item must propagate to the receiving - // end before we attach any submenu items. Otherwise the receiver may not - // yet record the parent menu item and error out. - // - // On waybar with libdbusmenu-gtk, this manifests as the following warning: - // (waybar:153009): LIBDBUSMENU-GTK-WARNING **: 18:07:11.551: Children but no menu, someone's been naughty with their 'children-display' property: 'submenu' - time.Sleep(100 * time.Millisecond) + time.Sleep(newMenuDelay) // Aggregate all clicks into a shared channel. menu.accountsCh = make(chan ipn.ProfileID) for _, profile := range state.allProfiles {