// Copyright (C) 2021 The Qt Company Ltd. // Copyright (C) 2019 Luxoft Sweden AB // Copyright (C) 2018 Pelagicore AG // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only /*! \page howto-apps.html \ingroup qtappman \ingroup qtappman-highlights \title Writing Applications \brief Discusses writing an application to run as a client within the application manager. Writing an application to run as a client within the application manager is similar to writing a stand-alone QML application, except for these three additional tasks or limitations: \list 1 \li If you write a QML application, make your QML scene's root element an ApplicationManagerWindow; or derive your own custom root item from it. \li Provide a valid \l{Manifest definition}{info.yaml} file. \li Restart the application manager to make it aware of your application. \endlist \section2 The Root Element It's recommended to use either an ApplicationManagerWindow or a QtObject as the root of your QML application. This is especially important if you require similar behavior in single-process and multi-process mode. If you use a QtObject, any visible base elements should still be \l{ApplicationManagerWindow}{ApplicationManagerWindows}. Nevertheless, other root elements are supported for convenience, as well. Here are a few things to consider: \list \li Only \l{ApplicationManagerWindow}{ApplicationManagerWindows} support window properties that are shared between the System UI and the client applications. \li In multi-process mode, \l Window root elements always get a decoration (unless you set QT_WAYLAND_DISABLE_WINDOWDECORATION) and are invisible by default. QQuick \l{Item}{Items} are wrapped inside a \l Window representing a Wayland client window. \li In single-process mode \l Window root elements appear parallel to instead of inside the System UI. \endlist \section2 The Manifest and Updating the Database The \l{Manifest Definition} has all the information you need to produce a minimal \c info.yaml file. Finding and and parsing \c info.yaml files recursively, for potentially hundreds of applications can be a very time consuming task and would severely slow down the application manager's startup. Therefore, all manifest files are cached in a binary database. To notify the application manager about changes to an \c info.yaml file, you have to force a rebuild of this database by calling \c{appman --recreate-database}. \note Dynamically adding, updating, or removing individual applications is supported via the ApplicationInstaller interface. \section2 qmake Integration To install applications into a System UI using the \l{Installer}{Installer Sub-System}, the application needs to be packaged first. This can be done using the \l{Packager} utility. To better integrate the packaging into your usual developer workflow you can also use the qmake integration provided. The integration adds an additional \c{package} target to the Makefile. You can create a new application in one of two ways: \list \li Call \c{make package} on the command line. \li Add \c{make package} as an additional build step in QtCreator. \endlist \section3 Simple QML Applications For simple QML-only applications, create a qmake project file which defines an install step for all the needed files. The actual install location doesn't matter in this case, because it is used as a temporary path when the package is being created. \code TEMPLATE = aux FILES += info.yaml \ icon.png \ Main.qml app.files = $$FILES app.path = /apps/com.example.application INSTALLS += app \endcode In addition add the following two lines to provide the install location to the packaging step and to load the qmake integration. \code AM_PACKAGE_DIR = $$app.path load(am-app) \endcode \section3 Complex Applications For complex applications, where you need to deploy a C++ based QML plugin in addition to your QML content, you must split your app into multiple folders and project files. One folder for the QML part, another one for the C++ plugin, and a \c SUBDIRS project to glue them together. The packaging integration is done in the \c SUBDIRS project and this process expects that the other project files provide install targets to a shared install location. In this case, the QML part installs its files in \c{/apps/com.example.application}, while the C++ plugin installs in \c{/apps/com.example.application/imports/com/example/application}. In the \c SUBDIRS project you need to define the \c AM_MANIFEST variable and set it to the location of your \c info.yaml file. Then, define the shared install location as \c AM_PACKAGE_DIR: \code AM_MANIFEST = $$PWD/app/info.yaml AM_PACKAGE_DIR = /apps/com.example.application load(am-app) \endcode \section3 Package Multiple Applications If your repository provides multiple applications, like the \l{http://code.qt.io/cgit/qt-apps/qt-auto-extra-apps.git/}{Qt Auto Extra Apps Repository}, you can use qmake's am-package feature to provide a repository-wide \c{package} step. Add a \c{.qmake.conf} file with the following content to your repository, which is loaded automatically by qmake: \code CONFIG += am-package \endcode */