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 <[email protected]>
---
 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

_______________________________________________
wayland-devel mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/wayland-devel

Reply via email to