summaryrefslogtreecommitdiffstats
path: root/demo#3/common/agl-service-windowmanager/src
diff options
context:
space:
mode:
Diffstat (limited to 'demo#3/common/agl-service-windowmanager/src')
-rw-r--r--demo#3/common/agl-service-windowmanager/src/CMakeLists.txt124
-rw-r--r--demo#3/common/agl-service-windowmanager/src/applist.cpp635
-rw-r--r--demo#3/common/agl-service-windowmanager/src/applist.hpp99
-rw-r--r--demo#3/common/agl-service-windowmanager/src/config/areas.json204
-rw-r--r--demo#3/common/agl-service-windowmanager/src/config/connection.json5
-rw-r--r--demo#3/common/agl-service-windowmanager/src/config/old_roles.json68
-rw-r--r--demo#3/common/agl-service-windowmanager/src/controller_hooks.hpp42
-rw-r--r--demo#3/common/agl-service-windowmanager/src/json_helper.cpp149
-rw-r--r--demo#3/common/agl-service-windowmanager/src/json_helper.hpp34
-rw-r--r--demo#3/common/agl-service-windowmanager/src/layers.cpp382
-rw-r--r--demo#3/common/agl-service-windowmanager/src/layers.hpp174
-rw-r--r--demo#3/common/agl-service-windowmanager/src/low_can_client.cpp187
-rw-r--r--demo#3/common/agl-service-windowmanager/src/low_can_client.hpp113
-rw-r--r--demo#3/common/agl-service-windowmanager/src/main.cpp844
-rw-r--r--demo#3/common/agl-service-windowmanager/src/pm_wrapper.cpp439
-rw-r--r--demo#3/common/agl-service-windowmanager/src/pm_wrapper.hpp76
-rw-r--r--demo#3/common/agl-service-windowmanager/src/request.cpp51
-rw-r--r--demo#3/common/agl-service-windowmanager/src/request.hpp109
-rw-r--r--demo#3/common/agl-service-windowmanager/src/result.hpp86
-rw-r--r--demo#3/common/agl-service-windowmanager/src/util.cpp172
-rw-r--r--demo#3/common/agl-service-windowmanager/src/util.hpp125
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wayland_ivi_wm.cpp724
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wayland_ivi_wm.hpp327
-rw-r--r--demo#3/common/agl-service-windowmanager/src/window_manager.cpp2326
-rw-r--r--demo#3/common/agl-service-windowmanager/src/window_manager.hpp346
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_client.cpp271
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_client.hpp92
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_connection.cpp457
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_connection.hpp64
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_error.cpp46
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_error.hpp41
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_layer.cpp271
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_layer.hpp104
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_layer_control.cpp911
-rw-r--r--demo#3/common/agl-service-windowmanager/src/wm_layer_control.hpp118
35 files changed, 10216 insertions, 0 deletions
diff --git a/demo#3/common/agl-service-windowmanager/src/CMakeLists.txt b/demo#3/common/agl-service-windowmanager/src/CMakeLists.txt
new file mode 100644
index 0000000..9fa4b73
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/CMakeLists.txt
@@ -0,0 +1,124 @@
+#
+# Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+#
+# 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(FindPkgConfig)
+pkg_check_modules(AFB REQUIRED afb-daemon)
+pkg_check_modules(ILM REQUIRED ilmControl ilmCommon)
+pkg_check_modules(SD REQUIRED libsystemd>=222)
+
+# We do not want a prefix for our module
+set(CMAKE_SHARED_MODULE_PREFIX "")
+
+set(TARGETS_WM windowmanager-service)
+
+add_library(${TARGETS_WM} MODULE
+ main.cpp
+ util.cpp
+ json_helper.cpp
+ applist.cpp
+ request.cpp
+ pm_wrapper.cpp
+ window_manager.cpp
+ wm_client.cpp
+ wm_error.cpp
+ wm_layer.cpp
+ wm_layer_control.cpp
+ wm_connection.cpp
+ low_can_client.cpp)
+
+target_include_directories(${TARGETS_WM}
+ PRIVATE
+ ${AFB_INCLUDE_DIRS}
+ ${SD_INCLUDE_DIRS}
+ ${ILM_INCLUDE_DIRS}
+ ../include
+ ../src
+ ../${PLUGIN_PM})
+
+target_link_libraries(${TARGETS_WM}
+ PRIVATE
+ ${AFB_LIBRARIES}
+ ${WLC_LIBRARIES}
+ ${ILM_LIBRARIES}
+ ${SD_LIBRARIES}
+ ${PLUGIN_PM})
+
+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)
+
+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 -Wl,-rpath,'$ORIGIN'")
+
+if (LINK_LIBCXX)
+ set_target_properties(${TARGETS_WM}
+ PROPERTIES
+ LINK_FLAGS "-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../export.map -lc++ -Wl,-rpath,'$ORIGIN'")
+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
+ COMMAND mkdir -p ${PROJECT_BINARY_DIR}/package/root/etc
+ COMMAND cp -f ${PROJECT_SOURCE_DIR}/layers_setting.json ${PROJECT_BINARY_DIR}/package/root/etc
+ COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/old_roles.json ${PROJECT_BINARY_DIR}/package/root/etc
+ COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/areas.json ${PROJECT_BINARY_DIR}/package/root/etc
+ COMMAND cp -f ${PROJECT_SOURCE_DIR}/src/config/connection.json ${PROJECT_BINARY_DIR}/package/root/etc
+)
+
+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/demo#3/common/agl-service-windowmanager/src/applist.cpp b/demo#3/common/agl-service-windowmanager/src/applist.cpp
new file mode 100644
index 0000000..44865f6
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/applist.cpp
@@ -0,0 +1,635 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <iostream>
+#include <algorithm>
+#include "applist.hpp"
+#include "util.hpp"
+
+using std::shared_ptr;
+using std::string;
+using std::vector;
+
+namespace wm
+{
+
+const static int kReserveClientSize = 100;
+const static int kReserveReqSize = 10;
+
+/**
+ * AppList Constructor.
+ *
+ * Reserve the container size to avoid re-allocating memory.
+ *
+ * @note Size should be changed according to the system.
+ * If the number of applications becomes over the size, re-allocating memory will happen.
+ */
+AppList::AppList()
+ : req_list(),
+ app2client(),
+ current_req(1)
+{
+ this->app2client.reserve(kReserveClientSize);
+ this->req_list.reserve(kReserveReqSize);
+}
+
+AppList::~AppList() {}
+
+// =================== Client Date container API ===================
+
+/**
+ * Add Client to the list
+ *
+ * Add Client to the list.
+ * The Client means application which has role, layer, surface
+ * This function should be called once for the app.
+ * Caller should take care not to be called more than once.
+ *
+ * @param string[in] Application id. This will be the key to withdraw the information.
+ * @param unsigned[in] Layer ID in which the application is
+ * @param unsigned[in] surface ID which the application has
+ * @param string[in] Role which means what behavior the application will do.
+ * @return None
+ * @attention This function should be called once for the app
+ * Caller should take care not to be called more than once.
+ */
+void AppList::addClient(const string &appid, unsigned layer, unsigned surface, const string &role)
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, surface, role);
+ this->app2client[appid] = client;
+ this->clientDump();
+}
+
+void AppList::addClient(const string &appid, unsigned layer, const string &role)
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ shared_ptr<WMClient> client = std::make_shared<WMClient>(appid, layer, role);
+ this->app2client[appid] = client;
+ this->clientDump();
+}
+
+/**
+ * Remove WMClient from the list
+ *
+ * @param string[in] Application id. This will be the key to withdraw the information.
+ */
+void AppList::removeClient(const string &appid)
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ this->app2client.erase(appid);
+ HMI_INFO("Remove client %s", appid.c_str());
+}
+
+/**
+ * Check this class stores the appid.
+ *
+ * @param string[in] Application id. This will be the key to withdraw the information.
+ * @return true if the class has the requested key(appid)
+ */
+bool AppList::contains(const string &appid) const
+{
+ auto result = this->app2client.find(appid);
+ return (this->app2client.end() != result) ? true : false;
+}
+
+/**
+ * Remove surface from client
+ *
+ * @param unsigned[in] surface id.
+ * @return None
+ */
+void AppList::removeSurface(unsigned surface){
+ // This function may be very slow
+ std::lock_guard<std::mutex> lock(this->mtx);
+ bool ret = false;
+ for (auto &x : this->app2client)
+ {
+ ret = x.second->removeSurfaceIfExist(surface);
+ if(ret){
+ HMI_DEBUG("remove surface %d from Client %s finish",
+ surface, x.second->appID().c_str());
+ break;
+ }
+ }
+
+}
+
+/**
+ * Get WMClient object.
+ *
+ * After get the WMClient object, caller can call the client method.
+ * Before call this function, caller must call "contains"
+ * to check the key is contained, otherwise, you have to take care of std::out_of_range.
+ *
+ * @param string[in] application id(key)
+ * @return WMClient object
+ * @attention Must call cantains to check appid is stored before this function.
+ */
+shared_ptr<WMClient> AppList::lookUpClient(const string &appid)
+{
+ if(this->app2client.count(appid) != 0)
+ {
+ return this->app2client.at(appid);
+ }
+ else
+ {
+ return nullptr;
+ }
+}
+
+/**
+ * Count Client.
+ *
+ * Returns the number of client stored in the list.
+ *
+ * @param None
+ * @return The number of client
+ */
+int AppList::countClient() const
+{
+ return this->app2client.size();
+}
+
+/**
+ * Get AppID with surface and role.
+ *
+ * Returns AppID if found.
+ *
+ * @param unsigned[in] surfaceID
+ * @param string[in] role
+ * @param bool[in,out] AppID is found or not
+ * @return AppID
+ * @attention If AppID is not found, param found will be false.
+ */
+/* string AppList::getAppID(unsigned surface, const string& role, bool* found) const
+{
+ *found = false;
+ for (const auto &x : this->app2client)
+ {
+ if(x.second->surfaceID(role) == surface){
+ *found = true;
+ return x.second->appID();
+ }
+ }
+ return string("");
+} */
+
+string AppList::getAppID(unsigned surface, bool* found) const
+{
+ *found = false;
+ for (const auto &x : this->app2client)
+ {
+ if(x.second->surfaceID() == surface){
+ *found = true;
+ return x.second->appID();
+ }
+ }
+ return string("");
+}
+
+WMError AppList::popFloatingSurface(unsigned pid, unsigned *surface)
+{
+ WMError ret = WMError::NO_ENTRY;
+
+ auto fwd_itr = std::remove_if(this->floating_surfaces.begin(), this->floating_surfaces.end(),
+ [pid, surface, &ret](FloatingSurface x) {
+ if(pid == x.pid){
+ *surface = x.surface_id;
+ ret = WMError::SUCCESS;
+ return true;
+ }
+ else{
+ return false;
+ }
+ });
+ if (fwd_itr != this->floating_surfaces.cend())
+ {
+ HMI_INFO("pop floating surface: %d", *surface);
+ }
+ this->floating_surfaces.erase(fwd_itr, this->floating_surfaces.end());
+ return ret;
+}
+
+// =================== Floating(Temporary) surface/client API ===================
+
+// TODO: After testing setRole, remove these API
+
+WMError AppList::popFloatingSurface(const string &appid, unsigned *surface)
+{
+ HMI_ERROR("This function is not implemented");
+ return WMError::SUCCESS;
+}
+
+void AppList::addFloatingClient(const string &appid, unsigned layer, const string &role)
+{
+}
+
+void AppList::addFloatingSurface(const string &appid, unsigned surface, unsigned pid)
+{
+ struct FloatingSurface fsurface{appid, surface, pid};
+ this->floating_surfaces.push_back(fsurface);
+ this->dumpFloatingSurfaces();
+}
+
+void AppList::removeFloatingSurface(unsigned surface)
+{
+ this->dumpFloatingSurfaces();
+ auto fwd_itr = std::remove_if(
+ this->floating_surfaces.begin(), this->floating_surfaces.end(),
+ [surface](FloatingSurface x) {
+ return x.surface_id == surface;
+ });
+ if(fwd_itr != this->floating_surfaces.cend()){
+ HMI_INFO("remove floating surface: %d", surface);
+ }
+ this->floating_surfaces.erase(fwd_itr, this->floating_surfaces.end());
+}
+
+// =================== Request Date container API ===================
+
+/**
+ * Get current request number
+ *
+ * Request number is the numeric ID to designate the request.
+ * But returned request number from this function doesn't mean the request exists.
+ * This number is used as key to withdraw the WMRequest object.
+ *
+ * @param None
+ * @return current request number.
+ * @note request number is more than 0.
+ */
+unsigned AppList::currentRequestNumber() const
+{
+ return this->current_req;
+}
+
+/**
+ * Get request number
+ *
+ * Request number is the numeric ID to designate the request.
+ * But returned request number from this function doesn't mean the request exists.
+ * This number is used as key to withdraw the WMRequest object.
+ *
+ * @param None
+ * @return request number.
+ * @attention If returned value is 0, no request exists.
+ */
+unsigned AppList::getRequestNumber(const string &appid) const
+{
+ for (const auto &x : this->req_list)
+ {
+ // Since app will not request twice and more, comparing appid is enough?
+ if ((x.trigger.appid == appid))
+ {
+ return x.req_num;
+ }
+ }
+ return 0;
+}
+
+/**
+ * Add Request
+ *
+ * Request number is the numeric ID to designate the request.
+ * But returned request number from this function doesn't mean the request exists.
+ * This number is used as key to withdraw the WMRequest object.
+ *
+ * @param WMRequest[in] WMRequest object caller creates
+ * @return Request number
+ * @attention If the request number is different with curent request number,
+ * it means the previous request is not finished.
+ */
+unsigned AppList::addRequest(WMRequest req)
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ if (this->req_list.size() == 0)
+ {
+ req.req_num = current_req;
+ }
+ else
+ {
+ HMI_SEQ_INFO(this->current_req, "add: %d", this->req_list.back().req_num + 1);
+ req.req_num = this->req_list.back().req_num + 1;
+ }
+ this->req_list.push_back(req);
+ return req.req_num;
+}
+
+/**
+ * Get trigger which the application requests
+ *
+ * WMTrigger contains which application requests what role and where to put(area) and task.
+ * This is used for input event to Window Policy Manager(state machine).
+ *
+ * @param unsigned[in] request number
+ * @param bool[in,out] Check request number of the parameter is valid.
+ * @return WMTrigger which associates with the request number
+ * @attention If the request number is not valid, parameter "found" is false
+ * and return value will be meaningless value.
+ * Caller can check the request parameter is valid.
+ */
+struct WMTrigger AppList::getRequest(unsigned req_num, bool *found)
+{
+ *found = false;
+ for (const auto &x : this->req_list)
+ {
+ if (req_num == x.req_num)
+ {
+ *found = true;
+ return x.trigger;
+ }
+ }
+ HMI_SEQ_ERROR(req_num, "Couldn't get request : %d", req_num);
+ return WMTrigger{"", "", "", Task::TASK_INVALID};
+}
+
+/**
+ * Get actions which the application requests
+ *
+ * WMAciton contains the information of state transition.
+ * In other words, it contains actions of Window Manager,
+ * which role should be put to the area.
+ *
+ * @param unsigned[in] request number
+ * @param bool[in,out] Check request number of the parameter is valid.
+ * @return WMTrigger which associates with the request number
+ * @attention If the request number is not valid, parameter "found" is false
+ * and return value will be no reference pointer.
+ * Caller must check the request parameter is valid.
+ */
+const vector<struct WMAction> &AppList::getActions(unsigned req_num, bool* found)
+{
+ *found = false;
+ for (auto &x : this->req_list)
+ {
+ if (req_num == x.req_num)
+ {
+ *found = true;
+ return x.sync_draw_req;
+ }
+ }
+ HMI_SEQ_ERROR(req_num, "Couldn't get action with the request : %d", req_num);
+}
+
+/**
+ * Set actions to the request.
+ *
+ * Add actions to the request.
+ * This function can be called many times, and actions increase.
+ * This function is used for decision of actions of Window Manager
+ * according to the result of Window Policy Manager.
+ *
+ * @param unsigned[in] request number
+ * @param WMAction[in] Action of Window Manager.
+ * @return WMError If request number is not valid, FAIL will be returned.
+ */
+WMError AppList::setAction(unsigned req_num, const struct WMAction &action)
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ WMError result = WMError::FAIL;
+ for (auto &x : this->req_list)
+ {
+ if (req_num != x.req_num)
+ {
+ continue;
+ }
+ x.sync_draw_req.push_back(action);
+ result = WMError::SUCCESS;
+ break;
+ }
+ return result;
+}
+
+/**
+ * Note:
+ * @note This function set action with parameters.
+ * If visible is true, it means app should be visible, so enddraw_finished parameter should be false.
+ * otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
+ * This function doesn't support actions for focus yet.
+ */
+/**
+ * Set actions to the request.
+ *
+ * This function is overload function.
+ * The feature is same as other one.
+ *
+ * @param unsigned[in] request number
+ * @param string[in] application id
+ * @param string[in] role
+ * @param string[in] area
+ * @param Task[in] the role should be visible or not.
+ * @return WMError If request number is not valid, FAIL will be returned.
+ * @attention This function set action with parameters, then caller doesn't need to create WMAction object.
+ * If visible is true, it means app should be visible, so enddraw_finished parameter will be false.
+ * otherwise (visible is false) app should be invisible. Then enddraw_finished param is set to true.
+ * This function doesn't support actions for focus yet.
+ */
+WMError AppList::setAction(unsigned req_num, shared_ptr<WMClient> client, const string &role, const string &area, TaskVisible visible)
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ WMError result = WMError::FAIL;
+ for (auto &x : req_list)
+ {
+ if (req_num != x.req_num)
+ {
+ continue;
+ }
+ // If visible task is not invisible, redraw is required -> true
+ bool edraw_f = (visible != TaskVisible::INVISIBLE) ? false : true;
+ WMAction action{req_num, client, role, area, visible, edraw_f, TaskCarState::NO_TASK};
+
+ x.sync_draw_req.push_back(action);
+ result = WMError::SUCCESS;
+ break;
+ }
+ return result;
+}
+
+/**
+ * Set end_draw_finished param is true
+ *
+ * This function checks
+ * - req_num is equal to current request number
+ * - appid and role are equeal to the appid and role stored in action list
+ * If it is valid, set the action is finished.
+ *
+ * @param unsigned[in] request number
+ * @param string[in] application id
+ * @param string[in] role
+ * @return If the parameters are not valid in action list, returns false
+ */
+bool AppList::setEndDrawFinished(unsigned req_num, const string &appid, const string &role)
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ bool result = false;
+ for (auto &x : req_list)
+ {
+ if (req_num < x.req_num)
+ {
+ break;
+ }
+ if (req_num == x.req_num)
+ {
+ for (auto &y : x.sync_draw_req)
+ {
+ if (nullptr != y.client)
+ {
+ if (y.client->appID() == appid && y.role == role)
+ {
+ HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str());
+ y.end_draw_finished = true;
+ result = true;
+ }
+ }
+ else
+ {
+ if (y.role == role)
+ {
+ HMI_SEQ_INFO(req_num, "Role %s finish redraw", y.role.c_str());
+ y.end_draw_finished = true;
+ result = true;
+ }
+ }
+ }
+ }
+ }
+ this->reqDump();
+ return result;
+}
+
+/**
+ * Check all actions of the requested sequence is finished
+ *
+ * @param unsigned[in] request_number
+ * @return true if all action is set.
+ */
+bool AppList::endDrawFullfilled(unsigned req_num)
+{
+ bool result = false;
+ for (const auto &x : req_list)
+ {
+ if (req_num < x.req_num)
+ {
+ break;
+ }
+ if (req_num == x.req_num)
+ {
+ result = true;
+ for (const auto &y : x.sync_draw_req)
+ {
+ result &= y.end_draw_finished;
+ if (!result)
+ {
+ break;
+ }
+ }
+ }
+ }
+ return result;
+}
+
+/**
+ * Finish the request, then remove it.
+ *
+ * @param unsigned[in] request_number
+ * @return None
+ * @note Please call next after this function to receive or process next request.
+ */
+void AppList::removeRequest(unsigned req_num)
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ this->req_list.erase(remove_if(this->req_list.begin(), this->req_list.end(),
+ [req_num](WMRequest x) {
+ return x.req_num == req_num;
+ }));
+}
+
+/**
+ * Move the current request to next
+ *
+ * @param None
+ * @return None
+ */
+void AppList::next()
+{
+ std::lock_guard<std::mutex> lock(this->mtx);
+ ++this->current_req;
+ if (0 == this->current_req)
+ {
+ this->current_req = 1;
+ }
+}
+
+/**
+ * Check the request exists is in request list
+ *
+ * @param None
+ * @return true if WMRequest exists in the request list
+ */
+bool AppList::haveRequest() const
+{
+ return !this->req_list.empty();
+}
+
+void AppList::clientDump()
+{
+ DUMP("======= client dump =====");
+ for (const auto &x : this->app2client)
+ {
+ const auto &y = x.second;
+ y->dumpInfo();
+ }
+ DUMP("======= client dump end=====");
+}
+
+void AppList::reqDump()
+{
+ DUMP("======= req dump =====");
+ DUMP("current request : %d", current_req);
+ for (const auto &x : req_list)
+ {
+ DUMP("requested : %d", x.req_num);
+ DUMP("Trigger : (APPID :%s, ROLE :%s, AREA :%s, TASK: %d)",
+ x.trigger.appid.c_str(),
+ x.trigger.role.c_str(),
+ x.trigger.area.c_str(),
+ x.trigger.task);
+
+ for (const auto &y : x.sync_draw_req)
+ {
+ DUMP(
+ "Action : (APPID :%s, ROLE :%s, AREA :%s, VISIBLE : %s, END_DRAW_FINISHED: %d)",
+ (y.client) ? y.client->appID().c_str() : "-",
+ y.role.c_str(),
+ y.area.c_str(),
+ (y.visible == TaskVisible::INVISIBLE) ? "invisible" : "visible",
+ y.end_draw_finished);
+ }
+ }
+ DUMP("======= req dump end =====");
+}
+
+void AppList::dumpFloatingSurfaces()
+{
+ DUMP("======= floating surface dump =====");
+ for (const auto &x : this->floating_surfaces)
+ {
+ DUMP("surface : %d, pid : %d", x.surface_id, x.pid);
+ }
+ DUMP("======= floating surface dump end =====\n");
+}
+
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/applist.hpp b/demo#3/common/agl-service-windowmanager/src/applist.hpp
new file mode 100644
index 0000000..36e0524
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/applist.hpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 ALLOCATE_LIST_HPP
+#define ALLOCATE_LIST_HPP
+#include <vector>
+#include <string>
+#include <map>
+#include <memory>
+#include <mutex>
+#include "wm_client.hpp"
+#include "request.hpp"
+#include "wm_error.hpp"
+
+namespace wm
+{
+
+/* using std::experimental::nullopt;
+using std::experimental::optional; */
+
+struct FloatingSurface
+{
+ std::string appid;
+ unsigned surface_id;
+ unsigned pid;
+};
+
+class AppList
+{
+ public:
+ AppList();
+ virtual ~AppList();
+ AppList(const AppList &obj) = delete;
+
+ // Client Database Interface
+ /* TODO: consider, which is better WMClient as parameter or not
+ If the WMClient should be more flexible, I think this param should be WMClient class
+ */
+ void addClient(const std::string &appid, unsigned layer,
+ unsigned surface, const std::string &role);
+ void addClient(const std::string &appid, unsigned layer, const std::string &role);
+ void removeClient(const std::string &appid);
+ bool contains(const std::string &appid) const;
+ int countClient() const;
+ std::shared_ptr<WMClient> lookUpClient(const std::string &appid);
+ void removeSurface(unsigned surface);
+ std::string getAppID(unsigned surface, bool* found) const; // TODO: remove
+
+
+ // Floating surface
+ void addFloatingClient(const std::string &appid, unsigned layer, const std::string &role);
+ void addFloatingSurface(const std::string &appid, unsigned surface, unsigned pid);
+ WMError popFloatingSurface(unsigned pid, unsigned *surface);
+ WMError popFloatingSurface(const std::string &appid, unsigned *surface);
+ void removeFloatingSurface(unsigned surface);
+
+ // Request Interface
+ unsigned currentRequestNumber() const;
+ unsigned getRequestNumber(const std::string &appid) const;
+ unsigned addRequest(WMRequest req);
+ WMError setAction(unsigned req_num, const struct WMAction &action);
+ WMError setAction(unsigned req_num, std::shared_ptr<WMClient> client,
+ const std::string &role, const std::string &area, TaskVisible visible);
+ bool setEndDrawFinished(unsigned req_num, const std::string &appid, const std::string &role);
+ bool endDrawFullfilled(unsigned req_num);
+ void removeRequest(unsigned req_num);
+ void next();
+ bool haveRequest() const;
+
+ struct WMTrigger getRequest(unsigned req_num, bool* found);
+ const std::vector<struct WMAction> &getActions(unsigned req_num, bool* found);
+
+ void clientDump();
+ void reqDump();
+ void dumpFloatingSurfaces();
+
+ private:
+ std::vector<WMRequest> req_list;
+ std::unordered_map<std::string, std::shared_ptr<WMClient>> app2client;
+ unsigned current_req;
+ std::mutex mtx;
+ std::vector<struct FloatingSurface> floating_surfaces;
+};
+
+} // namespace wm
+#endif // ALLOCATE_LIST_HPP \ No newline at end of file
diff --git a/demo#3/common/agl-service-windowmanager/src/config/areas.json b/demo#3/common/agl-service-windowmanager/src/config/areas.json
new file mode 100644
index 0000000..d4f3531
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/config/areas.json
@@ -0,0 +1,204 @@
+{
+ "ecus": [
+ {
+ "name": "master",
+ "screens": [
+ {
+ "id": 0,
+ "areas": [
+ {
+ "name": "fullscreen",
+ "rect": {
+ "x": 0,
+ "y": 0,
+ "w": 1920,
+ "h": 720
+ }
+ },
+ {
+ "name": "normal.full",
+ "rect": {
+ "x": 0,
+ "y": 0,
+ "w": 1920,
+ "h": 720
+ }
+ },
+ {
+ "name": "split.main",
+ "rect": {
+ "x": 0,
+ "y": 0,
+ "w": 1280,
+ "h": 720
+ }
+ },
+ {
+ "name": "split.sub",
+ "rect": {
+ "x": 1280,
+ "y": 0,
+ "w": 640,
+ "h": 720
+ }
+ },
+ {
+ "name": "software_keyboard",
+ "rect": {
+ "x": 0,
+ "y": 962,
+ "w": 1080,
+ "h": 744
+ }
+ },
+ {
+ "name": "restriction.normal",
+ "rect": {
+ "x": 0,
+ "y": 0,
+ "w": 1920,
+ "h": 1080
+ }
+ },
+ {
+ "name": "restriction.split.main",
+ "rect": {
+ "x": 0,
+ "y": 0,
+ "w": 1920,
+ "h": 540
+ }
+ },
+ {
+ "name": "restriction.split.sub",
+ "rect": {
+ "x": 0,
+ "y": 540,
+ "w": 1920,
+ "h": 540
+ }
+ },
+ {
+ "name": "on_screen",
+ "rect": {
+ "x": 1280,
+ "y": 0,
+ "w": 640,
+ "h": 720
+ }
+ },
+ {
+ "name": "master.split.sub",
+ "rect": {
+ "x": 1280,
+ "y": 0,
+ "w": 640,
+ "h": 720
+ }
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "name": "slave",
+ "screens": [
+ {
+ "id": 0,
+ "areas": [
+ {
+ "name": "fullscreen",
+ "rect": {
+ "x": 0,
+ "y": 0,
+ "w": 1080,
+ "h": 1920
+ }
+ },
+ {
+ "name": "normal.full",
+ "rect": {
+ "x": 0,
+ "y": 218,
+ "w": 1080,
+ "h": 1488
+ }
+ },
+ {
+ "name": "split.main",
+ "rect": {
+ "x": 0,
+ "y": 218,
+ "w": 1080,
+ "h": 744
+ }
+ },
+ {
+ "name": "split.sub",
+ "rect": {
+ "x": 0,
+ "y": 962,
+ "w": 1080,
+ "h": 744
+ }
+ },
+ {
+ "name": "software_keyboard",
+ "rect": {
+ "x": 0,
+ "y": 962,
+ "w": 1080,
+ "h": 744
+ }
+ },
+ {
+ "name": "restriction.normal",
+ "rect": {
+ "x": 0,
+ "y": 218,
+ "w": 1080,
+ "h": 1488
+ }
+ },
+ {
+ "name": "restriction.split.main",
+ "rect": {
+ "x": 0,
+ "y": 218,
+ "w": 1080,
+ "h": 744
+ }
+ },
+ {
+ "name": "restriction.split.sub",
+ "rect": {
+ "x": 0,
+ "y": 962,
+ "w": 1080,
+ "h": 744
+ }
+ },
+ {
+ "name": "on_screen",
+ "rect": {
+ "x": 0,
+ "y": 218,
+ "w": 1080,
+ "h": 1488
+ }
+ },
+ {
+ "name": "master.split.sub",
+ "rect": {
+ "x": 0,
+ "y": 180,
+ "w": 640,
+ "h": 720
+ }
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
diff --git a/demo#3/common/agl-service-windowmanager/src/config/connection.json b/demo#3/common/agl-service-windowmanager/src/config/connection.json
new file mode 100644
index 0000000..3ee06c3
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/config/connection.json
@@ -0,0 +1,5 @@
+{
+ "mode": "master",
+ "master_ip": "10.4.1.78",
+ "master_port": 54400
+}
diff --git a/demo#3/common/agl-service-windowmanager/src/config/old_roles.json b/demo#3/common/agl-service-windowmanager/src/config/old_roles.json
new file mode 100644
index 0000000..02a4c2d
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/config/old_roles.json
@@ -0,0 +1,68 @@
+{
+ "old_roles": [
+ {
+ "name": "HomeScreen",
+ "new": "homescreen"
+ },
+ {
+ "name": "Music",
+ "new": "music"
+ },
+ {
+ "name": "MediaPlayer",
+ "new": "music"
+ },
+ {
+ "name": "Video",
+ "new": "video"
+ },
+ {
+ "name": "VideoPlayer",
+ "new": "video"
+ },
+ {
+ "name": "WebBrowser",
+ "new": "browser"
+ },
+ {
+ "name": "Radio",
+ "new": "radio"
+ },
+ {
+ "name": "Phone",
+ "new": "phone"
+ },
+ {
+ "name": "Navigation",
+ "new": "map"
+ },
+ {
+ "name": "HVAC",
+ "new": "hvac"
+ },
+ {
+ "name": "Settings",
+ "new": "settings"
+ },
+ {
+ "name": "Dashboard",
+ "new": "dashboard"
+ },
+ {
+ "name": "POI",
+ "new": "poi"
+ },
+ {
+ "name": "Mixer",
+ "new": "mixer"
+ },
+ {
+ "name": "Restriction",
+ "new": "restriction"
+ },
+ {
+ "name": "^OnScreen.*",
+ "new": "on_screen"
+ }
+ ]
+}
diff --git a/demo#3/common/agl-service-windowmanager/src/controller_hooks.hpp b/demo#3/common/agl-service-windowmanager/src/controller_hooks.hpp
new file mode 100644
index 0000000..ae88187
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/controller_hooks.hpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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
+{
+
+class WindowManager;
+
+struct controller_hooks
+{
+ WindowManager *wmgr;
+
+ 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);
+ void surface_properties(uint32_t surface_id, uint32_t pid);
+};
+
+} // namespace wm
+
+#endif // TMCAGLWM_CONTROLLER_HOOKS_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/json_helper.cpp b/demo#3/common/agl-service-windowmanager/src/json_helper.cpp
new file mode 100644
index 0000000..d9cf5eb
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/json_helper.cpp
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "util.hpp"
+
+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(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;
+}
+
+namespace jh {
+
+const char* getStringFromJson(json_object* obj, const char* key)
+{
+ json_object* tmp;
+ if (!json_object_object_get_ex(obj, key, &tmp))
+ {
+ HMI_DEBUG("Not found key \"%s\"", key);
+ return nullptr;
+ }
+
+ return json_object_get_string(tmp);
+}
+
+int getIntFromJson(json_object *obj, const char *key)
+{
+ json_object *tmp;
+ if (!json_object_object_get_ex(obj, key, &tmp))
+ {
+ HMI_DEBUG("Not found key \"%s\"", key);
+ return 0;
+ }
+
+ return json_object_get_int(tmp);
+}
+
+double getDoubleFromJson(json_object *obj, const char *key)
+{
+ json_object *tmp;
+ if (!json_object_object_get_ex(obj, key, &tmp))
+ {
+ HMI_DEBUG("Not found key \"%s\"", key);
+ return 0;
+ }
+
+ return json_object_get_double(tmp);
+}
+
+json_bool getBoolFromJson(json_object *obj, const char *key)
+{
+ json_object *tmp;
+ if (!json_object_object_get_ex(obj, key, &tmp))
+ {
+ HMI_DEBUG("Not found key \"%s\"", key);
+ return FALSE;
+ }
+
+ return json_object_get_boolean(tmp);
+}
+
+int inputJsonFilie(const char* file, json_object** obj)
+{
+ const int input_size = 128;
+ int ret = -1;
+
+ HMI_DEBUG("Input file: %s", file);
+
+ // Open json file
+ FILE *fp = fopen(file, "rb");
+ if (nullptr == fp)
+ {
+ HMI_ERROR("Could not open file");
+ return ret;
+ }
+
+ // Parse file data
+ struct json_tokener *tokener = json_tokener_new();
+ enum json_tokener_error json_error;
+ char buffer[input_size];
+ int block_cnt = 1;
+ while (1)
+ {
+ size_t len = fread(buffer, sizeof(char), input_size, fp);
+ *obj = json_tokener_parse_ex(tokener, buffer, len);
+ if (nullptr != *obj)
+ {
+ HMI_DEBUG("File input is success");
+ ret = 0;
+ break;
+ }
+
+ json_error = json_tokener_get_error(tokener);
+ if ((json_tokener_continue != json_error)
+ || (input_size > len))
+ {
+ HMI_ERROR("Failed to parse file (byte:%d err:%s)",
+ (input_size * block_cnt), json_tokener_error_desc(json_error));
+ HMI_ERROR("\n%s", buffer);
+ *obj = nullptr;
+ break;
+ }
+ block_cnt++;
+ }
+
+ // Close json file
+ fclose(fp);
+
+ // Free json_tokener
+ json_tokener_free(tokener);
+
+ return ret;
+}
+
+} // namespace jh
diff --git a/demo#3/common/agl-service-windowmanager/src/json_helper.hpp b/demo#3/common/agl-service-windowmanager/src/json_helper.hpp
new file mode 100644
index 0000000..d4ae85a
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/json_helper.hpp
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 JSON_HELPER_HPP
+#define JSON_HELPER_HPP
+
+#include <json-c/json.h>
+#include <vector>
+
+struct json_object;
+json_object *to_json(std::vector<uint32_t> const &v);
+
+namespace jh {
+const char* getStringFromJson(json_object* obj, const char* key);
+int getIntFromJson(json_object *obj, const char *key);
+double getDoubleFromJson(json_object *obj, const char *key);
+json_bool getBoolFromJson(json_object *obj, const char *key);
+int inputJsonFilie(const char* file, json_object** obj);
+} // namespace jh
+
+#endif // JSON_HELPER_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/layers.cpp b/demo#3/common/agl-service-windowmanager/src/layers.cpp
new file mode 100644
index 0000000..05d404d
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/layers.cpp
@@ -0,0 +1,382 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <regex>
+
+#include "layers.hpp"
+#include "json_helper.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"];
+
+ // Init flag of normal layout only
+ this->is_normal_layout_only = true;
+
+ auto split_layouts = j.find("split_layouts");
+ if (split_layouts != j.end())
+ {
+
+ // Clear flag of normal layout only
+ this->is_normal_layout_only = false;
+
+ 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"]
+ };
+ HMI_DEBUG("wm",
+ "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;
+ });
+ }
+ HMI_DEBUG("layer_id:%d is_normal_layout_only:%d\n",
+ this->layer_id, this->is_normal_layout_only);
+}
+
+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));
+ });
+
+ // TODO: 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))
+ {
+ HMI_DEBUG("role %s matches layer %d", role.c_str(), r.second);
+ return optional<int>(r.second);
+ }
+ }
+ HMI_DEBUG("role %s does NOT match any layer", role.c_str());
+ return nullopt;
+}
+
+json layer::to_json() const
+{
+ auto is_full = this->rect == compositor::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;
+}
+
+void layer_map::setupArea(double scaling)
+{
+ compositor::rect rct;
+
+ rct = this->area2size["normal.full"];
+ this->area2size["normalfull"] = rct;
+ this->area2size["normal"] = rct;
+
+ for (auto &i : this->area2size)
+ {
+ i.second.x = static_cast<int>(scaling * i.second.x + 0.5);
+ i.second.y = static_cast<int>(scaling * i.second.y + 0.5);
+ i.second.w = static_cast<int>(scaling * i.second.w + 0.5);
+ i.second.h = static_cast<int>(scaling * i.second.h + 0.5);
+
+ HMI_DEBUG("wm:lm", "area:%s size(after) : x:%d y:%d w:%d h:%d",
+ i.first.c_str(), i.second.x, i.second.y, i.second.w, i.second.h);
+ }
+}
+
+compositor::rect layer_map::getAreaSize(const std::string &area)
+{
+ return area2size[area];
+}
+
+int layer_map::loadAreaDb()
+{
+ HMI_DEBUG("wm:lm", "Call");
+
+ // Get afm application installed dir
+ char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
+ HMI_DEBUG("wm:lm", "afm_app_install_dir:%s", afm_app_install_dir);
+
+ std::string file_name;
+ if (!afm_app_install_dir)
+ {
+ HMI_ERROR("wm:lm", "AFM_APP_INSTALL_DIR is not defined");
+ }
+ else
+ {
+ file_name = std::string(afm_app_install_dir) + std::string("/etc/areas.db");
+ }
+
+ // Load area.db
+ json_object *json_obj;
+ int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj);
+ if (0 > ret)
+ {
+ HMI_DEBUG("wm:lm", "Could not open area.db, so use default area information");
+ json_obj = json_tokener_parse(kDefaultAreaDb);
+ }
+ HMI_DEBUG("wm:lm", "json_obj dump:%s", json_object_get_string(json_obj));
+
+ // Perse areas
+ HMI_DEBUG("wm:lm", "Perse areas");
+ json_object *json_cfg;
+ if (!json_object_object_get_ex(json_obj, "areas", &json_cfg))
+ {
+ HMI_ERROR("wm:lm", "Parse Error!!");
+ return -1;
+ }
+
+ int len = json_object_array_length(json_cfg);
+ HMI_DEBUG("wm:lm", "json_cfg len:%d", len);
+ HMI_DEBUG("wm:lm", "json_cfg dump:%s", json_object_get_string(json_cfg));
+
+ const char *area;
+ for (int i = 0; i < len; i++)
+ {
+ json_object *json_tmp = json_object_array_get_idx(json_cfg, i);
+ HMI_DEBUG("wm:lm", "> json_tmp dump:%s", json_object_get_string(json_tmp));
+
+ area = jh::getStringFromJson(json_tmp, "name");
+ if (nullptr == area)
+ {
+ HMI_ERROR("wm:lm", "Parse Error!!");
+ return -1;
+ }
+ HMI_DEBUG("wm:lm", "> area:%s", area);
+
+ json_object *json_rect;
+ if (!json_object_object_get_ex(json_tmp, "rect", &json_rect))
+ {
+ HMI_ERROR("wm:lm", "Parse Error!!");
+ return -1;
+ }
+ HMI_DEBUG("wm:lm", "> json_rect dump:%s", json_object_get_string(json_rect));
+
+ compositor::rect area_size;
+ area_size.x = jh::getIntFromJson(json_rect, "x");
+ area_size.y = jh::getIntFromJson(json_rect, "y");
+ area_size.w = jh::getIntFromJson(json_rect, "w");
+ area_size.h = jh::getIntFromJson(json_rect, "h");
+
+ this->area2size[area] = area_size;
+ }
+
+ // Check
+ for (auto itr = this->area2size.begin();
+ itr != this->area2size.end(); ++itr)
+ {
+ HMI_DEBUG("wm:lm", "area:%s x:%d y:%d w:%d h:%d",
+ itr->first.c_str(), itr->second.x, itr->second.y,
+ itr->second.w, itr->second.h);
+ }
+
+ // Release json_object
+ json_object_put(json_obj);
+
+ return 0;
+}
+
+const char* layer_map::kDefaultAreaDb = "{ \
+ \"areas\": [ \
+ { \
+ \"name\": \"fullscreen\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 0, \
+ \"w\": 1080, \
+ \"h\": 1920 \
+ } \
+ }, \
+ { \
+ \"name\": \"normal.full\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 218, \
+ \"w\": 1080, \
+ \"h\": 1488 \
+ } \
+ }, \
+ { \
+ \"name\": \"split.main\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 218, \
+ \"w\": 1080, \
+ \"h\": 744 \
+ } \
+ }, \
+ { \
+ \"name\": \"split.sub\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 962, \
+ \"w\": 1080, \
+ \"h\": 744 \
+ } \
+ }, \
+ { \
+ \"name\": \"software_keyboard\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 962, \
+ \"w\": 1080, \
+ \"h\": 744 \
+ } \
+ }, \
+ { \
+ \"name\": \"restriction.normal\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 218, \
+ \"w\": 1080, \
+ \"h\": 1488 \
+ } \
+ }, \
+ { \
+ \"name\": \"restriction.split.main\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 218, \
+ \"w\": 1080, \
+ \"h\": 744 \
+ } \
+ }, \
+ { \
+ \"name\": \"restriction.split.sub\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 962, \
+ \"w\": 1080, \
+ \"h\": 744 \
+ } \
+ }, \
+ { \
+ \"name\": \"on_screen\", \
+ \"rect\": { \
+ \"x\": 0, \
+ \"y\": 218, \
+ \"w\": 1080, \
+ \"h\": 1488 \
+ } \
+ } \
+ ] \
+}";
+
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/layers.hpp b/demo#3/common/agl-service-windowmanager/src/layers.hpp
new file mode 100644
index 0000000..f52886e
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/layers.hpp
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <string>
+
+#include "../include/json.hpp"
+#include "layout.hpp"
+#include "result.hpp"
+#include "wayland_ivi_wm.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.
+ compositor::rect rect;
+ // Specify a role prefix for surfaces that should be
+ // put on this layer.
+ std::string role;
+ // TODO: perhaps a zorder is needed here?
+ std::vector<struct split_layout> layouts;
+
+ mutable struct LayoutState state;
+
+ // Flag of normal layout only
+ bool is_normal_layout_only;
+
+ 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>;
+
+ 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;
+ void setupArea(double scaling);
+ compositor::rect getAreaSize(const std::string &area);
+ int loadAreaDb();
+
+ private:
+ std::unordered_map<std::string, compositor::rect> area2size;
+
+ static const char *kDefaultAreaDb;
+};
+
+struct result<struct layer_map> to_layer_map(nlohmann::json const &j);
+
+static const nlohmann::json default_layers_json = {
+ {"main_surface", {
+ {"surface_role", "HomeScreen"}
+ }},
+ {"mappings", {
+ {
+ {"role", "^HomeScreen$"},
+ {"name", "HomeScreen"},
+ {"layer_id", 1000},
+ {"area", {
+ {"type", "full"}
+ }}
+ },
+ {
+ {"role", "MediaPlayer|Radio|Phone|Navigation|HVAC|Settings|Dashboard|POI|Mixer"},
+ {"name", "apps"},
+ {"layer_id", 1001},
+ {"area", {
+ {"type", "rect"},
+ {"rect", {
+ {"x", 0},
+ {"y", 218},
+ {"width", -1},
+ {"height", -433}
+ }}
+ }}
+ },
+ {
+ {"role", "^OnScreen.*"},
+ {"name", "popups"},
+ {"layer_id", 9999},
+ {"area", {
+ {"type", "rect"},
+ {"rect", {
+ {"x", 0},
+ {"y", 760},
+ {"width", -1},
+ {"height", 400}
+ }}
+ }}
+ }
+ }}
+};
+} // namespace wm
+
+#endif // TMCAGLWM_LAYERS_H
diff --git a/demo#3/common/agl-service-windowmanager/src/low_can_client.cpp b/demo#3/common/agl-service-windowmanager/src/low_can_client.cpp
new file mode 100644
index 0000000..090aa14
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/low_can_client.cpp
@@ -0,0 +1,187 @@
+/*
+ * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "low_can_client.hpp"
+#include "json_helper.hpp"
+#include "util.hpp"
+
+extern "C"
+{
+#include <afb/afb-binding.h>
+}
+
+namespace wm
+{
+
+LowCanClient::LowCanClient()
+ : vehicle_speed(0),
+ trans_gear_pos(0),
+ headlamp_status(FALSE),
+ parking_brake_status(TRUE),
+ accel_pedal_pos(0),
+ accel_pedal_stt(FALSE),
+ lightstatus_brake_status(TRUE),
+ is_changed_accel_pedal_stt(false)
+{
+}
+
+void LowCanClient::initialize()
+{
+ int ret;
+
+ // Require API "low-can"
+ ret = afb_daemon_require_api_v2("low-can", 1);
+ if (0 > ret)
+ {
+ HMI_INFO("Requirement API \"low-can\" failed");
+ return;
+ }
+
+ // Subscribe low-level-can
+ // low-can subscribe { "event": "vehicle.speed" }
+ // low-can subscribe { "event": "transmission_gear_position" }
+ // low-can subscribe { "event": "headlamp_status" }
+ // low-can subscribe { "event": "parking_brake_status" }
+ // low-can subscribe { "event": "accelerator.pedal.position" }
+ // low-can subscribe { "event": "lightstatus.brake" }
+ for (int i = SignalNoMin; i <= SignalNoMax; i++)
+ {
+ // Set Event
+ json_object *json_obj = json_object_new_object();
+ json_object_object_add(json_obj, "event",
+ json_object_new_string(this->kSignalName[i]));
+
+ // Set filter
+ if (0 != strcmp("", this->kFilterValue[i]))
+ {
+ json_object_object_add(json_obj, "filter",
+ json_tokener_parse(this->kFilterValue[i]));
+ }
+ HMI_DEBUG("subscribe message:%s", json_object_get_string(json_obj));
+
+ // Subscribe
+ afb_service_call("low-can", "subscribe", json_obj,
+ [](void *closure, int status, json_object *result) {
+ HMI_DEBUG("subscribe result:%s", json_object_get_string(result));
+ },
+ nullptr);
+ }
+
+ return;
+}
+
+const char *LowCanClient::analyzeCanSignal(struct json_object *object)
+{
+ HMI_DEBUG("object:%s", json_object_get_string(object));
+
+ const char *name = jh::getStringFromJson(object, "name");
+ HMI_DEBUG("CAN signal name:%s", name);
+
+ if (strstr(name, this->kSignalName[SignalNoVehicliSpeed]))
+ {
+ // Update vehicle speed
+ this->vehicle_speed = jh::getIntFromJson(object, "value");
+ HMI_DEBUG("Update vehicle speed:%d", this->vehicle_speed);
+ }
+ else if (strstr(name, this->kSignalName[SignalNoTransGearPos]))
+ {
+ // Update transmission gear position
+ this->trans_gear_pos = jh::getIntFromJson(object, "value");
+ HMI_DEBUG("Update transmission gear position:%d", this->trans_gear_pos);
+ }
+ else if (strstr(name, this->kSignalName[SignalNoHeadlame]))
+ {
+ // Update headlamp status
+ this->headlamp_status = jh::getBoolFromJson(object, "value");
+ HMI_DEBUG("Update headlamp status:%d", this->headlamp_status);
+ }
+ else if (strstr(name, this->kSignalName[SignalNoParkingBrake]))
+ {
+ // Update parking gear status
+ this->parking_brake_status = jh::getBoolFromJson(object, "value");
+ HMI_DEBUG("Update parking brake status:%d", this->parking_brake_status);
+ }
+ else if (strstr(name, this->kSignalName[SignalNoAccelPedalPos]))
+ {
+ // Clear flag for whether accel pedal state is changed
+ this->is_changed_accel_pedal_stt = false;
+
+ // Update accelerator pedal status
+ this->accel_pedal_pos = jh::getDoubleFromJson(object, "value");
+ HMI_DEBUG("Update accelerator pedal position:%lf", this->accel_pedal_pos);
+
+ bool accel_pedal_stt;
+ if (0 != this->accel_pedal_pos)
+ {
+ accel_pedal_stt = true;
+ }
+ else
+ {
+ accel_pedal_stt = false;
+ }
+
+ if (accel_pedal_stt != this->accel_pedal_stt)
+ {
+ this->is_changed_accel_pedal_stt = true;
+ this->accel_pedal_stt = accel_pedal_stt;
+ }
+ }
+ else if (strstr(name, this->kSignalName[SignalNoLightstatusBrake]))
+ {
+ // Update lightstatus brake status
+ this->lightstatus_brake_status = jh::getBoolFromJson(object, "value");
+ HMI_DEBUG("Update lightstatus brake status:%d", this->lightstatus_brake_status);
+ }
+
+ return name;
+}
+
+bool LowCanClient::isChangedAccelPedalState()
+{
+ return this->is_changed_accel_pedal_stt;
+}
+
+int LowCanClient::getCurrentTransGearState()
+{
+ return this->trans_gear_pos;
+}
+
+bool LowCanClient::getCurrentHeadlampState()
+{
+ return (bool)this->headlamp_status;
+}
+
+bool LowCanClient::getCurrentParkingBrakeState()
+{
+ return (bool)this->parking_brake_status;
+}
+
+double LowCanClient::getCurrentAccelPedalPosition()
+{
+ return this->accel_pedal_pos;
+}
+
+bool LowCanClient::getCurrentAccelPedalState()
+{
+ return this->accel_pedal_stt;
+}
+
+bool LowCanClient::getCurrentLightstatusBrakeState()
+{
+ return (bool)this->lightstatus_brake_status;
+}
+
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/low_can_client.hpp b/demo#3/common/agl-service-windowmanager/src/low_can_client.hpp
new file mode 100644
index 0000000..9b7f509
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/low_can_client.hpp
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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_LOW_CAN_CLIENT_HPP
+#define TMCAGLWM_LOW_CAN_CLIENT_HPP
+
+#include <string>
+#include <vector>
+#include <json-c/json.h>
+
+namespace wm
+{
+
+class LowCanClient
+{
+
+ public:
+ explicit LowCanClient();
+ ~LowCanClient() = default;
+
+ enum SignalNo
+ {
+ SignalNoVehicliSpeed = 0,
+ SignalNoTransGearPos,
+ SignalNoHeadlame,
+ SignalNoParkingBrake,
+ SignalNoAccelPedalPos,
+ SignalNoLightstatusBrake,
+
+ SignalNum,
+
+ SignalNoMin = SignalNoVehicliSpeed,
+ SignalNoMax = SignalNum - 1,
+ };
+
+ const std::vector<const char *> kSignalName{
+ "vehicle.speed",
+ "transmission_gear_position",
+ "headlamp_status",
+ "parking_brake_status",
+ "accelerator.pedal.position",
+ "lightstatus.brake",
+ };
+
+ void initialize();
+ const char *analyzeCanSignal(struct json_object *object);
+
+ int getCurrentTransGearState();
+ bool getCurrentHeadlampState();
+ bool getCurrentParkingBrakeState();
+ double getCurrentAccelPedalPosition();
+ bool getCurrentAccelPedalState();
+ bool getCurrentLightstatusBrakeState();
+
+ bool isChangedAccelPedalState();
+
+ private:
+ // Disable copy and move
+ LowCanClient(LowCanClient const &) = delete;
+ LowCanClient &operator=(LowCanClient const &) = delete;
+ LowCanClient(LowCanClient &&) = delete;
+ LowCanClient &operator=(LowCanClient &&) = delete;
+
+ enum TransGearPosVal
+ {
+ TransGearPosValD1 = 1,
+ TransGearPosValD2,
+ TransGearPosValD3,
+ TransGearPosValD4,
+ TransGearPosValD5,
+ TransGearPosValD6,
+ TransGearPosValD7,
+ TransGearPosValD8,
+ TransGearPosValR,
+ TransGearPosValN,
+ };
+
+ const std::vector<const char *> kFilterValue{
+ "", // vehicle.speed
+ "", // transmission_gear_position
+ "", // headlamp_status
+ "", // parking_brake_status
+ "", // accelerator.pedal.position
+ "", // lightstatus.brake
+ };
+
+ int vehicle_speed;
+ int trans_gear_pos;
+ json_bool headlamp_status;
+ json_bool parking_brake_status;
+ double accel_pedal_pos;
+ bool accel_pedal_stt;
+ json_bool lightstatus_brake_status;
+
+ bool is_changed_accel_pedal_stt;
+};
+
+} // namespace wm
+
+#endif // TMCAGLWM_LOW_CAN_CLIENT_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/main.cpp b/demo#3/common/agl-service-windowmanager/src/main.cpp
new file mode 100644
index 0000000..3766152
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/main.cpp
@@ -0,0 +1,844 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <algorithm>
+#include <mutex>
+#include <json.h>
+#include <stdlib.h>
+#include <vector>
+#include "window_manager.hpp"
+#include "json_helper.hpp"
+
+extern "C"
+{
+#include <afb/afb-binding.h>
+#include <systemd/sd-event.h>
+}
+
+typedef struct WMClientCtxt
+{
+ std::string name;
+ std::string role;
+ WMClientCtxt(const char *appName, const char* appRole)
+ {
+ name = appName;
+ role = appRole;
+ }
+} WMClientCtxt;
+
+struct afb_instance
+{
+ wm::WindowManager wmgr;
+
+ afb_instance() : wmgr() {}
+ ~afb_instance() = default;
+
+ int init();
+};
+
+struct afb_instance *g_afb_instance;
+std::mutex binding_m;
+
+int afb_instance::init()
+{
+ return this->wmgr.init();
+}
+
+int _binding_init()
+{
+ HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);
+
+ g_afb_instance = new afb_instance;
+
+ if (g_afb_instance->init() == -1)
+ {
+ HMI_ERROR("Could not connect to compositor");
+ 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)
+ {
+ HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
+ }
+ return -1;
+}
+
+static void cbRemoveClientCtxt(void *data)
+{
+ WMClientCtxt *ctxt = (WMClientCtxt *)data;
+ if (ctxt == nullptr)
+ {
+ return;
+ }
+ HMI_DEBUG("remove app %s", ctxt->name.c_str());
+
+ // Policy Manager does not know this app was killed,
+ // so notify it by deactivate request.
+ g_afb_instance->wmgr.api_deactivate_surface(
+ ctxt->name.c_str(), ctxt->role.c_str(),
+ [](const char *) {});
+
+ g_afb_instance->wmgr.removeClient(ctxt->name);
+ delete ctxt;
+}
+
+static void createSecurityContext(afb_req req, const char* appid, const char* role)
+{
+ WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
+ if (!ctxt)
+ {
+ // Create Security Context at first time
+ const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
+ WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
+ HMI_DEBUG("create session for %s", ctxt->name.c_str());
+ afb_req_session_set_LOA(req, 1);
+ afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
+ }
+}
+
+void windowmanager_requestsurface(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ const char *a_drawing_name = afb_req_value(req, "drawing_name");
+ if (!a_drawing_name)
+ {
+ afb_req_fail(req, "failed", "Need char const* argument drawing_name");
+ return;
+ }
+
+ char *appid = afb_req_get_application_id(req);
+ if(appid)
+ {
+ auto ret = g_afb_instance->wmgr.api_request_surface(
+ appid, a_drawing_name);
+
+ if (ret.is_err())
+ {
+ afb_req_fail(req, "failed", ret.unwrap_err());
+ }
+ else
+ {
+ createSecurityContext(req, appid, a_drawing_name);
+ afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
+ }
+ free(appid);
+ }
+ else
+ {
+ afb_req_fail(req, "failed", nullptr);
+ }
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
+ return;
+ }
+}
+
+void windowmanager_requestsurfacexdg(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ json_object *jreq = afb_req_json(req);
+
+ json_object *j_drawing_name = nullptr;
+ if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
+ {
+ afb_req_fail(req, "failed", "Need char const* argument drawing_name");
+ return;
+ }
+ char const *a_drawing_name = json_object_get_string(j_drawing_name);
+
+ json_object *j_ivi_id = nullptr;
+ if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
+ {
+ afb_req_fail(req, "failed", "Need char const* argument ivi_id");
+ return;
+ }
+ char const *a_ivi_id = json_object_get_string(j_ivi_id);
+ char *appid = afb_req_get_application_id(req);
+ if(appid)
+ {
+ auto ret = g_afb_instance->wmgr.api_request_surface(
+ appid, a_drawing_name, a_ivi_id);
+ if (ret != nullptr)
+ {
+ afb_req_fail(req, "failed", ret);
+ }
+ else
+ {
+ createSecurityContext(req, appid, a_drawing_name);
+ afb_req_success(req, NULL, "success");
+ }
+ free(appid);
+ }
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
+ return;
+ }
+}
+
+void windowmanager_setrole(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+ try
+ {
+ json_object *jreq = afb_req_json(req);
+
+ json_object *j_role = nullptr;
+ if (!json_object_object_get_ex(jreq, "role", &j_role))
+ {
+ afb_req_fail(req, "failed", "Need char const* argument role");
+ return;
+ }
+ char const *a_role = json_object_get_string(j_role);
+ char *appid = afb_req_get_application_id(req);
+
+ if(appid)
+ {
+ auto ret = g_afb_instance->wmgr.api_set_role(appid, a_role);
+ if (!ret)
+ {
+ afb_req_fail(req, "failed", "Couldn't register");
+ }
+ else
+ {
+ createSecurityContext(req, appid, a_role);
+ afb_req_success(req, NULL, "success");
+ }
+ free(appid);
+ }
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
+ return;
+ }
+}
+
+void windowmanager_activatewindow(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ const char *a_drawing_name = afb_req_value(req, "drawing_name");
+ if (!a_drawing_name)
+ {
+ afb_req_fail(req, "failed", "Need char const* argument drawing_name");
+ return;
+ }
+
+ const char *a_drawing_area = afb_req_value(req, "drawing_area");
+ if (!a_drawing_area)
+ {
+ afb_req_fail(req, "failed", "Need char const* argument drawing_area");
+ return;
+ }
+
+ char* appid = afb_req_get_application_id(req);
+ if(appid)
+ {
+ auto reply = [&req](const char *errmsg) {
+ if (errmsg != nullptr)
+ {
+ HMI_ERROR(errmsg);
+ afb_req_fail(req, "failed", errmsg);
+ return;
+ }
+ afb_req_success(req, NULL, "success");
+ };
+
+ if (g_afb_instance->wmgr.wmcon.isMasterMode() ||
+ !g_afb_instance->wmgr.wmcon.isMasterArea(a_drawing_area))
+ {
+ g_afb_instance->wmgr.api_activate_surface(
+ appid, a_drawing_name, a_drawing_area, reply);
+ }
+ else
+ {
+ // TODO: temporarily
+ if (!g_afb_instance->wmgr.wmcon.isConnecting())
+ {
+ g_afb_instance->wmgr.wmcon.connectToMaster();
+ }
+
+ // If Window Manager is slave and this request is for master,
+ // request activateWindow to master
+ g_afb_instance->wmgr.api_activate_surface_to_master(
+ appid, a_drawing_name, a_drawing_area, reply);
+ }
+ free(appid);
+ }
+ }
+ catch (std::exception &e)
+ {
+ HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
+ g_afb_instance->wmgr.exceptionProcessForTransition();
+ return;
+ }
+}
+
+void windowmanager_deactivatewindow(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ const char *a_drawing_name = afb_req_value(req, "drawing_name");
+ if (!a_drawing_name)
+ {
+ afb_req_fail(req, "failed", "Need char const* argument drawing_name");
+ return;
+ }
+
+ char* appid = afb_req_get_application_id(req);
+ if(appid)
+ {
+ auto reply = [&req](const char *errmsg) {
+ if (errmsg != nullptr)
+ {
+ HMI_ERROR(errmsg);
+ afb_req_fail(req, "failed", errmsg);
+ return;
+ }
+ afb_req_success(req, NULL, "success");
+ };
+
+ // TODO: Check whether role is tbtnavi to request remote invisible
+ if (g_afb_instance->wmgr.wmcon.isMasterMode() ||
+ ("tbtnavi" != std::string(a_drawing_name)))
+ {
+ g_afb_instance->wmgr.api_deactivate_surface(
+ appid, a_drawing_name, reply);
+ }
+ else
+ {
+ // If Window Manager is slave and this request is for master,
+ // request deactivateWindow to master
+ g_afb_instance->wmgr.api_deactivate_surface_to_master(
+ appid, a_drawing_name, reply);
+ }
+ free(appid);
+ }
+ }
+ catch (std::exception &e)
+ {
+ HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
+ g_afb_instance->wmgr.exceptionProcessForTransition();
+ return;
+ }
+}
+
+void windowmanager_enddraw(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ const char *a_drawing_name = afb_req_value(req, "drawing_name");
+ if (!a_drawing_name)
+ {
+ afb_req_fail(req, "failed", "Need char const* argument drawing_name");
+ return;
+ }
+ afb_req_success(req, NULL, "success");
+
+ char* appid = afb_req_get_application_id(req);
+ if(appid)
+ {
+ if (g_afb_instance->wmgr.wmcon.isMasterMode() ||
+ !g_afb_instance->wmgr.wmcon.isSyncDrawingForRemote(appid))
+ {
+ g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
+ }
+ else
+ {
+ // If Window Manager is slave and requesting app is syncDrawing,
+ // request endDraw to master
+ g_afb_instance->wmgr.api_enddraw_for_remote(appid, a_drawing_name);
+ }
+ free(appid);
+ }
+ }
+ catch (std::exception &e)
+ {
+ HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
+ g_afb_instance->wmgr.exceptionProcessForTransition();
+ return;
+ }
+}
+
+void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ auto ret = g_afb_instance->wmgr.api_get_display_info();
+ if (ret.is_err())
+ {
+ afb_req_fail(req, "failed", ret.unwrap_err());
+ return;
+ }
+
+ afb_req_success(req, ret.unwrap(), "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
+ return;
+ }
+}
+
+void windowmanager_getareainfo_thunk(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ json_object *jreq = afb_req_json(req);
+
+ json_object *j_drawing_name = nullptr;
+ if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
+ {
+ afb_req_fail(req, "failed", "Need char const* argument drawing_name");
+ return;
+ }
+ char const *a_drawing_name = json_object_get_string(j_drawing_name);
+
+ auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
+ if (ret.is_err())
+ {
+ afb_req_fail(req, "failed", ret.unwrap_err());
+ return;
+ }
+
+ afb_req_success(req, ret.unwrap(), "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
+ return;
+ }
+}
+
+void windowmanager_getcarinfo_thunk(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ json_object *jreq = afb_req_json(req);
+
+ json_object *j_label = nullptr;
+ if (! json_object_object_get_ex(jreq, "label", &j_label))
+ {
+ afb_req_fail(req, "failed", "Need char const* argument label");
+ return;
+ }
+ char const* a_label = json_object_get_string(j_label);
+
+ auto ret = g_afb_instance->wmgr.api_get_car_info(a_label);
+ if (ret.is_err())
+ {
+ afb_req_fail(req, "failed", ret.unwrap_err());
+ return;
+ }
+
+ afb_req_success(req, ret.unwrap(), "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling getcarinfo: %s", e.what());
+ return;
+ }
+}
+
+void windowmanager_set_render_order(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ char* appid = afb_req_get_application_id(req);
+ if(appid)
+ {
+ json_object *jreq = afb_req_json(req);
+ json_object *j_ro; // Do not free this. binder frees jreq, then free j_ro
+ if (json_object_object_get_ex(jreq, "render_order", &j_ro))
+ {
+ int size = json_object_array_length(j_ro);
+ std::vector<std::string> ro(size);
+ for(int i = 0; i < size; i++)
+ {
+ ro[i] = json_object_get_string(json_object_array_get_idx(j_ro, i));
+ }
+
+ auto ret = g_afb_instance->wmgr.api_client_set_render_order(appid, ro);
+ if (!ret)
+ {
+ afb_req_fail(req, "failed", nullptr);
+ }
+ else
+ {
+ afb_req_success(req, nullptr, nullptr);
+ }
+ }
+ free(appid);
+ }
+ else
+ {
+ afb_req_fail(req, "failed", nullptr);
+ }
+}
+
+void windowmanager_attach_app(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ char* appid = afb_req_get_application_id(req);
+ if(appid)
+ {
+ json_object *jreq = afb_req_json(req);
+ json_object *j_dest, *j_id; // Do not free this. binder frees jreq, then free j_ro
+ if (json_object_object_get_ex(jreq, "destination", &j_dest) &&
+ json_object_object_get_ex(jreq, "service_surface", &j_id))
+ {
+ const char* dest_app = json_object_get_string(j_dest);
+ const char* service = json_object_get_string(j_id);
+
+ std::string uuid = g_afb_instance->wmgr.api_client_attach_service_surface(appid, dest_app, service);
+ if (uuid.empty())
+ {
+ afb_req_fail(req, "failed", nullptr);
+ }
+ else
+ {
+ json_object *resp = json_object_new_object();
+ json_object_object_add(resp, "uuid", json_object_new_string(uuid.c_str()));
+ afb_req_success(req, resp, nullptr);
+ }
+ }
+ free(appid);
+ }
+ else
+ {
+ afb_req_fail(req, "failed", nullptr);
+ }
+}
+
+void windowmanager_wm_subscribe(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ json_object *jreq = afb_req_json(req);
+ json_object *j = nullptr;
+ if (!json_object_object_get_ex(jreq, "event", &j))
+ {
+ afb_req_fail(req, "failed", "Need char const* argument event");
+ return;
+ }
+ int event_type = json_object_get_int(j);
+ const char *event_name = g_afb_instance->wmgr.kListEventName[event_type];
+ struct afb_event event = g_afb_instance->wmgr.map_afb_event[event_name];
+ int ret = afb_req_subscribe(req, event);
+ if (ret)
+ {
+ afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
+ return;
+ }
+ afb_req_success(req, NULL, "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
+ return;
+ }
+}
+
+void windowmanager_list_drawing_names(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ /* if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+
+ nlohmann::json j = g_afb_instance->wmgr.id_alloc.name2id;
+ auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
+ if (ret.is_err())
+ {
+ afb_req_fail(req, "failed", ret.unwrap_err());
+ return;
+ }
+
+ afb_req_success(req, ret.unwrap(), "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
+ return;
+ } */
+}
+
+void windowmanager_ping(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+ else
+ {
+ afb_req_success(req, NULL, "success");
+ }
+}
+
+void windowmanager_debug_status(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ /* if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+
+ json_object *jr = json_object_new_object();
+ json_object_object_add(jr, "surfaces",
+ to_json(g_afb_instance->wmgr.controller->sprops));
+ json_object_object_add(jr, "layers", to_json(g_afb_instance->wmgr.controller->lprops));
+
+ afb_req_success(req, jr, "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
+ return;
+ } */
+}
+
+void windowmanager_debug_layers(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ /* if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+ auto ret = wm::Ok(json_tokener_parse(g_afb_instance->wmgr.layers.to_json().dump().c_str()));
+
+ afb_req_success(req, ret, "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
+ return;
+ } */
+}
+
+void windowmanager_debug_surfaces(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ /* if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+
+ auto ret = wm::Ok(to_json(g_afb_instance->wmgr.controller->sprops));
+ if (ret.is_err())
+ {
+ afb_req_fail(req, "failed", ret.unwrap_err());
+ return;
+ }
+
+ afb_req_success(req, ret.unwrap(), "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
+ return;
+ } */
+}
+
+void windowmanager_debug_terminate(afb_req req) noexcept
+{
+ std::lock_guard<std::mutex> guard(binding_m);
+
+ if (g_afb_instance == nullptr)
+ {
+ afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
+ return;
+ }
+
+ try
+ {
+
+ if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
+ {
+ raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
+ // doesn't play well with perf
+ }
+
+ afb_req_success(req, NULL, "success");
+ }
+ catch (std::exception &e)
+ {
+ afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
+ return;
+ }
+}
+
+void on_event(const char *event, struct json_object *object)
+{
+ g_afb_instance->wmgr.analyzeReceivedEvent(event, object);
+}
+
+const struct afb_verb_v2 windowmanager_verbs[] = {
+ {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
+ {"requestSurfaceXdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
+ {"setRole", windowmanager_setrole, nullptr, nullptr, AFB_SESSION_NONE},
+ {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
+ {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
+ {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
+ {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
+ {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
+ {"getCarInfo", windowmanager_getcarinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE },
+ {"setRenderOrder", windowmanager_set_render_order, nullptr, nullptr, AFB_SESSION_NONE},
+ {"attachApp", windowmanager_attach_app, nullptr, nullptr, AFB_SESSION_NONE},
+ {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
+ {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
+ {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
+ {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
+ {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
+ {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
+ {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
+ {}};
+
+extern "C" const struct afb_binding_v2 afbBindingV2 = {
+ "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, on_event, 0};
diff --git a/demo#3/common/agl-service-windowmanager/src/pm_wrapper.cpp b/demo#3/common/agl-service-windowmanager/src/pm_wrapper.cpp
new file mode 100644
index 0000000..7cf90f0
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/pm_wrapper.cpp
@@ -0,0 +1,439 @@
+/*
+ * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "pm_wrapper.hpp"
+#include "json_helper.hpp"
+#include "util.hpp"
+
+namespace wm
+{
+
+static PMWrapper *g_context;
+
+namespace
+{
+
+static void onStateTransitioned(json_object *json_out)
+{
+ g_context->updateStates(json_out);
+}
+
+static void onError(json_object *json_out)
+{
+ HMI_DEBUG("error message from PolicyManager:%s",
+ json_object_get_string(json_out));
+
+ g_context->processError();
+}
+
+} // namespace
+
+PMWrapper::PMWrapper() {}
+
+int PMWrapper::initialize(std::string ecu_name)
+{
+ int ret = 0;
+
+ ret = this->pm.initialize(ecu_name);
+ if (0 > ret)
+ {
+ HMI_ERROR("wm:pmw", "Faild to initialize PolicyManager");
+ }
+
+ g_context = this;
+
+ return ret;
+}
+
+void PMWrapper::registerCallback(StateTransitionHandler on_state_transitioned,
+ ErrorHandler on_error)
+{
+ this->on_state_transitioned = on_state_transitioned;
+ this->on_error = on_error;
+
+ PolicyManager::CallbackTable my_callback;
+ my_callback.onStateTransitioned = onStateTransitioned;
+ my_callback.onError = onError;
+ this->pm.registerCallback(my_callback);
+}
+
+int PMWrapper::setInputEventData(Task task, std::string role, std::string area)
+{
+ const char* event;
+ if (Task::TASK_ALLOCATE == task)
+ {
+ event = "activate";
+ }
+ else if (Task::TASK_RELEASE == task)
+ {
+ event = "deactivate";
+ }
+ else if (Task::TASK_PARKING_BRAKE_OFF == task)
+ {
+ event = "parking_brake_off";
+ }
+ else if (Task::TASK_PARKING_BRAKE_ON == task)
+ {
+ event = "parking_brake_on";
+ }
+ else if (Task::TASK_ACCEL_PEDAL_OFF == task)
+ {
+ event = "accel_pedal_off";
+ }
+ else if (Task::TASK_ACCEL_PEDAL_ON == task)
+ {
+ event = "accel_pedal_on";
+ }
+ else if (Task::TASK_HEDLAMP_OFF == task)
+ {
+ event = "headlamp_off";
+ }
+ else if (Task::TASK_HEDLAMP_ON == task)
+ {
+ event = "headlamp_on";
+ }
+ else if (Task::TASK_LIGHTSTATUS_BRAKE_OFF == task)
+ {
+ event = "lightstatus_brake_off";
+ }
+ else if (Task::TASK_LIGHTSTATUS_BRAKE_ON == task)
+ {
+ event = "lightstatus_brake_on";
+ }
+ else
+ {
+ event = "";
+ }
+
+ json_object *json_in = json_object_new_object();
+ json_object_object_add(json_in, "event", json_object_new_string(event));
+ json_object_object_add(json_in, "role", json_object_new_string(role.c_str()));
+ json_object_object_add(json_in, "area", json_object_new_string(area.c_str()));
+
+ int ret;
+ ret = this->pm.setInputEventData(json_in);
+ if (0 > ret)
+ {
+ HMI_ERROR("wm:pmw", "Faild to set input event data to PolicyManager");
+ }
+ json_object_put(json_in);
+
+ return ret;
+}
+
+int PMWrapper::executeStateTransition()
+{
+ int ret;
+ ret = this->pm.executeStateTransition();
+ if (0 > ret)
+ {
+ HMI_ERROR("wm:pmw", "Failed to execute state transition for PolicyManager");
+ }
+
+ return ret;
+}
+
+void PMWrapper::undoState()
+{
+ this->pm.undoState();
+
+ this->crrlayer2rolestate = this->prvlayer2rolestate;
+}
+
+void PMWrapper::updateStates(json_object *json_out)
+{
+ std::vector<WMAction> actions;
+
+ HMI_DEBUG("json_out dump:%s", json_object_get_string(json_out));
+
+ this->createCarStateChangeAction(json_out, actions);
+ this->createLayoutChangeAction(json_out, actions);
+
+ this->on_state_transitioned(actions);
+}
+
+void PMWrapper::createCarStateChangeAction(json_object *json_out, std::vector<WMAction> &actions)
+{
+ json_object *json_car_ele;
+ if (!json_object_object_get_ex(json_out, "car_elements", &json_car_ele))
+ {
+ HMI_DEBUG("Not found key \"car_elements\"");
+ return;
+ }
+
+ int len = json_object_array_length(json_car_ele);
+ HMI_DEBUG("json_car_ele len:%d", len);
+
+ for (int i = 0; i < len; i++)
+ {
+ json_object *json_tmp = json_object_array_get_idx(json_car_ele, i);
+
+ std::string car_ele_name = jh::getStringFromJson(json_tmp, "name");
+ std::string state = jh::getStringFromJson(json_tmp, "state");
+ json_bool changed = jh::getBoolFromJson(json_tmp, "changed");
+ HMI_DEBUG("car_element:%s changed:%d", car_ele_name.c_str(), changed);
+
+ if (changed)
+ {
+ TaskCarState task = TaskCarState::NO_TASK;
+ if ("parking_brake" == car_ele_name)
+ {
+ if ("off" == state)
+ {
+ task = TaskCarState::PARKING_BRAKE_OFF;
+ }
+ else if ("on" == state)
+ {
+ task = TaskCarState::PARKING_BRAKE_ON;
+ }
+ else
+ {
+ HMI_DEBUG("Unknown parking brake state: %s", state.c_str());
+ }
+ }
+ else if ("accel_pedal" == car_ele_name)
+ {
+ if ("off" == state)
+ {
+ task = TaskCarState::ACCEL_PEDAL_OFF;
+ }
+ else if ("on" == state)
+ {
+ task = TaskCarState::ACCEL_PEDAL_ON;
+ }
+ else
+ {
+ HMI_DEBUG("Unknown accel pedal state: %s", state.c_str());
+ }
+ }
+ else if ("lamp" == car_ele_name)
+ {
+ if ("off" == state)
+ {
+ task = TaskCarState::HEDLAMP_OFF;
+ }
+ else if ("on" == state)
+ {
+ task = TaskCarState::HEDLAMP_ON;
+ }
+ else
+ {
+ HMI_DEBUG("Unknown lamp state: %s", state.c_str());
+ }
+ }
+ else if ("lightstatus_brake" == car_ele_name)
+ {
+ if ("off" == state)
+ {
+ task = TaskCarState::LIGHTSTATUS_BRAKE_OFF;
+ }
+ else if ("on" == state)
+ {
+ task = TaskCarState::LIGHTSTATUS_BRAKE_ON;
+ }
+ else
+ {
+ HMI_DEBUG("Unknown lightstatus brake state: %s", state.c_str());
+ }
+ }
+ else if ("running" == car_ele_name)
+ {
+ if ("stop" == state)
+ {
+ task = TaskCarState::CAR_STOP;
+ }
+ else if ("run" == state)
+ {
+ task = TaskCarState::CAR_RUN;
+ }
+ else
+ {
+ HMI_DEBUG("Unknown car state: %s", state.c_str());
+ }
+ }
+ else if ("restriction_mode" == car_ele_name)
+ {
+ if ("off" == state)
+ {
+ task = TaskCarState::RESTRICTION_MODE_OFF;
+ }
+ else if ("on" == state)
+ {
+ task = TaskCarState::RESTRICTION_MODE_ON;
+ }
+ else
+ {
+ HMI_DEBUG("Unknown car state: %s", state.c_str());
+ }
+ }
+ else
+ {
+ HMI_DEBUG("Unknown car element: %s", car_ele_name.c_str());
+ }
+
+ // Set action
+ if (TaskCarState::NO_TASK != task)
+ {
+ bool end_draw_finished = true;
+ WMAction act
+ {
+ 0,
+ nullptr,
+ "",
+ "",
+ TaskVisible::NO_CHANGE,
+ end_draw_finished,
+ task
+ };
+ actions.push_back(act);
+ }
+ }
+ }
+}
+
+void PMWrapper::createLayoutChangeAction(json_object *json_out, std::vector<WMAction> &actions)
+{
+ // Get displayed roles from previous layout
+ json_object *json_layers;
+ if (!json_object_object_get_ex(json_out, "layers", &json_layers))
+ {
+ HMI_DEBUG("Not found key \"layers\"");
+ return;
+ }
+
+ int len = json_object_array_length(json_layers);
+ HMI_DEBUG("json_layers len:%d", len);
+
+ for (int i = 0; i < len; i++)
+ {
+ json_object *json_tmp = json_object_array_get_idx(json_layers, i);
+
+ std::string layer_name = jh::getStringFromJson(json_tmp, "name");
+ json_bool changed = jh::getBoolFromJson(json_tmp, "changed");
+ HMI_DEBUG("layer:%s changed:%d", layer_name.c_str(), changed);
+
+ if (changed)
+ {
+ json_object *json_areas;
+ if (!json_object_object_get_ex(json_tmp, "areas", &json_areas))
+ {
+ HMI_DEBUG("Not found key \"areas\"");
+ return;
+ }
+
+ int len = json_object_array_length(json_areas);
+ HMI_DEBUG("json_layers len:%d", len);
+
+ // Store previous role state in this layer
+ this->prvlayer2rolestate[layer_name] = this->crrlayer2rolestate[layer_name];
+
+ RoleState crr_roles;
+ RoleState prv_roles = this->prvlayer2rolestate[layer_name];
+ for (int j = 0; j < len; j++)
+ {
+ json_object *json_tmp2 = json_object_array_get_idx(json_areas, j);
+
+ std::string area_name = jh::getStringFromJson(json_tmp2, "name");
+ std::string role_name = jh::getStringFromJson(json_tmp2, "role");
+
+ crr_roles[role_name] = area_name;
+
+ auto i_prv = prv_roles.find(role_name);
+ HMI_DEBUG("current role:%s area:%s",
+ role_name.c_str(), area_name.c_str());
+
+ // If current role does not exist in previous
+ if (prv_roles.end() == i_prv)
+ {
+ HMI_DEBUG("current role does not exist in previous");
+
+ // Set activate action
+ bool end_draw_finished = false;
+ WMAction act
+ {
+ 0,
+ nullptr,
+ role_name,
+ area_name,
+ TaskVisible::VISIBLE,
+ end_draw_finished,
+ TaskCarState::NO_TASK
+ };
+ actions.push_back(act);
+ }
+ else
+ {
+ HMI_DEBUG("previous role:%s area:%s",
+ i_prv->first.c_str(), i_prv->second.c_str());
+
+ // If current role exists in previous and area is different with previous
+ if (area_name != i_prv->second)
+ {
+ HMI_DEBUG("current role exists in previous and area is different with previous");
+
+ // Set activate action
+ bool end_draw_finished = false;
+ WMAction act
+ {
+ 0,
+ nullptr,
+ role_name,
+ area_name,
+ TaskVisible::VISIBLE,
+ end_draw_finished,
+ TaskCarState::NO_TASK
+ };
+ actions.push_back(act);
+ }
+
+ // Remove role which exist in current list from previous list
+ prv_roles.erase(i_prv);
+ }
+ }
+
+ // Deactivate roles which remains in previous list
+ // because these are not displayed in current layout
+ for (auto i_prv : prv_roles)
+ {
+ HMI_DEBUG("Deactivate role:%s", i_prv.first.c_str());
+
+ // Set deactivate action
+ bool end_draw_finished = true;
+ WMAction act
+ {
+ 0,
+ nullptr,
+ i_prv.first,
+ "",
+ TaskVisible::INVISIBLE,
+ end_draw_finished,
+ TaskCarState::NO_TASK
+ };
+ actions.push_back(act);
+ }
+
+ // Update previous role list
+ this->crrlayer2rolestate[layer_name] = crr_roles;
+ }
+ }
+}
+
+void PMWrapper::processError()
+{
+ this->on_error();
+}
+
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/pm_wrapper.hpp b/demo#3/common/agl-service-windowmanager/src/pm_wrapper.hpp
new file mode 100644
index 0000000..84d68df
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/pm_wrapper.hpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2018 TOYOTA MOTOR CORPORATION
+ *
+ * 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_PM_WRAPPER_HPP
+#define TMCAGLWM_PM_WRAPPER_HPP
+
+#include <functional>
+#include <vector>
+#include <string>
+#include <map>
+#include "policy_manager.hpp"
+#include "request.hpp"
+
+struct json_object;
+struct sd_event;
+struct sd_event_source;
+struct StmState;
+
+namespace wm
+{
+
+class PMWrapper
+{
+ public:
+ explicit PMWrapper();
+ ~PMWrapper() = default;
+
+ using StateTransitionHandler = std::function<void(std::vector<WMAction>)>;
+ using ErrorHandler = std::function<void(void)>;
+
+ int initialize(std::string ecu_name);
+ void registerCallback(StateTransitionHandler on_state_transitioned,
+ ErrorHandler on_error);
+ int setInputEventData(Task task, std::string role, std::string area);
+ int executeStateTransition();
+ void undoState();
+
+ // Do not use these functions
+ void updateStates(json_object *json_out);
+ void processError();
+
+ private:
+ // Disable copy and move
+ PMWrapper(PMWrapper const &) = delete;
+ PMWrapper &operator=(PMWrapper const &) = delete;
+ PMWrapper(PMWrapper &&) = delete;
+ PMWrapper &operator=(PMWrapper &&) = delete;
+
+ typedef std::map<std::string, std::string> RoleState;
+
+ PolicyManager pm;
+ StateTransitionHandler on_state_transitioned;
+ ErrorHandler on_error;
+ std::map<std::string, RoleState> prvlayer2rolestate;
+ std::map<std::string, RoleState> crrlayer2rolestate;
+
+ void createCarStateChangeAction(json_object *json_out, std::vector<WMAction> &actions);
+ void createLayoutChangeAction(json_object *json_out, std::vector<WMAction> &actions);
+};
+
+} // namespace wm
+
+#endif // TMCAGLWM_PM_WRAPPER_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/request.cpp b/demo#3/common/agl-service-windowmanager/src/request.cpp
new file mode 100644
index 0000000..0d8e5d4
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/request.cpp
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "request.hpp"
+
+namespace wm
+{
+
+using std::string;
+
+WMRequest::WMRequest() {}
+
+WMRequest::WMRequest(string appid, string role, string area, Task task)
+ : req_num(0),
+ trigger{appid, role, area, task},
+ sync_draw_req(0)
+{
+}
+
+WMRequest::WMRequest(Task task)
+ : req_num(0),
+ trigger{"", "", "", task},
+ sync_draw_req(0)
+{
+}
+
+WMRequest::~WMRequest()
+{
+}
+
+WMRequest::WMRequest(const WMRequest &obj)
+{
+ this->req_num = obj.req_num;
+ this->trigger = obj.trigger;
+ this->sync_draw_req = obj.sync_draw_req;
+}
+
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/request.hpp b/demo#3/common/agl-service-windowmanager/src/request.hpp
new file mode 100644
index 0000000..bb203e3
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/request.hpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 WMREQUEST_HPP
+#define WMREQUEST_HPP
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace wm
+{
+
+class WMClient;
+
+enum Task
+{
+ TASK_ALLOCATE,
+ TASK_RELEASE,
+ TASK_PARKING_BRAKE_OFF,
+ TASK_PARKING_BRAKE_ON,
+ TASK_ACCEL_PEDAL_OFF,
+ TASK_ACCEL_PEDAL_ON,
+ TASK_HEDLAMP_OFF,
+ TASK_HEDLAMP_ON,
+ TASK_LIGHTSTATUS_BRAKE_OFF,
+ TASK_LIGHTSTATUS_BRAKE_ON,
+ TASK_RESTRICTION_MODE_OFF,
+ TASK_RESTRICTION_MODE_ON,
+ TASK_INVALID
+};
+
+enum TaskVisible
+{
+ VISIBLE,
+ INVISIBLE,
+ REQ_REMOTE_VISIBLE,
+ REQ_REMOTE_INVISIBLE,
+ REMOTE_VISIBLE,
+ REMOTE_INVISIBLE,
+ NO_CHANGE
+};
+
+enum TaskCarState
+{
+ PARKING_BRAKE_OFF,
+ PARKING_BRAKE_ON,
+ ACCEL_PEDAL_OFF,
+ ACCEL_PEDAL_ON,
+ HEDLAMP_OFF,
+ HEDLAMP_ON,
+ LIGHTSTATUS_BRAKE_OFF,
+ LIGHTSTATUS_BRAKE_ON,
+ CAR_STOP,
+ CAR_RUN,
+ RESTRICTION_MODE_OFF,
+ RESTRICTION_MODE_ON,
+ NO_TASK,
+};
+
+struct WMTrigger
+{
+ std::string appid;
+ std::string role;
+ std::string area;
+ Task task;
+};
+
+struct WMAction
+{
+ unsigned req_num;
+ std::shared_ptr<WMClient> client;
+ std::string role;
+ std::string area;
+ TaskVisible visible;
+ bool end_draw_finished;
+ TaskCarState car_state;
+};
+
+struct WMRequest
+{
+ WMRequest();
+ explicit WMRequest(std::string appid, std::string role,
+ std::string area, Task task);
+ explicit WMRequest(Task task);
+ virtual ~WMRequest();
+ WMRequest(const WMRequest &obj);
+
+ unsigned req_num;
+ struct WMTrigger trigger;
+ std::vector<struct WMAction> sync_draw_req;
+};
+
+} // namespace wm
+
+#endif //WMREQUEST_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/result.hpp b/demo#3/common/agl-service-windowmanager/src/result.hpp
new file mode 100644
index 0000000..8a59a90
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/result.hpp
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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::nullopt;
+using std::experimental::optional;
+
+// 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/demo#3/common/agl-service-windowmanager/src/util.cpp b/demo#3/common/agl-service-windowmanager/src/util.cpp
new file mode 100644
index 0000000..b22a704
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/util.cpp
@@ -0,0 +1,172 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <sstream>
+#include <time.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#include <unistd.h>
+
+static char ERROR_FLAG[6][20] = {"NONE", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"};
+
+void rectangle::fit(unsigned long to_width, unsigned long to_height)
+{
+ // fit rect within (to_width x to_height)
+
+ if (to_width <= width()) {
+ // scale to fit with
+ set_bottom(top() + (static_cast<long>(to_width) * height() / width()) - 1);
+ set_right(left() + to_width - 1);
+ } else {
+ // scale to fit height
+ set_right(left() + (static_cast<long>(to_height) * width () / height()) - 1);
+ set_bottom(top() + to_height - 1);
+ }
+}
+
+void rectangle::center(unsigned long outer_w, unsigned long outer_h)
+{
+ long inner_w = width();
+ long inner_h = height();
+
+ set_left((outer_w - inner_w) / 2);
+ set_right(left() + inner_w - 1);
+ set_top((outer_h - inner_h) / 2);
+ set_bottom(top() + inner_h - 1);
+}
+
+void rectangle::set_aspect(double ratio)
+{
+ // aspect ratio is width:height (= width/height)
+ // e.g. Landscape of HD's ratio is 16:9 (= 1.777...)
+ // Portrait of HD's ratio is 9:16 (= 0.5625)
+ //
+ // width / height = ratio
+ // width * height = area
+ //
+ // width = sqrt(ratio * area)
+ // height = width / ratio
+
+ long orig_w = width();
+ long orig_h = height();
+
+ if (ratio >= 1) {
+ // width >= height
+ // try to keep width
+ set_right(left() + orig_w - 1);
+ set_bottom(top() + static_cast<long>(orig_w / ratio + 0.5) - 1);
+ } else {
+ set_bottom(top() + orig_h - 1);
+ set_right(left() + static_cast<long>(orig_h * ratio + 0.5) - 1);
+ }
+}
+
+void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, const char* prefix, const char* log, ...)
+{
+ const int log_level = (getenv("USE_HMI_DEBUG") == NULL)?LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG"));
+ if(log_level < level)
+ {
+ return;
+ }
+
+ char *message;
+ struct timespec tp;
+ unsigned int time;
+
+ clock_gettime(CLOCK_REALTIME, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ va_list args;
+ va_start(args, log);
+ if (log == NULL || vasprintf(&message, log, args) < 0)
+ message = NULL;
+ fprintf(stderr, "[%10.3f] [%s %s] [%s, %s(), Line:%d] >>> %s \n", time / 1000.0, prefix, ERROR_FLAG[level], file, func, line, message);
+ va_end(args);
+ free(message);
+}
+
+void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...){
+ const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR:atoi(getenv("USE_HMI_DEBUG"));
+ if(log_level < level)
+ {
+ return;
+ }
+
+ char *message;
+ struct timespec tp;
+ unsigned int time;
+
+ clock_gettime(CLOCK_REALTIME, &tp);
+ time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+ va_list args;
+ va_start(args, log);
+ if (log == NULL || vasprintf(&message, log, args) < 0)
+ message = NULL;
+ fprintf(stderr, "[%10.3f] [wm %s] [%s, %s(), Line:%d] >>> req %d: %s \n", time / 1000.0, ERROR_FLAG[level], file, func, line, seq_num, message);
+ va_end(args);
+ free(message);
+}
+
+void _DUMP(enum LOG_LEVEL level, const char *log, ...)
+{
+ const int log_level = (getenv("USE_HMI_DEBUG") == NULL) ? LOG_LEVEL_ERROR : atoi(getenv("USE_HMI_DEBUG"));
+ if (log_level < level)
+ {
+ return;
+ }
+ char *message;
+ va_list args;
+ va_start(args, log);
+ if (log == NULL || vasprintf(&message, log, args) < 0)
+ message = NULL;
+ fprintf(stderr, "%s \n", message);
+ va_end(args);
+ free(message);
+}
+
+std::vector<std::string> parseString(std::string str, char delimiter)
+{
+ // Parse string by delimiter
+ std::vector<std::string> vct;
+ std::stringstream ss{str};
+ std::string buf;
+ while (std::getline(ss, buf, delimiter))
+ {
+ if (!buf.empty())
+ {
+ // Delete space and push back to vector
+ vct.push_back(deleteSpace(buf));
+ }
+ }
+ return vct;
+}
+
+std::string deleteSpace(std::string str)
+{
+ std::string ret = str;
+ size_t pos;
+ while ((pos = ret.find_first_of(" ")) != std::string::npos)
+ {
+ ret.erase(pos, 1);
+ }
+ return ret;
+}
+
diff --git a/demo#3/common/agl-service-windowmanager/src/util.hpp b/demo#3/common/agl-service-windowmanager/src/util.hpp
new file mode 100644
index 0000000..d049fff
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/util.hpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <string>
+#include <vector>
+#include <sys/poll.h>
+#include <string.h>
+
+#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+
+#define HMI_ERROR(args,...) _HMI_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__,"wm",args, ##__VA_ARGS__)
+#define HMI_WARNING(args,...) _HMI_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__,__LINE__, "wm", args,##__VA_ARGS__)
+#define HMI_NOTICE(args,...) _HMI_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__,__LINE__, "wm", args,##__VA_ARGS__)
+#define HMI_INFO(args,...) _HMI_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__,__LINE__, "wm", args,##__VA_ARGS__)
+#define HMI_DEBUG(args,...) _HMI_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__,__LINE__, "wm", args,##__VA_ARGS__)
+
+#define HMI_SEQ_ERROR(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_ERROR, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
+#define HMI_SEQ_WARNING(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_WARNING, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
+#define HMI_SEQ_NOTICE(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_NOTICE, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
+#define HMI_SEQ_INFO(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
+#define HMI_SEQ_DEBUG(seq_num, args,...) _HMI_SEQ_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__, __LINE__, seq_num, args, ##__VA_ARGS__)
+
+#define DUMP(args, ...) _DUMP(LOG_LEVEL_DEBUG, args, ##__VA_ARGS__)
+
+enum LOG_LEVEL{
+ LOG_LEVEL_NONE = 0,
+ LOG_LEVEL_ERROR,
+ LOG_LEVEL_WARNING,
+ LOG_LEVEL_NOTICE,
+ LOG_LEVEL_INFO,
+ LOG_LEVEL_DEBUG,
+ LOG_LEVEL_MAX = LOG_LEVEL_DEBUG
+};
+
+void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, const char* prefix, const char* log, ...);
+void _HMI_SEQ_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, unsigned seq_num, const char* log, ...);
+void _DUMP(enum LOG_LEVEL level, const char *log, ...);
+
+std::vector<std::string> parseString(std::string str, char delimiter);
+std::string deleteSpace(std::string str);
+
+struct rect
+{
+ int32_t w, h;
+ int32_t x, y;
+};
+
+struct size
+{
+ uint32_t w, h;
+};
+
+class rectangle
+{
+ public:
+ explicit rectangle(long wd, long ht) : _right(wd - 1), _bottom(ht - 1) {};
+
+ void set_left(long l) {
+ _left = l;
+ }
+ long left() const { return _left; };
+
+ void set_right(long r) {
+ _right = r;
+ }
+ long right() const { return _right; };
+
+ void set_top(long t) {
+ _top = t;
+ }
+ long top() const { return _top; };
+
+ void set_bottom(long b) {
+ _bottom = b;
+ }
+ long bottom() const { return _bottom; }
+
+ long width() const {
+ if (is_valid())
+ return 0;
+ else
+ return _right - _left + 1;
+ }
+
+ long height() const {
+ if (is_valid())
+ return 0;
+ else
+ return _bottom - _top + 1;
+ }
+
+ void set_aspect(double ratio);
+ void fit(unsigned long to_width, unsigned long to_height);
+ void center(unsigned long outer_w, unsigned long outer_h);
+
+ private:
+ bool is_valid() const {
+ return (_top > _bottom || _left > _right);
+ }
+
+ long _left = 0;
+ long _top = 0;
+ long _right;
+ long _bottom;
+};
+
+#endif // !WM_UTIL_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/wayland_ivi_wm.cpp b/demo#3/common/agl-service-windowmanager/src/wayland_ivi_wm.cpp
new file mode 100644
index 0000000..28bd024
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wayland_ivi_wm.cpp
@@ -0,0 +1,724 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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_ivi_wm.hpp"
+
+/**
+ * namespace wl
+ */
+namespace wl
+{
+
+/**
+ * display
+ */
+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()
+{
+ ;
+ while (wl_display_prepare_read(this->d.get()) == -1)
+ {
+ 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()); }
+
+/**
+ * registry
+ */
+namespace
+{
+void registry_global_created(void *data, struct wl_registry * /*r*/, uint32_t name,
+ char const *iface, uint32_t v)
+{
+ static_cast<struct registry *>(data)->global_created(name, iface, v);
+}
+
+void registry_global_removed(void *data, struct wl_registry * /*r*/,
+ uint32_t name)
+{
+ static_cast<struct registry *>(data)->global_removed(name);
+}
+
+constexpr struct wl_registry_listener registry_listener = {
+ registry_global_created, registry_global_removed};
+} // 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_created(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);
+ }
+ HMI_DEBUG("wl::registry @ %p global n %u i %s v %u", this->proxy.get(), name,
+ iface, v);
+}
+
+void registry::global_removed(uint32_t /*name*/) {}
+
+/**
+ * output
+ */
+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)
+{
+ HMI_DEBUG("wm",
+ "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->physical_width = pw;
+ this->physical_height = ph;
+ this->transform = tx;
+}
+
+void output::mode(uint32_t flags, int32_t w, int32_t h, int32_t r)
+{
+ HMI_DEBUG("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()
+{
+ HMI_DEBUG("wl::output %s @ %p done", __func__, this->proxy.get());
+ // Pivot and flipped
+ if (this->transform == WL_OUTPUT_TRANSFORM_90 ||
+ this->transform == WL_OUTPUT_TRANSFORM_270 ||
+ this->transform == WL_OUTPUT_TRANSFORM_FLIPPED_90 ||
+ this->transform == WL_OUTPUT_TRANSFORM_FLIPPED_270)
+ {
+ std::swap(this->width, this->height);
+ std::swap(this->physical_width, this->physical_height);
+ }
+}
+
+void output::scale(int32_t factor)
+{
+ HMI_DEBUG("wl::output %s @ %p f %i", __func__, this->proxy.get(), factor);
+}
+} // namespace wl
+
+/**
+ * namespace compositor
+ */
+namespace compositor
+{
+
+namespace
+{
+
+void surface_visibility_changed(
+ void *data, struct ivi_wm * /*ivi_wm*/,
+ uint32_t surface_id, int32_t visibility)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->surface_visibility_changed(surface_id, visibility);
+}
+
+void surface_opacity_changed(void *data, struct ivi_wm * /*ivi_wm*/,
+ uint32_t surface_id, wl_fixed_t opacity)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->surface_opacity_changed(surface_id, float(wl_fixed_to_double(opacity)));
+}
+
+void surface_source_rectangle_changed(
+ void *data, struct ivi_wm * /*ivi_wm*/, uint32_t surface_id,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->surface_source_rectangle_changed(surface_id, x, y, width, height);
+}
+
+void surface_destination_rectangle_changed(
+ void *data, struct ivi_wm * /*ivi_wm*/, uint32_t surface_id,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->surface_destination_rectangle_changed(surface_id, x, y, width, height);
+}
+
+void surface_created(void *data, struct ivi_wm * /*ivi_wm*/,
+ uint32_t id_surface)
+{
+ static_cast<struct controller *>(data)->surface_created(id_surface);
+}
+
+void surface_destroyed(
+ void *data, struct ivi_wm * /*ivi_wm*/, uint32_t surface_id)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->surface_destroyed(surface_id);
+}
+
+void surface_error_detected(void *data, struct ivi_wm * /*ivi_wm*/, uint32_t object_id,
+ uint32_t error_code, const char *error_text)
+{
+ static_cast<struct controller *>(data)->surface_error_detected(
+ object_id, error_code, error_text);
+}
+
+void surface_size_changed(
+ void *data, struct ivi_wm * /*ivi_wm*/, uint32_t surface_id,
+ int32_t width, int32_t height)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->surface_size_changed(surface_id, width, height);
+}
+
+void surface_stats_received(void *data, struct ivi_wm * /*ivi_wm*/,
+ uint32_t surface_id, uint32_t frame_count, uint32_t pid)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->surface_stats_received(surface_id, frame_count, pid);
+}
+
+void surface_added_to_layer(void *data, struct ivi_wm * /*ivi_wm*/,
+ uint32_t layer_id, uint32_t surface_id)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->surface_added_to_layer(layer_id, surface_id);
+}
+
+void layer_visibility_changed(void *data, struct ivi_wm * /*ivi_wm*/,
+ uint32_t layer_id, int32_t visibility)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->layer_visibility_changed(layer_id, visibility);
+}
+
+void layer_opacity_changed(void *data, struct ivi_wm * /*ivi_wm*/,
+ uint32_t layer_id, wl_fixed_t opacity)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->layer_opacity_changed(layer_id, float(wl_fixed_to_double(opacity)));
+}
+
+void layer_source_rectangle_changed(
+ void *data, struct ivi_wm * /*ivi_wm*/, uint32_t layer_id,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->layer_source_rectangle_changed(layer_id, x, y, width, height);
+}
+
+void layer_destination_rectangle_changed(
+ void *data, struct ivi_wm * /*ivi_wm*/, uint32_t layer_id,
+ int32_t x, int32_t y, int32_t width, int32_t height)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->layer_destination_rectangle_changed(layer_id, x, y, width, height);
+}
+
+void layer_created(void *data, struct ivi_wm * /*ivi_wm*/,
+ uint32_t id_layer)
+{
+ static_cast<struct controller *>(data)->layer_created(id_layer);
+}
+
+void layer_destroyed(void *data, struct ivi_wm * /*ivi_wm*/, uint32_t layer_id)
+{
+ auto c = static_cast<struct controller *>(data);
+ c->layer_destroyed(layer_id);
+}
+
+void layer_error_detected(void *data, struct ivi_wm * /*ivi_wm*/, uint32_t object_id,
+ uint32_t error_code, const char *error_text)
+{
+ static_cast<struct controller *>(data)->layer_error_detected(
+ object_id, error_code, error_text);
+}
+
+constexpr struct ivi_wm_listener listener = {
+ surface_visibility_changed,
+ layer_visibility_changed,
+ surface_opacity_changed,
+ layer_opacity_changed,
+ surface_source_rectangle_changed,
+ layer_source_rectangle_changed,
+ surface_destination_rectangle_changed,
+ layer_destination_rectangle_changed,
+ surface_created,
+ layer_created,
+ surface_destroyed,
+ layer_destroyed,
+ surface_error_detected,
+ layer_error_detected,
+ surface_size_changed,
+ surface_stats_received,
+ surface_added_to_layer,
+};
+
+void screen_created(void *data, struct ivi_wm_screen *ivi_wm_screen, uint32_t id)
+{
+ static_cast<struct screen *>(data)->screen_created((struct screen *)data, id);
+}
+
+void layer_added(void *data,
+ struct ivi_wm_screen *ivi_wm_screen,
+ uint32_t layer_id)
+{
+ HMI_DEBUG("added layer_id:%d", layer_id);
+}
+
+void connector_name(void *data,
+ struct ivi_wm_screen *ivi_wm_screen,
+ const char *process_name)
+{
+ HMI_DEBUG("process_name:%s", process_name);
+}
+
+void screen_error(void *data,
+ struct ivi_wm_screen *ivi_wm_screen,
+ uint32_t error,
+ const char *message)
+{
+ HMI_DEBUG("screen error:%d message:%s", error, message);
+}
+
+constexpr struct ivi_wm_screen_listener screen_listener = {
+ screen_created,
+ layer_added,
+ connector_name,
+ screen_error,
+};
+} // namespace
+
+/**
+ * surface
+ */
+surface::surface(uint32_t i, struct controller *c)
+ : controller_child(c, i)
+{
+ this->parent->add_proxy_to_sid_mapping(this->parent->proxy.get(), i);
+}
+
+void surface::set_visibility(uint32_t visibility)
+{
+ HMI_DEBUG("compositor::surface id:%d v:%d", this->id, visibility);
+ ivi_wm_set_surface_visibility(this->parent->proxy.get(), this->id, visibility);
+}
+
+void surface::set_source_rectangle(int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ ivi_wm_set_surface_source_rectangle(this->parent->proxy.get(), this->id,
+ x, y, width, height);
+}
+
+void surface::set_destination_rectangle(int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ ivi_wm_set_surface_destination_rectangle(this->parent->proxy.get(), this->id,
+ x, y, width, height);
+}
+
+/**
+ * layer
+ */
+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)
+ : controller_child(c, i)
+{
+ this->parent->add_proxy_to_lid_mapping(this->parent->proxy.get(), i);
+ ivi_wm_create_layout_layer(c->proxy.get(), i, w, h);
+}
+
+void layer::set_visibility(uint32_t visibility)
+{
+ ivi_wm_set_layer_visibility(this->parent->proxy.get(), this->id, visibility);
+}
+
+void layer::set_destination_rectangle(int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ ivi_wm_set_layer_destination_rectangle(this->parent->proxy.get(), this->id,
+ x, y, width, height);
+}
+
+void layer::add_surface(uint32_t surface_id)
+{
+ ivi_wm_layer_add_surface(this->parent->proxy.get(), this->id, surface_id);
+}
+
+void layer::remove_surface(uint32_t surface_id)
+{
+ ivi_wm_layer_remove_surface(this->parent->proxy.get(), this->id, surface_id);
+}
+
+/**
+ * screen
+ */
+screen::screen(uint32_t i, struct controller *c, struct wl_output *o)
+ : wayland_proxy(ivi_wm_create_screen(c->proxy.get(), o)),
+ controller_child(c, i)
+{
+ HMI_DEBUG("compositor::screen @ %p id %u o %p", this->proxy.get(), i, o);
+
+ // Add listener for screen
+ ivi_wm_screen_add_listener(this->proxy.get(), &screen_listener, this);
+}
+
+void screen::clear() { ivi_wm_screen_clear(this->proxy.get()); }
+
+void screen::screen_created(struct screen *screen, uint32_t id)
+{
+ HMI_DEBUG("compositor::screen @ %p screen %u (%x) @ %p", this->proxy.get(),
+ id, id, screen);
+ this->id = id;
+ this->parent->screens[id] = screen;
+}
+
+void screen::set_render_order(std::vector<uint32_t> const &ro)
+{
+ std::size_t i;
+
+ // Remove all layers from the screen render order
+ ivi_wm_screen_clear(this->proxy.get());
+
+ for (i = 0; i < ro.size(); i++)
+ {
+ HMI_DEBUG("compositor::screen @ %p add layer %u", this->proxy.get(), ro[i]);
+ // Add the layer to screen render order at nearest z-position
+ ivi_wm_screen_add_layer(this->proxy.get(), ro[i]);
+ }
+}
+
+/**
+ * controller
+ */
+controller::controller(struct wl_registry *r, uint32_t name, uint32_t version)
+ : wayland_proxy(
+ wl_registry_bind(r, name, &ivi_wm_interface, version)),
+ output_size{}
+{
+ ivi_wm_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);
+
+ // TODO: If Clipping is necessary, this process should be modified.
+ {
+ // Set surface type:IVI_WM_SURFACE_TYPE_DESKTOP)
+ // for resizing wayland surface when switching from split to full surface.
+ ivi_wm_set_surface_type(this->proxy.get(), id, IVI_WM_SURFACE_TYPE_DESKTOP);
+
+ // Set source reactangle even if we should not need to set it
+ // for enable setting for destination region.
+ this->surfaces[id]->set_source_rectangle(0, 0, this->output_size.w, this->output_size.h);
+
+ // Flush display
+ this->display->flush();
+ }
+}
+
+void controller::create_screen(struct wl_output *output)
+{
+ // TODO: screen id is 0 (WM manages one screen for now)
+ this->screen = std::make_unique<struct screen>(0, this, output);
+}
+
+void controller::get_surface_properties(uint32_t surface_id, int param)
+{
+ ivi_wm_surface_get(this->proxy.get(), surface_id, param);
+}
+
+void controller::layer_created(uint32_t id)
+{
+ HMI_DEBUG("compositor::controller @ %p layer %u (%x)", this->proxy.get(), id, id);
+ if (this->layers.find(id) != this->layers.end())
+ {
+ HMI_DEBUG("WindowManager has created layer %u (%x) already", id, id);
+ }
+ else
+ {
+ this->layers[id] = std::make_unique<struct layer>(id, this);
+ }
+}
+
+void controller::layer_error_detected(uint32_t object_id,
+ uint32_t error_code, const char *error_text)
+{
+ HMI_DEBUG("compositor::controller @ %p error o %d c %d text %s",
+ this->proxy.get(), object_id, error_code, error_text);
+}
+
+void controller::surface_visibility_changed(uint32_t id, int32_t visibility)
+{
+ HMI_DEBUG("compositor::surface %s @ %d v %i", __func__, id,
+ visibility);
+ this->sprops[id].visibility = visibility;
+ this->chooks->surface_visibility(id, visibility);
+}
+
+void controller::surface_opacity_changed(uint32_t id, float opacity)
+{
+ HMI_DEBUG("compositor::surface %s @ %d o %f",
+ __func__, id, opacity);
+ this->sprops[id].opacity = opacity;
+}
+
+void controller::surface_source_rectangle_changed(uint32_t id, int32_t x,
+ int32_t y, int32_t width,
+ int32_t height)
+{
+ HMI_DEBUG("compositor::surface %s @ %d x %i y %i w %i h %i", __func__,
+ id, x, y, width, height);
+ this->sprops[id].src_rect = rect{width, height, x, y};
+}
+
+void controller::surface_destination_rectangle_changed(uint32_t id, int32_t x,
+ int32_t y, int32_t width,
+ int32_t height)
+{
+ HMI_DEBUG("compositor::surface %s @ %d x %i y %i w %i h %i", __func__,
+ id, x, y, width, height);
+ this->sprops[id].dst_rect = rect{width, height, x, y};
+ this->chooks->surface_destination_rectangle(id, x, y, width, height);
+}
+
+void controller::surface_size_changed(uint32_t id, int32_t width,
+ int32_t height)
+{
+ HMI_DEBUG("compositor::surface %s @ %d w %i h %i", __func__, id,
+ width, height);
+ this->sprops[id].size = size{uint32_t(width), uint32_t(height)};
+ this->surfaces[id]->set_source_rectangle(0, 0, width, height);
+}
+
+void controller::surface_added_to_layer(uint32_t layer_id, uint32_t surface_id)
+{
+ HMI_DEBUG("compositor::surface %s @ %d l %u",
+ __func__, layer_id, surface_id);
+}
+
+void controller::surface_stats_received(uint32_t surface_id,
+ uint32_t frame_count, uint32_t pid)
+{
+ HMI_DEBUG("compositor::surface %s @ %d f %u pid %u",
+ __func__, surface_id, frame_count, pid);
+ this->sprops[surface_id].pid = pid;
+}
+
+void controller::surface_created(uint32_t id)
+{
+ HMI_DEBUG("compositor::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);
+
+ // Set surface type:IVI_WM_SURFACE_TYPE_DESKTOP)
+ // for resizing wayland surface when switching from split to full surface.
+ ivi_wm_set_surface_type(this->proxy.get(), id, IVI_WM_SURFACE_TYPE_DESKTOP);
+
+ // Flush display
+ this->display->flush();
+ }
+}
+
+void controller::surface_destroyed(uint32_t surface_id)
+{
+ HMI_DEBUG("compositor::surface %s @ %d", __func__, surface_id);
+ this->chooks->surface_removed(surface_id);
+ this->sprops.erase(surface_id);
+ this->surfaces.erase(surface_id);
+}
+
+void controller::surface_error_detected(uint32_t object_id,
+ uint32_t error_code, const char *error_text)
+{
+ HMI_DEBUG("compositor::controller @ %p error o %d c %d text %s",
+ this->proxy.get(), object_id, error_code, error_text);
+}
+
+void controller::layer_visibility_changed(uint32_t layer_id, int32_t visibility)
+{
+ HMI_DEBUG("compositor::layer %s @ %d v %i", __func__, layer_id, visibility);
+ this->lprops[layer_id].visibility = visibility;
+}
+
+void controller::layer_opacity_changed(uint32_t layer_id, float opacity)
+{
+ HMI_DEBUG("compositor::layer %s @ %d o %f", __func__, layer_id, opacity);
+ this->lprops[layer_id].opacity = opacity;
+}
+
+void controller::layer_source_rectangle_changed(uint32_t layer_id,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ HMI_DEBUG("compositor::layer %s @ %d x %i y %i w %i h %i",
+ __func__, layer_id, x, y, width, height);
+ this->lprops[layer_id].src_rect = rect{width, height, x, y};
+}
+
+void controller::layer_destination_rectangle_changed(uint32_t layer_id,
+ int32_t x, int32_t y,
+ int32_t width, int32_t height)
+{
+ HMI_DEBUG("compositor::layer %s @ %d x %i y %i w %i h %i",
+ __func__, layer_id, x, y, width, height);
+ this->lprops[layer_id].dst_rect = rect{width, height, x, y};
+}
+
+void controller::layer_destroyed(uint32_t layer_id)
+{
+ HMI_DEBUG("compositor::layer %s @ %d", __func__, layer_id);
+ this->lprops.erase(layer_id);
+ this->layers.erase(layer_id);
+}
+
+void controller::add_proxy_to_sid_mapping(struct ivi_wm *p,
+ uint32_t id)
+{
+ HMI_DEBUG("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_sid_mapping(struct ivi_wm *p)
+{
+ HMI_DEBUG("Remove surface proxy mapping for %p", p);
+ this->surface_proxy_to_id.erase(uintptr_t(p));
+}
+
+void controller::add_proxy_to_lid_mapping(struct ivi_wm *p,
+ uint32_t id)
+{
+ HMI_DEBUG("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_lid_mapping(struct ivi_wm *p)
+{
+ HMI_DEBUG("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)
+{
+ HMI_DEBUG("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)
+{
+ HMI_DEBUG("Remove screen proxy mapping for %p", p);
+ this->screen_proxy_to_id.erase(uintptr_t(p));
+}
+
+} // namespace compositor
diff --git a/demo#3/common/agl-service-windowmanager/src/wayland_ivi_wm.hpp b/demo#3/common/agl-service-windowmanager/src/wayland_ivi_wm.hpp
new file mode 100644
index 0000000..d8915a1
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wayland_ivi_wm.hpp
@@ -0,0 +1,327 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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-wm-client-protocol.h"
+#include "util.hpp"
+
+#include <functional>
+#include <memory>
+#include <unordered_map>
+#include <vector>
+
+/**
+ * @struct wayland_proxy
+ */
+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)) {}
+};
+
+/**
+ * namespace wl
+ */
+namespace wl
+{
+
+/**
+ * @struct registry
+ */
+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_created(uint32_t name, char const *iface, uint32_t v);
+ void global_removed(uint32_t name);
+};
+
+/**
+ * @struct display
+ */
+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
+ */
+struct output : public wayland_proxy<struct wl_output>
+{
+ int width{};
+ int height{};
+ int physical_width{};
+ int physical_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
+
+/**
+ * namespace compositor
+ */
+namespace compositor
+{
+
+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;
+ uint32_t pid;
+};
+
+/**
+ * @struct surface
+ */
+struct surface : public 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_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);
+};
+
+/**
+ * @struct layer
+ */
+struct layer : public 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_destination_rectangle(int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void add_surface(uint32_t surface_id);
+ void remove_surface(uint32_t surface_id);
+};
+
+/**
+ * @struct screen
+ */
+struct screen : public wayland_proxy<struct ivi_wm_screen>,
+ public controller_child
+{
+ screen(screen const &) = delete;
+ screen &operator=(screen const &) = delete;
+ screen(uint32_t i, struct controller *c, struct wl_output *o);
+
+ void clear();
+ void screen_created(struct screen *screen, uint32_t id);
+ void set_render_order(std::vector<uint32_t> const &ro);
+};
+
+/**
+ * @struct controller
+ */
+struct controller : public wayland_proxy<struct ivi_wm>
+{
+ // 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, 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;
+
+ std::unique_ptr<struct screen> screen;
+
+ size output_size; // Display size[pixel]
+ size physical_size; // Display size[mm]
+
+ // Scale for conversion CSS PX -> DP(Device Pixel)
+ double scale;
+
+ wm::controller_hooks *chooks;
+
+ struct wl::display *display;
+
+ void add_proxy_to_sid_mapping(struct ivi_wm *p, uint32_t id);
+ void remove_proxy_to_sid_mapping(struct ivi_wm *p);
+
+ void add_proxy_to_lid_mapping(struct ivi_wm *p, uint32_t id);
+ void remove_proxy_to_lid_mapping(struct ivi_wm *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_wm_commit_changes(this->proxy.get());
+ }
+ void layer_create(uint32_t id, int32_t w, int32_t h);
+ void surface_create(uint32_t id);
+ void create_screen(struct wl_output *output);
+ void get_surface_properties(uint32_t surface_id, int param = 0);
+
+ // Events
+ void surface_visibility_changed(uint32_t id, int32_t visibility);
+ void surface_opacity_changed(uint32_t id, float opacity);
+ void surface_source_rectangle_changed(uint32_t id, int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void surface_destination_rectangle_changed(uint32_t id, int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void surface_created(uint32_t id);
+ void surface_destroyed(uint32_t surface_id);
+ void surface_error_detected(uint32_t object_id,
+ uint32_t error_code, char const *error_text);
+ void surface_size_changed(uint32_t id, int32_t width, int32_t height);
+ void surface_stats_received(uint32_t surface_id,
+ uint32_t frame_count, uint32_t pid);
+ void surface_added_to_layer(uint32_t layer_id, uint32_t surface_id);
+
+ void layer_visibility_changed(uint32_t layer_id, int32_t visibility);
+ void layer_opacity_changed(uint32_t layer_id, float opacity);
+ void layer_source_rectangle_changed(uint32_t layer_id, int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void layer_destination_rectangle_changed(uint32_t layer_id, int32_t x, int32_t y,
+ int32_t width, int32_t height);
+ void layer_created(uint32_t id);
+ void layer_destroyed(uint32_t layer_id);
+ void layer_error_detected(uint32_t object_id,
+ uint32_t error_code, char const *error_text);
+};
+} // namespace compositor
+
+#endif // !WM_WAYLAND_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/window_manager.cpp b/demo#3/common/agl-service-windowmanager/src/window_manager.cpp
new file mode 100644
index 0000000..f209f12
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/window_manager.cpp
@@ -0,0 +1,2326 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <fstream>
+#include <regex>
+#include <sstream>
+
+#include "window_manager.hpp"
+#include "json_helper.hpp"
+#include "applist.hpp"
+
+extern "C"
+{
+#include <systemd/sd-event.h>
+}
+
+using std::string;
+using std::vector;
+
+namespace wm
+{
+
+static const uint64_t kTimeOut = 3ULL; /* 3s */
+
+/* DrawingArea name used by "{layout}.{area}" */
+const char kNameLayoutNormal[] = "normal";
+const char kNameLayoutSplit[] = "split";
+const char kNameAreaFull[] = "full";
+const char kNameAreaMain[] = "main";
+const char kNameAreaSub[] = "sub";
+
+/* Key for json obejct */
+const char kKeyDrawingName[] = "drawing_name";
+const char kKeyDrawingArea[] = "drawing_area";
+const char kKeyDrawingRect[] = "drawing_rect";
+const char kKeyX[] = "x";
+const char kKeyY[] = "y";
+const char kKeyWidth[] = "width";
+const char kKeyHeight[] = "height";
+const char kKeyWidthPixel[] = "width_pixel";
+const char kKeyHeightPixel[] = "height_pixel";
+const char kKeyWidthMm[] = "width_mm";
+const char kKeyHeightMm[] = "height_mm";
+const char kKeyScale[] = "scale";
+const char kKeyIds[] = "ids";
+
+static const char kPathOldRolesConfigFile[] = "/etc/old_roles.json";
+
+static sd_event_source *g_timer_ev_src = nullptr;
+static AppList g_app_list;
+static WindowManager *g_context;
+
+struct AfbClosure {
+public:
+ AfbClosure(unsigned pid, unsigned ppid, unsigned surface)
+ : pid(pid), ppid(ppid), surface(surface) {}
+ ~AfbClosure() = default;
+ unsigned pid;
+ unsigned ppid;
+ unsigned surface;
+};
+
+namespace
+{
+
+static int processTimerHandler(sd_event_source *s, uint64_t usec, void *userdata)
+{
+ HMI_NOTICE("Time out occurs because the client replys endDraw slow, so revert the request");
+ reinterpret_cast<wm::WindowManager *>(userdata)->timerHandler();
+ return 0;
+}
+
+static void onStateTransitioned(vector<WMAction> actions)
+{
+ g_context->startTransitionWrapper(actions);
+}
+
+static void onError()
+{
+ g_context->processError(WMError::LAYOUT_CHANGE_FAIL);
+}
+
+static void onReceiveRemoteRequest(json_object *data)
+{
+ g_context->processForRemoteRequest(data);
+}
+} // namespace
+
+/**
+ * WindowManager Impl
+ */
+WindowManager::WindowManager()
+ : wmcon{},
+ id_alloc{}
+{
+ const char *path = getenv("AFM_APP_INSTALL_DIR");
+ if (!path)
+ {
+ HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
+ }
+ string root = path;
+
+ // TODO: ECU name should be decide by config file
+ // Get mode and decide ECU name
+ string ecu_name = this->wmcon.getEcuName();
+
+ this->lc = std::make_shared<LayerControl>(root, ecu_name);
+
+ HMI_DEBUG("Layer Controller initialized");
+}
+
+int WindowManager::init()
+{
+ LayerControlCallbacks lmcb;
+ lmcb.surfaceCreated = [&](unsigned pid, unsigned surface){
+ this->surface_created(pid, surface);
+ };
+ lmcb.surfaceDestroyed = [&](unsigned surface){
+ this->surface_removed(surface);
+ };
+ this->lc->init(lmcb);
+
+ // TODO: application requests by old role,
+ // so create role map (old, new)
+ // Load old_roles config file
+ this->loadOldRolesConfigFile();
+
+ // Initialize LowCanClient
+ this->lcc.initialize();
+
+ // Store my context for calling callback from PolicyManager
+ g_context = this;
+
+ // Initialize PMWrapper
+ this->pmw.initialize(this->wmcon.getEcuName());
+
+ // Register callback to PolicyManager
+ this->pmw.registerCallback(onStateTransitioned, onError);
+
+ // Initialize WMConnection
+ this->wmcon.initialize();
+
+ // Register callback to WMConnection
+ this->wmcon.registerCallback(onReceiveRemoteRequest);
+
+ // Make afb event
+ for (int i = Event_Val_Min; i <= Event_Val_Max; i++)
+ {
+ map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i]);
+ }
+
+ const struct rect css_bg = this->lc->getAreaSize("fullscreen");
+ Screen screen = this->lc->getScreenInfo();
+ rectangle dp_bg(screen.width(), screen.height());
+
+ dp_bg.set_aspect(static_cast<double>(css_bg.w) / css_bg.h);
+ dp_bg.fit(screen.width(), screen.height());
+ dp_bg.center(screen.width(), screen.height());
+ HMI_DEBUG("SCALING: CSS BG(%dx%d) -> DDP %dx%d,(%dx%d)",
+ css_bg.w, css_bg.h, dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.height());
+
+ double scale = static_cast<double>(dp_bg.height()) / css_bg.h;
+ this->lc->setupArea(dp_bg, scale);
+
+ return 0; //init_layers();
+}
+
+result<int> WindowManager::api_request_surface(char const *appid, char const *drawing_name)
+{
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *role = this->convertRoleOldToNew(drawing_name);
+ string l_name;
+ string s_appid = appid;
+ string s_role = role;
+
+ if(!g_app_list.contains(s_appid))
+ {
+ // auto lid = this->layers.get_layer_id(string(role));
+ unsigned l_id = this->lc->getNewLayerID(s_role, &l_name);
+ if (l_id == 0)
+ {
+ /**
+ * register drawing_name as fallback and make it displayed.
+ */
+ l_id = this->lc->getNewLayerID("fallback", &l_name);
+ HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role);
+ if (l_id == 0)
+ {
+ return Err<int>("Designated role does not match any role, fallback is disabled");
+ }
+ }
+
+ // TODO: remote layer size is fixed value
+ if ("Remote" == l_name)
+ {
+ this->lc->createNewRemoteLayer(l_id);
+ }
+ else
+ {
+ this->lc->createNewLayer(l_id);
+ }
+
+ // add client into the db
+ g_app_list.addClient(s_appid, l_id, s_role);
+ }
+
+ // generate surface ID for ivi-shell application
+
+ auto rname = this->id_alloc.lookup(string(role));
+ if (!rname)
+ {
+ // name does not exist yet, allocate surface id...
+ auto id = int(this->id_alloc.generate_id(role));
+ this->tmp_surface2app[id] = {s_appid, 0};
+
+ // Work Around
+ HMI_NOTICE("WORK AROUND: add surface on request surface");
+ auto client = g_app_list.lookUpClient(s_appid);
+ client->addSurface(id);
+ ///////////////
+
+ // Set role map of (new, old)
+ this->rolenew2old[role] = string(drawing_name);
+
+ return Ok<int>(id);
+ }
+
+ // Check currently registered drawing names if it is already there.
+ return Err<int>("Surface already present");
+}
+
+char const *WindowManager::api_request_surface(char const *appid, char const *drawing_name,
+ char const *ivi_id)
+{
+ unsigned sid = std::stol(ivi_id);
+
+ HMI_DEBUG("This API(requestSurfaceXDG) is for XDG Application using runXDG");
+ /*
+ * IVI-shell doesn't send surface_size event via ivi-wm protocol
+ * if the application is using XDG surface.
+ * So WM has to set surface size with original size here
+ */
+ WMError ret = this->lc->setXDGSurfaceOriginSize(sid);
+ if(ret != SUCCESS)
+ {
+ HMI_ERROR("%s", errorDescription(ret));
+ HMI_WARNING("The main user of this API is runXDG");
+ return "fail";
+ }
+
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *role = this->convertRoleOldToNew(drawing_name);
+ string s_role = role;
+ string s_appid = appid;
+ string l_name;
+
+ if(!g_app_list.contains(s_appid))
+ {
+ // auto lid = this->layers.get_layer_id(string(role));
+ unsigned l_id = this->lc->getNewLayerID(s_role, &l_name);
+ if (l_id == 0)
+ {
+ /**
+ * register drawing_name as fallback and make it displayed.
+ */
+ l_id = this->lc->getNewLayerID("fallback", &l_name);
+ HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role);
+ if (l_id == 0)
+ {
+ return "Designated role does not match any role, fallback is disabled";
+ }
+ }
+
+ // TODO: remote layer size is fixed value
+ if ("Remote" == l_name)
+ {
+ this->lc->createNewRemoteLayer(l_id);
+ }
+ else
+ {
+ this->lc->createNewLayer(l_id);
+ }
+
+ // add client into the db
+ g_app_list.addClient(s_appid, l_id, s_role);
+ }
+
+ auto rname = this->id_alloc.lookup(s_role);
+ if (rname)
+ {
+ return "Surface already present";
+ }
+
+ // register pair drawing_name and ivi_id
+ this->id_alloc.register_name_id(role, sid);
+
+ auto client = g_app_list.lookUpClient(s_appid);
+ client->addSurface(sid);
+
+ // Set role map of (new, old)
+ this->rolenew2old[role] = string(drawing_name);
+
+ return nullptr;
+}
+
+bool WindowManager::api_set_role(char const *appid, char const *drawing_name)
+{
+ bool ret = false;
+
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *role = this->convertRoleOldToNew(drawing_name);
+ string s_role = role;
+ string s_appid = appid;
+ string l_name;
+
+ // Create WMClient
+ if(!g_app_list.contains(s_appid))
+ {
+ // auto lid = this->layers.get_layer_id(string(role));
+ unsigned l_id = this->lc->getNewLayerID(s_role, &l_name);
+ if (l_id == 0)
+ {
+ /**
+ * register drawing_name as fallback and make it displayed.
+ */
+ l_id = this->lc->getNewLayerID("fallback", &l_name);
+ HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role);
+ if (l_id == 0)
+ {
+ HMI_ERROR("Designated role does not match any role, fallback is disabled");
+ return ret;
+ }
+ }
+
+ // TODO: remote layer size is fixed value
+ if ("Remote" == l_name)
+ {
+ this->lc->createNewRemoteLayer(l_id);
+ }
+ else
+ {
+ this->lc->createNewLayer(l_id);
+ }
+
+ // add client into the db
+ g_app_list.addClient(s_appid, l_id, s_role);
+ // Set role map of (new, old)
+ this->rolenew2old[role] = string(drawing_name);
+ }
+
+ // for(auto itr = this->tmp_surface2app.begin();
+ // itr != this->tmp_surface2app.end() ; ++itr)
+ // {
+ for(auto& x : this->tmp_surface2app)
+ {
+ if(x.second.appid == s_appid)
+ {
+ unsigned surface = x.first;
+ auto client = g_app_list.lookUpClient(s_appid);
+ client->addSurface(surface);
+ this->tmp_surface2app.erase(surface);
+ this->id_alloc.register_name_id(s_role, surface);
+ break;
+ }
+ }
+
+/* if(0 != pid){
+ // search floating surfaceID from pid if pid is designated.
+ wm_err = g_app_list.popFloatingSurface(pid, &surface);
+ }
+ else{
+ // get floating surface with appid. If WM queries appid from pid,
+ // WM can bind surface and role with appid(not implemented yet)
+ //wm_err = g_app_list.popFloatingSurface(id);
+ }
+ if(wm_err != WMError::SUCCESS){
+ HMI_ERROR("No floating surface for app: %s", id.c_str());
+ g_app_list.addFloatingClient(id, lid, role);
+ HMI_NOTICE("%s : Waiting for surface creation", id.c_str());
+ return ret;
+ }
+
+ ret = true;
+ if (g_app_list.contains(id))
+ {
+ HMI_INFO("Add role: %s with surface: %d. Client %s has multi surfaces.",
+ role.c_str(), surface, id.c_str());
+ auto client = g_app_list.lookUpClient(id);
+ client->appendRole(role);
+ }
+ else{
+ HMI_INFO("Create new client: %s, surface: %d into layer: %d with role: %s",
+ id.c_str(), surface, lid, role.c_str());
+ g_app_list.addClient(id, lid, role);
+ } */
+
+ // register pair drawing_name and ivi_id
+
+ return true;
+}
+
+void WindowManager::api_activate_surface(char const *appid, char const *drawing_name,
+ char const *drawing_area, const reply_func &reply)
+{
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ string id = appid;
+ string role = c_role;
+ string area = drawing_area;
+
+ if(!g_app_list.contains(id))
+ {
+ reply("app doesn't request 'requestSurface' or 'setRole' yet");
+ return;
+ }
+ auto client = g_app_list.lookUpClient(id);
+
+ // unsigned srfc = client->surfaceID(role);
+ // unsigned layer = client->layerID();
+
+ // g_app_list.removeFloatingSurface(client->surfaceID());
+ // g_app_list.removeFloatingSurface(client);
+
+ Task task = Task::TASK_ALLOCATE;
+ unsigned req_num = 0;
+ WMError ret = WMError::UNKNOWN;
+
+ ret = this->setRequest(id, role, area, task, &req_num);
+
+ //vector<WMLayerState> current_states = this->lc->getCurrentStates();
+ // ret = this->setRequest(id, role, area, task, current_states, &req_num);
+
+ if(ret != WMError::SUCCESS)
+ {
+ HMI_ERROR(errorDescription(ret));
+ reply("Failed to set request");
+ return;
+ }
+
+ reply(nullptr);
+ if (req_num != g_app_list.currentRequestNumber())
+ {
+ // Add request, then invoked after the previous task is finished
+ HMI_SEQ_DEBUG(req_num, "request is accepted");
+ return;
+ }
+
+ /*
+ * Do allocate tasks
+ */
+ ret = this->checkPolicy(req_num);
+
+ if (ret != WMError::SUCCESS)
+ {
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(ret));
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+ }
+}
+
+void WindowManager::api_activate_surface_for_slave(
+ char const *appid, char const *drawing_name,
+ char const *drawing_area, const reply_func &reply)
+{
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ string id = appid;
+ string role = c_role;
+ string area = drawing_area;
+
+ if(!g_app_list.contains(id))
+ {
+ // Request surface of app in slave to register app information
+ this->api_request_surface(appid, drawing_name);
+
+ // Set role of app in slave to register app information
+ this->api_set_role(appid, drawing_name);
+ }
+ auto client = g_app_list.lookUpClient(id);
+
+ // unsigned srfc = client->surfaceID(role);
+ // unsigned layer = client->layerID();
+
+ // g_app_list.removeFloatingSurface(client->surfaceID());
+ // g_app_list.removeFloatingSurface(client);
+
+ Task task = Task::TASK_ALLOCATE;
+ unsigned req_num = 0;
+ WMError ret = WMError::UNKNOWN;
+
+ ret = this->setRequestForSlave(id, role, area, task, &req_num);
+
+ //vector<WMLayerState> current_states = this->lc->getCurrentStates();
+ // ret = this->setRequest(id, role, area, task, current_states, &req_num);
+
+ if(ret != WMError::SUCCESS)
+ {
+ HMI_ERROR(errorDescription(ret));
+ reply("Failed to set request");
+ return;
+ }
+
+ reply(nullptr);
+ if (req_num != g_app_list.currentRequestNumber())
+ {
+ // Add request, then invoked after the previous task is finished
+ HMI_SEQ_DEBUG(req_num, "request is accepted");
+ return;
+ }
+
+ /*
+ * Do allocate tasks
+ */
+ ret = this->checkPolicyForSlave(req_num);
+
+ if (ret != WMError::SUCCESS)
+ {
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(ret));
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+ }
+}
+
+void WindowManager::api_activate_surface_to_master(
+ char const *appid, char const *drawing_name,
+ char const *drawing_area, const reply_func &reply)
+{
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ string id = appid;
+ string role = c_role;
+ string area = drawing_area;
+
+ if(!g_app_list.contains(id))
+ {
+ reply("app doesn't request 'requestSurface' or 'setRole' yet");
+ return;
+ }
+ auto client = g_app_list.lookUpClient(id);
+
+ // unsigned srfc = client->surfaceID(role);
+ // unsigned layer = client->layerID();
+
+ // g_app_list.removeFloatingSurface(client->surfaceID());
+ // g_app_list.removeFloatingSurface(client);
+
+ Task task = Task::TASK_ALLOCATE;
+ unsigned req_num = 0;
+ WMError ret = WMError::UNKNOWN;
+
+ ret = this->setRequest(id, role, area, task, &req_num);
+
+ //vector<WMLayerState> current_states = this->lc->getCurrentStates();
+ // ret = this->setRequest(id, role, area, task, current_states, &req_num);
+
+ if(ret != WMError::SUCCESS)
+ {
+ HMI_ERROR(errorDescription(ret));
+ reply("Failed to set request");
+ return;
+ }
+
+ reply(nullptr);
+ if (req_num != g_app_list.currentRequestNumber())
+ {
+ // Add request, then invoked after the previous task is finished
+ HMI_SEQ_DEBUG(req_num, "request is accepted");
+ return;
+ }
+
+ /*
+ * Do allocate tasks
+ */
+ int i_ret = this->wmcon.sendRequest("activateWindow", appid,
+ drawing_name, drawing_area);
+ if (0 > i_ret)
+ {
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(ret));
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+ }
+
+ this->setTimer();
+}
+
+void WindowManager::api_deactivate_surface(char const *appid, char const *drawing_name,
+ const reply_func &reply)
+{
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ /*
+ * Check Phase
+ */
+ string id = appid;
+ string role = c_role;
+ string area = ""; //drawing_area;
+ Task task = Task::TASK_RELEASE;
+ unsigned req_num = 0;
+ WMError ret = WMError::UNKNOWN;
+
+ ret = this->setRequest(id, role, area, task, &req_num);
+
+ if (ret != WMError::SUCCESS)
+ {
+ HMI_ERROR(errorDescription(ret));
+ reply("Failed to set request");
+ return;
+ }
+
+ reply(nullptr);
+ if (req_num != g_app_list.currentRequestNumber())
+ {
+ // Add request, then invoked after the previous task is finished
+ HMI_SEQ_DEBUG(req_num, "request is accepted");
+ return;
+ }
+
+ /*
+ * Do allocate tasks
+ */
+ ret = this->checkPolicy(req_num);
+
+ if (ret != WMError::SUCCESS)
+ {
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(ret));
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+ }
+}
+
+void WindowManager::api_deactivate_surface_for_slave(char const *appid, char const *drawing_name,
+ const reply_func &reply)
+{
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ /*
+ * Check Phase
+ */
+ string id = appid;
+ string role = c_role;
+ string area = "";//drawing_area;
+ Task task = Task::TASK_RELEASE;
+ unsigned req_num = 0;
+ WMError ret = WMError::UNKNOWN;
+
+ ret = this->setRequest(id, role, area, task, &req_num);
+
+ if (ret != WMError::SUCCESS)
+ {
+ HMI_ERROR(errorDescription(ret));
+ reply("Failed to set request");
+ return;
+ }
+
+ reply(nullptr);
+ if (req_num != g_app_list.currentRequestNumber())
+ {
+ // Add request, then invoked after the previous task is finished
+ HMI_SEQ_DEBUG(req_num, "request is accepted");
+ return;
+ }
+
+ /*
+ * Do allocate tasks
+ */
+ ret = this->checkPolicyForSlave(req_num);
+
+ if (ret != WMError::SUCCESS)
+ {
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(ret));
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+ }
+}
+
+void WindowManager::api_deactivate_surface_to_master(char const *appid, char const *drawing_name,
+ const reply_func &reply)
+{
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ /*
+ * Check Phase
+ */
+ string id = appid;
+ string role = c_role;
+ string area = "";//drawing_area;
+ Task task = Task::TASK_RELEASE;
+ unsigned req_num = 0;
+ WMError ret = WMError::UNKNOWN;
+
+ ret = this->setRequest(id, role, area, task, &req_num);
+
+ if (ret != WMError::SUCCESS)
+ {
+ HMI_ERROR(errorDescription(ret));
+ reply("Failed to set request");
+ return;
+ }
+
+ reply(nullptr);
+ if (req_num != g_app_list.currentRequestNumber())
+ {
+ // Add request, then invoked after the previous task is finished
+ HMI_SEQ_DEBUG(req_num, "request is accepted");
+ return;
+ }
+
+ /*
+ * Do allocate tasks
+ */
+ int i_ret = this->wmcon.sendRequest("deactivateWindow", appid,
+ drawing_name, "");
+ if (0 > i_ret)
+ {
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(ret));
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+ }
+
+ this->setTimer();
+}
+
+void WindowManager::api_enddraw(char const *appid, char const *drawing_name)
+{
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ string id = appid;
+ string role = c_role;
+ unsigned current_req = g_app_list.currentRequestNumber();
+ bool result = g_app_list.setEndDrawFinished(current_req, id, role);
+
+ if (!result)
+ {
+ HMI_ERROR("%s is not in transition state", id.c_str());
+ return;
+ }
+
+ if (g_app_list.endDrawFullfilled(current_req))
+ {
+ // do task for endDraw
+ this->stopTimer();
+ WMError ret = this->doEndDraw(current_req);
+
+ if(ret != WMError::SUCCESS)
+ {
+ //this->emit_error();
+
+ // Undo state of PolicyManager
+ this->pmw.undoState();
+ this->lc->undoUpdate();
+ }
+ this->emitScreenUpdated(current_req);
+ HMI_SEQ_INFO(current_req, "Finish request status: %s", errorDescription(ret));
+
+ g_app_list.removeRequest(current_req);
+
+ this->processNextRequest();
+ }
+ else
+ {
+ HMI_SEQ_INFO(current_req, "Wait other App call endDraw");
+ return;
+ }
+}
+
+void WindowManager::api_enddraw_for_remote(char const *appid, char const *drawing_name)
+{
+ int ret = this->wmcon.sendRequest("endDraw", appid, drawing_name, "");
+ if (0 > ret)
+ {
+ //this->emit_error()
+
+ this->pmw.undoState();
+ this->lc->undoUpdate();
+
+ unsigned current_req = g_app_list.currentRequestNumber();
+ g_app_list.removeRequest(current_req);
+ this->processNextRequest();
+
+ return;
+ }
+
+ this->api_enddraw(appid, drawing_name);
+}
+
+bool WindowManager::api_client_set_render_order(char const* appid, const vector<string>& render_order)
+{
+ bool ret = false;
+ string id = appid;
+ auto client = g_app_list.lookUpClient(id);
+ if(client)
+ {
+ client->setRenderOrder(render_order);
+ }
+ return ret;
+}
+
+string WindowManager::api_client_attach_service_surface
+ (const char* appid, const char* dest, const char* service_surface)
+{
+ string uuid, s_dest = dest;
+ auto client = g_app_list.lookUpClient(s_dest);
+ if(!client)
+ {
+ HMI_ERROR("Failed to look up destination [%s]", dest);
+ return uuid;
+ }
+ uuid = client->attachTmpServiceSurface(appid, service_surface);
+ this->tmp_services.emplace_back(TmpService{appid, dest, service_surface, uuid});
+ return uuid;
+}
+
+result<json_object *> WindowManager::api_get_display_info()
+{
+ Screen screen = this->lc->getScreenInfo();
+
+ json_object *object = json_object_new_object();
+ json_object_object_add(object, kKeyWidthPixel, json_object_new_int(screen.width()));
+ json_object_object_add(object, kKeyHeightPixel, json_object_new_int(screen.height()));
+ // TODO: set size
+ json_object_object_add(object, kKeyWidthMm, json_object_new_int(0));
+ json_object_object_add(object, kKeyHeightMm, json_object_new_int(0));
+ json_object_object_add(object, kKeyScale, json_object_new_double(this->lc->scale()));
+
+ return Ok<json_object *>(object);
+}
+
+result<json_object *> WindowManager::api_get_area_info(char const *drawing_name)
+{
+ HMI_DEBUG("called");
+
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *role = this->convertRoleOldToNew(drawing_name);
+
+ // Check drawing name, surface/layer id
+ auto const &surface_id = this->id_alloc.lookup(string(role));
+ if (!surface_id)
+ {
+ return Err<json_object *>("Surface does not exist");
+ }
+
+ // Set area rectangle
+ rect area_info = this->area_info[*surface_id];
+ json_object *object = json_object_new_object();
+ json_object_object_add(object, kKeyX, json_object_new_int(area_info.x));
+ json_object_object_add(object, kKeyY, json_object_new_int(area_info.y));
+ json_object_object_add(object, kKeyWidth, json_object_new_int(area_info.w));
+ json_object_object_add(object, kKeyHeight, json_object_new_int(area_info.h));
+
+ return Ok<json_object *>(object);
+}
+
+result<json_object *> WindowManager::api_get_car_info(char const *label)
+{
+ json_object *j_in = nullptr;
+ json_object *j_out = nullptr;
+
+ if (0 == strcmp("parking_brake_status", label))
+ {
+ // Get parking brake status
+ json_bool val = (this->crr_car_info.parking_brake_stt) ? TRUE : FALSE;
+ j_in = json_object_new_boolean(val);
+ }
+ else if (0 == strcmp("accelerator.pedal.position", label))
+ {
+ // Get accelerator pedal position
+ double val = this->crr_car_info.accel_pedal_pos;
+ j_in = json_object_new_double(val);
+ }
+ else if (0 == strcmp("car_state", label))
+ {
+ // Get running state
+ const char* val = (this->crr_car_info.running_stt) ? "run" : "stop";
+ j_in = json_object_new_string(val);
+ }
+ else if (0 == strcmp("lightstatus.brake", label)) {
+ // Get lightstatus brake status
+ json_bool val = (this->crr_car_info.lightstatus_brake_stt) ? TRUE : FALSE;
+ j_in = json_object_new_boolean(val);
+ }
+ else
+ {
+ return Err<json_object *>("Car info does not exist");
+ }
+
+ // Create output object
+ j_out = json_object_new_object();
+ json_object_object_add(j_out, "value", j_in);
+
+ return Ok<json_object *>(j_out);
+}
+
+void WindowManager::send_event(char const *evname)
+{
+ HMI_DEBUG("%s: %s", __func__, evname);
+
+ int ret = afb_event_push(this->map_afb_event[evname], nullptr);
+ if (ret != 0)
+ {
+ HMI_DEBUG("afb_event_push: %m");
+ }
+}
+
+void WindowManager::send_event(char const *evname, char const *label)
+{
+ HMI_DEBUG("%s: %s(%s)", __func__, evname, label);
+
+ json_object *j = json_object_new_object();
+ json_object_object_add(j, kKeyDrawingName, json_object_new_string(label));
+
+ int ret = afb_event_push(this->map_afb_event[evname], j);
+ if (ret != 0)
+ {
+ HMI_DEBUG("afb_event_push failed: %m");
+ }
+}
+
+void WindowManager::send_event(char const *evname, char const *label, char const *area,
+ int x, int y, int w, int h)
+{
+ HMI_DEBUG("%s: %s(%s, %s) x:%d y:%d w:%d h:%d",
+ __func__, evname, label, area, x, y, w, h);
+
+ json_object *j_rect = json_object_new_object();
+ json_object_object_add(j_rect, kKeyX, json_object_new_int(x));
+ json_object_object_add(j_rect, kKeyY, json_object_new_int(y));
+ json_object_object_add(j_rect, kKeyWidth, json_object_new_int(w));
+ json_object_object_add(j_rect, kKeyHeight, json_object_new_int(h));
+
+ json_object *j = json_object_new_object();
+ json_object_object_add(j, kKeyDrawingName, json_object_new_string(label));
+ json_object_object_add(j, kKeyDrawingArea, json_object_new_string(area));
+ json_object_object_add(j, kKeyDrawingRect, j_rect);
+
+ int ret = afb_event_push(this->map_afb_event[evname], j);
+ if (ret != 0)
+ {
+ HMI_DEBUG("afb_event_push failed: %m");
+ }
+}
+
+string WindowManager::searchApp(unsigned pid, unsigned ppid, unsigned surface, json_object* resp)
+{
+ // retrieve appid from pid from application manager
+ string appid;
+ // check appid then add it to the client
+ HMI_INFO("Runners:%s", json_object_get_string(resp));
+ int size = json_object_array_length(resp);
+ HMI_INFO("pid %d, ppid %d, surface %d",pid, ppid, surface);
+ for(int i = 0; i < size; i++)
+ {
+ json_object *j = json_object_array_get_idx(resp, i);
+ int runid = jh::getIntFromJson(j, "runid");
+ const char* id = jh::getStringFromJson(j, "id");
+ HMI_DEBUG("Appid %s, runid %d", id, runid);
+ if(id && (runid == ppid))
+ {
+ string s_id = id;
+ s_id.erase(s_id.find('@'));
+ appid = s_id;
+ HMI_INFO("App found %s", appid.c_str());
+ break;
+ }
+ }
+ if(appid.empty())
+ {
+ HMI_WARNING("Failed to retrieve id");
+ }
+ return appid;
+}
+
+void WindowManager::storeSurface(const string& appid, unsigned ppid, unsigned surface)
+{
+ auto elem = std::find_if(this->tmp_services.begin(), this->tmp_services.end(),
+ [&appid](TmpService& ts){
+ return (ts.dest == appid );
+ });
+
+ this->lc->setXDGSurfaceOriginSize(surface);
+ if(elem != this->tmp_services.end())
+ {
+ // attachApp
+ auto client = g_app_list.lookUpClient(elem->dest);
+ if(client == nullptr)
+ {
+ return;
+ }
+ HMI_INFO("Attach surface %d (service %s) to app %s", surface, elem->service.c_str(), elem->dest.c_str());
+ client->attachServiceSurface(elem->service, surface);
+ }
+ else
+ {
+ // setRole
+ auto client = g_app_list.lookUpClient(appid);
+ if(client != nullptr)
+ {
+ client->addSurface(surface);
+ this->id_alloc.register_name_id(client->role(), surface);
+ }
+ else
+ {
+ // Store tmp surface and appid for application
+ // who requests setRole after creating shell surface
+ this->tmp_surface2app.emplace(surface, TmpClient{appid, ppid});
+ }
+ }
+}
+
+/**
+ * proxied events
+ */
+void WindowManager::surface_created(unsigned pid, unsigned surface_id)
+{
+ // requestSurface
+ if(this->tmp_surface2app.count(surface_id) != 0)
+ {
+ string appid = this->tmp_surface2app[surface_id].appid;
+ auto client = g_app_list.lookUpClient(appid);
+ if(client != nullptr)
+ {
+ WMError ret = client->addSurface(surface_id);
+ HMI_INFO("Add surface %d to \"%s\"", surface_id, appid.c_str());
+ if(ret != WMError::SUCCESS)
+ {
+ HMI_ERROR("Failed to add surface to client %s", client->appID().c_str());
+ }
+ }
+ this->tmp_surface2app.erase(surface_id);
+ }
+ else
+ {
+ HMI_NOTICE("Unknown surface %d", surface_id);
+ // retrieve ppid
+ std::ostringstream os;
+ os << pid ;
+ string path = "/proc/" + os.str() + "/stat";
+ std::ifstream ifs(path.c_str());
+ string str;
+ unsigned ppid = 0;
+ if(!ifs.fail() && std::getline(ifs, str))
+ {
+ std::sscanf(str.data(), "%*d %*s %*c %d", &ppid);
+ HMI_INFO("Retrieve ppid %d", ppid);
+ }
+ else
+ {
+ HMI_ERROR("Failed to open /proc/%d/stat", pid);
+ HMI_ERROR("File system may be different");
+ return;
+ }
+ struct AfbClosure* c = new struct AfbClosure(pid, ppid, surface_id);
+ // search pid from surfaceID
+ afb_service_call("afm-main", "runners", json_object_new_object(),
+ [](void* closure, int stat, json_object* resp){
+ HMI_DEBUG("check %s", json_object_get_string(resp));
+ struct AfbClosure* c = static_cast<struct AfbClosure*>(closure);
+ HMI_DEBUG("check");
+ if(stat != 0)
+ {
+ HMI_ERROR("Failed to call runners");
+ }
+ else
+ {
+ json_object* j;
+ json_object_object_get_ex(resp, "response", &j);
+ string appid = g_context->searchApp(c->pid, c->ppid, c->surface, j);
+ if(!appid.empty())
+ {
+ g_context->storeSurface(appid, c->ppid, c->surface);
+ }
+ }
+ json_object_put(resp);
+ delete c;
+ }, c);
+ }
+}
+
+void WindowManager::surface_removed(unsigned surface_id)
+{
+ HMI_DEBUG("Delete surface_id %u", surface_id);
+ this->id_alloc.remove_id(surface_id);
+ // this->layers.remove_surface(surface_id);
+ g_app_list.removeSurface(surface_id);
+}
+
+void WindowManager::removeClient(const string &appid)
+{
+ HMI_DEBUG("Remove clinet %s from list", appid.c_str());
+ auto client = g_app_list.lookUpClient(appid);
+ this->lc->terminateApp(client);
+ g_app_list.removeClient(appid);
+}
+
+void WindowManager::exceptionProcessForTransition()
+{
+ unsigned req_num = g_app_list.currentRequestNumber();
+ HMI_SEQ_NOTICE(req_num, "Process exception handling for request. Remove current request %d", req_num);
+ g_app_list.removeRequest(req_num);
+ HMI_SEQ_NOTICE(g_app_list.currentRequestNumber(), "Process next request if exists");
+ this->processNextRequest();
+}
+
+void WindowManager::analyzeReceivedEvent(const char *event, struct json_object *object)
+{
+ HMI_DEBUG("event:%s", event);
+
+ // If receive low can signal
+ if (strstr(event, "low-can"))
+ {
+ // Analyze low can signal
+ const char *signal_name = this->lcc.analyzeCanSignal(object);
+
+ // Create task for car state and input it to PolicyManager
+ Task task = this->convertCanSignalToCarStateTask(signal_name);
+ if (Task::TASK_INVALID != task)
+ {
+ this->inputCarStateTask(task);
+ }
+ }
+}
+
+void WindowManager::timerHandler()
+{
+ unsigned req_num = g_app_list.currentRequestNumber();
+ HMI_SEQ_DEBUG(req_num, "Timer expired remove Request");
+ g_app_list.reqDump();
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+}
+
+void WindowManager::startTransitionWrapper(vector<WMAction> &actions)
+{
+ WMError ret = WMError::UNKNOWN;
+ // req_num is guaranteed by Window Manager
+ unsigned req_num = g_app_list.currentRequestNumber();
+ Task task = Task::TASK_INVALID;
+
+ if (actions.empty())
+ {
+ if (g_app_list.haveRequest())
+ {
+ HMI_SEQ_DEBUG(req_num, "There is no WMAction for this request");
+ goto proc_remove_request;
+ }
+ else
+ {
+ HMI_SEQ_DEBUG(req_num, "There is no request");
+ return;
+ }
+ }
+
+ // Check weather there is the no request task
+ // [The no request task]
+ // - TaskCarState::RESTRICTION_MODE_OFF
+ // - TaskCarState::RESTRICTION_MODE_ON
+ for (const auto &act : actions)
+ {
+ if (TaskCarState::RESTRICTION_MODE_OFF == act.car_state)
+ {
+ task = Task::TASK_RESTRICTION_MODE_OFF;
+ break;
+ }
+ else if (TaskCarState::RESTRICTION_MODE_ON == act.car_state)
+ {
+ task = Task::TASK_RESTRICTION_MODE_ON;
+ break;
+ }
+ }
+
+ // If there is the request-less task, set request here
+ if (Task::TASK_INVALID != task) {
+ unsigned req_num;
+ ret = this->setRequest(task, &req_num);
+
+ if(ret != WMError::SUCCESS)
+ {
+ goto error;
+ }
+ }
+
+ for (auto &act : actions)
+ {
+ if ("" != act.role)
+ {
+ bool found;
+ auto const &surface_id = this->id_alloc.lookup(act.role.c_str());
+ if(surface_id == nullopt)
+ {
+ HMI_SEQ_DEBUG(req_num, "There is not surface id for role:%s", act.role.c_str());
+ continue;
+ }
+
+ std::string appid = g_app_list.getAppID(*surface_id, &found);
+ if (!found)
+ {
+ if (TaskVisible::INVISIBLE == act.visible)
+ {
+ HMI_SEQ_DEBUG(req_num, "role:%s is killed, so do not set this action", act.role.c_str());
+ continue;
+ }
+ else
+ {
+ HMI_SEQ_ERROR(req_num, "appid of role:%s which is visible is not found", act.role.c_str());
+ ret = WMError::FAIL;
+ goto error;
+ }
+ }
+ auto client = g_app_list.lookUpClient(appid);
+ act.req_num = req_num;
+ act.client = client;
+
+ // If Window Manager is master and this action is for slave,
+ // change TaskVisible
+ if (this->wmcon.isMasterMode())
+ {
+ if (this->wmcon.isMasterArea(act.area.c_str()))
+ {
+ HMI_DEBUG("Set TaskVisible::REQ_REMOTE_VISIBLE");
+ act.visible = TaskVisible::REQ_REMOTE_VISIBLE;
+ }
+ // TODO: Check whether role is tbtnavi to request remote invisible
+ else if (("tbtnavi" == act.role) &&
+ (TaskVisible::INVISIBLE == act.visible))
+ {
+ HMI_DEBUG("Set TaskVisible::REQ_REMOTE_INVISIBLE");
+ act.visible = TaskVisible::REQ_REMOTE_INVISIBLE;
+ }
+ }
+ }
+
+ ret = g_app_list.setAction(req_num, act);
+ if (ret != WMError::SUCCESS)
+ {
+ HMI_SEQ_ERROR(req_num, "Setting action is failed");
+ goto error;
+ }
+ }
+
+ HMI_SEQ_DEBUG(req_num, "Start transition.");
+ ret = this->startTransition(req_num);
+ if (ret != WMError::SUCCESS)
+ {
+ if (ret == WMError::NO_LAYOUT_CHANGE)
+ {
+ goto proc_remove_request;
+ }
+ else
+ {
+ HMI_SEQ_ERROR(req_num, "Transition state is failed");
+ goto error;
+ }
+ }
+
+ return;
+
+error:
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(ret));
+ this->pmw.undoState();
+
+proc_remove_request:
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+}
+
+void WindowManager::processError(WMError error)
+{
+ unsigned req_num = g_app_list.currentRequestNumber();
+
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(error));
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+}
+
+void WindowManager::processForRemoteRequest(json_object *data)
+{
+ const char *req = jh::getStringFromJson(data, "req");
+ const char *appid = jh::getStringFromJson(data, "appid");
+ const char *drawing_name = jh::getStringFromJson(data, "drawing_name");
+ const char *drawing_area = jh::getStringFromJson(data, "drawing_area");
+
+ if (!req || !drawing_name)
+ {
+ HMI_ERROR("Parse Error!!");
+ return;
+ }
+
+ if (this->wmcon.isMasterMode())
+ {
+ if (!appid)
+ {
+ HMI_ERROR("Parse Error!!");
+ return;
+ }
+
+ auto reply = [](const char *errmsg) {
+ if (errmsg != nullptr)
+ {
+ HMI_ERROR(errmsg);
+ return;
+ }
+ };
+
+ if ("activateWindow" == std::string(req))
+ {
+ if (!drawing_area)
+ {
+ HMI_ERROR("Parse Error!!");
+ return;
+ }
+
+ this->api_activate_surface_for_slave(
+ appid, drawing_name, drawing_area, reply);
+ }
+ else if ("deactivateWindow" == std::string(req))
+ {
+ this->api_deactivate_surface_for_slave(
+ appid, drawing_name, reply);
+ }
+ else if ("endDraw" == std::string(req))
+ {
+ this->api_enddraw(appid, drawing_name);
+ }
+ }
+ else
+ {
+ if ("syncDraw" == std::string(req))
+ {
+ this->stopTimer();
+
+ if (!appid || !drawing_area)
+ {
+ HMI_ERROR("Parse Error!!");
+ return;
+ }
+
+ unsigned req_num = g_app_list.currentRequestNumber();
+ auto client = g_app_list.lookUpClient(appid);
+
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ // Create action
+ bool end_draw_finished = false;
+ WMAction act
+ {
+ req_num,
+ client,
+ string(c_role),
+ string(drawing_area),
+ TaskVisible::REMOTE_VISIBLE,
+ end_draw_finished,
+ TaskCarState::NO_TASK
+ };
+
+ // Set action
+ WMError ret = g_app_list.setAction(req_num, act);
+ if (ret != WMError::SUCCESS)
+ {
+ HMI_SEQ_ERROR(req_num, "Setting action is failed");
+ return;
+ }
+
+ this->emit_syncdraw(string(drawing_name), string(drawing_area));
+ this->wmcon.startSyncDrawForRemote(appid);
+ this->setTimer();
+ }
+ else if ("activated" == std::string(req))
+ {
+ this->emit_visible(drawing_name);
+ this->emit_activated(drawing_name);
+ }
+ else if ("deactivated" == std::string(req))
+ {
+ this->stopTimer();
+
+ if (!appid || !drawing_area)
+ {
+ HMI_ERROR("Parse Error!!");
+ return;
+ }
+
+ unsigned req_num = g_app_list.currentRequestNumber();
+ auto client = g_app_list.lookUpClient(appid);
+
+ // TODO: application requests by old role,
+ // so convert role old to new
+ const char *c_role = this->convertRoleOldToNew(drawing_name);
+
+ // Create action
+ bool end_draw_finished = true;
+ WMAction act
+ {
+ req_num,
+ client,
+ string(c_role),
+ "",
+ TaskVisible::REMOTE_INVISIBLE,
+ end_draw_finished,
+ TaskCarState::NO_TASK
+ };
+
+ this->lc->visibilityChange(act);
+ this->lc->renderLayers();
+ this->lc->renderLayersRemote();
+
+ this->emit_invisible(drawing_name);
+ this->emit_deactivated(drawing_name);
+ this->emitScreenUpdated(req_num);
+
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+ }
+ else if ("flushDraw" == std::string(req))
+ {
+ this->emit_flushdraw(drawing_name);
+ }
+ }
+}
+
+/*
+ ******* Private Functions *******
+ */
+
+void WindowManager::emit_activated(char const *label)
+{
+ this->send_event(kListEventName[Event_Active], label);
+}
+
+void WindowManager::emit_deactivated(char const *label)
+{
+ this->send_event(kListEventName[Event_Inactive], label);
+}
+
+void WindowManager::emit_syncdraw(char const *label, char const *area, int x, int y, int w, int h)
+{
+ this->send_event(kListEventName[Event_SyncDraw], label, area, x, y, w, h);
+}
+
+void WindowManager::emit_syncdraw(const string &role, const string &area)
+{
+ rect rect = this->lc->getAreaSize(area);
+ this->send_event(kListEventName[Event_SyncDraw],
+ role.c_str(), area.c_str(), rect.x, rect.y, rect.w, rect.h);
+}
+
+void WindowManager::emit_flushdraw(char const *label)
+{
+ this->send_event(kListEventName[Event_FlushDraw], label);
+}
+
+void WindowManager::emit_visible(char const *label, bool is_visible)
+{
+ this->send_event(is_visible ? kListEventName[Event_Visible] : kListEventName[Event_Invisible], label);
+}
+
+void WindowManager::emit_invisible(char const *label)
+{
+ return emit_visible(label, false);
+}
+
+void WindowManager::emit_visible(char const *label) { return emit_visible(label, true); }
+
+void WindowManager::emitHeadlampOff()
+{
+ // Send HeadlampOff event for all application
+ this->send_event(kListEventName[Event_HeadlampOff]);
+}
+
+void WindowManager::emitHeadlampOn()
+{
+ // Send HeadlampOn event for all application
+ this->send_event(kListEventName[Event_HeadlampOn]);
+}
+
+void WindowManager::emitParkingBrakeOff()
+{
+ // Send ParkingBrakeOff event for all application
+ this->send_event(kListEventName[Event_ParkingBrakeOff]);
+}
+
+void WindowManager::emitParkingBrakeOn()
+{
+ // Send ParkingBrakeOn event for all application
+ this->send_event(kListEventName[Event_ParkingBrakeOn]);
+}
+
+void WindowManager::emitLightstatusBrakeOff()
+{
+ // Send LightstatusBrakeOff event for all application
+ this->send_event(kListEventName[Event_LightstatusBrakeOff]);
+}
+
+void WindowManager::emitLightstatusBrakeOn()
+{
+ // Send LightstatusBrakeOn event for all application
+ this->send_event(kListEventName[Event_LightstatusBrakeOn]);
+}
+
+void WindowManager::emitCarStop()
+{
+ // Send CarStop event for all application
+ this->send_event(kListEventName[Event_CarStop]);
+}
+
+void WindowManager::emitCarRun()
+{
+ // Send CarRun event for all application
+ this->send_event(kListEventName[Event_CarRun]);
+}
+
+WMError WindowManager::setRequest(const string& appid, const string &role, const string &area,
+ Task task, unsigned* req_num)
+{
+ if (!g_app_list.contains(appid))
+ {
+ return WMError::NOT_REGISTERED;
+ }
+
+ auto client = g_app_list.lookUpClient(appid);
+
+ /*
+ * Queueing Phase
+ */
+ unsigned current = g_app_list.currentRequestNumber();
+ unsigned requested_num = g_app_list.getRequestNumber(appid);
+ if (requested_num != 0)
+ {
+ HMI_SEQ_INFO(requested_num,
+ "%s %s %s request is already queued", appid.c_str(), role.c_str(), area.c_str());
+ return REQ_REJECTED;
+ }
+
+ WMRequest req = WMRequest(appid, role, area, task);
+ unsigned new_req = g_app_list.addRequest(req);
+ *req_num = new_req;
+ g_app_list.reqDump();
+
+ HMI_SEQ_DEBUG(current, "%s start sequence with %s, %s", appid.c_str(), role.c_str(), area.c_str());
+
+ return WMError::SUCCESS;
+}
+
+WMError WindowManager::setRequest(Task task, unsigned* req_num)
+{
+ /*
+ * Queueing Phase
+ */
+ unsigned current = g_app_list.currentRequestNumber();
+
+ WMRequest req = WMRequest(task);
+ unsigned new_req = g_app_list.addRequest(req);
+ *req_num = new_req;
+ g_app_list.reqDump();
+
+ HMI_SEQ_DEBUG(current, "start sequence for task:%d", task);
+
+ return WMError::SUCCESS;
+}
+
+WMError WindowManager::setRequestForSlave(const string& appid, const string &role, const string &area,
+ Task task, unsigned* req_num)
+{
+ /*
+ * Queueing Phase
+ */
+ unsigned current = g_app_list.currentRequestNumber();
+ unsigned requested_num = g_app_list.getRequestNumber(appid);
+ if (requested_num != 0)
+ {
+ HMI_SEQ_INFO(requested_num,
+ "%s %s %s request is already queued", appid.c_str(), role.c_str(), area.c_str());
+ return REQ_REJECTED;
+ }
+
+ WMRequest req = WMRequest(appid, role, area, task);
+ unsigned new_req = g_app_list.addRequest(req);
+ *req_num = new_req;
+ g_app_list.reqDump();
+
+ HMI_SEQ_DEBUG(current, "%s start sequence with %s, %s", appid.c_str(), role.c_str(), area.c_str());
+
+ return WMError::SUCCESS;
+}
+
+WMError WindowManager::checkPolicy(unsigned req_num)
+{
+ /*
+ * Check Policy
+ */
+ // get current trigger
+ bool found = false;
+ WMError ret = WMError::LAYOUT_CHANGE_FAIL;
+ auto trigger = g_app_list.getRequest(req_num, &found);
+ if (!found)
+ {
+ ret = WMError::NO_ENTRY;
+ return ret;
+ }
+ string req_area = trigger.area;
+
+ if (trigger.task == Task::TASK_ALLOCATE)
+ {
+ const char *msg = this->check_surface_exist(trigger.role.c_str());
+
+ if (msg)
+ {
+ HMI_SEQ_ERROR(req_num, msg);
+ return ret;
+ }
+ }
+
+ // Input event data to PolicyManager
+ if (0 > this->pmw.setInputEventData(trigger.task, trigger.role, trigger.area))
+ {
+ HMI_SEQ_ERROR(req_num, "Failed to set input event data to PolicyManager");
+ return ret;
+ }
+
+ // Execute state transition of PolicyManager
+ if (0 > this->pmw.executeStateTransition())
+ {
+ HMI_SEQ_ERROR(req_num, "Failed to execute state transition of PolicyManager");
+ return ret;
+ }
+
+ ret = WMError::SUCCESS;
+
+ g_app_list.reqDump();
+
+ return ret;
+}
+
+WMError WindowManager::checkPolicyForSlave(unsigned req_num)
+{
+ /*
+ * Check Policy
+ */
+ // get current trigger
+ bool found = false;
+ WMError ret = WMError::LAYOUT_CHANGE_FAIL;
+ auto trigger = g_app_list.getRequest(req_num, &found);
+ if (!found)
+ {
+ ret = WMError::NO_ENTRY;
+ return ret;
+ }
+ string req_area = trigger.area;
+
+ // Input event data to PolicyManager
+ if (0 > this->pmw.setInputEventData(trigger.task, trigger.role, trigger.area))
+ {
+ HMI_SEQ_ERROR(req_num, "Failed to set input event data to PolicyManager");
+ return ret;
+ }
+
+ // Execute state transition of PolicyManager
+ if (0 > this->pmw.executeStateTransition())
+ {
+ HMI_SEQ_ERROR(req_num, "Failed to execute state transition of PolicyManager");
+ return ret;
+ }
+
+ ret = WMError::SUCCESS;
+
+ g_app_list.reqDump();
+
+ return ret;
+}
+
+WMError WindowManager::startTransition(unsigned req_num)
+{
+ bool sync_draw_happen = false;
+ bool found = false;
+ WMError ret = WMError::SUCCESS;
+ auto actions = g_app_list.getActions(req_num, &found);
+ if (!found)
+ {
+ ret = WMError::NO_ENTRY;
+ HMI_SEQ_ERROR(req_num,
+ "Window Manager bug :%s : Action is not set", errorDescription(ret));
+ return ret;
+ }
+
+ g_app_list.reqDump();
+ for (const auto &action : actions)
+ {
+ // TODO: application requests by old role,
+ // so convert role new to old for emitting event
+ string old_role = this->rolenew2old[action.role];
+
+ if (action.visible == TaskVisible::VISIBLE)
+ {
+ sync_draw_happen = true;
+
+ this->emit_syncdraw(old_role, action.area);
+ /* TODO: emit event for app not subscriber
+ if(g_app_list.contains(y.appid))
+ g_app_list.lookUpClient(y.appid)->emit_syncdraw(y.role, y.area); */
+ }
+ else if(action.visible == TaskVisible::REQ_REMOTE_VISIBLE)
+ {
+ // If this action is for slave, send to slave
+ this->wmcon.sendRequest("syncDraw", action.client->appID().c_str(),
+ old_role.c_str(), action.area.c_str());
+ }
+ else if (action.car_state != TaskCarState::NO_TASK)
+ {
+ this->transitionCarState(action.car_state);
+ }
+ }
+
+ if (sync_draw_happen)
+ {
+ this->setTimer();
+ }
+ else
+ {
+ // deactivate only, no syncDraw
+ // Make it deactivate here
+ for (const auto &x : actions)
+ {
+ this->lc->visibilityChange(x);
+ string old_role = this->rolenew2old[x.role];
+
+ if (x.visible == TaskVisible::INVISIBLE)
+ {
+ emit_deactivated(old_role.c_str());
+ }
+ else if (x.visible == TaskVisible::REQ_REMOTE_INVISIBLE)
+ {
+ // If this action is for slave, send to slave
+ int i_ret = this->wmcon.sendRequest("deactivated", x.client->appID().c_str(),
+ old_role.c_str(), "");
+ if (0 > i_ret)
+ {
+ ret = WMError::FAIL;
+ }
+ }
+
+ /* if (g_app_list.contains(x.appid))
+ {
+ auto client = g_app_list.lookUpClient(x.appid);
+ //this->deactivate(client->surfaceID(x.role));
+ } */
+ }
+ this->lc->renderLayers();
+ this->lc->renderLayersRemote();
+ ret = WMError::NO_LAYOUT_CHANGE;
+ }
+ return ret;
+}
+
+void WindowManager::transitionCarState(TaskCarState task)
+{
+ if (TaskCarState::PARKING_BRAKE_OFF == task)
+ {
+ this->crr_car_info.parking_brake_stt = false;
+ this->emitParkingBrakeOff();
+ }
+ else if (TaskCarState::PARKING_BRAKE_ON == task)
+ {
+ this->crr_car_info.parking_brake_stt = true;
+ this->emitParkingBrakeOn();
+ }
+ else if (TaskCarState::ACCEL_PEDAL_OFF == task)
+ {
+ this->crr_car_info.accel_pedal_stt = false;
+ }
+ else if (TaskCarState::ACCEL_PEDAL_ON == task)
+ {
+ this->crr_car_info.accel_pedal_stt = true;
+ }
+ else if (TaskCarState::HEDLAMP_OFF == task)
+ {
+ this->crr_car_info.headlamp_stt = false;
+ this->emitHeadlampOff();
+ }
+ else if (TaskCarState::HEDLAMP_ON == task)
+ {
+ this->crr_car_info.headlamp_stt = true;
+ this->emitHeadlampOn();
+ }
+ else if (TaskCarState::LIGHTSTATUS_BRAKE_OFF == task)
+ {
+ this->crr_car_info.lightstatus_brake_stt = false;
+ this->emitLightstatusBrakeOff();
+ }
+ else if (TaskCarState::LIGHTSTATUS_BRAKE_ON == task)
+ {
+ this->crr_car_info.lightstatus_brake_stt = true;
+ this->emitLightstatusBrakeOn();
+ }
+ else if (TaskCarState::CAR_STOP == task)
+ {
+ this->crr_car_info.running_stt = false;
+ this->emitCarStop();
+ }
+ else if (TaskCarState::CAR_RUN == task)
+ {
+ this->crr_car_info.running_stt = true;
+ this->emitCarRun();
+ }
+}
+
+WMError WindowManager::doEndDraw(unsigned req_num)
+{
+ // get actions
+ bool found;
+ auto actions = g_app_list.getActions(req_num, &found);
+ WMError ret = WMError::SUCCESS;
+ if (!found)
+ {
+ ret = WMError::NO_ENTRY;
+ return ret;
+ }
+
+ HMI_SEQ_INFO(req_num, "do endDraw");
+
+ // layout change and make it visible
+ for (const auto &act : actions)
+ {
+ if(act.visible != TaskVisible::NO_CHANGE)
+ {
+ // layout change
+ ret = this->lc->layoutChange(act);
+ if(ret != WMError::SUCCESS)
+ {
+ HMI_SEQ_WARNING(req_num,
+ "Failed to manipulate surfaces while state change : %s", errorDescription(ret));
+ return ret;
+ }
+ ret = this->lc->visibilityChange(act);
+
+ // Emit active/deactive event
+ string old_role = this->rolenew2old[act.role];
+ if(act.visible == TaskVisible::VISIBLE)
+ {
+ emit_visible(old_role.c_str());
+ emit_activated(old_role.c_str());
+ }
+ else if(act.visible == TaskVisible::REQ_REMOTE_VISIBLE)
+ {
+ // If this action is for slave, send to slave
+ int i_ret = this->wmcon.sendRequest("activated", "", old_role.c_str(), "");
+ if (0 > i_ret)
+ {
+ ret = WMError::FAIL;
+ }
+ }
+ else if(act.visible == TaskVisible::REQ_REMOTE_INVISIBLE)
+ {
+ // If this action is for slave, send to slave
+ int i_ret = this->wmcon.sendRequest("deactivated", "", old_role.c_str(), "");
+ if (0 > i_ret)
+ {
+ ret = WMError::FAIL;
+ }
+ }
+ else if((act.visible == TaskVisible::REMOTE_VISIBLE) ||
+ (act.visible == TaskVisible::REMOTE_INVISIBLE))
+ {
+ // nop because emit active/deactive by event from remote
+ }
+ else
+ {
+ emit_invisible(old_role.c_str());
+ emit_deactivated(old_role.c_str());
+ }
+
+ if (ret != WMError::SUCCESS)
+ {
+ HMI_SEQ_WARNING(req_num,
+ "Failed to manipulate surfaces while state change : %s", errorDescription(ret));
+ return ret;
+ }
+ HMI_SEQ_DEBUG(req_num, "visible %s", act.role.c_str());
+ }
+ }
+ this->lc->renderLayers();
+ this->lc->renderLayersRemote();
+
+ HMI_SEQ_INFO(req_num, "emit flushDraw");
+
+ for(const auto &act_flush : actions)
+ {
+ // TODO: application requests by old role,
+ // so convert role new to old for emitting event
+ string old_role = this->rolenew2old[act_flush.role];
+
+ if(act_flush.visible == TaskVisible::VISIBLE)
+ {
+ this->emit_flushdraw(old_role.c_str());
+ }
+ else if(act_flush.visible == TaskVisible::REQ_REMOTE_VISIBLE)
+ {
+ // If this action is for slave, send to slave
+ this->wmcon.sendRequest("flushDraw", "", old_role.c_str(), "");
+ }
+ }
+
+ return ret;
+}
+
+void WindowManager::emitScreenUpdated(unsigned req_num)
+{
+ // Get visible apps
+ HMI_SEQ_DEBUG(req_num, "emit screen updated");
+ bool found = false;
+ auto actions = g_app_list.getActions(req_num, &found);
+
+ HMI_DEBUG("@@@@@");
+ // create json object
+ json_object *j = json_object_new_object();
+ json_object *jarray = json_object_new_array();
+
+ for(const auto& action: actions)
+ {
+ if((action.visible == TaskVisible::VISIBLE) ||
+ (action.visible == TaskVisible::REMOTE_VISIBLE))
+ {
+ json_object_array_add(jarray, json_object_new_string(action.client->appID().c_str()));
+ }
+ }
+ json_object_object_add(j, kKeyIds, jarray);
+ HMI_SEQ_INFO(req_num, "Visible app: %s", json_object_get_string(j));
+
+ int ret = afb_event_push(
+ this->map_afb_event[kListEventName[Event_ScreenUpdated]], j);
+ if (ret != 0)
+ {
+ HMI_DEBUG("afb_event_push failed: %m");
+ }
+}
+
+void WindowManager::setTimer()
+{
+ struct timespec ts;
+ if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) {
+ HMI_ERROR("Could't set time (clock_gettime() returns with error");
+ return;
+ }
+
+ HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "Timer set activate");
+ if (g_timer_ev_src == nullptr)
+ {
+ // firsttime set into sd_event
+ int ret = sd_event_add_time(afb_daemon_get_event_loop(), &g_timer_ev_src,
+ CLOCK_BOOTTIME, (uint64_t)(ts.tv_sec + kTimeOut) * 1000000ULL, 1, processTimerHandler, this);
+ if (ret < 0)
+ {
+ HMI_ERROR("Could't set timer");
+ }
+ }
+ else
+ {
+ // update timer limitation after second time
+ sd_event_source_set_time(g_timer_ev_src, (uint64_t)(ts.tv_sec + kTimeOut) * 1000000ULL);
+ sd_event_source_set_enabled(g_timer_ev_src, SD_EVENT_ONESHOT);
+ }
+}
+
+void WindowManager::stopTimer()
+{
+ unsigned req_num = g_app_list.currentRequestNumber();
+ HMI_SEQ_DEBUG(req_num, "Timer stop");
+ int rc = sd_event_source_set_enabled(g_timer_ev_src, SD_EVENT_OFF);
+ if (rc < 0)
+ {
+ HMI_SEQ_ERROR(req_num, "Timer stop failed");
+ }
+}
+
+void WindowManager::processNextRequest()
+{
+ g_app_list.next();
+ g_app_list.reqDump();
+ unsigned req_num = g_app_list.currentRequestNumber();
+ if (g_app_list.haveRequest())
+ {
+ HMI_SEQ_DEBUG(req_num, "Process next request");
+ WMError rc = checkPolicy(req_num);
+ if (rc != WMError::SUCCESS)
+ {
+ HMI_SEQ_ERROR(req_num, errorDescription(rc));
+ }
+ }
+ else
+ {
+ HMI_SEQ_DEBUG(req_num, "Nothing Request. Waiting Request");
+ }
+}
+
+const char* WindowManager::convertRoleOldToNew(char const *old_role)
+{
+ const char *new_role = nullptr;
+
+ for (auto const &on : this->roleold2new)
+ {
+ std::regex regex = std::regex(on.first);
+ if (std::regex_match(old_role, regex))
+ {
+ // role is old. So convert to new.
+ new_role = on.second.c_str();
+ break;
+ }
+ }
+
+ if (nullptr == new_role)
+ {
+ // role is new or fallback.
+ new_role = old_role;
+ }
+
+ HMI_DEBUG("old:%s -> new:%s", old_role, new_role);
+
+ return new_role;
+}
+
+int WindowManager::loadOldRolesConfigFile()
+{
+ // Get afm application installed dir
+ char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
+ HMI_DEBUG("afm_app_install_dir:%s", afm_app_install_dir);
+
+ string file_name;
+ if (!afm_app_install_dir)
+ {
+ HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
+ }
+ else
+ {
+ file_name = string(afm_app_install_dir) + string(kPathOldRolesConfigFile);
+ }
+
+ // Load old_rolea config file
+ json_object* json_obj;
+ int ret = jh::inputJsonFilie(file_name.c_str(), &json_obj);
+ if (0 > ret)
+ {
+ HMI_ERROR("Could not open %s, so use default old_roles information", kPathOldRolesConfigFile);
+ json_obj = json_tokener_parse(kDefaultOldRolesConfig);
+ }
+ HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
+
+ // Perse apps
+ json_object* json_cfg;
+ if (!json_object_object_get_ex(json_obj, "old_roles", &json_cfg))
+ {
+ HMI_ERROR("Parse Error!!");
+ return -1;
+ }
+
+ int len = json_object_array_length(json_cfg);
+ HMI_DEBUG("json_cfg len:%d", len);
+ HMI_DEBUG("json_cfg dump:%s", json_object_get_string(json_cfg));
+
+ for (int i=0; i<len; i++)
+ {
+ json_object* json_tmp = json_object_array_get_idx(json_cfg, i);
+
+ const char* old_role = jh::getStringFromJson(json_tmp, "name");
+ if (nullptr == old_role)
+ {
+ HMI_ERROR("Parse Error!!");
+ return -1;
+ }
+
+ const char* new_role = jh::getStringFromJson(json_tmp, "new");
+ if (nullptr == new_role)
+ {
+ HMI_ERROR("Parse Error!!");
+ return -1;
+ }
+
+ this->roleold2new[old_role] = string(new_role);
+ }
+
+ // Check
+ for(auto itr = this->roleold2new.begin();
+ itr != this->roleold2new.end(); ++itr)
+ {
+ HMI_DEBUG(">>> role old:%s new:%s",
+ itr->first.c_str(), itr->second.c_str());
+ }
+
+ // Release json_object
+ json_object_put(json_obj);
+
+ return 0;
+}
+
+Task WindowManager::convertCanSignalToCarStateTask(const char *signal_name)
+{
+ wm::LowCanClient *lcc = &(this->lcc);
+ Task task = Task::TASK_INVALID;
+
+ // If car info is updated, set car state change event
+ if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoParkingBrake]))
+ {
+ HMI_DEBUG("Parking Brake state is changed");
+
+ if (lcc->getCurrentParkingBrakeState())
+ {
+ task = wm::Task::TASK_PARKING_BRAKE_ON;
+ }
+ else
+ {
+ task = wm::Task::TASK_PARKING_BRAKE_OFF;
+ }
+ }
+ else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoAccelPedalPos]))
+ {
+ // Update accel pedal position
+ this->crr_car_info.accel_pedal_pos = lcc->getCurrentAccelPedalPosition();
+
+ if (lcc->isChangedAccelPedalState())
+ {
+ HMI_DEBUG("Accelerator Pedal state is changed");
+
+ if (lcc->getCurrentAccelPedalState())
+ {
+ task = wm::Task::TASK_ACCEL_PEDAL_ON;
+ }
+ else
+ {
+ task = wm::Task::TASK_ACCEL_PEDAL_OFF;
+ }
+ }
+ }
+ else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoHeadlame]))
+ {
+ HMI_DEBUG("Headlamp state is changed");
+
+ if (lcc->getCurrentHeadlampState())
+ {
+ task = wm::Task::TASK_HEDLAMP_ON;
+ }
+ else
+ {
+ task = wm::Task::TASK_HEDLAMP_OFF;
+ }
+ }
+ else if (strstr(signal_name, lcc->kSignalName[lcc->SignalNoLightstatusBrake]))
+ {
+ HMI_DEBUG("Lightstatus Brake state is changed");
+
+ if (lcc->getCurrentLightstatusBrakeState())
+ {
+ task = wm::Task::TASK_LIGHTSTATUS_BRAKE_ON;
+ }
+ else
+ {
+ task = wm::Task::TASK_LIGHTSTATUS_BRAKE_OFF;
+ }
+ }
+ return task;
+}
+
+void WindowManager::inputCarStateTask(Task task)
+{
+ unsigned req_num = 0;
+ WMError ret = WMError::UNKNOWN;
+
+ ret = this->setRequest(task, &req_num);
+
+ if(ret != WMError::SUCCESS)
+ {
+ HMI_ERROR(errorDescription(ret));
+ return;
+ }
+
+ if (req_num != g_app_list.currentRequestNumber())
+ {
+ // Add request, then invoked after the previous task is finished
+ HMI_SEQ_DEBUG(req_num, "request is accepted");
+ return;
+ }
+
+ /*
+ * Do allocate tasks
+ */
+ ret = this->checkPolicy(req_num);
+
+ if (ret != WMError::SUCCESS)
+ {
+ //this->emit_error()
+ HMI_SEQ_ERROR(req_num, errorDescription(ret));
+ g_app_list.removeRequest(req_num);
+ this->processNextRequest();
+ }
+}
+
+const char *WindowManager::check_surface_exist(const char *drawing_name)
+{
+ auto const &surface_id = this->id_alloc.lookup(string(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!";
+ } */
+
+ HMI_DEBUG("surface %d is detected", *surface_id);
+ return nullptr;
+}
+
+const char* WindowManager::kDefaultOldRolesConfig = "{ \
+ \"old_roles\": [ \
+ { \
+ \"name\": \"HomeScreen\", \
+ \"new\": \"homescreen\" \
+ }, \
+ { \
+ \"name\": \"Music\", \
+ \"new\": \"music\" \
+ }, \
+ { \
+ \"name\": \"MediaPlayer\", \
+ \"new\": \"music\" \
+ }, \
+ { \
+ \"name\": \"Video\", \
+ \"new\": \"video\" \
+ }, \
+ { \
+ \"name\": \"VideoPlayer\", \
+ \"new\": \"video\" \
+ }, \
+ { \
+ \"name\": \"WebBrowser\", \
+ \"new\": \"browser\" \
+ }, \
+ { \
+ \"name\": \"Radio\", \
+ \"new\": \"radio\" \
+ }, \
+ { \
+ \"name\": \"Phone\", \
+ \"new\": \"phone\" \
+ }, \
+ { \
+ \"name\": \"Navigation\", \
+ \"new\": \"map\" \
+ }, \
+ { \
+ \"name\": \"HVAC\", \
+ \"new\": \"hvac\" \
+ }, \
+ { \
+ \"name\": \"Settings\", \
+ \"new\": \"settings\" \
+ }, \
+ { \
+ \"name\": \"Dashboard\", \
+ \"new\": \"dashboard\" \
+ }, \
+ { \
+ \"name\": \"POI\", \
+ \"new\": \"poi\" \
+ }, \
+ { \
+ \"name\": \"Mixer\", \
+ \"new\": \"mixer\" \
+ }, \
+ { \
+ \"name\": \"Restriction\", \
+ \"new\": \"restriction\" \
+ }, \
+ { \
+ \"name\": \"^OnScreen.*\", \
+ \"new\": \"on_screen\" \
+ } \
+ ] \
+}";
+
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/window_manager.hpp b/demo#3/common/agl-service-windowmanager/src/window_manager.hpp
new file mode 100644
index 0000000..c4ad0f5
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/window_manager.hpp
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 WINDOW_MANAGER_HPP
+#define WINDOW_MANAGER_HPP
+
+#include <atomic>
+#include <memory>
+#include <unordered_map>
+#include <experimental/optional>
+#include "result.hpp"
+#include "pm_wrapper.hpp"
+#include "util.hpp"
+#include "request.hpp"
+#include "wm_error.hpp"
+#include "wm_layer_control.hpp"
+#include "wm_connection.hpp"
+#include "low_can_client.hpp"
+extern "C"
+{
+#include <afb/afb-binding.h>
+}
+
+struct json_object;
+
+namespace wm
+{
+
+using std::experimental::optional;
+
+/* DrawingArea name used by "{layout}.{area}" */
+extern const char kNameLayoutNormal[];
+extern const char kNameLayoutSplit[];
+extern const char kNameAreaFull[];
+extern const char kNameAreaMain[];
+extern const char kNameAreaSub[];
+
+/* Key for json obejct */
+extern const char kKeyDrawingName[];
+extern const char kKeyDrawingArea[];
+extern const char kKeyDrawingRect[];
+extern const char kKeyX[];
+extern const char kKeyY[];
+extern const char kKeyWidth[];
+extern const char kKeyHeigh[];
+extern const char kKeyWidthPixel[];
+extern const char kKeyHeightPixel[];
+extern const char kKeyWidthMm[];
+extern const char kKeyHeightMm[];
+extern const char kKeyScale[];
+extern const char kKeyIds[];
+
+struct id_allocator
+{
+ unsigned next = 1;
+
+ // Surfaces that where requested but not yet created
+ std::unordered_map<unsigned, std::string> id2name;
+ 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->name2id[name] = sid;
+ HMI_DEBUG("allocated new id %u with name %s", sid, name.c_str());
+ return sid;
+ }
+
+ // Insert a new ID which defined outside
+ void register_name_id(std::string const &name, unsigned sid)
+ {
+ this->id2name[sid] = name;
+ this->name2id[name] = sid;
+ HMI_DEBUG("register id %u with name %s", sid, name.c_str());
+ return;
+ }
+
+ // 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
+ 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 TmpClient
+{
+ std::string appid;
+ unsigned pid;
+};
+
+struct TmpService
+{
+ std::string appid; // Used to search who create service surface
+ std::string dest; // Used to attach service to destination application
+ std::string service;// The name of service surface
+ std::string uuid; // uuid
+ TmpService(const std::string& app, const std::string& dst,
+ const std::string& svc, const std::string& uuid)
+ : appid(app), dest(dst), service(svc), uuid(uuid) {}
+};
+
+struct CarInfo
+{
+ CarInfo()
+ : parking_brake_stt(true),
+ accel_pedal_stt(false),
+ accel_pedal_pos(0.0),
+ running_stt(false),
+ headlamp_stt(false),
+ lightstatus_brake_stt(true)
+ {};
+
+ bool parking_brake_stt;
+ bool accel_pedal_stt;
+ double accel_pedal_pos;
+ bool running_stt;
+ bool headlamp_stt;
+ bool lightstatus_brake_stt;
+};
+
+class WindowManager
+{
+ public:
+ typedef std::unordered_map<uint32_t, struct rect> rect_map;
+ typedef std::function<void(const char *err_msg)> reply_func;
+
+ enum EventType
+ {
+ Event_Val_Min = 0,
+
+ Event_Active = Event_Val_Min,
+ Event_Inactive,
+
+ Event_Visible,
+ Event_Invisible,
+
+ Event_SyncDraw,
+ Event_FlushDraw,
+
+ Event_ScreenUpdated,
+
+ Event_HeadlampOff,
+ Event_HeadlampOn,
+
+ Event_ParkingBrakeOff,
+ Event_ParkingBrakeOn,
+
+ Event_LightstatusBrakeOff,
+ Event_LightstatusBrakeOn,
+
+ Event_CarStop,
+ Event_CarRun,
+
+ Event_Error,
+
+ Event_Val_Max = Event_Error,
+ };
+
+ explicit WindowManager();
+ ~WindowManager() = default;
+
+ WindowManager(WindowManager const &) = delete;
+ WindowManager &operator=(WindowManager const &) = delete;
+ WindowManager(WindowManager &&) = delete;
+ WindowManager &operator=(WindowManager &&) = delete;
+
+ int init();
+
+ result<int> api_request_surface(char const *appid, char const *role);
+ char const *api_request_surface(char const *appid, char const *role, char const *ivi_id);
+ bool api_set_role(char const *appid, char const *role);
+ void api_activate_surface(char const *appid, char const *role, char const *drawing_area, const reply_func &reply);
+ void api_activate_surface_for_slave(char const *appid, char const *drawing_name,
+ char const *drawing_area, const reply_func &reply);
+ void api_activate_surface_to_master(char const *appid, char const *drawing_name,
+ char const *drawing_area, const reply_func &reply);
+ void api_deactivate_surface(char const *appid, char const *role, const reply_func &reply);
+ void api_deactivate_surface_for_slave(char const *appid, char const *drawing_name,
+ const reply_func &reply);
+ void api_deactivate_surface_to_master(char const *appid, char const *drawing_name,
+ const reply_func &reply);
+ void api_enddraw(char const *appid, char const *role);
+ void api_enddraw_for_remote(char const *appid, char const *drawing_name);
+ bool api_client_set_render_order(const char *appid, const std::vector<std::string> &render_order);
+ std::string api_client_attach_service_surface(const char* appid, const char* dest, const char* service_surface);
+ result<json_object *> api_get_display_info();
+ result<json_object *> api_get_area_info(char const *role);
+ result<json_object *> api_get_car_info(char const *label);
+ void send_event(char const *evname);
+ void send_event(char const *evname, char const *label);
+ void send_event(char const *evname, char const *label, char const *area, int x, int y, int w, int h);
+
+ // Events from the compositor we are interested in
+ void surface_created(unsigned pid, unsigned surface_id);
+ void surface_removed(unsigned surface_id);
+
+ void removeClient(const std::string &appid);
+ void exceptionProcessForTransition();
+ const char* convertRoleOldToNew(char const *role);
+
+ void analyzeReceivedEvent(const char *event, struct json_object *object);
+
+ // Do not use this function
+ void timerHandler();
+ void startTransitionWrapper(std::vector<WMAction> &actions);
+ void processError(WMError error);
+ void processForRemoteRequest(json_object *data);
+ std::string searchApp(unsigned pid, unsigned ppid, unsigned surface, json_object* resp);
+ void storeSurface(const std::string& appid, unsigned ppid, unsigned surface);
+
+ const std::vector<const char *> kListEventName{
+ "active",
+ "inactive",
+ "visible",
+ "invisible",
+ "syncDraw",
+ "flushDraw",
+ "screenUpdated",
+ "headlampOff",
+ "headlampOn",
+ "parkingBrakeOff",
+ "parkingBrakeOn",
+ "lightstatusBrakeOff",
+ "lightstatusBrakeOn",
+ "carStop",
+ "carRun",
+ "error"};
+ std::map<const char *, struct afb_event> map_afb_event;
+
+ WMConnection wmcon;
+
+ private:
+ // WM Events to clients
+ void emit_activated(char const *label);
+ void emit_deactivated(char const *label);
+ void emit_syncdraw(char const *label, char const *area, int x, int y, int w, int h);
+ void emit_syncdraw(const std::string &role, const std::string &area);
+ 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 emitHeadlampOff();
+ void emitHeadlampOn();
+ void emitParkingBrakeOff();
+ void emitParkingBrakeOn();
+ void emitLightstatusBrakeOff();
+ void emitLightstatusBrakeOn();
+ void emitCarStop();
+ void emitCarRun();
+
+ WMError setRequest(const std::string &appid, const std::string &role, const std::string &area,
+ Task task, unsigned *req_num);
+ WMError setRequest(Task task, unsigned* req_num);
+ WMError setRequestForSlave(const std::string& appid, const std::string &role,
+ const std::string &area, Task task, unsigned* req_num);
+ WMError checkPolicy(unsigned req_num);
+ WMError checkPolicyForSlave(unsigned req_num);
+ WMError startTransition(unsigned req_num);
+ void transitionCarState(TaskCarState task);
+
+ WMError doEndDraw(unsigned req_num);
+ void emitScreenUpdated(unsigned req_num);
+
+ void setTimer();
+ void stopTimer();
+ void processNextRequest();
+
+ int loadOldRolesConfigFile();
+
+ Task convertCanSignalToCarStateTask(const char *signal_name);
+ void inputCarStateTask(Task task);
+
+ const char *check_surface_exist(const char *role);
+
+ private:
+ std::unordered_map<std::string, std::string> roleold2new;
+ std::unordered_map<std::string, std::string> rolenew2old;
+ std::shared_ptr<LayerControl> lc;
+
+ LowCanClient lcc;
+ CarInfo crr_car_info;
+
+ PMWrapper pmw;
+
+ // ID allocation and proxy methods for lookup
+ struct id_allocator id_alloc;
+ // Surface are info (x, y, w, h)
+ rect_map area_info;
+ // FOR CES DEMO
+ std::unordered_map<unsigned, struct TmpClient> tmp_surface2app;
+ std::vector<struct TmpService> tmp_services;
+ static const char* kDefaultOldRolesConfig;
+};
+
+} // namespace wm
+
+#endif // WINDOW_MANAGER_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_client.cpp b/demo#3/common/agl-service-windowmanager/src/wm_client.cpp
new file mode 100644
index 0000000..f2ad7be
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_client.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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-c/json.h>
+#include "wm_client.hpp"
+#include "util.hpp"
+#include <ilm/ilm_control.h>
+#include <uuid/uuid.h>
+
+
+#define INVALID_SURFACE_ID 0
+
+using std::string;
+using std::vector;
+
+namespace wm
+{
+
+static const vector<string> kWMEvents = {
+ // Private event for applications
+ "syncDraw", "flushDraw", "visible", "invisible", "active", "inactive", "error"};
+static const vector<string> kErrorDescription = {
+ "unknown-error"};
+
+static const char kKeyDrawingName[] = "drawing_name";
+static const char kKeyrole[] = "role";
+static const char kKeyError[] = "error";
+static const char kKeyErrorDesc[] = "kErrorDescription";
+
+WMClient::WMClient(const string &appid, unsigned layer, unsigned surface, const string &role)
+ : id(appid), layer(layer),
+ role2surface(0)
+{
+ role2surface[role] = surface;
+ for (auto x : kWMEvents)
+ {
+#if GTEST_ENABLED
+ string ev = x;
+#else
+ afb_event ev = afb_daemon_make_event(x.c_str());
+#endif
+ evname2afb_event[x] = ev;
+ }
+}
+
+WMClient::WMClient(const string &appid, const string &role)
+ : id(appid),
+ layer(0),
+ role2surface(0),
+ evname2afb_event(0)
+{
+ role2surface[role] = INVALID_SURFACE_ID;
+ for (auto x : kWMEvents)
+ {
+#if GTEST_ENABLED
+ string ev = x;
+#else
+ afb_event ev = afb_daemon_make_event(x.c_str());
+#endif
+ evname2afb_event[x] = ev;
+ }
+}
+
+WMClient::WMClient(const string &appid, unsigned layer, const string &role)
+ : id(appid),
+ layer(layer),
+ main_role(role),
+ role2surface(0),
+ evname2afb_event(0)
+{
+ role2surface[role] = INVALID_SURFACE_ID;
+ for (auto x : kWMEvents)
+ {
+#if GTEST_ENABLED
+ string ev = x;
+#else
+ afb_event ev = afb_daemon_make_event(x.c_str());
+#endif
+ evname2afb_event[x] = ev;
+ }
+}
+
+string WMClient::appID() const
+{
+ return this->id;
+}
+
+string WMClient::role() const
+{
+ return this->main_role;
+}
+
+unsigned WMClient::layerID() const
+{
+ return this->layer;
+}
+
+unsigned WMClient::surfaceID() const
+{
+ return this->surface;
+}
+
+/**
+ * Add surface to the client
+ *
+ * This function add main surface to the client(ivi_layer).
+ *
+ * @param string[in] role
+ * @return WMError
+ */
+WMError WMClient::addSurface(unsigned surface)
+{
+ this->surface = surface;
+ ilmErrorTypes err = ilm_layerAddSurface(this->layer, surface);
+
+ if(err == ILM_SUCCESS)
+ {
+ err = ilm_commitChanges();
+ }
+ return (err == ILM_SUCCESS) ? WMError::SUCCESS : WMError::FAIL;
+}
+
+bool WMClient::removeSurfaceIfExist(unsigned surface)
+{
+ bool ret = false;
+ if(surface == this->surface)
+ {
+ this->surface = INVALID_SURFACE_ID;
+ ret = true;
+ }
+ else
+ {
+ for(auto &x : this->service2surfaces)
+ {
+ if(x.second = surface)
+ {
+ ret = true;
+ string key = x.first;
+ this->service2surfaces.erase(key);
+ this->service2supplier.erase(key);
+ }
+ }
+ }
+ return ret;
+}
+
+WMError WMClient::setRenderOrder(const vector<string> &order)
+{
+ WMError ret = WMError::SUCCESS;
+ this->surface_render_order.clear();
+ for(const auto& x : order)
+ {
+ unsigned s; // surface
+ if(x == this->role())
+ {
+ s = this->surfaceID();
+ }
+ else if(this->service2surfaces.count(x) != 0)
+ {
+ s = this->service2surfaces[x];
+ }
+ else
+ {
+ ret = WMError::NOT_REGISTERED;
+ break;
+ }
+ this->surface_render_order.push_back(s);
+ }
+ if(ret == WMError::SUCCESS)
+ {
+ int count = 0;
+ t_ilm_layer* id_array = new t_ilm_surface[this->surface_render_order.size()];
+ if(id_array == nullptr)
+ {
+ HMI_WARNING("short memory");
+ ret = WMError::FAIL;
+ }
+ else
+ {
+ for(const auto& i : this->surface_render_order)
+ {
+ id_array[count] = i;
+ ++count;
+ }
+ ilm_layerSetRenderOrder(this->layerID(),
+ id_array, this->surface_render_order.size());
+ delete id_array;
+ }
+ }
+ return ret;
+}
+
+string WMClient::attachTmpServiceSurface(const string& supplier, const string& service_surface)
+{
+ string uuid;
+ uuid_t u;
+ char out[37]; // uuid is 36 characters
+ uuid_generate_random(u);
+ uuid_unparse(u, out);
+ uuid = out;
+ this->service2supplier.emplace(service_surface, supplier);
+ return uuid;
+}
+
+WMError WMClient::attachServiceSurface(const string& service_surface, unsigned surface)
+{
+ WMError ret = WMError::NOT_REGISTERED;
+ if(this->service2supplier.count(service_surface) != 0)
+ {
+ this->service2surfaces.emplace(service_surface, surface);
+ ret = WMError::SUCCESS;
+ }
+ return ret;
+}
+
+#if GTEST_ENABLED
+bool WMClient::subscribe(afb_req req, const string &evname)
+{
+ if(evname != kKeyError){
+ HMI_DEBUG("error is only enabeled for now");
+ return false;
+ }
+ int ret = afb_req_subscribe(req, this->evname2afb_event[evname]);
+ if (ret)
+ {
+ HMI_DEBUG("Failed to subscribe %s", evname.c_str());
+ return false;
+ }
+ return true;
+}
+
+void WMClient::emitError(WM_CLIENT_ERROR_EVENT ev)
+{
+ if (!afb_event_is_valid(this->evname2afb_event[kKeyError])){
+ HMI_ERROR("event err is not valid");
+ return;
+ }
+ json_object *j = json_object_new_object();
+ json_object_object_add(j, kKeyError, json_object_new_int(ev));
+ json_object_object_add(j, kKeyErrorDesc, json_object_new_string(kErrorDescription[ev].c_str()));
+ HMI_DEBUG("error: %d, description:%s", ev, kErrorDescription[ev].c_str());
+
+ int ret = afb_event_push(this->evname2afb_event[kKeyError], j);
+ if (ret != 0)
+ {
+ HMI_DEBUG("afb_event_push failed: %m");
+ }
+}
+#endif
+
+void WMClient::dumpInfo()
+{
+ DUMP("APPID : %s", id.c_str());
+ DUMP(" LAYER : %d", layer);
+ DUMP(" ROLE : %s , SURFACE : %d", main_role.c_str(), surface);
+}
+
+} // namespace wm \ No newline at end of file
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_client.hpp b/demo#3/common/agl-service-windowmanager/src/wm_client.hpp
new file mode 100644
index 0000000..fc171f4
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_client.hpp
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 WINDOWMANAGER_CLIENT_HPP
+#define WINDOWMANAGER_CLIENT_HPP
+
+#include <vector>
+#include <string>
+#include <unordered_map>
+#include "wm_error.hpp"
+
+extern "C"
+{
+#define AFB_BINDING_VERSION 2
+#include <afb/afb-binding.h>
+}
+
+namespace wm
+{
+
+enum WM_CLIENT_ERROR_EVENT
+{
+ UNKNOWN_ERROR
+};
+
+class WMClient
+{
+ public:
+ WMClient();
+ WMClient(const std::string &appid, unsigned layer,
+ unsigned surface, const std::string &role);
+ WMClient(const std::string &appid, const std::string &role);
+ WMClient(const std::string &appid, unsigned layer, const std::string &role);
+ WMClient(const std::string &appid, unsigned layer,
+ const std::string& layer_name, unsigned surface, const std::string &role);
+ ~WMClient() = default;
+
+ std::string appID() const;
+ std::string role() const;
+ unsigned layerID() const;
+ unsigned surfaceID() const;
+ // void setRole(const std::string& role);
+ // void appendRole(const std::string& role);
+ WMError addSurface(unsigned surface);
+ bool removeSurfaceIfExist(unsigned surface);
+ // bool removeRole(const std::string& role);
+ std::vector<unsigned> renderOrder() const;
+ WMError setRenderOrder(const std::vector<std::string>& order);
+ std::string attachTmpServiceSurface(const std::string& from, const std::string& service_surface);
+ WMError attachServiceSurface(const std::string& service_surface, unsigned surface);
+
+#if GTEST_ENABLED
+ bool subscribe(afb_req req, const std::string &event_name);
+ void emitError(WM_CLIENT_ERROR_EVENT ev);
+#endif
+
+ void dumpInfo();
+
+ private:
+ std::string id;
+ unsigned layer;
+ std::string main_role;
+ std::string area;
+ unsigned surface; // currently, main application has only one surface.
+ //std::vector<std::string> role_list;
+ std::vector<unsigned> surface_render_order;
+ std::unordered_map<std::string, unsigned> service2surfaces;
+ std::unordered_map<std::string, unsigned> role2surface;
+ std::unordered_map<std::string, std::string> service2supplier;
+#if GTEST_ENABLED
+ // This is for unit test. afb_make_event occurs sig11 if call not in afb-binding
+ std::unordered_map<std::string, std::string> evname2afb_event;
+#else
+ std::unordered_map<std::string, struct afb_event> evname2afb_event;
+#endif
+};
+} // namespace wm
+
+#endif \ No newline at end of file
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_connection.cpp b/demo#3/common/agl-service-windowmanager/src/wm_connection.cpp
new file mode 100644
index 0000000..10ecc3b
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_connection.cpp
@@ -0,0 +1,457 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "wm_connection.hpp"
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "json_helper.hpp"
+#include "util.hpp"
+
+extern "C"
+{
+#include <afb/afb-binding.h>
+#include <systemd/sd-event.h>
+}
+
+
+/**
+ * namespace wm
+ */
+namespace wm
+{
+
+
+namespace
+{
+
+static const char kPathConnectionConfigFile[] = "/etc/connection.json";
+static const char kDefaultIpAddr[] = "192.168.10.10";
+static const int kDefaultPort = 4000;
+
+static int onIoEventReceive(sd_event_source *src, int fd, uint32_t revents, void * data)
+{
+ WMConnection *p_wmcon = (WMConnection*)data;
+
+ json_object *j_out;
+ int ret = p_wmcon->receive(&j_out);
+ if (0 > ret)
+ {
+ return 0;
+ }
+
+ const char* rq = jh::getStringFromJson(j_out, "req");
+ const char* id = jh::getStringFromJson(j_out, "appid");
+ const char* dn = jh::getStringFromJson(j_out, "drawing_name");
+ const char* da = jh::getStringFromJson(j_out, "drawing_area");
+
+ HMI_DEBUG("req:%s appid:%s, drawing_name:%s, drawing_area:%s", rq, id, dn, da);
+
+ // Callback
+ p_wmcon->callOnReceivedHandler(j_out);
+
+ return 0;
+}
+
+static int onIoEventAccept(sd_event_source *src, int fd, uint32_t revents, void * data)
+{
+ struct sockaddr_in addr;
+
+ WMConnection *p_wmcon = (WMConnection*)data;
+
+ // Accept connection
+ socklen_t len = sizeof(addr);
+ int my_socket = p_wmcon->getMySocket();
+ int connected_socket = accept(my_socket, (struct sockaddr *)&addr, &len);
+ if (0 > connected_socket)
+ {
+ HMI_ERROR("Failed to accept connection (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Store connected socket
+ p_wmcon->setConnectedSocket(connected_socket);
+
+ // Register callback to receive
+ int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
+ connected_socket, EPOLLIN,
+ onIoEventReceive, p_wmcon);
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
+ return -1;
+ }
+
+ return 0;
+}
+
+} // namespace
+
+WMConnection::WMConnection()
+{
+ // Load connection config file
+ this->loadConnectionConfigFile();
+
+ // TODO: ECU name should be decide by config file
+ this->ecu_name = this->mode;
+}
+
+int WMConnection::initialize()
+{
+ int ret;
+
+ // Initialize for Master/Slave
+ if (this->isMasterMode())
+ {
+ ret = this->initializeMaster();
+ }
+ else
+ {
+ ret = this->initializeSlave();
+ }
+
+ return ret;
+}
+
+void WMConnection::registerCallback(ReceivedHandler on_received)
+{
+ this->onReceived = on_received;
+}
+
+int WMConnection::sendRequest(char const *req, char const *appid,
+ char const *drawing_name, char const *drawing_area)
+{
+ int ret;
+ json_object *j_obj = json_object_new_object();
+ json_object_object_add(j_obj, "req", json_object_new_string(req));
+ json_object_object_add(j_obj, "appid", json_object_new_string(appid));
+ json_object_object_add(j_obj, "drawing_name", json_object_new_string(drawing_name));
+ json_object_object_add(j_obj, "drawing_area", json_object_new_string(drawing_area));
+
+ ret = this->send(j_obj);
+
+ json_object_put(j_obj);
+
+ return ret;
+}
+
+int WMConnection::send(struct json_object* j_in)
+{
+ // Convert json_object to string to send
+ const char *buf = json_object_to_json_string(j_in);
+ if (nullptr == buf)
+ {
+ HMI_ERROR("Failed to convert json_object to string");
+ return -1;
+ }
+
+ int len = strlen(buf);
+
+ HMI_DEBUG("Send data(len:%d): %s", len, buf);
+
+ int n = write(this->connected_socket, buf, len);
+ if(0 > n)
+ {
+ HMI_ERROR("Failed to send data (%s)", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+bool WMConnection::isMasterMode()
+{
+ if ("master" == this->mode)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool WMConnection::isMasterArea(const char* area)
+{
+ if (nullptr == area)
+ {
+ return false;
+ }
+
+ std::string str_area = std::string(area);
+ if ("" == str_area)
+ {
+ return false;
+ }
+
+ std::vector<std::string> elements;
+ elements = parseString(str_area, '.');
+
+ if ("master" == elements[0])
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+bool WMConnection::isConnecting()
+{
+ return (0 > this->connected_socket) ? false : true;
+}
+
+std::string WMConnection::parseMasterArea(const char* area)
+{
+ std::string ret_area = "";
+ std::vector<std::string> elements;
+ elements = parseString(std::string(area), '.');
+
+ if ("master" != elements[0])
+ {
+ return std::string(area);
+ }
+
+ for (auto itr = (elements.begin() + 1); itr != elements.end(); ++itr)
+ {
+ ret_area += *itr;
+
+ if ((elements.end() - 1) != itr)
+ {
+ ret_area += ".";
+ }
+ }
+ return ret_area;
+}
+
+bool WMConnection::isSyncDrawingForRemote(const char* appid)
+{
+ if (std::string(appid) == this->syndDrawingAppId)
+ {
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+}
+
+void WMConnection::startSyncDrawForRemote(const char* appid)
+{
+ this->syndDrawingAppId = std::string(appid);
+}
+
+void WMConnection::finishSyncDrawForRemote(const char* appid)
+{
+ if (std::string(appid) == this->syndDrawingAppId)
+ {
+ this->syndDrawingAppId = "";
+ }
+}
+
+int WMConnection::getMySocket()
+{
+ return this->my_socket;
+}
+
+int WMConnection::getConnectedSocket()
+{
+ return this->connected_socket;
+}
+
+void WMConnection::setConnectedSocket(int connected_socket)
+{
+ this->connected_socket = connected_socket;
+}
+
+std::string WMConnection::getEcuName()
+{
+ return this->ecu_name;
+}
+
+void WMConnection::callOnReceivedHandler(json_object *j_out)
+{
+ this->onReceived(j_out);
+}
+
+int WMConnection::initializeMaster()
+{
+ int ret = 0;
+ struct sockaddr_in addr;
+
+ // Create socket
+ this->my_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if (0 > this->my_socket)
+ {
+ HMI_ERROR("Failed to create socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Bind socket
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(this->port);
+ addr.sin_addr.s_addr = htonl(INADDR_ANY);
+
+ ret = bind(this->my_socket, (struct sockaddr *)&addr, sizeof(addr));
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to bind socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Listen connection
+ ret = listen(this->my_socket, 1);
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to listen connection (%s)", strerror(errno));
+ return -1;
+ }
+
+ // Register callback to accept connection
+ ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
+ this->my_socket, EPOLLIN,
+ onIoEventAccept, this);
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to add I/O event accept(%s)", strerror(-ret));
+ return -1;
+ }
+
+ return ret;
+}
+
+int WMConnection::initializeSlave()
+{
+ // Create socket
+ this->my_socket = socket(AF_INET, SOCK_STREAM, 0);
+ if (0 > this->my_socket)
+ {
+ HMI_ERROR("Failed to create socket (%s)", strerror(errno));
+ return -1;
+ }
+
+ return 0;
+}
+
+int WMConnection::connectToMaster()
+{
+ int ret = 0;
+ struct sockaddr_in addr;
+
+ // Connect to master
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(this->port);
+ addr.sin_addr.s_addr = inet_addr(this->ip.c_str());
+
+ ret = connect(this->my_socket, (struct sockaddr *)&addr, sizeof(addr));
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to connect to master (%s)", strerror(errno));
+ return ret;
+ }
+
+ HMI_DEBUG("Connected to master");
+
+ // Store connected socket
+ this->connected_socket = this->my_socket;
+
+ // Register callback to receive
+ ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
+ this->connected_socket, EPOLLIN,
+ onIoEventReceive, this);
+ if (0 > ret)
+ {
+ HMI_ERROR("Failed to add I/O event receive(%s)", strerror(-ret));
+ return -1;
+ }
+
+ return ret;
+}
+
+int WMConnection::receive(struct json_object** j_out)
+{
+ char buf[1024];
+ int n;
+
+ n = read(this->connected_socket, buf, sizeof(buf));
+ if(0 > n)
+ {
+ HMI_ERROR("Failed to receive data (%s)", strerror(errno));
+ return -1;
+ }
+
+ HMI_DEBUG("Received data length: %d", n);
+ HMI_DEBUG("Received data: %s", buf);
+
+ // Parse received data
+ struct json_tokener *tokener = json_tokener_new();
+ *j_out = json_tokener_parse_ex(tokener, buf, n);
+ if (nullptr == *j_out)
+ {
+ HMI_DEBUG("Failed to parse received data");
+ return -1;
+ }
+
+ return 0;
+}
+
+int WMConnection::loadConnectionConfigFile()
+{
+ // Get afm application installed dir
+ char const *afm_app_install_dir = getenv("AFM_APP_INSTALL_DIR");
+ if (!afm_app_install_dir)
+ {
+ HMI_ERROR("AFM_APP_INSTALL_DIR is not defined");
+ }
+ std::string path = std::string(afm_app_install_dir) + std::string(kPathConnectionConfigFile);
+
+ // Load connection config file
+ json_object* json_obj;
+ int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
+ if (0 > ret)
+ {
+ HMI_ERROR("Could not open %s, so use default mode \"slave\"", kPathConnectionConfigFile);
+ this->mode = "slave";
+ this->ip = kDefaultIpAddr;
+ this->port = kDefaultPort;
+ return 0;
+ }
+ HMI_DEBUG("json_obj dump:%s", json_object_get_string(json_obj));
+
+ const char* mode = jh::getStringFromJson(json_obj, "mode");
+ this->mode = (nullptr != mode) ? mode : "slave";
+
+ const char* ip = jh::getStringFromJson(json_obj, "master_ip");
+ this->ip = (nullptr != ip) ? ip : kDefaultIpAddr;
+
+ int port = jh::getIntFromJson(json_obj, "master_port");
+ this->port = (0 != port) ? port : kDefaultPort;
+
+ // Check
+ HMI_DEBUG("mode:%s master_ip:%s master_port:%d", mode, ip, port);
+
+ // Release json_object
+ json_object_put(json_obj);
+
+ return 0;
+}
+
+
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_connection.hpp b/demo#3/common/agl-service-windowmanager/src/wm_connection.hpp
new file mode 100644
index 0000000..9d3180f
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_connection.hpp
@@ -0,0 +1,64 @@
+/*
+ * Insert Copyright if needed.
+ */
+
+#ifndef WM_CONNECTION_HPP
+#define WM_CONNECTION_HPP
+
+#include <functional>
+
+struct json_object;
+
+namespace wm
+{
+
+class WMConnection
+{
+ public:
+ WMConnection();
+ ~WMConnection() = default;
+
+ using ReceivedHandler = std::function<void(json_object* j_out)>;
+
+ int initialize();
+ void registerCallback(ReceivedHandler on_received);
+ int sendRequest(char const *req, char const *appid,
+ char const *drawing_name, char const *drawing_area);
+ bool isMasterMode();
+ bool isMasterArea(const char* area);
+ bool isConnecting();
+ std::string parseMasterArea(const char* area);
+ bool isSyncDrawingForRemote(const char* role);
+ void startSyncDrawForRemote(const char* role);
+ void finishSyncDrawForRemote(const char* role);
+ int getMySocket();
+ int getConnectedSocket();
+ void setConnectedSocket(int connected_socket);
+ std::string getEcuName();
+ void callOnReceivedHandler(json_object *j_out);
+ int connectToMaster();
+
+ int receive(json_object** j_out);
+
+ private:
+ std::string mode;
+ std::string ip;
+ int port;
+ int my_socket = -1;
+ int connected_socket = -1;
+ ReceivedHandler onReceived;
+ std::string syndDrawingAppId;
+
+ std::string ecu_name;
+
+ int initializeMaster();
+ int initializeSlave();
+ int loadConnectionConfigFile();
+
+ int send(json_object* j_in);
+};
+
+} // namespace wm
+
+#endif // WM_CONNECTION_HPP
+
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_error.cpp b/demo#3/common/agl-service-windowmanager/src/wm_error.cpp
new file mode 100644
index 0000000..694a7d0
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_error.cpp
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 "wm_error.hpp"
+
+namespace wm {
+
+const char *errorDescription(WMError enum_error_number)
+{
+ switch (enum_error_number){
+ case SUCCESS:
+ return "Success";
+ case FAIL:
+ return "Request failed";
+ case REQ_REJECTED:
+ return "Request is rejected, due to the policy rejection of the request.";
+ case REQ_DROPPED:
+ return "Request is dropped, because the high priority request is done";
+ case NOT_REGISTERED:
+ return "Not registered";
+ case TIMEOUT_EXPIRED:
+ return "Request is dropped, due to time out expiring";
+ case LAYOUT_CHANGE_FAIL:
+ return "Layout change fails, due to some reasons";
+ case NO_ENTRY:
+ return "No element";
+ case NO_LAYOUT_CHANGE:
+ return "No layout change(deactivate only)";
+ default:
+ return "Unknown error number. Window manager bug.";
+ }
+}
+
+} \ No newline at end of file
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_error.hpp b/demo#3/common/agl-service-windowmanager/src/wm_error.hpp
new file mode 100644
index 0000000..c4c61b4
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_error.hpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 WINDOW_MANAGER_ERROR
+#define WINDOW_MANAGER_ERROR
+
+namespace wm {
+
+typedef enum WINDOWMANAGER_ERROR
+{
+ SUCCESS = 0,
+ FAIL,
+ REQ_REJECTED,
+ REQ_DROPPED,
+ TIMEOUT_EXPIRED,
+ NOT_REGISTERED,
+ LAYOUT_CHANGE_FAIL,
+ NO_ENTRY,
+ NO_LAYOUT_CHANGE,
+ UNKNOWN,
+ ERR_MAX = UNKNOWN
+}
+WMError;
+
+const char *errorDescription(WMError enum_error_number);
+
+}
+#endif // WINDOW_MANAGER_ERROR \ No newline at end of file
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_layer.cpp b/demo#3/common/agl-service-windowmanager/src/wm_layer.cpp
new file mode 100644
index 0000000..d3e7073
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_layer.cpp
@@ -0,0 +1,271 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <regex>
+#include <ilm/ilm_control.h>
+#include <stdlib.h>
+#include "wm_client.hpp"
+#include "wm_layer.hpp"
+#include "json_helper.hpp"
+#include "util.hpp"
+
+using std::string;
+using std::vector;
+using std::unordered_map;
+
+#define BG_LAYER_NAME "BackGroundLayer"
+
+namespace wm
+{
+
+LayerState::LayerState()
+ : render_order(),
+ area2appid()
+{}
+
+
+void LayerState::attachIdToArea(const string& area, const WMClient& client)
+{
+ this->area2appid[area] = client.appID();
+ this->render_order.push_back(client.layerID());
+}
+
+const unordered_map<string, string> LayerState::popCurrentState()
+{
+ unordered_map<string, string> tmp = this->area2appid;
+ this->area2appid.clear();
+ this->render_order.clear();
+ return tmp;
+}
+
+const unordered_map<string, string> LayerState::getCurrentState()
+{
+ return this->area2appid;
+}
+
+const vector<unsigned> LayerState::getIviIdList()
+{
+ return this->render_order;
+}
+
+void LayerState::addLayer(unsigned layer)
+{
+ auto result = std::find(this->render_order.begin(), this->render_order.end(), layer);
+ if(result == this->render_order.end())
+ this->render_order.push_back(layer);
+}
+
+void LayerState::removeLayer(unsigned layer)
+{
+ auto fwd_itr = std::remove_if(
+ this->render_order.begin(), this->render_order.end(),
+ [layer](unsigned elm) {
+ if(elm == layer)
+ HMI_DEBUG("remove layer %d", elm);
+ return elm == layer;
+ }
+ );
+ this->render_order.erase(fwd_itr, this->render_order.end());
+}
+
+void LayerState::setArea(const string& app, const string& area)
+{
+ this->area2appid[area] = app;
+}
+
+void LayerState::dump()
+{
+ std::string ids, apps;
+ for(const auto& ro : this->render_order)
+ {
+ ids += std::to_string(ro);
+ ids += ",";
+ }
+ for(const auto& area : this->area2appid)
+ {
+ apps += area.first;
+ apps += ":";
+ apps += area.second;
+ apps += ",";
+ }
+ DUMP(" render order : %s", ids.c_str());
+ DUMP(" area, app : %s", apps.c_str());
+}
+
+WMLayer::WMLayer(json_object* j, unsigned uuid) : tmp_state(), state(), uuid(uuid)
+{
+ this->name = jh::getStringFromJson(j, "name");
+ this->role_list = jh::getStringFromJson(j, "role");
+ const char* type = jh::getStringFromJson(j, "type");
+ this->id_begin = static_cast<unsigned>(jh::getIntFromJson(j, "id_range_begin"));
+ this->id_end = static_cast<unsigned>(jh::getIntFromJson(j, "id_range_end"));
+
+ if (name.size() == 0 || !type)
+ {
+ HMI_ERROR("Parse Error!!");
+ exit(1);
+ }
+ if(this->id_begin > this->id_end)
+ {
+ HMI_ERROR("INVALID");
+ exit(1);
+ }
+ string str_type = type;
+ this->type = (str_type == "tile") ? MANAGEMENT_TYPE::TILE : MANAGEMENT_TYPE::STACK;
+}
+
+unsigned WMLayer::getNewLayerID(const string& role)
+{
+ unsigned ret = 0;
+ if(this->name == BG_LAYER_NAME)
+ return ret;
+
+ // generate new layer id;
+ if(this->hasRole(role))
+ {
+ if(this->id_list.size() == 0)
+ {
+ ret = this->idBegin();
+ this->id_list.push_back(ret);
+ }
+ else
+ {
+ ret = this->id_list.back() + 1;
+ }
+ HMI_INFO("Generate new id: %d", ret);
+ }
+ else
+ {
+ return ret;
+ }
+
+ size_t count = std::count(id_list.begin(), id_list.end(), ret);
+ if( (ret > this->idEnd()) || (count > 1))
+ {
+ HMI_NOTICE("id %d is not available then generate new id", ret);
+ ret = 0; // reset
+ for(unsigned i = this->idBegin(); i < this->idEnd(); i++)
+ {
+ auto ret_found = std::find(id_list.begin(), id_list.end(), i);
+ if(ret_found == id_list.cend())
+ {
+ HMI_INFO("set new id: %d", i);
+ ret = i;
+ break;
+ }
+ }
+ }
+
+ if(ret != 0)
+ {
+ id_list.push_back(ret);
+ }
+ else
+ {
+ HMI_ERROR("failed to get New ID");
+ }
+ return ret;
+}
+
+const string& WMLayer::layerName()
+{
+ return this->name;
+}
+
+WMError WMLayer::setLayerState(const LayerState& l)
+{
+ this->tmp_state = l;
+ return WMError::SUCCESS;
+}
+
+void WMLayer::addLayerToState(unsigned layer)
+{
+ this->tmp_state.addLayer(layer);
+}
+
+void WMLayer::removeLayerFromState(unsigned layer)
+{
+ this->tmp_state.removeLayer(layer);
+}
+
+void WMLayer::setAreaToState(const string& app, const string& area)
+{
+ this->tmp_state.setArea(app, area);
+}
+
+void WMLayer::appendArea(const string& area)
+{
+ this->area_list.push_back(area);
+}
+
+void WMLayer::terminateApp(unsigned id)
+{
+ auto fwd_itr = std::remove_if(this->id_list.begin(), this->id_list.end(),
+ [id](unsigned elm) {
+ return elm == id;
+ });
+ this->id_list.erase(fwd_itr, this->id_list.end());
+ this->tmp_state.removeLayer(id);
+ this->state.removeLayer(id);
+ ilm_layerRemove(id);
+}
+
+bool WMLayer::hasLayerID(unsigned id)
+{
+ bool ret = (id >= this->idBegin() && id <= this->idEnd());
+ if(!ret)
+ return ret;
+ auto itr = std::find(this->id_list.begin(), this->id_list.end(), id);
+ return (itr != this->id_list.end()) ? true : false;
+}
+
+bool WMLayer::hasRole(const string& role)
+{
+ auto re = std::regex(this->role_list);
+ if (std::regex_match(role, re))
+ {
+ HMI_DEBUG("role %s matches layer %s", role.c_str(), this->name.c_str());
+ return true;
+ }
+ return false;
+}
+
+void WMLayer::update()
+{
+ this->state = this->tmp_state;
+}
+
+void WMLayer::undo()
+{
+ this->tmp_state = this->state;
+}
+
+void WMLayer::dump()
+{
+ DUMP("===== wm layer status =====");
+ DUMP("Layer :%s", this->name.c_str());
+ this->tmp_state.dump();
+ this->state.dump();
+ DUMP("===== wm layer status end =====");
+
+}
+
+/* void WMLayer::undo()
+{
+ this->tmp_state = this->state;
+}
+ */
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_layer.hpp b/demo#3/common/agl-service-windowmanager/src/wm_layer.hpp
new file mode 100644
index 0000000..a6a359e
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_layer.hpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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_LAYER_HPP
+#define WM_LAYER_HPP
+
+#include <string>
+#include <vector>
+#include <unordered_map>
+#include <memory>
+#include "wm_error.hpp"
+
+struct json_object;
+
+namespace wm
+{
+
+class WMClient;
+class LayerState
+{
+ public:
+ LayerState();
+ ~LayerState() = default;
+ void attachIdToArea(const std::string& area, const WMClient&);
+ const std::unordered_map<std::string, std::string> popCurrentState();
+ const std::unordered_map<std::string, std::string> getCurrentState();
+ const std::vector<unsigned> getIviIdList();
+ void addLayer(unsigned layer);
+ void removeLayer(unsigned layer);
+ void setArea(const std::string& app, const std::string& area);
+
+ // Debug
+ void dump();
+
+ private:
+ std::vector<unsigned> render_order;
+ std::unordered_map<std::string, std::string> area2appid;
+};
+
+class WMLayer
+{
+ public:
+ enum MANAGEMENT_TYPE
+ {
+ TILE,
+ STACK
+ };
+
+ explicit WMLayer(json_object* j, unsigned uuid);
+ ~WMLayer() = default;
+
+ // Status & Setting API
+ unsigned getNewLayerID(const std::string& role);
+ unsigned idBegin() { return this->id_begin; }
+ unsigned idEnd() { return this->id_end; }
+ unsigned getUuid() { return this->uuid; }
+ const std::string& layerName();
+ MANAGEMENT_TYPE layerType() { return this->type; }
+ void appendArea(const std::string& area);
+ LayerState& getLayerState() { return tmp_state; }
+ WMError setLayerState(const LayerState& l);
+ bool hasLayerID(unsigned id);
+ bool hasRole(const std::string& role);
+
+ // Manipulation
+ void addLayerToState(unsigned layer);
+ void removeLayerFromState(unsigned layer);
+ void setAreaToState(const std::string& app, const std::string& area);
+ void terminateApp(unsigned layer);
+ void update();
+ void undo();
+
+ // Debug
+ void dump();
+
+ private:
+ LayerState tmp_state;
+ LayerState state;
+ unsigned uuid;
+ std::string name = ""; // Layer name
+ MANAGEMENT_TYPE type;
+ std::string role_list;
+ std::vector<std::string> area_list;
+ std::vector<unsigned> id_list;
+ unsigned id_begin;
+ unsigned id_end;
+};
+
+} // namespace wm
+
+#endif // WM_LAYER_HPP
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_layer_control.cpp b/demo#3/common/agl-service-windowmanager/src/wm_layer_control.cpp
new file mode 100644
index 0000000..80dc0c9
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_layer_control.cpp
@@ -0,0 +1,911 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <assert.h>
+#include <unistd.h>
+#include "wm_layer_control.hpp"
+#include "wm_layer.hpp"
+#include "wm_client.hpp"
+#include "request.hpp"
+#include "json_helper.hpp"
+
+#define LC_AREA_PATH "/etc/areas.json"
+#define LC_LAYER_SETTING_PATH "/etc/layers_setting.json"
+#define LC_DEFAULT_AREA "fullscreen"
+#define BACK_GROUND_LAYER "BackGroundLayer"
+
+using std::string;
+using std::vector;
+using std::shared_ptr;
+
+namespace wm {
+
+LayerControl* g_lc_ctxt;
+
+static void createCallback_static(ilmObjectType object,
+ t_ilm_uint id,
+ t_ilm_bool created,
+ void* data)
+{
+ static_cast<LayerControl*>(data)->dispatchCreateEvent(object, id, created);
+}
+
+static void surfaceCallback_static(t_ilm_surface surface,
+ struct ilmSurfaceProperties* surface_prop,
+ t_ilm_notification_mask mask)
+{
+ g_lc_ctxt->dispatchSurfacePropChangeEvent(surface, surface_prop, mask);
+}
+
+static void layerCallback_static(t_ilm_layer layer,
+ struct ilmLayerProperties* layer_prop,
+ t_ilm_notification_mask mask)
+{
+ g_lc_ctxt->dispatchLayerPropChangeEvent(layer, layer_prop, mask);
+}
+
+LayerControl::LayerControl(const std::string& root, const std::string& ecu_name)
+{
+ string area_path = root + LC_AREA_PATH;
+ string layer_path= root + LC_LAYER_SETTING_PATH;
+ // load layers.setting.json
+ WMError ret = this->loadLayerSetting(layer_path);
+ assert(ret == WMError::SUCCESS);
+ // load areas.json
+ ret = this->loadAreasConfigFile(area_path, ecu_name);
+ assert(ret == WMError::SUCCESS);
+}
+
+WMError LayerControl::init(const LayerControlCallbacks& cb)
+{
+ HMI_DEBUG("Initialize of ilm library and display");
+ t_ilm_uint num = 0;
+ t_ilm_uint *ids;
+ int cnt = 0;
+ ilmErrorTypes rc = ilm_init();
+
+ while (rc != ILM_SUCCESS)
+ {
+ cnt++;
+ if (20 <= cnt)
+ {
+ HMI_ERROR("Could not connect to compositor");
+ goto lc_init_error;
+ }
+ HMI_ERROR("Wait to start weston ...");
+ sleep(1);
+ rc = ilm_init();
+ }
+ if(rc != ILM_SUCCESS) goto lc_init_error;
+
+ // Get current screen setting
+ rc = ilm_getScreenIDs(&num, &ids);
+
+ if(rc != ILM_SUCCESS) goto lc_init_error;
+
+ for(unsigned i = 0; i < num; i++)
+ {
+ HMI_INFO("get screen: %d", ids[i]);
+ }
+ // Currently, 0 is only available
+ this->screenID = ids[0];
+
+ if (1 < num)
+ {
+ // TODO: set remote screen id
+ HMI_INFO("There is remote screen (id:%d)", ids[1]);
+ this->remoteScreenID = ids[1];
+ }
+ else
+ {
+ HMI_INFO("There is no remote screen");
+ this->remoteScreenID = -1;
+ }
+
+ rc = ilm_getPropertiesOfScreen(this->screenID, &this->screen_prop);
+
+ if(rc != ILM_SUCCESS) goto lc_init_error;
+
+ // Register Callback to Window Manager and from ILM
+ this->cb = cb;
+ ilm_registerNotification(createCallback_static, this);
+
+ return WMError::SUCCESS;
+
+lc_init_error:
+ HMI_ERROR("Failed to initialize. Terminate WM");
+
+ return WMError::FAIL;
+}
+
+void LayerControl::createNewLayer(unsigned id)
+{
+ HMI_INFO("create new ID :%d", id);
+ struct rect rct = this->area2size[LC_DEFAULT_AREA];
+ ilm_layerCreateWithDimension(&id, rct.w, rct.h);
+ //ilm_layerSetSourceRectangle(id, rct.x, rct.y, rct.w, rct.h);
+ ilm_layerSetDestinationRectangle(id, this->offset_x, this->offset_y, rct.w, rct.h);
+ ilm_layerSetOpacity(id, 1.0);
+ ilm_layerSetVisibility(id, ILM_FALSE);
+ ilm_commitChanges();
+ auto wm_layer = getWMLayer(id);
+ wm_layer->addLayerToState(id);
+ this->renderLayers();
+ this->renderLayersRemote();
+}
+
+void LayerControl::createNewRemoteLayer(unsigned id)
+{
+ HMI_INFO("create new ID :%d (For remote layer)", id);
+ struct rect rct = {640, 720, 0, 0};
+ ilm_layerCreateWithDimension(&id, rct.w, rct.h);
+ //ilm_layerSetSourceRectangle(id, rct.x, rct.y, rct.w, rct.h);
+ ilm_layerSetDestinationRectangle(id, this->offset_x, this->offset_y, rct.w, rct.h);
+ ilm_layerSetOpacity(id, 1.0);
+ ilm_layerSetVisibility(id, ILM_FALSE);
+ ilm_commitChanges();
+ auto wm_layer = getWMLayer(id);
+ wm_layer->addLayerToState(id);
+ this->renderLayers();
+ this->renderLayersRemote();
+}
+
+unsigned LayerControl::getNewLayerID(const string& role, string* layer_name)
+{
+ unsigned ret = 0;
+ for(const auto& l: this->wm_layers)
+ {
+ ret = l->getNewLayerID(role);
+ if(ret != 0)
+ {
+ *layer_name = l->layerName();
+ unsigned uid = l->getUuid();
+ this->lid2wmlid[ret] = uid;
+ break;
+ }
+ }
+ return ret;
+}
+
+shared_ptr<WMLayer> LayerControl::getWMLayer(unsigned layer)
+{
+ unsigned uuid = this->lid2wmlid[layer];
+ return this->wm_layers[uuid];
+}
+
+std::shared_ptr<WMLayer> LayerControl::getWMLayer(std::string layer_name)
+{
+ for(auto &l : this->wm_layers)
+ {
+ if(l->layerName() == layer_name)
+ {
+ return l;
+ }
+ }
+ return nullptr;
+}
+
+struct rect LayerControl::getAreaSize(const std::string& area)
+{
+ return area2size[area];
+}
+
+void LayerControl::setupArea(const rectangle& base_rct, double scaling)
+{
+ this->scaling = scaling;
+ this->offset_x = base_rct.left();
+ this->offset_y = base_rct.top();
+
+ for (auto &i : this->area2size)
+ {
+ i.second.x = static_cast<int>(scaling * i.second.x + 0.5);
+ i.second.y = static_cast<int>(scaling * i.second.y + 0.5);
+ i.second.w = static_cast<int>(scaling * i.second.w + 0.5);
+ i.second.h = static_cast<int>(scaling * i.second.h + 0.5);
+
+ HMI_DEBUG("area:%s size(after) : x:%d y:%d w:%d h:%d",
+ i.first.c_str(), i.second.x, i.second.y, i.second.w, i.second.h);
+ }
+}
+
+Screen LayerControl::getScreenInfo()
+{
+ return Screen(this->screen_prop.screenWidth, this->screen_prop.screenHeight);
+}
+
+double LayerControl::scale()
+{
+ return this->scaling;
+}
+
+WMError LayerControl::updateLayer(LayerState& layer_state)
+{
+ return WMError::SUCCESS;
+}
+
+WMError LayerControl::renderLayers()
+{
+ HMI_INFO("Commit change");
+ WMError rc = WMError::SUCCESS;
+
+ // Check the number of layers
+ vector<unsigned> ivi_l_ids;
+ for(auto& l : this->wm_layers)
+ {
+ auto state = l->getLayerState();
+ HMI_DEBUG("layer %s", l->layerName().c_str());
+ for(const auto& id : state.getIviIdList())
+ {
+ HMI_DEBUG("Add %d", id);
+ ivi_l_ids.push_back(id);
+ }
+ }
+
+ // Create render order
+ t_ilm_layer* id_array = new t_ilm_layer[ivi_l_ids.size()];
+ if(id_array == nullptr)
+ {
+ HMI_WARNING("short memory");
+ this->undoUpdate();
+ return WMError::FAIL;
+ }
+ int count = 0;
+ for(const auto& i : ivi_l_ids)
+ {
+ id_array[count] = i;
+ ++count;
+ }
+
+ // Display
+ ilmErrorTypes ret = ilm_displaySetRenderOrder(this->screenID, id_array, ivi_l_ids.size());
+ if(ret != ILM_SUCCESS)
+ {
+ this->undoUpdate();
+ rc = WMError::FAIL;
+ }
+ else
+ {
+ for(auto& l : this->wm_layers)
+ {
+ l->update();
+ }
+ }
+ ilm_commitChanges();
+ delete id_array;
+ return rc;
+}
+
+WMError LayerControl::renderLayersRemote()
+{
+ HMI_INFO("Commit change");
+ WMError rc = WMError::SUCCESS;
+
+ if (0 > this->remoteScreenID)
+ {
+ return rc;
+ }
+
+ // Check the number of layers
+ vector<unsigned> ivi_l_ids;
+ for(auto& l : this->wm_remote_layers)
+ {
+ auto state = l->getLayerState();
+ HMI_DEBUG("layer %s", l->layerName().c_str());
+ for(const auto& id : state.getIviIdList())
+ {
+ HMI_DEBUG("Add %d", id);
+ ivi_l_ids.push_back(id);
+ }
+ }
+
+ if (0 == ivi_l_ids.size())
+ {
+ ilm_displaySetRenderOrder(this->remoteScreenID, nullptr, 0);
+ return rc;
+ }
+
+ // Create render order
+ t_ilm_layer* id_array = new t_ilm_layer[ivi_l_ids.size()];
+ if(id_array == nullptr)
+ {
+ HMI_WARNING("short memory");
+ this->undoUpdate();
+ return WMError::FAIL;
+ }
+ int count = 0;
+ for(const auto& i : ivi_l_ids)
+ {
+ id_array[count] = i;
+ ++count;
+ }
+
+ // Display
+ ilmErrorTypes ret = ilm_displaySetRenderOrder(this->remoteScreenID, id_array, ivi_l_ids.size());
+ if(ret != ILM_SUCCESS)
+ {
+ this->undoUpdate();
+ rc = WMError::FAIL;
+ }
+ else
+ {
+ for(auto& l : this->wm_remote_layers)
+ {
+ l->update();
+ }
+ }
+ ilm_commitChanges();
+ delete id_array;
+ return rc;
+}
+
+WMError LayerControl::setXDGSurfaceOriginSize(unsigned surface)
+{
+ WMError ret = WMError::NOT_REGISTERED;
+ ilmSurfaceProperties prop;
+ ilmErrorTypes rc = ilm_getPropertiesOfSurface(surface, &prop);
+ if(rc == ILM_SUCCESS)
+ {
+ HMI_INFO("xdg surface info %d, %d", prop.origSourceWidth, prop.origSourceHeight);
+ ilm_surfaceSetSourceRectangle(surface, 0, 0, prop.origSourceWidth, prop.origSourceHeight);
+ ret = WMError::SUCCESS;
+ }
+ return ret;
+}
+
+
+void LayerControl::undoUpdate()
+{
+ for(auto& l : this->wm_layers)
+ {
+ l->undo();
+ }
+}
+
+WMError LayerControl::loadLayerSetting(const string &path)
+{
+ HMI_DEBUG("loading WMLayer(Application Containers) Setting from %s", path);
+
+ json_object *json_obj, *json_cfg;
+ int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
+ if (0 > ret)
+ {
+ HMI_ERROR("Could not open %s", path.c_str());
+ return WMError::FAIL;
+ }
+ HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj));
+
+ if (!json_object_object_get_ex(json_obj, "mappings", &json_cfg))
+ {
+ HMI_ERROR("Parse Error!!");
+ return WMError::FAIL;
+ }
+
+ int len = json_object_array_length(json_cfg);
+ HMI_DEBUG("json_cfg len:%d", len);
+
+ for (int i = 0; i < len; i++)
+ {
+ json_object *json_tmp = json_object_array_get_idx(json_cfg, i);
+ HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp));
+
+ this->wm_layers.emplace_back(std::make_shared<WMLayer>(json_tmp, i));
+ }
+ json_object_put(json_obj);
+
+ return WMError::SUCCESS;
+}
+
+WMError LayerControl::loadAreasConfigFile(const std::string& path, const std::string& ecu_name)
+{
+ // Load areas config file
+ json_object *json_obj;
+ int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
+ if (0 > ret)
+ {
+ HMI_ERROR("Could not open %s", path.c_str());
+ return WMError::FAIL;
+ }
+ HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj));
+
+ // Parse ecus
+ json_object *json_cfg;
+ if (!json_object_object_get_ex(json_obj, "ecus", &json_cfg))
+ {
+ HMI_ERROR("Parse Error!!");
+ return WMError::FAIL;
+ }
+
+ int num_ecu = json_object_array_length(json_cfg);
+ HMI_DEBUG("json_cfg(ecus) len:%d", num_ecu);
+
+ const char* c_ecu_name;
+ json_object *json_ecu;
+ for (int i = 0; i < num_ecu; i++)
+ {
+ json_ecu= json_object_array_get_idx(json_cfg, i);
+
+ c_ecu_name = jh::getStringFromJson(json_ecu, "name");
+ if (nullptr == c_ecu_name)
+ {
+ HMI_ERROR("Parse Error!!");
+ return WMError::FAIL;
+ }
+
+ if (ecu_name == string(c_ecu_name))
+ {
+ break;
+ }
+ else
+ {
+ json_ecu = nullptr;
+ }
+ }
+
+ if (!json_ecu)
+ {
+ HMI_ERROR("Areas for ecu:%s is NOT exist!!", ecu_name.c_str());
+ return WMError::FAIL;
+ }
+
+ // Parse screens
+ if (!json_object_object_get_ex(json_ecu, "screens", &json_cfg))
+ {
+ HMI_ERROR("Parse Error!!");
+ return WMError::FAIL;
+ }
+
+ int num_screen = json_object_array_length(json_cfg);
+ HMI_DEBUG("json_cfg(screens) len:%d", num_screen);
+
+ int screen_id;
+ json_object *json_screen;
+ for (int i = 0; i < num_screen; i++)
+ {
+ json_screen = json_object_array_get_idx(json_cfg, i);
+ HMI_INFO("json_cfg dump:%s", json_object_get_string(json_cfg));
+
+ // TODO: Currently only one display is connected to a ECU.
+
+ screen_id = jh::getIntFromJson(json_screen, "id");
+
+ // Parse areas
+ json_object *json_tmp;
+ if (!json_object_object_get_ex(json_screen, "areas", &json_tmp))
+ {
+ HMI_ERROR("Parse Error!!");
+ return WMError::FAIL;
+ }
+
+ int num_area = json_object_array_length(json_tmp);
+ HMI_DEBUG("json_tmp(areas) len:%d", num_area);
+
+ const char *area;
+ for (int j = 0; j < num_area; j++)
+ {
+ json_object *json_area = json_object_array_get_idx(json_tmp, j);
+
+ area = jh::getStringFromJson(json_area, "name");
+ if (nullptr == area)
+ {
+ HMI_ERROR("Parse Error!!");
+ return WMError::FAIL;
+ }
+ HMI_DEBUG("> area:%s", area);
+
+ json_object *json_rect;
+ if (!json_object_object_get_ex(json_area, "rect", &json_rect))
+ {
+ HMI_ERROR("Parse Error!!");
+ return WMError::FAIL;
+ }
+
+ struct rect area_size;
+ area_size.x = jh::getIntFromJson(json_rect, "x");
+ area_size.y = jh::getIntFromJson(json_rect, "y");
+ area_size.w = jh::getIntFromJson(json_rect, "w");
+ area_size.h = jh::getIntFromJson(json_rect, "h");
+
+ this->area2size[area] = area_size;
+ }
+
+ // Check
+ for (const auto& itr : this->area2size)
+ {
+ HMI_DEBUG("area:%s x:%d y:%d w:%d h:%d",
+ itr.first.c_str(), itr.second.x, itr.second.y,
+ itr.second.w, itr.second.h);
+ }
+ }
+
+ // Release json_object
+ json_object_put(json_obj);
+
+ return WMError::SUCCESS;
+}
+
+WMError LayerControl::layoutChange(const WMAction& action)
+{
+ if ((action.visible == TaskVisible::INVISIBLE) ||
+ (action.visible == TaskVisible::REQ_REMOTE_VISIBLE) ||
+ (action.visible == TaskVisible::REQ_REMOTE_INVISIBLE))
+ {
+ // Visibility is not change -> no redraw is required
+ return WMError::SUCCESS;
+ }
+ if(action.client == nullptr)
+ {
+ HMI_SEQ_ERROR(action.req_num, "client may vanish");
+ return WMError::NOT_REGISTERED;
+ }
+ unsigned layer = action.client->layerID();
+ unsigned surface = action.client->surfaceID();
+
+ auto rect = this->getAreaSize(action.area);
+ HMI_DEBUG("Set layout %d, %d, %d, %d",rect.x, rect.y, rect.w, rect.h);
+
+ // TO BE FIXED:
+ // Sometimes, ivi_wm_surface_size signal doesn't reach window manager,
+ // then, Window Manager can't set source size.
+ // This fixes it but it takes about 200ns(on R-Car M3) wastefully
+ ilmSurfaceProperties sp;
+ ilm_getPropertiesOfSurface(surface, &sp);
+ if(sp.origSourceHeight != sp.sourceHeight) {
+ HMI_SEQ_NOTICE(action.req_num, "WORK AROUND: set source size w:%d h%d", sp.origSourceWidth, sp.origSourceHeight);
+ ilm_surfaceSetSourceRectangle(surface, 0, 0, sp.origSourceWidth, sp.origSourceHeight);
+ ilm_commitChanges();
+ }
+
+ ilm_surfaceSetDestinationRectangle(surface, rect.x, rect.y, rect.w, rect.h);
+ ilm_commitChanges();
+ for(auto &wm_layer: this->wm_layers)
+ {
+ // Store the state who is assigned to the area
+ if(wm_layer->hasLayerID(layer))
+ {
+ wm_layer->setAreaToState(action.client->appID(), action.area);
+ /* TODO: manipulate state directly
+ LayerState ls = wm_layer->getLayerState();
+ ls.setArea(action.client->appID(), action.area);
+ wm_layer->dump(); */
+ }
+ }
+
+ return WMError::SUCCESS;
+}
+
+WMError LayerControl::visibilityChange(const WMAction& action)
+{
+ WMError ret = WMError::FAIL;
+ if(action.client == nullptr)
+ {
+ HMI_SEQ_ERROR(action.req_num, "client may vanish");
+ return WMError::NOT_REGISTERED;
+ }
+
+ if (action.visible == TaskVisible::VISIBLE)
+ {
+ ret = this->makeVisible(action.client);
+ }
+ else if (action.visible == TaskVisible::INVISIBLE)
+ {
+ ret = this->makeInvisible(action.client);
+ }
+ else if (action.visible == TaskVisible::REMOTE_VISIBLE)
+ {
+ ret = this->makeRemoteVisible(action.client);
+ }
+ else if (action.visible == TaskVisible::REMOTE_INVISIBLE)
+ {
+ ret = this->makeRemoteInvisible(action.client);
+ }
+ else // TaskVisible::REQ_REMOTE_VISIBLE || TaskVisible::REQ_REMOTE_INVISIBLE
+ {
+ // Visibility is not change
+ ret = WMError::SUCCESS;
+ }
+
+ return ret;
+}
+
+void LayerControl::terminateApp(const shared_ptr<WMClient> client)
+{
+ for(auto& l : this->wm_layers)
+ {
+ l->terminateApp(client->layerID());
+ }
+}
+
+void LayerControl::dispatchCreateEvent(ilmObjectType object, unsigned id, bool created)
+{
+ if (ILM_SURFACE == object)
+ {
+ if (created)
+ {
+ ilmSurfaceProperties sp;
+ ilmErrorTypes rc;
+ rc = ilm_getPropertiesOfSurface(id, &sp);
+ if(rc != ILM_SUCCESS)
+ {
+ HMI_ERROR("Failed to get surface %d property due to %d", id, ilm_getError());
+ return;
+ }
+ this->cb.surfaceCreated(sp.creatorPid, id);
+ ilm_surfaceSetSourceRectangle(id, 0, 0, sp.origSourceWidth, sp.origSourceHeight);
+ ilm_surfaceAddNotification(id, surfaceCallback_static);
+ ilm_surfaceSetVisibility(id, ILM_TRUE);
+ ilm_surfaceSetType(id, ILM_SURFACETYPE_DESKTOP);
+ }
+ else
+ {
+ this->cb.surfaceDestroyed(id);
+ }
+ }
+ if (ILM_LAYER == object)
+ {
+ if(created)
+ {
+ ilm_layerAddNotification(id, layerCallback_static);
+ }
+ else
+ {
+ // Ignore here. Nothing to do currently.
+ // Process of application dead is handled by Window Manager
+ // from binder notification
+ }
+ }
+}
+
+void LayerControl::dispatchSurfacePropChangeEvent(unsigned id,
+ struct ilmSurfaceProperties* sprop,
+ t_ilm_notification_mask mask)
+{
+ /*
+ ILM_NOTIFICATION_CONTENT_AVAILABLE & ILM_NOTIFICATION_CONTENT_REMOVED
+ are not handled here, handled in create/destroy event
+ */
+ if (ILM_NOTIFICATION_VISIBILITY & mask)
+ {
+ HMI_DEBUG("surface %d turns visibility %d", id, sprop->visibility);
+ }
+ if (ILM_NOTIFICATION_OPACITY & mask)
+ {
+ HMI_DEBUG("surface %d turns opacity %f", id, sprop->opacity);
+ }
+ if (ILM_NOTIFICATION_SOURCE_RECT & mask)
+ {
+ HMI_DEBUG("surface %d source rect changes", id);
+ }
+ if (ILM_NOTIFICATION_DEST_RECT & mask)
+ {
+ HMI_DEBUG("surface %d dest rect changes", id);
+ }
+ if (ILM_NOTIFICATION_CONFIGURED & mask)
+ {
+ HMI_DEBUG("surface %d size %d, %d, %d, %d", id,
+ sprop->sourceX, sprop->sourceY, sprop->origSourceWidth, sprop->origSourceHeight);
+ ilm_surfaceSetSourceRectangle(id, 0, 0, sprop->origSourceWidth, sprop->origSourceHeight);
+ }
+}
+
+void LayerControl::dispatchLayerPropChangeEvent(unsigned id,
+ struct ilmLayerProperties* lprop,
+ t_ilm_notification_mask mask)
+{
+ if (ILM_NOTIFICATION_VISIBILITY & mask)
+ {
+ HMI_DEBUG("layer %d turns visibility %d", id, lprop->visibility);
+ }
+ if (ILM_NOTIFICATION_OPACITY & mask)
+ {
+ HMI_DEBUG("layer %d turns opacity %f", id, lprop->opacity);
+ }
+ if (ILM_NOTIFICATION_SOURCE_RECT & mask)
+ {
+ HMI_DEBUG("layer %d source rect changes", id);
+ }
+ if (ILM_NOTIFICATION_DEST_RECT & mask)
+ {
+ HMI_DEBUG("layer %d dest rect changes", id);
+ }
+}
+
+WMError LayerControl::makeVisible(const shared_ptr<WMClient> client)
+{
+ WMError ret = WMError::SUCCESS;
+ // Don't check here the client is not nullptr
+ unsigned layer = client->layerID();
+
+ this->moveForeGround(client);
+
+ ilm_layerSetVisibility(layer, ILM_TRUE);
+
+ /* for(auto& wm_layer : this->wm_layers)
+ {
+ if(wm_layer->hasLayerID(layer))
+ {
+ LayerState ls = wm_layer->getLayerState();
+ ls.addLayer(layer);;
+ }
+ } */
+
+ // Move foreground from back ground layer
+ /* for(auto& wm_layer : this->wm_layers)
+ {
+ if(wm_layer->layerName() == "BackGroundLayer")
+ {
+ if(wm_layer->hasRole(client->role()))
+ {
+ LayerState ls = wm_layer->getLayerState();
+ ls.removeLayer(layer);
+ }
+ break;
+ }
+ } */
+
+ return ret;
+}
+
+WMError LayerControl::makeInvisible(const shared_ptr<WMClient> client)
+{
+ WMError ret = WMError::SUCCESS;
+ unsigned layer = client->layerID(); // Don't check here the client is not nullptr
+
+ bool mv_ok = this->moveBackGround(client);
+
+ if(!mv_ok)
+ {
+ HMI_INFO("make invisible client %s", client->appID().c_str());
+ ilm_layerSetVisibility(layer, ILM_FALSE);
+ }
+
+ //ilm_layerSetDestinationRectangle(layer, 0, 0, 0, 0);
+
+ /* for(auto& wm_layer : this->wm_layers)
+ {
+ if(wm_layer->hasLayerID(layer))
+ {
+ LayerState ls = wm_layer->getLayerState();
+ ls.removeLayer(layer);;
+ }
+ } */
+
+
+
+ return ret;
+}
+
+WMError LayerControl::makeRemoteVisible(const shared_ptr<WMClient> client)
+{
+ WMError ret = WMError::SUCCESS;
+ unsigned layer = client->layerID(); // Don't check here the client is not nullptr
+
+ if (0 > this->remoteScreenID)
+ {
+ return ret;
+ }
+
+ // TODO: Currently there is only one remote screen.
+ for (auto itr = this->wm_layers.begin(); itr != this->wm_layers.end(); ++itr)
+ {
+ if((*itr)->hasLayerID(layer))
+ {
+ HMI_DEBUG("Add layer:%d to remote screen:%d", layer, this->remoteScreenID);
+ this->wm_remote_layers.push_back(*itr);
+ this->wm_layers.erase(itr);
+ }
+
+ if (this->wm_layers.end() == itr)
+ {
+ HMI_DEBUG("iteretor indicates end of vector of wm_layers");
+ break;
+ }
+ }
+
+ ilm_layerSetVisibility(layer, ILM_TRUE);
+
+ return ret;
+}
+
+WMError LayerControl::makeRemoteInvisible(const shared_ptr<WMClient> client)
+{
+ WMError ret = WMError::SUCCESS;
+ unsigned layer = client->layerID(); // Don't check here the client is not nullptr
+
+ if (0 > this->remoteScreenID)
+ {
+ return ret;
+ }
+
+ // TODO: Currently there is only one remote screen.
+ for (auto itr = this->wm_remote_layers.begin();
+ itr != this->wm_remote_layers.end(); ++itr)
+ {
+ if((*itr)->hasLayerID(layer))
+ {
+ HMI_DEBUG("Remove layer:%d from remote screen:%d", layer, this->remoteScreenID);
+ this->wm_layers.push_back(*itr);
+ this->wm_remote_layers.erase(itr);
+ }
+
+ if (this->wm_remote_layers.end() == itr)
+ {
+ HMI_DEBUG("iteretor indicates end of vector of wm_remote_layers");
+ break;
+ }
+ }
+
+ ilm_layerSetVisibility(layer, ILM_FALSE);
+
+ return ret;
+}
+
+bool LayerControl::moveBackGround(const shared_ptr<WMClient> client)
+{
+ bool ret = false;
+
+ // Move background from foreground layer
+ auto bg = this->getWMLayer(BACK_GROUND_LAYER);
+ if(bg != nullptr)
+ {
+ HMI_DEBUG("client %s role %s", client->appID().c_str(), client->role().c_str());
+ unsigned layer = client->layerID();
+ if(bg->hasRole(client->role()))
+ {
+ HMI_INFO("%s go to background", client->appID().c_str());
+ bg->addLayerToState(layer);
+ auto wm_layer = this->getWMLayer(layer);
+ wm_layer->removeLayerFromState(layer);
+ /* TODO: manipulate state directly
+ LayerState bg_ls = bg->getLayerState();
+ bg_ls.addLayer(layer);
+ LayerState ls = wm_layer->getLayerState();
+ ls.removeLayer(layer); */
+ bg->dump();
+ wm_layer->dump();
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+bool LayerControl::moveForeGround(const shared_ptr<WMClient> client)
+{
+ bool ret = false;
+
+ // Move foreground from foreground layer
+ auto bg = this->getWMLayer(BACK_GROUND_LAYER);
+ if(bg != nullptr)
+ {
+ if(bg->hasRole(client->role()))
+ {
+ unsigned layer = client->layerID();
+ HMI_INFO("%s go to foreground", client->appID().c_str());
+ bg->removeLayerFromState(layer);
+ auto wm_layer = this->getWMLayer(layer);
+ wm_layer->addLayerToState(layer);
+ /* TODO: manipulate state directly
+ LayerState bg_ls = bg->getLayerState();
+ bg_ls.removeLayer(layer);
+ LayerState ls = wm_layer->getLayerState();
+ ls.addLayer(layer); */
+ bg->dump();
+ wm_layer->dump();
+ ret = true;
+ }
+ }
+ return ret;
+}
+
+} // namespace wm
diff --git a/demo#3/common/agl-service-windowmanager/src/wm_layer_control.hpp b/demo#3/common/agl-service-windowmanager/src/wm_layer_control.hpp
new file mode 100644
index 0000000..fa7c7cb
--- /dev/null
+++ b/demo#3/common/agl-service-windowmanager/src/wm_layer_control.hpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
+ *
+ * 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 <string>
+#include <memory>
+#include <vector>
+#include <unordered_map>
+#include <functional>
+#include <ilm/ilm_control.h>
+#include "wm_error.hpp"
+#include "util.hpp"
+
+namespace wm {
+
+class Screen {
+ public:
+ Screen(unsigned w, unsigned h) : _width(w), _height(h){}
+ unsigned width() { return _width; }
+ unsigned height() { return _height; }
+ private:
+ unsigned _width;
+ unsigned _height;
+ unsigned _pysical_width = 0;
+ unsigned _pysical_height = 0;
+};
+
+class LayerControlCallbacks {
+ public:
+ LayerControlCallbacks() {};
+ ~LayerControlCallbacks() = default;
+ LayerControlCallbacks(const LayerControlCallbacks &obj) = default;
+
+ // callback functions
+ std::function<void(unsigned, unsigned)> surfaceCreated;
+ std::function<void(unsigned)> surfaceDestroyed;
+ /* std::function<void(unsigned)> surfaceDestroyed;
+ std::function<void(unsigned)> layerCreated;
+ std::function<void(unsigned)> layerDestroyed; */
+};
+
+class WMLayer;
+class LayerState;
+class WMAction;
+class WMClient;
+
+class LayerControl
+{
+ public:
+ explicit LayerControl(const std::string& root, const std::string& ecu_name);
+ ~LayerControl() = default;
+ WMError init(const LayerControlCallbacks& cb);
+ void createNewLayer(unsigned id);
+ void createNewRemoteLayer(unsigned id);
+ unsigned getNewLayerID(const std::string& role, std::string* layer_name);
+ std::shared_ptr<WMLayer> getWMLayer(unsigned layer);
+ std::shared_ptr<WMLayer> getWMLayer(std::string layer_name);
+ struct rect getAreaSize(const std::string& area);
+ void setupArea(const rectangle& base_rct, double scaling);
+ Screen getScreenInfo();
+ double scale();
+ // void setRenderOrder(const std::vector<unsigned> layer_render_order);
+ // std::vector<unsigned> getAllRenderOrder();
+ // std::vector<std::shared_ptr<WMLayer>>& getAllLayers();
+ // std::vector<unsigned> getRenderOrder(const std::string& layer_name);
+ WMError updateLayer(LayerState& layer_state);
+ WMError renderLayers();
+ WMError renderLayersRemote();
+ WMError setXDGSurfaceOriginSize(unsigned surface);
+ // WMError renderWMLayers();
+ void undoUpdate();
+ WMError layoutChange(const WMAction& action);
+ WMError visibilityChange(const WMAction &action);
+ void terminateApp(const std::shared_ptr<WMClient> client);
+
+ // Don't use this function.
+ void dispatchCreateEvent(ilmObjectType object, unsigned id, bool created);
+ void dispatchSurfacePropChangeEvent(unsigned id, struct ilmSurfaceProperties*, t_ilm_notification_mask);
+ void dispatchLayerPropChangeEvent(unsigned id, struct ilmLayerProperties*, t_ilm_notification_mask);
+
+ private:
+ WMError makeVisible(const std::shared_ptr<WMClient> client);
+ WMError makeInvisible(const std::shared_ptr<WMClient> client);
+ bool moveForeGround(const std::shared_ptr<WMClient> client);
+ bool moveBackGround(const std::shared_ptr<WMClient> client);
+ WMError loadLayerSetting(const std::string& path);
+ WMError loadAreasConfigFile(const std::string& path, const std::string& ecu_name);
+
+ // For Remote
+ WMError makeRemoteVisible(const std::shared_ptr<WMClient> client);
+ WMError makeRemoteInvisible(const std::shared_ptr<WMClient> client);
+
+ std::vector<std::shared_ptr<WMLayer>> wm_layers;
+ std::vector<std::shared_ptr<WMLayer>> wm_remote_layers;
+ std::unordered_map<unsigned, unsigned> lid2wmlid;
+ std::unordered_map<std::string, struct rect> area2size;
+ unsigned screenID;
+ signed remoteScreenID;
+ struct ilmScreenProperties screen_prop;
+ double scaling;
+ int offset_x;
+ int offset_y;
+ LayerControlCallbacks cb;
+};
+
+} // namespace wm