Refactor : Hide wayland operations from Window Manager
[apps/agl-service-windowmanager.git] / src / main.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 <unistd.h>
18 #include <algorithm>
19 #include <mutex>
20 #include <json.h>
21 #include "window_manager.hpp"
22 #include "json_helper.hpp"
23
24 extern "C"
25 {
26 #include <afb/afb-binding.h>
27 #include <systemd/sd-event.h>
28 }
29
30 typedef struct WMClientCtxt
31 {
32     std::string name;
33     std::string role;
34     WMClientCtxt(const char *appName, const char* appRole)
35     {
36         name = appName;
37         role = appRole;
38     }
39 } WMClientCtxt;
40
41 struct afb_instance
42 {
43     wm::WindowManager wmgr;
44
45     afb_instance() : wmgr() {}
46     ~afb_instance() = default;
47
48     int init();
49 };
50
51 struct afb_instance *g_afb_instance;
52 std::mutex binding_m;
53
54 int afb_instance::init()
55 {
56     return this->wmgr.init();
57 }
58
59 int _binding_init()
60 {
61     HMI_NOTICE("WinMan ver. %s", WINMAN_VERSION_STRING);
62
63     g_afb_instance = new afb_instance;
64
65     if (g_afb_instance->init() == -1)
66     {
67         HMI_ERROR("Could not connect to compositor");
68         goto error;
69     }
70
71     atexit([] { delete g_afb_instance; });
72
73     return 0;
74
75 error:
76     delete g_afb_instance;
77     g_afb_instance = nullptr;
78     return -1;
79 }
80
81 int binding_init() noexcept
82 {
83     try
84     {
85         return _binding_init();
86     }
87     catch (std::exception &e)
88     {
89         HMI_ERROR("Uncaught exception in binding_init(): %s", e.what());
90     }
91     return -1;
92 }
93
94 static void cbRemoveClientCtxt(void *data)
95 {
96     WMClientCtxt *ctxt = (WMClientCtxt *)data;
97     if (ctxt == nullptr)
98     {
99         return;
100     }
101     HMI_DEBUG("remove app %s", ctxt->name.c_str());
102
103     // Policy Manager does not know this app was killed,
104     // so notify it by deactivate request.
105     g_afb_instance->wmgr.api_deactivate_surface(
106         ctxt->name.c_str(), ctxt->role.c_str(),
107         [](const char *) {});
108
109     g_afb_instance->wmgr.removeClient(ctxt->name);
110     delete ctxt;
111 }
112
113 static void createSecurityContext(afb_req req, const char* appid, const char* role)
114 {
115     WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
116     if (!ctxt)
117     {
118         // Create Security Context at first time
119         const char *new_role = g_afb_instance->wmgr.convertRoleOldToNew(role);
120         WMClientCtxt *ctxt = new WMClientCtxt(appid, new_role);
121         HMI_DEBUG("create session for %s", ctxt->name.c_str());
122         afb_req_session_set_LOA(req, 1);
123         afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
124     }
125 }
126
127 void windowmanager_requestsurface(afb_req req) noexcept
128 {
129     std::lock_guard<std::mutex> guard(binding_m);
130     if (g_afb_instance == nullptr)
131     {
132         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
133         return;
134     }
135
136     try
137     {
138         const char *a_drawing_name = afb_req_value(req, "drawing_name");
139         if (!a_drawing_name)
140         {
141             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
142             return;
143         }
144
145         char *appid = afb_req_get_application_id(req);
146         if(appid)
147         {
148             auto ret = g_afb_instance->wmgr.api_request_surface(
149                 appid, a_drawing_name);
150             if (ret.is_err())
151             {
152                 afb_req_fail(req, "failed", ret.unwrap_err());
153             }
154             else
155             {
156                 createSecurityContext(req, appid, a_drawing_name);
157                 afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
158             }
159             free(appid);
160         }
161         else
162         {
163             afb_req_fail(req, "failed", nullptr);
164         }
165     }
166     catch (std::exception &e)
167     {
168         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
169         return;
170     }
171 }
172
173 void windowmanager_requestsurfacexdg(afb_req req) noexcept
174 {
175     std::lock_guard<std::mutex> guard(binding_m);
176     if (g_afb_instance == nullptr)
177     {
178         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
179         return;
180     }
181
182     try
183     {
184         json_object *jreq = afb_req_json(req);
185
186         json_object *j_drawing_name = nullptr;
187         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
188         {
189             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
190             return;
191         }
192         char const *a_drawing_name = json_object_get_string(j_drawing_name);
193
194         json_object *j_ivi_id = nullptr;
195         if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
196         {
197             afb_req_fail(req, "failed", "Need char const* argument ivi_id");
198             return;
199         }
200         char const *a_ivi_id = json_object_get_string(j_ivi_id);
201         char *appid = afb_req_get_application_id(req);
202         if(appid)
203         {
204             auto ret = g_afb_instance->wmgr.api_request_surface(
205                 appid, a_drawing_name, a_ivi_id);
206
207             if (ret != nullptr)
208             {
209                 afb_req_fail(req, "failed", ret);
210             }
211             else
212             {
213                 createSecurityContext(req, appid, a_drawing_name);
214                 afb_req_success(req, NULL, "success");
215             }
216             free(appid);
217         }
218     }
219     catch (std::exception &e)
220     {
221         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
222         return;
223     }
224 }
225
226 void windowmanager_activatewindow(afb_req req) noexcept
227 {
228     std::lock_guard<std::mutex> guard(binding_m);
229     if (g_afb_instance == nullptr)
230     {
231         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
232         return;
233     }
234
235     try
236     {
237         const char *a_drawing_name = afb_req_value(req, "drawing_name");
238         if (!a_drawing_name)
239         {
240             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
241             return;
242         }
243
244         const char *a_drawing_area = afb_req_value(req, "drawing_area");
245         if (!a_drawing_area)
246         {
247             afb_req_fail(req, "failed", "Need char const* argument drawing_area");
248             return;
249         }
250
251         char* appid = afb_req_get_application_id(req);
252         if(appid)
253         {
254             g_afb_instance->wmgr.api_activate_surface(
255                 appid, a_drawing_name, a_drawing_area,
256                 [&req](const char *errmsg) {
257                     if (errmsg != nullptr)
258                     {
259                         HMI_ERROR(errmsg);
260                         afb_req_fail(req, "failed", errmsg);
261                         return;
262                     }
263                     afb_req_success(req, NULL, "success");
264                 });
265             free(appid);
266         }
267     }
268     catch (std::exception &e)
269     {
270         HMI_WARNING("failed: Uncaught exception while calling activatesurface: %s", e.what());
271         g_afb_instance->wmgr.exceptionProcessForTransition();
272         return;
273     }
274 }
275
276 void windowmanager_deactivatewindow(afb_req req) noexcept
277 {
278     std::lock_guard<std::mutex> guard(binding_m);
279     if (g_afb_instance == nullptr)
280     {
281         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
282         return;
283     }
284
285     try
286     {
287         const char *a_drawing_name = afb_req_value(req, "drawing_name");
288         if (!a_drawing_name)
289         {
290             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
291             return;
292         }
293
294         char* appid = afb_req_get_application_id(req);
295         if(appid)
296         {
297             g_afb_instance->wmgr.api_deactivate_surface(
298                 appid, a_drawing_name,
299                 [&req](const char *errmsg) {
300                     if (errmsg != nullptr)
301                     {
302                         HMI_ERROR(errmsg);
303                         afb_req_fail(req, "failed", errmsg);
304                         return;
305                     }
306                     afb_req_success(req, NULL, "success");
307                 });
308             free(appid);
309         }
310     }
311     catch (std::exception &e)
312     {
313         HMI_WARNING("failed: Uncaught exception while calling deactivatesurface: %s", e.what());
314         g_afb_instance->wmgr.exceptionProcessForTransition();
315         return;
316     }
317 }
318
319 void windowmanager_enddraw(afb_req req) noexcept
320 {
321     std::lock_guard<std::mutex> guard(binding_m);
322     if (g_afb_instance == nullptr)
323     {
324         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
325         return;
326     }
327
328     try
329     {
330         const char *a_drawing_name = afb_req_value(req, "drawing_name");
331         if (!a_drawing_name)
332         {
333             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
334             return;
335         }
336         afb_req_success(req, NULL, "success");
337
338         char* appid = afb_req_get_application_id(req);
339         if(appid)
340         {
341             g_afb_instance->wmgr.api_enddraw(appid, a_drawing_name);
342             free(appid);
343         }
344     }
345     catch (std::exception &e)
346     {
347         HMI_WARNING("failed: Uncaught exception while calling enddraw: %s", e.what());
348         g_afb_instance->wmgr.exceptionProcessForTransition();
349         return;
350     }
351 }
352
353 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
354 {
355     std::lock_guard<std::mutex> guard(binding_m);
356     if (g_afb_instance == nullptr)
357     {
358         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
359         return;
360     }
361
362     try
363     {
364         auto ret = g_afb_instance->wmgr.api_get_display_info();
365         if (ret.is_err())
366         {
367             afb_req_fail(req, "failed", ret.unwrap_err());
368             return;
369         }
370
371         afb_req_success(req, ret.unwrap(), "success");
372     }
373     catch (std::exception &e)
374     {
375         afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
376         return;
377     }
378 }
379
380 void windowmanager_getareainfo_thunk(afb_req req) noexcept
381 {
382     std::lock_guard<std::mutex> guard(binding_m);
383     if (g_afb_instance == nullptr)
384     {
385         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
386         return;
387     }
388
389     try
390     {
391         json_object *jreq = afb_req_json(req);
392
393         json_object *j_drawing_name = nullptr;
394         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
395         {
396             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
397             return;
398         }
399         char const *a_drawing_name = json_object_get_string(j_drawing_name);
400
401         auto ret = g_afb_instance->wmgr.api_get_area_info(a_drawing_name);
402         if (ret.is_err())
403         {
404             afb_req_fail(req, "failed", ret.unwrap_err());
405             return;
406         }
407
408         afb_req_success(req, ret.unwrap(), "success");
409     }
410     catch (std::exception &e)
411     {
412         afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
413         return;
414     }
415 }
416
417 void windowmanager_wm_subscribe(afb_req req) noexcept
418 {
419     std::lock_guard<std::mutex> guard(binding_m);
420     if (g_afb_instance == nullptr)
421     {
422         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
423         return;
424     }
425
426     try
427     {
428         json_object *jreq = afb_req_json(req);
429         json_object *j = nullptr;
430         if (!json_object_object_get_ex(jreq, "event", &j))
431         {
432             afb_req_fail(req, "failed", "Need char const* argument event");
433             return;
434         }
435         int event_id = json_object_get_int(j);
436         int ret = g_afb_instance->wmgr.api_subscribe(req, event_id);
437
438         if (ret)
439         {
440             afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
441             return;
442         }
443         afb_req_success(req, NULL, "success");
444     }
445     catch (std::exception &e)
446     {
447         afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
448         return;
449     }
450 }
451
452 void windowmanager_list_drawing_names(afb_req req) noexcept
453 {
454     /* std::lock_guard<std::mutex> guard(binding_m);
455
456     if (g_afb_instance == nullptr)
457     {
458         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
459         return;
460     }
461
462     try
463     {
464
465         nlohmann::json j = g_afb_instance->wmgr.id_alloc.name2id;
466         auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
467         if (ret.is_err())
468         {
469             afb_req_fail(req, "failed", ret.unwrap_err());
470             return;
471         }
472
473         afb_req_success(req, ret.unwrap(), "success");
474     }
475     catch (std::exception &e)
476     {
477         afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
478         return;
479     } */
480     afb_req_success(req, NULL, "not-implemented");
481 }
482
483 void windowmanager_ping(afb_req req) noexcept
484 {
485     std::lock_guard<std::mutex> guard(binding_m);
486
487     if (g_afb_instance == nullptr)
488     {
489         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
490         return;
491     }
492     else
493     {
494         afb_req_success(req, NULL, "success");
495     }
496 }
497
498 void windowmanager_debug_status(afb_req req) noexcept
499 {
500     std::lock_guard<std::mutex> guard(binding_m);
501
502     /* if (g_afb_instance == nullptr)
503     {
504         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
505         return;
506     }
507
508     try
509     {
510
511         json_object *jr = json_object_new_object();
512         json_object_object_add(jr, "surfaces",
513                                to_json(g_afb_instance->wmgr.controller->sprops));
514         json_object_object_add(jr, "layers", to_json(g_afb_instance->wmgr.controller->lprops));
515
516         afb_req_success(req, jr, "success");
517     }
518     catch (std::exception &e)
519     {
520         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
521         return;
522     } */
523     afb_req_fail(req, NULL, "not-implemented");
524 }
525
526 void windowmanager_debug_layers(afb_req req) noexcept
527 {
528     /* std::lock_guard<std::mutex> guard(binding_m);
529
530     if (g_afb_instance == nullptr)
531     {
532         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
533         return;
534     }
535
536     try
537     {
538         auto ret = wm::Ok(json_tokener_parse(g_afb_instance->wmgr.layers.to_json().dump().c_str()));
539
540         afb_req_success(req, ret, "success");
541     }
542     catch (std::exception &e)
543     {
544         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
545         return;
546     } */
547     afb_req_fail(req, NULL, "not-implemented");
548 }
549
550 void windowmanager_debug_surfaces(afb_req req) noexcept
551 {
552     /* std::lock_guard<std::mutex> guard(binding_m);
553
554     if (g_afb_instance == nullptr)
555     {
556         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
557         return;
558     }
559
560     try
561     {
562
563         auto ret = wm::Ok(to_json(g_afb_instance->wmgr.controller->sprops));
564         if (ret.is_err())
565         {
566             afb_req_fail(req, "failed", ret.unwrap_err());
567             return;
568         }
569
570         afb_req_success(req, ret.unwrap(), "success");
571     }
572     catch (std::exception &e)
573     {
574         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
575         return;
576     } */
577     afb_req_fail(req, NULL, "not-implemented");
578 }
579
580 void windowmanager_debug_terminate(afb_req req) noexcept
581 {
582     std::lock_guard<std::mutex> guard(binding_m);
583     if (g_afb_instance == nullptr)
584     {
585         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
586         return;
587     }
588
589     try
590     {
591
592         if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
593         {
594             raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
595                             // doesn't play well with perf
596         }
597
598         afb_req_success(req, NULL, "success");
599     }
600     catch (std::exception &e)
601     {
602         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
603         return;
604     }
605 }
606
607 const struct afb_verb_v2 windowmanager_verbs[] = {
608     {"requestSurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
609     {"requestSurfaceXDG", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
610     {"activateWindow", windowmanager_activatewindow, nullptr, nullptr, AFB_SESSION_NONE},
611     {"deactivateWindow", windowmanager_deactivatewindow, nullptr, nullptr, AFB_SESSION_NONE},
612     {"endDraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE},
613     {"getDisplayInfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
614     {"getAreaInfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
615     {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
616     {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
617     {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
618     {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
619     {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
620     {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
621     {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
622     {}};
623
624 extern "C" const struct afb_binding_v2 afbBindingV2 = {
625     "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};