From 96b4294e47ae84d720327c3f2ac1c3d9d397926f Mon Sep 17 00:00:00 2001 From: Jente Hidskes Date: Sun, 2 Feb 2020 15:14:31 +0100 Subject: [PATCH] Implement the fullscreen shell protocol Fixes #86. --- cage.c | 11 ++++ fullscreen_shell.c | 132 +++++++++++++++++++++++++++++++++++++++++++++ fullscreen_shell.h | 15 ++++++ meson.build | 3 ++ server.h | 1 + view.c | 7 +++ view.h | 1 + 7 files changed, 170 insertions(+) create mode 100644 fullscreen_shell.c create mode 100644 fullscreen_shell.h diff --git a/cage.c b/cage.c index 54945db..6f0a040 100644 --- a/cage.c +++ b/cage.c @@ -39,6 +39,7 @@ #include #endif +#include "fullscreen_shell.h" #include "idle_inhibit_v1.h" #include "output.h" #include "seat.h" @@ -181,6 +182,7 @@ main(int argc, char *argv[]) struct wlr_screencopy_manager_v1 *screencopy_manager = NULL; struct wlr_xdg_output_manager_v1 *output_manager = NULL; struct wlr_gamma_control_manager_v1 *gamma_control_manager = NULL; + struct wlr_fullscreen_shell_v1 *fullscreen_shell = NULL; struct wlr_xdg_shell *xdg_shell = NULL; #if CAGE_HAS_XWAYLAND struct wlr_xwayland *xwayland = NULL; @@ -283,6 +285,15 @@ main(int argc, char *argv[]) wl_signal_add(&server.idle_inhibit_v1->events.new_inhibitor, &server.new_idle_inhibitor_v1); wl_list_init(&server.inhibitors); + fullscreen_shell = wlr_fullscreen_shell_v1_create(server.wl_display); + if (!fullscreen_shell) { + wlr_log(WLR_ERROR, "Unable to create the Fullscreen Shell interface"); + ret = 1; + goto end; + } + server.fullscreen_shell_present_surface.notify = handle_fullscreen_shell_present_surface; + wl_signal_add(&fullscreen_shell->events.present_surface, &server.fullscreen_shell_present_surface); + xdg_shell = wlr_xdg_shell_create(server.wl_display); if (!xdg_shell) { wlr_log(WLR_ERROR, "Unable to create the XDG shell interface"); diff --git a/fullscreen_shell.c b/fullscreen_shell.c new file mode 100644 index 0000000..772a869 --- /dev/null +++ b/fullscreen_shell.c @@ -0,0 +1,132 @@ +/* + * Cage: A Wayland kiosk. + * + * Copyright (C) 2020 Jente Hidskes + * + * See the LICENSE file accompanying this file. + */ + +#include +#include +#include +#include +#include +#include + +#include "fullscreen_shell.h" +#include "output.h" +#include "server.h" +#include "view.h" + +static struct cg_fullscreen_shell_view * +fullscreen_shell_view_from_view(struct cg_view *view) +{ + return (struct cg_fullscreen_shell_view *) view; +} + +static void +get_geometry(struct cg_view *view, int *width_out, int *height_out) +{ + // struct wlr_box *layout_box = wlr_output_layout_get_box(view->server->output_layout, NULL); + // *width_out = layout_box->width; + // *height_out = layout_box->height; + *width_out = view->wlr_surface->current.width; + *height_out = view->wlr_surface->current.height; +} + +static bool +is_primary(struct cg_view *view) +{ + return true; +} + +static bool +is_transient_for(struct cg_view *child, struct cg_view *parent) +{ + return false; +} + +static void +maximize(struct cg_view *view, int output_width, int output_height) +{ + // view->wlr_surface->pending.width = output_width; + // view->wlr_surface->pending.height = output_height; +} + +static void +destroy(struct cg_view *view) +{ + struct cg_fullscreen_shell_view *fullscreen_shell_view = fullscreen_shell_view_from_view(view); + free(fullscreen_shell_view); +} + +static void +for_each_surface(struct cg_view *view, wlr_surface_iterator_func_t iterator, void *data) +{ + wlr_surface_for_each_surface(view->wlr_surface, iterator, data); +} + +static struct wlr_surface * +wlr_surface_at(struct cg_view *view, double sx, double sy, double *sub_x, double *sub_y) +{ + return wlr_surface_surface_at(view->wlr_surface, sx, sy, sub_x, sub_y); +} + +//static void output_set_surface(struct cg_output *output, struct wlr_surface *surface); +// +//static void +//output_handle_surface_destroy(struct wl_listener *listener, void *data) +//{ +// struct cg_output *output = wl_container_of(listener, output, surface_destroy); +// output_set_surface(output, NULL); +//} +// +//static void +//output_set_surface(struct cg_output *output, struct wlr_surface *surface) +//{ +// if (output->surface == surface) { +// return; +// } +// +// if (output->surface) { +// wl_list_remove(&output->surface_destroy.link); +// output->surface = NULL; +// } +// +// if (surface) { +// output->surface_destroy.notify = output_handle_surface_destroy; +// wl_signal_add(&surface->events.destroy, &output->surface_destroy); +// output->surface = surface; +// } +// +// wlr_log(WLR_DEBUG, "Presenting fullscreen shell surface %p on output %s", surface, output->wlr_output->name); +//} + +static const struct cg_view_impl fullscreen_shell_view_impl = { + .get_title = NULL, + .get_geometry = get_geometry, + .is_primary = is_primary, + .is_transient_for = is_transient_for, + .activate = NULL, + .maximize = maximize, + .destroy = destroy, + .for_each_surface = for_each_surface, + .for_each_popup = NULL, + .wlr_surface_at = wlr_surface_at, +}; + +void +handle_fullscreen_shell_present_surface(struct wl_listener *listener, void *data) +{ + struct cg_server *server = wl_container_of(listener, server, fullscreen_shell_present_surface); + struct wlr_fullscreen_shell_v1_present_surface_event *event = data; + + struct cg_fullscreen_shell_view *fullscreen_shell_view = calloc(1, sizeof(struct cg_fullscreen_shell_view)); + if (!fullscreen_shell_view) { + wlr_log(WLR_ERROR, "Failed to allocate Fullscreen Shell view"); + return; + } + + view_init(&fullscreen_shell_view->view, server, CAGE_FULLSCREEN_SHELL_VIEW, &fullscreen_shell_view_impl); + view_map(&fullscreen_shell_view->view, event->surface); +} diff --git a/fullscreen_shell.h b/fullscreen_shell.h new file mode 100644 index 0000000..e993894 --- /dev/null +++ b/fullscreen_shell.h @@ -0,0 +1,15 @@ +#ifndef CG_FULLSCREEN_SHELL_H +#define CG_FULLSCREEN_SHELL_H + +#include +#include + +#include "view.h" + +struct cg_fullscreen_shell_view { + struct cg_view view; +}; + +void handle_fullscreen_shell_present_surface(struct wl_listener *listener, void *data); + +#endif diff --git a/meson.build b/meson.build index 84eac11..e14f412 100644 --- a/meson.build +++ b/meson.build @@ -51,6 +51,7 @@ wayland_scanner_server = generator( server_protocols = [ [wl_protocol_dir, 'stable/xdg-shell/xdg-shell.xml'], + [wl_protocol_dir, 'unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml'], ] server_protos_headers = [] @@ -96,6 +97,7 @@ conf_data.set_quoted('CAGE_VERSION', version) cage_sources = [ 'cage.c', + 'fullscreen_shell.c', 'idle_inhibit_v1.c', 'output.c', 'render.c', @@ -109,6 +111,7 @@ cage_headers = [ configure_file(input: 'config.h.in', output: 'config.h', configuration: conf_data), + 'fullscreen_shell.h', 'idle_inhibit_v1.h', 'output.h', 'render.h', diff --git a/server.h b/server.h index d05dabf..e5ba02c 100644 --- a/server.h +++ b/server.h @@ -32,6 +32,7 @@ struct cg_server { struct wl_list outputs; struct wl_listener new_output; + struct wl_listener fullscreen_shell_present_surface; struct wl_listener xdg_toplevel_decoration; struct wl_listener new_xdg_shell_surface; #if CAGE_HAS_XWAYLAND diff --git a/view.c b/view.c index 5f9bed0..bc5ef19 100644 --- a/view.c +++ b/view.c @@ -117,6 +117,10 @@ handle_new_subsurface(struct wl_listener *listener, void *data) char * view_get_title(struct cg_view *view) { + if (!view->impl->get_title) { + return NULL; + } + const char *title = view->impl->get_title(view); if (!title) { return NULL; @@ -156,6 +160,9 @@ view_damage_whole(struct cg_view *view) void view_activate(struct cg_view *view, bool activate) { + if (!view->impl->activate) { + return; + } view->impl->activate(view, activate); } diff --git a/view.h b/view.h index 1da861c..66b1a40 100644 --- a/view.h +++ b/view.h @@ -15,6 +15,7 @@ #include "server.h" enum cg_view_type { + CAGE_FULLSCREEN_SHELL_VIEW, CAGE_XDG_SHELL_VIEW, #if CAGE_HAS_XWAYLAND CAGE_XWAYLAND_VIEW,