Application
Object Hierarchy:
Description:
[ Version ( since = "2.28" ) ]
public class Application : Object, ActionGroup, ActionMap
`GApplication` is the core class for application support.
A `GApplication` is the foundation of an application. It wraps some low-level platform-specific services and is intended to act as the foundation for higher-level application classes such as `GtkApplication` or `MxApplication`. In general, you should not use this class outside of a higher level framework.
`GApplication` provides convenient life-cycle management by maintaining a "use count" for the primary application instance. The use count can be changed using [method@Gio.Application.hold] and [method@Gio.Application.release]. If it drops to zero, the application exits. Higher-level classes such as `GtkApplication` employ the use count to ensure that the application stays alive as long as it has any opened windows.
Another feature that `GApplication` (optionally) provides is process uniqueness. Applications can make use of this functionality by providing a unique application ID. If given, only one application with this ID can be running at a time per session. The session concept is platform-dependent, but corresponds roughly to a graphical desktop login. When your application is launched again, its arguments are passed through platform communication to the already running program. The already running instance of the program is called the "primary instance"; for non-unique applications this is always the current instance. On Linux, the D-Bus session bus is used for communication.
The use of `GApplication` differs from some other commonly-used uniqueness libraries (such as libunique) in important ways. The application is
not expected to manually register itself and check if it is the primary instance. Instead, the main
function of a `GApplication`
should do very little more than instantiating the application instance, possibly connecting signal handlers, then calling [
method@Gio.Application.run]. All checks for uniqueness are done internally. If the application is the primary instance then the startup signal
is emitted and the mainloop runs. If the application is not the primary instance then a signal is sent to the primary instance and [
method@Gio.Application.run] promptly returns. See the code examples below.
If used, the expected form of an application identifier is the same as that of a D-Bus well-known bus name. Examples include: `com.example.MyApp`, `org.example.internal_apps.Calculator`, `org._7_zip.Archiver`. For details on valid application identifiers, see [func@Gio.Application.id_is_valid].
On Linux, the application identifier is claimed as a well-known bus name on the user's session bus. This means that the uniqueness of your application is scoped to the current session. It also means that your application may provide additional services (through registration of other object paths) at that bus name. The registration of these object paths should be done with the shared GDBus session bus. Note that due to the internal architecture of GDBus, method calls can be dispatched at any time (even if a main loop is not running). For this reason, you must ensure that any object paths that you wish to register are registered before Application attempts to acquire the bus name of your application (which happens in [method@Gio.Application.register]). Unfortunately, this means that you cannot use [ property@Gio.Application:is-remote] to decide if you want to register object paths.
`GApplication` also implements the [iface@Gio.ActionGroup] and [iface@Gio.ActionMap] interfaces and lets you easily export actions by adding them with [method@Gio.ActionMap.add_action]. When invoking an action by calling [method@Gio.ActionGroup.activate_action] on the application, it is always invoked in the primary instance. The actions are also exported on the session bus, and GIO provides the [class@Gio.DBusActionGroup] wrapper to conveniently access them remotely. GIO provides a [class@Gio.DBusMenuModel] wrapper for remote access to exported [ class@Gio.MenuModel]s.
Note: Due to the fact that actions are exported on the session bus, using `maybe` parameters is not supported, since D-Bus does not support `maybe` types.
There is a number of different entry points into a `GApplication`:
- via 'Activate' (i.e. just starting the application)
- via 'Open' (i.e. opening some files)
- by handling a command-line
- via activating an action
The [signal@Gio.Application:GApplication:startup
] signal lets you handle the application initialization for all of these in a
single place.
Regardless of which of these entry points is used to start the application, `GApplication` passes some ‘platform data’ from the launching instance to the primary instance, in the form of a [struct@GLib.Variant] dictionary mapping strings to variants. To use platform data, override the [vfunc@Gio.Application.before_emit] or [vfunc@Gio.Application.after_emit] virtual functions in your `GApplication` subclass. When dealing with [class@Gio.ApplicationCommandLine] objects, the platform data is directly available via [method@Gio.ApplicationCommandLine.get_cwd], [ method@Gio.ApplicationCommandLine.get_environ] and [method@Gio.ApplicationCommandLine.get_platform_data].
As the name indicates, the platform data may vary depending on the operating system, but it always includes the current directory (key `cwd`), and optionally the environment (ie the set of environment variables and their values) of the calling process (key `environ`). The environment is only added to the platform data if the `G_APPLICATION_SEND_ENVIRONMENT` flag is set. `GApplication` subclasses can add their own platform data by overriding the [vfunc@Gio.Application.add_platform_data] virtual function. For instance, `GtkApplication` adds startup notification data in this way.
To parse commandline arguments you may handle the [signal@Gio.Application:GApplication:command-line
] signal or override the [
vfunc@Gio.Application.local_command_line] virtual funcion, to parse them in either the primary instance or the local instance, respectively.
For an example of opening files with a `GApplication`, see gapplication-example-open.c.
For an example of using actions with `GApplication`, see gapplication-example-actions.c.
For an example of using extra D-Bus hooks with `GApplication`, see gapplication-example-dbushooks.c.
Example: Opening files with a GLib.Application::
public class MyApplication : Application {
private MyApplication () {
Object (application_id: "org.example.application", flags: ApplicationFlags.HANDLES_OPEN);
set_inactivity_timeout (10000);
}
public override void activate () {
// NOTE: when doing a longer-lasting action here that returns
// to the mainloop, you should use g_application_hold() and
// g_application_release() to keep the application alive until
// the action is completed.
print ("activated\n");
}
public override void open (File[] files, string hint) {
// NOTE: when doing a longer-lasting action here that returns
// to the mainloop, you should use g_application_hold() and
// g_application_release() to keep the application alive until
// the action is completed.
foreach (File file in files) {
string uri = file.get_uri ();
print (@"$uri\n");
}
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
int status = app.run (args);
return status;
}
}
valac --pkg gio-2.0 GLib.Application.0.vala
Example: Application with actions::
public class MyApplication : Application {
private MyApplication () {
Object (application_id: "org.example.application", flags: 0);
set_inactivity_timeout (10000);
add_actions ();
}
private void add_actions () {
SimpleAction simple_action = new SimpleAction ("simple-action", null);
simple_action.activate.connect (() => {
this.hold ();
print ("Simple action %s activated\n", simple_action.get_name ());
this.release ();
});
this.add_action (simple_action);
SimpleAction stateful_action = new SimpleAction.stateful ("toggle-action", null, new Variant.boolean (false));
stateful_action.activate.connect (() => {
print ("Action %s activated\n", stateful_action.get_name ());
this.hold ();
Variant state = stateful_action.get_state ();
bool b = state.get_boolean ();
stateful_action.set_state (new Variant.boolean (!b));
print (@"State change $b -> $(!b)\n");
this.release ();
});
this.add_action (stateful_action);
}
public override void activate () {
this.hold ();
print ("Activated\n");
this.release ();
}
private void describe_and_activate_action (string name) {
VariantType param_type = this.get_action_parameter_type (name);
Variant state = this.get_action_state (name);
bool enabled = this.get_action_enabled (name);
print (@"Action name: $name\n");
string? type = (param_type != null) ? param_type.dup_string () : "<none>";
print (@"Parameter type: $type\n");
print ("State type: %s\n", (state != null) ? state.get_type_string () : "<none>");
string state_val = (state != null) ? state.print (false) : "<none>";
print (@"State: $state_val\n");
print (@"Enabled: $enabled\n");
this.activate_action (name, null);
}
public static int main (string[] args) {
try {
MyApplication app = new MyApplication ();
if (args.length > 1) {
if (args[1] == "--simple-action") {
app.register (null);
app.describe_and_activate_action ("simple-action");
Process.exit (0);
} else if (args[1] == "--toggle-action") {
app.register (null);
app.describe_and_activate_action ("toggle-action");
Process.exit (0);
}
}
int status = app.run (args);
return status;
} catch (Error e) {
print ("Error: %s\n", e.message);
return 0;
}
}
}
valac --pkg gio-2.0 GLib.Application.1.vala
Example: Application with actions::
public class MyApplication : Application {
private MyApplication () {
Object (application_id: "org.example.application", flags: 0);
set_inactivity_timeout (10000);
add_actions ();
}
private void add_actions () {
SimpleAction simple_action = new SimpleAction ("simple-action", null);
simple_action.activate.connect (() => {
this.hold ();
print ("Simple action %s activated\n", simple_action.get_name ());
this.release ();
});
this.add_action (simple_action);
SimpleAction stateful_action = new SimpleAction.stateful ("toggle-action", null, new Variant.boolean (false));
stateful_action.activate.connect (() => {
print ("Action %s activated\n", stateful_action.get_name ());
this.hold ();
Variant state = stateful_action.get_state ();
bool b = state.get_boolean ();
stateful_action.set_state (new Variant.boolean (!b));
print (@"State change $b -> $(!b)\n");
this.release ();
});
this.add_action (stateful_action);
}
public override void activate () {
this.hold ();
print ("Activated\n");
this.release ();
}
private void describe_and_activate_action (string name) {
VariantType param_type = this.get_action_parameter_type (name);
Variant state = this.get_action_state (name);
bool enabled = this.get_action_enabled (name);
print (@"Action name: $name\n");
string? type = (param_type != null) ? param_type.dup_string () : "<none>";
print (@"Parameter type: $type\n");
print ("State type: %s\n", (state != null) ? state.get_type_string () : "<none>");
string state_val = (state != null) ? state.print (false) : "<none>";
print (@"State: $state_val\n");
print (@"Enabled: $enabled\n");
this.activate_action (name, null);
}
public static int main (string[] args) {
try {
MyApplication app = new MyApplication ();
if (args.length > 1) {
if (args[1] == "--simple-action") {
app.register (null);
app.describe_and_activate_action ("simple-action");
Process.exit (0);
} else if (args[1] == "--toggle-action") {
app.register (null);
app.describe_and_activate_action ("toggle-action");
Process.exit (0);
}
}
int status = app.run (args);
return status;
} catch (Error e) {
print ("Error: %s\n", e.message);
return 0;
}
}
}
valac --pkg gio-2.0 GLib.Application.1.vala
Example: Using extra D-Bus hooks with a GLib.Application::
public class MyApplication : Application {
private MyApplication () {
Object (application_id: "org.example.application", flags: 0);
set_inactivity_timeout (10000);
}
public override void activate () {
// NOTE: when doing a longer-lasting action here that returns
// to the mainloop, you should use g_application_hold() and
// g_application_release() to keep the application alive until
// the action is completed.
print ("Activated\n");
}
public override bool dbus_register (DBusConnection connection, string object_path) throws Error {
// We must chain up to the parent class:
base.dbus_register (connection, object_path);
// Now we can do our own stuff here. For example, we could export some D-Bus objects
return true;
}
public override void dbus_unregister (DBusConnection connection, string object_path) {
// Do our own stuff here, e.g. unexport any D-Bus objects we exported in the dbus_register
// hook above. Be sure to check that we actually did export them, since the hook
// above might have returned early due to the parent class' hook returning false!
base.dbus_unregister (connection, object_path);
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
int status = app.run (args);
return status;
}
}
valac --pkg gio-2.0 GLib.Application.3.vala
Example: Commandline-handling and GLib.Applications:
public class MyApplication : Application {
private int counter = 0;
private MyApplication () {
Object (application_id: "org.example.application", flags: ApplicationFlags.HANDLES_COMMAND_LINE);
set_inactivity_timeout (10000);
}
public override void activate () {
this.hold ();
print ("Activated\n");
this.release ();
}
private int _command_line (ApplicationCommandLine command_line) {
bool version = false;
bool count = false;
OptionEntry[] options = new OptionEntry[2];
options[0] = { "version", 0, 0, OptionArg.NONE, ref version, "Display version number", null };
options[1] = { "count", 0, 0, OptionArg.NONE, ref count, "Display version number", null };
// We have to make an extra copy of the array, since .parse assumes
// that it can remove strings from the array without freeing them.
string[] args = command_line.get_arguments ();
string*[] _args = new string[args.length];
for (int i = 0; i < args.length; i++) {
_args[i] = args[i];
}
try {
var opt_context = new OptionContext ("- OptionContext example");
opt_context.set_help_enabled (true);
opt_context.add_main_entries (options, null);
unowned string[] tmp = _args;
opt_context.parse (ref tmp);
} catch (OptionError e) {
command_line.print ("error: %s\n", e.message);
command_line.print ("Run '%s --help' to see a full list of available command line options.\n", args[0]);
return 0;
}
if (version) {
command_line.print ("Test 0.1\n");
return 0;
}
if (count) {
command_line.print ("%d\n", ++this.counter);
return 0;
}
return 0;
}
public override int command_line (ApplicationCommandLine command_line) {
// keep the application running until we are done with this commandline
this.hold ();
int res = _command_line (command_line);
this.release ();
return res;
}
public static int main (string[] args) {
MyApplication app = new MyApplication ();
int status = app.run (args);
return status;
}
}
valac --pkg gio-2.0 GLib.Application.4.vala