Fix internal function name for consistency
[apps/agl-service-windowmanager.git] / src / wm_layer_control.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 #include <assert.h>
17 #include <unistd.h>
18 #include "wm_layer_control.hpp"
19 #include "wm_layer.hpp"
20 #include "wm_client.hpp"
21 #include "request.hpp"
22 #include "json_helper.hpp"
23
24 #define LC_AREA_PATH "/etc/areas.db"
25 #define LC_LAYER_SETTING_PATH "/etc/layers.json"
26 #define LC_DEFAULT_AREA "fullscreen"
27 #define BACK_GROUND_LAYER "BackGroundLayer"
28
29 using std::string;
30 using std::vector;
31 using std::shared_ptr;
32
33 namespace wm {
34
35 LayerControl* g_lc_ctxt;
36
37 static void createCallback_static(ilmObjectType object,
38                             t_ilm_uint id,
39                             t_ilm_bool created,
40                             void* data)
41 {
42     static_cast<LayerControl*>(data)->dispatchCreateEvent(object, id, created);
43 }
44
45 static void surfaceCallback_static(t_ilm_surface surface,
46             struct ilmSurfaceProperties* surface_prop,
47             t_ilm_notification_mask mask)
48 {
49     g_lc_ctxt->dispatchSurfacePropChangeEvent(surface, surface_prop, mask);
50 }
51
52 static void layerCallback_static(t_ilm_layer layer,
53             struct ilmLayerProperties* layer_prop,
54             t_ilm_notification_mask mask)
55 {
56     g_lc_ctxt->dispatchLayerPropChangeEvent(layer, layer_prop, mask);
57 }
58
59 LayerControl::LayerControl(const std::string& root)
60 {
61     string area_path = root + LC_AREA_PATH;
62     string layer_path= root + LC_LAYER_SETTING_PATH;
63     // load layers.setting.json
64     WMError ret = this->loadLayerSetting(layer_path);
65     assert(ret == WMError::SUCCESS);
66     // load areas.json
67     ret = this->loadAreaDb(area_path);
68     assert(ret == WMError::SUCCESS);
69 }
70
71 WMError LayerControl::init(const LayerControlCallbacks& cb)
72 {
73     HMI_DEBUG("Initialize of ilm library and display");
74     t_ilm_uint num = 0;
75     t_ilm_uint *ids;
76     int cnt = 0;
77     ilmErrorTypes rc = ilm_init();
78
79     while (rc != ILM_SUCCESS)
80     {
81         cnt++;
82         if (20 <= cnt)
83         {
84             HMI_ERROR("Could not connect to compositor");
85             goto lc_init_error;
86         }
87         HMI_ERROR("Wait to start weston ...");
88         sleep(1);
89         rc = ilm_init();
90     }
91     if(rc != ILM_SUCCESS) goto lc_init_error;
92
93     // Get current screen setting
94     rc = ilm_getScreenIDs(&num, &ids);
95
96     if(rc != ILM_SUCCESS) goto lc_init_error;
97
98     for(unsigned i = 0; i < num; i++)
99     {
100         HMI_INFO("get screen: %d", ids[i]);
101     }
102     // Currently, 0 is only available
103     this->screenID = ids[0];
104
105     rc = ilm_getPropertiesOfScreen(this->screenID, &this->screen_prop);
106
107     if(rc != ILM_SUCCESS) goto lc_init_error;
108
109     // Register Callback to Window Manager and from ILM
110     this->cb = cb;
111     ilm_registerNotification(createCallback_static, this);
112
113     return WMError::SUCCESS;
114
115 lc_init_error:
116     HMI_ERROR("Failed to initialize. Terminate WM");
117
118     return WMError::FAIL;
119 }
120
121 unsigned LayerControl::getLayerID(const string& role)
122 {
123     unsigned ret = 0;
124     for(const auto& l: this->wm_layers)
125     {
126         if(l->hasRole(role))
127         {
128             ret = l->layerID();
129         }
130     }
131     return ret;
132 }
133
134 void LayerControl::addSurface(unsigned surface, unsigned layer)
135 {
136     ilm_layerAddSurface(layer, surface);
137     ilm_commitChanges();
138 }
139
140 void LayerControl::createLayers()
141 {
142     for(const auto &layer : this->wm_layers)
143     {
144         unsigned id = layer->layerID();
145         HMI_INFO("create new ID :%d", id);
146         struct rect rct = this->area2size[LC_DEFAULT_AREA];
147         ilm_layerCreateWithDimension(&id, rct.w, rct.h);
148         //ilm_layerSetSourceRectangle(id, rct.x, rct.y, rct.w, rct.h);
149         ilm_layerSetDestinationRectangle(id, this->offset_x, this->offset_y, rct.w, rct.h);
150         ilm_layerSetOpacity(id, 1.0);
151         ilm_layerSetVisibility(id, ILM_TRUE);
152         ilm_commitChanges();
153         /* auto wm_layer = getWMLayer(id);
154         wm_layer->addLayerToState(id); */
155     }
156     this->renderLayers();
157 }
158
159 shared_ptr<WMLayer> LayerControl::getWMLayer(unsigned layer)
160 {
161     unsigned uuid = this->lid2wmlid[layer];
162     return this->wm_layers[uuid];
163 }
164
165 std::shared_ptr<WMLayer> LayerControl::getWMLayer(std::string layer_name)
166 {
167     for(auto &l : this->wm_layers)
168     {
169         if(l->layerName() == layer_name)
170         {
171             return l;
172         }
173     }
174     return nullptr;
175 }
176
177 struct rect LayerControl::getAreaSize(const std::string& area)
178 {
179     return area2size[area];
180 }
181
182 void LayerControl::setupArea(const rectangle& base_rct, double scaling)
183 {
184     this->scaling = scaling;
185     this->offset_x = base_rct.left();
186     this->offset_y = base_rct.top();
187
188     for (auto &i : this->area2size)
189     {
190         i.second.x = static_cast<int>(scaling * i.second.x + 0.5);
191         i.second.y = static_cast<int>(scaling * i.second.y + 0.5);
192         i.second.w = static_cast<int>(scaling * i.second.w + 0.5);
193         i.second.h = static_cast<int>(scaling * i.second.h + 0.5);
194
195         HMI_DEBUG("area:%s size(after) : x:%d y:%d w:%d h:%d",
196             i.first.c_str(), i.second.x, i.second.y, i.second.w, i.second.h);
197     }
198 }
199
200 Screen LayerControl::getScreenInfo()
201 {
202     return Screen(this->screen_prop.screenWidth, this->screen_prop.screenHeight);
203 }
204
205 double LayerControl::scale()
206 {
207     return this->scaling;
208 }
209
210 WMError LayerControl::renderLayers()
211 {
212     HMI_INFO("Commit change");
213     WMError rc = WMError::SUCCESS;
214
215     // Create render order
216     t_ilm_layer* id_array = new t_ilm_layer[this->wm_layers.size()];
217     if(id_array == nullptr)
218     {
219         HMI_WARNING("short memory");
220         return WMError::FAIL;
221     }
222     int count = 0;
223     for(const auto& i : this->wm_layers)
224     {
225         id_array[count] = i->layerID();
226         ++count;
227     }
228
229     // Display
230     ilmErrorTypes ret = ilm_displaySetRenderOrder(this->screenID, id_array, this->wm_layers.size());
231     if(ret != ILM_SUCCESS)
232     {
233         rc = WMError::FAIL;
234     }
235     ilm_commitChanges();
236     delete id_array;
237     return rc;
238 }
239
240 WMError LayerControl::setXDGSurfaceOriginSize(unsigned surface)
241 {
242     WMError ret = WMError::NOT_REGISTERED;
243     ilmSurfaceProperties prop;
244     ilmErrorTypes rc = ilm_getPropertiesOfSurface(surface, &prop);
245     if(rc == ILM_SUCCESS)
246     {
247         HMI_INFO("xdg surface info %d, %d", prop.origSourceWidth, prop.origSourceHeight);
248         ilm_surfaceSetSourceRectangle(surface, 0, 0, prop.origSourceWidth, prop.origSourceHeight);
249         ret = WMError::SUCCESS;
250     }
251     return ret;
252 }
253
254 WMError LayerControl::loadLayerSetting(const string &path)
255 {
256     HMI_DEBUG("loading WMLayer(Application Containers) Setting from %s", path);
257
258     json_object *json_obj, *json_cfg;
259     int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
260     if (0 > ret)
261     {
262         HMI_ERROR("Could not open %s", path.c_str());
263         return WMError::FAIL;
264     }
265     HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj));
266
267     if (!json_object_object_get_ex(json_obj, "mappings", &json_cfg))
268     {
269         HMI_ERROR("Parse Error!!");
270         return WMError::FAIL;
271     }
272
273     int len = json_object_array_length(json_cfg);
274     HMI_DEBUG("json_cfg len:%d", len);
275
276     for (int i = 0; i < len; i++)
277     {
278         json_object *json_tmp = json_object_array_get_idx(json_cfg, i);
279         HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp));
280
281         this->wm_layers.emplace_back(std::make_shared<WMLayer>(json_tmp));
282     }
283     json_object_put(json_obj);
284
285     return WMError::SUCCESS;
286 }
287
288 WMError LayerControl::loadAreaDb(const std::string& path)
289 {
290     // Load area.db
291     json_object *json_obj;
292     int ret = jh::inputJsonFilie(path.c_str(), &json_obj);
293     if (0 > ret)
294     {
295         HMI_ERROR("Could not open %s", path.c_str());
296         return WMError::FAIL;
297     }
298     HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj));
299
300     // Perse areas
301     json_object *json_cfg;
302     if (!json_object_object_get_ex(json_obj, "areas", &json_cfg))
303     {
304         HMI_ERROR("Parse Error!!");
305         return WMError::FAIL;
306     }
307
308     int len = json_object_array_length(json_cfg);
309     HMI_DEBUG("json_cfg len:%d", len);
310
311     const char *area;
312     for (int i = 0; i < len; i++)
313     {
314         json_object *json_tmp = json_object_array_get_idx(json_cfg, i);
315         HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp));
316
317         area = jh::getStringFromJson(json_tmp, "name");
318         if (nullptr == area)
319         {
320             HMI_ERROR("Parse Error!!");
321             return WMError::FAIL;
322         }
323         HMI_DEBUG("> area:%s", area);
324
325         json_object *json_rect;
326         if (!json_object_object_get_ex(json_tmp, "rect", &json_rect))
327         {
328             HMI_ERROR("Parse Error!!");
329             return WMError::FAIL;
330         }
331         HMI_DEBUG("> json_rect dump:%s", json_object_get_string(json_rect));
332
333         struct rect area_size;
334         area_size.x = jh::getIntFromJson(json_rect, "x");
335         area_size.y = jh::getIntFromJson(json_rect, "y");
336         area_size.w = jh::getIntFromJson(json_rect, "w");
337         area_size.h = jh::getIntFromJson(json_rect, "h");
338
339         this->area2size[area] = area_size;
340     }
341
342     // Check
343     for (const auto& itr : this->area2size)
344     {
345         HMI_DEBUG("area:%s x:%d y:%d w:%d h:%d",
346                   itr.first.c_str(), itr.second.x, itr.second.y,
347                   itr.second.w, itr.second.h);
348     }
349
350     // Release json_object
351     json_object_put(json_obj);
352
353     return WMError::SUCCESS;
354 }
355
356 WMError LayerControl::layoutChange(const WMAction& action)
357 {
358     if (action.visible == TaskVisible::INVISIBLE)
359     {
360         // Visibility is not change -> no redraw is required
361         return WMError::SUCCESS;
362     }
363     if(action.client == nullptr)
364     {
365         HMI_SEQ_ERROR(action.req_num, "client may vanish");
366         return WMError::NOT_REGISTERED;
367     }
368     unsigned surface = action.client->surfaceID(action.role);
369
370     auto rect = this->getAreaSize(action.area);
371     HMI_DEBUG("Set layout %d, %d, %d, %d",rect.x, rect.y, rect.w, rect.h);
372     ilm_commitChanges();
373     ilm_surfaceSetDestinationRectangle(surface, rect.x, rect.y, rect.w, rect.h);
374     ilm_commitChanges();
375
376     return WMError::SUCCESS;
377 }
378
379 WMError LayerControl::visibilityChange(const WMAction& action)
380 {
381     WMError ret = WMError::FAIL;
382     if(action.client == nullptr)
383     {
384         HMI_SEQ_ERROR(action.req_num, "client may vanish");
385         return WMError::NOT_REGISTERED;
386     }
387
388     if (action.visible == TaskVisible::VISIBLE)
389     {
390         ret = this->makeVisible(action.client, action.role);
391     }
392     else if (action.visible == TaskVisible::INVISIBLE)
393     {
394         ret = this->makeInvisible(action.client, action.role);
395     }
396     ilm_commitChanges();
397     return ret;
398 }
399
400 void LayerControl::dispatchCreateEvent(ilmObjectType object, unsigned id, bool created)
401 {
402     if (ILM_SURFACE == object)
403     {
404         if (created)
405         {
406             ilmSurfaceProperties sp;
407             ilmErrorTypes rc;
408             rc = ilm_getPropertiesOfSurface(id, &sp);
409             if(rc != ILM_SUCCESS)
410             {
411                 HMI_ERROR("Failed to get surface %d property due to %d", id, ilm_getError());
412                 return;
413             }
414             this->cb.surfaceCreated(sp.creatorPid, id);
415             ilm_surfaceAddNotification(id, surfaceCallback_static);
416             ilm_surfaceSetType(id, ILM_SURFACETYPE_DESKTOP);
417         }
418         else
419         {
420             this->cb.surfaceDestroyed(id);
421         }
422     }
423     if (ILM_LAYER == object)
424     {
425         if(created)
426         {
427             ilm_layerAddNotification(id, layerCallback_static);
428         }
429         else
430         {
431             // Ignore here. Nothing to do currently.
432             // Process of application dead is handled by Window Manager
433             // from binder notification
434         }
435     }
436 }
437
438 void LayerControl::dispatchSurfacePropChangeEvent(unsigned id,
439         struct ilmSurfaceProperties* sprop,
440         t_ilm_notification_mask mask)
441 {
442     /*
443       ILM_NOTIFICATION_CONTENT_AVAILABLE & ILM_NOTIFICATION_CONTENT_REMOVED
444       are not handled here, handled in create/destroy event
445      */
446     if (ILM_NOTIFICATION_VISIBILITY & mask)
447     {
448         HMI_DEBUG("surface %d turns visibility %d", id, sprop->visibility);
449     }
450     if (ILM_NOTIFICATION_OPACITY & mask)
451     {
452         HMI_DEBUG("surface %d turns opacity %f", id, sprop->opacity);
453     }
454     if (ILM_NOTIFICATION_SOURCE_RECT & mask)
455     {
456         HMI_DEBUG("surface %d source rect changes", id);
457     }
458     if (ILM_NOTIFICATION_DEST_RECT & mask)
459     {
460         HMI_DEBUG("surface %d dest rect changes", id);
461     }
462     if (ILM_NOTIFICATION_CONFIGURED & mask)
463     {
464         HMI_DEBUG("surface %d size %d, %d, %d, %d", id,
465             sprop->sourceX, sprop->sourceY, sprop->origSourceWidth, sprop->origSourceHeight);
466         ilm_surfaceSetSourceRectangle(id, 0, 0, sprop->origSourceWidth, sprop->origSourceHeight);
467     }
468 }
469
470 void LayerControl::dispatchLayerPropChangeEvent(unsigned id,
471         struct ilmLayerProperties* lprop,
472         t_ilm_notification_mask mask)
473 {
474     if (ILM_NOTIFICATION_VISIBILITY & mask)
475     {
476         HMI_DEBUG("layer %d turns visibility %d", id, lprop->visibility);
477     }
478     if (ILM_NOTIFICATION_OPACITY & mask)
479     {
480         HMI_DEBUG("layer %d turns opacity %f", id, lprop->opacity);
481     }
482     if (ILM_NOTIFICATION_SOURCE_RECT & mask)
483     {
484         HMI_DEBUG("layer %d source rect changes", id);
485     }
486     if (ILM_NOTIFICATION_DEST_RECT & mask)
487     {
488         HMI_DEBUG("layer %d dest rect changes", id);
489     }
490 }
491
492 WMError LayerControl::makeVisible(const shared_ptr<WMClient> client, const string& role)
493 {
494     WMError ret = WMError::SUCCESS;
495     // Don't check here the client is not nullptr
496     unsigned surface = client->surfaceID(role);
497
498     this->moveForeGround(client, role);
499
500     ilm_surfaceSetVisibility(surface, ILM_TRUE);
501
502     return ret;
503 }
504
505 WMError LayerControl::makeInvisible(const shared_ptr<WMClient> client, const string& role)
506 {
507     WMError ret = WMError::SUCCESS;
508     unsigned surface = client->surfaceID(role); // Don't check here the client is not nullptr
509
510     bool mv_ok = this->moveBackGround(client, role);
511
512     if(!mv_ok)
513     {
514         HMI_INFO("make invisible client %s", client->appID().c_str());
515         ilm_surfaceSetVisibility(surface, ILM_FALSE);
516     }
517
518     return ret;
519 }
520
521 bool LayerControl::moveBackGround(const shared_ptr<WMClient> client, const string& role)
522 {
523     bool ret = false;
524     const char* label = role.c_str();
525
526     if ((0 == strcmp(label, "radio")) ||
527         (0 == strcmp(label, "music")) ||
528         (0 == strcmp(label, "video")) ||
529         (0 == strcmp(label, "map")))
530     {
531         unsigned surface = client->surfaceID(role);
532         this->surface_bg.push_back(surface);
533         auto bg = this->getWMLayer(BACK_GROUND_LAYER);
534         auto layer = 0;
535         for(const auto& l : this->wm_layers)
536         {
537             if(l->hasRole(role))
538             {
539                 layer = l->layerID();
540                 ilm_layerRemoveSurface(layer, surface);
541                 ilm_layerAddSurface(bg->layerID(), surface);
542                 ret = true;
543                 break;
544             }
545         }
546     }
547     ilm_commitChanges();
548     return ret;
549 }
550
551 bool LayerControl::moveForeGround(const shared_ptr<WMClient> client, const string& role)
552 {
553     bool ret = false;
554     const char* label = role.c_str();
555
556     // Move foreground from foreground layer
557     if ((0 == strcmp(label, "radio")) ||
558         (0 == strcmp(label, "music")) ||
559         (0 == strcmp(label, "video")) ||
560         (0 == strcmp(label, "map")))
561     {
562         for (auto i = surface_bg.begin(); i != surface_bg.end(); ++i)
563         {
564             if (client->surfaceID(role) == *i)
565             {
566                 // Remove id
567                 unsigned surface = *i;
568
569                 this->surface_bg.erase(i);
570
571                 // Remove from BG layer (999)
572                 HMI_DEBUG("wm", "Remove %s(%d) from BG layer", label, surface);
573                 auto bg = this->getWMLayer(BACK_GROUND_LAYER);
574                 unsigned layer = 0;
575                 for(const auto& l : this->wm_layers)
576                 {
577                     if(l->hasRole(role))
578                     {
579                         layer = l->layerID();
580                         break;
581                     }
582                 }
583                 ilm_layerRemoveSurface(bg->layerID(), surface);
584                 ilm_layerAddSurface(layer, surface);
585                 ret = true;
586                 break;
587             }
588         }
589     }
590     ilm_commitChanges();
591     return ret;
592 }
593
594 } // namespace wm