8 struct wl_display *wl_display;
9 struct agl_shell *shell;
10 struct agl_shell_ext *shell_ext;
20 struct wl_list output_list; /** window_output::link */
23 struct window_output {
24 struct shell_data *shell_data;
25 struct wl_output *output;
27 struct wl_list link; /** display::output_list */
30 static struct shell_data *sh = nullptr;
32 grpc::ServerUnaryReactor *
33 GrpcServiceImpl::ActivateApp(grpc::CallbackServerContext *context,
34 const ::agl_shell_ipc::ActivateRequest* request,
35 google::protobuf::Empty* /*response*/)
37 fprintf(stderr, "activating app %s on output %s\n",
38 request->app_id().c_str(),
39 request->output_name().c_str());
41 sh->aglShell->ActivateApp(request->app_id(), request->output_name());
43 grpc::ServerUnaryReactor* reactor = context->DefaultReactor();
44 reactor->Finish(grpc::Status::OK);
48 grpc::ServerUnaryReactor *
49 GrpcServiceImpl::DeactivateApp(grpc::CallbackServerContext *context,
50 const ::agl_shell_ipc::DeactivateRequest* request,
51 google::protobuf::Empty* /*response*/)
53 sh->aglShell->DeactivateApp(request->app_id());
55 grpc::ServerUnaryReactor* reactor = context->DefaultReactor();
56 reactor->Finish(grpc::Status::OK);
60 grpc::ServerUnaryReactor *
61 GrpcServiceImpl::SetAppFloat(grpc::CallbackServerContext *context,
62 const ::agl_shell_ipc::FloatRequest* request,
63 google::protobuf::Empty* /* response */)
65 sh->aglShell->SetAppFloat(request->app_id());
67 grpc::ServerUnaryReactor* reactor = context->DefaultReactor();
68 reactor->Finish(grpc::Status::OK);
72 grpc::ServerUnaryReactor *
73 GrpcServiceImpl::SetAppSplit(grpc::CallbackServerContext *context,
74 const ::agl_shell_ipc::SplitRequest* request,
75 google::protobuf::Empty* /*response*/)
77 sh->aglShell->SetAppSplit(request->app_id(), request->tile_orientation());
79 grpc::ServerUnaryReactor* reactor = context->DefaultReactor();
80 reactor->Finish(grpc::Status::OK);
85 Shell::ActivateApp(const std::string &app_id, const std::string &output_name)
87 struct window_output *woutput, *w_output;
92 wl_list_for_each(woutput, &sh->output_list, link) {
93 if (woutput->name && !strcmp(woutput->name, output_name.c_str())) {
99 // else, get the first one available
101 w_output = wl_container_of(sh->output_list.prev, w_output, link);
103 agl_shell_activate_app(this->m_shell.get(), app_id.c_str(), w_output->output);
104 wl_display_flush(sh->wl_display);
108 Shell::DeactivateApp(const std::string &app_id)
114 Shell::SetAppFloat(const std::string &app_id)
120 Shell::SetAppSplit(const std::string &app_id, uint32_t orientation)
127 start_grpc_server(void)
129 // instantiante the grpc server
130 std::string server_address(kDefaultGrpcServiceAddress);
131 GrpcServiceImpl service;
133 grpc::EnableDefaultHealthCheckService(true);
134 grpc::reflection::InitProtoReflectionServerBuilderPlugin();
136 grpc::ServerBuilder builder;
137 builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
138 builder.RegisterService(&service);
140 std::unique_ptr<grpc::Server> server(builder.BuildAndStart());
141 fprintf(stderr, "Server listening on %s\n", server_address.c_str());
147 agl_shell_bound_ok(void *data, struct agl_shell *agl_shell)
151 struct shell_data *sh = static_cast<struct shell_data *>(data);
152 sh->wait_for_bound = false;
158 agl_shell_bound_fail(void *data, struct agl_shell *agl_shell)
162 struct shell_data *sh = static_cast<struct shell_data *>(data);
163 sh->wait_for_bound = false;
165 sh->bound_ok = false;
169 agl_shell_app_state(void *data, struct agl_shell *agl_shell,
170 const char *app_id, uint32_t state)
178 static const struct agl_shell_listener shell_listener = {
180 agl_shell_bound_fail,
185 agl_shell_ext_doas_done(void *data, struct agl_shell_ext *agl_shell_ext, uint32_t status)
187 (void) agl_shell_ext;
189 struct shell_data *sh = static_cast<struct shell_data *>(data);
190 sh->wait_for_doas = false;
192 if (status == AGL_SHELL_EXT_DOAS_SHELL_CLIENT_STATUS_SUCCESS)
196 static const struct agl_shell_ext_listener shell_ext_listener = {
197 agl_shell_ext_doas_done,
201 display_handle_geometry(void *data, struct wl_output *wl_output,
202 int x, int y, int physical_width, int physical_height,
203 int subpixel, const char *make, const char *model, int transform)
209 (void) physical_width;
210 (void) physical_height;
218 display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags,
219 int width, int height, int refresh)
230 display_handle_done(void *data, struct wl_output *wl_output)
237 display_handle_scale(void *data, struct wl_output *wl_output, int32_t factor)
246 display_handle_name(void *data, struct wl_output *wl_output, const char *name)
250 struct window_output *woutput = static_cast<struct window_output *>(data);
251 woutput->name = strdup(name);
255 display_handle_description(void *data, struct wl_output *wl_output, const char *description)
262 static const struct wl_output_listener output_listener = {
263 display_handle_geometry,
266 display_handle_scale,
268 display_handle_description,
272 display_add_output(struct shell_data *sh, struct wl_registry *reg,
273 uint32_t id, uint32_t version)
275 struct window_output *w_output;
277 w_output = new struct window_output;
278 w_output->shell_data = sh;
281 static_cast<struct wl_output *>(wl_registry_bind(reg, id,
282 &wl_output_interface,
283 std::min(version, static_cast<uint32_t>(4))));
285 wl_list_insert(&sh->output_list, &w_output->link);
286 wl_output_add_listener(w_output->output, &output_listener, w_output);
290 destroy_output(struct window_output *w_output)
292 free(w_output->name);
293 wl_list_remove(&w_output->link);
299 global_add(void *data, struct wl_registry *reg, uint32_t id,
300 const char *interface, uint32_t version)
303 struct shell_data *sh = static_cast<struct shell_data *>(data);
308 if (strcmp(interface, agl_shell_interface.name) == 0) {
310 static_cast<struct agl_shell *>(wl_registry_bind(reg, id,
311 &agl_shell_interface, std::min(static_cast<uint32_t>(3),
313 agl_shell_add_listener(sh->shell, &shell_listener, data);
314 sh->version = version;
315 } else if (strcmp(interface, "wl_output") == 0) {
316 display_add_output(sh, reg, id, version);
321 global_remove(void *data, struct wl_registry *reg, uint32_t id)
330 global_add_ext(void *data, struct wl_registry *reg, uint32_t id,
331 const char *interface, uint32_t version)
333 struct shell_data *sh = static_cast<struct shell_data *>(data);
338 if (strcmp(interface, agl_shell_ext_interface.name) == 0) {
340 static_cast<struct agl_shell_ext *>(wl_registry_bind(reg, id,
341 &agl_shell_ext_interface, std::min(static_cast<uint32_t>(1),
343 agl_shell_ext_add_listener(sh->shell_ext, &shell_ext_listener, data);
348 global_remove_ext(void *data, struct wl_registry *reg, uint32_t id)
356 static const struct wl_registry_listener registry_ext_listener = {
361 static const struct wl_registry_listener registry_listener = {
367 register_shell_ext(struct wl_display *wl_display)
369 struct wl_registry *registry;
371 registry = wl_display_get_registry(wl_display);
373 wl_registry_add_listener(registry, ®istry_ext_listener, sh);
375 wl_display_roundtrip(wl_display);
376 wl_registry_destroy(registry);
380 register_shell(struct wl_display *wl_display)
382 struct wl_registry *registry;
384 wl_list_init(&sh->output_list);
386 registry = wl_display_get_registry(wl_display);
388 wl_registry_add_listener(registry, ®istry_listener, sh);
390 wl_display_roundtrip(wl_display);
391 wl_registry_destroy(registry);
395 start_agl_shell_client(void)
398 struct wl_display *wl_display;
400 wl_display = wl_display_connect(NULL);
402 sh = new struct shell_data;
403 sh->wl_display = wl_display;
404 sh->wait_for_doas = true;
405 sh->wait_for_bound = true;
407 register_shell_ext(wl_display);
409 // check for agl_shell_ext
410 if (!sh->shell_ext) {
411 fprintf(stderr, "Failed to bind to agl_shell_ext interface\n");
415 if (wl_list_empty(&sh->output_list)) {
416 fprintf(stderr, "Failed get any outputs!\n");
420 agl_shell_ext_doas_shell_client(sh->shell_ext);
421 while (ret != -1 && sh->wait_for_doas) {
422 ret = wl_display_dispatch(sh->wl_display);
423 if (sh->wait_for_doas)
428 fprintf(stderr, "Failed to get doas_done event\n");
433 register_shell(wl_display);
434 while (ret != -1 && sh->wait_for_bound) {
435 ret = wl_display_dispatch(sh->wl_display);
436 if (sh->wait_for_bound)
440 // at this point, we can't do anything about it
442 fprintf(stderr, "Failed to get bound_ok event!\n");
446 fprintf(stderr, "agl_shell/agl_shell_ext interface OK\n");
447 std::shared_ptr<struct agl_shell> agl_shell{sh->shell, agl_shell_destroy};
448 sh->aglShell = new Shell(agl_shell);
454 destroy_shell_data(void)
456 struct window_output *w_output, *w_output_next;
458 wl_list_for_each_safe(w_output, w_output_next, &sh->output_list, link)
459 destroy_output(w_output);
461 wl_display_flush(sh->wl_display);
462 wl_display_disconnect(sh->wl_display);
467 int main(int argc, char **argv)
473 // do not start right up, give shell client time to boot up
474 struct timespec ts = {};
476 clock_gettime(CLOCK_MONOTONIC, &ts);
480 nanosleep(&ts, NULL);
482 ret = start_agl_shell_client();
484 fprintf(stderr, "Failed to initialize agl-shell/agl-shell-ext\n");
490 destroy_shell_data();