main: move most of main to app, separate ownership
[staging/windowmanager.git] / src / app.cpp
1 //
2 // Created by mfritzsc on 7/11/17.
3 //
4
5 #include "app.hpp"
6 #include "util.hpp"
7 #include "json_helper.hpp"
8 #include "wayland.hpp"
9
10 #include <cassert>
11
12 #include <json-c/json.h>
13
14 namespace wm {
15
16     namespace {
17         App *g_app;
18     }
19
20     App::App(wl::display *d)
21             : api{this}, display{d}, controller{}, outputs()
22     {
23         assert(g_app == nullptr);
24         g_app = this;
25     }
26
27     int App::init() {
28         if (!this->display->ok()) {
29             return -1;
30         }
31
32         this->display->r.add_global_handler("wl_output", [](wl_registry *r,
33                                                             uint32_t name,
34                                                             uint32_t v) {
35             g_app->outputs.emplace_back(std::make_unique<wl::output>(r, name, v));
36         });
37
38         this->display->r.add_global_handler(
39                 "ivi_controller", [](wl_registry *r, uint32_t name, uint32_t v) {
40                     g_app->controller =
41                             std::make_unique<genivi::controller>(r, name, v);
42
43                     // XXX: This protocol needs the output, so lets just add our mapping
44                     // here...
45                     g_app->controller->add_proxy_to_id_mapping(
46                             g_app->outputs.back()->proxy.get(),
47                             wl_proxy_get_id(reinterpret_cast<struct wl_proxy *>(
48                                                     g_app->outputs.back()->proxy.get())));
49                 });
50
51         // First level objects
52         this->display->roundtrip();
53         // Second level objects
54         this->display->roundtrip();
55         // Third level objects
56         this->display->roundtrip();
57
58         return init_layout();
59     }
60
61     int App::dispatch_events() {
62         int ret = this->display->dispatch();
63         if (ret == -1) {
64             logerror("wl_display_dipatch() returned error %d",
65                      this->display->get_error());
66             return -1;
67         }
68         this->display->flush();
69
70         // execute pending tasks, that is layout changes etc.
71         this->controller->execute_pending();
72         this->display->roundtrip();
73
74         return 0;
75     }
76
77     //  _       _ _       _                         _    ____
78     // (_)_ __ (_) |_    | | __ _ _   _  ___  _   _| |_ / /\ \
79     // | | '_ \| | __|   | |/ _` | | | |/ _ \| | | | __| |  | |
80     // | | | | | | |_    | | (_| | |_| | (_) | |_| | |_| |  | |
81     // |_|_| |_|_|\__|___|_|\__,_|\__, |\___/ \__,_|\__| |  | |
82     //              |_____|       |___/                 \_\/_/
83     int App::init_layout() {
84         if (!this->controller) {
85             logerror("ivi_controller global not available");
86             return -1;
87         }
88
89         if (this->outputs.empty()) {
90             logerror("no output was set up!");
91             return -1;
92         }
93
94         auto &c = this->controller;
95
96         auto &o = this->outputs.front();
97         auto &s = c->screens.begin()->second;
98         auto &layers = c->layers;
99
100         // XXX: Write output dimensions to ivi controller...
101         c->output_size = genivi::size{uint32_t(o->width), uint32_t(o->height)};
102
103         // Clear scene
104         layers.clear();
105
106         // Clear screen
107         s->clear();
108
109         // Setup our dummy scene...
110         c->layer_create(100, 0, 0);   // bottom layer, anything else
111         c->layer_create(1000, 0, 0);  // top layer, mandelbrot
112
113         auto &l100 = c->layers[100];
114         auto &l1k = c->layers[1000];
115
116         // Set layers fullscreen
117         l100->set_destination_rectangle(0, 0, o->width, o->height);
118         l1k->set_destination_rectangle(0, 0, o->width, o->height);
119         l100->set_visibility(1);
120         l1k->set_visibility(1);
121
122         // Add layers to screen
123         s->set_render_order({100, 1000});
124
125         c->commit_changes();
126
127         this->display->flush();
128
129         return 0;
130     }
131
132     binding_api::result_type binding_api::register_surface(uint32_t appid,
133                                                           uint32_t surfid) {
134         logdebug("%s appid %u surfid %u", __func__, appid, surfid);
135         if (appid > 0xff) {
136             return Err<json_object *>("invalid appid");
137         }
138
139         if (surfid > 0xffff) {
140             return Err<json_object *>("invalid surfaceid");
141         }
142
143         return Ok(json_object_new_int((appid << 16) + surfid));
144     }
145
146     binding_api::result_type binding_api::debug_layers() {
147         logdebug("%s", __func__);
148         return Ok(to_json(this->app->controller->lprops));
149     }
150
151     binding_api::result_type binding_api::debug_surfaces() {
152         logdebug("%s", __func__);
153         return Ok(to_json(this->app->controller->sprops));
154     }
155
156     binding_api::result_type binding_api::debug_status() {
157         logdebug("%s", __func__);
158         json_object *jr = json_object_new_object();
159         json_object_object_add(jr, "surfaces", to_json(this->app->controller->sprops));
160         json_object_object_add(jr, "layers", to_json(this->app->controller->lprops));
161         return Ok(jr);
162     }
163
164 } // namespace wm