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