File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 1+ // FloatingWindowModifier.swift — Insomnia GUI
2+ //
3+ // A SwiftUI ViewModifier that makes a window float above all other windows.
4+ // Used for LSUIElement menu bar apps where windows should stay visible
5+ // even when the user clicks on other applications.
6+
7+ import SwiftUI
8+
9+ /// Makes the hosting NSWindow float above all other windows.
10+ ///
11+ /// Finds the NSWindow backing the SwiftUI view on appear and sets its
12+ /// level to `.floating`. This keeps Insomnia's windows visible even when
13+ /// focus moves to another app — important for a menu bar utility.
14+ struct FloatingWindow : ViewModifier {
15+ /// Applies the floating window level to the view's hosting window.
16+ func body( content: Content ) -> some View {
17+ content
18+ . onAppear {
19+ // Find the NSWindow hosting this SwiftUI view and float it
20+ setFloatingLevel ( )
21+ }
22+ }
23+
24+ /// Searches the app's windows for the one hosting this view and sets it to float.
25+ private func setFloatingLevel( ) {
26+ // Slight delay to ensure the window is created and visible
27+ DispatchQueue . main. asyncAfter ( deadline: . now( ) + 0.05 ) {
28+ // Set all non-main windows to floating level
29+ // (MenuBarExtra doesn't create a standard NSWindow)
30+ for window in NSApp . windows where window. isVisible {
31+ window. level = . floating
32+ }
33+ }
34+ }
35+ }
36+
37+ /// Convenience extension for applying the floating window modifier.
38+ extension View {
39+ /// Makes the hosting window float above all other windows.
40+ func floatingWindow( ) -> some View {
41+ modifier ( FloatingWindow ( ) )
42+ }
43+ }
Original file line number Diff line number Diff line change @@ -44,20 +44,23 @@ struct InsomniaApp: App {
4444 Window ( " Settings " , id: " settings " ) {
4545 if let viewModel {
4646 SettingsView ( viewModel: SettingsViewModel ( configuration: viewModel. configuration) )
47+ . floatingWindow ( )
4748 }
4849 }
4950 . windowResizability ( . contentSize)
5051
5152 // About dialog window — uses BuildEnvironment for variant-aware title
5253 Window ( " About \( BuildEnvironment . appName) " , id: " about " ) {
5354 AboutView ( )
55+ . floatingWindow ( )
5456 }
5557 . windowResizability ( . contentSize)
5658
5759 // Custom duration picker window
5860 Window ( " Custom Duration " , id: " duration-picker " ) {
5961 if let viewModel {
6062 DurationPickerView ( viewModel: viewModel)
63+ . floatingWindow ( )
6164 }
6265 }
6366 . windowResizability ( . contentSize)
@@ -66,6 +69,7 @@ struct InsomniaApp: App {
6669 Window ( " Caffeinate Until " , id: " time-picker " ) {
6770 if let viewModel {
6871 TimePickerView ( viewModel: viewModel)
72+ . floatingWindow ( )
6973 }
7074 }
7175 . windowResizability ( . contentSize)
@@ -74,6 +78,7 @@ struct InsomniaApp: App {
7478 Window ( " Schedules " , id: " schedules " ) {
7579 if let viewModel {
7680 ScheduleEditorView ( viewModel: viewModel)
81+ . floatingWindow ( )
7782 }
7883 }
7984 . windowResizability ( . contentSize)
You can’t perform that action at this time.
0 commit comments