util.h and its impl are now c++
[staging/windowmanager.git] / src / main.cpp
1 #include "util.hpp"
2 #include "wayland.hpp"
3
4 #include <unistd.h>
5
6 #include <signal.h>
7 #include <sys/poll.h>
8 #include <sys/signalfd.h>
9
10 #include <algorithm>
11
12 struct connection {
13    std::vector<std::unique_ptr<wl::output>> outputs;
14    std::unique_ptr<genivi::controller> c;
15 };
16
17 //      _                   _     ____       _ _
18 //  ___| |_ _ __ _   _  ___| |_  |  _ \ ___ | | | ___ _ __
19 // / __| __| '__| | | |/ __| __| | |_) / _ \| | |/ _ \ '__|
20 // \__ \ |_| |  | |_| | (__| |_  |  __/ (_) | | |  __/ |
21 // |___/\__|_|   \__,_|\___|\__| |_|   \___/|_|_|\___|_|
22 //
23 struct Poller {
24    std::vector<std::function<int(int)>> handlers;
25    std::vector<struct pollfd> pfds;
26
27    Poller() = default;
28    void add_fd(int fd, std::function<int(int)> handler);
29    int check_events();
30 };
31
32 void Poller::add_fd(int fd, std::function<int(int)> handler) {
33    pfds.emplace_back(pollfd{.fd = fd, .events = POLLIN, .revents = 0});
34    handlers.emplace_back(std::move(handler));
35 }
36
37 int Poller::check_events() {
38    int ret = 0;
39    if ((ret = poll(this->pfds.data(), this->pfds.size(), -1)) != -1 &&
40        errno != EINTR) {
41       for (unsigned i = 0; i < pfds.size(); i++) {
42          if (pfds[i].revents & POLLIN) {
43             if (handlers[i](pfds[i].fd) == -1) {
44                return -1;
45             }
46             pfds[i].revents = 0;
47             pfds[i].events = POLLIN;
48          }
49       }
50    }
51    return ret;
52 }
53
54 struct unique_fd {
55    int fd {-1};
56    unique_fd() = default;
57    explicit unique_fd(int f) : fd{f} {}
58    operator int() const { return fd; }
59    ~unique_fd() {
60       if (this->fd != -1)
61          close(this->fd);
62    }
63    unique_fd(unique_fd const &) = delete;
64    unique_fd &operator=(unique_fd const &) = delete;
65    unique_fd(unique_fd &&o) : fd(o.fd) { o.fd = -1; }
66    unique_fd &operator=(unique_fd &&o) {
67       std::swap(this->fd, o.fd);
68       return *this;
69    }
70 };
71
72
73 namespace {
74 //  _       _ _       _                         _    ____
75 // (_)_ __ (_) |_    | | __ _ _   _  ___  _   _| |_ / /\ \
76 // | | '_ \| | __|   | |/ _` | | | |/ _ \| | | | __| |  | |
77 // | | | | | | |_    | | (_| | |_| | (_) | |_| | |_| |  | |
78 // |_|_| |_|_|\__|___|_|\__,_|\__, |\___/ \__,_|\__| |  | |
79 //              |_____|       |___/                 \_\/_/
80 char const *init_layout(struct connection &c) {
81    if (!c.c) {
82       return "ivi_controller global not available";
83    }
84
85    if (c.outputs.empty()) {
86       return "no output was set up!";
87    }
88
89    auto &o = c.outputs.front();
90    auto &s = c.c->screens.begin()->second;
91    auto &layers = c.c->layers;
92
93    // XXX: Write output dimensions to ivi controller...
94    c.c->output_size = genivi::size{uint32_t(o->width), uint32_t(o->height)};
95
96    // Clear scene
97    layers.clear();
98
99    // Clear screen
100    s->clear();
101
102    // Setup our dummy scene...
103    c.c->layer_create(100, 0, 0);   // bottom layer, anything else
104    c.c->layer_create(1000, 0, 0);  // top layer, mandelbrot
105
106    auto &l100 = c.c->layers[100];
107    auto &l1k = c.c->layers[1000];
108
109    // Set layers fullscreen
110    l100->set_destination_rectangle(0, 0, o->width, o->height);
111    l1k->set_destination_rectangle(0, 0, o->width, o->height);
112    l100->set_visibility(1);
113    l1k->set_visibility(1);
114
115    // Add layers to screen
116    s->set_render_order({100, 1000});
117
118    c.c->commit_changes();
119    // Note: this does not flush the display!
120
121    return nullptr;
122 }
123 }  // namespace
124
125 //                  _        ____
126 //  _ __ ___   __ _(_)_ __  / /\ \
127 // | '_ ` _ \ / _` | | '_ \| |  | |
128 // | | | | | | (_| | | | | | |  | |
129 // |_| |_| |_|\__,_|_|_| |_| |  | |
130 //                          \_\/_/
131 int main(int /*argc*/, char ** /*argv*/) {
132    lognotice("WinMan ver. %s", WINMAN_VERSION_STRING);
133
134    if (getenv("XDG_RUNTIME_DIR") == nullptr) {
135       fatal("Environment variable XDG_RUNTIME_DIR not set");
136    }
137
138    struct wl::display d {};
139    if (!d.ok()) {
140       fatal("Could not connect to compositor");
141    }
142
143    struct connection c {};
144
145    d.r.add_global_handler(
146            "wl_output", [&c](wl_registry *r, uint32_t name, uint32_t v) {
147                c.outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
148            });
149
150    d.r.add_global_handler(
151       "ivi_controller", [&c](wl_registry *r, uint32_t name, uint32_t v) {
152          c.c = std::make_unique<genivi::controller>(r, name, v);
153
154          // XXX: This protocol needs the output, so lets just add our mapping here...
155          c.c->add_proxy_to_id_mapping(c.outputs.back()->proxy.get(),
156                                       wl_proxy_get_id(
157                                               reinterpret_cast<struct wl_proxy *>(
158                                                       c.outputs.back()->proxy.get())));
159       });
160
161    // First level objects
162    d.roundtrip();
163    // Second level objects
164    d.roundtrip();
165    // Third level objects
166    d.roundtrip();
167
168    if (char const *e = init_layout(c)) {
169       fatal("Could not init layout: %s", e);
170    }
171
172    struct Poller p{};
173    p.add_fd(STDIN_FILENO, [&c](int fd) {
174        int buf;
175        ssize_t ret;
176        ret = read(fd, &buf, sizeof(buf));
177        c.c->debug_dump_current_status();
178        return ret == 0 ? -1 : 0;
179    });
180
181    p.add_fd(d.get_fd(), [&d](int fd) {
182       return d.dispatch();
183    });
184
185    sigset_t sset{};
186    sigemptyset(&sset);
187    sigaddset(&sset, SIGINT);
188    sigaddset(&sset, SIGTERM);
189
190    auto sfd = unique_fd(signalfd(-1, &sset, SFD_NONBLOCK | SFD_CLOEXEC));
191    sigprocmask(SIG_BLOCK, &sset, NULL);
192    p.add_fd(sfd.fd, [](int fd) {
193       struct signalfd_siginfo si;
194       while (read(fd, &si, sizeof(si)) == sizeof(si)) {
195           lognotice("Received signal %u", si.ssi_signo);
196       }
197       return -1;
198    });
199
200    while ((d.flush(), p.check_events()) != -1) {
201       c.c->execute_pending();
202    }
203
204    c.c->commit_changes();
205    d.roundtrip();
206
207    return 0;
208 }