[PATCH weston 6/6] compositor-wayland: Add fullscreen support

Jason Ekstrand jason at jlekstrand.net
Thu Nov 7 18:13:33 PST 2013


This adds fullscreen support to the wayland backend.  You can make any
output fullscreen by the shortcut CTRL+ALT+F.  You can also run weston with
the --fullscreen option which causes it to create a single fullscreen
output.

Signed-off-by: Jason Ekstrand <jason at jlekstrand.net>
---
 src/compositor-wayland.c | 296 ++++++++++++++++++++++++++++++++++++++---------
 src/compositor.c         |   3 +-
 2 files changed, 244 insertions(+), 55 deletions(-)

diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index e688820..6b1c870 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -30,6 +30,7 @@
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/mman.h>
+#include <linux/input.h>
 
 #include <wayland-client.h>
 #include <wayland-egl.h>
@@ -75,10 +76,12 @@ struct wayland_output {
 		int draw_initial_frame;
 		struct wl_surface *surface;
 		struct wl_shell_surface *shell_surface;
+		int configure_width, configure_height;
 	} parent;
 
 	int keyboard_count;
 
+	char *name;
 	struct frame *frame;
 
 	struct {
@@ -552,13 +555,13 @@ wayland_output_destroy(struct weston_output *output_base)
 	wl_surface_destroy(output->parent.surface);
 	wl_shell_surface_destroy(output->parent.shell_surface);
 
-	if (output->frame) {
+	if (output->frame)
 		frame_destroy(output->frame);
-		cairo_surface_destroy(output->gl.border.top);
-		cairo_surface_destroy(output->gl.border.left);
-		cairo_surface_destroy(output->gl.border.right);
-		cairo_surface_destroy(output->gl.border.bottom);
-	}
+
+	cairo_surface_destroy(output->gl.border.top);
+	cairo_surface_destroy(output->gl.border.left);
+	cairo_surface_destroy(output->gl.border.right);
+	cairo_surface_destroy(output->gl.border.bottom);
 
 	weston_output_destroy(&output->base);
 	free(output);
@@ -606,23 +609,191 @@ wayland_output_init_pixman_renderer(struct wayland_output *output)
 	return pixman_renderer_output_create(&output->base);
 }
 
