diff options
author | Kazumasa Mitsunari <knimitz@witz-inc.co.jp> | 2018-06-25 11:22:00 +0900 |
---|---|---|
committer | Kazumasa Mitsunari <knimitz@witz-inc.co.jp> | 2018-06-27 08:18:41 +0000 |
commit | 847dde9621cef9b9a44eda95c63c0fe3f528468d (patch) | |
tree | 1273830d4ad87614ae7323eb9e338f621494652e | |
parent | d1127dd62c25e9c4c7d545de2456c6f4c4d7309f (diff) |
Rework: Window Manager handles by application
To manage role, surface, layer ... and other info more easily,
Window Manager handles info by application.
WMClient class holds infomation of application.
WMRequest class holds the request from application(trigger) and
the action list judged by policy manager.
The above info is in applist.
*applist
Hold client list.
And hold request list which comes from application to get the right of displaying.
*request
The request from application and the Action judged from Policy Manager
*client
Application information which has surface, role and so on.
*error
Error code and error message.
Integration patch is going to be pushed after this commit.
Bug-AGL: SPEC-1509
Change-Id: I52b161701e22e316137dc42f073b118d164c1e28
Signed-off-by: Kazumasa Mitsunari <knimitz@witz-inc.co.jp>
-rw-r--r-- | include/hmi-debug.h | 47 | ||||
-rw-r--r-- | src/CMakeLists.txt | 6 | ||||
-rw-r--r-- | src/app.hpp | 2 | ||||
-rw-r--r-- | src/applist.cpp | 526 | ||||
-rw-r--r-- | src/applist.hpp | 81 | ||||
-rw-r--r-- | src/request.cpp | 44 | ||||
-rw-r--r-- | src/request.hpp | 72 | ||||
-rw-r--r-- | src/wm_client.cpp | 222 | ||||
-rw-r--r-- | src/wm_client.hpp | 76 | ||||
-rw-r--r-- | src/wm_error.cpp | 46 | ||||
-rw-r--r-- | src/wm_error.hpp | 41 |
11 files changed, 1160 insertions, 3 deletions
diff --git a/include/hmi-debug.h b/include/hmi-debug.h index a1d3079..697ac80 100644 --- a/include/hmi-debug.h +++ b/include/hmi-debug.h @@ -41,6 +41,14 @@ enum LOG_LEVEL{ #define HMI_INFO(prefix, args,...) _HMI_LOG(LOG_LEVEL_INFO, __FILENAME__, __FUNCTION__,__LINE__, prefix, args,##__VA_ARGS__) #define HMI_DEBUG(prefix, args,...) _HMI_LOG(LOG_LEVEL_DEBUG, __FILENAME__, __FUNCTION__,__LINE__, prefix, 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__) + static char ERROR_FLAG[6][20] = {"NONE", "ERROR", "WARNING", "NOTICE", "INFO", "DEBUG"}; static void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, const int line, const char* prefix, const char* log, ...) @@ -67,4 +75,43 @@ static void _HMI_LOG(enum LOG_LEVEL level, const char* file, const char* func, c free(message); } +static 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); +} + +static 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); +} #endif //__HMI_DEBUG_H__
\ No newline at end of file diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index f727500..db3f9cd 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -33,7 +33,11 @@ add_library(${TARGETS_WM} MODULE ${IVI_CON_PROTO} json_helper.cpp app.cpp - layers.cpp) + layers.cpp + wm_client.cpp + wm_error.cpp + applist.cpp + request.cpp) target_include_directories(${TARGETS_WM} PRIVATE diff --git a/src/app.hpp b/src/app.hpp index ab4e809..4dce828 100644 --- a/src/app.hpp +++ b/src/app.hpp @@ -69,7 +69,6 @@ struct id_allocator // Surfaces that where requested but not yet created std::unordered_map<unsigned, std::string> id2name; - // std::unordered_set<unsigned> pending_surfaces; std::unordered_map<std::string, unsigned> name2id; id_allocator(id_allocator const &) = delete; @@ -82,7 +81,6 @@ struct id_allocator { unsigned sid = this->next++; this->id2name[sid] = name; - // this->pending_surfaces.insert({sid}); this->name2id[name] = sid; HMI_DEBUG("wm", "allocated new id %u with name %s", sid, name.c_str()); return sid; diff --git a/src/applist.cpp b/src/applist.cpp new file mode 100644 index 0000000..a5ae9f0 --- /dev/null +++ b/src/applist.cpp @@ -0,0 +1,526 @@ +/* + * 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 "../include/hmi-debug.h" + +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 std::string &appid, unsigned layer, unsigned surface, const std::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(); +} + +/** + * 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("wm", "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("wm", "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) +{ + return this->app2client.at(appid); +} + +/** + * 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(""); +} + +// =================== 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, const string &appid, 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{appid, role, area, visible, edraw_f}; + + 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 (y.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; + } + } + } + } + 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.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 ====="); +} +} // namespace wm diff --git a/src/applist.hpp b/src/applist.hpp new file mode 100644 index 0000000..a794b53 --- /dev/null +++ b/src/applist.hpp @@ -0,0 +1,81 @@ +/* + * 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; */ + +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 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, const std::string &role, bool *found) const; + + // 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, const std::string &appid, + 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(); + + private: + std::vector<WMRequest> req_list; + std::unordered_map<std::string, std::shared_ptr<WMClient>> app2client; + unsigned current_req; + std::mutex mtx; +}; + +} // namespace wm +#endif // ALLOCATE_LIST_HPP
\ No newline at end of file diff --git a/src/request.cpp b/src/request.cpp new file mode 100644 index 0000000..069f8ff --- /dev/null +++ b/src/request.cpp @@ -0,0 +1,44 @@ +/* + * 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() +{ +} + +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
\ No newline at end of file diff --git a/src/request.hpp b/src/request.hpp new file mode 100644 index 0000000..6b2bda1 --- /dev/null +++ b/src/request.hpp @@ -0,0 +1,72 @@ +/* + * 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> + +namespace wm +{ + +enum Task +{ + TASK_ALLOCATE, + TASK_RELEASE, + TASK_INVALID +}; + +enum TaskVisible +{ + VISIBLE, + INVISIBLE, + NO_CHANGE +}; + +struct WMTrigger +{ + std::string appid; + std::string role; + std::string area; + Task task; +}; + +struct WMAction +{ + std::string appid; + std::string role; + std::string area; + TaskVisible visible; + bool end_draw_finished; +}; + +struct WMRequest +{ + WMRequest(); + explicit WMRequest(std::string appid, std::string role, + std::string area, 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
\ No newline at end of file diff --git a/src/wm_client.cpp b/src/wm_client.cpp new file mode 100644 index 0000000..a9ed547 --- /dev/null +++ b/src/wm_client.cpp @@ -0,0 +1,222 @@ +/* + * 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 "hmi-debug.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 + event2list[x] = ev; + } +} + +WMClient::WMClient(const string &appid, const string &role) + : id(appid), + layer(0), + role2surface(0), + event2list(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 + event2list[x] = ev; + } +} + +WMClient::~WMClient() +{ +} + +string WMClient::appID() const +{ + return this->id; +} + +unsigned WMClient::surfaceID(const string &role) const +{ + if (0 == this->role2surface.count(role)) + { + return INVALID_SURFACE_ID; + } + return this->role2surface.at(role); +} + +std::string WMClient::role(unsigned surface) const +{ + for(const auto& x : this->role2surface) + { + if(x.second == surface) + { + return x.first; + } + } + return std::string(""); +} + +unsigned WMClient::layerID() const +{ + return this->layer; +} + +/** + * Set layerID the client belongs to + * + * This function set layerID the client belongs to. + * But this function may not used because the layer should be fixed at constructor. + * So this function will be used to change layer by some reasons. + * + * @param unsigned[in] layerID + * @return None + * @attention WMClient can't have multiple layer + */ +void WMClient::registerLayer(unsigned layer) +{ + this->layer = layer; +} + +/** + * Add the pair of role and surface to the client + * + * This function set the pair of role and surface to the client. + * This function is used for the client which has multi surfaces. + * If the model and relationship for role and surface(layer) + * is changed, this function will be changed + * Current Window Manager doesn't use this function. + * + * @param string[in] role + * @param unsigned[in] surface + * @return true + */ +bool WMClient::addSurface(const string &role, unsigned surface) +{ + HMI_DEBUG("wm", "Add role %s with surface %d", role.c_str(), surface); + if (0 != this->role2surface.count(role)) + { + HMI_NOTICE("wm", "override surfaceID %d with %d", this->role2surface[role], surface); + } + this->role2surface[role] = surface; + return true; +} + +bool WMClient::removeSurfaceIfExist(unsigned surface) +{ + bool ret = false; + for (auto &x : this->role2surface) + { + if (surface == x.second) + { + HMI_INFO("wm", "Remove surface from client %s: role %s, surface: %d", + this->id.c_str(), x.first.c_str(), x.second); + this->role2surface.erase(x.first); + ret = true; + break; + } + } + return ret; +} + +bool WMClient::removeRole(const string &role) +{ + bool ret = false; + if (this->role2surface.count(role) != 0) + { + this->role2surface.erase(role); + ret = true; + } + return ret; +} + +#ifndef GTEST_ENABLED +bool WMClient::subscribe(afb_req req, const string &evname) +{ + if(evname != kKeyError){ + HMI_DEBUG("wm", "error is only enabeled for now"); + return false; + } + int ret = afb_req_subscribe(req, this->event2list[evname]); + if (ret) + { + HMI_DEBUG("wm", "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->event2list[kKeyError])){ + HMI_ERROR("wm", "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("wm", "error: %d, description:%s", ev, kErrorDescription[ev].c_str()); + + int ret = afb_event_push(this->event2list[kKeyError], j); + if (ret != 0) + { + HMI_DEBUG("wm", "afb_event_push failed: %m"); + } +} +#endif + +void WMClient::dumpInfo() +{ + DUMP("APPID : %s", id.c_str()); + DUMP(" LAYER : %d", layer); + for (const auto &x : this->role2surface) + { + DUMP(" ROLE : %s , SURFACE : %d", x.first.c_str(), x.second); + } +} + +} // namespace wm
\ No newline at end of file diff --git a/src/wm_client.hpp b/src/wm_client.hpp new file mode 100644 index 0000000..0d6faeb --- /dev/null +++ b/src/wm_client.hpp @@ -0,0 +1,76 @@ +/* + * 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> + +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); + virtual ~WMClient(); + + std::string appID() const; + unsigned surfaceID(const std::string &role) const; + unsigned layerID() const; + std::string role(unsigned surface) const; + void registerLayer(unsigned layer); + bool addSurface(const std::string& role, unsigned surface); + bool removeSurfaceIfExist(unsigned surface); + bool removeRole(const std::string& role); + +#ifndef 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::unordered_map<std::string, unsigned> role2surface; +#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> event2list; +#else + std::unordered_map<std::string, struct afb_event> event2list; +#endif +}; +} // namespace wm + +#endif
\ No newline at end of file diff --git a/src/wm_error.cpp b/src/wm_error.cpp new file mode 100644 index 0000000..694a7d0 --- /dev/null +++ b/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/src/wm_error.hpp b/src/wm_error.hpp new file mode 100644 index 0000000..c4c61b4 --- /dev/null +++ b/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 |