aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcus Fritzsch <marcus_fritzsch@mentor.com>2017-09-13 14:46:15 +0200
committerMarcus Fritzsch <marcus_fritzsch@mentor.com>2017-09-14 14:04:51 +0200
commite30fe48e4c13ed57be74eaa65749e180d03c2e0c (patch)
tree76d7cef9a9a3b659387f958455470a35fe05a622
parentd6cd682d471b7bd8196ee6e031832f6307b3a8cf (diff)
add doc/
Signed-off-by: Marcus Fritzsch <marcus_fritzsch@mentor.com>
-rw-r--r--CMakeLists.txt1
-rw-r--r--doc/WindowManagerTMC.txt429
2 files changed, 430 insertions, 0 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index faeef67..464af6f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -81,6 +81,7 @@ set(LINK_LIBCXX OFF CACHE BOOL "Link against LLVMs libc++")
add_subdirectory(client-lib)
add_subdirectory(src)
+add_subdirectory(doc)
install(
FILES layers.json
diff --git a/doc/WindowManagerTMC.txt b/doc/WindowManagerTMC.txt
new file mode 100644
index 0000000..69182fd
--- /dev/null
+++ b/doc/WindowManagerTMC.txt
@@ -0,0 +1,429 @@
+= WindowManagerTMC
+:doctype: book
+:toc:
+:icons:
+:data-uri:
+:lang: en
+:encoding: utf-8
+
+== Introduction
+This WindowManager implements simple layout switching of applications on
+multiple layers and with different layer layouts.
+
+=== Intended audience
+This documentation is intended for developers and system integrators
+that need to know how the window manager works and how it is to be used.
+
+=== Scope of this Document
+This document covers the window manager that was implemented for TMC and
+delivered to the Automotive Grade Linux (AGL) project. It includes its
+implementation details, concepts of operation, configuration and usage.
+
+=== Known Issues
+Currently there are a couple of known issues:
+
+* Weston seems not to redraw the screen correctly. When the window
+ manager makes scene changes in quick succession, Weston seems not to
+ redraw the screen correctly and also not send wl_surface::enter
+ events, which in turn leaves applications "dead" - i.e. not rendering
+ or showing up. We developed a simple secondary ivi-controller client
+ application *redraw_fixer* (See <<_redraw_fixer,redraw_fixer>> for more)
+ that listens for specific scene-change events and issues other commands
+ that should prompt a correct redraw - however, this does not work in
+ all instances.
+* Only single-surface Qt applications are support through the AFBClient
+ library. This is a limitation of how Qt creates surface IDs for the
+ ivi-application interface.
+
+== Concepts
+The window manager implements a couple of concepts in order to allow
+efficient implementation.
+
+=== Layers
+Layers are entities that are stacked on top of each other. Each layer
+has an ID which is used for the ivi-controller interface, but this ID
+also implicitly specifies its stacking order. That is, the screen render
+order will be set according to the layer stacking which is determined by
+the layer IDs.
+
+Layers are always full-screen. We do not use layer dimensions as a way
+to setup the scene, rather - each layer has a layout attached to it,
+which specifies an area that is used by surfaces to draw on.
+
+Additionally, layers will generally leave surfaces on below layers
+activated, and only disable surfaces on layers the are above the
+currently used layer.
+
+In order to deactivate surfaces on lower layer, it is possible to
+deactivate these surfaces explicitly using the `deactivate_surface` API
+call.
+
+=== Surfaces
+Surfaces are _placed_ on layers according to their name. The surface
+will then be resized to dimensions, according to the layer's layout
+configuration.
+
+== Configuration
+The window manager is configured with the _layers.json_ configuration
+file, by default it is searched in `/etc/layers.json` but through the
+use of the environment variable `LAYERS_JSON` the WM can be instructed
+to use different file. Note, that the WM will not run unless this
+configuration is found and valid.
+
+=== Configuration Items
+This section describes configuration items available through
+`layers.json`. It will do this, by first providing an example, and then
+going into its components.
+
+Configuration items can contain `comment` objects, these are unused and
+only for documentation purposes in the json, they can safely be removed
+from the JSON file.
+
+==== main_surface
+------
+"main_surface": {
+ "surface_role": "HomeScreen",
+},
+------
+
+The `main_surface` object describes a surface that will internally be
+treated as the main surface - usually this mean _HomeScreen_. The only
+special handling this surface receives, is that it is not allowed to
+deactivate it. Placement of this surface on an layer is done by the
+other configuration described below.
+
+* `surface_role` this configuration item specifies the name of the main
+ surface. Set this to e.g. `HomeScreen` if the main surface is called
+ `HomeScreen`.
+
+==== mappings
+This configuration item is a list of surface-name to layer mappings.
+
+===== surface to layer mapping
+------
+"mappings": [
+ {
+ "role": "^HomeScreen$",
+ "name": "HomeScreen",
+ "layer_id": 1000,
+ "area": { "type": "full" },
+ },
+ {
+ "role": "^App.*",
+ "name": "apps",
+ "layer_id": 1001,
+ "area": { "type": "rect",
+ "rect": { "x": 0,
+ "y": 100,
+ "width": -1,
+ "height": -201 } },
+ "split_layouts": []
+ }
+]
+------
+
+Each mapping defines the following items to map corresponding surfaces
+to a layer.
+
+* `role` defines a regular expression that application drawing names are
+ matched against. If applications match tis regular expression, the
+ surface will be visible on this layer.
+* `name` is just a name definition for this layer, it has no functional use
+ apart from identifying a layer with a name.
+* `layer_id` specifies which ID this layer will use.
+* `area` is an object that defines the area assigned to surfaces.
+* `split_layouts` is an optional item, that - if present - defines a
+ number of possible split-screen layouts for this layer.
+
+===== Area
+Areas can be either `full` or `rect`, whereas `full` means a fullscreen
+layer, this is mostly useful for the main_surface or HomeScreen layer.
+`rect` declares a layer drawing area specified as a rectangle with
+start coordinates `x` and `y` as well as its dimensions `width` and
+`height`.
+
+The dimensions can be specified relative to the screen dimensions. For
+this negative values for width and height mus be used.
+
+For example, a fullscreen surface can have the following `rect`
+definition:
+
+------
+"rect": { "x": 0,
+ "y": 0,
+ "width": -1,
+ "height": -1 }
+------
+
+So the expression for the actual surface dimensions when using
+screen-size-relative values will be:
+
+------
+actual_width = screen_width + 1 + width
+actual_height = screen_height + 1 + height
+------
+
+Or in other words, to leave an `N` wide border around a surface, the
+actual value in the configuration needs to be `-N - 1`.
+
+===== split_layouts
+this configuration item allows the specification of split-screen layouts
+on layers for certain surfaces. A split screen layout always has a
+_main_ surface and a _sub_ surface. In order to enter a split screen
+layout, first the _main_ surface of the layout must be activated, and
+then the _sub_ surface. In order to disable the split layout, one of the
+two participating surface must be deactivate (or a surface on a layer
+below the current one must be activated).
+
+------
+"split_layouts": [
+ {
+ "name": "Media Player",
+ "main_match": "^App MPlayer Main$",
+ "sub_match": "^App MPlayer Sub",
+ }
+]
+------
+
+A split layout object has the following attributes:
+
+* `name` defines its name, it has no actual function other then a way to
+ identify this split layout.
+* `main_match` is a regular expression that matches for the _main_
+ surface of this split layout.
+* `sub_match` is a regular expression that matches for the _sub_ surface
+ of this layout.
+
+In the above example only the surface with drawing name
+`App MPlayer Main` will be used as the _main_ surface, but all surfaces
+that begin with `App MPlayer Sub` can be used as a _sub_ surface for
+this layout.
+
+.Note
+******
+The names must still match the layer's role match!
+******
+
+== Binding API
+The binding API consists of a couple of AFB _verbs_ - that is function
+calls to the Window Manager.
+
+=== Verbs (Functions)
+* `RequestSurface(drawing_name: string): int`
+ Request a surface ID for the given name. This name and ID association
+ will live until the surface is destroyed (or e.g. the application
+ exits). Each surface that is managed by the window manager needs to
+ call this function first!
+* `ActivateSurface(drawing_name: string)`
+ This function requests the activation of a surface. It usually is not
+ called by the application, but rather by the application framework or
+ the HomeScreen.
+* `DeactivateSurface(drawing_name: string)`
+ Request deactivation of a surface. This function is not usually called
+ by applications themselves, but rather by the application framework or
+ the HomeScreen.
+* `EndDraw(drawing_name: string)`
+ Signals the window manager, that the surface is finished drawing. This
+ is useful for consistent flicker-free layout switches, see the
+ Architecture document for details.
+
+There are a couple of non-essential (mostly for debugging and
+development) API calls:
+
+* `list_drawing_names(): json`
+ List known surface _name_ to _ID_ associations.
+* `ping()`
+ Ping the window manager. Does also dispatch pending events if any.
+* `debug_status(): json`
+ Returns a json representation of the current layers and surfaces known
+ to the window manager. This represents the wayland-ivi-extension
+ object's properties.
+* `debug_surfaces(): json`
+ Returns a json representation of all surfaces known to the window
+ manager. This represents the wayland-ivi-extension properties of the
+ surfaces.
+* `debug_layers(): json`
+ Returns the current layer configuration, as configured through
+ _layers.json_.
+* `debug_terminate()`
+ Terminates the afb-daemon running the window manager binding, if the
+ environment variable `WINMAN_DEBUG_TERMINATE` is set.
+
+=== Events
+The window manager broadcasts certain events (to all applications) that
+signal information on the state of the surface regarding the current
+layout.
+
+* `Active(drawing_name: string)`
+ Signal that the surface with the name `drawing_name` is now active.
+* `Inactive(drawing_name: string)`
+ Signal that the surface with the name `drawing_name` is now inactive.
+ This usually means, the layout got changed, and the surface is now
+ considered inactive (or sleeping).
+* `Visible(drawing_name: string)`
+ Signal applications, that the surface with name `drawing_name` is now
+ visible.
+* `Invisible(drawing_name: string)`
+ Signal applications that the surface with name `drawing_name` is now
+ invisible.
+* `SyncDraw(drawing_name: string)`
+ Signal applications, that the surface with name `drawing_name` needs
+ to redraw its content - this usually is sent when the surface geometry
+ changed.
+* `FlushDraw(drawing_name: string)`
+ Signal to applications, that the surface with name `drawing_name` can
+ now be swapped to its newly drawn content as the window manager is
+ ready to activate a new layout (i.e. a new surface geomtry).
+
+=== Binding API Usage
+For a detailed description on how the binding API is supposed to be
+used, refer to the Architecture document.
+
+== Building and Running
+
+=== Dependencies
+This project is intended to be build with the 4.0 release of AGL.
+
+Build dependencies are as follows:
+
+* afb-daemon >= 1.0
+* libsystemd >= 2222
+* wayland-client >= 1.11
+
+=== Build Configuration
+Use cmake to configure a build tree:
+
+--------
+mkdir build
+cd build
+cmake ..
+make
+[sudo] make install
+--------
+
+== Utilities
+With the actual window manager implementation, two general utilities are
+provided.
+
+=== wm-request
+A shell script, that wraps `afb-client-demo` and issues commands to the
+window manager using the AFB exposed API. It will call synchronously to
+the WM, and output any events that are happening in the meantime.
+Replies are printed to stdout using an failed/success annotation and a
+dump of the actual json reply from the AFB.
+
+==== Commands
+* `wm-request requestsurface $NAME`: request the surface with $NAME,
+ this will succeed only if the surface name is not yet (or anymore)
+ known. The actual call return is in the "response" json object of the
+ reply.
+* `wm-request activatesurface $NAME`: activate the surface with $NAME.
+ This call will only succeed of the surface is available and not
+ currently active. The reply just contains failure/success information,
+ but no actual return value from the API.
+* `wm-request deactivatesurface $NAME`: deactivate the surface with
+ $NAME. This call will only succeed if the surface is currently active,
+ no return value is provided by the API.
+* `wm-request ping`: Just send a *ping* to the window manager, can be
+ sued to check whether the WindowManager is alive or not.
+
+=== redraw_fixer
+This utility is intended to be ran alongside the compositor, it will
+listen for certain events regarding surfaces, and issue a couple of
+other commands, to hopefully trigger a redraw of the surface in the
+compositor.
+
+It will print messages for each acted-upon event, and exit when the
+compositor exits.
+
+== Implementation Notes
+The window manager is implemented as a app-framework-binder binding. That
+means, the build produces one shared object that exports a binding
+interface.
+
+=== Binding code generation
+The binding API is rather simple; functions receive a json object
+describing arguments and return a json object describing the result or
+an error. In order to simplify development, the
+`generate-binding-glue.py` script was added, that contains a description
+of the API as a python dictionary. This script generates the header
+`afb_binding_api.hpp` and the afb binding functions as
+`afb_binding_glue.inl`. Where the latter is included in `main.cpp`.
+
+Each function for the AFB binding that is generated does the following:
+
+* Lock the binding mutex, so that we serialize all access to the
+ binding.
+* Do some debug logging (if wanted).
+* Check the binding state, i.e. the compositor might have exited
+ unexpectedly at which point it would not make sense to continue.
+* Extract the arguments from the json object that is provided (doing
+ some primitive type checking).
+* Call the afb_binding_api method corresponding to this binding function
+* Check the afb_binding_api's function return value, log an error state
+ and return the result to the afb request.
+
+The generated functions do also check for any "loose" exception that
+comes out of the afb_binding_api call (which in turn might call the
+actual non-trivial implementation in `App`). However, *IF* an exception
+is thrown and not handled inside the afb_binding_call, that internal
+state of the window manager might be broken at this time (hence the
+talkative error log).
+
+=== Structure
+The implementation is loosely split across the following source files:
+
+* `main.cpp`: The program entry point as used by the afb-daemon. This
+ file defines the afbBindingV2 symbol tat is used by the afb-daemon in
+ order to load a binding. It also defines the wayland fd event
+ dispatcher and some globals to be used (as context for the afb calls
+ we receive).
+* `afb_binding_api.cpp`: The implementation of the afb binding
+ functions. The actual functions are generated by
+ `generate-binding-glue.py` which generates a *.inl* file that is
+ included by `main.cpp`.
+* `app.cpp` / `app.hpp`: This is the main application logic
+ implementation.
+* `config.cpp` / `config.hpp`: Very simple configuration item interface.
+* `controller_hooks.hpp`: hook functions called by the wayland
+ controller to call into the App instance. Only a very limited number
+ of events are passed to the Application, which allowed the usage of
+ such a simple interface.
+* `json_helper.cpp` / `json_helper.hpp`: Smaller json related helper
+ functions.
+* `layers.cpp` / `layers.hpp`: Actually hold all the data from
+ layers.json configuration, do some transformations and service the App
+ implementation.
+* `layout.cpp` / `layout.hpp`: Very simple layout state for the
+ implementation of split layouts and tracking of the surfaces involved.
+* `policy.hpp`: PolicyManager implementation stub. Gets passed the
+ current and new layout on layout switch and can decide upon it being
+ valid or not.
+* `result.hpp`: Simple result class around `std::experimental::optional`
+ that additionally can hold a `char const *` to describe the error.
+* `util.cpp` / `util.hpp`: general utility functions and structs - and
+ preprocessor definitions (e.g. `log*()` to AFB logging functions.
+* `wayland.cpp` / `wayland.hpp`: A C++ object-oriented libwayland-client
+ wrapper. It is instanced in `main.cpp` and handles all our wayland
+ needs.
+
+=== XXX
+a
+
+---------------------------
+Some code
+---------------------------
+
+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`.
+
+.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)]).
+******************
+
+// vim:set ft=asciidoc tw=72 spell spelllang=en_US: