Add new class
[apps/agl-service-windowmanager-2017.git] / src / window_manager.cpp
index de322df..62bbbcb 100644 (file)
@@ -19,6 +19,7 @@
 
 #include "window_manager.hpp"
 #include "json_helper.hpp"
+#include "wm_config.hpp"
 #include "applist.hpp"
 
 extern "C"
@@ -29,7 +30,7 @@ extern "C"
 namespace wm
 {
 
-static const unsigned kTimeOut = 3000000UL; /* 3s */
+static const uint64_t kTimeOut = 3ULL; /* 3s */
 
 /* DrawingArea name used by "{layout}.{area}" */
 const char kNameLayoutNormal[] = "normal";
@@ -146,6 +147,7 @@ WindowManager::WindowManager(wl::display *d)
 
 int WindowManager::init()
 {
+    int ret;
     if (!this->display->ok())
     {
         return -1;
@@ -183,12 +185,12 @@ int WindowManager::init()
 
             // This protocol needs the output, so lets just add our mapping here...
             this->controller->add_proxy_to_id_mapping(
-                this->outputs.back()->proxy.get(),
+                this->outputs.front()->proxy.get(),
                 wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
-                    this->outputs.back()->proxy.get())));
+                    this->outputs.front()->proxy.get())));
 
             // Create screen
-            this->controller->create_screen(this->outputs.back()->proxy.get());
+            this->controller->create_screen(this->outputs.front()->proxy.get());
 
             // Set display to controller
             this->controller->display = this->display;
@@ -201,7 +203,8 @@ int WindowManager::init()
     // Third level objects
     this->display->roundtrip();
 
-    return init_layers();
+    ret = init_layers();
+    return ret;
 }
 
 int WindowManager::dispatch_pending_events()
@@ -235,7 +238,7 @@ result<int> WindowManager::api_request_surface(char const *appid, char const *dr
         HMI_DEBUG("wm", "%s is not registered in layers.json, then fallback as normal app", role);
         if (!lid)
         {
-            return Err<int>("Drawing name does not match any role, Fallback is disabled");
+            return Err<int>("Drawing name does not match any role, fallback is disabled");
         }
     }
 
@@ -289,7 +292,7 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr
         HMI_DEBUG("wm", "%s is not registered in layers.json, then fallback as normal app", role);
         if (!lid)
         {
-            return "Drawing name does not match any role, Fallback is disabled";
+            return "Drawing name does not match any role, fallback is disabled";
         }
     }
 
@@ -320,6 +323,97 @@ char const *WindowManager::api_request_surface(char const *appid, char const *dr
     return nullptr;
 }
 
