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