System UI Example: "Hello World!"

Learn how to write your first System UI.

The Hello World example with two applications running.

Note: Please read this if you want to build the example on a Linux machine.

Introduction

This example shows a very simple System UI implementation that showcases Qt Application Manager's fundamental building blocks.

The applications' icons and names are on the left. You can click on their respective icons to start and stop them. The column layout on the right shows their windows.

The applications display "Hello World!" against a background of a specific color.

Files and Folder Structure

This example comprises of four separate QML applications: a System UI and three sample applications: "Hello Red", "Hello Green" and "Hello Blue". The System UI is also a QML application, albeit a special one.

Each application is put in a separate directory as follows:

  • system-ui.qml
  • apps
    • hello-world.blue
      • icon.png
      • info.yaml
      • main.qml
    • hello-world.red
      • icon.png
      • info.yaml
      • main.qml
    • hello-world.green
      • icon.png
      • info.yaml
      • main.qml

Each application has a main.qml file, an icon, and an info.yaml. This YAML file contains application metadata such as the name of the application, its icon filename, and more.

Run the System UI

The compiled hello-world binary contains a complete application manager including the am-config.yaml configuration file and the System UI QML files.

The screenshot below is what you should see when running the binary:

CMake integration and ApplicationManager configuration

As said above the example binary contains the QML files and the am-config.yaml configuration file. This is done by adding all those files into the executable as follows in the CMakeLists.txt file:

qt_add_qml_module(hello-world
    URI SystemUI
    QML_FILES
        system-ui.qml
    RESOURCES
        am-config.yaml
)

The am-config.yaml file contains the configuration for the Application Manager. It specifies where the builtin applications can be found by setting applications/builtinAppsManifestDir to "${EXECUTABLE_DIR}/apps". In addition the configuration file specifies the location of the main QML file by setting ui/mainQml to "${CONFIG_DIR}/system-ui.qml".

For information on the contents of am-config.yaml and other command line options you can run appman –help or have a look at the Configuration documentation.

In addition to the System UI itself, the application packages also need to be added to our CMakeLists.txt file. This is done by adding the following lines:

qt_am_create_builtin_package(hello-world.blue
    OUTPUT_DIRECTORY apps/hello-world.blue
    INSTALL_DIRECTORY ${INSTALL_EXAMPLEDIR}/apps/hello-world.blue
    FILES
        apps/hello-world.blue/info.yaml
        apps/hello-world.blue/icon.png
        apps/hello-world.blue/main.qml
)

Implement the System UI

Like any simple QML application, our example's code starts with some imports and a plain Item at the root. The only difference is that our System UI also imports the QtApplicationManager.SystemUI module, besides QtQuick.

import QtQuick
import QtApplicationManager.SystemUI

Item {
    width: 800
    height: 600

Next, we have a Column on the left side of the root Item where we place the icons of the available applications along with their names.

    // Show application names and icons
    Column {
        spacing: 20
        Repeater {
            model: ApplicationManager
            Column {
                id: delegate
                required property bool isRunning
                required property var icon
                required property var application
                required property string name
                Image {
                    source: delegate.icon
                    MouseArea {
                        anchors.fill: parent
                        onClicked: delegate.isRunning ? delegate.application.stop()
                                                      : delegate.application.start()
                    }
                }
                Text {
                    font.pixelSize: 20
                    text: delegate.name
                }
            }
        }
    }

We use the ApplicationManager singleton, as a model, which provides a row for each application available. In each row, we have:

  • an icon role with the icon URL
  • a name role with the localized application's name
  • a boolean isRunning that provides the application's status
  • an application role that contains its ApplicationObject

For information on the other roles available, see ApplicationManager QML Type.

Clicking on an icon either starts its application or stops it if it's already running.

Next, we place a Column anchored to the right side of the root Item. In this column, we lay out the existing windows for all applications that are currently running:

    // Show windows
    Column {
        anchors.right: parent.right
        Repeater {
            model: WindowManager
            WindowItem {
                required property var model
                width: 600
                height: 200
                window: model.window
            }
        }
    }

This time, we use the WindowManager singleton as the model. There's a row for each window, with its WindowObject in the window role.

To have a window rendered in our System UI, we have to assign its WindowObject to a WindowItem, as we did above. By default, the window is resized to match the size of the WindowItem rendering it.

Implement the Application

Our Hello World applications display a "Hello World!" text against a colored background.

import QtQuick
import QtApplicationManager.Application

ApplicationManagerWindow {
    color: "blue"

    Text {
        anchors.centerIn: parent
        text: "Hello World!"
    }
}

The only difference between this example and a plain QML application is that the root element is an ApplicationManagerWindow, provided by the QtApplicationManager.Application module.

Application Metadata

The info.yaml file contains the metadata about an application. It starts with some boilerplate describing that this file contains Qt Application Manager package metadata.

formatVersion: 1
formatType: am-package
---

Then comes the package ID, which uniquely identifies the package. It's recommended to follow a reverse DNS scheme, but it's not enforced. Here it's the "Blue" package from the "Hello World" example UI.

id:      'hello-world.blue'

Then the icon filename:

icon:    'icon.png'

Following comes the user-visible name of the package in any number of languages. For this example, we only provide English:

name:
  en: 'Hello Blue'

After this package level metadata, any number of applications can be added. In this simple example we define exactly one application and give it the same application id as the package. Since the application does not have an icon or name, it will inherit the package's icon and name.

applications:
- id:      'hello-world.blue'

The code field specifies the entry point of the application. For QML applications, this means the filename of its main QML file.

  code:    'main.qml'

The runtime field specifies the runtime used by the application. In this example, all applications are written in QML and hence we use the 'qml' runtime. Another runtime is 'native' for instance, used for compiled, executable, applications where the code entry would point to its binary executable filename.

  runtime: 'qml'

Example project @ code.qt.io

© 2024 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.