Search code examples
swiftcommand-linemacos-catalinansopenpanel

NSOpenPanel cannot get focus


First of all, I am completely new to Swift and I am sorry if my problem looks trivial.

I would like to have a very simple command line program that opens a dialog to choose a file or a folder. This tool must not run an actual full app with an icon bouncing in the Dock, but rather something subtle. That's it. What I have done produces exactly this, except the Panel cannot get focus. When I click on the Panel, it stays greyed out. Interestingly, it is possible to click on buttons, or drag and drop files, but exploring the file system is not possible. Keyboard events are not captured neither.

import AppKit

let dialog = NSOpenPanel()

dialog.title                   = "Choose a .tif file or a folder";
dialog.showsResizeIndicator    = true;
dialog.showsHiddenFiles        = false;
dialog.canChooseDirectories    = true;
dialog.canCreateDirectories    = true;
dialog.allowsMultipleSelection = false;
dialog.allowedFileTypes        = ["tif", "tiff"];
dialog.isFloatingPanel         = true;

if (dialog.runModal() == NSApplication.ModalResponse.OK)
{
  let result = dialog.url // Pathname of the file
  if (result != nil)
  {
    let path = result!.path
    print(path)
    exit(0)
  }
}

exit(1)

How could I display a NSOpenPanel that behaves normally? i.e.: can get the focus, can interact with mouse and keyboard, ...

The NSOpenPanel without focus


Solution

  • In this context (app without a window) you need to set the NSApplication activation policy to .accessory to activate the panel (there's also .regular but it would show a Dock icon and a menu bar).

    import AppKit
    
    NSApplication.shared.setActivationPolicy(.accessory)
    
    let dialog = NSOpenPanel()
    
    dialog.title                   = "Choose a .tif file or a folder"
    dialog.showsResizeIndicator    = true
    dialog.showsHiddenFiles        = false
    dialog.canChooseDirectories    = true
    dialog.canCreateDirectories    = true
    dialog.allowsMultipleSelection = false
    dialog.allowedFileTypes        = ["tif", "tiff"]
    dialog.isFloatingPanel         = true
    
    
    if (dialog.runModal() == NSApplication.ModalResponse.OK)
    {
        let result = dialog.url // Pathname of the file
        if (result != nil)
        {
            let path = result!.path
            print(path)
            exit(0)
        }
    }
    
    exit(1)