summaryrefslogtreecommitdiffstats
path: root/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc
blob: c2dfa68511ec4430c3b933cc78c4fdbc1def5082 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/****************************************************************************
**
** Copyright (C) 2018 Pelagicore AG
** Contact: https://www.qt.io/licensing/
**
** This file is part of the documentation of the Pelagicore Application Manager.
**
** $QT_BEGIN_LICENSE:FDL-QTAS$
** Commercial License Usage
** Licensees holding valid commercial Qt Automotive Suite licenses may use
** this file in accordance with the commercial license agreement provided
** with the Software or, alternatively, in accordance with the terms
** contained in a written agreement between you and The Qt Company.  For
** licensing terms and conditions see https://www.qt.io/terms-conditions.
** For further information use the contact form at https://www.qt.io/contact-us.
**
** GNU Free Documentation License Usage
** Alternatively, this file may be used under the terms of the GNU Free
** Documentation License version 1.3 as published by the Free Software
** Foundation and appearing in the file included in the packaging of
** this file. Please review the following information to ensure
** the GNU Free Documentation License version 1.3 requirements
** will be met: https://www.gnu.org/licenses/fdl-1.3.html.
** $QT_END_LICENSE$
**
****************************************************************************/

/*!

\example applicationmanager/minidesk
\title Desktop System-UI Example
\image minidesk.png Screenshot
\brief Minimal Desktop System-UI in pure QML
\ingroup applicationmanager-examples

\section1 Introduction

The \e {Desktop System-UI Example} showcases the application-manager API in a simple fashion. The
focus is on the concepts, less on elegance or completeness, for instance no error checking is done.
Some features will only print debug messages without further functionality. A classic desktop with
server-side window decorations is emulated.

The following features are supported:
\list
\li Start applications by clicking an icon on the top left
\li Stop applications by clicking on the top/left window decoration rectangle
\li Raise applications by clicking on the decoration
\li Drag windows by pressing on the window decoration and moving
\li System-UI sends 'propA' change when an app is started
\li System-UI and App2 react on window property changes with a debug message
\li App1 animation can be stopped and restarted by a click
\li App1 sends 'rotation' property to System-UI on stop
\li App1 shows a pop-up on the System-UI while it is paused
\li App2 will make use of an IPC extension when it is started
\li App2 logs the document URL it has been started with
\li App2 triggers a notification in the System-UI when the bulb icon is clicked
\li A separate (\"wayland\") process started outside of appman will be shown as App1
\endlist

\note The example can be run in single- and multi-process mode. In the following, multi-process is
assumed and corresponding terminology is used. The terms \e client and \e application, respectively
\e server and \e {System-UI} are used interchangeably. The System-UI comprises compositing and
generic inter-process communication (IPC).

\section2 Invocation
The example can be started from within the minidesk folder with:
\badcode
path/to/bin/appman -c am-config.yaml -r
\endcode

\note The application-manager attempts to register a \c freedesktop.org compliant notification
server. DBus errors might occur if it conflicts with the server running on the host desktop
environment. In this case, a private session bus needs to be started by adding the
\c --start-session-dbus option:
\badcode
path/to/bin/appman -c am-config.yaml -r --start-session-dbus
\endcode

\section1 Walkthrough

\section2 System-UI Window

\quotefromfile applicationmanager/minidesk/system-ui/main.qml
\skipto import Qt
\printuntil text:
\printline }
\dots

The \l{QtApplicationManager.SystemUI} module has to be imported to be able to access the application-manager
APIs. The System-UI window has a fixed size and linen background color. Instead of a \l{Rectangle},
the root element could as well be a \l{Window}. On top of the background the
\l{minidesk/system-ui/Readme.qml}{Readme} element is shown that displays a usage how-to. At the
bottom left there is a textual indication for whether the application-manager runs in single- or
multi-process mode.

\section2 Launcher

\printto System-UI chrome for applications

A \l{Repeater} provides the application icons arranged in a \l{Column} on the top-left corner of
the System-UI. This is achieved by using the \l{ApplicationManager} element as the model. Amongst
others, it provides the \c icon role which is used as the \l{Image} source URL. The \c icon URL is
defined in the \l{Manifest Definition}{info.yaml} file of the application. To indicate that an
application has been launched, the opacity of the corresponding application's icon is decreased
through a binding to the \c isRunning role.

Clicking on an application icon will launch the corresponding application through a call to
\l {ApplicationObject::start()}{ApplicationObject.start()}. If the application is already
running, \l {ApplicationObject::stop()}{ApplicationObject.stop()} will be called instead.

\section2 Application Windows in the System-UI

\printto System-UI for pop-ups

This second Repeater provides the window chrome for the application windows in its delegate.
The model is a plain ListModel fed with \l{WindowObject}{window objects} as they get created by
WindowManager and put on a \c window role. The code that populates this ListModel will be
shown later on. For now let's focus on what this Repeater's delegate does. It consists of:
\list
\li A fixed size window \l{Rectangle} with a "tan" color. The default location depends on the
    \c model.index, hence each application window has a different location.
\li The name of the application that created that window, prefixed with "Decoration" on the top
    horizontal center. The name is provided by the ApplicationObject related to that window
    and is defined in application's \l{Manifest Definition}{info.yaml} file.
\li A MouseArea for dragging and raising the window. The MouseArea fills the
    entire window, though the application container is placed on top of it and hence it will not
    handle dragging.
\li A small chocolate-colored \l Rectangle on the top left corner for closing the window (see
    \l{WindowObject::close()}{WindowObject.close()}). Since our sample applications
    only have one top-level window, closing it will also cause the corresponding application to
    quit.
\li The centerpiece: a \l WindowItem to render the \c WindowObject on screen.
    That's similar to the relationship between image files and QML's Image component.
\li Code for defining its initial position, so that when you start one app right after the other
    their windows get different positions and thus don't completely overlap each other.
\li And finally code to remove a row from the ListModel once its window has been destroyed from
    the client (application) side. Either because it was closed, made invisible, or the application
    itself quit or crashed. Any of these cases results in the \l WindowObject losing its surface.
    A more sophisticaded System-UI would animate the disappearance of a window. For that please
    check the \l {Animated Windows System-UI Example}
\endlist

\section2 Pop-ups

Two approaches are implemented to display pop-ups in the System-UI:
\list
\li Through a window rendered by the client application
\li Through the notification API provided by the application-manager
\endlist
This is the corresponding System-UI code:
\printto Handler for WindowManager signals

The first approach is the same as what was done for regular application windows in the previous
section: a ListModel delegate which is manually populated with \l{WindowObject}{WindowObjects}
coming from \l{WindowManager} (shown in \l{WindowManager Signal Handler} section later on).
The difference here is the decoration put around the WindowItem. Whereas regular application
windows are freely draggable and have title bars and borders, pop-up windows are just centered
and have no decorations at all. We also ensure they're put in front of regular windows by having
their Repeater declared after the Repeater for regular windows.

\section3 Client Application Rendering
App1 instantiates another \l{ApplicationManagerWindow} for the pop-up within its
\l{ApplicationManagerWindow} root element, as shown here:
\quotefromfile applicationmanager/minidesk/apps/tld.minidesk.app1/app1.qml
\skipto Rectangle
\skipto ApplicationManagerWindow
\printuntil Component.onCompleted
\printline }
The \l{ApplicationManagerWindow::setWindowProperty}{ApplicationManagerWindow.setWindowProperty()}
method is used to set a freely selectable shared property. Here we choose \c{type: "pop-up"} to
indicate that the window is supposed to be shown as a pop-up. In the \c onWindowAdded handler below
the System-UI checks for this property and handles the window appropriately as a pop-up.

\section3 Notification API Usage

An alternative to the window property approach is to use the application-manager's \l{Notification}
API on the application (client) side and the \l{NotificationManager} API on the System-UI (server)
side. The following code is invoked when the \e bulb icon of App2 is clicked:

\quotefromfile applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml
\skipto var notification
\printuntil notification.show();

App2 creates a new \l{Notification} element, sets its \l{Notification::summary}{summary} property
and calls \l{Notification::show()}{show()} on it. This call will increase the
\l{NotificationManager::count}{NotificationManager.count} on the System-UI side, and subsequently
the \l{Text} element's text property will be set to the \c summary string of the first
notification. Presenting the first notification only is a simplification to keep the code short.

\section2 WindowManager Signal Handler

\quotefromfile applicationmanager/minidesk/system-ui/main.qml
\skipto Handler for WindowManager signals
\printto IPC extension
Here we split the content of WindowManager into two separate models. This is where our two
\l{ListModel}{ListModels} get populated. Whenever WindowManager adds a new WindowObject to its
model we check its \c "type"  window property. If it's a pop-up we add it to the \c popupsModel,
so that it's displayed as such (centralized and in front of regular windows, without any decorations
whatsoever). Otherwise we add it to the \c topLevelWindowsModel and thus is gets displayed as a regular
top-level window (draggable and decorated with borders, a title bar and a close button).

If we didn't have this distinction on how we display different \l{WindowObject}{WindowObjects}
we could have used a single Repeater instead, and hence a single model, which could be WindowManager
itself (like in the \l{"Hello World!" System-UI Example}{Hello World} example).

WindowManager creates \l{WindowObject}{WindowObjects} for any wayland client connected to the System-UI
(which is a wayland server when in multi-process mode). If you have "\c flags/noSecurity: \c yes" in your
configuration it will include wayland clients which were not started by ApplicationManager and ones that
are not even registered as Qt Application Manager applications. So if you launch some Qt application
(such as KDE's Calculator for instance) from the command line as shown below:

\badcode
$ QT_WAYLAND_DISABLE_WINDOWDECORATION=1 QT_WAYLAND_SHELL_INTEGRATION=xdg-shell-v5 kcalc -platform wayland
\endcode

You will see that the System-UI does display it, even though it doesn't have a matching ApplicationObject.
But as System-UI doesn't know anything about the application that created this window it cannot show its
name on the window title bar, for instance.

\image kcalc.jpg

In case you were wondering, \c QT_WAYLAND_DISABLE_WINDOWDECORATION is set to disable client side
window decorations, since our System-UI already provides them. A \c QT_WAYLAND_SHELL_INTEGRATION is specified
so that the client can understand higher level concepts from window managers such as close events. Without
this, clicking on the close rectangle in the window decoration would yield nothing.

\section2 IPC Extension
The following snippet demonstrates how the \l{ApplicationIPCInterface} can be used to define an IPC
extension. The IPC interface has to be defined in the System-UI, for instance:
\printuntil Component.onCompleted
\printline }

Here, a property \c pi is defined, as well as a signal \c computed and a function \c circumference.
After registering this interface with
\l{ApplicationIPCManager::registerInterface()}{ApplicationIPCManager.registerInterface()}, it can
be used from the application processes.

On the application side, the \l{ApplicationInterfaceExtension} type has to be used. Here is how
App2 makes use of this interface extension:

\quotefromfile applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml
\skipto ApplicationInterfaceExtension
\printuntil onPiChanged
\printline }

The interface is used here immediately when it becomes ready. It can, of course, be accessed from
elsewhere, too. The \l{ApplicationInterfaceExtension::name}{ApplicationInterfaceExtension.name} has
to match the name it was registered with in
\l{ApplicationIPCManager::registerInterface()}{ApplicationIPCManager.registerInterface()}.

\section2 Application Termination
When an application is stopped from the System-UI through
\l{ApplicationManager::stopApplication()}{ApplicationManager.stopApplication()}, it will be sent
the \l{ApplicationInterface::quit()}{ApplicationInterface.quit()} signal. The application can do
some clean-up and must subsequently confirm with
\l{ApplicationInterface::acknowledgeQuit()}{ApplicationInterface.acknowledgeQuit()}, like App2 does:
\quotefromfile applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml
\skipto Connections
\printuntil onQuit
\printline }

Note that App1 is not well-behaved: it does not acknowledge the \c quit signal and will hence simply
be terminated by the application-manager.

*/