From 010ca3f3459a52e44deb5e70e94e9cd394814e3e Mon Sep 17 00:00:00 2001 From: Kazumasa Mitsunari Date: Mon, 22 Oct 2018 09:30:19 +0900 Subject: Attach application to ivi-layer not to surface Window Manager expresses the application in ivi-layer. So for, Window Manager tied the surface and role applied by the application. This patch associates the application with the ivi-layer, and the role and surface are the attributes that makes up the application. Bug-AGL: SPEC-1818, SPEC-1635 Change-Id: Ice1e398e1db037577b0721c16da6603ec5437561 Signed-off-by: Kazumasa Mitsunari --- layers.json | 97 ++++++++++--------- src/applist.cpp | 22 ++++- src/applist.hpp | 5 +- src/window_manager.cpp | 129 +++++++++++++------------- src/window_manager.hpp | 3 - src/wm_client.cpp | 111 ++++++++-------------- src/wm_client.hpp | 20 ++-- src/wm_layer.cpp | 199 ++++++++++++++++++++++++++++++++++++++- src/wm_layer.hpp | 64 ++++++++++--- src/wm_layer_control.cpp | 236 +++++++++++++++++++++++++++-------------------- src/wm_layer_control.hpp | 16 ++-- 11 files changed, 584 insertions(+), 318 deletions(-) diff --git a/layers.json b/layers.json index 44e2adb..539846a 100644 --- a/layers.json +++ b/layers.json @@ -1,47 +1,54 @@ { - "comment": "Surface ID to Layer ID mapping", - - "main_surface": { - "surface_role": "HomeScreen", - "comment": "This surface should never be made invisible (The HomeScreen)" - }, - - "mappings": [ - { - "role": "BackGroundLayer", - "name": "BackGroundLayer", - "layer_id": 999, - "comment": "Single BackGround layer map for the map, radio, music and video" - }, - { - "role": "homescreen", - "name": "FarHomeScreen", - "layer_id": 1000, - "comment": "FarHomeScreen is the part of HomeScreen. The z order of this layer is lower than NearHomeScreen" - }, - { - "role": "music|video|browser|radio|phone|navigation|map|hvac|settings|dashboard|poi|mixer|sdl|launcher|fallback", - "name": "Apps", - "layer_id": 1001, - "comment": "Range of IDs that will always be placed on layer 1001" - }, - { - "role": "software_keyboard", - "name": "NearHomeScreen", - "layer_id": 1002, - "comment": "NearHomeScreen is the part of HomeScreen. The z order of this layer is upper than FarHomeScreen" - }, - { - "role": "restriction", - "name": "Restriction", - "layer_id": 1003, - "comment": "This layer is for restriction notification. This is used by restriction role" - }, - { - "role": "^on_screen.*", - "name": "OnScreen", - "layer_id": 9999, - "comment": "Range of IDs that will always be placed on the OnScreen layer, that gets a very high 'dummy' id of 9999" - } - ] + "description": "Layer mapping", + "mappings": [ + { + "name": "BackGroundLayer", + "role" : "navigation|radio|music|video", + "id_range_begin": 0, + "id_range_end": 0, + "comment": "Work Around: This is a special fallback layer that not stopping wayland event loop." + }, + { + "name": "FarHomeScreen", + "role": "homescreen", + "id_range_begin": 100, + "id_range_end": 199, + "comment": "FarHomeScreen is the part of HomeScreen. The z order of this layer is lower than NearHomeScreen" + }, + { + "name": "Apps", + "role": "music|video|browser|radio|phone|navigation|map|hvac|settings|dashboard|poi|mixer|sdl|launcher|fallback", + "id_range_begin": 1000, + "id_range_end": 2999, + "comment": "Application layer" + }, + { + "name": "NearHomeScreen", + "role": "software_keyboard", + "id_range_begin": 3000, + "id_range_end": 3999, + "comment": "NearHomeScreen is the part of HomeScreen. The usecase is used by software_keyboard etc" + }, + { + "name": "Popup", + "role": "popup*", + "id_range_begin": 4000, + "id_range_end": 4999, + "comment": "This layer is for popup application layer" + }, + { + "name": "Restriction", + "role": "restriction", + "id_range_begin": 5000, + "id_range_end": 5999, + "comment": "This layer is for restriction notification on driving. This is used by restriction role" + }, + { + "name": "OnScreen", + "role": "^on_screen.*", + "id_range_begin": 6000, + "id_range_end": 6999, + "comment": "System notification layer. For example, on_screen_low_battery_alert to notify user" + } + ] } diff --git a/src/applist.cpp b/src/applist.cpp index 79df62c..17b47e3 100644 --- a/src/applist.cpp +++ b/src/applist.cpp @@ -73,6 +73,14 @@ void AppList::addClient(const string &appid, unsigned layer, unsigned surface, c this->clientDump(); } +void AppList::addClient(const string &appid, unsigned layer, const string &role) +{ + std::lock_guard lock(this->mtx); + shared_ptr client = std::make_shared(appid, layer, role); + this->app2client[appid] = client; + this->clientDump(); +} + /** * Remove WMClient from the list * @@ -132,7 +140,14 @@ void AppList::removeSurface(unsigned surface){ */ shared_ptr AppList::lookUpClient(const string &appid) { - return this->app2client.at(appid); + if(this->app2client.count(appid) != 0) + { + return this->app2client.at(appid); + } + else + { + return nullptr; + } } /** @@ -154,17 +169,16 @@ int AppList::countClient() const * 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 +string AppList::getAppID(unsigned surface, bool* found) const { *found = false; for (const auto &x : this->app2client) { - if(x.second->surfaceID(role) == surface){ + if(x.second->surfaceID() == surface){ *found = true; return x.second->appID(); } diff --git a/src/applist.hpp b/src/applist.hpp index 54ccdd1..085504a 100644 --- a/src/applist.hpp +++ b/src/applist.hpp @@ -43,13 +43,14 @@ class AppList 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); + 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 lookUpClient(const std::string &appid); void removeSurface(unsigned surface); - std::string getAppID(unsigned surface, const std::string &role, bool *found) const; + std::string getAppID(unsigned surface, bool* found) const; // TODO: remove // Request Interface unsigned currentRequestNumber() const; diff --git a/src/window_manager.cpp b/src/window_manager.cpp index c73952d..edd3c12 100644 --- a/src/window_manager.cpp +++ b/src/window_manager.cpp @@ -157,8 +157,6 @@ int WindowManager::init() double scale = static_cast(dp_bg.height()) / css_bg.h; this->lc->setupArea(dp_bg, scale); - this->lc->createLayers(); - return 0; } @@ -167,34 +165,35 @@ result WindowManager::api_request_surface(char const *appid, char const *dr // TODO: application requests by old role, // so convert role old to new const char *role = this->convertRoleOldToNew(drawing_name); + string str_id = appid; + string str_role = role; + unsigned lid = 0; - // auto lid = this->layers.get_layer_id(string(role)); - unsigned lid = this->lc->getLayerID(string(role)); - if (lid == 0) + if(!g_app_list.contains(str_id)) { - /** - * register drawing_name as fallback and make it displayed. - */ - // lid = this->layers.get_layer_id(string("fallback")); - lid = this->lc->getLayerID(string("fallback")); - HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); + lid = this->lc->getNewLayerID(str_role); if (lid == 0) { - return Err("Drawing name does not match any role, fallback is disabled"); + // register drawing_name as fallback and make it displayed. + lid = this->lc->getNewLayerID(string("fallback")); + HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); + if (lid == 0) + { + return Err("Designated role does not match any role, fallback is disabled"); + } } + this->lc->createNewLayer(lid); + // add client into the db + g_app_list.addClient(str_id, lid, str_role); } - auto rname = this->id_alloc.lookup(role); + // generate surface ID for ivi-shell application + auto rname = this->id_alloc.lookup(str_role); if (!rname) { // name does not exist yet, allocate surface id... - auto id = int(this->id_alloc.generate_id(role)); - // this->layers.add_surface(id, *lid); - this->tmp_surface2app[id] = {string(appid), lid}; - - // add client into the db - string appid_str(appid); - g_app_list.addClient(appid_str, lid, id, string(role)); + auto id = int(this->id_alloc.generate_id(str_role)); + this->tmp_surface2app[id] = {str_id, lid}; // Set role map of (new, old) this->rolenew2old[role] = string(drawing_name); @@ -212,8 +211,16 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr // TODO: application requests by old role, // so convert role old to new const char *role = this->convertRoleOldToNew(drawing_name); + string str_id = appid; + string str_role = role; 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) { @@ -222,22 +229,25 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr return "fail"; } - // auto lid = this->layers.get_layer_id(string(role)); - auto lid = this->lc->getLayerID(string(role)); - if (lid == 0) + if(!g_app_list.contains(str_id)) { - /** - * register drawing_name as fallback and make it displayed. - */ - lid = this->lc->getLayerID(string("fallback")); - HMI_DEBUG("%s is not registered in layers.json, then fallback as normal app", role); - if (lid == 0) + unsigned l_id = this->lc->getNewLayerID(str_role); + if (l_id == 0) { - return "Drawing name does not match any role, fallback is disabled"; + // register drawing_name as fallback and make it displayed. + l_id = this->lc->getNewLayerID("fallback"); + 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"; + } } + this->lc->createNewLayer(l_id); + // add client into the db + g_app_list.addClient(str_id, l_id, str_role); } - auto rname = this->id_alloc.lookup(role); + auto rname = this->id_alloc.lookup(str_role); if (rname) { @@ -245,14 +255,10 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr } // register pair drawing_name and ivi_id - this->id_alloc.register_name_id(role, sid); - this->lc->addSurface(sid, lid); + this->id_alloc.register_name_id(str_role, sid); - HMI_DEBUG("surface_id is %u, layer_id is %u", sid, lid); - - // add client into the list - string appid_str(appid); - g_app_list.addClient(appid_str, lid, sid, string(role)); + auto client = g_app_list.lookUpClient(str_id); + client->addSurface(sid); // Set role map of (new, old) this->rolenew2old[role] = string(drawing_name); @@ -276,8 +282,8 @@ void WindowManager::api_activate_window(char const *appid, char const *drawing_n reply("app doesn't request 'requestSurface' or 'setRole' yet"); return; } - auto client = g_app_list.lookUpClient(id); + Task task = Task::TASK_ALLOCATE; unsigned req_num = 0; WMError ret = WMError::UNKNOWN; @@ -390,6 +396,7 @@ void WindowManager::api_enddraw(char const *appid, char const *drawing_name) // 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)); @@ -493,10 +500,18 @@ void WindowManager::surface_created(unsigned surface_id) // requestSurface if(this->tmp_surface2app.count(surface_id) != 0) { - unsigned layer_id = this->tmp_surface2app[surface_id].layer; - this->lc->addSurface(surface_id, layer_id); + 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); - HMI_DEBUG("surface_id is %u, layer_id is %u", surface_id, layer_id); } } @@ -510,6 +525,8 @@ void WindowManager::surface_removed(unsigned 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->appTerminated(client); g_app_list.removeClient(appid); } @@ -560,7 +577,7 @@ void WindowManager::startTransitionWrapper(vector &actions) { goto proc_remove_request; } - string appid = g_app_list.getAppID(*surface_id, act.role, &found); + string appid = g_app_list.getAppID(*surface_id, &found); if (!found) { if (TaskVisible::INVISIBLE == act.visible) @@ -716,17 +733,6 @@ WMError WindowManager::checkPolicy(unsigned req_num) } 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)) { @@ -762,6 +768,7 @@ WMError WindowManager::startTransition(unsigned req_num) return ret; } + g_app_list.reqDump(); for (const auto &action : actions) { if (action.visible == TaskVisible::VISIBLE) @@ -798,6 +805,7 @@ WMError WindowManager::startTransition(unsigned req_num) this->deactivate(client->surfaceID(x.role)); } */ } + this->lc->renderLayers(); ret = WMError::NO_LAYOUT_CHANGE; } return ret; @@ -836,10 +844,12 @@ WMError WindowManager::doEndDraw(unsigned req_num) string old_role = this->rolenew2old[act.role]; if(act.visible == VISIBLE) { + emit_visible(old_role.c_str()); emit_activated(old_role.c_str()); } else { + emit_invisible(old_role.c_str()); emit_deactivated(old_role.c_str()); } @@ -852,6 +862,7 @@ WMError WindowManager::doEndDraw(unsigned req_num) HMI_SEQ_DEBUG(req_num, "visible %s", act.role.c_str()); } } + this->lc->renderLayers(); HMI_SEQ_INFO(req_num, "emit flushDraw"); @@ -1056,16 +1067,6 @@ int WindowManager::loadOldRoleDb() return 0; } -const char *WindowManager::check_surface_exist(const char *drawing_name) -{ - auto const &surface_id = this->id_alloc.lookup(drawing_name); - if (!surface_id) - { - return "Surface does not exist"; - } - return nullptr; -} - const char* WindowManager::kDefaultOldRoleDb = "{ \ \"old_roles\": [ \ { \ diff --git a/src/window_manager.hpp b/src/window_manager.hpp index 712edec..57b9fde 100644 --- a/src/window_manager.hpp +++ b/src/window_manager.hpp @@ -179,7 +179,6 @@ class WindowManager int api_subscribe(afb_req req, int event_id); result api_get_display_info(); result api_get_area_info(char const *role); - void api_ping(); void send_event(const std::string& evname, const std::string& role); void send_event(const std::string& evname, const std::string& role, const std::string& area, int x, int y, int w, int h); @@ -221,8 +220,6 @@ class WindowManager int loadOldRoleDb(); - const char *check_surface_exist(const char *role); - private: std::map map_afb_event; std::unordered_map area2size; diff --git a/src/wm_client.cpp b/src/wm_client.cpp index 2e12a69..7a93c7c 100644 --- a/src/wm_client.cpp +++ b/src/wm_client.cpp @@ -17,6 +17,7 @@ #include #include "wm_client.hpp" #include "util.hpp" +#include #define INVALID_SURFACE_ID 0 @@ -49,7 +50,7 @@ WMClient::WMClient(const string &appid, unsigned layer, unsigned surface, const #else afb_event ev = afb_daemon_make_event(x.c_str()); #endif - event2list[x] = ev; + evname2list[x] = ev; } } @@ -57,7 +58,7 @@ WMClient::WMClient(const string &appid, const string &role) : id(appid), layer(0), role2surface(0), - event2list(0) + evname2list(0) { role2surface[role] = INVALID_SURFACE_ID; for (auto x : kWMEvents) @@ -67,12 +68,27 @@ WMClient::WMClient(const string &appid, const string &role) #else afb_event ev = afb_daemon_make_event(x.c_str()); #endif - event2list[x] = ev; + evname2list[x] = ev; } } -WMClient::~WMClient() +WMClient::WMClient(const string &appid, unsigned layer, const string &role) + : id(appid), + layer(layer), + main_role(role), + role2surface(0), + evname2list(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 + evname2list[x] = ev; + } } string WMClient::appID() const @@ -80,25 +96,9 @@ 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 +string WMClient::role() const { - for(const auto& x : this->role2surface) - { - if(x.second == surface) - { - return x.first; - } - } - return std::string(""); + return this->main_role; } unsigned WMClient::layerID() const @@ -106,74 +106,43 @@ 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) +unsigned WMClient::surfaceID() const { - this->layer = layer; + return this->surface; } /** - * Add the pair of role and surface to the client + * Add 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. + * This function add main surface to the client(ivi_layer). * * @param string[in] role - * @param unsigned[in] surface - * @return true + * @return WMError */ -bool WMClient::addSurface(const string &role, unsigned surface) +WMError WMClient::addSurface(unsigned surface) { - HMI_DEBUG("Add role %s with surface %d", role.c_str(), surface); - if (0 != this->role2surface.count(role)) - { - HMI_NOTICE("override surfaceID %d with %d", this->role2surface[role], surface); - } - this->role2surface[role] = surface; - return true; -} + this->surface = surface; + ilmErrorTypes err = ilm_layerAddSurface(this->layer, surface); -bool WMClient::removeSurfaceIfExist(unsigned surface) -{ - bool ret = false; - for (auto &x : this->role2surface) + if(err == ILM_SUCCESS) { - if (surface == x.second) - { - HMI_INFO("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; - } + err = ilm_commitChanges(); } - return ret; + return (err == ILM_SUCCESS) ? WMError::SUCCESS : WMError::FAIL; } -bool WMClient::removeRole(const string &role) +bool WMClient::removeSurfaceIfExist(unsigned surface) { bool ret = false; - if (this->role2surface.count(role) != 0) + if(surface == this->surface) { - this->role2surface.erase(role); + this->surface = INVALID_SURFACE_ID; ret = true; } return ret; } + #if GTEST_ENABLED bool WMClient::subscribe(afb_req req, const string &evname) { @@ -181,7 +150,7 @@ bool WMClient::subscribe(afb_req req, const string &evname) HMI_DEBUG("error is only enabeled for now"); return false; } - int ret = afb_req_subscribe(req, this->event2list[evname]); + int ret = afb_req_subscribe(req, this->evname2list[evname]); if (ret) { HMI_DEBUG("Failed to subscribe %s", evname.c_str()); @@ -192,7 +161,7 @@ bool WMClient::subscribe(afb_req req, const string &evname) void WMClient::emitError(WM_CLIENT_ERROR_EVENT ev) { - if (!afb_event_is_valid(this->event2list[kKeyError])){ + if (!afb_event_is_valid(this->evname2list[kKeyError])){ HMI_ERROR("event err is not valid"); return; } @@ -201,7 +170,7 @@ void WMClient::emitError(WM_CLIENT_ERROR_EVENT 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->event2list[kKeyError], j); + int ret = afb_event_push(this->evname2list[kKeyError], j); if (ret != 0) { HMI_DEBUG("afb_event_push failed: %m"); diff --git a/src/wm_client.hpp b/src/wm_client.hpp index 259d504..7e92ed5 100644 --- a/src/wm_client.hpp +++ b/src/wm_client.hpp @@ -20,6 +20,7 @@ #include #include #include +#include "wm_error.hpp" extern "C" { @@ -42,16 +43,17 @@ class 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(); + 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; - unsigned surfaceID(const std::string &role) 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); + unsigned surfaceID() const; + WMError addSurface(unsigned surface); bool removeSurfaceIfExist(unsigned surface); - bool removeRole(const std::string& role); #if GTEST_ENABLED bool subscribe(afb_req req, const std::string &event_name); @@ -63,12 +65,16 @@ class WMClient private: std::string id; unsigned layer; + std::string main_role; + std::string area; + unsigned surface; // currently, main application has only one surface. + //std::vector role_list; std::unordered_map role2surface; #if GTEST_ENABLED // This is for unit test. afb_make_event occurs sig11 if call not in afb-binding std::unordered_map event2list; #else - std::unordered_map event2list; + std::unordered_map evname2list; #endif }; } // namespace wm diff --git a/src/wm_layer.cpp b/src/wm_layer.cpp index c702651..294e356 100644 --- a/src/wm_layer.cpp +++ b/src/wm_layer.cpp @@ -23,15 +23,190 @@ #include "util.hpp" using std::string; +using std::vector; +using std::unordered_map; + +#define BG_LAYER_NAME "BackGroundLayer" namespace wm { -WMLayer::WMLayer(json_object* j) +LayerState::LayerState() + : render_order(), + area2appid() +{} + +const vector 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::attachAppToArea(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 wm_layer_id) : tmp_state(), state(), wm_layer_id(wm_layer_id) { this->name = jh::getStringFromJson(j, "name"); this->role_list = jh::getStringFromJson(j, "role"); - this->layer_id = static_cast(jh::getIntFromJson(j, "layer_id")); + this->id_begin = static_cast(jh::getIntFromJson(j, "id_range_begin")); + this->id_end = static_cast(jh::getIntFromJson(j, "id_range_end")); + + if (name.empty()) + { + HMI_ERROR("Parse Error!!"); + exit(1); + } + if(this->id_begin > this->id_end) + { + HMI_ERROR("INVALID"); + exit(1); + } +} + +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::attachAppToArea(const string& app, const string& area) +{ + this->tmp_state.attachAppToArea(app, area); +} + +void WMLayer::appendArea(const string& area) +{ + this->area_list.push_back(area); +} + +void WMLayer::appTerminated(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) @@ -45,4 +220,24 @@ bool WMLayer::hasRole(const string& role) 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 ====="); + +} + } // namespace wm diff --git a/src/wm_layer.hpp b/src/wm_layer.hpp index 1d9435b..83a5e74 100644 --- a/src/wm_layer.hpp +++ b/src/wm_layer.hpp @@ -28,24 +28,66 @@ struct json_object; namespace wm { +class WMClient; +class LayerState +{ + public: + LayerState(); + ~LayerState() = default; + const std::vector getIviIdList(); + void addLayer(unsigned layer); + void removeLayer(unsigned layer); + void attachAppToArea(const std::string& app, const std::string& area); + + // Debug + void dump(); + + private: + std::vector render_order; + std::unordered_map area2appid; +}; + class WMLayer { public: - explicit WMLayer(json_object* j); + explicit WMLayer(json_object* j, unsigned wm_layer_id); ~WMLayer() = default; - // A more or less descriptive name? - const std::string& layerName(){ return this->role_list;} - unsigned layerID(){ return this->layer_id;} - const std::string& roleList(); + + // Status & Setting API + unsigned getNewLayerID(const std::string& role); + unsigned idBegin() { return this->id_begin; } + unsigned idEnd() { return this->id_end; } + unsigned getWMLayerID() { return this->wm_layer_id; } + const std::string& layerName(); + 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); - private: - std::string name = ""; - // The actual layer ID - int layer_id = 0; - // Specify a role prefix for surfaces that should be - // put on this layer. + // Manipulation + void addLayerToState(unsigned layer); + void removeLayerFromState(unsigned layer); + void attachAppToArea(const std::string& app, const std::string& area); + void update(); + void undo(); + + // Event + void appTerminated(unsigned layer); + + // Debug + void dump(); + + private: + LayerState tmp_state; + LayerState state; + unsigned wm_layer_id; + std::string name = ""; // Layer name std::string role_list; + std::vector area_list; + std::vector id_list; + unsigned id_begin; + unsigned id_end; }; } // namespace wm diff --git a/src/wm_layer_control.cpp b/src/wm_layer_control.cpp index 951c840..c76a070 100644 --- a/src/wm_layer_control.cpp +++ b/src/wm_layer_control.cpp @@ -118,48 +118,41 @@ lc_init_error: return WMError::FAIL; } -unsigned LayerControl::getLayerID(const string& role) +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(); +} + +unsigned LayerControl::getNewLayerID(const string& role) { unsigned ret = 0; for(const auto& l: this->wm_layers) { - if(l->hasRole(role)) + ret = l->getNewLayerID(role); + if(ret != 0) { - ret = l->layerID(); + unsigned wmlid = l->getWMLayerID(); + this->lid2wmlid[ret] = wmlid; + break; } } return ret; } -void LayerControl::addSurface(unsigned surface, unsigned layer) -{ - ilm_layerAddSurface(layer, surface); - ilm_commitChanges(); -} - -void LayerControl::createLayers() -{ - for(const auto &layer : this->wm_layers) - { - unsigned id = layer->layerID(); - 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_TRUE); - ilm_commitChanges(); - /* auto wm_layer = getWMLayer(id); - wm_layer->addLayerToState(id); */ - } - this->renderLayers(); -} - shared_ptr LayerControl::getWMLayer(unsigned layer) { - unsigned uuid = this->lid2wmlid[layer]; - return this->wm_layers[uuid]; + unsigned wm_lid = this->lid2wmlid[layer]; + return this->wm_layers[wm_lid]; } std::shared_ptr LayerControl::getWMLayer(std::string layer_name) @@ -212,26 +205,48 @@ WMError LayerControl::renderLayers() HMI_INFO("Commit change"); WMError rc = WMError::SUCCESS; + // Check the number of layers + vector 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[this->wm_layers.size()]; + 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 : this->wm_layers) + for(const auto& i : ivi_l_ids) { - id_array[count] = i->layerID(); + id_array[count] = i; ++count; } // Display - ilmErrorTypes ret = ilm_displaySetRenderOrder(this->screenID, id_array, this->wm_layers.size()); + 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; @@ -251,6 +266,15 @@ WMError LayerControl::setXDGSurfaceOriginSize(unsigned surface) 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); @@ -278,7 +302,7 @@ WMError LayerControl::loadLayerSetting(const string &path) 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(json_tmp)); + this->wm_layers.emplace_back(std::make_shared(json_tmp, i)); } json_object_put(json_obj); @@ -365,13 +389,26 @@ WMError LayerControl::layoutChange(const WMAction& action) HMI_SEQ_ERROR(action.req_num, "client may vanish"); return WMError::NOT_REGISTERED; } - unsigned surface = action.client->surfaceID(action.role); + 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); 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->attachAppToArea(action.client->appID(), action.area); + /* TODO: manipulate state directly + LayerState ls = wm_layer->getLayerState(); + ls.seattachAppToAreatArea(action.client->appID(), action.area); + wm_layer->dump(); */ + } + } return WMError::SUCCESS; } @@ -387,16 +424,27 @@ WMError LayerControl::visibilityChange(const WMAction& action) if (action.visible == TaskVisible::VISIBLE) { - ret = this->makeVisible(action.client, action.role); + ret = this->makeVisible(action.client); } else if (action.visible == TaskVisible::INVISIBLE) { - ret = this->makeInvisible(action.client, action.role); + ret = this->makeInvisible(action.client); } ilm_commitChanges(); return ret; } +void LayerControl::appTerminated(const shared_ptr client) +{ + for(auto& l : this->wm_layers) + { + if(l->hasLayerID(client->layerID())) + { + l->appTerminated(client->layerID()); + } + } +} + void LayerControl::dispatchCreateEvent(ilmObjectType object, unsigned id, bool created) { if (ILM_SURFACE == object) @@ -413,6 +461,7 @@ void LayerControl::dispatchCreateEvent(ilmObjectType object, unsigned id, bool c } this->cb.surfaceCreated(sp.creatorPid, id); ilm_surfaceAddNotification(id, surfaceCallback_static); + ilm_surfaceSetVisibility(id, ILM_TRUE); ilm_surfaceSetType(id, ILM_SURFACETYPE_DESKTOP); } else @@ -489,105 +538,90 @@ void LayerControl::dispatchLayerPropChangeEvent(unsigned id, } } -WMError LayerControl::makeVisible(const shared_ptr client, const string& role) +WMError LayerControl::makeVisible(const shared_ptr client) { WMError ret = WMError::SUCCESS; - // Don't check here the client is not nullptr - unsigned surface = client->surfaceID(role); + // Don't check here wheher client is nullptr or not + unsigned layer = client->layerID(); - this->moveForeGround(client, role); + this->moveForeGround(client); - ilm_surfaceSetVisibility(surface, ILM_TRUE); + ilm_layerSetVisibility(layer, ILM_TRUE); return ret; } -WMError LayerControl::makeInvisible(const shared_ptr client, const string& role) +WMError LayerControl::makeInvisible(const shared_ptr client) { WMError ret = WMError::SUCCESS; - unsigned surface = client->surfaceID(role); // Don't check here the client is not nullptr + // Don't check here the client is not nullptr + unsigned layer = client->layerID(); - bool mv_ok = this->moveBackGround(client, role); + bool mv_ok = this->moveBackGround(client); if(!mv_ok) { HMI_INFO("make invisible client %s", client->appID().c_str()); - ilm_surfaceSetVisibility(surface, ILM_FALSE); + ilm_layerSetVisibility(layer, ILM_FALSE); } return ret; } -bool LayerControl::moveBackGround(const shared_ptr client, const string& role) +bool LayerControl::moveBackGround(const shared_ptr client) { bool ret = false; - const char* label = role.c_str(); - - if ((0 == strcmp(label, "radio")) || - (0 == strcmp(label, "music")) || - (0 == strcmp(label, "video")) || - (0 == strcmp(label, "map"))) - { - unsigned surface = client->surfaceID(role); - this->surface_bg.push_back(surface); - auto bg = this->getWMLayer(BACK_GROUND_LAYER); - auto layer = 0; - for(const auto& l : this->wm_layers) + + // 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())) { - if(l->hasRole(role)) - { - layer = l->layerID(); - ilm_layerRemoveSurface(layer, surface); - ilm_layerAddSurface(bg->layerID(), surface); - ret = true; - break; - } + 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; } } - ilm_commitChanges(); return ret; } -bool LayerControl::moveForeGround(const shared_ptr client, const string& role) +bool LayerControl::moveForeGround(const shared_ptr client) { bool ret = false; - const char* label = role.c_str(); // Move foreground from foreground layer - if ((0 == strcmp(label, "radio")) || - (0 == strcmp(label, "music")) || - (0 == strcmp(label, "video")) || - (0 == strcmp(label, "map"))) + auto bg = this->getWMLayer(BACK_GROUND_LAYER); + if(bg != nullptr) { - for (auto i = surface_bg.begin(); i != surface_bg.end(); ++i) + if(bg->hasRole(client->role())) { - if (client->surfaceID(role) == *i) - { - // Remove id - unsigned surface = *i; - - this->surface_bg.erase(i); - - // Remove from BG layer (999) - HMI_DEBUG("wm", "Remove %s(%d) from BG layer", label, surface); - auto bg = this->getWMLayer(BACK_GROUND_LAYER); - unsigned layer = 0; - for(const auto& l : this->wm_layers) - { - if(l->hasRole(role)) - { - layer = l->layerID(); - break; - } - } - ilm_layerRemoveSurface(bg->layerID(), surface); - ilm_layerAddSurface(layer, surface); - ret = true; - break; - } + 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; } } - ilm_commitChanges(); return ret; } diff --git a/src/wm_layer_control.hpp b/src/wm_layer_control.hpp index 5244bf5..25d71fd 100644 --- a/src/wm_layer_control.hpp +++ b/src/wm_layer_control.hpp @@ -63,8 +63,8 @@ class LayerControl explicit LayerControl(const std::string& root); ~LayerControl() = default; WMError init(const LayerControlCallbacks& cb); - void createLayers(); - unsigned getLayerID(const std::string& role); + void createNewLayer(unsigned id); + unsigned getNewLayerID(const std::string& role); std::shared_ptr getWMLayer(unsigned layer); std::shared_ptr getWMLayer(std::string layer_name); struct rect getAreaSize(const std::string& area); @@ -73,9 +73,10 @@ class LayerControl double scale(); WMError renderLayers(); WMError setXDGSurfaceOriginSize(unsigned surface); + void undoUpdate(); WMError layoutChange(const WMAction& action); WMError visibilityChange(const WMAction &action); - void addSurface(unsigned surface, unsigned layer); + void appTerminated(const std::shared_ptr client); // Don't use this function. void dispatchCreateEvent(ilmObjectType object, unsigned id, bool created); @@ -83,14 +84,13 @@ class LayerControl void dispatchLayerPropChangeEvent(unsigned id, struct ilmLayerProperties*, t_ilm_notification_mask); private: - WMError makeVisible(const std::shared_ptr client, const std::string& role); - WMError makeInvisible(const std::shared_ptr client, const std::string& role); - bool moveForeGround(const std::shared_ptr client, const std::string& role); - bool moveBackGround(const std::shared_ptr client, const std::string& role); + WMError makeVisible(const std::shared_ptr client); + WMError makeInvisible(const std::shared_ptr client); + bool moveForeGround(const std::shared_ptr client); + bool moveBackGround(const std::shared_ptr client); WMError loadLayerSetting(const std::string& path); WMError loadAreaDb(const std::string& path); - std::vector surface_bg; // For CES demo std::vector> wm_layers; std::unordered_map lid2wmlid; std::unordered_map area2size; -- cgit 1.2.3-korg