[v3][Linux] detectFocusFollowsMouse() misses niri compositor, causing HideOnFocusLost popups to immediately dismiss
Maintainers usually reply within 1 day
@1steve78 is already working on this.
Since Oct 30, 2026.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 78/100
Research direction
Read pkg/application/environment_linux.go, especially detectCompositor() and detectFocusFollowsMouse(). Check how the existing compositor environment variables are detected, then add niri detection as described in the issue. Done means niri is recognized and focus-follows-mouse detection returns true for it, so HideOnFocusLost is skipped.
Written by the indexing model from the issue text.
Description
Wails version family
v3
Exact Wails version
v3.0.0-beta.24 (and master)
Operating System
Linux
Description
In Wails v3, WebviewWindowOptions.HideOnFocusLost is intended for popup / systray attached windows. As documented in pkg/application/webview_window_options.go (line 240):
"On Linux with focus-follows-mouse WMs (Hyprland, Sway, i3), this is automatically disabled as it would cause the window to hide immediately when the mouse moves away."
To achieve this, setupHideOnFocusLost() checks shouldSkipHideOnFocusLost() which calls detectFocusFollowsMouse() in pkg/application/environment_linux.go:
func detectFocusFollowsMouse() bool {
compositor := detectCompositor()
switch compositor {
case "hyprland", "sway", "i3":
return true
}
return false
}
However, detectFocusFollowsMouse() only matches hyprland, sway, and i3. It misses niri (a scrollable tiling Wayland compositor where focus-follows-mouse is widely used).
Under niri with focus-follows-mouse enabled:
- User clicks a StatusNotifierItem tray icon located on a top bar (e.g. Noctalia or Waybar) at $(x, 15)$.
- The Wails systray attached window / popup opens below the bar (e.g. at $(x, 40)$).
- The pointer remains on the bar surface at $(x, 15)$, outside the popup's visual geometry.
- Any pointer release, sub-pixel jitter, or initial movement triggers
niri'sfocus-follows-mouse, switching focus to the underlying tiled window. - GTK receives
focus-out-event(events.Common.WindowLostFocus), and Wails immediately hides the popup window within ~50ms. - The window appears and vanishes instantly.
To Reproduce
- Run a Wails v3 app with a systray attached window configured with
HideOnFocusLost: trueon Linux underniri. - Enable
focus-follows-mousein niri (~/.config/niri/config.kdl):input { focus-follows-mouse } - Click the tray icon on a top/bottom status bar.
- The attached popup window appears and disappears almost instantaneously upon pointer release/slight motion.
Expected behaviour
detectFocusFollowsMouse() should identify niri as a tiling compositor with focus-follows-mouse capability, disabling HideOnFocusLost so the popup remains interactive until explicitly closed or dismissed.
Screenshots
No response
Attempted Fixes
- Adding
open-floating truein niri window rules avoids tiling animations, butfocus-follows-mousestill causes immediate dismissal when the cursor is on the bar. - Disabling
focus-follows-mousein~/.config/niri/config.kdlor configuringwarp-mouse-to-focus mode="center-xy"prevents the focus loss, confirming thatHideOnFocusLostreceiving premature focus loss is the direct trigger.
System Details
OS: CachyOS Linux (Arch Linux rolling)
Kernel: 7.3.0-rc6-2-cachyos-rc
Architecture: x86_64
Compositor: niri 26.04 (Wayland)
Go Version: go1.26.4 linux/amd64
Wails Module: github.com/wailsapp/wails/v3 v3.0.0-beta.24
Additional context
Suggested Fix:
In pkg/application/environment_linux.go:
- Add
NIRI_SOCKETcheck todetectCompositor():
func detectCompositor() string {
if os.Getenv("HYPRLAND_INSTANCE_SIGNATURE") != "" {
return "hyprland"
}
if os.Getenv("SWAYSOCK") != "" {
return "sway"
}
if os.Getenv("I3SOCK") != "" {
return "i3"
}
+ if os.Getenv("NIRI_SOCKET") != "" {
+ return "niri"
+ }
if desktop := os.Getenv("XDG_CURRENT_DESKTOP"); desktop != "" {
return strings.ToLower(desktop)
}
return "unknown"
}
- Add
"niri"todetectFocusFollowsMouse():
func detectFocusFollowsMouse() bool {
compositor := detectCompositor()
switch compositor {
- case "hyprland", "sway", "i3":
+ case "hyprland", "sway", "i3", "niri":
return true
}
return false
}
- Dominant language
- Go
- Stars
- 36.9k
- Forks
- 1.9k
- Avg merge
- 21h 41m
- Merged PRs (30d)
- 181
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from wailsapp/wails
-
[v3][Windows] OnShutdown hook not called when closing last window on WindowsPossibly taken @DangTAnh claimed this 2 days ago. OpenBug
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
[v2] wails dev: ipc.js throws "Cannot read properties of null (reading 'nodes')" on every page load (Svelte 5 overlay mounted with new Component())Possibly taken @DangTAnh claimed this 5 days ago. OpenBug v2
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Bug v3
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
wailsapp/wails#6076 · 1 comment ·
Maintainers usually reply within 1 day
-
Android: /wails/* assets served with Content-Type application/json breaks runtime JS modules (screen resets on first interaction)Possibly taken @xvetu claimed this 50 days ago. OpenBug v3
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
Maintainers usually reply within 1 day
-
Svelte Templates Use Component API Removed in Svelte 5Possibly taken @haoku123 claimed this 70 days ago. OpenBug v2
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
wailsapp/wails#6001 · 2 comments ·
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 70/100
YoanWai/agent-manager#948 ·
Maintainers usually reply within 1 day
-
area: platform priority: normal
Difficulty 2/5 1-3 hours Newbie friendliness 85/100
margince/margince#9851 · 1 reaction ·
Maintainers usually reply within 1 day
-
Headerless responses block while skipping duplicate status linesPossibly taken @mynhe claimed this 1 day ago. Open
Difficulty 2/5 1-3 hours Newbie friendliness 73/100
projectdiscovery/rawhttp#554 ·
-
type:chore
Difficulty 1/5 Under an hour Newbie friendliness 85/100
nightgauge/nightgauge#2793 ·
Maintainers usually reply within 1 day
-
stage-fail
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
siyuan-note/bazaar#2447 ·
Maintainers usually reply within 1 day