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