Search code examples
user-interfacemacoscommand-linewxwidgetsbundle

wxWidgets Commandline / GUI Hybrid Application Fails to Get Dialog Input


I have a command-line application written in C++ and built with gcc/make that runs on MacOS. This application does not have its own GUI and it not supposed to have any root windows -- it's a console app meant to be controlled by another application.

However, there is a need to show a file selection dialog at one point, which makes this a bit of a hybrid.

I've used wxWidgets to create the dialog, but it fails to get input. I've seen in the various FAQs and user groups that a bundle is probably required. When I tried to create a bundle it didn't solve the problem.

Here's how wxWidgets is initialized:

#ifdef __WXMAC__
    if (!wxEntryStart(argc, argv))
    {
        cout << "Failed to initialize wxWidgets." << endl;
        return 0;  
    }
#endif
    clientApp = new MainClass();
    clientApp->Run(argc, argv);
#ifdef __WXMAC__   
    wxEntryCleanup();
#endif

When I try to show a browse file dialog, using this code, it shows the file chooser but does not respond, acting like it has no message pump:

#ifdef __WXMAC__
    wxFileDialog* dlg = new wxFileDialog( NULL, _("Upload File"), _(""), _(""),
        _("All Files (*.*)|*.*"), wxFD_OPEN|wxFD_FILE_MUST_EXIST );
    if (dlg->ShowModal() == wxID_CANCEL )
    {
        INFOLOG("File upload dialog has been cancelled." << endl )
        return false;
    }
#endif

Since the FAQs say that creating a bundle is a way to automagically create a message pump and make a GUI responsive. I tried creating a bundle:

myapp.app --> Contents --> MacOS --> myapp (executable file) --> cert.crt (ssl certificate used by app) --> Resources --> myapp.icns --> Info.plist (points ot myapp as executable and uses myapp.icns as icon)

The application controlling this is not one I have control over and has to run it in exactly this way:

myapp

The controlling app needs to read the console output of this app and that is primarily why this has been a console-only app.

Since the executable is a few directories deeper, I tried creating a shell script in the root directory above the bundle to run the application and calling it myapp. Myapp just runs myapp.app/Contents/MacOS/myapp, forwarding the commandline parameters.

This didn't work. The browse file window is created and just sits there, giving me the rainbow spinwheel every time I mouse over it.

What can I do to get a message pump going? Is there a call I can add to the wxWidgets code or do I need to do something differnently with the bundle? Does having the shell script launch the app that is inside the bundle completely defeat the "message pump magic" that the bundle is supposed to give, and if so, is there a sensible workaround? Do I just need to create some sort of pseudo-parent for the wxFileDialog?


Solution

  • I've heard reports that an alternative to creating an application bundle is to use the following code (which I never recommend to anyone over a bundle, but it sounds like your situation is a good reason to use it):

    #include <ApplicationServices/ApplicationServices.h>
    
    ProcessSerialNumber PSN;
    GetCurrentProcess(&PSN);
    TransformProcessType(&PSN,kProcessTransformToForegroundApplication);
    

    This is of course platform specific, so wrap it accordingly.

    Do you have a derived wxApp, and wxApp::OnInit()? These are likely still required to initialize the event loop.