[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, §ion, §ion_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