aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKazumasa Mitsunari <knimitz@witz-inc.co.jp>2018-10-22 09:30:19 +0900
committerKazumasa Mitsunari <knimitz@witz-inc.co.jp>2018-11-13 13:05:39 +0900
commit010ca3f3459a52e44deb5e70e94e9cd394814e3e (patch)
tree96b8cc678180df86c95f362049dc40e7ce09833b
parentc2110a3ec8fa74f2fc37e4909db547aa4a36c851 (diff)
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 <knimitz@witz-inc.co.jp>
-rw-r--r--layers.json97
-rw-r--r--src/applist.cpp22
-rw-r--r--src/applist.hpp5
-rw-r--r--src/window_manager.cpp129
-rw-r--r--src/window_manager.hpp3
-rw-r--r--src/wm_client.cpp111
-rw-r--r--src/wm_client.hpp20
-rw-r--r--src/wm_layer.cpp199
-rw-r--r--src/wm_layer.hpp64
-rw-r--r--src/wm_layer_control.cpp236
-rw-r--r--src/wm_layer_control.hpp16
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<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
*
@@ -132,7 +140,14 @@ void AppList::removeSurface(unsigned surface){
*/
shared_ptr<WMClient> 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<WMClient> 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<double>(dp_bg.height()) / css_bg.h;
this->lc->setupArea(dp_bg, scale);
- this->lc->createLayers();
-
return 0;
}
@@ -167,34 +165,35 @@ result<int> 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<int>("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<int>("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<WMAction> &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<json_object *> api_get_display_info();
result<json_object *> 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<std::string, struct afb_event> map_afb_event;
std::unordered_map<std::string, struct rect> 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 <json-c/json.h>
#include "wm_client.hpp"
#include "util.hpp"
+#include <ilm/ilm_control.h>
#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 <vector>
#include <string>
#include <unordered_map>
+#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<std::string> role_list;
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;
+ std::unordered_map<std::string, struct afb_event> 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<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::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<unsigned>(jh::getIntFromJson(j, "layer_id"));
+ 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.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<unsigned> 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<unsigned> render_order;
+ std::unordered_map<std::string, std::string> 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<std::string> area_list;
+ std::vector<unsigned> 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<WMLayer> 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<WMLayer> 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<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[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<WMLayer>(json_tmp));
+ this->wm_layers.emplace_back(std::make_shared<WMLayer>(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<WMClient> 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<WMClient> client, const string& role)
+WMError LayerControl::makeVisible(const shared_ptr<WMClient> 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<WMClient> client, const string& role)
+WMError LayerControl::makeInvisible(const shared_ptr<WMClient> 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<WMClient> client, const string& role)
+bool LayerControl::moveBackGround(const shared_ptr<WMClient> 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<WMClient> client, const string& role)
+bool LayerControl::moveForeGround(const shared_ptr<WMClient> 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<WMLayer> getWMLayer(unsigned layer);
std::shared_ptr<WMLayer> 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<WMClient> 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<WMClient> client, const std::string& role);
- WMError makeInvisible(const std::shared_ptr<WMClient> client, const std::string& role);
- bool moveForeGround(const std::shared_ptr<WMClient> client, const std::string& role);
- bool moveBackGround(const std::shared_ptr<WMClient> client, const std::string& role);
+ 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 loadAreaDb(const std::string& path);
- std::vector<unsigned> surface_bg; // For CES demo
std::vector<std::shared_ptr<WMLayer>> wm_layers;
std::unordered_map<unsigned, unsigned> lid2wmlid;
std::unordered_map<std::string, struct rect> area2size;