summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generate-binding-glue.py17
-rw-r--r--layers.json6
-rwxr-xr-xscripts/wm-request9
-rw-r--r--src/app.cpp91
-rw-r--r--src/app.hpp54
-rw-r--r--src/layers.cpp47
-rw-r--r--src/layers.hpp32
7 files changed, 225 insertions, 31 deletions
diff --git a/generate-binding-glue.py b/generate-binding-glue.py
index 43bc742..c6fda53 100644
--- a/generate-binding-glue.py
+++ b/generate-binding-glue.py
@@ -100,14 +100,23 @@ API = {
'api': 'g_afb_instance->app.api.', # where are our API functions
'functions': [
{
- 'name': 'register_surface',
+ 'name': 'request_surface',
#'return_type': 'int', # Or do they return all just some json?
'args': [ # describes the functions arguments, and their names as found in the json request
- { 'name': 'appid', 'type': 'uint32_t', 'jtype': 'int' }, # XXX: lookup jtypes automatically? i.e. char*|const char* would be string?
- { 'name': 'surfaceid', 'type': 'uint32_t', 'jtype': 'int' },
+ { 'name': 'drawing_name', 'type': 'char const*', 'jtype': 'string' },
],
},
- { 'name': 'demo_activate_surface', 'args': [ { 'name': 'surfaceid', 'type': 'uint32_t', 'jtype': 'int' } ] },
+ {
+ 'name': 'activate_surface',
+ 'args': [
+ { 'name': 'drawing_name', 'type': 'char const*', 'jtype': 'string' },
+ ],
+ },
+ { 'name': 'list_drawing_names', },
+ {
+ 'name': 'demo_activate_surface',
+ 'args': [ { 'name': 'surfaceid', 'type': 'uint32_t', 'jtype': 'int' } ]
+ },
{ 'name': 'demo_activate_all' },
{ 'name': 'debug_status', },
{ 'name': 'debug_layers', },
diff --git a/layers.json b/layers.json
index 0208502..280dd2e 100644
--- a/layers.json
+++ b/layers.json
@@ -3,9 +3,12 @@
"main_surface": {
"surface_id": 1000,
+ "surface_role": "HomeScreen",
"comment": "This surface should never be made invisible (The HomeScreen)"
},
+ "dynamic_ids_start": 16777216,
+
"layers": [
{
"name": "HomeScreen",
@@ -28,6 +31,7 @@
{
"type": "single",
"surface_id": 1000,
+ "role": "^HomeScreen$",
"name": "HomeScreen",
"layer_id": 1000,
"area": { "type": "full" },
@@ -37,6 +41,7 @@
"type": "range",
"first_surface_id": 2000,
"last_surface_id": 2999,
+ "role": "^App.*",
"name": "apps",
"layer_id": 1001,
"area": { "type": "rect", "rect": { "x": 0, "y": 100, "width": -1, "height": -201 } },
@@ -46,6 +51,7 @@
"type": "range",
"first_surface_id": 3000,
"last_surface_id": 3999,
+ "role": "^OnScreen.*",
"name": "popups",
"layer_id": 9999,
"area": { "type": "rect", "rect": { "x": 0, "y": 100, "width": -1, "height": -201 } },
diff --git a/scripts/wm-request b/scripts/wm-request
index 618da62..c98e748 100755
--- a/scripts/wm-request
+++ b/scripts/wm-request
@@ -1,5 +1,12 @@
#!/bin/sh
+nopygments=0
+if [ "$1" = "-p" ]
+then
+ nopygments=1
+ shift
+fi
+
if ! [ "$1" ]
then
echo "Usage: $0 VERB [ARGS]" >&2
@@ -15,7 +22,7 @@ set -eu
if which python 2>/dev/null 1>&2 && echo '{ "test": "1" }' | python -m json.tool 2>/dev/null 1>&2
then
- if which pygmentize 2>/dev/null 1>&2
+ if [ $nopygments = 0 ] && which pygmentize 2>/dev/null 1>&2
then
json_pretty() {
python -m json.tool | pygmentize -l json
diff --git a/src/app.cpp b/src/app.cpp
index db0a5e3..c38a7f4 100644
--- a/src/app.cpp
+++ b/src/app.cpp
@@ -31,6 +31,7 @@
#include <bits/signum.h>
#include <csignal>
#include <fstream>
+#include <algorithm>
#include <json.hpp>
namespace wm {
@@ -44,8 +45,7 @@ struct wm::area area_from_json(json const &j) {
return wm::area{
j["name"],
{
- j["width"], j["height"],
- j["x"], j["y"],
+ j["width"], j["height"], j["x"], j["y"],
},
j["zorder"],
};
@@ -126,7 +126,11 @@ App::App(wl::display *d)
outputs(),
config(),
layouts(),
- layers() {
+ layers(),
+ pending(),
+ name_mapping(),
+ id_alloc{}
+{
assert(g_app == nullptr);
g_app = this;
@@ -280,8 +284,10 @@ void App::surface_set_layout(uint32_t surface_id) {
}
uint32_t layer_id = o_layer_id.value();
+ logdebug("surface_set_layout for surface %u on layer %u", surface_id, layer_id);
- auto rect = this->layers.get_layer_rect(surface_id).value();
+ auto const &layer = this->layers.get_layer(layer_id);
+ auto rect = layer.value().rect;
auto &s = this->controller->surfaces[surface_id];
int x = rect.x;
@@ -305,7 +311,7 @@ void App::surface_set_layout(uint32_t surface_id) {
// XXX: visibility should be determined independently of our
// layer + geometry setup.
- s->set_visibility(1);
+ s->set_visibility(surface_id == (unsigned)this->layers.main_surface ? 1 : 0);
this->controller->layers[layer_id]->add_surface(s.get());
logdebug("Surface %u now on layer %u with rect { %d, %d, %d, %d }",
@@ -317,7 +323,7 @@ char const *App::activate_surface(uint32_t surface_id) {
return "Surface does not exist";
}
- // This shouild involve a policy check, but as we do not (yet) have
+ // This should involve a policy check, but as we do not (yet) have
// such a thing, we will just switch to this surface.
// XXX: input focus missing!!1
@@ -376,24 +382,81 @@ void App::surface_removed(uint32_t surface_id) {
logdebug("surface_id is %u", surface_id);
}
+result<int> App::request_surface(char const *drawing_name) {
+ auto lid = this->layers.get_layer_id(std::string(drawing_name));
+ if (!lid) {
+ // XXX: to we need to put these applications on the App layer?
+ return Err<int>("Drawing name does not match any role");
+ }
+
+ auto rname = this->id_alloc[drawing_name];
+ if (! rname) {
+ // name does not exist yet, allocate surface id...
+ // XXX: how to allocate surface IDs?
+ // * allocate by running a counter for each layer?
+ // * allocate IDs globally, i.e. do not have layers contain
+ // ID ranges (only define the surfaces on the layer by
+ // role?)
+ auto id = int(this->id_alloc(drawing_name));
+ this->layers.add_surface(id, lid.value());
+
+ // XXX: setup the main_surface id if we registered HomeScreen
+ // XXX: you should fix this!
+ if (!this->layers.main_surface_name.empty() &&
+ this->layers.main_surface_name == drawing_name) {
+ this->layers.main_surface = id;
+ this->activate_surface(id);
+ logdebug("Set main_surface id to %u", id);
+ }
+
+ return Ok<int>(id);
+ }
+
+ // Check currently registered drawing names if it is already there.
+ return Err<int>("Surface already present");
+}
+
+char const* App::activate_surface(char const *drawing_name) {
+ auto osid = this->id_alloc[drawing_name];
+
+ if (osid) {
+ logdebug("ativate surface with name %s and id %u", drawing_name, osid.value());
+ this->activate_surface(osid.value());
+ return nullptr;
+ }
+
+ logerror("surface %s unknown", drawing_name);
+ return "Surface unknown";
+}
+
// _ _ _ _ _ _ _
// | |__ (_)_ __ __| (_)_ __ __ _ __ _ _ __ (_) (_)_ __ ___ _ __ | |
// | '_ \| | '_ \ / _` | | '_ \ / _` | / _` | '_ \| | | | '_ ` _ \| '_ \| |
// | |_) | | | | | (_| | | | | | (_| | | (_| | |_) | | | | | | | | | |_) | |
// |_.__/|_|_| |_|\__,_|_|_| |_|\__, |___\__,_| .__/|_| |_|_| |_| |_| .__/|_|
// |___/_____| |_| |_|
-binding_api::result_type binding_api::register_surface(uint32_t appid,
- uint32_t surfid) {
- logdebug("%s appid %u surfid %u", __func__, appid, surfid);
- if (appid > 0xff) {
- return Err<json_object *>("invalid appid");
+binding_api::result_type binding_api::request_surface(
+ char const *drawing_name) {
+ auto r = this->app->request_surface(drawing_name);
+ if (r.is_err()) {
+ return Err<json_object*>(r.unwrap_err());
}
+ return Ok(json_object_new_int(r.unwrap()));
+}
- if (surfid > 0xffff) {
- return Err<json_object *>("invalid surfaceid");
+binding_api::result_type binding_api::activate_surface(
+ char const *drawing_name) {
+ logdebug("%s drawing_name %s", __func__, drawing_name);
+ auto r = this->app->activate_surface(drawing_name);
+ if (r) {
+ return Err<json_object *>(r);
}
+ return Ok(json_object_new_object());
+}
- return Ok(json_object_new_int((appid << 16) + surfid));
+binding_api::result_type binding_api::list_drawing_names() {
+ json j = this->app->id_alloc.names;
+ return Ok(json_tokener_parse(j.dump().c_str()));
}
binding_api::result_type binding_api::debug_layers() {
diff --git a/src/app.hpp b/src/app.hpp
index 90ab42c..12d26b4 100644
--- a/src/app.hpp
+++ b/src/app.hpp
@@ -19,6 +19,8 @@
#include <json-c/json.h>
#include <memory>
+#include <unordered_map>
+#include <unordered_set>
#include "afb_binding_api.hpp"
#include "config.hpp"
@@ -38,6 +40,41 @@ struct controller;
namespace wm {
+struct id_allocator {
+ unsigned next = 0x0100'0000;
+
+ // Surfaces that where requested but not yet created
+ std::unordered_map<unsigned, std::string> surfaces;
+ // std::unordered_set<unsigned> pending_surfaces;
+ std::unordered_map<std::string, unsigned> names;
+
+ id_allocator(id_allocator const &) = delete;
+ id_allocator(id_allocator &&) = delete;
+ id_allocator &operator=(id_allocator const &);
+ id_allocator &operator=(id_allocator &&) = delete;
+
+ // Allocate a new ID
+ unsigned operator()(std::string const &name) {
+ unsigned sid = this->next++;
+ this->surfaces[sid] = name;
+ // this->pending_surfaces.insert({sid});
+ this->names[name] = sid;
+ logdebug("allocated new id %u with name %s", sid, name.c_str());
+ return sid;
+ }
+
+ // Lookup by ID or by name
+ optional<unsigned> operator[](std::string const &name) {
+ auto i = this->names.find(name);
+ return i == this->names.end() ? nullopt : optional<unsigned>(i->second);
+ }
+
+ optional<std::string> operator[](unsigned id) {
+ auto i = this->surfaces.find(id);
+ return i == this->surfaces.end() ? nullopt : optional<std::string>(i->second);
+ }
+};
+
struct App {
struct binding_api api;
struct controller_hooks chooks;
@@ -56,6 +93,11 @@ struct App {
typedef std::pair<char const *, std::function<void()>> name_task_pair;
std::vector<name_task_pair> pending;
+ typedef std::map<std::string, int> drawing_name_map;
+ drawing_name_map name_mapping;
+
+ struct id_allocator id_alloc;
+
explicit App(wl::display *d);
~App();
@@ -65,14 +107,24 @@ struct App {
App &operator=(App &&) = delete;
int init();
- int dispatch_events();
int init_layout();
+
+ int dispatch_events();
+
void surface_set_layout(uint32_t surface_id);
char const *activate_surface(uint32_t surface_id);
+ // Allocate a surface ID for this role
+ result<int> request_surface(char const *drawing_name);
+
+ // Activate (i.e. make visible, if allowed!) a surface
+ char const *activate_surface(char const *drawng_name);
+
+ // add tasks, executed after dispatch_events()
void add_task(char const *name, std::function<void()> &&f);
void execute_pending();
+ // Events from the compositor we are interested in
void surface_created(uint32_t surface_id);
void surface_removed(uint32_t surface_id);
};
diff --git a/src/layers.cpp b/src/layers.cpp
index 8f79451..464e20b 100644
--- a/src/layers.cpp
+++ b/src/layers.cpp
@@ -15,6 +15,7 @@
*/
#include <algorithm>
+#include <regex>
#include "json_helper.hpp"
#include "layers.hpp"
@@ -31,7 +32,8 @@ layer::layer(nlohmann::json const &j) {
} else {
this->id_min = this->id_max = j["surface_id"];
}
- this->name = j["name"].get<std::string>();
+ this->role = j["role"];
+ this->name = j["name"];
this->layer_id = j["layer_id"];
this->rect = genivi::full_rect;
if (j["area"]["type"] == "rect") {
@@ -47,14 +49,25 @@ struct result<struct layer_map> to_layer_map(nlohmann::json const &j) {
try {
layer_map stl{};
auto m = j["mappings"];
- stl.layers.reserve(m.size());
+
std::transform(std::cbegin(m), std::cend(m),
std::inserter(stl.mapping, stl.mapping.end()),
- [&stl](nlohmann::json const &j) {
- auto k = layer(j);
- stl.layers.push_back(unsigned(k.layer_id));
- return k;
+ [](nlohmann::json const &j) {
+ return layer(j);
});
+
+ // XXX: add sanity checks here?
+ // * check for double IDs
+ // * check for double names/roles
+
+ stl.layers.reserve(m.size());
+ std::transform(std::cbegin(stl.mapping), std::cend(stl.mapping),
+ std::back_inserter(stl.layers),
+ [&stl](struct layer const &k) {
+ stl.roles.emplace_back(std::make_pair(k.role, k.layer_id));
+ return unsigned(k.layer_id);
+ });
+
// XXX need to sort layers?
for (auto i : stl.mapping) {
if (i.name.empty()) {
@@ -68,6 +81,7 @@ struct result<struct layer_map> to_layer_map(nlohmann::json const &j) {
auto msi = j.find("main_surface");
if (msi != j.end()) {
stl.main_surface = (*msi)["surface_id"];
+ stl.main_surface_name = msi->value("surface_role", "");
}
// Check lookup
@@ -125,7 +139,26 @@ optional<layer> get_surface_id_to_layer(struct layer_map const *s2l,
optional<int> layer_map::get_layer_id(int surface_id) {
auto e = get_surface_id_to_layer(this, surface_id);
- return e ? optional<int>(e->layer_id) : nullopt;
+ if (! e) {
+ auto i = this->surfaces.find(surface_id);
+ if (i != this->surfaces.end()) {
+ return optional<int>(int(i->second));
+ }
+ return nullopt;
+ }
+ return optional<int>(e->layer_id);
+}
+
+optional<int> layer_map::get_layer_id(std::string const &role) {
+ for (auto const &r : this->roles) {
+ auto re = std::regex(r.first);
+ if (std::regex_match(role, re)) {
+ logdebug("role %s matches layer %d", role.c_str(), r.second);
+ return optional<int>(r.second);
+ }
+ }
+ logdebug("role %s does NOT match any layer", role.c_str());
+ return nullopt;
}
optional<genivi::rect> layer_map::get_layer_rect(int surface_id) {
diff --git a/src/layers.hpp b/src/layers.hpp
index 525a8b1..ae609fc 100644
--- a/src/layers.hpp
+++ b/src/layers.hpp
@@ -43,6 +43,9 @@ struct layer {
// That is; allow us to specify dimensions dependent on
// e.g. screen dimension, w/o knowing the actual screen size.
genivi::rect rect;
+ // Specify a role prefix for surfaces that should be
+ // put on this layer.
+ std::string role;
// XXX perhaps a zorder is needed here?
explicit layer(nlohmann::json const &j);
@@ -54,24 +57,45 @@ struct layer {
json to_json() const;
};
-// Actually, we shouldn't need a struct here ... but let's just keep it at that
-// for now, to contain its mapping type and the _single_ useful method.
struct layer_map {
using json = nlohmann::json;
typedef std::set<struct layer> storage_type;
typedef std::vector<unsigned int> layers_type;
+ typedef std::vector<std::pair<std::string, int>> role_to_layer_map;
+ typedef std::map<unsigned, unsigned> addsurf_layer_map;
- storage_type mapping;
- layers_type layers;
+ // XXX: we also will need a layer_id to layer map, perhaps
+ // make this the primary map, and the surface_id->layer a
+ // secondary map.
+
+ storage_type mapping; // map surface_id to layer
+ layers_type layers; // the actual layer IDs we have
int main_surface;
+ std::string main_surface_name;
+ role_to_layer_map roles;
+ addsurf_layer_map surfaces; // additional surfaces on layers
optional<int> get_layer_id(int surface_id);
+ optional<int> get_layer_id(std::string const &role);
+ optional<struct layer> get_layer(int layer_id) {
+ auto i = std::find_if(std::cbegin(this->mapping),
+ std::cend(this->mapping),
+ [layer_id](struct layer const &l) {
+ return layer_id == l.layer_id;
+ });
+ return i == this->mapping.end() ? nullopt : optional<struct layer>(*i);
+ }
+
optional<genivi::rect> get_layer_rect(int surface_id);
layers_type::size_type get_layers_count() const {
return this->layers.size();
}
+ void add_surface(unsigned surface_id, unsigned layer_id) {
+ this->surfaces[surface_id] = layer_id;
+ }
+
json to_json() const;
};