+int App::init_layers()
+{
+ if (!this->controller)
+ {
+ HMI_ERROR("wm", "ivi_controller global not available");
+ return -1;
+ }
+
+ if (this->outputs.empty())
+ {
+ HMI_ERROR("wm", "no output was set up!");
+ return -1;
+ }
+
+ auto &c = this->controller;
+
+ auto &o = this->outputs.front();
+ auto &s = c->screens.begin()->second;
+ auto &layers = c->layers;
+
+ // 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),
+ uint32_t(o->physical_height)};
+
+ // Clear scene
+ layers.clear();
+
+ // Clear screen
+ s->clear();
+
+ // Quick and dirty setup of layers
+ for (auto const &i : this->layers.mapping)
+ {
+ c->layer_create(i.second.layer_id, o->width, o->height);
+ auto &l = layers[i.second.layer_id];
+ l->set_destination_rectangle(0, 0, o->width, o->height);
+ 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());
+ }
+
+ // Add layers to screen
+ s->set_render_order(this->layers.layers);
+
+ this->layout_commit();
+
+ return 0;
+}
+
+void App::surface_set_layout(int surface_id, optional<int> sub_surface_id)
+{
+ if (!this->controller->surface_exists(surface_id))
+ {
+ HMI_ERROR("wm", "Surface %d does not exist", surface_id);
+ return;
+ }
+
+ auto o_layer_id = this->layers.get_layer_id(surface_id);
+
+ if (!o_layer_id)
+ {
+ HMI_ERROR("wm", "Surface %d is not associated with any layer!", surface_id);
+ return;
+ }
+
+ uint32_t layer_id = *o_layer_id;
+
+ auto const &layer = this->layers.get_layer(layer_id);
+ auto rect = layer.value().rect;
+ auto &s = this->controller->surfaces[surface_id];
+
+ int x = rect.x;
+ int y = rect.y;
+ int w = rect.w;
+ int h = rect.h;
+
+ // less-than-0 values refer to MAX + 1 - $VALUE
+ // e.g. MAX is either screen width or height
+ if (w < 0)
+ {
+ w = this->controller->output_size.w + 1 + w;
+ }
+ if (h < 0)
+ {
+ h = this->controller->output_size.h + 1 + h;
+ }
+
+ if (sub_surface_id)
+ {
+ if (o_layer_id != this->layers.get_layer_id(*sub_surface_id))
+ {
+ HMI_ERROR("wm",
+ "surface_set_layout: layers of surfaces (%d and %d) don't match!",
+ surface_id, *sub_surface_id);
+ return;
+ }
+
+ int x_off = 0;
+ int y_off = 0;
+
+ // split along major axis
+ if (w > h)
+ {
+ w /= 2;
+ x_off = w;
+ }
+ else
+ {
+ h /= 2;
+ y_off = h;
+ }
+
+ auto &ss = this->controller->surfaces[*sub_surface_id];
+
+ HMI_DEBUG("wm", "surface_set_layout for sub surface %u on layer %u",
+ *sub_surface_id, layer_id);
+
+ // set destination to the display rectangle
+ ss->set_destination_rectangle(x + x_off, y + y_off, w, h);
+
+ this->area_info[*sub_surface_id].x = x;
+ this->area_info[*sub_surface_id].y = y;
+ this->area_info[*sub_surface_id].w = w;
+ this->area_info[*sub_surface_id].h = h;
+ }
+
+ HMI_DEBUG("wm", "surface_set_layout for surface %u on layer %u", surface_id,
+ layer_id);
+
+ // set destination to the display rectangle
+ s->set_destination_rectangle(x, y, w, h);
+
+ // update area information
+ this->area_info[surface_id].x = x;
+ this->area_info[surface_id].y = y;
+ this->area_info[surface_id].w = w;
+ this->area_info[surface_id].h = h;
+
+ HMI_DEBUG("wm", "Surface %u now on layer %u with rect { %d, %d, %d, %d }",
+ surface_id, layer_id, x, y, w, h);
+}
+
+void App::layout_commit()
+{
+ this->controller->commit_changes();
+ this->display->flush();
+}
+
+void App::set_timer()
+{
+ HMI_SEQ_DEBUG(app_list.currentSequenceNumber(), "Timer set activate");
+ if (timer_ev_src == nullptr)
+ {
+ // firsttime set into sd_event
+ int ret = sd_event_add_time(afb_daemon_get_event_loop(), &timer_ev_src,
+ CLOCK_REALTIME, time(NULL) * (1000000UL) + TIME_OUT, 1, processTimerHandler, this);
+ if (ret < 0)
+ {
+ HMI_ERROR("wm", "Could't set timer");
+ }
+ }
+ else
+ {
+ // update timer limitation after second time
+ sd_event_source_set_time(timer_ev_src, time(NULL) * (1000000UL) + TIME_OUT);
+ sd_event_source_set_enabled(timer_ev_src, SD_EVENT_ONESHOT);
+ }
+}
+
+void App::stop_timer()
+{
+ unsigned seq = app_list.currentSequenceNumber();
+ HMI_SEQ_DEBUG(seq, "Timer stop");
+ int rc = sd_event_source_set_enabled(timer_ev_src, SD_EVENT_OFF);
+ if (rc < 0)
+ {
+ HMI_SEQ_ERROR(seq, "Timer stop failed");
+ }
+}
+
+bool App::lm_release(const struct WMAction &action)
+{
+ //auto const &surface_id = this->lookup_id(drawing_name);
+ unsigned req_num = app_list.currentSequenceNumber();
+ auto const &surface_id = this->lookup_id(action.role.c_str());
+ if (!surface_id)
+ {
+ HMI_SEQ_ERROR(req_num, "Surface does not exist");
+ return false;
+ }
+
+ if (*surface_id == this->layers.main_surface)
+ {
+ HMI_SEQ_ERROR(req_num, "Cannot deactivate main_surface");
+ return false;
+ }
+
+ auto o_state = *this->layers.get_layout_state(*surface_id);
+
+ if (o_state == nullptr)
+ {
+ HMI_SEQ_ERROR(req_num, "Could not find layer for surface");
+ return false;
+ }
+
+ struct LayoutState &state = *o_state;
+
+ if (state.main == -1)
+ {
+ HMI_SEQ_ERROR(req_num, "No surface active");
+ return false;
+ }
+
+ // Check against main_surface, main_surface_name is the configuration item.
+ if (*surface_id == this->layers.main_surface)
+ {
+ HMI_SEQ_DEBUG(req_num, "Refusing to deactivate main_surface %d", *surface_id);
+ //reply(nullptr);
+ return true;
+ }
+ if ((state.main == *surface_id) && (state.sub == *surface_id))
+ {
+ HMI_SEQ_ERROR(req_num, "Surface is not active");
+ return false;
+ }
+
+ if (state.main == *surface_id)
+ {
+ if (state.sub != -1)
+ {
+ this->try_layout(
+ state, LayoutState{state.sub, -1}, [&](LayoutState const &nl) {
+ std::string sub = std::move(*this->lookup_name(state.sub));
+
+ this->deactivate(*surface_id);
+ this->surface_set_layout(state.sub);
+ state = nl;
+
+ this->layout_commit();
+ std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
+ compositor::rect area_rect = this->area_info[state.sub];
+ this->emit_syncdraw(sub.c_str(), str_area.c_str(),
+ area_rect.x, area_rect.y, area_rect.w, area_rect.h);
+ this->enqueue_flushdraw(state.sub);
+ });
+ }
+ else
+ {
+ this->try_layout(state, LayoutState{-1, -1}, [&](LayoutState const &nl) {
+ this->deactivate(*surface_id);
+ state = nl;
+ this->layout_commit();
+ });
+ }
+ }
+ else if (state.sub == *surface_id)
+ {
+ this->try_layout(
+ state, LayoutState{state.main, -1}, [&](LayoutState const &nl) {
+ std::string main = std::move(*this->lookup_name(state.main));
+
+ this->deactivate(*surface_id);
+ this->surface_set_layout(state.main);
+ state = nl;
+
+ this->layout_commit();
+ std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
+ compositor::rect area_rect = this->area_info[state.main];
+ this->emit_syncdraw(main.c_str(), str_area.c_str(),
+ area_rect.x, area_rect.y, area_rect.w, area_rect.h);
+ this->enqueue_flushdraw(state.main);
+ });
+ }
+ return true;
+}
+
+bool App::lm_layout_change(const struct WMAction &action)
+{
+ const char *msg = this->check_surface_exist(action.role.c_str());
+
+ /*
+ lm_.updateLayout(action);
+ TODO: emit syncDraw with application*/
+ if (msg)
+ {
+ HMI_SEQ_DEBUG(app_list.currentSequenceNumber(), msg);
+ //app_list.removeRequest(req_num);
+ return false;
+ }
+ this->lm_layout_change(action.role.c_str());
+ return true;
+}
+
+bool App::do_transition(unsigned req_num)
+{
+ /*
+ * Check Policy
+ */
+ // get current trigger
+ auto trigger = app_list.getRequest(req_num);
+ bool is_activate = true;
+
+ /* get new status from Policy Manager
+
+ (json_object*?) newLayout = checkPolicy(trigger);
+ (vector<struct WMAction>&) auto actions = translator.inputActionFromLayout(newLayout, currentLayout)
+ for(const auto& x : actions){
+ app_list.setAciton(req_num, x)
+ }
+
+ or
+
+ translator.inputActionFromLayout(newLayout, currentLayout, &app_list, req_num);
+
+ /* The following error check is not necessary because main.cpp will reject the message form not registered object
+ } */
+ HMI_SEQ_NOTICE(req_num, "ATM, Policy manager does't exist, then set WMAction as is");
+
+ if (TASK_RELEASE == trigger.task)
+ {
+ is_activate = false;
+ }
+ bool ret = app_list.setAction(req_num, trigger.appid, trigger.role, trigger.area, is_activate);
+ app_list.req_dump();
+
+ if (!ret)
+ {
+ HMI_SEQ_ERROR(req_num, "Failed to set action");
+ return ret;
+ }
+
+ // layer manager task
+ bool sync_draw_happen = false;
+ for (const auto &y : app_list.getActions(req_num))
+ {
+ /*
+ do_task(y);
+ */
+ /* TODO
+ but current we can't do do_task,
+ so divide the processing into lm_layout_change and lm_release
+ */
+ if (y.visible)
+ {
+ sync_draw_happen = true;
+ ret = lm_layout_change(y);
+ if (!ret)
+ {
+ HMI_SEQ_ERROR(req_num, "Failed layout change: %s", y.appid.c_str());
+ app_list.removeRequest(req_num);
+ break;
+ // TODO: if transition fails, what should we do?
+ }
+ /* app_list.lookUpClient(y.appid)->emit_syncdraw(y.role, y.area); */
+ }
+ else
+ {
+ ret = lm_release(y);
+ if (!ret)
+ {
+ HMI_SEQ_ERROR(req_num, "Failed release resource: %s", y.appid.c_str());
+ app_list.removeRequest(req_num);
+ break;
+ // TODO: if transition fails, what should we do?
+ }
+ /* app_list.lookUpClient(y.appid)->emit_invisible(y.role, y.area); */
+ }
+ }
+
+ if (!ret)
+ {
+ //this->emit_error(request_seq, 0 /*error_num*/, "error happens"); // test
+ }
+ else if (ret && sync_draw_happen)
+ {
+ this->set_timer();
+ }
+ else
+ {
+ app_list.removeRequest(req_num); // HACK!!!
+ }
+ return ret;