+static void
+wayland_output_resize_surface(struct wayland_output *output)
+{
+	struct wayland_compositor *c =
+		(struct wayland_compositor *)output->base.compositor;
+	struct wayland_shm_buffer *buffer, *next;
+	int32_t ix, iy, iwidth, iheight;
+	int32_t width, height;
+	struct wl_region *region;
+
+	width = output->base.current_mode->width;
+	height = output->base.current_mode->height;
+
+	if (output->frame) {
+		frame_resize_inside(output->frame, width, height);
+
+		frame_input_rect(output->frame, &ix, &iy, &iwidth, &iheight);
+		region = wl_compositor_create_region(c->parent.compositor);
+		wl_region_add(region, ix, iy, iwidth, iheight);
+		wl_surface_set_input_region(output->parent.surface, region);
+		wl_region_destroy(region);
+
+		frame_opaque_rect(output->frame, &ix, &iy, &iwidth, &iheight);
+		region = wl_compositor_create_region(c->parent.compositor);
+		wl_region_add(region, ix, iy, iwidth, iheight);
+		wl_surface_set_opaque_region(output->parent.surface, region);
+		wl_region_destroy(region);
+
+		width = frame_width(output->frame);
+		height = frame_height(output->frame);
+	} else {
+		region = wl_compositor_create_region(c->parent.compositor);
+		wl_region_add(region, 0, 0, width, height);
+		wl_surface_set_input_region(output->parent.surface, region);
+		wl_region_destroy(region);
+
+		region = wl_compositor_create_region(c->parent.compositor);
+		wl_region_add(region, 0, 0, width, height);
+		wl_surface_set_opaque_region(output->parent.surface, region);
+		wl_region_destroy(region);
+	}
+
+	if (output->gl.egl_window) {
+		wl_egl_window_resize(output->gl.egl_window,
+				     width, height, 0, 0);
+
+		/* These will need to be re-created due to the resize */
+		gl_renderer->output_set_border(&output->base,
+					       GL_RENDERER_BORDER_TOP,
+					       0, 0, 0, NULL);
+		cairo_surface_destroy(output->gl.border.top);
+		output->gl.border.top = NULL;
+		gl_renderer->output_set_border(&output->base,
+					       GL_RENDERER_BORDER_LEFT,
+					       0, 0, 0, NULL);
+		cairo_surface_destroy(output->gl.border.left);
+		output->gl.border.left = NULL;
+		gl_renderer->output_set_border(&output->base,
+					       GL_RENDERER_BORDER_RIGHT,
+					       0, 0, 0, NULL);
+		cairo_surface_destroy(output->gl.border.right);
+		output->gl.border.right = NULL;
+		gl_renderer->output_set_border(&output->base,
+					       GL_RENDERER_BORDER_BOTTOM,
+					       0, 0, 0, NULL);
+		cairo_surface_destroy(output->gl.border.bottom);
+		output->gl.border.bottom = NULL;
+	}
+
+	/* Throw away any remaining SHM buffers */
+	wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, link)
+		wayland_shm_buffer_destroy(buffer);
+	/* These will get thrown away when they get released */
+	wl_list_for_each(buffer, &output->shm.buffers, link)
+		buffer->output = NULL;
+}
+
+static int
+wayland_output_set_windowed(struct wayland_output *output)
+{
+	struct wayland_compositor *c =
+		(struct wayland_compositor *)output->base.compositor;
+	int tlen;
+	char *title;
+
+	if (output->frame)
+		return 0;
+
+	if (output->name) {
+		tlen = strlen(output->name) + strlen(WINDOW_TITLE " - ");
+		title = malloc(tlen + 1);
+		if (!title)
+			return -1;
+
+		snprintf(title, tlen + 1, WINDOW_TITLE " - %s", output->name);
+	} else {
+		title = strdup(WINDOW_TITLE);
+	}
+
+	if (!c->theme) {
+		c->theme = theme_create();
+		if (!c->theme) {
+			free(title);
+			return -1;
+		}
+	}
+	output->frame = frame_create(c->theme, 100, 100,
+				     FRAME_BUTTON_CLOSE, title);
+	free(title);
+	if (!output->frame)
+		return -1;
+
+	if (output->keyboard_count)
+		frame_set_flag(output->frame, FRAME_FLAG_ACTIVE);
+
+	wayland_output_resize_surface(output);
+
+	wl_shell_surface_set_toplevel(output->parent.shell_surface);
+
+	return 0;
+}
+
+static void
+wayland_output_set_fullscreen(struct wayland_output *output,
+			      enum wl_shell_surface_fullscreen_method method,
+			      uint32_t framerate, struct wl_output *target)
+{
+	if (output->frame) {
+		frame_destroy(output->frame);
+		output->frame = NULL;
+	}
+
+	wayland_output_resize_surface(output);
+
+	wl_shell_surface_set_fullscreen(output->parent.shell_surface,
+					method, framerate, target);
+}
+
 static struct wayland_output *
 wayland_output_create(struct wayland_compositor *c, int x, int y,
-		      int width, int height, const char *name,
+		      int width, int height, const char *name, int fullscreen,
 		      uint32_t transform, int32_t scale)
 {
 	struct wayland_output *output;
-	int32_t fx, fy, fwidth, fheight;
 	int output_width, output_height;
-	struct wl_region *region;
+
+	weston_log("Creating %dx%d wayland output at (%d, %d)\n",
+		   width, height, x, y);
 
 	output = zalloc(sizeof *output);
 	if (output == NULL)
 		return NULL;
 
+	output->name = name ? strdup(name) : NULL;
+	output->base.make = "waywayland";
+	output->base.model = "none";
+
 	output_width = width * scale;
 	output_height = height * scale;
 
+	output->parent.surface =
+		wl_compositor_create_surface(c->parent.compositor);
+	if (!output->parent.surface)
+		goto err_name;
+	wl_surface_set_user_data(output->parent.surface, output);
+
+	output->parent.draw_initial_frame = 1;
+	output->parent.shell_surface =
+		wl_shell_get_shell_surface(c->parent.shell,
+					   output->parent.surface);
+	if (!output->parent.shell_surface)
+		goto err_surface;
+	wl_shell_surface_add_listener(output->parent.shell_surface,
+				      &shell_surface_listener, output);
+
+	if (fullscreen) {
+		wl_shell_surface_set_fullscreen(output->parent.shell_surface,
+						0, 0, NULL);
+		wl_display_roundtrip(c->parent.wl_display);
+		if (!width)
+			output_width = output->parent.configure_width;
+		if (!height)
+			output_height = output->parent.configure_height;
+	}
+	
 	output->mode.flags =
 		WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
 	output->mode.width = output_width;
@@ -631,60 +802,24 @@ wayland_output_create(struct wayland_compositor *c, int x, int y,
 	output->scale = scale;
 	wl_list_init(&output->base.mode_list);
 	wl_list_insert(&output->base.mode_list, &output->mode.link);
-
-	weston_log("Creating %dx%d wayland output at (%d, %d)\n",
-		   width, height, x, y);
-
 	output->base.current_mode = &output->mode;
-	weston_output_init(&output->base, &c->base, x, y, width, height,
-			   transform, scale);
-
-	output->base.make = "waywayland";
-	output->base.model = "none";
 
 	wl_list_init(&output->shm.buffers);
 	wl_list_init(&output->shm.free_buffers);
 
-	if (!c->theme)
-		c->theme = theme_create();
-	output->frame = frame_create(c->theme, width, height,
-				     FRAME_BUTTON_CLOSE, name);
-	frame_resize_inside(output->frame, output_width, output_height);
-
-	output->parent.surface =
-		wl_compositor_create_surface(c->parent.compositor);
-	wl_surface_set_user_data(output->parent.surface, output);
+	weston_output_init(&output->base, &c->base, x, y, width, height,
+			   transform, scale);
 
 	if (c->use_pixman) {
 		if (wayland_output_init_pixman_renderer(output) < 0)
-			goto cleanup_output;
+			goto err_output;
 		output->base.repaint = wayland_output_repaint_pixman;
 	} else {
 		if (wayland_output_init_gl_renderer(output) < 0)
-			goto cleanup_output;
+			goto err_output;
 		output->base.repaint = wayland_output_repaint_gl;
 	}
 
-	frame_input_rect(output->frame, &fx, &fy, &fwidth, &fheight);
-	region = wl_compositor_create_region(c->parent.compositor);
-	wl_region_add(region, fx, fy, fwidth, fheight);
-	wl_surface_set_input_region(output->parent.surface, region);
-	wl_region_destroy(region);
-
-	frame_opaque_rect(output->frame, &fx, &fy, &fwidth, &fheight);
-	region = wl_compositor_create_region(c->parent.compositor);
-	wl_region_add(region, fx, fy, fwidth, fheight);
-	wl_surface_set_opaque_region(output->parent.surface, region);
-	wl_region_destroy(region);
-
-	output->parent.draw_initial_frame = 1;
-	output->parent.shell_surface =
-		wl_shell_get_shell_surface(c->parent.shell,
-					   output->parent.surface);
-	wl_shell_surface_add_listener(output->parent.shell_surface,
-				      &shell_surface_listener, output);
-	wl_shell_surface_set_toplevel(output->parent.shell_surface);
-
 	output->base.start_repaint_loop = wayland_output_start_repaint_loop;
 	output->base.destroy = wayland_output_destroy;
 	output->base.assign_planes = NULL;
@@ -696,7 +831,14 @@ wayland_output_create(struct wayland_compositor *c, int x, int y,
 
 	return output;
 
-cleanup_output:
+err_output:
+	weston_output_destroy(&output->base);
+	wl_shell_surface_destroy(output->parent.shell_surface);
+err_surface:
+	wl_surface_destroy(output->parent.surface);
+err_name:
+	free(output->name);
+
 	/* FIXME: cleanup weston_output */
 	free(output);
 
@@ -772,7 +914,8 @@ wayland_output_create_for_config(struct wayland_compositor *c,
 		weston_log("Invalid transform \"%s\" for output %s\n", t, name);
 	free(t);
 
-	output = wayland_output_create(c, x, y, width, height, name, transform, scale);
+	output = wayland_output_create(c, x, y, width, height, name, 0,
+				       transform, scale);
 	free(name);
 
 	return output;
@@ -789,6 +932,11 @@ static void
 shell_surface_configure(void *data, struct wl_shell_surface *shell_surface,
 			uint32_t edges, int32_t width, int32_t height)
 {
+	struct wayland_output *output = data;
+
+	output->parent.configure_width = width;
+	output->parent.configure_height = height;
+
 	/* FIXME: implement resizing */
 }
 
@@ -1291,6 +1439,28 @@ create_cursor(struct wayland_compositor *c, struct weston_config *config)
 	}
 }
 
+static void
+fullscreen_binding(struct weston_seat *seat_base, uint32_t time, uint32_t key,
+		   void *data)
+{
+	struct wayland_compositor *c = data;
+	struct wayland_input *input = NULL;
+
+	wl_list_for_each(input, &c->input_list, link)
+		if (&input->base == seat_base)
+			break;
+
+	if (!input || !input->output)
+		return;
+
+	if (input->output->frame)
+		wayland_output_set_fullscreen(input->output, 0, 0, NULL);
+	else
+		wayland_output_set_windowed(input->output);
+
+	weston_output_schedule_repaint(&input->output->base);
+}
+
 static struct wayland_compositor *
 wayland_compositor_create(struct wl_display *display, int use_pixman,
 			  const char *display_name, int *argc, char *argv[],
@@ -1364,6 +1534,10 @@ wayland_compositor_create(struct wl_display *display, int use_pixman,
 
 	wl_event_source_check(c->parent.wl_source);
 
+	weston_compositor_add_key_binding(&c->base, KEY_F,
+				          MODIFIER_CTRL | MODIFIER_ALT,
+				          fullscreen_binding, c);
+
 	return c;
 err_renderer:
 	c->base.renderer->destroy(&c->base);
@@ -1404,7 +1578,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 	struct wayland_compositor *c;
 	struct wayland_output *output;
 	struct weston_config_section *section;
-	int x, count, width, height, scale, use_pixman;
+	int x, count, width, height, scale, use_pixman, fullscreen;
 	const char *section_name, *display_name;
 	char *name;
 
@@ -1415,6 +1589,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 		{ WESTON_OPTION_STRING, "display", 0, &display_name },
 		{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
 		{ WESTON_OPTION_INTEGER, "output-count", 0, &count },
+		{ WESTON_OPTION_BOOLEAN, "fullscreen", 0, &fullscreen },
 	};
 
 	width = 0;
@@ -1423,7 +1598,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 	display_name = NULL;
 	use_pixman = 0;
 	count = 1;
-
+	fullscreen = 0;
 	parse_options(wayland_options,
 		      ARRAY_LENGTH(wayland_options), argc, argv);
 
@@ -1432,6 +1607,15 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 	if (!c)
 		return NULL;
 
+	if (fullscreen) {
+		output = wayland_output_create(c, 0, 0, width, height,
+					       NULL, 1, 0, 1);
+		if (!output)
+			goto err_outputs;
+
+		return &c->base;
+	}
+
 	section = NULL;
 	x = 0;
 	while (weston_config_next_section(config, &section, &section_name)) {
@@ -1451,6 +1635,8 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 							  height, scale, x, 0);
 		if (!output)
 			goto err_outputs;
+		if (wayland_output_set_windowed(output))
+			goto err_outputs;
 
 		x += output->base.width;
 		--count;
@@ -1464,9 +1650,11 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
 		scale = 1;
 	while (count > 0) {
 		output = wayland_output_create(c, x, 0, width, height,
-					       NULL, 0, scale);
+					       NULL, 0, 0, scale);
 		if (!output)
 			goto err_outputs;
+		if (wayland_output_set_windowed(output))
+			goto err_outputs;
 
 		x += width;
 		--count;
diff --git a/src/compositor.c b/src/compositor.c
index d77d565..2ca73d9 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -3699,7 +3699,8 @@ usage(int error_code)
 		"Options for wayland-backend.so:\n\n"
 		"  --width=WIDTH\t\tWidth of Wayland surface\n"
 		"  --height=HEIGHT\tHeight of Wayland surface\n"
- 		"  --scale=SCALE\tScale factor of ouput\n"
+		"  --scale=SCALE\tScale factor of ouput\n"
+		"  --fullscreen\t\tRun in fullscreen mode\n"
 		"  --use-pixman\t\tUse the pixman (CPU) renderer\n"
 		"  --output-count=COUNT\tCreate multiple outputs\n"
 		"  --display=DISPLAY\tWayland display to connect to\n\n");
-- 
1.8.3.1



More information about the wayland-devel mailing list