1

I need to open a modal dialog on macOS from C++ application from the plugin level - no access to any existing windows, handles, etc (the application is written in QT). So basically I have a handler in which I need to construct the window and show it, and then continue after the dialog is closed.

How should I proceed?

I created xib/nib (Window.nib) file in Xcode, included it in Resources folder of my plugin bundle and then invoked this (compiled in *.mm file):

NSWindowController * windowController = 
    [[NSWindowController alloc] initWithWindowNibName:@"Window"];
[[NSApplication sharedApplication] runModalForWindow: 
    windowController.window];

but looks like the second line is failing. Perhaps I'm not running it in the UI thread? Any pointers what else I can try?

hateom
  • 21
  • 4

1 Answers1

0

First try making a new window in code like here: How do I create a Cocoa window programmatically?

And wrap all the code to run in the main thread.

This worked for me:

MyDialog (NSWindowController)

@interface MyDialog : NSWindowController
- (instancetype)initWithFrame:(NSRect)frame;
- (void)runModal;
@end

@implementation MyDialog

- (instancetype)initWithFrame:(NSRect)frame {
    NSWindowStyleMask windowMask = NSWindowStyleMaskTitled
        | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
    NSWindow *window = [[NSWindow alloc] initWithContentRect:frame
                                                   styleMask:windowMask
                                                     backing:NSBackingStoreBuffered
                                                       defer:NO];

    [NSNotificationCenter.defaultCenter addObserver:self
                                           selector:@selector(windowWillClose:)
                                               name:NSWindowWillCloseNotification
                                             object:nil];
    return [super initWithWindow:window];
}

- (void)dealloc {
    [NSNotificationCenter.defaultCenter removeObserver:self];
}

- (void)runModal {
    [[NSApplication sharedApplication] runModalForWindow:self.window];
}

- (void)windowWillClose:(NSNotification *)notification {
    [[NSApplication sharedApplication] stopModal];
}

@end

Inside presenting function:

[NSOperationQueue.mainQueue addOperationWithBlock:^{
    NSRect frame = NSMakeRect(0, 0, 200, 200);
    MyDialog *dialog = [[MyDialog alloc] initWithFrame:frame];
    [dialog runModal];
    NSLog(@"done");
}];

If that works, you can probably achieve the same result with a help of your Window.xib, but you need to make sure that the corresponding Window.nib file (a compiled xib) is present and it is possible to find it in runtime from your plugin. If you place this file somewhere in plugin resources, you could use initWithWindowNibPath: to specify the full path to it.

battlmonstr
  • 5,841
  • 1
  • 23
  • 33
  • 1
    One more question - would it be possible to open a modal window like in the above example but allowing other modal windows to be shown? I encountered a situation where the host application invokes a small window with the "Autosave" progress while my window is open and it's making the whole application getting stuck forever. – hateom Aug 30 '18 at 10:41
  • Most likely not. To be on a safe side I would spawn a completely separate standalone window, and waited for it somehow. – battlmonstr Aug 31 '18 at 08:20