Application Start-up Patterns

From Qt Wiki
Jump to navigation Jump to search

There are various ways that different platforms support third-party software (e.g. us and our clients) starting a process. The need to fit into each of these constrains the architecture of Qt. We document them here to help illustrate what's needed from our architecture and what the pain points are in the present architecture.

Traditional C main()

This is the simple entry-point where your application is a function – int main(int count, char *args[]) – that gets called by the environment. Your application is started by main() being called and exits when main() returns. Whatever happens in your main() is all your program does.

Since modern applications are generally interactive, this architecture requires that we support an event loop (which other architectures may provide for us). Archetypical (albeit not quite real) code for it looks like:

int main(int count, char *args[])
{
    QApplication app(count, args); // prepare application global state
    // optional set-up
    return app.exec(); // run event loop
}

macOS / Objective C

  • Define application delegate with app lifecycle callbacks:
  @interface AppDelegate ()
  @end

  @implementation AppDelegate
  - (void)applicationDidFinishLaunching:(NSNotification *)aNotification {
     // Init application here
  }

  - (void)applicationWillTerminate:(NSNotification *)aNotification {
     // Tear down here
  }
  @end
  • In main, install application delegate and start the app:
  int main(int argc, const char *argv[])
  {
       NSApplication *app = [NSApplication sharedApplication];
       app.delegate = [[AppDelegate alloc] initWithArgc:argc argv:argv];
       return NSApplicationMain(argc, argv);
  }

The init code selects and loads a platform plugin, and then asks that platform plugin to create an event dispatcher, which hooks into the native event queue.

The Qt event dispatcher implementation on macOS supports integrating with an already running event loop, which is the case here. Calling app.exec() is not required (and would not work in the callback).

NaCl (Native Client)

Define pp::CreateModule() and return the application module (which is a subclass of pp::Module):

  namespace pp {
    Module* CreateModule() {
       return new ApplicationModule();
    }
  }

emscripten

Implement main():

  int main(int argc, const char *argv[) {
     // Init application here
     return 0;
  }

main() should/must return to keep the web page responsive. There is API for simulating a main that does not return and preserve the stack, see emscripten_set_main_loop()</kdb> in the emscripten documentation.