Add doc/
authorMarcus Fritzsch <marcus_fritzsch@mentor.com>
Mon, 4 Sep 2017 13:20:56 +0000 (15:20 +0200)
committerMarcus Fritzsch <marcus_fritzsch@mentor.com>
Thu, 14 Sep 2017 12:04:51 +0000 (14:04 +0200)
Signed-off-by: Marcus Fritzsch <marcus_fritzsch@mentor.com>
doc/AFBClient.txt [new file with mode: 0644]
doc/GNUmakefile [new file with mode: 0644]

diff --git a/doc/AFBClient.txt b/doc/AFBClient.txt
new file mode 100644 (file)
index 0000000..d80891c
--- /dev/null
@@ -0,0 +1,300 @@
+= AFBClient Library User Guide
+:doctype: book
+:toc:
+:icons:
+:data-uri:
+:lang: en
+:encoding: utf-8
+
+== Introduction
+The AFBClient library provides a simple interface to manipulate and
+query the state of the window manager application framework binding. It
+is composed of one singleton class that needs to be integrated and called
+from the client application.
+
+=== Intended audience
+This document is intended to be useful to application developers.
+
+=== Scope of this Document
+This document describes the singleton class interface to the _Window
+Manager_ binding service.
+
+== class AFBClient
+This is the public interface of the class `AFBClient`. Private members
+and methods are not reproduced as they will not affect usage of the
+class by client applications.
+
+---------------------------
+class AFBClient
+{
+public:
+    static AFBClient &instance();
+
+    int init(int port, char const *token);
+    int dispatch();
+
+    // WM API
+    int requestSurface(const char *label);
+    int activateSurface(const char *label);
+    int deactivateSurface(const char *label);
+    int endDraw(const char *label);
+
+    enum EventType {
+       Event_Active,
+       Event_Inactive,
+       Event_Visible,
+       Event_Invisible,
+       Event_SyncDraw,
+       Event_FlushDraw,
+    };
+
+    void set_event_handler(enum EventType et,
+         std::function<void(char const *label)> f);
+};
+---------------------------
+
+=== Errors
+Methods returning an `int` signal successful operation when returning
+`0`. In case of an error, an error value is returned as a negative errno
+value. E.g. `-EINVAL` to signal that some input value was invalid.
+
+Additionally, logging of error messages is done on the standard error
+file descriptor to help debugging the issue.
+
+=== Labels
+Surface labels are any valid strings. For `requestSurface()` these strings
+must match the _Window Manager_ configuration in order to be allowed to
+be displayed on one layer or the other. For all other calls the label
+must match the exact name of a requested surface.
+
+=== Caveats
+Any of the API calls to the _Window Manager_ will be synchronous (and
+thus block until a reply from the _Window Manager_ service is received).
+
+.Note
+************************
+These are the Methods `requestSurface()`, `activateSurface()`,
+`deactivateSurface()` and `endDraw()`. However, `requestSurface()` is
+only ever called once to request a surface so this should not be a
+concern for this Method.
+************************
+
+=== Methods
+
+==== AFBClient::init(port, token)
+Initialize the Binding communication.
+
+The `token` parameter is a string consisting of only alphanumeric
+characters, and with a maximum length of 20 characters. If these
+conditions are not met, the AFBClient instance will not initialize,
+i.e. this call will return `-EINVAL`.
+
+The `port` parameter is the port the afb daemon is listening on,
+an invalid port will lead to a failure of the call and return `-EINVAL`.
+
+==== AFBClient::requestSurface(label)
+This method requests a surface with the label given from the _Window
+Manager_. It will return `0` for a successful surface request, and
+`-errno` on failure. Additionally, on the standard error, messages are
+logged to help debgging the issue.
+
+==== AFBClient::activateSurface(label)
+This method is mainly intended for _manager_ applications that control
+other applications (think an application manager or the _HomeScreen_). It
+instructs the window manager to activate the surface with the given
+_label_.
+
+This method only is effective after the actual window or surface was
+created by the application.
+
+==== AFBClient::deactivateSurface(label)
+This method is mainly intended for _manager_ applications that control
+other applications. It instructs the window manager to deactivate the
+surface associated with the given label. Note, that deactivating a
+surface also means to implicitly activate another (the last active or
+if not available _main surface_ or _HomeScreen_.)
+
+This method only is effective after the actual window or surface was
+created by the application.
+
+==== AFBClient::endDraw(label)
+This function is called from a client application when it is done
+drawing its surface content.
+
+It is not crucial to make this call at every time a drawing is finished -
+it is mainly intended to allow the window manager to synchronize drawing
+in case of layout switch. The exact semantics are explained in the next
+<<_events,Events>> Section.
+
+==== AFBClient::dispatch()
+This function needs to be called periodically from the application main
+loop in order to dispatch binder events and requests. This function
+will block at most 1ms if no events are ready. For more information,
+see the <<_usage,Usage>> and <<_example_use_case,Example Use Case>>
+sections below.
+
+==== AFBClient::set_event_handler(et, func)
+This method needs to be used to register event handlers for the WM
+events described in the EventType enum. Only one hendler for each
+EventType is possible, i.e. if it is called multiple times with the same
+EventType the previous handler will be replaced.
+
+The `func` handler functions will receive the label of the surface this
+event is targeted at.
+
+See Section <<_events,Events>> for mor detailed information about event
+delivery to client applications.
+
+=== Usage
+
+==== Initialization of AFBClient
+Before usage of the AFBClient singleton, the method `init()` must be
+called once, it will return `-errno` in case of en error and log diagnostic
+messages to stderr.
+
+==== Request a surface
+When creating a surface with _Qt_ - it is necessary to request a surface
+from the WM, internally this will communicate with the window manager
+binding. Only after `requestSurface()` was successful, a surface should
+be created.
+
+This is also true for _QML_ aplications, where only after the
+`requestSurface()` should the load of the resource be done. The method
+returns `0` after the surface was requested successfully.
+
+===== Workings of requestSurface()
+`AFBClient::requestSurface()` calls the AFB binding verb
+`requestsurface` of the `winman` API. This API call will return a
+numeric ID to be used when creating the surface. This ID is never
+explicitly returned to the client application, instead, it is set in the
+application environment in order for _Qt_ to then use it when creating the
+surface.
+
+.Remarks
+********************************
+With the current _Qt_ implementation this means, that only one surface
+will be available to client applications, as subsequent windows will
+increment this numeric ID internally - which then will lead to IDs that
+cannot be known by the window manager as there is no direct
+communication from _Qt_ to the WM.
+********************************
+
+==== Integration into the application main loop
+Calls directed at the window manager are synchronoous, i.e. they wil
+ensure communication to the WM happens at the time of the call and
+finishes before returning to the client application. However, in order
+for events to be received by the application, the `dispatch()` method
+needs to be called periodically with a small timeout from the
+application mainloop. In _Qt_ this can be achieved by a code fragment
+analogous to the following:
+
+----------------------
+    QTimer timer;
+    QObject::connect(&timer, &QTimer::timeout, &app,
+         [] {AFBClient::instance().dispatch();});
+    timer.setInterval(16);
+    timer.start();
+----------------------
+
+This creates a contineously firing timer that calls the AFBClient's
+`dispatch()` method. Note that calls to event handlers will be done in
+this context from the thread that called `dispatch()`.
+
+.Note
+******************
+The timeout should be small in order to not block too long, but also a
+0 timeout will not dispatch anything and return immediately (see
+https://linux.die.net/man/2/epoll_wait[epoll_wait(2)]).
+******************
+
+=== Events
+Events are a way for the _Window Manager_ to propagate information to
+client applications. It was vital for the project to implement a number
+of events, that mirror functionality that is already present in the
+wayland protocol.
+
+All events have the surface `label` as argument - a way to enable future
+multi-surface applications.
+
+.Remarks
+**************************
+As already stated above, this is currently not possible with the way
+_Qt_ implements its surface ID setting.
+**************************
+
+==== Active and Inactive Events
+These events signal an application that it was activated or deactivated
+respectively. Usually this means it was switched visible - which means
+the surface will now be on the screen and therefor continue to render.
+
+==== Visible and Invisible
+These events signal an application that it was switched to be visible or
+invisible respectively. These events too are handled implicitly through
+the wayland protocol by means of `wl_surface::enter` and
+`wl_surface::leave` events to the client.
+
+==== SyncDraw and FlushDraw
+These events instruct applications that they should redraw their surface
+contents - again, this is handled implicitly by the wayland protocol.
+
+`SyncDraw` is sent to the application when it has to redraw its surface.
+
+`FlushDraw` is sent to the application when it should swap its buffers,
+that is _signal_ the compositor that its surface contains new content.
+
+=== Example Use Case
+In order to enable application to use the `WM` surface registration
+function the above described steps need to be implemented.
+
+As a minimal example the usage and initialization can look like the
+following.
+
+-----------------------
+    // Assume a program argc and argv.
+    QGuiApplication app(argc, argv);
+
+    auto &wm = AFBClient::instance();
+
+    // initialize the AFBClient binding.
+    if(wm.init(1234, "wmtest") != 0) {
+        exit(EXIT_FAILURE);
+    }
+
+    // Request a surface label from the WM.
+    char const *surface_label = "AppMediaPlayer";
+    if (wm.requestSurface(surface_label) != 0) {
+        exit(EXIT_FAILURE);
+    }
+
+    // Register an Active event handler.
+    wm.set_event_handler(Event_Active,
+         [](char const *label) {
+            qDebug() << "Surface" << label << "got activated";
+         });
+
+    // Initialize application window
+    // ...
+
+    // request to activate the surface, this should usually
+    // not be done by the client application.
+    if (wm.activateSurface(surface_label) != 0) {
+       fprintf(stderr, "Could not activate the surface\n");
+       exit(EXIT_FAILURE);
+    }
+
+    // enable main loop integration.
+    QTimer timer;
+    QObject::connect(&timer, &QTimer::timeout, &app,
+         [&wm] {wm.dispatch();});
+    timer.setInterval(16);
+    timer.start();
+
+    // e.g. exec the qt application
+    app.exec();
+-----------------------
+
+Alternatively to the `QTimer` mainloop integration a thread could be
+started up which does the periodic polling of the binding. However,
+using a timer event is a much cleaner approach.
+
+// vim:set ft=asciidoc tw=72:
diff --git a/doc/GNUmakefile b/doc/GNUmakefile
new file mode 100644 (file)
index 0000000..23aa9d5
--- /dev/null
@@ -0,0 +1,7 @@
+all: AFBClient.html
+
+AFBClient.html: AFBClient.txt
+       asciidoc -a max-width=55em $^
+
+clean:
+       rm -f AFBClient.html