summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/CMakeLists.txt129
-rw-r--r--src/afb_binding_api.cpp114
-rw-r--r--src/app.cpp733
-rw-r--r--src/app.hpp188
-rw-r--r--src/config.cpp26
-rw-r--r--src/config.hpp49
-rw-r--r--src/controller_hooks.hpp40
-rw-r--r--src/json_helper.cpp102
-rw-r--r--src/json_helper.hpp30
-rw-r--r--src/layers.cpp154
-rw-r--r--src/layers.hpp118
-rw-r--r--src/layout.cpp17
-rw-r--r--src/layout.hpp43
-rwxr-xr-xsrc/main.cpp175
-rw-r--r--src/policy.hpp35
-rw-r--r--src/redraw_fixer.cpp128
-rw-r--r--src/result.hpp77
-rw-r--r--src/util.cpp39
-rw-r--r--src/util.hpp109
-rw-r--r--src/wayland.cpp765
-rw-r--r--src/wayland.hpp354
21 files changed, 3425 insertions, 0 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..7bbc35d
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,129 @@
+#
+# Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+wlproto(IVI_CON ivi-controller)
+
+include(FindPkgConfig)
+pkg_check_modules(AFB REQUIRED afb-daemon)
+pkg_check_modules(SD REQUIRED libsystemd>=222)
+
+# We do not want a prefix for our module
+set(CMAKE_SHARED_MODULE_PREFIX "")
+
+add_custom_command(
+ OUTPUT afb_binding_api.hpp afb_binding_glue.inl
+ DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/../generate-binding-glue.py
+ COMMAND python ${CMAKE_CURRENT_SOURCE_DIR}/../generate-binding-glue.py)
+
+set(TARGETS_WM windowmanager-service)
+
+add_library(${TARGETS_WM} MODULE
+ main.cpp
+ wayland.cpp
+ wayland.hpp
+ util.cpp
+ util.hpp
+ layout.cpp
+ layout.hpp
+ ${IVI_CON_PROTO}
+ json_helper.cpp
+ json_helper.hpp
+ app.hpp app.cpp
+ afb_binding_api.cpp
+ result.hpp
+ afb_binding_api.hpp
+ afb_binding_glue.inl
+ layers.cpp
+ layers.hpp
+ controller_hooks.hpp
+ config.cpp
+ config.hpp
+ policy.hpp)
+
+target_include_directories(${TARGETS_WM}
+ PRIVATE
+ ${AFB_INCLUDE_DIRS}
+ ${SD_INCLUDE_DIRS}
+ ../include
+ ../src)
+
+target_link_libraries(${TARGETS_WM}
+ PRIVATE
+ ${AFB_LIBRARIES}
+ ${WLC_LIBRARIES}
+ ${SD_LIBRARIES})
+
+target_compile_definitions(${TARGETS_WM}
+ PRIVATE
+ AFB_BINDING_VERSION=2
+ # We do not want source location of messages
+ AFB_BINDING_PRAGMA_NO_VERBOSE_DETAILS
+ WINMAN_VERSION_STRING="${PACKAGE_VERSION}"
+ _GNU_SOURCE) # XXX should I define this here?!
+
+if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release")
+ target_compile_definitions(${TARGETS_WM}
+ PRIVATE
+ _GLIBCXX_DEBUG)
+endif()
+
+target_compile_options(${TARGETS_WM}
+ PRIVATE
+ -Wall -Wextra -Wno-unused-parameter -Wno-comment)
+
+set_target_properties(${TARGETS_WM}
+ PROPERTIES
+ # INTERPROCEDURAL_OPTIMIZATION ON
+
+ CXX_EXTENSIONS OFF
+ CXX_STANDARD 14
+ CXX_STANDARD_REQUIRED ON
+
+ C_EXTENSIONS OFF
+ C_STANDARD 99
+ C_STANDARD_REQUIRED ON
+
+ LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../export.map")
+
+if (LINK_LIBCXX)
+ set_target_properties(${TARGETS_WM}
+ PROPERTIES
+ LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../export.map -lc++")
+endif()
+
+if (NOT ${SANITIZER_MODE} STREQUAL "none" AND NOT ${SANITIZER_MODE} STREQUAL "")
+ target_compile_options(${TARGETS_WM}
+ PRIVATE
+ -fsanitize=${SANITIZER_MODE} -g -fno-omit-frame-pointer)
+ set_target_properties(${TARGETS_WM}
+ PROPERTIES
+ LINK_FLAGS "-fsanitize=${SANITIZER_MODE} -g")
+endif()
+
+if(NOT EXISTS ${PROJECT_BINARY_DIR}/package)
+ add_custom_command(TARGET ${TARGETS_WM} POST_BUILD
+ COMMAND cp -rf ${PROJECT_SOURCE_DIR}/package ${PROJECT_BINARY_DIR}
+ )
+endif()
+
+add_custom_command(TARGET ${TARGETS_WM} POST_BUILD
+ COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/lib
+ COMMAND cp -rf ${PROJECT_BINARY_DIR}/src/${TARGETS_WM}.so ${PROJECT_BINARY_DIR}/package/root/lib
+)
+
+add_custom_target(package DEPENDS ${PROJECT_BINARY_DIR}/package/root
+ COMMAND wgtpkg-pack -f -o ${PROJECT_BINARY_DIR}/package/${TARGETS_WM}-2017.wgt ${PROJECT_BINARY_DIR}/package/root
+)
diff --git a/src/afb_binding_api.cpp b/src/afb_binding_api.cpp
new file mode 100644
index 0000000..9311700
--- /dev/null
+++ b/src/afb_binding_api.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "app.hpp"
+#include "json_helper.hpp"
+
+#include <csignal>
+
+#include <json.hpp>
+
+using json = nlohmann::json;
+
+#include <json-c/json.h>
+
+namespace wm {
+// _ _ _ _ _ _ _
+// | |__ (_)_ __ __| (_)_ __ __ _ __ _ _ __ (_) (_)_ __ ___ _ __ | |
+// | '_ \| | '_ \ / _` | | '_ \ / _` | / _` | '_ \| | | | '_ ` _ \| '_ \| |
+// | |_) | | | | | (_| | | | | | (_| | | (_| | |_) | | | | | | | | | |_) | |
+// |_.__/|_|_| |_|\__,_|_|_| |_|\__, |___\__,_| .__/|_| |_|_| |_| |_| .__/|_|
+// |___/_____| |_| |_|
+binding_api::result_type binding_api::requestsurface(
+ char const *drawing_name) {
+ auto r = this->app->api_request_surface(drawing_name);
+ if (r.is_err()) {
+ return Err<json_object *>(r.unwrap_err());
+ }
+ return Ok(json_object_new_int(r.unwrap()));
+}
+
+binding_api::result_type binding_api::activatesurface(
+ char const *drawing_name) {
+ logdebug("%s drawing_name %s", __func__, drawing_name);
+ auto r = this->app->api_activate_surface(drawing_name);
+ if (r != nullptr) {
+ logdebug("%s failed with error: %s", __func__, r);
+ return Err<json_object *>(r);
+ }
+ return Ok(json_object_new_object());
+}
+
+binding_api::result_type binding_api::deactivatesurface(char const* drawing_name) {
+ logdebug("%s drawing_name %s", __func__, drawing_name);
+ auto r = this->app->api_deactivate_surface(drawing_name);
+ if (r != nullptr) {
+ logdebug("%s failed with error: %s", __func__, r);
+ return Err<json_object *>(r);
+ }
+ return Ok(json_object_new_object());
+}
+
+binding_api::result_type binding_api::enddraw(char const* drawing_name) {
+ logdebug("%s drawing_name %s", __func__, drawing_name);
+ auto r = this->app->api_enddraw(drawing_name);
+ if (r != nullptr) {
+ logdebug("%s failed with error: %s", __func__, r);
+ return Err<json_object *>(r);
+ }
+ return Ok(json_object_new_object());
+}
+
+binding_api::result_type binding_api::list_drawing_names() {
+ logdebug("%s", __func__);
+ json j = this->app->id_alloc.name2id;
+ return Ok(json_tokener_parse(j.dump().c_str()));
+}
+
+binding_api::result_type binding_api::debug_layers() {
+ logdebug("%s", __func__);
+ return Ok(json_tokener_parse(this->app->layers.to_json().dump().c_str()));
+}
+
+binding_api::result_type binding_api::debug_surfaces() {
+ logdebug("%s", __func__);
+ return Ok(to_json(this->app->controller->sprops));
+}
+
+binding_api::result_type binding_api::debug_status() {
+ logdebug("%s", __func__);
+ json_object *jr = json_object_new_object();
+ json_object_object_add(jr, "surfaces",
+ to_json(this->app->controller->sprops));
+ json_object_object_add(jr, "layers", to_json(this->app->controller->lprops));
+ return Ok(jr);
+}
+
+binding_api::result_type binding_api::debug_terminate() {
+ logdebug("%s", __func__);
+ if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr) {
+ raise(SIGKILL); // XXX afb-daemon kills it's pgroup using TERM, which
+ // doesn't play well with perf
+ }
+ return Ok(json_object_new_object());
+}
+
+binding_api::result_type binding_api::ping() {
+ this->app->api_ping();
+ return Ok(json_object_new_object());
+}
+
+} // namespace wm
diff --git a/src/app.cpp b/src/app.cpp
new file mode 100644
index 0000000..75df8d7
--- /dev/null
+++ b/src/app.cpp
@@ -0,0 +1,733 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "app.hpp"
+#include "json_helper.hpp"
+#include "layers.hpp"
+#include "layout.hpp"
+#include "util.hpp"
+#include "wayland.hpp"
+
+#include <cstdio>
+#include <memory>
+
+#include <cassert>
+
+#include <json-c/json.h>
+
+#include <algorithm>
+#include <bits/signum.h>
+#include <csignal>
+#include <fstream>
+#include <json.hpp>
+#include <regex>
+#include <thread>
+
+namespace wm {
+
+namespace {
+
+using nlohmann::json;
+
+result<json> file_to_json(char const *filename) {
+ std::ifstream i(filename);
+ if (i.fail()) {
+ return Err<json>("Could not open config file");
+ }
+ json j;
+ i >> j;
+ return Ok(j);
+}
+
+struct result<layer_map> load_layer_map(char const *filename) {
+ logdebug("loading IDs from %s", filename);
+
+ auto j = file_to_json(filename);
+ if (j.is_err()) {
+ return Err<layer_map>(j.unwrap_err());
+ }
+ json jids = j.unwrap();
+
+ return to_layer_map(jids);
+}
+
+} // namespace
+
+// _ _ _ _
+// ___| | __ _ ___ ___ / \ _ __ _ __ (_)_ __ ___ _ __ | |
+// / __| |/ _` / __/ __| / _ \ | '_ \| '_ \ | | '_ ` _ \| '_ \| |
+// | (__| | (_| \__ \__ \ / ___ \| |_) | |_) | | | | | | | | |_) | |
+// \___|_|\__,_|___/___/ /_/ \_\ .__/| .__/ |_|_| |_| |_| .__/|_|
+// |_| |_| |_|
+App::App(wl::display *d)
+ : api{this},
+ chooks{this},
+ display{d},
+ controller{},
+ outputs(),
+ config(),
+ layers(),
+ id_alloc{},
+ pending_events(false),
+ policy{} {
+ try {
+ {
+ auto l = load_layer_map(
+ this->config.get_string("layers.json").value().c_str());
+ if (l.is_ok()) {
+ this->layers = l.unwrap();
+ } else {
+ logerror("%s", l.err().value());
+ }
+ }
+ } catch (std::exception &e) {
+ logerror("Loading of configuration failed: %s", e.what());
+ }
+}
+
+int App::init() {
+ if (!this->display->ok()) {
+ return -1;
+ }
+
+ if (this->layers.mapping.empty()) {
+ logerror("No surface -> layer mapping loaded");
+ return -1;
+ }
+
+ this->display->add_global_handler(
+ "wl_output", [this](wl_registry *r, uint32_t name, uint32_t v) {
+ this->outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
+ });
+
+ this->display->add_global_handler(
+ "ivi_controller", [this](wl_registry *r, uint32_t name, uint32_t v) {
+ this->controller =
+ std::make_unique<struct genivi::controller>(r, name, v);
+
+ // Init controller hooks
+ this->controller->chooks = &this->chooks;
+
+ // XXX: This protocol needs the output, so lets just add our mapping
+ // here...
+ this->controller->add_proxy_to_id_mapping(
+ this->outputs.back()->proxy.get(),
+ wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
+ this->outputs.back()->proxy.get())));
+ });
+
+ // First level objects
+ this->display->roundtrip();
+ // Second level objects
+ this->display->roundtrip();
+ // Third level objects
+ this->display->roundtrip();
+
+ return init_layers();
+}
+
+int App::dispatch_events() {
+ if (this->dispatch_events() == 0) {
+ return 0;
+ }
+
+ int ret = this->display->dispatch();
+ if (ret == -1) {
+ logerror("wl_display_dipatch() returned error %d",
+ this->display->get_error());
+ return -1;
+ }
+ this->display->flush();
+
+ return 0;
+}
+
+int App::dispatch_pending_events() {
+ if (this->pop_pending_events()) {
+ this->display->dispatch_pending();
+ return 0;
+}
+ return -1;
+}
+
+bool App::pop_pending_events() {
+ bool x{true};
+ return this->pending_events.compare_exchange_strong(
+ x, false, std::memory_order_consume);
+}
+
+void App::set_pending_events() {
+ this->pending_events.store(true, std::memory_order_release);
+}
+
+optional<int> App::lookup_id(char const *name) {
+ return this->id_alloc.lookup(std::string(name));
+}
+optional<std::string> App::lookup_name(int id) {
+ return this->id_alloc.lookup(id);
+}
+
+// _ _ _ _ _ ____
+// (_)_ __ (_) |_ | | __ _ _ _ ___ _ _| |_ / /\ \
+// | | '_ \| | __| | |/ _` | | | |/ _ \| | | | __| | | |
+// | | | | | | |_ | | (_| | |_| | (_) | |_| | |_| | | |
+// |_|_| |_|_|\__|___|_|\__,_|\__, |\___/ \__,_|\__| | | |
+// |_____| |___/ \_\/_/
+int App::init_layers() {
+ if (!this->controller) {
+ logerror("ivi_controller global not available");
+ return -1;
+ }
+
+ if (this->outputs.empty()) {
+ logerror("no output was set up!");
+ return -1;
+ }
+
+ auto &c = this->controller;
+
+ auto &o = this->outputs.front();
+ auto &s = c->screens.begin()->second;
+ auto &layers = c->layers;
+
+ // XXX: Write output dimensions to ivi controller...
+ c->output_size = genivi::size{uint32_t(o->width), uint32_t(o->height)};
+
+ // Clear scene
+ layers.clear();
+
+ // Clear screen
+ s->clear();
+
+ // Quick and dirty setup of layers
+ // XXX: This likely needs to be sorted by order (note, we don't (yet?)
+ // do any zorder arrangement).
+ for (auto const &i : this->layers.mapping) {
+ c->layer_create(i.second.layer_id, o->width, o->height);
+ auto &l = layers[i.second.layer_id];
+ l->set_destination_rectangle(0, 0, o->width, o->height);
+ l->set_visibility(1);
+ logdebug("Setting up layer %s (%d) for surface role match \"%s\"",
+ i.second.name.c_str(), i.second.layer_id, i.second.role.c_str());
+ }
+
+ // Add layers to screen (XXX: are they sorted correctly?)
+ s->set_render_order(this->layers.layers);
+
+ this->layout_commit();
+
+ return 0;
+}
+
+void App::surface_set_layout(int surface_id, optional<int> sub_surface_id) {
+ if (!this->controller->surface_exists(surface_id)) {
+ logerror("Surface %d does not exist", surface_id);
+ return;
+ }
+
+ auto o_layer_id = this->layers.get_layer_id(surface_id);
+
+ if (!o_layer_id) {
+ logerror("Surface %d is not associated with any layer!", surface_id);
+ return;
+ }
+
+ uint32_t layer_id = *o_layer_id;
+
+ 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;
+ int y = rect.y;
+ int w = rect.w;
+ int h = rect.h;
+
+ // less-than-0 values refer to MAX + 1 - $VALUE
+ // e.g. MAX is either screen width or height
+ if (w < 0) {
+ w = this->controller->output_size.w + 1 + w;
+ }
+ if (h < 0) {
+ h = this->controller->output_size.h + 1 + h;
+ }
+
+ if (sub_surface_id) {
+ if (o_layer_id != this->layers.get_layer_id(*sub_surface_id)) {
+ logerror(
+ "surface_set_layout: layers of surfaces (%d and %d) don't match!",
+ surface_id, *sub_surface_id);
+ return;
+ }
+
+ int x_off = 0;
+ int y_off = 0;
+
+ // split along major axis
+ if (w > h) {
+ w /= 2;
+ x_off = w;
+ } else {
+ h /= 2;
+ y_off = h;
+ }
+
+ auto &ss = this->controller->surfaces[*sub_surface_id];
+
+ logdebug("surface_set_layout for sub surface %u on layer %u",
+ *sub_surface_id, layer_id);
+
+ // configure surface to wxh dimensions
+ ss->set_configuration(w, h);
+ // set source reactangle, even if we should not need to set it.
+ ss->set_source_rectangle(0, 0, w, h);
+ // set destination to the display rectangle
+ ss->set_destination_rectangle(x + x_off, y + y_off, w, h);
+ }
+
+ logdebug("surface_set_layout for surface %u on layer %u", surface_id,
+ layer_id);
+
+ // configure surface to wxh dimensions
+ s->set_configuration(w, h);
+ // set source reactangle, even if we should not need to set it.
+ s->set_source_rectangle(0, 0, w, h);
+
+ // set destination to the display rectangle
+ s->set_destination_rectangle(x, y, w, h);
+
+ logdebug("Surface %u now on layer %u with rect { %d, %d, %d, %d }",
+ surface_id, layer_id, x, y, w, h);
+}
+
+void App::layout_commit() {
+ this->controller->commit_changes();
+ this->display->flush();
+}
+
+char const *App::api_activate_surface(char const *drawing_name) {
+ ST();
+ auto const &surface_id = this->lookup_id(drawing_name);
+
+ if (!surface_id) {
+ return "Surface does not exist";
+ }
+
+ if (!this->controller->surface_exists(*surface_id)) {
+ return "Surface does not exist in controller!";
+ }
+
+ auto layer_id = this->layers.get_layer_id(*surface_id);
+
+ if (!layer_id) {
+ return "Surface is not on any layer!";
+ }
+
+ auto o_state = *this->layers.get_layout_state(*surface_id);
+
+ if (o_state == nullptr) {
+ return "Could not find layer for surface";
+}
+
+ struct LayoutState &state = *o_state;
+
+ // disable layers that are above our current layer
+ for (auto const &l : this->layers.mapping) {
+ if (l.second.layer_id <= *layer_id) {
+ continue;
+ }
+
+ bool flush = false;
+ if (l.second.state.main != -1) {
+ this->deactivate(l.second.state.main);
+ l.second.state.main = -1;
+ flush = true;
+ }
+
+ if (l.second.state.sub != -1) {
+ this->deactivate(l.second.state.sub);
+ l.second.state.sub = -1;
+ flush = true;
+ }
+
+ if (flush) {
+ this->layout_commit();
+ }
+ }
+
+ if (state.main == *surface_id || state.sub == *surface_id) {
+ return "Surface already active";
+ }
+
+ if (state.main == -1) {
+ this->try_layout(
+ state, LayoutState{*surface_id}, [&] (LayoutState const &nl) {
+ this->surface_set_layout(*surface_id);
+ // XXX do we need to activate after enddraw?
+ state = nl;
+ this->emit_syncdraw(drawing_name);
+ this->enqueue_flushdraw(state.main);
+ });
+ } else {
+ bool can_split = this->can_split(state, *surface_id);
+
+ if (can_split) {
+ this->try_layout(
+ state,
+ LayoutState{state.main, *surface_id},
+ [&] (LayoutState const &nl) {
+ std::string main =
+ std::move(*this->lookup_name(state.main));
+
+ this->surface_set_layout(state.main, surface_id);
+ if (state.sub != -1) {
+ this->deactivate(state.sub);
+ }
+ state = nl;
+
+ this->emit_syncdraw(drawing_name);
+ this->emit_syncdraw(main.c_str());
+ this->enqueue_flushdraw(state.main);
+ this->enqueue_flushdraw(state.sub);
+ });
+ } else {
+ this->try_layout(
+ state, LayoutState{*surface_id}, [&] (LayoutState const &nl) {
+ this->surface_set_layout(*surface_id);
+ this->deactivate(state.main);
+ if (state.sub != -1) {
+ this->deactivate(state.sub);
+ }
+ state = nl;
+
+ this->emit_syncdraw(drawing_name);
+ this->enqueue_flushdraw(state.main);
+ });
+ }
+ }
+
+ // no error
+ return nullptr;
+}
+
+char const *App::api_deactivate_surface(char const *drawing_name) {
+ ST();
+ auto const &surface_id = this->lookup_id(drawing_name);
+
+ if (!surface_id) {
+ return "Surface does not exist";
+ }
+
+ if (*surface_id == this->layers.main_surface) {
+ return "Cannot deactivate main_surface";
+ }
+
+ auto o_state = *this->layers.get_layout_state(*surface_id);
+
+ if (o_state == nullptr) {
+ return "Could not find layer for surface";
+ }
+
+ struct LayoutState &state = *o_state;
+
+ if (state.main == -1) {
+ return "No surface active";
+ }
+
+ // XXX: check against main_surface, main_surface_name is the configuration
+ // item.
+ if (*surface_id == this->layers.main_surface) {
+ logdebug("Refusing to deactivate main_surface %d", *surface_id);
+ return nullptr;
+ }
+
+ if (state.main == *surface_id) {
+ if (state.sub != -1) {
+ this->try_layout(
+ state, LayoutState{state.sub, -1}, [&] (LayoutState const &nl) {
+ std::string sub = std::move(*this->lookup_name(state.sub));
+
+ this->deactivate(*surface_id);
+ this->surface_set_layout(state.sub);
+ state = nl;
+
+ this->layout_commit();
+ this->emit_syncdraw(sub.c_str());
+ this->enqueue_flushdraw(state.sub);
+ });
+ } else {
+ this->try_layout(state, LayoutState{-1, -1}, [&] (LayoutState const &nl) {
+ this->deactivate(*surface_id);
+ state = nl;
+ this->layout_commit();
+ });
+ }
+ } else if (state.sub == *surface_id) {
+ this->try_layout(
+ state, LayoutState{state.main, -1}, [&] (LayoutState const &nl) {
+ std::string main = std::move(*this->lookup_name(state.main));
+
+ this->deactivate(*surface_id);
+ this->surface_set_layout(state.main);
+ state = nl;
+
+ this->layout_commit();
+ this->emit_syncdraw(main.c_str());
+ this->enqueue_flushdraw(state.main);
+ });
+ } else {
+ return "Surface is not active";
+ }
+
+ return nullptr;
+}
+
+void App::enqueue_flushdraw(int surface_id) {
+ this->check_flushdraw(surface_id);
+ logdebug("Enqueuing EndDraw for surface_id %d", surface_id);
+ this->pending_end_draw.push_back(surface_id);
+}
+
+void App::check_flushdraw(int surface_id) {
+ auto i = std::find(std::begin(this->pending_end_draw),
+ std::end(this->pending_end_draw), surface_id);
+ if (i != std::end(this->pending_end_draw)) {
+ auto n = this->lookup_name(surface_id);
+ logerror("Application %s (%d) has pending EndDraw call(s)!",
+ n ? n->c_str() : "unknown-name", surface_id);
+ std::swap(this->pending_end_draw[std::distance(
+ std::begin(this->pending_end_draw), i)],
+ this->pending_end_draw.back());
+ this->pending_end_draw.resize(this->pending_end_draw.size() - 1);
+ }
+}
+
+char const *App::api_enddraw(char const *drawing_name) {
+ for (unsigned i = 0, iend = this->pending_end_draw.size(); i < iend; i++) {
+ auto n = this->lookup_name(this->pending_end_draw[i]);
+ if (n && *n == drawing_name) {
+ std::swap(this->pending_end_draw[i], this->pending_end_draw[iend - 1]);
+ this->pending_end_draw.resize(iend - 1);
+ // XXX: Please tell the compositor to thaw the surface...
+ this->activate(this->pending_end_draw[i]);
+ this->layout_commit();
+ this->emit_flushdraw(drawing_name);
+ return nullptr;
+ }
+ }
+ return "No EndDraw pending for surface";
+}
+
+void App::api_ping() { this->dispatch_pending_events(); }
+
+// _ _ _____ _
+// _ __ _ __ _____ _(_) ___ __| | | ____|_ _____ _ __ | |_ ___
+// | '_ \| '__/ _ \ \/ / |/ _ \/ _` | | _| \ \ / / _ \ '_ \| __/ __|
+// | |_) | | | (_) > <| | __/ (_| | | |___ \ V / __/ | | | |_\__ \
+// | .__/|_| \___/_/\_\_|\___|\__,_| |_____| \_/ \___|_| |_|\__|___/
+// |_|
+void App::surface_created(uint32_t surface_id) {
+ auto layer_id = this->layers.get_layer_id(surface_id);
+ if (!layer_id) {
+ logdebug("Newly created surfce %d is not associated with any layer!",
+ surface_id);
+ return;
+ }
+
+ logdebug("surface_id is %u, layer_id is %u", surface_id, *layer_id);
+
+ this->controller->layers[*layer_id]->add_surface(
+ this->controller->surfaces[surface_id].get());
+
+ // activate the main_surface right away
+ /*if (surface_id == static_cast<unsigned>(this->layers.main_surface)) {
+ logdebug("Activating main_surface (%d)", surface_id);
+
+ this->api_activate_surface(
+ this->lookup_name(surface_id).value_or("unknown-name").c_str());
+ }*/
+}
+
+void App::surface_removed(uint32_t surface_id) {
+ logdebug("surface_id is %u", surface_id);
+
+ // We cannot normally deactivate the main_surface, so be explicit
+ // about it:
+ if (int(surface_id) == this->layers.main_surface) {
+ this->deactivate_main_surface();
+ } else {
+ auto drawing_name = this->lookup_name(surface_id);
+ if (drawing_name) {
+ this->api_deactivate_surface(drawing_name->c_str());
+ }
+ }
+
+ this->id_alloc.remove_id(surface_id);
+ this->layers.remove_surface(surface_id);
+}
+
+void App::emit_activated(char const *label) {
+ this->api.send_event("active", label);
+}
+
+void App::emit_deactivated(char const *label) {
+ this->api.send_event("inactive", label);
+}
+
+void App::emit_syncdraw(char const *label) {
+ this->api.send_event("syncdraw", label);
+}
+
+void App::emit_flushdraw(char const *label) {
+ this->api.send_event("flushdraw", label);
+}
+
+void App::emit_visible(char const *label, bool is_visible) {
+ this->api.send_event(is_visible ? "visible" : "invisible", label);
+}
+
+void App::emit_invisible(char const *label) {
+ return emit_visible(label, false);
+}
+
+void App::emit_visible(char const *label) { return emit_visible(label, true); }
+
+result<int> App::api_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->lookup_id(drawing_name);
+ if (!rname) {
+ // name does not exist yet, allocate surface id...
+ auto id = int(this->id_alloc.generate_id(drawing_name));
+ this->layers.add_surface(id, *lid);
+
+ // XXX: we set the main_surface[_name] here and now,
+ // not sure if we want this, but it worked so far.
+ if (!this->layers.main_surface_name.empty() &&
+ this->layers.main_surface_name == drawing_name) {
+ this->layers.main_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");
+}
+
+void App::activate(int id) {
+ auto ip = this->controller->sprops.find(id);
+ if (ip != this->controller->sprops.end() && ip->second.visibility == 0) {
+ this->controller->surfaces[id]->set_visibility(1);
+ char const *label =
+ this->lookup_name(id).value_or("unknown-name").c_str();
+ this->emit_activated(label);
+ this->emit_visible(label);
+ }
+}
+
+void App::deactivate(int id) {
+ auto ip = this->controller->sprops.find(id);
+ if (ip != this->controller->sprops.end() && ip->second.visibility != 0) {
+ this->controller->surfaces[id]->set_visibility(0);
+ char const *label =
+ this->lookup_name(id).value_or("unknown-name").c_str();
+ this->emit_deactivated(label);
+ this->emit_invisible(label);
+ }
+}
+
+void App::deactivate_main_surface() {
+ this->layers.main_surface = -1;
+ this->api_deactivate_surface(this->layers.main_surface_name.c_str());
+}
+
+bool App::can_split(struct LayoutState const &state, int new_id) {
+ if (state.main != -1 && state.main != new_id) {
+ auto new_id_layer = this->layers.get_layer_id(new_id).value();
+ auto current_id_layer = this->layers.get_layer_id(state.main).value();
+
+ // surfaces are on separate layers, don't bother.
+ if (new_id_layer != current_id_layer) {
+ return false;
+}
+
+ std::string const &new_id_str = this->lookup_name(new_id).value();
+ std::string const &cur_id_str = this->lookup_name(state.main).value();
+
+ auto const &layer = this->layers.get_layer(new_id_layer);
+
+ logdebug("layer info name: %s", layer->name.c_str());
+
+ if (layer->layouts.empty()) {
+ return false;
+}
+
+ for (auto i = layer->layouts.cbegin(); i != layer->layouts.cend(); i++) {
+ logdebug("%d main_match '%s'", new_id_layer, i->main_match.c_str());
+ auto rem = std::regex(i->main_match);
+ if (std::regex_match(cur_id_str, rem)) {
+ // build the second one only if the first already matched
+ logdebug("%d sub_match '%s'", new_id_layer, i->sub_match.c_str());
+ auto res = std::regex(i->sub_match);
+ if (std::regex_match(new_id_str, res)) {
+ logdebug("layout matched!");
+ return true;
+}
+ }
+ }
+ }
+
+ return false;
+}
+
+void App::try_layout(struct LayoutState & /*state*/,
+ struct LayoutState const &new_layout,
+ std::function<void(LayoutState const &nl)> apply) {
+ if (this->policy.layout_is_valid(new_layout)) {
+ apply(new_layout);
+ }
+}
+
+// _ _ _ _ _
+// ___ ___ _ __ | |_ _ __ ___ | | | ___ _ __ | |__ ___ ___ | | _____
+// / __/ _ \| '_ \| __| '__/ _ \| | |/ _ \ '__|| '_ \ / _ \ / _ \| |/ / __|
+// | (_| (_) | | | | |_| | | (_) | | | __/ | | | | | (_) | (_) | <\__ \
+// \___\___/|_| |_|\__|_| \___/|_|_|\___|_|___|_| |_|\___/ \___/|_|\_\___/
+// |_____|
+void controller_hooks::surface_created(uint32_t surface_id) {
+ this->app->surface_created(surface_id);
+}
+
+void controller_hooks::surface_removed(uint32_t surface_id) {
+ this->app->surface_removed(surface_id);
+}
+
+void controller_hooks::surface_visibility(uint32_t /*surface_id*/,
+ uint32_t /*v*/) {}
+
+void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/,
+ uint32_t /*x*/,
+ uint32_t /*y*/,
+ uint32_t /*w*/,
+ uint32_t /*h*/) {}
+
+} // namespace wm
diff --git a/src/app.hpp b/src/app.hpp
new file mode 100644
index 0000000..9424d9f
--- /dev/null
+++ b/src/app.hpp
@@ -0,0 +1,188 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_APP_HPP
+#define TMCAGLWM_APP_HPP
+
+#include <json-c/json.h>
+
+#include <atomic>
+#include <memory>
+#include <unordered_map>
+#include <unordered_set>
+#include <experimental/optional>
+
+#include "afb_binding_api.hpp"
+#include "config.hpp"
+#include "controller_hooks.hpp"
+#include "layers.hpp"
+#include "layout.hpp"
+#include "policy.hpp"
+#include "result.hpp"
+#include "wayland.hpp"
+
+namespace wl {
+struct display;
+}
+
+namespace genivi {
+struct controller;
+}
+
+namespace wm {
+
+using std::experimental::optional;
+
+struct id_allocator {
+ unsigned next = 1;
+
+ // Surfaces that where requested but not yet created
+ std::unordered_map<unsigned, std::string> id2name;
+ // std::unordered_set<unsigned> pending_surfaces;
+ std::unordered_map<std::string, unsigned> name2id;
+
+ id_allocator(id_allocator const &) = delete;
+ id_allocator(id_allocator &&) = delete;
+ id_allocator &operator=(id_allocator const &);
+ id_allocator &operator=(id_allocator &&) = delete;
+
+ // Insert and return a new ID
+ unsigned generate_id(std::string const &name) {
+ unsigned sid = this->next++;
+ this->id2name[sid] = name;
+ // this->pending_surfaces.insert({sid});
+ this->name2id[name] = sid;
+ logdebug("allocated new id %u with name %s", sid, name.c_str());
+ return sid;
+ }
+
+ // Lookup by ID or by name
+ optional<unsigned> lookup(std::string const &name) const {
+ auto i = this->name2id.find(name);
+ return i == this->name2id.end() ? nullopt : optional<unsigned>(i->second);
+ }
+
+ optional<std::string> lookup(unsigned id) const {
+ auto i = this->id2name.find(id);
+ return i == this->id2name.end() ? nullopt
+ : optional<std::string>(i->second);
+ }
+
+ // Remove a surface id and name
+ // I don't think I will need this, do I?
+ void remove_id(std::string const &name) {
+ auto i = this->name2id.find(name);
+ if (i != this->name2id.end()) {
+ this->id2name.erase(i->second);
+ this->name2id.erase(i);
+ }
+ }
+
+ void remove_id(unsigned id) {
+ auto i = this->id2name.find(id);
+ if (i != this->id2name.end()) {
+ this->name2id.erase(i->second);
+ this->id2name.erase(i);
+ }
+ }
+};
+
+struct App {
+ struct binding_api api;
+ struct controller_hooks chooks;
+
+ // This is the one thing, we do not own.
+ struct wl::display *display;
+
+ std::unique_ptr<struct genivi::controller> controller;
+ std::vector<std::unique_ptr<struct wl::output>> outputs;
+
+ struct config config;
+
+ // track current layouts separately
+ layer_map layers;
+
+ // ID allocation and proxy methods for lookup
+ struct id_allocator id_alloc;
+
+ // Set by AFB API when wayland events need to be dispatched
+ std::atomic<bool> pending_events;
+
+ std::vector<int> pending_end_draw;
+
+ Policy policy;
+
+ explicit App(wl::display *d);
+ ~App() = default;
+
+ App(App const &) = delete;
+ App &operator=(App const &) = delete;
+ App(App &&) = delete;
+ App &operator=(App &&) = delete;
+
+ int init();
+
+ int dispatch_events();
+ int dispatch_pending_events();
+
+ void set_pending_events();
+
+ result<int> api_request_surface(char const *drawing_name);
+ char const *api_activate_surface(char const *drawing_name);
+ char const *api_deactivate_surface(char const *drawing_name);
+ char const *api_enddraw(char const *drawing_name);
+ void api_ping();
+
+ // Events from the compositor we are interested in
+ void surface_created(uint32_t surface_id);
+ void surface_removed(uint32_t surface_id);
+
+private:
+ optional<int> lookup_id(char const *name);
+ optional<std::string> lookup_name(int id);
+
+ bool pop_pending_events();
+
+ void enqueue_flushdraw(int surface_id);
+ void check_flushdraw(int surface_id);
+
+ int init_layers();
+
+ void surface_set_layout(int surface_id, optional<int> sub_surface_id = nullopt);
+ void layout_commit();
+
+ // TMC WM Events to clients
+ void emit_activated(char const *label);
+ void emit_deactivated(char const *label);
+ void emit_syncdraw(char const *label);
+ void emit_flushdraw(char const *label);
+ void emit_visible(char const *label, bool is_visible);
+ void emit_invisible(char const *label);
+ void emit_visible(char const *label);
+
+ void activate(int id);
+ void deactivate(int id);
+ void deactivate_main_surface();
+
+ bool can_split(struct LayoutState const &state, int new_id);
+ void try_layout(struct LayoutState &state,
+ struct LayoutState const &new_layout,
+ std::function<void(LayoutState const &nl)> apply);
+};
+
+} // namespace wm
+
+#endif // TMCAGLWM_APP_HPP
diff --git a/src/config.cpp b/src/config.cpp
new file mode 100644
index 0000000..d5a549a
--- /dev/null
+++ b/src/config.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "config.hpp"
+
+namespace wm {
+
+config::config() : cfg() {
+ // Supply default values for these...
+ this->cfg["layers.json"] = getenv("LAYERS_JSON") ?: "/etc/windowmanager/layers.json";
+}
+
+} // namespace wm
diff --git a/src/config.hpp b/src/config.hpp
new file mode 100644
index 0000000..d470b85
--- /dev/null
+++ b/src/config.hpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_CONFIG_HPP
+#define TMCAGLWM_CONFIG_HPP
+
+#include <experimental/optional>
+#include <map>
+
+namespace wm {
+
+using std::experimental::optional;
+using std::experimental::nullopt;
+
+struct config {
+ typedef std::map<std::string, std::string> map;
+
+ map cfg;
+
+ config();
+
+ optional<std::string> get_string(char const *s) {
+ auto i = this->cfg.find(s);
+ return i != this->cfg.end() ? optional<std::string>(i->second) : nullopt;
+ }
+
+ optional<int> get_int(char const *s) {
+ auto i = this->cfg.find(s);
+ return i != this->cfg.end() ? optional<int>(std::stoi(i->second))
+ : nullopt;
+ }
+};
+
+} // namespace wm
+
+#endif // TMCAGLWM_CONFIG_HPP
diff --git a/src/controller_hooks.hpp b/src/controller_hooks.hpp
new file mode 100644
index 0000000..31962ee
--- /dev/null
+++ b/src/controller_hooks.hpp
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_CONTROLLER_HOOKS_HPP
+#define TMCAGLWM_CONTROLLER_HOOKS_HPP
+
+#include <cstdint>
+
+#include <functional>
+
+namespace wm {
+
+struct App;
+
+struct controller_hooks {
+ struct App *app;
+
+ void surface_created(uint32_t surface_id);
+
+ void surface_removed(uint32_t surface_id);
+ void surface_visibility(uint32_t surface_id, uint32_t v);
+ void surface_destination_rectangle(uint32_t surface_id, uint32_t x, uint32_t y, uint32_t w, uint32_t h);
+};
+
+} // namespace wm
+
+#endif // TMCAGLWM_CONTROLLER_HOOKS_HPP
diff --git a/src/json_helper.cpp b/src/json_helper.cpp
new file mode 100644
index 0000000..179c8cc
--- /dev/null
+++ b/src/json_helper.cpp
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "json_helper.hpp"
+
+#include <json.h>
+
+json_object *to_json(genivi::surface_properties const &s) {
+ // auto j = json::object({
+ auto j = json_object_new_object();
+
+ // {"id", s.id},
+ json_object_object_add(j, "id", json_object_new_int(s.id));
+
+ // {"size", {{"width", s.size.w}, {"height", s.size.h}}},
+ auto jsize = json_object_new_object();
+ json_object_object_add(jsize, "width", json_object_new_int(s.size.w));
+ json_object_object_add(jsize, "height", json_object_new_int(s.size.h));
+ json_object_object_add(j, "size", jsize);
+
+ // {"dst",
+ // {{"width", s.dst_rect.w},
+ // {"height", s.dst_rect.h},
+ // {"x", s.dst_rect.x},
+ // {"y", s.dst_rect.y}}},
+ auto jdst = json_object_new_object();
+ json_object_object_add(jdst, "width", json_object_new_int(s.dst_rect.w));
+ json_object_object_add(jdst, "height", json_object_new_int(s.dst_rect.h));
+ json_object_object_add(jdst, "x", json_object_new_int(s.dst_rect.x));
+ json_object_object_add(jdst, "y", json_object_new_int(s.dst_rect.y));
+ json_object_object_add(j, "dst", jdst);
+
+ // {"src",
+ // {{"width", s.src_rect.w},
+ // {"height", s.src_rect.h},
+ // {"x", s.src_rect.x},
+ // {"y", s.src_rect.y}}},
+ auto jsrc = json_object_new_object();
+ json_object_object_add(jsrc, "width", json_object_new_int(s.src_rect.w));
+ json_object_object_add(jsrc, "height", json_object_new_int(s.src_rect.h));
+ json_object_object_add(jsrc, "x", json_object_new_int(s.src_rect.x));
+ json_object_object_add(jsrc, "y", json_object_new_int(s.src_rect.y));
+ json_object_object_add(j, "src", jsrc);
+
+ // {"visibility", s.visibility},
+ json_object_object_add(
+ j, "visibility",
+ json_object_new_boolean(static_cast<json_bool>(s.visibility == 1)));
+
+ // {"opacity", s.opacity},
+ json_object_object_add(j, "opacity", json_object_new_double(s.opacity));
+
+ // {"orientation", s.orientation},
+ json_object_object_add(j, "orientation", json_object_new_int(s.orientation));
+
+ // });
+ return j;
+}
+
+json_object *to_json(genivi::screen const *s) {
+ auto o = json_object_new_object();
+ json_object_object_add(o, "id", json_object_new_int(s->id));
+ return o;
+}
+
+template <typename T>
+json_object *to_json_(T const &s) {
+ auto a = json_object_new_array();
+
+ if (!s.empty()) {
+ for (auto const &i : s) {
+ json_object_array_add(a, to_json(i.second));
+ }
+ }
+
+ return a;
+}
+
+json_object *to_json(genivi::controller::props_map const &s) {
+ return to_json_(s);
+}
+
+json_object *to_json(std::vector<uint32_t> const &v) {
+ auto a = json_object_new_array();
+ for (const auto i : v) {
+ json_object_array_add(a, json_object_new_int(i));
+ }
+ return a;
+}
diff --git a/src/json_helper.hpp b/src/json_helper.hpp
new file mode 100644
index 0000000..15d72c3
--- /dev/null
+++ b/src/json_helper.hpp
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_JSON_HELPER_HPP
+#define TMCAGLWM_JSON_HELPER_HPP
+
+#include "result.hpp"
+#include "wayland.hpp"
+#include <json.hpp>
+
+struct json_object;
+
+json_object *to_json(genivi::screen const *s);
+json_object *to_json(genivi::controller::props_map const &s);
+json_object *to_json(std::vector<uint32_t> const &v);
+
+#endif // TMCAGLWM_JSON_HELPER_HPP
diff --git a/src/layers.cpp b/src/layers.cpp
new file mode 100644
index 0000000..9219766
--- /dev/null
+++ b/src/layers.cpp
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <algorithm>
+#include <regex>
+
+#include "json_helper.hpp"
+#include "layers.hpp"
+#include "util.hpp"
+
+namespace wm {
+
+using json = nlohmann::json;
+
+layer::layer(nlohmann::json const &j) {
+ this->role = j["role"];
+ this->name = j["name"];
+ this->layer_id = j["layer_id"];
+ this->rect = genivi::full_rect;
+ if (j["area"]["type"] == "rect") {
+ auto jr = j["area"]["rect"];
+ this->rect = genivi::rect{
+ jr["width"], jr["height"], jr["x"], jr["y"],
+ };
+ }
+ auto split_layouts = j.find("split_layouts");
+ if (split_layouts != j.end()) {
+ auto &sls = j["split_layouts"];
+ // this->layouts.reserve(sls.size());
+ std::transform(std::cbegin(sls), std::cend(sls),
+ std::back_inserter(this->layouts), [this](json const &sl) {
+ struct split_layout l {
+ sl["name"], sl["main_match"], sl["sub_match"] };
+ logdebug(
+ "layer %d add split_layout \"%s\" (main: \"%s\") (sub: "
+ "\"%s\")", this->layer_id,
+ l.name.c_str(), l.main_match.c_str(),
+ l.sub_match.c_str());
+ return l;
+ });
+ }
+}
+
+struct result<struct layer_map> to_layer_map(nlohmann::json const &j) {
+ try {
+ layer_map stl{};
+ auto m = j["mappings"];
+
+ std::transform(std::cbegin(m), std::cend(m),
+ std::inserter(stl.mapping, stl.mapping.end()),
+ [](nlohmann::json const &j) {
+ return std::pair<int, struct layer>(
+ j.value("layer_id", -1), 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](std::pair<int, struct layer> const &k) {
+ stl.roles.emplace_back(
+ std::make_pair(k.second.role, k.second.layer_id));
+ return unsigned(k.second.layer_id);
+ });
+
+ std::sort(stl.layers.begin(), stl.layers.end());
+
+ for (auto i : stl.mapping) {
+ if (i.second.name.empty()) {
+ return Err<struct layer_map>("Found mapping w/o name");
+ }
+ if (i.second.layer_id == -1) {
+ return Err<struct layer_map>("Found invalid/unset IDs in mapping");
+ }
+ }
+
+ auto msi = j.find("main_surface");
+ if (msi != j.end()) {
+ stl.main_surface_name = msi->value("surface_role", "");
+ stl.main_surface = -1;
+ }
+
+ return Ok(stl);
+ } catch (std::exception &e) {
+ return Err<struct layer_map>(e.what());
+ }
+}
+
+optional<int> layer_map::get_layer_id(int surface_id) {
+ auto i = this->surfaces.find(surface_id);
+ if (i != this->surfaces.end()) {
+ return optional<int>(i->second);
+ }
+ return nullopt;
+}
+
+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;
+}
+
+json layer::to_json() const {
+ auto is_full = this->rect == genivi::full_rect;
+
+ json r{};
+ if (is_full) {
+ r = {{"type", "full"}};
+ } else {
+ r = {{"type", "rect"},
+ {"rect",
+ {{"x", this->rect.x},
+ {"y", this->rect.y},
+ {"width", this->rect.w},
+ {"height", this->rect.h}}}};
+ }
+
+ return {
+ {"name", this->name}, {"role", this->role},
+ {"layer_id", this->layer_id}, {"area", r},
+ };
+}
+
+json layer_map::to_json() const {
+ json j{};
+ for (auto const &i : this->mapping) {
+ j.push_back(i.second.to_json());
+ }
+ return j;
+}
+
+} // namespace wm
diff --git a/src/layers.hpp b/src/layers.hpp
new file mode 100644
index 0000000..0603d24
--- /dev/null
+++ b/src/layers.hpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_LAYERS_H
+#define TMCAGLWM_LAYERS_H
+
+#include <json.hpp>
+
+#include <regex>
+#include <set>
+#include <string>
+
+#include "layout.hpp"
+#include "result.hpp"
+#include "wayland.hpp"
+
+namespace wm {
+
+struct split_layout {
+ std::string name;
+ std::string main_match;
+ std::string sub_match;
+};
+
+struct layer {
+ using json = nlohmann::json;
+
+ // A more or less descriptive name?
+ std::string name = "";
+ // The actual layer ID
+ int layer_id = -1;
+ // The rectangular region surfaces are allowed to draw on
+ // this layer, note however, width and hieght of the rect
+ // can be negative, in which case they specify that
+ // the actual value is computed using MAX + 1 - w
+ // 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?
+ std::vector<struct split_layout> layouts;
+ // XXX need to change the way we store these things...
+ mutable struct LayoutState state;
+
+ explicit layer(nlohmann::json const &j);
+
+ json to_json() const;
+};
+
+struct layer_map {
+ using json = nlohmann::json;
+
+ using storage_type = std::map<int, struct layer>;
+ using layers_type = std::vector<uint32_t>;
+ using role_to_layer_map = std::vector<std::pair<std::string, int>>;
+ using addsurf_layer_map = std::map<int, int>;
+
+ // 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 LayoutState*> get_layout_state(int surface_id) {
+ int layer_id = *this->get_layer_id(surface_id);
+ auto i = this->mapping.find(layer_id);
+ return i == this->mapping.end()
+ ? nullopt
+ : optional<struct LayoutState *>(&i->second.state);
+ }
+ optional<struct layer> get_layer(int layer_id) {
+ auto i = this->mapping.find(layer_id);
+ return i == this->mapping.end() ? nullopt
+ : optional<struct layer>(i->second);
+ }
+
+ layers_type::size_type get_layers_count() const {
+ return this->layers.size();
+ }
+
+ void add_surface(int surface_id, int layer_id) {
+ this->surfaces[surface_id] = layer_id;
+ }
+
+ void remove_surface(int surface_id) {
+ this->surfaces.erase(surface_id);
+ }
+
+ json to_json() const;
+};
+
+struct result<struct layer_map> to_layer_map(nlohmann::json const &j);
+
+} // namespace wm
+
+#endif // TMCAGLWM_LAYERS_H
diff --git a/src/layout.cpp b/src/layout.cpp
new file mode 100644
index 0000000..1589ee9
--- /dev/null
+++ b/src/layout.cpp
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "layout.hpp"
diff --git a/src/layout.hpp b/src/layout.hpp
new file mode 100644
index 0000000..b7a3c28
--- /dev/null
+++ b/src/layout.hpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_LAYOUT_HPP
+#define TMCAGLWM_LAYOUT_HPP
+
+#include <cstdint>
+#include <string>
+
+#include "result.hpp"
+#include "wayland.hpp"
+
+namespace wm {
+
+struct LayoutState {
+ int main{-1};
+ int sub{-1};
+
+ bool operator==(const LayoutState &b) const {
+ return main == b.main && sub == b.sub;
+ }
+
+ bool operator!=(const LayoutState &b) const {
+ return !(*this == b);
+ }
+};
+
+} // namespace wm
+
+#endif // TMCAGLWM_LAYOUT_HPP
diff --git a/src/main.cpp b/src/main.cpp
new file mode 100755
index 0000000..a1e3db8
--- /dev/null
+++ b/src/main.cpp
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include "app.hpp"
+#include "json_helper.hpp"
+#include "util.hpp"
+#include "wayland.hpp"
+
+#include <algorithm>
+#include <mutex>
+
+#include <json.h>
+
+extern "C" {
+#include <afb/afb-binding.h>
+#include <systemd/sd-event.h>
+}
+
+namespace {
+
+struct afb_instance {
+ std::unique_ptr<wl::display> display;
+ wm::App app;
+
+ afb_instance() : display{new wl::display}, app{this->display.get()} {}
+
+ int init();
+};
+
+struct afb_instance *g_afb_instance;
+
+int afb_instance::init() {
+ return this->app.init();
+}
+
+int display_event_callback(sd_event_source *evs, int /*fd*/, uint32_t events,
+ void * /*data*/) {
+ ST();
+
+ if ((events & EPOLLHUP) != 0) {
+ logerror("The compositor hung up, dying now.");
+ delete g_afb_instance;
+ g_afb_instance = nullptr;
+ goto error;
+ }
+
+ if ((events & EPOLLIN) != 0u) {
+ {
+ STN(display_read_events);
+ g_afb_instance->app.display->read_events();
+ g_afb_instance->app.set_pending_events();
+ }
+ {
+ // We want do dispatch pending wayland events from within
+ // the API context
+ STN(winman_ping_api_call);
+ afb_service_call("windowmanager", "ping", json_object_new_object(),
+ [](void *c, int st, json_object *j) {
+ STN(winman_ping_api_call_return);
+ },
+ nullptr);
+ }
+ }
+
+ return 0;
+
+error:
+ sd_event_source_unref(evs);
+ if (getenv("WINMAN_EXIT_ON_HANGUP") != nullptr) {
+ exit(1);
+}
+ return -1;
+}
+
+// _ _ _ _ _ _ _ ____
+// | |__ (_)_ __ __| (_)_ __ __ _ (_)_ __ (_) |_ / /\ \
+// | '_ \| | '_ \ / _` | | '_ \ / _` | | | '_ \| | __| | | |
+// | |_) | | | | | (_| | | | | | (_| | | | | | | | |_| | | |
+// |_.__/|_|_| |_|\__,_|_|_| |_|\__, |___|_|_| |_|_|\__| | | |
+// |___/_____| \_\/_/
+int binding_init_() {
+ lognotice("WinMan ver. %s", WINMAN_VERSION_STRING);
+
+ if (g_afb_instance != nullptr) {
+ logerror("Wayland context already initialized?");
+ return 0;
+ }
+
+ if (getenv("XDG_RUNTIME_DIR") == nullptr) {
+ logerror("Environment variable XDG_RUNTIME_DIR not set");
+ goto error;
+ }
+
+ {
+ // wait until wayland compositor starts up.
+ int cnt = 0;
+ g_afb_instance = new afb_instance;
+ while (!g_afb_instance->display->ok()) {
+ cnt++;
+ if (20 <= cnt) {
+ logerror("Could not connect to compositor");
+ goto error;
+ }
+ logerror("Wait to start weston ...");
+ sleep(1);
+ delete g_afb_instance;
+ g_afb_instance = new afb_instance;
+ }
+ }
+
+ if (g_afb_instance->init() == -1) {
+ logerror("Could not connect to compositor");
+ goto error;
+ }
+
+ {
+ int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
+ g_afb_instance->display->get_fd(), EPOLLIN,
+ display_event_callback, g_afb_instance);
+ if (ret < 0) {
+ logerror("Could not initialize afb_instance event handler: %d", -ret);
+ goto error;
+ }
+ }
+
+ atexit([] { delete g_afb_instance; });
+
+ return 0;
+
+error:
+ delete g_afb_instance;
+ g_afb_instance = nullptr;
+ return -1;
+}
+
+int binding_init() noexcept {
+ try {
+ return binding_init_();
+ } catch (std::exception &e) {
+ logerror("Uncaught exception in binding_init(): %s", e.what());
+ }
+ return -1;
+}
+
+} // namespace
+
+#include "afb_binding_glue.inl"
+
+// XXX implement send_event right here...
+namespace wm {
+void binding_api::send_event(char const *evname, char const *label) {
+ logdebug("%s: %s(%s)", __func__, evname, label);
+ int ret = afb_daemon_broadcast_event(evname, json_object_new_string(label));
+ if (ret != 0) {
+ logdebug("afb_event_broadcast failed: %m");
+ }
+}
+} // namespace wm
+
+extern "C" const struct afb_binding_v2 afbBindingV2 = {
+ "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};
diff --git a/src/policy.hpp b/src/policy.hpp
new file mode 100644
index 0000000..ed5d6ba
--- /dev/null
+++ b/src/policy.hpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_POLICY_HPP
+#define TMCAGLWM_POLICY_HPP
+
+#include "layout.hpp"
+
+namespace wm {
+
+class Policy {
+public:
+ bool layout_is_valid(LayoutState const & /* layout */) {
+ // We do not check for policy currently
+ logdebug("Policy check returns positive");
+ return true;
+ }
+};
+
+} // namespace wm
+
+#endif //TMCAGLWM_POLICY_HPP
diff --git a/src/redraw_fixer.cpp b/src/redraw_fixer.cpp
new file mode 100644
index 0000000..94964af
--- /dev/null
+++ b/src/redraw_fixer.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "wayland.hpp"
+
+#include <algorithm>
+#include <chrono>
+#include <thread>
+
+using namespace std::chrono_literals;
+
+// pretend we are a WM ...
+namespace wm {
+
+struct App {
+ controller_hooks chooks;
+ std::unique_ptr<wl::display> display;
+ std::unique_ptr<genivi::controller> controller;
+ std::vector<std::unique_ptr<wl::output>> outputs;
+
+ App();
+ void commit();
+ void surface_visibility(uint32_t surface_id, uint32_t v);
+ void surface_destination_rectangle(uint32_t surface_id, uint32_t x,
+ uint32_t y, uint32_t w, uint32_t h);
+ void try_fix(uint32_t surface_id);
+};
+
+void controller_hooks::surface_created(uint32_t /*surface_id*/) {}
+
+void controller_hooks::surface_removed(uint32_t /*surface_id*/) {}
+
+void controller_hooks::surface_visibility(uint32_t surface_id, uint32_t v) {
+ this->app->surface_visibility(surface_id, v);
+}
+
+void controller_hooks::surface_destination_rectangle(uint32_t surface_id,
+ uint32_t x, uint32_t y,
+ uint32_t w, uint32_t h) {
+ this->app->surface_destination_rectangle(surface_id, x, y, w, h);
+}
+
+App::App() : chooks{this}, display{new wl::display}, controller{}, outputs{} {
+ // The same init, the WM does, at least we can reuse the wayland stuff
+ if (!this->display->ok()) {
+ return;
+ }
+
+ this->display->add_global_handler(
+ "wl_output", [this](wl_registry *r, uint32_t name, uint32_t v) {
+ this->outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
+ });
+
+ this->display->add_global_handler(
+ "ivi_controller", [this](wl_registry *r, uint32_t name, uint32_t v) {
+ this->controller =
+ std::make_unique<struct genivi::controller>(r, name, v);
+
+ // Init controller hooks
+ this->controller->chooks = &this->chooks;
+
+ this->controller->add_proxy_to_id_mapping(
+ this->outputs.back()->proxy.get(),
+ wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
+ this->outputs.back()->proxy.get())));
+ });
+
+ for (int i : {1, 2, 3}) {
+ this->display->roundtrip();
+}
+}
+
+void App::commit() {
+ this->controller->commit_changes();
+ this->display->roundtrip(); // read: flush()++
+}
+
+void App::surface_visibility(uint32_t surface_id, uint32_t v) {
+ fprintf(stderr, "surface %u visibility %u\n", surface_id, v);
+
+ if (v == 1) {
+ this->try_fix(surface_id);
+ }
+}
+
+void App::surface_destination_rectangle(uint32_t surface_id, uint32_t x,
+ uint32_t y, uint32_t w, uint32_t h) {
+ fprintf(stderr, "surface %u dst %u %u %u %u\n", surface_id, x, y, w, h);
+
+ if (w != 1 && h != 1 && this->controller->sprops[surface_id].visibility != 0) {
+ this->try_fix(surface_id);
+ }
+}
+
+void App::try_fix(uint32_t surface_id) {
+ this->controller->surfaces[surface_id]->set_opacity(255);
+ this->commit();
+ std::this_thread::sleep_for(200ms);
+ this->controller->surfaces[surface_id]->set_opacity(256);
+ this->commit();
+}
+
+} // namespace wm
+
+int main(int /*argc*/, char ** /*argv*/) {
+ wm::App app;
+ if (!app.display->ok()) {
+ fputs("Could not init wayland display\n", stderr);
+ return 1;
+ }
+ while (app.display->dispatch() != -1) {
+ ;
+ }
+ return 0;
+}
diff --git a/src/result.hpp b/src/result.hpp
new file mode 100644
index 0000000..e14f92b
--- /dev/null
+++ b/src/result.hpp
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef TMCAGLWM_RESULT_HPP
+#define TMCAGLWM_RESULT_HPP
+
+#include <experimental/optional>
+#include <functional>
+
+namespace wm {
+
+using std::experimental::optional;
+using std::experimental::nullopt;
+
+// We only ever return a string as an error - so just parametrize
+// this over result type T
+template <typename T>
+struct result {
+ char const *e;
+ optional<T> t;
+
+ bool is_ok() const { return this->t != nullopt; }
+ bool is_err() const { return this->e != nullptr; }
+
+ T unwrap() {
+ if (this->e != nullptr) {
+ throw std::logic_error(this->e);
+ }
+ return this->t.value();
+ }
+
+ operator T() { return this->unwrap(); }
+
+ char const *unwrap_err() { return this->e; }
+
+ optional<T> const &ok() const { return this->t; }
+ optional<char const *> err() const {
+ return this->e ? optional<char const *>(this->e) : nullopt;
+ }
+
+ result<T> map_err(std::function<char const *(char const *)> f);
+};
+
+template <typename T>
+struct result<T> Err(char const *e) {
+ return result<T>{e, nullopt};
+}
+
+template <typename T>
+struct result<T> Ok(T t) {
+ return result<T>{nullptr, t};
+}
+
+template <typename T>
+result<T> result<T>::map_err(std::function<char const *(char const *)> f) {
+ if (this->is_err()) {
+ return Err<T>(f(this->e));
+ }
+ return *this;
+}
+
+} // namespace wm
+
+#endif // TMCAGLWM_RESULT_HPP
diff --git a/src/util.cpp b/src/util.cpp
new file mode 100644
index 0000000..c178d90
--- /dev/null
+++ b/src/util.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "util.hpp"
+
+#include <cerrno>
+#include <cstdarg>
+#include <cstdio>
+#include <cstdlib>
+#include <ctime>
+
+#include <unistd.h>
+
+#ifdef SCOPE_TRACING
+thread_local int ScopeTrace::indent = 0;
+ScopeTrace::ScopeTrace(char const *func) : f(func) {
+ fprintf(stderr, "%lu %*s%s -->\n", pthread_self(), 2 * indent++, "", this->f);
+}
+ScopeTrace::~ScopeTrace() { fprintf(stderr, "%lu %*s%s <--\n", pthread_self(), 2 * --indent, "", this->f); }
+#endif
+
+unique_fd::~unique_fd() {
+ if (this->fd != -1) {
+ close(this->fd);
+ }
+}
diff --git a/src/util.hpp b/src/util.hpp
new file mode 100644
index 0000000..b3f43de
--- /dev/null
+++ b/src/util.hpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WM_UTIL_HPP
+#define WM_UTIL_HPP
+
+#include <functional>
+#include <thread>
+#include <vector>
+
+#include <sys/poll.h>
+
+#ifndef DO_NOT_USE_AFB
+extern "C" {
+#include <afb/afb-binding.h>
+};
+#endif
+
+#define CONCAT_(X, Y) X##Y
+#define CONCAT(X, Y) CONCAT_(X, Y)
+
+#ifdef __GNUC__
+#define ATTR_FORMAT(stringindex, firsttocheck) \
+ __attribute__((format(printf, stringindex, firsttocheck)))
+#define ATTR_NORETURN __attribute__((noreturn))
+#else
+#define ATTR_FORMAT(stringindex, firsttocheck)
+#define ATTR_NORETURN
+#endif
+
+#ifdef AFB_BINDING_VERSION
+#define lognotice(...) AFB_NOTICE(__VA_ARGS__)
+#define logerror(...) AFB_ERROR(__VA_ARGS__)
+#define fatal(...) \
+ do { \
+ AFB_ERROR(__VA_ARGS__); \
+ abort(); \
+ } while (0)
+#else
+#define lognotice(...)
+#define logerror(...)
+#define fatal(...) \
+ do { \
+ abort(); \
+ } while (0)
+#endif
+
+#ifdef DEBUG_OUTPUT
+#ifdef AFB_BINDING_VERSION
+#define logdebug(...) AFB_DEBUG(__VA_ARGS__)
+#else
+#define logdebug(...)
+#endif
+#else
+#define logdebug(...)
+#endif
+
+#ifndef SCOPE_TRACING
+#define ST()
+#define STN(N)
+#else
+#define ST() \
+ ScopeTrace __attribute__((unused)) CONCAT(trace_scope_, __LINE__)(__func__)
+#define STN(N) \
+ ScopeTrace __attribute__((unused)) CONCAT(named_trace_scope_, __LINE__)(#N)
+
+struct ScopeTrace {
+ thread_local static int indent;
+ char const *f{};
+ explicit ScopeTrace(char const *func);
+ ~ScopeTrace();
+};
+#endif
+
+// _ _ _ __ _
+// ___| |_ _ __ _ _ ___| |_ _ _ _ __ (_) __ _ _ _ ___ / _| __| |
+// / __| __| '__| | | |/ __| __| | | | | '_ \| |/ _` | | | |/ _ \ | |_ / _` |
+// \__ \ |_| | | |_| | (__| |_ | |_| | | | | | (_| | |_| | __/ | _| (_| |
+// |___/\__|_| \__,_|\___|\__| \__,_|_| |_|_|\__, |\__,_|\___|___|_| \__,_|
+// |_| |_____|
+struct unique_fd {
+ int fd{-1};
+ unique_fd() = default;
+ explicit unique_fd(int f) : fd{f} {}
+ operator int() const { return fd; }
+ ~unique_fd();
+ unique_fd(unique_fd const &) = delete;
+ unique_fd &operator=(unique_fd const &) = delete;
+ unique_fd(unique_fd &&o) : fd(o.fd) { o.fd = -1; }
+ unique_fd &operator=(unique_fd &&o) {
+ std::swap(this->fd, o.fd);
+ return *this;
+ }
+};
+
+#endif // !WM_UTIL_HPP
diff --git a/src/wayland.cpp b/src/wayland.cpp
new file mode 100644
index 0000000..05e155f
--- /dev/null
+++ b/src/wayland.cpp
@@ -0,0 +1,765 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <utility>
+
+#include "util.hpp"
+#include "wayland.hpp"
+
+// _
+// _ __ __ _ _ __ ___ ___ ___ _ __ __ _ ___ ___ __ _| |
+// | '_ \ / _` | '_ ` _ \ / _ \/ __| '_ \ / _` |/ __/ _ \ \ \ /\ / / |
+// | | | | (_| | | | | | | __/\__ \ |_) | (_| | (_| __/ \ V V /| |
+// |_| |_|\__,_|_| |_| |_|\___||___/ .__/ \__,_|\___\___| \_/\_/ |_|
+// |_|
+namespace wl {
+
+// _ _ _
+// __| (_)___ _ __ | | __ _ _ _
+// / _` | / __| '_ \| |/ _` | | | |
+// | (_| | \__ \ |_) | | (_| | |_| |
+// \__,_|_|___/ .__/|_|\__,_|\__, |
+// |_| |___/
+display::display()
+ : d(std::unique_ptr<struct wl_display, void (*)(struct wl_display *)>(
+ wl_display_connect(nullptr), &wl_display_disconnect)),
+ r(d.get()) {}
+
+bool display::ok() const { return d && wl_display_get_error(d.get()) == 0; }
+
+void display::roundtrip() { wl_display_roundtrip(this->d.get()); }
+
+int display::dispatch() { return wl_display_dispatch(this->d.get()); }
+
+int display::dispatch_pending() { return wl_display_dispatch_pending(this->d.get()); }
+
+int display::read_events() {
+ ST();
+ // XXX: uhm, how?!
+ while (wl_display_prepare_read(this->d.get()) == -1) {
+ STN(pending_events_dispatch);
+ if (wl_display_dispatch_pending(this->d.get()) == -1) {
+ return -1;
+ }
+ }
+
+ if (wl_display_flush(this->d.get()) == -1) {
+ return -1;
+ }
+
+ if (wl_display_read_events(this->d.get()) == -1) {
+ wl_display_cancel_read(this->d.get());
+ }
+
+ return 0;
+}
+
+void display::flush() { wl_display_flush(this->d.get()); }
+
+int display::get_fd() const { return wl_display_get_fd(this->d.get()); }
+
+int display::get_error() { return wl_display_get_error(this->d.get()); }
+
+// _ _
+// _ __ ___ __ _(_)___| |_ _ __ _ _
+// | '__/ _ \/ _` | / __| __| '__| | | |
+// | | | __/ (_| | \__ \ |_| | | |_| |
+// |_| \___|\__, |_|___/\__|_| \__, |
+// |___/ |___/
+namespace {
+void registry_global(void *data, struct wl_registry * /*r*/, uint32_t name,
+ char const *iface, uint32_t v) {
+ static_cast<struct registry *>(data)->global(name, iface, v);
+}
+
+void registry_global_remove(void *data, struct wl_registry * /*r*/,
+ uint32_t name) {
+ static_cast<struct registry *>(data)->global_remove(name);
+}
+
+constexpr struct wl_registry_listener registry_listener = {
+ registry_global, registry_global_remove};
+} // namespace
+
+registry::registry(struct wl_display *d)
+ : wayland_proxy(d == nullptr ? nullptr : wl_display_get_registry(d)) {
+ if (this->proxy != nullptr) {
+ wl_registry_add_listener(this->proxy.get(), &registry_listener, this);
+ }
+}
+
+void registry::add_global_handler(char const *iface, binder bind) {
+ this->bindings[iface] = std::move(bind);
+}
+
+void registry::global(uint32_t name, char const *iface, uint32_t v) {
+ auto b = this->bindings.find(iface);
+ if (b != this->bindings.end()) {
+ b->second(this->proxy.get(), name, v);
+ }
+ logdebug("wl::registry @ %p global n %u i %s v %u", this->proxy.get(), name,
+ iface, v);
+}
+
+void registry::global_remove(uint32_t /*name*/) {}
+
+// _ _
+// ___ _ _| |_ _ __ _ _| |_
+// / _ \| | | | __| '_ \| | | | __|
+// | (_) | |_| | |_| |_) | |_| | |_
+// \___/ \__,_|\__| .__/ \__,_|\__|
+// |_|
+namespace {
+void output_geometry(void *data, struct wl_output * /*wl_output*/, int32_t x,
+ int32_t y, int32_t physical_width, int32_t physical_height,
+ int32_t subpixel, const char *make, const char *model,
+ int32_t transform) {
+ static_cast<struct output *>(data)->geometry(
+ x, y, physical_width, physical_height, subpixel, make, model, transform);
+}
+
+void output_mode(void *data, struct wl_output * /*wl_output*/, uint32_t flags,
+ int32_t width, int32_t height, int32_t refresh) {
+ static_cast<struct output *>(data)->mode(flags, width, height, refresh);
+}
+
+void output_done(void *data, struct wl_output * /*wl_output*/) {
+ static_cast<struct output *>(data)->done();
+}
+
+void output_scale(void *data, struct wl_output * /*wl_output*/,
+ int32_t factor) {
+ static_cast<struct output *>(data)->scale(factor);
+}
+
+constexpr struct wl_output_listener output_listener = {
+ output_geometry, output_mode, output_done, output_scale};
+} // namespace
+
+output::output(struct wl_registry *r, uint32_t name, uint32_t v)
+ : wayland_proxy(wl_registry_bind(r, name, &wl_output_interface, v)) {
+ wl_output_add_listener(this->proxy.get(), &output_listener, this);
+}
+
+void output::geometry(int32_t x, int32_t y, int32_t pw, int32_t ph,
+ int32_t subpel, char const *make, char const *model,
+ int32_t tx) {
+ logdebug(
+ "wl::output %s @ %p x %i y %i w %i h %i spel %x make %s model %s tx %i",
+ __func__, this->proxy.get(), x, y, pw, ph, subpel, make, model, tx);
+ this->transform = tx;
+}
+
+void output::mode(uint32_t flags, int32_t w, int32_t h, int32_t r) {
+ logdebug("wl::output %s @ %p f %x w %i h %i r %i", __func__,
+ this->proxy.get(), flags, w, h, r);
+ if ((flags & WL_OUTPUT_MODE_CURRENT) != 0u) {
+ this->width = w;
+ this->height = h;
+ this->refresh = r;
+ }
+}
+
+void output::done() {
+ logdebug("wl::output %s @ %p done", __func__, this->proxy.get());
+ // Let's just disregard the flipped ones...
+ if (this->transform == WL_OUTPUT_TRANSFORM_90 ||
+ this->transform == WL_OUTPUT_TRANSFORM_270) {
+ std::swap(this->width, this->height);
+ }
+}
+
+void output::scale(int32_t factor) {
+ logdebug("wl::output %s @ %p f %i", __func__, this->proxy.get(), factor);
+}
+} // namespace wl
+
+// _ __ __ _ _ __ ___ ___ ___ _ __ __ _ ___ ___
+// | '_ \ / _` | '_ ` _ \ / _ \/ __| '_ \ / _` |/ __/ _ \
+// | | | | (_| | | | | | | __/\__ \ |_) | (_| | (_| __/
+// |_| |_|\__,_|_| |_| |_|\___||___/ .__/ \__,_|\___\___|
+// |_|
+// _ _
+// __ _ ___ _ __ (_)_ _(_)
+// / _` |/ _ \ '_ \| \ \ / / |
+// | (_| | __/ | | | |\ V /| |
+// \__, |\___|_| |_|_| \_/ |_|
+// |___/
+namespace genivi {
+
+// _ _ _
+// ___ ___ _ __ | |_ _ __ ___ | | | ___ _ __
+// / __/ _ \| '_ \| __| '__/ _ \| | |/ _ \ '__|
+// | (_| (_) | | | | |_| | | (_) | | | __/ |
+// \___\___/|_| |_|\__|_| \___/|_|_|\___|_|
+//
+namespace {
+void controller_screen(void *data, struct ivi_controller * /*ivi_controller*/,
+ uint32_t id_screen,
+ struct ivi_controller_screen *screen) {
+ static_cast<struct controller *>(data)->controller_screen(id_screen, screen);
+}
+
+void controller_layer(void *data, struct ivi_controller * /*ivi_controller*/,
+ uint32_t id_layer) {
+ static_cast<struct controller *>(data)->controller_layer(id_layer);
+}
+
+void controller_surface(void *data, struct ivi_controller * /*ivi_controller*/,
+ uint32_t id_surface) {
+ static_cast<struct controller *>(data)->controller_surface(id_surface);
+}
+
+void controller_error(void *data, struct ivi_controller * /*ivi_controller*/,
+ int32_t object_id, int32_t object_type,
+ int32_t error_code, const char *error_text) {
+ static_cast<struct controller *>(data)->controller_error(
+ object_id, object_type, error_code, error_text);
+}
+
+constexpr struct ivi_controller_listener listener = {
+ controller_screen, controller_layer, controller_surface, controller_error};
+} // namespace
+
+controller::controller(struct wl_registry *r, uint32_t name, uint32_t version)
+ : wayland_proxy(
+ wl_registry_bind(r, name, &ivi_controller_interface, version)),
+ output_size{} {
+ ivi_controller_add_listener(this->proxy.get(), &listener, this);
+}
+
+void controller::layer_create(uint32_t id, int32_t w, int32_t h) {
+ this->layers[id] = std::make_unique<struct layer>(id, w, h, this);
+}
+
+void controller::surface_create(uint32_t id) {
+ this->surfaces[id] = std::make_unique<struct surface>(id, this);
+}
+
+void controller::controller_screen(uint32_t id,
+ struct ivi_controller_screen *screen) {
+ logdebug("genivi::controller @ %p screen %u (%x) @ %p", this->proxy.get(),
+ id, id, screen);
+ this->screens[id] = std::make_unique<struct screen>(id, this, screen);
+}
+
+void controller::controller_layer(uint32_t id) {
+ logdebug("genivi::controller @ %p layer %u (%x)", this->proxy.get(), id, id);
+ if (this->layers.find(id) != this->layers.end()) {
+ logerror("Someone created a layer without asking US! (%d)", id);
+ } else {
+ auto &l = this->layers[id] = std::make_unique<struct layer>(id, this);
+ l->clear_surfaces();
+ }
+}
+
+void controller::controller_surface(uint32_t id) {
+ logdebug("genivi::controller @ %p surface %u (%x)", this->proxy.get(), id,
+ id);
+ if (this->surfaces.find(id) == this->surfaces.end()) {
+ this->surfaces[id] = std::make_unique<struct surface>(id, this);
+ this->chooks->surface_created(id);
+ }
+}
+
+void controller::controller_error(int32_t object_id, int32_t object_type,
+ int32_t error_code, const char *error_text) {
+ logdebug("genivi::controller @ %p error o %i t %i c %i text %s",
+ this->proxy.get(), object_id, object_type, error_code, error_text);
+}
+
+// _
+// | | __ _ _ _ ___ _ __
+// | |/ _` | | | |/ _ \ '__|
+// | | (_| | |_| | __/ |
+// |_|\__,_|\__, |\___|_|
+// |___/
+namespace {
+void layer_visibility(void *data,
+ struct ivi_controller_layer * /*ivi_controller_layer*/,
+ int32_t visibility) {
+ auto l = static_cast<struct layer *>(data);
+ l->parent->layer_visibility(l, visibility);
+}
+
+void layer_opacity(void *data,
+ struct ivi_controller_layer * /*ivi_controller_layer*/,
+ wl_fixed_t opacity) {
+ auto l = static_cast<struct layer *>(data);
+ l->parent->layer_opacity(l, float(wl_fixed_to_double(opacity)));
+}
+
+void layer_source_rectangle(
+ void *data, struct ivi_controller_layer * /*ivi_controller_layer*/,
+ int32_t x, int32_t y, int32_t width, int32_t height) {
+ auto l = static_cast<struct layer *>(data);
+ l->parent->layer_source_rectangle(l, x, y, width, height);
+}
+
+void layer_destination_rectangle(
+ void *data, struct ivi_controller_layer * /*ivi_controller_layer*/,
+ int32_t x, int32_t y, int32_t width, int32_t height) {
+ auto l = static_cast<struct layer *>(data);
+ l->parent->layer_destination_rectangle(l, x, y, width, height);
+}
+
+void layer_configuration(void *data,
+ struct ivi_controller_layer * /*ivi_controller_layer*/,
+ int32_t width, int32_t height) {
+ auto l = static_cast<struct layer *>(data);
+ l->parent->layer_configuration(l, width, height);
+}
+
+void layer_orientation(void *data,
+ struct ivi_controller_layer * /*ivi_controller_layer*/,
+ int32_t orientation) {
+ auto l = static_cast<struct layer *>(data);
+ l->parent->layer_orientation(l, orientation);
+}
+
+void layer_screen(void *data,
+ struct ivi_controller_layer * /*ivi_controller_layer*/,
+ struct wl_output *screen) {
+ auto l = static_cast<struct layer *>(data);
+ l->parent->layer_screen(l, screen);
+}
+
+void layer_destroyed(void *data,
+ struct ivi_controller_layer * /*ivi_controller_layer*/) {
+ auto l = static_cast<struct layer *>(data);
+ l->parent->layer_destroyed(l);
+}
+
+constexpr struct ivi_controller_layer_listener layer_listener = {
+ layer_visibility, layer_opacity,
+ layer_source_rectangle, layer_destination_rectangle,
+ layer_configuration, layer_orientation,
+ layer_screen, layer_destroyed,
+};
+} // namespace
+
+layer::layer(uint32_t i, struct controller *c) : layer(i, 0, 0, c) {}
+
+layer::layer(uint32_t i, int32_t w, int32_t h, struct controller *c)
+ : wayland_proxy(ivi_controller_layer_create(c->proxy.get(), i, w, h),
+ [c, i](ivi_controller_layer *l) {
+ logdebug("~layer layer %i @ %p", i, l);
+ c->remove_proxy_to_id_mapping(l);
+ ivi_controller_layer_destroy(l, 1);
+ }),
+ controller_child(c, i) {
+ this->parent->add_proxy_to_id_mapping(this->proxy.get(), i);
+ ivi_controller_layer_add_listener(this->proxy.get(), &layer_listener, this);
+}
+
+void layer::set_visibility(uint32_t visibility) {
+ ivi_controller_layer_set_visibility(this->proxy.get(), visibility);
+}
+
+void layer::set_opacity(wl_fixed_t opacity) {
+ ivi_controller_layer_set_opacity(this->proxy.get(), opacity);
+}
+
+void layer::set_source_rectangle(int32_t x, int32_t y, int32_t width,
+ int32_t height) {
+ ivi_controller_layer_set_source_rectangle(this->proxy.get(), x, y, width,
+ height);
+}
+
+void layer::set_destination_rectangle(int32_t x, int32_t y, int32_t width,
+ int32_t height) {
+ ivi_controller_layer_set_destination_rectangle(this->proxy.get(), x, y,
+ width, height);
+}
+
+void layer::set_configuration(int32_t width, int32_t height) {
+ ivi_controller_layer_set_configuration(this->proxy.get(), width, height);
+}
+
+void layer::set_orientation(int32_t orientation) {
+ ivi_controller_layer_set_orientation(this->proxy.get(), orientation);
+}
+
+void layer::screenshot(const char *filename) {
+ ivi_controller_layer_screenshot(this->proxy.get(), filename);
+}
+
+void layer::clear_surfaces() {
+ ivi_controller_layer_clear_surfaces(this->proxy.get());
+}
+
+void layer::add_surface(struct surface *surface) {
+ ivi_controller_layer_add_surface(this->proxy.get(), surface->proxy.get());
+}
+
+void layer::remove_surface(struct surface *surface) {
+ ivi_controller_layer_remove_surface(this->proxy.get(), surface->proxy.get());
+}
+
+void layer::set_render_order(std::vector<uint32_t> const &ro) {
+ struct wl_array wlro {
+ .size = ro.size() * sizeof(ro[0]), .alloc = ro.capacity() * sizeof(ro[0]),
+ .data = const_cast<void *>(static_cast<void const *>(ro.data()))
+ };
+ ivi_controller_layer_set_render_order(this->proxy.get(), &wlro);
+}
+
+void controller::layer_visibility(struct layer *l, int32_t visibility) {
+ logdebug("genivi::layer %s @ %d v %i", __func__, l->id, visibility);
+ this->lprops[l->id].visibility = visibility;
+}
+
+void controller::layer_opacity(struct layer *l, float opacity) {
+ logdebug("genivi::layer %s @ %d o %f", __func__, l->id, opacity);
+ this->lprops[l->id].opacity = opacity;
+}
+
+void controller::layer_source_rectangle(struct layer *l, int32_t x, int32_t y,
+ int32_t width, int32_t height) {
+ logdebug("genivi::layer %s @ %d x %i y %i w %i h %i", __func__,
+ l->id, x, y, width, height);
+ this->lprops[l->id].src_rect = rect{width, height, x, y};
+}
+
+void controller::layer_destination_rectangle(struct layer *l, int32_t x,
+ int32_t y, int32_t width,
+ int32_t height) {
+ logdebug("genivi::layer %s @ %d x %i y %i w %i h %i", __func__,
+ l->id, x, y, width, height);
+ this->lprops[l->id].dst_rect = rect{width, height, x, y};
+}
+
+void controller::layer_configuration(struct layer *l, int32_t width,
+ int32_t height) {
+ logdebug("genivi::layer %s @ %d w %i h %i", __func__, l->id,
+ width, height);
+ this->lprops[l->id].size = size{uint32_t(width), uint32_t(height)};
+}
+
+void controller::layer_orientation(struct layer *l, int32_t orientation) {
+ logdebug("genivi::layer %s @ %d o %i", __func__, l->id,
+ orientation);
+ this->lprops[l->id].orientation = orientation;
+}
+
+void controller::layer_screen(struct layer *l, struct wl_output *screen) {
+ logdebug("genivi::layer %s @ %d s %p", __func__, l->id, screen);
+}
+
+void controller::layer_destroyed(struct layer *l) {
+ logdebug("genivi::layer %s @ %d", __func__, l->id);
+ this->lprops.erase(l->id);
+ this->layers.erase(l->id);
+}
+
+// __
+// ___ _ _ _ __ / _| __ _ ___ ___
+// / __| | | | '__| |_ / _` |/ __/ _ \
+// \__ \ |_| | | | _| (_| | (_| __/
+// |___/\__,_|_| |_| \__,_|\___\___|
+//
+namespace {
+
+void surface_visibility(
+ void *data, struct ivi_controller_surface * /*ivi_controller_surface*/,
+ int32_t visibility) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_visibility(s, visibility);
+}
+
+void surface_opacity(void *data,
+ struct ivi_controller_surface * /*ivi_controller_surface*/,
+ wl_fixed_t opacity) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_opacity(s, float(wl_fixed_to_double(opacity)));
+}
+
+void surface_source_rectangle(
+ void *data, struct ivi_controller_surface * /*ivi_controller_surface*/,
+ int32_t x, int32_t y, int32_t width, int32_t height) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_source_rectangle(s, x, y, width, height);
+}
+
+void surface_destination_rectangle(
+ void *data, struct ivi_controller_surface * /*ivi_controller_surface*/,
+ int32_t x, int32_t y, int32_t width, int32_t height) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_destination_rectangle(s, x, y, width, height);
+}
+
+void surface_configuration(
+ void *data, struct ivi_controller_surface * /*ivi_controller_surface*/,
+ int32_t width, int32_t height) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_configuration(s, width, height);
+}
+
+void surface_orientation(
+ void *data, struct ivi_controller_surface * /*ivi_controller_surface*/,
+ int32_t orientation) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_orientation(s, orientation);
+}
+
+void surface_pixelformat(
+ void *data, struct ivi_controller_surface * /*ivi_controller_surface*/,
+ int32_t pixelformat) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_pixelformat(s, pixelformat);
+}
+
+void surface_layer(void *data,
+ struct ivi_controller_surface * /*ivi_controller_surface*/,
+ struct ivi_controller_layer *layer) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_layer(s, layer);
+}
+
+void surface_stats(void *data,
+ struct ivi_controller_surface * /*ivi_controller_surface*/,
+ uint32_t redraw_count, uint32_t frame_count,
+ uint32_t update_count, uint32_t pid,
+ const char *process_name) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_stats(s, redraw_count, frame_count, update_count, pid,
+ process_name);
+}
+
+void surface_destroyed(
+ void *data, struct ivi_controller_surface * /*ivi_controller_surface*/) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_destroyed(s);
+}
+
+void surface_content(void *data,
+ struct ivi_controller_surface * /*ivi_controller_surface*/,
+ int32_t content_state) {
+ auto s = static_cast<struct surface *>(data);
+ s->parent->surface_content(s, content_state);
+}
+
+constexpr struct ivi_controller_surface_listener surface_listener = {
+ surface_visibility,
+ surface_opacity,
+ surface_source_rectangle,
+ surface_destination_rectangle,
+ surface_configuration,
+ surface_orientation,
+ surface_pixelformat,
+ surface_layer,
+ surface_stats,
+ surface_destroyed,
+ surface_content,
+};
+} // namespace
+
+surface::surface(uint32_t i, struct controller *c)
+ : wayland_proxy(ivi_controller_surface_create(c->proxy.get(), i),
+ [c, i](ivi_controller_surface *s) {
+ logdebug("~surface surface %i @ %p", i, s);
+ c->remove_proxy_to_id_mapping(s);
+ ivi_controller_surface_destroy(s, 1);
+ }),
+ controller_child(c, i) {
+ this->parent->add_proxy_to_id_mapping(this->proxy.get(), i);
+ ivi_controller_surface_add_listener(this->proxy.get(), &surface_listener,
+ this);
+}
+
+void surface::set_visibility(uint32_t visibility) {
+ ivi_controller_surface_set_visibility(this->proxy.get(), visibility);
+}
+
+void surface::set_opacity(wl_fixed_t opacity) {
+ ivi_controller_surface_set_opacity(this->proxy.get(), opacity);
+}
+
+void surface::set_source_rectangle(int32_t x, int32_t y, int32_t width,
+ int32_t height) {
+ ivi_controller_surface_set_source_rectangle(this->proxy.get(), x, y, width,
+ height);
+}
+
+void surface::set_destination_rectangle(int32_t x, int32_t y, int32_t width,
+ int32_t height) {
+ ivi_controller_surface_set_destination_rectangle(this->proxy.get(), x, y,
+ width, height);
+}
+
+void surface::set_configuration(int32_t width, int32_t height) {
+ ivi_controller_surface_set_configuration(this->proxy.get(), width, height);
+}
+
+void surface::set_orientation(int32_t orientation) {
+ ivi_controller_surface_set_orientation(this->proxy.get(), orientation);
+}
+
+void surface::screenshot(const char *filename) {
+ ivi_controller_surface_screenshot(this->proxy.get(), filename);
+}
+
+void surface::send_stats() {
+ ivi_controller_surface_send_stats(this->proxy.get());
+}
+
+void surface::destroy(int32_t destroy_scene_object) {
+ ivi_controller_surface_destroy(this->proxy.get(), destroy_scene_object);
+}
+
+void controller::surface_visibility(struct surface *s, int32_t visibility) {
+ logdebug("genivi::surface %s @ %d v %i", __func__, s->id,
+ visibility);
+ this->sprops[s->id].visibility = visibility;
+ this->chooks->surface_visibility(s->id, visibility);
+}
+
+void controller::surface_opacity(struct surface *s, float opacity) {
+ logdebug("genivi::surface %s @ %d o %f", __func__, s->id,
+ opacity);
+ this->sprops[s->id].opacity = opacity;
+}
+
+void controller::surface_source_rectangle(struct surface *s, int32_t x,
+ int32_t y, int32_t width,
+ int32_t height) {
+ logdebug("genivi::surface %s @ %d x %i y %i w %i h %i", __func__,
+ s->id, x, y, width, height);
+ this->sprops[s->id].src_rect = rect{width, height, x, y};
+}
+
+void controller::surface_destination_rectangle(struct surface *s, int32_t x,
+ int32_t y, int32_t width,
+ int32_t height) {
+ logdebug("genivi::surface %s @ %d x %i y %i w %i h %i", __func__,
+ s->id, x, y, width, height);
+ this->sprops[s->id].dst_rect = rect{width, height, x, y};
+ this->chooks->surface_destination_rectangle(s->id, x, y, width, height);
+}
+
+void controller::surface_configuration(struct surface *s, int32_t width,
+ int32_t height) {
+ logdebug("genivi::surface %s @ %d w %i h %i", __func__, s->id,
+ width, height);
+ this->sprops[s->id].size = size{uint32_t(width), uint32_t(height)};
+}
+
+void controller::surface_orientation(struct surface *s, int32_t orientation) {
+ logdebug("genivi::surface %s @ %d o %i", __func__, s->id,
+ orientation);
+ this->sprops[s->id].orientation = orientation;
+}
+
+void controller::surface_pixelformat(struct surface * s,
+ int32_t pixelformat) {
+ logdebug("genivi::surface %s @ %d f %i", __func__, s->id,
+ pixelformat);
+}
+
+void controller::surface_layer(struct surface * s,
+ struct ivi_controller_layer *layer) {
+ logdebug("genivi::surface %s @ %d l %u @ %p", __func__, s->id,
+ this->layer_proxy_to_id[uintptr_t(layer)], layer);
+}
+
+void controller::surface_stats(struct surface *s, uint32_t redraw_count,
+ uint32_t frame_count, uint32_t update_count,
+ uint32_t pid, const char *process_name) {
+ logdebug("genivi::surface %s @ %d r %u f %u u %u pid %u p %s", __func__,
+ s->id, redraw_count, frame_count, update_count, pid,
+ process_name);
+}
+
+void controller::surface_destroyed(struct surface *s) {
+ logdebug("genivi::surface %s @ %d", __func__, s->id);
+ this->chooks->surface_removed(s->id);
+ // XXX: do I need to actually remove the surface late, i.e. using add_task()?
+ this->sprops.erase(s->id);
+ this->surfaces.erase(s->id);
+}
+
+void controller::surface_content(struct surface *s, int32_t content_state) {
+ logdebug("genivi::surface %s @ %d s %i", __func__, s->id,
+ content_state);
+ if (content_state == IVI_CONTROLLER_SURFACE_CONTENT_STATE_CONTENT_REMOVED) {
+ // XXX is this the right thing to do?
+ this->chooks->surface_removed(s->id);
+ this->sprops.erase(s->id);
+ this->surfaces.erase(s->id);
+ }
+}
+
+void controller::add_proxy_to_id_mapping(struct ivi_controller_surface *p,
+ uint32_t id) {
+ logdebug("Add surface proxy mapping for %p (%u)", p, id);
+ this->surface_proxy_to_id[uintptr_t(p)] = id;
+ this->sprops[id].id = id;
+}
+
+void controller::remove_proxy_to_id_mapping(struct ivi_controller_surface *p) {
+ logdebug("Remove surface proxy mapping for %p", p);
+ this->surface_proxy_to_id.erase(uintptr_t(p));
+}
+
+void controller::add_proxy_to_id_mapping(struct ivi_controller_layer *p,
+ uint32_t id) {
+ logdebug("Add layer proxy mapping for %p (%u)", p, id);
+ this->layer_proxy_to_id[uintptr_t(p)] = id;
+ this->lprops[id].id = id;
+}
+
+void controller::remove_proxy_to_id_mapping(struct ivi_controller_layer *p) {
+ logdebug("Remove layer proxy mapping for %p", p);
+ this->layer_proxy_to_id.erase(uintptr_t(p));
+}
+
+void controller::add_proxy_to_id_mapping(struct wl_output *p, uint32_t id) {
+ logdebug("Add screen proxy mapping for %p (%u)", p, id);
+ this->screen_proxy_to_id[uintptr_t(p)] = id;
+}
+
+void controller::remove_proxy_to_id_mapping(struct wl_output *p) {
+ logdebug("Remove screen proxy mapping for %p", p);
+ this->screen_proxy_to_id.erase(uintptr_t(p));
+}
+
+//
+// ___ ___ _ __ ___ ___ _ __
+// / __|/ __| '__/ _ \/ _ \ '_ \
+// \__ \ (__| | | __/ __/ | | |
+// |___/\___|_| \___|\___|_| |_|
+//
+screen::screen(uint32_t i, struct controller *c,
+ struct ivi_controller_screen *p)
+ : wayland_proxy(p), controller_child(c, i) {
+ logdebug("genivi::screen @ %p id %u", p, i);
+}
+
+void screen::clear() { ivi_controller_screen_clear(this->proxy.get()); }
+
+void screen::add_layer(layer *l) {
+ ivi_controller_screen_add_layer(this->proxy.get(), l->proxy.get());
+}
+
+void screen::set_render_order(std::vector<uint32_t> const &ro) {
+ struct wl_array wlro {
+ .size = ro.size() * sizeof(ro[0]), .alloc = ro.capacity() * sizeof(ro[0]),
+ .data = const_cast<void *>(static_cast<void const *>(ro.data()))
+ };
+ ivi_controller_screen_set_render_order(this->proxy.get(), &wlro);
+}
+
+} // namespace genivi
diff --git a/src/wayland.hpp b/src/wayland.hpp
new file mode 100644
index 0000000..61a840d
--- /dev/null
+++ b/src/wayland.hpp
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef WM_WAYLAND_HPP
+#define WM_WAYLAND_HPP
+
+#include "controller_hooks.hpp"
+#include "ivi-controller-client-protocol.h"
+#include "util.hpp"
+
+#include <functional>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+// _ _
+// __ ____ _ _ _| | __ _ _ __ __| | _ __ _ __ _____ ___ _
+// \ \ /\ / / _` | | | | |/ _` | '_ \ / _` | | '_ \| '__/ _ \ \/ / | | |
+// \ V V / (_| | |_| | | (_| | | | | (_| | | |_) | | | (_) > <| |_| |
+// \_/\_/ \__,_|\__, |_|\__,_|_| |_|\__,_|____| .__/|_| \___/_/\_\\__, |
+// |___/ |_____|_| |___/
+template <typename ProxyT>
+struct wayland_proxy {
+ std::unique_ptr<ProxyT, std::function<void(ProxyT *)>> proxy;
+ wayland_proxy(wayland_proxy const &) = delete;
+ wayland_proxy &operator=(wayland_proxy const &) = delete;
+ wayland_proxy(void *p)
+ : wayland_proxy(p,
+ reinterpret_cast<void (*)(ProxyT *)>(wl_proxy_destroy)) {}
+ wayland_proxy(void *p, std::function<void(ProxyT *)> &&p_del)
+ : proxy(std::unique_ptr<ProxyT, std::function<void(ProxyT *)>>(
+ static_cast<ProxyT *>(p), p_del)) {}
+};
+
+// _
+// _ __ __ _ _ __ ___ ___ ___ _ __ __ _ ___ ___ __ _| |
+// | '_ \ / _` | '_ ` _ \ / _ \/ __| '_ \ / _` |/ __/ _ \ \ \ /\ / / |
+// | | | | (_| | | | | | | __/\__ \ |_) | (_| | (_| __/ \ V V /| |
+// |_| |_|\__,_|_| |_| |_|\___||___/ .__/ \__,_|\___\___| \_/\_/ |_|
+// |_|
+namespace wl {
+// _ _
+// _ __ ___ __ _(_)___| |_ _ __ _ _
+// | '__/ _ \/ _` | / __| __| '__| | | |
+// | | | __/ (_| | \__ \ |_| | | |_| |
+// |_| \___|\__, |_|___/\__|_| \__, |
+// |___/ |___/
+struct registry : public wayland_proxy<struct wl_registry> {
+ typedef std::function<void(struct wl_registry *, uint32_t, uint32_t)> binder;
+ std::unordered_map<std::string, binder> bindings;
+
+ registry(registry const &) = delete;
+ registry &operator=(registry const &) = delete;
+ registry(struct wl_display *d);
+
+ void add_global_handler(char const *iface, binder bind);
+
+ // Events
+ void global(uint32_t name, char const *iface, uint32_t v);
+ void global_remove(uint32_t name);
+};
+
+// _ _ _
+// __| (_)___ _ __ | | __ _ _ _
+// / _` | / __| '_ \| |/ _` | | | |
+// | (_| | \__ \ |_) | | (_| | |_| |
+// \__,_|_|___/ .__/|_|\__,_|\__, |
+// |_| |___/
+struct display {
+ std::unique_ptr<struct wl_display, void (*)(struct wl_display *)> d;
+ struct registry r;
+
+ display(display const &) = delete;
+ display &operator=(display const &) = delete;
+ display();
+ bool ok() const;
+ void roundtrip();
+ int dispatch();
+ int dispatch_pending();
+ int read_events();
+ void flush();
+ int get_fd() const;
+ int get_error();
+
+ // Lets just proxy this for the registry
+ inline void add_global_handler(char const *iface, registry::binder bind) {
+ this->r.add_global_handler(iface, bind);
+ }
+};
+
+// _ _
+// ___ _ _| |_ _ __ _ _| |_
+// / _ \| | | | __| '_ \| | | | __|
+// | (_) | |_| | |_| |_) | |_| | |_
+// \___/ \__,_|\__| .__/ \__,_|\__|
+// |_|
+struct output : wayland_proxy<struct wl_output> {
+ int width{};
+ int height{};
+ int refresh{};
+ int transform{};
+
+ output(output const &) = delete;
+ output &operator=(output const &) = delete;
+ output(struct wl_registry *r, uint32_t name, uint32_t v);
+
+ // Events
+ void geometry(int32_t x, int32_t y, int32_t pw, int32_t ph, int32_t subpel,
+ char const *make, char const *model, int32_t tx);
+ void mode(uint32_t flags, int32_t w, int32_t h, int32_t r);
+ void done();
+ void scale(int32_t factor);
+};
+} // namespace wl
+
+// _ __ __ _ _ __ ___ ___ ___ _ __ __ _ ___ ___
+// | '_ \ / _` | '_ ` _ \ / _ \/ __| '_ \ / _` |/ __/ _ \
+// | | | | (_| | | | | | | __/\__ \ |_) | (_| | (_| __/
+// |_| |_|\__,_|_| |_| |_|\___||___/ .__/ \__,_|\___\___|
+// |_|
+// _ _
+// __ _ ___ _ __ (_)_ _(_)
+// / _` |/ _ \ '_ \| \ \ / / |
+// | (_| | __/ | | | |\ V /| |
+// \__, |\___|_| |_|_| \_/ |_|
+// |___/
+namespace genivi {
+
+struct size {
+ uint32_t w, h;
+};
+
+struct rect {
+ int32_t w, h;
+ int32_t x, y;
+};
+
+static const constexpr rect full_rect = rect{-1, -1, 0, 0};
+
+inline bool operator==(struct rect a, struct rect b) {
+ return a.w == b.w && a.h == b.h && a.x == b.x && a.y == b.y;
+}
+
+struct controller;
+
+struct controller_child {
+ struct controller *parent;
+ uint32_t id;
+
+ controller_child(controller_child const &) = delete;
+ controller_child &operator=(controller_child const &) = delete;
+ controller_child(struct controller *c, uint32_t i) : parent(c), id(i) {}
+ virtual ~controller_child() {}
+};
+
+struct surface_properties {
+ uint32_t id; // let's just save an ID here too
+ struct rect dst_rect;
+ struct rect src_rect;
+ struct size size;
+ int32_t orientation;
+ int32_t visibility;
+ float opacity;
+};
+
+// __
+// ___ _ _ _ __ / _| __ _ ___ ___
+// / __| | | | '__| |_ / _` |/ __/ _ \
+// \__ \ |_| | | | _| (_| | (_| __/
+// |___/\__,_|_| |_| \__,_|\___\___|
+//
+struct surface : public wayland_proxy<struct ivi_controller_surface>,
+ controller_child {
+ surface(surface const &) = delete;
+ surface &operator=(surface const &) = delete;
+ surface(uint32_t i, struct controller *c);
+
+ // Requests
+ void set_visibility(uint32_t visibility);
+ void set_opacity(wl_fixed_t opacity);
+ void set_source_rectangle(int32_t x, int32_t y, int32_t width,
+ int32_t height);
+ void set_destination_rectangle(int32_t x, int32_t y, int32_t width,
+ int32_t height);
+ void set_configuration(int32_t width, int32_t height);
+ void set_orientation(int32_t orientation);
+ void screenshot(const char *filename);
+ void send_stats();
+ void destroy(int32_t destroy_scene_object);
+};
+
+// _
+// | | __ _ _ _ ___ _ __
+// | |/ _` | | | |/ _ \ '__|
+// | | (_| | |_| | __/ |
+// |_|\__,_|\__, |\___|_|
+// |___/
+struct layer : public wayland_proxy<struct ivi_controller_layer>,
+ controller_child {
+ layer(layer const &) = delete;
+ layer &operator=(layer const &) = delete;
+ layer(uint32_t i, struct controller *c);
+ layer(uint32_t i, int32_t w, int32_t h, struct controller *c);
+
+ // Requests
+ void set_visibility(uint32_t visibility);
+ void set_opacity(wl_fixed_t opacity);
+ void set_source_rectangle(int32_t x, int32_t y, int32_t width,
+ int32_t height);
+ void set_destination_rectangle(int32_t x, int32_t y, int32_t width,
+ int32_t height);
+ void set_configuration(int32_t width, int32_t height);
+ void set_orientation(int32_t orientation);
+ void screenshot(const char *filename);
+ void clear_surfaces();
+ void add_surface(struct surface *surface);
+ void remove_surface(struct surface *surface);
+ void set_render_order(std::vector<uint32_t> const &ro);
+};
+
+//
+// ___ ___ _ __ ___ ___ _ __
+// / __|/ __| '__/ _ \/ _ \ '_ \
+// \__ \ (__| | | __/ __/ | | |
+// |___/\___|_| \___|\___|_| |_|
+//
+struct screen : public wayland_proxy<struct ivi_controller_screen>,
+ controller_child {
+ screen(screen const &) = delete;
+ screen &operator=(screen const &) = delete;
+ screen(uint32_t i, struct controller *c, struct ivi_controller_screen *p);
+ void clear();
+ void add_layer(layer *l);
+ void set_render_order(std::vector<uint32_t> const &ro);
+};
+
+// _ _ _
+// ___ ___ _ __ | |_ _ __ ___ | | | ___ _ __
+// / __/ _ \| '_ \| __| '__/ _ \| | |/ _ \ '__|
+// | (_| (_) | | | | |_| | | (_) | | | __/ |
+// \___\___/|_| |_|\__|_| \___/|_|_|\___|_|
+//
+struct controller : public wayland_proxy<struct ivi_controller> {
+ // This controller is still missing ivi-input
+
+ typedef std::unordered_map<uintptr_t, uint32_t> proxy_to_id_map_type;
+ typedef std::unordered_map<uint32_t, std::unique_ptr<struct surface>>
+ surface_map_type;
+ typedef std::unordered_map<uint32_t, std::unique_ptr<struct layer>>
+ layer_map_type;
+ typedef std::unordered_map<uint32_t, std::unique_ptr<struct screen>>
+ screen_map_type;
+
+ typedef std::unordered_map<uint32_t, struct surface_properties> props_map;
+
+ // HACK:
+ // The order of these member is mandatory, as when objects are destroyed
+ // they will call their parent (that's us right here!) and remove their
+ // proxy-to-id mapping. I.e. the *_proxy_to_id members need to be valid
+ // when the surfaces/layers/screens maps are destroyed. This sucks, but
+ // I cannot see a better solution w/o globals or some other horrible
+ // call-our-parent construct.
+ proxy_to_id_map_type surface_proxy_to_id;
+ proxy_to_id_map_type layer_proxy_to_id;
+ proxy_to_id_map_type screen_proxy_to_id;
+
+ props_map sprops;
+ props_map lprops;
+
+ surface_map_type surfaces;
+ layer_map_type layers;
+ screen_map_type screens;
+
+ size output_size;
+
+ wm::controller_hooks *chooks;
+
+ void add_proxy_to_id_mapping(struct ivi_controller_surface *p, uint32_t id);
+ void remove_proxy_to_id_mapping(struct ivi_controller_surface *p);
+ void add_proxy_to_id_mapping(struct ivi_controller_layer *p, uint32_t id);
+ void remove_proxy_to_id_mapping(struct ivi_controller_layer *p);
+ void add_proxy_to_id_mapping(struct wl_output *p, uint32_t id);
+ void remove_proxy_to_id_mapping(struct wl_output *p);
+
+ bool surface_exists(uint32_t id) const {
+ return this->surfaces.find(id) != this->surfaces.end();
+ }
+
+ bool layer_exists(uint32_t id) const {
+ return this->layers.find(id) != this->layers.end();
+ }
+
+ controller(struct wl_registry *r, uint32_t name, uint32_t version);
+
+ // Requests
+ void commit_changes() const {
+ ivi_controller_commit_changes(this->proxy.get());
+ }
+ void layer_create(uint32_t id, int32_t w, int32_t h);
+ void surface_create(uint32_t id);
+
+ // Events
+ // controller
+ void controller_screen(uint32_t id, struct ivi_controller_screen *screen);
+ void controller_layer(uint32_t id);
+ void controller_surface(uint32_t id);
+ void controller_error(int32_t object_id, int32_t object_type,
+ int32_t error_code, char const *error_text);
+
+ // surface
+ void surface_visibility(struct surface *s, int32_t visibility);
+ void surface_opacity(struct surface *s, float opacity);
+ void surface_source_rectangle(struct surface *s, int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void surface_destination_rectangle(struct surface *s, int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void surface_configuration(struct surface *s, int32_t width, int32_t height);
+ void surface_orientation(struct surface *s, int32_t orientation);
+ void surface_pixelformat(struct surface *s, int32_t pixelformat);
+ void surface_layer(struct surface *s, struct ivi_controller_layer *layer);
+ void surface_stats(struct surface *s, uint32_t redraw_count,
+ uint32_t frame_count, uint32_t update_count, uint32_t pid,
+ const char *process_name);
+ void surface_destroyed(struct surface *s);
+ void surface_content(struct surface *s, int32_t content_state);
+
+ // layer
+ void layer_visibility(struct layer *l, int32_t visibility);
+ void layer_opacity(struct layer *l, float opacity);
+ void layer_source_rectangle(struct layer *l, int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void layer_destination_rectangle(struct layer *l, int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void layer_configuration(struct layer *l, int32_t width, int32_t height);
+ void layer_orientation(struct layer *l, int32_t orientation);
+ void layer_screen(struct layer *l, struct wl_output *screen);
+ void layer_destroyed(struct layer *l);
+};
+} // namespace genivi
+
+#endif // !WM_WAYLAND_HPP