+/**
+ * This function is substitute of requestSurface
+ * If surface creation is faster than application request of this function,
+ * WM will bind surfaceID with application and role.
+ * If surface creation is slower than application request of thie function,
+ * WM will put Client into pending list.
+ *
+ * Note :
+ * Application can request with pid but this is temporary solution for now.
+ * This will be removed.
+ * */
+bool WindowManager::api_set_role(char const *appid, char const *drawing_name, unsigned pid){
+    std::string id = appid;
+    std::string role = drawing_name;
+    unsigned surface = 0;
+    WMError wm_err = WMError::UNKNOWN;
+    bool ret = false;
+
+    // get layer ID which role should be in
+    auto lid = this->layers.get_layer_id(role);
+    if (!lid)
+    {
+        /**
+       * register drawing_name as fallback and make it displayed.
+       */
+        lid = this->layers.get_layer_id(std::string("fallback"));
+        HMI_DEBUG("wm", "%s is not registered in layers.json, then fallback as normal app", role.c_str());
+        if (!lid)
+        {
+            HMI_ERROR("wm", "Drawing name does not match any role, fallback is disabled");
+            return ret;
+        }
+    }
+
+    if(0 != pid){
+        // search floating surfaceID from pid if pid is designated.
+        // It is not good that application request with its pid
+        wm_err = g_app_list.popFloatingSurface(pid, &surface);
+    }
+    else{
+        // get floating surface with appid. If WM queries appid from pid,
+        // WM can bind surface and role with appid(not implemented yet)
+        //wm_err = g_app_list.popFloatingSurface(id);
+    }
+    if(wm_err != WMError::SUCCESS){
+        HMI_ERROR("wm", "No floating surface for app: %s", id.c_str());
+        g_app_list.addFloatingClient(id, *lid, role);
+        HMI_NOTICE("wm", "%s : Waiting for surface creation", id.c_str());
+        return ret;
+    }
+
+    ret = true;
+    if (g_app_list.contains(id))
+    {
+        HMI_INFO("wm", "Add role: %s with surface: %d. Client %s has multi surfaces.",
+                 role.c_str(), surface, id.c_str());
+        wm_err = g_app_list.appendRole(id, role, surface);
+        if(wm_err != WMError::SUCCESS){
+            HMI_INFO("wm", errorDescription(wm_err));
+        }
+    }
+    else{
+        HMI_INFO("wm", "Create new client: %s, surface: %d into layer: %d with role: %s",
+                 id.c_str(), surface, *lid, role.c_str());
+        g_app_list.addClient(id, *lid, surface, role);
+    }
+
+    // register pair drawing_name and ivi_id
+    this->id_alloc.register_name_id(role.c_str(), surface);
+    this->layers.add_surface(surface, *lid);
+
+    // this surface is already created
+    HMI_DEBUG("wm", "surface_id is %u, layer_id is %u", surface, *lid);
+
+    const auto &o_layer = this->layers.get_layer(*lid);
+    auto rect = o_layer.value().rect;
+    if(rect.w < 0)
+    {
+        rect.w = this->controller->output_size.w + 1 + rect.w;
+    }
+    if(rect.h < 0)
+    {
+        rect.h = this->controller->output_size.h + 1 + rect.h;
+    }
+
+    this->controller->layers[*lid]->add_surface(surface);
+    this->layout_commit();
+
+    return ret;
+}
+
 void WindowManager::api_activate_surface(char const *appid, char const *drawing_name,
                                char const *drawing_area, const reply_func &reply)
 {
@@ -332,6 +426,23 @@ void WindowManager::api_activate_surface(char const *appid, char const *drawing_
     std::string id = appid;
     std::string role = c_role;
     std::string area = drawing_area;
+
+    if(!g_app_list.contains(id))
+    {
+        reply("app doesn't request 'requestSurface' or 'setRole' yet");
+        return;
+    }
+    auto client = g_app_list.lookUpClient(id);
+
+    unsigned srfc = client->surfaceID();
+    if(srfc == 0)
+    {
+        HMI_ERROR("wm", "role sould be set with surface");
+        reply("role sould be set with surface");
+        return;
+    }
+    g_app_list.removeFloatingSurface(client->surfaceID());
+
     Task task = Task::TASK_ALLOCATE;
     unsigned req_num = 0;
     WMError ret = WMError::UNKNOWN;
@@ -573,6 +684,8 @@ void WindowManager::send_event(char const *evname, char const *label, char const
  */
 void WindowManager::surface_created(uint32_t surface_id)
 {
+    this->controller->get_surface_properties(surface_id, IVI_WM_PARAM_SIZE);
+
     auto layer_id = this->layers.get_layer_id(surface_id);
     if (!layer_id)
     {
@@ -593,6 +706,45 @@ void WindowManager::surface_removed(uint32_t surface_id)
     g_app_list.removeSurface(surface_id);
 }
 
+void WindowManager::surface_properties(unsigned surface_id, unsigned pid)
+{
+    HMI_DEBUG("wm", "get surface properties");
+
+    // search pid from surfaceID
+    json_object *response;
+    afb_service_call_sync("afm-main", "runners", nullptr, &response);
+
+    // retrieve appid from pid from application manager
+    std::string appid = "";
+    if(response == nullptr)
+    {
+        HMI_ERROR("wm", "No runners");
+    }
+    else
+    {
+        // check appid then add it to the client
+        HMI_INFO("wm", "Runners:%s", json_object_get_string(response));
+        int size = json_object_array_length(response);
+        for(int i = 0; i < size; i++)
+        {
+            json_object *j = json_object_array_get_idx(response, i);
+            const char* id = jh::getStringFromJson(j, "id");
+            int runid      = jh::getIntFromJson(j, "runid");
+            if(id && (runid > 0))
+            {
+                if(runid == pid)
+                {
+                    appid = id;
+                    break;
+                }
+            }
+        }
+    }
+    json_object_put(response);
+
+    g_app_list.addFloatingSurface(appid, surface_id, pid);
+}
+
 void WindowManager::removeClient(const std::string &appid)
 {
     HMI_DEBUG("wm", "Remove clinet %s from list", appid.c_str());
@@ -654,12 +806,22 @@ int WindowManager::init_layers()
         return -1;
     }
 
+    WMConfig wm_config;
+    wm_config.loadConfigs();
+
     auto &c = this->controller;
 
     auto &o = this->outputs.front();
     auto &s = c->screens.begin()->second;
     auto &layers = c->layers;
 
+    this->layers.loadAreaDb();
+    const compositor::rect base = this->layers.getAreaSize("fullscreen");
+
+    const std::string aspect_setting = wm_config.getConfigAspect();
+    const compositor::rect scale_rect =
+        this->layers.getScaleDestRect(o->width, o->height, aspect_setting);
+
     // Write output dimensions to ivi controller...
     c->output_size = compositor::size{uint32_t(o->width), uint32_t(o->height)};
     c->physical_size = compositor::size{uint32_t(o->physical_width),
@@ -674,9 +836,11 @@ int WindowManager::init_layers()
     // Quick and dirty setup of layers
     for (auto const &i : this->layers.mapping)
     {
-        c->layer_create(i.second.layer_id, o->width, o->height);
+        c->layer_create(i.second.layer_id, scale_rect.w, scale_rect.h);
         auto &l = layers[i.second.layer_id];
-        l->set_destination_rectangle(0, 0, o->width, o->height);
+        l->set_source_rectangle(0, 0, base.w, base.h);
+        l->set_destination_rectangle(
+            scale_rect.x, scale_rect.y, scale_rect.w, scale_rect.h);
         l->set_visibility(1);
         HMI_DEBUG("wm", "Setting up layer %s (%d) for surface role match \"%s\"",
                   i.second.name.c_str(), i.second.layer_id, i.second.role.c_str());
@@ -687,9 +851,6 @@ int WindowManager::init_layers()
 
     this->layout_commit();
 
-    this->layers.loadAreaDb();
-    this->layers.setupArea(o->width, o->height);
-
     return 0;
 }
 
@@ -1076,7 +1237,7 @@ WMError WindowManager::startTransition(unsigned req_num)
             if (g_app_list.contains(x.appid))
             {
                 auto client = g_app_list.lookUpClient(x.appid);
-                this->deactivate(client->surfaceID(x.role));
+                this->deactivate(client->surfaceID());
             }
         }
         ret = NO_LAYOUT_CHANGE;
@@ -1088,6 +1249,15 @@ WMError WindowManager::setInvisibleTask(const std::string &role, bool split)
 {
     unsigned req_num = g_app_list.currentRequestNumber();
     HMI_SEQ_DEBUG(req_num, "set current visible app to invisible task");
+    bool found = false;
+    auto trigger = g_app_list.getRequest(req_num, &found);
+    // I don't check found == true here because this is checked in caller.
+    if(trigger.role == "homescreen")
+    {
+        HMI_SEQ_INFO(req_num, "In case of 'homescreen' visible, don't change app to invisible");
+        return WMError::SUCCESS;
+    }
+
     // This task is copied from original actiavete surface
     const char *drawing_name = this->rolenew2old[role].c_str();
     auto const &surface_id = this->lookup_id(role.c_str());
@@ -1099,7 +1269,6 @@ WMError WindowManager::setInvisibleTask(const std::string &role, bool split)
     int surface;
     TaskVisible task_visible = TaskVisible::INVISIBLE;
     bool end_draw_finished = true;
-    bool found = false;
 
     for (auto const &l : this->layers.mapping)
     {
@@ -1266,6 +1435,7 @@ WMError WindowManager::doEndDraw(unsigned req_num)
         HMI_SEQ_DEBUG(req_num, "visible %s", act.role.c_str());
         //this->lm_enddraw(act.role.c_str());
     }
+    this->layout_commit();
 
     // Change current state
     this->changeCurrentState(req_num);
@@ -1295,7 +1465,7 @@ WMError WindowManager::layoutChange(const WMAction &action)
         return WMError::SUCCESS;
     }
     auto client = g_app_list.lookUpClient(action.appid);
-    unsigned surface = client->surfaceID(action.role);
+    unsigned surface = client->surfaceID();
     if (surface == 0)
     {
         HMI_SEQ_ERROR(g_app_list.currentRequestNumber(),
@@ -1314,7 +1484,7 @@ WMError WindowManager::visibilityChange(const WMAction &action)
         return WMError::NOT_REGISTERED;
     }
     auto client = g_app_list.lookUpClient(action.appid);
-    unsigned surface = client->surfaceID(action.role);
+    unsigned surface = client->surfaceID();
     if(surface == 0)
     {
         HMI_SEQ_ERROR(g_app_list.currentRequestNumber(),
@@ -1361,7 +1531,7 @@ WMError WindowManager::changeCurrentState(unsigned req_num)
             return WMError::NOT_REGISTERED;
         }
         auto client = g_app_list.lookUpClient(action.appid);
-        auto pCurState = *this->layers.get_layout_state((int)client->surfaceID(action.role));
+        auto pCurState = *this->layers.get_layout_state((int)client->surfaceID());
         if(pCurState == nullptr)
         {
             HMI_SEQ_ERROR(req_num, "Counldn't find current status");
@@ -1375,7 +1545,7 @@ WMError WindowManager::changeCurrentState(unsigned req_num)
     for (const auto &action : actions)
     {
         auto client = g_app_list.lookUpClient(action.appid);
-        auto pLayerCurState = *this->layers.get_layout_state((int)client->surfaceID(action.role));
+        auto pLayerCurState = *this->layers.get_layout_state((int)client->surfaceID());
         if (pLayerCurState == nullptr)
         {
             HMI_SEQ_ERROR(req_num, "Counldn't find current status");
@@ -1385,7 +1555,7 @@ WMError WindowManager::changeCurrentState(unsigned req_num)
 
         if (action.visible != TaskVisible::INVISIBLE)
         {
-            surface = (int)client->surfaceID(action.role);
+            surface = (int)client->surfaceID();
             HMI_SEQ_INFO(req_num, "Change %s surface : %d, state visible area : %s",
                             action.role.c_str(), surface, action.area.c_str());
             // visible == true -> layout changes
@@ -1435,17 +1605,22 @@ void WindowManager::emitScreenUpdated(unsigned req_num)
     {
         HMI_DEBUG("wm", "afb_event_push failed: %m");
     }
-    json_object_put(jarray);
 }
 
 void WindowManager::setTimer()
 {
+    struct timespec ts;
+    if (clock_gettime(CLOCK_BOOTTIME, &ts) != 0) {
+        HMI_ERROR("wm", "Could't set time (clock_gettime() returns with error");
+        return;
+    }
+
     HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "Timer set activate");
     if (g_timer_ev_src == nullptr)
     {
         // firsttime set into sd_event
         int ret = sd_event_add_time(afb_daemon_get_event_loop(), &g_timer_ev_src,
-            CLOCK_REALTIME, time(NULL) * (1000000UL) + kTimeOut, 1, processTimerHandler, this);
+            CLOCK_BOOTTIME, (uint64_t)(ts.tv_sec + kTimeOut) * 1000000ULL, 1, processTimerHandler, this);
         if (ret < 0)
         {
             HMI_ERROR("wm", "Could't set timer");
@@ -1454,7 +1629,7 @@ void WindowManager::setTimer()
     else
     {
         // update timer limitation after second time
-        sd_event_source_set_time(g_timer_ev_src, time(NULL) * (1000000UL) + kTimeOut);
+        sd_event_source_set_time(g_timer_ev_src, (uint64_t)(ts.tv_sec + kTimeOut) * 1000000ULL);
         sd_event_source_set_enabled(g_timer_ev_src, SD_EVENT_ONESHOT);
     }
 }
@@ -1740,12 +1915,12 @@ const char* WindowManager::kDefaultOldRoleDb = "{ \
  */
 void controller_hooks::surface_created(uint32_t surface_id)
 {
-    this->app->surface_created(surface_id);
+    this->wmgr->surface_created(surface_id);
 }
 
 void controller_hooks::surface_removed(uint32_t surface_id)
 {
-    this->app->surface_removed(surface_id);
+    this->wmgr->surface_removed(surface_id);
 }
 
 void controller_hooks::surface_visibility(uint32_t /*surface_id*/,
@@ -1757,4 +1932,9 @@ void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/,
                                                      uint32_t /*w*/,
                                                      uint32_t /*h*/) {}
 
+void controller_hooks::surface_properties(uint32_t surface_id, uint32_t pid)
+{
+    this->wmgr->surface_properties(surface_id, pid);
+}
+
 } // namespace wm