1 = AFBClient Library User Guide
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.
16 This document is intended to be useful to application developers.
18 === Scope of this Document
19 This document describes the singleton class interface to the _Window
20 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.
27 ---------------------------
31 static AFBClient &instance();
33 int init(int port, char const *token);
37 int requestSurface(const char *label);
38 int activateSurface(const char *label);
39 int deactivateSurface(const char *label);
40 int endDraw(const char *label);
51 void set_event_handler(enum EventType et,
52 std::function<void(char const *label)> f);
54 ---------------------------
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.
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.
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).
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 ************************
84 ==== AFBClient::init(port, token)
85 Initialize the Binding communication.
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`.
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`.
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.
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
107 This method only is effective after the actual window or surface was
108 created by the application.
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_.)
117 This method only is effective after the actual window or surface was
118 created by the application.
120 ==== AFBClient::endDraw(label)
121 This function is called from a client application when it is done
122 drawing its surface content.
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.
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>>
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.
142 The `func` handler functions will receive the label of the surface this
143 event is targeted at.
145 See Section <<_events,Events>> for mor detailed information about event
146 delivery to client applications.
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
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
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.
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
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 ********************************
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:
191 ----------------------
193 QObject::connect(&timer, &QTimer::timeout, &app,
194 [] {AFBClient::instance().dispatch();});
195 timer.setInterval(16);
197 ----------------------
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()`.
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)]).
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
216 All events have the surface `label` as argument - a way to enable future
217 multi-surface applications.
220 **************************
221 As already stated above, this is currently not possible with the way
222 _Qt_ implements its surface ID setting.
223 **************************
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.
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.
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.
240 `SyncDraw` is sent to the application when it has to redraw its surface.
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.
246 In order to enable application to use the `WM` surface registration
247 function the above described steps need to be implemented.
249 As a minimal example the usage and initialization can look like the
252 -----------------------
253 // Assume a program argc and argv.
254 QGuiApplication app(argc, argv);
256 auto &wm = AFBClient::instance();
258 // initialize the AFBClient binding.
259 if(wm.init(1234, "wmtest") != 0) {
263 // Request a surface label from the WM.
264 char const *surface_label = "AppMediaPlayer";
265 if (wm.requestSurface(surface_label) != 0) {
269 // Register an Active event handler.
270 wm.set_event_handler(Event_Active,
271 [](char const *label) {
272 qDebug() << "Surface" << label << "got activated";
275 // Initialize application window
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");
285 // enable main loop integration.
287 QObject::connect(&timer, &QTimer::timeout, &app,
288 [&wm] {wm.dispatch();});
289 timer.setInterval(16);
292 // e.g. exec the qt application
294 -----------------------
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.
300 // vim:set ft=asciidoc tw=72: