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.
12 This document is intended to be useful to application developers.
14 Scope of this Document
15 ----------------------
17 This document describes the singleton class interface to the *Window
18 Manager* binding service.
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.
30 static AFBClient &instance();
32 int init(int port, char const *token);
36 int requestSurface(const char *label);
37 int activateSurface(const char *label);
38 int deactivateSurface(const char *label);
39 int endDraw(const char *label);
50 void set_event_handler(enum EventType et,
51 std::function<void(char const *label)> f);
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.
61 Additionally, logging of error messages is done on the standard error
62 file descriptor to help debugging the issue.
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.
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).
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.
86 ### AFBClient::init(port, token)
88 Initialize the Binding communication.
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`.
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`.
98 ### AFBClient::requestSurface(label)
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.
105 ### AFBClient::activateSurface(label)
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
112 This method only is effective after the actual window or surface was
113 created by the application.
115 ### AFBClient::deactivateSurface(label)
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*.)
123 This method only is effective after the actual window or surface was
124 created by the application.
126 ### AFBClient::endDraw(label)
128 This function is called from a client application when it is done
129 drawing its surface content.
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.
136 ### AFBClient::dispatch()
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
144 ### AFBClient::set\_event\_handler(et, func)
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.
151 The `func` handler functions will receive the label of the surface this
152 event is targeted at.
154 See Section [Events](#_events) for mor detailed information about event
155 delivery to client applications.
160 ### Initialization of AFBClient
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.
166 ### Request a surface
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
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.
177 #### Workings of requestSurface()
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
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.
192 ### Integration into the application main loop
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:
203 QObject::connect(&timer, &QTimer::timeout, &app,
204 [] {AFBClient::instance().dispatch();});
205 timer.setInterval(16);
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()`.
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)).
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
224 All events have the surface `label` as argument - a way to enable future
225 multi-surface applications.
227 As already stated above, this is currently not possible with the way
228 *Qt* implements its surface ID setting.
230 ### Active and Inactive Events
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.
236 ### Visible and Invisible
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.
243 ### SyncDraw and FlushDraw
245 These events instruct applications that they should redraw their surface
246 contents - again, this is handled implicitly by the wayland protocol.
248 `SyncDraw` is sent to the application when it has to redraw its surface.
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.
256 In order to enable application to use the `WM` surface registration
257 function the above described steps need to be implemented.
259 As a minimal example the usage and initialization can look like the
262 // Assume a program argc and argv.
263 QGuiApplication app(argc, argv);
265 auto &wm = AFBClient::instance();
267 // initialize the AFBClient binding.
268 if(wm.init(1234, "wmtest") != 0) {
272 // Request a surface label from the WM.
273 char const *surface_label = "AppMediaPlayer";
274 if (wm.requestSurface(surface_label) != 0) {
278 // Register an Active event handler.
279 wm.set_event_handler(Event_Active,
280 [](char const *label) {
281 qDebug() << "Surface" << label << "got activated";
284 // Initialize application window
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");
294 // enable main loop integration.
296 QObject::connect(&timer, &QTimer::timeout, &app,
297 [&wm] {wm.dispatch();});
298 timer.setInterval(16);
301 // e.g. exec the qt application
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.