9ac1ffce3cbb339c1781826ab0f467cd3f19d892
[apps/agl-service-windowmanager.git] / src / wm_layer_control.cpp
1 /*\r
2  * Copyright (c) 2017 TOYOTA MOTOR CORPORATION\r
3  *\r
4  * Licensed under the Apache License, Version 2.0 (the "License");\r
5  * you may not use this file except in compliance with the License.\r
6  * You may obtain a copy of the License at\r
7  *\r
8  *      http://www.apache.org/licenses/LICENSE-2.0\r
9  *\r
10  * Unless required by applicable law or agreed to in writing, software\r
11  * distributed under the License is distributed on an "AS IS" BASIS,\r
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
13  * See the License for the specific language governing permissions and\r
14  * limitations under the License.\r
15  */\r
16 #include <assert.h>\r
17 #include <unistd.h>\r
18 #include "wm_layer_control.hpp"\r
19 #include "wm_layer.hpp"\r
20 #include "wm_client.hpp"\r
21 #include "request.hpp"\r
22 #include "json_helper.hpp"\r
23 \r
24 #define LC_AREA_PATH "/etc/areas.db"\r
25 #define LC_LAYER_SETTING_PATH "/etc/layer_setting.json"\r
26 #define LC_DEFAULT_AREA "normal.full"\r
27 \r
28 using std::string;\r
29 using std::vector;\r
30 using std::shared_ptr;\r
31 \r
32 namespace wm {\r
33 \r
34 LayerControl* g_lc_ctxt;\r
35 \r
36 static void createCallback_static(ilmObjectType object,\r
37                             t_ilm_uint id,\r
38                             t_ilm_bool created,\r
39                             void* data)\r
40 {\r
41     static_cast<LayerControl*>(data)->dispatchCreateEvent(object, id, created);\r
42 }\r
43 \r
44 static void surfaceCallback_static(t_ilm_surface surface,\r
45             struct ilmSurfaceProperties* surface_prop,\r
46             t_ilm_notification_mask mask)\r
47 {\r
48     g_lc_ctxt->dispatchPropertyChangeEvent(surface, surface_prop, mask);\r
49 }\r
50 \r
51 static void layerCallback_static(t_ilm_layer layer,\r
52             struct ilmLayerProperties* layer_prop,\r
53             t_ilm_notification_mask mask)\r
54 {\r
55     g_lc_ctxt->dispatchPropertyChangeEvent(layer, layer_prop, mask);\r
56 }\r
57 \r
58 LayerControl::LayerControl(const std::string& root)\r
59 {\r
60     string area_path = root + LC_AREA_PATH;\r
61     string layer_path= root + LC_LAYER_SETTING_PATH;\r
62     // load layers.setting.json\r
63     WMError ret = this->loadLayerSetting(layer_path);\r
64     assert(ret == WMError::SUCCESS);\r
65     // load area.db\r
66     ret = this->loadAreaDb(area_path);\r
67     assert(ret == WMError::SUCCESS);\r
68 }\r
69 \r
70 WMError LayerControl::init(const LayerControlCallbacks& cb)\r
71 {\r
72     ilmErrorTypes rc = ilm_init();\r
73     t_ilm_uint num = 0;\r
74     t_ilm_uint *ids;\r
75     int cnt = 0;\r
76 \r
77     while (rc != ILM_SUCCESS)\r
78     {\r
79         cnt++;\r
80         if (20 <= cnt)\r
81         {\r
82             HMI_ERROR("Could not connect to compositor");\r
83             goto lc_init_error;\r
84         }\r
85         HMI_ERROR("Wait to start weston ...");\r
86         sleep(1);\r
87         ilm_init();\r
88     }\r
89     if(rc != ILM_SUCCESS) goto lc_init_error;\r
90 \r
91     // Get current screen setting\r
92     rc = ilm_getScreenIDs(&num, &ids);\r
93 \r
94     if(rc != ILM_SUCCESS) goto lc_init_error;\r
95 \r
96     for(unsigned i = 0; i < num; i++)\r
97     {\r
98         HMI_INFO("get screen: %d", ids[i]);\r
99     }\r
100     // Currently, 0 is only available\r
101     this->screenID = ids[0];\r
102 \r
103     rc = ilm_getPropertiesOfScreen(this->screenID, &this->screen_prop);\r
104 \r
105     if(rc != ILM_SUCCESS) goto lc_init_error;\r
106 \r
107     // Register Callback from ILM\r
108     this->cb = cb;\r
109     ilm_registerNotification(createCallback_static, this);\r
110 \r
111     return WMError::SUCCESS;\r
112 \r
113 lc_init_error:\r
114     HMI_ERROR("Failed to initialize. Terminate WM");\r
115 \r
116     return WMError::FAIL;\r
117 }\r
118 \r
119 void LayerControl::createNewLayer(unsigned id)\r
120 {\r
121     HMI_INFO("create new ID :%d", id);\r
122     struct rect rct = this->area2size[LC_DEFAULT_AREA];\r
123     ilm_layerCreateWithDimension(&id, rct.w, rct.h);\r
124     ilm_layerSetSourceRectangle(id, rct.x, rct.y, rct.w, rct.h);\r
125     ilm_layerSetDestinationRectangle(id, rct.x, rct.y, rct.w, rct.h);\r
126     ilm_layerSetOpacity(id, 1.0);\r
127     ilm_layerSetVisibility(id, ILM_TRUE);\r
128     ilm_commitChanges();\r
129 }\r
130 \r
131 unsigned LayerControl::getNewLayerID(const string& role, string* layer_name)\r
132 {\r
133     unsigned ret = 0;\r
134     for(const auto& l: this->wm_layers)\r
135     {\r
136         ret = l->getNewLayerID(role);\r
137         if(ret != 0)\r
138         {\r
139             *layer_name = l->layerName();\r
140             break;\r
141         }\r
142     }\r
143     return ret;\r
144 }\r
145 \r
146 struct rect LayerControl::getAreaSize(const std::string& area)\r
147 {\r
148     return area2size[area];\r
149 }\r
150 \r
151 void LayerControl::setupArea(double scaling)\r
152 {\r
153     struct rect rct;\r
154     this->scaling = scaling;\r
155 \r
156     rct = this->area2size["normal.full"];\r
157     this->area2size["normalfull"] = rct;\r
158     this->area2size["normal"] = rct;\r
159 \r
160     for (auto &i : this->area2size)\r
161     {\r
162         i.second.x = static_cast<int>(scaling * i.second.x + 0.5);\r
163         i.second.y = static_cast<int>(scaling * i.second.y + 0.5);\r
164         i.second.w = static_cast<int>(scaling * i.second.w + 0.5);\r
165         i.second.h = static_cast<int>(scaling * i.second.h + 0.5);\r
166 \r
167         HMI_DEBUG("wm:lm", "area:%s size(after) : x:%d y:%d w:%d h:%d",\r
168             i.first.c_str(), i.second.x, i.second.y, i.second.w, i.second.h);\r
169     }\r
170 }\r
171 \r
172 Screen LayerControl::getScreenInfo()\r
173 {\r
174     return Screen(this->screen_prop.screenWidth, this->screen_prop.screenHeight);\r
175 }\r
176 \r
177 double LayerControl::scale()\r
178 {\r
179     return this->scaling;\r
180 }\r
181 \r
182 WMError LayerControl::updateLayer(LayerState& layer_state)\r
183 {\r
184     return WMError::SUCCESS;\r
185 }\r
186 \r
187 WMError LayerControl::commitChange()\r
188 {\r
189     WMError rc = WMError::SUCCESS;\r
190     vector<unsigned> ivi_l_ids;\r
191     for(const auto& l : this->wm_layers)\r
192     {\r
193         auto state = l->getLayerState();\r
194         for(const auto& id : state.getIviIdList())\r
195         {\r
196             ivi_l_ids.push_back(id);\r
197         }\r
198     }\r
199     t_ilm_layer* id_array = new t_ilm_layer[ivi_l_ids.size()];\r
200     if(id_array == nullptr)\r
201     {\r
202         HMI_WARNING("short memory");\r
203         this->undoUpdate();\r
204         return WMError::FAIL;\r
205     }\r
206     int count = 0;\r
207     for(const auto& i : ivi_l_ids)\r
208     {\r
209         id_array[count] = i;\r
210     }\r
211 \r
212     ilmErrorTypes ret = ilm_displaySetRenderOrder(this->screenID, id_array, ivi_l_ids.size());\r
213     if(ret != ILM_SUCCESS)\r
214     {\r
215         this->undoUpdate();\r
216         rc = WMError::FAIL;\r
217     }\r
218     delete id_array;\r
219     return rc;\r
220 }\r
221 \r
222 void LayerControl::undoUpdate() {}\r
223 \r
224 WMError LayerControl::loadLayerSetting(const string &path)\r
225 {\r
226     HMI_DEBUG("loading WMLayer(Application Containers) Setting from %s", path);\r
227 \r
228     json_object *json_obj, *json_cfg;\r
229     int ret = jh::inputJsonFilie(path.c_str(), &json_obj);\r
230     if (0 > ret)\r
231     {\r
232         HMI_DEBUG("Could not open %s, so use default area information", path.c_str());\r
233         return WMError::FAIL;\r
234     }\r
235     HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj));\r
236 \r
237     if (!json_object_object_get_ex(json_obj, "mappings", &json_cfg))\r
238     {\r
239         HMI_ERROR("Parse Error!!");\r
240         return WMError::FAIL;\r
241     }\r
242 \r
243     int len = json_object_array_length(json_cfg);\r
244     HMI_DEBUG("json_cfg len:%d", len);\r
245 \r
246     for (int i = 0; i < len; i++)\r
247     {\r
248         json_object *json_tmp = json_object_array_get_idx(json_cfg, i);\r
249         HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp));\r
250 \r
251         this->wm_layers.emplace_back(std::make_shared<WMLayer>(json_tmp));\r
252     }\r
253 \r
254     return WMError::SUCCESS;\r
255 }\r
256 \r
257 WMError LayerControl::loadAreaDb(const std::string& path)\r
258 {\r
259     // Load area.db\r
260     json_object *json_obj;\r
261     int ret = jh::inputJsonFilie(path.c_str(), &json_obj);\r
262     if (0 > ret)\r
263     {\r
264         HMI_DEBUG("Could not open %s, so use default area information", path.c_str());\r
265         return WMError::FAIL;\r
266     }\r
267     HMI_INFO("json_obj dump:%s", json_object_get_string(json_obj));\r
268 \r
269     // Perse areas\r
270     json_object *json_cfg;\r
271     if (!json_object_object_get_ex(json_obj, "areas", &json_cfg))\r
272     {\r
273         HMI_ERROR("Parse Error!!");\r
274         return WMError::FAIL;\r
275     }\r
276 \r
277     int len = json_object_array_length(json_cfg);\r
278     HMI_DEBUG("json_cfg len:%d", len);\r
279 \r
280     const char *area;\r
281     for (int i = 0; i < len; i++)\r
282     {\r
283         json_object *json_tmp = json_object_array_get_idx(json_cfg, i);\r
284         HMI_DEBUG("> json_tmp dump:%s", json_object_get_string(json_tmp));\r
285 \r
286         area = jh::getStringFromJson(json_tmp, "name");\r
287         if (nullptr == area)\r
288         {\r
289             HMI_ERROR("Parse Error!!");\r
290             return WMError::FAIL;\r
291         }\r
292         HMI_DEBUG("> area:%s", area);\r
293 \r
294         json_object *json_rect;\r
295         if (!json_object_object_get_ex(json_tmp, "rect", &json_rect))\r
296         {\r
297             HMI_ERROR("Parse Error!!");\r
298             return WMError::FAIL;\r
299         }\r
300         HMI_DEBUG("> json_rect dump:%s", json_object_get_string(json_rect));\r
301 \r
302         struct rect area_size;\r
303         area_size.x = jh::getIntFromJson(json_rect, "x");\r
304         area_size.y = jh::getIntFromJson(json_rect, "y");\r
305         area_size.w = jh::getIntFromJson(json_rect, "w");\r
306         area_size.h = jh::getIntFromJson(json_rect, "h");\r
307 \r
308         this->area2size[area] = area_size;\r
309     }\r
310 \r
311     // Check\r
312     for (const auto& itr : this->area2size)\r
313     {\r
314         HMI_DEBUG("area:%s x:%d y:%d w:%d h:%d",\r
315                   itr.first.c_str(), itr.second.x, itr.second.y,\r
316                   itr.second.w, itr.second.h);\r
317     }\r
318 \r
319     // Release json_object\r
320     json_object_put(json_obj);\r
321 \r
322     return WMError::SUCCESS;\r
323 }\r
324 \r
325 WMError LayerControl::layoutChange(const WMAction& action)\r
326 {\r
327     WMError ret = WMError::FAIL;\r
328     if (action.visible == TaskVisible::INVISIBLE)\r
329     {\r
330         // Visibility is not change -> no redraw is required\r
331         return WMError::SUCCESS;\r
332     }\r
333     if(action.client == nullptr)\r
334     {\r
335         HMI_SEQ_ERROR(action.req_num, "client may vanish");\r
336         return WMError::NOT_REGISTERED;\r
337     }\r
338     unsigned layer = action.client->layerID();\r
339 \r
340     // Layout Manager\r
341     // WMError ret = this->setLayerSize(layer, action.area);\r
342     auto rect = this->getAreaSize(action.area);\r
343     ilmErrorTypes err = ilm_layerSetDestinationRectangle(layer, rect.x, rect.y, rect.w, rect.h);\r
344     if(err == ILM_SUCCESS)\r
345     {\r
346         ret = WMError::SUCCESS;\r
347     }\r
348     return ret;\r
349 }\r
350 \r
351 WMError LayerControl::visibilityChange(const WMAction& action)\r
352 {\r
353     WMError ret = WMError::FAIL;\r
354     if(action.client == nullptr)\r
355     {\r
356         HMI_SEQ_ERROR(action.req_num, "client may vanish");\r
357         return WMError::NOT_REGISTERED;\r
358     }\r
359 \r
360     if (action.visible != TaskVisible::INVISIBLE)\r
361     {\r
362         ret = this->makeVisible(action.client);\r
363     }\r
364     else\r
365     {\r
366         ret = this->makeInvisible(action.client);\r
367     }\r
368     return ret;\r
369 }\r
370 \r
371 void LayerControl::dispatchCreateEvent(ilmObjectType object, unsigned id, bool created)\r
372 {\r
373     this->cb.test(id);\r
374     if (ILM_SURFACE == object)\r
375     {\r
376         if (created)\r
377         {\r
378             ilmSurfaceProperties sp;\r
379             ilmErrorTypes rc;\r
380             rc = ilm_getPropertiesOfSurface(id, &sp);\r
381             if(rc != ILM_SUCCESS)\r
382                 return;\r
383             // this->cb->surfaceCreated(pid, id);\r
384             ilm_surfaceAddNotification(id, surfaceCallback_static);\r
385             ilm_surfaceSetSourceRectangle(id, 0, 0, sp.origSourceWidth, sp.origSourceHeight);\r
386         }\r
387         else\r
388         {\r
389             // this->cb->surfaceDestroyed(id);\r
390         }\r
391     }\r
392     if (ILM_LAYER == object)\r
393     {\r
394         if(created)\r
395         {\r
396             ilm_layerAddNotification(id, layerCallback_static);\r
397             // this->cb->layerCreated(id);\r
398         }\r
399         else\r
400         {\r
401             // this->cb->layerDestroyed(id); // Means Application is dead.\r
402         }\r
403     }\r
404 }\r
405 \r
406 void LayerControl::dispatchPropertyChangeEvent(unsigned id,\r
407         struct ilmSurfaceProperties* sprop,\r
408         t_ilm_notification_mask mask)\r
409 {\r
410     pid_t pid = sprop->creatorPid;\r
411     HMI_DEBUG("pid : %d", pid);\r
412 \r
413     if (ILM_NOTIFICATION_VISIBILITY & mask)\r
414     {\r
415         //this->cb->surfaceVisibilityChanged(id, sprop->visibility);\r
416     }\r
417     if (ILM_NOTIFICATION_OPACITY & mask)\r
418     {\r
419     }\r
420     if (ILM_NOTIFICATION_ORIENTATION & mask)\r
421     {\r
422     }\r
423     if (ILM_NOTIFICATION_SOURCE_RECT & mask)\r
424     {\r
425         // this->cb->surfaceSourceRectChanged(id, )\r
426     }\r
427     if (ILM_NOTIFICATION_DEST_RECT & mask)\r
428     {\r
429         // this->cb->surfaceSourceRectChanged(id, )\r
430     }\r
431     if (ILM_NOTIFICATION_CONTENT_AVAILABLE & mask)\r
432     {\r
433     }\r
434     if (ILM_NOTIFICATION_CONTENT_REMOVED & mask)\r
435     {\r
436         /* application being down */\r
437         // m_appLayers.remove(pid);\r
438     }\r
439     if (ILM_NOTIFICATION_CONFIGURED & mask)\r
440     {\r
441         /* qDebug("ILM_NOTIFICATION_CONFIGURED");\r
442         qDebug("  surfaceProperties %d", surface);\r
443         qDebug("    surfaceProperties.origSourceWidth: %d", surfaceProperties->origSourceWidth);\r
444         qDebug("    surfaceProperties.origSourceHeight: %d", surfaceProperties->origSourceHeight);\r
445 \r
446         if (surface == WINDOWMANAGER_HOMESCREEN_MAIN_SURFACE_ID) {\r
447             addSurfaceToLayer(surface, WINDOWMANAGER_LAYER_HOMESCREEN);\r
448             configureHomeScreenMainSurface(surface, surfaceProperties->origSourceWidth, surfaceProperties->origSourceHeight);\r
449         } else {\r
450             ilmErrorTypes result;\r
451             t_ilm_layer layer = addSurfaceToAppLayer(pid, surface);\r
452 \r
453             if (layer != 0) {\r
454                 configureAppSurface(surface,\r
455                                     surfaceProperties->origSourceWidth,\r
456                                     surfaceProperties->origSourceHeight);\r
457 \r
458                 result = ilm_layerAddSurface(layer, surface);\r
459                 if (result != ILM_SUCCESS) {\r
460                     qDebug("ilm_layerAddSurface(%d,%d) failed.", layer, surface);\r
461                 }\r
462                 ilm_commitChanges();\r
463             }\r
464         }\r
465         updateScreen(); */\r
466     }\r
467 }\r
468 \r
469 void LayerControl::dispatchPropertyChangeEvent(unsigned id,\r
470         struct ilmLayerProperties* lprop,\r
471         t_ilm_notification_mask mask)\r
472 {\r
473     if (ILM_NOTIFICATION_VISIBILITY & mask)\r
474     {\r
475         //this->cb->layerVisibilityChanged(id, sprop->visibility);\r
476     }\r
477     if (ILM_NOTIFICATION_OPACITY & mask)\r
478     {\r
479     }\r
480     if (ILM_NOTIFICATION_ORIENTATION & mask)\r
481     {\r
482     }\r
483     if (ILM_NOTIFICATION_SOURCE_RECT & mask)\r
484     {\r
485         // this->cb->surfaceSourceRectChanged(id, )\r
486     }\r
487     if (ILM_NOTIFICATION_DEST_RECT & mask)\r
488     {\r
489         // this->cb->surfaceSourceRectChanged(id, )\r
490     }\r
491     if (ILM_NOTIFICATION_CONTENT_AVAILABLE & mask)\r
492     {\r
493     }\r
494     if (ILM_NOTIFICATION_CONTENT_REMOVED & mask)\r
495     {\r
496         /* application being down */\r
497         // m_appLayers.remove(pid);\r
498     }\r
499     if (ILM_NOTIFICATION_CONFIGURED & mask)\r
500     {\r
501         /* qDebug("ILM_NOTIFICATION_CONFIGURED");\r
502         qDebug("  surfaceProperties %d", surface);\r
503         qDebug("    surfaceProperties.origSourceWidth: %d", surfaceProperties->origSourceWidth);\r
504         qDebug("    surfaceProperties.origSourceHeight: %d", surfaceProperties->origSourceHeight);\r
505 \r
506         if (surface == WINDOWMANAGER_HOMESCREEN_MAIN_SURFACE_ID) {\r
507             addSurfaceToLayer(surface, WINDOWMANAGER_LAYER_HOMESCREEN);\r
508             configureHomeScreenMainSurface(surface, surfaceProperties->origSourceWidth, surfaceProperties->origSourceHeight);\r
509         } else {\r
510             ilmErrorTypes result;\r
511             t_ilm_layer layer = addSurfaceToAppLayer(pid, surface);\r
512 \r
513             if (layer != 0) {\r
514                 configureAppSurface(surface,\r
515                                     surfaceProperties->origSourceWidth,\r
516                                     surfaceProperties->origSourceHeight);\r
517 \r
518                 result = ilm_layerAddSurface(layer, surface);\r
519                 if (result != ILM_SUCCESS) {\r
520                     qDebug("ilm_layerAddSurface(%d,%d) failed.", layer, surface);\r
521                 }\r
522                 ilm_commitChanges();\r
523             }\r
524         }\r
525         updateScreen(); */\r
526     }\r
527 }\r
528 \r
529 WMError LayerControl::makeVisible(const shared_ptr<WMClient> client)\r
530 {\r
531     WMError ret = WMError::FAIL;\r
532     // Don't check here the client is not nullptr\r
533     unsigned layer = client->layerID();\r
534     bool contains;// = this->checkBackGround(action.client->role());\r
535     if(contains)\r
536     {\r
537         shared_ptr<WMLayer> l;\r
538         // Move background from back ground layer\r
539         for(const auto& wm_layer : this->wm_layers)\r
540         {\r
541             if(wm_layer->layerName() == "BackGroundLayer")\r
542             {\r
543                 //wm_layer.removeLayer(layer);\r
544             }\r
545             else\r
546             {\r
547                 if(wm_layer->checkIDBelongTo(layer))\r
548                 {\r
549                     l = wm_layer;\r
550                 }\r
551             }\r
552         }\r
553         if(l != nullptr)\r
554         {\r
555             // make invisible first\r
556             ilm_layerSetVisibility(layer, 0);\r
557             ilm_commitChanges();\r
558             //l->addLayer(layer);\r
559         }\r
560     }\r
561     for(const auto& wm_layer : this->wm_layers)\r
562     {\r
563         // make visible\r
564         //l->makeVisible(layer);\r
565     }\r
566 \r
567     return ret;\r
568 }\r
569 \r
570 WMError LayerControl::makeInvisible(const shared_ptr<WMClient> client)\r
571 {\r
572     WMError ret = WMError::FAIL;\r
573     // Don't check here the client is not nullptr\r
574     unsigned layer = client->layerID();\r
575     bool contains;// = this->checkBackGround(client->role());\r
576     if(contains)\r
577     {\r
578         // Pop from background\r
579     }\r
580     else\r
581     {\r
582 \r
583     }\r
584     return ret;\r
585 }\r
586 } // namespace wm