diff options
Diffstat (limited to 'src/main.cpp')
-rw-r--r-- | src/main.cpp | 315 |
1 files changed, 315 insertions, 0 deletions
diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..079001f --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,315 @@ +/* + * Copyright 2021, 2022 Collabora, Ltd. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial + * portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <stddef.h> +#include <assert.h> +#include <thread> + +#include <wayland-client.h> +#include <wayland-util.h> + +#include "AglShellGrpcClient.h" +#include "agl-shell-desktop-client-protocol.h" + +#ifndef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#endif +#ifndef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#endif + +static int running = 1; +const char *app_id_to_activate = NULL; + +struct display; + +struct window_output { + struct display *display; + struct wl_output *output; + char *name; + struct wl_list link; /** display::output_list */ +}; + +struct display { + struct wl_display *display; + struct wl_registry *registry; + struct agl_shell_desktop *agl_shell_desktop; + + struct wl_list output_list; /** window_output::link */ +}; + +static void +display_handle_geometry(void *data, struct wl_output *wl_output, + int x, int y, int physical_width, int physical_height, + int subpixel, const char *make, const char *model, int transform) +{ +} + +static void +display_handle_mode(void *data, struct wl_output *wl_output, uint32_t flags, + int width, int height, int refresh) +{ +} + +static void +display_handle_done(void *data, struct wl_output *wl_output) +{ +} + +static void +display_handle_scale(void *data, struct wl_output *wl_output, int32_t factor) +{ +} + +static void +display_handle_name(void *data, struct wl_output *wl_output, const char *name) +{ + struct window_output *woutput = static_cast<struct window_output *>(data); + woutput->name = strdup(name); + + fprintf(stderr, "Adding output '%s'\n", name); +} + +static void +display_handle_description(void *data, struct wl_output *wl_output, const char *description) +{ +} + +static const struct wl_output_listener output_listener = { + display_handle_geometry, + display_handle_mode, + display_handle_done, + display_handle_scale, + display_handle_name, + display_handle_description, +}; + + +static void +display_add_output(struct display *display, uint32_t id, uint32_t version) +{ + struct window_output *w_output; + + w_output = static_cast<struct window_output *>(calloc(1, sizeof(*w_output))); + w_output->display = display; + + if (version < 4) + w_output->output = + static_cast<struct wl_output *>(wl_registry_bind(display->registry, id, &wl_output_interface, MAX(version, 3))); + else + w_output->output = + static_cast<struct wl_output *>(wl_registry_bind(display->registry, id, &wl_output_interface, MIN(version, 4))); + + wl_list_insert(&display->output_list, &w_output->link); + wl_output_add_listener(w_output->output, &output_listener, w_output); +} + +static void +destroy_output(struct window_output *w_output) +{ + free(w_output->name); + wl_list_remove(&w_output->link); + free(w_output); +} + +static void app(void *data, struct agl_shell_desktop *agl_shell_desktop, + const char *appid) +{ + /* UNUSED */ +} + +static void state_app(void *data, struct agl_shell_desktop *agl_shell_desktop, + const char *app_id, const char *app_data, uint32_t state, + uint32_t role) +{ + if (strcmp(app_id, app_id_to_activate) == 0 && + state == AGL_SHELL_DESKTOP_APP_STATE_ACTIVATED) { + running = 0; + } +} + +static const struct agl_shell_desktop_listener desktop_shell_listener = { + app, + state_app, +}; + +static void +registry_handle_global(void *data, struct wl_registry *registry, + uint32_t id, const char *interface, uint32_t version) +{ + struct display *d = static_cast<struct display *>(data); + + if (strcmp(interface, "agl_shell_desktop") == 0) { + d->agl_shell_desktop = + static_cast<struct agl_shell_desktop *>(wl_registry_bind(registry, id, &agl_shell_desktop_interface, 1)); + agl_shell_desktop_add_listener(d->agl_shell_desktop, + &desktop_shell_listener, d); + } else if (strcmp(interface, "wl_output") == 0) { + if (version < 4) + fprintf(stderr, "Failed to bind to version 4. " + "Current version %d\n", version); + display_add_output(d, id, version); + } +} + +static void +registry_handle_global_remove(void *data, struct wl_registry *registry, + uint32_t name) +{ + +} + +static const struct wl_registry_listener registry_listener = { + registry_handle_global, + registry_handle_global_remove +}; + +static struct display * +create_display(void) +{ + struct display *display; + + display = static_cast<struct display *>(malloc(sizeof *display)); + if (display == NULL) { + fprintf(stderr, "out of memory\n"); + exit(1); + } + + wl_list_init(&display->output_list); + display->display = wl_display_connect(NULL); + assert(display->display); + + display->registry = wl_display_get_registry(display->display); + + wl_registry_add_listener(display->registry, ®istry_listener, display); + wl_display_roundtrip(display->display); + + if (display->agl_shell_desktop == NULL) { + fprintf(stderr, "No agl_shell_desktop extension present\n"); + } + + wl_display_roundtrip(display->display); + return display; +} + +static void +destroy_display(struct display *display) +{ + struct window_output *w_output, *w_output_next; + + wl_list_for_each_safe(w_output, w_output_next, &display->output_list, link) + destroy_output(w_output); + + wl_registry_destroy(display->registry); + + wl_display_flush(display->display); + wl_display_disconnect(display->display); + + free(display); +} + +static void +run_in_thread(GrpcClient *client) +{ + grpc::Status status = client->Wait(); +} + +int main(int argc, char *argv[]) +{ + struct display *display; + struct window_output *w_output = NULL; + char *output_name = NULL; + int ret = 0; + bool use_grpc_activation = false; + + if (argc < 2) { + exit(EXIT_FAILURE); + } + + if (argc == 3) { + output_name = argv[2]; + } + + if (argc == 4 && strcmp(argv[3], "use-grpc") == 0) + use_grpc_activation = true; + + + display = create_display(); + + /* the app has to be already started, or not already active */ + app_id_to_activate = argv[1]; + if (app_id_to_activate && strlen(app_id_to_activate) == 0) + exit(EXIT_FAILURE); + + if (output_name) { + struct window_output *woutput; + + wl_list_for_each(woutput, &display->output_list, link) { + if (woutput->name && !strcmp(woutput->name, output_name)) { + w_output = woutput; + break; + } + } + } else { + w_output = wl_container_of(display->output_list.prev, w_output, link); + } + + /* maybe that output doesn't exit, still allow a fallback */ + if (!w_output) + w_output = wl_container_of(display->output_list.prev, w_output, link); + + fprintf(stderr, "Activating application '%s' on output '%s'\n", + app_id_to_activate, w_output->name ? + w_output->name : "first default output"); + + if (use_grpc_activation) { + fprintf(stderr, "using grpc\n"); + GrpcClient *client = new GrpcClient(); + + // this blocks in wait + std::thread thread(run_in_thread, client); + + // this does the actually call to get events + client->AppStatusState(); + + client->ActivateApp(std::string(app_id_to_activate), + std::string(w_output->name)); + thread.join(); + } else { + fprintf(stderr, "using agl_shell_desktop\n"); + agl_shell_desktop_activate_app(display->agl_shell_desktop, + app_id_to_activate, NULL, w_output->output); + + while (running && ret != -1) { + ret = wl_display_dispatch(display->display); + } + } + + destroy_display(display); + return 0; +} |