4bb53b3790b1d2ac6f50127db45b35e200f852a7
[staging/windowmanager.git] / src / main.cpp
1 /*
2  * Copyright (C) 2017 Mentor Graphics Development (Deutschland) GmbH
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 "app.hpp"
18 #include "json_helper.hpp"
19 #include "util.hpp"
20 #include "wayland.hpp"
21
22 #include <algorithm>
23 #include <mutex>
24
25 #include <json.h>
26
27 extern "C" {
28 #include <afb/afb-binding.h>
29 #include <systemd/sd-event.h>
30 }
31
32 namespace {
33 //std::mutex binding_m;
34
35 struct afb_instance {
36    std::unique_ptr<wl::display> display;
37    wm::App app;
38
39    afb_instance() : display{new wl::display}, app{this->display.get()} {}
40
41    int init();
42 };
43
44 struct afb_instance *g_afb_instance;
45
46 int afb_instance::init() {
47    if (!this->display->ok()) {
48       return -1;
49    }
50
51    return this->app.init();
52 }
53
54 int display_event_callback(sd_event_source *evs, int fd, uint32_t events,
55                            void * /*data*/) {
56    ST();
57    // std::lock_guard<std::mutex> guard(binding_m);
58
59    if ((events & EPOLLHUP) != 0) {
60       logerror("The compositor hung up, dying now.");
61       delete g_afb_instance;
62       g_afb_instance = nullptr;
63       goto error;
64    }
65
66    if ((events & EPOLLIN) != 0u) {
67       {
68          STN(display_read_events);
69          g_afb_instance->app.display->read_events();
70          g_afb_instance->app.pending_events.store(true, std::memory_order_release);
71       }
72       {
73          STN(winman_ping_api_call);
74          afb_service_call("winman", "ping", json_object_new_object(), [](void *c, int st,  json_object* j) {
75             STN(winman_ping_api_call_return);
76          }, nullptr);
77       }
78    }
79
80    return 0;
81
82 error:
83    sd_event_source_unref(evs);
84    if (getenv("WINMAN_EXIT_ON_HANGUP") != nullptr)
85       exit(1);
86    return -1;
87 }
88
89 //  _     _           _ _                 _       _ _    ____
90 // | |__ (_)_ __   __| (_)_ __   __ _    (_)_ __ (_) |_ / /\ \
91 // | '_ \| | '_ \ / _` | | '_ \ / _` |   | | '_ \| | __| |  | |
92 // | |_) | | | | | (_| | | | | | (_| |   | | | | | | |_| |  | |
93 // |_.__/|_|_| |_|\__,_|_|_| |_|\__, |___|_|_| |_|_|\__| |  | |
94 //                              |___/_____|             \_\/_/
95 int binding_init_() {
96    lognotice("WinMan ver. %s", WINMAN_VERSION_STRING);
97
98    if (g_afb_instance != nullptr) {
99       logerror("Wayland context already initialized?");
100       return 0;
101    }
102
103    if (getenv("XDG_RUNTIME_DIR") == nullptr) {
104       logerror("Environment variable XDG_RUNTIME_DIR not set");
105       goto error;
106    }
107
108    g_afb_instance = new afb_instance;
109    if (g_afb_instance->init() == -1) {
110       logerror("Could not connect to compositor");
111       goto error;
112    }
113
114    {
115       int ret = sd_event_add_io(afb_daemon_get_event_loop(), nullptr,
116                                 g_afb_instance->display->get_fd(), EPOLLIN,
117                                 display_event_callback, g_afb_instance);
118       if (ret < 0) {
119          logerror("Could not initialize afb_instance event handler: %d", -ret);
120          goto error;
121       }
122    }
123
124    atexit([] { delete g_afb_instance; });
125
126    return 0;
127
128 error:
129    delete g_afb_instance;
130    g_afb_instance = nullptr;
131    return -1;
132 }
133
134 int binding_init() noexcept {
135    try {
136       return binding_init_();
137    } catch (std::exception &e) {
138       logerror("Uncaught exception in binding_init(): %s", e.what());
139    }
140    return -1;
141 }
142
143 }  // namespace
144
145 #include "afb_binding_glue.inl"
146
147 // XXX implement send_event right here...
148 namespace wm {
149 void binding_api::send_event(char const *evname, char const *label) {
150    logdebug("%s: %s(%s)", __func__, evname, label);
151    int ret = afb_daemon_broadcast_event(evname, json_object_new_string(label));
152    if (ret != 0) {
153       logdebug("afb_event_broadcast failed: %m");
154    }
155 }
156 }
157
158 extern "C" const struct afb_binding_v2 afbBindingV2 = {
159    "winman", nullptr, nullptr, winman_verbs, nullptr, binding_init, nullptr, 1};