Remove automatic code generation
[apps/agl-service-windowmanager-2017.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 "app.hpp"
19 #include "json_helper.hpp"
20 #include "util.hpp"
21 #include "wayland.hpp"
22
23 #include <algorithm>
24 #include <mutex>
25
26 #include <json.h>
27
28 extern "C" {
29 #include <afb/afb-binding.h>
30 #include <systemd/sd-event.h>
31 }
32
33 struct afb_instance {
34    std::unique_ptr<wl::display> display;
35    wm::App app;
36
37    afb_instance() : display{new wl::display}, app{this->display.get()} {}
38
39    int init();
40 };
41
42 struct afb_instance *g_afb_instance;
43 std::mutex binding_m;
44
45 int afb_instance::init() {
46    return this->app.init();
47 }
48
49 int display_event_callback(sd_event_source *evs, int /*fd*/, uint32_t events,
50                            void * /*data*/) {
51    ST();
52
53    if ((events & EPOLLHUP) != 0) {
54       HMI_ERROR("wm", "The compositor hung up, dying now.");
55       delete g_afb_instance;
56       g_afb_instance = nullptr;
57       goto error;
58    }
59
60    if ((events & EPOLLIN) != 0u) {
61       {
62          STN(display_read_events);
63          g_afb_instance->app.display->read_events();
64          g_afb_instance->app.set_pending_events();
65       }
66       {
67          // We want do dispatch pending wayland events from within
68          // the API context
69          STN(winman_ping_api_call);
70          afb_service_call("windowmanager", "ping", json_object_new_object(),
71                           [](void *c, int st, json_object *j) {
72                              STN(winman_ping_api_call_return);
73                           },
74                           nullptr);
75       }
76    }
77
78    return 0;
79
80 error:
81    sd_event_source_unref(evs);
82    if (getenv("WINMAN_EXIT_ON_HANGUP") != nullptr) {
83    exit(1);
84 }
85    return -1;
86 }
87
88 /**
89  * binding_init_()
90  */
91 int binding_init_() {
92    HMI_NOTICE("wm", "WinMan ver. %s", WINMAN_VERSION_STRING);
93
94    if (g_afb_instance != nullptr) {
95       HMI_ERROR("wm", "Wayland context already initialized?");
96       return 0;
97    }
98
99    if (getenv("XDG_RUNTIME_DIR") == nullptr) {
100       HMI_ERROR("wm", "Environment variable XDG_RUNTIME_DIR not set");
101       goto error;
102    }
103
104    {
105       // wait until wayland compositor starts up.
106       int cnt = 0;
107       g_afb_instance = new afb_instance;
108       while (!g_afb_instance->display->ok()) {
109          cnt++;
110          if (20 <= cnt) {
111             HMI_ERROR("wm", "Could not connect to compositor");
112             goto error;
113          }
114          HMI_ERROR("wm", "Wait to start weston ...");
115          sleep(1);
116          delete g_afb_instance;
117          g_afb_instance = new afb_instance;
118       }
119    }
120
121    if (g_afb_instance->init() == -1) {
122       HMI_ERROR("wm", "Could not connect to compositor");
123       goto error;
124    }
125
126    {
127       int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
128                                 g_afb_instance->display->get_fd(), EPOLLIN,
129                                 display_event_callback, g_afb_instance);
130       if (ret < 0) {
131          HMI_ERROR("wm", "Could not initialize afb_instance event handler: %d", -ret);
132          goto error;
133       }
134    }
135
136    atexit([] { delete g_afb_instance; });
137
138    return 0;
139
140 error:
141    delete g_afb_instance;
142    g_afb_instance = nullptr;
143    return -1;
144 }
145
146 int binding_init() noexcept {
147    try {
148       return binding_init_();
149    } catch (std::exception &e) {
150       HMI_ERROR("wm", "Uncaught exception in binding_init(): %s", e.what());
151    }
152    return -1;
153 }
154
155 void windowmanager_requestsurface(afb_req req) noexcept {
156    std::lock_guard<std::mutex> guard(binding_m);
157    #ifdef ST
158    ST();
159    #endif
160    if (g_afb_instance == nullptr) {
161       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
162       return;
163    }
164
165    try {
166    // BEGIN impl
167    const char* a_drawing_name = afb_req_value(req, "drawing_name");
168    if(!a_drawing_name){
169        afb_req_fail(req, "failed", "Need char const* argument drawing_name");
170        return;
171    }
172
173    auto ret = g_afb_instance->app.api.requestsurface(a_drawing_name);
174    if (ret.is_err()) {
175       afb_req_fail(req, "failed", ret.unwrap_err());
176       return;
177    }
178
179    afb_req_success(req, ret.unwrap(), "success");
180    // END impl
181    } catch (std::exception &e) {
182       afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurface: %s", e.what());
183       return;
184    }
185
186 }
187
188 void windowmanager_requestsurfacexdg(afb_req req) noexcept {
189    std::lock_guard<std::mutex> guard(binding_m);
190    #ifdef ST
191    ST();
192    #endif
193    if (g_afb_instance == nullptr) {
194       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
195       return;
196    }
197
198    try {
199    // BEGIN impl
200    json_object *jreq = afb_req_json(req);
201
202    json_object *j_drawing_name = nullptr;
203    if (! json_object_object_get_ex(jreq, "drawing_name", &j_drawing_name)) {
204       afb_req_fail(req, "failed", "Need char const* argument drawing_name");
205       return;
206    }
207    char const* a_drawing_name = json_object_get_string(j_drawing_name);
208
209    json_object *j_ivi_id = nullptr;
210    if (! json_object_object_get_ex(jreq, "ivi_id", &j_ivi_id)) {
211       afb_req_fail(req, "failed", "Need char const* argument ivi_id");
212       return;
213    }
214    char const* a_ivi_id = json_object_get_string(j_ivi_id);
215
216    auto ret = g_afb_instance->app.api.requestsurfacexdg(a_drawing_name, a_ivi_id);
217    if (ret.is_err()) {
218       afb_req_fail(req, "failed", ret.unwrap_err());
219       return;
220    }
221
222    afb_req_success(req, ret.unwrap(), "success");
223    // END impl
224    } catch (std::exception &e) {
225       afb_req_fail_f(req, "failed", "Uncaught exception while calling requestsurfacexdg: %s", e.what());
226       return;
227    }
228
229 }
230
231 void windowmanager_activatesurface(afb_req req) noexcept {
232    std::lock_guard<std::mutex> guard(binding_m);
233    #ifdef ST
234    ST();
235    #endif
236    if (g_afb_instance == nullptr) {
237       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
238       return;
239    }
240
241    try {
242    // BEGIN impl
243    const char* a_drawing_name = afb_req_value(req, "drawing_name");
244    if(!a_drawing_name){
245        afb_req_fail(req, "failed", "Need char const* argument drawing_name");
246        return;
247    }
248
249    const char* a_drawing_area = afb_req_value(req, "drawing_area");
250    if(!a_drawing_area){
251        afb_req_fail(req, "failed", "Need char const* argument drawing_area");
252        return;
253    }
254
255    auto ret = g_afb_instance->app.api.activatesurface(a_drawing_name, a_drawing_area);
256    if (ret.is_err()) {
257       afb_req_fail(req, "failed", ret.unwrap_err());
258       return;
259    }
260
261    afb_req_success(req, ret.unwrap(), "success");
262    // END impl
263    } catch (std::exception &e) {
264       afb_req_fail_f(req, "failed", "Uncaught exception while calling activatesurface: %s", e.what());
265       return;
266    }
267
268 }
269
270 void windowmanager_deactivatesurface(afb_req req) noexcept {
271    std::lock_guard<std::mutex> guard(binding_m);
272    #ifdef ST
273    ST();
274    #endif
275    if (g_afb_instance == nullptr) {
276       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
277       return;
278    }
279
280    try {
281    // BEGIN impl
282    const char* a_drawing_name = afb_req_value(req, "drawing_name");
283    if(!a_drawing_name){
284        afb_req_fail(req, "failed", "Need char const* argument drawing_name");
285        return;
286    }
287
288    auto ret = g_afb_instance->app.api.deactivatesurface(a_drawing_name);
289    if (ret.is_err()) {
290       afb_req_fail(req, "failed", ret.unwrap_err());
291       return;
292    }
293
294    afb_req_success(req, ret.unwrap(), "success");
295    // END impl
296    } catch (std::exception &e) {
297       afb_req_fail_f(req, "failed", "Uncaught exception while calling deactivatesurface: %s", e.what());
298       return;
299    }
300
301 }
302
303 void windowmanager_enddraw(afb_req req) noexcept {
304    std::lock_guard<std::mutex> guard(binding_m);
305    #ifdef ST
306    ST();
307    #endif
308    if (g_afb_instance == nullptr) {
309       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
310       return;
311    }
312
313    try {
314    // BEGIN impl
315    const char* a_drawing_name = afb_req_value(req, "drawing_name");
316    if(!a_drawing_name){
317        afb_req_fail(req, "failed", "Need char const* argument drawing_name");
318        return;
319    }
320
321    auto ret = g_afb_instance->app.api.enddraw(a_drawing_name);
322    if (ret.is_err()) {
323       afb_req_fail(req, "failed", ret.unwrap_err());
324       return;
325    }
326
327    afb_req_success(req, ret.unwrap(), "success");
328    // END impl
329    } catch (std::exception &e) {
330       afb_req_fail_f(req, "failed", "Uncaught exception while calling enddraw: %s", e.what());
331       return;
332    }
333
334 }
335
336 void windowmanager_wm_subscribe(afb_req req) noexcept {
337    std::lock_guard<std::mutex> guard(binding_m);
338    #ifdef ST
339    ST();
340    #endif
341    if (g_afb_instance == nullptr) {
342       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
343       return;
344    }
345
346    try {
347    // BEGIN impl
348    json_object *jreq = afb_req_json(req);
349    json_object *j = nullptr;
350    if (! json_object_object_get_ex(jreq, "event", &j)) {
351       afb_req_fail(req, "failed", "Need char const* argument event");
352       return;
353    }
354    int event_type = json_object_get_int(j);
355    const char *event_name = g_afb_instance->app.kListEventName[event_type];
356    struct afb_event event = g_afb_instance->app.map_afb_event[event_name];
357    int ret = afb_req_subscribe(req, event);
358    if (ret) {
359       afb_req_fail(req, "failed", "Error: afb_req_subscribe()");
360       return;
361    }
362    afb_req_success(req, NULL, "success");
363    // END impl
364    } catch (std::exception &e) {
365       afb_req_fail_f(req, "failed", "Uncaught exception while calling wm_subscribe: %s", e.what());
366       return;
367    }
368
369 }
370
371 void windowmanager_list_drawing_names(afb_req req) noexcept {
372    std::lock_guard<std::mutex> guard(binding_m);
373    #ifdef ST
374    ST();
375    #endif
376    if (g_afb_instance == nullptr) {
377       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
378       return;
379    }
380
381    try {
382    // BEGIN impl
383    auto ret = g_afb_instance->app.api.list_drawing_names();
384    if (ret.is_err()) {
385       afb_req_fail(req, "failed", ret.unwrap_err());
386       return;
387    }
388
389    afb_req_success(req, ret.unwrap(), "success");
390    // END impl
391    } catch (std::exception &e) {
392       afb_req_fail_f(req, "failed", "Uncaught exception while calling list_drawing_names: %s", e.what());
393       return;
394    }
395
396 }
397
398 void windowmanager_ping(afb_req req) noexcept {
399    std::lock_guard<std::mutex> guard(binding_m);
400    #ifdef ST
401    ST();
402    #endif
403    if (g_afb_instance == nullptr) {
404       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
405       return;
406    }
407
408    try {
409    // BEGIN impl
410    auto ret = g_afb_instance->app.api.ping();
411    if (ret.is_err()) {
412       afb_req_fail(req, "failed", ret.unwrap_err());
413       return;
414    }
415
416    afb_req_success(req, ret.unwrap(), "success");
417    // END impl
418    } catch (std::exception &e) {
419       afb_req_fail_f(req, "failed", "Uncaught exception while calling ping: %s", e.what());
420       return;
421    }
422
423 }
424
425 void windowmanager_debug_status(afb_req req) noexcept {
426    std::lock_guard<std::mutex> guard(binding_m);
427    #ifdef ST
428    ST();
429    #endif
430    if (g_afb_instance == nullptr) {
431       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
432       return;
433    }
434
435    try {
436    // BEGIN impl
437    auto ret = g_afb_instance->app.api.debug_status();
438    if (ret.is_err()) {
439       afb_req_fail(req, "failed", ret.unwrap_err());
440       return;
441    }
442
443    afb_req_success(req, ret.unwrap(), "success");
444    // END impl
445    } catch (std::exception &e) {
446       afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_status: %s", e.what());
447       return;
448    }
449
450 }
451
452 void windowmanager_debug_layers(afb_req req) noexcept {
453    std::lock_guard<std::mutex> guard(binding_m);
454    #ifdef ST
455    ST();
456    #endif
457    if (g_afb_instance == nullptr) {
458       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
459       return;
460    }
461
462    try {
463    // BEGIN impl
464    auto ret = g_afb_instance->app.api.debug_layers();
465    if (ret.is_err()) {
466       afb_req_fail(req, "failed", ret.unwrap_err());
467       return;
468    }
469
470    afb_req_success(req, ret.unwrap(), "success");
471    // END impl
472    } catch (std::exception &e) {
473       afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_layers: %s", e.what());
474       return;
475    }
476
477 }
478
479 void windowmanager_debug_surfaces(afb_req req) noexcept {
480    std::lock_guard<std::mutex> guard(binding_m);
481    #ifdef ST
482    ST();
483    #endif
484    if (g_afb_instance == nullptr) {
485       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
486       return;
487    }
488
489    try {
490    // BEGIN impl
491    auto ret = g_afb_instance->app.api.debug_surfaces();
492    if (ret.is_err()) {
493       afb_req_fail(req, "failed", ret.unwrap_err());
494       return;
495    }
496
497    afb_req_success(req, ret.unwrap(), "success");
498    // END impl
499    } catch (std::exception &e) {
500       afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_surfaces: %s", e.what());
501       return;
502    }
503
504 }
505
506 void windowmanager_debug_terminate(afb_req req) noexcept {
507    std::lock_guard<std::mutex> guard(binding_m);
508    #ifdef ST
509    ST();
510    #endif
511    if (g_afb_instance == nullptr) {
512       afb_req_fail(req, "failed", "Binding not initialized, did the compositor die?");
513       return;
514    }
515
516    try {
517    // BEGIN impl
518    auto ret = g_afb_instance->app.api.debug_terminate();
519    if (ret.is_err()) {
520       afb_req_fail(req, "failed", ret.unwrap_err());
521       return;
522    }
523
524    afb_req_success(req, ret.unwrap(), "success");
525    // END impl
526    } catch (std::exception &e) {
527       afb_req_fail_f(req, "failed", "Uncaught exception while calling debug_terminate: %s", e.what());
528       return;
529    }
530
531 }
532
533 const struct afb_verb_v2 windowmanager_verbs[] = {
534    { "requestsurface", windowmanager_requestsurface, nullptr, nullptr, AFB_SESSION_NONE },
535    { "requestsurfacexdg", windowmanager_requestsurfacexdg, nullptr, nullptr, AFB_SESSION_NONE },
536    { "activatesurface", windowmanager_activatesurface, nullptr, nullptr, AFB_SESSION_NONE },
537    { "deactivatesurface", windowmanager_deactivatesurface, nullptr, nullptr, AFB_SESSION_NONE },
538    { "enddraw", windowmanager_enddraw, nullptr, nullptr, AFB_SESSION_NONE },
539    { "wm_subscribe", windowmanager_wm_subscribe, nullptr, nullptr, AFB_SESSION_NONE },
540    { "list_drawing_names", windowmanager_list_drawing_names, nullptr, nullptr, AFB_SESSION_NONE },
541    { "ping", windowmanager_ping, nullptr, nullptr, AFB_SESSION_NONE },
542    { "debug_status", windowmanager_debug_status, nullptr, nullptr, AFB_SESSION_NONE },
543    { "debug_layers", windowmanager_debug_layers, nullptr, nullptr, AFB_SESSION_NONE },
544    { "debug_surfaces", windowmanager_debug_surfaces, nullptr, nullptr, AFB_SESSION_NONE },
545    { "debug_terminate", windowmanager_debug_terminate, nullptr, nullptr, AFB_SESSION_NONE },
546    {}
547 };
548
549 namespace wm {
550 void binding_api::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(g_afb_instance->app.map_afb_event[evname], j);
557    if (ret != 0) {
558       HMI_DEBUG("wm", "afb_event_push failed: %m");
559    }
560 }
561
562 void binding_api::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(g_afb_instance->app.map_afb_event[evname], j);
570    if (ret != 0) {
571       HMI_DEBUG("wm", "afb_event_push failed: %m");
572    }
573 }
574 } // namespace wm
575
576 extern "C" const struct afb_binding_v2 afbBindingV2 = {
577    "windowmanager", nullptr, nullptr, windowmanager_verbs, nullptr, binding_init, nullptr, 0};