Remove unused headers
[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 <json.hpp>
22 #include "app.hpp"
23 #include "result.hpp"
24 #include "json_helper.hpp"
25 #include "util.hpp"
26 #include "wayland_ivi_wm.hpp"
27
28 extern "C"
29 {
30 #include <afb/afb-binding.h>
31 #include <systemd/sd-event.h>
32 }
33
34 typedef struct WMClientCtxt
35 {
36     std::string name;
37     std::string role;
38     WMClientCtxt(const char *appName, const char* appRole)
39     {
40         name = appName;
41         role = appRole;
42     }
43 } WMClientCtxt;
44
45 struct afb_instance
46 {
47     std::unique_ptr<wl::display> display;
48     wm::App app;
49
50     afb_instance() : display{new wl::display}, app{this->display.get()} {}
51
52     int init();
53 };
54
55 struct afb_instance *g_afb_instance;
56 std::mutex binding_m;
57
58 int afb_instance::init()
59 {
60     return this->app.init();
61 }
62
63 int display_event_callback(sd_event_source *evs, int /*fd*/, uint32_t events,
64                            void * /*data*/)
65 {
66     ST();
67
68     if ((events & EPOLLHUP) != 0)
69     {
70         HMI_ERROR("wm", "The compositor hung up, dying now.");
71         delete g_afb_instance;
72         g_afb_instance = nullptr;
73         goto error;
74     }
75
76     if ((events & EPOLLIN) != 0u)
77     {
78         {
79             STN(display_read_events);
80             g_afb_instance->app.display->read_events();
81             g_afb_instance->app.set_pending_events();
82         }
83         {
84             // We want do dispatch pending wayland events from within
85             // the API context
86             STN(winman_ping_api_call);
87             afb_service_call("windowmanager", "ping", json_object_new_object(),
88                              [](void *c, int st, json_object *j) {
89                                  STN(winman_ping_api_call_return);
90                              },
91                              nullptr);
92         }
93     }
94
95     return 0;
96
97 error:
98     sd_event_source_unref(evs);
99     if (getenv("WINMAN_EXIT_ON_HANGUP") != nullptr)
100     {
101         exit(1);
102     }
103     return -1;
104 }
105
106 int _binding_init()
107 {
108     HMI_NOTICE("wm", "WinMan ver. %s", WINMAN_VERSION_STRING);
109
110     if (g_afb_instance != nullptr)
111     {
112         HMI_ERROR("wm", "Wayland context already initialized?");
113         return 0;
114     }
115
116     if (getenv("XDG_RUNTIME_DIR") == nullptr)
117     {
118         HMI_ERROR("wm", "Environment variable XDG_RUNTIME_DIR not set");
119         goto error;
120     }
121
122     {
123         // wait until wayland compositor starts up.
124         int cnt = 0;
125         g_afb_instance = new afb_instance;
126         while (!g_afb_instance->display->ok())
127         {
128             cnt++;
129             if (20 <= cnt)
130             {
131                 HMI_ERROR("wm", "Could not connect to compositor");
132                 goto error;
133             }
134             HMI_ERROR("wm", "Wait to start weston ...");
135             sleep(1);
136             delete g_afb_instance;
137             g_afb_instance = new afb_instance;
138         }
139     }
140
141     if (g_afb_instance->init() == -1)
142     {
143         HMI_ERROR("wm", "Could not connect to compositor");
144         goto error;
145     }
146
147     {
148         int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
149                                   g_afb_instance->display->get_fd(), EPOLLIN,
150                                   display_event_callback, g_afb_instance);
151         if (ret < 0)
152         {
153             HMI_ERROR("wm", "Could not initialize afb_instance event handler: %d", -ret);
154             goto error;
155         }
156     }
157
158     atexit([] { delete g_afb_instance; });
159
160     return 0;
161
162 error:
163     delete g_afb_instance;
164     g_afb_instance = nullptr;
165     return -1;
166 }
167
168 int binding_init() noexcept
169 {
170     try
171     {
172         return _binding_init();
173     }
174     catch (std::exception &e)
175     {
176         HMI_ERROR("wm", "Uncaught exception in binding_init(): %s", e.what());
177     }
178     return -1;
179 }
180
181 static bool checkFirstReq(afb_req req)
182 {
183     WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
184     return (ctxt) ? false : true;
185 }
186
187 static void cbRemoveClientCtxt(void *data)
188 {
189     WMClientCtxt *ctxt = (WMClientCtxt *)data;
190     if (ctxt == nullptr)
191     {
192         return;
193     }
194     HMI_DEBUG("wm", "remove app %s", ctxt->name.c_str());
195     // Lookup surfaceID and remove it because App is dead.
196     auto pSid = g_afb_instance->app.id_alloc.lookup(ctxt->role.c_str());
197     if (pSid)
198     {
199         auto sid = *pSid;
200         auto o_state = *g_afb_instance->app.layers.get_layout_state(sid);
201         if (o_state != nullptr)
202         {
203             if (o_state->main == sid)
204             {
205                 o_state->main = -1;
206             }
207             else if (o_state->sub == sid)
208             {
209                 o_state->sub = -1;
210             }
211         }
212         g_afb_instance->app.id_alloc.remove_id(sid);
213         g_afb_instance->app.layers.remove_surface(sid);
214         g_afb_instance->app.controller->sprops.erase(sid);
215         g_afb_instance->app.controller->surfaces.erase(sid);
216         HMI_DEBUG("wm", "delete surfaceID %d", sid);
217     }
218     g_afb_instance->app.removeClient(ctxt->name);
219     delete ctxt;
220 }
221
222 void windowmanager_requestsurface(afb_req req) noexcept
223 {
224     std::lock_guard<std::mutex> guard(binding_m);
225 #ifdef ST
226     ST();
227 #endif
228     if (g_afb_instance == nullptr)
229     {
230         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
231         return;
232     }
233
234     try
235     {
236         const char *a_drawing_name = afb_req_value(req, "drawing_name");
237         if (!a_drawing_name)
238         {
239             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
240             return;
241         }
242
243         /* Create Security Context */
244         bool isFirstReq = checkFirstReq(req);
245         if (!isFirstReq)
246         {
247             WMClientCtxt *ctxt = (WMClientCtxt *)afb_req_context_get(req);
248             HMI_DEBUG("wm", "You're %s.", ctxt->name.c_str());
249             if (ctxt->name != std::string(a_drawing_name))
250             {
251                 afb_req_fail_f(req, "failed", "Dont request with other name: %s for now", a_drawing_name);
252                 HMI_DEBUG("wm", "Don't request with other name: %s for now", a_drawing_name);
253                 return;
254             }
255         }
256
257         auto ret = g_afb_instance->app.api_request_surface(
258             afb_req_get_application_id(req), a_drawing_name);
259
260         if (isFirstReq)
261         {
262             WMClientCtxt *ctxt = new WMClientCtxt(afb_req_get_application_id(req), a_drawing_name);
263             HMI_DEBUG("wm", "create session for %s", ctxt->name.c_str());
264             afb_req_session_set_LOA(req, 1);
265             afb_req_context_set(req, ctxt, cbRemoveClientCtxt);
266         }
267         else
268         {
269             HMI_DEBUG("wm", "session already created for %s", a_drawing_name);
270         }
271
272         if (ret.is_err())
273         {
274             afb_req_fail(req, "failed", ret.unwrap_err());
275             return;
276         }
277
278         afb_req_success(req, json_object_new_int(ret.unwrap()), "success");
279     }
280     catch (std::exception &e)
281     {
282         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
283         return;
284     }
285 }
286
287 void windowmanager_requestsurfacexdg(afb_req req) noexcept
288 {
289     std::lock_guard<std::mutex> guard(binding_m);
290 #ifdef ST
291     ST();
292 #endif
293     if (g_afb_instance == nullptr)
294     {
295         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
296         return;
297     }
298
299     try
300     {
301         json_object *jreq = afb_req_json(req);
302
303         json_object *j_drawing_name = nullptr;
304         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
305         {
306             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
307             return;
308         }
309         char const *a_drawing_name = json_object_get_string(j_drawing_name);
310
311         json_object *j_ivi_id = nullptr;
312         if (!json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id))
313         {
314             afb_req_fail(req, "failed", "Need char const* argument ivi_id");
315             return;
316         }
317         char const *a_ivi_id = json_object_get_string(j_ivi_id);
318
319         auto ret = g_afb_instance->app.api_request_surface(
320             afb_req_get_application_id(req), a_drawing_name, a_ivi_id);
321         if (ret != nullptr)
322         {
323             afb_req_fail(req, "failed", ret);
324             return;
325         }
326
327         afb_req_success(req, NULL, "success");
328     }
329     catch (std::exception &e)
330     {
331         afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
332         return;
333     }
334 }
335
336 void windowmanager_activatesurface(afb_req req) noexcept
337 {
338     std::lock_guard<std::mutex> guard(binding_m);
339 #ifdef ST
340     ST();
341 #endif
342     if (g_afb_instance == nullptr)
343     {
344         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
345         return;
346     }
347
348     try
349     {
350         const char *a_drawing_name = afb_req_value(req, "drawing_name");
351         if (!a_drawing_name)
352         {
353             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
354             return;
355         }
356
357         const char *a_drawing_area = afb_req_value(req, "drawing_area");
358         if (!a_drawing_area)
359         {
360             afb_req_fail(req, "failed", "Need char const* argument drawing_area");
361             return;
362         }
363
364         g_afb_instance->app.api_activate_surface(
365             afb_req_get_application_id(req),
366             a_drawing_name, a_drawing_area,
367             [&req](const char *errmsg) {
368                 if (errmsg != nullptr)
369                 {
370                     HMI_ERROR("wm", errmsg);
371                     afb_req_fail(req, "failed", errmsg);
372                     return;
373                 }
374                 afb_req_success(req, NULL, "success");
375             });
376     }
377     catch (std::exception &e)
378     {
379         HMI_WARNING("wm", "failed: Uncaught exception while calling activatesurface: %s", e.what());
380         g_afb_instance->app.exeptionProcessForTransition();
381         return;
382     }
383 }
384
385 void windowmanager_deactivatesurface(afb_req req) noexcept
386 {
387     std::lock_guard<std::mutex> guard(binding_m);
388 #ifdef ST
389     ST();
390 #endif
391     if (g_afb_instance == nullptr)
392     {
393         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
394         return;
395     }
396
397     try
398     {
399         const char *a_drawing_name = afb_req_value(req, "drawing_name");
400         if (!a_drawing_name)
401         {
402             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
403             return;
404         }
405
406         g_afb_instance->app.api_deactivate_surface(
407             afb_req_get_application_id(req), a_drawing_name,
408             [&req](const char *errmsg) {
409                 if (errmsg != nullptr)
410                 {
411                     HMI_ERROR("wm", errmsg);
412                     afb_req_fail(req, "failed", errmsg);
413                     return;
414                 }
415                 afb_req_success(req, NULL, "success");
416             });
417     }
418     catch (std::exception &e)
419     {
420         HMI_WARNING("wm", "failed: Uncaught exception while calling deactivatesurface: %s", e.what());
421         g_afb_instance->app.exeptionProcessForTransition();
422         return;
423     }
424 }
425
426 void windowmanager_enddraw(afb_req req) noexcept
427 {
428     std::lock_guard<std::mutex> guard(binding_m);
429 #ifdef ST
430     ST();
431 #endif
432     if (g_afb_instance == nullptr)
433     {
434         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
435         return;
436     }
437
438     try
439     {
440         const char *a_drawing_name = afb_req_value(req, "drawing_name");
441         if (!a_drawing_name)
442         {
443             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
444             return;
445         }
446         afb_req_success(req, NULL, "success");
447
448         g_afb_instance->app.api_enddraw(
449             afb_req_get_application_id(req), a_drawing_name);
450     }
451     catch (std::exception &e)
452     {
453         HMI_WARNING("wm", "failed: Uncaught exception while calling enddraw: %s", e.what());
454         g_afb_instance->app.exeptionProcessForTransition();
455         return;
456     }
457 }
458
459 void windowmanager_getdisplayinfo_thunk(afb_req req) noexcept
460 {
461     std::lock_guard<std::mutex> guard(binding_m);
462 #ifdef ST
463     ST();
464 #endif
465     if (g_afb_instance == nullptr)
466     {
467         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
468         return;
469     }
470
471     try
472     {
473         auto ret = g_afb_instance->app.api_get_display_info();
474         if (ret.is_err())
475         {
476             afb_req_fail(req, "failed", ret.unwrap_err());
477             return;
478         }
479
480         afb_req_success(req, ret.unwrap(), "success");
481     }
482     catch (std::exception &e)
483     {
484         afb_req_fail_f(req, "failed", "Uncaught exception while calling getdisplayinfo: %s", e.what());
485         return;
486     }
487 }
488
489 void windowmanager_getareainfo_thunk(afb_req req) noexcept
490 {
491     std::lock_guard<std::mutex> guard(binding_m);
492 #ifdef ST
493     ST();
494 #endif
495     if (g_afb_instance == nullptr)
496     {
497         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
498         return;
499     }
500
501     try
502     {
503         json_object *jreq = afb_req_json(req);
504
505         json_object *j_drawing_name = nullptr;
506         if (!json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name))
507         {
508             afb_req_fail(req, "failed", "Need char const* argument drawing_name");
509             return;
510         }
511         char const *a_drawing_name = json_object_get_string(j_drawing_name);
512
513         auto ret = g_afb_instance->app.api_get_area_info(a_drawing_name);
514         if (ret.is_err())
515         {
516             afb_req_fail(req, "failed", ret.unwrap_err());
517             return;
518         }
519
520         afb_req_success(req, ret.unwrap(), "success");
521     }
522     catch (std::exception &e)
523     {
524         afb_req_fail_f(req, "failed", "Uncaught exception while calling getareainfo: %s", e.what());
525         return;
526     }
527 }
528
529 void windowmanager_wm_subscribe(afb_req req) noexcept
530 {
531     std::lock_guard<std::mutex> guard(binding_m);
532 #ifdef ST
533     ST();
534 #endif
535     if (g_afb_instance == nullptr)
536     {
537         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
538         return;
539     }
540
541     try
542     {
543         json_object *jreq = afb_req_json(req);
544         json_object *j = nullptr;
545         if (!json_object_object_get_ex(jreq, "event", &j))
546         {
547             afb_req_fail(req, "failed", "Need char const* argument event");
548             return;
549         }
550         int event_type = json_object_get_int(j);
551         const char *event_name = g_afb_instance->app.kListEventName[event_type];
552         struct afb_event event = g_afb_instance->app.map_afb_event[event_name];
553         int ret = afb_req_subscribe(req, event);
554         if (ret)
555         {
556             afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
557             return;
558         }
559         afb_req_success(req, NULL, "success");
560     }
561     catch (std::exception &e)
562     {
563         afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
564         return;
565     }
566 }
567
568 void windowmanager_list_drawing_names(afb_req req) noexcept
569 {
570     std::lock_guard<std::mutex> guard(binding_m);
571 #ifdef ST
572     ST();
573 #endif
574     if (g_afb_instance == nullptr)
575     {
576         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
577         return;
578     }
579
580     try
581     {
582
583         nlohmann::json j = g_afb_instance->app.id_alloc.name2id;
584         auto ret = wm::Ok(json_tokener_parse(j.dump().c_str()));
585         if (ret.is_err())
586         {
587             afb_req_fail(req, "failed", ret.unwrap_err());
588             return;
589         }
590
591         afb_req_success(req, ret.unwrap(), "success");
592     }
593     catch (std::exception &e)
594     {
595         afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
596         return;
597     }
598 }
599
600 void windowmanager_ping(afb_req req) noexcept
601 {
602     std::lock_guard<std::mutex> guard(binding_m);
603 #ifdef ST
604     ST();
605 #endif
606     if (g_afb_instance == nullptr)
607     {
608         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
609         return;
610     }
611
612     try
613     {
614
615         g_afb_instance->app.api_ping();
616
617         afb_req_success(req, NULL, "success");
618     }
619     catch (std::exception &e)
620     {
621         afb_req_fail_f(req, "failed", "Uncaught exception while calling ping: %s", e.what());
622         return;
623     }
624 }
625
626 void windowmanager_debug_status(afb_req req) noexcept
627 {
628     std::lock_guard<std::mutex> guard(binding_m);
629 #ifdef ST
630     ST();
631 #endif
632     if (g_afb_instance == nullptr)
633     {
634         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
635         return;
636     }
637
638     try
639     {
640
641         json_object *jr = json_object_new_object();
642         json_object_object_add(jr, "surfaces",
643                                to_json(g_afb_instance->app.controller->sprops));
644         json_object_object_add(jr, "layers", to_json(g_afb_instance->app.controller->lprops));
645
646         afb_req_success(req, jr, "success");
647     }
648     catch (std::exception &e)
649     {
650         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
651         return;
652     }
653 }
654
655 void windowmanager_debug_layers(afb_req req) noexcept
656 {
657     std::lock_guard<std::mutex> guard(binding_m);
658 #ifdef ST
659     ST();
660 #endif
661     if (g_afb_instance == nullptr)
662     {
663         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
664         return;
665     }
666
667     try
668     {
669         auto ret = wm::Ok(json_tokener_parse(g_afb_instance->app.layers.to_json().dump().c_str()));
670
671         afb_req_success(req, ret, "success");
672     }
673     catch (std::exception &e)
674     {
675         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
676         return;
677     }
678 }
679
680 void windowmanager_debug_surfaces(afb_req req) noexcept
681 {
682     std::lock_guard<std::mutex> guard(binding_m);
683 #ifdef ST
684     ST();
685 #endif
686     if (g_afb_instance == nullptr)
687     {
688         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
689         return;
690     }
691
692     try
693     {
694
695         auto ret = wm::Ok(to_json(g_afb_instance->app.controller->sprops));
696         if (ret.is_err())
697         {
698             afb_req_fail(req, "failed", ret.unwrap_err());
699             return;
700         }
701
702         afb_req_success(req, ret.unwrap(), "success");
703     }
704     catch (std::exception &e)
705     {
706         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
707         return;
708     }
709 }
710
711 void windowmanager_debug_terminate(afb_req req) noexcept
712 {
713     std::lock_guard<std::mutex> guard(binding_m);
714 #ifdef ST
715     ST();
716 #endif
717     if (g_afb_instance == nullptr)
718     {
719         afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
720         return;
721     }
722
723     try
724     {
725
726         if (getenv("WINMAN_DEBUG_TERMINATE") != nullptr)
727         {
728             raise(SIGKILL); // afb-daemon kills it's pgroup using TERM, which
729                             // doesn't play well with perf
730         }
731
732         afb_req_success(req, NULL, "success");
733     }
734     catch (std::exception &e)
735     {
736         afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
737         return;
738     }
739 }
740
741 const struct afb_verb_v2 windowmanager_verbs[] = {
742     {"requestsurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE},
743     {"requestsurfacexdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE},
744     {"activatesurface", windowmanager_activatesurface, nullptr, nullptr, AFB_SESSION_LOA_1},
745     {"deactivatesurface", windowmanager_deactivatesurface, nullptr, nullptr, AFB_SESSION_LOA_1},
746     {"enddraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_LOA_1},
747     {"getdisplayinfo", windowmanager_getdisplayinfo_thunk, nullptr, nullptr, AFB_SESSION_NONE},
748     {"getareainfo", windowmanager_getareainfo_thunk, nullptr, nullptr, AFB_SESSION_LOA_1},
749     {"wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE},
750     {"list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE},
751     {"ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE},
752     {"debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE},
753     {"debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE},
754     {"debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE},
755     {"debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE},
756     {}};
757
758 extern "C" const struct afb_binding_v2 afbBindingV2 = {
759     "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};