Attach application to ivi-layer not to surface 59/17459/2
authorKazumasa Mitsunari <knimitz@witz-inc.co.jp>
Mon, 22 Oct 2018 00:30:19 +0000 (09:30 +0900)
committerKazumasa Mitsunari <knimitz@witz-inc.co.jp>
Tue, 13 Nov 2018 04:05:39 +0000 (13:05 +0900)
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>
layers.json
src/applist.cpp
src/applist.hpp
src/window_manager.cpp
src/window_manager.hpp
src/wm_client.cpp
src/wm_client.hpp
src/wm_layer.cpp
src/wm_layer.hpp
src/wm_layer_control.cpp
src/wm_layer_control.hpp

index 44e2adb..539846a 100644 (file)
@@ -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"
+        }
+    ]
 }
index 79df62c..17b47e3 100644 (file)
@@ -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();
         }
index 54ccdd1..085504a 100644 (file)
@@ -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;
index c73952d..edd3c12 100644 (file)
@@ -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\": [ \
         { \
index 712edec..57b9fde 100644 (file)
@@ -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;
index 2e12a69..7a93c7c 100644 (file)
@@ -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");
index 259d504..7e92ed5 100644 (file)
@@ -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
index c702651..294e356 100644 (file)
 #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
index 1d9435b..83a5e74 100644 (file)
@@ -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
index 951c840..c76a070 100644 (file)
@@ -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;
 }
 
index 5244bf5..25d71fd 100644 (file)
@@ -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;