0

I have C++ console application getting written in XCode, and I need to open a file selector dialog. To do this I'm using Cocoa with objective-c. I'm trying to open an NSOpenPanel to use it for this purpose. I'm using the following code currently:

const char* openDialog()
{
    NSOpenPanel* openDlg = [NSOpenPanel openPanel];
    [openDlg setCanChooseFiles:YES];
    [openDlg setFloatingPanel:YES];

    if ( [openDlg runModal] == NSOKButton )
    {
        for( NSURL* URL in [openDlg URLs] )
        {
            NSLog( @"%@", [URL path] );     
            return [URL.path UTF8String];
        }
    }
    
    return NULL;
}

This works, however the created file selector doesnt accept mouse and keyboard events properly. It's hard to explain, but for example when I run the code from XCode when hovering above the window the mouse still behaves as if were in XCode, showing the caret symbol. When i run the application from the terminal whenever I type something it sends the input to the terminal, even though the file selector is "in front". Command clicking gives the mouse events properly to the file selector though.

I looked through NSOpenPanel's documentation and googled the problem extensively but I couldn't find an answer to this.

Á. Márton
  • 497
  • 1
  • 3
  • 21
  • There is an example here: https://www.dropbox.com/s/n2ly8qkgh7j5r93/openfile.m.zip?dl=0. If it's helpful I'll post as answer. Problem may be the main.m that you are using. Demo does not use nibs. – apodidae Nov 13 '21 at 21:45
  • Does this answer your question? [NSOpenPanel cannot get focus](https://stackoverflow.com/questions/62324273/nsopenpanel-cannot-get-focus) – Willeke Nov 14 '21 at 01:09
  • @Willeke No it doesn't, since that answer is for Swift. How do I do the same thing in objective c? – Á. Márton Nov 14 '21 at 14:11
  • @apodidae Which part of the dropbox code is meant to solve my problem? – Á. Márton Nov 14 '21 at 14:23
  • Take a look at the main.m that you are using. I think that it is this line: NSApplication *application = [NSApplication sharedApplication]; Does my example run ok? – apodidae Nov 14 '21 at 15:25
  • The answer says "In this context (app without a window) you need to set the NSApplication activation policy to .accessory to activate the panel". Try to translate `NSApplication.shared.setActivationPolicy(.accessory)`. – Willeke Nov 14 '21 at 16:26
  • Just for grins: Run your non-workable code. Is the open button grayed out? If so, select the file that you want to see and drag it to the left so that it highlights. Does the open button become active? If so hit open and you should see the name of the file displayed in the Terminal window. I doubt that you want this interface, but that works on my system without any NSApplication code. Just an observation. – apodidae Nov 14 '21 at 17:07
  • @Willeke Okay, but how do I do that in objective c? I don't know neither swift, nor objective c, i tried googling the problem but no avail. NSApplication doesnt have a setActivationPolicy method for me. Heres the line I figured would be the equivalent: NSApplication.sharedApplication.setActivationPolicy:YES; However this method doesnt exist, the compiler says. – Á. Márton Nov 14 '21 at 17:13
  • @apodidae I don't have a main.m. My main is a c++ main.cpp. I'm not writing an objective c application, I'm writing a c++ application, but you can't access the relevant Cocoa API functions from C++, so I need to use objective c. I'm sure your example works, but I can't just copy it, that would achieve nothing. I need a standalone file selector dialog. – Á. Márton Nov 14 '21 at 17:16
  • @apodidae As I stated in the question the dialog works if I command click. It needs to work without command click. What works on your system? What's the minimal objective C code that works on your system for opening a file selector dialog? – Á. Márton Nov 14 '21 at 17:20
  • Just a dialog is here: https://www.dropbox.com/s/nueqhij3d1bnddn/openpanel.m.zip?dl=0. Are you using .mm file (for mixed cpp and objc)? – apodidae Nov 14 '21 at 17:27
  • This works on my system using @Willeke 's suggestion: https://www.dropbox.com/s/og5amknw7lwrw2w/openpanel2.m.zip?dl=0. The translation is: NSApplication *application = [NSApplication sharedApplication]; [application setActivationPolicy:NSApplicationActivationPolicyAccessory]; – apodidae Nov 14 '21 at 17:51
  • You don't need `[NSApp run]`. – Willeke Nov 14 '21 at 18:04

1 Answers1

1
/*
To run in Terminal: clang openpanel.m -fobjc-arc -framework Cocoa -o openpanel && ./openpanel
*/

#import <Cocoa/Cocoa.h>

int main() {
 NSApplication *application = [NSApplication sharedApplication]; 
 [application setActivationPolicy:NSApplicationActivationPolicyAccessory];
 NSOpenPanel* openDlg = [NSOpenPanel openPanel];
 [openDlg setCanChooseFiles:YES];
 [openDlg setFloatingPanel:YES];

 if ( [openDlg runModal] == NSModalResponseOK ) {
   for( NSURL* URL in [openDlg URLs] ) {
     NSLog( @"%@", [URL path] );     
   }
 }  
 return 0;
}

Thanks to @Willeke.

apodidae
  • 1,988
  • 2
  • 5
  • 9
  • Yes, this works! Thank you! What does application mean in this context? When I'm running this code from my C++ app does application refer to the whole thing or just to the file selector dialog? – Á. Márton Nov 14 '21 at 19:32
  • The following is a quote from Xcode/Help/DeveloperDocumentation/NSApplication: "Every app uses a single instance of NSApplication to control the main event loop, keep track of the app’s windows and menus, distribute events to the appropriate objects (that’s, itself or one of its windows), set up autorelease pools, and receive notification of app-level events." It can do a lot. – apodidae Nov 14 '21 at 20:10
  • I tried to edit your post but wouldn't let me. Before returning we need to set the activation policy back so that our app does not disappear from the dock. [application setActivationPolicy:NSApplicationActivationPolicyRegular]; – Á. Márton Nov 19 '21 at 20:47