doc: documentation update, more examples, some external links
[staging/windowmanager.git] / doc / AFBClient.txt
1 = AFBClient Library User Guide
2 :doctype: book
3 :toc:
4 :icons:
5 :data-uri:
6 :lang: en
7 :encoding: utf-8
8
9 == Introduction
10 The AFBClient library provides a simple interface to manipulate and
11 query the state of the window manager application framework binding. It
12 is composed of one singleton class that needs to be integrated and called
13 from the client application.
14
15 === Intended audience
16 This document is intended to be useful to application developers.
17
18 === Scope of this Document
19 This document describes the singleton class interface to the _Window
20 Manager_ binding service.
21
22 == class AFBClient
23 This is the public interface of the class `AFBClient`. Private members
24 and methods are not reproduced as they will not affect usage of the
25 class by client applications.
26
27 ---------------------------
28 class AFBClient
29 {
30 public:
31     static AFBClient &instance();
32
33     int init(int port, char const *token);
34     int dispatch();
35
36     // WM API
37     int requestSurface(const char *label);
38     int activateSurface(const char *label);
39     int deactivateSurface(const char *label);
40     int endDraw(const char *label);
41
42     enum EventType {
43        Event_Active,
44        Event_Inactive,
45        Event_Visible,
46        Event_Invisible,
47        Event_SyncDraw,
48        Event_FlushDraw,
49     };
50
51     void set_event_handler(enum EventType et,
52          std::function<void(char const *label)> f);
53 };
54 ---------------------------
55
56 === Errors
57 Methods returning an `int` signal successful operation when returning
58 `0`. In case of an error, an error value is returned as a negative errno
59 value. E.g. `-EINVAL` to signal that some input value was invalid.
60
61 Additionally, logging of error messages is done on the standard error
62 file descriptor to help debugging the issue.
63
64 === Labels
65 Surface labels are any valid strings. For `requestSurface()` these strings
66 must match the _Window Manager_ configuration in order to be allowed to
67 be displayed on one layer or the other. For all other calls the label
68 must match the exact name of a requested surface.
69
70 === Caveats
71 Any of the API calls to the _Window Manager_ will be synchronous (and
72 thus block until a reply from the _Window Manager_ service is received).
73
74 .Note
75 ************************
76 These are the Methods `requestSurface()`, `activateSurface()`,
77 `deactivateSurface()` and `endDraw()`. However, `requestSurface()` is
78 only ever called once to request a surface so this should not be a
79 concern for this Method.
80 ************************
81
82 === Methods
83
84 ==== AFBClient::init(port, token)
85 Initialize the Binding communication.
86
87 The `token` parameter is a string consisting of only alphanumeric
88 characters, and with a maximum length of 20 characters. If these
89 conditions are not met, the AFBClient instance will not initialize,
90 i.e. this call will return `-EINVAL`.
91
92 The `port` parameter is the port the afb daemon is listening on,
93 an invalid port will lead to a failure of the call and return `-EINVAL`.
94
95 ==== AFBClient::requestSurface(label)
96 This method requests a surface with the label given from the _Window
97 Manager_. It will return `0` for a successful surface request, and
98 `-errno` on failure. Additionally, on the standard error, messages are
99 logged to help debgging the issue.
100
101 ==== AFBClient::activateSurface(label)
102 This method is mainly intended for _manager_ applications that control
103 other applications (think an application manager or the _HomeScreen_). It
104 instructs the window manager to activate the surface with the given
105 _label_.
106
107 This method only is effective after the actual window or surface was
108 created by the application.
109
110 ==== AFBClient::deactivateSurface(label)
111 This method is mainly intended for _manager_ applications that control
112 other applications. It instructs the window manager to deactivate the
113 surface associated with the given label. Note, that deactivating a
114 surface also means to implicitly activate another (the last active or
115 if not available _main surface_ or _HomeScreen_.)
116
117 This method only is effective after the actual window or surface was
118 created by the application.
119
120 ==== AFBClient::endDraw(label)
121 This function is called from a client application when it is done
122 drawing its surface content.
123
124 It is not crucial to make this call at every time a drawing is finished -
125 it is mainly intended to allow the window manager to synchronize drawing
126 in case of layout switch. The exact semantics are explained in the next
127 <<_events,Events>> Section.
128
129 ==== AFBClient::dispatch()
130 This function needs to be called periodically from the application main
131 loop in order to dispatch binder events and requests. This function
132 will block at most 1ms if no events are ready. For more information,
133 see the <<_usage,Usage>> and <<_example_use_case,Example Use Case>>
134 sections below.
135
136 ==== AFBClient::set_event_handler(et, func)
137 This method needs to be used to register event handlers for the WM
138 events described in the EventType enum. Only one hendler for each
139 EventType is possible, i.e. if it is called multiple times with the same
140 EventType the previous handler will be replaced.
141
142 The `func` handler functions will receive the label of the surface this
143 event is targeted at.
144
145 See Section <<_events,Events>> for mor detailed information about event
146 delivery to client applications.
147
148 === Usage
149
150 ==== Initialization of AFBClient
151 Before usage of the AFBClient singleton, the method `init()` must be
152 called once, it will return `-errno` in case of en error and log diagnostic
153 messages to stderr.
154
155 ==== Request a surface
156 When creating a surface with _Qt_ - it is necessary to request a surface
157 from the WM, internally this will communicate with the window manager
158 binding. Only after `requestSurface()` was successful, a surface should
159 be created.
160
161 This is also true for _QML_ aplications, where only after the
162 `requestSurface()` should the load of the resource be done. The method
163 returns `0` after the surface was requested successfully.
164
165 ===== Workings of requestSurface()
166 `AFBClient::requestSurface()` calls the AFB binding verb
167 `requestsurface` of the `winman` API. This API call will return a
168 numeric ID to be used when creating the surface. This ID is never
169 explicitly returned to the client application, instead, it is set in the
170 application environment in order for _Qt_ to then use it when creating the
171 surface.
172
173 .Remarks
174 ********************************
175 With the current _Qt_ implementation this means, that only one surface
176 will be available to client applications, as subsequent windows will
177 increment this numeric ID internally - which then will lead to IDs that
178 cannot be known by the window manager as there is no direct
179 communication from _Qt_ to the WM.
180 ********************************
181
182 ==== Integration into the application main loop
183 Calls directed at the window manager are synchronoous, i.e. they wil
184 ensure communication to the WM happens at the time of the call and
185 finishes before returning to the client application. However, in order
186 for events to be received by the application, the `dispatch()` method
187 needs to be called periodically with a small timeout from the
188 application mainloop. In _Qt_ this can be achieved by a code fragment
189 analogous to the following:
190
191 ----------------------
192     QTimer timer;
193     QObject::connect(&timer, &QTimer::timeout, &app,
194          [] {AFBClient::instance().dispatch();});
195     timer.setInterval(16);
196     timer.start();
197 ----------------------
198
199 This creates a contineously firing timer that calls the AFBClient's
200 `dispatch()` method. Note that calls to event handlers will be done in
201 this context from the thread that called `dispatch()`.
202
203 .Note
204 ******************
205 The timeout should be small in order to not block too long, but also a
206 0 timeout will not dispatch anything and return immediately (see
207 https://linux.die.net/man/2/epoll_wait[epoll_wait(2)]).
208 ******************
209
210 === Events
211 Events are a way for the _Window Manager_ to propagate information to
212 client applications. It was vital for the project to implement a number
213 of events, that mirror functionality that is already present in the
214 wayland protocol.
215
216 All events have the surface `label` as argument - a way to enable future
217 multi-surface applications.
218
219 .Remarks
220 **************************
221 As already stated above, this is currently not possible with the way
222 _Qt_ implements its surface ID setting.
223 **************************
224
225 ==== Active and Inactive Events
226 These events signal an application that it was activated or deactivated
227 respectively. Usually this means it was switched visible - which means
228 the surface will now be on the screen and therefor continue to render.
229
230 ==== Visible and Invisible
231 These events signal an application that it was switched to be visible or
232 invisible respectively. These events too are handled implicitly through
233 the wayland protocol by means of `wl_surface::enter` and
234 `wl_surface::leave` events to the client.
235
236 ==== SyncDraw and FlushDraw
237 These events instruct applications that they should redraw their surface
238 contents - again, this is handled implicitly by the wayland protocol.
239
240 `SyncDraw` is sent to the application when it has to redraw its surface.
241
242 `FlushDraw` is sent to the application when it should swap its buffers,
243 that is _signal_ the compositor that its surface contains new content.
244
245 === Example Use Case
246 In order to enable application to use the `WM` surface registration
247 function the above described steps need to be implemented.
248
249 As a minimal example the usage and initialization can look like the
250 following.
251
252 -----------------------
253     // Assume a program argc and argv.
254     QGuiApplication app(argc, argv);
255
256     auto &wm = AFBClient::instance();
257
258     // initialize the AFBClient binding.
259     if(wm.init(1234, "wmtest") != 0) {
260         exit(EXIT_FAILURE);
261     }
262
263     // Request a surface label from the WM.
264     char const *surface_label = "AppMediaPlayer";
265     if (wm.requestSurface(surface_label) != 0) {
266         exit(EXIT_FAILURE);
267     }
268
269     // Register an Active event handler.
270     wm.set_event_handler(Event_Active,
271          [](char const *label) {
272             qDebug() << "Surface" << label << "got activated";
273          });
274
275     // Initialize application window
276     // ...
277
278     // request to activate the surface, this should usually
279     // not be done by the client application.
280     if (wm.activateSurface(surface_label) != 0) {
281        fprintf(stderr, "Could not activate the surface\n");
282        exit(EXIT_FAILURE);
283     }
284
285     // enable main loop integration.
286     QTimer timer;
287     QObject::connect(&timer, &QTimer::timeout, &app,
288          [&wm] {wm.dispatch();});
289     timer.setInterval(16);
290     timer.start();
291
292     // e.g. exec the qt application
293     app.exec();
294 -----------------------
295
296 Alternatively to the `QTimer` mainloop integration a thread could be
297 started up which does the periodic polling of the binding. However,
298 using a timer event is a much cleaner approach.
299
300 // vim:set ft=asciidoc tw=72: