14

I was wondering how could spotlight floating with focus, and another window still has focus!

enter image description here

I could easy make a window floating over all other window with window?.level = Int(CGWindowLevelForKey(.maximumWindow)),but I cannot let two windows both has focus, help!

Is there any function like ShowWithoutActivating in Cocoa?

Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Seven
  • 203
  • 3
  • 7
  • 2
    What do you mean "both has focus"? That's not possible. If it were, then your typing would go to both windows, which would be very confusing and troublesome. The Spotlight window absolutely "steals" focus. (I wouldn't really consider it "stealing", since it was requested by the user.) – Ken Thomases Sep 03 '17 at 19:38

2 Answers2

20

I've been playing around with this a bit, and I seem to be able to produce this effect when the frontmost window is not from the same process as the frontmost application, which is what I suspect Spotlight is probably doing. I can achieve this like so:

  1. Set LSUIElement to YES in my app's Info.plist.

  2. In Interface Builder, set the window's class to NSPanel, check "Non Activating" in the Attributes Inspector, and set "isFloatingPanel" to YES in the User Defined Runtime Attributes under the Identity Inspector.

  3. During some time that some other application is in front (I just used a 5-second delay to give myself time to pop some other app to the front and select a text field), call makeKeyAndOrderFront() followed by orderFrontRegardless() on the window.

When I do this, I get the following (note the focus ring still drawn on Xcode's "Module" field):

enter image description here

Charles Srstka
  • 16,665
  • 3
  • 34
  • 60
  • Thanks so much! That`s what I want. And your answer is very clear, Truly grateful for your help. – Seven Sep 04 '17 at 01:57
  • 1
    Do give the focus back to the previous app I needed to grab which app was active (`NSWorkspace.shared.runningApplications.first(where: {$0.isActive})`), stop text field from being first responder (`win.makeFirstResponder(nil)`), then call `activeApp?.activate(options: NSApplication.ActivationOptions.activateAllWindows)` to make the app have focus again. – Daniel Compton Sep 20 '18 at 04:59
  • 1
    How to make it work with "Hide on deactivate" option. After it is hid, I'm not able to bring it back. It works without this option. Only with `activate(ignoringOtherApps: true)` but it steals focus :( – Wojciech Kulik Aug 13 '20 at 13:14
  • 1
    I have found a solution. I had to disable this option and code some workaround: https://stackoverflow.com/questions/15077471/show-window-without-activating-keep-application-below-it-active#comment112101726_15079362 – Wojciech Kulik Aug 13 '20 at 14:07
  • I personally had to add in `window.becomeKey()` for my NSPanel() to get it to take focus the way Spotlight does – tyirvine May 20 '21 at 16:16
  • 1
    In response to @DanielCompton - I just used `window.resignKey()`. This gives focus to the previously focused view – tyirvine May 20 '21 at 23:23
  • MacOS noob here, where do I find the window in IB to change its class? Also, how would I do this for an NSPopover? – Akash Kundu Aug 28 '21 at 22:44
  • @tyirvine [Never call this method directly.](https://developer.apple.com/documentation/uikit/uiwindow/1621618-resignkey) – ManuelSchneid3r Jul 25 '23 at 11:40
0

There are two key conditions:

  1. Use NSPanel as window
  2. Add .nonactivatingPanel to NSPanel's styleMask
let window = NSPanel(
    contentRect: NSRect(x: 0, y: 0, width: 375, height: 800),
    styleMask: [
        .nonactivatingPanel,
        .titled,
        .closable,
        .miniaturizable,
        .resizable,
        .fullSizeContentView
    ],
    backing: .buffered,
    defer: false
)

Alex
  • 124
  • 1
  • 4