de7686f9fb2f2955af89fb2a4dfe774cf3d8ed3a
[apps/agl-service-windowmanager.git] / src / app.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <fstream>
18 #include <regex>
19
20 #include "app.hpp"
21 #include "../include/json.hpp"
22 #include "applist.hpp"
23
24 extern "C"
25 {
26 #include <systemd/sd-event.h>
27 }
28
29 namespace wm
30 {
31
32 static const unsigned kTimeOut = 3000000UL; /* 3s */
33
34 /* DrawingArea name used by "{layout}.{area}" */
35 const char kNameLayoutNormal[] = "normal";
36 const char kNameLayoutSplit[] = "split";
37 const char kNameAreaFull[] = "full";
38 const char kNameAreaMain[] = "main";
39 const char kNameAreaSub[] = "sub";
40
41 /* Key for json obejct */
42 const char kKeyDrawingName[] = "drawing_name";
43 const char kKeyDrawingArea[] = "drawing_area";
44 const char kKeyDrawingRect[] = "drawing_rect";
45 const char kKeyX[] = "x";
46 const char kKeyY[] = "y";
47 const char kKeyWidth[] = "width";
48 const char kKeyHeight[] = "height";
49 const char kKeyWidthPixel[] = "width_pixel";
50 const char kKeyHeightPixel[] = "height_pixel";
51 const char kKeyWidthMm[] = "width_mm";
52 const char kKeyHeightMm[] = "height_mm";
53
54 static sd_event_source *g_timer_ev_src = nullptr;
55
56 static AppList g_app_list;
57
58 namespace
59 {
60
61 using nlohmann::json;
62
63 result<json> file_to_json(char const *filename)
64 {
65     json j;
66     std::ifstream i(filename);
67     if (i.fail())
68     {
69         HMI_DEBUG("wm", "Could not open config file, so use default layer information");
70         j = default_layers_json;
71     }
72     else
73     {
74         i >> j;
75     }
76
77     return Ok(j);
78 }
79
80 struct result<layer_map> load_layer_map(char const *filename)
81 {
82     HMI_DEBUG("wm", "loading IDs from %s", filename);
83
84     auto j = file_to_json(filename);
85     if (j.is_err())
86     {
87         return Err<layer_map>(j.unwrap_err());
88     }
89     json jids = j.unwrap();
90
91     return to_layer_map(jids);
92 }
93
94 static int
95 processTimerHandler(sd_event_source *s, uint64_t usec, void *userdata)
96 {
97     HMI_NOTICE("wm", "Time out occurs because the client replys endDraw slow, so revert the request");
98     reinterpret_cast<wm::App *>(userdata)->timerHandler();
99     return 0;
100 }
101
102 } // namespace
103
104 void App::timerHandler()
105 {
106     unsigned req_num = g_app_list.currentRequestNumber();
107     HMI_SEQ_DEBUG(req_num, "Timer expired remove Request");
108     g_app_list.reqDump();
109     g_app_list.removeRequest(req_num);
110     this->processNextRequest();
111 }
112
113 void App::removeClient(const std::string &appid)
114 {
115     HMI_DEBUG("wm", "Remove clinet %s from list", appid.c_str());
116     g_app_list.removeClient(appid);
117 }
118
119 void App::exeptionProcessForTransition()
120 {
121     unsigned req_num = g_app_list.currentRequestNumber();
122     HMI_SEQ_NOTICE(req_num, "Process exeption handling for request. Remove current request %d", req_num);
123     g_app_list.removeRequest(req_num);
124     HMI_SEQ_NOTICE(g_app_list.currentRequestNumber(), "Process next request if exists");
125     this->processNextRequest();
126 }
127
128 bool App::subscribeEventForApp(const std::string &appid, afb_req req, const std::string &evname)
129 {
130     if(!g_app_list.contains(appid)){
131         HMI_DEBUG("wm", "Client %s is not registered", appid.c_str());
132         return false;
133     }
134     auto client = g_app_list.lookUpClient(appid);
135     return client->subscribe(req, evname);
136 }
137
138 /**
139  * App Impl
140  */
141 App::App(wl::display *d)
142     : chooks{this},
143       display{d},
144       controller{},
145       outputs(),
146       layers(),
147       id_alloc{},
148       pending_events(false)
149 {
150     char const *path_layers_json = getenv("AFM_APP_INSTALL_DIR");
151     std::string path;
152     if (!path_layers_json)
153     {
154         HMI_ERROR("wm", "AFM_APP_INSTALL_DIR is not defined");
155         path = std::string(path_layers_json);
156     }
157     else
158     {
159         path = std::string(path_layers_json) + std::string("/etc/layers.json");
160     }
161
162     try
163     {
164         {
165             auto l = load_layer_map(path.c_str());
166             if (l.is_ok())
167             {
168                 this->layers = l.unwrap();
169             }
170             else
171             {
172                 HMI_ERROR("wm", "%s", l.err().value());
173             }
174         }
175     }
176     catch (std::exception &e)
177     {
178         HMI_ERROR("wm", "Loading of configuration failed: %s", e.what());
179     }
180 }
181
182 int App::init()
183 {
184     if (!this->display->ok())
185     {
186         return -1;
187     }
188
189     if (this->layers.mapping.empty())
190     {
191         HMI_ERROR("wm", "No surface -> layer mapping loaded");
192         return -1;
193     }
194
195     // Make afb event
196     for (int i = Event_Val_Min; i <= Event_Val_Max; i++)
197     {
198         map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i]);
199     }
200
201     this->display->add_global_handler(
202         "wl_output", [this](wl_registry *r, uint32_t name, uint32_t v) {
203             this->outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
204         });
205
206     this->display->add_global_handler(
207         "ivi_wm", [this](wl_registry *r, uint32_t name, uint32_t v) {
208             this->controller =
209                 std::make_unique<struct compositor::controller>(r, name, v);
210
211             // Init controller hooks
212             this->controller->chooks = &this->chooks;
213
214             // This protocol needs the output, so lets just add our mapping here...
215             this->controller->add_proxy_to_id_mapping(
216                 this->outputs.back()->proxy.get(),
217                 wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
218                     this->outputs.back()->proxy.get())));
219
220             // Create screen
221             this->controller->create_screen(this->outputs.back()->proxy.get());
222
223             // Set display to controller
224             this->controller->display = this->display;
225         });
226
227     // First level objects
228     this->display->roundtrip();
229     // Second level objects
230     this->display->roundtrip();
231     // Third level objects
232     this->display->roundtrip();
233
234     return init_layers();
235 }
236
237 int App::dispatch_pending_events()
238 {
239     if (this->pop_pending_events())
240     {
241         this->display->dispatch_pending();
242         return 0;
243     }
244     return -1;
245 }
246
247 bool App::pop_pending_events()
248 {
249     bool x{true};
250     return this->pending_events.compare_exchange_strong(
251         x, false, std::memory_order_consume);
252 }
253
254 void App::set_pending_events()
255 {
256     this->pending_events.store(true, std::memory_order_release);
257 }
258
259 optional<int> App::lookup_id(char const *name)
260 {
261     return this->id_alloc.lookup(std::string(name));
262 }
263 optional<std::string> App::lookup_name(int id)
264 {
265     return this->id_alloc.lookup(id);
266 }
267
268 /**
269  * init_layers()
270  */
271 int App::init_layers()
272 {
273     if (!this->controller)
274     {
275         HMI_ERROR("wm", "ivi_controller global not available");
276         return -1;
277     }
278
279     if (this->outputs.empty())
280     {
281         HMI_ERROR("wm", "no output was set up!");
282         return -1;
283     }
284
285     auto &c = this->controller;
286
287     auto &o = this->outputs.front();
288     auto &s = c->screens.begin()->second;
289     auto &layers = c->layers;
290
291     // Write output dimensions to ivi controller...
292     c->output_size = compositor::size{uint32_t(o->width), uint32_t(o->height)};
293     c->physical_size = compositor::size{uint32_t(o->physical_width),
294                                         uint32_t(o->physical_height)};
295
296     // Clear scene
297     layers.clear();
298
299     // Clear screen
300     s->clear();
301
302     // Quick and dirty setup of layers
303     for (auto const &i : this->layers.mapping)
304     {
305         c->layer_create(i.second.layer_id, o->width, o->height);
306         auto &l = layers[i.second.layer_id];
307         l->set_destination_rectangle(0, 0, o->width, o->height);
308         l->set_visibility(1);
309         HMI_DEBUG("wm", "Setting up layer %s (%d) for surface role match \"%s\"",
310                   i.second.name.c_str(), i.second.layer_id, i.second.role.c_str());
311     }
312
313     // Add layers to screen
314     s->set_render_order(this->layers.layers);
315
316     this->layout_commit();
317
318     this->layers.setupArea(o->width, o->height);
319
320     return 0;
321 }
322
323 void App::surface_set_layout(int surface_id, const std::string& area)
324 {
325     if (!this->controller->surface_exists(surface_id))
326     {
327         HMI_ERROR("wm", "Surface %d does not exist", surface_id);
328         return;
329     }
330
331     auto o_layer_id = this->layers.get_layer_id(surface_id);
332
333     if (!o_layer_id)
334     {
335         HMI_ERROR("wm", "Surface %d is not associated with any layer!", surface_id);
336         return;
337     }
338
339     uint32_t layer_id = *o_layer_id;
340
341     auto const &layer = this->layers.get_layer(layer_id);
342     auto rect = this->layers.getAreaSize(area);
343     HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "%s : x:%d y:%d w:%d h:%d", area.c_str(),
344                     rect.x, rect.y, rect.w, rect.h);
345     auto &s = this->controller->surfaces[surface_id];
346
347     int x = rect.x;
348     int y = rect.y;
349     int w = rect.w;
350     int h = rect.h;
351
352     // less-than-0 values refer to MAX + 1 - $VALUE
353     // e.g. MAX is either screen width or height
354     if (w < 0)
355     {
356         w = this->controller->output_size.w + 1 + w;
357     }
358     if (h < 0)
359     {
360         h = this->controller->output_size.h + 1 + h;
361     }
362
363     HMI_DEBUG("wm", "surface_set_layout for surface %u on layer %u", surface_id,
364               layer_id);
365
366     // set destination to the display rectangle
367     s->set_destination_rectangle(x, y, w, h);
368
369     // update area information
370     this->area_info[surface_id].x = x;
371     this->area_info[surface_id].y = y;
372     this->area_info[surface_id].w = w;
373     this->area_info[surface_id].h = h;
374
375     HMI_DEBUG("wm", "Surface %u now on layer %u with rect { %d, %d, %d, %d }",
376               surface_id, layer_id, x, y, w, h);
377 }
378
379 void App::layout_commit()
380 {
381     this->controller->commit_changes();
382     this->display->flush();
383 }
384
385 void App::setTimer()
386 {
387     HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "Timer set activate");
388     if (g_timer_ev_src == nullptr)
389     {
390         // firsttime set into sd_event
391         int ret = sd_event_add_time(afb_daemon_get_event_loop(), &g_timer_ev_src,
392             CLOCK_REALTIME, time(NULL) * (1000000UL) + kTimeOut, 1, processTimerHandler, this);
393         if (ret < 0)
394         {
395             HMI_ERROR("wm", "Could't set timer");
396         }
397     }
398     else
399     {
400         // update timer limitation after second time
401         sd_event_source_set_time(g_timer_ev_src, time(NULL) * (1000000UL) + kTimeOut);
402         sd_event_source_set_enabled(g_timer_ev_src, SD_EVENT_ONESHOT);
403     }
404 }
405
406 void App::stopTimer()
407 {
408     unsigned req_num = g_app_list.currentRequestNumber();
409     HMI_SEQ_DEBUG(req_num, "Timer stop");
410     int rc = sd_event_source_set_enabled(g_timer_ev_src, SD_EVENT_OFF);
411     if (rc < 0)
412     {
413         HMI_SEQ_ERROR(req_num, "Timer stop failed");
414     }
415 }
416
417 WMError App::doTransition(unsigned req_num)
418 {
419     HMI_SEQ_DEBUG(req_num, "check policy");
420     WMError ret = this->checkPolicy(req_num);
421     if (ret != WMError::SUCCESS)
422     {
423         return ret;
424     }
425     HMI_SEQ_DEBUG(req_num, "Start transition.");
426     ret = this->startTransition(req_num);
427     return ret;
428 }
429
430 WMError App::checkPolicy(unsigned req_num)
431 {
432     /*
433     * Check Policy
434     */
435     // get current trigger
436     bool found = false;
437     bool split = false;
438     WMError ret = WMError::LAYOUT_CHANGE_FAIL;
439     auto trigger = g_app_list.getRequest(req_num, &found);
440     if (!found)
441     {
442         ret = WMError::NO_ENTRY;
443         return ret;
444     }
445     std::string req_area = trigger.area;
446
447     // >>>> Compatible with current window manager until policy manager coming
448     if (trigger.task == Task::TASK_ALLOCATE)
449     {
450         HMI_SEQ_DEBUG(req_num, "Check split or not");
451         const char *msg = this->check_surface_exist(trigger.role.c_str());
452
453         if (msg)
454         {
455             HMI_SEQ_ERROR(req_num, msg);
456             ret = WMError::LAYOUT_CHANGE_FAIL;
457             return ret;
458         }
459
460         auto const &surface_id = this->lookup_id(trigger.role.c_str());
461         auto o_state = *this->layers.get_layout_state(*surface_id);
462         struct LayoutState &state = *o_state;
463
464         unsigned curernt_sid = state.main;
465         split = this->can_split(state, *surface_id);
466
467         if (split)
468         {
469             HMI_SEQ_DEBUG(req_num, "Split happens");
470             // Get current visible role
471             std::string add_role = this->lookup_name(state.main).value();
472             // Set next area
473             std::string add_area = std::string(kNameLayoutSplit) + "." + std::string(kNameAreaMain);
474             // Change request area
475             req_area = std::string(kNameLayoutSplit) + "." + std::string(kNameAreaSub);
476             HMI_SEQ_NOTICE(req_num, "Change request area from %s to %s, because split happens",
477                                 trigger.area.c_str(), req_area.c_str());
478             // set another action
479             std::string add_name = g_app_list.getAppID(curernt_sid, add_role, &found);
480             if (!found)
481             {
482                 HMI_SEQ_ERROR(req_num, "Couldn't widhdraw with surfaceID : %d", curernt_sid);
483                 ret = WMError::NOT_REGISTERED;
484                 return ret;
485             }
486             HMI_SEQ_INFO(req_num, "Additional split app %s, role: %s, area: %s",
487                          add_name.c_str(), add_role.c_str(), add_area.c_str());
488             // Set split action
489             bool end_draw_finished = false;
490             WMAction split_action{
491                 add_name,
492                 add_role,
493                 add_area,
494                 TaskVisible::VISIBLE,
495                 end_draw_finished};
496             WMError ret = g_app_list.setAction(req_num, split_action);
497             if (ret != WMError::SUCCESS)
498             {
499                 HMI_SEQ_ERROR(req_num, "Failed to set action");
500                 return ret;
501             }
502             g_app_list.reqDump();
503         }
504     }
505     else
506     {
507         HMI_SEQ_DEBUG(req_num, "split doesn't happen");
508     }
509
510     // Set invisible task(Remove if policy manager finish)
511     ret = this->setInvisibleTask(trigger.role, split);
512     if(ret != WMError::SUCCESS)
513     {
514         HMI_SEQ_ERROR(req_num, "Failed to set invisible task: %s", errorDescription(ret));
515         return ret;
516     }
517
518     /*  get new status from Policy Manager */
519     HMI_SEQ_NOTICE(req_num, "ATM, Policy manager does't exist, then set WMAction as is");
520     if(trigger.role == "HomeScreen")
521     {
522         // TODO : Remove when Policy Manager completed
523         HMI_SEQ_NOTICE(req_num, "Hack. This process will be removed. Change HomeScreen code!!");
524         req_area = "fullscreen";
525     }
526     TaskVisible task_visible =
527         (trigger.task == Task::TASK_ALLOCATE) ? TaskVisible::VISIBLE : TaskVisible::INVISIBLE;
528
529     ret = g_app_list.setAction(req_num, trigger.appid, trigger.role, req_area, task_visible);
530     g_app_list.reqDump();
531
532     return ret;
533 }
534
535 WMError App::startTransition(unsigned req_num)
536 {
537     bool sync_draw_happen = false;
538     bool found = false;
539     WMError ret = WMError::SUCCESS;
540     auto actions = g_app_list.getActions(req_num, &found);
541     if (!found)
542     {
543         ret = WMError::NO_ENTRY;
544         HMI_SEQ_ERROR(req_num,
545             "Window Manager bug :%s : Action is not set", errorDescription(ret));
546         return ret;
547     }
548
549     for (const auto &action : actions)
550     {
551         if (action.visible != TaskVisible::INVISIBLE)
552         {
553             sync_draw_happen = true;
554             this->emit_syncdraw(action.role, action.area);
555             /* TODO: emit event for app not subscriber
556             if(g_app_list.contains(y.appid))
557                 g_app_list.lookUpClient(y.appid)->emit_syncdraw(y.role, y.area); */
558         }
559     }
560
561     if (sync_draw_happen)
562     {
563         this->setTimer();
564     }
565     else
566     {
567         // deactivate only, no syncDraw
568         // Make it deactivate here
569         for (const auto &x : actions)
570         {
571             if (g_app_list.contains(x.appid))
572             {
573                 auto client = g_app_list.lookUpClient(x.appid);
574                 this->deactivate(client->surfaceID(x.role));
575             }
576         }
577         ret = NO_LAYOUT_CHANGE;
578     }
579     return ret;
580 }
581
582 WMError App::setInvisibleTask(const std::string &role, bool split)
583 {
584     unsigned req_num = g_app_list.currentRequestNumber();
585     HMI_SEQ_DEBUG(req_num, "set current visible app to invisible task");
586     // This task is copied from original actiavete surface
587     const char *drawing_name = role.c_str();
588     auto const &surface_id = this->lookup_id(drawing_name);
589     auto layer_id = this->layers.get_layer_id(*surface_id);
590     auto o_state = *this->layers.get_layout_state(*surface_id);
591     struct LayoutState &state = *o_state;
592     std::string add_name, add_role;
593     std::string add_area = "";
594     int surface;
595     TaskVisible task_visible = TaskVisible::INVISIBLE;
596     bool end_draw_finished = true;
597     bool found = false;
598
599     for (auto const &l : this->layers.mapping)
600     {
601         if (l.second.layer_id <= *layer_id)
602         {
603             continue;
604         }
605         HMI_DEBUG("wm", "debug: main %d , sub : %d", l.second.state.main, l.second.state.sub);
606         if (l.second.state.main != -1)
607         {
608             //this->deactivate(l.second.state.main);
609             surface = l.second.state.main;
610             add_role = *this->id_alloc.lookup(surface);
611             add_name = g_app_list.getAppID(surface, add_role, &found);
612             if(!found){
613                 return WMError::NOT_REGISTERED;
614             }
615             HMI_SEQ_INFO(req_num, "Invisible %s", add_name.c_str());
616             WMAction act{add_name, add_role, add_area, task_visible, end_draw_finished};
617             g_app_list.setAction(req_num, act);
618             l.second.state.main = -1;
619         }
620
621         if (l.second.state.sub != -1)
622         {
623             //this->deactivate(l.second.state.sub);
624             surface = l.second.state.sub;
625             add_role = *this->id_alloc.lookup(surface);
626             add_name = g_app_list.getAppID(surface, add_role, &found);
627             if (!found)
628             {
629                 return WMError::NOT_REGISTERED;
630             }
631             HMI_SEQ_INFO(req_num, "Invisible %s", add_name.c_str());
632             WMAction act{add_name, add_role, add_area, task_visible, end_draw_finished};
633             g_app_list.setAction(req_num, act);
634             l.second.state.sub = -1;
635         }
636     }
637
638     // change current state here, but this is hack
639     auto layer = this->layers.get_layer(*layer_id);
640
641     if (state.main == -1)
642     {
643         HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal);
644     }
645     else
646     {
647         if (0 != strcmp(drawing_name, "HomeScreen"))
648         {
649             if (split)
650             {
651                 if (state.sub != *surface_id)
652                 {
653                     if (state.sub != -1)
654                     {
655                         //this->deactivate(state.sub);
656                         WMAction deact_sub;
657                         deact_sub.role =
658                             std::move(*this->id_alloc.lookup(state.sub));
659                         deact_sub.area = add_area;
660                         deact_sub.appid = g_app_list.getAppID(state.sub, deact_sub.role, &found);
661                         if (!found)
662                         {
663                             HMI_SEQ_ERROR(req_num, "App doesn't exist for role : %s",
664                                             deact_sub.role.c_str());
665                             return WMError::NOT_REGISTERED;
666                         }
667                         deact_sub.visible = task_visible;
668                         deact_sub.end_draw_finished = end_draw_finished;
669                         HMI_SEQ_DEBUG(req_num, "Set invisible task for %s", deact_sub.appid.c_str());
670                         g_app_list.setAction(req_num, deact_sub);
671                     }
672                 }
673                 //state = LayoutState{state.main, *surface_id};
674             }
675             else
676             {
677                 HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal);
678
679                 //this->surface_set_layout(*surface_id);
680                 if (state.main != *surface_id)
681                 {
682                     // this->deactivate(state.main);
683                     WMAction deact_main;
684                     deact_main.role = std::move(*this->id_alloc.lookup(state.main));
685                     ;
686                     deact_main.area = add_area;
687                     deact_main.appid = g_app_list.getAppID(state.main, deact_main.role, &found);
688                     if (!found)
689                     {
690                         HMI_SEQ_DEBUG(req_num, "sub surface ddoesn't exist");
691                         return WMError::NOT_REGISTERED;
692                     }
693                     deact_main.visible = task_visible;
694                     deact_main.end_draw_finished = end_draw_finished;
695                     HMI_SEQ_DEBUG(req_num, "sub surface doesn't exist");
696                     g_app_list.setAction(req_num, deact_main);
697                 }
698                 if (state.sub != -1)
699                 {
700                     if (state.sub != *surface_id)
701                     {
702                         //this->deactivate(state.sub);
703                         WMAction deact_sub;
704                         deact_sub.role = std::move(*this->id_alloc.lookup(state.sub));
705                         ;
706                         deact_sub.area = add_area;
707                         deact_sub.appid = g_app_list.getAppID(state.sub, deact_sub.role, &found);
708                         if (!found)
709                         {
710                             HMI_SEQ_DEBUG(req_num, "sub surface ddoesn't exist");
711                             return WMError::NOT_REGISTERED;
712                         }
713                         deact_sub.visible = task_visible;
714                         deact_sub.end_draw_finished = end_draw_finished;
715                         HMI_SEQ_DEBUG(req_num, "sub surface doesn't exist");
716                         g_app_list.setAction(req_num, deact_sub);
717                     }
718                 }
719                 //state = LayoutState{*surface_id};
720             }
721         }
722     }
723     return WMError::SUCCESS;
724 }
725
726 const char *App::check_surface_exist(const char *drawing_name)
727 {
728     auto const &surface_id = this->lookup_id(drawing_name);
729     if (!surface_id)
730     {
731         //reply("Surface does not exist");
732         return "Surface does not exist";
733     }
734
735     if (!this->controller->surface_exists(*surface_id))
736     {
737         //reply("Surface does not exist in controller!");
738         return "Surface does not exist in controller!";
739     }
740
741     auto layer_id = this->layers.get_layer_id(*surface_id);
742
743     if (!layer_id)
744     {
745         //reply("Surface is not on any layer!");
746         return "Surface is not on any layer!";
747     }
748
749     auto o_state = *this->layers.get_layout_state(*surface_id);
750
751     if (o_state == nullptr)
752     {
753         //reply("Could not find layer for surface");
754         return "Could not find layer for surface";
755     }
756
757     HMI_DEBUG("wm", "surface %d is detected", *surface_id);
758     return nullptr;
759     //reply(nullptr);
760 }
761
762 WMError App::setRequest(const std::string& appid, const std::string &role, const std::string &area,
763                             Task task, unsigned* req_num)
764 {
765     if (!g_app_list.contains(appid))
766     {
767         return WMError::NOT_REGISTERED;
768     }
769
770     auto client = g_app_list.lookUpClient(appid);
771
772     /*
773    * Queueing Phase
774    */
775     unsigned current = g_app_list.currentRequestNumber();
776     unsigned requested_num = g_app_list.getRequestNumber(appid);
777     if (requested_num != 0)
778     {
779         HMI_SEQ_INFO(requested_num,
780             "%s %s %s request is already queued", appid.c_str(), role.c_str(), area.c_str());
781         return REQ_REJECTED;
782     }
783
784     WMRequest req = WMRequest(appid, role, area, task);
785     unsigned new_req = g_app_list.addRequest(req);
786     *req_num = new_req;
787     g_app_list.reqDump();
788
789     HMI_SEQ_DEBUG(current, "%s start sequence with %s, %s", appid.c_str(), role.c_str(), area.c_str());
790
791     return WMError::SUCCESS;
792 }
793
794 void App::api_activate_surface(char const *appid, char const *drawing_name,
795                                char const *drawing_area, const reply_func &reply)
796 {
797     ST();
798
799     std::string id = appid;
800     std::string role = drawing_name;
801     std::string area = drawing_area;
802     Task task = Task::TASK_ALLOCATE;
803     unsigned req_num = 0;
804     WMError ret = WMError::UNKNOWN;
805
806     ret = this->setRequest(id, role, area, task, &req_num);
807
808     if(ret != WMError::SUCCESS)
809     {
810         HMI_ERROR("wm", errorDescription(ret));
811         reply("Failed to set request");
812         return;
813     }
814
815     reply(nullptr);
816     if (req_num != g_app_list.currentRequestNumber())
817     {
818         // Add request, then invoked after the previous task is finished
819         HMI_SEQ_DEBUG(req_num, "request is accepted");
820         return;
821     }
822
823     /*
824     * Do allocate tasks
825     */
826     ret = this->doTransition(req_num);
827
828     if (ret != WMError::SUCCESS)
829     {
830         //this->emit_error()
831         HMI_SEQ_ERROR(req_num, errorDescription(ret));
832         g_app_list.removeRequest(req_num);
833         this->processNextRequest();
834     }
835 }
836
837 void App::api_deactivate_surface(char const *appid, char const *drawing_name,
838                                  const reply_func &reply)
839 {
840     ST();
841
842     /*
843    * Check Phase
844    */
845     std::string id = appid;
846     std::string role = drawing_name;
847     std::string area = ""; //drawing_area;
848     Task task = Task::TASK_RELEASE;
849     unsigned req_num = 0;
850     WMError ret = WMError::UNKNOWN;
851
852     ret = this->setRequest(id, role, area, task, &req_num);
853
854     if (ret != WMError::SUCCESS)
855     {
856         HMI_ERROR("wm", errorDescription(ret));
857         reply("Failed to set request");
858         return;
859     }
860
861     reply(nullptr);
862     if (req_num != g_app_list.currentRequestNumber())
863     {
864         // Add request, then invoked after the previous task is finished
865         HMI_SEQ_DEBUG(req_num, "request is accepted");
866         return;
867     }
868
869     /*
870     * Do allocate tasks
871     */
872     ret = this->doTransition(req_num);
873
874     if (ret != WMError::SUCCESS)
875     {
876         //this->emit_error()
877         HMI_SEQ_ERROR(req_num, errorDescription(ret));
878         g_app_list.removeRequest(req_num);
879         this->processNextRequest();
880     }
881 }
882
883 WMError App::doEndDraw(unsigned req_num)
884 {
885     // get actions
886     bool found;
887     auto actions = g_app_list.getActions(req_num, &found);
888     WMError ret = WMError::SUCCESS;
889     if (!found)
890     {
891         ret = WMError::NO_ENTRY;
892         return ret;
893     }
894
895     HMI_SEQ_INFO(req_num, "do endDraw");
896
897     // layout change and make it visible
898     for (const auto &act : actions)
899     {
900         // layout change
901         if(!g_app_list.contains(act.appid)){
902             ret = WMError::NOT_REGISTERED;
903         }
904         ret = this->layoutChange(act);
905         if(ret != WMError::SUCCESS)
906         {
907             HMI_SEQ_WARNING(req_num,
908                 "Failed to manipulate surfaces while state change : %s", errorDescription(ret));
909             return ret;
910         }
911         ret = this->visibilityChange(act);
912         if (ret != WMError::SUCCESS)
913         {
914             HMI_SEQ_WARNING(req_num,
915                 "Failed to manipulate surfaces while state change : %s", errorDescription(ret));
916             return ret;
917         }
918         HMI_SEQ_DEBUG(req_num, "visible %s", act.role.c_str());
919         //this->lm_enddraw(act.role.c_str());
920     }
921
922     // Change current state
923     this->changeCurrentState(req_num);
924
925     HMI_SEQ_INFO(req_num, "emit flushDraw");
926
927     for(const auto &act_flush : actions)
928     {
929         if(act_flush.visible != TaskVisible::INVISIBLE)
930         {
931             this->emit_flushdraw(act_flush.role.c_str());
932         }
933     }
934
935     return ret;
936 }
937
938 WMError App::setSurfaceSize(unsigned surface, const std::string &area)
939 {
940     this->surface_set_layout(surface, area);
941
942     return WMError::SUCCESS;
943 }
944
945 WMError App::layoutChange(const WMAction &action)
946 {
947     if (action.visible == TaskVisible::INVISIBLE)
948     {
949         // Visibility is not change -> no redraw is required
950         return WMError::SUCCESS;
951     }
952     auto client = g_app_list.lookUpClient(action.appid);
953     unsigned surface = client->surfaceID(action.role);
954     if (surface == 0)
955     {
956         HMI_SEQ_ERROR(g_app_list.currentRequestNumber(),
957                       "client doesn't have surface with role(%s)", action.role.c_str());
958         return WMError::NOT_REGISTERED;
959     }
960     // Layout Manager
961     WMError ret = this->setSurfaceSize(surface, action.area);
962     return ret;
963 }
964
965 WMError App::visibilityChange(const WMAction &action)
966 {
967     HMI_SEQ_DEBUG(g_app_list.currentRequestNumber(), "Change visibility");
968     if(!g_app_list.contains(action.appid)){
969         return WMError::NOT_REGISTERED;
970     }
971     auto client = g_app_list.lookUpClient(action.appid);
972     unsigned surface = client->surfaceID(action.role);
973     if(surface == 0)
974     {
975         HMI_SEQ_ERROR(g_app_list.currentRequestNumber(),
976                       "client doesn't have surface with role(%s)", action.role.c_str());
977         return WMError::NOT_REGISTERED;
978     }
979
980     if (action.visible != TaskVisible::INVISIBLE)
981     {
982         this->activate(surface); // Layout Manager task
983     }
984     else
985     {
986         this->deactivate(surface); // Layout Manager task
987     }
988     return WMError::SUCCESS;
989 }
990
991 WMError App::changeCurrentState(unsigned req_num)
992 {
993     HMI_SEQ_DEBUG(req_num, "Change current layout state");
994     bool trigger_found = false, action_found = false;
995     auto trigger = g_app_list.getRequest(req_num, &trigger_found);
996     auto actions = g_app_list.getActions(req_num, &action_found);
997     if (!trigger_found || !action_found)
998     {
999         HMI_SEQ_ERROR(req_num, "Action not found");
1000         return WMError::LAYOUT_CHANGE_FAIL;
1001     }
1002
1003     // Layout state reset
1004     struct LayoutState reset_state{-1, -1};
1005     HMI_SEQ_DEBUG(req_num,"Reset layout state");
1006     for (const auto &action : actions)
1007     {
1008         if(!g_app_list.contains(action.appid)){
1009             return WMError::NOT_REGISTERED;
1010         }
1011         auto client = g_app_list.lookUpClient(action.appid);
1012         auto pCurState = *this->layers.get_layout_state((int)client->surfaceID(action.role));
1013         if(pCurState == nullptr)
1014         {
1015             HMI_SEQ_ERROR(req_num, "Counldn't find current status");
1016             continue;
1017         }
1018         pCurState->main = reset_state.main;
1019         pCurState->sub = reset_state.sub;
1020     }
1021
1022     HMI_SEQ_DEBUG(req_num, "Change state");
1023     for (const auto &action : actions)
1024     {
1025         auto client = g_app_list.lookUpClient(action.appid);
1026         auto pLayerCurState = *this->layers.get_layout_state((int)client->surfaceID(action.role));
1027         if (pLayerCurState == nullptr)
1028         {
1029             HMI_SEQ_ERROR(req_num, "Counldn't find current status");
1030             continue;
1031         }
1032         int surface = -1;
1033
1034         if (action.visible != TaskVisible::INVISIBLE)
1035         {
1036             surface = (int)client->surfaceID(action.role);
1037             HMI_SEQ_INFO(req_num, "Change %s surface : %d, state visible area : %s",
1038                             action.role.c_str(), surface, action.area.c_str());
1039             // visible == true -> layout changes
1040             if(action.area == "normal.full" || action.area == "split.main")
1041             {
1042                 pLayerCurState->main = surface;
1043             }
1044             else if (action.area == "split.sub")
1045             {
1046                 pLayerCurState->sub = surface;
1047             }
1048             else
1049             {
1050                 // normalfull
1051                 pLayerCurState->main = surface;
1052             }
1053         }
1054     }
1055
1056     return WMError::SUCCESS;
1057 }
1058
1059 void App::api_enddraw(char const *appid, char const *drawing_name)
1060 {
1061     std::string id = appid;
1062     std::string role = drawing_name;
1063     unsigned current_req = g_app_list.currentRequestNumber();
1064     bool result = g_app_list.setEndDrawFinished(current_req, id, role);
1065
1066     if (!result)
1067     {
1068         HMI_ERROR("wm", "%s is not in transition state", id.c_str());
1069         return;
1070     }
1071
1072     if (g_app_list.endDrawFullfilled(current_req))
1073     {
1074         // do task for endDraw
1075         this->stopTimer();
1076         WMError ret = this->doEndDraw(current_req);
1077
1078         if(ret != WMError::SUCCESS)
1079         {
1080             //this->emit_error();
1081         }
1082         HMI_SEQ_INFO(current_req, "Finish request status: %s", errorDescription(ret));
1083
1084         g_app_list.removeRequest(current_req);
1085
1086         this->processNextRequest();
1087     }
1088     else
1089     {
1090         HMI_SEQ_INFO(current_req, "Wait other App call endDraw");
1091         return;
1092     }
1093 }
1094
1095 void App::processNextRequest()
1096 {
1097     g_app_list.next();
1098     g_app_list.reqDump();
1099     unsigned req_num = g_app_list.currentRequestNumber();
1100     if (g_app_list.haveRequest())
1101     {
1102         HMI_SEQ_DEBUG(req_num, "Process next request");
1103         WMError rc = doTransition(req_num);
1104         if (rc != WMError::SUCCESS)
1105         {
1106             HMI_SEQ_ERROR(req_num, errorDescription(rc));
1107         }
1108     }
1109     else
1110     {
1111         HMI_SEQ_DEBUG(req_num, "Nothing Request. Waiting Request");
1112     }
1113 }
1114
1115 void App::api_ping() { this->dispatch_pending_events(); }
1116
1117 void App::send_event(char const *evname, char const *label)
1118 {
1119     HMI_DEBUG("wm", "%s: %s(%s)", __func__, evname, label);
1120
1121     json_object *j = json_object_new_object();
1122     json_object_object_add(j, kKeyDrawingName, json_object_new_string(label));
1123
1124     int ret = afb_event_push(this->map_afb_event[evname], j);
1125     if (ret != 0)
1126     {
1127         HMI_DEBUG("wm", "afb_event_push failed: %m");
1128     }
1129 }
1130
1131 void App::send_event(char const *evname, char const *label, char const *area,
1132                      int x, int y, int w, int h)
1133 {
1134     HMI_DEBUG("wm", "%s: %s(%s, %s) x:%d y:%d w:%d h:%d",
1135               __func__, evname, label, area, x, y, w, h);
1136
1137     json_object *j_rect = json_object_new_object();
1138     json_object_object_add(j_rect, kKeyX, json_object_new_int(x));
1139     json_object_object_add(j_rect, kKeyY, json_object_new_int(y));
1140     json_object_object_add(j_rect, kKeyWidth, json_object_new_int(w));
1141     json_object_object_add(j_rect, kKeyHeight, json_object_new_int(h));
1142
1143     json_object *j = json_object_new_object();
1144     json_object_object_add(j, kKeyDrawingName, json_object_new_string(label));
1145     json_object_object_add(j, kKeyDrawingArea, json_object_new_string(area));
1146     json_object_object_add(j, kKeyDrawingRect, j_rect);
1147
1148     int ret = afb_event_push(this->map_afb_event[evname], j);
1149     if (ret != 0)
1150     {
1151         HMI_DEBUG("wm", "afb_event_push failed: %m");
1152     }
1153 }
1154
1155 /**
1156  * proxied events
1157  */
1158 void App::surface_created(uint32_t surface_id)
1159 {
1160     auto layer_id = this->layers.get_layer_id(surface_id);
1161     if (!layer_id)
1162     {
1163         HMI_DEBUG("wm", "Newly created surfce %d is not associated with any layer!",
1164                   surface_id);
1165         return;
1166     }
1167
1168     HMI_DEBUG("wm", "surface_id is %u, layer_id is %u", surface_id, *layer_id);
1169
1170     this->controller->layers[*layer_id]->add_surface(surface_id);
1171     this->layout_commit();
1172 }
1173
1174 void App::surface_removed(uint32_t surface_id)
1175 {
1176     HMI_DEBUG("wm", "surface_id is %u", surface_id);
1177
1178     g_app_list.removeSurface(surface_id);
1179 }
1180
1181 void App::emit_activated(char const *label)
1182 {
1183     this->send_event(kListEventName[Event_Active], label);
1184 }
1185
1186 void App::emit_deactivated(char const *label)
1187 {
1188     this->send_event(kListEventName[Event_Inactive], label);
1189 }
1190
1191 void App::emit_syncdraw(char const *label, char const *area, int x, int y, int w, int h)
1192 {
1193     this->send_event(kListEventName[Event_SyncDraw], label, area, x, y, w, h);
1194 }
1195
1196 void App::emit_syncdraw(const std::string &role, const std::string &area)
1197 {
1198     compositor::rect rect = this->layers.getAreaSize(area);
1199     //this->lm_get_area_info(area, &x, &y, &w, &h);
1200     this->send_event(kListEventName[Event_SyncDraw],
1201         role.c_str(), area.c_str(), rect.x, rect.y, rect.w, rect.h);
1202 }
1203
1204 void App::emit_flushdraw(char const *label)
1205 {
1206     this->send_event(kListEventName[Event_FlushDraw], label);
1207 }
1208
1209 void App::emit_visible(char const *label, bool is_visible)
1210 {
1211     this->send_event(is_visible ? kListEventName[Event_Visible] : kListEventName[Event_Invisible], label);
1212 }
1213
1214 void App::emit_invisible(char const *label)
1215 {
1216     return emit_visible(label, false);
1217 }
1218
1219 void App::emit_visible(char const *label) { return emit_visible(label, true); }
1220
1221 result<int> App::api_request_surface(char const *appid, char const *drawing_name)
1222 {
1223     auto lid = this->layers.get_layer_id(std::string(drawing_name));
1224     if (!lid)
1225     {
1226         /**
1227        * register drawing_name as fallback and make it displayed.
1228        */
1229         lid = this->layers.get_layer_id(std::string("Fallback"));
1230         HMI_DEBUG("wm", "%s is not registered in layers.json, then fallback as normal app", drawing_name);
1231         if (!lid)
1232         {
1233             return Err<int>("Drawing name does not match any role, Fallback is disabled");
1234         }
1235     }
1236
1237     auto rname = this->lookup_id(drawing_name);
1238     if (!rname)
1239     {
1240         // name does not exist yet, allocate surface id...
1241         auto id = int(this->id_alloc.generate_id(drawing_name));
1242         this->layers.add_surface(id, *lid);
1243
1244         // set the main_surface[_name] here and now
1245         if (!this->layers.main_surface_name.empty() &&
1246             this->layers.main_surface_name == drawing_name)
1247         {
1248             this->layers.main_surface = id;
1249             HMI_DEBUG("wm", "Set main_surface id to %u", id);
1250         }
1251
1252         // add client into the db
1253         std::string appid_str(appid);
1254         std::string role(drawing_name);
1255         //g_app_list.addClient(appid_str, role);
1256         g_app_list.addClient(appid_str, *lid, id, role);
1257
1258         return Ok<int>(id);
1259     }
1260
1261     // Check currently registered drawing names if it is already there.
1262     return Err<int>("Surface already present");
1263 }
1264
1265 char const *App::api_request_surface(char const *appid, char const *drawing_name,
1266                                      char const *ivi_id)
1267 {
1268     ST();
1269
1270     auto lid = this->layers.get_layer_id(std::string(drawing_name));
1271     unsigned sid = std::stol(ivi_id);
1272
1273     if (!lid)
1274     {
1275         /**
1276        * register drawing_name as fallback and make it displayed.
1277        */
1278         lid = this->layers.get_layer_id(std::string("Fallback"));
1279         HMI_DEBUG("wm", "%s is not registered in layers.json, then fallback as normal app", drawing_name);
1280         if (!lid)
1281         {
1282             return "Drawing name does not match any role, Fallback is disabled";
1283         }
1284     }
1285
1286     auto rname = this->lookup_id(drawing_name);
1287
1288     if (rname)
1289     {
1290         return "Surface already present";
1291     }
1292
1293     // register pair drawing_name and ivi_id
1294     this->id_alloc.register_name_id(drawing_name, sid);
1295     this->layers.add_surface(sid, *lid);
1296
1297     // this surface is already created
1298     HMI_DEBUG("wm", "surface_id is %u, layer_id is %u", sid, *lid);
1299
1300     this->controller->layers[*lid]->add_surface(sid);
1301     this->layout_commit();
1302
1303     return nullptr;
1304 }
1305
1306 result<json_object *> App::api_get_display_info()
1307 {
1308     // Check controller
1309     if (!this->controller)
1310     {
1311         return Err<json_object *>("ivi_controller global not available");
1312     }
1313
1314     // Set display info
1315     compositor::size o_size = this->controller->output_size;
1316     compositor::size p_size = this->controller->physical_size;
1317
1318     json_object *object = json_object_new_object();
1319     json_object_object_add(object, kKeyWidthPixel, json_object_new_int(o_size.w));
1320     json_object_object_add(object, kKeyHeightPixel, json_object_new_int(o_size.h));
1321     json_object_object_add(object, kKeyWidthMm, json_object_new_int(p_size.w));
1322     json_object_object_add(object, kKeyHeightMm, json_object_new_int(p_size.h));
1323
1324     return Ok<json_object *>(object);
1325 }
1326
1327 result<json_object *> App::api_get_area_info(char const *drawing_name)
1328 {
1329     HMI_DEBUG("wm", "called");
1330
1331     // Check drawing name, surface/layer id
1332     auto const &surface_id = this->lookup_id(drawing_name);
1333     if (!surface_id)
1334     {
1335         return Err<json_object *>("Surface does not exist");
1336     }
1337
1338     if (!this->controller->surface_exists(*surface_id))
1339     {
1340         return Err<json_object *>("Surface does not exist in controller!");
1341     }
1342
1343     auto layer_id = this->layers.get_layer_id(*surface_id);
1344     if (!layer_id)
1345     {
1346         return Err<json_object *>("Surface is not on any layer!");
1347     }
1348
1349     auto o_state = *this->layers.get_layout_state(*surface_id);
1350     if (o_state == nullptr)
1351     {
1352         return Err<json_object *>("Could not find layer for surface");
1353     }
1354
1355     struct LayoutState &state = *o_state;
1356     if ((state.main != *surface_id) && (state.sub != *surface_id))
1357     {
1358         return Err<json_object *>("Surface is inactive");
1359     }
1360
1361     // Set area rectangle
1362     compositor::rect area_info = this->area_info[*surface_id];
1363     json_object *object = json_object_new_object();
1364     json_object_object_add(object, kKeyX, json_object_new_int(area_info.x));
1365     json_object_object_add(object, kKeyY, json_object_new_int(area_info.y));
1366     json_object_object_add(object, kKeyWidth, json_object_new_int(area_info.w));
1367     json_object_object_add(object, kKeyHeight, json_object_new_int(area_info.h));
1368
1369     return Ok<json_object *>(object);
1370 }
1371
1372 void App::activate(int id)
1373 {
1374     auto ip = this->controller->sprops.find(id);
1375     if (ip != this->controller->sprops.end())
1376     {
1377         this->controller->surfaces[id]->set_visibility(1);
1378         char const *label =
1379             this->lookup_name(id).value_or("unknown-name").c_str();
1380
1381          // FOR CES DEMO >>>
1382         if ((0 == strcmp(label, "Radio"))       ||
1383             (0 == strcmp(label, "MediaPlayer")) ||
1384             (0 == strcmp(label, "Music"))       ||
1385             (0 == strcmp(label, "Navigation")))
1386         {
1387             for (auto i = surface_bg.begin(); i != surface_bg.end(); ++i)
1388             {
1389                 if (id == *i)
1390                 {
1391                     // Remove id
1392                     this->surface_bg.erase(i);
1393
1394                     // Remove from BG layer (999)
1395                     HMI_DEBUG("wm", "Remove %s(%d) from BG layer", label, id);
1396                     this->controller->layers[999]->remove_surface(id);
1397
1398                     // Add to FG layer (1001)
1399                     HMI_DEBUG("wm", "Add %s(%d) to FG layer", label, id);
1400                     this->controller->layers[1001]->add_surface(id);
1401
1402                     for (int j : this->surface_bg)
1403                     {
1404                         HMI_DEBUG("wm", "Stored id:%d", j);
1405                     }
1406                     break;
1407                 }
1408             }
1409         }
1410         // <<< FOR CES DEMO
1411         this->layout_commit();
1412
1413         this->emit_visible(label);
1414         this->emit_activated(label);
1415     }
1416 }
1417
1418 void App::deactivate(int id)
1419 {
1420     auto ip = this->controller->sprops.find(id);
1421     if (ip != this->controller->sprops.end())
1422     {
1423         char const *label =
1424             this->lookup_name(id).value_or("unknown-name").c_str();
1425
1426         // FOR CES DEMO >>>
1427         if ((0 == strcmp(label, "Radio")) || (0 == strcmp(label, "MediaPlayer")) || (0 == strcmp(label, "Music")) || (0 == strcmp(label, "Navigation")))
1428         {
1429
1430             // Store id
1431             this->surface_bg.push_back(id);
1432
1433             // Remove from FG layer (1001)
1434             HMI_DEBUG("wm", "Remove %s(%d) from FG layer", label, id);
1435             this->controller->layers[1001]->remove_surface(id);
1436
1437             // Add to BG layer (999)
1438             HMI_DEBUG("wm", "Add %s(%d) to BG layer", label, id);
1439             this->controller->layers[999]->add_surface(id);
1440
1441             for (int j : surface_bg)
1442             {
1443                 HMI_DEBUG("wm", "Stored id:%d", j);
1444             }
1445         }
1446         else
1447         {
1448             this->controller->surfaces[id]->set_visibility(0);
1449         }
1450         // <<< FOR CES DEMO
1451
1452         this->emit_deactivated(label);
1453         this->emit_invisible(label);
1454     }
1455 }
1456
1457 bool App::can_split(struct LayoutState const &state, int new_id)
1458 {
1459     if (state.main != -1 && state.main != new_id)
1460     {
1461         auto new_id_layer = this->layers.get_layer_id(new_id).value();
1462         auto current_id_layer = this->layers.get_layer_id(state.main).value();
1463
1464         // surfaces are on separate layers, don't bother.
1465         if (new_id_layer != current_id_layer)
1466         {
1467             return false;
1468         }
1469
1470         std::string const &new_id_str = this->lookup_name(new_id).value();
1471         std::string const &cur_id_str = this->lookup_name(state.main).value();
1472
1473         auto const &layer = this->layers.get_layer(new_id_layer);
1474
1475         HMI_DEBUG("wm", "layer info name: %s", layer->name.c_str());
1476
1477         if (layer->layouts.empty())
1478         {
1479             return false;
1480         }
1481
1482         for (auto i = layer->layouts.cbegin(); i != layer->layouts.cend(); i++)
1483         {
1484             HMI_DEBUG("wm", "%d main_match '%s'", new_id_layer, i->main_match.c_str());
1485             auto rem = std::regex(i->main_match);
1486             if (std::regex_match(cur_id_str, rem))
1487             {
1488                 // build the second one only if the first already matched
1489                 HMI_DEBUG("wm", "%d sub_match '%s'", new_id_layer, i->sub_match.c_str());
1490                 auto res = std::regex(i->sub_match);
1491                 if (std::regex_match(new_id_str, res))
1492                 {
1493                     HMI_DEBUG("wm", "layout matched!");
1494                     return true;
1495                 }
1496             }
1497         }
1498     }
1499
1500     return false;
1501 }
1502
1503 /**
1504  * controller_hooks
1505  */
1506 void controller_hooks::surface_created(uint32_t surface_id)
1507 {
1508     this->app->surface_created(surface_id);
1509 }
1510
1511 void controller_hooks::surface_removed(uint32_t surface_id)
1512 {
1513     this->app->surface_removed(surface_id);
1514 }
1515
1516 void controller_hooks::surface_visibility(uint32_t /*surface_id*/,
1517                                           uint32_t /*v*/) {}
1518
1519 void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/,
1520                                                      uint32_t /*x*/,
1521                                                      uint32_t /*y*/,
1522                                                      uint32_t /*w*/,
1523                                                      uint32_t /*h*/) {}
1524
1525 } // namespace wm