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
|
// 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/intents
\title Intents System UI and Applications Example
\image intents-example.png The Intents example with all applications running.
\brief Three applications and a System UI communicating over Intents.
\ingroup applicationmanager-examples
\note Please \l{wayland-dev-packages}{read this} if you want to build the example on a Linux machine.
\section1 Introduction
This example shows how the System UI and applications can send and receive Intents. Similar to the
\l{System UI Example: "Hello World!"}, the window management aspect is kept to a minimum to focus
only on Intents: the 2x2 grid on the right will always show the System UI part (gray) in the
top-left corner, while the three apps (red, green and blue) will dynamically occupy the other
corner in the order they are started. You can see the names and icons for the available
applications on the left; click on their respective icons to start and stop these applications.
Each application, as well as the System UI, look alike and have the same functionality available in
the UI: You can choose from one of the available intent IDs in the top combo-box (labeled \e Intent),
and optionally also specify the corresponding application that should handle the chosen request
(labeled \e Application).
Clicking the \e Request / \e Broadcast button will create and send the corresponding intent request
to the application manager's IntentServer for handling:
\list
\li The combination of \e Intent and \e Application was valid and the target application was able to
handle the request; the \l{IntentRequest::result}{result of this request} will be shown
as JSON text in the lower output field labeled \e Request.
\li Either the combination of \e Intent and \e Application was invalid or the target application
was not able to handle the request properly; the \l{IntentRequest::errorMessage}
{error message of this request} will be shown as plain text in the lower output field
labeled \e Request.
\li The \e Application was not specified, plus the \e Intent chosen can be handled by more than one
application; in this case the example's System UI will display a dialog, prompting the user
to \l{IntentServer::disambiguationRequest}{disambiguate the request}.
\endlist
\section1 Files and Folder Structure
This example comprises of a System UI and three sample applications ("Red Intents", "Green Intents"
and "Blue Intents"), resulting in four separate QML applications in total. System UI is also just a
QML application in the end, albeit a special one.
Each application is put in its own separate directory as described below. Since the QtQuickControls
2 based UI is used by all the applications and the System UI, its components live in a shared
directory.
\list
\li \tt{am-config.yaml}
\li \tt{system-ui.qml}
\li \tt{\b{apps}}
\list
\li \tt{\b{intents.blue}}
\list
\li \tt{icon.png}
\li \tt{info.yaml}
\li \tt{main.qml}
\endlist
\li \tt{\b{intents.red}}
\list
\li \tt{icon.png}
\li \tt{info.yaml}
\li \tt{main.qml}
\endlist
\li \tt{\b{intents.green}}
\list
\li \tt{icon.png}
\li \tt{info.yaml}
\li \tt{main.qml}
\endlist
\endlist
\li \tt{\b{shared}}
\list
\li \tt{IntentsApplicationWindow.qml}
\li \tt{IntentsUIPage.qml}
\endlist
\endlist
As you can see above, each application, besides its main QML file, also has an icon and a
\tt{info.yaml} file that contains the application metadata, which also includes the
definition of the intents that this application can handle.
\section1 Running the Example
After starting the example you should see the following:
\image intents-launched.png
\section1 Application Implementation
All the applications (red, green and blue) are identical and their \c main.qml just
instantiates the shared \c IntentsApplicationWindow component.
\snippet applicationmanager/intents/apps/intents.red/main.qml Main
The IntentsApplicationWindow component is actually a top-level ApplicationManagerWindow, with its
UI contents being defined by instantiating the \c IntentsUIPage component, that is also shared. This
UI component does not have any intent-specific code, so the actual sending is done in the signal
handlers attached to the IntentsUIPage request and broadcast signals:
\snippet applicationmanager/intents/shared/IntentsApplicationWindow.qml Send Intent
and
\snippet applicationmanager/intents/shared/IntentsApplicationWindow.qml Broadcast Intent
After calling IntentClient::sendIntentRequest with the parameters as chosen in the UI, the
example code will connect a function object to the \l{IntentRequest::replyReceived}
{request's replyReceived} signal. The result is placed in the \e Request field in the UI.
Broadcasts on the other hand do not generate replies.
In addition, IntentsApplicationWindow defines all the necessary IntentHandlers for the applications,
for example:
\snippet applicationmanager/intents/shared/IntentsApplicationWindow.qml Intent Handler
These intent handlers are not complex, with each one just triggering a basic animation that is
also defined in this file, so for the \c rotate-window intent this would be:
\snippet applicationmanager/intents/shared/IntentsApplicationWindow.qml Intent Animation
In QML, only implementing the IntentHandlers is not sufficient, because the application manager
needs to have information on which application supports which intents. This information must be
available to the application manager \b before the applications run, to facilitate auto-starting
applications on intent requests.
As for every other application configuration in the application manager, this is done through the
application's manifest file \c info.yaml:
The \b Red application defines three available intents:
\quotefromfile applicationmanager/intents/apps/intents.red/info.yaml
\skipto intents:
\printto
Additionally, the \b Red application gains the \c call-blue capability, which is required by certain
intents in the \b Blue application.
\quotefromfile applicationmanager/intents/apps/intents.red/info.yaml
\skipto capabilities:
\printline capabilities
The \b Green application defines only two available intents. Note that even though this
application has an IntentHandler for the \c scale-window intent through the shared
IntentsApplicationWindow component, this handler is never called, since this intent ID is not
registered with the system via the \c info.yaml manifest:
\quotefromfile applicationmanager/intents/apps/intents.green/info.yaml
\skipto intents:
\printto
On top of that, the \c broadcast/blink-window intent is marked as \c{handleOnlyWhenRunning: yes},
which prevents auto-starting the \c Green application on broadcasts of this specific intent.
The \b Blue application has the most complex intent definition. In addition to handling the same
three intents as the \b Red application, it registers the \c blue-window-private intent that has the
attribute \c{visibility: private}. Private intents can only be requested from the same application
that registered them, so in this case only \b Blue can successfully request the \c blue-window-private
intent. Furthermore, the \c rotate-window intent can only be requested by
applications that have the \c call-blue capability: here the \b Red application comes with the
required capability, while the \b Green doesn't.
\quotefromfile applicationmanager/intents/apps/intents.blue/info.yaml
\skipto intents:
\printto
\section1 System UI Implementation
Apart from the left side bar that deals with starting and stopping the apps, the System UI has two
special features that deal with the intent mechanism:
\list
\li Handling Intents in the System UI and
\li Disambiguation of Intent Requests
\endlist
\section2 Handling Intents in the System UI
Intents can not only be handled in applications, but also in the System UI. Since the System UI is
always running, we do not need to rely on \c info.yaml manifest files to define the supported
intents, but instead can declare the needed meta-data directly as properties of the
IntentServerHandler component. The IntentServerHandler is actually derived from IntentHandler, so
it works the same way as its application side counter part: it only adds the required properties to
define all the meta-data (e.g. \c names, \c icon, ...) on top.
\snippet applicationmanager/intents/system-ui.qml IntentServerHandler
The handler callback is nearly the same as the one in the applications. The only noteworthy
difference here is, that we have access to the \l{IntentRequest::}{requestingApplicationId}
to identify where the request originated from; for security reasons, this data is not available to
intent handlers in applications.
\section2 Disambiguation of Intent Requests
The example implements an UI that lets the user choose how to
\l {IntentServer::disambiguationRequest}{to disambiguate incoming intent requests}.
Registering for the IntentServer's disambiguation requests is done here:
\snippet applicationmanager/intents/system-ui.qml Connection
Since we want to stay flexible with regards to the number of parallel intent requests in the system,
we just add the incoming request to a queue (\c allRequests). The \c Dialog that consumes that
queue is a fairly standard QtQuickControls 2 dialog, that gives you a nice UI showing you the
possible application choices coming from the IntentServer::disambiguationRequested() signal. Upon
pressing \e Ok or \e Cancel, the dialog will notify the IntentServer about the user's decision:
\snippet applicationmanager/intents/system-ui.qml OkCancel
*/
|