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