Search code examples
swiftmacosfullscreennswindow

How to locate window over all of apps (even if they are fullscreen-ed)


So i did the following:

  1. configured plist.info: Application is agent(UIElement) configured to "YES" (but possibly it is for iOS only ?)

wnd.collectionBehavior = [.stationary, .canJoinAllSpaces, .fullScreenAuxiliary]
wnd.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)) + 2 )
NSApp.activate(ignoringOtherApps: true)

both doing nothing!

All that can help is:

NSApp.setActivationPolicy(.prohibited)

but it is not solution for me as it's disable lot of other features and abilities of the app. =(

Is there exist some other ways to show window above fullscreen apps?

full code:

func openMainWnd(show: Bool = true) {
    if mainWndController == nil {
        let styleMask: NSWindow.StyleMask = [ /*.closable,.miniaturizable, .resizable, .titled*/]
        
        let wnd = NSWindow()
        wnd.styleMask = styleMask
        wnd.title = "Main1"
        
        wnd.contentView = NSHostingView(rootView: MainView(model: appVm) )
        wnd.standardWindowButton(.closeButton)?.isHidden = true
        wnd.standardWindowButton(.miniaturizeButton)?.isHidden = true
        wnd.standardWindowButton(.zoomButton)?.isHidden = true
        wnd.isMovable = false
        wnd.acceptsMouseMovedEvents = true
        wnd.hasShadow = true
        wnd.titleVisibility = .hidden
        wnd.titlebarAppearsTransparent = true
        wnd.backgroundColor = .clear
        
        wnd.collectionBehavior = [.stationary, .canJoinAllSpaces, .fullScreenAuxiliary]
        wnd.level = NSWindow.Level(rawValue: Int(CGWindowLevelForKey(.maximumWindow)) + 2 )
        NSApp.activate(ignoringOtherApps: true)
        
        wnd.setPosition(vertical: .top(offset: MainWndConfig.topOffset), horizontal: .center)
        
        mainWndController = NSWindowController(window: wnd)
    }
    
    if show {
        mainWndController?.showWindow(mainWndController?.window)
    }
} 

Solution

  • Solution is to use NSPanel instead of NSWindow + .nonactivatingPanel + few more things

    call display of View in floating NSPanel from AppDelegate:

    class AppDelegate: NSObject, NSApplicationDelegate {
        var mainWndController: NSWindowController?
    
        func openMainWnd(show: Bool = true) {
            if mainWndController == nil {
                let wnd = NSPanel(contentRect: NSRect(x: 0, y: 0, width: 200, height: 200),
                                     styleMask: [.nonactivatingPanel],
                                     backing: .buffered,
                                     defer: true)
                
                wnd.orderFrontRegardless()
                
                wnd.contentView = NSHostingView(rootView: MainView(model: appVm))
                wnd.standardWindowButton(.closeButton)?.isHidden = true
                wnd.standardWindowButton(.miniaturizeButton)?.isHidden = true
                wnd.standardWindowButton(.zoomButton)?.isHidden = true
                wnd.isMovable = false
                wnd.acceptsMouseMovedEvents = true
                wnd.hasShadow = true
                wnd.titleVisibility = .hidden
                wnd.titlebarAppearsTransparent = true
                wnd.backgroundColor = .clear
    
                wnd.collectionBehavior = [.canJoinAllSpaces, .fullScreenAuxiliary] //[.stationary, .canJoinAllSpaces, .fullScreenAuxiliary]
                wnd.level = .mainMenu
                NSApp.activate(ignoringOtherApps: true)
                
                
                wnd.setPosition(vertical: .top(offset: MainWndConfig.topOffset), horizontal: .center)
                
                mainWndController = NSWindowController(window: wnd )
            }
            
            if show {
                mainWndController?.showWindow(mainWndController?.window)
            }
        }
    }
    
    
    extension NSPanel {
        // Allow panel to become key, that is, accepts keyboard events
        // and give ability to use TextFields inside NSPanel
        open override var canBecomeKey: Bool { true }
    }