summaryrefslogtreecommitdiffstats
path: root/examples/applicationmanager/minidesk/doc/src/minidesk.qdoc
blob: 86fa9a592cd3076ffdeca41083ca915ba2a18ab1 (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
// 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

/*!

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

\section1 Introduction

This example showcases the application manager API in a simple way, as a classic desktop with
server-side window decorations. The example focuses more on the concepts, but less on elegance or
completeness. For example, there's no error checking done. Some features in this minimal Desktop
System only print debug messages.

The following features are supported:
\list
    \li Start applications by clicking on an icon in the top left
    \li Stop an application by clicking on the icon in the top left again
    \li Close an application window by clicking on the window's close icon
    \li Raise a window and set focus by pressing on the window (focus window is blue)
    \li Drag a window by pressing on the top window decoration and moving them
    \li The System UI sends a 'propA' change when an app starts
    \li The System UI and App2 react to window property changes with a debug message
    \li Stop or restart App1 animations with a click
    \li App1 sends rotation angle as a window property to System UI on stop
    \li App1 shows a pop up on the System UI when it is paused
    \li App2 logs the document URL that started it
    \li App2 triggers a notification in the System UI, when the bulb icon is clicked
    \li Show Wayland client windows that originate from processes outside of \c appman
\endlist

\note This example can be run in single-process or multi-process mode. In the walkthrough below, we
use multi-process and its corresponding terminology. The terms \e client and \e application;
\e server and \e {System UI} are used interchangeably.

To start the example, navigate to the \c minidesk folder, and run the following command:
\badcode
<path-to-appman-binary> -c am-config.yaml
\endcode
The \c appman binary (executable file) is usually located in the Qt installation \c bin folder.

\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 access the application manager
APIs. The System UI window has a fixed size and "whitesmoke" background color. Instead of a
\l{Window}, the root element could also be a regular item, like a \l{Rectangle}. The application
manager would wrap it in a window for you. On top of the background, we display a \c Readme element
with information on the features available. At the bottom left there is a textual indication for
whether the application manager runs in single-process 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; the \l{ApplicationManager} element is the model. Among others, the
ApplicationManager provides the \c icon role which is used as the \l{Image} source URL. The
\c icon URL is defined in the application's \l{Manifest Definition}{info.yaml} file. To indicate
that an application has launched, the corresponding application icon's opacity is decreased by
binding it to the \c isRunning role.

Clicking on an application icon launches the corresponding application through a call to
\l {ApplicationObject::start()}{ApplicationObject.start()}. This function is accessible through
the \c application role in the ApplicationManager model. Both applications start with
the (optional) document URL, \c documentUrl. If the application is already running,
\l {ApplicationObject::stop()}{ApplicationObject.stop()} is called instead.

\section2 Application Windows in the System UI

\printto System UI for a pop-up

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 are created by the
WindowManager. The code that populates the window role of this ListModel is shown below. For
now let's focus on what this Repeater's delegate consists of:

\list
    \li The enclosing type is a \l{FocusSope} that allows to track focus changes.
    \li A mostly transparent \l{Image} that acts as the window decoration (border). A blue border
        indicates the focus window, otherwise the border is grey. The location depends on the
        \c model.index, hence each application window has a different initial location.
    \li The name of the application that created that window, prefixed with "Decoration" on top.
        This name is from the related ApplicationObject, defined in the application's
        \l{Manifest Definition}{info.yaml} file.
    \li A MouseArea for dragging and raising the window. Only the top decoration bar is covered by
        that area and will hence handle dragging.
    \li A close icon 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 causes the corresponding application to quit.
    \li The centerpiece: a \l WindowItem to render the \c WindowObject in the System UI; similar to
        the relationship between image files and QML's Image component.
    \li And finally code to remove a row from the ListModel once its window has been destroyed from
        the application (client) 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 sophisticated System UI could animate the disappearance of a
        window, as illustrated in 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

\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 chose \c{type: "pop-up"} to
indicate that the window is supposed to be shown as a pop-up.

In the WindowManager::onWindowAdded() signal handler \l{WindowManager Signal Handler}{below}, the
System UI checks this property and handles the window appropriately as a pop-up.

A pop-up window will be set as the content window of the \c popUpContainer WindowItem in the
System UI code above. For demonstration purposes, the implementation supports only one pop-up at a
time. This is sufficient, since only App1 will display a single pop-up when its animation is
paused. It is essential to understand, that there has to be an agreement between the System UI
and applications, in terms of how windows are mapped. In contrast to regular application windows
that are freely draggable and have title bars and borders, the pop-up window is just centered and
has no decoration at all. Note also how the
\l{WindowObject::contentState}{WindowObject.contentStateChanged} signal is handled in the
\c popUpContainer: the window is released when it has no surface associated any more. This is
important to free any resources that the \l{WindowObject}{window} object is using. Note that this
is done implicitly when the WindowManager model is used directly. This approach is recommended as
it's more convenient.

\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 you click on the \e bulb icon in App2:

\quotefromfile applicationmanager/minidesk/apps/tld.minidesk.app2/app2.qml
\skipto let 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 increases 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. For brevity, the example only presents the first notification.

\section2 WindowManager Signal Handler

\quotefromfile applicationmanager/minidesk/system-ui/main.qml
\skipto Handler for WindowManager signals
\printto /^\}/

This is the vital part of the System UI, where the window (surfaces) of the applications are mapped
to \l{WindowItem}s in the System UI. When a new application window is available (becomes visible),
the \l {WindowManager::windowAdded}{onWindowAdded} handler is invoked.

Only App1's "pop-up" ApplicationManagerWindow has the user-defined \c type property set. Such a
window is placed in the \c popUpContainer WindowItem. All other windows don't have a \c type
property; they are added to the \c topLevelWindowsModel. This model is used in the System UI chrome
Repeater above. Consequently, the \l {WindowObject}{window} object passed as an argument to
\l {WindowManager::windowAdded}{onWindowAdded} is set as the
\l{WindowItem::window}{window} property of the WindowItem (within the Repeater's delegate).

Incidentally, any Wayland client window from a process started outside of the application manager
will also be displayed since in the configuration file, "\c flags/noSecurity: \c yes" is set, for
instance in KDE's Calculator:

\badcode
$ QT_WAYLAND_DISABLE_WINDOWDECORATION=1 WAYLAND_DISPLAY=qtam-wayland-0 kcalc -platform wayland
\endcode

\section2 Application Termination

When an application is stopped from the System UI through
\l{ApplicationManager::stopApplication()}{ApplicationManager.stopApplication()}, it is sent
the \l{ApplicationInterface::quit()}{ApplicationInterface.quit()} signal. Then, the application can
do some clean-up and it 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
\printuntil /^\s{4}\}/

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.

*/