Change the protocol from ivi-controller to ivi-wm
[apps/agl-service-windowmanager-2017.git] / src / app.cpp
1 /*
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "app.hpp"
18 #include "json_helper.hpp"
19 #include "layers.hpp"
20 #include "layout.hpp"
21 #include "util.hpp"
22 #include "wayland_ivi_wm.hpp"
23
24 #include <cstdio>
25 #include <memory>
26
27 #include <cassert>
28
29 #include <json-c/json.h>
30
31 #include <algorithm>
32 #include <csignal>
33 #include <fstream>
34 #include <json.hpp>
35 #include <regex>
36 #include <thread>
37
38
39 namespace wm {
40
41 namespace {
42
43 using nlohmann::json;
44
45 result<json> file_to_json(char const *filename) {
46    json j;
47    std::ifstream i(filename);
48    if (i.fail()) {
49       HMI_DEBUG("wm", "Could not open config file, so use default layer information");
50       j = default_layers_json;
51    }
52    else {
53       i >> j;
54    }
55
56    return Ok(j);
57 }
58
59 struct result<layer_map> load_layer_map(char const *filename) {
60    HMI_DEBUG("wm", "loading IDs from %s", filename);
61
62    auto j = file_to_json(filename);
63    if (j.is_err()) {
64       return Err<layer_map>(j.unwrap_err());
65    }
66    json jids = j.unwrap();
67
68    return to_layer_map(jids);
69 }
70
71 }  // namespace
72
73
74 /**
75  * App Impl
76  */
77 App::App(wl::display *d)
78    : chooks{this},
79      display{d},
80      controller{},
81      outputs(),
82      config(),
83      layers(),
84      id_alloc{},
85      pending_events(false),
86      policy{} {
87    try {
88       {
89          auto l = load_layer_map(
90             this->config.get_string("layers.json").value().c_str());
91          if (l.is_ok()) {
92             this->layers = l.unwrap();
93          } else {
94             HMI_ERROR("wm", "%s", l.err().value());
95          }
96       }
97    } catch (std::exception &e) {
98       HMI_ERROR("wm", "Loading of configuration failed: %s", e.what());
99    }
100 }
101
102 int App::init() {
103    if (!this->display->ok()) {
104       return -1;
105    }
106
107    if (this->layers.mapping.empty()) {
108       HMI_ERROR("wm", "No surface -> layer mapping loaded");
109       return -1;
110    }
111
112    // Make afb event
113    for (int i=Event_Val_Min; i<=Event_Val_Max; i++) {
114       map_afb_event[kListEventName[i]] = afb_daemon_make_event(kListEventName[i]);
115    }
116
117    this->display->add_global_handler(
118       "wl_output", [this](wl_registry *r, uint32_t name, uint32_t v) {
119          this->outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
120       });
121
122    this->display->add_global_handler(
123       "ivi_wm", [this](wl_registry *r, uint32_t name, uint32_t v) {
124          this->controller =
125             std::make_unique<struct compositor::controller>(r, name, v);
126
127          // Init controller hooks
128          this->controller->chooks = &this->chooks;
129
130          // This protocol needs the output, so lets just add our mapping here...
131          this->controller->add_proxy_to_id_mapping(
132             this->outputs.back()->proxy.get(),
133             wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
134                this->outputs.back()->proxy.get())));
135
136          // Create screen
137          this->controller->create_screen(this->outputs.back()->proxy.get());
138
139          // Set display to controller
140          this->controller->display = this->display;
141       });
142
143    // First level objects
144    this->display->roundtrip();
145    // Second level objects
146    this->display->roundtrip();
147    // Third level objects
148    this->display->roundtrip();
149
150    return init_layers();
151 }
152
153 int App::dispatch_pending_events() {
154    if (this->pop_pending_events()) {
155       this->display->dispatch_pending();
156       return 0;
157    }
158    return -1;
159 }
160
161 bool App::pop_pending_events() {
162    bool x{true};
163    return this->pending_events.compare_exchange_strong(
164       x, false, std::memory_order_consume);
165 }
166
167 void App::set_pending_events() {
168    this->pending_events.store(true, std::memory_order_release);
169 }
170
171 optional<int> App::lookup_id(char const *name) {
172    return this->id_alloc.lookup(std::string(name));
173 }
174 optional<std::string> App::lookup_name(int id) {
175    return this->id_alloc.lookup(id);
176 }
177
178 /**
179  * init_layers()
180  */
181 int App::init_layers() {
182    if (!this->controller) {
183       HMI_ERROR("wm", "ivi_controller global not available");
184       return -1;
185    }
186
187    if (this->outputs.empty()) {
188       HMI_ERROR("wm", "no output was set up!");
189       return -1;
190    }
191
192    auto &c = this->controller;
193
194    auto &o = this->outputs.front();
195    auto &s = c->screens.begin()->second;
196    auto &layers = c->layers;
197
198    // Write output dimensions to ivi controller...
199    c->output_size = compositor::size{uint32_t(o->width), uint32_t(o->height)};
200
201    // Clear scene
202    layers.clear();
203
204    // Clear screen
205    s->clear();
206
207    // Quick and dirty setup of layers
208    for (auto const &i : this->layers.mapping) {
209       c->layer_create(i.second.layer_id, o->width, o->height);
210       auto &l = layers[i.second.layer_id];
211       l->set_destination_rectangle(0, 0, o->width, o->height);
212       l->set_visibility(1);
213       HMI_DEBUG("wm", "Setting up layer %s (%d) for surface role match \"%s\"",
214                i.second.name.c_str(), i.second.layer_id, i.second.role.c_str());
215    }
216
217    // Add layers to screen
218    s->set_render_order(this->layers.layers);
219
220    this->layout_commit();
221
222    return 0;
223 }
224
225 void App::surface_set_layout(int surface_id, optional<int> sub_surface_id) {
226    if (!this->controller->surface_exists(surface_id)) {
227       HMI_ERROR("wm", "Surface %d does not exist", surface_id);
228       return;
229    }
230
231    auto o_layer_id = this->layers.get_layer_id(surface_id);
232
233    if (!o_layer_id) {
234       HMI_ERROR("wm", "Surface %d is not associated with any layer!", surface_id);
235       return;
236    }
237
238    uint32_t layer_id = *o_layer_id;
239
240    auto const &layer = this->layers.get_layer(layer_id);
241    auto rect = layer.value().rect;
242    auto &s = this->controller->surfaces[surface_id];
243
244    int x = rect.x;
245    int y = rect.y;
246    int w = rect.w;
247    int h = rect.h;
248
249    // less-than-0 values refer to MAX + 1 - $VALUE
250    // e.g. MAX is either screen width or height
251    if (w < 0) {
252       w = this->controller->output_size.w + 1 + w;
253    }
254    if (h < 0) {
255       h = this->controller->output_size.h + 1 + h;
256    }
257
258    if (sub_surface_id) {
259       if (o_layer_id != this->layers.get_layer_id(*sub_surface_id)) {
260          HMI_ERROR("wm",
261             "surface_set_layout: layers of surfaces (%d and %d) don't match!",
262             surface_id, *sub_surface_id);
263          return;
264       }
265
266       int x_off = 0;
267       int y_off = 0;
268
269       // split along major axis
270       if (w > h) {
271          w /= 2;
272          x_off = w;
273       } else {
274          h /= 2;
275          y_off = h;
276       }
277
278       auto &ss = this->controller->surfaces[*sub_surface_id];
279
280       HMI_DEBUG("wm", "surface_set_layout for sub surface %u on layer %u",
281                *sub_surface_id, layer_id);
282
283       // set destination to the display rectangle
284       ss->set_destination_rectangle(x + x_off, y + y_off, w, h);
285
286    }
287
288    HMI_DEBUG("wm", "surface_set_layout for surface %u on layer %u", surface_id,
289             layer_id);
290
291    // set destination to the display rectangle
292    s->set_destination_rectangle(x, y, w, h);
293
294    HMI_DEBUG("wm", "Surface %u now on layer %u with rect { %d, %d, %d, %d }",
295             surface_id, layer_id, x, y, w, h);
296 }
297
298 void App::layout_commit() {
299    this->controller->commit_changes();
300    this->display->flush();
301 }
302
303 char const *App::api_activate_surface(char const *drawing_name, char const *drawing_area) {
304    ST();
305
306    auto const &surface_id = this->lookup_id(drawing_name);
307
308    if (!surface_id) {
309       return "Surface does not exist";
310    }
311
312    if (!this->controller->surface_exists(*surface_id)) {
313       return "Surface does not exist in controller!";
314    }
315
316    auto layer_id = this->layers.get_layer_id(*surface_id);
317
318    if (!layer_id) {
319       return "Surface is not on any layer!";
320    }
321
322    auto o_state = *this->layers.get_layout_state(*surface_id);
323
324    if (o_state == nullptr) {
325       return "Could not find layer for surface";
326    }
327
328    struct LayoutState &state = *o_state;
329
330    // disable layers that are above our current layer
331    for (auto const &l : this->layers.mapping) {
332       if (l.second.layer_id <= *layer_id) {
333          continue;
334       }
335
336       bool flush = false;
337       if (l.second.state.main != -1) {
338          this->deactivate(l.second.state.main);
339          l.second.state.main = -1;
340          flush = true;
341       }
342
343       if (l.second.state.sub != -1) {
344          this->deactivate(l.second.state.sub);
345          l.second.state.sub = -1;
346          flush = true;
347       }
348
349       if (flush) {
350          this->layout_commit();
351       }
352    }
353
354    auto layer = this->layers.get_layer(*layer_id);
355
356    if (state.main == -1) {
357       this->try_layout(
358          state, LayoutState{*surface_id}, [&] (LayoutState const &nl) {
359             HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal);
360             this->surface_set_layout(*surface_id);
361             state = nl;
362
363             // Commit for configuraton
364             this->layout_commit();
365
366             std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
367             this->emit_syncdraw(drawing_name, str_area.c_str());
368             this->enqueue_flushdraw(state.main);
369          });
370    } else {
371       if (0 == strcmp(drawing_name, "HomeScreen")) {
372          this->try_layout(
373             state, LayoutState{*surface_id}, [&] (LayoutState const &nl) {
374                HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal);
375                std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
376                this->emit_syncdraw(drawing_name, str_area.c_str());
377                this->enqueue_flushdraw(state.main);
378             });
379       } else {
380          bool can_split = this->can_split(state, *surface_id);
381
382          if (can_split) {
383             this->try_layout(
384                state,
385                LayoutState{state.main, *surface_id},
386                [&] (LayoutState const &nl) {
387                   HMI_DEBUG("wm", "Layout: %s", kNameLayoutSplit);
388                   std::string main =
389                      std::move(*this->lookup_name(state.main));
390
391                   this->surface_set_layout(state.main, surface_id);
392                   if (state.sub != *surface_id) {
393                       if (state.sub != -1) {
394                          this->deactivate(state.sub);
395                       }
396                   }
397                   state = nl;
398
399                   // Commit for configuration and visibility(0)
400                   this->layout_commit();
401
402                   std::string str_area_main = std::string(kNameLayoutSplit) + "." + std::string(kNameAreaMain);
403                   std::string str_area_sub = std::string(kNameLayoutSplit) + "." + std::string(kNameAreaSub);
404                   this->emit_syncdraw(main.c_str(), str_area_main.c_str());
405                   this->emit_syncdraw(drawing_name, str_area_sub.c_str());
406                   this->enqueue_flushdraw(state.main);
407                   this->enqueue_flushdraw(state.sub);
408                });
409          } else {
410             this->try_layout(
411                state, LayoutState{*surface_id}, [&] (LayoutState const &nl) {
412                   HMI_DEBUG("wm", "Layout: %s", kNameLayoutNormal);
413
414                   this->surface_set_layout(*surface_id);
415                   if (state.main != *surface_id) {
416                       this->deactivate(state.main);
417                   }
418                   if (state.sub != -1) {
419                       if (state.sub != *surface_id) {
420                          this->deactivate(state.sub);
421                       }
422                   }
423                   state = nl;
424
425                   // Commit for configuraton and visibility(0)
426                   this->layout_commit();
427
428                   std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
429                   this->emit_syncdraw(drawing_name, str_area.c_str());
430                   this->enqueue_flushdraw(state.main);
431                });
432          }
433       }
434    }
435
436    // no error
437    return nullptr;
438 }
439
440 char const *App::api_deactivate_surface(char const *drawing_name) {
441    ST();
442    auto const &surface_id = this->lookup_id(drawing_name);
443
444    if (!surface_id) {
445          return "Surface does not exist";
446       }
447
448    if (*surface_id == this->layers.main_surface) {
449       return "Cannot deactivate main_surface";
450    }
451
452    auto o_state = *this->layers.get_layout_state(*surface_id);
453
454    if (o_state == nullptr) {
455       return "Could not find layer for surface";
456    }
457
458    struct LayoutState &state = *o_state;
459
460    if (state.main == -1) {
461       return "No surface active";
462    }
463
464    // Check against main_surface, main_surface_name is the configuration item.
465    if (*surface_id == this->layers.main_surface) {
466       HMI_DEBUG("wm", "Refusing to deactivate main_surface %d", *surface_id);
467       return nullptr;
468    }
469
470    if (state.main == *surface_id) {
471       if (state.sub != -1) {
472          this->try_layout(
473             state, LayoutState{state.sub, -1}, [&] (LayoutState const &nl) {
474                std::string sub = std::move(*this->lookup_name(state.sub));
475
476                this->deactivate(*surface_id);
477                this->surface_set_layout(state.sub);
478                state = nl;
479
480                this->layout_commit();
481                std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
482                this->emit_syncdraw(sub.c_str(), str_area.c_str());
483                this->enqueue_flushdraw(state.sub);
484             });
485       } else {
486          this->try_layout(state, LayoutState{-1, -1}, [&] (LayoutState const &nl) {
487             this->deactivate(*surface_id);
488             state = nl;
489             this->layout_commit();
490          });
491       }
492    } else if (state.sub == *surface_id) {
493       this->try_layout(
494          state, LayoutState{state.main, -1}, [&] (LayoutState const &nl) {
495             std::string main = std::move(*this->lookup_name(state.main));
496
497             this->deactivate(*surface_id);
498             this->surface_set_layout(state.main);
499             state = nl;
500
501             this->layout_commit();
502             std::string str_area = std::string(kNameLayoutNormal) + "." + std::string(kNameAreaFull);
503             this->emit_syncdraw(main.c_str(), str_area.c_str());
504             this->enqueue_flushdraw(state.main);
505          });
506    } else {
507       return "Surface is not active";
508    }
509
510    return nullptr;
511 }
512
513 void App::enqueue_flushdraw(int surface_id) {
514    this->check_flushdraw(surface_id);
515    HMI_DEBUG("wm", "Enqueuing EndDraw for surface_id %d", surface_id);
516    this->pending_end_draw.push_back(surface_id);
517 }
518
519 void App::check_flushdraw(int surface_id) {
520    auto i = std::find(std::begin(this->pending_end_draw),
521                       std::end(this->pending_end_draw), surface_id);
522    if (i != std::end(this->pending_end_draw)) {
523       auto n = this->lookup_name(surface_id);
524       HMI_ERROR("wm", "Application %s (%d) has pending EndDraw call(s)!",
525                n ? n->c_str() : "unknown-name", surface_id);
526       std::swap(this->pending_end_draw[std::distance(
527                    std::begin(this->pending_end_draw), i)],
528                 this->pending_end_draw.back());
529       this->pending_end_draw.resize(this->pending_end_draw.size() - 1);
530    }
531 }
532
533 char const *App::api_enddraw(char const *drawing_name) {
534    for (unsigned i = 0, iend = this->pending_end_draw.size(); i < iend; i++) {
535       auto n = this->lookup_name(this->pending_end_draw[i]);
536       if (n && *n == drawing_name) {
537          std::swap(this->pending_end_draw[i], this->pending_end_draw[iend - 1]);
538          this->pending_end_draw.resize(iend - 1);
539          this->activate(this->pending_end_draw[i]);
540          this->layout_commit();
541          this->emit_flushdraw(drawing_name);
542          return nullptr;
543       }
544    }
545    return "No EndDraw pending for surface";
546 }
547
548 void App::api_ping() { this->dispatch_pending_events(); }
549
550 void App::send_event(char const *evname, char const *label){
551    HMI_DEBUG("wm", "%s: %s(%s)", __func__, evname, label);
552
553    json_object *j = json_object_new_object();
554    json_object_object_add(j, kKeyDrawingName, json_object_new_string(label));
555
556    int ret = afb_event_push(this->map_afb_event[evname], j);
557    if (ret != 0) {
558       HMI_DEBUG("wm", "afb_event_push failed: %m");
559    }
560 }
561
562 void App::send_event(char const *evname, char const *label, char const *area){
563    HMI_DEBUG("wm", "%s: %s(%s, %s)", __func__, evname, label, area);
564
565    json_object *j = json_object_new_object();
566    json_object_object_add(j, kKeyDrawingName, json_object_new_string(label));
567    json_object_object_add(j, kKeyDrawingArea, json_object_new_string(area));
568
569    int ret = afb_event_push(this->map_afb_event[evname], j);
570    if (ret != 0) {
571       HMI_DEBUG("wm", "afb_event_push failed: %m");
572    }
573 }
574
575 /**
576  * proxied events
577  */
578 void App::surface_created(uint32_t surface_id) {
579    auto layer_id = this->layers.get_layer_id(surface_id);
580    if (!layer_id) {
581       HMI_DEBUG("wm", "Newly created surfce %d is not associated with any layer!",
582                surface_id);
583       return;
584    }
585
586    HMI_DEBUG("wm", "surface_id is %u, layer_id is %u", surface_id, *layer_id);
587
588    this->controller->layers[*layer_id]->add_surface(surface_id);
589    this->layout_commit();
590    // activate the main_surface right away
591    /*if (surface_id == static_cast<unsigned>(this->layers.main_surface)) {
592       HMI_DEBUG("wm", "Activating main_surface (%d)", surface_id);
593
594       this->api_activate_surface(
595          this->lookup_name(surface_id).value_or("unknown-name").c_str());
596    }*/
597 }
598
599 void App::surface_removed(uint32_t surface_id) {
600    HMI_DEBUG("wm", "surface_id is %u", surface_id);
601
602    // We cannot normally deactivate the main_surface, so be explicit
603    // about it:
604    if (int(surface_id) == this->layers.main_surface) {
605       this->deactivate_main_surface();
606    } else {
607       auto drawing_name = this->lookup_name(surface_id);
608       if (drawing_name) {
609          this->api_deactivate_surface(drawing_name->c_str());
610       }
611    }
612
613    this->id_alloc.remove_id(surface_id);
614    this->layers.remove_surface(surface_id);
615 }
616
617 void App::emit_activated(char const *label) {
618    this->send_event(kListEventName[Event_Active], label);
619 }
620
621 void App::emit_deactivated(char const *label) {
622    this->send_event(kListEventName[Event_Inactive], label);
623 }
624
625 void App::emit_syncdraw(char const *label, char const *area) {
626     this->send_event(kListEventName[Event_SyncDraw], label, area);
627 }
628
629 void App::emit_flushdraw(char const *label) {
630    this->send_event(kListEventName[Event_FlushDraw], label);
631 }
632
633 void App::emit_visible(char const *label, bool is_visible) {
634    this->send_event(is_visible ? kListEventName[Event_Visible] : kListEventName[Event_Invisible], label);
635 }
636
637 void App::emit_invisible(char const *label) {
638    return emit_visible(label, false);
639 }
640
641 void App::emit_visible(char const *label) { return emit_visible(label, true); }
642
643 result<int> App::api_request_surface(char const *drawing_name) {
644    auto lid = this->layers.get_layer_id(std::string(drawing_name));
645    if (!lid) {
646       // TODO: Do we need to put these applications on the App layer?
647       return Err<int>("Drawing name does not match any role");
648    }
649
650    auto rname = this->lookup_id(drawing_name);
651    if (!rname) {
652       // name does not exist yet, allocate surface id...
653       auto id = int(this->id_alloc.generate_id(drawing_name));
654       this->layers.add_surface(id, *lid);
655
656       // set the main_surface[_name] here and now
657       if (!this->layers.main_surface_name.empty() &&
658           this->layers.main_surface_name == drawing_name) {
659          this->layers.main_surface = id;
660          HMI_DEBUG("wm", "Set main_surface id to %u", id);
661       }
662
663       return Ok<int>(id);
664    }
665
666    // Check currently registered drawing names if it is already there.
667    return Err<int>("Surface already present");
668 }
669
670 char const *App::api_request_surface(char const *drawing_name,
671                                      char const *ivi_id) {
672    ST();
673
674    auto lid = this->layers.get_layer_id(std::string(drawing_name));
675    unsigned sid = std::stol(ivi_id);
676
677    if (!lid) {
678        return "Drawing name does not match any role";
679    }
680
681    auto rname = this->lookup_id(drawing_name);
682
683    if (rname) {
684        return "Surface already present";
685    }
686
687    // register pair drawing_name and ivi_id
688    this->id_alloc.register_name_id(drawing_name, sid);
689    this->layers.add_surface(sid, *lid);
690
691    // this surface is already created
692    HMI_DEBUG("wm", "surface_id is %u, layer_id is %u", sid, *lid);
693
694    this->controller->layers[*lid]->add_surface(sid);
695    this->layout_commit();
696
697    return nullptr;
698 }
699
700 void App::activate(int id) {
701    auto ip = this->controller->sprops.find(id);
702    if (ip != this->controller->sprops.end()) {
703       this->controller->surfaces[id]->set_visibility(1);
704       char const *label =
705          this->lookup_name(id).value_or("unknown-name").c_str();
706
707       // FOR CES DEMO >>>
708       if ((0 == strcmp(label, "Radio"))
709           || (0 == strcmp(label, "MediaPlayer"))
710           || (0 == strcmp(label, "Music"))
711           || (0 == strcmp(label, "Navigation"))) {
712         for (auto i = surface_bg.begin(); i != surface_bg.end(); ++i) {
713             if (id == *i) {
714                // Remove id
715                this->surface_bg.erase(i);
716
717                // Remove from BG layer (999)
718                HMI_DEBUG("wm", "Remove %s(%d) from BG layer", label, id);
719                this->controller->layers[999]->remove_surface(id);
720
721                // Add to FG layer (1001)
722                HMI_DEBUG("wm", "Add %s(%d) to FG layer", label, id);
723                this->controller->layers[1001]->add_surface(id);
724
725                for (int j : this->surface_bg) {
726                  HMI_DEBUG("wm", "Stored id:%d", j);
727                }
728                break;
729             }
730          }
731       }
732       // <<< FOR CES DEMO
733
734       this->emit_visible(label);
735       this->emit_activated(label);
736    }
737 }
738
739 void App::deactivate(int id) {
740    auto ip = this->controller->sprops.find(id);
741    if (ip != this->controller->sprops.end()) {
742       char const *label =
743          this->lookup_name(id).value_or("unknown-name").c_str();
744
745       // FOR CES DEMO >>>
746       if ((0 == strcmp(label, "Radio"))
747           || (0 == strcmp(label, "MediaPlayer"))
748           || (0 == strcmp(label, "Music"))
749           || (0 == strcmp(label, "Navigation"))) {
750
751          // Store id
752          this->surface_bg.push_back(id);
753
754          // Remove from FG layer (1001)
755          HMI_DEBUG("wm", "Remove %s(%d) from FG layer", label, id);
756          this->controller->layers[1001]->remove_surface(id);
757
758          // Add to BG layer (999)
759          HMI_DEBUG("wm", "Add %s(%d) to BG layer", label, id);
760          this->controller->layers[999]->add_surface(id);
761
762          for (int j : surface_bg) {
763             HMI_DEBUG("wm", "Stored id:%d", j);
764          }
765       }
766       else {
767          this->controller->surfaces[id]->set_visibility(0);
768       }
769       // <<< FOR CES DEMO
770
771       this->emit_deactivated(label);
772       this->emit_invisible(label);
773    }
774 }
775
776 void App::deactivate_main_surface() {
777    this->layers.main_surface = -1;
778    this->api_deactivate_surface(this->layers.main_surface_name.c_str());
779 }
780
781 bool App::can_split(struct LayoutState const &state, int new_id) {
782    if (state.main != -1 && state.main != new_id) {
783       auto new_id_layer = this->layers.get_layer_id(new_id).value();
784       auto current_id_layer = this->layers.get_layer_id(state.main).value();
785
786       // surfaces are on separate layers, don't bother.
787       if (new_id_layer != current_id_layer) {
788          return false;
789       }
790
791       std::string const &new_id_str = this->lookup_name(new_id).value();
792       std::string const &cur_id_str = this->lookup_name(state.main).value();
793
794       auto const &layer = this->layers.get_layer(new_id_layer);
795
796       HMI_DEBUG("wm", "layer info name: %s", layer->name.c_str());
797
798       if (layer->layouts.empty()) {
799          return false;
800       }
801
802       for (auto i = layer->layouts.cbegin(); i != layer->layouts.cend(); i++) {
803          HMI_DEBUG("wm", "%d main_match '%s'", new_id_layer, i->main_match.c_str());
804          auto rem = std::regex(i->main_match);
805          if (std::regex_match(cur_id_str, rem)) {
806             // build the second one only if the first already matched
807             HMI_DEBUG("wm", "%d sub_match '%s'", new_id_layer, i->sub_match.c_str());
808             auto res = std::regex(i->sub_match);
809             if (std::regex_match(new_id_str, res)) {
810                HMI_DEBUG("wm", "layout matched!");
811                return true;
812             }
813          }
814       }
815    }
816
817    return false;
818 }
819
820 void App::try_layout(struct LayoutState & /*state*/,
821                      struct LayoutState const &new_layout,
822                      std::function<void(LayoutState const &nl)> apply) {
823    if (this->policy.layout_is_valid(new_layout)) {
824       apply(new_layout);
825    }
826 }
827
828 /**
829  * controller_hooks
830  */
831 void controller_hooks::surface_created(uint32_t surface_id) {
832    this->app->surface_created(surface_id);
833 }
834
835 void controller_hooks::surface_removed(uint32_t surface_id) {
836    this->app->surface_removed(surface_id);
837 }
838
839 void controller_hooks::surface_visibility(uint32_t /*surface_id*/,
840                                           uint32_t /*v*/) {}
841
842 void controller_hooks::surface_destination_rectangle(uint32_t /*surface_id*/,
843                                                      uint32_t /*x*/,
844                                                      uint32_t /*y*/,
845                                                      uint32_t /*w*/,
846                                                      uint32_t /*h*/) {}
847
848 }  // namespace wm