main: add wl_output proxy-to-id mapping in wl_output global handler
[staging/windowmanager.git] / src / main.cpp
1 #include "util.h"
2 #include "wayland.hpp"
3
4 #include <unistd.h>
5
6 #include <sys/poll.h>
7
8 struct connection {
9    std::vector<std::unique_ptr<wl::output>> outputs;
10    std::unique_ptr<genivi::controller> c;
11 };
12
13 namespace {
14 //       _               _                            _        ____
15 //   ___| |__   ___  ___| | __    _____   _____ _ __ | |_ ___ / /\ \
16 //  / __| '_ \ / _ \/ __| |/ /   / _ \ \ / / _ \ '_ \| __/ __| |  | |
17 // | (__| | | |  __/ (__|   <   |  __/\ V /  __/ | | | |_\__ \ |  | |
18 //  \___|_| |_|\___|\___|_|\_\___\___| \_/ \___|_| |_|\__|___/ |  | |
19 //                          |_____|                           \_\/_/
20 int check_events(struct wl::display &d, struct connection &c, int fd) {
21    struct pollfd pfd[2] = {{.fd = d.get_fd(), .events = POLLIN, .revents = 0},
22                            {.fd = fd, .events = POLLIN, .revents = 0}};
23
24    d.flush();
25
26    if (poll(pfd, fd != -1 ? 2 : 1, -1) != -1 && errno != EINTR) {
27       int ret = 0;
28
29       if ((pfd[0].revents & POLLIN) != 0) {
30          ret = d.dispatch();
31       }
32
33       if (ret == -1) {
34          return ret;
35       }
36
37       if (fd != -1 && ((pfd[1].revents & POLLIN) != 0)) {
38          char buf[256];
39
40          // read all there is ...
41          while (read(pfd[1].fd, buf, sizeof(buf)) == sizeof(buf)) {
42             ;
43          }
44
45          // Display current status
46          if (!c.c->surfaces.empty()) {
47             puts("Surfaces:");
48             for (auto const &i : c.c->surfaces) {
49                auto const &r = i.second->dst_rect;
50                auto const &s = i.second->size;
51                printf("%d [%ux%u] (%ux%u@%dx%d), ", i.first, s.w, s.h, r.w, r.h,
52                       r.x, r.y);
53             }
54             puts("\b\b ");
55          }
56
57          if (!c.c->layers.empty()) {
58             puts("Layers:");
59             for (auto const &i : c.c->layers) {
60                auto const &r = i.second->dst_rect;
61                auto const &s = i.second->size;
62                printf("%d [%ux%u] (%ux%u@%dx%d), ", i.first, s.w, s.h, r.w, r.h,
63                       r.x, r.y);
64             }
65             puts("\b\b ");
66          }
67       }
68    }
69
70    return 0;
71 }
72
73 //  _       _ _       _                         _    ____
74 // (_)_ __ (_) |_    | | __ _ _   _  ___  _   _| |_ / /\ \
75 // | | '_ \| | __|   | |/ _` | | | |/ _ \| | | | __| |  | |
76 // | | | | | | |_    | | (_| | |_| | (_) | |_| | |_| |  | |
77 // |_|_| |_|_|\__|___|_|\__,_|\__, |\___/ \__,_|\__| |  | |
78 //              |_____|       |___/                 \_\/_/
79 char const *init_layout(struct connection &c) {
80    if (!c.c) {
81       return "ivi_controller global not available";
82    }
83
84    if (c.outputs.empty()) {
85       return "no output was set up!";
86    }
87
88    auto &o = c.outputs.front();
89    auto &s = c.c->screens.begin()->second;
90    auto &layers = c.c->layers;
91
92    // XXX: Write output dimensions to ivi controller...
93    c.c->output_size = genivi::size{uint32_t(o->width), uint32_t(o->height)};
94
95    // Clear scene
96    layers.clear();
97
98    // Clear screen
99    s->clear();
100
101    // Setup our dummy scene...
102    c.c->layer_create(100, 0, 0);   // bottom layer, anything else
103    c.c->layer_create(1000, 0, 0);  // top layer, mandelbrot
104
105    auto &l100 = c.c->layers[100];
106    auto &l1k = c.c->layers[1000];
107
108    // Set layers fullscreen
109    l100->set_destination_rectangle(0, 0, o->width, o->height);
110    l1k->set_destination_rectangle(0, 0, o->width, o->height);
111    l100->set_visibility(1);
112    l1k->set_visibility(1);
113
114    // Add layers to screen
115    s->set_render_order({100, 1000});
116
117    c.c->commit_changes();
118    // Note: this does not flush the display!
119
120    return nullptr;
121 }
122 }  // namespace
123
124 //                  _        ____
125 //  _ __ ___   __ _(_)_ __  / /\ \
126 // | '_ ` _ \ / _` | | '_ \| |  | |
127 // | | | | | | (_| | | | | | |  | |
128 // |_| |_| |_|\__,_|_|_| |_| |  | |
129 //                          \_\/_/
130 int main(int /*argc*/, char ** /*argv*/) {
131    lognotice("WinMan ver. %s", WINMAN_VERSION_STRING);
132
133    if (getenv("XDG_RUNTIME_DIR") == nullptr) {
134       fatal("Environment variable XDG_RUNTIME_DIR not set");
135    }
136
137    struct wl::display d {};
138    if (!d.ok()) {
139       fatal("Could not connect to compositor");
140    }
141
142    struct connection c {};
143
144    d.r.add_global_handler(
145            "wl_output", [&c](wl_registry *r, uint32_t name, uint32_t v) {
146                c.outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
147            });
148
149    d.r.add_global_handler(
150       "ivi_controller", [&c](wl_registry *r, uint32_t name, uint32_t v) {
151          c.c = std::make_unique<genivi::controller>(r, name, v);
152
153          // XXX: This protocol needs the output, so lets just add our mapping here...
154          c.c->add_proxy_to_id_mapping(c.outputs.back()->proxy.get(),
155                                       wl_proxy_get_id(
156                                               reinterpret_cast<struct wl_proxy *>(
157                                                       c.outputs.back()->proxy.get())));
158       });
159
160    // First level objects
161    d.roundtrip();
162    // Second level objects
163    d.roundtrip();
164    // Third level objects
165    d.roundtrip();
166
167    if (char const *e = init_layout(c)) {
168       fatal("Could not init layout: %s", e);
169    }
170
171    while (check_events(d, c, STDIN_FILENO) != -1) {
172       c.c->execute_pending();
173       d.flush();
174    }
175
176    return 0;
177 }