input: introduce weston_touch_device
[platform/upstream/weston.git] / libweston / compositor-wayland.c
index 7c12b4c..5ed90c0 100644 (file)
@@ -26,6 +26,7 @@
 
 #include "config.h"
 
+#include <assert.h>
 #include <stddef.h>
 #include <stdint.h>
 #include <stdio.h>
 #include <linux/input.h>
 
 #include <wayland-client.h>
-#include <wayland-egl.h>
 #include <wayland-cursor.h>
 
+#ifdef ENABLE_EGL
+#include <wayland-egl.h>
+#endif
+
 #include "compositor.h"
 #include "compositor-wayland.h"
 #include "gl-renderer.h"
+#include "weston-egl-ext.h"
 #include "pixman-renderer.h"
 #include "shared/helpers.h"
 #include "shared/image-loader.h"
 #include "shared/os-compatibility.h"
 #include "shared/cairo-util.h"
+#include "shared/timespec-util.h"
 #include "fullscreen-shell-unstable-v1-client-protocol.h"
+#include "xdg-shell-unstable-v6-client-protocol.h"
 #include "presentation-time-server-protocol.h"
 #include "linux-dmabuf.h"
+#include "windowed-output-api.h"
 
 #define WINDOW_TITLE "Weston Compositor"
 
