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