7 #include <condition_variable>
11 #include "main-grpc.h"
12 #include "grpc-async-cb.h"
14 static int running = 1;
17 agl_shell_bound_ok(void *data, struct agl_shell *agl_shell)
21 struct shell_data *sh = static_cast<struct shell_data *>(data);
22 sh->wait_for_bound = false;
28 agl_shell_bound_fail(void *data, struct agl_shell *agl_shell)
32 struct shell_data *sh = static_cast<struct shell_data *>(data);
33 sh->wait_for_bound = false;
39 agl_shell_app_state(void *data, struct agl_shell *agl_shell,
40 const char *app_id, uint32_t state)
43 struct shell_data *sh = static_cast<struct shell_data *>(data);
44 LOG("got app_state event app_id %s, state %d\n", app_id, state);
46 if (sh->server_context_list.empty())
49 ::agl_shell_ipc::AppState app;
51 sh->current_app_state.set_app_id(std::string(app_id));
52 sh->current_app_state.set_state(state);
54 auto start = sh->server_context_list.begin();
55 while (start != sh->server_context_list.end()) {
56 LOG("writing to lister %p\n", static_cast<void *>(start->second));
57 start->second->NextWrite();
62 static const struct agl_shell_listener shell_listener = {
69 agl_shell_ext_doas_done(void *data, struct agl_shell_ext *agl_shell_ext, uint32_t status)
73 struct shell_data *sh = static_cast<struct shell_data *>(data);
74 sh->wait_for_doas = false;
76 if (status == AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_SUCCESS)
80 static const struct agl_shell_ext_listener shell_ext_listener = {
81 agl_shell_ext_doas_done,
85 display_handle_geometry(void *data, struct wl_output *wl_output,
86 int x, int y, int physical_width, int physical_height,
87 int subpixel, const char *make, const char *model, int transform)
93 (void) physical_width;
94 (void) physical_height;
102 display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
103 int width, int height, int refresh)
114 display_handle_done(void *data, struct wl_output *wl_output)
121 display_handle_scale(void *data, struct wl_output *wl_output, int32_t factor)
130 display_handle_name(void *data, struct wl_output *wl_output, const char *name)
134 struct window_output *woutput = static_cast<struct window_output *>(data);
135 woutput->name = strdup(name);
139 display_handle_description(void *data, struct wl_output *wl_output, const char *description)
146 static const struct wl_output_listener output_listener = {
147 display_handle_geometry,
150 display_handle_scale,
152 display_handle_description,
156 display_add_output(struct shell_data *sh, struct wl_registry *reg,
157 uint32_t id, uint32_t version)
159 struct window_output *w_output;
161 w_output = new struct window_output;
162 w_output->shell_data = sh;
165 static_cast<struct wl_output *>(wl_registry_bind(reg, id,
166 &wl_output_interface,
167 std::min(version, static_cast<uint32_t>(4))));
169 wl_list_insert(&sh->output_list, &w_output->link);
170 wl_output_add_listener(w_output->output, &output_listener, w_output);
174 destroy_output(struct window_output *w_output)
176 free(w_output->name);
177 wl_list_remove(&w_output->link);
182 global_add(void *data, struct wl_registry *reg, uint32_t id,
183 const char *interface, uint32_t version)
186 struct shell_data *sh = static_cast<struct shell_data *>(data);
191 if (strcmp(interface, agl_shell_interface.name) == 0) {
193 static_cast<struct agl_shell *>(wl_registry_bind(reg, id,
194 &agl_shell_interface, std::min(static_cast<uint32_t>(3),
196 agl_shell_add_listener(sh->shell, &shell_listener, data);
197 sh->version = version;
198 } else if (strcmp(interface, "wl_output") == 0) {
199 display_add_output(sh, reg, id, version);
204 global_remove(void *data, struct wl_registry *reg, uint32_t id)
213 global_add_ext(void *data, struct wl_registry *reg, uint32_t id,
214 const char *interface, uint32_t version)
216 struct shell_data *sh = static_cast<struct shell_data *>(data);
221 if (strcmp(interface, agl_shell_ext_interface.name) == 0) {
223 static_cast<struct agl_shell_ext *>(wl_registry_bind(reg, id,
224 &agl_shell_ext_interface, std::min(static_cast<uint32_t>(1),
226 agl_shell_ext_add_listener(sh->shell_ext,
227 &shell_ext_listener, data);
232 global_remove_ext(void *data, struct wl_registry *reg, uint32_t id)
240 static const struct wl_registry_listener registry_ext_listener = {
245 static const struct wl_registry_listener registry_listener = {
251 register_shell_ext(struct wl_display *wl_display, struct shell_data *sh)
253 struct wl_registry *registry;
255 registry = wl_display_get_registry(wl_display);
257 wl_registry_add_listener(registry, ®istry_ext_listener, sh);
259 wl_display_roundtrip(wl_display);
260 wl_registry_destroy(registry);
264 register_shell(struct wl_display *wl_display, struct shell_data *sh)
266 struct wl_registry *registry;
268 wl_list_init(&sh->output_list);
270 registry = wl_display_get_registry(wl_display);
272 wl_registry_add_listener(registry, ®istry_listener, sh);
274 wl_display_roundtrip(wl_display);
275 wl_registry_destroy(registry);
279 destroy_shell_data(struct shell_data *sh)
281 struct window_output *w_output, *w_output_next;
283 wl_list_for_each_safe(w_output, w_output_next, &sh->output_list, link)
284 destroy_output(w_output);
286 wl_display_flush(sh->wl_display);
287 wl_display_disconnect(sh->wl_display);
292 static struct shell_data *
293 start_agl_shell_client(void)
296 struct wl_display *wl_display;
298 wl_display = wl_display_connect(NULL);
300 struct shell_data *sh = new struct shell_data;
302 sh->wl_display = wl_display;
303 sh->wait_for_doas = true;
304 sh->wait_for_bound = true;
306 register_shell_ext(wl_display, sh);
308 // check for agl_shell_ext
309 if (!sh->shell_ext) {
310 fprintf(stderr, "Failed to bind to agl_shell_ext interface\n");
315 if (wl_list_empty(&sh->output_list)) {
316 fprintf(stderr, "Failed get any outputs!\n");
321 agl_shell_ext_doas_shell_client(sh->shell_ext);
322 while (ret != -1 && sh->wait_for_doas) {
323 ret = wl_display_dispatch(sh->wl_display);
324 if (sh->wait_for_doas)
329 fprintf(stderr, "Failed to get doas_done event\n");
335 register_shell(wl_display, sh);
336 while (ret != -1 && sh->wait_for_bound) {
337 ret = wl_display_dispatch(sh->wl_display);
338 if (sh->wait_for_bound)
342 // at this point, we can't do anything about it
344 fprintf(stderr, "Failed to get bound_ok event!\n");
349 fprintf(stderr, "agl_shell/agl_shell_ext interface OK\n");
355 start_grpc_server(Shell *aglShell)
357 // instantiante the grpc server
358 std::string server_address(kDefaultGrpcServiceAddress);
359 GrpcServiceImpl service{aglShell};
361 grpc::EnableDefaultHealthCheckService(true);
362 grpc::reflection::InitProtoReflectionServerBuilderPlugin();
364 grpc::ServerBuilder builder;
365 builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
366 builder.RegisterService(&service);
368 std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
369 LOG("Server listening on %s\n", server_address.c_str());
374 int main(int argc, char **argv)
381 // do not start right up, give shell client time to boot up
382 struct timespec ts = {};
384 clock_gettime(CLOCK_MONOTONIC, &ts);
388 nanosleep(&ts, NULL);
390 struct shell_data *sh = start_agl_shell_client();
392 LOG("Failed to initialize agl-shell/agl-shell-ext\n");
396 std::shared_ptr<struct agl_shell> agl_shell{sh->shell, agl_shell_destroy};
397 aglShell = new Shell(agl_shell, sh);
399 std::thread thread(start_grpc_server, aglShell);
401 // serve wayland requests
402 while (running && ret != -1) {
403 ret = wl_display_dispatch(sh->wl_display);
406 destroy_shell_data(sh);