@@ -63,6 +71,7 @@ struct wayland_backend {
                struct wl_registry *registry;
                struct wl_compositor *compositor;
                struct wl_shell *shell;
+               struct zxdg_shell_v6 *xdg_shell;
                struct zwp_fullscreen_shell_v1 *fshell;
                struct wl_shm *shm;
 
@@ -72,8 +81,9 @@ struct wayland_backend {
                uint32_t event_mask;
        } parent;
 
-       int use_pixman;
-       int sprawl_across_outputs;
+       bool use_pixman;
+       bool sprawl_across_outputs;
+       bool fullscreen;
 
        struct theme *theme;
        cairo_device_t *frame_device;
@@ -87,19 +97,22 @@ struct wayland_output {
        struct weston_output base;
 
        struct {
-               int draw_initial_frame;
+               bool draw_initial_frame;
                struct wl_surface *surface;
 
                struct wl_output *output;
                uint32_t global_id;
 
                struct wl_shell_surface *shell_surface;
+               struct zxdg_surface_v6 *xdg_surface;
+               struct zxdg_toplevel_v6 *xdg_toplevel;
                int configure_width, configure_height;
+               bool wait_for_configure;
        } parent;
 
        int keyboard_count;
 
-       char *name;
+       char *title;
        struct frame *frame;
 
        struct {
@@ -118,11 +131,13 @@ struct wayland_output {
        } shm;
 
        struct weston_mode mode;
-       uint32_t scale;
+
+       struct wl_callback *frame_cb;
 };
 
 struct wayland_parent_output {
-       struct wayland_output *output;
+       struct wayland_backend *backend;        /**< convenience */
+       struct wayland_head *head;
        struct wl_list link;
 
        struct wl_output *global;
@@ -139,11 +154,18 @@ struct wayland_parent_output {
        uint32_t transform;
        uint32_t scale;
 
+       struct wl_callback *sync_cb;    /**< wl_output < 2 done replacement */
+
        struct wl_list mode_list;
        struct weston_mode *preferred_mode;
        struct weston_mode *current_mode;
 };
 
+struct wayland_head {
+       struct weston_head base;
+       struct wayland_parent_output *parent_output;
+};
+
 struct wayland_shm_buffer {
        struct wayland_output *output;
        struct wl_list link;
@@ -152,7 +174,7 @@ struct wayland_shm_buffer {
        struct wl_buffer *buffer;
        void *data;
        size_t size;
-       pixman_region32_t damage;
+       pixman_region32_t damage;               /**< in global coords */
        int frame_damaged;
 
        pixman_image_t *pm_image;
@@ -176,6 +198,8 @@ struct wayland_input {
                } cursor;
        } parent;
 
+       struct weston_touch_device *touch_device;
+
        enum weston_key_state_update keyboard_state_update;
        uint32_t key_serial;
        uint32_t enter_serial;
@@ -193,6 +217,12 @@ struct wayland_input {
 
 struct gl_renderer_interface *gl_renderer;
 
+static inline struct wayland_head *
+to_wayland_head(struct weston_head *base)
+{
+       return container_of(base, struct wayland_head, base);
+}
+
 static inline struct wayland_output *
 to_wayland_output(struct weston_output *base)
 {
@@ -287,7 +317,7 @@ wayland_output_get_shm_buffer(struct wayland_output *output)
        if (sb == NULL) {
                weston_log("could not zalloc %zu memory for sb: %m\n", sizeof *sb);
                close(fd);
-               free(data);
+               munmap(data, height * stride);
                return NULL;
        }
 
@@ -295,8 +325,8 @@ wayland_output_get_shm_buffer(struct wayland_output *output)
        wl_list_init(&sb->free_link);
        wl_list_insert(&output->shm.buffers, &sb->link);
 
-       pixman_region32_init_rect(&sb->damage, 0, 0,
-                                 output->base.width, output->base.height);
+       pixman_region32_init(&sb->damage);
+       pixman_region32_copy(&sb->damage, &output->base.region);
        sb->frame_damaged = 1;
 
        sb->data = data;
@@ -333,10 +363,12 @@ wayland_output_get_shm_buffer(struct wayland_output *output)
 static void
 frame_done(void *data, struct wl_callback *callback, uint32_t time)
 {
-       struct weston_output *output = data;
+       struct wayland_output *output = data;
        struct timespec ts;
 
+       assert(callback == output->frame_cb);
        wl_callback_destroy(callback);
+       output->frame_cb = NULL;
 
        /* XXX: use the presentation extension for proper timings */
 
@@ -347,8 +379,8 @@ frame_done(void *data, struct wl_callback *callback, uint32_t time)
         * we can, and pretend finish_frame time is when we process this
         * event.
         */
-       weston_compositor_read_presentation_clock(output->compositor, &ts);
-       weston_output_finish_frame(output, &ts, 0);
+       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
+       weston_output_finish_frame(&output->base, &ts, 0);
 }
 
 static const struct wl_callback_listener frame_listener = {
@@ -373,6 +405,7 @@ draw_initial_frame(struct wayland_output *output)
                          output->base.current_mode->height);
 }
 
+#ifdef ENABLE_EGL
 static void
 wayland_output_update_gl_border(struct wayland_output *output)
 {
@@ -442,6 +475,7 @@ wayland_output_update_gl_border(struct wayland_output *output)
                                       cairo_image_surface_get_stride(output->gl.border.bottom) / 4,
                                       cairo_image_surface_get_data(output->gl.border.bottom));
 }
+#endif
 
 static void
 wayland_output_start_repaint_loop(struct weston_output *output_base)
@@ -449,7 +483,6 @@ wayland_output_start_repaint_loop(struct weston_output *output_base)
        struct wayland_output *output = to_wayland_output(output_base);
        struct wayland_backend *wb =
                to_wayland_backend(output->base.compositor);
-       struct wl_callback *callback;
 
        /* If this is the initial frame, we need to attach a buffer so that
         * the compositor can map the surface and include it in its render
@@ -457,27 +490,28 @@ wayland_output_start_repaint_loop(struct weston_output *output_base)
         * callback won't be invoked. The buffer is transparent and of the
         * same size as the future real output buffer. */
        if (output->parent.draw_initial_frame) {
-               output->parent.draw_initial_frame = 0;
+               output->parent.draw_initial_frame = false;
 
                draw_initial_frame(output);
        }
 
-       callback = wl_surface_frame(output->parent.surface);
-       wl_callback_add_listener(callback, &frame_listener, output);
+       output->frame_cb = wl_surface_frame(output->parent.surface);
+       wl_callback_add_listener(output->frame_cb, &frame_listener, output);
        wl_surface_commit(output->parent.surface);
        wl_display_flush(wb->parent.wl_display);
 }
 
+#ifdef ENABLE_EGL
 static int
 wayland_output_repaint_gl(struct weston_output *output_base,
-                         pixman_region32_t *damage)
+                         pixman_region32_t *damage,
+                         void *repaint_data)
 {
        struct wayland_output *output = to_wayland_output(output_base);
        struct weston_compositor *ec = output->base.compositor;
-       struct wl_callback *callback;
 
-       callback = wl_surface_frame(output->parent.surface);
-       wl_callback_add_listener(callback, &frame_listener, output);
+       output->frame_cb = wl_surface_frame(output->parent.surface);
+       wl_callback_add_listener(output->frame_cb, &frame_listener, output);
 
        wayland_output_update_gl_border(output);
 
@@ -487,6 +521,7 @@ wayland_output_repaint_gl(struct weston_output *output_base,
                                 &ec->primary_plane.damage, damage);
        return 0;
 }
+#endif
 
 static void
 wayland_output_update_shm_border(struct wayland_shm_buffer *buffer)
@@ -537,11 +572,15 @@ wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
        int i, n;
 
        pixman_region32_init(&damage);
+       pixman_region32_copy(&damage, &sb->damage);
+       pixman_region32_translate(&damage, -sb->output->base.x,
+                                 -sb->output->base.y);
+
        weston_transformed_region(sb->output->base.width,
                                  sb->output->base.height,
                                  sb->output->base.transform,
                                  sb->output->base.current_scale,
-                                 &sb->damage, &damage);
+                                 &damage, &damage);
 
        if (sb->output->frame) {
                frame_interior(sb->output->frame, &ix, &iy, &iwidth, &iheight);
@@ -577,12 +616,12 @@ wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
 
 static int
 wayland_output_repaint_pixman(struct weston_output *output_base,
-                             pixman_region32_t *damage)
+                             pixman_region32_t *damage,
+                             void *repaint_data)
 {
        struct wayland_output *output = to_wayland_output(output_base);
        struct wayland_backend *b =
                to_wayland_backend(output->base.compositor);
-       struct wl_callback *callback;
        struct wayland_shm_buffer *sb;
 
        if (output->frame) {
@@ -602,8 +641,8 @@ wayland_output_repaint_pixman(struct weston_output *output_base,
 
        wayland_shm_buffer_attach(sb);
 
-       callback = wl_surface_frame(output->parent.surface);
-       wl_callback_add_listener(callback, &frame_listener, output);
+       output->frame_cb = wl_surface_frame(output->parent.surface);
+       wl_callback_add_listener(output->frame_cb, &frame_listener, output);
        wl_surface_commit(output->parent.surface);
        wl_display_flush(b->parent.wl_display);
 
@@ -617,22 +656,63 @@ wayland_output_repaint_pixman(struct weston_output *output_base,
 }
 
 static void
-wayland_output_destroy(struct weston_output *output_base)
+wayland_backend_destroy_output_surface(struct wayland_output *output)
 {
-       struct wayland_output *output = to_wayland_output(output_base);
-       struct wayland_backend *b =
-               to_wayland_backend(output->base.compositor);
+       assert(output->parent.surface);
+
+       if (output->parent.xdg_toplevel) {
+               zxdg_toplevel_v6_destroy(output->parent.xdg_toplevel);
+               output->parent.xdg_toplevel = NULL;
+       }
+
+       if (output->parent.xdg_surface) {
+               zxdg_surface_v6_destroy(output->parent.xdg_surface);
+               output->parent.xdg_surface = NULL;
+       }
+
+       if (output->parent.shell_surface) {
+               wl_shell_surface_destroy(output->parent.shell_surface);
+               output->parent.shell_surface = NULL;
+       }
+
+       wl_surface_destroy(output->parent.surface);
+       output->parent.surface = NULL;
+}
+
+static void
+wayland_output_destroy_shm_buffers(struct wayland_output *output)
+{
+       struct wayland_shm_buffer *buffer, *next;
+
+       /* Throw away any remaining SHM buffers */
+       wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, free_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_disable(struct weston_output *base)
+{
+       struct wayland_output *output = to_wayland_output(base);
+       struct wayland_backend *b = to_wayland_backend(base->compositor);
+
+       if (!output->base.enabled)
+               return 0;
 
        if (b->use_pixman) {
-               pixman_renderer_output_destroy(output_base);
+               pixman_renderer_output_destroy(&output->base);
+#ifdef ENABLE_EGL
        } else {
-               gl_renderer->output_destroy(output_base);
+               gl_renderer->output_destroy(&output->base);
+               wl_egl_window_destroy(output->gl.egl_window);
+#endif
        }
 
-       wl_egl_window_destroy(output->gl.egl_window);
-       wl_surface_destroy(output->parent.surface);
-       if (output->parent.shell_surface)
-               wl_shell_surface_destroy(output->parent.shell_surface);
+       wayland_output_destroy_shm_buffers(output);
+
+       wayland_backend_destroy_output_surface(output);
 
        if (output->frame)
                frame_destroy(output->frame);
@@ -642,14 +722,28 @@ wayland_output_destroy(struct weston_output *output_base)
        cairo_surface_destroy(output->gl.border.right);
        cairo_surface_destroy(output->gl.border.bottom);
 
-       weston_output_destroy(&output->base);
-       free(output);
+       return 0;
+}
 
-       return;
+static void
+wayland_output_destroy(struct weston_output *base)
+{
+       struct wayland_output *output = to_wayland_output(base);
+
+       wayland_output_disable(&output->base);
+
+       weston_output_release(&output->base);
+
+       if (output->frame_cb)
+               wl_callback_destroy(output->frame_cb);
+
+       free(output->title);
+       free(output);
 }
 
 static const struct wl_shell_surface_listener shell_surface_listener;
 
+#ifdef ENABLE_EGL
 static int
 wayland_output_init_gl_renderer(struct wayland_output *output)
 {
@@ -671,12 +765,12 @@ wayland_output_init_gl_renderer(struct wayland_output *output)
                return -1;
        }
 
-       if (gl_renderer->output_create(&output->base,
-                                      output->gl.egl_window,
-                                      output->gl.egl_window,
-                                      gl_renderer->alpha_attribs,
-                                      NULL,
-                                      0) < 0)
+       if (gl_renderer->output_window_create(&output->base,
+                                             output->gl.egl_window,
+                                             output->gl.egl_window,
+                                             gl_renderer->alpha_attribs,
+                                             NULL,
+                                             0) < 0)
                goto cleanup_window;
 
        return 0;
@@ -685,11 +779,13 @@ cleanup_window:
        wl_egl_window_destroy(output->gl.egl_window);
        return -1;
 }
+#endif
 
 static int
 wayland_output_init_pixman_renderer(struct wayland_output *output)
 {
-       return pixman_renderer_output_create(&output->base);
+       return pixman_renderer_output_create(&output->base,
+                                    PIXMAN_RENDERER_OUTPUT_USE_SHADOW);
 }
 
 static void
@@ -697,7 +793,6 @@ wayland_output_resize_surface(struct wayland_output *output)
 {
        struct wayland_backend *b =
                to_wayland_backend(output->base.compositor);
-       struct wayland_shm_buffer *buffer, *next;
        int32_t ix, iy, iwidth, iheight;
        int32_t width, height;
        struct wl_region *region;
@@ -714,6 +809,14 @@ wayland_output_resize_surface(struct wayland_output *output)
                wl_surface_set_input_region(output->parent.surface, region);
                wl_region_destroy(region);
 
+               if (output->parent.xdg_surface) {
+                       zxdg_surface_v6_set_window_geometry(output->parent.xdg_surface,
+                                                           ix,
+                                                           iy,
+                                                           iwidth,
+                                                           iheight);
+               }
+
                frame_opaque_rect(output->frame, &ix, &iy, &iwidth, &iheight);
                region = wl_compositor_create_region(b->parent.compositor);
                wl_region_add(region, ix, iy, iwidth, iheight);
@@ -732,8 +835,17 @@ wayland_output_resize_surface(struct wayland_output *output)
                wl_region_add(region, 0, 0, width, height);
                wl_surface_set_opaque_region(output->parent.surface, region);
                wl_region_destroy(region);
+
+               if (output->parent.xdg_surface) {
+                       zxdg_surface_v6_set_window_geometry(output->parent.xdg_surface,
+                                                           0,
+                                                           0,
+                                                           width,
+                                                           height);
+               }
        }
 
+#ifdef ENABLE_EGL
        if (output->gl.egl_window) {
                wl_egl_window_resize(output->gl.egl_window,
                                     width, height, 0, 0);
@@ -760,13 +872,9 @@ wayland_output_resize_surface(struct wayland_output *output)
                cairo_surface_destroy(output->gl.border.bottom);
                output->gl.border.bottom = NULL;
        }
+#endif
 
-       /* Throw away any remaining SHM buffers */
-       wl_list_for_each_safe(buffer, next, &output->shm.free_buffers, free_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;
+       wayland_output_destroy_shm_buffers(output);
 }
 
 static int
@@ -774,33 +882,17 @@ wayland_output_set_windowed(struct wayland_output *output)
 {
        struct wayland_backend *b =
                to_wayland_backend(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 (!b->theme) {
                b->theme = theme_create();
-               if (!b->theme) {
-                       free(title);
+               if (!b->theme)
                        return -1;
-               }
        }
        output->frame = frame_create(b->theme, 100, 100,
-                                    FRAME_BUTTON_CLOSE, title);
-       free(title);
+                                    FRAME_BUTTON_CLOSE, output->title, NULL);
        if (!output->frame)
                return -1;
 
@@ -809,7 +901,13 @@ wayland_output_set_windowed(struct wayland_output *output)
 
        wayland_output_resize_surface(output);
 
-       wl_shell_surface_set_toplevel(output->parent.shell_surface);
+       if (output->parent.xdg_toplevel) {
+               zxdg_toplevel_v6_unset_fullscreen(output->parent.xdg_toplevel);
+       } else if (output->parent.shell_surface) {
+               wl_shell_surface_set_toplevel(output->parent.shell_surface);
+       } else {
+               abort();
+       }
 
        return 0;
 }
@@ -819,9 +917,6 @@ wayland_output_set_fullscreen(struct wayland_output *output,
                              enum wl_shell_surface_fullscreen_method method,
                              uint32_t framerate, struct wl_output *target)
 {
-       struct wayland_backend *b =
-               to_wayland_backend(output->base.compositor);
-
        if (output->frame) {
                frame_destroy(output->frame);
                output->frame = NULL;
@@ -829,13 +924,13 @@ wayland_output_set_fullscreen(struct wayland_output *output,
 
        wayland_output_resize_surface(output);
 
-       if (output->parent.shell_surface) {
+       if (output->parent.xdg_toplevel) {
+               zxdg_toplevel_v6_set_fullscreen(output->parent.xdg_toplevel, target);
+       } else if (output->parent.shell_surface) {
                wl_shell_surface_set_fullscreen(output->parent.shell_surface,
                                                method, framerate, target);
-       } else if (b->parent.fshell) {
-               zwp_fullscreen_shell_v1_present_surface(b->parent.fshell,
-                                                       output->parent.surface,
-                                                       method, target);
+       } else {
+               abort();
        }
 }
 
@@ -906,6 +1001,38 @@ struct zwp_fullscreen_shell_mode_feedback_v1_listener mode_feedback_listener = {
        mode_feedback_cancelled,
 };
 
+static enum mode_status
+wayland_output_fullscreen_shell_mode_feedback(struct wayland_output *output,
+                                             struct weston_mode *mode)
+{
+       struct wayland_backend *b = to_wayland_backend(output->base.compositor);
+       struct zwp_fullscreen_shell_mode_feedback_v1 *mode_feedback;
+       enum mode_status mode_status;
+       int ret = 0;
+
+       mode_feedback =
+               zwp_fullscreen_shell_v1_present_surface_for_mode(b->parent.fshell,
+                                                                output->parent.surface,
+                                                                output->parent.output,
+                                                                mode->refresh);
+
+       zwp_fullscreen_shell_mode_feedback_v1_add_listener(mode_feedback,
+                                                          &mode_feedback_listener,
+                                                          &mode_status);
+
+       output->parent.draw_initial_frame = false;
+       draw_initial_frame(output);
+       wl_surface_commit(output->parent.surface);
+
+       mode_status = MODE_STATUS_UNKNOWN;
+       while (mode_status == MODE_STATUS_UNKNOWN && ret >= 0)
+               ret = wl_display_dispatch(b->parent.wl_display);
+
+       zwp_fullscreen_shell_mode_feedback_v1_destroy(mode_feedback);
+
+       return mode_status;
+}
+
 static int
 wayland_output_switch_mode(struct weston_output *output_base,
                           struct weston_mode *mode)
@@ -914,9 +1041,7 @@ wayland_output_switch_mode(struct weston_output *output_base,
        struct wayland_backend *b;
        struct wl_surface *old_surface;
        struct weston_mode *old_mode;
-       struct zwp_fullscreen_shell_mode_feedback_v1 *mode_feedback;
        enum mode_status mode_status;
-       int ret = 0;
 
        if (output_base == NULL) {
                weston_log("output is NULL.\n");
@@ -930,7 +1055,7 @@ wayland_output_switch_mode(struct weston_output *output_base,
 
        b = to_wayland_backend(output_base->compositor);
 
-       if (output->parent.shell_surface || !b->parent.fshell)
+       if (output->parent.xdg_surface || output->parent.shell_surface || !b->parent.fshell)
                return -1;
 
        mode = wayland_output_choose_mode(output, mode);
@@ -950,25 +1075,11 @@ wayland_output_switch_mode(struct weston_output *output_base,
        /* Blow the old buffers because we changed size/surfaces */
        wayland_output_resize_surface(output);
 
-       mode_feedback =
-               zwp_fullscreen_shell_v1_present_surface_for_mode(b->parent.fshell,
-                                                                output->parent.surface,
-                                                                output->parent.output,
-                                                                mode->refresh);
-       zwp_fullscreen_shell_mode_feedback_v1_add_listener(mode_feedback,
-                                                          &mode_feedback_listener,
-                                                          &mode_status);
+       mode_status = wayland_output_fullscreen_shell_mode_feedback(output, mode);
 
        /* This should kick-start things again */
-       output->parent.draw_initial_frame = 1;
        wayland_output_start_repaint_loop(&output->base);
 
-       mode_status = MODE_STATUS_UNKNOWN;
-       while (mode_status == MODE_STATUS_UNKNOWN && ret >= 0)
-               ret = wl_display_dispatch(b->parent.wl_display);
-
-       zwp_fullscreen_shell_mode_feedback_v1_destroy(mode_feedback);
-
        if (mode_status == MODE_STATUS_FAIL) {
                output->base.current_mode = old_mode;
                wl_surface_destroy(output->parent.surface);
@@ -985,11 +1096,13 @@ wayland_output_switch_mode(struct weston_output *output_base,
                pixman_renderer_output_destroy(output_base);
                if (wayland_output_init_pixman_renderer(output) < 0)
                        goto err_output;
+#ifdef ENABLE_EGL
        } else {
                gl_renderer->output_destroy(output_base);
                wl_egl_window_destroy(output->gl.egl_window);
                if (wayland_output_init_gl_renderer(output) < 0)
                        goto err_output;
+#endif
        }
        wl_surface_destroy(old_surface);
 
@@ -1002,128 +1115,386 @@ err_output:
        return -1;
 }
 
-static struct wayland_output *
-wayland_output_create(struct wayland_backend *b, int x, int y,
-                     int width, int height, const char *name, int fullscreen,
-                     uint32_t transform, int32_t scale)
+static void
+handle_xdg_surface_configure(void *data, struct zxdg_surface_v6 *surface,
+                        uint32_t serial)
 {
-       struct wayland_output *output;
-       int output_width, output_height;
+       zxdg_surface_v6_ack_configure(surface, serial);
+}
 
-       weston_log("Creating %dx%d wayland output at (%d, %d)\n",
-                  width, height, x, y);
+static const struct zxdg_surface_v6_listener xdg_surface_listener = {
+       handle_xdg_surface_configure
+};
 
-       output = zalloc(sizeof *output);
-       if (output == NULL)
-               return NULL;
+static void
+handle_xdg_toplevel_configure(void *data, struct zxdg_toplevel_v6 *toplevel,
+                         int32_t width, int32_t height,
+                         struct wl_array *states)
+{
+       struct wayland_output *output = data;
+
+       output->parent.configure_width = width;
+       output->parent.configure_height = height;
 
-       output->name = name ? strdup(name) : NULL;
-       output->base.make = "wayland";
-       output->base.model = "none";
+       output->parent.wait_for_configure = false;
+       /* FIXME: implement resizing */
+}
 
-       output_width = width * scale;
-       output_height = height * scale;
+static void
+handle_xdg_toplevel_close(void *data, struct zxdg_toplevel_v6 *xdg_toplevel)
+{
+       struct wayland_output *output = data;
+       struct weston_compositor *compositor = output->base.compositor;
+
+       wayland_output_destroy(&output->base);
+
+       if (wl_list_empty(&compositor->output_list))
+               weston_compositor_exit(compositor);
+}
+
+static const struct zxdg_toplevel_v6_listener xdg_toplevel_listener = {
+       handle_xdg_toplevel_configure,
+       handle_xdg_toplevel_close,
+};
+
+static int
+wayland_backend_create_output_surface(struct wayland_output *output)
+{
+       struct wayland_backend *b = to_wayland_backend(output->base.compositor);
+
+       assert(!output->parent.surface);
 
        output->parent.surface =
                wl_compositor_create_surface(b->parent.compositor);
        if (!output->parent.surface)
-               goto err_name;
+               return -1;
+
        wl_surface_set_user_data(output->parent.surface, output);
 
-       output->parent.draw_initial_frame = 1;
+       output->parent.draw_initial_frame = true;
+
+       if (b->parent.xdg_shell) {
+               output->parent.xdg_surface =
+                       zxdg_shell_v6_get_xdg_surface(b->parent.xdg_shell,
+                                                     output->parent.surface);
+               zxdg_surface_v6_add_listener(output->parent.xdg_surface,
+                                            &xdg_surface_listener, output);
+
+               output->parent.xdg_toplevel =
+                       zxdg_surface_v6_get_toplevel(output->parent.xdg_surface);
+               zxdg_toplevel_v6_add_listener(output->parent.xdg_toplevel,
+                                             &xdg_toplevel_listener, output);
 
-       if (b->parent.shell) {
+               zxdg_toplevel_v6_set_title(output->parent.xdg_toplevel, output->title);
+
+               wl_surface_commit(output->parent.surface);
+
+               output->parent.wait_for_configure = true;
+
+               while (output->parent.wait_for_configure)
+                       wl_display_dispatch(b->parent.wl_display);
+
+               weston_log("wayland-backend: Using xdg_shell_v6\n");
+       }
+       else if (b->parent.shell) {
                output->parent.shell_surface =
                        wl_shell_get_shell_surface(b->parent.shell,
                                                   output->parent.surface);
-               if (!output->parent.shell_surface)
-                       goto err_surface;
+               if (!output->parent.shell_surface) {
+                       wl_surface_destroy(output->parent.surface);
+                       return -1;
+               }
+
                wl_shell_surface_add_listener(output->parent.shell_surface,
                                              &shell_surface_listener, output);
-       }
 
-       if (fullscreen && b->parent.shell) {
-               wl_shell_surface_set_fullscreen(output->parent.shell_surface,
-                                               0, 0, NULL);
-               wl_display_roundtrip(b->parent.wl_display);
-               if (!width)
-                       output_width = output->parent.configure_width;
-               if (!height)
-                       output_height = output->parent.configure_height;
+               weston_log("wayland-backend: Using wl_shell\n");
        }
 
-       output->mode.flags =
-               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-       output->mode.width = output_width;
-       output->mode.height = output_height;
-       output->mode.refresh = 60000;
-       output->scale = scale;
-       wl_list_init(&output->base.mode_list);
-       wl_list_insert(&output->base.mode_list, &output->mode.link);
-       output->base.current_mode = &output->mode;
+       return 0;
+}
+
+static int
+wayland_output_enable(struct weston_output *base)
+{
+       struct wayland_output *output = to_wayland_output(base);
+       struct wayland_backend *b = to_wayland_backend(base->compositor);
+       enum mode_status mode_status;
+       int ret = 0;
+
+       weston_log("Creating %dx%d wayland output at (%d, %d)\n",
+                  output->base.current_mode->width,
+                  output->base.current_mode->height,
+                  output->base.x, output->base.y);
+
+       if (!output->parent.surface)
+               ret = wayland_backend_create_output_surface(output);
+
+       if (ret < 0)
+               return -1;
 
        wl_list_init(&output->shm.buffers);
        wl_list_init(&output->shm.free_buffers);
 
-       weston_output_init(&output->base, b->compositor, x, y, width, height,
-                          transform, scale);
-
        if (b->use_pixman) {
                if (wayland_output_init_pixman_renderer(output) < 0)
                        goto err_output;
+
                output->base.repaint = wayland_output_repaint_pixman;
+#ifdef ENABLE_EGL
        } else {
                if (wayland_output_init_gl_renderer(output) < 0)
                        goto err_output;
+
                output->base.repaint = wayland_output_repaint_gl;
+#endif
        }
 
        output->base.start_repaint_loop = wayland_output_start_repaint_loop;
-       output->base.destroy = wayland_output_destroy;
        output->base.assign_planes = NULL;
        output->base.set_backlight = NULL;
        output->base.set_dpms = NULL;
        output->base.switch_mode = wayland_output_switch_mode;
 
-       weston_compositor_add_output(b->compositor, &output->base);
+       if (b->sprawl_across_outputs) {
+               if (b->parent.fshell) {
+                       wayland_output_resize_surface(output);
+
+                       mode_status = wayland_output_fullscreen_shell_mode_feedback(output, &output->mode);
+
+                       if (mode_status == MODE_STATUS_FAIL) {
+                               zwp_fullscreen_shell_v1_present_surface(b->parent.fshell,
+                                                                       output->parent.surface,
+                                                                       ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER,
+                                                                       output->parent.output);
+
+                               output->parent.draw_initial_frame = true;
+                       }
+               } else {
+                       wayland_output_set_fullscreen(output,
+                                                     WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER,
+                                                     output->mode.refresh, output->parent.output);
+               }
+       } else if (b->fullscreen) {
+               wayland_output_set_fullscreen(output, 0, 0, NULL);
+       } else {
+               wayland_output_set_windowed(output);
+       }
 
-       return output;
+       return 0;
 
 err_output:
-       weston_output_destroy(&output->base);
-       if (output->parent.shell_surface)
-               wl_shell_surface_destroy(output->parent.shell_surface);
-err_surface:
-       wl_surface_destroy(output->parent.surface);
-err_name:
-       free(output->name);
+       wayland_backend_destroy_output_surface(output);
 
-       /* FIXME: cleanup weston_output */
-       free(output);
+       return -1;
+}
 
-       return NULL;
+static int
+wayland_output_setup_for_parent_output(struct wayland_output *output,
+                                      struct wayland_parent_output *poutput);
+
+static int
+wayland_output_setup_fullscreen(struct wayland_output *output,
+                               struct wayland_head *head);
+
+static int
+wayland_output_attach_head(struct weston_output *output_base,
+                          struct weston_head *head_base)
+{
+       struct wayland_backend *b = to_wayland_backend(output_base->compositor);
+       struct wayland_output *output = to_wayland_output(output_base);
+       struct wayland_head *head = to_wayland_head(head_base);
+
+       if (!wl_list_empty(&output->base.head_list))
+               return -1;
+
+       if (head->parent_output) {
+               if (wayland_output_setup_for_parent_output(output,
+                                                          head->parent_output) < 0)
+                       return -1;
+       } else if (b->fullscreen) {
+               if (wayland_output_setup_fullscreen(output, head) < 0)
+                       return -1;
+       } else {
+               /* A floating window, nothing to do. */
+       }
+
+       return 0;
 }
 
-static struct wayland_output *
-wayland_output_create_for_config(struct wayland_backend *b,
-                                struct weston_wayland_backend_output_config *oc,
-                                int fullscreen, int32_t x, int32_t y)
+static void
+wayland_output_detach_head(struct weston_output *output_base,
+                          struct weston_head *head)
 {
-       struct wayland_output *output;
+       struct wayland_output *output = to_wayland_output(output_base);
 
-       output = wayland_output_create(b, x, y, oc->width, oc->height, oc->name,
-                                      fullscreen, oc->transform, oc->scale);
+       /* Rely on the disable hook if the output was enabled. We do not
+        * support cloned heads, so detaching is guaranteed to disable the
+        * output.
+        */
+       if (output->base.enabled)
+               return;
 
-       return output;
+       /* undo setup fullscreen */
+       if (output->parent.surface)
+               wayland_backend_destroy_output_surface(output);
 }
 
-static struct wayland_output *
-wayland_output_create_for_parent_output(struct wayland_backend *b,
-                                       struct wayland_parent_output *poutput)
+static struct weston_output *
+wayland_output_create(struct weston_compositor *compositor, const char *name)
 {
        struct wayland_output *output;
+       char *title;
+
+       /* name can't be NULL. */
+       assert(name);
+
+       output = zalloc(sizeof *output);
+       if (output == NULL) {
+               perror("zalloc");
+               return NULL;
+       }
+
+       if (asprintf(&title, "%s - %s", WINDOW_TITLE, name) < 0) {
+               free(output);
+               return NULL;
+       }
+       output->title = title;
+
+       weston_output_init(&output->base, compositor, name);
+
+       output->base.destroy = wayland_output_destroy;
+       output->base.disable = wayland_output_disable;
+       output->base.enable = wayland_output_enable;
+       output->base.attach_head = wayland_output_attach_head;
+       output->base.detach_head = wayland_output_detach_head;
+
+       weston_compositor_add_pending_output(&output->base, compositor);
+
+       return &output->base;
+}
+
+static struct wayland_head *
+wayland_head_create(struct weston_compositor *compositor, const char *name)
+{
+       struct wayland_head *head;
+
+       assert(name);
+
+       head = zalloc(sizeof *head);
+       if (!head)
+               return NULL;
+
+       weston_head_init(&head->base, name);
+       weston_head_set_connection_status(&head->base, true);
+       weston_compositor_add_head(compositor, &head->base);
+
+       return head;
+}
+
+static int
+wayland_head_create_windowed(struct weston_compositor *compositor,
+                            const char *name)
+{
+        if (!wayland_head_create(compositor, name))
+               return -1;
+
+       return 0;
+}
+
+static int
+wayland_head_create_for_parent_output(struct weston_compositor *compositor,
+                                     struct wayland_parent_output *poutput)
+{
+       struct wayland_head *head;
+       char name[100];
+       int ret;
+
+       ret = snprintf(name, sizeof(name), "wlparent-%d", poutput->id);
+       if (ret < 1 || (unsigned)ret >= sizeof(name))
+               return -1;
+
+       head = wayland_head_create(compositor, name);
+       if (!head)
+               return -1;
+
+       assert(!poutput->head);
+       head->parent_output = poutput;
+       poutput->head = head;
+
+       weston_head_set_monitor_strings(&head->base,
+                                       poutput->physical.make,
+                                       poutput->physical.model, NULL);
+       weston_head_set_physical_size(&head->base,
+                                     poutput->physical.width,
+                                     poutput->physical.height);
+
+       return 0;
+}
+
+static void
+wayland_head_destroy(struct wayland_head *head)
+{
+       if (head->parent_output)
+               head->parent_output->head = NULL;
+
+       weston_head_release(&head->base);
+       free(head);
+}
+
+static int
+wayland_output_set_size(struct weston_output *base, int width, int height)
+{
+       struct wayland_output *output = to_wayland_output(base);
+       struct weston_head *head;
+       int output_width, output_height;
+
+       /* We can only be called once. */
+       assert(!output->base.current_mode);
+
+       /* Make sure we have scale set. */
+       assert(output->base.scale);
+
+       if (width < 1) {
+               weston_log("Invalid width \"%d\" for output %s\n",
+                          width, output->base.name);
+               return -1;
+       }
+
+       if (height < 1) {
+               weston_log("Invalid height \"%d\" for output %s\n",
+                          height, output->base.name);
+               return -1;
+       }
+
+       wl_list_for_each(head, &output->base.head_list, output_link) {
+               weston_head_set_monitor_strings(head, "wayland", "none", NULL);
+
+               /* XXX: Calculate proper size. */
+               weston_head_set_physical_size(head, width, height);
+       }
+
+       output_width = width * output->base.scale;
+       output_height = height * output->base.scale;
+
+       output->mode.flags =
+               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+
+       output->mode.width = output_width;
+       output->mode.height = output_height;
+       output->mode.refresh = 60000;
+       wl_list_insert(&output->base.mode_list, &output->mode.link);
+
+       output->base.current_mode = &output->mode;
+
+       return 0;
+}
+
+static int
+wayland_output_setup_for_parent_output(struct wayland_output *output,
+                                      struct wayland_parent_output *poutput)
+{
        struct weston_mode *mode;
-       int32_t x;
 
        if (poutput->current_mode) {
                mode = poutput->current_mode;
@@ -1133,53 +1504,69 @@ wayland_output_create_for_parent_output(struct wayland_backend *b,
                mode = container_of(poutput->mode_list.next,
                                    struct weston_mode, link);
        } else {
-               weston_log("No valid modes found.  Skipping output\n");
-               return NULL;
-       }
-
-       if (!wl_list_empty(&b->compositor->output_list)) {
-               output = container_of(b->compositor->output_list.prev,
-                                     struct wayland_output, base.link);
-               x = output->base.x + output->base.current_mode->width;
-       } else {
-               x = 0;
+               weston_log("No valid modes found. Skipping output.\n");
+               return -1;
        }
 
-       output = wayland_output_create(b, x, 0, mode->width, mode->height,
-                                      NULL, 0,
-                                      WL_OUTPUT_TRANSFORM_NORMAL, 1);
-       if (!output)
-               return NULL;
+       output->base.scale = 1;
+       output->base.transform = WL_OUTPUT_TRANSFORM_NORMAL;
 
        output->parent.output = poutput->global;
 
-       output->base.make = poutput->physical.make;
-       output->base.model = poutput->physical.model;
-       wl_list_init(&output->base.mode_list);
        wl_list_insert_list(&output->base.mode_list, &poutput->mode_list);
        wl_list_init(&poutput->mode_list);
 
-       wayland_output_set_fullscreen(output,
-                                     WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER,
-                                     mode->refresh, poutput->global);
+       /* No other mode should have CURRENT already. */
+       mode->flags |= WL_OUTPUT_MODE_CURRENT;
+       output->base.current_mode = mode;
 
-       if (output->parent.shell_surface) {
-               wl_shell_surface_set_fullscreen(output->parent.shell_surface,
-                                               WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER,
-                                               mode->refresh, poutput->global);
-       } else if (b->parent.fshell) {
-               zwp_fullscreen_shell_v1_present_surface(b->parent.fshell,
-                                                       output->parent.surface,
-                                                       ZWP_FULLSCREEN_SHELL_V1_PRESENT_METHOD_CENTER,
-                                                       poutput->global);
-               zwp_fullscreen_shell_mode_feedback_v1_destroy(
-                       zwp_fullscreen_shell_v1_present_surface_for_mode(b->parent.fshell,
-                                                                        output->parent.surface,
-                                                                        poutput->global,
-                                                                        mode->refresh));
+       /* output->mode is unused in this path. */
+
+       return 0;
+}
+
+static int
+wayland_output_setup_fullscreen(struct wayland_output *output,
+                               struct wayland_head *head)
+{
+       struct wayland_backend *b = to_wayland_backend(output->base.compositor);
+       int width = 0, height = 0;
+
+       output->base.scale = 1;
+       output->base.transform = WL_OUTPUT_TRANSFORM_NORMAL;
+
+       if (wayland_backend_create_output_surface(output) < 0)
+               return -1;
+
+       /* What should size be set if conditional is false? */
+       if (b->parent.xdg_shell || b->parent.shell) {
+               if (output->parent.xdg_toplevel)
+                       zxdg_toplevel_v6_set_fullscreen(output->parent.xdg_toplevel,
+                                                       output->parent.output);
+               else if (output->parent.shell_surface)
+                       wl_shell_surface_set_fullscreen(output->parent.shell_surface,
+                                                       0, 0, NULL);
+
+               wl_display_roundtrip(b->parent.wl_display);
+
+               width = output->parent.configure_width;
+               height = output->parent.configure_height;
        }
 
-       return output;
+       if (wayland_output_set_size(&output->base, width, height) < 0)
+               goto err_set_size;
+
+       /* The head is not attached yet, so set_size did not set these. */
+       weston_head_set_monitor_strings(&head->base, "wayland", "none", NULL);
+       /* XXX: Calculate proper size. */
+       weston_head_set_physical_size(&head->base, width, height);
+
+       return 0;
+
+err_set_size:
+       wayland_backend_destroy_output_surface(output);
+
+       return -1;
 }
 
 static void
@@ -1250,6 +1637,13 @@ input_handle_pointer_enter(void *data, struct wl_pointer *pointer,
        enum theme_location location;
        double x, y;
 
+       if (!surface) {
+               input->output = NULL;
+               input->has_focus = false;
+               notify_pointer_focus(&input->base, NULL, 0, 0);
+               return;
+       }
+
        x = wl_fixed_to_double(fixed_x);
        y = wl_fixed_to_double(fixed_y);
 
@@ -1315,6 +1709,7 @@ input_handle_motion(void *data, struct wl_pointer *pointer,
        enum theme_location location;
        bool want_frame = false;
        double x, y;
+       struct timespec ts;
 
        if (!input->output)
                return;
@@ -1352,7 +1747,8 @@ input_handle_motion(void *data, struct wl_pointer *pointer,
        }
 
        if (location == THEME_LOCATION_CLIENT_AREA) {
-               notify_motion_absolute(&input->base, time, x, y);
+               timespec_from_msec(&ts, time);
+               notify_motion_absolute(&input->base, &ts, x, y);
                want_frame = true;
        }
 
@@ -1363,27 +1759,26 @@ input_handle_motion(void *data, struct wl_pointer *pointer,
 static void
 input_handle_button(void *data, struct wl_pointer *pointer,
                    uint32_t serial, uint32_t time, uint32_t button,
-                   uint32_t state_w)
+                   enum wl_pointer_button_state state)
 {
        struct wayland_input *input = data;
-       enum wl_pointer_button_state state = state_w;
-       enum frame_button_state fstate;
        enum theme_location location;
+       struct timespec ts;
 
        if (!input->output)
                return;
 
        if (input->output->frame) {
-               fstate = state == WL_POINTER_BUTTON_STATE_PRESSED ?
-                       FRAME_BUTTON_PRESSED : FRAME_BUTTON_RELEASED;
-
                location = frame_pointer_button(input->output->frame, input,
-                                               button, fstate);
+                                               button, state);
 
                if (frame_status(input->output->frame) & FRAME_STATUS_MOVE) {
-
-                       wl_shell_surface_move(input->output->parent.shell_surface,
+                       if (input->output->parent.xdg_toplevel)
+                               zxdg_toplevel_v6_move(input->output->parent.xdg_toplevel,
                                              input->parent.seat, serial);
+                       else if (input->output->parent.shell_surface)
+                               wl_shell_surface_move(input->output->parent.shell_surface,
+                                                     input->parent.seat, serial);
                        frame_status_clear(input->output->frame,
                                           FRAME_STATUS_MOVE);
                        return;
@@ -1407,7 +1802,8 @@ input_handle_button(void *data, struct wl_pointer *pointer,
        }
 
        if (location == THEME_LOCATION_CLIENT_AREA) {
-               notify_button(&input->base, time, button, state);
+               timespec_from_msec(&ts, time);
+               notify_button(&input->base, &ts, button, state);
                if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
                        notify_pointer_frame(&input->base);
        }
@@ -1419,9 +1815,11 @@ input_handle_axis(void *data, struct wl_pointer *pointer,
 {
        struct wayland_input *input = data;
        struct weston_pointer_axis_event weston_event;
+       struct timespec ts;
 
        weston_event.axis = axis;
        weston_event.value = wl_fixed_to_double(value);
+       weston_event.has_discrete = false;
 
        if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL &&
            input->vert.has_discrete) {
@@ -1435,7 +1833,9 @@ input_handle_axis(void *data, struct wl_pointer *pointer,
                input->horiz.has_discrete = false;
        }
 
-       notify_axis(&input->base, time, &weston_event);
+       timespec_from_msec(&ts, time);
+
+       notify_axis(&input->base, &ts, &weston_event);
 
        if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
                notify_pointer_frame(&input->base);
@@ -1464,11 +1864,14 @@ input_handle_axis_stop(void *data, struct wl_pointer *pointer,
 {
        struct wayland_input *input = data;
        struct weston_pointer_axis_event weston_event;
+       struct timespec ts;
 
        weston_event.axis = axis;
        weston_event.value = 0;
 
-       notify_axis(&input->base, time, &weston_event);
+       timespec_from_msec(&ts, time);
+
+       notify_axis(&input->base, &ts, &weston_event);
 }
 
 static void
@@ -1575,6 +1978,11 @@ input_handle_keyboard_enter(void *data,
                        weston_output_schedule_repaint(&focus->base);
        }
 
+       if (!surface) {
+               input->keyboard_focus = NULL;
+               return;
+       }
+
        input->keyboard_focus = wl_surface_get_user_data(surface);
        input->keyboard_focus->keyboard_count++;
 
@@ -1622,9 +2030,15 @@ input_handle_key(void *data, struct wl_keyboard *keyboard,
                 uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
 {
        struct wayland_input *input = data;
+       struct timespec ts;
+
+       if (!input->keyboard_focus)
+               return;
+
+       timespec_from_msec(&ts, time);
 
        input->key_serial = serial;
-       notify_key(&input->base, time, key,
+       notify_key(&input->base, &ts, key,
                   state ? WL_KEYBOARD_KEY_STATE_PRESSED :
                           WL_KEYBOARD_KEY_STATE_RELEASED,
                   input->keyboard_state_update);
@@ -1688,10 +2102,13 @@ input_handle_touch_down(void *data, struct wl_touch *wl_touch,
        bool first_touch;
        int32_t fx, fy;
        double x, y;
+       struct timespec ts;
 
        x = wl_fixed_to_double(fixed_x);
        y = wl_fixed_to_double(fixed_y);
 
+       timespec_from_msec(&ts, time);
+
        first_touch = (input->touch_points == 0);
        input->touch_points++;
 
@@ -1712,8 +2129,12 @@ input_handle_touch_down(void *data, struct wl_touch *wl_touch,
 
                if (first_touch && (frame_status(output->frame) & FRAME_STATUS_MOVE)) {
                        input->touch_points--;
-                       wl_shell_surface_move(output->parent.shell_surface,
-                                             input->parent.seat, serial);
+                       if (output->parent.xdg_toplevel)
+                               zxdg_toplevel_v6_move(output->parent.xdg_toplevel,
+                                                     input->parent.seat, serial);
+                       else if (output->parent.shell_surface)
+                               wl_shell_surface_move(output->parent.shell_surface,
+                                                     input->parent.seat, serial);
                        frame_status_clear(output->frame,
                                           FRAME_STATUS_MOVE);
                        return;
@@ -1725,7 +2146,7 @@ input_handle_touch_down(void *data, struct wl_touch *wl_touch,
 
        weston_output_transform_coordinate(&output->base, x, y, &x, &y);
 
-       notify_touch(&input->base, time, id, x, y, WL_TOUCH_DOWN);
+       notify_touch(&input->base, &ts, id, x, y, WL_TOUCH_DOWN);
        input->touch_active = true;
 }
 
@@ -1736,6 +2157,9 @@ input_handle_touch_up(void *data, struct wl_touch *wl_touch,
        struct wayland_input *input = data;
        struct wayland_output *output = input->touch_focus;
        bool active = input->touch_active;
+       struct timespec ts;
+
+       timespec_from_msec(&ts, time);
 
        input->touch_points--;
        if (input->touch_points == 0) {
@@ -1763,7 +2187,7 @@ input_handle_touch_up(void *data, struct wl_touch *wl_touch,
        }
 
        if (active)
-               notify_touch(&input->base, time, id, 0, 0, WL_TOUCH_UP);
+               notify_touch(&input->base, &ts, id, 0, 0, WL_TOUCH_UP);
 }
 
 static void
@@ -1775,9 +2199,11 @@ input_handle_touch_motion(void *data, struct wl_touch *wl_touch,
        struct wayland_output *output = input->touch_focus;
        int32_t fx, fy;
        double x, y;
+       struct timespec ts;
 
        x = wl_fixed_to_double(fixed_x);
        y = wl_fixed_to_double(fixed_y);
+       timespec_from_msec(&ts, time);
 
        if (!output || !input->touch_active)
                return;
@@ -1790,7 +2216,7 @@ input_handle_touch_motion(void *data, struct wl_touch *wl_touch,
 
        weston_output_transform_coordinate(&output->base, x, y, &x, &y);
 
-       notify_touch(&input->base, time, id, x, y, WL_TOUCH_MOTION);
+       notify_touch(&input->base, &ts, id, x, y, WL_TOUCH_MOTION);
 }
 
 static void
@@ -1824,6 +2250,22 @@ static const struct wl_touch_listener touch_listener = {
 };
 
 
+static struct weston_touch_device *
+create_touch_device(struct wayland_input *input)
+{
+       struct weston_touch_device *touch_device;
+       char str[128];
+
+       /* manufacture a unique'ish name */
+       snprintf(str, sizeof str, "wayland-touch[%u]",
+                wl_proxy_get_id((struct wl_proxy *)input->parent.seat));
+
+       touch_device = weston_touch_create_touch_device(input->base.touch_state,
+                                                       str, NULL, NULL);
+
+       return touch_device;
+}
+
 static void
 input_handle_capabilities(void *data, struct wl_seat *seat,
                          enum wl_seat_capability caps)
@@ -1865,7 +2307,10 @@ input_handle_capabilities(void *data, struct wl_seat *seat,
                wl_touch_add_listener(input->parent.touch,
                                      &touch_listener, input);
                weston_seat_init_touch(&input->base);
+               input->touch_device = create_touch_device(input);
        } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->parent.touch) {
+               weston_touch_device_destroy(input->touch_device);
+               input->touch_device = NULL;
                if (input->seat_version >= WL_TOUCH_RELEASE_SINCE_VERSION)
                        wl_touch_release(input->parent.touch);
                else
@@ -1959,16 +2404,32 @@ find_mode(struct wl_list *list, int32_t width, int32_t height, uint32_t refresh)
        return mode;
 }
 
+static struct weston_output *
+wayland_parent_output_get_enabled_output(struct wayland_parent_output *poutput)
+{
+       struct wayland_head *head = poutput->head;
+
+       if (!head)
+               return NULL;
+
+       if (!weston_head_is_enabled(&head->base))
+               return NULL;
+
+       return weston_head_get_output(&head->base);
+}
+
 static void
 wayland_parent_output_mode(void *data, struct wl_output *wl_output_proxy,
                           uint32_t flags, int32_t width, int32_t height,
                           int32_t refresh)
 {
        struct wayland_parent_output *output = data;
+       struct weston_output *enabled_output;
        struct weston_mode *mode;
 
-       if (output->output) {
-               mode = find_mode(&output->output->base.mode_list,
+       enabled_output = wayland_parent_output_get_enabled_output(output);
+       if (enabled_output) {
+               mode = find_mode(&enabled_output->mode_list,
                                 width, height, refresh);
                if (!mode)
                        return;
@@ -1992,6 +2453,24 @@ static const struct wl_output_listener output_listener = {
 };
 
 static void
+output_sync_callback(void *data, struct wl_callback *callback, uint32_t unused)
+{
+       struct wayland_parent_output *output = data;
+
+       assert(output->sync_cb == callback);
+       wl_callback_destroy(callback);
+       output->sync_cb = NULL;
+
+       assert(output->backend->sprawl_across_outputs);
+
+       wayland_head_create_for_parent_output(output->backend->compositor, output);
+}
+
+static const struct wl_callback_listener output_sync_listener = {
+       output_sync_callback
+};
+
+static void
 wayland_backend_register_output(struct wayland_backend *b, uint32_t id)
 {
        struct wayland_parent_output *output;
@@ -2000,6 +2479,7 @@ wayland_backend_register_output(struct wayland_backend *b, uint32_t id)
        if (!output)
                return;
 
+       output->backend = b;
        output->id = id;
        output->global = wl_registry_bind(b->parent.registry, id,
                                          &wl_output_interface, 1);
@@ -2017,8 +2497,9 @@ wayland_backend_register_output(struct wayland_backend *b, uint32_t id)
        wl_list_insert(&b->parent.output_list, &output->link);
 
        if (b->sprawl_across_outputs) {
-               wl_display_roundtrip(b->parent.wl_display);
-               wayland_output_create_for_parent_output(b, output);
+               output->sync_cb = wl_display_sync(b->parent.wl_display);
+               wl_callback_add_listener(output->sync_cb,
+                                        &output_sync_listener, output);
        }
 }
 
@@ -2027,8 +2508,11 @@ wayland_parent_output_destroy(struct wayland_parent_output *output)
 {
        struct weston_mode *mode, *next;
 
-       if (output->output)
-               wayland_output_destroy(&output->output->base);
+       if (output->sync_cb)
+               wl_callback_destroy(output->sync_cb);
+
+       if (output->head)
+               wayland_head_destroy(output->head);
 
        wl_output_destroy(output->global);
        free(output->physical.make);
@@ -2038,9 +2522,22 @@ wayland_parent_output_destroy(struct wayland_parent_output *output)
                wl_list_remove(&mode->link);
                free(mode);
        }
+
+       wl_list_remove(&output->link);
+       free(output);
 }
 
 static void
+xdg_shell_ping(void *data, struct zxdg_shell_v6 *shell, uint32_t serial)
+{
+       zxdg_shell_v6_pong(shell, serial);
+}
+
+static const struct zxdg_shell_v6_listener xdg_shell_listener = {
+       xdg_shell_ping,
+};
+
+static void
 registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
                       const char *interface, uint32_t version)
 {
@@ -2049,7 +2546,14 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
        if (strcmp(interface, "wl_compositor") == 0) {
                b->parent.compositor =
                        wl_registry_bind(registry, name,
-                                        &wl_compositor_interface, 1);
+                                        &wl_compositor_interface,
+                                        MIN(version, 4));
+       } else if (strcmp(interface, "zxdg_shell_v6") == 0) {
+               b->parent.xdg_shell =
+                       wl_registry_bind(registry, name,
+                                        &zxdg_shell_v6_interface, 1);
+               zxdg_shell_v6_add_listener(b->parent.xdg_shell,
+                                          &xdg_shell_listener, b);
        } else if (strcmp(interface, "wl_shell") == 0) {
                b->parent.shell =
                        wl_registry_bind(registry, name,
@@ -2073,9 +2577,9 @@ registry_handle_global_remove(void *data, struct wl_registry *registry,
                              uint32_t name)
 {
        struct wayland_backend *b = data;
-       struct wayland_parent_output *output;
+       struct wayland_parent_output *output, *next;
 
-       wl_list_for_each(output, &b->parent.output_list, link)
+       wl_list_for_each_safe(output, next, &b->parent.output_list, link)
                if (output->id == name)
                        wayland_parent_output_destroy(output);
 }
@@ -2110,20 +2614,45 @@ wayland_backend_handle_event(int fd, uint32_t mask, void *data)
 }
 
 static void
-wayland_restore(struct weston_compositor *ec)
-{
-}
-
-static void
 wayland_destroy(struct weston_compositor *ec)
 {
        struct wayland_backend *b = to_wayland_backend(ec);
+       struct weston_head *base, *next;
+
+       wl_event_source_remove(b->parent.wl_source);
 
        weston_compositor_shutdown(ec);
 
+       wl_list_for_each_safe(base, next, &ec->head_list, compositor_link)
+               wayland_head_destroy(to_wayland_head(base));
+
        if (b->parent.shm)
                wl_shm_destroy(b->parent.shm);
 
+       if (b->parent.xdg_shell)
+               zxdg_shell_v6_destroy(b->parent.xdg_shell);
+
+       if (b->parent.shell)
+               wl_shell_destroy(b->parent.shell);
+
+       if (b->parent.fshell)
+               zwp_fullscreen_shell_v1_release(b->parent.fshell);
+
+       if (b->parent.compositor)
+               wl_compositor_destroy(b->parent.compositor);
+
+       if (b->theme)
+               theme_destroy(b->theme);
+
+       if (b->frame_device)
+               cairo_device_destroy(b->frame_device);
+
+       wl_cursor_theme_destroy(b->cursor_theme);
+
+       wl_registry_destroy(b->parent.registry);
+       wl_display_flush(b->parent.wl_display);
+       wl_display_disconnect(b->parent.wl_display);
+
        free(b);
 }
 
@@ -2159,8 +2688,8 @@ create_cursor(struct wayland_backend *b,
 }
 
 static void
-fullscreen_binding(struct weston_keyboard *keyboard, uint32_t time,
-                  uint32_t key, void *data)
+fullscreen_binding(struct weston_keyboard *keyboard,
+                  const struct timespec *time, uint32_t key, void *data)
 {
        struct wayland_backend *b = data;
        struct wayland_input *input = NULL;
@@ -2193,12 +2722,17 @@ wayland_backend_create(struct weston_compositor *compositor,
                return NULL;
 
        b->compositor = compositor;
+       compositor->backend = &b->base;
+
        if (weston_compositor_set_presentation_clock_software(compositor) < 0)
                goto err_compositor;
 
        b->parent.wl_display = wl_display_connect(new_config->display_name);
        if (b->parent.wl_display == NULL) {
-               weston_log("failed to create display: %m\n");
+               weston_log("Error: Failed to connect to parent Wayland compositor: %m\n");
+               weston_log_continue(STAMP_SPACE "display option: %s, WAYLAND_DISPLAY=%s\n",
+                                   new_config->display_name ?: "(none)",
+                                   getenv("WAYLAND_DISPLAY") ?: "(not set)");
                goto err_compositor;
        }
 
@@ -2210,25 +2744,31 @@ wayland_backend_create(struct weston_compositor *compositor,
 
        create_cursor(b, new_config);
 
+#ifdef ENABLE_EGL
        b->use_pixman = new_config->use_pixman;
+#else
+       b->use_pixman = true;
+#endif
+       b->fullscreen = new_config->fullscreen;
 
        if (!b->use_pixman) {
                gl_renderer = weston_load_module("gl-renderer.so",
                                                 "gl_renderer_interface");
                if (!gl_renderer)
-                       b->use_pixman = 1;
+                       b->use_pixman = true;
        }
 
        if (!b->use_pixman) {
-               if (gl_renderer->create(compositor,
-                                       EGL_PLATFORM_WAYLAND_KHR,
-                                       b->parent.wl_display,
-                                       gl_renderer->alpha_attribs,
-                                       NULL,
-                                       0) < 0) {
+               if (gl_renderer->display_create(compositor,
+                                               EGL_PLATFORM_WAYLAND_KHR,
+                                               b->parent.wl_display,
+                                               NULL,
+                                               gl_renderer->alpha_attribs,
+                                               NULL,
+                                               0) < 0) {
                        weston_log("Failed to initialize the GL renderer; "
                                   "falling back to pixman.\n");
-                       b->use_pixman = 1;
+                       b->use_pixman = true;
                }
        }
 
@@ -2240,7 +2780,7 @@ wayland_backend_create(struct weston_compositor *compositor,
        }
 
        b->base.destroy = wayland_destroy;
-       b->base.restore = wayland_restore;
+       b->base.create_output = wayland_output_create;
 
        loop = wl_display_get_event_loop(compositor->wl_display);
 
@@ -2259,7 +2799,6 @@ wayland_backend_create(struct weston_compositor *compositor,
                                   "support failed.\n");
        }
 
-       compositor->backend = &b->base;
        return b;
 err_display:
        wl_display_disconnect(b->parent.wl_display);
@@ -2284,20 +2823,24 @@ wayland_backend_destroy(struct wayland_backend *b)
        free(b);
 }
 
+static const struct weston_windowed_output_api windowed_api = {
+       wayland_output_set_size,
+       wayland_head_create_windowed,
+};
+
 static void
 config_init_to_defaults(struct weston_wayland_backend_config *config)
 {
 }
 
 WL_EXPORT int
-backend_init(struct weston_compositor *compositor,
-            struct weston_backend_config *config_base)
+weston_backend_init(struct weston_compositor *compositor,
+                   struct weston_backend_config *config_base)
 {
        struct wayland_backend *b;
-       struct wayland_output *output;
        struct wayland_parent_output *poutput;
        struct weston_wayland_backend_config new_config;
-       int x, count;
+       int ret;
 
        if (config_base == NULL ||
            config_base->struct_version != WESTON_WAYLAND_BACKEND_CONFIG_VERSION ||
@@ -2315,39 +2858,31 @@ backend_init(struct weston_compositor *compositor,
                return -1;
 
        if (new_config.sprawl || b->parent.fshell) {
-               b->sprawl_across_outputs = 1;
+               b->sprawl_across_outputs = true;
                wl_display_roundtrip(b->parent.wl_display);
 
                wl_list_for_each(poutput, &b->parent.output_list, link)
-                       wayland_output_create_for_parent_output(b, poutput);
+                       wayland_head_create_for_parent_output(compositor, poutput);
 
                return 0;
        }
 
        if (new_config.fullscreen) {
-               if (new_config.num_outputs != 1 || !new_config.outputs)
-                       goto err_outputs;
-
-               output = wayland_output_create_for_config(b,
-                                                         &new_config.outputs[0],
-                                                         1, 0, 0);
-               if (!output)
+               if (!wayland_head_create(compositor, "wayland-fullscreen")) {
+                       weston_log("Unable to create a fullscreen head.\n");
                        goto err_outputs;
+               }
 
-               wayland_output_set_fullscreen(output, 0, 0, NULL);
                return 0;
        }
 
-       x = 0;
-       for (count = 0; count < new_config.num_outputs; ++count) {
-               output = wayland_output_create_for_config(b, &new_config.outputs[count],
-                                                         0, x, 0);
-               if (!output)
-                       goto err_outputs;
-               if (wayland_output_set_windowed(output))
-                       goto err_outputs;
+       ret = weston_plugin_api_register(compositor, WESTON_WINDOWED_OUTPUT_API_NAME,
+                                        &windowed_api, sizeof(windowed_api));
 
-               x += output->base.width;
+       if (ret < 0) {
+               weston_log("Failed to register output API.\n");
+               wayland_backend_destroy(b);
+               return -1;
        }
 
        weston_compositor_add_key_binding(compositor, KEY_F,