+void WindowManager::onApplicationTerminated(const WMClientCtxt& ctxt)
+{
+ if(!g_app_list.contains(ctxt.name))
+ {
+ return;
+ }
+ struct LayoutState priv;
+ bool found = false;
+ auto client = g_app_list.lookUpClient(ctxt.name);
+ unsigned sid = client->surfaceID(ctxt.role);
+ if(sid == 0) {
+ auto pSid = this->id_alloc.lookup(ctxt.role.c_str());
+ if(pSid) {
+ sid = *pSid;
+ }
+ }
+ // reset state
+ if(sid != 0)
+ {
+ auto o_state = *this->layers.get_layout_state(sid);
+ if (o_state != nullptr)
+ {
+ priv = *o_state;
+ if (o_state->main == sid)
+ {
+ o_state->main = -1;
+ }
+ else if (o_state->sub == sid)
+ {
+ o_state->sub = -1;
+ }
+ }
+ this->id_alloc.remove_id(sid);
+ this->layers.remove_surface(sid);
+ HMI_INFO("wm", "delete surfaceID %d", sid);
+ }
+
+ // Recovery Phase
+ if(priv.main == sid)
+ {
+ HMI_DEBUG("wm", "go to launcher");
+ if(ctxt.role != "launcher")
+ {
+ // goto launcher
+ auto pSid = this->id_alloc.lookup("launcher");
+ std::string app = g_app_list.getAppID(*pSid, "launcher", &found);
+ if(found)
+ {
+ this->api_activate_surface(app.c_str(), "launcher", kNameAreaDefault,
+ [](const char*){});
+ }
+ }
+ }
+ else if(priv.main != sid && priv.sub != sid)
+ {
+ // re-show top surface
+ this->deactivate(priv.main);
+ this->activate(priv.main);
+ this->layout_commit();
+ }
+ else {}
+ g_app_list.removeClient(ctxt.name);
+}
+
+/*
+ ******* Private Functions *******
+ */
+
+bool WindowManager::pop_pending_events()
+{
+ bool x{true};
+ return this->pending_events.compare_exchange_strong(
+ x, false, std::memory_order_consume);
+}
+
+optional<int> WindowManager::lookup_id(char const *name)
+{
+ return this->id_alloc.lookup(std::string(name));
+}
+optional<std::string> WindowManager::lookup_name(int id)
+{
+ return this->id_alloc.lookup(id);
+}
+
+/**
+ * init_layers()
+ */
+int WindowManager::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)};
+
+
+ HMI_DEBUG("wm", "SCALING: screen (%dx%d), physical (%dx%d)",
+ o->width, o->height, o->physical_width, o->physical_height);
+
+ this->layers.loadAreaDb();
+
+ const compositor::rect css_bg = this->layers.getAreaSize("fullscreen");
+ rectangle dp_bg(o->width, o->height);
+
+ dp_bg.set_aspect(static_cast<double>(css_bg.w) / css_bg.h);
+ dp_bg.fit(o->width, o->height);
+ dp_bg.center(o->width, o->height);
+ HMI_DEBUG("wm", "SCALING: CSS BG(%dx%d) -> DDP %dx%d,(%dx%d)",
+ css_bg.w, css_bg.h, dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.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, dp_bg.width(), dp_bg.height());
+ auto &l = layers[i.second.layer_id];
+ l->set_destination_rectangle(dp_bg.left(), dp_bg.top(), dp_bg.width(), dp_bg.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();
+
+ c->scale = static_cast<double>(dp_bg.height()) / css_bg.h;
+ this->layers.setupArea(c->scale);
+
+ return 0;
+}
+
+void WindowManager::surface_set_layout(int surface_id, const std::string& area)
+{
+ 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 = this->layers.getAreaSize(area);
+ HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "%s : x:%d y:%d w:%d h:%d", area.c_str(),
+ rect.x, rect.y, rect.w, rect.h);
+ auto &s = this->controller->surfaces[surface_id];
+
+ int x = rect.x;
+ int y = rect.y;
+ int w = rect.w;
+ int h = rect.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 WindowManager::layout_commit()
+{
+ this->controller->commit_changes();
+ this->display->flush();
+}
+