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