Main Program
The following portability considerations affect the form of the main program:
To build an executable with Poly/ML, a single function of type unit -> unit is required for the main program.
In the event of an unhandled exception at the top-level, an executable built with some compilers may not report it nor exit with a non-zero status, so it is recommended that the main program explicitly does this to aid diagnostics.
With this in mind, a portable main program may have the following form:
fun main () =
let
…
in
Giraffe.exit status
end
handle e => Giraffe.error 1 ["Uncaught exception\n", exnMessage e, "\n"]
For convenience, functions from the special structure Giraffe are used to exit the application.
To build an executable from the main program, see the sections on building with MLton and Poly/ML.
The main program typically performs some initial set up and then runs an event loop. There is more than one way to do this for a GTK application, as shown in the following sections.
A non-GTK program may use GLib without running an event loop. Such a program simply needs to initialize the GObject dynamic type system using GObject.typeInit if the version of GLib is older than 2.36. This function is deprecated and has no effect since GLib 2.36.
fun main () =
let
val () = GObject.typeInit () (* in case GLib < 2.36 *)
…
in
Giraffe.exit status
end
handle e => Giraffe.error 1 ["Uncaught exception\n", exnMessage e, "\n"]
Using the class Gtk.Application
For a GTK application, the class Gtk.Application, based on Gio.Application, provides many useful features. Using this class, a main program could have the following form:
fun main () =
let
val app = Gtk.Application.new (SOME appId, Gio.ApplicationFlags.flags […])
…
val argv = Utf8CPtrArrayN.fromList (CommandLine.name () :: CommandLine.arguments ())
val status = Gio.Application.run app argv
in
Giraffe.exit status
end
handle e => Giraffe.error 1 ["Uncaught exception\n", exnMessage e, "\n"]
It is common to set up GTK objects in the handler for the “activate” signal as follows:
fun activate app () =
let
… (* set up *)
in
()
end
fun main () =
let
val app = Gtk.Application.new (SOME appId, Gio.ApplicationFlags.flags [])
val id = Signal.connect app (Gio.Application.activateSig, activate app)
val argv = Utf8CPtrArrayN.fromList (CommandLine.name () :: CommandLine.arguments ())
val status = Gio.Application.run app argv
val () = Signal.handlerDisconnect app id
in
Giraffe.exit status
end
handle e => Giraffe.error 1 ["Uncaught exception\n", exnMessage e, "\n"]
Using Gtk.init and Gtk.main
The class Gtk.Application was not available in GTK 2 and applications were required to use Gtk.init and Gtk.main to initialize GTK and run an event loop. This approach is still possible with GTK 3. Using this approach, a main program could have the following form:
fun main () =
let
val argv = Utf8CPtrArrayN.fromList (CommandLine.name () :: CommandLine.arguments ())
val … = Gtk.init argv
… (* set up *)
val () = Gtk.main ()
in
Giraffe.exit 0
end
handle e => Giraffe.error 1 ["Uncaught exception\n", exnMessage e, "\n"]
Gtk.init initializes GTK and parses command line options. The function should be passed the command line (program name and arguments) and returns any arguments not consumed by GTK.
Gtk.main enters the GTK main loop. The main loop runs until Gtk.mainQuit is called (from a signal handler) whereupon Gtk.main returns.