Rename src/ to libweston/
authorPekka Paalanen <pekka.paalanen@collabora.co.uk>
Fri, 3 Jun 2016 14:12:10 +0000 (17:12 +0300)
committerPekka Paalanen <pekka.paalanen@collabora.co.uk>
Thu, 23 Jun 2016 14:44:54 +0000 (17:44 +0300)
This clarifies what is supposed to be the libweston code.

v2: screen-share.c is already in compositor/ instead.

Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.co.uk>
Reviewed-by: Yong Bakos <ybakos@humanoriented.com>
Acked-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Quentin Glidic <sardemff7+git@sardemff7.net>
Tested-by: Quentin Glidic <sardemff7+git@sardemff7.net>
Tested-by: Benoit Gschwind <gschwind@gnu-log.net>
Acked-by: Benoit Gschwind <gschwind@gnu-log.net>
[Pekka: rebased]

121 files changed:
Makefile.am
clients/cliptest.c
configure.ac
libweston/animation.c [new file with mode: 0644]
libweston/bindings.c [new file with mode: 0644]
libweston/clipboard.c [new file with mode: 0644]
libweston/compositor-drm.c [new file with mode: 0644]
libweston/compositor-drm.h [new file with mode: 0644]
libweston/compositor-fbdev.c [new file with mode: 0644]
libweston/compositor-fbdev.h [new file with mode: 0644]
libweston/compositor-headless.c [new file with mode: 0644]
libweston/compositor-headless.h [new file with mode: 0644]
libweston/compositor-rdp.c [new file with mode: 0644]
libweston/compositor-rdp.h [new file with mode: 0644]
libweston/compositor-wayland.c [new file with mode: 0644]
libweston/compositor-wayland.h [new file with mode: 0644]
libweston/compositor-x11.c [new file with mode: 0644]
libweston/compositor-x11.h [new file with mode: 0644]
libweston/compositor.c [new file with mode: 0644]
libweston/compositor.h [new file with mode: 0644]
libweston/data-device.c [new file with mode: 0644]
libweston/dbus.c [new file with mode: 0644]
libweston/dbus.h [new file with mode: 0644]
libweston/gl-renderer.c [new file with mode: 0644]
libweston/gl-renderer.h [new file with mode: 0644]
libweston/input.c [new file with mode: 0644]
libweston/launcher-direct.c [new file with mode: 0644]
libweston/launcher-impl.h [new file with mode: 0644]
libweston/launcher-logind.c [new file with mode: 0644]
libweston/launcher-util.c [new file with mode: 0644]
libweston/launcher-util.h [new file with mode: 0644]
libweston/launcher-weston-launch.c [new file with mode: 0644]
libweston/libbacklight.c [new file with mode: 0644]
libweston/libbacklight.h [new file with mode: 0644]
libweston/libinput-device.c [new file with mode: 0644]
libweston/libinput-device.h [new file with mode: 0644]
libweston/libinput-seat.c [new file with mode: 0644]
libweston/libinput-seat.h [new file with mode: 0644]
libweston/libweston.pc.in [new file with mode: 0644]
libweston/linux-dmabuf.c [new file with mode: 0644]
libweston/linux-dmabuf.h [new file with mode: 0644]
libweston/log.c [new file with mode: 0644]
libweston/noop-renderer.c [new file with mode: 0644]
libweston/pixman-renderer.c [new file with mode: 0644]
libweston/pixman-renderer.h [new file with mode: 0644]
libweston/screenshooter.c [new file with mode: 0644]
libweston/spring-tool.c [new file with mode: 0644]
libweston/timeline-object.h [new file with mode: 0644]
libweston/timeline.c [new file with mode: 0644]
libweston/timeline.h [new file with mode: 0644]
libweston/vaapi-recorder.c [new file with mode: 0644]
libweston/vaapi-recorder.h [new file with mode: 0644]
libweston/version.h.in [new file with mode: 0644]
libweston/vertex-clipping.c [new file with mode: 0644]
libweston/vertex-clipping.h [new file with mode: 0644]
libweston/weston-egl-ext.h [new file with mode: 0644]
libweston/weston-launch.c [new file with mode: 0644]
libweston/weston-launch.h [new file with mode: 0644]
libweston/zoom.c [new file with mode: 0644]
src/animation.c [deleted file]
src/bindings.c [deleted file]
src/clipboard.c [deleted file]
src/compositor-drm.c [deleted file]
src/compositor-drm.h [deleted file]
src/compositor-fbdev.c [deleted file]
src/compositor-fbdev.h [deleted file]
src/compositor-headless.c [deleted file]
src/compositor-headless.h [deleted file]
src/compositor-rdp.c [deleted file]
src/compositor-rdp.h [deleted file]
src/compositor-wayland.c [deleted file]
src/compositor-wayland.h [deleted file]
src/compositor-x11.c [deleted file]
src/compositor-x11.h [deleted file]
src/compositor.c [deleted file]
src/compositor.h [deleted file]
src/data-device.c [deleted file]
src/dbus.c [deleted file]
src/dbus.h [deleted file]
src/gl-renderer.c [deleted file]
src/gl-renderer.h [deleted file]
src/input.c [deleted file]
src/launcher-direct.c [deleted file]
src/launcher-impl.h [deleted file]
src/launcher-logind.c [deleted file]
src/launcher-util.c [deleted file]
src/launcher-util.h [deleted file]
src/launcher-weston-launch.c [deleted file]
src/libbacklight.c [deleted file]
src/libbacklight.h [deleted file]
src/libinput-device.c [deleted file]
src/libinput-device.h [deleted file]
src/libinput-seat.c [deleted file]
src/libinput-seat.h [deleted file]
src/libweston.pc.in [deleted file]
src/linux-dmabuf.c [deleted file]
src/linux-dmabuf.h [deleted file]
src/log.c [deleted file]
src/noop-renderer.c [deleted file]
src/pixman-renderer.c [deleted file]
src/pixman-renderer.h [deleted file]
src/screenshooter.c [deleted file]
src/spring-tool.c [deleted file]
src/timeline-object.h [deleted file]
src/timeline.c [deleted file]
src/timeline.h [deleted file]
src/vaapi-recorder.c [deleted file]
src/vaapi-recorder.h [deleted file]
src/version.h.in [deleted file]
src/vertex-clipping.c [deleted file]
src/vertex-clipping.h [deleted file]
src/weston-egl-ext.h [deleted file]
src/weston-launch.c [deleted file]
src/weston-launch.h [deleted file]
src/zoom.c [deleted file]
tests/ivi_layout-internal-test.c
tests/ivi_layout-test-plugin.c
tests/surface-global-test.c
tests/surface-test.c
tests/vertex-clip-test.c
tests/weston-test.c

index 0d0334a745d3c5da0aa9fc0ab59fbb6d885e0ddc..67ac351623b181a117619a178ef53d100e5a3984 100644 (file)
@@ -44,8 +44,8 @@ all-local : weston.ini ivi-shell/weston.ini
 AM_CFLAGS = $(GCC_CFLAGS)
 
 AM_CPPFLAGS =                                  \
-       -I$(top_srcdir)/src                     \
-       -I$(top_builddir)/src                   \
+       -I$(top_srcdir)/libweston               \
+       -I$(top_builddir)/libweston             \
        -I$(top_builddir)/clients               \
        -I$(top_builddir)/tests                 \
        -I$(top_srcdir)/shared                  \
@@ -70,38 +70,38 @@ libweston_la_LIBADD = $(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \
 libweston_la_LDFLAGS = -release ${LIBWESTON_ABI_VERSION}
 
 libweston_la_SOURCES =                                 \
-       src/git-version.h                               \
-       src/log.c                                       \
-       src/compositor.c                                \
-       src/compositor.h                                \
-       src/compositor-drm.h                            \
-       src/compositor-fbdev.h                          \
-       src/compositor-headless.h                       \
-       src/compositor-rdp.h                            \
-       src/compositor-wayland.h                        \
-       src/compositor-x11.h                            \
-       src/input.c                                     \
-       src/data-device.c                               \
-       src/screenshooter.c                             \
-       src/clipboard.c                                 \
-       src/zoom.c                                      \
-       src/bindings.c                                  \
-       src/animation.c                                 \
-       src/noop-renderer.c                             \
-       src/pixman-renderer.c                           \
-       src/pixman-renderer.h                           \
-       src/timeline.c                                  \
-       src/timeline.h                                  \
-       src/timeline-object.h                           \
-       src/linux-dmabuf.c                              \
-       src/linux-dmabuf.h                              \
+       libweston/git-version.h                         \
+       libweston/log.c                                 \
+       libweston/compositor.c                          \
+       libweston/compositor.h                          \
+       libweston/compositor-drm.h                      \
+       libweston/compositor-fbdev.h                    \
+       libweston/compositor-headless.h                 \
+       libweston/compositor-rdp.h                      \
+       libweston/compositor-wayland.h                  \
+       libweston/compositor-x11.h                      \
+       libweston/input.c                               \
+       libweston/data-device.c                         \
+       libweston/screenshooter.c                       \
+       libweston/clipboard.c                           \
+       libweston/zoom.c                                \
+       libweston/bindings.c                            \
+       libweston/animation.c                           \
+       libweston/noop-renderer.c                       \
+       libweston/pixman-renderer.c                     \
+       libweston/pixman-renderer.h                     \
+       libweston/timeline.c                            \
+       libweston/timeline.h                            \
+       libweston/timeline-object.h                     \
+       libweston/linux-dmabuf.c                        \
+       libweston/linux-dmabuf.h                        \
        shared/helpers.h                                \
        shared/matrix.c                                 \
        shared/matrix.h                                 \
        shared/timespec-util.h                          \
        shared/zalloc.h                                 \
        shared/platform.h                               \
-       src/weston-egl-ext.h
+       libweston/weston-egl-ext.h
 
 if SYSTEMD_NOTIFY_SUPPORT
 module_LTLIBRARIES += systemd-notify.la
@@ -116,7 +116,7 @@ systemd_notify_la_SOURCES =                 \
        compositor/systemd-notify.c             \
        shared/helpers.h                        \
        shared/zalloc.h                         \
-       src/compositor.h
+       libweston/compositor.h
 endif
 
 nodist_libweston_la_SOURCES =                                  \
@@ -156,37 +156,37 @@ weston_SOURCES =                                  \
 # add BUILT_SOURCES to CLEANFILES, but we want to keep git-version.h
 # in case we're building from tarballs.
 
-src/compositor.c : $(top_builddir)/src/git-version.h
+libweston/compositor.c : $(top_builddir)/libweston/git-version.h
 
 noinst_LTLIBRARIES +=                          \
        libsession-helper.la
 
 libsession_helper_la_SOURCES =                 \
-       src/launcher-util.c                     \
-       src/launcher-util.h                     \
-       src/launcher-impl.h                     \
-       src/weston-launch.h                     \
-       src/launcher-weston-launch.c            \
-       src/launcher-direct.c
+       libweston/launcher-util.c               \
+       libweston/launcher-util.h               \
+       libweston/launcher-impl.h               \
+       libweston/weston-launch.h               \
+       libweston/launcher-weston-launch.c      \
+       libweston/launcher-direct.c
 libsession_helper_la_CFLAGS = $(AM_CFLAGS) $(LIBDRM_CFLAGS) $(PIXMAN_CFLAGS) $(COMPOSITOR_CFLAGS)
 libsession_helper_la_LIBADD = $(LIBDRM_LIBS)
 
 if ENABLE_DBUS
 if HAVE_SYSTEMD_LOGIN
 libsession_helper_la_SOURCES +=                        \
-       src/dbus.h                              \
-       src/dbus.c                              \
-       src/launcher-logind.c
+       libweston/dbus.h                        \
+       libweston/dbus.c                        \
+       libweston/launcher-logind.c
 libsession_helper_la_CFLAGS += $(SYSTEMD_LOGIN_CFLAGS) $(DBUS_CFLAGS)
 libsession_helper_la_LIBADD += $(SYSTEMD_LOGIN_LIBS) $(DBUS_LIBS)
 endif
 endif
 
 if HAVE_GIT_REPO
-src/git-version.h : $(top_srcdir)/.git/logs/HEAD
+libweston/git-version.h : $(top_srcdir)/.git/logs/HEAD
        $(AM_V_GEN)echo "#define BUILD_ID \"$(shell git --git-dir=$(top_srcdir)/.git describe --always --dirty) $(shell git --git-dir=$(top_srcdir)/.git log -1 --format='%s (%ci)')\"" > $@
 else
-src/git-version.h :
+libweston/git-version.h :
        $(AM_V_GEN)echo "#define BUILD_ID \"unknown (not built from git or tarball)\"" > $@
 
 endif
@@ -195,7 +195,7 @@ endif
 
 if BUILD_WESTON_LAUNCH
 bin_PROGRAMS += weston-launch
-weston_launch_SOURCES = src/weston-launch.c src/weston-launch.h
+weston_launch_SOURCES = libweston/weston-launch.c libweston/weston-launch.h
 weston_launch_CPPFLAGS = -DBINDIR='"$(bindir)"'
 weston_launch_CFLAGS=                          \
        $(AM_CFLAGS)                            \
@@ -220,22 +220,22 @@ endif
 endif # BUILD_WESTON_LAUNCH
 
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = compositor/weston.pc src/libweston-${LIBWESTON_ABI_VERSION}.pc
+pkgconfig_DATA = compositor/weston.pc libweston/libweston-${LIBWESTON_ABI_VERSION}.pc
 
 wayland_sessiondir = $(datadir)/wayland-sessions
 dist_wayland_session_DATA = compositor/weston.desktop
 
 libwestonincludedir = $(includedir)/libweston-${LIBWESTON_ABI_VERSION}
-libwestoninclude_HEADERS =                             \
-       src/version.h                           \
-       src/compositor.h                        \
-       src/compositor-drm.h                    \
-       src/compositor-fbdev.h                  \
-       src/compositor-headless.h               \
-       src/compositor-rdp.h                    \
-       src/compositor-wayland.h                \
-       src/compositor-x11.h                    \
-       src/timeline-object.h                   \
+libwestoninclude_HEADERS =                     \
+       libweston/version.h                     \
+       libweston/compositor.h                  \
+       libweston/compositor-drm.h              \
+       libweston/compositor-fbdev.h            \
+       libweston/compositor-headless.h         \
+       libweston/compositor-rdp.h              \
+       libweston/compositor-wayland.h          \
+       libweston/compositor-x11.h              \
+       libweston/timeline-object.h             \
        shared/matrix.h                         \
        shared/config-parser.h                  \
        shared/zalloc.h                         \
@@ -259,10 +259,10 @@ gl_renderer_la_CFLAGS =                           \
        $(GL_RENDERER_CFLAGS)                   \
        $(AM_CFLAGS)
 gl_renderer_la_SOURCES =                       \
-       src/gl-renderer.h                       \
-       src/gl-renderer.c                       \
-       src/vertex-clipping.c                   \
-       src/vertex-clipping.h                   \
+       libweston/gl-renderer.h                 \
+       libweston/gl-renderer.c                 \
+       libweston/vertex-clipping.c             \
+       libweston/vertex-clipping.h             \
        shared/helpers.h
 endif
 
@@ -279,17 +279,17 @@ x11_backend_la_CFLAGS =                           \
        $(X11_COMPOSITOR_CFLAGS)                \
        $(AM_CFLAGS)
 x11_backend_la_SOURCES =                       \
-       src/compositor-x11.c                    \
-       src/compositor-x11.h                    \
+       libweston/compositor-x11.c              \
+       libweston/compositor-x11.h              \
        shared/helpers.h
 endif
 
 INPUT_BACKEND_LIBS = $(LIBINPUT_BACKEND_LIBS)
 INPUT_BACKEND_SOURCES =                                \
-       src/libinput-seat.c                     \
-       src/libinput-seat.h                     \
-       src/libinput-device.c                   \
-       src/libinput-device.h                   \
+       libweston/libinput-seat.c               \
+       libweston/libinput-seat.h               \
+       libweston/libinput-device.c             \
+       libweston/libinput-device.h             \
        shared/helpers.h
 
 if ENABLE_DRM_COMPOSITOR
@@ -308,16 +308,16 @@ drm_backend_la_CFLAGS =                           \
        $(DRM_COMPOSITOR_CFLAGS)                \
        $(AM_CFLAGS)
 drm_backend_la_SOURCES =                       \
-       src/compositor-drm.c                    \
-       src/compositor-drm.h            \
+       libweston/compositor-drm.c              \
+       libweston/compositor-drm.h              \
        $(INPUT_BACKEND_SOURCES)                \
        shared/helpers.h                        \
        shared/timespec-util.h                  \
-       src/libbacklight.c                      \
-       src/libbacklight.h
+       libweston/libbacklight.c                \
+       libweston/libbacklight.h
 
 if ENABLE_VAAPI_RECORDER
-drm_backend_la_SOURCES += src/vaapi-recorder.c src/vaapi-recorder.h
+drm_backend_la_SOURCES += libweston/vaapi-recorder.c libweston/vaapi-recorder.h
 drm_backend_la_LIBADD += $(LIBVA_LIBS)
 drm_backend_la_CFLAGS += $(LIBVA_CFLAGS)
 endif
@@ -338,8 +338,8 @@ wayland_backend_la_CFLAGS =                 \
        $(WAYLAND_COMPOSITOR_CFLAGS)            \
        $(AM_CFLAGS)
 wayland_backend_la_SOURCES =                   \
-       src/compositor-wayland.c                \
-       src/compositor-wayland.h                \
+       libweston/compositor-wayland.c          \
+       libweston/compositor-wayland.h          \
        shared/helpers.h
 nodist_wayland_backend_la_SOURCES =                    \
        protocol/fullscreen-shell-unstable-v1-protocol.c                \
@@ -352,8 +352,8 @@ headless_backend_la_LDFLAGS = -module -avoid-version
 headless_backend_la_LIBADD = $(COMPOSITOR_LIBS) libshared.la
 headless_backend_la_CFLAGS = $(COMPOSITOR_CFLAGS) $(AM_CFLAGS)
 headless_backend_la_SOURCES =                  \
-       src/compositor-headless.c               \
-       src/compositor-headless.h               \
+       libweston/compositor-headless.c         \
+       libweston/compositor-headless.h         \
        shared/helpers.h
 endif
 
@@ -373,8 +373,8 @@ fbdev_backend_la_CFLAGS =                   \
        $(PIXMAN_CFLAGS)                        \
        $(AM_CFLAGS)
 fbdev_backend_la_SOURCES =                     \
-       src/compositor-fbdev.c                  \
-       src/compositor-fbdev.h                  \
+       libweston/compositor-fbdev.c            \
+       libweston/compositor-fbdev.h            \
        shared/helpers.h                        \
        $(INPUT_BACKEND_SOURCES)
 endif
@@ -390,8 +390,8 @@ rdp_backend_la_CFLAGS =                             \
        $(RDP_COMPOSITOR_CFLAGS)                \
        $(AM_CFLAGS)
 rdp_backend_la_SOURCES =                       \
-       src/compositor-rdp.c                    \
-       src/compositor-rdp.h                    \
+       libweston/compositor-rdp.c              \
+       libweston/compositor-rdp.h              \
        shared/helpers.h
 endif
 
@@ -422,11 +422,11 @@ noinst_PROGRAMS += spring-tool
 spring_tool_CFLAGS = $(AM_CFLAGS) $(COMPOSITOR_CFLAGS)
 spring_tool_LDADD = $(COMPOSITOR_LIBS) -lm
 spring_tool_SOURCES =                          \
-       src/spring-tool.c                       \
-       src/animation.c                         \
+       libweston/spring-tool.c                 \
+       libweston/animation.c                   \
        shared/matrix.c                         \
        shared/matrix.h                         \
-       src/compositor.h
+       libweston/compositor.h
 
 if BUILD_CLIENTS
 
@@ -607,8 +607,8 @@ weston_image_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
 
 weston_cliptest_SOURCES =                              \
        clients/cliptest.c                              \
-       src/vertex-clipping.c                           \
-       src/vertex-clipping.h
+       libweston/vertex-clipping.c                     \
+       libweston/vertex-clipping.h
 weston_cliptest_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
 weston_cliptest_LDADD = libtoytoolkit.la
 
@@ -837,8 +837,8 @@ module_LTLIBRARIES += desktop-shell.la
 desktop_shell_la_CPPFLAGS =                    \
        -I$(top_builddir)/protocol              \
        -I$(top_srcdir)/shared                  \
-       -I$(top_srcdir)/src                     \
-       -I$(top_builddir)/src                   \
+       -I$(top_srcdir)/libweston               \
+       -I$(top_builddir)/libweston             \
        -I$(top_builddir)/desktop-shell         \
        -DDATADIR='"$(datadir)"'                \
        -DMODULEDIR='"$(moduledir)"'            \
@@ -870,8 +870,8 @@ module_LTLIBRARIES += fullscreen-shell.la
 fullscreen_shell_la_CPPFLAGS =                 \
        -I$(top_builddir)/protocol              \
        -I$(top_srcdir)/shared                  \
-       -I$(top_srcdir)/src                     \
-       -I$(top_builddir)/src                   \
+       -I$(top_srcdir)/libweston               \
+       -I$(top_builddir)/libweston             \
        -DIN_WESTON
 
 fullscreen_shell_la_LDFLAGS = -module -avoid-version
@@ -960,8 +960,8 @@ module_LTLIBRARIES += xwayland.la
 xwayland_la_CPPFLAGS =                         \
        -I$(top_builddir)/protocol              \
        -I$(top_srcdir)/shared                  \
-       -I$(top_srcdir)/src                     \
-       -I$(top_builddir)/src                   \
+       -I$(top_srcdir)/libweston               \
+       -I$(top_builddir)/libweston             \
        -I$(top_builddir)/xwayland              \
        -DDATADIR='"$(datadir)"'                \
        -DMODULEDIR='"$(moduledir)"'            \
@@ -1184,8 +1184,8 @@ config_parser_test_CFLAGS =                       \
 vertex_clip_test_SOURCES =                     \
        tests/vertex-clip-test.c                \
        shared/helpers.h                        \
-       src/vertex-clipping.c                   \
-       src/vertex-clipping.h
+       libweston/vertex-clipping.c             \
+       libweston/vertex-clipping.h
 vertex_clip_test_LDADD = libtest-runner.la -lm $(CLOCK_GETTIME_LIBS)
 
 libtest_client_la_SOURCES =                    \
@@ -1334,8 +1334,8 @@ if BUILD_SETBACKLIGHT
 noinst_PROGRAMS += setbacklight
 setbacklight_SOURCES =                         \
        tests/setbacklight.c                    \
-       src/libbacklight.c                      \
-       src/libbacklight.h
+       libweston/libbacklight.c                \
+       libweston/libbacklight.h
 setbacklight_CFLAGS = $(AM_CFLAGS) $(SETBACKLIGHT_CFLAGS)
 setbacklight_LDADD = $(SETBACKLIGHT_LIBS)
 endif
index d0f4e3ea96e71f7e9da164641d2bab4c7e12243e..57aefdab4e01c8f164c57e78dafc231dea26545c 100644 (file)
@@ -49,7 +49,7 @@
 #include <linux/input.h>
 #include <wayland-client.h>
 
-#include "src/vertex-clipping.h"
+#include "libweston/vertex-clipping.h"
 #include "shared/xalloc.h"
 #include "window.h"
 
index 41191f69cee659e33b2272e499a691f103da21a0..9a7211d2e98290738ec5ff12f4a0bcdf5fb73e60 100644 (file)
@@ -633,11 +633,11 @@ if test "x$enable_systemd_notify" = "xyes"; then
   PKG_CHECK_MODULES(SYSTEMD_DAEMON, [libsystemd])
 fi
 
-AC_CONFIG_FILES([Makefile src/version.h compositor/weston.pc])
+AC_CONFIG_FILES([Makefile libweston/version.h compositor/weston.pc])
 
 # AC_CONFIG_FILES needs the full name when running autoconf, so we need to use
 # libweston_abi_version here, and outside [] because of m4 quoting rules
-AC_CONFIG_FILES([src/libweston-]libweston_abi_version[.pc:src/libweston.pc.in])
+AC_CONFIG_FILES([libweston/libweston-]libweston_abi_version[.pc:libweston/libweston.pc.in])
 
 AM_CONDITIONAL([HAVE_GIT_REPO], [test -f $srcdir/.git/logs/HEAD])
 
diff --git a/libweston/animation.c b/libweston/animation.c
new file mode 100644 (file)
index 0000000..2c7943f
--- /dev/null
@@ -0,0 +1,485 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <math.h>
+
+#include <unistd.h>
+#include <fcntl.h>
+
+#include "compositor.h"
+#include "shared/helpers.h"
+
+WL_EXPORT void
+weston_spring_init(struct weston_spring *spring,
+                  double k, double current, double target)
+{
+       spring->k = k;
+       spring->friction = 400.0;
+       spring->current = current;
+       spring->previous = current;
+       spring->target = target;
+       spring->clip = WESTON_SPRING_OVERSHOOT;
+       spring->min = 0.0;
+       spring->max = 1.0;
+}
+
+WL_EXPORT void
+weston_spring_update(struct weston_spring *spring, uint32_t msec)
+{
+       double force, v, current, step;
+
+       /* Limit the number of executions of the loop below by ensuring that
+        * the timestamp for last update of the spring is no more than 1s ago.
+        * This handles the case where time moves backwards or forwards in
+        * large jumps.
+        */
+       if (msec - spring->timestamp > 1000) {
+               weston_log("unexpectedly large timestamp jump (from %u to %u)\n",
+                          spring->timestamp, msec);
+               spring->timestamp = msec - 1000;
+       }
+
+       step = 0.01;
+       while (4 < msec - spring->timestamp) {
+               current = spring->current;
+               v = current - spring->previous;
+               force = spring->k * (spring->target - current) / 10.0 +
+                       (spring->previous - current) - v * spring->friction;
+
+               spring->current =
+                       current + (current - spring->previous) +
+                       force * step * step;
+               spring->previous = current;
+
+               switch (spring->clip) {
+               case WESTON_SPRING_OVERSHOOT:
+                       break;
+
+               case WESTON_SPRING_CLAMP:
+                       if (spring->current > spring->max) {
+                               spring->current = spring->max;
+                               spring->previous = spring->max;
+                       } else if (spring->current < 0.0) {
+                               spring->current = spring->min;
+                               spring->previous = spring->min;
+                       }
+                       break;
+
+               case WESTON_SPRING_BOUNCE:
+                       if (spring->current > spring->max) {
+                               spring->current =
+                                       2 * spring->max - spring->current;
+                               spring->previous =
+                                       2 * spring->max - spring->previous;
+                       } else if (spring->current < spring->min) {
+                               spring->current =
+                                       2 * spring->min - spring->current;
+                               spring->previous =
+                                       2 * spring->min - spring->previous;
+                       }
+                       break;
+               }
+
+               spring->timestamp += 4;
+       }
+}
+
+WL_EXPORT int
+weston_spring_done(struct weston_spring *spring)
+{
+       return fabs(spring->previous - spring->target) < 0.002 &&
+               fabs(spring->current - spring->target) < 0.002;
+}
+
+typedef        void (*weston_view_animation_frame_func_t)(struct weston_view_animation *animation);
+
+struct weston_view_animation {
+       struct weston_view *view;
+       struct weston_animation animation;
+       struct weston_spring spring;
+       struct weston_transform transform;
+       struct wl_listener listener;
+       float start, stop;
+       weston_view_animation_frame_func_t frame;
+       weston_view_animation_frame_func_t reset;
+       weston_view_animation_done_func_t done;
+       void *data;
+       void *private;
+};
+
+WL_EXPORT void
+weston_view_animation_destroy(struct weston_view_animation *animation)
+{
+       wl_list_remove(&animation->animation.link);
+       wl_list_remove(&animation->listener.link);
+       wl_list_remove(&animation->transform.link);
+       if (animation->reset)
+               animation->reset(animation);
+       weston_view_geometry_dirty(animation->view);
+       if (animation->done)
+               animation->done(animation, animation->data);
+       free(animation);
+}
+
+static void
+handle_animation_view_destroy(struct wl_listener *listener, void *data)
+{
+       struct weston_view_animation *animation =
+               container_of(listener,
+                            struct weston_view_animation, listener);
+
+       weston_view_animation_destroy(animation);
+}
+
+static void
+weston_view_animation_frame(struct weston_animation *base,
+                           struct weston_output *output, uint32_t msecs)
+{
+       struct weston_view_animation *animation =
+               container_of(base,
+                            struct weston_view_animation, animation);
+       struct weston_compositor *compositor =
+               animation->view->surface->compositor;
+
+       if (base->frame_counter <= 1)
+               animation->spring.timestamp = msecs;
+
+       weston_spring_update(&animation->spring, msecs);
+
+       if (weston_spring_done(&animation->spring)) {
+               weston_view_schedule_repaint(animation->view);
+               weston_view_animation_destroy(animation);
+               return;
+       }
+
+       if (animation->frame)
+               animation->frame(animation);
+
+       weston_view_geometry_dirty(animation->view);
+       weston_view_schedule_repaint(animation->view);
+
+       /* The view's output_mask will be zero if its position is
+        * offscreen. Animations should always run but as they are also
+        * run off the repaint cycle, if there's nothing to repaint
+        * the animation stops running. Therefore if we catch this situation
+        * and schedule a repaint on all outputs it will be avoided.
+        */
+       if (animation->view->output_mask == 0)
+               weston_compositor_schedule_repaint(compositor);
+}
+
+static struct weston_view_animation *
+weston_view_animation_create(struct weston_view *view,
+                            float start, float stop,
+                            weston_view_animation_frame_func_t frame,
+                            weston_view_animation_frame_func_t reset,
+                            weston_view_animation_done_func_t done,
+                            void *data,
+                            void *private)
+{
+       struct weston_view_animation *animation;
+
+       animation = malloc(sizeof *animation);
+       if (!animation)
+               return NULL;
+
+       animation->view = view;
+       animation->frame = frame;
+       animation->reset = reset;
+       animation->done = done;
+       animation->data = data;
+       animation->start = start;
+       animation->stop = stop;
+       animation->private = private;
+
+       weston_matrix_init(&animation->transform.matrix);
+       wl_list_insert(&view->geometry.transformation_list,
+                      &animation->transform.link);
+
+       animation->animation.frame = weston_view_animation_frame;
+
+       animation->listener.notify = handle_animation_view_destroy;
+       wl_signal_add(&view->destroy_signal, &animation->listener);
+
+       wl_list_insert(&view->output->animation_list,
+                      &animation->animation.link);
+
+       return animation;
+}
+
+static void
+weston_view_animation_run(struct weston_view_animation *animation)
+{
+       animation->animation.frame_counter = 0;
+       weston_view_animation_frame(&animation->animation, NULL, 0);
+}
+
+static void
+reset_alpha(struct weston_view_animation *animation)
+{
+       struct weston_view *view = animation->view;
+
+       view->alpha = animation->stop;
+}
+
+static void
+zoom_frame(struct weston_view_animation *animation)
+{
+       struct weston_view *es = animation->view;
+       float scale;
+
+       scale = animation->start +
+               (animation->stop - animation->start) *
+               animation->spring.current;
+       weston_matrix_init(&animation->transform.matrix);
+       weston_matrix_translate(&animation->transform.matrix,
+                               -0.5f * es->surface->width,
+                               -0.5f * es->surface->height, 0);
+       weston_matrix_scale(&animation->transform.matrix, scale, scale, scale);
+       weston_matrix_translate(&animation->transform.matrix,
+                               0.5f * es->surface->width,
+                               0.5f * es->surface->height, 0);
+
+       es->alpha = animation->spring.current;
+       if (es->alpha > 1.0)
+               es->alpha = 1.0;
+}
+
+WL_EXPORT struct weston_view_animation *
+weston_zoom_run(struct weston_view *view, float start, float stop,
+               weston_view_animation_done_func_t done, void *data)
+{
+       struct weston_view_animation *zoom;
+
+       zoom = weston_view_animation_create(view, start, stop,
+                                           zoom_frame, reset_alpha,
+                                           done, data, NULL);
+
+       if (zoom == NULL)
+               return NULL;
+
+       weston_spring_init(&zoom->spring, 300.0, start, stop);
+       zoom->spring.friction = 1400;
+       zoom->spring.previous = start - (stop - start) * 0.03;
+
+       weston_view_animation_run(zoom);
+
+       return zoom;
+}
+
+static void
+fade_frame(struct weston_view_animation *animation)
+{
+       if (animation->spring.current > 0.999)
+               animation->view->alpha = 1;
+       else if (animation->spring.current < 0.001 )
+               animation->view->alpha = 0;
+       else
+               animation->view->alpha = animation->spring.current;
+}
+
+WL_EXPORT struct weston_view_animation *
+weston_fade_run(struct weston_view *view,
+               float start, float end, float k,
+               weston_view_animation_done_func_t done, void *data)
+{
+       struct weston_view_animation *fade;
+
+       fade = weston_view_animation_create(view, start, end,
+                                           fade_frame, reset_alpha,
+                                           done, data, NULL);
+
+       if (fade == NULL)
+               return NULL;
+
+       weston_spring_init(&fade->spring, 1000.0, start, end);
+       fade->spring.friction = 4000;
+       fade->spring.previous = start - (end - start) * 0.1;
+
+       view->alpha = start;
+
+       weston_view_animation_run(fade);
+
+       return fade;
+}
+
+WL_EXPORT void
+weston_fade_update(struct weston_view_animation *fade, float target)
+{
+       fade->spring.target = target;
+       fade->stop = target;
+}
+
+static void
+stable_fade_frame(struct weston_view_animation *animation)
+{
+       struct weston_view *back_view;
+
+       if (animation->spring.current > 0.999)
+               animation->view->alpha = 1;
+       else if (animation->spring.current < 0.001 )
+               animation->view->alpha = 0;
+       else
+               animation->view->alpha = animation->spring.current;
+
+       back_view = (struct weston_view *) animation->private;
+       back_view->alpha =
+               (animation->spring.target - animation->view->alpha) /
+               (1.0 - animation->view->alpha);
+       weston_view_geometry_dirty(back_view);
+}
+
+WL_EXPORT struct weston_view_animation *
+weston_stable_fade_run(struct weston_view *front_view, float start,
+               struct weston_view *back_view, float end,
+               weston_view_animation_done_func_t done, void *data)
+{
+       struct weston_view_animation *fade;
+
+       fade = weston_view_animation_create(front_view, 0, 0,
+                                           stable_fade_frame, NULL,
+                                           done, data, back_view);
+
+       if (fade == NULL)
+               return NULL;
+
+       weston_spring_init(&fade->spring, 400, start, end);
+       fade->spring.friction = 1150;
+
+       front_view->alpha = start;
+       back_view->alpha = end;
+
+       weston_view_animation_run(fade);
+
+       return fade;
+}
+
+static void
+slide_frame(struct weston_view_animation *animation)
+{
+       float scale;
+
+       scale = animation->start +
+               (animation->stop - animation->start) *
+               animation->spring.current;
+       weston_matrix_init(&animation->transform.matrix);
+       weston_matrix_translate(&animation->transform.matrix, 0, scale, 0);
+}
+
+WL_EXPORT struct weston_view_animation *
+weston_slide_run(struct weston_view *view, float start, float stop,
+                weston_view_animation_done_func_t done, void *data)
+{
+       struct weston_view_animation *animation;
+
+       animation = weston_view_animation_create(view, start, stop,
+                                             slide_frame, NULL, done,
+                                             data, NULL);
+       if (!animation)
+               return NULL;
+
+       weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
+       animation->spring.friction = 600;
+       animation->spring.clip = WESTON_SPRING_BOUNCE;
+
+       weston_view_animation_run(animation);
+
+       return animation;
+}
+
+struct weston_move_animation {
+       int dx;
+       int dy;
+       int reverse;
+       weston_view_animation_done_func_t done;
+};
+
+static void
+move_frame(struct weston_view_animation *animation)
+{
+       struct weston_move_animation *move = animation->private;
+       float scale;
+       float progress = animation->spring.current;
+
+       if (move->reverse)
+               progress = 1.0 - progress;
+
+       scale = animation->start +
+                (animation->stop - animation->start) *
+                progress;
+       weston_matrix_init(&animation->transform.matrix);
+       weston_matrix_scale(&animation->transform.matrix, scale, scale, 1.0f);
+       weston_matrix_translate(&animation->transform.matrix,
+                                move->dx * progress, move->dy * progress,
+                               0);
+}
+
+static void
+move_done(struct weston_view_animation *animation, void *data)
+{
+       struct weston_move_animation *move = animation->private;
+
+       if (move->done)
+               move->done(animation, data);
+
+       free(move);
+}
+
+WL_EXPORT struct weston_view_animation *
+weston_move_scale_run(struct weston_view *view, int dx, int dy,
+                     float start, float end, int reverse,
+                     weston_view_animation_done_func_t done, void *data)
+{
+       struct weston_move_animation *move;
+       struct weston_view_animation *animation;
+
+       move = malloc(sizeof(*move));
+       if (!move)
+               return NULL;
+       move->dx = dx;
+       move->dy = dy;
+       move->reverse = reverse;
+       move->done = done;
+
+       animation = weston_view_animation_create(view, start, end, move_frame,
+                                                NULL, move_done, data, move);
+
+       if (animation == NULL){
+               free(move);
+               return NULL;
+       }
+
+       weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
+       animation->spring.friction = 1150;
+
+       weston_view_animation_run(animation);
+
+       return animation;
+}
diff --git a/libweston/bindings.c b/libweston/bindings.c
new file mode 100644 (file)
index 0000000..cc68cfe
--- /dev/null
@@ -0,0 +1,579 @@
+/*
+ * Copyright © 2011-2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <linux/input.h>
+
+#include "compositor.h"
+#include "shared/helpers.h"
+
+struct weston_binding {
+       uint32_t key;
+       uint32_t button;
+       uint32_t axis;
+       uint32_t modifier;
+       void *handler;
+       void *data;
+       struct wl_list link;
+};
+
+static struct weston_binding *
+weston_compositor_add_binding(struct weston_compositor *compositor,
+                             uint32_t key, uint32_t button, uint32_t axis,
+                             uint32_t modifier, void *handler, void *data)
+{
+       struct weston_binding *binding;
+
+       binding = malloc(sizeof *binding);
+       if (binding == NULL)
+               return NULL;
+
+       binding->key = key;
+       binding->button = button;
+       binding->axis = axis;
+       binding->modifier = modifier;
+       binding->handler = handler;
+       binding->data = data;
+
+       return binding;
+}
+
+WL_EXPORT struct weston_binding *
+weston_compositor_add_key_binding(struct weston_compositor *compositor,
+                                 uint32_t key, uint32_t modifier,
+                                 weston_key_binding_handler_t handler,
+                                 void *data)
+{
+       struct weston_binding *binding;
+
+       binding = weston_compositor_add_binding(compositor, key, 0, 0,
+                                               modifier, handler, data);
+       if (binding == NULL)
+               return NULL;
+
+       wl_list_insert(compositor->key_binding_list.prev, &binding->link);
+
+       return binding;
+}
+
+WL_EXPORT struct weston_binding *
+weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
+                                      uint32_t modifier,
+                                      weston_modifier_binding_handler_t handler,
+                                      void *data)
+{
+       struct weston_binding *binding;
+
+       binding = weston_compositor_add_binding(compositor, 0, 0, 0,
+                                               modifier, handler, data);
+       if (binding == NULL)
+               return NULL;
+
+       wl_list_insert(compositor->modifier_binding_list.prev, &binding->link);
+
+       return binding;
+}
+
+WL_EXPORT struct weston_binding *
+weston_compositor_add_button_binding(struct weston_compositor *compositor,
+                                    uint32_t button, uint32_t modifier,
+                                    weston_button_binding_handler_t handler,
+                                    void *data)
+{
+       struct weston_binding *binding;
+
+       binding = weston_compositor_add_binding(compositor, 0, button, 0,
+                                               modifier, handler, data);
+       if (binding == NULL)
+               return NULL;
+
+       wl_list_insert(compositor->button_binding_list.prev, &binding->link);
+
+       return binding;
+}
+
+WL_EXPORT struct weston_binding *
+weston_compositor_add_touch_binding(struct weston_compositor *compositor,
+                                   uint32_t modifier,
+                                   weston_touch_binding_handler_t handler,
+                                   void *data)
+{
+       struct weston_binding *binding;
+
+       binding = weston_compositor_add_binding(compositor, 0, 0, 0,
+                                               modifier, handler, data);
+       if (binding == NULL)
+               return NULL;
+
+       wl_list_insert(compositor->touch_binding_list.prev, &binding->link);
+
+       return binding;
+}
+
+WL_EXPORT struct weston_binding *
+weston_compositor_add_axis_binding(struct weston_compositor *compositor,
+                                  uint32_t axis, uint32_t modifier,
+                                  weston_axis_binding_handler_t handler,
+                                  void *data)
+{
+       struct weston_binding *binding;
+
+       binding = weston_compositor_add_binding(compositor, 0, 0, axis,
+                                               modifier, handler, data);
+       if (binding == NULL)
+               return NULL;
+
+       wl_list_insert(compositor->axis_binding_list.prev, &binding->link);
+
+       return binding;
+}
+
+WL_EXPORT struct weston_binding *
+weston_compositor_add_debug_binding(struct weston_compositor *compositor,
+                                   uint32_t key,
+                                   weston_key_binding_handler_t handler,
+                                   void *data)
+{
+       struct weston_binding *binding;
+
+       binding = weston_compositor_add_binding(compositor, key, 0, 0, 0,
+                                               handler, data);
+
+       wl_list_insert(compositor->debug_binding_list.prev, &binding->link);
+
+       return binding;
+}
+
+WL_EXPORT void
+weston_binding_destroy(struct weston_binding *binding)
+{
+       wl_list_remove(&binding->link);
+       free(binding);
+}
+
+void
+weston_binding_list_destroy_all(struct wl_list *list)
+{
+       struct weston_binding *binding, *tmp;
+
+       wl_list_for_each_safe(binding, tmp, list, link)
+               weston_binding_destroy(binding);
+}
+
+struct binding_keyboard_grab {
+       uint32_t key;
+       struct weston_keyboard_grab grab;
+};
+
+static void
+binding_key(struct weston_keyboard_grab *grab,
+           uint32_t time, uint32_t key, uint32_t state_w)
+{
+       struct binding_keyboard_grab *b =
+               container_of(grab, struct binding_keyboard_grab, grab);
+       struct wl_resource *resource;
+       enum wl_keyboard_key_state state = state_w;
+       uint32_t serial;
+       struct weston_keyboard *keyboard = grab->keyboard;
+       struct wl_display *display = keyboard->seat->compositor->wl_display;
+
+       if (key == b->key) {
+               if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
+                       weston_keyboard_end_grab(grab->keyboard);
+                       if (keyboard->input_method_resource)
+                               keyboard->grab = &keyboard->input_method_grab;
+                       free(b);
+               } else {
+                       /* Don't send the key press event for the binding key */
+                       return;
+               }
+       }
+       if (!wl_list_empty(&keyboard->focus_resource_list)) {
+               serial = wl_display_next_serial(display);
+               wl_resource_for_each(resource, &keyboard->focus_resource_list) {
+                       wl_keyboard_send_key(resource,
+                                            serial,
+                                            time,
+                                            key,
+                                            state);
+               }
+       }
+}
+
+static void
+binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
+                 uint32_t mods_depressed, uint32_t mods_latched,
+                 uint32_t mods_locked, uint32_t group)
+{
+       struct wl_resource *resource;
+
+       wl_resource_for_each(resource, &grab->keyboard->focus_resource_list) {
+               wl_keyboard_send_modifiers(resource, serial, mods_depressed,
+                                          mods_latched, mods_locked, group);
+       }
+}
+
+static void
+binding_cancel(struct weston_keyboard_grab *grab)
+{
+       struct binding_keyboard_grab *binding_grab =
+               container_of(grab, struct binding_keyboard_grab, grab);
+
+       weston_keyboard_end_grab(grab->keyboard);
+       free(binding_grab);
+}
+
+static const struct weston_keyboard_grab_interface binding_grab = {
+       binding_key,
+       binding_modifiers,
+       binding_cancel,
+};
+
+static void
+install_binding_grab(struct weston_keyboard *keyboard, uint32_t time,
+                    uint32_t key, struct weston_surface *focus)
+{
+       struct binding_keyboard_grab *grab;
+
+       grab = malloc(sizeof *grab);
+       grab->key = key;
+       grab->grab.interface = &binding_grab;
+       weston_keyboard_start_grab(keyboard, &grab->grab);
+
+       /* Notify the surface which had the focus before this binding
+        * triggered that we stole a keypress from under it, by forcing
+        * a wl_keyboard leave/enter pair. The enter event will contain
+        * the pressed key in the keys array, so the client will know
+        * the exact state of the keyboard.
+        * If the old focus surface is different than the new one it
+        * means it was changed in the binding handler, so it received
+        * the enter event already. */
+       if (focus && keyboard->focus == focus) {
+               weston_keyboard_set_focus(keyboard, NULL);
+               weston_keyboard_set_focus(keyboard, focus);
+       }
+}
+
+void
+weston_compositor_run_key_binding(struct weston_compositor *compositor,
+                                 struct weston_keyboard *keyboard,
+                                 uint32_t time, uint32_t key,
+                                 enum wl_keyboard_key_state state)
+{
+       struct weston_binding *b, *tmp;
+       struct weston_surface *focus;
+       struct weston_seat *seat = keyboard->seat;
+
+       if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
+               return;
+
+       /* Invalidate all active modifier bindings. */
+       wl_list_for_each(b, &compositor->modifier_binding_list, link)
+               b->key = key;
+
+       wl_list_for_each_safe(b, tmp, &compositor->key_binding_list, link) {
+               if (b->key == key && b->modifier == seat->modifier_state) {
+                       weston_key_binding_handler_t handler = b->handler;
+                       focus = keyboard->focus;
+                       handler(keyboard, time, key, b->data);
+
+                       /* If this was a key binding and it didn't
+                        * install a keyboard grab, install one now to
+                        * swallow the key press. */
+                       if (keyboard->grab ==
+                           &keyboard->default_grab)
+                               install_binding_grab(keyboard,
+                                                    time,
+                                                    key,
+                                                    focus);
+               }
+       }
+}
+
+void
+weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
+                                      struct weston_keyboard *keyboard,
+                                      enum weston_keyboard_modifier modifier,
+                                      enum wl_keyboard_key_state state)
+{
+       struct weston_binding *b, *tmp;
+
+       if (keyboard->grab != &keyboard->default_grab)
+               return;
+
+       wl_list_for_each_safe(b, tmp, &compositor->modifier_binding_list, link) {
+               weston_modifier_binding_handler_t handler = b->handler;
+
+               if (b->modifier != modifier)
+                       continue;
+
+               /* Prime the modifier binding. */
+               if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+                       b->key = 0;
+                       continue;
+               }
+               /* Ignore the binding if a key was pressed in between. */
+               else if (b->key != 0) {
+                       return;
+               }
+
+               handler(keyboard, modifier, b->data);
+       }
+}
+
+void
+weston_compositor_run_button_binding(struct weston_compositor *compositor,
+                                    struct weston_pointer *pointer,
+                                    uint32_t time, uint32_t button,
+                                    enum wl_pointer_button_state state)
+{
+       struct weston_binding *b, *tmp;
+
+       if (state == WL_POINTER_BUTTON_STATE_RELEASED)
+               return;
+
+       /* Invalidate all active modifier bindings. */
+       wl_list_for_each(b, &compositor->modifier_binding_list, link)
+               b->key = button;
+
+       wl_list_for_each_safe(b, tmp, &compositor->button_binding_list, link) {
+               if (b->button == button &&
+                   b->modifier == pointer->seat->modifier_state) {
+                       weston_button_binding_handler_t handler = b->handler;
+                       handler(pointer, time, button, b->data);
+               }
+       }
+}
+
+void
+weston_compositor_run_touch_binding(struct weston_compositor *compositor,
+                                   struct weston_touch *touch, uint32_t time,
+                                   int touch_type)
+{
+       struct weston_binding *b, *tmp;
+
+       if (touch->num_tp != 1 || touch_type != WL_TOUCH_DOWN)
+               return;
+
+       wl_list_for_each_safe(b, tmp, &compositor->touch_binding_list, link) {
+               if (b->modifier == touch->seat->modifier_state) {
+                       weston_touch_binding_handler_t handler = b->handler;
+                       handler(touch, time, b->data);
+               }
+       }
+}
+
+int
+weston_compositor_run_axis_binding(struct weston_compositor *compositor,
+                                  struct weston_pointer *pointer,
+                                  uint32_t time,
+                                  struct weston_pointer_axis_event *event)
+{
+       struct weston_binding *b, *tmp;
+
+       /* Invalidate all active modifier bindings. */
+       wl_list_for_each(b, &compositor->modifier_binding_list, link)
+               b->key = event->axis;
+
+       wl_list_for_each_safe(b, tmp, &compositor->axis_binding_list, link) {
+               if (b->axis == event->axis &&
+                   b->modifier == pointer->seat->modifier_state) {
+                       weston_axis_binding_handler_t handler = b->handler;
+                       handler(pointer, time, event, b->data);
+                       return 1;
+               }
+       }
+
+       return 0;
+}
+
+int
+weston_compositor_run_debug_binding(struct weston_compositor *compositor,
+                                   struct weston_keyboard *keyboard,
+                                   uint32_t time, uint32_t key,
+                                   enum wl_keyboard_key_state state)
+{
+       weston_key_binding_handler_t handler;
+       struct weston_binding *binding, *tmp;
+       int count = 0;
+
+       wl_list_for_each_safe(binding, tmp, &compositor->debug_binding_list, link) {
+               if (key != binding->key)
+                       continue;
+
+               count++;
+               handler = binding->handler;
+               handler(keyboard, time, key, binding->data);
+       }
+
+       return count;
+}
+
+struct debug_binding_grab {
+       struct weston_keyboard_grab grab;
+       struct weston_seat *seat;
+       uint32_t key[2];
+       int key_released[2];
+};
+
+static void
+debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
+                 uint32_t key, uint32_t state)
+{
+       struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
+       struct weston_compositor *ec = db->seat->compositor;
+       struct wl_display *display = ec->wl_display;
+       struct wl_resource *resource;
+       uint32_t serial;
+       int send = 0, terminate = 0;
+       int check_binding = 1;
+       int i;
+       struct wl_list *resource_list;
+
+       if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
+               /* Do not run bindings on key releases */
+               check_binding = 0;
+
+               for (i = 0; i < 2; i++)
+                       if (key == db->key[i])
+                               db->key_released[i] = 1;
+
+               if (db->key_released[0] && db->key_released[1]) {
+                       /* All key releases been swalled so end the grab */
+                       terminate = 1;
+               } else if (key != db->key[0] && key != db->key[1]) {
+                       /* Should not swallow release of other keys */
+                       send = 1;
+               }
+       } else if (key == db->key[0] && !db->key_released[0]) {
+               /* Do not check bindings for the first press of the binding
+                * key. This allows it to be used as a debug shortcut.
+                * We still need to swallow this event. */
+               check_binding = 0;
+       } else if (db->key[1]) {
+               /* If we already ran a binding don't process another one since
+                * we can't keep track of all the binding keys that were
+                * pressed in order to swallow the release events. */
+               send = 1;
+               check_binding = 0;
+       }
+
+       if (check_binding) {
+               if (weston_compositor_run_debug_binding(ec, grab->keyboard,
+                                                       time, key, state)) {
+                       /* We ran a binding so swallow the press and keep the
+                        * grab to swallow the released too. */
+                       send = 0;
+                       terminate = 0;
+                       db->key[1] = key;
+               } else {
+                       /* Terminate the grab since the key pressed is not a
+                        * debug binding key. */
+                       send = 1;
+                       terminate = 1;
+               }
+       }
+
+       if (send) {
+               serial = wl_display_next_serial(display);
+               resource_list = &grab->keyboard->focus_resource_list;
+               wl_resource_for_each(resource, resource_list) {
+                       wl_keyboard_send_key(resource, serial, time, key, state);
+               }
+       }
+
+       if (terminate) {
+               weston_keyboard_end_grab(grab->keyboard);
+               if (grab->keyboard->input_method_resource)
+                       grab->keyboard->grab = &grab->keyboard->input_method_grab;
+               free(db);
+       }
+}
+
+static void
+debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
+                       uint32_t mods_depressed, uint32_t mods_latched,
+                       uint32_t mods_locked, uint32_t group)
+{
+       struct wl_resource *resource;
+       struct wl_list *resource_list;
+
+       resource_list = &grab->keyboard->focus_resource_list;
+
+       wl_resource_for_each(resource, resource_list) {
+               wl_keyboard_send_modifiers(resource, serial, mods_depressed,
+                                          mods_latched, mods_locked, group);
+       }
+}
+
+static void
+debug_binding_cancel(struct weston_keyboard_grab *grab)
+{
+       struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
+
+       weston_keyboard_end_grab(grab->keyboard);
+       free(db);
+}
+
+struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
+       debug_binding_key,
+       debug_binding_modifiers,
+       debug_binding_cancel,
+};
+
+static void
+debug_binding(struct weston_keyboard *keyboard, uint32_t time,
+             uint32_t key, void *data)
+{
+       struct debug_binding_grab *grab;
+
+       grab = calloc(1, sizeof *grab);
+       if (!grab)
+               return;
+
+       grab->seat = keyboard->seat;
+       grab->key[0] = key;
+       grab->grab.interface = &debug_binding_keyboard_grab;
+       weston_keyboard_start_grab(keyboard, &grab->grab);
+}
+
+/** Install the trigger binding for debug bindings.
+ *
+ * \param compositor The compositor.
+ * \param mod The modifier.
+ *
+ * This will add a key binding for modifier+SHIFT+SPACE that will trigger
+ * debug key bindings.
+ */
+WL_EXPORT void
+weston_install_debug_key_binding(struct weston_compositor *compositor,
+                                uint32_t mod)
+{
+       weston_compositor_add_key_binding(compositor, KEY_SPACE,
+                                         mod | MODIFIER_SHIFT,
+                                         debug_binding, NULL);
+}
diff --git a/libweston/clipboard.c b/libweston/clipboard.c
new file mode 100644 (file)
index 0000000..54a578f
--- /dev/null
@@ -0,0 +1,306 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <linux/input.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include "compositor.h"
+#include "shared/helpers.h"
+
+struct clipboard_source {
+       struct weston_data_source base;
+       struct wl_array contents;
+       struct clipboard *clipboard;
+       struct wl_event_source *event_source;
+       uint32_t serial;
+       int refcount;
+       int fd;
+};
+
+struct clipboard {
+       struct weston_seat *seat;
+       struct wl_listener selection_listener;
+       struct wl_listener destroy_listener;
+       struct clipboard_source *source;
+};
+
+static void clipboard_client_create(struct clipboard_source *source, int fd);
+
+static void
+clipboard_source_unref(struct clipboard_source *source)
+{
+       char **s;
+
+       source->refcount--;
+       if (source->refcount > 0)
+               return;
+
+       if (source->event_source) {
+               wl_event_source_remove(source->event_source);
+               close(source->fd);
+       }
+       wl_signal_emit(&source->base.destroy_signal,
+                      &source->base);
+       s = source->base.mime_types.data;
+       free(*s);
+       wl_array_release(&source->base.mime_types);
+       wl_array_release(&source->contents);
+       free(source);
+}
+
+static int
+clipboard_source_data(int fd, uint32_t mask, void *data)
+{
+       struct clipboard_source *source = data;
+       struct clipboard *clipboard = source->clipboard;
+       char *p;
+       int len, size;
+
+       if (source->contents.alloc - source->contents.size < 1024) {
+               wl_array_add(&source->contents, 1024);
+               source->contents.size -= 1024;
+       }
+
+       p = source->contents.data + source->contents.size;
+       size = source->contents.alloc - source->contents.size;
+       len = read(fd, p, size);
+       if (len == 0) {
+               wl_event_source_remove(source->event_source);
+               close(fd);
+               source->event_source = NULL;
+       } else if (len < 0) {
+               clipboard_source_unref(source);
+               clipboard->source = NULL;
+       } else {
+               source->contents.size += len;
+       }
+
+       return 1;
+}
+
+static void
+clipboard_source_accept(struct weston_data_source *source,
+                       uint32_t time, const char *mime_type)
+{
+}
+
+static void
+clipboard_source_send(struct weston_data_source *base,
+                     const char *mime_type, int32_t fd)
+{
+       struct clipboard_source *source =
+               container_of(base, struct clipboard_source, base);
+       char **s;
+
+       s = source->base.mime_types.data;
+       if (strcmp(mime_type, s[0]) == 0)
+               clipboard_client_create(source, fd);
+       else
+               close(fd);
+}
+
+static void
+clipboard_source_cancel(struct weston_data_source *source)
+{
+}
+
+static struct clipboard_source *
+clipboard_source_create(struct clipboard *clipboard,
+                       const char *mime_type, uint32_t serial, int fd)
+{
+       struct wl_display *display = clipboard->seat->compositor->wl_display;
+       struct wl_event_loop *loop = wl_display_get_event_loop(display);
+       struct clipboard_source *source;
+       char **s;
+
+       source = zalloc(sizeof *source);
+       if (source == NULL)
+               return NULL;
+
+       wl_array_init(&source->contents);
+       wl_array_init(&source->base.mime_types);
+       source->base.resource = NULL;
+       source->base.accept = clipboard_source_accept;
+       source->base.send = clipboard_source_send;
+       source->base.cancel = clipboard_source_cancel;
+       wl_signal_init(&source->base.destroy_signal);
+       source->refcount = 1;
+       source->clipboard = clipboard;
+       source->serial = serial;
+       source->fd = fd;
+
+       s = wl_array_add(&source->base.mime_types, sizeof *s);
+       if (s == NULL)
+               goto err_add;
+       *s = strdup(mime_type);
+       if (*s == NULL)
+               goto err_strdup;
+       source->event_source =
+               wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
+                                    clipboard_source_data, source);
+       if (source->event_source == NULL)
+               goto err_source;
+
+       return source;
+
+ err_source:
+       free(*s);
+ err_strdup:
+       wl_array_release(&source->base.mime_types);
+ err_add:
+       free(source);
+
+       return NULL;
+}
+
+struct clipboard_client {
+       struct wl_event_source *event_source;
+       size_t offset;
+       struct clipboard_source *source;
+};
+
+static int
+clipboard_client_data(int fd, uint32_t mask, void *data)
+{
+       struct clipboard_client *client = data;
+       char *p;
+       size_t size;
+       int len;
+
+       size = client->source->contents.size;
+       p = client->source->contents.data;
+       len = write(fd, p + client->offset, size - client->offset);
+       if (len > 0)
+               client->offset += len;
+
+       if (client->offset == size || len <= 0) {
+               close(fd);
+               wl_event_source_remove(client->event_source);
+               clipboard_source_unref(client->source);
+               free(client);
+       }
+
+       return 1;
+}
+
+static void
+clipboard_client_create(struct clipboard_source *source, int fd)
+{
+       struct weston_seat *seat = source->clipboard->seat;
+       struct clipboard_client *client;
+       struct wl_event_loop *loop =
+               wl_display_get_event_loop(seat->compositor->wl_display);
+
+       client = zalloc(sizeof *client);
+       if (client == NULL)
+               return;
+
+       client->source = source;
+       source->refcount++;
+       client->event_source =
+               wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
+                                    clipboard_client_data, client);
+}
+
+static void
+clipboard_set_selection(struct wl_listener *listener, void *data)
+{
+       struct clipboard *clipboard =
+               container_of(listener, struct clipboard, selection_listener);
+       struct weston_seat *seat = data;
+       struct weston_data_source *source = seat->selection_data_source;
+       const char **mime_types;
+       int p[2];
+
+       if (source == NULL) {
+               if (clipboard->source)
+                       weston_seat_set_selection(seat,
+                                                 &clipboard->source->base,
+                                                 clipboard->source->serial);
+               return;
+       } else if (source->accept == clipboard_source_accept) {
+               /* Callback for our data source. */
+               return;
+       }
+
+       if (clipboard->source)
+               clipboard_source_unref(clipboard->source);
+
+       clipboard->source = NULL;
+
+       mime_types = source->mime_types.data;
+
+       if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
+               return;
+
+       source->send(source, mime_types[0], p[1]);
+
+       clipboard->source =
+               clipboard_source_create(clipboard, mime_types[0],
+                                       seat->selection_serial, p[0]);
+       if (clipboard->source == NULL) {
+               close(p[0]);
+               return;
+       }
+}
+
+static void
+clipboard_destroy(struct wl_listener *listener, void *data)
+{
+       struct clipboard *clipboard =
+               container_of(listener, struct clipboard, destroy_listener);
+
+       wl_list_remove(&clipboard->selection_listener.link);
+       wl_list_remove(&clipboard->destroy_listener.link);
+
+       free(clipboard);
+}
+
+struct clipboard *
+clipboard_create(struct weston_seat *seat)
+{
+       struct clipboard *clipboard;
+
+       clipboard = zalloc(sizeof *clipboard);
+       if (clipboard == NULL)
+               return NULL;
+
+       clipboard->seat = seat;
+       clipboard->selection_listener.notify = clipboard_set_selection;
+       clipboard->destroy_listener.notify = clipboard_destroy;
+
+       wl_signal_add(&seat->selection_signal,
+                     &clipboard->selection_listener);
+       wl_signal_add(&seat->destroy_signal,
+                     &clipboard->destroy_listener);
+
+       return clipboard;
+}
diff --git a/libweston/compositor-drm.c b/libweston/compositor-drm.c
new file mode 100644 (file)
index 0000000..f903a3b
--- /dev/null
@@ -0,0 +1,3285 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/input.h>
+#include <linux/vt.h>
+#include <assert.h>
+#include <sys/mman.h>
+#include <dlfcn.h>
+#include <time.h>
+
+#include <xf86drm.h>
+#include <xf86drmMode.h>
+#include <drm_fourcc.h>
+
+#include <gbm.h>
+#include <libudev.h>
+
+#include "compositor.h"
+#include "compositor-drm.h"
+#include "shared/helpers.h"
+#include "shared/timespec-util.h"
+#include "gl-renderer.h"
+#include "pixman-renderer.h"
+#include "libbacklight.h"
+#include "libinput-seat.h"
+#include "launcher-util.h"
+#include "vaapi-recorder.h"
+#include "presentation-time-server-protocol.h"
+#include "linux-dmabuf.h"
+
+#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
+#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
+#endif
+
+#ifndef DRM_CAP_CURSOR_WIDTH
+#define DRM_CAP_CURSOR_WIDTH 0x8
+#endif
+
+#ifndef DRM_CAP_CURSOR_HEIGHT
+#define DRM_CAP_CURSOR_HEIGHT 0x9
+#endif
+
+#ifndef GBM_BO_USE_CURSOR
+#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
+#endif
+
+struct drm_backend {
+       struct weston_backend base;
+       struct weston_compositor *compositor;
+
+       struct udev *udev;
+       struct wl_event_source *drm_source;
+
+       struct udev_monitor *udev_monitor;
+       struct wl_event_source *udev_drm_source;
+
+       struct {
+               int id;
+               int fd;
+               char *filename;
+       } drm;
+       struct gbm_device *gbm;
+       uint32_t *crtcs;
+       int num_crtcs;
+       uint32_t crtc_allocator;
+       uint32_t connector_allocator;
+       struct wl_listener session_listener;
+       uint32_t gbm_format;
+
+       /* we need these parameters in order to not fail drmModeAddFB2()
+        * due to out of bounds dimensions, and then mistakenly set
+        * sprites_are_broken:
+        */
+       uint32_t min_width, max_width;
+       uint32_t min_height, max_height;
+       int no_addfb2;
+
+       struct wl_list sprite_list;
+       int sprites_are_broken;
+       int sprites_hidden;
+
+       int cursors_are_broken;
+
+       int use_pixman;
+
+       uint32_t prev_state;
+
+       struct udev_input input;
+
+       int32_t cursor_width;
+       int32_t cursor_height;
+
+        /** Callback used to configure the outputs.
+        *
+         * This function will be called by the backend when a new DRM
+         * output needs to be configured.
+         */
+        enum weston_drm_backend_output_mode
+       (*configure_output)(struct weston_compositor *compositor,
+                           bool use_current_mode,
+                           const char *name,
+                           struct weston_drm_backend_output_config *output_config);
+       bool use_current_mode;
+};
+
+struct drm_mode {
+       struct weston_mode base;
+       drmModeModeInfo mode_info;
+};
+
+struct drm_fb {
+       uint32_t fb_id, stride, handle, size;
+       int fd;
+       int is_client_buffer;
+       struct weston_buffer_reference buffer_ref;
+
+       /* Used by gbm fbs */
+       struct gbm_bo *bo;
+
+       /* Used by dumb fbs */
+       void *map;
+};
+
+struct drm_edid {
+       char eisa_id[13];
+       char monitor_name[13];
+       char pnp_id[5];
+       char serial_number[13];
+};
+
+struct drm_output {
+       struct weston_output   base;
+
+       uint32_t crtc_id;
+       int pipe;
+       uint32_t connector_id;
+       drmModeCrtcPtr original_crtc;
+       struct drm_edid edid;
+       drmModePropertyPtr dpms_prop;
+       uint32_t gbm_format;
+
+       enum dpms_enum dpms;
+
+       int vblank_pending;
+       int page_flip_pending;
+       int destroy_pending;
+
+       struct gbm_surface *gbm_surface;
+       struct gbm_bo *gbm_cursor_bo[2];
+       struct weston_plane cursor_plane;
+       struct weston_plane fb_plane;
+       struct weston_view *cursor_view;
+       int current_cursor;
+       struct drm_fb *current, *next;
+       struct backlight *backlight;
+
+       struct drm_fb *dumb[2];
+       pixman_image_t *image[2];
+       int current_image;
+       pixman_region32_t previous_damage;
+
+       struct vaapi_recorder *recorder;
+       struct wl_listener recorder_frame_listener;
+};
+
+/*
+ * An output has a primary display plane plus zero or more sprites for
+ * blending display contents.
+ */
+struct drm_sprite {
+       struct wl_list link;
+
+       struct weston_plane plane;
+
+       struct drm_fb *current, *next;
+       struct drm_output *output;
+       struct drm_backend *backend;
+
+       uint32_t possible_crtcs;
+       uint32_t plane_id;
+       uint32_t count_formats;
+
+       int32_t src_x, src_y;
+       uint32_t src_w, src_h;
+       uint32_t dest_x, dest_y;
+       uint32_t dest_w, dest_h;
+
+       uint32_t formats[];
+};
+
+static struct gl_renderer_interface *gl_renderer;
+
+static const char default_seat[] = "seat0";
+
+static void
+drm_output_set_cursor(struct drm_output *output);
+
+static void
+drm_output_update_msc(struct drm_output *output, unsigned int seq);
+
+static int
+drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
+{
+       struct weston_compositor *ec = output->base.compositor;
+       struct drm_backend *b =(struct drm_backend *)ec->backend;
+       int crtc;
+
+       for (crtc = 0; crtc < b->num_crtcs; crtc++) {
+               if (b->crtcs[crtc] != output->crtc_id)
+                       continue;
+
+               if (supported & (1 << crtc))
+                       return -1;
+       }
+
+       return 0;
+}
+
+static void
+drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
+{
+       struct drm_fb *fb = data;
+       struct gbm_device *gbm = gbm_bo_get_device(bo);
+
+       if (fb->fb_id)
+               drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
+
+       weston_buffer_reference(&fb->buffer_ref, NULL);
+
+       free(data);
+}
+
+static struct drm_fb *
+drm_fb_create_dumb(struct drm_backend *b, unsigned width, unsigned height,
+                  uint32_t format)
+{
+       struct drm_fb *fb;
+       int ret;
+       uint32_t bpp, depth;
+
+       struct drm_mode_create_dumb create_arg;
+       struct drm_mode_destroy_dumb destroy_arg;
+       struct drm_mode_map_dumb map_arg;
+
+       fb = zalloc(sizeof *fb);
+       if (!fb)
+               return NULL;
+
+       switch (format) {
+               case GBM_FORMAT_XRGB8888:
+                       bpp = 32;
+                       depth = 24;
+                       break;
+               case GBM_FORMAT_RGB565:
+                       bpp = depth = 16;
+                       break;
+               default:
+                       return NULL;
+       }
+
+       memset(&create_arg, 0, sizeof create_arg);
+       create_arg.bpp = bpp;
+       create_arg.width = width;
+       create_arg.height = height;
+
+       ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
+       if (ret)
+               goto err_fb;
+
+       fb->handle = create_arg.handle;
+       fb->stride = create_arg.pitch;
+       fb->size = create_arg.size;
+       fb->fd = b->drm.fd;
+
+       ret = -1;
+
+       if (!b->no_addfb2) {
+               uint32_t handles[4], pitches[4], offsets[4];
+
+               handles[0] = fb->handle;
+               pitches[0] = fb->stride;
+               offsets[0] = 0;
+
+               ret = drmModeAddFB2(b->drm.fd, width, height,
+                                   format, handles, pitches, offsets,
+                                   &fb->fb_id, 0);
+               if (ret) {
+                       weston_log("addfb2 failed: %m\n");
+                       b->no_addfb2 = 1;
+               }
+       }
+
+       if (ret) {
+               ret = drmModeAddFB(b->drm.fd, width, height, depth, bpp,
+                                  fb->stride, fb->handle, &fb->fb_id);
+       }
+
+       if (ret)
+               goto err_bo;
+
+       memset(&map_arg, 0, sizeof map_arg);
+       map_arg.handle = fb->handle;
+       ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
+       if (ret)
+               goto err_add_fb;
+
+       fb->map = mmap(NULL, fb->size, PROT_WRITE,
+                      MAP_SHARED, b->drm.fd, map_arg.offset);
+       if (fb->map == MAP_FAILED)
+               goto err_add_fb;
+
+       return fb;
+
+err_add_fb:
+       drmModeRmFB(b->drm.fd, fb->fb_id);
+err_bo:
+       memset(&destroy_arg, 0, sizeof(destroy_arg));
+       destroy_arg.handle = create_arg.handle;
+       drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
+err_fb:
+       free(fb);
+       return NULL;
+}
+
+static void
+drm_fb_destroy_dumb(struct drm_fb *fb)
+{
+       struct drm_mode_destroy_dumb destroy_arg;
+
+       if (!fb->map)
+               return;
+
+       if (fb->fb_id)
+               drmModeRmFB(fb->fd, fb->fb_id);
+
+       weston_buffer_reference(&fb->buffer_ref, NULL);
+
+       munmap(fb->map, fb->size);
+
+       memset(&destroy_arg, 0, sizeof(destroy_arg));
+       destroy_arg.handle = fb->handle;
+       drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
+
+       free(fb);
+}
+
+static struct drm_fb *
+drm_fb_get_from_bo(struct gbm_bo *bo,
+                  struct drm_backend *backend, uint32_t format)
+{
+       struct drm_fb *fb = gbm_bo_get_user_data(bo);
+       uint32_t width, height;
+       uint32_t handles[4], pitches[4], offsets[4];
+       int ret;
+
+       if (fb)
+               return fb;
+
+       fb = zalloc(sizeof *fb);
+       if (fb == NULL)
+               return NULL;
+
+       fb->bo = bo;
+
+       width = gbm_bo_get_width(bo);
+       height = gbm_bo_get_height(bo);
+       fb->stride = gbm_bo_get_stride(bo);
+       fb->handle = gbm_bo_get_handle(bo).u32;
+       fb->size = fb->stride * height;
+       fb->fd = backend->drm.fd;
+
+       if (backend->min_width > width || width > backend->max_width ||
+           backend->min_height > height ||
+           height > backend->max_height) {
+               weston_log("bo geometry out of bounds\n");
+               goto err_free;
+       }
+
+       ret = -1;
+
+       if (format && !backend->no_addfb2) {
+               handles[0] = fb->handle;
+               pitches[0] = fb->stride;
+               offsets[0] = 0;
+
+               ret = drmModeAddFB2(backend->drm.fd, width, height,
+                                   format, handles, pitches, offsets,
+                                   &fb->fb_id, 0);
+               if (ret) {
+                       weston_log("addfb2 failed: %m\n");
+                       backend->no_addfb2 = 1;
+                       backend->sprites_are_broken = 1;
+               }
+       }
+
+       if (ret)
+               ret = drmModeAddFB(backend->drm.fd, width, height, 24, 32,
+                                  fb->stride, fb->handle, &fb->fb_id);
+
+       if (ret) {
+               weston_log("failed to create kms fb: %m\n");
+               goto err_free;
+       }
+
+       gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
+
+       return fb;
+
+err_free:
+       free(fb);
+       return NULL;
+}
+
+static void
+drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
+{
+       assert(fb->buffer_ref.buffer == NULL);
+
+       fb->is_client_buffer = 1;
+
+       weston_buffer_reference(&fb->buffer_ref, buffer);
+}
+
+static void
+drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
+{
+       if (!fb)
+               return;
+
+       if (fb->map &&
+            (fb != output->dumb[0] && fb != output->dumb[1])) {
+               drm_fb_destroy_dumb(fb);
+       } else if (fb->bo) {
+               if (fb->is_client_buffer)
+                       gbm_bo_destroy(fb->bo);
+               else
+                       gbm_surface_release_buffer(output->gbm_surface,
+                                                  fb->bo);
+       }
+}
+
+static uint32_t
+drm_output_check_scanout_format(struct drm_output *output,
+                               struct weston_surface *es, struct gbm_bo *bo)
+{
+       uint32_t format;
+       pixman_region32_t r;
+
+       format = gbm_bo_get_format(bo);
+
+       if (format == GBM_FORMAT_ARGB8888) {
+               /* We can scanout an ARGB buffer if the surface's
+                * opaque region covers the whole output, but we have
+                * to use XRGB as the KMS format code. */
+               pixman_region32_init_rect(&r, 0, 0,
+                                         output->base.width,
+                                         output->base.height);
+               pixman_region32_subtract(&r, &r, &es->opaque);
+
+               if (!pixman_region32_not_empty(&r))
+                       format = GBM_FORMAT_XRGB8888;
+
+               pixman_region32_fini(&r);
+       }
+
+       if (output->gbm_format == format)
+               return format;
+
+       return 0;
+}
+
+static struct weston_plane *
+drm_output_prepare_scanout_view(struct drm_output *output,
+                               struct weston_view *ev)
+{
+       struct drm_backend *b =
+               (struct drm_backend *)output->base.compositor->backend;
+       struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
+       struct gbm_bo *bo;
+       uint32_t format;
+
+       if (ev->geometry.x != output->base.x ||
+           ev->geometry.y != output->base.y ||
+           buffer == NULL || b->gbm == NULL ||
+           buffer->width != output->base.current_mode->width ||
+           buffer->height != output->base.current_mode->height ||
+           output->base.transform != viewport->buffer.transform ||
+           ev->transform.enabled)
+               return NULL;
+
+       if (ev->geometry.scissor_enabled)
+               return NULL;
+
+       bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
+                          buffer->resource, GBM_BO_USE_SCANOUT);
+
+       /* Unable to use the buffer for scanout */
+       if (!bo)
+               return NULL;
+
+       format = drm_output_check_scanout_format(output, ev->surface, bo);
+       if (format == 0) {
+               gbm_bo_destroy(bo);
+               return NULL;
+       }
+
+       output->next = drm_fb_get_from_bo(bo, b, format);
+       if (!output->next) {
+               gbm_bo_destroy(bo);
+               return NULL;
+       }
+
+       drm_fb_set_buffer(output->next, buffer);
+
+       return &output->fb_plane;
+}
+
+static void
+drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
+{
+       struct drm_backend *b =
+               (struct drm_backend *)output->base.compositor->backend;
+       struct gbm_bo *bo;
+
+       output->base.compositor->renderer->repaint_output(&output->base,
+                                                         damage);
+
+       bo = gbm_surface_lock_front_buffer(output->gbm_surface);
+       if (!bo) {
+               weston_log("failed to lock front buffer: %m\n");
+               return;
+       }
+
+       output->next = drm_fb_get_from_bo(bo, b, output->gbm_format);
+       if (!output->next) {
+               weston_log("failed to get drm_fb for bo\n");
+               gbm_surface_release_buffer(output->gbm_surface, bo);
+               return;
+       }
+}
+
+static void
+drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
+{
+       struct weston_compositor *ec = output->base.compositor;
+       pixman_region32_t total_damage, previous_damage;
+
+       pixman_region32_init(&total_damage);
+       pixman_region32_init(&previous_damage);
+
+       pixman_region32_copy(&previous_damage, damage);
+
+       pixman_region32_union(&total_damage, damage, &output->previous_damage);
+       pixman_region32_copy(&output->previous_damage, &previous_damage);
+
+       output->current_image ^= 1;
+
+       output->next = output->dumb[output->current_image];
+       pixman_renderer_output_set_buffer(&output->base,
+                                         output->image[output->current_image]);
+
+       ec->renderer->repaint_output(&output->base, &total_damage);
+
+       pixman_region32_fini(&total_damage);
+       pixman_region32_fini(&previous_damage);
+}
+
+static void
+drm_output_render(struct drm_output *output, pixman_region32_t *damage)
+{
+       struct weston_compositor *c = output->base.compositor;
+       struct drm_backend *b = (struct drm_backend *)c->backend;
+
+       if (b->use_pixman)
+               drm_output_render_pixman(output, damage);
+       else
+               drm_output_render_gl(output, damage);
+
+       pixman_region32_subtract(&c->primary_plane.damage,
+                                &c->primary_plane.damage, damage);
+}
+
+static void
+drm_output_set_gamma(struct weston_output *output_base,
+                    uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
+{
+       int rc;
+       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_backend *backend =
+               (struct drm_backend *) output->base.compositor->backend;
+
+       /* check */
+       if (output_base->gamma_size != size)
+               return;
+       if (!output->original_crtc)
+               return;
+
+       rc = drmModeCrtcSetGamma(backend->drm.fd,
+                                output->crtc_id,
+                                size, r, g, b);
+       if (rc)
+               weston_log("set gamma failed: %m\n");
+}
+
+/* Determine the type of vblank synchronization to use for the output.
+ *
+ * The pipe parameter indicates which CRTC is in use.  Knowing this, we
+ * can determine which vblank sequence type to use for it.  Traditional
+ * cards had only two CRTCs, with CRTC 0 using no special flags, and
+ * CRTC 1 using DRM_VBLANK_SECONDARY.  The first bit of the pipe
+ * parameter indicates this.
+ *
+ * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
+ * 0-31.  If this is non-zero it indicates we're dealing with a
+ * multi-gpu situation and we need to calculate the vblank sync
+ * using DRM_BLANK_HIGH_CRTC_MASK.
+ */
+static unsigned int
+drm_waitvblank_pipe(struct drm_output *output)
+{
+       if (output->pipe > 1)
+               return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
+                               DRM_VBLANK_HIGH_CRTC_MASK;
+       else if (output->pipe > 0)
+               return DRM_VBLANK_SECONDARY;
+       else
+               return 0;
+}
+
+static int
+drm_output_repaint(struct weston_output *output_base,
+                  pixman_region32_t *damage)
+{
+       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_backend *backend =
+               (struct drm_backend *)output->base.compositor->backend;
+       struct drm_sprite *s;
+       struct drm_mode *mode;
+       int ret = 0;
+
+       if (output->destroy_pending)
+               return -1;
+
+       if (!output->next)
+               drm_output_render(output, damage);
+       if (!output->next)
+               return -1;
+
+       mode = container_of(output->base.current_mode, struct drm_mode, base);
+       if (!output->current ||
+           output->current->stride != output->next->stride) {
+               ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
+                                    output->next->fb_id, 0, 0,
+                                    &output->connector_id, 1,
+                                    &mode->mode_info);
+               if (ret) {
+                       weston_log("set mode failed: %m\n");
+                       goto err_pageflip;
+               }
+               output_base->set_dpms(output_base, WESTON_DPMS_ON);
+       }
+
+       if (drmModePageFlip(backend->drm.fd, output->crtc_id,
+                           output->next->fb_id,
+                           DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
+               weston_log("queueing pageflip failed: %m\n");
+               goto err_pageflip;
+       }
+
+       output->page_flip_pending = 1;
+
+       drm_output_set_cursor(output);
+
+       /*
+        * Now, update all the sprite surfaces
+        */
+       wl_list_for_each(s, &backend->sprite_list, link) {
+               uint32_t flags = 0, fb_id = 0;
+               drmVBlank vbl = {
+                       .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
+                       .request.sequence = 1,
+               };
+
+               if ((!s->current && !s->next) ||
+                   !drm_sprite_crtc_supported(output, s->possible_crtcs))
+                       continue;
+
+               if (s->next && !backend->sprites_hidden)
+                       fb_id = s->next->fb_id;
+
+               ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
+                                     output->crtc_id, fb_id, flags,
+                                     s->dest_x, s->dest_y,
+                                     s->dest_w, s->dest_h,
+                                     s->src_x, s->src_y,
+                                     s->src_w, s->src_h);
+               if (ret)
+                       weston_log("setplane failed: %d: %s\n",
+                               ret, strerror(errno));
+
+               vbl.request.type |= drm_waitvblank_pipe(output);
+
+               /*
+                * Queue a vblank signal so we know when the surface
+                * becomes active on the display or has been replaced.
+                */
+               vbl.request.signal = (unsigned long)s;
+               ret = drmWaitVBlank(backend->drm.fd, &vbl);
+               if (ret) {
+                       weston_log("vblank event request failed: %d: %s\n",
+                               ret, strerror(errno));
+               }
+
+               s->output = output;
+               output->vblank_pending = 1;
+       }
+
+       return 0;
+
+err_pageflip:
+       output->cursor_view = NULL;
+       if (output->next) {
+               drm_output_release_fb(output, output->next);
+               output->next = NULL;
+       }
+
+       return -1;
+}
+
+static void
+drm_output_start_repaint_loop(struct weston_output *output_base)
+{
+       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_backend *backend = (struct drm_backend *)
+               output_base->compositor->backend;
+       uint32_t fb_id;
+       struct timespec ts, tnow;
+       struct timespec vbl2now;
+       int64_t refresh_nsec;
+       int ret;
+       drmVBlank vbl = {
+               .request.type = DRM_VBLANK_RELATIVE,
+               .request.sequence = 0,
+               .request.signal = 0,
+       };
+
+       if (output->destroy_pending)
+               return;
+
+       if (!output->current) {
+               /* We can't page flip if there's no mode set */
+               goto finish_frame;
+       }
+
+       /* Try to get current msc and timestamp via instant query */
+       vbl.request.type |= drm_waitvblank_pipe(output);
+       ret = drmWaitVBlank(backend->drm.fd, &vbl);
+
+       /* Error ret or zero timestamp means failure to get valid timestamp */
+       if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
+               ts.tv_sec = vbl.reply.tval_sec;
+               ts.tv_nsec = vbl.reply.tval_usec * 1000;
+
+               /* Valid timestamp for most recent vblank - not stale?
+                * Stale ts could happen on Linux 3.17+, so make sure it
+                * is not older than 1 refresh duration since now.
+                */
+               weston_compositor_read_presentation_clock(backend->compositor,
+                                                         &tnow);
+               timespec_sub(&vbl2now, &tnow, &ts);
+               refresh_nsec =
+                       millihz_to_nsec(output->base.current_mode->refresh);
+               if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
+                       drm_output_update_msc(output, vbl.reply.sequence);
+                       weston_output_finish_frame(output_base, &ts,
+                                               WP_PRESENTATION_FEEDBACK_INVALID);
+                       return;
+               }
+       }
+
+       /* Immediate query didn't provide valid timestamp.
+        * Use pageflip fallback.
+        */
+       fb_id = output->current->fb_id;
+
+       if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
+                           DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
+               weston_log("queueing pageflip failed: %m\n");
+               goto finish_frame;
+       }
+
+       return;
+
+finish_frame:
+       /* if we cannot page-flip, immediately finish frame */
+       weston_compositor_read_presentation_clock(output_base->compositor, &ts);
+       weston_output_finish_frame(output_base, &ts,
+                                  WP_PRESENTATION_FEEDBACK_INVALID);
+}
+
+static void
+drm_output_update_msc(struct drm_output *output, unsigned int seq)
+{
+       uint64_t msc_hi = output->base.msc >> 32;
+
+       if (seq < (output->base.msc & 0xffffffff))
+               msc_hi++;
+
+       output->base.msc = (msc_hi << 32) + seq;
+}
+
+static void
+vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
+              void *data)
+{
+       struct drm_sprite *s = (struct drm_sprite *)data;
+       struct drm_output *output = s->output;
+       struct timespec ts;
+       uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
+                        WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+
+       drm_output_update_msc(output, frame);
+       output->vblank_pending = 0;
+
+       drm_output_release_fb(output, s->current);
+       s->current = s->next;
+       s->next = NULL;
+
+       if (!output->page_flip_pending) {
+               ts.tv_sec = sec;
+               ts.tv_nsec = usec * 1000;
+               weston_output_finish_frame(&output->base, &ts, flags);
+       }
+}
+
+static void
+drm_output_destroy(struct weston_output *output_base);
+
+static void
+page_flip_handler(int fd, unsigned int frame,
+                 unsigned int sec, unsigned int usec, void *data)
+{
+       struct drm_output *output = (struct drm_output *) data;
+       struct timespec ts;
+       uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
+                        WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
+                        WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
+
+       drm_output_update_msc(output, frame);
+
+       /* We don't set page_flip_pending on start_repaint_loop, in that case
+        * we just want to page flip to the current buffer to get an accurate
+        * timestamp */
+       if (output->page_flip_pending) {
+               drm_output_release_fb(output, output->current);
+               output->current = output->next;
+               output->next = NULL;
+       }
+
+       output->page_flip_pending = 0;
+
+       if (output->destroy_pending)
+               drm_output_destroy(&output->base);
+       else if (!output->vblank_pending) {
+               ts.tv_sec = sec;
+               ts.tv_nsec = usec * 1000;
+               weston_output_finish_frame(&output->base, &ts, flags);
+
+               /* We can't call this from frame_notify, because the output's
+                * repaint needed flag is cleared just after that */
+               if (output->recorder)
+                       weston_output_schedule_repaint(&output->base);
+       }
+}
+
+static uint32_t
+drm_output_check_sprite_format(struct drm_sprite *s,
+                              struct weston_view *ev, struct gbm_bo *bo)
+{
+       uint32_t i, format;
+
+       format = gbm_bo_get_format(bo);
+
+       if (format == GBM_FORMAT_ARGB8888) {
+               pixman_region32_t r;
+
+               pixman_region32_init_rect(&r, 0, 0,
+                                         ev->surface->width,
+                                         ev->surface->height);
+               pixman_region32_subtract(&r, &r, &ev->surface->opaque);
+
+               if (!pixman_region32_not_empty(&r))
+                       format = GBM_FORMAT_XRGB8888;
+
+               pixman_region32_fini(&r);
+       }
+
+       for (i = 0; i < s->count_formats; i++)
+               if (s->formats[i] == format)
+                       return format;
+
+       return 0;
+}
+
+static int
+drm_view_transform_supported(struct weston_view *ev)
+{
+       return !ev->transform.enabled ||
+               (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
+}
+
+static struct weston_plane *
+drm_output_prepare_overlay_view(struct drm_output *output,
+                               struct weston_view *ev)
+{
+       struct weston_compositor *ec = output->base.compositor;
+       struct drm_backend *b = (struct drm_backend *)ec->backend;
+       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
+       struct wl_resource *buffer_resource;
+       struct drm_sprite *s;
+       struct linux_dmabuf_buffer *dmabuf;
+       int found = 0;
+       struct gbm_bo *bo;
+       pixman_region32_t dest_rect, src_rect;
+       pixman_box32_t *box, tbox;
+       uint32_t format;
+       wl_fixed_t sx1, sy1, sx2, sy2;
+
+       if (b->gbm == NULL)
+               return NULL;
+
+       if (viewport->buffer.transform != output->base.transform)
+               return NULL;
+
+       if (viewport->buffer.scale != output->base.current_scale)
+               return NULL;
+
+       if (b->sprites_are_broken)
+               return NULL;
+
+       if (ev->output_mask != (1u << output->base.id))
+               return NULL;
+
+       if (ev->surface->buffer_ref.buffer == NULL)
+               return NULL;
+       buffer_resource = ev->surface->buffer_ref.buffer->resource;
+
+       if (ev->alpha != 1.0f)
+               return NULL;
+
+       if (wl_shm_buffer_get(buffer_resource))
+               return NULL;
+
+       if (!drm_view_transform_supported(ev))
+               return NULL;
+
+       wl_list_for_each(s, &b->sprite_list, link) {
+               if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
+                       continue;
+
+               if (!s->next) {
+                       found = 1;
+                       break;
+               }
+       }
+
+       /* No sprites available */
+       if (!found)
+               return NULL;
+
+       if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
+#ifdef HAVE_GBM_FD_IMPORT
+               /* XXX: TODO:
+                *
+                * Use AddFB2 directly, do not go via GBM.
+                * Add support for multiplanar formats.
+                * Both require refactoring in the DRM-backend to
+                * support a mix of gbm_bos and drmfbs.
+                */
+               struct gbm_import_fd_data gbm_dmabuf = {
+                       .fd     = dmabuf->attributes.fd[0],
+                       .width  = dmabuf->attributes.width,
+                       .height = dmabuf->attributes.height,
+                       .stride = dmabuf->attributes.stride[0],
+                       .format = dmabuf->attributes.format
+               };
+
+               if (dmabuf->attributes.n_planes != 1 || dmabuf->attributes.offset[0] != 0)
+                       return NULL;
+
+               bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
+                                  GBM_BO_USE_SCANOUT);
+#else
+               return NULL;
+#endif
+       } else {
+               bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
+                                  buffer_resource, GBM_BO_USE_SCANOUT);
+       }
+       if (!bo)
+               return NULL;
+
+       format = drm_output_check_sprite_format(s, ev, bo);
+       if (format == 0) {
+               gbm_bo_destroy(bo);
+               return NULL;
+       }
+
+       s->next = drm_fb_get_from_bo(bo, b, format);
+       if (!s->next) {
+               gbm_bo_destroy(bo);
+               return NULL;
+       }
+
+       drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
+
+       box = pixman_region32_extents(&ev->transform.boundingbox);
+       s->plane.x = box->x1;
+       s->plane.y = box->y1;
+
+       /*
+        * Calculate the source & dest rects properly based on actual
+        * position (note the caller has called weston_view_update_transform()
+        * for us already).
+        */
+       pixman_region32_init(&dest_rect);
+       pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
+                                 &output->base.region);
+       pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
+       box = pixman_region32_extents(&dest_rect);
+       tbox = weston_transformed_rect(output->base.width,
+                                      output->base.height,
+                                      output->base.transform,
+                                      output->base.current_scale,
+                                      *box);
+       s->dest_x = tbox.x1;
+       s->dest_y = tbox.y1;
+       s->dest_w = tbox.x2 - tbox.x1;
+       s->dest_h = tbox.y2 - tbox.y1;
+       pixman_region32_fini(&dest_rect);
+
+       pixman_region32_init(&src_rect);
+       pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
+                                 &output->base.region);
+       box = pixman_region32_extents(&src_rect);
+
+       weston_view_from_global_fixed(ev,
+                                     wl_fixed_from_int(box->x1),
+                                     wl_fixed_from_int(box->y1),
+                                     &sx1, &sy1);
+       weston_view_from_global_fixed(ev,
+                                     wl_fixed_from_int(box->x2),
+                                     wl_fixed_from_int(box->y2),
+                                     &sx2, &sy2);
+
+       if (sx1 < 0)
+               sx1 = 0;
+       if (sy1 < 0)
+               sy1 = 0;
+       if (sx2 > wl_fixed_from_int(ev->surface->width))
+               sx2 = wl_fixed_from_int(ev->surface->width);
+       if (sy2 > wl_fixed_from_int(ev->surface->height))
+               sy2 = wl_fixed_from_int(ev->surface->height);
+
+       tbox.x1 = sx1;
+       tbox.y1 = sy1;
+       tbox.x2 = sx2;
+       tbox.y2 = sy2;
+
+       tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
+                                      wl_fixed_from_int(ev->surface->height),
+                                      viewport->buffer.transform,
+                                      viewport->buffer.scale,
+                                      tbox);
+
+       s->src_x = tbox.x1 << 8;
+       s->src_y = tbox.y1 << 8;
+       s->src_w = (tbox.x2 - tbox.x1) << 8;
+       s->src_h = (tbox.y2 - tbox.y1) << 8;
+       pixman_region32_fini(&src_rect);
+
+       return &s->plane;
+}
+
+static struct weston_plane *
+drm_output_prepare_cursor_view(struct drm_output *output,
+                              struct weston_view *ev)
+{
+       struct drm_backend *b =
+               (struct drm_backend *)output->base.compositor->backend;
+       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
+       struct wl_shm_buffer *shmbuf;
+
+       if (ev->transform.enabled &&
+           (ev->transform.matrix.type > WESTON_MATRIX_TRANSFORM_TRANSLATE))
+               return NULL;
+       if (b->gbm == NULL)
+               return NULL;
+       if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
+               return NULL;
+       if (viewport->buffer.scale != output->base.current_scale)
+               return NULL;
+       if (output->cursor_view)
+               return NULL;
+       if (ev->output_mask != (1u << output->base.id))
+               return NULL;
+       if (b->cursors_are_broken)
+               return NULL;
+       if (ev->geometry.scissor_enabled)
+               return NULL;
+       if (ev->surface->buffer_ref.buffer == NULL)
+               return NULL;
+       shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
+       if (!shmbuf)
+               return NULL;
+       if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)
+               return NULL;
+       if (ev->surface->width > b->cursor_width ||
+           ev->surface->height > b->cursor_height)
+               return NULL;
+
+       output->cursor_view = ev;
+
+       return &output->cursor_plane;
+}
+
+/**
+ * Update the image for the current cursor surface
+ *
+ * @param b DRM backend structure
+ * @param bo GBM buffer object to write into
+ * @param ev View to use for cursor image
+ */
+static void
+cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
+                struct weston_view *ev)
+{
+       struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
+       uint32_t buf[b->cursor_width * b->cursor_height];
+       int32_t stride;
+       uint8_t *s;
+       int i;
+
+       assert(buffer && buffer->shm_buffer);
+       assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
+       assert(ev->surface->width <= b->cursor_width);
+       assert(ev->surface->height <= b->cursor_height);
+
+       memset(buf, 0, sizeof buf);
+       stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
+       s = wl_shm_buffer_get_data(buffer->shm_buffer);
+
+       wl_shm_buffer_begin_access(buffer->shm_buffer);
+       for (i = 0; i < ev->surface->height; i++)
+               memcpy(buf + i * b->cursor_width,
+                      s + i * stride,
+                      ev->surface->width * 4);
+       wl_shm_buffer_end_access(buffer->shm_buffer);
+
+       if (gbm_bo_write(bo, buf, sizeof buf) < 0)
+               weston_log("failed update cursor: %m\n");
+}
+
+static void
+drm_output_set_cursor(struct drm_output *output)
+{
+       struct weston_view *ev = output->cursor_view;
+       struct weston_buffer *buffer;
+       struct drm_backend *b =
+               (struct drm_backend *) output->base.compositor->backend;
+       EGLint handle;
+       struct gbm_bo *bo;
+       float x, y;
+
+       output->cursor_view = NULL;
+       if (ev == NULL) {
+               drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+               output->cursor_plane.x = INT32_MIN;
+               output->cursor_plane.y = INT32_MIN;
+               return;
+       }
+
+       buffer = ev->surface->buffer_ref.buffer;
+
+       if (buffer &&
+           pixman_region32_not_empty(&output->cursor_plane.damage)) {
+               pixman_region32_fini(&output->cursor_plane.damage);
+               pixman_region32_init(&output->cursor_plane.damage);
+               output->current_cursor ^= 1;
+               bo = output->gbm_cursor_bo[output->current_cursor];
+
+               cursor_bo_update(b, bo, ev);
+               handle = gbm_bo_get_handle(bo).s32;
+               if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
+                               b->cursor_width, b->cursor_height)) {
+                       weston_log("failed to set cursor: %m\n");
+                       b->cursors_are_broken = 1;
+               }
+       }
+
+       weston_view_to_global_float(ev, 0, 0, &x, &y);
+
+       /* From global to output space, output transform is guaranteed to be
+        * NORMAL by drm_output_prepare_cursor_view().
+        */
+       x = (x - output->base.x) * output->base.current_scale;
+       y = (y - output->base.y) * output->base.current_scale;
+
+       if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
+               if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
+                       weston_log("failed to move cursor: %m\n");
+                       b->cursors_are_broken = 1;
+               }
+
+               output->cursor_plane.x = x;
+               output->cursor_plane.y = y;
+       }
+}
+
+static void
+drm_assign_planes(struct weston_output *output_base)
+{
+       struct drm_backend *b =
+               (struct drm_backend *)output_base->compositor->backend;
+       struct drm_output *output = (struct drm_output *)output_base;
+       struct weston_view *ev, *next;
+       pixman_region32_t overlap, surface_overlap;
+       struct weston_plane *primary, *next_plane;
+
+       /*
+        * Find a surface for each sprite in the output using some heuristics:
+        * 1) size
+        * 2) frequency of update
+        * 3) opacity (though some hw might support alpha blending)
+        * 4) clipping (this can be fixed with color keys)
+        *
+        * The idea is to save on blitting since this should save power.
+        * If we can get a large video surface on the sprite for example,
+        * the main display surface may not need to update at all, and
+        * the client buffer can be used directly for the sprite surface
+        * as we do for flipping full screen surfaces.
+        */
+       pixman_region32_init(&overlap);
+       primary = &output_base->compositor->primary_plane;
+
+       wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
+               struct weston_surface *es = ev->surface;
+
+               /* Test whether this buffer can ever go into a plane:
+                * non-shm, or small enough to be a cursor.
+                *
+                * Also, keep a reference when using the pixman renderer.
+                * That makes it possible to do a seamless switch to the GL
+                * renderer and since the pixman renderer keeps a reference
+                * to the buffer anyway, there is no side effects.
+                */
+               if (b->use_pixman ||
+                   (es->buffer_ref.buffer &&
+                   (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
+                    (ev->surface->width <= b->cursor_width &&
+                     ev->surface->height <= b->cursor_height))))
+                       es->keep_buffer = true;
+               else
+                       es->keep_buffer = false;
+
+               pixman_region32_init(&surface_overlap);
+               pixman_region32_intersect(&surface_overlap, &overlap,
+                                         &ev->transform.boundingbox);
+
+               next_plane = NULL;
+               if (pixman_region32_not_empty(&surface_overlap))
+                       next_plane = primary;
+               if (next_plane == NULL)
+                       next_plane = drm_output_prepare_cursor_view(output, ev);
+               if (next_plane == NULL)
+                       next_plane = drm_output_prepare_scanout_view(output, ev);
+               if (next_plane == NULL)
+                       next_plane = drm_output_prepare_overlay_view(output, ev);
+               if (next_plane == NULL)
+                       next_plane = primary;
+
+               weston_view_move_to_plane(ev, next_plane);
+
+               if (next_plane == primary)
+                       pixman_region32_union(&overlap, &overlap,
+                                             &ev->transform.boundingbox);
+
+               if (next_plane == primary ||
+                   next_plane == &output->cursor_plane) {
+                       /* cursor plane involves a copy */
+                       ev->psf_flags = 0;
+               } else {
+                       /* All other planes are a direct scanout of a
+                        * single client buffer.
+                        */
+                       ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
+               }
+
+               pixman_region32_fini(&surface_overlap);
+       }
+       pixman_region32_fini(&overlap);
+}
+
+static void
+drm_output_fini_pixman(struct drm_output *output);
+
+static void
+drm_output_destroy(struct weston_output *output_base)
+{
+       struct drm_output *output = (struct drm_output *) output_base;
+       struct drm_backend *b =
+               (struct drm_backend *)output->base.compositor->backend;
+       drmModeCrtcPtr origcrtc = output->original_crtc;
+
+       if (output->page_flip_pending) {
+               output->destroy_pending = 1;
+               weston_log("destroy output while page flip pending\n");
+               return;
+       }
+
+       if (output->backlight)
+               backlight_destroy(output->backlight);
+
+       drmModeFreeProperty(output->dpms_prop);
+
+       /* Turn off hardware cursor */
+       drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+
+       /* Restore original CRTC state */
+       drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
+                      origcrtc->x, origcrtc->y,
+                      &output->connector_id, 1, &origcrtc->mode);
+       drmModeFreeCrtc(origcrtc);
+
+       b->crtc_allocator &= ~(1 << output->crtc_id);
+       b->connector_allocator &= ~(1 << output->connector_id);
+
+       if (b->use_pixman) {
+               drm_output_fini_pixman(output);
+       } else {
+               gl_renderer->output_destroy(output_base);
+               gbm_surface_destroy(output->gbm_surface);
+       }
+
+       weston_plane_release(&output->fb_plane);
+       weston_plane_release(&output->cursor_plane);
+
+       weston_output_destroy(&output->base);
+
+       free(output);
+}
+
+/**
+ * Find the closest-matching mode for a given target
+ *
+ * Given a target mode, find the most suitable mode amongst the output's
+ * current mode list to use, preferring the current mode if possible, to
+ * avoid an expensive mode switch.
+ *
+ * @param output DRM output
+ * @param target_mode Mode to attempt to match
+ * @returns Pointer to a mode from the output's mode list
+ */
+static struct drm_mode *
+choose_mode (struct drm_output *output, struct weston_mode *target_mode)
+{
+       struct drm_mode *tmp_mode = NULL, *mode;
+
+       if (output->base.current_mode->width == target_mode->width &&
+           output->base.current_mode->height == target_mode->height &&
+           (output->base.current_mode->refresh == target_mode->refresh ||
+            target_mode->refresh == 0))
+               return (struct drm_mode *)output->base.current_mode;
+
+       wl_list_for_each(mode, &output->base.mode_list, base.link) {
+               if (mode->mode_info.hdisplay == target_mode->width &&
+                   mode->mode_info.vdisplay == target_mode->height) {
+                       if (mode->base.refresh == target_mode->refresh ||
+                           target_mode->refresh == 0) {
+                               return mode;
+                       } else if (!tmp_mode)
+                               tmp_mode = mode;
+               }
+       }
+
+       return tmp_mode;
+}
+
+static int
+drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
+static int
+drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
+
+static int
+drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
+{
+       struct drm_output *output;
+       struct drm_mode *drm_mode;
+       struct drm_backend *b;
+
+       if (output_base == NULL) {
+               weston_log("output is NULL.\n");
+               return -1;
+       }
+
+       if (mode == NULL) {
+               weston_log("mode is NULL.\n");
+               return -1;
+       }
+
+       b = (struct drm_backend *)output_base->compositor->backend;
+       output = (struct drm_output *)output_base;
+       drm_mode  = choose_mode (output, mode);
+
+       if (!drm_mode) {
+               weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
+               return -1;
+       }
+
+       if (&drm_mode->base == output->base.current_mode)
+               return 0;
+
+       output->base.current_mode->flags = 0;
+
+       output->base.current_mode = &drm_mode->base;
+       output->base.current_mode->flags =
+               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+
+       /* reset rendering stuff. */
+       drm_output_release_fb(output, output->current);
+       drm_output_release_fb(output, output->next);
+       output->current = output->next = NULL;
+
+       if (b->use_pixman) {
+               drm_output_fini_pixman(output);
+               if (drm_output_init_pixman(output, b) < 0) {
+                       weston_log("failed to init output pixman state with "
+                                  "new mode\n");
+                       return -1;
+               }
+       } else {
+               gl_renderer->output_destroy(&output->base);
+               gbm_surface_destroy(output->gbm_surface);
+
+               if (drm_output_init_egl(output, b) < 0) {
+                       weston_log("failed to init output egl state with "
+                                  "new mode");
+                       return -1;
+               }
+       }
+
+       return 0;
+}
+
+static int
+on_drm_input(int fd, uint32_t mask, void *data)
+{
+       drmEventContext evctx;
+
+       memset(&evctx, 0, sizeof evctx);
+       evctx.version = DRM_EVENT_CONTEXT_VERSION;
+       evctx.page_flip_handler = page_flip_handler;
+       evctx.vblank_handler = vblank_handler;
+       drmHandleEvent(fd, &evctx);
+
+       return 1;
+}
+
+static int
+init_drm(struct drm_backend *b, struct udev_device *device)
+{
+       const char *filename, *sysnum;
+       uint64_t cap;
+       int fd, ret;
+       clockid_t clk_id;
+
+       sysnum = udev_device_get_sysnum(device);
+       if (sysnum)
+               b->drm.id = atoi(sysnum);
+       if (!sysnum || b->drm.id < 0) {
+               weston_log("cannot get device sysnum\n");
+               return -1;
+       }
+
+       filename = udev_device_get_devnode(device);
+       fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
+       if (fd < 0) {
+               /* Probably permissions error */
+               weston_log("couldn't open %s, skipping\n",
+                       udev_device_get_devnode(device));
+               return -1;
+       }
+
+       weston_log("using %s\n", filename);
+
+       b->drm.fd = fd;
+       b->drm.filename = strdup(filename);
+
+       ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
+       if (ret == 0 && cap == 1)
+               clk_id = CLOCK_MONOTONIC;
+       else
+               clk_id = CLOCK_REALTIME;
+
+       if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
+               weston_log("Error: failed to set presentation clock %d.\n",
+                          clk_id);
+               return -1;
+       }
+
+       ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
+       if (ret == 0)
+               b->cursor_width = cap;
+       else
+               b->cursor_width = 64;
+
+       ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
+       if (ret == 0)
+               b->cursor_height = cap;
+       else
+               b->cursor_height = 64;
+
+       return 0;
+}
+
+static struct gbm_device *
+create_gbm_device(int fd)
+{
+       struct gbm_device *gbm;
+
+       gl_renderer = weston_load_module("gl-renderer.so",
+                                        "gl_renderer_interface");
+       if (!gl_renderer)
+               return NULL;
+
+       /* GBM will load a dri driver, but even though they need symbols from
+        * libglapi, in some version of Mesa they are not linked to it. Since
+        * only the gl-renderer module links to it, the call above won't make
+        * these symbols globally available, and loading the DRI driver fails.
+        * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
+       dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
+
+       gbm = gbm_create_device(fd);
+
+       return gbm;
+}
+
+/* When initializing EGL, if the preferred buffer format isn't available
+ * we may be able to substitute an ARGB format for an XRGB one.
+ *
+ * This returns 0 if substitution isn't possible, but 0 might be a
+ * legitimate format for other EGL platforms, so the caller is
+ * responsible for checking for 0 before calling gl_renderer->create().
+ *
+ * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
+ * but it's entirely possible we'll see this again on other implementations.
+ */
+static int
+fallback_format_for(uint32_t format)
+{
+       switch (format) {
+       case GBM_FORMAT_XRGB8888:
+               return GBM_FORMAT_ARGB8888;
+       case GBM_FORMAT_XRGB2101010:
+               return GBM_FORMAT_ARGB2101010;
+       default:
+               return 0;
+       }
+}
+
+static int
+drm_backend_create_gl_renderer(struct drm_backend *b)
+{
+       EGLint format[3] = {
+               b->gbm_format,
+               fallback_format_for(b->gbm_format),
+               0,
+       };
+       int n_formats = 2;
+
+       if (format[1])
+               n_formats = 3;
+       if (gl_renderer->create(b->compositor,
+                               EGL_PLATFORM_GBM_KHR,
+                               (void *)b->gbm,
+                               gl_renderer->opaque_attribs,
+                               format,
+                               n_formats) < 0) {
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+init_egl(struct drm_backend *b)
+{
+       b->gbm = create_gbm_device(b->drm.fd);
+
+       if (!b->gbm)
+               return -1;
+
+       if (drm_backend_create_gl_renderer(b) < 0) {
+               gbm_device_destroy(b->gbm);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+init_pixman(struct drm_backend *b)
+{
+       return pixman_renderer_init(b->compositor);
+}
+
+/**
+ * Add a mode to output's mode list
+ *
+ * Copy the supplied DRM mode into a Weston mode structure, and add it to the
+ * output's mode list.
+ *
+ * @param output DRM output to add mode to
+ * @param info DRM mode structure to add
+ * @returns Newly-allocated Weston/DRM mode structure
+ */
+static struct drm_mode *
+drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
+{
+       struct drm_mode *mode;
+       uint64_t refresh;
+
+       mode = malloc(sizeof *mode);
+       if (mode == NULL)
+               return NULL;
+
+       mode->base.flags = 0;
+       mode->base.width = info->hdisplay;
+       mode->base.height = info->vdisplay;
+
+       /* Calculate higher precision (mHz) refresh rate */
+       refresh = (info->clock * 1000000LL / info->htotal +
+                  info->vtotal / 2) / info->vtotal;
+
+       if (info->flags & DRM_MODE_FLAG_INTERLACE)
+               refresh *= 2;
+       if (info->flags & DRM_MODE_FLAG_DBLSCAN)
+               refresh /= 2;
+       if (info->vscan > 1)
+           refresh /= info->vscan;
+
+       mode->base.refresh = refresh;
+       mode->mode_info = *info;
+
+       if (info->type & DRM_MODE_TYPE_PREFERRED)
+               mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
+
+       wl_list_insert(output->base.mode_list.prev, &mode->base.link);
+
+       return mode;
+}
+
+static int
+drm_subpixel_to_wayland(int drm_value)
+{
+       switch (drm_value) {
+       default:
+       case DRM_MODE_SUBPIXEL_UNKNOWN:
+               return WL_OUTPUT_SUBPIXEL_UNKNOWN;
+       case DRM_MODE_SUBPIXEL_NONE:
+               return WL_OUTPUT_SUBPIXEL_NONE;
+       case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
+               return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
+       case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
+               return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
+       case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
+               return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
+       case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
+               return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
+       }
+}
+
+/* returns a value between 0-255 range, where higher is brighter */
+static uint32_t
+drm_get_backlight(struct drm_output *output)
+{
+       long brightness, max_brightness, norm;
+
+       brightness = backlight_get_brightness(output->backlight);
+       max_brightness = backlight_get_max_brightness(output->backlight);
+
+       /* convert it on a scale of 0 to 255 */
+       norm = (brightness * 255)/(max_brightness);
+
+       return (uint32_t) norm;
+}
+
+/* values accepted are between 0-255 range */
+static void
+drm_set_backlight(struct weston_output *output_base, uint32_t value)
+{
+       struct drm_output *output = (struct drm_output *) output_base;
+       long max_brightness, new_brightness;
+
+       if (!output->backlight)
+               return;
+
+       if (value > 255)
+               return;
+
+       max_brightness = backlight_get_max_brightness(output->backlight);
+
+       /* get denormalized value */
+       new_brightness = (value * max_brightness) / 255;
+
+       backlight_set_brightness(output->backlight, new_brightness);
+}
+
+static drmModePropertyPtr
+drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
+{
+       drmModePropertyPtr props;
+       int i;
+
+       for (i = 0; i < connector->count_props; i++) {
+               props = drmModeGetProperty(fd, connector->props[i]);
+               if (!props)
+                       continue;
+
+               if (!strcmp(props->name, name))
+                       return props;
+
+               drmModeFreeProperty(props);
+       }
+
+       return NULL;
+}
+
+static void
+drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
+{
+       struct drm_output *output = (struct drm_output *) output_base;
+       struct weston_compositor *ec = output_base->compositor;
+       struct drm_backend *b = (struct drm_backend *)ec->backend;
+       int ret;
+
+       if (!output->dpms_prop)
+               return;
+
+       ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
+                                         output->dpms_prop->prop_id, level);
+       if (ret) {
+               weston_log("DRM: DPMS: failed property set for %s\n",
+                          output->base.name);
+               return;
+       }
+
+       output->dpms = level;
+}
+
+static const char * const connector_type_names[] = {
+       [DRM_MODE_CONNECTOR_Unknown]     = "Unknown",
+       [DRM_MODE_CONNECTOR_VGA]         = "VGA",
+       [DRM_MODE_CONNECTOR_DVII]        = "DVI-I",
+       [DRM_MODE_CONNECTOR_DVID]        = "DVI-D",
+       [DRM_MODE_CONNECTOR_DVIA]        = "DVI-A",
+       [DRM_MODE_CONNECTOR_Composite]   = "Composite",
+       [DRM_MODE_CONNECTOR_SVIDEO]      = "SVIDEO",
+       [DRM_MODE_CONNECTOR_LVDS]        = "LVDS",
+       [DRM_MODE_CONNECTOR_Component]   = "Component",
+       [DRM_MODE_CONNECTOR_9PinDIN]     = "DIN",
+       [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
+       [DRM_MODE_CONNECTOR_HDMIA]       = "HDMI-A",
+       [DRM_MODE_CONNECTOR_HDMIB]       = "HDMI-B",
+       [DRM_MODE_CONNECTOR_TV]          = "TV",
+       [DRM_MODE_CONNECTOR_eDP]         = "eDP",
+#ifdef DRM_MODE_CONNECTOR_DSI
+       [DRM_MODE_CONNECTOR_VIRTUAL]     = "Virtual",
+       [DRM_MODE_CONNECTOR_DSI]         = "DSI",
+#endif
+};
+
+static char *
+make_connector_name(const drmModeConnector *con)
+{
+       char name[32];
+       const char *type_name = NULL;
+
+       if (con->connector_type < ARRAY_LENGTH(connector_type_names))
+               type_name = connector_type_names[con->connector_type];
+
+       if (!type_name)
+               type_name = "UNNAMED";
+
+       snprintf(name, sizeof name, "%s-%d", type_name, con->connector_type_id);
+
+       return strdup(name);
+}
+
+static int
+find_crtc_for_connector(struct drm_backend *b,
+                       drmModeRes *resources, drmModeConnector *connector)
+{
+       drmModeEncoder *encoder;
+       uint32_t possible_crtcs;
+       int i, j;
+
+       for (j = 0; j < connector->count_encoders; j++) {
+               encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
+               if (encoder == NULL) {
+                       weston_log("Failed to get encoder.\n");
+                       return -1;
+               }
+               possible_crtcs = encoder->possible_crtcs;
+               drmModeFreeEncoder(encoder);
+
+               for (i = 0; i < resources->count_crtcs; i++) {
+                       if (possible_crtcs & (1 << i) &&
+                           !(b->crtc_allocator & (1 << resources->crtcs[i])))
+                               return i;
+               }
+       }
+
+       return -1;
+}
+
+/* Init output state that depends on gl or gbm */
+static int
+drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
+{
+       EGLint format[2] = {
+               output->gbm_format,
+               fallback_format_for(output->gbm_format),
+       };
+       int i, flags, n_formats = 1;
+
+       output->gbm_surface = gbm_surface_create(b->gbm,
+                                            output->base.current_mode->width,
+                                            output->base.current_mode->height,
+                                            format[0],
+                                            GBM_BO_USE_SCANOUT |
+                                            GBM_BO_USE_RENDERING);
+       if (!output->gbm_surface) {
+               weston_log("failed to create gbm surface\n");
+               return -1;
+       }
+
+       if (format[1])
+               n_formats = 2;
+       if (gl_renderer->output_create(&output->base,
+                                      (EGLNativeWindowType)output->gbm_surface,
+                                      output->gbm_surface,
+                                      gl_renderer->opaque_attribs,
+                                      format,
+                                      n_formats) < 0) {
+               weston_log("failed to create gl renderer output state\n");
+               gbm_surface_destroy(output->gbm_surface);
+               return -1;
+       }
+
+       flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
+
+       for (i = 0; i < 2; i++) {
+               if (output->gbm_cursor_bo[i])
+                       continue;
+
+               output->gbm_cursor_bo[i] =
+                       gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
+                               GBM_FORMAT_ARGB8888, flags);
+       }
+
+       if (output->gbm_cursor_bo[0] == NULL || output->gbm_cursor_bo[1] == NULL) {
+               weston_log("cursor buffers unavailable, using gl cursors\n");
+               b->cursors_are_broken = 1;
+       }
+
+       return 0;
+}
+
+static int
+drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
+{
+       int w = output->base.current_mode->width;
+       int h = output->base.current_mode->height;
+       uint32_t format = output->gbm_format;
+       uint32_t pixman_format;
+       unsigned int i;
+
+       switch (format) {
+               case GBM_FORMAT_XRGB8888:
+                       pixman_format = PIXMAN_x8r8g8b8;
+                       break;
+               case GBM_FORMAT_RGB565:
+                       pixman_format = PIXMAN_r5g6b5;
+                       break;
+               default:
+                       weston_log("Unsupported pixman format 0x%x\n", format);
+                       return -1;
+       }
+
+       /* FIXME error checking */
+       for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+               output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
+               if (!output->dumb[i])
+                       goto err;
+
+               output->image[i] =
+                       pixman_image_create_bits(pixman_format, w, h,
+                                                output->dumb[i]->map,
+                                                output->dumb[i]->stride);
+               if (!output->image[i])
+                       goto err;
+       }
+
+       if (pixman_renderer_output_create(&output->base) < 0)
+               goto err;
+
+       pixman_region32_init_rect(&output->previous_damage,
+                                 output->base.x, output->base.y, output->base.width, output->base.height);
+
+       return 0;
+
+err:
+       for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+               if (output->dumb[i])
+                       drm_fb_destroy_dumb(output->dumb[i]);
+               if (output->image[i])
+                       pixman_image_unref(output->image[i]);
+
+               output->dumb[i] = NULL;
+               output->image[i] = NULL;
+       }
+
+       return -1;
+}
+
+static void
+drm_output_fini_pixman(struct drm_output *output)
+{
+       unsigned int i;
+
+       pixman_renderer_output_destroy(&output->base);
+       pixman_region32_fini(&output->previous_damage);
+
+       for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
+               drm_fb_destroy_dumb(output->dumb[i]);
+               pixman_image_unref(output->image[i]);
+               output->dumb[i] = NULL;
+               output->image[i] = NULL;
+       }
+}
+
+static void
+edid_parse_string(const uint8_t *data, char text[])
+{
+       int i;
+       int replaced = 0;
+
+       /* this is always 12 bytes, but we can't guarantee it's null
+        * terminated or not junk. */
+       strncpy(text, (const char *) data, 12);
+
+       /* guarantee our new string is null-terminated */
+       text[12] = '\0';
+
+       /* remove insane chars */
+       for (i = 0; text[i] != '\0'; i++) {
+               if (text[i] == '\n' ||
+                   text[i] == '\r') {
+                       text[i] = '\0';
+                       break;
+               }
+       }
+
+       /* ensure string is printable */
+       for (i = 0; text[i] != '\0'; i++) {
+               if (!isprint(text[i])) {
+                       text[i] = '-';
+                       replaced++;
+               }
+       }
+
+       /* if the string is random junk, ignore the string */
+       if (replaced > 4)
+               text[0] = '\0';
+}
+
+#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING       0xfe
+#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME           0xfc
+#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER  0xff
+#define EDID_OFFSET_DATA_BLOCKS                                0x36
+#define EDID_OFFSET_LAST_BLOCK                         0x6c
+#define EDID_OFFSET_PNPID                              0x08
+#define EDID_OFFSET_SERIAL                             0x0c
+
+static int
+edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
+{
+       int i;
+       uint32_t serial_number;
+
+       /* check header */
+       if (length < 128)
+               return -1;
+       if (data[0] != 0x00 || data[1] != 0xff)
+               return -1;
+
+       /* decode the PNP ID from three 5 bit words packed into 2 bytes
+        * /--08--\/--09--\
+        * 7654321076543210
+        * |\---/\---/\---/
+        * R  C1   C2   C3 */
+       edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
+       edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
+       edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
+       edid->pnp_id[3] = '\0';
+
+       /* maybe there isn't a ASCII serial number descriptor, so use this instead */
+       serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
+       serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
+       serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
+       serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
+       if (serial_number > 0)
+               sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
+
+       /* parse EDID data */
+       for (i = EDID_OFFSET_DATA_BLOCKS;
+            i <= EDID_OFFSET_LAST_BLOCK;
+            i += 18) {
+               /* ignore pixel clock data */
+               if (data[i] != 0)
+                       continue;
+               if (data[i+2] != 0)
+                       continue;
+
+               /* any useful blocks? */
+               if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
+                       edid_parse_string(&data[i+5],
+                                         edid->monitor_name);
+               } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
+                       edid_parse_string(&data[i+5],
+                                         edid->serial_number);
+               } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
+                       edid_parse_string(&data[i+5],
+                                         edid->eisa_id);
+               }
+       }
+       return 0;
+}
+
+static void
+find_and_parse_output_edid(struct drm_backend *b,
+                          struct drm_output *output,
+                          drmModeConnector *connector)
+{
+       drmModePropertyBlobPtr edid_blob = NULL;
+       drmModePropertyPtr property;
+       int i;
+       int rc;
+
+       for (i = 0; i < connector->count_props && !edid_blob; i++) {
+               property = drmModeGetProperty(b->drm.fd, connector->props[i]);
+               if (!property)
+                       continue;
+               if ((property->flags & DRM_MODE_PROP_BLOB) &&
+                   !strcmp(property->name, "EDID")) {
+                       edid_blob = drmModeGetPropertyBlob(b->drm.fd,
+                                                          connector->prop_values[i]);
+               }
+               drmModeFreeProperty(property);
+       }
+       if (!edid_blob)
+               return;
+
+       rc = edid_parse(&output->edid,
+                       edid_blob->data,
+                       edid_blob->length);
+       if (!rc) {
+               weston_log("EDID data '%s', '%s', '%s'\n",
+                          output->edid.pnp_id,
+                          output->edid.monitor_name,
+                          output->edid.serial_number);
+               if (output->edid.pnp_id[0] != '\0')
+                       output->base.make = output->edid.pnp_id;
+               if (output->edid.monitor_name[0] != '\0')
+                       output->base.model = output->edid.monitor_name;
+               if (output->edid.serial_number[0] != '\0')
+                       output->base.serial_number = output->edid.serial_number;
+       }
+       drmModeFreePropertyBlob(edid_blob);
+}
+
+
+
+static int
+parse_modeline(const char *s, drmModeModeInfo *mode)
+{
+       char hsync[16];
+       char vsync[16];
+       float fclock;
+
+       mode->type = DRM_MODE_TYPE_USERDEF;
+       mode->hskew = 0;
+       mode->vscan = 0;
+       mode->vrefresh = 0;
+       mode->flags = 0;
+
+       if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
+                  &fclock,
+                  &mode->hdisplay,
+                  &mode->hsync_start,
+                  &mode->hsync_end,
+                  &mode->htotal,
+                  &mode->vdisplay,
+                  &mode->vsync_start,
+                  &mode->vsync_end,
+                  &mode->vtotal, hsync, vsync) != 11)
+               return -1;
+
+       mode->clock = fclock * 1000;
+       if (strcmp(hsync, "+hsync") == 0)
+               mode->flags |= DRM_MODE_FLAG_PHSYNC;
+       else if (strcmp(hsync, "-hsync") == 0)
+               mode->flags |= DRM_MODE_FLAG_NHSYNC;
+       else
+               return -1;
+
+       if (strcmp(vsync, "+vsync") == 0)
+               mode->flags |= DRM_MODE_FLAG_PVSYNC;
+       else if (strcmp(vsync, "-vsync") == 0)
+               mode->flags |= DRM_MODE_FLAG_NVSYNC;
+       else
+               return -1;
+
+       snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
+                mode->hdisplay, mode->vdisplay, fclock);
+
+       return 0;
+}
+
+static void
+setup_output_seat_constraint(struct drm_backend *b,
+                            struct weston_output *output,
+                            const char *s)
+{
+       if (strcmp(s, "") != 0) {
+               struct weston_pointer *pointer;
+               struct udev_seat *seat;
+
+               seat = udev_seat_get_named(&b->input, s);
+               if (!seat)
+                       return;
+
+               seat->base.output = output;
+
+               pointer = weston_seat_get_pointer(&seat->base);
+               if (pointer)
+                       weston_pointer_clamp(pointer,
+                                            &pointer->x,
+                                            &pointer->y);
+       }
+}
+
+static int
+parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
+{
+       int ret = 0;
+
+       if (s == NULL)
+               *gbm_format = default_value;
+       else if (strcmp(s, "xrgb8888") == 0)
+               *gbm_format = GBM_FORMAT_XRGB8888;
+       else if (strcmp(s, "rgb565") == 0)
+               *gbm_format = GBM_FORMAT_RGB565;
+       else if (strcmp(s, "xrgb2101010") == 0)
+               *gbm_format = GBM_FORMAT_XRGB2101010;
+       else {
+               weston_log("fatal: unrecognized pixel format: %s\n", s);
+               ret = -1;
+       }
+
+       return ret;
+}
+
+/**
+ * Choose suitable mode for an output
+ *
+ * Find the most suitable mode to use for initial setup (or reconfiguration on
+ * hotplug etc) for a DRM output.
+ *
+ * @param output DRM output to choose mode for
+ * @param kind Strategy and preference to use when choosing mode
+ * @param width Desired width for this output
+ * @param height Desired height for this output
+ * @param current_mode Mode currently being displayed on this output
+ * @param modeline Manually-entered mode (may be NULL)
+ * @returns A mode from the output's mode list, or NULL if none available
+ */
+static struct drm_mode *
+drm_output_choose_initial_mode(struct drm_backend *backend,
+                              struct drm_output *output,
+                              enum weston_drm_backend_output_mode mode,
+                              struct weston_drm_backend_output_config *config,
+                              const drmModeModeInfo *current_mode)
+{
+       struct drm_mode *preferred = NULL;
+       struct drm_mode *current = NULL;
+       struct drm_mode *configured = NULL;
+       struct drm_mode *best = NULL;
+       struct drm_mode *drm_mode;
+       drmModeModeInfo modeline;
+       int32_t width = 0;
+       int32_t height = 0;
+
+       if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && config->modeline) {
+               if (sscanf(config->modeline, "%dx%d", &width, &height) != 2) {
+                       width = -1;
+
+                       if (parse_modeline(config->modeline, &modeline) == 0) {
+                               configured = drm_output_add_mode(output, &modeline);
+                               if (!configured)
+                                       return NULL;
+                       } else {
+                               weston_log("Invalid modeline \"%s\" for output %s\n",
+                                          config->modeline, output->base.name);
+                       }
+               }
+       }
+
+       wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
+               if (width == drm_mode->base.width &&
+                   height == drm_mode->base.height)
+                       configured = drm_mode;
+
+               if (memcmp(current_mode, &drm_mode->mode_info,
+                          sizeof *current_mode) == 0)
+                       current = drm_mode;
+
+               if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
+                       preferred = drm_mode;
+
+               best = drm_mode;
+       }
+
+       if (current == NULL && current_mode->clock != 0) {
+               current = drm_output_add_mode(output, current_mode);
+               if (!current)
+                       return NULL;
+       }
+
+       if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
+               configured = current;
+
+       if (configured)
+               return configured;
+
+       if (preferred)
+               return preferred;
+
+       if (current)
+               return current;
+
+       if (best)
+               return best;
+
+       weston_log("no available modes for %s\n", output->base.name);
+       return NULL;
+}
+
+static int
+connector_get_current_mode(drmModeConnector *connector, int drm_fd,
+                          drmModeModeInfo *mode)
+{
+       drmModeEncoder *encoder;
+       drmModeCrtc *crtc;
+
+       /* Get the current mode on the crtc that's currently driving
+        * this connector. */
+       encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
+       memset(mode, 0, sizeof *mode);
+       if (encoder != NULL) {
+               crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
+               drmModeFreeEncoder(encoder);
+               if (crtc == NULL)
+                       return -1;
+               if (crtc->mode_valid)
+                       *mode = crtc->mode;
+               drmModeFreeCrtc(crtc);
+       }
+
+       return 0;
+}
+
+/**
+ * Create and configure a Weston output structure
+ *
+ * Given a DRM connector, create a matching drm_output structure and add it
+ * to Weston's output list.
+ *
+ * @param b Weston backend structure structure
+ * @param resources DRM resources for this device
+ * @param connector DRM connector to use for this new output
+ * @param x Horizontal offset to use into global co-ordinate space
+ * @param y Vertical offset to use into global co-ordinate space
+ * @param drm_device udev device pointer
+ * @returns 0 on success, or -1 on failure
+ */
+static int
+create_output_for_connector(struct drm_backend *b,
+                           drmModeRes *resources,
+                           drmModeConnector *connector,
+                           int x, int y, struct udev_device *drm_device)
+{
+       struct drm_output *output;
+       struct drm_mode *drm_mode, *next, *current;
+       struct weston_mode *m;
+
+       drmModeModeInfo crtc_mode;
+       int i;
+       enum weston_drm_backend_output_mode mode;
+       struct weston_drm_backend_output_config config = {{ 0 }};
+
+       i = find_crtc_for_connector(b, resources, connector);
+       if (i < 0) {
+               weston_log("No usable crtc/encoder pair for connector.\n");
+               return -1;
+       }
+
+       output = zalloc(sizeof *output);
+       if (output == NULL)
+               return -1;
+
+       output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
+       output->base.name = make_connector_name(connector);
+       output->base.make = "unknown";
+       output->base.model = "unknown";
+       output->base.serial_number = "unknown";
+       wl_list_init(&output->base.mode_list);
+
+       mode = b->configure_output(b->compositor, b->use_current_mode,
+                                  output->base.name, &config);
+       if (parse_gbm_format(config.gbm_format, b->gbm_format, &output->gbm_format) == -1)
+               output->gbm_format = b->gbm_format;
+
+       setup_output_seat_constraint(b, &output->base,
+                                    config.seat ? config.seat : "");
+       free(config.seat);
+
+       output->crtc_id = resources->crtcs[i];
+       output->pipe = i;
+       b->crtc_allocator |= (1 << output->crtc_id);
+       output->connector_id = connector->connector_id;
+       b->connector_allocator |= (1 << output->connector_id);
+
+       output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
+       output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
+
+       if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
+               goto err_free;
+
+       for (i = 0; i < connector->count_modes; i++) {
+               drm_mode = drm_output_add_mode(output, &connector->modes[i]);
+               if (!drm_mode)
+                       goto err_free;
+       }
+
+       if (mode == WESTON_DRM_BACKEND_OUTPUT_OFF) {
+               weston_log("Disabling output %s\n", output->base.name);
+               drmModeSetCrtc(b->drm.fd, output->crtc_id,
+                              0, 0, 0, 0, 0, NULL);
+               goto err_free;
+       }
+
+       current = drm_output_choose_initial_mode(b, output, mode, &config,
+                                                &crtc_mode);
+       if (!current)
+               goto err_free;
+       output->base.current_mode = &current->base;
+       output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
+
+       weston_output_init(&output->base, b->compositor, x, y,
+                          connector->mmWidth, connector->mmHeight,
+                          config.base.transform, config.base.scale);
+
+       if (b->use_pixman) {
+               if (drm_output_init_pixman(output, b) < 0) {
+                       weston_log("Failed to init output pixman state\n");
+                       goto err_output;
+               }
+       } else if (drm_output_init_egl(output, b) < 0) {
+               weston_log("Failed to init output gl state\n");
+               goto err_output;
+       }
+
+       output->backlight = backlight_init(drm_device,
+                                          connector->connector_type);
+       if (output->backlight) {
+               weston_log("Initialized backlight, device %s\n",
+                          output->backlight->path);
+               output->base.set_backlight = drm_set_backlight;
+               output->base.backlight_current = drm_get_backlight(output);
+       } else {
+               weston_log("Failed to initialize backlight\n");
+       }
+
+       weston_compositor_add_output(b->compositor, &output->base);
+
+       find_and_parse_output_edid(b, output, connector);
+       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
+               output->base.connection_internal = 1;
+
+       output->base.start_repaint_loop = drm_output_start_repaint_loop;
+       output->base.repaint = drm_output_repaint;
+       output->base.destroy = drm_output_destroy;
+       output->base.assign_planes = drm_assign_planes;
+       output->base.set_dpms = drm_set_dpms;
+       output->base.switch_mode = drm_output_switch_mode;
+
+       output->base.gamma_size = output->original_crtc->gamma_size;
+       output->base.set_gamma = drm_output_set_gamma;
+
+       weston_plane_init(&output->cursor_plane, b->compositor,
+                         INT32_MIN, INT32_MIN);
+       weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
+
+       weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
+       weston_compositor_stack_plane(b->compositor, &output->fb_plane,
+                                     &b->compositor->primary_plane);
+
+       weston_log("Output %s, (connector %d, crtc %d)\n",
+                  output->base.name, output->connector_id, output->crtc_id);
+       wl_list_for_each(m, &output->base.mode_list, link)
+               weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
+                                   m->width, m->height, m->refresh / 1000.0,
+                                   m->flags & WL_OUTPUT_MODE_PREFERRED ?
+                                   ", preferred" : "",
+                                   m->flags & WL_OUTPUT_MODE_CURRENT ?
+                                   ", current" : "",
+                                   connector->count_modes == 0 ?
+                                   ", built-in" : "");
+
+       /* Set native_ fields, so weston_output_mode_switch_to_native() works */
+       output->base.native_mode = output->base.current_mode;
+       output->base.native_scale = output->base.current_scale;
+
+       return 0;
+
+err_output:
+       weston_output_destroy(&output->base);
+err_free:
+       wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
+                                                       base.link) {
+               wl_list_remove(&drm_mode->base.link);
+               free(drm_mode);
+       }
+
+       drmModeFreeCrtc(output->original_crtc);
+       b->crtc_allocator &= ~(1 << output->crtc_id);
+       b->connector_allocator &= ~(1 << output->connector_id);
+       free(output);
+       free(config.modeline);
+
+       return -1;
+}
+
+static void
+create_sprites(struct drm_backend *b)
+{
+       struct drm_sprite *sprite;
+       drmModePlaneRes *plane_res;
+       drmModePlane *plane;
+       uint32_t i;
+
+       plane_res = drmModeGetPlaneResources(b->drm.fd);
+       if (!plane_res) {
+               weston_log("failed to get plane resources: %s\n",
+                       strerror(errno));
+               return;
+       }
+
+       for (i = 0; i < plane_res->count_planes; i++) {
+               plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
+               if (!plane)
+                       continue;
+
+               sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
+                                                  plane->count_formats));
+               if (!sprite) {
+                       weston_log("%s: out of memory\n",
+                               __func__);
+                       drmModeFreePlane(plane);
+                       continue;
+               }
+
+               sprite->possible_crtcs = plane->possible_crtcs;
+               sprite->plane_id = plane->plane_id;
+               sprite->current = NULL;
+               sprite->next = NULL;
+               sprite->backend = b;
+               sprite->count_formats = plane->count_formats;
+               memcpy(sprite->formats, plane->formats,
+                      plane->count_formats * sizeof(plane->formats[0]));
+               drmModeFreePlane(plane);
+               weston_plane_init(&sprite->plane, b->compositor, 0, 0);
+               weston_compositor_stack_plane(b->compositor, &sprite->plane,
+                                             &b->compositor->primary_plane);
+
+               wl_list_insert(&b->sprite_list, &sprite->link);
+       }
+
+       drmModeFreePlaneResources(plane_res);
+}
+
+static void
+destroy_sprites(struct drm_backend *backend)
+{
+       struct drm_sprite *sprite, *next;
+       struct drm_output *output;
+
+       output = container_of(backend->compositor->output_list.next,
+                             struct drm_output, base.link);
+
+       wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
+               drmModeSetPlane(backend->drm.fd,
+                               sprite->plane_id,
+                               output->crtc_id, 0, 0,
+                               0, 0, 0, 0, 0, 0, 0, 0);
+               drm_output_release_fb(output, sprite->current);
+               drm_output_release_fb(output, sprite->next);
+               weston_plane_release(&sprite->plane);
+               free(sprite);
+       }
+}
+
+static int
+create_outputs(struct drm_backend *b, uint32_t option_connector,
+              struct udev_device *drm_device)
+{
+       drmModeConnector *connector;
+       drmModeRes *resources;
+       int i;
+       int x = 0, y = 0;
+
+       resources = drmModeGetResources(b->drm.fd);
+       if (!resources) {
+               weston_log("drmModeGetResources failed\n");
+               return -1;
+       }
+
+       b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
+       if (!b->crtcs) {
+               drmModeFreeResources(resources);
+               return -1;
+       }
+
+       b->min_width  = resources->min_width;
+       b->max_width  = resources->max_width;
+       b->min_height = resources->min_height;
+       b->max_height = resources->max_height;
+
+       b->num_crtcs = resources->count_crtcs;
+       memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
+
+       for (i = 0; i < resources->count_connectors; i++) {
+               connector = drmModeGetConnector(b->drm.fd,
+                                               resources->connectors[i]);
+               if (connector == NULL)
+                       continue;
+
+               if (connector->connection == DRM_MODE_CONNECTED &&
+                   (option_connector == 0 ||
+                    connector->connector_id == option_connector)) {
+                       if (create_output_for_connector(b, resources,
+                                                       connector, x, y,
+                                                       drm_device) < 0) {
+                               drmModeFreeConnector(connector);
+                               continue;
+                       }
+
+                       x += container_of(b->compositor->output_list.prev,
+                                         struct weston_output,
+                                         link)->width;
+               }
+
+               drmModeFreeConnector(connector);
+       }
+
+       if (wl_list_empty(&b->compositor->output_list)) {
+               weston_log("No currently active connector found.\n");
+               drmModeFreeResources(resources);
+               return -1;
+       }
+
+       drmModeFreeResources(resources);
+
+       return 0;
+}
+
+static void
+update_outputs(struct drm_backend *b, struct udev_device *drm_device)
+{
+       drmModeConnector *connector;
+       drmModeRes *resources;
+       struct drm_output *output, *next;
+       int x = 0, y = 0;
+       uint32_t connected = 0, disconnects = 0;
+       int i;
+
+       resources = drmModeGetResources(b->drm.fd);
+       if (!resources) {
+               weston_log("drmModeGetResources failed\n");
+               return;
+       }
+
+       /* collect new connects */
+       for (i = 0; i < resources->count_connectors; i++) {
+               int connector_id = resources->connectors[i];
+
+               connector = drmModeGetConnector(b->drm.fd, connector_id);
+               if (connector == NULL)
+                       continue;
+
+               if (connector->connection != DRM_MODE_CONNECTED) {
+                       drmModeFreeConnector(connector);
+                       continue;
+               }
+
+               connected |= (1 << connector_id);
+
+               if (!(b->connector_allocator & (1 << connector_id))) {
+                       struct weston_output *last =
+                               container_of(b->compositor->output_list.prev,
+                                            struct weston_output, link);
+
+                       /* XXX: not yet needed, we die with 0 outputs */
+                       if (!wl_list_empty(&b->compositor->output_list))
+                               x = last->x + last->width;
+                       else
+                               x = 0;
+                       y = 0;
+                       create_output_for_connector(b, resources,
+                                                   connector, x, y,
+                                                   drm_device);
+                       weston_log("connector %d connected\n", connector_id);
+
+               }
+               drmModeFreeConnector(connector);
+       }
+       drmModeFreeResources(resources);
+
+       disconnects = b->connector_allocator & ~connected;
+       if (disconnects) {
+               wl_list_for_each_safe(output, next, &b->compositor->output_list,
+                                     base.link) {
+                       if (disconnects & (1 << output->connector_id)) {
+                               disconnects &= ~(1 << output->connector_id);
+                               weston_log("connector %d disconnected\n",
+                                      output->connector_id);
+                               drm_output_destroy(&output->base);
+                       }
+               }
+       }
+
+       /* FIXME: handle zero outputs, without terminating */
+       if (b->connector_allocator == 0)
+               weston_compositor_exit(b->compositor);
+}
+
+static int
+udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
+{
+       const char *sysnum;
+       const char *val;
+
+       sysnum = udev_device_get_sysnum(device);
+       if (!sysnum || atoi(sysnum) != b->drm.id)
+               return 0;
+
+       val = udev_device_get_property_value(device, "HOTPLUG");
+       if (!val)
+               return 0;
+
+       return strcmp(val, "1") == 0;
+}
+
+static int
+udev_drm_event(int fd, uint32_t mask, void *data)
+{
+       struct drm_backend *b = data;
+       struct udev_device *event;
+
+       event = udev_monitor_receive_device(b->udev_monitor);
+
+       if (udev_event_is_hotplug(b, event))
+               update_outputs(b, event);
+
+       udev_device_unref(event);
+
+       return 1;
+}
+
+static void
+drm_restore(struct weston_compositor *ec)
+{
+       weston_launcher_restore(ec->launcher);
+}
+
+static void
+drm_destroy(struct weston_compositor *ec)
+{
+       struct drm_backend *b = (struct drm_backend *) ec->backend;
+
+       udev_input_destroy(&b->input);
+
+       wl_event_source_remove(b->udev_drm_source);
+       wl_event_source_remove(b->drm_source);
+
+       destroy_sprites(b);
+
+       weston_compositor_shutdown(ec);
+
+       if (b->gbm)
+               gbm_device_destroy(b->gbm);
+
+       weston_launcher_destroy(ec->launcher);
+
+       close(b->drm.fd);
+       free(b);
+}
+
+static void
+drm_backend_set_modes(struct drm_backend *backend)
+{
+       struct drm_output *output;
+       struct drm_mode *drm_mode;
+       int ret;
+
+       wl_list_for_each(output, &backend->compositor->output_list, base.link) {
+               if (!output->current) {
+                       /* If something that would cause the output to
+                        * switch mode happened while in another vt, we
+                        * might not have a current drm_fb. In that case,
+                        * schedule a repaint and let drm_output_repaint
+                        * handle setting the mode. */
+                       weston_output_schedule_repaint(&output->base);
+                       continue;
+               }
+
+               drm_mode = (struct drm_mode *) output->base.current_mode;
+               ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
+                                    output->current->fb_id, 0, 0,
+                                    &output->connector_id, 1,
+                                    &drm_mode->mode_info);
+               if (ret < 0) {
+                       weston_log(
+                               "failed to set mode %dx%d for output at %d,%d: %m\n",
+                               drm_mode->base.width, drm_mode->base.height,
+                               output->base.x, output->base.y);
+               }
+       }
+}
+
+static void
+session_notify(struct wl_listener *listener, void *data)
+{
+       struct weston_compositor *compositor = data;
+       struct drm_backend *b = (struct drm_backend *)compositor->backend;
+       struct drm_sprite *sprite;
+       struct drm_output *output;
+
+       if (compositor->session_active) {
+               weston_log("activating session\n");
+               compositor->state = b->prev_state;
+               drm_backend_set_modes(b);
+               weston_compositor_damage_all(compositor);
+               udev_input_enable(&b->input);
+       } else {
+               weston_log("deactivating session\n");
+               udev_input_disable(&b->input);
+
+               b->prev_state = compositor->state;
+               weston_compositor_offscreen(compositor);
+
+               /* If we have a repaint scheduled (either from a
+                * pending pageflip or the idle handler), make sure we
+                * cancel that so we don't try to pageflip when we're
+                * vt switched away.  The OFFSCREEN state will prevent
+                * further attemps at repainting.  When we switch
+                * back, we schedule a repaint, which will process
+                * pending frame callbacks. */
+
+               wl_list_for_each(output, &compositor->output_list, base.link) {
+                       output->base.repaint_needed = 0;
+                       drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
+               }
+
+               output = container_of(compositor->output_list.next,
+                                     struct drm_output, base.link);
+
+               wl_list_for_each(sprite, &b->sprite_list, link)
+                       drmModeSetPlane(b->drm.fd,
+                                       sprite->plane_id,
+                                       output->crtc_id, 0, 0,
+                                       0, 0, 0, 0, 0, 0, 0, 0);
+       };
+}
+
+/*
+ * Find primary GPU
+ * Some systems may have multiple DRM devices attached to a single seat. This
+ * function loops over all devices and tries to find a PCI device with the
+ * boot_vga sysfs attribute set to 1.
+ * If no such device is found, the first DRM device reported by udev is used.
+ */
+static struct udev_device*
+find_primary_gpu(struct drm_backend *b, const char *seat)
+{
+       struct udev_enumerate *e;
+       struct udev_list_entry *entry;
+       const char *path, *device_seat, *id;
+       struct udev_device *device, *drm_device, *pci;
+
+       e = udev_enumerate_new(b->udev);
+       udev_enumerate_add_match_subsystem(e, "drm");
+       udev_enumerate_add_match_sysname(e, "card[0-9]*");
+
+       udev_enumerate_scan_devices(e);
+       drm_device = NULL;
+       udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
+               path = udev_list_entry_get_name(entry);
+               device = udev_device_new_from_syspath(b->udev, path);
+               if (!device)
+                       continue;
+               device_seat = udev_device_get_property_value(device, "ID_SEAT");
+               if (!device_seat)
+                       device_seat = default_seat;
+               if (strcmp(device_seat, seat)) {
+                       udev_device_unref(device);
+                       continue;
+               }
+
+               pci = udev_device_get_parent_with_subsystem_devtype(device,
+                                                               "pci", NULL);
+               if (pci) {
+                       id = udev_device_get_sysattr_value(pci, "boot_vga");
+                       if (id && !strcmp(id, "1")) {
+                               if (drm_device)
+                                       udev_device_unref(drm_device);
+                               drm_device = device;
+                               break;
+                       }
+               }
+
+               if (!drm_device)
+                       drm_device = device;
+               else
+                       udev_device_unref(device);
+       }
+
+       udev_enumerate_unref(e);
+       return drm_device;
+}
+
+static void
+planes_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
+              void *data)
+{
+       struct drm_backend *b = data;
+
+       switch (key) {
+       case KEY_C:
+               b->cursors_are_broken ^= 1;
+               break;
+       case KEY_V:
+               b->sprites_are_broken ^= 1;
+               break;
+       case KEY_O:
+               b->sprites_hidden ^= 1;
+               break;
+       default:
+               break;
+       }
+}
+
+#ifdef BUILD_VAAPI_RECORDER
+static void
+recorder_destroy(struct drm_output *output)
+{
+       vaapi_recorder_destroy(output->recorder);
+       output->recorder = NULL;
+
+       output->base.disable_planes--;
+
+       wl_list_remove(&output->recorder_frame_listener.link);
+       weston_log("[libva recorder] done\n");
+}
+
+static void
+recorder_frame_notify(struct wl_listener *listener, void *data)
+{
+       struct drm_output *output;
+       struct drm_backend *b;
+       int fd, ret;
+
+       output = container_of(listener, struct drm_output,
+                             recorder_frame_listener);
+       b = (struct drm_backend *)output->base.compositor->backend;
+
+       if (!output->recorder)
+               return;
+
+       ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
+                                DRM_CLOEXEC, &fd);
+       if (ret) {
+               weston_log("[libva recorder] "
+                          "failed to create prime fd for front buffer\n");
+               return;
+       }
+
+       ret = vaapi_recorder_frame(output->recorder, fd,
+                                  output->current->stride);
+       if (ret < 0) {
+               weston_log("[libva recorder] aborted: %m\n");
+               recorder_destroy(output);
+       }
+}
+
+static void *
+create_recorder(struct drm_backend *b, int width, int height,
+               const char *filename)
+{
+       int fd;
+       drm_magic_t magic;
+
+       fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
+       if (fd < 0)
+               return NULL;
+
+       drmGetMagic(fd, &magic);
+       drmAuthMagic(b->drm.fd, magic);
+
+       return vaapi_recorder_create(fd, width, height, filename);
+}
+
+static void
+recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
+                void *data)
+{
+       struct drm_backend *b = data;
+       struct drm_output *output;
+       int width, height;
+
+       output = container_of(b->compositor->output_list.next,
+                             struct drm_output, base.link);
+
+       if (!output->recorder) {
+               if (output->gbm_format != GBM_FORMAT_XRGB8888) {
+                       weston_log("failed to start vaapi recorder: "
+                                  "output format not supported\n");
+                       return;
+               }
+
+               width = output->base.current_mode->width;
+               height = output->base.current_mode->height;
+
+               output->recorder =
+                       create_recorder(b, width, height, "capture.h264");
+               if (!output->recorder) {
+                       weston_log("failed to create vaapi recorder\n");
+                       return;
+               }
+
+               output->base.disable_planes++;
+
+               output->recorder_frame_listener.notify = recorder_frame_notify;
+               wl_signal_add(&output->base.frame_signal,
+                             &output->recorder_frame_listener);
+
+               weston_output_schedule_repaint(&output->base);
+
+               weston_log("[libva recorder] initialized\n");
+       } else {
+               recorder_destroy(output);
+       }
+}
+#else
+static void
+recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
+                void *data)
+{
+       weston_log("Compiled without libva support\n");
+}
+#endif
+
+static void
+switch_to_gl_renderer(struct drm_backend *b)
+{
+       struct drm_output *output;
+       bool dmabuf_support_inited;
+
+       if (!b->use_pixman)
+               return;
+
+       dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
+
+       weston_log("Switching to GL renderer\n");
+
+       b->gbm = create_gbm_device(b->drm.fd);
+       if (!b->gbm) {
+               weston_log("Failed to create gbm device. "
+                          "Aborting renderer switch\n");
+               return;
+       }
+
+       wl_list_for_each(output, &b->compositor->output_list, base.link)
+               pixman_renderer_output_destroy(&output->base);
+
+       b->compositor->renderer->destroy(b->compositor);
+
+       if (drm_backend_create_gl_renderer(b) < 0) {
+               gbm_device_destroy(b->gbm);
+               weston_log("Failed to create GL renderer. Quitting.\n");
+               /* FIXME: we need a function to shutdown cleanly */
+               assert(0);
+       }
+
+       wl_list_for_each(output, &b->compositor->output_list, base.link)
+               drm_output_init_egl(output, b);
+
+       b->use_pixman = 0;
+
+       if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
+               if (linux_dmabuf_setup(b->compositor) < 0)
+                       weston_log("Error: initializing dmabuf "
+                                  "support failed.\n");
+       }
+}
+
+static void
+renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
+                       uint32_t key, void *data)
+{
+       struct drm_backend *b =
+               (struct drm_backend *) keyboard->seat->compositor;
+
+       switch_to_gl_renderer(b);
+}
+
+static struct drm_backend *
+drm_backend_create(struct weston_compositor *compositor,
+                  struct weston_drm_backend_config *config)
+{
+       struct drm_backend *b;
+       struct udev_device *drm_device;
+       struct wl_event_loop *loop;
+       const char *path;
+       const char *seat_id = default_seat;
+
+       weston_log("initializing drm backend\n");
+
+       b = zalloc(sizeof *b);
+       if (b == NULL)
+               return NULL;
+
+       /*
+        * KMS support for hardware planes cannot properly synchronize
+        * without nuclear page flip. Without nuclear/atomic, hw plane
+        * and cursor plane updates would either tear or cause extra
+        * waits for vblanks which means dropping the compositor framerate
+        * to a fraction. For cursors, it's not so bad, so they are
+        * enabled.
+        *
+        * These can be enabled again when nuclear/atomic support lands.
+        */
+       b->sprites_are_broken = 1;
+       b->compositor = compositor;
+       b->use_pixman = config->use_pixman;
+       b->configure_output = config->configure_output;
+       b->use_current_mode = config->use_current_mode;
+
+       if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
+               goto err_compositor;
+
+       if (config->seat_id)
+               seat_id = config->seat_id;
+
+       /* Check if we run drm-backend using weston-launch */
+       compositor->launcher = weston_launcher_connect(compositor, config->tty,
+                                                      seat_id, true);
+       if (compositor->launcher == NULL) {
+               weston_log("fatal: drm backend should be run "
+                          "using weston-launch binary or as root\n");
+               goto err_compositor;
+       }
+
+       b->udev = udev_new();
+       if (b->udev == NULL) {
+               weston_log("failed to initialize udev context\n");
+               goto err_launcher;
+       }
+
+       b->session_listener.notify = session_notify;
+       wl_signal_add(&compositor->session_signal, &b->session_listener);
+
+       drm_device = find_primary_gpu(b, seat_id);
+       if (drm_device == NULL) {
+               weston_log("no drm device found\n");
+               goto err_udev;
+       }
+       path = udev_device_get_syspath(drm_device);
+
+       if (init_drm(b, drm_device) < 0) {
+               weston_log("failed to initialize kms\n");
+               goto err_udev_dev;
+       }
+
+       if (b->use_pixman) {
+               if (init_pixman(b) < 0) {
+                       weston_log("failed to initialize pixman renderer\n");
+                       goto err_udev_dev;
+               }
+       } else {
+               if (init_egl(b) < 0) {
+                       weston_log("failed to initialize egl\n");
+                       goto err_udev_dev;
+               }
+       }
+
+       b->base.destroy = drm_destroy;
+       b->base.restore = drm_restore;
+
+       b->prev_state = WESTON_COMPOSITOR_ACTIVE;
+
+       weston_setup_vt_switch_bindings(compositor);
+
+       wl_list_init(&b->sprite_list);
+       create_sprites(b);
+
+       if (udev_input_init(&b->input,
+                           compositor, b->udev, seat_id,
+                           config->configure_device) < 0) {
+               weston_log("failed to create input devices\n");
+               goto err_sprite;
+       }
+
+       if (create_outputs(b, config->connector, drm_device) < 0) {
+               weston_log("failed to create output for %s\n", path);
+               goto err_udev_input;
+       }
+
+       /* A this point we have some idea of whether or not we have a working
+        * cursor plane. */
+       if (!b->cursors_are_broken)
+               compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
+
+       path = NULL;
+
+       loop = wl_display_get_event_loop(compositor->wl_display);
+       b->drm_source =
+               wl_event_loop_add_fd(loop, b->drm.fd,
+                                    WL_EVENT_READABLE, on_drm_input, b);
+
+       b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
+       if (b->udev_monitor == NULL) {
+               weston_log("failed to intialize udev monitor\n");
+               goto err_drm_source;
+       }
+       udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
+                                                       "drm", NULL);
+       b->udev_drm_source =
+               wl_event_loop_add_fd(loop,
+                                    udev_monitor_get_fd(b->udev_monitor),
+                                    WL_EVENT_READABLE, udev_drm_event, b);
+
+       if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
+               weston_log("failed to enable udev-monitor receiving\n");
+               goto err_udev_monitor;
+       }
+
+       udev_device_unref(drm_device);
+
+       weston_compositor_add_debug_binding(compositor, KEY_O,
+                                           planes_binding, b);
+       weston_compositor_add_debug_binding(compositor, KEY_C,
+                                           planes_binding, b);
+       weston_compositor_add_debug_binding(compositor, KEY_V,
+                                           planes_binding, b);
+       weston_compositor_add_debug_binding(compositor, KEY_Q,
+                                           recorder_binding, b);
+       weston_compositor_add_debug_binding(compositor, KEY_W,
+                                           renderer_switch_binding, b);
+
+       if (compositor->renderer->import_dmabuf) {
+               if (linux_dmabuf_setup(compositor) < 0)
+                       weston_log("Error: initializing dmabuf "
+                                  "support failed.\n");
+       }
+
+       compositor->backend = &b->base;
+
+       return b;
+
+err_udev_monitor:
+       wl_event_source_remove(b->udev_drm_source);
+       udev_monitor_unref(b->udev_monitor);
+err_drm_source:
+       wl_event_source_remove(b->drm_source);
+err_udev_input:
+       udev_input_destroy(&b->input);
+err_sprite:
+       if (b->gbm)
+               gbm_device_destroy(b->gbm);
+       destroy_sprites(b);
+err_udev_dev:
+       udev_device_unref(drm_device);
+err_launcher:
+       weston_launcher_destroy(compositor->launcher);
+err_udev:
+       udev_unref(b->udev);
+err_compositor:
+       weston_compositor_shutdown(compositor);
+       free(b);
+       return NULL;
+}
+
+static void
+config_init_to_defaults(struct weston_drm_backend_config *config)
+{
+}
+
+WL_EXPORT int
+backend_init(struct weston_compositor *compositor,
+            struct weston_backend_config *config_base)
+{
+       struct drm_backend *b;
+       struct weston_drm_backend_config config = {{ 0, }};
+
+       if (config_base == NULL ||
+           config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
+           config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
+               weston_log("drm backend config structure is invalid\n");
+               return -1;
+       }
+
+       config_init_to_defaults(&config);
+       memcpy(&config, config_base, config_base->struct_size);
+
+       b = drm_backend_create(compositor, &config);
+       if (b == NULL)
+               return -1;
+
+       return 0;
+}
diff --git a/libweston/compositor-drm.h b/libweston/compositor-drm.h
new file mode 100644 (file)
index 0000000..1266031
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2015 Giulio Camuffo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_COMPOSITOR_DRM_H
+#define WESTON_COMPOSITOR_DRM_H
+
+#include "compositor.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define WESTON_DRM_BACKEND_CONFIG_VERSION 1
+
+struct libinput_device;
+
+enum weston_drm_backend_output_mode {
+       /** The output is disabled */
+       WESTON_DRM_BACKEND_OUTPUT_OFF,
+       /** The output will use the current active mode */
+       WESTON_DRM_BACKEND_OUTPUT_CURRENT,
+       /** The output will use the preferred mode. A modeline can be provided
+        * by setting weston_backend_output_config::modeline in the form of
+        * "WIDTHxHEIGHT" or in the form of an explicit modeline calculated
+        * using e.g. the cvt tool. If a valid modeline is supplied it will be
+        * used, if invalid or NULL the preferred available mode will be used. */
+       WESTON_DRM_BACKEND_OUTPUT_PREFERRED,
+};
+
+struct weston_drm_backend_output_config {
+       struct weston_backend_output_config base;
+
+       /** The pixel format to be used by the output. Valid values are:
+        * - NULL - The format set at backend creation time will be used;
+        * - "xrgb8888";
+        * - "rgb565"
+        * - "xrgb2101010"
+        */
+       char *gbm_format;
+       /** The seat to be used by the output. Set to NULL to use the
+        * default seat. */
+       char *seat;
+       /** The modeline to be used by the output. Refer to the documentation
+        * of WESTON_DRM_BACKEND_OUTPUT_PREFERRED for details. */
+       char *modeline;
+};
+
+/** The backend configuration struct.
+ *
+ * weston_drm_backend_config contains the configuration used by a DRM
+ * backend.
+ */
+struct weston_drm_backend_config {
+       struct weston_backend_config base;
+
+       /** The connector id of the output to be initialized.
+        *
+        * A value of 0 will enable all available outputs.
+        */
+       int connector;
+
+       /** The tty to be used. Set to 0 to use the current tty. */
+       int tty;
+
+       /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
+       bool use_pixman;
+
+       /** The seat to be used for input and output.
+        *
+        * If NULL the default "seat0" will be used.  The backend will
+        * take ownership of the seat_id pointer and will free it on
+        * backend destruction.
+        */
+       char *seat_id;
+
+       /** The pixel format of the framebuffer to be used.
+        *
+        * Valid values are:
+        * - NULL - The default format ("xrgb8888") will be used;
+        * - "xrgb8888";
+        * - "rgb565"
+        * - "xrgb2101010"
+        * The backend will take ownership of the format pointer and will free
+        * it on backend destruction.
+        */
+       char *gbm_format;
+
+       /** Callback used to configure the outputs.
+        *
+        * This function will be called by the backend when a new DRM
+        * output needs to be configured.
+        */
+       enum weston_drm_backend_output_mode
+               (*configure_output)(struct weston_compositor *compositor,
+                                   bool use_current_mode,
+                                   const char *name,
+                                   struct weston_drm_backend_output_config *output_config);
+
+       /** Callback used to configure input devices.
+        *
+        * This function will be called by the backend when a new input device
+        * needs to be configured.
+        * If NULL the device will use the default configuration.
+        */
+       void (*configure_device)(struct weston_compositor *compositor,
+                                struct libinput_device *device);
+       bool use_current_mode;
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WESTON_COMPOSITOR_DRM_H */
diff --git a/libweston/compositor-fbdev.c b/libweston/compositor-fbdev.c
new file mode 100644 (file)
index 0000000..e21ceca
--- /dev/null
@@ -0,0 +1,783 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2012 Raspberry Pi Foundation
+ * Copyright © 2013 Philip Withnall
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/fb.h>
+#include <linux/input.h>
+
+#include <libudev.h>
+
+#include "shared/helpers.h"
+#include "compositor.h"
+#include "compositor-fbdev.h"
+#include "launcher-util.h"
+#include "pixman-renderer.h"
+#include "libinput-seat.h"
+#include "presentation-time-server-protocol.h"
+
+struct fbdev_backend {
+       struct weston_backend base;
+       struct weston_compositor *compositor;
+       uint32_t prev_state;
+
+       struct udev *udev;
+       struct udev_input input;
+       uint32_t output_transform;
+       struct wl_listener session_listener;
+};
+
+struct fbdev_screeninfo {
+       unsigned int x_resolution; /* pixels, visible area */
+       unsigned int y_resolution; /* pixels, visible area */
+       unsigned int width_mm; /* visible screen width in mm */
+       unsigned int height_mm; /* visible screen height in mm */
+       unsigned int bits_per_pixel;
+
+       size_t buffer_length; /* length of frame buffer memory in bytes */
+       size_t line_length; /* length of a line in bytes */
+       char id[16]; /* screen identifier */
+
+       pixman_format_code_t pixel_format; /* frame buffer pixel format */
+       unsigned int refresh_rate; /* Hertz */
+};
+
+struct fbdev_output {
+       struct fbdev_backend *backend;
+       struct weston_output base;
+
+       struct weston_mode mode;
+       struct wl_event_source *finish_frame_timer;
+
+       /* Frame buffer details. */
+       char *device;
+       struct fbdev_screeninfo fb_info;
+       void *fb; /* length is fb_info.buffer_length */
+
+       /* pixman details. */
+       pixman_image_t *hw_surface;
+       uint8_t depth;
+};
+
+static const char default_seat[] = "seat0";
+
+static inline struct fbdev_output *
+to_fbdev_output(struct weston_output *base)
+{
+       return container_of(base, struct fbdev_output, base);
+}
+
+static inline struct fbdev_backend *
+to_fbdev_backend(struct weston_compositor *base)
+{
+       return container_of(base->backend, struct fbdev_backend, base);
+}
+
+static void
+fbdev_output_start_repaint_loop(struct weston_output *output)
+{
+       struct timespec ts;
+
+       weston_compositor_read_presentation_clock(output->compositor, &ts);
+       weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
+}
+
+static int
+fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
+{
+       struct fbdev_output *output = to_fbdev_output(base);
+       struct weston_compositor *ec = output->base.compositor;
+
+       /* Repaint the damaged region onto the back buffer. */
+       pixman_renderer_output_set_buffer(base, output->hw_surface);
+       ec->renderer->repaint_output(base, damage);
+
+       /* Update the damage region. */
+       pixman_region32_subtract(&ec->primary_plane.damage,
+                                &ec->primary_plane.damage, damage);
+
+       /* Schedule the end of the frame. We do not sync this to the frame
+        * buffer clock because users who want that should be using the DRM
+        * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
+        * panning, which is broken in most kernel drivers.
+        *
+        * Finish the frame synchronised to the specified refresh rate. The
+        * refresh rate is given in mHz and the interval in ms. */
+       wl_event_source_timer_update(output->finish_frame_timer,
+                                    1000000 / output->mode.refresh);
+
+       return 0;
+}
+
+static int
+finish_frame_handler(void *data)
+{
+       struct fbdev_output *output = data;
+       struct timespec ts;
+
+       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
+       weston_output_finish_frame(&output->base, &ts, 0);
+
+       return 1;
+}
+
+static pixman_format_code_t
+calculate_pixman_format(struct fb_var_screeninfo *vinfo,
+                        struct fb_fix_screeninfo *finfo)
+{
+       /* Calculate the pixman format supported by the frame buffer from the
+        * buffer's metadata. Return 0 if no known pixman format is supported
+        * (since this has depth 0 it's guaranteed to not conflict with any
+        * actual pixman format).
+        *
+        * Documentation on the vinfo and finfo structures:
+        *    http://www.mjmwired.net/kernel/Documentation/fb/api.txt
+        *
+        * TODO: Try a bit harder to support other formats, including setting
+        * the preferred format in the hardware. */
+       int type;
+
+       weston_log("Calculating pixman format from:\n"
+                  STAMP_SPACE " - type: %i (aux: %i)\n"
+                  STAMP_SPACE " - visual: %i\n"
+                  STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
+                  STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
+                  STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
+                  STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
+                  STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
+                  finfo->type, finfo->type_aux, finfo->visual,
+                  vinfo->bits_per_pixel, vinfo->grayscale,
+                  vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
+                  vinfo->green.offset, vinfo->green.length,
+                  vinfo->green.msb_right,
+                  vinfo->blue.offset, vinfo->blue.length,
+                  vinfo->blue.msb_right,
+                  vinfo->transp.offset, vinfo->transp.length,
+                  vinfo->transp.msb_right);
+
+       /* We only handle packed formats at the moment. */
+       if (finfo->type != FB_TYPE_PACKED_PIXELS)
+               return 0;
+
+       /* We only handle true-colour frame buffers at the moment. */
+       switch(finfo->visual) {
+               case FB_VISUAL_TRUECOLOR:
+               case FB_VISUAL_DIRECTCOLOR:
+                       if (vinfo->grayscale != 0)
+                               return 0;
+               break;
+               default:
+                       return 0;
+       }
+
+       /* We only support formats with MSBs on the left. */
+       if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
+           vinfo->blue.msb_right != 0)
+               return 0;
+
+       /* Work out the format type from the offsets. We only support RGBA and
+        * ARGB at the moment. */
+       type = PIXMAN_TYPE_OTHER;
+
+       if ((vinfo->transp.offset >= vinfo->red.offset ||
+            vinfo->transp.length == 0) &&
+           vinfo->red.offset >= vinfo->green.offset &&
+           vinfo->green.offset >= vinfo->blue.offset)
+               type = PIXMAN_TYPE_ARGB;
+       else if (vinfo->red.offset >= vinfo->green.offset &&
+                vinfo->green.offset >= vinfo->blue.offset &&
+                vinfo->blue.offset >= vinfo->transp.offset)
+               type = PIXMAN_TYPE_RGBA;
+
+       if (type == PIXMAN_TYPE_OTHER)
+               return 0;
+
+       /* Build the format. */
+       return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
+                            vinfo->transp.length,
+                            vinfo->red.length,
+                            vinfo->green.length,
+                            vinfo->blue.length);
+}
+
+static int
+calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
+{
+       uint64_t quot;
+
+       /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
+       quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
+       quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
+       quot *= vinfo->pixclock;
+
+       if (quot > 0) {
+               uint64_t refresh_rate;
+
+               refresh_rate = 1000000000000000LLU / quot;
+               if (refresh_rate > 200000)
+                       refresh_rate = 200000; /* cap at 200 Hz */
+
+               return refresh_rate;
+       }
+
+       return 60 * 1000; /* default to 60 Hz */
+}
+
+static int
+fbdev_query_screen_info(struct fbdev_output *output, int fd,
+                        struct fbdev_screeninfo *info)
+{
+       struct fb_var_screeninfo varinfo;
+       struct fb_fix_screeninfo fixinfo;
+
+       /* Probe the device for screen information. */
+       if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
+           ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
+               return -1;
+       }
+
+       /* Store the pertinent data. */
+       info->x_resolution = varinfo.xres;
+       info->y_resolution = varinfo.yres;
+       info->width_mm = varinfo.width;
+       info->height_mm = varinfo.height;
+       info->bits_per_pixel = varinfo.bits_per_pixel;
+
+       info->buffer_length = fixinfo.smem_len;
+       info->line_length = fixinfo.line_length;
+       strncpy(info->id, fixinfo.id, sizeof(info->id));
+       info->id[sizeof(info->id)-1] = '\0';
+
+       info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
+       info->refresh_rate = calculate_refresh_rate(&varinfo);
+
+       if (info->pixel_format == 0) {
+               weston_log("Frame buffer uses an unsupported format.\n");
+               return -1;
+       }
+
+       return 1;
+}
+
+static int
+fbdev_set_screen_info(struct fbdev_output *output, int fd,
+                      struct fbdev_screeninfo *info)
+{
+       struct fb_var_screeninfo varinfo;
+
+       /* Grab the current screen information. */
+       if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
+               return -1;
+       }
+
+       /* Update the information. */
+       varinfo.xres = info->x_resolution;
+       varinfo.yres = info->y_resolution;
+       varinfo.width = info->width_mm;
+       varinfo.height = info->height_mm;
+       varinfo.bits_per_pixel = info->bits_per_pixel;
+
+       /* Try to set up an ARGB (x8r8g8b8) pixel format. */
+       varinfo.grayscale = 0;
+       varinfo.transp.offset = 24;
+       varinfo.transp.length = 0;
+       varinfo.transp.msb_right = 0;
+       varinfo.red.offset = 16;
+       varinfo.red.length = 8;
+       varinfo.red.msb_right = 0;
+       varinfo.green.offset = 8;
+       varinfo.green.length = 8;
+       varinfo.green.msb_right = 0;
+       varinfo.blue.offset = 0;
+       varinfo.blue.length = 8;
+       varinfo.blue.msb_right = 0;
+
+       /* Set the device's screen information. */
+       if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
+               return -1;
+       }
+
+       return 1;
+}
+
+static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
+
+/* Returns an FD for the frame buffer device. */
+static int
+fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
+                        struct fbdev_screeninfo *screen_info)
+{
+       int fd = -1;
+
+       weston_log("Opening fbdev frame buffer.\n");
+
+       /* Open the frame buffer device. */
+       fd = open(fb_dev, O_RDWR | O_CLOEXEC);
+       if (fd < 0) {
+               weston_log("Failed to open frame buffer device ‘%s’: %s\n",
+                          fb_dev, strerror(errno));
+               return -1;
+       }
+
+       /* Grab the screen info. */
+       if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
+               weston_log("Failed to get frame buffer info: %s\n",
+                          strerror(errno));
+
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+/* Closes the FD on success or failure. */
+static int
+fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
+{
+       int retval = -1;
+
+       weston_log("Mapping fbdev frame buffer.\n");
+
+       /* Map the frame buffer. Write-only mode, since we don't want to read
+        * anything back (because it's slow). */
+       output->fb = mmap(NULL, output->fb_info.buffer_length,
+                         PROT_WRITE, MAP_SHARED, fd, 0);
+       if (output->fb == MAP_FAILED) {
+               weston_log("Failed to mmap frame buffer: %s\n",
+                          strerror(errno));
+               goto out_close;
+       }
+
+       /* Create a pixman image to wrap the memory mapped frame buffer. */
+       output->hw_surface =
+               pixman_image_create_bits(output->fb_info.pixel_format,
+                                        output->fb_info.x_resolution,
+                                        output->fb_info.y_resolution,
+                                        output->fb,
+                                        output->fb_info.line_length);
+       if (output->hw_surface == NULL) {
+               weston_log("Failed to create surface for frame buffer.\n");
+               goto out_unmap;
+       }
+
+       /* Success! */
+       retval = 0;
+
+out_unmap:
+       if (retval != 0 && output->fb != NULL)
+               fbdev_frame_buffer_destroy(output);
+
+out_close:
+       if (fd >= 0)
+               close(fd);
+
+       return retval;
+}
+
+static void
+fbdev_frame_buffer_destroy(struct fbdev_output *output)
+{
+       weston_log("Destroying fbdev frame buffer.\n");
+
+       if (munmap(output->fb, output->fb_info.buffer_length) < 0)
+               weston_log("Failed to munmap frame buffer: %s\n",
+                          strerror(errno));
+
+       output->fb = NULL;
+}
+
+static void fbdev_output_destroy(struct weston_output *base);
+static void fbdev_output_disable(struct weston_output *base);
+
+static int
+fbdev_output_create(struct fbdev_backend *backend,
+                    const char *device)
+{
+       struct fbdev_output *output;
+       int fb_fd;
+       struct wl_event_loop *loop;
+
+       weston_log("Creating fbdev output.\n");
+
+       output = zalloc(sizeof *output);
+       if (output == NULL)
+               return -1;
+
+       output->backend = backend;
+       output->device = strdup(device);
+
+       /* Create the frame buffer. */
+       fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
+       if (fb_fd < 0) {
+               weston_log("Creating frame buffer failed.\n");
+               goto out_free;
+       }
+
+       if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
+               weston_log("Mapping frame buffer failed.\n");
+               goto out_free;
+       }
+
+       output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
+       output->base.repaint = fbdev_output_repaint;
+       output->base.destroy = fbdev_output_destroy;
+
+       /* only one static mode in list */
+       output->mode.flags =
+               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+       output->mode.width = output->fb_info.x_resolution;
+       output->mode.height = output->fb_info.y_resolution;
+       output->mode.refresh = output->fb_info.refresh_rate;
+       wl_list_init(&output->base.mode_list);
+       wl_list_insert(&output->base.mode_list, &output->mode.link);
+
+       output->base.current_mode = &output->mode;
+       output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
+       output->base.make = "unknown";
+       output->base.model = output->fb_info.id;
+       output->base.name = strdup("fbdev");
+
+       weston_output_init(&output->base, backend->compositor,
+                          0, 0, output->fb_info.width_mm,
+                          output->fb_info.height_mm,
+                          backend->output_transform,
+                          1);
+
+       if (pixman_renderer_output_create(&output->base) < 0)
+               goto out_hw_surface;
+
+       loop = wl_display_get_event_loop(backend->compositor->wl_display);
+       output->finish_frame_timer =
+               wl_event_loop_add_timer(loop, finish_frame_handler, output);
+
+       weston_compositor_add_output(backend->compositor, &output->base);
+
+       weston_log("fbdev output %d×%d px\n",
+                  output->mode.width, output->mode.height);
+       weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
+                           output->mode.refresh / 1000);
+
+       return 0;
+
+out_hw_surface:
+       pixman_image_unref(output->hw_surface);
+       output->hw_surface = NULL;
+       weston_output_destroy(&output->base);
+       fbdev_frame_buffer_destroy(output);
+out_free:
+       free(output->device);
+       free(output);
+
+       return -1;
+}
+
+static void
+fbdev_output_destroy(struct weston_output *base)
+{
+       struct fbdev_output *output = to_fbdev_output(base);
+
+       weston_log("Destroying fbdev output.\n");
+
+       /* Close the frame buffer. */
+       fbdev_output_disable(base);
+
+       if (base->renderer_state != NULL)
+               pixman_renderer_output_destroy(base);
+
+       /* Remove the output. */
+       weston_output_destroy(&output->base);
+
+       free(output->device);
+       free(output);
+}
+
+/* strcmp()-style return values. */
+static int
+compare_screen_info (const struct fbdev_screeninfo *a,
+                     const struct fbdev_screeninfo *b)
+{
+       if (a->x_resolution == b->x_resolution &&
+           a->y_resolution == b->y_resolution &&
+           a->width_mm == b->width_mm &&
+           a->height_mm == b->height_mm &&
+           a->bits_per_pixel == b->bits_per_pixel &&
+           a->pixel_format == b->pixel_format &&
+           a->refresh_rate == b->refresh_rate)
+               return 0;
+
+       return 1;
+}
+
+static int
+fbdev_output_reenable(struct fbdev_backend *backend,
+                      struct weston_output *base)
+{
+       struct fbdev_output *output = to_fbdev_output(base);
+       struct fbdev_screeninfo new_screen_info;
+       int fb_fd;
+       char *device;
+
+       weston_log("Re-enabling fbdev output.\n");
+
+       /* Create the frame buffer. */
+       fb_fd = fbdev_frame_buffer_open(output, output->device,
+                                       &new_screen_info);
+       if (fb_fd < 0) {
+               weston_log("Creating frame buffer failed.\n");
+               goto err;
+       }
+
+       /* Check whether the frame buffer details have changed since we were
+        * disabled. */
+       if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
+               /* Perform a mode-set to restore the old mode. */
+               if (fbdev_set_screen_info(output, fb_fd,
+                                         &output->fb_info) < 0) {
+                       weston_log("Failed to restore mode settings. "
+                                  "Attempting to re-open output anyway.\n");
+               }
+
+               close(fb_fd);
+
+               /* Remove and re-add the output so that resources depending on
+                * the frame buffer X/Y resolution (such as the shadow buffer)
+                * are re-initialised. */
+               device = strdup(output->device);
+               fbdev_output_destroy(&output->base);
+               fbdev_output_create(backend, device);
+               free(device);
+
+               return 0;
+       }
+
+       /* Map the device if it has the same details as before. */
+       if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
+               weston_log("Mapping frame buffer failed.\n");
+               goto err;
+       }
+
+       return 0;
+
+err:
+       return -1;
+}
+
+/* NOTE: This leaves output->fb_info populated, caching data so that if
+ * fbdev_output_reenable() is called again, it can determine whether a mode-set
+ * is needed. */
+static void
+fbdev_output_disable(struct weston_output *base)
+{
+       struct fbdev_output *output = to_fbdev_output(base);
+
+       weston_log("Disabling fbdev output.\n");
+
+       if (output->hw_surface != NULL) {
+               pixman_image_unref(output->hw_surface);
+               output->hw_surface = NULL;
+       }
+
+       fbdev_frame_buffer_destroy(output);
+}
+
+static void
+fbdev_backend_destroy(struct weston_compositor *base)
+{
+       struct fbdev_backend *backend = to_fbdev_backend(base);
+
+       udev_input_destroy(&backend->input);
+
+       /* Destroy the output. */
+       weston_compositor_shutdown(base);
+
+       /* Chain up. */
+       weston_launcher_destroy(base->launcher);
+
+       free(backend);
+}
+
+static void
+session_notify(struct wl_listener *listener, void *data)
+{
+       struct weston_compositor *compositor = data;
+       struct fbdev_backend *backend = to_fbdev_backend(compositor);
+       struct weston_output *output;
+
+       if (compositor->session_active) {
+               weston_log("entering VT\n");
+               compositor->state = backend->prev_state;
+
+               wl_list_for_each(output, &compositor->output_list, link) {
+                       fbdev_output_reenable(backend, output);
+               }
+
+               weston_compositor_damage_all(compositor);
+
+               udev_input_enable(&backend->input);
+       } else {
+               weston_log("leaving VT\n");
+               udev_input_disable(&backend->input);
+
+               wl_list_for_each(output, &compositor->output_list, link) {
+                       fbdev_output_disable(output);
+               }
+
+               backend->prev_state = compositor->state;
+               weston_compositor_offscreen(compositor);
+
+               /* If we have a repaint scheduled (from the idle handler), make
+                * sure we cancel that so we don't try to pageflip when we're
+                * vt switched away.  The OFFSCREEN state will prevent
+                * further attempts at repainting.  When we switch
+                * back, we schedule a repaint, which will process
+                * pending frame callbacks. */
+
+               wl_list_for_each(output,
+                                &compositor->output_list, link) {
+                       output->repaint_needed = 0;
+               }
+       }
+}
+
+static void
+fbdev_restore(struct weston_compositor *compositor)
+{
+       weston_launcher_restore(compositor->launcher);
+}
+
+static struct fbdev_backend *
+fbdev_backend_create(struct weston_compositor *compositor,
+                     struct weston_fbdev_backend_config *param)
+{
+       struct fbdev_backend *backend;
+       const char *seat_id = default_seat;
+
+       weston_log("initializing fbdev backend\n");
+
+       backend = zalloc(sizeof *backend);
+       if (backend == NULL)
+               return NULL;
+
+       backend->compositor = compositor;
+       if (weston_compositor_set_presentation_clock_software(
+                                                       compositor) < 0)
+               goto out_compositor;
+
+       backend->udev = udev_new();
+       if (backend->udev == NULL) {
+               weston_log("Failed to initialize udev context.\n");
+               goto out_compositor;
+       }
+
+       /* Set up the TTY. */
+       backend->session_listener.notify = session_notify;
+       wl_signal_add(&compositor->session_signal,
+                     &backend->session_listener);
+       compositor->launcher =
+               weston_launcher_connect(compositor, param->tty, "seat0", false);
+       if (!compositor->launcher) {
+               weston_log("fatal: fbdev backend should be run "
+                          "using weston-launch binary or as root\n");
+               goto out_udev;
+       }
+
+       backend->base.destroy = fbdev_backend_destroy;
+       backend->base.restore = fbdev_restore;
+
+       backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
+       backend->output_transform = param->output_transform;
+
+       weston_setup_vt_switch_bindings(compositor);
+
+       if (pixman_renderer_init(compositor) < 0)
+               goto out_launcher;
+
+       if (fbdev_output_create(backend, param->device) < 0)
+               goto out_launcher;
+
+       udev_input_init(&backend->input, compositor, backend->udev,
+                       seat_id, param->configure_device);
+
+       compositor->backend = &backend->base;
+       return backend;
+
+out_launcher:
+       weston_launcher_destroy(compositor->launcher);
+
+out_udev:
+       udev_unref(backend->udev);
+
+out_compositor:
+       weston_compositor_shutdown(compositor);
+       free(backend);
+
+       return NULL;
+}
+
+static void
+config_init_to_defaults(struct weston_fbdev_backend_config *config)
+{
+       /* TODO: Ideally, available frame buffers should be enumerated using
+        * udev, rather than passing a device node in as a parameter. */
+       config->tty = 0; /* default to current tty */
+       config->device = "/dev/fb0"; /* default frame buffer */
+       config->output_transform = WL_OUTPUT_TRANSFORM_NORMAL;
+}
+
+WL_EXPORT int
+backend_init(struct weston_compositor *compositor,
+            struct weston_backend_config *config_base)
+{
+       struct fbdev_backend *b;
+       struct weston_fbdev_backend_config config = {{ 0, }};
+
+       if (config_base == NULL ||
+           config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
+           config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
+               weston_log("fbdev backend config structure is invalid\n");
+               return -1;
+       }
+
+       config_init_to_defaults(&config);
+       memcpy(&config, config_base, config_base->struct_size);
+
+       b = fbdev_backend_create(compositor, &config);
+       if (b == NULL)
+               return -1;
+       return 0;
+}
diff --git a/libweston/compositor-fbdev.h b/libweston/compositor-fbdev.h
new file mode 100644 (file)
index 0000000..9b5bf8e
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2016 Benoit Gschwind
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_COMPOSITOR_FBDEV_H
+#define WESTON_COMPOSITOR_FBDEV_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include "compositor.h"
+
+#define WESTON_FBDEV_BACKEND_CONFIG_VERSION 1
+
+struct libinput_device;
+
+struct weston_fbdev_backend_config {
+       struct weston_backend_config base;
+
+       int tty;
+       char *device;
+
+       uint32_t output_transform;
+
+       /** Callback used to configure input devices.
+        *
+        * This function will be called by the backend when a new input device
+        * needs to be configured.
+        * If NULL the device will use the default configuration.
+        */
+       void (*configure_device)(struct weston_compositor *compositor,
+                                struct libinput_device *device);
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WESTON_COMPOSITOR_FBDEV_H */
diff --git a/libweston/compositor-headless.c b/libweston/compositor-headless.c
new file mode 100644 (file)
index 0000000..b78c321
--- /dev/null
@@ -0,0 +1,258 @@
+/*
+ * Copyright © 2010-2011 Benjamin Franzke
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <stdbool.h>
+
+#include "compositor.h"
+#include "compositor-headless.h"
+#include "shared/helpers.h"
+#include "pixman-renderer.h"
+#include "presentation-time-server-protocol.h"
+
+struct headless_backend {
+       struct weston_backend base;
+       struct weston_compositor *compositor;
+
+       struct weston_seat fake_seat;
+       bool use_pixman;
+};
+
+struct headless_output {
+       struct weston_output base;
+
+       struct weston_mode mode;
+       struct wl_event_source *finish_frame_timer;
+       uint32_t *image_buf;
+       pixman_image_t *image;
+};
+
+static void
+headless_output_start_repaint_loop(struct weston_output *output)
+{
+       struct timespec ts;
+
+       weston_compositor_read_presentation_clock(output->compositor, &ts);
+       weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
+}
+
+static int
+finish_frame_handler(void *data)
+{
+       struct headless_output *output = data;
+       struct timespec ts;
+
+       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
+       weston_output_finish_frame(&output->base, &ts, 0);
+
+       return 1;
+}
+
+static int
+headless_output_repaint(struct weston_output *output_base,
+                      pixman_region32_t *damage)
+{
+       struct headless_output *output = (struct headless_output *) output_base;
+       struct weston_compositor *ec = output->base.compositor;
+
+       ec->renderer->repaint_output(&output->base, damage);
+
+       pixman_region32_subtract(&ec->primary_plane.damage,
+                                &ec->primary_plane.damage, damage);
+
+       wl_event_source_timer_update(output->finish_frame_timer, 16);
+
+       return 0;
+}
+
+static void
+headless_output_destroy(struct weston_output *output_base)
+{
+       struct headless_output *output = (struct headless_output *) output_base;
+       struct headless_backend *b =
+                       (struct headless_backend *) output->base.compositor->backend;
+
+       wl_event_source_remove(output->finish_frame_timer);
+
+       if (b->use_pixman) {
+               pixman_renderer_output_destroy(&output->base);
+               pixman_image_unref(output->image);
+               free(output->image_buf);
+       }
+
+       weston_output_destroy(&output->base);
+
+       free(output);
+
+       return;
+}
+
+static int
+headless_backend_create_output(struct headless_backend *b,
+                              struct weston_headless_backend_config *config)
+{
+       struct weston_compositor *c = b->compositor;
+       struct headless_output *output;
+       struct wl_event_loop *loop;
+
+       output = zalloc(sizeof *output);
+       if (output == NULL)
+               return -1;
+
+       output->mode.flags =
+               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+       output->mode.width = config->width;
+       output->mode.height = config->height;
+       output->mode.refresh = 60000;
+       wl_list_init(&output->base.mode_list);
+       wl_list_insert(&output->base.mode_list, &output->mode.link);
+
+       output->base.current_mode = &output->mode;
+       weston_output_init(&output->base, c, 0, 0, config->width,
+                          config->height, config->transform, 1);
+
+       output->base.make = "weston";
+       output->base.model = "headless";
+
+       loop = wl_display_get_event_loop(c->wl_display);
+       output->finish_frame_timer =
+               wl_event_loop_add_timer(loop, finish_frame_handler, output);
+
+       output->base.start_repaint_loop = headless_output_start_repaint_loop;
+       output->base.repaint = headless_output_repaint;
+       output->base.destroy = headless_output_destroy;
+       output->base.assign_planes = NULL;
+       output->base.set_backlight = NULL;
+       output->base.set_dpms = NULL;
+       output->base.switch_mode = NULL;
+
+       if (b->use_pixman) {
+               output->image_buf = malloc(config->width * config->height * 4);
+               if (!output->image_buf)
+                       return -1;
+
+               output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+                                                        config->width,
+                                                        config->height,
+                                                        output->image_buf,
+                                                        config->width * 4);
+
+               if (pixman_renderer_output_create(&output->base) < 0)
+                       return -1;
+
+               pixman_renderer_output_set_buffer(&output->base,
+                                                 output->image);
+       }
+
+       weston_compositor_add_output(c, &output->base);
+
+       return 0;
+}
+
+static void
+headless_restore(struct weston_compositor *ec)
+{
+}
+
+static void
+headless_destroy(struct weston_compositor *ec)
+{
+       struct headless_backend *b = (struct headless_backend *) ec->backend;
+
+       weston_compositor_shutdown(ec);
+
+       free(b);
+}
+
+static struct headless_backend *
+headless_backend_create(struct weston_compositor *compositor,
+                       struct weston_headless_backend_config *config)
+{
+       struct headless_backend *b;
+
+       b = zalloc(sizeof *b);
+       if (b == NULL)
+               return NULL;
+
+       b->compositor = compositor;
+       if (weston_compositor_set_presentation_clock_software(compositor) < 0)
+               goto err_free;
+
+       b->base.destroy = headless_destroy;
+       b->base.restore = headless_restore;
+
+       b->use_pixman = config->use_pixman;
+       if (b->use_pixman) {
+               pixman_renderer_init(compositor);
+       }
+       if (headless_backend_create_output(b, config) < 0)
+               goto err_input;
+
+       if (!b->use_pixman && noop_renderer_init(compositor) < 0)
+               goto err_input;
+
+       compositor->backend = &b->base;
+       return b;
+
+err_input:
+       weston_compositor_shutdown(compositor);
+err_free:
+       free(b);
+       return NULL;
+}
+
+static void
+config_init_to_defaults(struct weston_headless_backend_config *config)
+{
+}
+
+WL_EXPORT int
+backend_init(struct weston_compositor *compositor,
+            struct weston_backend_config *config_base)
+{
+       struct headless_backend *b;
+       struct weston_headless_backend_config config = {{ 0, }};
+
+       if (config_base == NULL ||
+           config_base->struct_version != WESTON_HEADLESS_BACKEND_CONFIG_VERSION ||
+           config_base->struct_size > sizeof(struct weston_headless_backend_config)) {
+               weston_log("headless backend config structure is invalid\n");
+               return -1;
+       }
+
+       config_init_to_defaults(&config);
+       memcpy(&config, config_base, config_base->struct_size);
+
+       b = headless_backend_create(compositor, &config);
+       if (b == NULL)
+               return -1;
+
+       return 0;
+}
diff --git a/libweston/compositor-headless.h b/libweston/compositor-headless.h
new file mode 100644 (file)
index 0000000..79f39c8
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2016 Benoit Gschwind
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_COMPOSITOR_HEADLESS_H
+#define WESTON_COMPOSITOR_HEADLESS_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include "compositor.h"
+
+#define WESTON_HEADLESS_BACKEND_CONFIG_VERSION 1
+
+struct weston_headless_backend_config {
+       struct weston_backend_config base;
+
+       int width;
+       int height;
+
+       /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
+       int use_pixman;
+
+       uint32_t transform;
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WESTON_COMPOSITOR_HEADLESS_H */
diff --git a/libweston/compositor-rdp.c b/libweston/compositor-rdp.c
new file mode 100644 (file)
index 0000000..d74dd5e
--- /dev/null
@@ -0,0 +1,1331 @@
+/*
+ * Copyright © 2013 Hardening <rdp.effort@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <linux/input.h>
+
+#if HAVE_FREERDP_VERSION_H
+#include <freerdp/version.h>
+#else
+/* assume it's a early 1.1 version */
+#define FREERDP_VERSION_MAJOR 1
+#define FREERDP_VERSION_MINOR 1
+#define FREERDP_VERSION_REVISION 0
+#endif
+
+#define FREERDP_VERSION_NUMBER ((FREERDP_VERSION_MAJOR * 0x10000) + \
+               (FREERDP_VERSION_MINOR * 0x100) + FREERDP_VERSION_REVISION)
+
+
+#if FREERDP_VERSION_NUMBER >= 0x10201
+#define HAVE_SKIP_COMPRESSION
+#endif
+
+#if FREERDP_VERSION_NUMBER < 0x10202
+#      define FREERDP_CB_RET_TYPE void
+#      define FREERDP_CB_RETURN(V) return
+#      define NSC_RESET(C, W, H)
+#      define RFX_RESET(C, W, H) do { rfx_context_reset(C); C->width = W; C->height = H; } while(0)
+#else
+#if FREERDP_VERSION_MAJOR >= 2
+#      define NSC_RESET(C, W, H) nsc_context_reset(C, W, H)
+#      define RFX_RESET(C, W, H) rfx_context_reset(C, W, H)
+#else
+#      define NSC_RESET(C, W, H) do { nsc_context_reset(C); C->width = W; C->height = H; } while(0)
+#      define RFX_RESET(C, W, H) do { rfx_context_reset(C); C->width = W; C->height = H; } while(0)
+#endif
+#define FREERDP_CB_RET_TYPE BOOL
+#define FREERDP_CB_RETURN(V) return TRUE
+#endif
+
+#include <freerdp/freerdp.h>
+#include <freerdp/listener.h>
+#include <freerdp/update.h>
+#include <freerdp/input.h>
+#include <freerdp/codec/color.h>
+#include <freerdp/codec/rfx.h>
+#include <freerdp/codec/nsc.h>
+#include <freerdp/locale/keyboard.h>
+#include <winpr/input.h>
+
+#include "shared/helpers.h"
+#include "compositor.h"
+#include "compositor-rdp.h"
+#include "pixman-renderer.h"
+
+#define MAX_FREERDP_FDS 32
+#define DEFAULT_AXIS_STEP_DISTANCE 10
+#define RDP_MODE_FREQ 60 * 1000
+
+
+struct rdp_output;
+
+struct rdp_backend {
+       struct weston_backend base;
+       struct weston_compositor *compositor;
+
+       freerdp_listener *listener;
+       struct wl_event_source *listener_events[MAX_FREERDP_FDS];
+       struct rdp_output *output;
+
+       char *server_cert;
+       char *server_key;
+       char *rdp_key;
+       int tls_enabled;
+       int no_clients_resize;
+};
+
+enum peer_item_flags {
+       RDP_PEER_ACTIVATED      = (1 << 0),
+       RDP_PEER_OUTPUT_ENABLED = (1 << 1),
+};
+
+struct rdp_peers_item {
+       int flags;
+       freerdp_peer *peer;
+       struct weston_seat *seat;
+
+       struct wl_list link;
+};
+
+struct rdp_output {
+       struct weston_output base;
+       struct wl_event_source *finish_frame_timer;
+       pixman_image_t *shadow_surface;
+
+       struct wl_list peers;
+};
+
+struct rdp_peer_context {
+       rdpContext _p;
+
+       struct rdp_backend *rdpBackend;
+       struct wl_event_source *events[MAX_FREERDP_FDS];
+       RFX_CONTEXT *rfx_context;
+       wStream *encode_stream;
+       RFX_RECT *rfx_rects;
+       NSC_CONTEXT *nsc_context;
+
+       struct rdp_peers_item item;
+};
+typedef struct rdp_peer_context RdpPeerContext;
+
+static void
+rdp_peer_refresh_rfx(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
+{
+       int width, height, nrects, i;
+       pixman_box32_t *region, *rects;
+       uint32_t *ptr;
+       RFX_RECT *rfxRect;
+       rdpUpdate *update = peer->update;
+       SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
+       RdpPeerContext *context = (RdpPeerContext *)peer->context;
+
+       Stream_Clear(context->encode_stream);
+       Stream_SetPosition(context->encode_stream, 0);
+
+       width = (damage->extents.x2 - damage->extents.x1);
+       height = (damage->extents.y2 - damage->extents.y1);
+
+#ifdef HAVE_SKIP_COMPRESSION
+       cmd->skipCompression = TRUE;
+#else
+       memset(cmd, 0, sizeof(*cmd));
+#endif
+       cmd->destLeft = damage->extents.x1;
+       cmd->destTop = damage->extents.y1;
+       cmd->destRight = damage->extents.x2;
+       cmd->destBottom = damage->extents.y2;
+       cmd->bpp = 32;
+       cmd->codecID = peer->settings->RemoteFxCodecId;
+       cmd->width = width;
+       cmd->height = height;
+
+       ptr = pixman_image_get_data(image) + damage->extents.x1 +
+                               damage->extents.y1 * (pixman_image_get_stride(image) / sizeof(uint32_t));
+
+       rects = pixman_region32_rectangles(damage, &nrects);
+       context->rfx_rects = realloc(context->rfx_rects, nrects * sizeof *rfxRect);
+
+       for (i = 0; i < nrects; i++) {
+               region = &rects[i];
+               rfxRect = &context->rfx_rects[i];
+
+               rfxRect->x = (region->x1 - damage->extents.x1);
+               rfxRect->y = (region->y1 - damage->extents.y1);
+               rfxRect->width = (region->x2 - region->x1);
+               rfxRect->height = (region->y2 - region->y1);
+       }
+
+       rfx_compose_message(context->rfx_context, context->encode_stream, context->rfx_rects, nrects,
+                       (BYTE *)ptr, width, height,
+                       pixman_image_get_stride(image)
+       );
+
+       cmd->bitmapDataLength = Stream_GetPosition(context->encode_stream);
+       cmd->bitmapData = Stream_Buffer(context->encode_stream);
+
+       update->SurfaceBits(update->context, cmd);
+}
+
+
+static void
+rdp_peer_refresh_nsc(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
+{
+       int width, height;
+       uint32_t *ptr;
+       rdpUpdate *update = peer->update;
+       SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
+       RdpPeerContext *context = (RdpPeerContext *)peer->context;
+
+       Stream_Clear(context->encode_stream);
+       Stream_SetPosition(context->encode_stream, 0);
+
+       width = (damage->extents.x2 - damage->extents.x1);
+       height = (damage->extents.y2 - damage->extents.y1);
+
+#ifdef HAVE_SKIP_COMPRESSION
+       cmd->skipCompression = TRUE;
+#else
+       memset(cmd, 0, sizeof(*cmd));
+#endif
+       cmd->destLeft = damage->extents.x1;
+       cmd->destTop = damage->extents.y1;
+       cmd->destRight = damage->extents.x2;
+       cmd->destBottom = damage->extents.y2;
+       cmd->bpp = 32;
+       cmd->codecID = peer->settings->NSCodecId;
+       cmd->width = width;
+       cmd->height = height;
+
+       ptr = pixman_image_get_data(image) + damage->extents.x1 +
+                               damage->extents.y1 * (pixman_image_get_stride(image) / sizeof(uint32_t));
+
+       nsc_compose_message(context->nsc_context, context->encode_stream, (BYTE *)ptr,
+                       cmd->width,     cmd->height,
+                       pixman_image_get_stride(image));
+       cmd->bitmapDataLength = Stream_GetPosition(context->encode_stream);
+       cmd->bitmapData = Stream_Buffer(context->encode_stream);
+       update->SurfaceBits(update->context, cmd);
+}
+
+static void
+pixman_image_flipped_subrect(const pixman_box32_t *rect, pixman_image_t *img, BYTE *dest)
+{
+       int stride = pixman_image_get_stride(img);
+       int h;
+       int toCopy = (rect->x2 - rect->x1) * 4;
+       int height = (rect->y2 - rect->y1);
+       const BYTE *src = (const BYTE *)pixman_image_get_data(img);
+       src += ((rect->y2-1) * stride) + (rect->x1 * 4);
+
+       for (h = 0; h < height; h++, src -= stride, dest += toCopy)
+                  memcpy(dest, src, toCopy);
+}
+
+static void
+rdp_peer_refresh_raw(pixman_region32_t *region, pixman_image_t *image, freerdp_peer *peer)
+{
+       rdpUpdate *update = peer->update;
+       SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
+       SURFACE_FRAME_MARKER *marker = &update->surface_frame_marker;
+       pixman_box32_t *rect, subrect;
+       int nrects, i;
+       int heightIncrement, remainingHeight, top;
+
+       rect = pixman_region32_rectangles(region, &nrects);
+       if (!nrects)
+               return;
+
+       marker->frameId++;
+       marker->frameAction = SURFACECMD_FRAMEACTION_BEGIN;
+       update->SurfaceFrameMarker(peer->context, marker);
+
+       memset(cmd, 0, sizeof(*cmd));
+       cmd->bpp = 32;
+       cmd->codecID = 0;
+
+       for (i = 0; i < nrects; i++, rect++) {
+               /*weston_log("rect(%d,%d, %d,%d)\n", rect->x1, rect->y1, rect->x2, rect->y2);*/
+               cmd->destLeft = rect->x1;
+               cmd->destRight = rect->x2;
+               cmd->width = rect->x2 - rect->x1;
+
+               heightIncrement = peer->settings->MultifragMaxRequestSize / (16 + cmd->width * 4);
+               remainingHeight = rect->y2 - rect->y1;
+               top = rect->y1;
+
+               subrect.x1 = rect->x1;
+               subrect.x2 = rect->x2;
+
+               while (remainingHeight) {
+                          cmd->height = (remainingHeight > heightIncrement) ? heightIncrement : remainingHeight;
+                          cmd->destTop = top;
+                          cmd->destBottom = top + cmd->height;
+                          cmd->bitmapDataLength = cmd->width * cmd->height * 4;
+                          cmd->bitmapData = (BYTE *)realloc(cmd->bitmapData, cmd->bitmapDataLength);
+
+                          subrect.y1 = top;
+                          subrect.y2 = top + cmd->height;
+                          pixman_image_flipped_subrect(&subrect, image, cmd->bitmapData);
+
+                          /*weston_log("*  sending (%d,%d, %d,%d)\n", subrect.x1, subrect.y1, subrect.x2, subrect.y2); */
+                          update->SurfaceBits(peer->context, cmd);
+
+                          remainingHeight -= cmd->height;
+                          top += cmd->height;
+               }
+       }
+
+       marker->frameAction = SURFACECMD_FRAMEACTION_END;
+       update->SurfaceFrameMarker(peer->context, marker);
+}
+
+static void
+rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer)
+{
+       RdpPeerContext *context = (RdpPeerContext *)peer->context;
+       struct rdp_output *output = context->rdpBackend->output;
+       rdpSettings *settings = peer->settings;
+
+       if (settings->RemoteFxCodec)
+               rdp_peer_refresh_rfx(region, output->shadow_surface, peer);
+       else if (settings->NSCodec)
+               rdp_peer_refresh_nsc(region, output->shadow_surface, peer);
+       else
+               rdp_peer_refresh_raw(region, output->shadow_surface, peer);
+}
+
+static void
+rdp_output_start_repaint_loop(struct weston_output *output)
+{
+       struct timespec ts;
+
+       weston_compositor_read_presentation_clock(output->compositor, &ts);
+       weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
+}
+
+static int
+rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
+{
+       struct rdp_output *output = container_of(output_base, struct rdp_output, base);
+       struct weston_compositor *ec = output->base.compositor;
+       struct rdp_peers_item *outputPeer;
+
+       pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
+       ec->renderer->repaint_output(&output->base, damage);
+
+       if (pixman_region32_not_empty(damage)) {
+               wl_list_for_each(outputPeer, &output->peers, link) {
+                       if ((outputPeer->flags & RDP_PEER_ACTIVATED) &&
+                                       (outputPeer->flags & RDP_PEER_OUTPUT_ENABLED))
+                       {
+                               rdp_peer_refresh_region(damage, outputPeer->peer);
+                       }
+               }
+       }
+
+       pixman_region32_subtract(&ec->primary_plane.damage,
+                                &ec->primary_plane.damage, damage);
+
+       wl_event_source_timer_update(output->finish_frame_timer, 16);
+       return 0;
+}
+
+static void
+rdp_output_destroy(struct weston_output *output_base)
+{
+       struct rdp_output *output = (struct rdp_output *)output_base;
+
+       wl_event_source_remove(output->finish_frame_timer);
+       free(output);
+}
+
+static int
+finish_frame_handler(void *data)
+{
+       struct rdp_output *output = data;
+       struct timespec ts;
+
+       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
+       weston_output_finish_frame(&output->base, &ts, 0);
+
+       return 1;
+}
+
+static struct weston_mode *
+rdp_insert_new_mode(struct weston_output *output, int width, int height, int rate)
+{
+       struct weston_mode *ret;
+       ret = zalloc(sizeof *ret);
+       if (!ret)
+               return NULL;
+       ret->width = width;
+       ret->height = height;
+       ret->refresh = rate;
+       wl_list_insert(&output->mode_list, &ret->link);
+       return ret;
+}
+
+static struct weston_mode *
+ensure_matching_mode(struct weston_output *output, struct weston_mode *target)
+{
+       struct weston_mode *local;
+
+       wl_list_for_each(local, &output->mode_list, link) {
+               if ((local->width == target->width) && (local->height == target->height))
+                       return local;
+       }
+
+       return rdp_insert_new_mode(output, target->width, target->height, RDP_MODE_FREQ);
+}
+
+static int
+rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode)
+{
+       struct rdp_output *rdpOutput = container_of(output, struct rdp_output, base);
+       struct rdp_peers_item *rdpPeer;
+       rdpSettings *settings;
+       pixman_image_t *new_shadow_buffer;
+       struct weston_mode *local_mode;
+
+       local_mode = ensure_matching_mode(output, target_mode);
+       if (!local_mode) {
+               weston_log("mode %dx%d not available\n", target_mode->width, target_mode->height);
+               return -ENOENT;
+       }
+
+       if (local_mode == output->current_mode)
+               return 0;
+
+       output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
+
+       output->current_mode = local_mode;
+       output->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
+
+       pixman_renderer_output_destroy(output);
+       pixman_renderer_output_create(output);
+
+       new_shadow_buffer = pixman_image_create_bits(PIXMAN_x8r8g8b8, target_mode->width,
+                       target_mode->height, 0, target_mode->width * 4);
+       pixman_image_composite32(PIXMAN_OP_SRC, rdpOutput->shadow_surface, 0, new_shadow_buffer,
+                       0, 0, 0, 0, 0, 0, target_mode->width, target_mode->height);
+       pixman_image_unref(rdpOutput->shadow_surface);
+       rdpOutput->shadow_surface = new_shadow_buffer;
+
+       wl_list_for_each(rdpPeer, &rdpOutput->peers, link) {
+               settings = rdpPeer->peer->settings;
+               if (settings->DesktopWidth == (UINT32)target_mode->width &&
+                               settings->DesktopHeight == (UINT32)target_mode->height)
+                       continue;
+
+               if (!settings->DesktopResize) {
+                       /* too bad this peer does not support desktop resize */
+                       rdpPeer->peer->Close(rdpPeer->peer);
+               } else {
+                       settings->DesktopWidth = target_mode->width;
+                       settings->DesktopHeight = target_mode->height;
+                       rdpPeer->peer->update->DesktopResize(rdpPeer->peer->context);
+               }
+       }
+       return 0;
+}
+
+static int
+rdp_backend_create_output(struct rdp_backend *b, int width, int height)
+{
+       struct rdp_output *output;
+       struct wl_event_loop *loop;
+       struct weston_mode *currentMode;
+       struct weston_mode initMode;
+
+       output = zalloc(sizeof *output);
+       if (output == NULL)
+               return -1;
+
+       wl_list_init(&output->peers);
+       wl_list_init(&output->base.mode_list);
+
+       initMode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
+       initMode.width = width;
+       initMode.height = height;
+       initMode.refresh = RDP_MODE_FREQ;
+
+       currentMode = ensure_matching_mode(&output->base, &initMode);
+       if (!currentMode)
+               goto out_free_output;
+
+       output->base.current_mode = output->base.native_mode = currentMode;
+       weston_output_init(&output->base, b->compositor, 0, 0, width, height,
+                          WL_OUTPUT_TRANSFORM_NORMAL, 1);
+
+       output->base.make = "weston";
+       output->base.model = "rdp";
+       output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8,
+                       width, height,
+                   NULL,
+                   width * 4);
+       if (output->shadow_surface == NULL) {
+               weston_log("Failed to create surface for frame buffer.\n");
+               goto out_output;
+       }
+
+       if (pixman_renderer_output_create(&output->base) < 0)
+               goto out_shadow_surface;
+
+       loop = wl_display_get_event_loop(b->compositor->wl_display);
+       output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
+
+       output->base.start_repaint_loop = rdp_output_start_repaint_loop;
+       output->base.repaint = rdp_output_repaint;
+       output->base.destroy = rdp_output_destroy;
+       output->base.assign_planes = NULL;
+       output->base.set_backlight = NULL;
+       output->base.set_dpms = NULL;
+       output->base.switch_mode = rdp_switch_mode;
+       b->output = output;
+
+       weston_compositor_add_output(b->compositor, &output->base);
+       return 0;
+
+out_shadow_surface:
+       pixman_image_unref(output->shadow_surface);
+out_output:
+       weston_output_destroy(&output->base);
+out_free_output:
+       free(output);
+       return -1;
+}
+
+static void
+rdp_restore(struct weston_compositor *ec)
+{
+}
+
+static void
+rdp_destroy(struct weston_compositor *ec)
+{
+       struct rdp_backend *b = (struct rdp_backend *) ec->backend;
+       int i;
+
+       weston_compositor_shutdown(ec);
+       for (i = 0; i < MAX_FREERDP_FDS; i++)
+               if (b->listener_events[i])
+                       wl_event_source_remove(b->listener_events[i]);
+
+       freerdp_listener_free(b->listener);
+
+       free(b->server_cert);
+       free(b->server_key);
+       free(b->rdp_key);
+       free(b);
+}
+
+static
+int rdp_listener_activity(int fd, uint32_t mask, void *data)
+{
+       freerdp_listener* instance = (freerdp_listener *)data;
+
+       if (!(mask & WL_EVENT_READABLE))
+               return 0;
+       if (!instance->CheckFileDescriptor(instance)) {
+               weston_log("failed to check FreeRDP file descriptor\n");
+               return -1;
+       }
+       return 0;
+}
+
+static
+int rdp_implant_listener(struct rdp_backend *b, freerdp_listener* instance)
+{
+       int i, fd;
+       int rcount = 0;
+       void* rfds[MAX_FREERDP_FDS];
+       struct wl_event_loop *loop;
+
+       if (!instance->GetFileDescriptor(instance, rfds, &rcount)) {
+               weston_log("Failed to get FreeRDP file descriptor\n");
+               return -1;
+       }
+
+       loop = wl_display_get_event_loop(b->compositor->wl_display);
+       for (i = 0; i < rcount; i++) {
+               fd = (int)(long)(rfds[i]);
+               b->listener_events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
+                               rdp_listener_activity, instance);
+       }
+
+       for ( ; i < MAX_FREERDP_FDS; i++)
+               b->listener_events[i] = 0;
+       return 0;
+}
+
+
+static FREERDP_CB_RET_TYPE
+rdp_peer_context_new(freerdp_peer* client, RdpPeerContext* context)
+{
+       context->item.peer = client;
+       context->item.flags = RDP_PEER_OUTPUT_ENABLED;
+
+#if FREERDP_VERSION_MAJOR == 1 && FREERDP_VERSION_MINOR == 1
+       context->rfx_context = rfx_context_new();
+#else
+       context->rfx_context = rfx_context_new(TRUE);
+#endif
+       if (!context->rfx_context) {
+               FREERDP_CB_RETURN(FALSE);
+       }
+
+       context->rfx_context->mode = RLGR3;
+       context->rfx_context->width = client->settings->DesktopWidth;
+       context->rfx_context->height = client->settings->DesktopHeight;
+       rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8);
+
+       context->nsc_context = nsc_context_new();
+       if (!context->nsc_context)
+               goto out_error_nsc;
+
+       nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_B8G8R8A8);
+
+       context->encode_stream = Stream_New(NULL, 65536);
+       if (!context->encode_stream)
+               goto out_error_stream;
+
+       FREERDP_CB_RETURN(TRUE);
+
+out_error_nsc:
+       rfx_context_free(context->rfx_context);
+out_error_stream:
+       nsc_context_free(context->nsc_context);
+       FREERDP_CB_RETURN(FALSE);
+}
+
+static void
+rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
+{
+       int i;
+       if (!context)
+               return;
+
+       wl_list_remove(&context->item.link);
+       for (i = 0; i < MAX_FREERDP_FDS; i++) {
+               if (context->events[i])
+                       wl_event_source_remove(context->events[i]);
+       }
+
+       if (context->item.flags & RDP_PEER_ACTIVATED) {
+               weston_seat_release_keyboard(context->item.seat);
+               weston_seat_release_pointer(context->item.seat);
+               /* XXX we should weston_seat_release(context->item.seat); here
+                * but it would crash on reconnect */
+       }
+
+       Stream_Free(context->encode_stream, TRUE);
+       nsc_context_free(context->nsc_context);
+       rfx_context_free(context->rfx_context);
+       free(context->rfx_rects);
+}
+
+
+static int
+rdp_client_activity(int fd, uint32_t mask, void *data)
+{
+       freerdp_peer* client = (freerdp_peer *)data;
+
+       if (!client->CheckFileDescriptor(client)) {
+               weston_log("unable to checkDescriptor for %p\n", client);
+               goto out_clean;
+       }
+       return 0;
+
+out_clean:
+       freerdp_peer_context_free(client);
+       freerdp_peer_free(client);
+       return 0;
+}
+
+static BOOL
+xf_peer_capabilities(freerdp_peer* client)
+{
+       return TRUE;
+}
+
+struct rdp_to_xkb_keyboard_layout {
+       UINT32 rdpLayoutCode;
+       const char *xkbLayout;
+       const char *xkbVariant;
+};
+
+/* table reversed from
+       https://github.com/awakecoding/FreeRDP/blob/master/libfreerdp/locale/xkb_layout_ids.c#L811 */
+static
+struct rdp_to_xkb_keyboard_layout rdp_keyboards[] = {
+       {KBD_ARABIC_101, "ara", 0},
+       {KBD_BULGARIAN, 0, 0},
+       {KBD_CHINESE_TRADITIONAL_US, 0},
+       {KBD_CZECH, "cz", 0},
+       {KBD_CZECH_PROGRAMMERS, "cz", "bksl"},
+       {KBD_CZECH_QWERTY, "cz", "qwerty"},
+       {KBD_DANISH, "dk", 0},
+       {KBD_GERMAN, "de", 0},
+       {KBD_GERMAN_NEO, "de", "neo"},
+       {KBD_GERMAN_IBM, "de", "qwerty"},
+       {KBD_GREEK, "gr", 0},
+       {KBD_GREEK_220, "gr", "simple"},
+       {KBD_GREEK_319, "gr", "extended"},
+       {KBD_GREEK_POLYTONIC, "gr", "polytonic"},
+       {KBD_US, "us", 0},
+       {KBD_US_ENGLISH_TABLE_FOR_IBM_ARABIC_238_L, "ara", "buckwalter"},
+       {KBD_SPANISH, "es", 0},
+       {KBD_SPANISH_VARIATION, "es", "nodeadkeys"},
+       {KBD_FINNISH, "fi", 0},
+       {KBD_FRENCH, "fr", 0},
+       {KBD_HEBREW, "il", 0},
+       {KBD_HUNGARIAN, "hu", 0},
+       {KBD_HUNGARIAN_101_KEY, "hu", "standard"},
+       {KBD_ICELANDIC, "is", 0},
+       {KBD_ITALIAN, "it", 0},
+       {KBD_ITALIAN_142, "it", "nodeadkeys"},
+       {KBD_JAPANESE, "jp", 0},
+       {KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002, "jp", "kana"},
+       {KBD_KOREAN, "kr", 0},
+       {KBD_KOREAN_INPUT_SYSTEM_IME_2000, "kr", "kr104"},
+       {KBD_DUTCH, "nl", 0},
+       {KBD_NORWEGIAN, "no", 0},
+       {KBD_POLISH_PROGRAMMERS, "pl", 0},
+       {KBD_POLISH_214, "pl", "qwertz"},
+       {KBD_ROMANIAN, "ro", 0},
+       {KBD_RUSSIAN, "ru", 0},
+       {KBD_RUSSIAN_TYPEWRITER, "ru", "typewriter"},
+       {KBD_CROATIAN, "hr", 0},
+       {KBD_SLOVAK, "sk", 0},
+       {KBD_SLOVAK_QWERTY, "sk", "qwerty"},
+       {KBD_ALBANIAN, 0, 0},
+       {KBD_SWEDISH, "se", 0},
+       {KBD_THAI_KEDMANEE, "th", 0},
+       {KBD_THAI_KEDMANEE_NON_SHIFTLOCK, "th", "tis"},
+       {KBD_TURKISH_Q, "tr", 0},
+       {KBD_TURKISH_F, "tr", "f"},
+       {KBD_URDU, "in", "urd-phonetic3"},
+       {KBD_UKRAINIAN, "ua", 0},
+       {KBD_BELARUSIAN, "by", 0},
+       {KBD_SLOVENIAN, "si", 0},
+       {KBD_ESTONIAN, "ee", 0},
+       {KBD_LATVIAN, "lv", 0},
+       {KBD_LITHUANIAN_IBM, "lt", "ibm"},
+       {KBD_FARSI, "af", 0},
+       {KBD_VIETNAMESE, "vn", 0},
+       {KBD_ARMENIAN_EASTERN, "am", 0},
+       {KBD_AZERI_LATIN, 0, 0},
+       {KBD_FYRO_MACEDONIAN, "mk", 0},
+       {KBD_GEORGIAN, "ge", 0},
+       {KBD_FAEROESE, 0, 0},
+       {KBD_DEVANAGARI_INSCRIPT, 0, 0},
+       {KBD_MALTESE_47_KEY, 0, 0},
+       {KBD_NORWEGIAN_WITH_SAMI, "no", "smi"},
+       {KBD_KAZAKH, "kz", 0},
+       {KBD_KYRGYZ_CYRILLIC, "kg", "phonetic"},
+       {KBD_TATAR, "ru", "tt"},
+       {KBD_BENGALI, "bd", 0},
+       {KBD_BENGALI_INSCRIPT, "bd", "probhat"},
+       {KBD_PUNJABI, 0, 0},
+       {KBD_GUJARATI, "in", "guj"},
+       {KBD_TAMIL, "in", "tam"},
+       {KBD_TELUGU, "in", "tel"},
+       {KBD_KANNADA, "in", "kan"},
+       {KBD_MALAYALAM, "in", "mal"},
+       {KBD_HINDI_TRADITIONAL, "in", 0},
+       {KBD_MARATHI, 0, 0},
+       {KBD_MONGOLIAN_CYRILLIC, "mn", 0},
+       {KBD_UNITED_KINGDOM_EXTENDED, "gb", "intl"},
+       {KBD_SYRIAC, "syc", 0},
+       {KBD_SYRIAC_PHONETIC, "syc", "syc_phonetic"},
+       {KBD_NEPALI, "np", 0},
+       {KBD_PASHTO, "af", "ps"},
+       {KBD_DIVEHI_PHONETIC, 0, 0},
+       {KBD_LUXEMBOURGISH, 0, 0},
+       {KBD_MAORI, "mao", 0},
+       {KBD_CHINESE_SIMPLIFIED_US, 0, 0},
+       {KBD_SWISS_GERMAN, "ch", "de_nodeadkeys"},
+       {KBD_UNITED_KINGDOM, "gb", 0},
+       {KBD_LATIN_AMERICAN, "latam", 0},
+       {KBD_BELGIAN_FRENCH, "be", 0},
+       {KBD_BELGIAN_PERIOD, "be", "oss_sundeadkeys"},
+       {KBD_PORTUGUESE, "pt", 0},
+       {KBD_SERBIAN_LATIN, "rs", 0},
+       {KBD_AZERI_CYRILLIC, "az", "cyrillic"},
+       {KBD_SWEDISH_WITH_SAMI, "se", "smi"},
+       {KBD_UZBEK_CYRILLIC, "af", "uz"},
+       {KBD_INUKTITUT_LATIN, "ca", "ike"},
+       {KBD_CANADIAN_FRENCH_LEGACY, "ca", "fr-legacy"},
+       {KBD_SERBIAN_CYRILLIC, "rs", 0},
+       {KBD_CANADIAN_FRENCH, "ca", "fr-legacy"},
+       {KBD_SWISS_FRENCH, "ch", "fr"},
+       {KBD_BOSNIAN, "ba", 0},
+       {KBD_IRISH, 0, 0},
+       {KBD_BOSNIAN_CYRILLIC, "ba", "us"},
+       {KBD_UNITED_STATES_DVORAK, "us", "dvorak"},
+       {KBD_PORTUGUESE_BRAZILIAN_ABNT2, "br", "nativo"},
+       {KBD_CANADIAN_MULTILINGUAL_STANDARD, "ca", "multix"},
+       {KBD_GAELIC, "ie", "CloGaelach"},
+
+       {0x00000000, 0, 0},
+};
+
+/* taken from 2.2.7.1.6 Input Capability Set (TS_INPUT_CAPABILITYSET) */
+static char *rdp_keyboard_types[] = {
+       "",     /* 0: unused */
+       "", /* 1: IBM PC/XT or compatible (83-key) keyboard */
+       "", /* 2: Olivetti "ICO" (102-key) keyboard */
+       "", /* 3: IBM PC/AT (84-key) or similar keyboard */
+       "pc102",/* 4: IBM enhanced (101- or 102-key) keyboard */
+       "", /* 5: Nokia 1050 and similar keyboards */
+       "",     /* 6: Nokia 9140 and similar keyboards */
+       ""      /* 7: Japanese keyboard */
+};
+
+static BOOL
+xf_peer_activate(freerdp_peer* client)
+{
+       RdpPeerContext *peerCtx;
+       struct rdp_backend *b;
+       struct rdp_output *output;
+       rdpSettings *settings;
+       rdpPointerUpdate *pointer;
+       struct rdp_peers_item *peersItem;
+       struct xkb_context *xkbContext;
+       struct xkb_rule_names xkbRuleNames;
+       struct xkb_keymap *keymap;
+       struct weston_output *weston_output;
+       int i;
+       pixman_box32_t box;
+       pixman_region32_t damage;
+       char seat_name[50];
+
+
+       peerCtx = (RdpPeerContext *)client->context;
+       b = peerCtx->rdpBackend;
+       peersItem = &peerCtx->item;
+       output = b->output;
+       settings = client->settings;
+
+       if (!settings->SurfaceCommandsEnabled) {
+               weston_log("client doesn't support required SurfaceCommands\n");
+               return FALSE;
+       }
+
+       if (output->base.width != (int)settings->DesktopWidth ||
+                       output->base.height != (int)settings->DesktopHeight)
+       {
+               if (b->no_clients_resize) {
+                       /* RDP peers don't dictate their resolution to weston */
+                       if (!settings->DesktopResize) {
+                               /* peer does not support desktop resize */
+                               weston_log("%s: client doesn't support resizing, closing connection\n", __FUNCTION__);
+                               return FALSE;
+                       } else {
+                               settings->DesktopWidth = output->base.width;
+                               settings->DesktopHeight = output->base.height;
+                               client->update->DesktopResize(client->context);
+                       }
+               } else {
+                       /* ask weston to adjust size */
+                       struct weston_mode new_mode;
+                       struct weston_mode *target_mode;
+                       new_mode.width = (int)settings->DesktopWidth;
+                       new_mode.height = (int)settings->DesktopHeight;
+                       target_mode = ensure_matching_mode(&output->base, &new_mode);
+                       if (!target_mode) {
+                               weston_log("client mode not found\n");
+                               return FALSE;
+                       }
+                       weston_output_mode_set_native(&output->base, target_mode, 1);
+                       output->base.width = new_mode.width;
+                       output->base.height = new_mode.height;
+               }
+       }
+
+       weston_output = &output->base;
+       RFX_RESET(peerCtx->rfx_context, weston_output->width, weston_output->height);
+       NSC_RESET(peerCtx->nsc_context, weston_output->width, weston_output->height);
+
+       if (peersItem->flags & RDP_PEER_ACTIVATED)
+               return TRUE;
+
+       /* when here it's the first reactivation, we need to setup a little more */
+       weston_log("kbd_layout:0x%x kbd_type:0x%x kbd_subType:0x%x kbd_functionKeys:0x%x\n",
+                       settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType,
+                       settings->KeyboardFunctionKey);
+
+       memset(&xkbRuleNames, 0, sizeof(xkbRuleNames));
+       if (settings->KeyboardType <= 7)
+               xkbRuleNames.model = rdp_keyboard_types[settings->KeyboardType];
+       for (i = 0; rdp_keyboards[i].rdpLayoutCode; i++) {
+               if (rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) {
+                       xkbRuleNames.layout = rdp_keyboards[i].xkbLayout;
+                       xkbRuleNames.variant = rdp_keyboards[i].xkbVariant;
+                       weston_log("%s: matching layout=%s variant=%s\n", __FUNCTION__,
+                                       xkbRuleNames.layout, xkbRuleNames.variant);
+                       break;
+               }
+       }
+
+       keymap = NULL;
+       if (xkbRuleNames.layout) {
+               xkbContext = xkb_context_new(0);
+               if (!xkbContext) {
+                       weston_log("unable to create a xkb_context\n");
+                       return FALSE;
+               }
+
+               keymap = xkb_keymap_new_from_names(xkbContext, &xkbRuleNames, 0);
+       }
+
+       if (settings->ClientHostname)
+               snprintf(seat_name, sizeof(seat_name), "RDP %s", settings->ClientHostname);
+       else
+               snprintf(seat_name, sizeof(seat_name), "RDP peer @%s", settings->ClientAddress);
+
+       peersItem->seat = zalloc(sizeof(*peersItem->seat));
+       if (!peersItem->seat) {
+               xkb_keymap_unref(keymap);
+               weston_log("unable to create a weston_seat\n");
+               return FALSE;
+       }
+
+       weston_seat_init(peersItem->seat, b->compositor, seat_name);
+       weston_seat_init_keyboard(peersItem->seat, keymap);
+       weston_seat_init_pointer(peersItem->seat);
+
+       peersItem->flags |= RDP_PEER_ACTIVATED;
+
+       /* disable pointer on the client side */
+       pointer = client->update->pointer;
+       pointer->pointer_system.type = SYSPTR_NULL;
+       pointer->PointerSystem(client->context, &pointer->pointer_system);
+
+       /* sends a full refresh */
+       box.x1 = 0;
+       box.y1 = 0;
+       box.x2 = output->base.width;
+       box.y2 = output->base.height;
+       pixman_region32_init_with_extents(&damage, &box);
+
+       rdp_peer_refresh_region(&damage, client);
+
+       pixman_region32_fini(&damage);
+
+       return TRUE;
+}
+
+static BOOL xf_peer_post_connect(freerdp_peer *client)
+{
+       return TRUE;
+}
+
+static FREERDP_CB_RET_TYPE
+xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
+{
+       RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
+       struct rdp_output *output;
+       uint32_t button = 0;
+       bool need_frame = false;
+
+       if (flags & PTR_FLAGS_MOVE) {
+               output = peerContext->rdpBackend->output;
+               if (x < output->base.width && y < output->base.height) {
+                       notify_motion_absolute(peerContext->item.seat, weston_compositor_get_time(),
+                                       x, y);
+                       need_frame = true;
+               }
+       }
+
+       if (flags & PTR_FLAGS_BUTTON1)
+               button = BTN_LEFT;
+       else if (flags & PTR_FLAGS_BUTTON2)
+               button = BTN_RIGHT;
+       else if (flags & PTR_FLAGS_BUTTON3)
+               button = BTN_MIDDLE;
+
+       if (button) {
+               notify_button(peerContext->item.seat, weston_compositor_get_time(), button,
+                       (flags & PTR_FLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED
+               );
+               need_frame = true;
+       }
+
+       if (flags & PTR_FLAGS_WHEEL) {
+               struct weston_pointer_axis_event weston_event;
+               double value;
+
+               /* DEFAULT_AXIS_STEP_DISTANCE is stolen from compositor-x11.c
+                * The RDP specs says the lower bits of flags contains the "the number of rotation
+                * units the mouse wheel was rotated".
+                *
+                * https://blogs.msdn.microsoft.com/oldnewthing/20130123-00/?p=5473 explains the 120 value
+                */
+               value = (flags & 0xff) / 120.0;
+               if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
+                       value = -value;
+
+               weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
+               weston_event.value = DEFAULT_AXIS_STEP_DISTANCE * value;
+               weston_event.discrete = (int)value;
+               weston_event.has_discrete = true;
+
+               notify_axis(peerContext->item.seat, weston_compositor_get_time(),
+                           &weston_event);
+               need_frame = true;
+       }
+
+       if (need_frame)
+               notify_pointer_frame(peerContext->item.seat);
+
+       FREERDP_CB_RETURN(TRUE);
+}
+
+static FREERDP_CB_RET_TYPE
+xf_extendedMouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
+{
+       RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
+       struct rdp_output *output;
+
+       output = peerContext->rdpBackend->output;
+       if (x < output->base.width && y < output->base.height) {
+               notify_motion_absolute(peerContext->item.seat, weston_compositor_get_time(),
+                               x, y);
+       }
+
+       FREERDP_CB_RETURN(TRUE);
+}
+
+
+static FREERDP_CB_RET_TYPE
+xf_input_synchronize_event(rdpInput *input, UINT32 flags)
+{
+       freerdp_peer *client = input->context->peer;
+       RdpPeerContext *peerCtx = (RdpPeerContext *)input->context;
+       struct rdp_output *output = peerCtx->rdpBackend->output;
+       pixman_box32_t box;
+       pixman_region32_t damage;
+
+       /* sends a full refresh */
+       box.x1 = 0;
+       box.y1 = 0;
+       box.x2 = output->base.width;
+       box.y2 = output->base.height;
+       pixman_region32_init_with_extents(&damage, &box);
+
+       rdp_peer_refresh_region(&damage, client);
+
+       pixman_region32_fini(&damage);
+       FREERDP_CB_RETURN(TRUE);
+}
+
+
+static FREERDP_CB_RET_TYPE
+xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
+{
+       uint32_t scan_code, vk_code, full_code;
+       enum wl_keyboard_key_state keyState;
+       RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
+       int notify = 0;
+
+       if (!(peerContext->item.flags & RDP_PEER_ACTIVATED))
+               FREERDP_CB_RETURN(TRUE);
+
+       if (flags & KBD_FLAGS_DOWN) {
+               keyState = WL_KEYBOARD_KEY_STATE_PRESSED;
+               notify = 1;
+       } else if (flags & KBD_FLAGS_RELEASE) {
+               keyState = WL_KEYBOARD_KEY_STATE_RELEASED;
+               notify = 1;
+       }
+
+       if (notify) {
+               full_code = code;
+               if (flags & KBD_FLAGS_EXTENDED)
+                       full_code |= KBD_FLAGS_EXTENDED;
+
+               vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, 4);
+               if (flags & KBD_FLAGS_EXTENDED)
+                       vk_code |= KBDEXT;
+
+               scan_code = GetKeycodeFromVirtualKeyCode(vk_code, KEYCODE_TYPE_EVDEV);
+
+               /*weston_log("code=%x ext=%d vk_code=%x scan_code=%x\n", code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0,
+                               vk_code, scan_code);*/
+               notify_key(peerContext->item.seat, weston_compositor_get_time(),
+                                       scan_code - 8, keyState, STATE_UPDATE_AUTOMATIC);
+       }
+
+       FREERDP_CB_RETURN(TRUE);
+}
+
+static FREERDP_CB_RET_TYPE
+xf_input_unicode_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
+{
+       weston_log("Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code);
+       FREERDP_CB_RETURN(TRUE);
+}
+
+
+static FREERDP_CB_RET_TYPE
+xf_suppress_output(rdpContext *context, BYTE allow, RECTANGLE_16 *area)
+{
+       RdpPeerContext *peerContext = (RdpPeerContext *)context;
+
+       if (allow)
+               peerContext->item.flags |= RDP_PEER_OUTPUT_ENABLED;
+       else
+               peerContext->item.flags &= (~RDP_PEER_OUTPUT_ENABLED);
+
+       FREERDP_CB_RETURN(TRUE);
+}
+
+static int
+rdp_peer_init(freerdp_peer *client, struct rdp_backend *b)
+{
+       int rcount = 0;
+       void *rfds[MAX_FREERDP_FDS];
+       int i, fd;
+       struct wl_event_loop *loop;
+       rdpSettings     *settings;
+       rdpInput *input;
+       RdpPeerContext *peerCtx;
+
+       client->ContextSize = sizeof(RdpPeerContext);
+       client->ContextNew = (psPeerContextNew)rdp_peer_context_new;
+       client->ContextFree = (psPeerContextFree)rdp_peer_context_free;
+       freerdp_peer_context_new(client);
+
+       peerCtx = (RdpPeerContext *) client->context;
+       peerCtx->rdpBackend = b;
+
+       settings = client->settings;
+       /* configure security settings */
+       if (b->rdp_key)
+               settings->RdpKeyFile = strdup(b->rdp_key);
+       if (b->tls_enabled) {
+               settings->CertificateFile = strdup(b->server_cert);
+               settings->PrivateKeyFile = strdup(b->server_key);
+       } else {
+               settings->TlsSecurity = FALSE;
+       }
+       settings->NlaSecurity = FALSE;
+
+       if (!client->Initialize(client)) {
+               weston_log("peer initialization failed\n");
+               goto error_initialize;
+       }
+
+       settings->OsMajorType = OSMAJORTYPE_UNIX;
+       settings->OsMinorType = OSMINORTYPE_PSEUDO_XSERVER;
+       settings->ColorDepth = 32;
+       settings->RefreshRect = TRUE;
+       settings->RemoteFxCodec = TRUE;
+       settings->NSCodec = TRUE;
+       settings->FrameMarkerCommandEnabled = TRUE;
+       settings->SurfaceFrameMarkerEnabled = TRUE;
+
+       client->Capabilities = xf_peer_capabilities;
+       client->PostConnect = xf_peer_post_connect;
+       client->Activate = xf_peer_activate;
+
+       client->update->SuppressOutput = xf_suppress_output;
+
+       input = client->input;
+       input->SynchronizeEvent = xf_input_synchronize_event;
+       input->MouseEvent = xf_mouseEvent;
+       input->ExtendedMouseEvent = xf_extendedMouseEvent;
+       input->KeyboardEvent = xf_input_keyboard_event;
+       input->UnicodeKeyboardEvent = xf_input_unicode_keyboard_event;
+
+       if (!client->GetFileDescriptor(client, rfds, &rcount)) {
+               weston_log("unable to retrieve client fds\n");
+               goto error_initialize;
+       }
+
+       loop = wl_display_get_event_loop(b->compositor->wl_display);
+       for (i = 0; i < rcount; i++) {
+               fd = (int)(long)(rfds[i]);
+
+               peerCtx->events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
+                               rdp_client_activity, client);
+       }
+       for ( ; i < MAX_FREERDP_FDS; i++)
+               peerCtx->events[i] = 0;
+
+       wl_list_insert(&b->output->peers, &peerCtx->item.link);
+       return 0;
+
+error_initialize:
+       client->Close(client);
+       return -1;
+}
+
+
+static FREERDP_CB_RET_TYPE
+rdp_incoming_peer(freerdp_listener *instance, freerdp_peer *client)
+{
+       struct rdp_backend *b = (struct rdp_backend *)instance->param4;
+       if (rdp_peer_init(client, b) < 0) {
+               weston_log("error when treating incoming peer\n");
+               FREERDP_CB_RETURN(FALSE);
+       }
+
+       FREERDP_CB_RETURN(TRUE);
+}
+
+static struct rdp_backend *
+rdp_backend_create(struct weston_compositor *compositor,
+                  struct weston_rdp_backend_config *config)
+{
+       struct rdp_backend *b;
+       char *fd_str;
+       int fd;
+
+       b = zalloc(sizeof *b);
+       if (b == NULL)
+               return NULL;
+
+       b->compositor = compositor;
+       b->base.destroy = rdp_destroy;
+       b->base.restore = rdp_restore;
+       b->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL;
+       b->no_clients_resize = config->no_clients_resize;
+
+       /* activate TLS only if certificate/key are available */
+       if (config->server_cert && config->server_key) {
+               weston_log("TLS support activated\n");
+               b->server_cert = strdup(config->server_cert);
+               b->server_key = strdup(config->server_key);
+               if (!b->server_cert || !b->server_key)
+                       goto err_free_strings;
+               b->tls_enabled = 1;
+       }
+
+       if (weston_compositor_set_presentation_clock_software(compositor) < 0)
+               goto err_compositor;
+
+       if (pixman_renderer_init(compositor) < 0)
+               goto err_compositor;
+
+       if (rdp_backend_create_output(b, config->width, config->height) < 0)
+               goto err_compositor;
+
+       compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES;
+
+       if (!config->env_socket) {
+               b->listener = freerdp_listener_new();
+               b->listener->PeerAccepted = rdp_incoming_peer;
+               b->listener->param4 = b;
+               if (!b->listener->Open(b->listener, config->bind_address, config->port)) {
+                       weston_log("unable to bind rdp socket\n");
+                       goto err_listener;
+               }
+
+               if (rdp_implant_listener(b, b->listener) < 0)
+                       goto err_compositor;
+       } else {
+               /* get the socket from RDP_FD var */
+               fd_str = getenv("RDP_FD");
+               if (!fd_str) {
+                       weston_log("RDP_FD env variable not set\n");
+                       goto err_output;
+               }
+
+               fd = strtoul(fd_str, NULL, 10);
+               if (rdp_peer_init(freerdp_peer_new(fd), b))
+                       goto err_output;
+       }
+
+       compositor->backend = &b->base;
+       return b;
+
+err_listener:
+       freerdp_listener_free(b->listener);
+err_output:
+       weston_output_destroy(&b->output->base);
+err_compositor:
+       weston_compositor_shutdown(compositor);
+err_free_strings:
+       free(b->rdp_key);
+       free(b->server_cert);
+       free(b->server_key);
+       free(b);
+       return NULL;
+}
+
+static void
+config_init_to_defaults(struct weston_rdp_backend_config *config)
+{
+       config->width = 640;
+       config->height = 480;
+       config->bind_address = NULL;
+       config->port = 3389;
+       config->rdp_key = NULL;
+       config->server_cert = NULL;
+       config->server_key = NULL;
+       config->env_socket = 0;
+       config->no_clients_resize = 0;
+}
+
+WL_EXPORT int
+backend_init(struct weston_compositor *compositor,
+            struct weston_backend_config *config_base)
+{
+       struct rdp_backend *b;
+       struct weston_rdp_backend_config config = {{ 0, }};
+       int major, minor, revision;
+
+       freerdp_get_version(&major, &minor, &revision);
+       weston_log("using FreeRDP version %d.%d.%d\n", major, minor, revision);
+
+       if (config_base == NULL ||
+           config_base->struct_version != WESTON_RDP_BACKEND_CONFIG_VERSION ||
+           config_base->struct_size > sizeof(struct weston_rdp_backend_config)) {
+               weston_log("RDP backend config structure is invalid\n");
+               return -1;
+       }
+
+       config_init_to_defaults(&config);
+       memcpy(&config, config_base, config_base->struct_size);
+
+       if (!config.rdp_key && (!config.server_cert || !config.server_key)) {
+               weston_log("the RDP compositor requires keys and an optional certificate for RDP or TLS security ("
+                               "--rdp4-key or --rdp-tls-cert/--rdp-tls-key)\n");
+               return -1;
+       }
+
+       b = rdp_backend_create(compositor, &config);
+       if (b == NULL)
+               return -1;
+       return 0;
+}
diff --git a/libweston/compositor-rdp.h b/libweston/compositor-rdp.h
new file mode 100644 (file)
index 0000000..dfa1759
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2016 Benoit Gschwind
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_COMPOSITOR_RDP_H
+#define WESTON_COMPOSITOR_RDP_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include "compositor.h"
+
+#define WESTON_RDP_BACKEND_CONFIG_VERSION 1
+
+struct weston_rdp_backend_config {
+       struct weston_backend_config base;
+       int width;
+       int height;
+       char *bind_address;
+       int port;
+       char *rdp_key;
+       char *server_cert;
+       char *server_key;
+       int env_socket;
+       int no_clients_resize;
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WESTON_COMPOSITOR_RDP_H */
diff --git a/libweston/compositor-wayland.c b/libweston/compositor-wayland.c
new file mode 100644 (file)
index 0000000..1343e21
--- /dev/null
@@ -0,0 +1,2348 @@
+/*
+ * Copyright © 2010-2011 Benjamin Franzke
+ * Copyright © 2013 Jason Ekstrand
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <linux/input.h>
+
+#include <wayland-client.h>
+#include <wayland-egl.h>
+#include <wayland-cursor.h>
+
+#include "compositor.h"
+#include "compositor-wayland.h"
+#include "gl-renderer.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 "fullscreen-shell-unstable-v1-client-protocol.h"
+#include "presentation-time-server-protocol.h"
+#include "linux-dmabuf.h"
+
+#define WINDOW_TITLE "Weston Compositor"
+
+struct wayland_backend {
+       struct weston_backend base;
+       struct weston_compositor *compositor;
+
+       struct {
+               struct wl_display *wl_display;
+               struct wl_registry *registry;
+               struct wl_compositor *compositor;
+               struct wl_shell *shell;
+               struct zwp_fullscreen_shell_v1 *fshell;
+               struct wl_shm *shm;
+
+               struct wl_list output_list;
+
+               struct wl_event_source *wl_source;
+               uint32_t event_mask;
+       } parent;
+
+       int use_pixman;
+       int sprawl_across_outputs;
+
+       struct theme *theme;
+       cairo_device_t *frame_device;
+       struct wl_cursor_theme *cursor_theme;
+       struct wl_cursor *cursor;
+
+       struct wl_list input_list;
+};
+
+struct wayland_output {
+       struct weston_output base;
+
+       struct {
+               int draw_initial_frame;
+               struct wl_surface *surface;
+
+               struct wl_output *output;
+               uint32_t global_id;
+
+               struct wl_shell_surface *shell_surface;
+               int configure_width, configure_height;
+       } parent;
+
+       int keyboard_count;
+
+       char *name;
+       struct frame *frame;
+
+       struct {
+               struct wl_egl_window *egl_window;
+               struct {
+                       cairo_surface_t *top;
+                       cairo_surface_t *left;
+                       cairo_surface_t *right;
+                       cairo_surface_t *bottom;
+               } border;
+       } gl;
+
+       struct {
+               struct wl_list buffers;
+               struct wl_list free_buffers;
+       } shm;
+
+       struct weston_mode mode;
+       uint32_t scale;
+};
+
+struct wayland_parent_output {
+       struct wayland_output *output;
+       struct wl_list link;
+
+       struct wl_output *global;
+       uint32_t id;
+
+       struct {
+               char *make;
+               char *model;
+               int32_t width, height;
+               uint32_t subpixel;
+       } physical;
+
+       int32_t x, y;
+       uint32_t transform;
+       uint32_t scale;
+
+       struct wl_list mode_list;
+       struct weston_mode *preferred_mode;
+       struct weston_mode *current_mode;
+};
+
+struct wayland_shm_buffer {
+       struct wayland_output *output;
+       struct wl_list link;
+       struct wl_list free_link;
+
+       struct wl_buffer *buffer;
+       void *data;
+       size_t size;
+       pixman_region32_t damage;
+       int frame_damaged;
+
+       pixman_image_t *pm_image;
+       cairo_surface_t *c_surface;
+};
+
+struct wayland_input {
+       struct weston_seat base;
+       struct wayland_backend *backend;
+       struct wl_list link;
+
+       struct {
+               struct wl_seat *seat;
+               struct wl_pointer *pointer;
+               struct wl_keyboard *keyboard;
+               struct wl_touch *touch;
+
+               struct {
+                       struct wl_surface *surface;
+                       int32_t hx, hy;
+               } cursor;
+       } parent;
+
+       enum weston_key_state_update keyboard_state_update;
+       uint32_t key_serial;
+       uint32_t enter_serial;
+       uint32_t touch_points;
+       bool touch_active;
+       bool has_focus;
+       int seat_version;
+
+       struct wayland_output *output;
+       struct wayland_output *touch_focus;
+       struct wayland_output *keyboard_focus;
+
+       struct weston_pointer_axis_event vert, horiz;
+};
+
+struct gl_renderer_interface *gl_renderer;
+
+static void
+wayland_shm_buffer_destroy(struct wayland_shm_buffer *buffer)
+{
+       cairo_surface_destroy(buffer->c_surface);
+       pixman_image_unref(buffer->pm_image);
+
+       wl_buffer_destroy(buffer->buffer);
+       munmap(buffer->data, buffer->size);
+
+       pixman_region32_fini(&buffer->damage);
+
+       wl_list_remove(&buffer->link);
+       wl_list_remove(&buffer->free_link);
+       free(buffer);
+}
+
+static void
+buffer_release(void *data, struct wl_buffer *buffer)
+{
+       struct wayland_shm_buffer *sb = data;
+
+       if (sb->output) {
+               wl_list_insert(&sb->output->shm.free_buffers, &sb->free_link);
+       } else {
+               wayland_shm_buffer_destroy(sb);
+       }
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+       buffer_release
+};
+
+static struct wayland_shm_buffer *
+wayland_output_get_shm_buffer(struct wayland_output *output)
+{
+       struct wayland_backend *b =
+               (struct wayland_backend *) output->base.compositor->backend;
+       struct wl_shm *shm = b->parent.shm;
+       struct wayland_shm_buffer *sb;
+
+       struct wl_shm_pool *pool;
+       int width, height, stride;
+       int32_t fx, fy;
+       int fd;
+       unsigned char *data;
+
+       if (!wl_list_empty(&output->shm.free_buffers)) {
+               sb = container_of(output->shm.free_buffers.next,
+                                 struct wayland_shm_buffer, free_link);
+               wl_list_remove(&sb->free_link);
+               wl_list_init(&sb->free_link);
+
+               return sb;
+       }
+
+       if (output->frame) {
+               width = frame_width(output->frame);
+               height = frame_height(output->frame);
+       } else {
+               width = output->base.current_mode->width;
+               height = output->base.current_mode->height;
+       }
+
+       stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
+
+       fd = os_create_anonymous_file(height * stride);
+       if (fd < 0) {
+               weston_log("could not create an anonymous file buffer: %m\n");
+               return NULL;
+       }
+
+       data = mmap(NULL, height * stride, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+       if (data == MAP_FAILED) {
+               weston_log("could not mmap %d memory for data: %m\n", height * stride);
+               close(fd);
+               return NULL;
+       }
+
+       sb = zalloc(sizeof *sb);
+       if (sb == NULL) {
+               weston_log("could not zalloc %zu memory for sb: %m\n", sizeof *sb);
+               close(fd);
+               free(data);
+               return NULL;
+       }
+
+       sb->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);
+       sb->frame_damaged = 1;
+
+       sb->data = data;
+       sb->size = height * stride;
+
+       pool = wl_shm_create_pool(shm, fd, sb->size);
+
+       sb->buffer = wl_shm_pool_create_buffer(pool, 0,
+                                              width, height,
+                                              stride,
+                                              WL_SHM_FORMAT_ARGB8888);
+       wl_buffer_add_listener(sb->buffer, &buffer_listener, sb);
+       wl_shm_pool_destroy(pool);
+       close(fd);
+
+       memset(data, 0, sb->size);
+
+       sb->c_surface =
+               cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
+                                                   width, height, stride);
+
+       fx = 0;
+       fy = 0;
+       if (output->frame)
+               frame_interior(output->frame, &fx, &fy, 0, 0);
+       sb->pm_image =
+               pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height,
+                                        (uint32_t *)(data + fy * stride) + fx,
+                                        stride);
+
+       return sb;
+}
+
+static void
+frame_done(void *data, struct wl_callback *callback, uint32_t time)
+{
+       struct weston_output *output = data;
+       struct timespec ts;
+
+       wl_callback_destroy(callback);
+
+       /* XXX: use the presentation extension for proper timings */
+
+       /*
+        * This is the fallback case, where Presentation extension is not
+        * available from the parent compositor. We do not know the base for
+        * 'time', so we cannot feed it to finish_frame(). Do the only thing
+        * 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);
+}
+
+static const struct wl_callback_listener frame_listener = {
+       frame_done
+};
+
+static void
+draw_initial_frame(struct wayland_output *output)
+{
+       struct wayland_shm_buffer *sb;
+
+       sb = wayland_output_get_shm_buffer(output);
+
+       /* If we are rendering with GL, then orphan it so that it gets
+        * destroyed immediately */
+       if (output->gl.egl_window)
+               sb->output = NULL;
+
+       wl_surface_attach(output->parent.surface, sb->buffer, 0, 0);
+       wl_surface_damage(output->parent.surface, 0, 0,
+                         output->base.current_mode->width,
+                         output->base.current_mode->height);
+}
+
+static void
+wayland_output_update_gl_border(struct wayland_output *output)
+{
+       int32_t ix, iy, iwidth, iheight, fwidth, fheight;
+       cairo_t *cr;
+
+       if (!output->frame)
+               return;
+       if (!(frame_status(output->frame) & FRAME_STATUS_REPAINT))
+               return;
+
+       fwidth = frame_width(output->frame);
+       fheight = frame_height(output->frame);
+       frame_interior(output->frame, &ix, &iy, &iwidth, &iheight);
+
+       if (!output->gl.border.top)
+               output->gl.border.top =
+                       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+                                                  fwidth, iy);
+       cr = cairo_create(output->gl.border.top);
+       frame_repaint(output->frame, cr);
+       cairo_destroy(cr);
+       gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_TOP,
+                                      fwidth, iy,
+                                      cairo_image_surface_get_stride(output->gl.border.top) / 4,
+                                      cairo_image_surface_get_data(output->gl.border.top));
+
+
+       if (!output->gl.border.left)
+               output->gl.border.left =
+                       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+                                                  ix, 1);
+       cr = cairo_create(output->gl.border.left);
+       cairo_translate(cr, 0, -iy);
+       frame_repaint(output->frame, cr);
+       cairo_destroy(cr);
+       gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_LEFT,
+                                      ix, 1,
+                                      cairo_image_surface_get_stride(output->gl.border.left) / 4,
+                                      cairo_image_surface_get_data(output->gl.border.left));
+
+
+       if (!output->gl.border.right)
+               output->gl.border.right =
+                       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+                                                  fwidth - (ix + iwidth), 1);
+       cr = cairo_create(output->gl.border.right);
+       cairo_translate(cr, -(iwidth + ix), -iy);
+       frame_repaint(output->frame, cr);
+       cairo_destroy(cr);
+       gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_RIGHT,
+                                      fwidth - (ix + iwidth), 1,
+                                      cairo_image_surface_get_stride(output->gl.border.right) / 4,
+                                      cairo_image_surface_get_data(output->gl.border.right));
+
+
+       if (!output->gl.border.bottom)
+               output->gl.border.bottom =
+                       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
+                                                  fwidth, fheight - (iy + iheight));
+       cr = cairo_create(output->gl.border.bottom);
+       cairo_translate(cr, 0, -(iy + iheight));
+       frame_repaint(output->frame, cr);
+       cairo_destroy(cr);
+       gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_BOTTOM,
+                                      fwidth, fheight - (iy + iheight),
+                                      cairo_image_surface_get_stride(output->gl.border.bottom) / 4,
+                                      cairo_image_surface_get_data(output->gl.border.bottom));
+}
+
+static void
+wayland_output_start_repaint_loop(struct weston_output *output_base)
+{
+       struct wayland_output *output = (struct wayland_output *) output_base;
+       struct wayland_backend *wb =
+               (struct wayland_backend *)output->base.compositor->backend;
+       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
+        * loop. If the surface doesn't end up in the render loop, the frame
+        * 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;
+
+               draw_initial_frame(output);
+       }
+
+       callback = wl_surface_frame(output->parent.surface);
+       wl_callback_add_listener(callback, &frame_listener, output);
+       wl_surface_commit(output->parent.surface);
+       wl_display_flush(wb->parent.wl_display);
+}
+
+static int
+wayland_output_repaint_gl(struct weston_output *output_base,
+                         pixman_region32_t *damage)
+{
+       struct wayland_output *output = (struct 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);
+
+       wayland_output_update_gl_border(output);
+
+       ec->renderer->repaint_output(&output->base, damage);
+
+       pixman_region32_subtract(&ec->primary_plane.damage,
+                                &ec->primary_plane.damage, damage);
+       return 0;
+}
+
+static void
+wayland_output_update_shm_border(struct wayland_shm_buffer *buffer)
+{
+       int32_t ix, iy, iwidth, iheight, fwidth, fheight;
+       cairo_t *cr;
+
+       if (!buffer->output->frame || !buffer->frame_damaged)
+               return;
+
+       cr = cairo_create(buffer->c_surface);
+
+       frame_interior(buffer->output->frame, &ix, &iy, &iwidth, &iheight);
+       fwidth = frame_width(buffer->output->frame);
+       fheight = frame_height(buffer->output->frame);
+
+       /* Set the clip so we don't unnecisaraly damage the surface */
+       cairo_move_to(cr, ix, iy);
+       cairo_rel_line_to(cr, iwidth, 0);
+       cairo_rel_line_to(cr, 0, iheight);
+       cairo_rel_line_to(cr, -iwidth, 0);
+       cairo_line_to(cr, ix, iy);
+       cairo_line_to(cr, 0, iy);
+       cairo_line_to(cr, 0, fheight);
+       cairo_line_to(cr, fwidth, fheight);
+       cairo_line_to(cr, fwidth, 0);
+       cairo_line_to(cr, 0, 0);
+       cairo_line_to(cr, 0, iy);
+       cairo_close_path(cr);
+       cairo_clip(cr);
+
+       /* Draw using a pattern so that the final result gets clipped */
+       cairo_push_group(cr);
+       frame_repaint(buffer->output->frame, cr);
+       cairo_pop_group_to_source(cr);
+       cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
+       cairo_paint(cr);
+
+       cairo_destroy(cr);
+}
+
+static void
+wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
+{
+       pixman_region32_t damage;
+       pixman_box32_t *rects;
+       int32_t ix, iy, iwidth, iheight, fwidth, fheight;
+       int i, n;
+
+       pixman_region32_init(&damage);
+       weston_transformed_region(sb->output->base.width,
+                                 sb->output->base.height,
+                                 sb->output->base.transform,
+                                 sb->output->base.current_scale,
+                                 &sb->damage, &damage);
+
+       if (sb->output->frame) {
+               frame_interior(sb->output->frame, &ix, &iy, &iwidth, &iheight);
+               fwidth = frame_width(sb->output->frame);
+               fheight = frame_height(sb->output->frame);
+
+               pixman_region32_translate(&damage, ix, iy);
+
+               if (sb->frame_damaged) {
+                       pixman_region32_union_rect(&damage, &damage,
+                                                  0, 0, fwidth, iy);
+                       pixman_region32_union_rect(&damage, &damage,
+                                                  0, iy, ix, iheight);
+                       pixman_region32_union_rect(&damage, &damage,
+                                                  ix + iwidth, iy,
+                                                  fwidth - (ix + iwidth), iheight);
+                       pixman_region32_union_rect(&damage, &damage,
+                                                  0, iy + iheight,
+                                                  fwidth, fheight - (iy + iheight));
+               }
+       }
+
+       rects = pixman_region32_rectangles(&damage, &n);
+       wl_surface_attach(sb->output->parent.surface, sb->buffer, 0, 0);
+       for (i = 0; i < n; ++i)
+               wl_surface_damage(sb->output->parent.surface, rects[i].x1,
+                                 rects[i].y1, rects[i].x2 - rects[i].x1,
+                                 rects[i].y2 - rects[i].y1);
+
+       if (sb->output->frame)
+               pixman_region32_fini(&damage);
+}
+
+static int
+wayland_output_repaint_pixman(struct weston_output *output_base,
+                             pixman_region32_t *damage)
+{
+       struct wayland_output *output = (struct wayland_output *) output_base;
+       struct wayland_backend *b =
+               (struct wayland_backend *)output->base.compositor->backend;
+       struct wl_callback *callback;
+       struct wayland_shm_buffer *sb;
+
+       if (output->frame) {
+               if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
+                       wl_list_for_each(sb, &output->shm.buffers, link)
+                               sb->frame_damaged = 1;
+       }
+
+       wl_list_for_each(sb, &output->shm.buffers, link)
+               pixman_region32_union(&sb->damage, &sb->damage, damage);
+
+       sb = wayland_output_get_shm_buffer(output);
+
+       wayland_output_update_shm_border(sb);
+       pixman_renderer_output_set_buffer(output_base, sb->pm_image);
+       b->compositor->renderer->repaint_output(output_base, &sb->damage);
+
+       wayland_shm_buffer_attach(sb);
+
+       callback = wl_surface_frame(output->parent.surface);
+       wl_callback_add_listener(callback, &frame_listener, output);
+       wl_surface_commit(output->parent.surface);
+       wl_display_flush(b->parent.wl_display);
+
+       pixman_region32_fini(&sb->damage);
+       pixman_region32_init(&sb->damage);
+       sb->frame_damaged = 0;
+
+       pixman_region32_subtract(&b->compositor->primary_plane.damage,
+                                &b->compositor->primary_plane.damage, damage);
+       return 0;
+}
+
+static void
+wayland_output_destroy(struct weston_output *output_base)
+{
+       struct wayland_output *output = (struct wayland_output *) output_base;
+       struct wayland_backend *b =
+               (struct wayland_backend *) output->base.compositor->backend;
+
+       if (b->use_pixman) {
+               pixman_renderer_output_destroy(output_base);
+       } else {
+               gl_renderer->output_destroy(output_base);
+       }
+
+       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);
+
+       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);
+
+       weston_output_destroy(&output->base);
+       free(output);
+
+       return;
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener;
+
+static int
+wayland_output_init_gl_renderer(struct wayland_output *output)
+{
+       int32_t fwidth = 0, fheight = 0;
+
+       if (output->frame) {
+               fwidth = frame_width(output->frame);
+               fheight = frame_height(output->frame);
+       } else {
+               fwidth = output->base.current_mode->width;
+               fheight = output->base.current_mode->height;
+       }
+
+       output->gl.egl_window =
+               wl_egl_window_create(output->parent.surface,
+                                    fwidth, fheight);
+       if (!output->gl.egl_window) {
+               weston_log("failure to create wl_egl_window\n");
+               return -1;
+       }
+
+       if (gl_renderer->output_create(&output->base,
+                                      output->gl.egl_window,
+                                      output->gl.egl_window,
+                                      gl_renderer->alpha_attribs,
+                                      NULL,
+                                      0) < 0)
+               goto cleanup_window;
+
+       return 0;
+
+cleanup_window:
+       wl_egl_window_destroy(output->gl.egl_window);
+       return -1;
+}
+
+static int
+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_backend *b =
+               (struct wayland_backend *)output->base.compositor->backend;
+       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(b->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(b->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(b->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(b->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, 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_set_windowed(struct wayland_output *output)
+{
+       struct wayland_backend *b =
+               (struct wayland_backend *)output->base.compositor->backend;
+       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);
+                       return -1;
+               }
+       }
+       output->frame = frame_create(b->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)
+{
+       struct wayland_backend *b =
+               (struct wayland_backend *)output->base.compositor->backend;
+
+       if (output->frame) {
+               frame_destroy(output->frame);
+               output->frame = NULL;
+       }
+
+       wayland_output_resize_surface(output);
+
+       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);
+       }
+}
+
+static struct weston_mode *
+wayland_output_choose_mode(struct wayland_output *output,
+                          struct weston_mode *ref_mode)
+{
+       struct weston_mode *mode;
+
+       /* First look for an exact match */
+       wl_list_for_each(mode, &output->base.mode_list, link)
+               if (mode->width == ref_mode->width &&
+                   mode->height == ref_mode->height &&
+                   mode->refresh == ref_mode->refresh)
+                       return mode;
+
+       /* If we can't find an exact match, ignore refresh and try again */
+       wl_list_for_each(mode, &output->base.mode_list, link)
+               if (mode->width == ref_mode->width &&
+                   mode->height == ref_mode->height)
+                       return mode;
+
+       /* Yeah, we failed */
+       return NULL;
+}
+
+enum mode_status {
+       MODE_STATUS_UNKNOWN,
+       MODE_STATUS_SUCCESS,
+       MODE_STATUS_FAIL,
+       MODE_STATUS_CANCEL,
+};
+
+static void
+mode_feedback_successful(void *data,
+                        struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
+{
+       enum mode_status *value = data;
+
+       printf("Mode switch successful\n");
+
+       *value = MODE_STATUS_SUCCESS;
+}
+
+static void
+mode_feedback_failed(void *data, struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
+{
+       enum mode_status *value = data;
+
+       printf("Mode switch failed\n");
+
+       *value = MODE_STATUS_FAIL;
+}
+
+static void
+mode_feedback_cancelled(void *data, struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
+{
+       enum mode_status *value = data;
+
+       printf("Mode switch cancelled\n");
+
+       *value = MODE_STATUS_CANCEL;
+}
+
+struct zwp_fullscreen_shell_mode_feedback_v1_listener mode_feedback_listener = {
+       mode_feedback_successful,
+       mode_feedback_failed,
+       mode_feedback_cancelled,
+};
+
+static int
+wayland_output_switch_mode(struct weston_output *output_base,
+                          struct weston_mode *mode)
+{
+       struct wayland_output *output = (struct wayland_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");
+               return -1;
+       }
+
+       if (mode == NULL) {
+               weston_log("mode is NULL.\n");
+               return -1;
+       }
+
+       b = (struct wayland_backend *)output_base->compositor->backend;
+
+       if (output->parent.shell_surface || !b->parent.fshell)
+               return -1;
+
+       mode = wayland_output_choose_mode(output, mode);
+       if (mode == NULL)
+               return -1;
+
+       if (output->base.current_mode == mode)
+               return 0;
+
+       old_mode = output->base.current_mode;
+       old_surface = output->parent.surface;
+       output->base.current_mode = mode;
+       output->parent.surface =
+               wl_compositor_create_surface(b->parent.compositor);
+       wl_surface_set_user_data(output->parent.surface, output);
+
+       /* 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);
+
+       /* 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);
+               output->parent.surface = old_surface;
+               wayland_output_resize_surface(output);
+
+               return -1;
+       }
+
+       old_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
+       output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
+
+       if (b->use_pixman) {
+               pixman_renderer_output_destroy(output_base);
+               if (wayland_output_init_pixman_renderer(output) < 0)
+                       goto err_output;
+       } 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;
+       }
+       wl_surface_destroy(old_surface);
+
+       weston_output_schedule_repaint(&output->base);
+
+       return 0;
+
+err_output:
+       /* XXX */
+       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)
+{
+       struct wayland_output *output;
+       int output_width, output_height;
+
+       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 = "wayland";
+       output->base.model = "none";
+
+       output_width = width * scale;
+       output_height = height * scale;
+
+       output->parent.surface =
+               wl_compositor_create_surface(b->parent.compositor);
+       if (!output->parent.surface)
+               goto err_name;
+       wl_surface_set_user_data(output->parent.surface, output);
+
+       output->parent.draw_initial_frame = 1;
+
+       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;
+               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;
+       }
+
+       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;
+
+       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;
+       } else {
+               if (wayland_output_init_gl_renderer(output) < 0)
+                       goto err_output;
+               output->base.repaint = wayland_output_repaint_gl;
+       }
+
+       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);
+
+       return output;
+
+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);
+
+       /* FIXME: cleanup weston_output */
+       free(output);
+
+       return NULL;
+}
+
+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)
+{
+       struct wayland_output *output;
+
+       output = wayland_output_create(b, x, y, oc->width, oc->height, oc->name,
+                                      fullscreen, oc->transform, oc->scale);
+
+       return output;
+}
+
+static struct wayland_output *
+wayland_output_create_for_parent_output(struct wayland_backend *b,
+                                       struct wayland_parent_output *poutput)
+{
+       struct wayland_output *output;
+       struct weston_mode *mode;
+       int32_t x;
+
+       if (poutput->current_mode) {
+               mode = poutput->current_mode;
+       } else if (poutput->preferred_mode) {
+               mode = poutput->preferred_mode;
+       } else if (!wl_list_empty(&poutput->mode_list)) {
+               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;
+       }
+
+       output = wayland_output_create(b, x, 0, mode->width, mode->height,
+                                      NULL, 0,
+                                      WL_OUTPUT_TRANSFORM_NORMAL, 1);
+       if (!output)
+               return NULL;
+
+       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);
+
+       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));
+       }
+
+       return output;
+}
+
+static void
+shell_surface_ping(void *data, struct wl_shell_surface *shell_surface,
+                  uint32_t serial)
+{
+       wl_shell_surface_pong(shell_surface, serial);
+}
+
+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 */
+}
+
+static void
+shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface)
+{
+}
+
+static const struct wl_shell_surface_listener shell_surface_listener = {
+       shell_surface_ping,
+       shell_surface_configure,
+       shell_surface_popup_done
+};
+
+/* Events received from the wayland-server this compositor is client of: */
+
+/* parent input interface */
+static void
+input_set_cursor(struct wayland_input *input)
+{
+
+       struct wl_buffer *buffer;
+       struct wl_cursor_image *image;
+
+       if (!input->backend->cursor)
+               return; /* Couldn't load the cursor. Can't set it */
+
+       image = input->backend->cursor->images[0];
+       buffer = wl_cursor_image_get_buffer(image);
+       if (!buffer)
+               return;
+
+       wl_pointer_set_cursor(input->parent.pointer, input->enter_serial,
+                             input->parent.cursor.surface,
+                             image->hotspot_x, image->hotspot_y);
+
+       wl_surface_attach(input->parent.cursor.surface, buffer, 0, 0);
+       wl_surface_damage(input->parent.cursor.surface, 0, 0,
+                         image->width, image->height);
+       wl_surface_commit(input->parent.cursor.surface);
+}
+
+static void
+input_handle_pointer_enter(void *data, struct wl_pointer *pointer,
+                          uint32_t serial, struct wl_surface *surface,
+                          wl_fixed_t fixed_x, wl_fixed_t fixed_y)
+{
+       struct wayland_input *input = data;
+       int32_t fx, fy;
+       enum theme_location location;
+       double x, y;
+
+       x = wl_fixed_to_double(fixed_x);
+       y = wl_fixed_to_double(fixed_y);
+
+       /* XXX: If we get a modifier event immediately before the focus,
+        *      we should try to keep the same serial. */
+       input->enter_serial = serial;
+       input->output = wl_surface_get_user_data(surface);
+
+       if (input->output->frame) {
+               location = frame_pointer_enter(input->output->frame, input,
+                                              x, y);
+               frame_interior(input->output->frame, &fx, &fy, NULL, NULL);
+               x -= fx;
+               y -= fy;
+
+               if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&input->output->base);
+       } else {
+               location = THEME_LOCATION_CLIENT_AREA;
+       }
+
+       weston_output_transform_coordinate(&input->output->base, x, y, &x, &y);
+
+       if (location == THEME_LOCATION_CLIENT_AREA) {
+               input->has_focus = true;
+               notify_pointer_focus(&input->base, &input->output->base, x, y);
+               wl_pointer_set_cursor(input->parent.pointer,
+                                     input->enter_serial, NULL, 0, 0);
+       } else {
+               input->has_focus = false;
+               notify_pointer_focus(&input->base, NULL, 0, 0);
+               input_set_cursor(input);
+       }
+}
+
+static void
+input_handle_pointer_leave(void *data, struct wl_pointer *pointer,
+                          uint32_t serial, struct wl_surface *surface)
+{
+       struct wayland_input *input = data;
+
+       if (!input->output)
+               return;
+
+       if (input->output->frame) {
+               frame_pointer_leave(input->output->frame, input);
+
+               if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&input->output->base);
+       }
+
+       notify_pointer_focus(&input->base, NULL, 0, 0);
+       input->output = NULL;
+       input->has_focus = false;
+}
+
+static void
+input_handle_motion(void *data, struct wl_pointer *pointer,
+                   uint32_t time, wl_fixed_t fixed_x, wl_fixed_t fixed_y)
+{
+       struct wayland_input *input = data;
+       int32_t fx, fy;
+       enum theme_location location;
+       bool want_frame = false;
+       double x, y;
+
+       if (!input->output)
+               return;
+
+       x = wl_fixed_to_double(fixed_x);
+       y = wl_fixed_to_double(fixed_y);
+
+       if (input->output->frame) {
+               location = frame_pointer_motion(input->output->frame, input,
+                                               x, y);
+               frame_interior(input->output->frame, &fx, &fy, NULL, NULL);
+               x -= fx;
+               y -= fy;
+
+               if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&input->output->base);
+       } else {
+               location = THEME_LOCATION_CLIENT_AREA;
+       }
+
+       weston_output_transform_coordinate(&input->output->base, x, y, &x, &y);
+
+       if (input->has_focus && location != THEME_LOCATION_CLIENT_AREA) {
+               input_set_cursor(input);
+               notify_pointer_focus(&input->base, NULL, 0, 0);
+               input->has_focus = false;
+               want_frame = true;
+       } else if (!input->has_focus &&
+                  location == THEME_LOCATION_CLIENT_AREA) {
+               wl_pointer_set_cursor(input->parent.pointer,
+                                     input->enter_serial, NULL, 0, 0);
+               notify_pointer_focus(&input->base, &input->output->base, x, y);
+               input->has_focus = true;
+               want_frame = true;
+       }
+
+       if (location == THEME_LOCATION_CLIENT_AREA) {
+               notify_motion_absolute(&input->base, time, x, y);
+               want_frame = true;
+       }
+
+       if (want_frame && input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
+               notify_pointer_frame(&input->base);
+}
+
+static void
+input_handle_button(void *data, struct wl_pointer *pointer,
+                   uint32_t serial, uint32_t time, uint32_t button,
+                   uint32_t state_w)
+{
+       struct wayland_input *input = data;
+       enum wl_pointer_button_state state = state_w;
+       enum frame_button_state fstate;
+       enum theme_location location;
+
+       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);
+
+               if (frame_status(input->output->frame) & FRAME_STATUS_MOVE) {
+
+                       wl_shell_surface_move(input->output->parent.shell_surface,
+                                             input->parent.seat, serial);
+                       frame_status_clear(input->output->frame,
+                                          FRAME_STATUS_MOVE);
+                       return;
+               }
+
+               if (frame_status(input->output->frame) & FRAME_STATUS_CLOSE) {
+                       wayland_output_destroy(&input->output->base);
+                       input->output = NULL;
+                       input->keyboard_focus = NULL;
+
+                       if (wl_list_empty(&input->backend->compositor->output_list))
+                               weston_compositor_exit(input->backend->compositor);
+
+                       return;
+               }
+
+               if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&input->output->base);
+       } else {
+               location = THEME_LOCATION_CLIENT_AREA;
+       }
+
+       if (location == THEME_LOCATION_CLIENT_AREA) {
+               notify_button(&input->base, time, button, state);
+               if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
+                       notify_pointer_frame(&input->base);
+       }
+}
+
+static void
+input_handle_axis(void *data, struct wl_pointer *pointer,
+                 uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+       struct wayland_input *input = data;
+       struct weston_pointer_axis_event weston_event;
+
+       weston_event.axis = axis;
+       weston_event.value = wl_fixed_to_double(value);
+
+       if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL &&
+           input->vert.has_discrete) {
+               weston_event.has_discrete = true;
+               weston_event.discrete = input->vert.discrete;
+               input->vert.has_discrete = false;
+       } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL &&
+                  input->horiz.has_discrete) {
+               weston_event.has_discrete = true;
+               weston_event.discrete = input->horiz.discrete;
+               input->horiz.has_discrete = false;
+       }
+
+       notify_axis(&input->base, time, &weston_event);
+
+       if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
+               notify_pointer_frame(&input->base);
+}
+
+static void
+input_handle_frame(void *data, struct wl_pointer *pointer)
+{
+       struct wayland_input *input = data;
+
+       notify_pointer_frame(&input->base);
+}
+
+static void
+input_handle_axis_source(void *data, struct wl_pointer *pointer,
+                        uint32_t source)
+{
+       struct wayland_input *input = data;
+
+       notify_axis_source(&input->base, source);
+}
+
+static void
+input_handle_axis_stop(void *data, struct wl_pointer *pointer,
+                      uint32_t time, uint32_t axis)
+{
+       struct wayland_input *input = data;
+       struct weston_pointer_axis_event weston_event;
+
+       weston_event.axis = axis;
+       weston_event.value = 0;
+
+       notify_axis(&input->base, time, &weston_event);
+}
+
+static void
+input_handle_axis_discrete(void *data, struct wl_pointer *pointer,
+                          uint32_t axis, int32_t discrete)
+{
+       struct wayland_input *input = data;
+
+       if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
+               input->vert.has_discrete = true;
+               input->vert.discrete = discrete;
+       } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
+               input->horiz.has_discrete = true;
+               input->horiz.discrete = discrete;
+       }
+}
+
+static const struct wl_pointer_listener pointer_listener = {
+       input_handle_pointer_enter,
+       input_handle_pointer_leave,
+       input_handle_motion,
+       input_handle_button,
+       input_handle_axis,
+       input_handle_frame,
+       input_handle_axis_source,
+       input_handle_axis_stop,
+       input_handle_axis_discrete,
+};
+
+static void
+input_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
+                   int fd, uint32_t size)
+{
+       struct wayland_input *input = data;
+       struct xkb_keymap *keymap;
+       char *map_str;
+
+       if (!data) {
+               close(fd);
+               return;
+       }
+
+       if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
+               map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
+               if (map_str == MAP_FAILED) {
+                       weston_log("mmap failed: %m\n");
+                       goto error;
+               }
+
+               keymap = xkb_keymap_new_from_string(input->backend->compositor->xkb_context,
+                                                   map_str,
+                                                   XKB_KEYMAP_FORMAT_TEXT_V1,
+                                                   0);
+               munmap(map_str, size);
+
+               if (!keymap) {
+                       weston_log("failed to compile keymap\n");
+                       goto error;
+               }
+
+               input->keyboard_state_update = STATE_UPDATE_NONE;
+       } else if (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) {
+               weston_log("No keymap provided; falling back to defalt\n");
+               keymap = NULL;
+               input->keyboard_state_update = STATE_UPDATE_AUTOMATIC;
+       } else {
+               weston_log("Invalid keymap\n");
+               goto error;
+       }
+
+       close(fd);
+
+       if (weston_seat_get_keyboard(&input->base))
+               weston_seat_update_keymap(&input->base, keymap);
+       else
+               weston_seat_init_keyboard(&input->base, keymap);
+
+       xkb_keymap_unref(keymap);
+
+       return;
+
+error:
+       wl_keyboard_release(input->parent.keyboard);
+       close(fd);
+}
+
+static void
+input_handle_keyboard_enter(void *data,
+                           struct wl_keyboard *keyboard,
+                           uint32_t serial,
+                           struct wl_surface *surface,
+                           struct wl_array *keys)
+{
+       struct wayland_input *input = data;
+       struct wayland_output *focus;
+
+       focus = input->keyboard_focus;
+       if (focus) {
+               /* This shouldn't happen */
+               focus->keyboard_count--;
+               if (!focus->keyboard_count && focus->frame)
+                       frame_unset_flag(focus->frame, FRAME_FLAG_ACTIVE);
+               if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&focus->base);
+       }
+
+       input->keyboard_focus = wl_surface_get_user_data(surface);
+       input->keyboard_focus->keyboard_count++;
+
+       focus = input->keyboard_focus;
+       if (focus->frame) {
+               frame_set_flag(focus->frame, FRAME_FLAG_ACTIVE);
+               if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&focus->base);
+       }
+
+
+       /* XXX: If we get a modifier event immediately before the focus,
+        *      we should try to keep the same serial. */
+       notify_keyboard_focus_in(&input->base, keys,
+                                STATE_UPDATE_AUTOMATIC);
+}
+
+static void
+input_handle_keyboard_leave(void *data,
+                           struct wl_keyboard *keyboard,
+                           uint32_t serial,
+                           struct wl_surface *surface)
+{
+       struct wayland_input *input = data;
+       struct wayland_output *focus;
+
+       notify_keyboard_focus_out(&input->base);
+
+       focus = input->keyboard_focus;
+       if (!focus)
+               return;
+
+       focus->keyboard_count--;
+       if (!focus->keyboard_count && focus->frame) {
+               frame_unset_flag(focus->frame, FRAME_FLAG_ACTIVE);
+               if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&focus->base);
+       }
+
+       input->keyboard_focus = NULL;
+}
+
+static void
+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;
+
+       input->key_serial = serial;
+       notify_key(&input->base, time, key,
+                  state ? WL_KEYBOARD_KEY_STATE_PRESSED :
+                          WL_KEYBOARD_KEY_STATE_RELEASED,
+                  input->keyboard_state_update);
+}
+
+static void
+input_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
+                      uint32_t serial_in, uint32_t mods_depressed,
+                      uint32_t mods_latched, uint32_t mods_locked,
+                      uint32_t group)
+{
+       struct weston_keyboard *keyboard;
+       struct wayland_input *input = data;
+       struct wayland_backend *b = input->backend;
+       uint32_t serial_out;
+
+       /* If we get a key event followed by a modifier event with the
+        * same serial number, then we try to preserve those semantics by
+        * reusing the same serial number on the way out too. */
+       if (serial_in == input->key_serial)
+               serial_out = wl_display_get_serial(b->compositor->wl_display);
+       else
+               serial_out = wl_display_next_serial(b->compositor->wl_display);
+
+       keyboard = weston_seat_get_keyboard(&input->base);
+       xkb_state_update_mask(keyboard->xkb_state.state,
+                             mods_depressed, mods_latched,
+                             mods_locked, 0, 0, group);
+       notify_modifiers(&input->base, serial_out);
+}
+
+static void
+input_handle_repeat_info(void *data, struct wl_keyboard *keyboard,
+                        int32_t rate, int32_t delay)
+{
+       struct wayland_input *input = data;
+       struct wayland_backend *b = input->backend;
+
+       b->compositor->kb_repeat_rate = rate;
+       b->compositor->kb_repeat_delay = delay;
+}
+
+static const struct wl_keyboard_listener keyboard_listener = {
+       input_handle_keymap,
+       input_handle_keyboard_enter,
+       input_handle_keyboard_leave,
+       input_handle_key,
+       input_handle_modifiers,
+       input_handle_repeat_info,
+};
+
+static void
+input_handle_touch_down(void *data, struct wl_touch *wl_touch,
+                       uint32_t serial, uint32_t time,
+                       struct wl_surface *surface, int32_t id,
+                       wl_fixed_t fixed_x, wl_fixed_t fixed_y)
+{
+       struct wayland_input *input = data;
+       struct wayland_output *output;
+       enum theme_location location;
+       bool first_touch;
+       int32_t fx, fy;
+       double x, y;
+
+       x = wl_fixed_to_double(fixed_x);
+       y = wl_fixed_to_double(fixed_y);
+
+       first_touch = (input->touch_points == 0);
+       input->touch_points++;
+
+       input->touch_focus = wl_surface_get_user_data(surface);
+       output = input->touch_focus;
+       if (!first_touch && !input->touch_active)
+               return;
+
+       if (output->frame) {
+               location = frame_touch_down(output->frame, input, id, x, y);
+
+               frame_interior(output->frame, &fx, &fy, NULL, NULL);
+               x -= fx;
+               y -= fy;
+
+               if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&output->base);
+
+               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);
+                       frame_status_clear(output->frame,
+                                          FRAME_STATUS_MOVE);
+                       return;
+               }
+
+               if (first_touch && location != THEME_LOCATION_CLIENT_AREA)
+                       return;
+       }
+
+       weston_output_transform_coordinate(&output->base, x, y, &x, &y);
+
+       notify_touch(&input->base, time, id, x, y, WL_TOUCH_DOWN);
+       input->touch_active = true;
+}
+
+static void
+input_handle_touch_up(void *data, struct wl_touch *wl_touch,
+                     uint32_t serial, uint32_t time, int32_t id)
+{
+       struct wayland_input *input = data;
+       struct wayland_output *output = input->touch_focus;
+       bool active = input->touch_active;
+
+       input->touch_points--;
+       if (input->touch_points == 0) {
+               input->touch_focus = NULL;
+               input->touch_active = false;
+       }
+
+       if (!output)
+               return;
+
+       if (output->frame) {
+               frame_touch_up(output->frame, input, id);
+
+               if (frame_status(output->frame) & FRAME_STATUS_CLOSE) {
+                       wayland_output_destroy(&output->base);
+                       input->touch_focus = NULL;
+                       input->keyboard_focus = NULL;
+                       if (wl_list_empty(&input->backend->compositor->output_list))
+                               weston_compositor_exit(input->backend->compositor);
+
+                       return;
+               }
+               if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
+                       weston_output_schedule_repaint(&output->base);
+       }
+
+       if (active)
+               notify_touch(&input->base, time, id, 0, 0, WL_TOUCH_UP);
+}
+
+static void
+input_handle_touch_motion(void *data, struct wl_touch *wl_touch,
+                        uint32_t time, int32_t id,
+                        wl_fixed_t fixed_x, wl_fixed_t fixed_y)
+{
+       struct wayland_input *input = data;
+       struct wayland_output *output = input->touch_focus;
+       int32_t fx, fy;
+       double x, y;
+
+       x = wl_fixed_to_double(fixed_x);
+       y = wl_fixed_to_double(fixed_y);
+
+       if (!output || !input->touch_active)
+               return;
+
+       if (output->frame) {
+               frame_interior(output->frame, &fx, &fy, NULL, NULL);
+               x -= fx;
+               y -= fy;
+       }
+
+       weston_output_transform_coordinate(&output->base, x, y, &x, &y);
+
+       notify_touch(&input->base, time, id, x, y, WL_TOUCH_MOTION);
+}
+
+static void
+input_handle_touch_frame(void *data, struct wl_touch *wl_touch)
+{
+       struct wayland_input *input = data;
+
+       if (!input->touch_focus || !input->touch_active)
+               return;
+
+       notify_touch_frame(&input->base);
+}
+
+static void
+input_handle_touch_cancel(void *data, struct wl_touch *wl_touch)
+{
+       struct wayland_input *input = data;
+
+       if (!input->touch_focus || !input->touch_active)
+               return;
+
+       notify_touch_cancel(&input->base);
+}
+
+static const struct wl_touch_listener touch_listener = {
+       input_handle_touch_down,
+       input_handle_touch_up,
+       input_handle_touch_motion,
+       input_handle_touch_frame,
+       input_handle_touch_cancel,
+};
+
+
+static void
+input_handle_capabilities(void *data, struct wl_seat *seat,
+                         enum wl_seat_capability caps)
+{
+       struct wayland_input *input = data;
+
+       if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->parent.pointer) {
+               input->parent.pointer = wl_seat_get_pointer(seat);
+               wl_pointer_set_user_data(input->parent.pointer, input);
+               wl_pointer_add_listener(input->parent.pointer,
+                                       &pointer_listener, input);
+               weston_seat_init_pointer(&input->base);
+       } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->parent.pointer) {
+               if (input->seat_version >= WL_POINTER_RELEASE_SINCE_VERSION)
+                       wl_pointer_release(input->parent.pointer);
+               else
+                       wl_pointer_destroy(input->parent.pointer);
+               input->parent.pointer = NULL;
+               weston_seat_release_pointer(&input->base);
+       }
+
+       if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->parent.keyboard) {
+               input->parent.keyboard = wl_seat_get_keyboard(seat);
+               wl_keyboard_set_user_data(input->parent.keyboard, input);
+               wl_keyboard_add_listener(input->parent.keyboard,
+                                        &keyboard_listener, input);
+       } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->parent.keyboard) {
+               if (input->seat_version >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
+                       wl_keyboard_release(input->parent.keyboard);
+               else
+                       wl_keyboard_destroy(input->parent.keyboard);
+               input->parent.keyboard = NULL;
+               weston_seat_release_keyboard(&input->base);
+       }
+
+       if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->parent.touch) {
+               input->parent.touch = wl_seat_get_touch(seat);
+               wl_touch_set_user_data(input->parent.touch, input);
+               wl_touch_add_listener(input->parent.touch,
+                                     &touch_listener, input);
+               weston_seat_init_touch(&input->base);
+       } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->parent.touch) {
+               if (input->seat_version >= WL_TOUCH_RELEASE_SINCE_VERSION)
+                       wl_touch_release(input->parent.touch);
+               else
+                       wl_touch_destroy(input->parent.touch);
+               input->parent.touch = NULL;
+               weston_seat_release_touch(&input->base);
+       }
+}
+
+static void
+input_handle_name(void *data, struct wl_seat *seat,
+                 const char *name)
+{
+}
+
+static const struct wl_seat_listener seat_listener = {
+       input_handle_capabilities,
+       input_handle_name,
+};
+
+static void
+display_add_seat(struct wayland_backend *b, uint32_t id, uint32_t available_version)
+{
+       struct wayland_input *input;
+       uint32_t version = MIN(available_version, 4);
+
+       input = zalloc(sizeof *input);
+       if (input == NULL)
+               return;
+
+       weston_seat_init(&input->base, b->compositor, "default");
+       input->backend = b;
+       input->parent.seat = wl_registry_bind(b->parent.registry, id,
+                                             &wl_seat_interface, version);
+       input->seat_version = version;
+       wl_list_insert(b->input_list.prev, &input->link);
+
+       wl_seat_add_listener(input->parent.seat, &seat_listener, input);
+       wl_seat_set_user_data(input->parent.seat, input);
+
+       input->parent.cursor.surface =
+               wl_compositor_create_surface(b->parent.compositor);
+
+       input->vert.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
+       input->horiz.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
+}
+
+static void
+wayland_parent_output_geometry(void *data, struct wl_output *output_proxy,
+                              int32_t x, int32_t y,
+                              int32_t physical_width, int32_t physical_height,
+                              int32_t subpixel, const char *make,
+                              const char *model, int32_t transform)
+{
+       struct wayland_parent_output *output = data;
+
+       output->x = x;
+       output->y = y;
+       output->physical.width = physical_width;
+       output->physical.height = physical_height;
+       output->physical.subpixel = subpixel;
+
+       free(output->physical.make);
+       output->physical.make = strdup(make);
+       free(output->physical.model);
+       output->physical.model = strdup(model);
+
+       output->transform = transform;
+}
+
+static struct weston_mode *
+find_mode(struct wl_list *list, int32_t width, int32_t height, uint32_t refresh)
+{
+       struct weston_mode *mode;
+
+       wl_list_for_each(mode, list, link) {
+               if (mode->width == width && mode->height == height &&
+                   mode->refresh == refresh)
+                       return mode;
+       }
+
+       mode = zalloc(sizeof *mode);
+       if (!mode)
+               return NULL;
+
+       mode->width = width;
+       mode->height = height;
+       mode->refresh = refresh;
+       wl_list_insert(list, &mode->link);
+
+       return mode;
+}
+
+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_mode *mode;
+
+       if (output->output) {
+               mode = find_mode(&output->output->base.mode_list,
+                                width, height, refresh);
+               if (!mode)
+                       return;
+               mode->flags = flags;
+               /* Do a mode-switch on current mode change? */
+       } else {
+               mode = find_mode(&output->mode_list, width, height, refresh);
+               if (!mode)
+                       return;
+               mode->flags = flags;
+               if (flags & WL_OUTPUT_MODE_CURRENT)
+                       output->current_mode = mode;
+               if (flags & WL_OUTPUT_MODE_PREFERRED)
+                       output->preferred_mode = mode;
+       }
+}
+
+static const struct wl_output_listener output_listener = {
+       wayland_parent_output_geometry,
+       wayland_parent_output_mode
+};
+
+static void
+wayland_backend_register_output(struct wayland_backend *b, uint32_t id)
+{
+       struct wayland_parent_output *output;
+
+       output = zalloc(sizeof *output);
+       if (!output)
+               return;
+
+       output->id = id;
+       output->global = wl_registry_bind(b->parent.registry, id,
+                                         &wl_output_interface, 1);
+       if (!output->global) {
+               free(output);
+               return;
+       }
+
+       wl_output_add_listener(output->global, &output_listener, output);
+
+       output->scale = 0;
+       output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
+       output->physical.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
+       wl_list_init(&output->mode_list);
+       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);
+       }
+}
+
+static void
+wayland_parent_output_destroy(struct wayland_parent_output *output)
+{
+       struct weston_mode *mode, *next;
+
+       if (output->output)
+               wayland_output_destroy(&output->output->base);
+
+       wl_output_destroy(output->global);
+       free(output->physical.make);
+       free(output->physical.model);
+
+       wl_list_for_each_safe(mode, next, &output->mode_list, link) {
+               wl_list_remove(&mode->link);
+               free(mode);
+       }
+}
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
+                      const char *interface, uint32_t version)
+{
+       struct wayland_backend *b = data;
+
+       if (strcmp(interface, "wl_compositor") == 0) {
+               b->parent.compositor =
+                       wl_registry_bind(registry, name,
+                                        &wl_compositor_interface, 1);
+       } else if (strcmp(interface, "wl_shell") == 0) {
+               b->parent.shell =
+                       wl_registry_bind(registry, name,
+                                        &wl_shell_interface, 1);
+       } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
+               b->parent.fshell =
+                       wl_registry_bind(registry, name,
+                                        &zwp_fullscreen_shell_v1_interface, 1);
+       } else if (strcmp(interface, "wl_seat") == 0) {
+               display_add_seat(b, name, version);
+       } else if (strcmp(interface, "wl_output") == 0) {
+               wayland_backend_register_output(b, name);
+       } else if (strcmp(interface, "wl_shm") == 0) {
+               b->parent.shm =
+                       wl_registry_bind(registry, name, &wl_shm_interface, 1);
+       }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+                             uint32_t name)
+{
+       struct wayland_backend *b = data;
+       struct wayland_parent_output *output;
+
+       wl_list_for_each(output, &b->parent.output_list, link)
+               if (output->id == name)
+                       wayland_parent_output_destroy(output);
+}
+
+static const struct wl_registry_listener registry_listener = {
+       registry_handle_global,
+       registry_handle_global_remove
+};
+
+static int
+wayland_backend_handle_event(int fd, uint32_t mask, void *data)
+{
+       struct wayland_backend *b = data;
+       int count = 0;
+
+       if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
+               weston_compositor_exit(b->compositor);
+               return 0;
+       }
+
+       if (mask & WL_EVENT_READABLE)
+               count = wl_display_dispatch(b->parent.wl_display);
+       if (mask & WL_EVENT_WRITABLE)
+               wl_display_flush(b->parent.wl_display);
+
+       if (mask == 0) {
+               count = wl_display_dispatch_pending(b->parent.wl_display);
+               wl_display_flush(b->parent.wl_display);
+       }
+
+       return count;
+}
+
+static void
+wayland_restore(struct weston_compositor *ec)
+{
+}
+
+static void
+wayland_destroy(struct weston_compositor *ec)
+{
+       struct wayland_backend *b = (struct wayland_backend *) ec->backend;
+
+       weston_compositor_shutdown(ec);
+
+       if (b->parent.shm)
+               wl_shm_destroy(b->parent.shm);
+
+       free(b);
+}
+
+static const char *left_ptrs[] = {
+       "left_ptr",
+       "default",
+       "top_left_arrow",
+       "left-arrow"
+};
+
+static void
+create_cursor(struct wayland_backend *b,
+             struct weston_wayland_backend_config *config)
+{
+       unsigned int i;
+
+       b->cursor_theme = wl_cursor_theme_load(config->cursor_theme,
+                                              config->cursor_size,
+                                              b->parent.shm);
+       if (!b->cursor_theme) {
+               fprintf(stderr, "could not load cursor theme\n");
+               return;
+       }
+
+       b->cursor = NULL;
+       for (i = 0; !b->cursor && i < ARRAY_LENGTH(left_ptrs); ++i)
+               b->cursor = wl_cursor_theme_get_cursor(b->cursor_theme,
+                                                      left_ptrs[i]);
+       if (!b->cursor) {
+               fprintf(stderr, "could not load left cursor\n");
+               return;
+       }
+}
+
+static void
+fullscreen_binding(struct weston_keyboard *keyboard, uint32_t time,
+                  uint32_t key, void *data)
+{
+       struct wayland_backend *b = data;
+       struct wayland_input *input = NULL;
+
+       wl_list_for_each(input, &b->input_list, link)
+               if (&input->base == keyboard->seat)
+                       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_backend *
+wayland_backend_create(struct weston_compositor *compositor,
+                      struct weston_wayland_backend_config *new_config)
+{
+       struct wayland_backend *b;
+       struct wl_event_loop *loop;
+       int fd;
+
+       b = zalloc(sizeof *b);
+       if (b == NULL)
+               return NULL;
+
+       b->compositor = compositor;
+       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");
+               goto err_compositor;
+       }
+
+       wl_list_init(&b->parent.output_list);
+       wl_list_init(&b->input_list);
+       b->parent.registry = wl_display_get_registry(b->parent.wl_display);
+       wl_registry_add_listener(b->parent.registry, &registry_listener, b);
+       wl_display_roundtrip(b->parent.wl_display);
+
+       create_cursor(b, new_config);
+
+       b->use_pixman = new_config->use_pixman;
+
+       if (!b->use_pixman) {
+               gl_renderer = weston_load_module("gl-renderer.so",
+                                                "gl_renderer_interface");
+               if (!gl_renderer)
+                       b->use_pixman = 1;
+       }
+
+       if (!b->use_pixman) {
+               if (gl_renderer->create(compositor,
+                                       EGL_PLATFORM_WAYLAND_KHR,
+                                       b->parent.wl_display,
+                                       gl_renderer->alpha_attribs,
+                                       NULL,
+                                       0) < 0) {
+                       weston_log("Failed to initialize the GL renderer; "
+                                  "falling back to pixman.\n");
+                       b->use_pixman = 1;
+               }
+       }
+
+       if (b->use_pixman) {
+               if (pixman_renderer_init(compositor) < 0) {
+                       weston_log("Failed to initialize pixman renderer\n");
+                       goto err_display;
+               }
+       }
+
+       b->base.destroy = wayland_destroy;
+       b->base.restore = wayland_restore;
+
+       loop = wl_display_get_event_loop(compositor->wl_display);
+
+       fd = wl_display_get_fd(b->parent.wl_display);
+       b->parent.wl_source =
+               wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
+                                    wayland_backend_handle_event, b);
+       if (b->parent.wl_source == NULL)
+               goto err_display;
+
+       wl_event_source_check(b->parent.wl_source);
+
+       if (compositor->renderer->import_dmabuf) {
+               if (linux_dmabuf_setup(compositor) < 0)
+                       weston_log("Error: initializing dmabuf "
+                                  "support failed.\n");
+       }
+
+       compositor->backend = &b->base;
+       return b;
+err_display:
+       wl_display_disconnect(b->parent.wl_display);
+err_compositor:
+       weston_compositor_shutdown(compositor);
+       free(b);
+       return NULL;
+}
+
+static void
+wayland_backend_destroy(struct wayland_backend *b)
+{
+       wl_display_disconnect(b->parent.wl_display);
+
+       if (b->theme)
+               theme_destroy(b->theme);
+       if (b->frame_device)
+               cairo_device_destroy(b->frame_device);
+       wl_cursor_theme_destroy(b->cursor_theme);
+
+       weston_compositor_shutdown(b->compositor);
+       free(b);
+}
+
+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)
+{
+       struct wayland_backend *b;
+       struct wayland_output *output;
+       struct wayland_parent_output *poutput;
+       struct weston_wayland_backend_config new_config;
+       int x, count;
+
+       if (config_base == NULL ||
+           config_base->struct_version != WESTON_WAYLAND_BACKEND_CONFIG_VERSION ||
+           config_base->struct_size > sizeof(struct weston_wayland_backend_config)) {
+               weston_log("wayland backend config structure is invalid\n");
+               return -1;
+       }
+
+       config_init_to_defaults(&new_config);
+       memcpy(&new_config, config_base, config_base->struct_size);
+
+       b = wayland_backend_create(compositor, &new_config);
+
+       if (!b)
+               return -1;
+
+       if (new_config.sprawl || b->parent.fshell) {
+               b->sprawl_across_outputs = 1;
+               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);
+
+               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)
+                       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;
+
+               x += output->base.width;
+       }
+
+       weston_compositor_add_key_binding(compositor, KEY_F,
+                                         MODIFIER_CTRL | MODIFIER_ALT,
+                                         fullscreen_binding, b);
+       return 0;
+
+err_outputs:
+       wayland_backend_destroy(b);
+       return -1;
+}
diff --git a/libweston/compositor-wayland.h b/libweston/compositor-wayland.h
new file mode 100644 (file)
index 0000000..de69b98
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright © 2016 Benoit Gschwind
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_COMPOSITOR_WAYLAND_H
+#define WESTON_COMPOSITOR_WAYLAND_H
+
+#include "compositor.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define WESTON_WAYLAND_BACKEND_CONFIG_VERSION 1
+
+struct weston_wayland_backend_output_config {
+       int width;
+       int height;
+       char *name;
+       uint32_t transform;
+       int32_t scale;
+};
+
+struct weston_wayland_backend_config {
+       struct weston_backend_config base;
+       int use_pixman;
+       int sprawl;
+       char *display_name;
+       int fullscreen;
+       char *cursor_theme;
+       int cursor_size;
+       int num_outputs;
+       struct weston_wayland_backend_output_config *outputs;
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WESTON_COMPOSITOR_WAYLAND_H */
diff --git a/libweston/compositor-x11.c b/libweston/compositor-x11.c
new file mode 100644 (file)
index 0000000..5e46e68
--- /dev/null
@@ -0,0 +1,1720 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/shm.h>
+#include <linux/input.h>
+
+#include <xcb/xcb.h>
+#include <xcb/shm.h>
+#ifdef HAVE_XCB_XKB
+#include <xcb/xkb.h>
+#endif
+
+#include <X11/Xlib.h>
+#include <X11/Xlib-xcb.h>
+
+#include <xkbcommon/xkbcommon.h>
+
+#include "compositor.h"
+#include "compositor-x11.h"
+#include "shared/config-parser.h"
+#include "shared/helpers.h"
+#include "shared/image-loader.h"
+#include "gl-renderer.h"
+#include "pixman-renderer.h"
+#include "presentation-time-server-protocol.h"
+#include "linux-dmabuf.h"
+
+#define DEFAULT_AXIS_STEP_DISTANCE 10
+
+struct x11_backend {
+       struct weston_backend    base;
+       struct weston_compositor *compositor;
+
+       Display                 *dpy;
+       xcb_connection_t        *conn;
+       xcb_screen_t            *screen;
+       xcb_cursor_t             null_cursor;
+       struct wl_array          keys;
+       struct wl_event_source  *xcb_source;
+       struct xkb_keymap       *xkb_keymap;
+       unsigned int             has_xkb;
+       uint8_t                  xkb_event_base;
+       int                      use_pixman;
+
+       int                      has_net_wm_state_fullscreen;
+
+       /* We could map multi-pointer X to multiple wayland seats, but
+        * for now we only support core X input. */
+       struct weston_seat               core_seat;
+       double                           prev_x;
+       double                           prev_y;
+
+       struct {
+               xcb_atom_t               wm_protocols;
+               xcb_atom_t               wm_normal_hints;
+               xcb_atom_t               wm_size_hints;
+               xcb_atom_t               wm_delete_window;
+               xcb_atom_t               wm_class;
+               xcb_atom_t               net_wm_name;
+               xcb_atom_t               net_supporting_wm_check;
+               xcb_atom_t               net_supported;
+               xcb_atom_t               net_wm_icon;
+               xcb_atom_t               net_wm_state;
+               xcb_atom_t               net_wm_state_fullscreen;
+               xcb_atom_t               string;
+               xcb_atom_t               utf8_string;
+               xcb_atom_t               cardinal;
+               xcb_atom_t               xkb_names;
+       } atom;
+};
+
+struct x11_output {
+       struct weston_output    base;
+
+       xcb_window_t            window;
+       struct weston_mode      mode;
+       struct wl_event_source *finish_frame_timer;
+
+       xcb_gc_t                gc;
+       xcb_shm_seg_t           segment;
+       pixman_image_t         *hw_surface;
+       int                     shm_id;
+       void                   *buf;
+       uint8_t                 depth;
+       int32_t                 scale;
+};
+
+struct window_delete_data {
+       struct x11_backend      *backend;
+       xcb_window_t            window;
+};
+
+struct gl_renderer_interface *gl_renderer;
+
+static xcb_screen_t *
+x11_compositor_get_default_screen(struct x11_backend *b)
+{
+       xcb_screen_iterator_t iter;
+       int i, screen_nbr = XDefaultScreen(b->dpy);
+
+       iter = xcb_setup_roots_iterator(xcb_get_setup(b->conn));
+       for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
+               if (i == screen_nbr)
+                       return iter.data;
+
+       return xcb_setup_roots_iterator(xcb_get_setup(b->conn)).data;
+}
+
+static struct xkb_keymap *
+x11_backend_get_keymap(struct x11_backend *b)
+{
+       xcb_get_property_cookie_t cookie;
+       xcb_get_property_reply_t *reply;
+       struct xkb_rule_names names;
+       struct xkb_keymap *ret;
+       const char *value_all, *value_part;
+       int length_all, length_part;
+
+       memset(&names, 0, sizeof(names));
+
+       cookie = xcb_get_property(b->conn, 0, b->screen->root,
+                                 b->atom.xkb_names, b->atom.string, 0, 1024);
+       reply = xcb_get_property_reply(b->conn, cookie, NULL);
+       if (reply == NULL)
+               return NULL;
+
+       value_all = xcb_get_property_value(reply);
+       length_all = xcb_get_property_value_length(reply);
+       value_part = value_all;
+
+#define copy_prop_value(to) \
+       length_part = strlen(value_part); \
+       if (value_part + length_part < (value_all + length_all) && \
+           length_part > 0) \
+               names.to = value_part; \
+       value_part += length_part + 1;
+
+       copy_prop_value(rules);
+       copy_prop_value(model);
+       copy_prop_value(layout);
+       copy_prop_value(variant);
+       copy_prop_value(options);
+#undef copy_prop_value
+
+       ret = xkb_keymap_new_from_names(b->compositor->xkb_context, &names, 0);
+
+       free(reply);
+       return ret;
+}
+
+static uint32_t
+get_xkb_mod_mask(struct x11_backend *b, uint32_t in)
+{
+       struct weston_keyboard *keyboard =
+               weston_seat_get_keyboard(&b->core_seat);
+       struct weston_xkb_info *info = keyboard->xkb_info;
+       uint32_t ret = 0;
+
+       if ((in & ShiftMask) && info->shift_mod != XKB_MOD_INVALID)
+               ret |= (1 << info->shift_mod);
+       if ((in & LockMask) && info->caps_mod != XKB_MOD_INVALID)
+               ret |= (1 << info->caps_mod);
+       if ((in & ControlMask) && info->ctrl_mod != XKB_MOD_INVALID)
+               ret |= (1 << info->ctrl_mod);
+       if ((in & Mod1Mask) && info->alt_mod != XKB_MOD_INVALID)
+               ret |= (1 << info->alt_mod);
+       if ((in & Mod2Mask) && info->mod2_mod != XKB_MOD_INVALID)
+               ret |= (1 << info->mod2_mod);
+       if ((in & Mod3Mask) && info->mod3_mod != XKB_MOD_INVALID)
+               ret |= (1 << info->mod3_mod);
+       if ((in & Mod4Mask) && info->super_mod != XKB_MOD_INVALID)
+               ret |= (1 << info->super_mod);
+       if ((in & Mod5Mask) && info->mod5_mod != XKB_MOD_INVALID)
+               ret |= (1 << info->mod5_mod);
+
+       return ret;
+}
+
+static void
+x11_backend_setup_xkb(struct x11_backend *b)
+{
+#ifndef HAVE_XCB_XKB
+       weston_log("XCB-XKB not available during build\n");
+       b->has_xkb = 0;
+       b->xkb_event_base = 0;
+       return;
+#else
+       struct weston_keyboard *keyboard;
+       const xcb_query_extension_reply_t *ext;
+       xcb_generic_error_t *error;
+       xcb_void_cookie_t select;
+       xcb_xkb_use_extension_cookie_t use_ext;
+       xcb_xkb_use_extension_reply_t *use_ext_reply;
+       xcb_xkb_per_client_flags_cookie_t pcf;
+       xcb_xkb_per_client_flags_reply_t *pcf_reply;
+       xcb_xkb_get_state_cookie_t state;
+       xcb_xkb_get_state_reply_t *state_reply;
+       uint32_t values[1] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
+
+       b->has_xkb = 0;
+       b->xkb_event_base = 0;
+
+       ext = xcb_get_extension_data(b->conn, &xcb_xkb_id);
+       if (!ext) {
+               weston_log("XKB extension not available on host X11 server\n");
+               return;
+       }
+       b->xkb_event_base = ext->first_event;
+
+       select = xcb_xkb_select_events_checked(b->conn,
+                                              XCB_XKB_ID_USE_CORE_KBD,
+                                              XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
+                                              0,
+                                              XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
+                                              0,
+                                              0,
+                                              NULL);
+       error = xcb_request_check(b->conn, select);
+       if (error) {
+               weston_log("error: failed to select for XKB state events\n");
+               free(error);
+               return;
+       }
+
+       use_ext = xcb_xkb_use_extension(b->conn,
+                                       XCB_XKB_MAJOR_VERSION,
+                                       XCB_XKB_MINOR_VERSION);
+       use_ext_reply = xcb_xkb_use_extension_reply(b->conn, use_ext, NULL);
+       if (!use_ext_reply) {
+               weston_log("couldn't start using XKB extension\n");
+               return;
+       }
+
+       if (!use_ext_reply->supported) {
+               weston_log("XKB extension version on the server is too old "
+                          "(want %d.%d, has %d.%d)\n",
+                          XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION,
+                          use_ext_reply->serverMajor, use_ext_reply->serverMinor);
+               free(use_ext_reply);
+               return;
+       }
+       free(use_ext_reply);
+
+       pcf = xcb_xkb_per_client_flags(b->conn,
+                                      XCB_XKB_ID_USE_CORE_KBD,
+                                      XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
+                                      XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
+                                      0,
+                                      0,
+                                      0);
+       pcf_reply = xcb_xkb_per_client_flags_reply(b->conn, pcf, NULL);
+       if (!pcf_reply ||
+           !(pcf_reply->value & XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT)) {
+               weston_log("failed to set XKB per-client flags, not using "
+                          "detectable repeat\n");
+               free(pcf_reply);
+               return;
+       }
+       free(pcf_reply);
+
+       state = xcb_xkb_get_state(b->conn, XCB_XKB_ID_USE_CORE_KBD);
+       state_reply = xcb_xkb_get_state_reply(b->conn, state, NULL);
+       if (!state_reply) {
+               weston_log("failed to get initial XKB state\n");
+               return;
+       }
+
+       keyboard = weston_seat_get_keyboard(&b->core_seat);
+       xkb_state_update_mask(keyboard->xkb_state.state,
+                             get_xkb_mod_mask(b, state_reply->baseMods),
+                             get_xkb_mod_mask(b, state_reply->latchedMods),
+                             get_xkb_mod_mask(b, state_reply->lockedMods),
+                             0,
+                             0,
+                             state_reply->group);
+
+       free(state_reply);
+
+       xcb_change_window_attributes(b->conn, b->screen->root,
+                                    XCB_CW_EVENT_MASK, values);
+
+       b->has_xkb = 1;
+#endif
+}
+
+#ifdef HAVE_XCB_XKB
+static void
+update_xkb_keymap(struct x11_backend *b)
+{
+       struct xkb_keymap *keymap;
+
+       keymap = x11_backend_get_keymap(b);
+       if (!keymap) {
+               weston_log("failed to get XKB keymap\n");
+               return;
+       }
+       weston_seat_update_keymap(&b->core_seat, keymap);
+       xkb_keymap_unref(keymap);
+}
+#endif
+
+static int
+x11_input_create(struct x11_backend *b, int no_input)
+{
+       struct xkb_keymap *keymap;
+
+       weston_seat_init(&b->core_seat, b->compositor, "default");
+
+       if (no_input)
+               return 0;
+
+       weston_seat_init_pointer(&b->core_seat);
+
+       keymap = x11_backend_get_keymap(b);
+       if (weston_seat_init_keyboard(&b->core_seat, keymap) < 0)
+               return -1;
+       xkb_keymap_unref(keymap);
+
+       x11_backend_setup_xkb(b);
+
+       return 0;
+}
+
+static void
+x11_input_destroy(struct x11_backend *b)
+{
+       weston_seat_release(&b->core_seat);
+}
+
+static void
+x11_output_start_repaint_loop(struct weston_output *output)
+{
+       struct timespec ts;
+
+       weston_compositor_read_presentation_clock(output->compositor, &ts);
+       weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
+}
+
+static int
+x11_output_repaint_gl(struct weston_output *output_base,
+                     pixman_region32_t *damage)
+{
+       struct x11_output *output = (struct x11_output *)output_base;
+       struct weston_compositor *ec = output->base.compositor;
+
+       ec->renderer->repaint_output(output_base, damage);
+
+       pixman_region32_subtract(&ec->primary_plane.damage,
+                                &ec->primary_plane.damage, damage);
+
+       wl_event_source_timer_update(output->finish_frame_timer, 10);
+       return 0;
+}
+
+static void
+set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region)
+{
+       struct x11_output *output = (struct x11_output *)output_base;
+       struct weston_compositor *ec = output->base.compositor;
+       struct x11_backend *b = (struct x11_backend *)ec->backend;
+       pixman_region32_t transformed_region;
+       pixman_box32_t *rects;
+       xcb_rectangle_t *output_rects;
+       xcb_void_cookie_t cookie;
+       int nrects, i;
+       xcb_generic_error_t *err;
+
+       pixman_region32_init(&transformed_region);
+       pixman_region32_copy(&transformed_region, region);
+       pixman_region32_translate(&transformed_region,
+                                 -output_base->x, -output_base->y);
+       weston_transformed_region(output_base->width, output_base->height,
+                                 output_base->transform,
+                                 output_base->current_scale,
+                                 &transformed_region, &transformed_region);
+
+       rects = pixman_region32_rectangles(&transformed_region, &nrects);
+       output_rects = calloc(nrects, sizeof(xcb_rectangle_t));
+
+       if (output_rects == NULL) {
+               pixman_region32_fini(&transformed_region);
+               return;
+       }
+
+       for (i = 0; i < nrects; i++) {
+               output_rects[i].x = rects[i].x1;
+               output_rects[i].y = rects[i].y1;
+               output_rects[i].width = rects[i].x2 - rects[i].x1;
+               output_rects[i].height = rects[i].y2 - rects[i].y1;
+       }
+
+       pixman_region32_fini(&transformed_region);
+
+       cookie = xcb_set_clip_rectangles_checked(b->conn, XCB_CLIP_ORDERING_UNSORTED,
+                                       output->gc,
+                                       0, 0, nrects,
+                                       output_rects);
+       err = xcb_request_check(b->conn, cookie);
+       if (err != NULL) {
+               weston_log("Failed to set clip rects, err: %d\n", err->error_code);
+               free(err);
+       }
+       free(output_rects);
+}
+
+
+static int
+x11_output_repaint_shm(struct weston_output *output_base,
+                      pixman_region32_t *damage)
+{
+       struct x11_output *output = (struct x11_output *)output_base;
+       struct weston_compositor *ec = output->base.compositor;
+       struct x11_backend *b = (struct x11_backend *)ec->backend;
+       xcb_void_cookie_t cookie;
+       xcb_generic_error_t *err;
+
+       pixman_renderer_output_set_buffer(output_base, output->hw_surface);
+       ec->renderer->repaint_output(output_base, damage);
+
+       pixman_region32_subtract(&ec->primary_plane.damage,
+                                &ec->primary_plane.damage, damage);
+       set_clip_for_output(output_base, damage);
+       cookie = xcb_shm_put_image_checked(b->conn, output->window, output->gc,
+                                       pixman_image_get_width(output->hw_surface),
+                                       pixman_image_get_height(output->hw_surface),
+                                       0, 0,
+                                       pixman_image_get_width(output->hw_surface),
+                                       pixman_image_get_height(output->hw_surface),
+                                       0, 0, output->depth, XCB_IMAGE_FORMAT_Z_PIXMAP,
+                                       0, output->segment, 0);
+       err = xcb_request_check(b->conn, cookie);
+       if (err != NULL) {
+               weston_log("Failed to put shm image, err: %d\n", err->error_code);
+               free(err);
+       }
+
+       wl_event_source_timer_update(output->finish_frame_timer, 10);
+       return 0;
+}
+
+static int
+finish_frame_handler(void *data)
+{
+       struct x11_output *output = data;
+       struct timespec ts;
+
+       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
+       weston_output_finish_frame(&output->base, &ts, 0);
+
+       return 1;
+}
+
+static void
+x11_output_deinit_shm(struct x11_backend *b, struct x11_output *output)
+{
+       xcb_void_cookie_t cookie;
+       xcb_generic_error_t *err;
+       xcb_free_gc(b->conn, output->gc);
+
+       pixman_image_unref(output->hw_surface);
+       output->hw_surface = NULL;
+       cookie = xcb_shm_detach_checked(b->conn, output->segment);
+       err = xcb_request_check(b->conn, cookie);
+       if (err) {
+               weston_log("xcb_shm_detach failed, error %d\n", err->error_code);
+               free(err);
+       }
+       shmdt(output->buf);
+}
+
+static void
+x11_output_destroy(struct weston_output *output_base)
+{
+       struct x11_output *output = (struct x11_output *)output_base;
+       struct x11_backend *backend =
+               (struct x11_backend *)output->base.compositor->backend;
+
+       wl_event_source_remove(output->finish_frame_timer);
+
+       if (backend->use_pixman) {
+               pixman_renderer_output_destroy(output_base);
+               x11_output_deinit_shm(backend, output);
+       } else
+               gl_renderer->output_destroy(output_base);
+
+       xcb_destroy_window(backend->conn, output->window);
+
+       weston_output_destroy(&output->base);
+
+       free(output);
+}
+
+static void
+x11_output_set_wm_protocols(struct x11_backend *b,
+                           struct x11_output *output)
+{
+       xcb_atom_t list[1];
+
+       list[0] = b->atom.wm_delete_window;
+       xcb_change_property (b->conn,
+                            XCB_PROP_MODE_REPLACE,
+                            output->window,
+                            b->atom.wm_protocols,
+                            XCB_ATOM_ATOM,
+                            32,
+                            ARRAY_LENGTH(list),
+                            list);
+}
+
+struct wm_normal_hints {
+       uint32_t flags;
+       uint32_t pad[4];
+       int32_t min_width, min_height;
+       int32_t max_width, max_height;
+       int32_t width_inc, height_inc;
+       int32_t min_aspect_x, min_aspect_y;
+       int32_t max_aspect_x, max_aspect_y;
+       int32_t base_width, base_height;
+       int32_t win_gravity;
+};
+
+#define WM_NORMAL_HINTS_MIN_SIZE       16
+#define WM_NORMAL_HINTS_MAX_SIZE       32
+
+static void
+x11_output_set_icon(struct x11_backend *b,
+                   struct x11_output *output, const char *filename)
+{
+       uint32_t *icon;
+       int32_t width, height;
+       pixman_image_t *image;
+
+       image = load_image(filename);
+       if (!image)
+               return;
+       width = pixman_image_get_width(image);
+       height = pixman_image_get_height(image);
+       icon = malloc(width * height * 4 + 8);
+       if (!icon) {
+               pixman_image_unref(image);
+               return;
+       }
+
+       icon[0] = width;
+       icon[1] = height;
+       memcpy(icon + 2, pixman_image_get_data(image), width * height * 4);
+       xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
+                           b->atom.net_wm_icon, b->atom.cardinal, 32,
+                           width * height + 2, icon);
+       free(icon);
+       pixman_image_unref(image);
+}
+
+static void
+x11_output_wait_for_map(struct x11_backend *b, struct x11_output *output)
+{
+       xcb_map_notify_event_t *map_notify;
+       xcb_configure_notify_event_t *configure_notify;
+       xcb_generic_event_t *event;
+       int mapped = 0, configured = 0;
+       uint8_t response_type;
+
+       /* This isn't the nicest way to do this.  Ideally, we could
+        * just go back to the main loop and once we get the configure
+        * notify, we add the output to the compositor.  While we do
+        * support output hotplug, we can't start up with no outputs.
+        * We could add the output and then resize once we get the
+        * configure notify, but we don't want to start up and
+        * immediately resize the output.
+        *
+        * Also, some window managers don't give us our final
+        * fullscreen size before map_notify, so if we don't get a
+        * configure_notify before map_notify, we just wait for the
+        * first one and hope that's our size. */
+
+       xcb_flush(b->conn);
+
+       while (!mapped || !configured) {
+               event = xcb_wait_for_event(b->conn);
+               response_type = event->response_type & ~0x80;
+
+               switch (response_type) {
+               case XCB_MAP_NOTIFY:
+                       map_notify = (xcb_map_notify_event_t *) event;
+                       if (map_notify->window == output->window)
+                               mapped = 1;
+                       break;
+
+               case XCB_CONFIGURE_NOTIFY:
+                       configure_notify =
+                               (xcb_configure_notify_event_t *) event;
+
+
+                       if (configure_notify->width % output->scale != 0 ||
+                           configure_notify->height % output->scale != 0)
+                               weston_log("Resolution is not a multiple of screen size, rounding\n");
+                       output->mode.width = configure_notify->width;
+                       output->mode.height = configure_notify->height;
+                       configured = 1;
+                       break;
+               }
+       }
+}
+
+static xcb_visualtype_t *
+find_visual_by_id(xcb_screen_t *screen,
+                  xcb_visualid_t id)
+{
+       xcb_depth_iterator_t i;
+       xcb_visualtype_iterator_t j;
+       for (i = xcb_screen_allowed_depths_iterator(screen);
+            i.rem;
+            xcb_depth_next(&i)) {
+               for (j = xcb_depth_visuals_iterator(i.data);
+                    j.rem;
+                    xcb_visualtype_next(&j)) {
+                       if (j.data->visual_id == id)
+                               return j.data;
+               }
+       }
+       return 0;
+}
+
+static uint8_t
+get_depth_of_visual(xcb_screen_t *screen,
+                  xcb_visualid_t id)
+{
+       xcb_depth_iterator_t i;
+       xcb_visualtype_iterator_t j;
+       for (i = xcb_screen_allowed_depths_iterator(screen);
+            i.rem;
+            xcb_depth_next(&i)) {
+               for (j = xcb_depth_visuals_iterator(i.data);
+                    j.rem;
+                    xcb_visualtype_next(&j)) {
+                       if (j.data->visual_id == id)
+                               return i.data->depth;
+               }
+       }
+       return 0;
+}
+
+static int
+x11_output_init_shm(struct x11_backend *b, struct x11_output *output,
+       int width, int height)
+{
+       xcb_visualtype_t *visual_type;
+       xcb_screen_t *screen;
+       xcb_format_iterator_t fmt;
+       xcb_void_cookie_t cookie;
+       xcb_generic_error_t *err;
+       const xcb_query_extension_reply_t *ext;
+       int bitsperpixel = 0;
+       pixman_format_code_t pixman_format;
+
+       /* Check if SHM is available */
+       ext = xcb_get_extension_data(b->conn, &xcb_shm_id);
+       if (ext == NULL || !ext->present) {
+               /* SHM is missing */
+               weston_log("SHM extension is not available\n");
+               errno = ENOENT;
+               return -1;
+       }
+
+       screen = x11_compositor_get_default_screen(b);
+       visual_type = find_visual_by_id(screen, screen->root_visual);
+       if (!visual_type) {
+               weston_log("Failed to lookup visual for root window\n");
+               errno = ENOENT;
+               return -1;
+       }
+       weston_log("Found visual, bits per value: %d, red_mask: %.8x, green_mask: %.8x, blue_mask: %.8x\n",
+               visual_type->bits_per_rgb_value,
+               visual_type->red_mask,
+               visual_type->green_mask,
+               visual_type->blue_mask);
+       output->depth = get_depth_of_visual(screen, screen->root_visual);
+       weston_log("Visual depth is %d\n", output->depth);
+
+       for (fmt = xcb_setup_pixmap_formats_iterator(xcb_get_setup(b->conn));
+            fmt.rem;
+            xcb_format_next(&fmt)) {
+               if (fmt.data->depth == output->depth) {
+                       bitsperpixel = fmt.data->bits_per_pixel;
+                       break;
+               }
+       }
+       weston_log("Found format for depth %d, bpp: %d\n",
+               output->depth, bitsperpixel);
+
+       if  (bitsperpixel == 32 &&
+            visual_type->red_mask == 0xff0000 &&
+            visual_type->green_mask == 0x00ff00 &&
+            visual_type->blue_mask == 0x0000ff) {
+               weston_log("Will use x8r8g8b8 format for SHM surfaces\n");
+               pixman_format = PIXMAN_x8r8g8b8;
+       } else if (bitsperpixel == 16 &&
+                  visual_type->red_mask == 0x00f800 &&
+                  visual_type->green_mask == 0x0007e0 &&
+                  visual_type->blue_mask == 0x00001f) {
+               weston_log("Will use r5g6b5 format for SHM surfaces\n");
+               pixman_format = PIXMAN_r5g6b5;
+       } else {
+               weston_log("Can't find appropriate format for SHM pixmap\n");
+               errno = ENOTSUP;
+               return -1;
+       }
+
+
+       /* Create SHM segment and attach it */
+       output->shm_id = shmget(IPC_PRIVATE, width * height * (bitsperpixel / 8), IPC_CREAT | S_IRWXU);
+       if (output->shm_id == -1) {
+               weston_log("x11shm: failed to allocate SHM segment\n");
+               return -1;
+       }
+       output->buf = shmat(output->shm_id, NULL, 0 /* read/write */);
+       if (-1 == (long)output->buf) {
+               weston_log("x11shm: failed to attach SHM segment\n");
+               return -1;
+       }
+       output->segment = xcb_generate_id(b->conn);
+       cookie = xcb_shm_attach_checked(b->conn, output->segment, output->shm_id, 1);
+       err = xcb_request_check(b->conn, cookie);
+       if (err) {
+               weston_log("x11shm: xcb_shm_attach error %d, op code %d, resource id %d\n",
+                          err->error_code, err->major_code, err->minor_code);
+               free(err);
+               return -1;
+       }
+
+       shmctl(output->shm_id, IPC_RMID, NULL);
+
+       /* Now create pixman image */
+       output->hw_surface = pixman_image_create_bits(pixman_format, width, height, output->buf,
+               width * (bitsperpixel / 8));
+
+       output->gc = xcb_generate_id(b->conn);
+       xcb_create_gc(b->conn, output->gc, output->window, 0, NULL);
+
+       return 0;
+}
+
+static struct x11_output *
+x11_backend_create_output(struct x11_backend *b, int x, int y,
+                            int width, int height, int fullscreen,
+                            int no_input, char *configured_name,
+                            uint32_t transform, int32_t scale)
+{
+       static const char name[] = "Weston Compositor";
+       static const char class[] = "weston-1\0Weston Compositor";
+       char title[32];
+       struct x11_output *output;
+       xcb_screen_t *screen;
+       struct wm_normal_hints normal_hints;
+       struct wl_event_loop *loop;
+       int output_width, output_height, width_mm, height_mm;
+       int ret;
+       uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
+       xcb_atom_t atom_list[1];
+       uint32_t values[2] = {
+               XCB_EVENT_MASK_EXPOSURE |
+               XCB_EVENT_MASK_STRUCTURE_NOTIFY,
+               0
+       };
+
+       output_width = width * scale;
+       output_height = height * scale;
+
+       if (configured_name)
+               sprintf(title, "%s - %s", name, configured_name);
+       else
+               strcpy(title, name);
+
+       if (!no_input)
+               values[0] |=
+                       XCB_EVENT_MASK_KEY_PRESS |
+                       XCB_EVENT_MASK_KEY_RELEASE |
+                       XCB_EVENT_MASK_BUTTON_PRESS |
+                       XCB_EVENT_MASK_BUTTON_RELEASE |
+                       XCB_EVENT_MASK_POINTER_MOTION |
+                       XCB_EVENT_MASK_ENTER_WINDOW |
+                       XCB_EVENT_MASK_LEAVE_WINDOW |
+                       XCB_EVENT_MASK_KEYMAP_STATE |
+                       XCB_EVENT_MASK_FOCUS_CHANGE;
+
+       output = zalloc(sizeof *output);
+       if (output == NULL) {
+               perror("zalloc");
+               return NULL;
+       }
+
+       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);
+
+       values[1] = b->null_cursor;
+       output->window = xcb_generate_id(b->conn);
+       screen = x11_compositor_get_default_screen(b);
+       xcb_create_window(b->conn,
+                         XCB_COPY_FROM_PARENT,
+                         output->window,
+                         screen->root,
+                         0, 0,
+                         output_width, output_height,
+                         0,
+                         XCB_WINDOW_CLASS_INPUT_OUTPUT,
+                         screen->root_visual,
+                         mask, values);
+
+       if (fullscreen) {
+               atom_list[0] = b->atom.net_wm_state_fullscreen;
+               xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE,
+                                   output->window,
+                                   b->atom.net_wm_state,
+                                   XCB_ATOM_ATOM, 32,
+                                   ARRAY_LENGTH(atom_list), atom_list);
+       } else {
+               /* Don't resize me. */
+               memset(&normal_hints, 0, sizeof normal_hints);
+               normal_hints.flags =
+                       WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
+               normal_hints.min_width = output_width;
+               normal_hints.min_height = output_height;
+               normal_hints.max_width = output_width;
+               normal_hints.max_height = output_height;
+               xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
+                                   b->atom.wm_normal_hints,
+                                   b->atom.wm_size_hints, 32,
+                                   sizeof normal_hints / 4,
+                                   (uint8_t *) &normal_hints);
+       }
+
+       /* Set window name.  Don't bother with non-EWMH WMs. */
+       xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
+                           b->atom.net_wm_name, b->atom.utf8_string, 8,
+                           strlen(title), title);
+       xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
+                           b->atom.wm_class, b->atom.string, 8,
+                           sizeof class, class);
+
+       x11_output_set_icon(b, output, DATADIR "/weston/wayland.png");
+
+       x11_output_set_wm_protocols(b, output);
+
+       xcb_map_window(b->conn, output->window);
+
+       if (fullscreen)
+               x11_output_wait_for_map(b, output);
+
+       output->base.start_repaint_loop = x11_output_start_repaint_loop;
+       if (b->use_pixman)
+               output->base.repaint = x11_output_repaint_shm;
+       else
+               output->base.repaint = x11_output_repaint_gl;
+       output->base.destroy = x11_output_destroy;
+       output->base.assign_planes = NULL;
+       output->base.set_backlight = NULL;
+       output->base.set_dpms = NULL;
+       output->base.switch_mode = NULL;
+       output->base.current_mode = &output->mode;
+       output->base.make = "weston-X11";
+       output->base.model = "none";
+
+       if (configured_name)
+               output->base.name = strdup(configured_name);
+
+       width_mm = width * b->screen->width_in_millimeters /
+               b->screen->width_in_pixels;
+       height_mm = height * b->screen->height_in_millimeters /
+               b->screen->height_in_pixels;
+       weston_output_init(&output->base, b->compositor,
+                          x, y, width_mm, height_mm, transform, scale);
+
+       if (b->use_pixman) {
+               if (x11_output_init_shm(b, output,
+                                       output->mode.width,
+                                       output->mode.height) < 0) {
+                       weston_log("Failed to initialize SHM for the X11 output\n");
+                       return NULL;
+               }
+               if (pixman_renderer_output_create(&output->base) < 0) {
+                       weston_log("Failed to create pixman renderer for output\n");
+                       x11_output_deinit_shm(b, output);
+                       return NULL;
+               }
+       } else {
+               /* eglCreatePlatformWindowSurfaceEXT takes a Window*
+                * but eglCreateWindowSurface takes a Window. */
+               Window xid = (Window) output->window;
+
+               ret = gl_renderer->output_create(&output->base,
+                                                (EGLNativeWindowType) output->window,
+                                                &xid,
+                                                gl_renderer->opaque_attribs,
+                                                NULL,
+                                                0);
+               if (ret < 0)
+                       return NULL;
+       }
+
+       loop = wl_display_get_event_loop(b->compositor->wl_display);
+       output->finish_frame_timer =
+               wl_event_loop_add_timer(loop, finish_frame_handler, output);
+
+       weston_compositor_add_output(b->compositor, &output->base);
+
+       weston_log("x11 output %dx%d, window id %d\n",
+                  width, height, output->window);
+
+       return output;
+}
+
+static struct x11_output *
+x11_backend_find_output(struct x11_backend *b, xcb_window_t window)
+{
+       struct x11_output *output;
+
+       wl_list_for_each(output, &b->compositor->output_list, base.link) {
+               if (output->window == window)
+                       return output;
+       }
+
+       return NULL;
+}
+
+static void
+x11_backend_delete_window(struct x11_backend *b, xcb_window_t window)
+{
+       struct x11_output *output;
+
+       output = x11_backend_find_output(b, window);
+       if (output)
+               x11_output_destroy(&output->base);
+
+       xcb_flush(b->conn);
+
+       if (wl_list_empty(&b->compositor->output_list))
+               weston_compositor_exit(b->compositor);
+}
+
+static void delete_cb(void *data)
+{
+       struct window_delete_data *wd = data;
+
+       x11_backend_delete_window(wd->backend, wd->window);
+       free(wd);
+}
+
+#ifdef HAVE_XCB_XKB
+static void
+update_xkb_state(struct x11_backend *b, xcb_xkb_state_notify_event_t *state)
+{
+       struct weston_keyboard *keyboard =
+               weston_seat_get_keyboard(&b->core_seat);
+
+       xkb_state_update_mask(keyboard->xkb_state.state,
+                             get_xkb_mod_mask(b, state->baseMods),
+                             get_xkb_mod_mask(b, state->latchedMods),
+                             get_xkb_mod_mask(b, state->lockedMods),
+                             0,
+                             0,
+                             state->group);
+
+       notify_modifiers(&b->core_seat,
+                        wl_display_next_serial(b->compositor->wl_display));
+}
+#endif
+
+/**
+ * This is monumentally unpleasant.  If we don't have XCB-XKB bindings,
+ * the best we can do (given that XCB also lacks XI2 support), is to take
+ * the state from the core key events.  Unfortunately that only gives us
+ * the effective (i.e. union of depressed/latched/locked) state, and we
+ * need the granularity.
+ *
+ * So we still update the state with every key event we see, but also use
+ * the state field from X11 events as a mask so we don't get any stuck
+ * modifiers.
+ */
+static void
+update_xkb_state_from_core(struct x11_backend *b, uint16_t x11_mask)
+{
+       uint32_t mask = get_xkb_mod_mask(b, x11_mask);
+       struct weston_keyboard *keyboard
+               = weston_seat_get_keyboard(&b->core_seat);
+
+       xkb_state_update_mask(keyboard->xkb_state.state,
+                             keyboard->modifiers.mods_depressed & mask,
+                             keyboard->modifiers.mods_latched & mask,
+                             keyboard->modifiers.mods_locked & mask,
+                             0,
+                             0,
+                             (x11_mask >> 13) & 3);
+       notify_modifiers(&b->core_seat,
+                        wl_display_next_serial(b->compositor->wl_display));
+}
+
+static void
+x11_backend_deliver_button_event(struct x11_backend *b,
+                                xcb_generic_event_t *event, int state)
+{
+       xcb_button_press_event_t *button_event =
+               (xcb_button_press_event_t *) event;
+       uint32_t button;
+       struct x11_output *output;
+       struct weston_pointer_axis_event weston_event;
+
+       output = x11_backend_find_output(b, button_event->event);
+       if (!output)
+               return;
+
+       if (state)
+               xcb_grab_pointer(b->conn, 0, output->window,
+                                XCB_EVENT_MASK_BUTTON_PRESS |
+                                XCB_EVENT_MASK_BUTTON_RELEASE |
+                                XCB_EVENT_MASK_POINTER_MOTION |
+                                XCB_EVENT_MASK_ENTER_WINDOW |
+                                XCB_EVENT_MASK_LEAVE_WINDOW,
+                                XCB_GRAB_MODE_ASYNC,
+                                XCB_GRAB_MODE_ASYNC,
+                                output->window, XCB_CURSOR_NONE,
+                                button_event->time);
+       else
+               xcb_ungrab_pointer(b->conn, button_event->time);
+
+       if (!b->has_xkb)
+               update_xkb_state_from_core(b, button_event->state);
+
+       switch (button_event->detail) {
+       case 1:
+               button = BTN_LEFT;
+               break;
+       case 2:
+               button = BTN_MIDDLE;
+               break;
+       case 3:
+               button = BTN_RIGHT;
+               break;
+       case 4:
+               /* Axis are measured in pixels, but the xcb events are discrete
+                * steps. Therefore move the axis by some pixels every step. */
+               if (state) {
+                       weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
+                       weston_event.discrete = -1;
+                       weston_event.has_discrete = true;
+                       weston_event.axis =
+                               WL_POINTER_AXIS_VERTICAL_SCROLL;
+                       notify_axis(&b->core_seat,
+                                   weston_compositor_get_time(),
+                                   &weston_event);
+                       notify_pointer_frame(&b->core_seat);
+               }
+               return;
+       case 5:
+               if (state) {
+                       weston_event.value = DEFAULT_AXIS_STEP_DISTANCE;
+                       weston_event.discrete = 1;
+                       weston_event.has_discrete = true;
+                       weston_event.axis =
+                               WL_POINTER_AXIS_VERTICAL_SCROLL;
+                       notify_axis(&b->core_seat,
+                                   weston_compositor_get_time(),
+                                   &weston_event);
+                       notify_pointer_frame(&b->core_seat);
+               }
+               return;
+       case 6:
+               if (state) {
+                       weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
+                       weston_event.discrete = -1;
+                       weston_event.has_discrete = true;
+                       weston_event.axis =
+                               WL_POINTER_AXIS_HORIZONTAL_SCROLL;
+                       notify_axis(&b->core_seat,
+                                   weston_compositor_get_time(),
+                                   &weston_event);
+                       notify_pointer_frame(&b->core_seat);
+               }
+               return;
+       case 7:
+               if (state) {
+                       weston_event.value = DEFAULT_AXIS_STEP_DISTANCE;
+                       weston_event.discrete = 1;
+                       weston_event.has_discrete = true;
+                       weston_event.axis =
+                               WL_POINTER_AXIS_HORIZONTAL_SCROLL;
+                       notify_axis(&b->core_seat,
+                                   weston_compositor_get_time(),
+                                   &weston_event);
+                       notify_pointer_frame(&b->core_seat);
+               }
+               return;
+       default:
+               button = button_event->detail + BTN_SIDE - 8;
+               break;
+       }
+
+       notify_button(&b->core_seat,
+                     weston_compositor_get_time(), button,
+                     state ? WL_POINTER_BUTTON_STATE_PRESSED :
+                             WL_POINTER_BUTTON_STATE_RELEASED);
+       notify_pointer_frame(&b->core_seat);
+}
+
+static void
+x11_backend_deliver_motion_event(struct x11_backend *b,
+                                xcb_generic_event_t *event)
+{
+       struct x11_output *output;
+       double x, y;
+       struct weston_pointer_motion_event motion_event = { 0 };
+       xcb_motion_notify_event_t *motion_notify =
+                       (xcb_motion_notify_event_t *) event;
+
+       if (!b->has_xkb)
+               update_xkb_state_from_core(b, motion_notify->state);
+       output = x11_backend_find_output(b, motion_notify->event);
+       if (!output)
+               return;
+
+       weston_output_transform_coordinate(&output->base,
+                                          motion_notify->event_x,
+                                          motion_notify->event_y,
+                                          &x, &y);
+
+       motion_event = (struct weston_pointer_motion_event) {
+               .mask = WESTON_POINTER_MOTION_REL,
+               .dx = x - b->prev_x,
+               .dy = y - b->prev_y
+       };
+
+       notify_motion(&b->core_seat, weston_compositor_get_time(),
+                     &motion_event);
+       notify_pointer_frame(&b->core_seat);
+
+       b->prev_x = x;
+       b->prev_y = y;
+}
+
+static void
+x11_backend_deliver_enter_event(struct x11_backend *b,
+                               xcb_generic_event_t *event)
+{
+       struct x11_output *output;
+       double x, y;
+
+       xcb_enter_notify_event_t *enter_notify =
+                       (xcb_enter_notify_event_t *) event;
+       if (enter_notify->state >= Button1Mask)
+               return;
+       if (!b->has_xkb)
+               update_xkb_state_from_core(b, enter_notify->state);
+       output = x11_backend_find_output(b, enter_notify->event);
+       if (!output)
+               return;
+
+       weston_output_transform_coordinate(&output->base,
+                                          enter_notify->event_x,
+                                          enter_notify->event_y, &x, &y);
+
+       notify_pointer_focus(&b->core_seat, &output->base, x, y);
+
+       b->prev_x = x;
+       b->prev_y = y;
+}
+
+static int
+x11_backend_next_event(struct x11_backend *b,
+                      xcb_generic_event_t **event, uint32_t mask)
+{
+       if (mask & WL_EVENT_READABLE) {
+               *event = xcb_poll_for_event(b->conn);
+       } else {
+#ifdef HAVE_XCB_POLL_FOR_QUEUED_EVENT
+               *event = xcb_poll_for_queued_event(b->conn);
+#else
+               *event = xcb_poll_for_event(b->conn);
+#endif
+       }
+
+       return *event != NULL;
+}
+
+static int
+x11_backend_handle_event(int fd, uint32_t mask, void *data)
+{
+       struct x11_backend *b = data;
+       struct x11_output *output;
+       xcb_generic_event_t *event, *prev;
+       xcb_client_message_event_t *client_message;
+       xcb_enter_notify_event_t *enter_notify;
+       xcb_key_press_event_t *key_press, *key_release;
+       xcb_keymap_notify_event_t *keymap_notify;
+       xcb_focus_in_event_t *focus_in;
+       xcb_expose_event_t *expose;
+       xcb_atom_t atom;
+       xcb_window_t window;
+       uint32_t *k;
+       uint32_t i, set;
+       uint8_t response_type;
+       int count;
+
+       prev = NULL;
+       count = 0;
+       while (x11_backend_next_event(b, &event, mask)) {
+               response_type = event->response_type & ~0x80;
+
+               switch (prev ? prev->response_type & ~0x80 : 0x80) {
+               case XCB_KEY_RELEASE:
+                       /* Suppress key repeat events; this is only used if we
+                        * don't have XCB XKB support. */
+                       key_release = (xcb_key_press_event_t *) prev;
+                       key_press = (xcb_key_press_event_t *) event;
+                       if (response_type == XCB_KEY_PRESS &&
+                           key_release->time == key_press->time &&
+                           key_release->detail == key_press->detail) {
+                               /* Don't deliver the held key release
+                                * event or the new key press event. */
+                               free(event);
+                               free(prev);
+                               prev = NULL;
+                               continue;
+                       } else {
+                               /* Deliver the held key release now
+                                * and fall through and handle the new
+                                * event below. */
+                               update_xkb_state_from_core(b, key_release->state);
+                               notify_key(&b->core_seat,
+                                          weston_compositor_get_time(),
+                                          key_release->detail - 8,
+                                          WL_KEYBOARD_KEY_STATE_RELEASED,
+                                          STATE_UPDATE_AUTOMATIC);
+                               free(prev);
+                               prev = NULL;
+                               break;
+                       }
+
+               case XCB_FOCUS_IN:
+                       assert(response_type == XCB_KEYMAP_NOTIFY);
+                       keymap_notify = (xcb_keymap_notify_event_t *) event;
+                       b->keys.size = 0;
+                       for (i = 0; i < ARRAY_LENGTH(keymap_notify->keys) * 8; i++) {
+                               set = keymap_notify->keys[i >> 3] &
+                                       (1 << (i & 7));
+                               if (set) {
+                                       k = wl_array_add(&b->keys, sizeof *k);
+                                       *k = i;
+                               }
+                       }
+
+                       /* Unfortunately the state only comes with the enter
+                        * event, rather than with the focus event.  I'm not
+                        * sure of the exact semantics around it and whether
+                        * we can ensure that we get both? */
+                       notify_keyboard_focus_in(&b->core_seat, &b->keys,
+                                                STATE_UPDATE_AUTOMATIC);
+
+                       free(prev);
+                       prev = NULL;
+                       break;
+
+               default:
+                       /* No previous event held */
+                       break;
+               }
+
+               switch (response_type) {
+               case XCB_KEY_PRESS:
+                       key_press = (xcb_key_press_event_t *) event;
+                       if (!b->has_xkb)
+                               update_xkb_state_from_core(b, key_press->state);
+                       notify_key(&b->core_seat,
+                                  weston_compositor_get_time(),
+                                  key_press->detail - 8,
+                                  WL_KEYBOARD_KEY_STATE_PRESSED,
+                                  b->has_xkb ? STATE_UPDATE_NONE :
+                                               STATE_UPDATE_AUTOMATIC);
+                       break;
+               case XCB_KEY_RELEASE:
+                       /* If we don't have XKB, we need to use the lame
+                        * autorepeat detection above. */
+                       if (!b->has_xkb) {
+                               prev = event;
+                               break;
+                       }
+                       key_release = (xcb_key_press_event_t *) event;
+                       notify_key(&b->core_seat,
+                                  weston_compositor_get_time(),
+                                  key_release->detail - 8,
+                                  WL_KEYBOARD_KEY_STATE_RELEASED,
+                                  STATE_UPDATE_NONE);
+                       break;
+               case XCB_BUTTON_PRESS:
+                       x11_backend_deliver_button_event(b, event, 1);
+                       break;
+               case XCB_BUTTON_RELEASE:
+                       x11_backend_deliver_button_event(b, event, 0);
+                       break;
+               case XCB_MOTION_NOTIFY:
+                       x11_backend_deliver_motion_event(b, event);
+                       break;
+
+               case XCB_EXPOSE:
+                       expose = (xcb_expose_event_t *) event;
+                       output = x11_backend_find_output(b, expose->window);
+                       if (!output)
+                               break;
+
+                       weston_output_damage(&output->base);
+                       weston_output_schedule_repaint(&output->base);
+                       break;
+
+               case XCB_ENTER_NOTIFY:
+                       x11_backend_deliver_enter_event(b, event);
+                       break;
+
+               case XCB_LEAVE_NOTIFY:
+                       enter_notify = (xcb_enter_notify_event_t *) event;
+                       if (enter_notify->state >= Button1Mask)
+                               break;
+                       if (!b->has_xkb)
+                               update_xkb_state_from_core(b, enter_notify->state);
+                       notify_pointer_focus(&b->core_seat, NULL, 0, 0);
+                       break;
+
+               case XCB_CLIENT_MESSAGE:
+                       client_message = (xcb_client_message_event_t *) event;
+                       atom = client_message->data.data32[0];
+                       window = client_message->window;
+                       if (atom == b->atom.wm_delete_window) {
+                               struct wl_event_loop *loop;
+                               struct window_delete_data *data = malloc(sizeof *data);
+
+                               /* if malloc failed we should at least try to
+                                * delete the window, even if it may result in
+                                * a crash.
+                                */
+                               if (!data) {
+                                       x11_backend_delete_window(b, window);
+                                       break;
+                               }
+                               data->backend = b;
+                               data->window = window;
+                               loop = wl_display_get_event_loop(b->compositor->wl_display);
+                               wl_event_loop_add_idle(loop, delete_cb, data);
+                       }
+                       break;
+
+               case XCB_FOCUS_IN:
+                       focus_in = (xcb_focus_in_event_t *) event;
+                       if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
+                               break;
+
+                       prev = event;
+                       break;
+
+               case XCB_FOCUS_OUT:
+                       focus_in = (xcb_focus_in_event_t *) event;
+                       if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED ||
+                           focus_in->mode == XCB_NOTIFY_MODE_UNGRAB)
+                               break;
+                       notify_keyboard_focus_out(&b->core_seat);
+                       break;
+
+               default:
+                       break;
+               }
+
+#ifdef HAVE_XCB_XKB
+               if (b->has_xkb) {
+                       if (response_type == b->xkb_event_base) {
+                               xcb_xkb_state_notify_event_t *state =
+                                       (xcb_xkb_state_notify_event_t *) event;
+                               if (state->xkbType == XCB_XKB_STATE_NOTIFY)
+                                       update_xkb_state(b, state);
+                       } else if (response_type == XCB_PROPERTY_NOTIFY) {
+                               xcb_property_notify_event_t *prop_notify =
+                                       (xcb_property_notify_event_t *) event;
+                               if (prop_notify->window == b->screen->root &&
+                                   prop_notify->atom == b->atom.xkb_names &&
+                                   prop_notify->state == XCB_PROPERTY_NEW_VALUE)
+                                       update_xkb_keymap(b);
+                       }
+               }
+#endif
+
+               count++;
+               if (prev != event)
+                       free (event);
+       }
+
+       switch (prev ? prev->response_type & ~0x80 : 0x80) {
+       case XCB_KEY_RELEASE:
+               key_release = (xcb_key_press_event_t *) prev;
+               update_xkb_state_from_core(b, key_release->state);
+               notify_key(&b->core_seat,
+                          weston_compositor_get_time(),
+                          key_release->detail - 8,
+                          WL_KEYBOARD_KEY_STATE_RELEASED,
+                          STATE_UPDATE_AUTOMATIC);
+               free(prev);
+               prev = NULL;
+               break;
+       default:
+               break;
+       }
+
+       return count;
+}
+
+#define F(field) offsetof(struct x11_backend, field)
+
+static void
+x11_backend_get_resources(struct x11_backend *b)
+{
+       static const struct { const char *name; int offset; } atoms[] = {
+               { "WM_PROTOCOLS",       F(atom.wm_protocols) },
+               { "WM_NORMAL_HINTS",    F(atom.wm_normal_hints) },
+               { "WM_SIZE_HINTS",      F(atom.wm_size_hints) },
+               { "WM_DELETE_WINDOW",   F(atom.wm_delete_window) },
+               { "WM_CLASS",           F(atom.wm_class) },
+               { "_NET_WM_NAME",       F(atom.net_wm_name) },
+               { "_NET_WM_ICON",       F(atom.net_wm_icon) },
+               { "_NET_WM_STATE",      F(atom.net_wm_state) },
+               { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
+               { "_NET_SUPPORTING_WM_CHECK",
+                                       F(atom.net_supporting_wm_check) },
+               { "_NET_SUPPORTED",     F(atom.net_supported) },
+               { "STRING",             F(atom.string) },
+               { "UTF8_STRING",        F(atom.utf8_string) },
+               { "CARDINAL",           F(atom.cardinal) },
+               { "_XKB_RULES_NAMES",   F(atom.xkb_names) },
+       };
+
+       xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
+       xcb_intern_atom_reply_t *reply;
+       xcb_pixmap_t pixmap;
+       xcb_gc_t gc;
+       unsigned int i;
+       uint8_t data[] = { 0, 0, 0, 0 };
+
+       for (i = 0; i < ARRAY_LENGTH(atoms); i++)
+               cookies[i] = xcb_intern_atom (b->conn, 0,
+                                             strlen(atoms[i].name),
+                                             atoms[i].name);
+
+       for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
+               reply = xcb_intern_atom_reply (b->conn, cookies[i], NULL);
+               *(xcb_atom_t *) ((char *) b + atoms[i].offset) = reply->atom;
+               free(reply);
+       }
+
+       pixmap = xcb_generate_id(b->conn);
+       gc = xcb_generate_id(b->conn);
+       xcb_create_pixmap(b->conn, 1, pixmap, b->screen->root, 1, 1);
+       xcb_create_gc(b->conn, gc, pixmap, 0, NULL);
+       xcb_put_image(b->conn, XCB_IMAGE_FORMAT_XY_PIXMAP,
+                     pixmap, gc, 1, 1, 0, 0, 0, 32, sizeof data, data);
+       b->null_cursor = xcb_generate_id(b->conn);
+       xcb_create_cursor (b->conn, b->null_cursor,
+                          pixmap, pixmap, 0, 0, 0,  0, 0, 0,  1, 1);
+       xcb_free_gc(b->conn, gc);
+       xcb_free_pixmap(b->conn, pixmap);
+}
+
+static void
+x11_backend_get_wm_info(struct x11_backend *c)
+{
+       xcb_get_property_cookie_t cookie;
+       xcb_get_property_reply_t *reply;
+       xcb_atom_t *atom;
+       unsigned int i;
+
+       cookie = xcb_get_property(c->conn, 0, c->screen->root,
+                                 c->atom.net_supported,
+                                 XCB_ATOM_ATOM, 0, 1024);
+       reply = xcb_get_property_reply(c->conn, cookie, NULL);
+       if (reply == NULL)
+               return;
+
+       atom = (xcb_atom_t *) xcb_get_property_value(reply);
+
+       for (i = 0; i < reply->value_len; i++) {
+               if (atom[i] == c->atom.net_wm_state_fullscreen)
+                       c->has_net_wm_state_fullscreen = 1;
+       }
+
+       free(reply);
+}
+
+static void
+x11_restore(struct weston_compositor *ec)
+{
+}
+
+static void
+x11_destroy(struct weston_compositor *ec)
+{
+       struct x11_backend *backend = (struct x11_backend *)ec->backend;
+
+       wl_event_source_remove(backend->xcb_source);
+       x11_input_destroy(backend);
+
+       weston_compositor_shutdown(ec); /* destroys outputs, too */
+
+       XCloseDisplay(backend->dpy);
+       free(backend);
+}
+
+static int
+init_gl_renderer(struct x11_backend *b)
+{
+       int ret;
+
+       gl_renderer = weston_load_module("gl-renderer.so",
+                                        "gl_renderer_interface");
+       if (!gl_renderer)
+               return -1;
+
+       ret = gl_renderer->create(b->compositor, EGL_PLATFORM_X11_KHR, (void *) b->dpy,
+                                 gl_renderer->opaque_attribs, NULL, 0);
+
+       return ret;
+}
+
+static struct x11_backend *
+x11_backend_create(struct weston_compositor *compositor,
+                  struct weston_x11_backend_config *config)
+{
+       struct x11_backend *b;
+       struct x11_output *output;
+       struct wl_event_loop *loop;
+       int x = 0;
+       unsigned i;
+
+       b = zalloc(sizeof *b);
+       if (b == NULL)
+               return NULL;
+
+       b->compositor = compositor;
+       if (weston_compositor_set_presentation_clock_software(compositor) < 0)
+               goto err_free;
+
+       b->dpy = XOpenDisplay(NULL);
+       if (b->dpy == NULL)
+               goto err_free;
+
+       b->conn = XGetXCBConnection(b->dpy);
+       XSetEventQueueOwner(b->dpy, XCBOwnsEventQueue);
+
+       if (xcb_connection_has_error(b->conn))
+               goto err_xdisplay;
+
+       b->screen = x11_compositor_get_default_screen(b);
+       wl_array_init(&b->keys);
+
+       x11_backend_get_resources(b);
+       x11_backend_get_wm_info(b);
+
+       if (!b->has_net_wm_state_fullscreen && config->fullscreen) {
+               weston_log("Can not fullscreen without window manager support"
+                          "(need _NET_WM_STATE_FULLSCREEN)\n");
+               config->fullscreen = 0;
+       }
+
+       b->use_pixman = config->use_pixman;
+       if (b->use_pixman) {
+               if (pixman_renderer_init(compositor) < 0) {
+                       weston_log("Failed to initialize pixman renderer for X11 backend\n");
+                       goto err_xdisplay;
+               }
+       }
+       else if (init_gl_renderer(b) < 0) {
+               goto err_xdisplay;
+       }
+       weston_log("Using %s renderer\n", config->use_pixman ? "pixman" : "gl");
+
+       b->base.destroy = x11_destroy;
+       b->base.restore = x11_restore;
+
+       if (x11_input_create(b, config->no_input) < 0) {
+               weston_log("Failed to create X11 input\n");
+               goto err_renderer;
+       }
+
+       for (i = 0; i < config->num_outputs; ++i) {
+               struct weston_x11_backend_output_config *output_iterator =
+                       &config->outputs[i];
+
+               if (output_iterator->name == NULL) {
+                       continue;
+               }
+
+               if (output_iterator->width < 1) {
+                       weston_log("Invalid width \"%d\" for output %s\n",
+                                  output_iterator->width, output_iterator->name);
+                       goto err_x11_input;
+               }
+
+               if (output_iterator->height < 1) {
+                       weston_log("Invalid height \"%d\" for output %s\n",
+                                  output_iterator->height, output_iterator->name);
+                       goto err_x11_input;
+               }
+
+               output = x11_backend_create_output(b,
+                                                  x,
+                                                  0,
+                                                  output_iterator->width,
+                                                  output_iterator->height,
+                                                  config->fullscreen,
+                                                  config->no_input,
+                                                  output_iterator->name,
+                                                  output_iterator->transform,
+                                                  output_iterator->scale);
+               if (output == NULL) {
+                       weston_log("Failed to create configured x11 output\n");
+                       goto err_x11_input;
+               }
+
+               x = pixman_region32_extents(&output->base.region)->x2;
+       }
+
+       loop = wl_display_get_event_loop(compositor->wl_display);
+       b->xcb_source =
+               wl_event_loop_add_fd(loop,
+                                    xcb_get_file_descriptor(b->conn),
+                                    WL_EVENT_READABLE,
+                                    x11_backend_handle_event, b);
+       wl_event_source_check(b->xcb_source);
+
+       if (compositor->renderer->import_dmabuf) {
+               if (linux_dmabuf_setup(compositor) < 0)
+                       weston_log("Error: initializing dmabuf "
+                                  "support failed.\n");
+       }
+
+       compositor->backend = &b->base;
+
+       return b;
+
+err_x11_input:
+       x11_input_destroy(b);
+err_renderer:
+       compositor->renderer->destroy(compositor);
+err_xdisplay:
+       XCloseDisplay(b->dpy);
+err_free:
+       free(b);
+       return NULL;
+}
+
+static void
+config_init_to_defaults(struct weston_x11_backend_config *config)
+{
+}
+
+WL_EXPORT int
+backend_init(struct weston_compositor *compositor,
+            struct weston_backend_config *config_base)
+{
+       struct x11_backend *b;
+       struct weston_x11_backend_config config = {{ 0, }};
+
+       if (config_base == NULL ||
+           config_base->struct_version != WESTON_X11_BACKEND_CONFIG_VERSION ||
+           config_base->struct_size > sizeof(struct weston_x11_backend_config)) {
+               weston_log("X11 backend config structure is invalid\n");
+               return -1;
+       }
+
+       config_init_to_defaults(&config);
+       memcpy(&config, config_base, config_base->struct_size);
+
+       b = x11_backend_create(compositor, &config);
+       if (b == NULL)
+               return -1;
+
+       return 0;
+}
diff --git a/libweston/compositor-x11.h b/libweston/compositor-x11.h
new file mode 100644 (file)
index 0000000..8363a76
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2016 Benoit Gschwind
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_COMPOSITOR_X11_H
+#define WESTON_COMPOSITOR_X11_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include "compositor.h"
+
+#define WESTON_X11_BACKEND_CONFIG_VERSION 1
+
+struct weston_x11_backend_output_config {
+       int width;
+       int height;
+       char *name;
+       uint32_t transform;
+       int32_t scale;
+};
+
+struct weston_x11_backend_config {
+       struct weston_backend_config base;
+
+       bool fullscreen;
+       bool no_input;
+
+       /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
+       bool use_pixman;
+
+       uint32_t num_outputs;
+       struct weston_x11_backend_output_config *outputs;
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif /* WESTON_COMPOSITOR_X11_H_ */
diff --git a/libweston/compositor.c b/libweston/compositor.c
new file mode 100644 (file)
index 0000000..37d94ec
--- /dev/null
@@ -0,0 +1,5015 @@
+/*
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2012-2015 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <math.h>
+#include <linux/input.h>
+#include <dlfcn.h>
+#include <signal.h>
+#include <setjmp.h>
+#include <sys/time.h>
+#include <time.h>
+#include <errno.h>
+
+#include "timeline.h"
+
+#include "compositor.h"
+#include "viewporter-server-protocol.h"
+#include "presentation-time-server-protocol.h"
+#include "shared/helpers.h"
+#include "shared/os-compatibility.h"
+#include "shared/timespec-util.h"
+#include "git-version.h"
+#include "version.h"
+
+#define DEFAULT_REPAINT_WINDOW 7 /* milliseconds */
+
+static void
+weston_output_transform_scale_init(struct weston_output *output,
+                                  uint32_t transform, uint32_t scale);
+
+static void
+weston_compositor_build_view_list(struct weston_compositor *compositor);
+
+static void weston_mode_switch_finish(struct weston_output *output,
+                                     int mode_changed,
+                                     int scale_changed)
+{
+       struct weston_seat *seat;
+       struct wl_resource *resource;
+       pixman_region32_t old_output_region;
+       int version;
+
+       pixman_region32_init(&old_output_region);
+       pixman_region32_copy(&old_output_region, &output->region);
+
+       /* Update output region and transformation matrix */
+       weston_output_transform_scale_init(output, output->transform, output->current_scale);
+
+       pixman_region32_init(&output->previous_damage);
+       pixman_region32_init_rect(&output->region, output->x, output->y,
+                                 output->width, output->height);
+
+       weston_output_update_matrix(output);
+
+       /* If a pointer falls outside the outputs new geometry, move it to its
+        * lower-right corner */
+       wl_list_for_each(seat, &output->compositor->seat_list, link) {
+               struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+               int32_t x, y;
+
+               if (!pointer)
+                       continue;
+
+               x = wl_fixed_to_int(pointer->x);
+               y = wl_fixed_to_int(pointer->y);
+
+               if (!pixman_region32_contains_point(&old_output_region,
+                                                   x, y, NULL) ||
+                   pixman_region32_contains_point(&output->region,
+                                                  x, y, NULL))
+                       continue;
+
+               if (x >= output->x + output->width)
+                       x = output->x + output->width - 1;
+               if (y >= output->y + output->height)
+                       y = output->y + output->height - 1;
+
+               pointer->x = wl_fixed_from_int(x);
+               pointer->y = wl_fixed_from_int(y);
+       }
+
+       pixman_region32_fini(&old_output_region);
+
+       if (!mode_changed && !scale_changed)
+               return;
+
+       /* notify clients of the changes */
+       wl_resource_for_each(resource, &output->resource_list) {
+               if (mode_changed) {
+                       wl_output_send_mode(resource,
+                                           output->current_mode->flags,
+                                           output->current_mode->width,
+                                           output->current_mode->height,
+                                           output->current_mode->refresh);
+               }
+
+               version = wl_resource_get_version(resource);
+               if (version >= WL_OUTPUT_SCALE_SINCE_VERSION && scale_changed)
+                       wl_output_send_scale(resource, output->current_scale);
+
+               if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
+                       wl_output_send_done(resource);
+       }
+}
+
+
+static void
+weston_compositor_reflow_outputs(struct weston_compositor *compositor,
+                               struct weston_output *resized_output, int delta_width);
+
+WL_EXPORT int
+weston_output_mode_set_native(struct weston_output *output,
+                             struct weston_mode *mode,
+                             int32_t scale)
+{
+       int ret;
+       int mode_changed = 0, scale_changed = 0;
+       int32_t old_width;
+
+       if (!output->switch_mode)
+               return -1;
+
+       if (!output->original_mode) {
+               mode_changed = 1;
+               ret = output->switch_mode(output, mode);
+               if (ret < 0)
+                       return ret;
+               if (output->current_scale != scale) {
+                       scale_changed = 1;
+                       output->current_scale = scale;
+               }
+       }
+
+       old_width = output->width;
+       output->native_mode = mode;
+       output->native_scale = scale;
+
+       weston_mode_switch_finish(output, mode_changed, scale_changed);
+
+       if (mode_changed || scale_changed) {
+               weston_compositor_reflow_outputs(output->compositor, output, output->width - old_width);
+
+               wl_signal_emit(&output->compositor->output_resized_signal, output);
+       }
+       return 0;
+}
+
+WL_EXPORT int
+weston_output_mode_switch_to_native(struct weston_output *output)
+{
+       int ret;
+       int mode_changed = 0, scale_changed = 0;
+
+       if (!output->switch_mode)
+               return -1;
+
+       if (!output->original_mode) {
+               weston_log("already in the native mode\n");
+               return -1;
+       }
+       /* the non fullscreen clients haven't seen a mode set since we
+        * switched into a temporary, so we need to notify them if the
+        * mode at that time is different from the native mode now.
+        */
+       mode_changed = (output->original_mode != output->native_mode);
+       scale_changed = (output->original_scale != output->native_scale);
+
+       ret = output->switch_mode(output, output->native_mode);
+       if (ret < 0)
+               return ret;
+
+       output->current_scale = output->native_scale;
+
+       output->original_mode = NULL;
+       output->original_scale = 0;
+
+       weston_mode_switch_finish(output, mode_changed, scale_changed);
+
+       return 0;
+}
+
+WL_EXPORT int
+weston_output_mode_switch_to_temporary(struct weston_output *output,
+                                      struct weston_mode *mode,
+                                      int32_t scale)
+{
+       int ret;
+
+       if (!output->switch_mode)
+               return -1;
+
+       /* original_mode is the last mode non full screen clients have seen,
+        * so we shouldn't change it if we already have one set.
+        */
+       if (!output->original_mode) {
+               output->original_mode = output->native_mode;
+               output->original_scale = output->native_scale;
+       }
+       ret = output->switch_mode(output, mode);
+       if (ret < 0)
+               return ret;
+
+       output->current_scale = scale;
+
+       weston_mode_switch_finish(output, 0, 0);
+
+       return 0;
+}
+
+static void
+region_init_infinite(pixman_region32_t *region)
+{
+       pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
+                                 UINT32_MAX, UINT32_MAX);
+}
+
+static struct weston_subsurface *
+weston_surface_to_subsurface(struct weston_surface *surface);
+
+WL_EXPORT struct weston_view *
+weston_view_create(struct weston_surface *surface)
+{
+       struct weston_view *view;
+
+       view = zalloc(sizeof *view);
+       if (view == NULL)
+               return NULL;
+
+       view->surface = surface;
+
+       /* Assign to surface */
+       wl_list_insert(&surface->views, &view->surface_link);
+
+       wl_signal_init(&view->destroy_signal);
+       wl_list_init(&view->link);
+       wl_list_init(&view->layer_link.link);
+
+       pixman_region32_init(&view->clip);
+
+       view->alpha = 1.0;
+       pixman_region32_init(&view->transform.opaque);
+
+       wl_list_init(&view->geometry.transformation_list);
+       wl_list_insert(&view->geometry.transformation_list,
+                      &view->transform.position.link);
+       weston_matrix_init(&view->transform.position.matrix);
+       wl_list_init(&view->geometry.child_list);
+       pixman_region32_init(&view->geometry.scissor);
+       pixman_region32_init(&view->transform.boundingbox);
+       view->transform.dirty = 1;
+
+       return view;
+}
+
+struct weston_frame_callback {
+       struct wl_resource *resource;
+       struct wl_list link;
+};
+
+struct weston_presentation_feedback {
+       struct wl_resource *resource;
+
+       /* XXX: could use just wl_resource_get_link() instead */
+       struct wl_list link;
+
+       /* The per-surface feedback flags */
+       uint32_t psf_flags;
+};
+
+static void
+weston_presentation_feedback_discard(
+               struct weston_presentation_feedback *feedback)
+{
+       wp_presentation_feedback_send_discarded(feedback->resource);
+       wl_resource_destroy(feedback->resource);
+}
+
+static void
+weston_presentation_feedback_discard_list(struct wl_list *list)
+{
+       struct weston_presentation_feedback *feedback, *tmp;
+
+       wl_list_for_each_safe(feedback, tmp, list, link)
+               weston_presentation_feedback_discard(feedback);
+}
+
+static void
+weston_presentation_feedback_present(
+               struct weston_presentation_feedback *feedback,
+               struct weston_output *output,
+               uint32_t refresh_nsec,
+               const struct timespec *ts,
+               uint64_t seq,
+               uint32_t flags)
+{
+       struct wl_client *client = wl_resource_get_client(feedback->resource);
+       struct wl_resource *o;
+       uint64_t secs;
+
+       wl_resource_for_each(o, &output->resource_list) {
+               if (wl_resource_get_client(o) != client)
+                       continue;
+
+               wp_presentation_feedback_send_sync_output(feedback->resource, o);
+       }
+
+       secs = ts->tv_sec;
+       wp_presentation_feedback_send_presented(feedback->resource,
+                                               secs >> 32, secs & 0xffffffff,
+                                               ts->tv_nsec,
+                                               refresh_nsec,
+                                               seq >> 32, seq & 0xffffffff,
+                                               flags | feedback->psf_flags);
+       wl_resource_destroy(feedback->resource);
+}
+
+static void
+weston_presentation_feedback_present_list(struct wl_list *list,
+                                         struct weston_output *output,
+                                         uint32_t refresh_nsec,
+                                         const struct timespec *ts,
+                                         uint64_t seq,
+                                         uint32_t flags)
+{
+       struct weston_presentation_feedback *feedback, *tmp;
+
+       assert(!(flags & WP_PRESENTATION_FEEDBACK_INVALID) ||
+              wl_list_empty(list));
+
+       wl_list_for_each_safe(feedback, tmp, list, link)
+               weston_presentation_feedback_present(feedback, output,
+                                                    refresh_nsec, ts, seq,
+                                                    flags);
+}
+
+static void
+surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
+{
+       struct weston_surface_state *state =
+               container_of(listener, struct weston_surface_state,
+                            buffer_destroy_listener);
+
+       state->buffer = NULL;
+}
+
+static void
+weston_surface_state_init(struct weston_surface_state *state)
+{
+       state->newly_attached = 0;
+       state->buffer = NULL;
+       state->buffer_destroy_listener.notify =
+               surface_state_handle_buffer_destroy;
+       state->sx = 0;
+       state->sy = 0;
+
+       pixman_region32_init(&state->damage_surface);
+       pixman_region32_init(&state->damage_buffer);
+       pixman_region32_init(&state->opaque);
+       region_init_infinite(&state->input);
+
+       wl_list_init(&state->frame_callback_list);
+       wl_list_init(&state->feedback_list);
+
+       state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
+       state->buffer_viewport.buffer.scale = 1;
+       state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
+       state->buffer_viewport.surface.width = -1;
+       state->buffer_viewport.changed = 0;
+}
+
+static void
+weston_surface_state_fini(struct weston_surface_state *state)
+{
+       struct weston_frame_callback *cb, *next;
+
+       wl_list_for_each_safe(cb, next,
+                             &state->frame_callback_list, link)
+               wl_resource_destroy(cb->resource);
+
+       weston_presentation_feedback_discard_list(&state->feedback_list);
+
+       pixman_region32_fini(&state->input);
+       pixman_region32_fini(&state->opaque);
+       pixman_region32_fini(&state->damage_surface);
+       pixman_region32_fini(&state->damage_buffer);
+
+       if (state->buffer)
+               wl_list_remove(&state->buffer_destroy_listener.link);
+       state->buffer = NULL;
+}
+
+static void
+weston_surface_state_set_buffer(struct weston_surface_state *state,
+                               struct weston_buffer *buffer)
+{
+       if (state->buffer == buffer)
+               return;
+
+       if (state->buffer)
+               wl_list_remove(&state->buffer_destroy_listener.link);
+       state->buffer = buffer;
+       if (state->buffer)
+               wl_signal_add(&state->buffer->destroy_signal,
+                             &state->buffer_destroy_listener);
+}
+
+WL_EXPORT struct weston_surface *
+weston_surface_create(struct weston_compositor *compositor)
+{
+       struct weston_surface *surface;
+
+       surface = zalloc(sizeof *surface);
+       if (surface == NULL)
+               return NULL;
+
+       wl_signal_init(&surface->destroy_signal);
+
+       surface->compositor = compositor;
+       surface->ref_count = 1;
+
+       surface->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
+       surface->buffer_viewport.buffer.scale = 1;
+       surface->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
+       surface->buffer_viewport.surface.width = -1;
+
+       weston_surface_state_init(&surface->pending);
+
+       pixman_region32_init(&surface->damage);
+       pixman_region32_init(&surface->opaque);
+       region_init_infinite(&surface->input);
+
+       wl_list_init(&surface->views);
+
+       wl_list_init(&surface->frame_callback_list);
+       wl_list_init(&surface->feedback_list);
+
+       wl_list_init(&surface->subsurface_list);
+       wl_list_init(&surface->subsurface_list_pending);
+
+       weston_matrix_init(&surface->buffer_to_surface_matrix);
+       weston_matrix_init(&surface->surface_to_buffer_matrix);
+
+       return surface;
+}
+
+WL_EXPORT void
+weston_surface_set_color(struct weston_surface *surface,
+                float red, float green, float blue, float alpha)
+{
+       surface->compositor->renderer->surface_set_color(surface, red, green, blue, alpha);
+}
+
+WL_EXPORT void
+weston_view_to_global_float(struct weston_view *view,
+                           float sx, float sy, float *x, float *y)
+{
+       if (view->transform.enabled) {
+               struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
+
+               weston_matrix_transform(&view->transform.matrix, &v);
+
+               if (fabsf(v.f[3]) < 1e-6) {
+                       weston_log("warning: numerical instability in "
+                               "%s(), divisor = %g\n", __func__,
+                               v.f[3]);
+                       *x = 0;
+                       *y = 0;
+                       return;
+               }
+
+               *x = v.f[0] / v.f[3];
+               *y = v.f[1] / v.f[3];
+       } else {
+               *x = sx + view->geometry.x;
+               *y = sy + view->geometry.y;
+       }
+}
+
+WL_EXPORT void
+weston_transformed_coord(int width, int height,
+                        enum wl_output_transform transform,
+                        int32_t scale,
+                        float sx, float sy, float *bx, float *by)
+{
+       switch (transform) {
+       case WL_OUTPUT_TRANSFORM_NORMAL:
+       default:
+               *bx = sx;
+               *by = sy;
+               break;
+       case WL_OUTPUT_TRANSFORM_FLIPPED:
+               *bx = width - sx;
+               *by = sy;
+               break;
+       case WL_OUTPUT_TRANSFORM_90:
+               *bx = height - sy;
+               *by = sx;
+               break;
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+               *bx = height - sy;
+               *by = width - sx;
+               break;
+       case WL_OUTPUT_TRANSFORM_180:
+               *bx = width - sx;
+               *by = height - sy;
+               break;
+       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+               *bx = sx;
+               *by = height - sy;
+               break;
+       case WL_OUTPUT_TRANSFORM_270:
+               *bx = sy;
+               *by = width - sx;
+               break;
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               *bx = sy;
+               *by = sx;
+               break;
+       }
+
+       *bx *= scale;
+       *by *= scale;
+}
+
+WL_EXPORT pixman_box32_t
+weston_transformed_rect(int width, int height,
+                       enum wl_output_transform transform,
+                       int32_t scale,
+                       pixman_box32_t rect)
+{
+       float x1, x2, y1, y2;
+
+       pixman_box32_t ret;
+
+       weston_transformed_coord(width, height, transform, scale,
+                                rect.x1, rect.y1, &x1, &y1);
+       weston_transformed_coord(width, height, transform, scale,
+                                rect.x2, rect.y2, &x2, &y2);
+
+       if (x1 <= x2) {
+               ret.x1 = x1;
+               ret.x2 = x2;
+       } else {
+               ret.x1 = x2;
+               ret.x2 = x1;
+       }
+
+       if (y1 <= y2) {
+               ret.y1 = y1;
+               ret.y2 = y2;
+       } else {
+               ret.y1 = y2;
+               ret.y2 = y1;
+       }
+
+       return ret;
+}
+
+/** Transform a region by a matrix, restricted to axis-aligned transformations
+ *
+ * Warning: This function does not work for projective, affine, or matrices
+ * that encode arbitrary rotations. Only 90-degree step rotations are
+ * supported.
+ */
+WL_EXPORT void
+weston_matrix_transform_region(pixman_region32_t *dest,
+                              struct weston_matrix *matrix,
+                              pixman_region32_t *src)
+{
+       pixman_box32_t *src_rects, *dest_rects;
+       int nrects, i;
+
+       src_rects = pixman_region32_rectangles(src, &nrects);
+       dest_rects = malloc(nrects * sizeof(*dest_rects));
+       if (!dest_rects)
+               return;
+
+       for (i = 0; i < nrects; i++) {
+               struct weston_vector vec1 = {{
+                       src_rects[i].x1, src_rects[i].y1, 0, 1
+               }};
+               weston_matrix_transform(matrix, &vec1);
+               vec1.f[0] /= vec1.f[3];
+               vec1.f[1] /= vec1.f[3];
+
+               struct weston_vector vec2 = {{
+                       src_rects[i].x2, src_rects[i].y2, 0, 1
+               }};
+               weston_matrix_transform(matrix, &vec2);
+               vec2.f[0] /= vec2.f[3];
+               vec2.f[1] /= vec2.f[3];
+
+               if (vec1.f[0] < vec2.f[0]) {
+                       dest_rects[i].x1 = floor(vec1.f[0]);
+                       dest_rects[i].x2 = ceil(vec2.f[0]);
+               } else {
+                       dest_rects[i].x1 = floor(vec2.f[0]);
+                       dest_rects[i].x2 = ceil(vec1.f[0]);
+               }
+
+               if (vec1.f[1] < vec2.f[1]) {
+                       dest_rects[i].y1 = floor(vec1.f[1]);
+                       dest_rects[i].y2 = ceil(vec2.f[1]);
+               } else {
+                       dest_rects[i].y1 = floor(vec2.f[1]);
+                       dest_rects[i].y2 = ceil(vec1.f[1]);
+               }
+       }
+
+       pixman_region32_clear(dest);
+       pixman_region32_init_rects(dest, dest_rects, nrects);
+       free(dest_rects);
+}
+
+WL_EXPORT void
+weston_transformed_region(int width, int height,
+                         enum wl_output_transform transform,
+                         int32_t scale,
+                         pixman_region32_t *src, pixman_region32_t *dest)
+{
+       pixman_box32_t *src_rects, *dest_rects;
+       int nrects, i;
+
+       if (transform == WL_OUTPUT_TRANSFORM_NORMAL && scale == 1) {
+               if (src != dest)
+                       pixman_region32_copy(dest, src);
+               return;
+       }
+
+       src_rects = pixman_region32_rectangles(src, &nrects);
+       dest_rects = malloc(nrects * sizeof(*dest_rects));
+       if (!dest_rects)
+               return;
+
+       if (transform == WL_OUTPUT_TRANSFORM_NORMAL) {
+               memcpy(dest_rects, src_rects, nrects * sizeof(*dest_rects));
+       } else {
+               for (i = 0; i < nrects; i++) {
+                       switch (transform) {
+                       default:
+                       case WL_OUTPUT_TRANSFORM_NORMAL:
+                               dest_rects[i].x1 = src_rects[i].x1;
+                               dest_rects[i].y1 = src_rects[i].y1;
+                               dest_rects[i].x2 = src_rects[i].x2;
+                               dest_rects[i].y2 = src_rects[i].y2;
+                               break;
+                       case WL_OUTPUT_TRANSFORM_90:
+                               dest_rects[i].x1 = height - src_rects[i].y2;
+                               dest_rects[i].y1 = src_rects[i].x1;
+                               dest_rects[i].x2 = height - src_rects[i].y1;
+                               dest_rects[i].y2 = src_rects[i].x2;
+                               break;
+                       case WL_OUTPUT_TRANSFORM_180:
+                               dest_rects[i].x1 = width - src_rects[i].x2;
+                               dest_rects[i].y1 = height - src_rects[i].y2;
+                               dest_rects[i].x2 = width - src_rects[i].x1;
+                               dest_rects[i].y2 = height - src_rects[i].y1;
+                               break;
+                       case WL_OUTPUT_TRANSFORM_270:
+                               dest_rects[i].x1 = src_rects[i].y1;
+                               dest_rects[i].y1 = width - src_rects[i].x2;
+                               dest_rects[i].x2 = src_rects[i].y2;
+                               dest_rects[i].y2 = width - src_rects[i].x1;
+                               break;
+                       case WL_OUTPUT_TRANSFORM_FLIPPED:
+                               dest_rects[i].x1 = width - src_rects[i].x2;
+                               dest_rects[i].y1 = src_rects[i].y1;
+                               dest_rects[i].x2 = width - src_rects[i].x1;
+                               dest_rects[i].y2 = src_rects[i].y2;
+                               break;
+                       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+                               dest_rects[i].x1 = height - src_rects[i].y2;
+                               dest_rects[i].y1 = width - src_rects[i].x2;
+                               dest_rects[i].x2 = height - src_rects[i].y1;
+                               dest_rects[i].y2 = width - src_rects[i].x1;
+                               break;
+                       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+                               dest_rects[i].x1 = src_rects[i].x1;
+                               dest_rects[i].y1 = height - src_rects[i].y2;
+                               dest_rects[i].x2 = src_rects[i].x2;
+                               dest_rects[i].y2 = height - src_rects[i].y1;
+                               break;
+                       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+                               dest_rects[i].x1 = src_rects[i].y1;
+                               dest_rects[i].y1 = src_rects[i].x1;
+                               dest_rects[i].x2 = src_rects[i].y2;
+                               dest_rects[i].y2 = src_rects[i].x2;
+                               break;
+                       }
+               }
+       }
+
+       if (scale != 1) {
+               for (i = 0; i < nrects; i++) {
+                       dest_rects[i].x1 *= scale;
+                       dest_rects[i].x2 *= scale;
+                       dest_rects[i].y1 *= scale;
+                       dest_rects[i].y2 *= scale;
+               }
+       }
+
+       pixman_region32_clear(dest);
+       pixman_region32_init_rects(dest, dest_rects, nrects);
+       free(dest_rects);
+}
+
+static void
+viewport_surface_to_buffer(struct weston_surface *surface,
+                          float sx, float sy, float *bx, float *by)
+{
+       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
+       double src_width, src_height;
+       double src_x, src_y;
+
+       if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
+               if (vp->surface.width == -1) {
+                       *bx = sx;
+                       *by = sy;
+                       return;
+               }
+
+               src_x = 0.0;
+               src_y = 0.0;
+               src_width = surface->width_from_buffer;
+               src_height = surface->height_from_buffer;
+       } else {
+               src_x = wl_fixed_to_double(vp->buffer.src_x);
+               src_y = wl_fixed_to_double(vp->buffer.src_y);
+               src_width = wl_fixed_to_double(vp->buffer.src_width);
+               src_height = wl_fixed_to_double(vp->buffer.src_height);
+       }
+
+       *bx = sx * src_width / surface->width + src_x;
+       *by = sy * src_height / surface->height + src_y;
+}
+
+WL_EXPORT void
+weston_surface_to_buffer_float(struct weston_surface *surface,
+                              float sx, float sy, float *bx, float *by)
+{
+       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
+
+       /* first transform coordinates if the viewport is set */
+       viewport_surface_to_buffer(surface, sx, sy, bx, by);
+
+       weston_transformed_coord(surface->width_from_buffer,
+                                surface->height_from_buffer,
+                                vp->buffer.transform, vp->buffer.scale,
+                                *bx, *by, bx, by);
+}
+
+/** Transform a rectangle from surface coordinates to buffer coordinates
+ *
+ * \param surface The surface to fetch wp_viewport and buffer transformation
+ * from.
+ * \param rect The rectangle to transform.
+ * \return The transformed rectangle.
+ *
+ * Viewport and buffer transformations can only do translation, scaling,
+ * and rotations in 90-degree steps. Therefore the only loss in the
+ * conversion is coordinate rounding.
+ *
+ * However, some coordinate rounding takes place as an intermediate
+ * step before the buffer scale factor is applied, so the rectangle
+ * boundary may not be exactly as expected.
+ *
+ * This is OK for damage tracking since a little extra coverage is
+ * not a problem.
+ */
+WL_EXPORT pixman_box32_t
+weston_surface_to_buffer_rect(struct weston_surface *surface,
+                             pixman_box32_t rect)
+{
+       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
+       float xf, yf;
+
+       /* first transform box coordinates if the viewport is set */
+       viewport_surface_to_buffer(surface, rect.x1, rect.y1, &xf, &yf);
+       rect.x1 = floorf(xf);
+       rect.y1 = floorf(yf);
+
+       viewport_surface_to_buffer(surface, rect.x2, rect.y2, &xf, &yf);
+       rect.x2 = ceilf(xf);
+       rect.y2 = ceilf(yf);
+
+       return weston_transformed_rect(surface->width_from_buffer,
+                                      surface->height_from_buffer,
+                                      vp->buffer.transform, vp->buffer.scale,
+                                      rect);
+}
+
+/** Transform a region from surface coordinates to buffer coordinates
+ *
+ * \param surface The surface to fetch wp_viewport and buffer transformation
+ * from.
+ * \param surface_region[in] The region in surface coordinates.
+ * \param buffer_region[out] The region converted to buffer coordinates.
+ *
+ * Buffer_region must be init'd, but will be completely overwritten.
+ *
+ * Viewport and buffer transformations can only do translation, scaling,
+ * and rotations in 90-degree steps. Therefore the only loss in the
+ * conversion is from the coordinate rounding that takes place in
+ * \ref weston_surface_to_buffer_rect.
+ */
+WL_EXPORT void
+weston_surface_to_buffer_region(struct weston_surface *surface,
+                               pixman_region32_t *surface_region,
+                               pixman_region32_t *buffer_region)
+{
+       pixman_box32_t *src_rects, *dest_rects;
+       int nrects, i;
+
+       src_rects = pixman_region32_rectangles(surface_region, &nrects);
+       dest_rects = malloc(nrects * sizeof(*dest_rects));
+       if (!dest_rects)
+               return;
+
+       for (i = 0; i < nrects; i++) {
+               dest_rects[i] = weston_surface_to_buffer_rect(surface,
+                                                             src_rects[i]);
+       }
+
+       pixman_region32_fini(buffer_region);
+       pixman_region32_init_rects(buffer_region, dest_rects, nrects);
+       free(dest_rects);
+}
+
+WL_EXPORT void
+weston_view_move_to_plane(struct weston_view *view,
+                            struct weston_plane *plane)
+{
+       if (view->plane == plane)
+               return;
+
+       weston_view_damage_below(view);
+       view->plane = plane;
+       weston_surface_damage(view->surface);
+}
+
+/** Inflict damage on the plane where the view is visible.
+ *
+ * \param view The view that causes the damage.
+ *
+ * If the view is currently on a plane (including the primary plane),
+ * take the view's boundingbox, subtract all the opaque views that cover it,
+ * and add the remaining region as damage to the plane. This corresponds
+ * to the damage inflicted to the plane if this view disappeared.
+ *
+ * A repaint is scheduled for this view.
+ *
+ * The region of all opaque views covering this view is stored in
+ * weston_view::clip and updated by view_accumulate_damage() during
+ * weston_output_repaint(). Specifically, that region matches the
+ * scenegraph as it was last painted.
+ */
+WL_EXPORT void
+weston_view_damage_below(struct weston_view *view)
+{
+       pixman_region32_t damage;
+
+       pixman_region32_init(&damage);
+       pixman_region32_subtract(&damage, &view->transform.boundingbox,
+                                &view->clip);
+       if (view->plane)
+               pixman_region32_union(&view->plane->damage,
+                                     &view->plane->damage, &damage);
+       pixman_region32_fini(&damage);
+       weston_view_schedule_repaint(view);
+}
+
+/**
+ * \param es    The surface
+ * \param mask  The new set of outputs for the surface
+ *
+ * Sets the surface's set of outputs to the ones specified by
+ * the new output mask provided.  Identifies the outputs that
+ * have changed, the posts enter and leave events for these
+ * outputs as appropriate.
+ */
+static void
+weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
+{
+       uint32_t different = es->output_mask ^ mask;
+       uint32_t entered = mask & different;
+       uint32_t left = es->output_mask & different;
+       struct weston_output *output;
+       struct wl_resource *resource = NULL;
+       struct wl_client *client;
+
+       es->output_mask = mask;
+       if (es->resource == NULL)
+               return;
+       if (different == 0)
+               return;
+
+       client = wl_resource_get_client(es->resource);
+
+       wl_list_for_each(output, &es->compositor->output_list, link) {
+               if (1u << output->id & different)
+                       resource =
+                               wl_resource_find_for_client(&output->resource_list,
+                                                        client);
+               if (resource == NULL)
+                       continue;
+               if (1u << output->id & entered)
+                       wl_surface_send_enter(es->resource, resource);
+               if (1u << output->id & left)
+                       wl_surface_send_leave(es->resource, resource);
+       }
+}
+
+/** Recalculate which output(s) the surface has views displayed on
+ *
+ * \param es  The surface to remap to outputs
+ *
+ * Finds the output that is showing the largest amount of one
+ * of the surface's various views.  This output becomes the
+ * surface's primary output for vsync and frame callback purposes.
+ *
+ * Also notes all outputs of all of the surface's views
+ * in the output_mask for the surface.
+ */
+static void
+weston_surface_assign_output(struct weston_surface *es)
+{
+       struct weston_output *new_output;
+       struct weston_view *view;
+       pixman_region32_t region;
+       uint32_t max, area, mask;
+       pixman_box32_t *e;
+
+       new_output = NULL;
+       max = 0;
+       mask = 0;
+       pixman_region32_init(&region);
+       wl_list_for_each(view, &es->views, surface_link) {
+               if (!view->output)
+                       continue;
+
+               pixman_region32_intersect(&region, &view->transform.boundingbox,
+                                         &view->output->region);
+
+               e = pixman_region32_extents(&region);
+               area = (e->x2 - e->x1) * (e->y2 - e->y1);
+
+               mask |= view->output_mask;
+
+               if (area >= max) {
+                       new_output = view->output;
+                       max = area;
+               }
+       }
+       pixman_region32_fini(&region);
+
+       es->output = new_output;
+       weston_surface_update_output_mask(es, mask);
+}
+
+/** Recalculate which output(s) the view is displayed on
+ *
+ * \param ev  The view to remap to outputs
+ *
+ * Identifies the set of outputs that the view is visible on,
+ * noting them into the output_mask.  The output that the view
+ * is most visible on is set as the view's primary output.
+ *
+ * Also does the same for the view's surface.  See
+ * weston_surface_assign_output().
+ */
+static void
+weston_view_assign_output(struct weston_view *ev)
+{
+       struct weston_compositor *ec = ev->surface->compositor;
+       struct weston_output *output, *new_output;
+       pixman_region32_t region;
+       uint32_t max, area, mask;
+       pixman_box32_t *e;
+
+       new_output = NULL;
+       max = 0;
+       mask = 0;
+       pixman_region32_init(&region);
+       wl_list_for_each(output, &ec->output_list, link) {
+               if (output->destroying)
+                       continue;
+
+               pixman_region32_intersect(&region, &ev->transform.boundingbox,
+                                         &output->region);
+
+               e = pixman_region32_extents(&region);
+               area = (e->x2 - e->x1) * (e->y2 - e->y1);
+
+               if (area > 0)
+                       mask |= 1u << output->id;
+
+               if (area >= max) {
+                       new_output = output;
+                       max = area;
+               }
+       }
+       pixman_region32_fini(&region);
+
+       ev->output = new_output;
+       ev->output_mask = mask;
+
+       weston_surface_assign_output(ev->surface);
+}
+
+static void
+weston_view_to_view_map(struct weston_view *from, struct weston_view *to,
+                       int from_x, int from_y, int *to_x, int *to_y)
+{
+       float x, y;
+
+       weston_view_to_global_float(from, from_x, from_y, &x, &y);
+       weston_view_from_global_float(to, x, y, &x, &y);
+
+       *to_x = round(x);
+       *to_y = round(y);
+}
+
+static void
+weston_view_transfer_scissor(struct weston_view *from, struct weston_view *to)
+{
+       pixman_box32_t *a;
+       pixman_box32_t b;
+
+       a = pixman_region32_extents(&from->geometry.scissor);
+
+       weston_view_to_view_map(from, to, a->x1, a->y1, &b.x1, &b.y1);
+       weston_view_to_view_map(from, to, a->x2, a->y2, &b.x2, &b.y2);
+
+       pixman_region32_fini(&to->geometry.scissor);
+       pixman_region32_init_with_extents(&to->geometry.scissor, &b);
+}
+
+static void
+view_compute_bbox(struct weston_view *view, const pixman_box32_t *inbox,
+                 pixman_region32_t *bbox)
+{
+       float min_x = HUGE_VALF,  min_y = HUGE_VALF;
+       float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
+       int32_t s[4][2] = {
+               { inbox->x1, inbox->y1 },
+               { inbox->x1, inbox->y2 },
+               { inbox->x2, inbox->y1 },
+               { inbox->x2, inbox->y2 },
+       };
+       float int_x, int_y;
+       int i;
+
+       if (inbox->x1 == inbox->x2 || inbox->y1 == inbox->y2) {
+               /* avoid rounding empty bbox to 1x1 */
+               pixman_region32_init(bbox);
+               return;
+       }
+
+       for (i = 0; i < 4; ++i) {
+               float x, y;
+               weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
+               if (x < min_x)
+                       min_x = x;
+               if (x > max_x)
+                       max_x = x;
+               if (y < min_y)
+                       min_y = y;
+               if (y > max_y)
+                       max_y = y;
+       }
+
+       int_x = floorf(min_x);
+       int_y = floorf(min_y);
+       pixman_region32_init_rect(bbox, int_x, int_y,
+                                 ceilf(max_x) - int_x, ceilf(max_y) - int_y);
+}
+
+static void
+weston_view_update_transform_disable(struct weston_view *view)
+{
+       view->transform.enabled = 0;
+
+       /* round off fractions when not transformed */
+       view->geometry.x = roundf(view->geometry.x);
+       view->geometry.y = roundf(view->geometry.y);
+
+       /* Otherwise identity matrix, but with x and y translation. */
+       view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
+       view->transform.position.matrix.d[12] = view->geometry.x;
+       view->transform.position.matrix.d[13] = view->geometry.y;
+
+       view->transform.matrix = view->transform.position.matrix;
+
+       view->transform.inverse = view->transform.position.matrix;
+       view->transform.inverse.d[12] = -view->geometry.x;
+       view->transform.inverse.d[13] = -view->geometry.y;
+
+       pixman_region32_init_rect(&view->transform.boundingbox,
+                                 0, 0,
+                                 view->surface->width,
+                                 view->surface->height);
+       if (view->geometry.scissor_enabled)
+               pixman_region32_intersect(&view->transform.boundingbox,
+                                         &view->transform.boundingbox,
+                                         &view->geometry.scissor);
+
+       pixman_region32_translate(&view->transform.boundingbox,
+                                 view->geometry.x, view->geometry.y);
+
+       if (view->alpha == 1.0) {
+               pixman_region32_copy(&view->transform.opaque,
+                                    &view->surface->opaque);
+               pixman_region32_translate(&view->transform.opaque,
+                                         view->geometry.x,
+                                         view->geometry.y);
+       }
+}
+
+static int
+weston_view_update_transform_enable(struct weston_view *view)
+{
+       struct weston_view *parent = view->geometry.parent;
+       struct weston_matrix *matrix = &view->transform.matrix;
+       struct weston_matrix *inverse = &view->transform.inverse;
+       struct weston_transform *tform;
+       pixman_region32_t surfregion;
+       const pixman_box32_t *surfbox;
+
+       view->transform.enabled = 1;
+
+       /* Otherwise identity matrix, but with x and y translation. */
+       view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
+       view->transform.position.matrix.d[12] = view->geometry.x;
+       view->transform.position.matrix.d[13] = view->geometry.y;
+
+       weston_matrix_init(matrix);
+       wl_list_for_each(tform, &view->geometry.transformation_list, link)
+               weston_matrix_multiply(matrix, &tform->matrix);
+
+       if (parent)
+               weston_matrix_multiply(matrix, &parent->transform.matrix);
+
+       if (weston_matrix_invert(inverse, matrix) < 0) {
+               /* Oops, bad total transformation, not invertible */
+               weston_log("error: weston_view %p"
+                       " transformation not invertible.\n", view);
+               return -1;
+       }
+
+       pixman_region32_init_rect(&surfregion, 0, 0,
+                                 view->surface->width, view->surface->height);
+       if (view->geometry.scissor_enabled)
+               pixman_region32_intersect(&surfregion, &surfregion,
+                                         &view->geometry.scissor);
+       surfbox = pixman_region32_extents(&surfregion);
+
+       view_compute_bbox(view, surfbox, &view->transform.boundingbox);
+       pixman_region32_fini(&surfregion);
+
+       return 0;
+}
+
+static struct weston_layer *
+get_view_layer(struct weston_view *view)
+{
+       if (view->parent_view)
+               return get_view_layer(view->parent_view);
+       return view->layer_link.layer;
+}
+
+WL_EXPORT void
+weston_view_update_transform(struct weston_view *view)
+{
+       struct weston_view *parent = view->geometry.parent;
+       struct weston_layer *layer;
+       pixman_region32_t mask;
+
+       if (!view->transform.dirty)
+               return;
+
+       if (parent)
+               weston_view_update_transform(parent);
+
+       view->transform.dirty = 0;
+
+       weston_view_damage_below(view);
+
+       pixman_region32_fini(&view->transform.boundingbox);
+       pixman_region32_fini(&view->transform.opaque);
+       pixman_region32_init(&view->transform.opaque);
+
+       /* transform.position is always in transformation_list */
+       if (view->geometry.transformation_list.next ==
+           &view->transform.position.link &&
+           view->geometry.transformation_list.prev ==
+           &view->transform.position.link &&
+           !parent) {
+               weston_view_update_transform_disable(view);
+       } else {
+               if (weston_view_update_transform_enable(view) < 0)
+                       weston_view_update_transform_disable(view);
+       }
+
+       layer = get_view_layer(view);
+       if (layer) {
+               pixman_region32_init_with_extents(&mask, &layer->mask);
+               pixman_region32_intersect(&view->transform.boundingbox,
+                                         &view->transform.boundingbox, &mask);
+               pixman_region32_intersect(&view->transform.opaque,
+                                         &view->transform.opaque, &mask);
+               pixman_region32_fini(&mask);
+       }
+
+       if (parent) {
+               if (parent->geometry.scissor_enabled) {
+                       view->geometry.scissor_enabled = true;
+                       weston_view_transfer_scissor(parent, view);
+               } else {
+                       view->geometry.scissor_enabled = false;
+               }
+       }
+
+       weston_view_damage_below(view);
+
+       weston_view_assign_output(view);
+
+       wl_signal_emit(&view->surface->compositor->transform_signal,
+                      view->surface);
+}
+
+WL_EXPORT void
+weston_view_geometry_dirty(struct weston_view *view)
+{
+       struct weston_view *child;
+
+       /*
+        * The invariant: if view->geometry.dirty, then all views
+        * in view->geometry.child_list have geometry.dirty too.
+        * Corollary: if not parent->geometry.dirty, then all ancestors
+        * are not dirty.
+        */
+
+       if (view->transform.dirty)
+               return;
+
+       view->transform.dirty = 1;
+
+       wl_list_for_each(child, &view->geometry.child_list,
+                        geometry.parent_link)
+               weston_view_geometry_dirty(child);
+}
+
+WL_EXPORT void
+weston_view_to_global_fixed(struct weston_view *view,
+                           wl_fixed_t vx, wl_fixed_t vy,
+                           wl_fixed_t *x, wl_fixed_t *y)
+{
+       float xf, yf;
+
+       weston_view_to_global_float(view,
+                                   wl_fixed_to_double(vx),
+                                   wl_fixed_to_double(vy),
+                                   &xf, &yf);
+       *x = wl_fixed_from_double(xf);
+       *y = wl_fixed_from_double(yf);
+}
+
+WL_EXPORT void
+weston_view_from_global_float(struct weston_view *view,
+                             float x, float y, float *vx, float *vy)
+{
+       if (view->transform.enabled) {
+               struct weston_vector v = { { x, y, 0.0f, 1.0f } };
+
+               weston_matrix_transform(&view->transform.inverse, &v);
+
+               if (fabsf(v.f[3]) < 1e-6) {
+                       weston_log("warning: numerical instability in "
+                               "weston_view_from_global(), divisor = %g\n",
+                               v.f[3]);
+                       *vx = 0;
+                       *vy = 0;
+                       return;
+               }
+
+               *vx = v.f[0] / v.f[3];
+               *vy = v.f[1] / v.f[3];
+       } else {
+               *vx = x - view->geometry.x;
+               *vy = y - view->geometry.y;
+       }
+}
+
+WL_EXPORT void
+weston_view_from_global_fixed(struct weston_view *view,
+                             wl_fixed_t x, wl_fixed_t y,
+                             wl_fixed_t *vx, wl_fixed_t *vy)
+{
+       float vxf, vyf;
+
+       weston_view_from_global_float(view,
+                                     wl_fixed_to_double(x),
+                                     wl_fixed_to_double(y),
+                                     &vxf, &vyf);
+       *vx = wl_fixed_from_double(vxf);
+       *vy = wl_fixed_from_double(vyf);
+}
+
+WL_EXPORT void
+weston_view_from_global(struct weston_view *view,
+                       int32_t x, int32_t y, int32_t *vx, int32_t *vy)
+{
+       float vxf, vyf;
+
+       weston_view_from_global_float(view, x, y, &vxf, &vyf);
+       *vx = floorf(vxf);
+       *vy = floorf(vyf);
+}
+
+/**
+ * \param surface  The surface to be repainted
+ *
+ * Marks the output(s) that the surface is shown on as needing to be
+ * repainted.  See weston_output_schedule_repaint().
+ */
+WL_EXPORT void
+weston_surface_schedule_repaint(struct weston_surface *surface)
+{
+       struct weston_output *output;
+
+       wl_list_for_each(output, &surface->compositor->output_list, link)
+               if (surface->output_mask & (1u << output->id))
+                       weston_output_schedule_repaint(output);
+}
+
+/**
+ * \param view  The view to be repainted
+ *
+ * Marks the output(s) that the view is shown on as needing to be
+ * repainted.  See weston_output_schedule_repaint().
+ */
+WL_EXPORT void
+weston_view_schedule_repaint(struct weston_view *view)
+{
+       struct weston_output *output;
+
+       wl_list_for_each(output, &view->surface->compositor->output_list, link)
+               if (view->output_mask & (1u << output->id))
+                       weston_output_schedule_repaint(output);
+}
+
+/**
+ * XXX: This function does it the wrong way.
+ * surface->damage is the damage from the client, and causes
+ * surface_flush_damage() to copy pixels. No window management action can
+ * cause damage to the client-provided content, warranting re-upload!
+ *
+ * Instead of surface->damage, this function should record the damage
+ * with all the views for this surface to avoid extraneous texture
+ * uploads.
+ */
+WL_EXPORT void
+weston_surface_damage(struct weston_surface *surface)
+{
+       pixman_region32_union_rect(&surface->damage, &surface->damage,
+                                  0, 0, surface->width,
+                                  surface->height);
+
+       weston_surface_schedule_repaint(surface);
+}
+
+WL_EXPORT void
+weston_view_set_position(struct weston_view *view, float x, float y)
+{
+       if (view->geometry.x == x && view->geometry.y == y)
+               return;
+
+       view->geometry.x = x;
+       view->geometry.y = y;
+       weston_view_geometry_dirty(view);
+}
+
+static void
+transform_parent_handle_parent_destroy(struct wl_listener *listener,
+                                      void *data)
+{
+       struct weston_view *view =
+               container_of(listener, struct weston_view,
+                            geometry.parent_destroy_listener);
+
+       weston_view_set_transform_parent(view, NULL);
+}
+
+WL_EXPORT void
+weston_view_set_transform_parent(struct weston_view *view,
+                                struct weston_view *parent)
+{
+       if (view->geometry.parent) {
+               wl_list_remove(&view->geometry.parent_destroy_listener.link);
+               wl_list_remove(&view->geometry.parent_link);
+
+               if (!parent)
+                       view->geometry.scissor_enabled = false;
+       }
+
+       view->geometry.parent = parent;
+
+       view->geometry.parent_destroy_listener.notify =
+               transform_parent_handle_parent_destroy;
+       if (parent) {
+               wl_signal_add(&parent->destroy_signal,
+                             &view->geometry.parent_destroy_listener);
+               wl_list_insert(&parent->geometry.child_list,
+                              &view->geometry.parent_link);
+       }
+
+       weston_view_geometry_dirty(view);
+}
+
+/** Set a clip mask rectangle on a view
+ *
+ * \param view The view to set the clip mask on.
+ * \param x Top-left corner X coordinate of the clip rectangle.
+ * \param y Top-left corner Y coordinate of the clip rectangle.
+ * \param width Width of the clip rectangle, non-negative.
+ * \param height Height of the clip rectangle, non-negative.
+ *
+ * A shell may set a clip mask rectangle on a view. Everything outside
+ * the rectangle is cut away for input and output purposes: it is
+ * not drawn and cannot be hit by hit-test based input like pointer
+ * motion or touch-downs. Everything inside the rectangle will behave
+ * normally. Clients are unaware of clipping.
+ *
+ * The rectangle is set in surface-local coordinates. Setting a clip
+ * mask rectangle does not affect the view position, the view is positioned
+ * as it would be without a clip. The clip also does not change
+ * weston_surface::width,height.
+ *
+ * The clip mask rectangle is part of transformation inheritance
+ * (weston_view_set_transform_parent()). A clip set in the root of the
+ * transformation inheritance tree will affect all views in the tree.
+ * A clip can be set only on the root view. Attempting to set a clip
+ * on view that has a transformation parent will fail. Assigning a parent
+ * to a view that has a clip set will cause the clip to be forgotten.
+ *
+ * Because the clip mask is an axis-aligned rectangle, it poses restrictions
+ * on the additional transformations in the child views. These transformations
+ * may not rotate the coordinate axes, i.e., only translation and scaling
+ * are allowed. Violating this restriction causes the clipping to malfunction.
+ * Furthermore, using scaling may cause rounding errors in child clipping.
+ *
+ * The clip mask rectangle is not automatically adjusted based on
+ * wl_surface.attach dx and dy arguments.
+ *
+ * A clip mask rectangle can be set only if the compositor capability
+ * WESTON_CAP_VIEW_CLIP_MASK is present.
+ *
+ * This function sets the clip mask rectangle and schedules a repaint for
+ * the view.
+ */
+WL_EXPORT void
+weston_view_set_mask(struct weston_view *view,
+                    int x, int y, int width, int height)
+{
+       struct weston_compositor *compositor = view->surface->compositor;
+
+       if (!(compositor->capabilities & WESTON_CAP_VIEW_CLIP_MASK)) {
+               weston_log("%s not allowed without capability!\n", __func__);
+               return;
+       }
+
+       if (view->geometry.parent) {
+               weston_log("view %p has a parent, clip forbidden!\n", view);
+               return;
+       }
+
+       if (width < 0 || height < 0) {
+               weston_log("%s: illegal args %d, %d, %d, %d\n", __func__,
+                          x, y, width, height);
+               return;
+       }
+
+       pixman_region32_fini(&view->geometry.scissor);
+       pixman_region32_init_rect(&view->geometry.scissor, x, y, width, height);
+       view->geometry.scissor_enabled = true;
+       weston_view_geometry_dirty(view);
+       weston_view_schedule_repaint(view);
+}
+
+/** Remove the clip mask from a view
+ *
+ * \param view The view to remove the clip mask from.
+ *
+ * Removed the clip mask rectangle and schedules a repaint.
+ *
+ * \sa weston_view_set_mask
+ */
+WL_EXPORT void
+weston_view_set_mask_infinite(struct weston_view *view)
+{
+       view->geometry.scissor_enabled = false;
+       weston_view_geometry_dirty(view);
+       weston_view_schedule_repaint(view);
+}
+
+WL_EXPORT bool
+weston_view_is_mapped(struct weston_view *view)
+{
+       if (view->output)
+               return true;
+       else
+               return false;
+}
+
+WL_EXPORT bool
+weston_surface_is_mapped(struct weston_surface *surface)
+{
+       if (surface->output)
+               return true;
+       else
+               return false;
+}
+
+static void
+surface_set_size(struct weston_surface *surface, int32_t width, int32_t height)
+{
+       struct weston_view *view;
+
+       if (surface->width == width && surface->height == height)
+               return;
+
+       surface->width = width;
+       surface->height = height;
+
+       wl_list_for_each(view, &surface->views, surface_link)
+               weston_view_geometry_dirty(view);
+}
+
+WL_EXPORT void
+weston_surface_set_size(struct weston_surface *surface,
+                       int32_t width, int32_t height)
+{
+       assert(!surface->resource);
+       surface_set_size(surface, width, height);
+}
+
+static int
+fixed_round_up_to_int(wl_fixed_t f)
+{
+       return wl_fixed_to_int(wl_fixed_from_int(1) - 1 + f);
+}
+
+static void
+convert_size_by_transform_scale(int32_t *width_out, int32_t *height_out,
+                               int32_t width, int32_t height,
+                               uint32_t transform,
+                               int32_t scale)
+{
+       assert(scale > 0);
+
+       switch (transform) {
+       case WL_OUTPUT_TRANSFORM_NORMAL:
+       case WL_OUTPUT_TRANSFORM_180:
+       case WL_OUTPUT_TRANSFORM_FLIPPED:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+               *width_out = width / scale;
+               *height_out = height / scale;
+               break;
+       case WL_OUTPUT_TRANSFORM_90:
+       case WL_OUTPUT_TRANSFORM_270:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               *width_out = height / scale;
+               *height_out = width / scale;
+               break;
+       default:
+               assert(0 && "invalid transform");
+       }
+}
+
+static void
+weston_surface_calculate_size_from_buffer(struct weston_surface *surface)
+{
+       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
+
+       if (!surface->buffer_ref.buffer) {
+               surface->width_from_buffer = 0;
+               surface->height_from_buffer = 0;
+               return;
+       }
+
+       convert_size_by_transform_scale(&surface->width_from_buffer,
+                                       &surface->height_from_buffer,
+                                       surface->buffer_ref.buffer->width,
+                                       surface->buffer_ref.buffer->height,
+                                       vp->buffer.transform,
+                                       vp->buffer.scale);
+}
+
+static void
+weston_surface_update_size(struct weston_surface *surface)
+{
+       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
+       int32_t width, height;
+
+       width = surface->width_from_buffer;
+       height = surface->height_from_buffer;
+
+       if (width != 0 && vp->surface.width != -1) {
+               surface_set_size(surface,
+                                vp->surface.width, vp->surface.height);
+               return;
+       }
+
+       if (width != 0 && vp->buffer.src_width != wl_fixed_from_int(-1)) {
+               int32_t w = fixed_round_up_to_int(vp->buffer.src_width);
+               int32_t h = fixed_round_up_to_int(vp->buffer.src_height);
+
+               surface_set_size(surface, w ?: 1, h ?: 1);
+               return;
+       }
+
+       surface_set_size(surface, width, height);
+}
+
+WL_EXPORT uint32_t
+weston_compositor_get_time(void)
+{
+       struct timeval tv;
+
+       gettimeofday(&tv, NULL);
+
+       return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+}
+
+WL_EXPORT struct weston_view *
+weston_compositor_pick_view(struct weston_compositor *compositor,
+                           wl_fixed_t x, wl_fixed_t y,
+                           wl_fixed_t *vx, wl_fixed_t *vy)
+{
+       struct weston_view *view;
+       wl_fixed_t view_x, view_y;
+       int view_ix, view_iy;
+       int ix = wl_fixed_to_int(x);
+       int iy = wl_fixed_to_int(y);
+
+       wl_list_for_each(view, &compositor->view_list, link) {
+               if (!pixman_region32_contains_point(
+                               &view->transform.boundingbox, ix, iy, NULL))
+                       continue;
+
+               weston_view_from_global_fixed(view, x, y, &view_x, &view_y);
+               view_ix = wl_fixed_to_int(view_x);
+               view_iy = wl_fixed_to_int(view_y);
+
+               if (!pixman_region32_contains_point(&view->surface->input,
+                                                   view_ix, view_iy, NULL))
+                       continue;
+
+               if (view->geometry.scissor_enabled &&
+                   !pixman_region32_contains_point(&view->geometry.scissor,
+                                                   view_ix, view_iy, NULL))
+                       continue;
+
+               *vx = view_x;
+               *vy = view_y;
+               return view;
+       }
+
+       *vx = wl_fixed_from_int(-1000000);
+       *vy = wl_fixed_from_int(-1000000);
+       return NULL;
+}
+
+static void
+weston_compositor_repick(struct weston_compositor *compositor)
+{
+       struct weston_seat *seat;
+
+       if (!compositor->session_active)
+               return;
+
+       wl_list_for_each(seat, &compositor->seat_list, link)
+               weston_seat_repick(seat);
+}
+
+WL_EXPORT void
+weston_view_unmap(struct weston_view *view)
+{
+       struct weston_seat *seat;
+
+       if (!weston_view_is_mapped(view))
+               return;
+
+       weston_view_damage_below(view);
+       view->output = NULL;
+       view->plane = NULL;
+       weston_layer_entry_remove(&view->layer_link);
+       wl_list_remove(&view->link);
+       wl_list_init(&view->link);
+       view->output_mask = 0;
+       weston_surface_assign_output(view->surface);
+
+       if (weston_surface_is_mapped(view->surface))
+               return;
+
+       wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
+               struct weston_touch *touch = weston_seat_get_touch(seat);
+               struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+               struct weston_keyboard *keyboard =
+                       weston_seat_get_keyboard(seat);
+
+               if (keyboard && keyboard->focus == view->surface)
+                       weston_keyboard_set_focus(keyboard, NULL);
+               if (pointer && pointer->focus == view)
+                       weston_pointer_clear_focus(pointer);
+               if (touch && touch->focus == view)
+                       weston_touch_set_focus(touch, NULL);
+       }
+}
+
+WL_EXPORT void
+weston_surface_unmap(struct weston_surface *surface)
+{
+       struct weston_view *view;
+
+       wl_list_for_each(view, &surface->views, surface_link)
+               weston_view_unmap(view);
+       surface->output = NULL;
+}
+
+static void
+weston_surface_reset_pending_buffer(struct weston_surface *surface)
+{
+       weston_surface_state_set_buffer(&surface->pending, NULL);
+       surface->pending.sx = 0;
+       surface->pending.sy = 0;
+       surface->pending.newly_attached = 0;
+       surface->pending.buffer_viewport.changed = 0;
+}
+
+WL_EXPORT void
+weston_view_destroy(struct weston_view *view)
+{
+       wl_signal_emit(&view->destroy_signal, view);
+
+       assert(wl_list_empty(&view->geometry.child_list));
+
+       if (weston_view_is_mapped(view)) {
+               weston_view_unmap(view);
+               weston_compositor_build_view_list(view->surface->compositor);
+       }
+
+       wl_list_remove(&view->link);
+       weston_layer_entry_remove(&view->layer_link);
+
+       pixman_region32_fini(&view->clip);
+       pixman_region32_fini(&view->geometry.scissor);
+       pixman_region32_fini(&view->transform.boundingbox);
+       pixman_region32_fini(&view->transform.opaque);
+
+       weston_view_set_transform_parent(view, NULL);
+
+       wl_list_remove(&view->surface_link);
+
+       free(view);
+}
+
+WL_EXPORT void
+weston_surface_destroy(struct weston_surface *surface)
+{
+       struct weston_frame_callback *cb, *next;
+       struct weston_view *ev, *nv;
+
+       if (--surface->ref_count > 0)
+               return;
+
+       assert(surface->resource == NULL);
+
+       wl_signal_emit(&surface->destroy_signal, surface);
+
+       assert(wl_list_empty(&surface->subsurface_list_pending));
+       assert(wl_list_empty(&surface->subsurface_list));
+
+       wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
+               weston_view_destroy(ev);
+
+       weston_surface_state_fini(&surface->pending);
+
+       weston_buffer_reference(&surface->buffer_ref, NULL);
+
+       pixman_region32_fini(&surface->damage);
+       pixman_region32_fini(&surface->opaque);
+       pixman_region32_fini(&surface->input);
+
+       wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link)
+               wl_resource_destroy(cb->resource);
+
+       weston_presentation_feedback_discard_list(&surface->feedback_list);
+
+       free(surface);
+}
+
+static void
+destroy_surface(struct wl_resource *resource)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+
+       assert(surface);
+
+       /* Set the resource to NULL, since we don't want to leave a
+        * dangling pointer if the surface was refcounted and survives
+        * the weston_surface_destroy() call. */
+       surface->resource = NULL;
+
+       if (surface->viewport_resource)
+               wl_resource_set_user_data(surface->viewport_resource, NULL);
+
+       weston_surface_destroy(surface);
+}
+
+static void
+weston_buffer_destroy_handler(struct wl_listener *listener, void *data)
+{
+       struct weston_buffer *buffer =
+               container_of(listener, struct weston_buffer, destroy_listener);
+
+       wl_signal_emit(&buffer->destroy_signal, buffer);
+       free(buffer);
+}
+
+WL_EXPORT struct weston_buffer *
+weston_buffer_from_resource(struct wl_resource *resource)
+{
+       struct weston_buffer *buffer;
+       struct wl_listener *listener;
+
+       listener = wl_resource_get_destroy_listener(resource,
+                                                   weston_buffer_destroy_handler);
+
+       if (listener)
+               return container_of(listener, struct weston_buffer,
+                                   destroy_listener);
+
+       buffer = zalloc(sizeof *buffer);
+       if (buffer == NULL)
+               return NULL;
+
+       buffer->resource = resource;
+       wl_signal_init(&buffer->destroy_signal);
+       buffer->destroy_listener.notify = weston_buffer_destroy_handler;
+       buffer->y_inverted = 1;
+       wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
+
+       return buffer;
+}
+
+static void
+weston_buffer_reference_handle_destroy(struct wl_listener *listener,
+                                      void *data)
+{
+       struct weston_buffer_reference *ref =
+               container_of(listener, struct weston_buffer_reference,
+                            destroy_listener);
+
+       assert((struct weston_buffer *)data == ref->buffer);
+       ref->buffer = NULL;
+}
+
+WL_EXPORT void
+weston_buffer_reference(struct weston_buffer_reference *ref,
+                       struct weston_buffer *buffer)
+{
+       if (ref->buffer && buffer != ref->buffer) {
+               ref->buffer->busy_count--;
+               if (ref->buffer->busy_count == 0) {
+                       assert(wl_resource_get_client(ref->buffer->resource));
+                       wl_resource_queue_event(ref->buffer->resource,
+                                               WL_BUFFER_RELEASE);
+               }
+               wl_list_remove(&ref->destroy_listener.link);
+       }
+
+       if (buffer && buffer != ref->buffer) {
+               buffer->busy_count++;
+               wl_signal_add(&buffer->destroy_signal,
+                             &ref->destroy_listener);
+       }
+
+       ref->buffer = buffer;
+       ref->destroy_listener.notify = weston_buffer_reference_handle_destroy;
+}
+
+static void
+weston_surface_attach(struct weston_surface *surface,
+                     struct weston_buffer *buffer)
+{
+       weston_buffer_reference(&surface->buffer_ref, buffer);
+
+       if (!buffer) {
+               if (weston_surface_is_mapped(surface))
+                       weston_surface_unmap(surface);
+       }
+
+       surface->compositor->renderer->attach(surface, buffer);
+
+       weston_surface_calculate_size_from_buffer(surface);
+       weston_presentation_feedback_discard_list(&surface->feedback_list);
+}
+
+WL_EXPORT void
+weston_compositor_damage_all(struct weston_compositor *compositor)
+{
+       struct weston_output *output;
+
+       wl_list_for_each(output, &compositor->output_list, link)
+               weston_output_damage(output);
+}
+
+WL_EXPORT void
+weston_output_damage(struct weston_output *output)
+{
+       struct weston_compositor *compositor = output->compositor;
+
+       pixman_region32_union(&compositor->primary_plane.damage,
+                             &compositor->primary_plane.damage,
+                             &output->region);
+       weston_output_schedule_repaint(output);
+}
+
+static void
+surface_flush_damage(struct weston_surface *surface)
+{
+       if (surface->buffer_ref.buffer &&
+           wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
+               surface->compositor->renderer->flush_damage(surface);
+
+       if (weston_timeline_enabled_ &&
+           pixman_region32_not_empty(&surface->damage))
+               TL_POINT("core_flush_damage", TLP_SURFACE(surface),
+                        TLP_OUTPUT(surface->output), TLP_END);
+
+       pixman_region32_clear(&surface->damage);
+}
+
+static void
+view_accumulate_damage(struct weston_view *view,
+                      pixman_region32_t *opaque)
+{
+       pixman_region32_t damage;
+
+       pixman_region32_init(&damage);
+       if (view->transform.enabled) {
+               pixman_box32_t *extents;
+
+               extents = pixman_region32_extents(&view->surface->damage);
+               view_compute_bbox(view, extents, &damage);
+       } else {
+               pixman_region32_copy(&damage, &view->surface->damage);
+               pixman_region32_translate(&damage,
+                                         view->geometry.x, view->geometry.y);
+       }
+
+       pixman_region32_intersect(&damage, &damage,
+                                 &view->transform.boundingbox);
+       pixman_region32_subtract(&damage, &damage, opaque);
+       pixman_region32_union(&view->plane->damage,
+                             &view->plane->damage, &damage);
+       pixman_region32_fini(&damage);
+       pixman_region32_copy(&view->clip, opaque);
+       pixman_region32_union(opaque, opaque, &view->transform.opaque);
+}
+
+static void
+compositor_accumulate_damage(struct weston_compositor *ec)
+{
+       struct weston_plane *plane;
+       struct weston_view *ev;
+       pixman_region32_t opaque, clip;
+
+       pixman_region32_init(&clip);
+
+       wl_list_for_each(plane, &ec->plane_list, link) {
+               pixman_region32_copy(&plane->clip, &clip);
+
+               pixman_region32_init(&opaque);
+
+               wl_list_for_each(ev, &ec->view_list, link) {
+                       if (ev->plane != plane)
+                               continue;
+
+                       view_accumulate_damage(ev, &opaque);
+               }
+
+               pixman_region32_union(&clip, &clip, &opaque);
+               pixman_region32_fini(&opaque);
+       }
+
+       pixman_region32_fini(&clip);
+
+       wl_list_for_each(ev, &ec->view_list, link)
+               ev->surface->touched = false;
+
+       wl_list_for_each(ev, &ec->view_list, link) {
+               if (ev->surface->touched)
+                       continue;
+               ev->surface->touched = true;
+
+               surface_flush_damage(ev->surface);
+
+               /* Both the renderer and the backend have seen the buffer
+                * by now. If renderer needs the buffer, it has its own
+                * reference set. If the backend wants to keep the buffer
+                * around for migrating the surface into a non-primary plane
+                * later, keep_buffer is true. Otherwise, drop the core
+                * reference now, and allow early buffer release. This enables
+                * clients to use single-buffering.
+                */
+               if (!ev->surface->keep_buffer)
+                       weston_buffer_reference(&ev->surface->buffer_ref, NULL);
+       }
+}
+
+static void
+surface_stash_subsurface_views(struct weston_surface *surface)
+{
+       struct weston_subsurface *sub;
+
+       wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
+               if (sub->surface == surface)
+                       continue;
+
+               wl_list_insert_list(&sub->unused_views, &sub->surface->views);
+               wl_list_init(&sub->surface->views);
+
+               surface_stash_subsurface_views(sub->surface);
+       }
+}
+
+static void
+surface_free_unused_subsurface_views(struct weston_surface *surface)
+{
+       struct weston_subsurface *sub;
+       struct weston_view *view, *nv;
+
+       wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
+               if (sub->surface == surface)
+                       continue;
+
+               wl_list_for_each_safe(view, nv, &sub->unused_views, surface_link) {
+                       weston_view_unmap (view);
+                       weston_view_destroy(view);
+               }
+
+               surface_free_unused_subsurface_views(sub->surface);
+       }
+}
+
+static void
+view_list_add_subsurface_view(struct weston_compositor *compositor,
+                             struct weston_subsurface *sub,
+                             struct weston_view *parent)
+{
+       struct weston_subsurface *child;
+       struct weston_view *view = NULL, *iv;
+
+       if (!weston_surface_is_mapped(sub->surface))
+               return;
+
+       wl_list_for_each(iv, &sub->unused_views, surface_link) {
+               if (iv->geometry.parent == parent) {
+                       view = iv;
+                       break;
+               }
+       }
+
+       if (view) {
+               /* Put it back in the surface's list of views */
+               wl_list_remove(&view->surface_link);
+               wl_list_insert(&sub->surface->views, &view->surface_link);
+       } else {
+               view = weston_view_create(sub->surface);
+               weston_view_set_position(view,
+                                        sub->position.x,
+                                        sub->position.y);
+               weston_view_set_transform_parent(view, parent);
+       }
+
+       view->parent_view = parent;
+       weston_view_update_transform(view);
+
+       if (wl_list_empty(&sub->surface->subsurface_list)) {
+               wl_list_insert(compositor->view_list.prev, &view->link);
+               return;
+       }
+
+       wl_list_for_each(child, &sub->surface->subsurface_list, parent_link) {
+               if (child->surface == sub->surface)
+                       wl_list_insert(compositor->view_list.prev, &view->link);
+               else
+                       view_list_add_subsurface_view(compositor, child, view);
+       }
+}
+
+static void
+view_list_add(struct weston_compositor *compositor,
+             struct weston_view *view)
+{
+       struct weston_subsurface *sub;
+
+       weston_view_update_transform(view);
+
+       if (wl_list_empty(&view->surface->subsurface_list)) {
+               wl_list_insert(compositor->view_list.prev, &view->link);
+               return;
+       }
+
+       wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
+               if (sub->surface == view->surface)
+                       wl_list_insert(compositor->view_list.prev, &view->link);
+               else
+                       view_list_add_subsurface_view(compositor, sub, view);
+       }
+}
+
+static void
+weston_compositor_build_view_list(struct weston_compositor *compositor)
+{
+       struct weston_view *view;
+       struct weston_layer *layer;
+
+       wl_list_for_each(layer, &compositor->layer_list, link)
+               wl_list_for_each(view, &layer->view_list.link, layer_link.link)
+                       surface_stash_subsurface_views(view->surface);
+
+       wl_list_init(&compositor->view_list);
+       wl_list_for_each(layer, &compositor->layer_list, link) {
+               wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
+                       view_list_add(compositor, view);
+               }
+       }
+
+       wl_list_for_each(layer, &compositor->layer_list, link)
+               wl_list_for_each(view, &layer->view_list.link, layer_link.link)
+                       surface_free_unused_subsurface_views(view->surface);
+}
+
+static void
+weston_output_take_feedback_list(struct weston_output *output,
+                                struct weston_surface *surface)
+{
+       struct weston_view *view;
+       struct weston_presentation_feedback *feedback;
+       uint32_t flags = 0xffffffff;
+
+       if (wl_list_empty(&surface->feedback_list))
+               return;
+
+       /* All views must have the flag for the flag to survive. */
+       wl_list_for_each(view, &surface->views, surface_link) {
+               /* ignore views that are not on this output at all */
+               if (view->output_mask & (1u << output->id))
+                       flags &= view->psf_flags;
+       }
+
+       wl_list_for_each(feedback, &surface->feedback_list, link)
+               feedback->psf_flags = flags;
+
+       wl_list_insert_list(&output->feedback_list, &surface->feedback_list);
+       wl_list_init(&surface->feedback_list);
+}
+
+static int
+weston_output_repaint(struct weston_output *output)
+{
+       struct weston_compositor *ec = output->compositor;
+       struct weston_view *ev;
+       struct weston_animation *animation, *next;
+       struct weston_frame_callback *cb, *cnext;
+       struct wl_list frame_callback_list;
+       pixman_region32_t output_damage;
+       int r;
+
+       if (output->destroying)
+               return 0;
+
+       TL_POINT("core_repaint_begin", TLP_OUTPUT(output), TLP_END);
+
+       /* Rebuild the surface list and update surface transforms up front. */
+       weston_compositor_build_view_list(ec);
+
+       if (output->assign_planes && !output->disable_planes) {
+               output->assign_planes(output);
+       } else {
+               wl_list_for_each(ev, &ec->view_list, link) {
+                       weston_view_move_to_plane(ev, &ec->primary_plane);
+                       ev->psf_flags = 0;
+               }
+       }
+
+       wl_list_init(&frame_callback_list);
+       wl_list_for_each(ev, &ec->view_list, link) {
+               /* Note: This operation is safe to do multiple times on the
+                * same surface.
+                */
+               if (ev->surface->output == output) {
+                       wl_list_insert_list(&frame_callback_list,
+                                           &ev->surface->frame_callback_list);
+                       wl_list_init(&ev->surface->frame_callback_list);
+
+                       weston_output_take_feedback_list(output, ev->surface);
+               }
+       }
+
+       compositor_accumulate_damage(ec);
+
+       pixman_region32_init(&output_damage);
+       pixman_region32_intersect(&output_damage,
+                                 &ec->primary_plane.damage, &output->region);
+       pixman_region32_subtract(&output_damage,
+                                &output_damage, &ec->primary_plane.clip);
+
+       if (output->dirty)
+               weston_output_update_matrix(output);
+
+       r = output->repaint(output, &output_damage);
+
+       pixman_region32_fini(&output_damage);
+
+       output->repaint_needed = 0;
+
+       weston_compositor_repick(ec);
+
+       wl_list_for_each_safe(cb, cnext, &frame_callback_list, link) {
+               wl_callback_send_done(cb->resource, output->frame_time);
+               wl_resource_destroy(cb->resource);
+       }
+
+       wl_list_for_each_safe(animation, next, &output->animation_list, link) {
+               animation->frame_counter++;
+               animation->frame(animation, output, output->frame_time);
+       }
+
+       TL_POINT("core_repaint_posted", TLP_OUTPUT(output), TLP_END);
+
+       return r;
+}
+
+static void
+weston_output_schedule_repaint_reset(struct weston_output *output)
+{
+       output->repaint_scheduled = 0;
+       TL_POINT("core_repaint_exit_loop", TLP_OUTPUT(output), TLP_END);
+}
+
+static int
+output_repaint_timer_handler(void *data)
+{
+       struct weston_output *output = data;
+       struct weston_compositor *compositor = output->compositor;
+
+       if (output->repaint_needed &&
+           compositor->state != WESTON_COMPOSITOR_SLEEPING &&
+           compositor->state != WESTON_COMPOSITOR_OFFSCREEN &&
+           weston_output_repaint(output) == 0)
+               return 0;
+
+       weston_output_schedule_repaint_reset(output);
+
+       return 0;
+}
+
+WL_EXPORT void
+weston_output_finish_frame(struct weston_output *output,
+                          const struct timespec *stamp,
+                          uint32_t presented_flags)
+{
+       struct weston_compositor *compositor = output->compositor;
+       int32_t refresh_nsec;
+       struct timespec now;
+       struct timespec gone;
+       int msec;
+
+       TL_POINT("core_repaint_finished", TLP_OUTPUT(output),
+                TLP_VBLANK(stamp), TLP_END);
+
+       refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
+       weston_presentation_feedback_present_list(&output->feedback_list,
+                                                 output, refresh_nsec, stamp,
+                                                 output->msc,
+                                                 presented_flags);
+
+       output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
+
+       weston_compositor_read_presentation_clock(compositor, &now);
+       timespec_sub(&gone, &now, stamp);
+       msec = (refresh_nsec - timespec_to_nsec(&gone)) / 1000000; /* floor */
+       msec -= compositor->repaint_msec;
+
+       if (msec < -1000 || msec > 1000) {
+               static bool warned;
+
+               if (!warned)
+                       weston_log("Warning: computed repaint delay is "
+                                  "insane: %d msec\n", msec);
+               warned = true;
+
+               msec = 0;
+       }
+
+       /* Called from restart_repaint_loop and restart happens already after
+        * the deadline given by repaint_msec? In that case we delay until
+        * the deadline of the next frame, to give clients a more predictable
+        * timing of the repaint cycle to lock on. */
+       if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && msec < 0)
+               msec += refresh_nsec / 1000000;
+
+       if (msec < 1)
+               output_repaint_timer_handler(output);
+       else
+               wl_event_source_timer_update(output->repaint_timer, msec);
+}
+
+static void
+idle_repaint(void *data)
+{
+       struct weston_output *output = data;
+
+       output->start_repaint_loop(output);
+}
+
+WL_EXPORT void
+weston_layer_entry_insert(struct weston_layer_entry *list,
+                         struct weston_layer_entry *entry)
+{
+       wl_list_insert(&list->link, &entry->link);
+       entry->layer = list->layer;
+}
+
+WL_EXPORT void
+weston_layer_entry_remove(struct weston_layer_entry *entry)
+{
+       wl_list_remove(&entry->link);
+       wl_list_init(&entry->link);
+       entry->layer = NULL;
+}
+
+WL_EXPORT void
+weston_layer_init(struct weston_layer *layer, struct wl_list *below)
+{
+       wl_list_init(&layer->view_list.link);
+       layer->view_list.layer = layer;
+       weston_layer_set_mask_infinite(layer);
+       if (below != NULL)
+               wl_list_insert(below, &layer->link);
+}
+
+WL_EXPORT void
+weston_layer_set_mask(struct weston_layer *layer,
+                     int x, int y, int width, int height)
+{
+       struct weston_view *view;
+
+       layer->mask.x1 = x;
+       layer->mask.x2 = x + width;
+       layer->mask.y1 = y;
+       layer->mask.y2 = y + height;
+
+       wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
+               weston_view_geometry_dirty(view);
+       }
+}
+
+WL_EXPORT void
+weston_layer_set_mask_infinite(struct weston_layer *layer)
+{
+       weston_layer_set_mask(layer, INT32_MIN, INT32_MIN,
+                                    UINT32_MAX, UINT32_MAX);
+}
+
+WL_EXPORT void
+weston_output_schedule_repaint(struct weston_output *output)
+{
+       struct weston_compositor *compositor = output->compositor;
+       struct wl_event_loop *loop;
+
+       if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
+           compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
+               return;
+
+       if (!output->repaint_needed)
+               TL_POINT("core_repaint_req", TLP_OUTPUT(output), TLP_END);
+
+       loop = wl_display_get_event_loop(compositor->wl_display);
+       output->repaint_needed = 1;
+       if (output->repaint_scheduled)
+               return;
+
+       wl_event_loop_add_idle(loop, idle_repaint, output);
+       output->repaint_scheduled = 1;
+       TL_POINT("core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
+}
+
+WL_EXPORT void
+weston_compositor_schedule_repaint(struct weston_compositor *compositor)
+{
+       struct weston_output *output;
+
+       wl_list_for_each(output, &compositor->output_list, link)
+               weston_output_schedule_repaint(output);
+}
+
+static void
+surface_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+surface_attach(struct wl_client *client,
+              struct wl_resource *resource,
+              struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+       struct weston_buffer *buffer = NULL;
+
+       if (buffer_resource) {
+               buffer = weston_buffer_from_resource(buffer_resource);
+               if (buffer == NULL) {
+                       wl_client_post_no_memory(client);
+                       return;
+               }
+       }
+
+       /* Attach, attach, without commit in between does not send
+        * wl_buffer.release. */
+       weston_surface_state_set_buffer(&surface->pending, buffer);
+
+       surface->pending.sx = sx;
+       surface->pending.sy = sy;
+       surface->pending.newly_attached = 1;
+}
+
+static void
+surface_damage(struct wl_client *client,
+              struct wl_resource *resource,
+              int32_t x, int32_t y, int32_t width, int32_t height)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+
+       if (width <= 0 || height <= 0)
+               return;
+
+       pixman_region32_union_rect(&surface->pending.damage_surface,
+                                  &surface->pending.damage_surface,
+                                  x, y, width, height);
+}
+
+static void
+surface_damage_buffer(struct wl_client *client,
+                     struct wl_resource *resource,
+                     int32_t x, int32_t y, int32_t width, int32_t height)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+
+       if (width <= 0 || height <= 0)
+               return;
+
+       pixman_region32_union_rect(&surface->pending.damage_buffer,
+                                  &surface->pending.damage_buffer,
+                                  x, y, width, height);
+}
+
+static void
+destroy_frame_callback(struct wl_resource *resource)
+{
+       struct weston_frame_callback *cb = wl_resource_get_user_data(resource);
+
+       wl_list_remove(&cb->link);
+       free(cb);
+}
+
+static void
+surface_frame(struct wl_client *client,
+             struct wl_resource *resource, uint32_t callback)
+{
+       struct weston_frame_callback *cb;
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+
+       cb = malloc(sizeof *cb);
+       if (cb == NULL) {
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       cb->resource = wl_resource_create(client, &wl_callback_interface, 1,
+                                         callback);
+       if (cb->resource == NULL) {
+               free(cb);
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       wl_resource_set_implementation(cb->resource, NULL, cb,
+                                      destroy_frame_callback);
+
+       wl_list_insert(surface->pending.frame_callback_list.prev, &cb->link);
+}
+
+static void
+surface_set_opaque_region(struct wl_client *client,
+                         struct wl_resource *resource,
+                         struct wl_resource *region_resource)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+       struct weston_region *region;
+
+       if (region_resource) {
+               region = wl_resource_get_user_data(region_resource);
+               pixman_region32_copy(&surface->pending.opaque,
+                                    &region->region);
+       } else {
+               pixman_region32_clear(&surface->pending.opaque);
+       }
+}
+
+static void
+surface_set_input_region(struct wl_client *client,
+                        struct wl_resource *resource,
+                        struct wl_resource *region_resource)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+       struct weston_region *region;
+
+       if (region_resource) {
+               region = wl_resource_get_user_data(region_resource);
+               pixman_region32_copy(&surface->pending.input,
+                                    &region->region);
+       } else {
+               pixman_region32_fini(&surface->pending.input);
+               region_init_infinite(&surface->pending.input);
+       }
+}
+
+static void
+weston_surface_commit_subsurface_order(struct weston_surface *surface)
+{
+       struct weston_subsurface *sub;
+
+       wl_list_for_each_reverse(sub, &surface->subsurface_list_pending,
+                                parent_link_pending) {
+               wl_list_remove(&sub->parent_link);
+               wl_list_insert(&surface->subsurface_list, &sub->parent_link);
+       }
+}
+
+static void
+weston_surface_build_buffer_matrix(const struct weston_surface *surface,
+                                  struct weston_matrix *matrix)
+{
+       const struct weston_buffer_viewport *vp = &surface->buffer_viewport;
+       double src_width, src_height, dest_width, dest_height;
+
+       weston_matrix_init(matrix);
+
+       if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
+               src_width = surface->width_from_buffer;
+               src_height = surface->height_from_buffer;
+       } else {
+               src_width = wl_fixed_to_double(vp->buffer.src_width);
+               src_height = wl_fixed_to_double(vp->buffer.src_height);
+       }
+
+       if (vp->surface.width == -1) {
+               dest_width = src_width;
+               dest_height = src_height;
+       } else {
+               dest_width = vp->surface.width;
+               dest_height = vp->surface.height;
+       }
+
+       if (src_width != dest_width || src_height != dest_height)
+               weston_matrix_scale(matrix,
+                                   src_width / dest_width,
+                                   src_height / dest_height, 1);
+
+       if (vp->buffer.src_width != wl_fixed_from_int(-1))
+               weston_matrix_translate(matrix,
+                                       wl_fixed_to_double(vp->buffer.src_x),
+                                       wl_fixed_to_double(vp->buffer.src_y),
+                                       0);
+
+       switch (vp->buffer.transform) {
+       case WL_OUTPUT_TRANSFORM_FLIPPED:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               weston_matrix_scale(matrix, -1, 1, 1);
+               weston_matrix_translate(matrix,
+                                       surface->width_from_buffer, 0, 0);
+               break;
+       }
+
+       switch (vp->buffer.transform) {
+       default:
+       case WL_OUTPUT_TRANSFORM_NORMAL:
+       case WL_OUTPUT_TRANSFORM_FLIPPED:
+               break;
+       case WL_OUTPUT_TRANSFORM_90:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+               weston_matrix_rotate_xy(matrix, 0, 1);
+               weston_matrix_translate(matrix,
+                                       surface->height_from_buffer, 0, 0);
+               break;
+       case WL_OUTPUT_TRANSFORM_180:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+               weston_matrix_rotate_xy(matrix, -1, 0);
+               weston_matrix_translate(matrix,
+                                       surface->width_from_buffer,
+                                       surface->height_from_buffer, 0);
+               break;
+       case WL_OUTPUT_TRANSFORM_270:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               weston_matrix_rotate_xy(matrix, 0, -1);
+               weston_matrix_translate(matrix,
+                                       0, surface->width_from_buffer, 0);
+               break;
+       }
+
+       weston_matrix_scale(matrix, vp->buffer.scale, vp->buffer.scale, 1);
+}
+
+/**
+ * Compute a + b > c while being safe to overflows.
+ */
+static bool
+fixed_sum_gt(wl_fixed_t a, wl_fixed_t b, wl_fixed_t c)
+{
+       return (int64_t)a + (int64_t)b > (int64_t)c;
+}
+
+static bool
+weston_surface_is_pending_viewport_source_valid(
+       const struct weston_surface *surface)
+{
+       const struct weston_surface_state *pend = &surface->pending;
+       const struct weston_buffer_viewport *vp = &pend->buffer_viewport;
+       int width_from_buffer = 0;
+       int height_from_buffer = 0;
+       wl_fixed_t w;
+       wl_fixed_t h;
+
+       /* If viewport source rect is not set, it is always ok. */
+       if (vp->buffer.src_width == wl_fixed_from_int(-1))
+               return true;
+
+       if (pend->newly_attached) {
+               if (pend->buffer) {
+                       convert_size_by_transform_scale(&width_from_buffer,
+                                                       &height_from_buffer,
+                                                       pend->buffer->width,
+                                                       pend->buffer->height,
+                                                       vp->buffer.transform,
+                                                       vp->buffer.scale);
+               } else {
+                       /* No buffer: viewport is irrelevant. */
+                       return true;
+               }
+       } else {
+               width_from_buffer = surface->width_from_buffer;
+               height_from_buffer = surface->height_from_buffer;
+       }
+
+       assert((width_from_buffer == 0) == (height_from_buffer == 0));
+       assert(width_from_buffer >= 0 && height_from_buffer >= 0);
+
+       /* No buffer: viewport is irrelevant. */
+       if (width_from_buffer == 0 || height_from_buffer == 0)
+               return true;
+
+       /* overflow checks for wl_fixed_from_int() */
+       if (width_from_buffer > wl_fixed_to_int(INT32_MAX))
+               return false;
+       if (height_from_buffer > wl_fixed_to_int(INT32_MAX))
+               return false;
+
+       w = wl_fixed_from_int(width_from_buffer);
+       h = wl_fixed_from_int(height_from_buffer);
+
+       if (fixed_sum_gt(vp->buffer.src_x, vp->buffer.src_width, w))
+               return false;
+       if (fixed_sum_gt(vp->buffer.src_y, vp->buffer.src_height, h))
+               return false;
+
+       return true;
+}
+
+static bool
+fixed_is_integer(wl_fixed_t v)
+{
+       return (v & 0xff) == 0;
+}
+
+static bool
+weston_surface_is_pending_viewport_dst_size_int(
+       const struct weston_surface *surface)
+{
+       const struct weston_buffer_viewport *vp =
+               &surface->pending.buffer_viewport;
+
+       if (vp->surface.width != -1) {
+               assert(vp->surface.width > 0 && vp->surface.height > 0);
+               return true;
+       }
+
+       return fixed_is_integer(vp->buffer.src_width) &&
+              fixed_is_integer(vp->buffer.src_height);
+}
+
+/* Translate pending damage in buffer co-ordinates to surface
+ * co-ordinates and union it with a pixman_region32_t.
+ * This should only be called after the buffer is attached.
+ */
+static void
+apply_damage_buffer(pixman_region32_t *dest,
+                   struct weston_surface *surface,
+                   struct weston_surface_state *state)
+{
+       struct weston_buffer *buffer = surface->buffer_ref.buffer;
+
+       /* wl_surface.damage_buffer needs to be clipped to the buffer,
+        * translated into surface co-ordinates and unioned with
+        * any other surface damage.
+        * None of this makes sense if there is no buffer though.
+        */
+       if (buffer && pixman_region32_not_empty(&state->damage_buffer)) {
+               pixman_region32_t buffer_damage;
+
+               pixman_region32_intersect_rect(&state->damage_buffer,
+                                              &state->damage_buffer,
+                                              0, 0, buffer->width,
+                                              buffer->height);
+               pixman_region32_init(&buffer_damage);
+               weston_matrix_transform_region(&buffer_damage,
+                                              &surface->buffer_to_surface_matrix,
+                                              &state->damage_buffer);
+               pixman_region32_union(dest, dest, &buffer_damage);
+               pixman_region32_fini(&buffer_damage);
+       }
+       /* We should clear this on commit even if there was no buffer */
+       pixman_region32_clear(&state->damage_buffer);
+}
+
+static void
+weston_surface_commit_state(struct weston_surface *surface,
+                           struct weston_surface_state *state)
+{
+       struct weston_view *view;
+       pixman_region32_t opaque;
+
+       /* wl_surface.set_buffer_transform */
+       /* wl_surface.set_buffer_scale */
+       /* wp_viewport.set_source */
+       /* wp_viewport.set_destination */
+       surface->buffer_viewport = state->buffer_viewport;
+
+       /* wl_surface.attach */
+       if (state->newly_attached)
+               weston_surface_attach(surface, state->buffer);
+       weston_surface_state_set_buffer(state, NULL);
+
+       weston_surface_build_buffer_matrix(surface,
+                                          &surface->surface_to_buffer_matrix);
+       weston_matrix_invert(&surface->buffer_to_surface_matrix,
+                            &surface->surface_to_buffer_matrix);
+
+       if (state->newly_attached || state->buffer_viewport.changed) {
+               weston_surface_update_size(surface);
+               if (surface->configure)
+                       surface->configure(surface, state->sx, state->sy);
+       }
+
+       state->sx = 0;
+       state->sy = 0;
+       state->newly_attached = 0;
+       state->buffer_viewport.changed = 0;
+
+       /* wl_surface.damage and wl_surface.damage_buffer */
+       if (weston_timeline_enabled_ &&
+           (pixman_region32_not_empty(&state->damage_surface) ||
+            pixman_region32_not_empty(&state->damage_buffer)))
+               TL_POINT("core_commit_damage", TLP_SURFACE(surface), TLP_END);
+
+       pixman_region32_union(&surface->damage, &surface->damage,
+                             &state->damage_surface);
+
+       apply_damage_buffer(&surface->damage, surface, state);
+
+       pixman_region32_intersect_rect(&surface->damage, &surface->damage,
+                                      0, 0, surface->width, surface->height);
+       pixman_region32_clear(&state->damage_surface);
+
+       /* wl_surface.set_opaque_region */
+       pixman_region32_init(&opaque);
+       pixman_region32_intersect_rect(&opaque, &state->opaque,
+                                      0, 0, surface->width, surface->height);
+
+       if (!pixman_region32_equal(&opaque, &surface->opaque)) {
+               pixman_region32_copy(&surface->opaque, &opaque);
+               wl_list_for_each(view, &surface->views, surface_link)
+                       weston_view_geometry_dirty(view);
+       }
+
+       pixman_region32_fini(&opaque);
+
+       /* wl_surface.set_input_region */
+       pixman_region32_intersect_rect(&surface->input, &state->input,
+                                      0, 0, surface->width, surface->height);
+
+       /* wl_surface.frame */
+       wl_list_insert_list(&surface->frame_callback_list,
+                           &state->frame_callback_list);
+       wl_list_init(&state->frame_callback_list);
+
+       /* XXX:
+        * What should happen with a feedback request, if there
+        * is no wl_buffer attached for this commit?
+        */
+
+       /* presentation.feedback */
+       wl_list_insert_list(&surface->feedback_list,
+                           &state->feedback_list);
+       wl_list_init(&state->feedback_list);
+}
+
+static void
+weston_surface_commit(struct weston_surface *surface)
+{
+       weston_surface_commit_state(surface, &surface->pending);
+
+       weston_surface_commit_subsurface_order(surface);
+
+       weston_surface_schedule_repaint(surface);
+}
+
+static void
+weston_subsurface_commit(struct weston_subsurface *sub);
+
+static void
+weston_subsurface_parent_commit(struct weston_subsurface *sub,
+                               int parent_is_synchronized);
+
+static void
+surface_commit(struct wl_client *client, struct wl_resource *resource)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+       struct weston_subsurface *sub = weston_surface_to_subsurface(surface);
+
+       if (!weston_surface_is_pending_viewport_source_valid(surface)) {
+               assert(surface->viewport_resource);
+
+               wl_resource_post_error(surface->viewport_resource,
+                       WP_VIEWPORT_ERROR_OUT_OF_BUFFER,
+                       "wl_surface@%d has viewport source outside buffer",
+                       wl_resource_get_id(resource));
+               return;
+       }
+
+       if (!weston_surface_is_pending_viewport_dst_size_int(surface)) {
+               assert(surface->viewport_resource);
+
+               wl_resource_post_error(surface->viewport_resource,
+                       WP_VIEWPORT_ERROR_BAD_SIZE,
+                       "wl_surface@%d viewport dst size not integer",
+                       wl_resource_get_id(resource));
+               return;
+       }
+
+       if (sub) {
+               weston_subsurface_commit(sub);
+               return;
+       }
+
+       weston_surface_commit(surface);
+
+       wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
+               if (sub->surface != surface)
+                       weston_subsurface_parent_commit(sub, 0);
+       }
+}
+
+static void
+surface_set_buffer_transform(struct wl_client *client,
+                            struct wl_resource *resource, int transform)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+
+       /* if wl_output.transform grows more members this will need to be updated. */
+       if (transform < 0 ||
+           transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
+               wl_resource_post_error(resource,
+                       WL_SURFACE_ERROR_INVALID_TRANSFORM,
+                       "buffer transform must be a valid transform "
+                       "('%d' specified)", transform);
+               return;
+       }
+
+       surface->pending.buffer_viewport.buffer.transform = transform;
+       surface->pending.buffer_viewport.changed = 1;
+}
+
+static void
+surface_set_buffer_scale(struct wl_client *client,
+                        struct wl_resource *resource,
+                        int32_t scale)
+{
+       struct weston_surface *surface = wl_resource_get_user_data(resource);
+
+       if (scale < 1) {
+               wl_resource_post_error(resource,
+                       WL_SURFACE_ERROR_INVALID_SCALE,
+                       "buffer scale must be at least one "
+                       "('%d' specified)", scale);
+               return;
+       }
+
+       surface->pending.buffer_viewport.buffer.scale = scale;
+       surface->pending.buffer_viewport.changed = 1;
+}
+
+static const struct wl_surface_interface surface_interface = {
+       surface_destroy,
+       surface_attach,
+       surface_damage,
+       surface_frame,
+       surface_set_opaque_region,
+       surface_set_input_region,
+       surface_commit,
+       surface_set_buffer_transform,
+       surface_set_buffer_scale,
+       surface_damage_buffer
+};
+
+static void
+compositor_create_surface(struct wl_client *client,
+                         struct wl_resource *resource, uint32_t id)
+{
+       struct weston_compositor *ec = wl_resource_get_user_data(resource);
+       struct weston_surface *surface;
+
+       surface = weston_surface_create(ec);
+       if (surface == NULL) {
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       surface->resource =
+               wl_resource_create(client, &wl_surface_interface,
+                                  wl_resource_get_version(resource), id);
+       if (surface->resource == NULL) {
+               weston_surface_destroy(surface);
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+       wl_resource_set_implementation(surface->resource, &surface_interface,
+                                      surface, destroy_surface);
+
+       wl_signal_emit(&ec->create_surface_signal, surface);
+}
+
+static void
+destroy_region(struct wl_resource *resource)
+{
+       struct weston_region *region = wl_resource_get_user_data(resource);
+
+       pixman_region32_fini(&region->region);
+       free(region);
+}
+
+static void
+region_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+region_add(struct wl_client *client, struct wl_resource *resource,
+          int32_t x, int32_t y, int32_t width, int32_t height)
+{
+       struct weston_region *region = wl_resource_get_user_data(resource);
+
+       pixman_region32_union_rect(&region->region, &region->region,
+                                  x, y, width, height);
+}
+
+static void
+region_subtract(struct wl_client *client, struct wl_resource *resource,
+               int32_t x, int32_t y, int32_t width, int32_t height)
+{
+       struct weston_region *region = wl_resource_get_user_data(resource);
+       pixman_region32_t rect;
+
+       pixman_region32_init_rect(&rect, x, y, width, height);
+       pixman_region32_subtract(&region->region, &region->region, &rect);
+       pixman_region32_fini(&rect);
+}
+
+static const struct wl_region_interface region_interface = {
+       region_destroy,
+       region_add,
+       region_subtract
+};
+
+static void
+compositor_create_region(struct wl_client *client,
+                        struct wl_resource *resource, uint32_t id)
+{
+       struct weston_region *region;
+
+       region = malloc(sizeof *region);
+       if (region == NULL) {
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       pixman_region32_init(&region->region);
+
+       region->resource =
+               wl_resource_create(client, &wl_region_interface, 1, id);
+       if (region->resource == NULL) {
+               free(region);
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+       wl_resource_set_implementation(region->resource, &region_interface,
+                                      region, destroy_region);
+}
+
+static const struct wl_compositor_interface compositor_interface = {
+       compositor_create_surface,
+       compositor_create_region
+};
+
+static void
+weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
+{
+       struct weston_surface *surface = sub->surface;
+
+       weston_surface_commit_state(surface, &sub->cached);
+       weston_buffer_reference(&sub->cached_buffer_ref, NULL);
+
+       weston_surface_commit_subsurface_order(surface);
+
+       weston_surface_schedule_repaint(surface);
+
+       sub->has_cached_data = 0;
+}
+
+static void
+weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
+{
+       struct weston_surface *surface = sub->surface;
+
+       /*
+        * If this commit would cause the surface to move by the
+        * attach(dx, dy) parameters, the old damage region must be
+        * translated to correspond to the new surface coordinate system
+        * origin.
+        */
+       pixman_region32_translate(&sub->cached.damage_surface,
+                                 -surface->pending.sx, -surface->pending.sy);
+       pixman_region32_union(&sub->cached.damage_surface,
+                             &sub->cached.damage_surface,
+                             &surface->pending.damage_surface);
+       pixman_region32_clear(&surface->pending.damage_surface);
+
+       if (surface->pending.newly_attached) {
+               sub->cached.newly_attached = 1;
+               weston_surface_state_set_buffer(&sub->cached,
+                                               surface->pending.buffer);
+               weston_buffer_reference(&sub->cached_buffer_ref,
+                                       surface->pending.buffer);
+               weston_presentation_feedback_discard_list(
+                                       &sub->cached.feedback_list);
+       }
+       sub->cached.sx += surface->pending.sx;
+       sub->cached.sy += surface->pending.sy;
+
+       apply_damage_buffer(&sub->cached.damage_surface, surface, &surface->pending);
+
+       sub->cached.buffer_viewport.changed |=
+               surface->pending.buffer_viewport.changed;
+       sub->cached.buffer_viewport.buffer =
+               surface->pending.buffer_viewport.buffer;
+       sub->cached.buffer_viewport.surface =
+               surface->pending.buffer_viewport.surface;
+
+       weston_surface_reset_pending_buffer(surface);
+
+       pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
+
+       pixman_region32_copy(&sub->cached.input, &surface->pending.input);
+
+       wl_list_insert_list(&sub->cached.frame_callback_list,
+                           &surface->pending.frame_callback_list);
+       wl_list_init(&surface->pending.frame_callback_list);
+
+       wl_list_insert_list(&sub->cached.feedback_list,
+                           &surface->pending.feedback_list);
+       wl_list_init(&surface->pending.feedback_list);
+
+       sub->has_cached_data = 1;
+}
+
+static bool
+weston_subsurface_is_synchronized(struct weston_subsurface *sub)
+{
+       while (sub) {
+               if (sub->synchronized)
+                       return true;
+
+               if (!sub->parent)
+                       return false;
+
+               sub = weston_surface_to_subsurface(sub->parent);
+       }
+
+       return false;
+}
+
+static void
+weston_subsurface_commit(struct weston_subsurface *sub)
+{
+       struct weston_surface *surface = sub->surface;
+       struct weston_subsurface *tmp;
+
+       /* Recursive check for effectively synchronized. */
+       if (weston_subsurface_is_synchronized(sub)) {
+               weston_subsurface_commit_to_cache(sub);
+       } else {
+               if (sub->has_cached_data) {
+                       /* flush accumulated state from cache */
+                       weston_subsurface_commit_to_cache(sub);
+                       weston_subsurface_commit_from_cache(sub);
+               } else {
+                       weston_surface_commit(surface);
+               }
+
+               wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
+                       if (tmp->surface != surface)
+                               weston_subsurface_parent_commit(tmp, 0);
+               }
+       }
+}
+
+static void
+weston_subsurface_synchronized_commit(struct weston_subsurface *sub)
+{
+       struct weston_surface *surface = sub->surface;
+       struct weston_subsurface *tmp;
+
+       /* From now on, commit_from_cache the whole sub-tree, regardless of
+        * the synchronized mode of each child. This sub-surface or some
+        * of its ancestors were synchronized, so we are synchronized
+        * all the way down.
+        */
+
+       if (sub->has_cached_data)
+               weston_subsurface_commit_from_cache(sub);
+
+       wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
+               if (tmp->surface != surface)
+                       weston_subsurface_parent_commit(tmp, 1);
+       }
+}
+
+static void
+weston_subsurface_parent_commit(struct weston_subsurface *sub,
+                               int parent_is_synchronized)
+{
+       struct weston_view *view;
+       if (sub->position.set) {
+               wl_list_for_each(view, &sub->surface->views, surface_link)
+                       weston_view_set_position(view,
+                                                sub->position.x,
+                                                sub->position.y);
+
+               sub->position.set = 0;
+       }
+
+       if (parent_is_synchronized || sub->synchronized)
+               weston_subsurface_synchronized_commit(sub);
+}
+
+static int
+subsurface_get_label(struct weston_surface *surface, char *buf, size_t len)
+{
+       return snprintf(buf, len, "sub-surface");
+}
+
+static void
+subsurface_configure(struct weston_surface *surface, int32_t dx, int32_t dy)
+{
+       struct weston_compositor *compositor = surface->compositor;
+       struct weston_view *view;
+
+       wl_list_for_each(view, &surface->views, surface_link)
+               weston_view_set_position(view,
+                                        view->geometry.x + dx,
+                                        view->geometry.y + dy);
+
+       /* No need to check parent mappedness, because if parent is not
+        * mapped, parent is not in a visible layer, so this sub-surface
+        * will not be drawn either.
+        */
+       if (!weston_surface_is_mapped(surface)) {
+               struct weston_output *output;
+
+               /* Cannot call weston_view_update_transform(),
+                * because that would call it also for the parent surface,
+                * which might not be mapped yet. That would lead to
+                * inconsistent state, where the window could never be
+                * mapped.
+                *
+                * Instead just assign any output, to make
+                * weston_surface_is_mapped() return true, so that when the
+                * parent surface does get mapped, this one will get
+                * included, too. See view_list_add().
+                */
+               assert(!wl_list_empty(&compositor->output_list));
+               output = container_of(compositor->output_list.next,
+                                     struct weston_output, link);
+
+               surface->output = output;
+               weston_surface_update_output_mask(surface, 1u << output->id);
+       }
+}
+
+static struct weston_subsurface *
+weston_surface_to_subsurface(struct weston_surface *surface)
+{
+       if (surface->configure == subsurface_configure)
+               return surface->configure_private;
+
+       return NULL;
+}
+
+WL_EXPORT struct weston_surface *
+weston_surface_get_main_surface(struct weston_surface *surface)
+{
+       struct weston_subsurface *sub;
+
+       while (surface && (sub = weston_surface_to_subsurface(surface)))
+               surface = sub->parent;
+
+       return surface;
+}
+
+WL_EXPORT int
+weston_surface_set_role(struct weston_surface *surface,
+                       const char *role_name,
+                       struct wl_resource *error_resource,
+                       uint32_t error_code)
+{
+       assert(role_name);
+
+       if (surface->role_name == NULL ||
+           surface->role_name == role_name ||
+           strcmp(surface->role_name, role_name) == 0) {
+               surface->role_name = role_name;
+
+               return 0;
+       }
+
+       wl_resource_post_error(error_resource, error_code,
+                              "Cannot assign role %s to wl_surface@%d,"
+                              " already has role %s\n",
+                              role_name,
+                              wl_resource_get_id(surface->resource),
+                              surface->role_name);
+       return -1;
+}
+
+WL_EXPORT void
+weston_surface_set_label_func(struct weston_surface *surface,
+                             int (*desc)(struct weston_surface *,
+                                         char *, size_t))
+{
+       surface->get_label = desc;
+       surface->timeline.force_refresh = 1;
+}
+
+/** Get the size of surface contents
+ *
+ * \param surface The surface to query.
+ * \param width Returns the width of raw contents.
+ * \param height Returns the height of raw contents.
+ *
+ * Retrieves the raw surface content size in pixels for the given surface.
+ * This is the whole content size in buffer pixels. If the surface
+ * has no content or the renderer does not implement this feature,
+ * zeroes are returned.
+ *
+ * This function is used to determine the buffer size needed for
+ * a weston_surface_copy_content() call.
+ */
+WL_EXPORT void
+weston_surface_get_content_size(struct weston_surface *surface,
+                               int *width, int *height)
+{
+       struct weston_renderer *rer = surface->compositor->renderer;
+
+       if (!rer->surface_get_content_size) {
+               *width = 0;
+               *height = 0;
+               return;
+       }
+
+       rer->surface_get_content_size(surface, width, height);
+}
+
+/** Copy surface contents to system memory.
+ *
+ * \param surface The surface to copy from.
+ * \param target Pointer to the target memory buffer.
+ * \param size Size of the target buffer in bytes.
+ * \param src_x X location on contents to copy from.
+ * \param src_y Y location on contents to copy from.
+ * \param width Width in pixels of the area to copy.
+ * \param height Height in pixels of the area to copy.
+ * \return 0 for success, -1 for failure.
+ *
+ * Surface contents are maintained by the renderer. They can be in a
+ * reserved weston_buffer or as a copy, e.g. a GL texture, or something
+ * else.
+ *
+ * Surface contents are copied into memory pointed to by target,
+ * which has size bytes of space available. The target memory
+ * may be larger than needed, but being smaller returns an error.
+ * The extra bytes in target may or may not be written; their content is
+ * unspecified. Size must be large enough to hold the image.
+ *
+ * The image in the target memory will be arranged in rows from
+ * top to bottom, and pixels on a row from left to right. The pixel
+ * format is PIXMAN_a8b8g8r8, 4 bytes per pixel, and stride is exactly
+ * width * 4.
+ *
+ * Parameters src_x and src_y define the upper-left corner in buffer
+ * coordinates (pixels) to copy from. Parameters width and height
+ * define the size of the area to copy in pixels.
+ *
+ * The rectangle defined by src_x, src_y, width, height must fit in
+ * the surface contents. Otherwise an error is returned.
+ *
+ * Use surface_get_data_size to determine the content size; the
+ * needed target buffer size and rectangle limits.
+ *
+ * CURRENT IMPLEMENTATION RESTRICTIONS:
+ * - the machine must be little-endian due to Pixman formats.
+ *
+ * NOTE: Pixman formats are premultiplied.
+ */
+WL_EXPORT int
+weston_surface_copy_content(struct weston_surface *surface,
+                           void *target, size_t size,
+                           int src_x, int src_y,
+                           int width, int height)
+{
+       struct weston_renderer *rer = surface->compositor->renderer;
+       int cw, ch;
+       const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
+
+       if (!rer->surface_copy_content)
+               return -1;
+
+       weston_surface_get_content_size(surface, &cw, &ch);
+
+       if (src_x < 0 || src_y < 0)
+               return -1;
+
+       if (width <= 0 || height <= 0)
+               return -1;
+
+       if (src_x + width > cw || src_y + height > ch)
+               return -1;
+
+       if (width * bytespp * height > size)
+               return -1;
+
+       return rer->surface_copy_content(surface, target, size,
+                                        src_x, src_y, width, height);
+}
+
+static void
+subsurface_set_position(struct wl_client *client,
+                       struct wl_resource *resource, int32_t x, int32_t y)
+{
+       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
+
+       if (!sub)
+               return;
+
+       sub->position.x = x;
+       sub->position.y = y;
+       sub->position.set = 1;
+}
+
+static struct weston_subsurface *
+subsurface_from_surface(struct weston_surface *surface)
+{
+       struct weston_subsurface *sub;
+
+       sub = weston_surface_to_subsurface(surface);
+       if (sub)
+               return sub;
+
+       wl_list_for_each(sub, &surface->subsurface_list, parent_link)
+               if (sub->surface == surface)
+                       return sub;
+
+       return NULL;
+}
+
+static struct weston_subsurface *
+subsurface_sibling_check(struct weston_subsurface *sub,
+                        struct weston_surface *surface,
+                        const char *request)
+{
+       struct weston_subsurface *sibling;
+
+       sibling = subsurface_from_surface(surface);
+
+       if (!sibling) {
+               wl_resource_post_error(sub->resource,
+                       WL_SUBSURFACE_ERROR_BAD_SURFACE,
+                       "%s: wl_surface@%d is not a parent or sibling",
+                       request, wl_resource_get_id(surface->resource));
+               return NULL;
+       }
+
+       if (sibling->parent != sub->parent) {
+               wl_resource_post_error(sub->resource,
+                       WL_SUBSURFACE_ERROR_BAD_SURFACE,
+                       "%s: wl_surface@%d has a different parent",
+                       request, wl_resource_get_id(surface->resource));
+               return NULL;
+       }
+
+       return sibling;
+}
+
+static void
+subsurface_place_above(struct wl_client *client,
+                      struct wl_resource *resource,
+                      struct wl_resource *sibling_resource)
+{
+       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
+       struct weston_surface *surface =
+               wl_resource_get_user_data(sibling_resource);
+       struct weston_subsurface *sibling;
+
+       if (!sub)
+               return;
+
+       sibling = subsurface_sibling_check(sub, surface, "place_above");
+       if (!sibling)
+               return;
+
+       wl_list_remove(&sub->parent_link_pending);
+       wl_list_insert(sibling->parent_link_pending.prev,
+                      &sub->parent_link_pending);
+}
+
+static void
+subsurface_place_below(struct wl_client *client,
+                      struct wl_resource *resource,
+                      struct wl_resource *sibling_resource)
+{
+       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
+       struct weston_surface *surface =
+               wl_resource_get_user_data(sibling_resource);
+       struct weston_subsurface *sibling;
+
+       if (!sub)
+               return;
+
+       sibling = subsurface_sibling_check(sub, surface, "place_below");
+       if (!sibling)
+               return;
+
+       wl_list_remove(&sub->parent_link_pending);
+       wl_list_insert(&sibling->parent_link_pending,
+                      &sub->parent_link_pending);
+}
+
+static void
+subsurface_set_sync(struct wl_client *client, struct wl_resource *resource)
+{
+       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
+
+       if (sub)
+               sub->synchronized = 1;
+}
+
+static void
+subsurface_set_desync(struct wl_client *client, struct wl_resource *resource)
+{
+       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
+
+       if (sub && sub->synchronized) {
+               sub->synchronized = 0;
+
+               /* If sub became effectively desynchronized, flush. */
+               if (!weston_subsurface_is_synchronized(sub))
+                       weston_subsurface_synchronized_commit(sub);
+       }
+}
+
+static void
+weston_subsurface_unlink_parent(struct weston_subsurface *sub)
+{
+       wl_list_remove(&sub->parent_link);
+       wl_list_remove(&sub->parent_link_pending);
+       wl_list_remove(&sub->parent_destroy_listener.link);
+       sub->parent = NULL;
+}
+
+static void
+weston_subsurface_destroy(struct weston_subsurface *sub);
+
+static void
+subsurface_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+       struct weston_subsurface *sub =
+               container_of(listener, struct weston_subsurface,
+                            surface_destroy_listener);
+       assert(data == sub->surface);
+
+       /* The protocol object (wl_resource) is left inert. */
+       if (sub->resource)
+               wl_resource_set_user_data(sub->resource, NULL);
+
+       weston_subsurface_destroy(sub);
+}
+
+static void
+subsurface_handle_parent_destroy(struct wl_listener *listener, void *data)
+{
+       struct weston_subsurface *sub =
+               container_of(listener, struct weston_subsurface,
+                            parent_destroy_listener);
+       assert(data == sub->parent);
+       assert(sub->surface != sub->parent);
+
+       if (weston_surface_is_mapped(sub->surface))
+               weston_surface_unmap(sub->surface);
+
+       weston_subsurface_unlink_parent(sub);
+}
+
+static void
+subsurface_resource_destroy(struct wl_resource *resource)
+{
+       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
+
+       if (sub)
+               weston_subsurface_destroy(sub);
+}
+
+static void
+subsurface_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+weston_subsurface_link_parent(struct weston_subsurface *sub,
+                             struct weston_surface *parent)
+{
+       sub->parent = parent;
+       sub->parent_destroy_listener.notify = subsurface_handle_parent_destroy;
+       wl_signal_add(&parent->destroy_signal,
+                     &sub->parent_destroy_listener);
+
+       wl_list_insert(&parent->subsurface_list, &sub->parent_link);
+       wl_list_insert(&parent->subsurface_list_pending,
+                      &sub->parent_link_pending);
+}
+
+static void
+weston_subsurface_link_surface(struct weston_subsurface *sub,
+                              struct weston_surface *surface)
+{
+       sub->surface = surface;
+       sub->surface_destroy_listener.notify =
+               subsurface_handle_surface_destroy;
+       wl_signal_add(&surface->destroy_signal,
+                     &sub->surface_destroy_listener);
+}
+
+static void
+weston_subsurface_destroy(struct weston_subsurface *sub)
+{
+       struct weston_view *view, *next;
+
+       assert(sub->surface);
+
+       if (sub->resource) {
+               assert(weston_surface_to_subsurface(sub->surface) == sub);
+               assert(sub->parent_destroy_listener.notify ==
+                      subsurface_handle_parent_destroy);
+
+               wl_list_for_each_safe(view, next, &sub->surface->views, surface_link) {
+                       weston_view_unmap(view);
+                       weston_view_destroy(view);
+               }
+
+               if (sub->parent)
+                       weston_subsurface_unlink_parent(sub);
+
+               weston_surface_state_fini(&sub->cached);
+               weston_buffer_reference(&sub->cached_buffer_ref, NULL);
+
+               sub->surface->configure = NULL;
+               sub->surface->configure_private = NULL;
+               weston_surface_set_label_func(sub->surface, NULL);
+       } else {
+               /* the dummy weston_subsurface for the parent itself */
+               assert(sub->parent_destroy_listener.notify == NULL);
+               wl_list_remove(&sub->parent_link);
+               wl_list_remove(&sub->parent_link_pending);
+       }
+
+       wl_list_remove(&sub->surface_destroy_listener.link);
+       free(sub);
+}
+
+static const struct wl_subsurface_interface subsurface_implementation = {
+       subsurface_destroy,
+       subsurface_set_position,
+       subsurface_place_above,
+       subsurface_place_below,
+       subsurface_set_sync,
+       subsurface_set_desync
+};
+
+static struct weston_subsurface *
+weston_subsurface_create(uint32_t id, struct weston_surface *surface,
+                        struct weston_surface *parent)
+{
+       struct weston_subsurface *sub;
+       struct wl_client *client = wl_resource_get_client(surface->resource);
+
+       sub = zalloc(sizeof *sub);
+       if (sub == NULL)
+               return NULL;
+
+       wl_list_init(&sub->unused_views);
+
+       sub->resource =
+               wl_resource_create(client, &wl_subsurface_interface, 1, id);
+       if (!sub->resource) {
+               free(sub);
+               return NULL;
+       }
+
+       wl_resource_set_implementation(sub->resource,
+                                      &subsurface_implementation,
+                                      sub, subsurface_resource_destroy);
+       weston_subsurface_link_surface(sub, surface);
+       weston_subsurface_link_parent(sub, parent);
+       weston_surface_state_init(&sub->cached);
+       sub->cached_buffer_ref.buffer = NULL;
+       sub->synchronized = 1;
+
+       return sub;
+}
+
+/* Create a dummy subsurface for having the parent itself in its
+ * sub-surface lists. Makes stacking order manipulation easy.
+ */
+static struct weston_subsurface *
+weston_subsurface_create_for_parent(struct weston_surface *parent)
+{
+       struct weston_subsurface *sub;
+
+       sub = zalloc(sizeof *sub);
+       if (sub == NULL)
+               return NULL;
+
+       weston_subsurface_link_surface(sub, parent);
+       sub->parent = parent;
+       wl_list_insert(&parent->subsurface_list, &sub->parent_link);
+       wl_list_insert(&parent->subsurface_list_pending,
+                      &sub->parent_link_pending);
+
+       return sub;
+}
+
+static void
+subcompositor_get_subsurface(struct wl_client *client,
+                            struct wl_resource *resource,
+                            uint32_t id,
+                            struct wl_resource *surface_resource,
+                            struct wl_resource *parent_resource)
+{
+       struct weston_surface *surface =
+               wl_resource_get_user_data(surface_resource);
+       struct weston_surface *parent =
+               wl_resource_get_user_data(parent_resource);
+       struct weston_subsurface *sub;
+       static const char where[] = "get_subsurface: wl_subsurface@";
+
+       if (surface == parent) {
+               wl_resource_post_error(resource,
+                       WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+                       "%s%d: wl_surface@%d cannot be its own parent",
+                       where, id, wl_resource_get_id(surface_resource));
+               return;
+       }
+
+       if (weston_surface_to_subsurface(surface)) {
+               wl_resource_post_error(resource,
+                       WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+                       "%s%d: wl_surface@%d is already a sub-surface",
+                       where, id, wl_resource_get_id(surface_resource));
+               return;
+       }
+
+       if (weston_surface_set_role(surface, "wl_subsurface", resource,
+                                   WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE) < 0)
+               return;
+
+       if (weston_surface_get_main_surface(parent) == surface) {
+               wl_resource_post_error(resource,
+                       WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
+                       "%s%d: wl_surface@%d is an ancestor of parent",
+                       where, id, wl_resource_get_id(surface_resource));
+               return;
+       }
+
+       /* make sure the parent is in its own list */
+       if (wl_list_empty(&parent->subsurface_list)) {
+               if (!weston_subsurface_create_for_parent(parent)) {
+                       wl_resource_post_no_memory(resource);
+                       return;
+               }
+       }
+
+       sub = weston_subsurface_create(id, surface, parent);
+       if (!sub) {
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       surface->configure = subsurface_configure;
+       surface->configure_private = sub;
+       weston_surface_set_label_func(surface, subsurface_get_label);
+}
+
+static void
+subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_subcompositor_interface subcompositor_interface = {
+       subcompositor_destroy,
+       subcompositor_get_subsurface
+};
+
+static void
+bind_subcompositor(struct wl_client *client,
+                  void *data, uint32_t version, uint32_t id)
+{
+       struct weston_compositor *compositor = data;
+       struct wl_resource *resource;
+
+       resource =
+               wl_resource_create(client, &wl_subcompositor_interface, 1, id);
+       if (resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+       wl_resource_set_implementation(resource, &subcompositor_interface,
+                                      compositor, NULL);
+}
+
+/** Set a DPMS mode on all of the compositor's outputs
+ *
+ * \param compositor The compositor instance
+ * \param state The DPMS state the outputs will be set to
+ */
+static void
+weston_compositor_dpms(struct weston_compositor *compositor,
+                      enum dpms_enum state)
+{
+        struct weston_output *output;
+
+        wl_list_for_each(output, &compositor->output_list, link)
+               if (output->set_dpms)
+                       output->set_dpms(output, state);
+}
+
+/** Restores the compositor to active status
+ *
+ * \param compositor The compositor instance
+ *
+ * If the compositor was in a sleeping mode, all outputs are powered
+ * back on via DPMS.  Otherwise if the compositor was inactive
+ * (idle/locked, offscreen, or sleeping) then the compositor's wake
+ * signal will fire.
+ *
+ * Restarts the idle timer.
+ */
+WL_EXPORT void
+weston_compositor_wake(struct weston_compositor *compositor)
+{
+       uint32_t old_state = compositor->state;
+
+       /* The state needs to be changed before emitting the wake
+        * signal because that may try to schedule a repaint which
+        * will not work if the compositor is still sleeping */
+       compositor->state = WESTON_COMPOSITOR_ACTIVE;
+
+       switch (old_state) {
+       case WESTON_COMPOSITOR_SLEEPING:
+               weston_compositor_dpms(compositor, WESTON_DPMS_ON);
+               /* fall through */
+       case WESTON_COMPOSITOR_IDLE:
+       case WESTON_COMPOSITOR_OFFSCREEN:
+               wl_signal_emit(&compositor->wake_signal, compositor);
+               /* fall through */
+       default:
+               wl_event_source_timer_update(compositor->idle_source,
+                                            compositor->idle_time * 1000);
+       }
+}
+
+/** Turns off rendering and frame events for the compositor.
+ *
+ * \param compositor The compositor instance
+ *
+ * This is used for example to prevent further rendering while the
+ * compositor is shutting down.
+ *
+ * \note When offscreen state is entered, outputs will be powered
+ * back on if they were sleeping (in DPMS off mode), even though
+ * no rendering will be performed.
+ *
+ * Stops the idle timer.
+ */
+WL_EXPORT void
+weston_compositor_offscreen(struct weston_compositor *compositor)
+{
+       switch (compositor->state) {
+       case WESTON_COMPOSITOR_OFFSCREEN:
+               return;
+       case WESTON_COMPOSITOR_SLEEPING:
+               weston_compositor_dpms(compositor, WESTON_DPMS_ON);
+               /* fall through */
+       default:
+               compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
+               wl_event_source_timer_update(compositor->idle_source, 0);
+       }
+}
+
+/** Powers down all attached output devices
+ *
+ * \param compositor The compositor instance
+ *
+ * Causes rendering to the outputs to cease, and no frame events to be
+ * sent.  Only powers down the outputs if the compositor is not already
+ * in sleep mode.
+ *
+ * Stops the idle timer.
+ */
+WL_EXPORT void
+weston_compositor_sleep(struct weston_compositor *compositor)
+{
+       if (compositor->state == WESTON_COMPOSITOR_SLEEPING)
+               return;
+
+       wl_event_source_timer_update(compositor->idle_source, 0);
+       compositor->state = WESTON_COMPOSITOR_SLEEPING;
+       weston_compositor_dpms(compositor, WESTON_DPMS_OFF);
+}
+
+/** Sets compositor to idle mode
+ *
+ * \param data The compositor instance
+ *
+ * This is called when the idle timer fires.  Once the compositor is in
+ * idle mode it requires a wake action (e.g. via
+ * weston_compositor_wake()) to restore it.  The compositor's
+ * idle_signal will be triggered when the idle event occurs.
+ *
+ * Idleness can be inhibited by setting the compositor's idle_inhibit
+ * property.
+ */
+static int
+idle_handler(void *data)
+{
+       struct weston_compositor *compositor = data;
+
+       if (compositor->idle_inhibit)
+               return 1;
+
+       compositor->state = WESTON_COMPOSITOR_IDLE;
+       wl_signal_emit(&compositor->idle_signal, compositor);
+
+       return 1;
+}
+
+WL_EXPORT void
+weston_plane_init(struct weston_plane *plane,
+                       struct weston_compositor *ec,
+                       int32_t x, int32_t y)
+{
+       pixman_region32_init(&plane->damage);
+       pixman_region32_init(&plane->clip);
+       plane->x = x;
+       plane->y = y;
+       plane->compositor = ec;
+
+       /* Init the link so that the call to wl_list_remove() when releasing
+        * the plane without ever stacking doesn't lead to a crash */
+       wl_list_init(&plane->link);
+}
+
+WL_EXPORT void
+weston_plane_release(struct weston_plane *plane)
+{
+       struct weston_view *view;
+
+       pixman_region32_fini(&plane->damage);
+       pixman_region32_fini(&plane->clip);
+
+       wl_list_for_each(view, &plane->compositor->view_list, link) {
+               if (view->plane == plane)
+                       view->plane = NULL;
+       }
+
+       wl_list_remove(&plane->link);
+}
+
+WL_EXPORT void
+weston_compositor_stack_plane(struct weston_compositor *ec,
+                             struct weston_plane *plane,
+                             struct weston_plane *above)
+{
+       if (above)
+               wl_list_insert(above->link.prev, &plane->link);
+       else
+               wl_list_insert(&ec->plane_list, &plane->link);
+}
+
+static void unbind_resource(struct wl_resource *resource)
+{
+       wl_list_remove(wl_resource_get_link(resource));
+}
+
+static void
+bind_output(struct wl_client *client,
+           void *data, uint32_t version, uint32_t id)
+{
+       struct weston_output *output = data;
+       struct weston_mode *mode;
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client, &wl_output_interface,
+                                     version, id);
+       if (resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_list_insert(&output->resource_list, wl_resource_get_link(resource));
+       wl_resource_set_implementation(resource, NULL, data, unbind_resource);
+
+       wl_output_send_geometry(resource,
+                               output->x,
+                               output->y,
+                               output->mm_width,
+                               output->mm_height,
+                               output->subpixel,
+                               output->make, output->model,
+                               output->transform);
+       if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
+               wl_output_send_scale(resource,
+                                    output->current_scale);
+
+       wl_list_for_each (mode, &output->mode_list, link) {
+               wl_output_send_mode(resource,
+                                   mode->flags,
+                                   mode->width,
+                                   mode->height,
+                                   mode->refresh);
+       }
+
+       if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
+               wl_output_send_done(resource);
+}
+
+/* Move other outputs when one is resized so the space remains contiguous. */
+static void
+weston_compositor_reflow_outputs(struct weston_compositor *compositor,
+                               struct weston_output *resized_output, int delta_width)
+{
+       struct weston_output *output;
+       bool start_resizing = false;
+
+       if (!delta_width)
+               return;
+
+       wl_list_for_each(output, &compositor->output_list, link) {
+               if (output == resized_output) {
+                       start_resizing = true;
+                       continue;
+               }
+
+               if (start_resizing) {
+                       weston_output_move(output, output->x + delta_width, output->y);
+                       output->dirty = 1;
+               }
+       }
+}
+
+WL_EXPORT void
+weston_output_destroy(struct weston_output *output)
+{
+       struct wl_resource *resource;
+       struct weston_view *view;
+
+       output->destroying = 1;
+
+       wl_list_for_each(view, &output->compositor->view_list, link) {
+               if (view->output_mask & (1u << output->id))
+                       weston_view_assign_output(view);
+       }
+
+       wl_event_source_remove(output->repaint_timer);
+
+       weston_presentation_feedback_discard_list(&output->feedback_list);
+
+       weston_compositor_reflow_outputs(output->compositor, output, output->width);
+       wl_list_remove(&output->link);
+
+       wl_signal_emit(&output->compositor->output_destroyed_signal, output);
+       wl_signal_emit(&output->destroy_signal, output);
+
+       free(output->name);
+       pixman_region32_fini(&output->region);
+       pixman_region32_fini(&output->previous_damage);
+       output->compositor->output_id_pool &= ~(1u << output->id);
+
+       wl_resource_for_each(resource, &output->resource_list) {
+               wl_resource_set_destructor(resource, NULL);
+       }
+
+       wl_global_destroy(output->global);
+}
+
+WL_EXPORT void
+weston_output_update_matrix(struct weston_output *output)
+{
+       float magnification;
+
+       weston_matrix_init(&output->matrix);
+       weston_matrix_translate(&output->matrix, -output->x, -output->y, 0);
+
+       if (output->zoom.active) {
+               magnification = 1 / (1 - output->zoom.spring_z.current);
+               weston_output_update_zoom(output);
+               weston_matrix_translate(&output->matrix, -output->zoom.trans_x,
+                                       -output->zoom.trans_y, 0);
+               weston_matrix_scale(&output->matrix, magnification,
+                                   magnification, 1.0);
+       }
+
+       switch (output->transform) {
+       case WL_OUTPUT_TRANSFORM_FLIPPED:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               weston_matrix_translate(&output->matrix, -output->width, 0, 0);
+               weston_matrix_scale(&output->matrix, -1, 1, 1);
+               break;
+       }
+
+       switch (output->transform) {
+       default:
+       case WL_OUTPUT_TRANSFORM_NORMAL:
+       case WL_OUTPUT_TRANSFORM_FLIPPED:
+               break;
+       case WL_OUTPUT_TRANSFORM_90:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+               weston_matrix_translate(&output->matrix, 0, -output->height, 0);
+               weston_matrix_rotate_xy(&output->matrix, 0, 1);
+               break;
+       case WL_OUTPUT_TRANSFORM_180:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+               weston_matrix_translate(&output->matrix,
+                                       -output->width, -output->height, 0);
+               weston_matrix_rotate_xy(&output->matrix, -1, 0);
+               break;
+       case WL_OUTPUT_TRANSFORM_270:
+       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+               weston_matrix_translate(&output->matrix, -output->width, 0, 0);
+               weston_matrix_rotate_xy(&output->matrix, 0, -1);
+               break;
+       }
+
+       if (output->current_scale != 1)
+               weston_matrix_scale(&output->matrix,
+                                   output->current_scale,
+                                   output->current_scale, 1);
+
+       output->dirty = 0;
+
+       weston_matrix_invert(&output->inverse_matrix, &output->matrix);
+}
+
+static void
+weston_output_transform_scale_init(struct weston_output *output, uint32_t transform, uint32_t scale)
+{
+       output->transform = transform;
+       output->native_scale = scale;
+       output->current_scale = scale;
+
+       convert_size_by_transform_scale(&output->width, &output->height,
+                                       output->current_mode->width,
+                                       output->current_mode->height,
+                                       transform, scale);
+}
+
+static void
+weston_output_init_geometry(struct weston_output *output, int x, int y)
+{
+       output->x = x;
+       output->y = y;
+
+       pixman_region32_init(&output->previous_damage);
+       pixman_region32_init_rect(&output->region, x, y,
+                                 output->width,
+                                 output->height);
+}
+
+WL_EXPORT void
+weston_output_move(struct weston_output *output, int x, int y)
+{
+       struct wl_resource *resource;
+
+       output->move_x = x - output->x;
+       output->move_y = y - output->y;
+
+       if (output->move_x == 0 && output->move_y == 0)
+               return;
+
+       weston_output_init_geometry(output, x, y);
+
+       output->dirty = 1;
+
+       /* Move views on this output. */
+       wl_signal_emit(&output->compositor->output_moved_signal, output);
+
+       /* Notify clients of the change for output position. */
+       wl_resource_for_each(resource, &output->resource_list) {
+               wl_output_send_geometry(resource,
+                                       output->x,
+                                       output->y,
+                                       output->mm_width,
+                                       output->mm_height,
+                                       output->subpixel,
+                                       output->make,
+                                       output->model,
+                                       output->transform);
+
+               if (wl_resource_get_version(resource) >= WL_OUTPUT_DONE_SINCE_VERSION)
+                       wl_output_send_done(resource);
+       }
+}
+
+/** Initialize a weston_output object's parameters
+ *
+ * \param output     The weston_output object to initialize
+ * \param c          The output's compositor
+ * \param x          x coordinate for the output in global coordinate space
+ * \param y          y coordinate for the output in global coordinate space
+ * \param mm_width   Physical width of the output as reported by the backend
+ * \param mm_height  Physical height of the output as reported by the backend
+ * \param transform  Rotation of the output
+ * \param scale      Native scaling factor for the output
+ *
+ * Sets up the transformation, zoom, and geometry of the output using
+ * the input properties.
+ *
+ * Establishes a repaint timer for the output with the relevant display
+ * object's event loop.  See output_repaint_timer_handler().
+ *
+ * The output is assigned an ID.  Weston can support up to 32 distinct
+ * outputs, with IDs numbered from 0-31; the compositor's output_id_pool
+ * is referred to and used to find the first available ID number, and
+ * then this ID is marked as used in output_id_pool.
+ *
+ * The output is also assigned a Wayland global with the wl_output
+ * external interface.
+ */
+WL_EXPORT void
+weston_output_init(struct weston_output *output, struct weston_compositor *c,
+                  int x, int y, int mm_width, int mm_height, uint32_t transform,
+                  int32_t scale)
+{
+       struct wl_event_loop *loop;
+
+       /* Verify we haven't reached the limit of 32 available output IDs */
+       assert(ffs(~c->output_id_pool) > 0);
+
+       output->compositor = c;
+       output->x = x;
+       output->y = y;
+       output->mm_width = mm_width;
+       output->mm_height = mm_height;
+       output->dirty = 1;
+       output->original_scale = scale;
+
+       weston_output_transform_scale_init(output, transform, scale);
+       weston_output_init_zoom(output);
+
+       weston_output_init_geometry(output, x, y);
+       weston_output_damage(output);
+
+       wl_signal_init(&output->frame_signal);
+       wl_signal_init(&output->destroy_signal);
+       wl_list_init(&output->animation_list);
+       wl_list_init(&output->resource_list);
+       wl_list_init(&output->feedback_list);
+       wl_list_init(&output->link);
+
+       loop = wl_display_get_event_loop(c->wl_display);
+       output->repaint_timer = wl_event_loop_add_timer(loop,
+                                       output_repaint_timer_handler, output);
+
+       /* Invert the output id pool and look for the lowest numbered
+        * switch (the least significant bit).  Take that bit's position
+        * as our ID, and mark it used in the compositor's output_id_pool.
+        */
+       output->id = ffs(~output->compositor->output_id_pool) - 1;
+       output->compositor->output_id_pool |= 1u << output->id;
+
+       output->global =
+               wl_global_create(c->wl_display, &wl_output_interface, 2,
+                                output, bind_output);
+}
+
+/** Adds an output to the compositor's output list and
+ *  send the compositor's output_created signal.
+ *
+ * \param compositor The compositor instance.
+ * \param output The output to be added.
+ */
+WL_EXPORT void
+weston_compositor_add_output(struct weston_compositor *compositor,
+                             struct weston_output *output)
+{
+       wl_list_insert(compositor->output_list.prev, &output->link);
+       wl_signal_emit(&compositor->output_created_signal, output);
+}
+
+WL_EXPORT void
+weston_output_transform_coordinate(struct weston_output *output,
+                                  double device_x, double device_y,
+                                  double *x, double *y)
+{
+       struct weston_vector p = { {
+               device_x,
+               device_y,
+               0.0,
+               1.0 } };
+
+       weston_matrix_transform(&output->inverse_matrix, &p);
+
+       *x = p.f[0] / p.f[3];
+       *y = p.f[1] / p.f[3];
+}
+
+static void
+destroy_viewport(struct wl_resource *resource)
+{
+       struct weston_surface *surface =
+               wl_resource_get_user_data(resource);
+
+       if (!surface)
+               return;
+
+       surface->viewport_resource = NULL;
+       surface->pending.buffer_viewport.buffer.src_width =
+               wl_fixed_from_int(-1);
+       surface->pending.buffer_viewport.surface.width = -1;
+       surface->pending.buffer_viewport.changed = 1;
+}
+
+static void
+viewport_destroy(struct wl_client *client,
+                struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+viewport_set_source(struct wl_client *client,
+                   struct wl_resource *resource,
+                   wl_fixed_t src_x,
+                   wl_fixed_t src_y,
+                   wl_fixed_t src_width,
+                   wl_fixed_t src_height)
+{
+       struct weston_surface *surface =
+               wl_resource_get_user_data(resource);
+
+       if (!surface) {
+               wl_resource_post_error(resource,
+                       WP_VIEWPORT_ERROR_NO_SURFACE,
+                       "wl_surface for this viewport is no longer exists");
+               return;
+       }
+
+       assert(surface->viewport_resource == resource);
+       assert(surface->resource);
+
+       if (src_width == wl_fixed_from_int(-1) &&
+           src_height == wl_fixed_from_int(-1) &&
+           src_x == wl_fixed_from_int(-1) &&
+           src_y == wl_fixed_from_int(-1)) {
+               /* unset source rect */
+               surface->pending.buffer_viewport.buffer.src_width =
+                       wl_fixed_from_int(-1);
+               surface->pending.buffer_viewport.changed = 1;
+               return;
+       }
+
+       if (src_width <= 0 || src_height <= 0 || src_x < 0 || src_y < 0) {
+               wl_resource_post_error(resource,
+                       WP_VIEWPORT_ERROR_BAD_VALUE,
+                       "wl_surface@%d viewport source "
+                       "w=%f <= 0, h=%f <= 0, x=%f < 0, or y=%f < 0",
+                       wl_resource_get_id(surface->resource),
+                       wl_fixed_to_double(src_width),
+                       wl_fixed_to_double(src_height),
+                       wl_fixed_to_double(src_x),
+                       wl_fixed_to_double(src_y));
+               return;
+       }
+
+       surface->pending.buffer_viewport.buffer.src_x = src_x;
+       surface->pending.buffer_viewport.buffer.src_y = src_y;
+       surface->pending.buffer_viewport.buffer.src_width = src_width;
+       surface->pending.buffer_viewport.buffer.src_height = src_height;
+       surface->pending.buffer_viewport.changed = 1;
+}
+
+static void
+viewport_set_destination(struct wl_client *client,
+                        struct wl_resource *resource,
+                        int32_t dst_width,
+                        int32_t dst_height)
+{
+       struct weston_surface *surface =
+               wl_resource_get_user_data(resource);
+
+       if (!surface) {
+               wl_resource_post_error(resource,
+                       WP_VIEWPORT_ERROR_NO_SURFACE,
+                       "wl_surface for this viewport no longer exists");
+               return;
+       }
+
+       assert(surface->viewport_resource == resource);
+
+       if (dst_width == -1 && dst_height == -1) {
+               /* unset destination size */
+               surface->pending.buffer_viewport.surface.width = -1;
+               surface->pending.buffer_viewport.changed = 1;
+               return;
+       }
+
+       if (dst_width <= 0 || dst_height <= 0) {
+               wl_resource_post_error(resource,
+                       WP_VIEWPORT_ERROR_BAD_VALUE,
+                       "destination size must be positive (%dx%d)",
+                       dst_width, dst_height);
+               return;
+       }
+
+       surface->pending.buffer_viewport.surface.width = dst_width;
+       surface->pending.buffer_viewport.surface.height = dst_height;
+       surface->pending.buffer_viewport.changed = 1;
+}
+
+static const struct wp_viewport_interface viewport_interface = {
+       viewport_destroy,
+       viewport_set_source,
+       viewport_set_destination
+};
+
+static void
+viewporter_destroy(struct wl_client *client,
+                  struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+viewporter_get_viewport(struct wl_client *client,
+                       struct wl_resource *viewporter,
+                       uint32_t id,
+                       struct wl_resource *surface_resource)
+{
+       int version = wl_resource_get_version(viewporter);
+       struct weston_surface *surface =
+               wl_resource_get_user_data(surface_resource);
+       struct wl_resource *resource;
+
+       if (surface->viewport_resource) {
+               wl_resource_post_error(viewporter,
+                       WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
+                       "a viewport for that surface already exists");
+               return;
+       }
+
+       resource = wl_resource_create(client, &wp_viewport_interface,
+                                     version, id);
+       if (resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_resource_set_implementation(resource, &viewport_interface,
+                                      surface, destroy_viewport);
+
+       surface->viewport_resource = resource;
+}
+
+static const struct wp_viewporter_interface viewporter_interface = {
+       viewporter_destroy,
+       viewporter_get_viewport
+};
+
+static void
+bind_viewporter(struct wl_client *client,
+               void *data, uint32_t version, uint32_t id)
+{
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client, &wp_viewporter_interface,
+                                     version, id);
+       if (resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_resource_set_implementation(resource, &viewporter_interface,
+                                      NULL, NULL);
+}
+
+static void
+destroy_presentation_feedback(struct wl_resource *feedback_resource)
+{
+       struct weston_presentation_feedback *feedback;
+
+       feedback = wl_resource_get_user_data(feedback_resource);
+
+       wl_list_remove(&feedback->link);
+       free(feedback);
+}
+
+static void
+presentation_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+presentation_feedback(struct wl_client *client,
+                     struct wl_resource *presentation_resource,
+                     struct wl_resource *surface_resource,
+                     uint32_t callback)
+{
+       struct weston_surface *surface;
+       struct weston_presentation_feedback *feedback;
+
+       surface = wl_resource_get_user_data(surface_resource);
+
+       feedback = zalloc(sizeof *feedback);
+       if (feedback == NULL)
+               goto err_calloc;
+
+       feedback->resource = wl_resource_create(client,
+                                       &wp_presentation_feedback_interface,
+                                       1, callback);
+       if (!feedback->resource)
+               goto err_create;
+
+       wl_resource_set_implementation(feedback->resource, NULL, feedback,
+                                      destroy_presentation_feedback);
+
+       wl_list_insert(&surface->pending.feedback_list, &feedback->link);
+
+       return;
+
+err_create:
+       free(feedback);
+
+err_calloc:
+       wl_client_post_no_memory(client);
+}
+
+static const struct wp_presentation_interface presentation_implementation = {
+       presentation_destroy,
+       presentation_feedback
+};
+
+static void
+bind_presentation(struct wl_client *client,
+                 void *data, uint32_t version, uint32_t id)
+{
+       struct weston_compositor *compositor = data;
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client, &wp_presentation_interface,
+                                     version, id);
+       if (resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_resource_set_implementation(resource, &presentation_implementation,
+                                      compositor, NULL);
+       wp_presentation_send_clock_id(resource, compositor->presentation_clock);
+}
+
+static void
+compositor_bind(struct wl_client *client,
+               void *data, uint32_t version, uint32_t id)
+{
+       struct weston_compositor *compositor = data;
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client, &wl_compositor_interface,
+                                     version, id);
+       if (resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_resource_set_implementation(resource, &compositor_interface,
+                                      compositor, NULL);
+}
+
+WL_EXPORT int
+weston_environment_get_fd(const char *env)
+{
+       char *e, *end;
+       int fd, flags;
+
+       e = getenv(env);
+       if (!e)
+               return -1;
+       fd = strtol(e, &end, 0);
+       if (*end != '\0')
+               return -1;
+
+       flags = fcntl(fd, F_GETFD);
+       if (flags == -1)
+               return -1;
+
+       fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+       unsetenv(env);
+
+       return fd;
+}
+
+static void
+timeline_key_binding_handler(struct weston_keyboard *keyboard, uint32_t time,
+                            uint32_t key, void *data)
+{
+       struct weston_compositor *compositor = data;
+
+       if (weston_timeline_enabled_)
+               weston_timeline_close();
+       else
+               weston_timeline_open(compositor);
+}
+
+/** Create the compositor.
+ *
+ * This functions creates and initializes a compositor instance.
+ *
+ * \param display The Wayland display to be used.
+ * \param user_data A pointer to an object that can later be retrieved
+ * using the \ref weston_compositor_get_user_data function.
+ * \return The compositor instance on success or NULL on failure.
+ */
+WL_EXPORT struct weston_compositor *
+weston_compositor_create(struct wl_display *display, void *user_data)
+{
+       struct weston_compositor *ec;
+       struct wl_event_loop *loop;
+
+       ec = zalloc(sizeof *ec);
+       if (!ec)
+               return NULL;
+
+       ec->wl_display = display;
+       ec->user_data = user_data;
+       wl_signal_init(&ec->destroy_signal);
+       wl_signal_init(&ec->create_surface_signal);
+       wl_signal_init(&ec->activate_signal);
+       wl_signal_init(&ec->transform_signal);
+       wl_signal_init(&ec->kill_signal);
+       wl_signal_init(&ec->idle_signal);
+       wl_signal_init(&ec->wake_signal);
+       wl_signal_init(&ec->show_input_panel_signal);
+       wl_signal_init(&ec->hide_input_panel_signal);
+       wl_signal_init(&ec->update_input_panel_signal);
+       wl_signal_init(&ec->seat_created_signal);
+       wl_signal_init(&ec->output_created_signal);
+       wl_signal_init(&ec->output_destroyed_signal);
+       wl_signal_init(&ec->output_moved_signal);
+       wl_signal_init(&ec->output_resized_signal);
+       wl_signal_init(&ec->session_signal);
+       ec->session_active = 1;
+
+       ec->output_id_pool = 0;
+       ec->repaint_msec = DEFAULT_REPAINT_WINDOW;
+
+       if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,
+                             ec, compositor_bind))
+               goto fail;
+
+       if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,
+                             ec, bind_subcompositor))
+               goto fail;
+
+       if (!wl_global_create(ec->wl_display, &wp_viewporter_interface, 1,
+                             ec, bind_viewporter))
+               goto fail;
+
+       if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,
+                             ec, bind_presentation))
+               goto fail;
+
+       wl_list_init(&ec->view_list);
+       wl_list_init(&ec->plane_list);
+       wl_list_init(&ec->layer_list);
+       wl_list_init(&ec->seat_list);
+       wl_list_init(&ec->output_list);
+       wl_list_init(&ec->key_binding_list);
+       wl_list_init(&ec->modifier_binding_list);
+       wl_list_init(&ec->button_binding_list);
+       wl_list_init(&ec->touch_binding_list);
+       wl_list_init(&ec->axis_binding_list);
+       wl_list_init(&ec->debug_binding_list);
+
+       weston_plane_init(&ec->primary_plane, ec, 0, 0);
+       weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
+
+       wl_data_device_manager_init(ec->wl_display);
+
+       wl_display_init_shm(ec->wl_display);
+
+       loop = wl_display_get_event_loop(ec->wl_display);
+       ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
+
+       weston_layer_init(&ec->fade_layer, &ec->layer_list);
+       weston_layer_init(&ec->cursor_layer, &ec->fade_layer.link);
+
+       weston_compositor_add_debug_binding(ec, KEY_T,
+                                           timeline_key_binding_handler, ec);
+
+       return ec;
+
+fail:
+       free(ec);
+       return NULL;
+}
+
+WL_EXPORT void
+weston_compositor_shutdown(struct weston_compositor *ec)
+{
+       struct weston_output *output, *next;
+
+       wl_event_source_remove(ec->idle_source);
+
+       /* Destroy all outputs associated with this compositor */
+       wl_list_for_each_safe(output, next, &ec->output_list, link)
+               output->destroy(output);
+
+       if (ec->renderer)
+               ec->renderer->destroy(ec);
+
+       weston_binding_list_destroy_all(&ec->key_binding_list);
+       weston_binding_list_destroy_all(&ec->modifier_binding_list);
+       weston_binding_list_destroy_all(&ec->button_binding_list);
+       weston_binding_list_destroy_all(&ec->touch_binding_list);
+       weston_binding_list_destroy_all(&ec->axis_binding_list);
+       weston_binding_list_destroy_all(&ec->debug_binding_list);
+
+       weston_plane_release(&ec->primary_plane);
+}
+
+WL_EXPORT void
+weston_compositor_exit_with_code(struct weston_compositor *compositor,
+                                int exit_code)
+{
+       if (compositor->exit_code == EXIT_SUCCESS)
+               compositor->exit_code = exit_code;
+
+       weston_compositor_exit(compositor);
+}
+
+WL_EXPORT void
+weston_compositor_set_default_pointer_grab(struct weston_compositor *ec,
+                       const struct weston_pointer_grab_interface *interface)
+{
+       struct weston_seat *seat;
+
+       ec->default_pointer_grab = interface;
+       wl_list_for_each(seat, &ec->seat_list, link) {
+               struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+               if (pointer)
+                       weston_pointer_set_default_grab(pointer, interface);
+       }
+}
+
+WL_EXPORT int
+weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
+                                        clockid_t clk_id)
+{
+       struct timespec ts;
+
+       if (clock_gettime(clk_id, &ts) < 0)
+               return -1;
+
+       compositor->presentation_clock = clk_id;
+
+       return 0;
+}
+
+/*
+ * For choosing the software clock, when the display hardware or API
+ * does not expose a compatible presentation timestamp.
+ */
+WL_EXPORT int
+weston_compositor_set_presentation_clock_software(
+                                       struct weston_compositor *compositor)
+{
+       /* In order of preference */
+       static const clockid_t clocks[] = {
+               CLOCK_MONOTONIC_RAW,    /* no jumps, no crawling */
+               CLOCK_MONOTONIC_COARSE, /* no jumps, may crawl, fast & coarse */
+               CLOCK_MONOTONIC,        /* no jumps, may crawl */
+               CLOCK_REALTIME_COARSE,  /* may jump and crawl, fast & coarse */
+               CLOCK_REALTIME          /* may jump and crawl */
+       };
+       unsigned i;
+
+       for (i = 0; i < ARRAY_LENGTH(clocks); i++)
+               if (weston_compositor_set_presentation_clock(compositor,
+                                                            clocks[i]) == 0)
+                       return 0;
+
+       weston_log("Error: no suitable presentation clock available.\n");
+
+       return -1;
+}
+
+/** Read the current time from the Presentation clock
+ *
+ * \param compositor
+ * \param ts[out] The current time.
+ *
+ * \note Reading the current time in user space is always imprecise to some
+ * degree.
+ *
+ * This function is never meant to fail. If reading the clock does fail,
+ * an error message is logged and a zero time is returned. Callers are not
+ * supposed to detect or react to failures.
+ */
+WL_EXPORT void
+weston_compositor_read_presentation_clock(
+                       const struct weston_compositor *compositor,
+                       struct timespec *ts)
+{
+       static bool warned;
+       int ret;
+
+       ret = clock_gettime(compositor->presentation_clock, ts);
+       if (ret < 0) {
+               ts->tv_sec = 0;
+               ts->tv_nsec = 0;
+
+               if (!warned)
+                       weston_log("Error: failure to read "
+                                  "the presentation clock %#x: '%m' (%d)\n",
+                                  compositor->presentation_clock, errno);
+               warned = true;
+       }
+}
+
+/** Import dmabuf buffer into current renderer
+ *
+ * \param compositor
+ * \param buffer the dmabuf buffer to import
+ * \return true on usable buffers, false otherwise
+ *
+ * This function tests that the linux_dmabuf_buffer is usable
+ * for the current renderer. Returns false on unusable buffers. Usually
+ * usability is tested by importing the dmabufs for composition.
+ *
+ * This hook is also used for detecting if the renderer supports
+ * dmabufs at all. If the renderer hook is NULL, dmabufs are not
+ * supported.
+ * */
+WL_EXPORT bool
+weston_compositor_import_dmabuf(struct weston_compositor *compositor,
+                               struct linux_dmabuf_buffer *buffer)
+{
+       struct weston_renderer *renderer;
+
+       renderer = compositor->renderer;
+
+       if (renderer->import_dmabuf == NULL)
+               return false;
+
+       return renderer->import_dmabuf(compositor, buffer);
+}
+
+WL_EXPORT void
+weston_version(int *major, int *minor, int *micro)
+{
+       *major = WESTON_VERSION_MAJOR;
+       *minor = WESTON_VERSION_MINOR;
+       *micro = WESTON_VERSION_MICRO;
+}
+
+WL_EXPORT void *
+weston_load_module(const char *name, const char *entrypoint)
+{
+       const char *builddir = getenv("WESTON_BUILD_DIR");
+       char path[PATH_MAX];
+       void *module, *init;
+
+       if (name == NULL)
+               return NULL;
+
+       if (name[0] != '/') {
+               if (builddir)
+                       snprintf(path, sizeof path, "%s/.libs/%s", builddir, name);
+               else
+                       snprintf(path, sizeof path, "%s/%s", LIBWESTON_MODULEDIR, name);
+       } else {
+               snprintf(path, sizeof path, "%s", name);
+       }
+
+       module = dlopen(path, RTLD_NOW | RTLD_NOLOAD);
+       if (module) {
+               weston_log("Module '%s' already loaded\n", path);
+               dlclose(module);
+               return NULL;
+       }
+
+       weston_log("Loading module '%s'\n", path);
+       module = dlopen(path, RTLD_NOW);
+       if (!module) {
+               weston_log("Failed to load module: %s\n", dlerror());
+               return NULL;
+       }
+
+       init = dlsym(module, entrypoint);
+       if (!init) {
+               weston_log("Failed to lookup init function: %s\n", dlerror());
+               dlclose(module);
+               return NULL;
+       }
+
+       return init;
+}
+
+
+/** Destroys the compositor.
+ *
+ * This function cleans up the compositor state and destroys it.
+ *
+ * \param compositor The compositor to be destroyed.
+ */
+WL_EXPORT void
+weston_compositor_destroy(struct weston_compositor *compositor)
+{
+       /* prevent further rendering while shutting down */
+       compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
+
+       wl_signal_emit(&compositor->destroy_signal, compositor);
+
+       weston_compositor_xkb_destroy(compositor);
+
+       if (compositor->backend)
+               compositor->backend->destroy(compositor);
+       free(compositor);
+}
+
+/** Instruct the compositor to exit.
+ *
+ * This functions does not directly destroy the compositor object, it merely
+ * command it to start the tear down process. It is not guaranteed that the
+ * tear down will happen immediately.
+ *
+ * \param compositor The compositor to tear down.
+ */
+WL_EXPORT void
+weston_compositor_exit(struct weston_compositor *compositor)
+{
+       compositor->exit(compositor);
+}
+
+/** Return the user data stored in the compositor.
+ *
+ * This function returns the user data pointer set with user_data parameter
+ * to the \ref weston_compositor_create function.
+ */
+WL_EXPORT void *
+weston_compositor_get_user_data(struct weston_compositor *compositor)
+{
+       return compositor->user_data;
+}
+
+static const char * const backend_map[] = {
+       [WESTON_BACKEND_DRM] =          "drm-backend.so",
+       [WESTON_BACKEND_FBDEV] =        "fbdev-backend.so",
+       [WESTON_BACKEND_HEADLESS] =     "headless-backend.so",
+       [WESTON_BACKEND_RDP] =          "rdp-backend.so",
+       [WESTON_BACKEND_WAYLAND] =      "wayland-backend.so",
+       [WESTON_BACKEND_X11] =          "x11-backend.so",
+};
+
+/** Load a backend into a weston_compositor
+ *
+ * A backend must be loaded to make a weston_compositor work. A backend
+ * provides input and output capabilities, and determines the renderer to use.
+ *
+ * \param compositor A compositor that has not had a backend loaded yet.
+ * \param backend Name of the backend file.
+ * \param config_base A pointer to a backend-specific configuration
+ * structure's 'base' member.
+ *
+ * \return 0 on success, or -1 on error.
+ */
+WL_EXPORT int
+weston_compositor_load_backend(struct weston_compositor *compositor,
+                              enum weston_compositor_backend backend,
+                              struct weston_backend_config *config_base)
+{
+       int (*backend_init)(struct weston_compositor *c,
+                           struct weston_backend_config *config_base);
+
+       if (backend < 0 || backend >= ARRAY_LENGTH(backend_map))
+               return -1;
+
+       backend_init = weston_load_module(backend_map[backend], "backend_init");
+       if (!backend_init)
+               return -1;
+
+       return backend_init(compositor, config_base);
+}
diff --git a/libweston/compositor.h b/libweston/compositor.h
new file mode 100644 (file)
index 0000000..9e5155c
--- /dev/null
@@ -0,0 +1,1724 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _WAYLAND_SYSTEM_COMPOSITOR_H_
+#define _WAYLAND_SYSTEM_COMPOSITOR_H_
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#include <stdbool.h>
+#include <time.h>
+#include <pixman.h>
+#include <xkbcommon/xkbcommon.h>
+
+#define WL_HIDE_DEPRECATED
+#include <wayland-server.h>
+
+#include "version.h"
+#include "matrix.h"
+#include "config-parser.h"
+#include "zalloc.h"
+#include "timeline-object.h"
+
+struct weston_transform {
+       struct weston_matrix matrix;
+       struct wl_list link;
+};
+
+struct weston_surface;
+struct weston_buffer;
+struct shell_surface;
+struct weston_seat;
+struct weston_output;
+struct input_method;
+struct weston_pointer;
+struct linux_dmabuf_buffer;
+struct weston_recorder;
+
+enum weston_keyboard_modifier {
+       MODIFIER_CTRL = (1 << 0),
+       MODIFIER_ALT = (1 << 1),
+       MODIFIER_SUPER = (1 << 2),
+       MODIFIER_SHIFT = (1 << 3),
+};
+
+enum weston_keyboard_locks {
+       WESTON_NUM_LOCK = (1 << 0),
+       WESTON_CAPS_LOCK = (1 << 1),
+};
+
+enum weston_led {
+       LED_NUM_LOCK = (1 << 0),
+       LED_CAPS_LOCK = (1 << 1),
+       LED_SCROLL_LOCK = (1 << 2),
+};
+
+struct weston_mode {
+       uint32_t flags;
+       int32_t width, height;
+       uint32_t refresh;
+       struct wl_list link;
+};
+
+struct weston_shell_client {
+       void (*send_configure)(struct weston_surface *surface, int32_t width, int32_t height);
+       void (*send_position)(struct weston_surface *surface, int32_t x, int32_t y);
+};
+
+struct weston_shell_interface {
+       void *shell;                    /* either desktop or tablet */
+
+       struct shell_surface *(*create_shell_surface)(void *shell,
+                                                     struct weston_surface *surface,
+                                                     const struct weston_shell_client *client);
+       void (*set_toplevel)(struct shell_surface *shsurf);
+
+       void (*set_transient)(struct shell_surface *shsurf,
+                             struct weston_surface *parent,
+                             int x, int y, uint32_t flags);
+       void (*set_fullscreen)(struct shell_surface *shsurf,
+                              uint32_t method,
+                              uint32_t framerate,
+                              struct weston_output *output);
+       void (*set_xwayland)(struct shell_surface *shsurf,
+                              int x, int y, uint32_t flags);
+       int (*move)(struct shell_surface *shsurf, struct weston_pointer *pointer);
+       int (*resize)(struct shell_surface *shsurf,
+                     struct weston_pointer *pointer, uint32_t edges);
+       void (*set_title)(struct shell_surface *shsurf,
+                         const char *title);
+       void (*set_window_geometry)(struct shell_surface *shsurf,
+                                   int32_t x, int32_t y,
+                                   int32_t width, int32_t height);
+       void (*set_maximized)(struct shell_surface *shsurf);
+       void (*set_pid)(struct shell_surface *shsurf, pid_t pid);
+       void (*get_output_work_area)(void *shell, struct weston_output *output, pixman_rectangle32_t *area);
+};
+
+struct weston_animation {
+       void (*frame)(struct weston_animation *animation,
+                     struct weston_output *output, uint32_t msecs);
+       int frame_counter;
+       struct wl_list link;
+};
+
+enum {
+       WESTON_SPRING_OVERSHOOT,
+       WESTON_SPRING_CLAMP,
+       WESTON_SPRING_BOUNCE
+};
+
+struct weston_spring {
+       double k;
+       double friction;
+       double current;
+       double target;
+       double previous;
+       double min, max;
+       uint32_t timestamp;
+       uint32_t clip;
+};
+
+struct weston_output_zoom {
+       bool active;
+       float increment;
+       float level;
+       float max_level;
+       float trans_x, trans_y;
+       struct {
+               double x, y;
+       } current;
+       struct weston_seat *seat;
+       struct weston_animation animation_z;
+       struct weston_spring spring_z;
+       struct wl_listener motion_listener;
+};
+
+/* bit compatible with drm definitions. */
+enum dpms_enum {
+       WESTON_DPMS_ON,
+       WESTON_DPMS_STANDBY,
+       WESTON_DPMS_SUSPEND,
+       WESTON_DPMS_OFF
+};
+
+struct weston_output {
+       uint32_t id;
+       char *name;
+
+       void *renderer_state;
+
+       struct wl_list link;
+       struct wl_list resource_list;
+       struct wl_global *global;
+       struct weston_compositor *compositor;
+
+       /** From global to output buffer coordinates. */
+       struct weston_matrix matrix;
+       /** From output buffer to global coordinates. */
+       struct weston_matrix inverse_matrix;
+
+       struct wl_list animation_list;
+       int32_t x, y, width, height;
+       int32_t mm_width, mm_height;
+
+       /** Output area in global coordinates, simple rect */
+       pixman_region32_t region;
+
+       pixman_region32_t previous_damage;
+       int repaint_needed;
+       int repaint_scheduled;
+       struct wl_event_source *repaint_timer;
+       struct weston_output_zoom zoom;
+       int dirty;
+       struct wl_signal frame_signal;
+       struct wl_signal destroy_signal;
+       int move_x, move_y;
+       uint32_t frame_time; /* presentation timestamp in milliseconds */
+       uint64_t msc;        /* media stream counter */
+       int disable_planes;
+       int destroying;
+       struct wl_list feedback_list;
+
+       char *make, *model, *serial_number;
+       uint32_t subpixel;
+       uint32_t transform;
+       int32_t native_scale;
+       int32_t current_scale;
+       int32_t original_scale;
+
+       struct weston_mode *native_mode;
+       struct weston_mode *current_mode;
+       struct weston_mode *original_mode;
+       struct wl_list mode_list;
+
+       void (*start_repaint_loop)(struct weston_output *output);
+       int (*repaint)(struct weston_output *output,
+                       pixman_region32_t *damage);
+       void (*destroy)(struct weston_output *output);
+       void (*assign_planes)(struct weston_output *output);
+       int (*switch_mode)(struct weston_output *output, struct weston_mode *mode);
+
+       /* backlight values are on 0-255 range, where higher is brighter */
+       int32_t backlight_current;
+       void (*set_backlight)(struct weston_output *output, uint32_t value);
+       void (*set_dpms)(struct weston_output *output, enum dpms_enum level);
+
+       int connection_internal;
+       uint16_t gamma_size;
+       void (*set_gamma)(struct weston_output *output,
+                         uint16_t size,
+                         uint16_t *r,
+                         uint16_t *g,
+                         uint16_t *b);
+
+       struct weston_timeline_object timeline;
+};
+
+enum weston_pointer_motion_mask {
+       WESTON_POINTER_MOTION_ABS = 1 << 0,
+       WESTON_POINTER_MOTION_REL = 1 << 1,
+};
+
+struct weston_pointer_motion_event {
+       uint32_t mask;
+       double x;
+       double y;
+       double dx;
+       double dy;
+};
+
+struct weston_pointer_axis_event {
+       uint32_t axis;
+       double value;
+       bool has_discrete;
+       int32_t discrete;
+};
+
+struct weston_pointer_grab;
+struct weston_pointer_grab_interface {
+       void (*focus)(struct weston_pointer_grab *grab);
+       void (*motion)(struct weston_pointer_grab *grab, uint32_t time,
+                      struct weston_pointer_motion_event *event);
+       void (*button)(struct weston_pointer_grab *grab,
+                      uint32_t time, uint32_t button, uint32_t state);
+       void (*axis)(struct weston_pointer_grab *grab,
+                    uint32_t time,
+                    struct weston_pointer_axis_event *event);
+       void (*axis_source)(struct weston_pointer_grab *grab, uint32_t source);
+       void (*frame)(struct weston_pointer_grab *grab);
+       void (*cancel)(struct weston_pointer_grab *grab);
+};
+
+struct weston_pointer_grab {
+       const struct weston_pointer_grab_interface *interface;
+       struct weston_pointer *pointer;
+};
+
+struct weston_keyboard_grab;
+struct weston_keyboard_grab_interface {
+       void (*key)(struct weston_keyboard_grab *grab, uint32_t time,
+                   uint32_t key, uint32_t state);
+       void (*modifiers)(struct weston_keyboard_grab *grab, uint32_t serial,
+                         uint32_t mods_depressed, uint32_t mods_latched,
+                         uint32_t mods_locked, uint32_t group);
+       void (*cancel)(struct weston_keyboard_grab *grab);
+};
+
+struct weston_keyboard_grab {
+       const struct weston_keyboard_grab_interface *interface;
+       struct weston_keyboard *keyboard;
+};
+
+struct weston_touch_grab;
+struct weston_touch_grab_interface {
+       void (*down)(struct weston_touch_grab *grab,
+                       uint32_t time,
+                       int touch_id,
+                       wl_fixed_t sx,
+                       wl_fixed_t sy);
+       void (*up)(struct weston_touch_grab *grab,
+                       uint32_t time,
+                       int touch_id);
+       void (*motion)(struct weston_touch_grab *grab,
+                       uint32_t time,
+                       int touch_id,
+                       wl_fixed_t sx,
+                       wl_fixed_t sy);
+       void (*frame)(struct weston_touch_grab *grab);
+       void (*cancel)(struct weston_touch_grab *grab);
+};
+
+struct weston_touch_grab {
+       const struct weston_touch_grab_interface *interface;
+       struct weston_touch *touch;
+};
+
+struct weston_data_offer {
+       struct wl_resource *resource;
+       struct weston_data_source *source;
+       struct wl_listener source_destroy_listener;
+       uint32_t dnd_actions;
+       enum wl_data_device_manager_dnd_action preferred_dnd_action;
+       bool in_ask;
+};
+
+struct weston_data_source {
+       struct wl_resource *resource;
+       struct wl_signal destroy_signal;
+       struct wl_array mime_types;
+       struct weston_data_offer *offer;
+       struct weston_seat *seat;
+       bool accepted;
+       bool actions_set;
+       uint32_t dnd_actions;
+       enum wl_data_device_manager_dnd_action current_dnd_action;
+       enum wl_data_device_manager_dnd_action compositor_action;
+
+       void (*accept)(struct weston_data_source *source,
+                      uint32_t serial, const char *mime_type);
+       void (*send)(struct weston_data_source *source,
+                    const char *mime_type, int32_t fd);
+       void (*cancel)(struct weston_data_source *source);
+};
+
+struct weston_pointer_client {
+       struct wl_list link;
+       struct wl_client *client;
+       struct wl_list pointer_resources;
+};
+
+struct weston_pointer {
+       struct weston_seat *seat;
+
+       struct wl_list pointer_clients;
+
+       struct weston_view *focus;
+       struct weston_pointer_client *focus_client;
+       uint32_t focus_serial;
+       struct wl_listener focus_view_listener;
+       struct wl_listener focus_resource_listener;
+       struct wl_signal focus_signal;
+       struct wl_signal motion_signal;
+
+       struct weston_view *sprite;
+       struct wl_listener sprite_destroy_listener;
+       int32_t hotspot_x, hotspot_y;
+
+       struct weston_pointer_grab *grab;
+       struct weston_pointer_grab default_grab;
+       wl_fixed_t grab_x, grab_y;
+       uint32_t grab_button;
+       uint32_t grab_serial;
+       uint32_t grab_time;
+
+       wl_fixed_t x, y;
+       wl_fixed_t sx, sy;
+       uint32_t button_count;
+
+       struct wl_listener output_destroy_listener;
+};
+
+
+struct weston_touch {
+       struct weston_seat *seat;
+
+       struct wl_list resource_list;
+       struct wl_list focus_resource_list;
+       struct weston_view *focus;
+       struct wl_listener focus_view_listener;
+       struct wl_listener focus_resource_listener;
+       uint32_t focus_serial;
+       struct wl_signal focus_signal;
+
+       uint32_t num_tp;
+
+       struct weston_touch_grab *grab;
+       struct weston_touch_grab default_grab;
+       int grab_touch_id;
+       wl_fixed_t grab_x, grab_y;
+       uint32_t grab_serial;
+       uint32_t grab_time;
+};
+
+void
+weston_pointer_motion_to_abs(struct weston_pointer *pointer,
+                            struct weston_pointer_motion_event *event,
+                            wl_fixed_t *x, wl_fixed_t *y);
+
+struct weston_pointer *
+weston_pointer_create(struct weston_seat *seat);
+void
+weston_pointer_destroy(struct weston_pointer *pointer);
+void
+weston_pointer_send_axis(struct weston_pointer *pointer,
+                        uint32_t time,
+                        struct weston_pointer_axis_event *event);
+void
+weston_pointer_send_axis_source(struct weston_pointer *pointer,
+                               uint32_t source);
+void
+weston_pointer_send_frame(struct weston_pointer *pointer);
+
+void
+weston_pointer_set_focus(struct weston_pointer *pointer,
+                        struct weston_view *view,
+                        wl_fixed_t sx, wl_fixed_t sy);
+void
+weston_pointer_clear_focus(struct weston_pointer *pointer);
+void
+weston_pointer_start_grab(struct weston_pointer *pointer,
+                         struct weston_pointer_grab *grab);
+void
+weston_pointer_end_grab(struct weston_pointer *pointer);
+void
+weston_pointer_clamp(struct weston_pointer *pointer,
+                           wl_fixed_t *fx, wl_fixed_t *fy);
+void
+weston_pointer_move(struct weston_pointer *pointer,
+                   struct weston_pointer_motion_event *event);
+void
+weston_pointer_set_default_grab(struct weston_pointer *pointer,
+               const struct weston_pointer_grab_interface *interface);
+
+struct weston_keyboard *
+weston_keyboard_create(void);
+void
+weston_keyboard_destroy(struct weston_keyboard *keyboard);
+void
+weston_keyboard_set_focus(struct weston_keyboard *keyboard,
+                         struct weston_surface *surface);
+void
+weston_keyboard_start_grab(struct weston_keyboard *device,
+                          struct weston_keyboard_grab *grab);
+void
+weston_keyboard_end_grab(struct weston_keyboard *keyboard);
+int
+/*
+ * 'mask' and 'value' should be a bitwise mask of one or more
+ * valued of the weston_keyboard_locks enum.
+ */
+weston_keyboard_set_locks(struct weston_keyboard *keyboard,
+                         uint32_t mask, uint32_t value);
+
+struct weston_touch *
+weston_touch_create(void);
+void
+weston_touch_destroy(struct weston_touch *touch);
+void
+weston_touch_set_focus(struct weston_touch *touch,
+                      struct weston_view *view);
+void
+weston_touch_start_grab(struct weston_touch *device,
+                       struct weston_touch_grab *grab);
+void
+weston_touch_end_grab(struct weston_touch *touch);
+
+void
+wl_data_device_set_keyboard_focus(struct weston_seat *seat);
+
+int
+wl_data_device_manager_init(struct wl_display *display);
+
+
+void
+weston_seat_set_selection(struct weston_seat *seat,
+                         struct weston_data_source *source, uint32_t serial);
+void
+weston_seat_send_selection(struct weston_seat *seat, struct wl_client *client);
+
+int
+weston_pointer_start_drag(struct weston_pointer *pointer,
+                      struct weston_data_source *source,
+                      struct weston_surface *icon,
+                      struct wl_client *client);
+int
+weston_touch_start_drag(struct weston_touch *touch,
+                       struct weston_data_source *source,
+                       struct weston_surface *icon,
+                       struct wl_client *client);
+
+struct weston_xkb_info {
+       struct xkb_keymap *keymap;
+       int keymap_fd;
+       size_t keymap_size;
+       char *keymap_area;
+       int32_t ref_count;
+       xkb_mod_index_t shift_mod;
+       xkb_mod_index_t caps_mod;
+       xkb_mod_index_t ctrl_mod;
+       xkb_mod_index_t alt_mod;
+       xkb_mod_index_t mod2_mod;
+       xkb_mod_index_t mod3_mod;
+       xkb_mod_index_t super_mod;
+       xkb_mod_index_t mod5_mod;
+       xkb_led_index_t num_led;
+       xkb_led_index_t caps_led;
+       xkb_led_index_t scroll_led;
+};
+
+struct weston_keyboard {
+       struct weston_seat *seat;
+
+       struct wl_list resource_list;
+       struct wl_list focus_resource_list;
+       struct weston_surface *focus;
+       struct wl_listener focus_resource_listener;
+       uint32_t focus_serial;
+       struct wl_signal focus_signal;
+
+       struct weston_keyboard_grab *grab;
+       struct weston_keyboard_grab default_grab;
+       uint32_t grab_key;
+       uint32_t grab_serial;
+       uint32_t grab_time;
+
+       struct wl_array keys;
+
+       struct {
+               uint32_t mods_depressed;
+               uint32_t mods_latched;
+               uint32_t mods_locked;
+               uint32_t group;
+       } modifiers;
+
+       struct weston_keyboard_grab input_method_grab;
+       struct wl_resource *input_method_resource;
+
+       struct weston_xkb_info *xkb_info;
+       struct {
+               struct xkb_state *state;
+               enum weston_led leds;
+       } xkb_state;
+       struct xkb_keymap *pending_keymap;
+};
+
+struct weston_seat {
+       struct wl_list base_resource_list;
+
+       struct wl_global *global;
+       struct weston_pointer *pointer_state;
+       struct weston_keyboard *keyboard_state;
+       struct weston_touch *touch_state;
+       int pointer_device_count;
+       int keyboard_device_count;
+       int touch_device_count;
+
+       struct weston_output *output; /* constraint */
+
+       struct wl_signal destroy_signal;
+       struct wl_signal updated_caps_signal;
+
+       struct weston_compositor *compositor;
+       struct wl_list link;
+       enum weston_keyboard_modifier modifier_state;
+       struct weston_surface *saved_kbd_focus;
+       struct wl_listener saved_kbd_focus_listener;
+       struct wl_list drag_resource_list;
+
+       uint32_t selection_serial;
+       struct weston_data_source *selection_data_source;
+       struct wl_listener selection_data_source_listener;
+       struct wl_signal selection_signal;
+
+       void (*led_update)(struct weston_seat *ws, enum weston_led leds);
+
+       struct input_method *input_method;
+       char *seat_name;
+};
+
+enum {
+       WESTON_COMPOSITOR_ACTIVE,       /* normal rendering and events */
+       WESTON_COMPOSITOR_IDLE,         /* shell->unlock called on activity */
+       WESTON_COMPOSITOR_OFFSCREEN,    /* no rendering, no frame events */
+       WESTON_COMPOSITOR_SLEEPING      /* same as offscreen, but also set dpms
+                                         * to off */
+};
+
+struct weston_layer_entry {
+       struct wl_list link;
+       struct weston_layer *layer;
+};
+
+struct weston_layer {
+       struct weston_layer_entry view_list;
+       struct wl_list link;
+       pixman_box32_t mask;
+};
+
+struct weston_plane {
+       struct weston_compositor *compositor;
+       pixman_region32_t damage; /**< in global coords */
+       pixman_region32_t clip;
+       int32_t x, y;
+       struct wl_list link;
+};
+
+struct weston_renderer {
+       int (*read_pixels)(struct weston_output *output,
+                              pixman_format_code_t format, void *pixels,
+                              uint32_t x, uint32_t y,
+                              uint32_t width, uint32_t height);
+       void (*repaint_output)(struct weston_output *output,
+                              pixman_region32_t *output_damage);
+       void (*flush_damage)(struct weston_surface *surface);
+       void (*attach)(struct weston_surface *es, struct weston_buffer *buffer);
+       void (*surface_set_color)(struct weston_surface *surface,
+                              float red, float green,
+                              float blue, float alpha);
+       void (*destroy)(struct weston_compositor *ec);
+
+
+       /** See weston_surface_get_content_size() */
+       void (*surface_get_content_size)(struct weston_surface *surface,
+                                        int *width, int *height);
+
+       /** See weston_surface_copy_content() */
+       int (*surface_copy_content)(struct weston_surface *surface,
+                                   void *target, size_t size,
+                                   int src_x, int src_y,
+                                   int width, int height);
+
+       /** See weston_compositor_import_dmabuf() */
+       bool (*import_dmabuf)(struct weston_compositor *ec,
+                             struct linux_dmabuf_buffer *buffer);
+};
+
+enum weston_capability {
+       /* backend/renderer supports arbitrary rotation */
+       WESTON_CAP_ROTATION_ANY                 = 0x0001,
+
+       /* screencaptures need to be y-flipped */
+       WESTON_CAP_CAPTURE_YFLIP                = 0x0002,
+
+       /* backend/renderer has a separate cursor plane */
+       WESTON_CAP_CURSOR_PLANE                 = 0x0004,
+
+       /* backend supports setting arbitrary resolutions */
+       WESTON_CAP_ARBITRARY_MODES              = 0x0008,
+
+       /* renderer supports weston_view_set_mask() clipping */
+       WESTON_CAP_VIEW_CLIP_MASK               = 0x0010,
+};
+
+/* Configuration struct for an output.
+ *
+ * This struct is used to pass the configuration for an output
+ * to the compositor backend when creating a new output.
+ * The backend can subclass this struct to handle backend
+ * specific data.
+ */
+struct weston_backend_output_config {
+       uint32_t transform;
+       uint32_t width;
+       uint32_t height;
+       uint32_t scale;
+};
+
+/* Configuration struct for a backend.
+ *
+ * This struct carries the configuration for a backend, and it's
+ * passed to the backend's init entry point. The backend will
+ * likely want to subclass this in order to handle backend specific
+ * data.
+ *
+ * NOTE: Alternate designs were proposed (Feb 2016) for using opaque
+ * structures[1] and for section+key/value getter/setters[2].  The rationale
+ * for selecting the transparent structure design is based on several
+ * assumptions[3] which may require re-evaluating the design choice if they
+ * fail to hold.
+ *
+ * 1: https://lists.freedesktop.org/archives/wayland-devel/2016-February/026989.html
+ * 2: https://lists.freedesktop.org/archives/wayland-devel/2016-February/026929.html
+ * 3: https://lists.freedesktop.org/archives/wayland-devel/2016-February/027228.html
+ */
+struct weston_backend_config {
+   /** Major version for the backend-specific config struct
+    *
+    * This version must match exactly what the backend expects, otherwise
+    * the struct is incompatible.
+    */
+   uint32_t struct_version;
+
+   /** Minor version of the backend-specific config struct
+    *
+    * This must be set to sizeof(struct backend-specific config).
+    * If the value here is smaller than what the backend expects, the
+    * extra config members will assume their default values.
+    *
+    * A value greater than what the backend expects is incompatible.
+    */
+   size_t struct_size;
+};
+
+struct weston_backend {
+       void (*destroy)(struct weston_compositor *compositor);
+       void (*restore)(struct weston_compositor *compositor);
+};
+
+struct weston_compositor {
+       struct wl_signal destroy_signal;
+
+       struct wl_display *wl_display;
+       struct weston_shell_interface shell_interface;
+
+       /* surface signals */
+       struct wl_signal create_surface_signal;
+       struct wl_signal activate_signal;
+       struct wl_signal transform_signal;
+
+       struct wl_signal kill_signal;
+       struct wl_signal idle_signal;
+       struct wl_signal wake_signal;
+
+       struct wl_signal show_input_panel_signal;
+       struct wl_signal hide_input_panel_signal;
+       struct wl_signal update_input_panel_signal;
+
+       struct wl_signal seat_created_signal;
+       struct wl_signal output_created_signal;
+       struct wl_signal output_destroyed_signal;
+       struct wl_signal output_moved_signal;
+       struct wl_signal output_resized_signal; /* callback argument: resized output */
+
+       struct wl_signal session_signal;
+       int session_active;
+
+       struct weston_layer fade_layer;
+       struct weston_layer cursor_layer;
+
+       struct wl_list output_list;
+       struct wl_list seat_list;
+       struct wl_list layer_list;
+       struct wl_list view_list;       /* struct weston_view::link */
+       struct wl_list plane_list;
+       struct wl_list key_binding_list;
+       struct wl_list modifier_binding_list;
+       struct wl_list button_binding_list;
+       struct wl_list touch_binding_list;
+       struct wl_list axis_binding_list;
+       struct wl_list debug_binding_list;
+
+       uint32_t state;
+       struct wl_event_source *idle_source;
+       uint32_t idle_inhibit;
+       int idle_time;                  /* timeout, s */
+
+       const struct weston_pointer_grab_interface *default_pointer_grab;
+
+       /* Repaint state. */
+       struct weston_plane primary_plane;
+       uint32_t capabilities; /* combination of enum weston_capability */
+
+       struct weston_renderer *renderer;
+
+       pixman_format_code_t read_format;
+
+       struct weston_backend *backend;
+
+       struct weston_launcher *launcher;
+
+       uint32_t output_id_pool;
+
+       struct xkb_rule_names xkb_names;
+       struct xkb_context *xkb_context;
+       struct weston_xkb_info *xkb_info;
+
+       /* Raw keyboard processing (no libxkbcommon initialization or handling) */
+       int use_xkbcommon;
+
+       int32_t kb_repeat_rate;
+       int32_t kb_repeat_delay;
+
+       bool vt_switching;
+
+       clockid_t presentation_clock;
+       int32_t repaint_msec;
+
+       int exit_code;
+
+       void *user_data;
+       void (*exit)(struct weston_compositor *c);
+};
+
+struct weston_buffer {
+       struct wl_resource *resource;
+       struct wl_signal destroy_signal;
+       struct wl_listener destroy_listener;
+
+       union {
+               struct wl_shm_buffer *shm_buffer;
+               void *legacy_buffer;
+       };
+       int32_t width, height;
+       uint32_t busy_count;
+       int y_inverted;
+};
+
+struct weston_buffer_reference {
+       struct weston_buffer *buffer;
+       struct wl_listener destroy_listener;
+};
+
+struct weston_buffer_viewport {
+       struct {
+               /* wl_surface.set_buffer_transform */
+               uint32_t transform;
+
+               /* wl_surface.set_scaling_factor */
+               int32_t scale;
+
+               /*
+                * If src_width != wl_fixed_from_int(-1),
+                * then and only then src_* are used.
+                */
+               wl_fixed_t src_x, src_y;
+               wl_fixed_t src_width, src_height;
+       } buffer;
+
+       struct {
+               /*
+                * If width == -1, the size is inferred from the buffer.
+                */
+               int32_t width, height;
+       } surface;
+
+       int changed;
+};
+
+struct weston_region {
+       struct wl_resource *resource;
+       pixman_region32_t region;
+};
+
+/* Using weston_view transformations
+ *
+ * To add a transformation to a view, create a struct weston_transform, and
+ * add it to the list view->geometry.transformation_list. Whenever you
+ * change the list, anything under view->geometry, or anything in the
+ * weston_transforms linked into the list, you must call
+ * weston_view_geometry_dirty().
+ *
+ * The order in the list defines the order of transformations. Let the list
+ * contain the transformation matrices M1, ..., Mn as head to tail. The
+ * transformation is applied to view-local coordinate vector p as
+ *    P = Mn * ... * M2 * M1 * p
+ * to produce the global coordinate vector P. The total transform
+ *    Mn * ... * M2 * M1
+ * is cached in view->transform.matrix, and the inverse of it in
+ * view->transform.inverse.
+ *
+ * The list always contains view->transform.position transformation, which
+ * is the translation by view->geometry.x and y.
+ *
+ * If you want to apply a transformation in local coordinates, add your
+ * weston_transform to the head of the list. If you want to apply a
+ * transformation in global coordinates, add it to the tail of the list.
+ *
+ * If view->geometry.parent is set, the total transformation of this
+ * view will be the parent's total transformation and this transformation
+ * combined:
+ *    Mparent * Mn * ... * M2 * M1
+ */
+
+struct weston_view {
+       struct weston_surface *surface;
+       struct wl_list surface_link;
+       struct wl_signal destroy_signal;
+
+       struct wl_list link;             /* weston_compositor::view_list */
+       struct weston_layer_entry layer_link; /* part of geometry */
+       struct weston_plane *plane;
+
+       /* For weston_layer inheritance from another view */
+       struct weston_view *parent_view;
+
+       pixman_region32_t clip;          /* See weston_view_damage_below() */
+       float alpha;                     /* part of geometry, see below */
+
+       void *renderer_state;
+
+       /* Surface geometry state, mutable.
+        * If you change anything, call weston_surface_geometry_dirty().
+        * That includes the transformations referenced from the list.
+        */
+       struct {
+               float x, y; /* surface translation on display */
+
+               /* struct weston_transform */
+               struct wl_list transformation_list;
+
+               /* managed by weston_surface_set_transform_parent() */
+               struct weston_view *parent;
+               struct wl_listener parent_destroy_listener;
+               struct wl_list child_list; /* geometry.parent_link */
+               struct wl_list parent_link;
+
+               /* managed by weston_view_set_mask() */
+               bool scissor_enabled;
+               pixman_region32_t scissor; /* always a simple rect */
+       } geometry;
+
+       /* State derived from geometry state, read-only.
+        * This is updated by weston_view_update_transform().
+        */
+       struct {
+               int dirty;
+
+               /* Approximations in global coordinates:
+                * - boundingbox is guaranteed to include the whole view in
+                *   the smallest possible single rectangle.
+                * - opaque is guaranteed to be fully opaque, though not
+                *   necessarily include all opaque areas.
+                */
+               pixman_region32_t boundingbox;
+               pixman_region32_t opaque;
+
+               /* matrix and inverse are used only if enabled = 1.
+                * If enabled = 0, use x, y, width, height directly.
+                */
+               int enabled;
+               struct weston_matrix matrix;
+               struct weston_matrix inverse;
+
+               struct weston_transform position; /* matrix from x, y */
+       } transform;
+
+       /*
+        * The primary output for this view.
+        * Used for picking the output for driving internal animations on the
+        * view, inheriting the primary output for related views in shells, etc.
+        */
+       struct weston_output *output;
+
+       /*
+        * A more complete representation of all outputs this surface is
+        * displayed on.
+        */
+       uint32_t output_mask;
+
+       /* Per-surface Presentation feedback flags, controlled by backend. */
+       uint32_t psf_flags;
+};
+
+struct weston_surface_state {
+       /* wl_surface.attach */
+       int newly_attached;
+       struct weston_buffer *buffer;
+       struct wl_listener buffer_destroy_listener;
+       int32_t sx;
+       int32_t sy;
+
+       /* wl_surface.damage */
+       pixman_region32_t damage_surface;
+       /* wl_surface.damage_buffer */
+       pixman_region32_t damage_buffer;
+
+       /* wl_surface.set_opaque_region */
+       pixman_region32_t opaque;
+
+       /* wl_surface.set_input_region */
+       pixman_region32_t input;
+
+       /* wl_surface.frame */
+       struct wl_list frame_callback_list;
+
+       /* presentation.feedback */
+       struct wl_list feedback_list;
+
+       /* wl_surface.set_buffer_transform */
+       /* wl_surface.set_scaling_factor */
+       /* wp_viewport.set_source */
+       /* wp_viewport.set_destination */
+       struct weston_buffer_viewport buffer_viewport;
+};
+
+struct weston_surface {
+       struct wl_resource *resource;
+       struct wl_signal destroy_signal; /* callback argument: this surface */
+       struct weston_compositor *compositor;
+
+       /** Damage in local coordinates from the client, for tex upload. */
+       pixman_region32_t damage;
+
+       pixman_region32_t opaque;        /* part of geometry, see below */
+       pixman_region32_t input;
+       int32_t width, height;
+       int32_t ref_count;
+
+       /* Not for long-term storage.  This exists for book-keeping while
+        * iterating over surfaces and views
+        */
+       bool touched;
+
+       void *renderer_state;
+
+       struct wl_list views;
+
+       /*
+        * Which output to vsync this surface to.
+        * Used to determine whether to send or queue frame events, and for
+        * other client-visible syncing/throttling tied to the output
+        * repaint cycle.
+        */
+       struct weston_output *output;
+
+       /*
+        * A more complete representation of all outputs this surface is
+        * displayed on.
+        */
+       uint32_t output_mask;
+
+       struct wl_list frame_callback_list;
+       struct wl_list feedback_list;
+
+       struct weston_buffer_reference buffer_ref;
+       struct weston_buffer_viewport buffer_viewport;
+       int32_t width_from_buffer; /* before applying viewport */
+       int32_t height_from_buffer;
+       bool keep_buffer; /* for backends to prevent early release */
+
+       /* wp_viewport resource for this surface */
+       struct wl_resource *viewport_resource;
+
+       /* All the pending state, that wl_surface.commit will apply. */
+       struct weston_surface_state pending;
+
+       /* Matrices representating of the full transformation between
+        * buffer and surface coordinates.  These matrices are updated
+        * using the weston_surface_build_buffer_matrix function. */
+       struct weston_matrix buffer_to_surface_matrix;
+       struct weston_matrix surface_to_buffer_matrix;
+
+       /*
+        * If non-NULL, this function will be called on
+        * wl_surface::commit after a new buffer has been set up for
+        * this surface. The integer params are the sx and sy
+        * parameters supplied to wl_surface::attach.
+        */
+       void (*configure)(struct weston_surface *es, int32_t sx, int32_t sy);
+       void *configure_private;
+       int (*get_label)(struct weston_surface *surface, char *buf, size_t len);
+
+       /* Parent's list of its sub-surfaces, weston_subsurface:parent_link.
+        * Contains also the parent itself as a dummy weston_subsurface,
+        * if the list is not empty.
+        */
+       struct wl_list subsurface_list; /* weston_subsurface::parent_link */
+       struct wl_list subsurface_list_pending; /* ...::parent_link_pending */
+
+       /*
+        * For tracking protocol role assignments. Different roles may
+        * have the same configure hook, e.g. in shell.c. Configure hook
+        * may get reset, this will not.
+        * XXX: map configure functions 1:1 to roles, and never reset it,
+        * and replace role_name with configure.
+        */
+       const char *role_name;
+
+       struct weston_timeline_object timeline;
+};
+
+struct weston_subsurface {
+       struct wl_resource *resource;
+
+       /* guaranteed to be valid and non-NULL */
+       struct weston_surface *surface;
+       struct wl_listener surface_destroy_listener;
+
+       /* can be NULL */
+       struct weston_surface *parent;
+       struct wl_listener parent_destroy_listener;
+       struct wl_list parent_link;
+       struct wl_list parent_link_pending;
+
+       struct {
+               int32_t x;
+               int32_t y;
+               int set;
+       } position;
+
+       int has_cached_data;
+       struct weston_surface_state cached;
+       struct weston_buffer_reference cached_buffer_ref;
+
+       int synchronized;
+
+       /* Used for constructing the view tree */
+       struct wl_list unused_views;
+};
+
+enum weston_key_state_update {
+       STATE_UPDATE_AUTOMATIC,
+       STATE_UPDATE_NONE,
+};
+
+void
+weston_version(int *major, int *minor, int *micro);
+
+void
+weston_view_update_transform(struct weston_view *view);
+
+void
+weston_view_geometry_dirty(struct weston_view *view);
+
+void
+weston_view_to_global_fixed(struct weston_view *view,
+                           wl_fixed_t sx, wl_fixed_t sy,
+                           wl_fixed_t *x, wl_fixed_t *y);
+void
+weston_view_to_global_float(struct weston_view *view,
+                           float sx, float sy, float *x, float *y);
+
+void
+weston_view_from_global_float(struct weston_view *view,
+                             float x, float y, float *vx, float *vy);
+void
+weston_view_from_global(struct weston_view *view,
+                       int32_t x, int32_t y, int32_t *vx, int32_t *vy);
+void
+weston_view_from_global_fixed(struct weston_view *view,
+                             wl_fixed_t x, wl_fixed_t y,
+                             wl_fixed_t *vx, wl_fixed_t *vy);
+
+void
+weston_surface_to_buffer_float(struct weston_surface *surface,
+                              float x, float y, float *bx, float *by);
+pixman_box32_t
+weston_surface_to_buffer_rect(struct weston_surface *surface,
+                             pixman_box32_t rect);
+
+void
+weston_surface_to_buffer_region(struct weston_surface *surface,
+                               pixman_region32_t *surface_region,
+                               pixman_region32_t *buffer_region);
+
+void
+weston_spring_init(struct weston_spring *spring,
+                  double k, double current, double target);
+void
+weston_spring_update(struct weston_spring *spring, uint32_t msec);
+int
+weston_spring_done(struct weston_spring *spring);
+
+void
+weston_surface_activate(struct weston_surface *surface,
+                       struct weston_seat *seat);
+void
+notify_motion(struct weston_seat *seat, uint32_t time,
+             struct weston_pointer_motion_event *event);
+void
+notify_motion_absolute(struct weston_seat *seat, uint32_t time,
+                      double x, double y);
+void
+notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
+             enum wl_pointer_button_state state);
+void
+notify_axis(struct weston_seat *seat, uint32_t time,
+           struct weston_pointer_axis_event *event);
+void
+notify_axis_source(struct weston_seat *seat, uint32_t source);
+
+void
+notify_pointer_frame(struct weston_seat *seat);
+
+void
+notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
+          enum wl_keyboard_key_state state,
+          enum weston_key_state_update update_state);
+void
+notify_modifiers(struct weston_seat *seat, uint32_t serial);
+
+void
+notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
+                    double x, double y);
+
+void
+notify_keyboard_focus_in(struct weston_seat *seat, struct wl_array *keys,
+                        enum weston_key_state_update update_state);
+void
+notify_keyboard_focus_out(struct weston_seat *seat);
+
+void
+notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
+            double x, double y, int touch_type);
+void
+notify_touch_frame(struct weston_seat *seat);
+
+void
+notify_touch_cancel(struct weston_seat *seat);
+
+void
+weston_layer_entry_insert(struct weston_layer_entry *list,
+                         struct weston_layer_entry *entry);
+void
+weston_layer_entry_remove(struct weston_layer_entry *entry);
+void
+weston_layer_init(struct weston_layer *layer, struct wl_list *below);
+
+void
+weston_layer_set_mask(struct weston_layer *layer, int x, int y, int width, int height);
+
+void
+weston_layer_set_mask_infinite(struct weston_layer *layer);
+
+void
+weston_plane_init(struct weston_plane *plane,
+                       struct weston_compositor *ec,
+                       int32_t x, int32_t y);
+void
+weston_plane_release(struct weston_plane *plane);
+
+void
+weston_compositor_stack_plane(struct weston_compositor *ec,
+                             struct weston_plane *plane,
+                             struct weston_plane *above);
+
+/* An invalid flag in presented_flags to catch logic errors. */
+#define WP_PRESENTATION_FEEDBACK_INVALID (1U << 31)
+
+void
+weston_output_finish_frame(struct weston_output *output,
+                          const struct timespec *stamp,
+                          uint32_t presented_flags);
+void
+weston_output_schedule_repaint(struct weston_output *output);
+void
+weston_output_damage(struct weston_output *output);
+void
+weston_compositor_schedule_repaint(struct weston_compositor *compositor);
+void
+weston_compositor_fade(struct weston_compositor *compositor, float tint);
+void
+weston_compositor_damage_all(struct weston_compositor *compositor);
+void
+weston_compositor_unlock(struct weston_compositor *compositor);
+void
+weston_compositor_wake(struct weston_compositor *compositor);
+void
+weston_compositor_offscreen(struct weston_compositor *compositor);
+void
+weston_compositor_sleep(struct weston_compositor *compositor);
+struct weston_view *
+weston_compositor_pick_view(struct weston_compositor *compositor,
+                           wl_fixed_t x, wl_fixed_t y,
+                           wl_fixed_t *sx, wl_fixed_t *sy);
+
+
+struct weston_binding;
+typedef void (*weston_key_binding_handler_t)(struct weston_keyboard *keyboard,
+                                            uint32_t time, uint32_t key,
+                                            void *data);
+struct weston_binding *
+weston_compositor_add_key_binding(struct weston_compositor *compositor,
+                                 uint32_t key,
+                                 enum weston_keyboard_modifier modifier,
+                                 weston_key_binding_handler_t binding,
+                                 void *data);
+
+typedef void (*weston_modifier_binding_handler_t)(struct weston_keyboard *keyboard,
+                                                 enum weston_keyboard_modifier modifier,
+                                                 void *data);
+struct weston_binding *
+weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
+                                      enum weston_keyboard_modifier modifier,
+                                      weston_modifier_binding_handler_t binding,
+                                      void *data);
+
+typedef void (*weston_button_binding_handler_t)(struct weston_pointer *pointer,
+                                               uint32_t time, uint32_t button,
+                                               void *data);
+struct weston_binding *
+weston_compositor_add_button_binding(struct weston_compositor *compositor,
+                                    uint32_t button,
+                                    enum weston_keyboard_modifier modifier,
+                                    weston_button_binding_handler_t binding,
+                                    void *data);
+
+typedef void (*weston_touch_binding_handler_t)(struct weston_touch *touch,
+                                              uint32_t time,
+                                              void *data);
+struct weston_binding *
+weston_compositor_add_touch_binding(struct weston_compositor *compositor,
+                                   enum weston_keyboard_modifier modifier,
+                                   weston_touch_binding_handler_t binding,
+                                   void *data);
+
+typedef void (*weston_axis_binding_handler_t)(struct weston_pointer *pointer,
+                                             uint32_t time,
+                                             struct weston_pointer_axis_event *event,
+                                             void *data);
+struct weston_binding *
+weston_compositor_add_axis_binding(struct weston_compositor *compositor,
+                                  uint32_t axis,
+                                  enum weston_keyboard_modifier modifier,
+                                  weston_axis_binding_handler_t binding,
+                                  void *data);
+struct weston_binding *
+weston_compositor_add_debug_binding(struct weston_compositor *compositor,
+                                   uint32_t key,
+                                   weston_key_binding_handler_t binding,
+                                   void *data);
+void
+weston_binding_destroy(struct weston_binding *binding);
+
+void
+weston_install_debug_key_binding(struct weston_compositor *compositor,
+                                uint32_t mod);
+
+void
+weston_binding_list_destroy_all(struct wl_list *list);
+
+void
+weston_compositor_run_key_binding(struct weston_compositor *compositor,
+                                 struct weston_keyboard *keyboard,
+                                 uint32_t time,
+                                 uint32_t key,
+                                 enum wl_keyboard_key_state state);
+
+void
+weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
+                                      struct weston_keyboard *keyboard,
+                                      enum weston_keyboard_modifier modifier,
+                                      enum wl_keyboard_key_state state);
+void
+weston_compositor_run_button_binding(struct weston_compositor *compositor,
+                                    struct weston_pointer *pointer, uint32_t time,
+                                    uint32_t button,
+                                    enum wl_pointer_button_state value);
+void
+weston_compositor_run_touch_binding(struct weston_compositor *compositor,
+                                   struct weston_touch *touch, uint32_t time,
+                                   int touch_type);
+int
+weston_compositor_run_axis_binding(struct weston_compositor *compositor,
+                                  struct weston_pointer *pointer, uint32_t time,
+                                  struct weston_pointer_axis_event *event);
+int
+weston_compositor_run_debug_binding(struct weston_compositor *compositor,
+                                   struct weston_keyboard *keyboard, uint32_t time,
+                                   uint32_t key,
+                                   enum wl_keyboard_key_state state);
+
+void
+weston_compositor_set_default_pointer_grab(struct weston_compositor *compositor,
+                       const struct weston_pointer_grab_interface *interface);
+
+int
+weston_environment_get_fd(const char *env);
+
+struct wl_list *
+weston_compositor_top(struct weston_compositor *compositor);
+
+struct weston_surface *
+weston_surface_create(struct weston_compositor *compositor);
+
+struct weston_view *
+weston_view_create(struct weston_surface *surface);
+
+void
+weston_view_destroy(struct weston_view *view);
+
+void
+weston_view_set_position(struct weston_view *view,
+                        float x, float y);
+
+void
+weston_view_set_transform_parent(struct weston_view *view,
+                                struct weston_view *parent);
+
+void
+weston_view_set_mask(struct weston_view *view,
+                    int x, int y, int width, int height);
+
+void
+weston_view_set_mask_infinite(struct weston_view *view);
+
+bool
+weston_view_is_mapped(struct weston_view *view);
+
+void
+weston_view_schedule_repaint(struct weston_view *view);
+
+bool
+weston_surface_is_mapped(struct weston_surface *surface);
+
+void
+weston_surface_set_size(struct weston_surface *surface,
+                       int32_t width, int32_t height);
+
+void
+weston_surface_schedule_repaint(struct weston_surface *surface);
+
+void
+weston_surface_damage(struct weston_surface *surface);
+
+void
+weston_view_damage_below(struct weston_view *view);
+
+void
+weston_view_move_to_plane(struct weston_view *view,
+                         struct weston_plane *plane);
+void
+weston_view_unmap(struct weston_view *view);
+
+void
+weston_surface_unmap(struct weston_surface *surface);
+
+struct weston_surface *
+weston_surface_get_main_surface(struct weston_surface *surface);
+
+int
+weston_surface_set_role(struct weston_surface *surface,
+                       const char *role_name,
+                       struct wl_resource *error_resource,
+                       uint32_t error_code);
+
+void
+weston_surface_set_label_func(struct weston_surface *surface,
+                             int (*desc)(struct weston_surface *,
+                                         char *, size_t));
+
+void
+weston_surface_get_content_size(struct weston_surface *surface,
+                               int *width, int *height);
+
+int
+weston_surface_copy_content(struct weston_surface *surface,
+                           void *target, size_t size,
+                           int src_x, int src_y,
+                           int width, int height);
+
+struct weston_buffer *
+weston_buffer_from_resource(struct wl_resource *resource);
+
+void
+weston_buffer_reference(struct weston_buffer_reference *ref,
+                       struct weston_buffer *buffer);
+
+uint32_t
+weston_compositor_get_time(void);
+
+void
+weston_compositor_destroy(struct weston_compositor *ec);
+struct weston_compositor *
+weston_compositor_create(struct wl_display *display, void *user_data);
+
+enum weston_compositor_backend {
+       WESTON_BACKEND_DRM,
+       WESTON_BACKEND_FBDEV,
+       WESTON_BACKEND_HEADLESS,
+       WESTON_BACKEND_RDP,
+       WESTON_BACKEND_WAYLAND,
+       WESTON_BACKEND_X11,
+};
+
+int
+weston_compositor_load_backend(struct weston_compositor *compositor,
+                              enum weston_compositor_backend backend,
+                              struct weston_backend_config *config_base);
+void
+weston_compositor_exit(struct weston_compositor *ec);
+void *
+weston_compositor_get_user_data(struct weston_compositor *compositor);
+int
+weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
+                                        clockid_t clk_id);
+int
+weston_compositor_set_presentation_clock_software(
+                                       struct weston_compositor *compositor);
+void
+weston_compositor_read_presentation_clock(
+                       const struct weston_compositor *compositor,
+                       struct timespec *ts);
+
+bool
+weston_compositor_import_dmabuf(struct weston_compositor *compositor,
+                               struct linux_dmabuf_buffer *buffer);
+
+void
+weston_compositor_shutdown(struct weston_compositor *ec);
+void
+weston_compositor_exit_with_code(struct weston_compositor *compositor,
+                                int exit_code);
+void
+weston_output_init_zoom(struct weston_output *output);
+void
+weston_output_update_zoom(struct weston_output *output);
+void
+weston_output_activate_zoom(struct weston_output *output,
+                           struct weston_seat *seat);
+void
+weston_output_update_matrix(struct weston_output *output);
+void
+weston_output_move(struct weston_output *output, int x, int y);
+void
+weston_output_init(struct weston_output *output, struct weston_compositor *c,
+                  int x, int y, int width, int height, uint32_t transform, int32_t scale);
+void
+weston_compositor_add_output(struct weston_compositor *compositor,
+                             struct weston_output *output);
+void
+weston_output_destroy(struct weston_output *output);
+void
+weston_output_transform_coordinate(struct weston_output *output,
+                                  double device_x, double device_y,
+                                  double *x, double *y);
+
+void
+weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
+                const char *seat_name);
+void
+weston_seat_init_pointer(struct weston_seat *seat);
+void
+weston_seat_release_pointer(struct weston_seat *seat);
+int
+weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap);
+void
+weston_seat_release_keyboard(struct weston_seat *seat);
+void
+weston_seat_init_touch(struct weston_seat *seat);
+void
+weston_seat_release_touch(struct weston_seat *seat);
+void
+weston_seat_repick(struct weston_seat *seat);
+void
+weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap);
+
+void
+weston_seat_release(struct weston_seat *seat);
+int
+weston_compositor_set_xkb_rule_names(struct weston_compositor *ec,
+                                    struct xkb_rule_names *names);
+void
+weston_compositor_xkb_destroy(struct weston_compositor *ec);
+
+/* String literal of spaces, the same width as the timestamp. */
+#define STAMP_SPACE "               "
+
+typedef int (*log_func_t)(const char *fmt, va_list ap);
+void
+weston_log_set_handler(log_func_t log, log_func_t cont);
+int
+weston_vlog(const char *fmt, va_list ap);
+int
+weston_vlog_continue(const char *fmt, va_list ap);
+int
+weston_log(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+int
+weston_log_continue(const char *fmt, ...)
+       __attribute__ ((format (printf, 1, 2)));
+
+enum {
+       TTY_ENTER_VT,
+       TTY_LEAVE_VT
+};
+
+struct tty *
+tty_create(struct weston_compositor *compositor, int tty_nr);
+
+void
+tty_destroy(struct tty *tty);
+
+void
+tty_reset(struct tty *tty);
+
+int
+tty_activate_vt(struct tty *tty, int vt);
+
+enum weston_screenshooter_outcome {
+       WESTON_SCREENSHOOTER_SUCCESS,
+       WESTON_SCREENSHOOTER_NO_MEMORY,
+       WESTON_SCREENSHOOTER_BAD_BUFFER
+};
+
+typedef void (*weston_screenshooter_done_func_t)(void *data,
+                               enum weston_screenshooter_outcome outcome);
+int
+weston_screenshooter_shoot(struct weston_output *output, struct weston_buffer *buffer,
+                          weston_screenshooter_done_func_t done, void *data);
+struct weston_recorder *
+weston_recorder_start(struct weston_output *output, const char *filename);
+void
+weston_recorder_stop(struct weston_recorder *recorder);
+
+struct clipboard *
+clipboard_create(struct weston_seat *seat);
+
+struct text_backend;
+
+struct text_backend *
+text_backend_init(struct weston_compositor *ec);
+
+void
+text_backend_destroy(struct text_backend *text_backend);
+
+struct weston_view_animation;
+typedef        void (*weston_view_animation_done_func_t)(struct weston_view_animation *animation, void *data);
+
+void
+weston_view_animation_destroy(struct weston_view_animation *animation);
+
+struct weston_view_animation *
+weston_zoom_run(struct weston_view *view, float start, float stop,
+               weston_view_animation_done_func_t done, void *data);
+
+struct weston_view_animation *
+weston_fade_run(struct weston_view *view,
+               float start, float end, float k,
+               weston_view_animation_done_func_t done, void *data);
+
+struct weston_view_animation *
+weston_move_scale_run(struct weston_view *view, int dx, int dy,
+                     float start, float end, int reverse,
+                     weston_view_animation_done_func_t done, void *data);
+
+void
+weston_fade_update(struct weston_view_animation *fade, float target);
+
+struct weston_view_animation *
+weston_stable_fade_run(struct weston_view *front_view, float start,
+                      struct weston_view *back_view, float end,
+                      weston_view_animation_done_func_t done, void *data);
+
+struct weston_view_animation *
+weston_slide_run(struct weston_view *view, float start, float stop,
+                weston_view_animation_done_func_t done, void *data);
+
+void
+weston_surface_set_color(struct weston_surface *surface,
+                        float red, float green, float blue, float alpha);
+
+void
+weston_surface_destroy(struct weston_surface *surface);
+
+int
+weston_output_mode_set_native(struct weston_output *output,
+                             struct weston_mode *mode,
+                             int32_t scale);
+int
+weston_output_mode_switch_to_temporary(struct weston_output *output,
+                                      struct weston_mode *mode,
+                                      int32_t scale);
+int
+weston_output_mode_switch_to_native(struct weston_output *output);
+
+int
+noop_renderer_init(struct weston_compositor *ec);
+
+int
+backend_init(struct weston_compositor *c,
+            struct weston_backend_config *config_base);
+int
+module_init(struct weston_compositor *compositor,
+           int *argc, char *argv[]);
+
+void
+weston_transformed_coord(int width, int height,
+                        enum wl_output_transform transform,
+                        int32_t scale,
+                        float sx, float sy, float *bx, float *by);
+pixman_box32_t
+weston_transformed_rect(int width, int height,
+                       enum wl_output_transform transform,
+                       int32_t scale,
+                       pixman_box32_t rect);
+void
+weston_matrix_transform_region(pixman_region32_t *dest,
+                               struct weston_matrix *matrix,
+                               pixman_region32_t *src);
+void
+weston_transformed_region(int width, int height,
+                         enum wl_output_transform transform,
+                         int32_t scale,
+                         pixman_region32_t *src, pixman_region32_t *dest);
+
+void *
+weston_load_module(const char *name, const char *entrypoint);
+
+int
+weston_parse_transform(const char *transform, uint32_t *out);
+
+const char *
+weston_transform_to_string(uint32_t output_transform);
+
+struct weston_keyboard *
+weston_seat_get_keyboard(struct weston_seat *seat);
+
+struct weston_pointer *
+weston_seat_get_pointer(struct weston_seat *seat);
+
+struct weston_touch *
+weston_seat_get_touch(struct weston_seat *seat);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/libweston/data-device.c b/libweston/data-device.c
new file mode 100644 (file)
index 0000000..f04f030
--- /dev/null
@@ -0,0 +1,1340 @@
+/*
+ * Copyright © 2011 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <assert.h>
+
+#include "compositor.h"
+#include "shared/helpers.h"
+
+struct weston_drag {
+       struct wl_client *client;
+       struct weston_data_source *data_source;
+       struct wl_listener data_source_listener;
+       struct weston_view *focus;
+       struct wl_resource *focus_resource;
+       struct wl_listener focus_listener;
+       struct weston_view *icon;
+       struct wl_listener icon_destroy_listener;
+       int32_t dx, dy;
+       struct weston_keyboard_grab keyboard_grab;
+};
+
+struct weston_pointer_drag {
+       struct weston_drag  base;
+       struct weston_pointer_grab grab;
+};
+
+struct weston_touch_drag {
+       struct weston_drag base;
+       struct weston_touch_grab grab;
+};
+
+#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
+                    WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
+                    WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
+
+static void
+data_offer_accept(struct wl_client *client, struct wl_resource *resource,
+                 uint32_t serial, const char *mime_type)
+{
+       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
+
+       /* Protect against untimely calls from older data offers */
+       if (!offer->source || offer != offer->source->offer)
+               return;
+
+       /* FIXME: Check that client is currently focused by the input
+        * device that is currently dragging this data source.  Should
+        * this be a wl_data_device request? */
+
+       offer->source->accept(offer->source, serial, mime_type);
+       offer->source->accepted = mime_type != NULL;
+}
+
+static void
+data_offer_receive(struct wl_client *client, struct wl_resource *resource,
+                  const char *mime_type, int32_t fd)
+{
+       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
+
+       if (offer->source && offer == offer->source->offer)
+               offer->source->send(offer->source, mime_type, fd);
+       else
+               close(fd);
+}
+
+static void
+data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+data_source_notify_finish(struct weston_data_source *source)
+{
+       if (!source->actions_set)
+               return;
+
+       if (source->offer->in_ask &&
+           wl_resource_get_version(source->resource) >=
+           WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
+               wl_data_source_send_action(source->resource,
+                                          source->current_dnd_action);
+       }
+
+       if (wl_resource_get_version(source->resource) >=
+           WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
+               wl_data_source_send_dnd_finished(source->resource);
+       }
+
+       source->offer = NULL;
+}
+
+static uint32_t
+data_offer_choose_action(struct weston_data_offer *offer)
+{
+       uint32_t available_actions, preferred_action = 0;
+       uint32_t source_actions, offer_actions;
+
+       if (wl_resource_get_version(offer->resource) >=
+           WL_DATA_OFFER_ACTION_SINCE_VERSION) {
+               offer_actions = offer->dnd_actions;
+               preferred_action = offer->preferred_dnd_action;
+       } else {
+               offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+       }
+
+       if (wl_resource_get_version(offer->source->resource) >=
+           WL_DATA_SOURCE_ACTION_SINCE_VERSION)
+               source_actions = offer->source->dnd_actions;
+       else
+               source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+
+       available_actions = offer_actions & source_actions;
+
+       if (!available_actions)
+               return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
+       if (offer->source->seat &&
+           offer->source->compositor_action & available_actions)
+               return offer->source->compositor_action;
+
+       /* If the dest side has a preferred DnD action, use it */
+       if ((preferred_action & available_actions) != 0)
+               return preferred_action;
+
+       /* Use the first found action, in bit order */
+       return 1 << (ffs(available_actions) - 1);
+}
+
+static void
+data_offer_update_action(struct weston_data_offer *offer)
+{
+       uint32_t action;
+
+       if (!offer->source)
+               return;
+
+       action = data_offer_choose_action(offer);
+
+       if (offer->source->current_dnd_action == action)
+               return;
+
+       offer->source->current_dnd_action = action;
+
+       if (offer->in_ask)
+               return;
+
+       if (wl_resource_get_version(offer->source->resource) >=
+           WL_DATA_SOURCE_ACTION_SINCE_VERSION)
+               wl_data_source_send_action(offer->source->resource, action);
+
+       if (wl_resource_get_version(offer->resource) >=
+           WL_DATA_OFFER_ACTION_SINCE_VERSION)
+               wl_data_offer_send_action(offer->resource, action);
+}
+
+static void
+data_offer_set_actions(struct wl_client *client,
+                      struct wl_resource *resource,
+                      uint32_t dnd_actions, uint32_t preferred_action)
+{
+       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
+
+       if (dnd_actions & ~ALL_ACTIONS) {
+               wl_resource_post_error(offer->resource,
+                                      WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
+                                      "invalid action mask %x", dnd_actions);
+               return;
+       }
+
+       if (preferred_action &&
+           (!(preferred_action & dnd_actions) ||
+            __builtin_popcount(preferred_action) > 1)) {
+               wl_resource_post_error(offer->resource,
+                                      WL_DATA_OFFER_ERROR_INVALID_ACTION,
+                                      "invalid action %x", preferred_action);
+               return;
+       }
+
+       offer->dnd_actions = dnd_actions;
+       offer->preferred_dnd_action = preferred_action;
+       data_offer_update_action(offer);
+}
+
+static void
+data_offer_finish(struct wl_client *client, struct wl_resource *resource)
+{
+       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
+
+       if (!offer->source || offer->source->offer != offer)
+               return;
+
+       /* Disallow finish while we have a grab driving drag-and-drop, or
+        * if the negotiation is not at the right stage
+        */
+       if (offer->source->seat ||
+           !offer->source->accepted) {
+               wl_resource_post_error(offer->resource,
+                                      WL_DATA_OFFER_ERROR_INVALID_FINISH,
+                                      "premature finish request");
+               return;
+       }
+
+       switch (offer->source->current_dnd_action) {
+       case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
+       case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
+               wl_resource_post_error(offer->resource,
+                                      WL_DATA_OFFER_ERROR_INVALID_OFFER,
+                                      "offer finished with an invalid action");
+               return;
+       default:
+               break;
+       }
+
+       data_source_notify_finish(offer->source);
+}
+
+static const struct wl_data_offer_interface data_offer_interface = {
+       data_offer_accept,
+       data_offer_receive,
+       data_offer_destroy,
+       data_offer_finish,
+       data_offer_set_actions,
+};
+
+static void
+destroy_data_offer(struct wl_resource *resource)
+{
+       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
+
+       if (!offer->source)
+               goto out;
+
+       wl_list_remove(&offer->source_destroy_listener.link);
+
+       if (offer->source->offer != offer)
+               goto out;
+
+       /* If the drag destination has version < 3, wl_data_offer.finish
+        * won't be called, so do this here as a safety net, because
+        * we still want the version >=3 drag source to be happy.
+        */
+       if (wl_resource_get_version(offer->resource) <
+           WL_DATA_OFFER_ACTION_SINCE_VERSION) {
+               data_source_notify_finish(offer->source);
+       } else if (offer->source->resource &&
+                  wl_resource_get_version(offer->source->resource) >=
+                  WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
+               wl_data_source_send_cancelled(offer->source->resource);
+       }
+
+       offer->source->offer = NULL;
+out:
+       free(offer);
+}
+
+static void
+destroy_offer_data_source(struct wl_listener *listener, void *data)
+{
+       struct weston_data_offer *offer;
+
+       offer = container_of(listener, struct weston_data_offer,
+                            source_destroy_listener);
+
+       offer->source = NULL;
+}
+
+static struct weston_data_offer *
+weston_data_source_send_offer(struct weston_data_source *source,
+                             struct wl_resource *target)
+{
+       struct weston_data_offer *offer;
+       char **p;
+
+       offer = malloc(sizeof *offer);
+       if (offer == NULL)
+               return NULL;
+
+       offer->resource =
+               wl_resource_create(wl_resource_get_client(target),
+                                  &wl_data_offer_interface,
+                                  wl_resource_get_version(target), 0);
+       if (offer->resource == NULL) {
+               free(offer);
+               return NULL;
+       }
+
+       wl_resource_set_implementation(offer->resource, &data_offer_interface,
+                                      offer, destroy_data_offer);
+
+       offer->in_ask = false;
+       offer->dnd_actions = 0;
+       offer->preferred_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+       offer->source = source;
+       offer->source_destroy_listener.notify = destroy_offer_data_source;
+       wl_signal_add(&source->destroy_signal,
+                     &offer->source_destroy_listener);
+
+       wl_data_device_send_data_offer(target, offer->resource);
+
+       wl_array_for_each(p, &source->mime_types)
+               wl_data_offer_send_offer(offer->resource, *p);
+
+       source->offer = offer;
+       source->accepted = false;
+
+       return offer;
+}
+
+static void
+data_source_offer(struct wl_client *client,
+                 struct wl_resource *resource,
+                 const char *type)
+{
+       struct weston_data_source *source =
+               wl_resource_get_user_data(resource);
+       char **p;
+
+       p = wl_array_add(&source->mime_types, sizeof *p);
+       if (p)
+               *p = strdup(type);
+       if (!p || !*p)
+               wl_resource_post_no_memory(resource);
+}
+
+static void
+data_source_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+data_source_set_actions(struct wl_client *client,
+                       struct wl_resource *resource,
+                       uint32_t dnd_actions)
+{
+       struct weston_data_source *source =
+               wl_resource_get_user_data(resource);
+
+       if (source->actions_set) {
+               wl_resource_post_error(source->resource,
+                                      WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+                                      "cannot set actions more than once");
+               return;
+       }
+
+       if (dnd_actions & ~ALL_ACTIONS) {
+               wl_resource_post_error(source->resource,
+                                      WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+                                      "invalid action mask %x", dnd_actions);
+               return;
+       }
+
+       if (source->seat) {
+               wl_resource_post_error(source->resource,
+                                      WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
+                                      "invalid action change after "
+                                      "wl_data_device.start_drag");
+               return;
+       }
+
+       source->dnd_actions = dnd_actions;
+       source->actions_set = true;
+}
+
+static struct wl_data_source_interface data_source_interface = {
+       data_source_offer,
+       data_source_destroy,
+       data_source_set_actions
+};
+
+static void
+drag_surface_configure(struct weston_drag *drag,
+                      struct weston_pointer *pointer,
+                      struct weston_touch *touch,
+                      struct weston_surface *es,
+                      int32_t sx, int32_t sy)
+{
+       struct weston_layer_entry *list;
+       float fx, fy;
+
+       assert((pointer != NULL && touch == NULL) ||
+                       (pointer == NULL && touch != NULL));
+
+       if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
+               if (pointer && pointer->sprite &&
+                       weston_view_is_mapped(pointer->sprite))
+                       list = &pointer->sprite->layer_link;
+               else
+                       list = &es->compositor->cursor_layer.view_list;
+
+               weston_layer_entry_remove(&drag->icon->layer_link);
+               weston_layer_entry_insert(list, &drag->icon->layer_link);
+               weston_view_update_transform(drag->icon);
+               pixman_region32_clear(&es->pending.input);
+       }
+
+       drag->dx += sx;
+       drag->dy += sy;
+
+       /* init to 0 for avoiding a compile warning */
+       fx = fy = 0;
+       if (pointer) {
+               fx = wl_fixed_to_double(pointer->x) + drag->dx;
+               fy = wl_fixed_to_double(pointer->y) + drag->dy;
+       } else if (touch) {
+               fx = wl_fixed_to_double(touch->grab_x) + drag->dx;
+               fy = wl_fixed_to_double(touch->grab_y) + drag->dy;
+       }
+       weston_view_set_position(drag->icon, fx, fy);
+}
+
+static int
+pointer_drag_surface_get_label(struct weston_surface *surface,
+                              char *buf, size_t len)
+{
+       return snprintf(buf, len, "pointer drag icon");
+}
+
+static void
+pointer_drag_surface_configure(struct weston_surface *es,
+                              int32_t sx, int32_t sy)
+{
+       struct weston_pointer_drag *drag = es->configure_private;
+       struct weston_pointer *pointer = drag->grab.pointer;
+
+       assert(es->configure == pointer_drag_surface_configure);
+
+       drag_surface_configure(&drag->base, pointer, NULL, es, sx, sy);
+}
+
+static int
+touch_drag_surface_get_label(struct weston_surface *surface,
+                            char *buf, size_t len)
+{
+       return snprintf(buf, len, "touch drag icon");
+}
+
+static void
+touch_drag_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
+{
+       struct weston_touch_drag *drag = es->configure_private;
+       struct weston_touch *touch = drag->grab.touch;
+
+       assert(es->configure == touch_drag_surface_configure);
+
+       drag_surface_configure(&drag->base, NULL, touch, es, sx, sy);
+}
+
+static void
+destroy_drag_focus(struct wl_listener *listener, void *data)
+{
+       struct weston_drag *drag =
+               container_of(listener, struct weston_drag, focus_listener);
+
+       drag->focus_resource = NULL;
+}
+
+static void
+weston_drag_set_focus(struct weston_drag *drag,
+                       struct weston_seat *seat,
+                       struct weston_view *view,
+                       wl_fixed_t sx, wl_fixed_t sy)
+{
+       struct wl_resource *resource, *offer_resource = NULL;
+       struct wl_display *display = seat->compositor->wl_display;
+       struct weston_data_offer *offer;
+       uint32_t serial;
+
+       if (drag->focus && view && drag->focus->surface == view->surface) {
+               drag->focus = view;
+               return;
+       }
+
+       if (drag->focus_resource) {
+               wl_data_device_send_leave(drag->focus_resource);
+               wl_list_remove(&drag->focus_listener.link);
+               drag->focus_resource = NULL;
+               drag->focus = NULL;
+       }
+
+       if (!view || !view->surface->resource)
+               return;
+
+       if (!drag->data_source &&
+           wl_resource_get_client(view->surface->resource) != drag->client)
+               return;
+
+       if (drag->data_source &&
+           drag->data_source->offer) {
+               /* Unlink the offer from the source */
+               offer = drag->data_source->offer;
+               offer->source = NULL;
+               drag->data_source->offer = NULL;
+               wl_list_remove(&offer->source_destroy_listener.link);
+       }
+
+       resource = wl_resource_find_for_client(&seat->drag_resource_list,
+                                              wl_resource_get_client(view->surface->resource));
+       if (!resource)
+               return;
+
+       serial = wl_display_next_serial(display);
+
+       if (drag->data_source) {
+               drag->data_source->accepted = false;
+               offer = weston_data_source_send_offer(drag->data_source, resource);
+               if (offer == NULL)
+                       return;
+
+               data_offer_update_action(offer);
+
+               offer_resource = offer->resource;
+               if (wl_resource_get_version (offer_resource) >=
+                   WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
+                       wl_data_offer_send_source_actions (offer_resource,
+                                                          drag->data_source->dnd_actions);
+               }
+       }
+
+       wl_data_device_send_enter(resource, serial, view->surface->resource,
+                                 sx, sy, offer_resource);
+
+       drag->focus = view;
+       drag->focus_listener.notify = destroy_drag_focus;
+       wl_resource_add_destroy_listener(resource, &drag->focus_listener);
+       drag->focus_resource = resource;
+}
+
+static void
+drag_grab_focus(struct weston_pointer_grab *grab)
+{
+       struct weston_pointer_drag *drag =
+               container_of(grab, struct weston_pointer_drag, grab);
+       struct weston_pointer *pointer = grab->pointer;
+       struct weston_view *view;
+       wl_fixed_t sx, sy;
+
+       view = weston_compositor_pick_view(pointer->seat->compositor,
+                                          pointer->x, pointer->y,
+                                          &sx, &sy);
+       if (drag->base.focus != view)
+               weston_drag_set_focus(&drag->base, pointer->seat, view, sx, sy);
+}
+
+static void
+drag_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
+                struct weston_pointer_motion_event *event)
+{
+       struct weston_pointer_drag *drag =
+               container_of(grab, struct weston_pointer_drag, grab);
+       struct weston_pointer *pointer = drag->grab.pointer;
+       float fx, fy;
+       wl_fixed_t sx, sy;
+
+       weston_pointer_move(pointer, event);
+
+       if (drag->base.icon) {
+               fx = wl_fixed_to_double(pointer->x) + drag->base.dx;
+               fy = wl_fixed_to_double(pointer->y) + drag->base.dy;
+               weston_view_set_position(drag->base.icon, fx, fy);
+               weston_view_schedule_repaint(drag->base.icon);
+       }
+
+       if (drag->base.focus_resource) {
+               weston_view_from_global_fixed(drag->base.focus,
+                                             pointer->x, pointer->y,
+                                             &sx, &sy);
+
+               wl_data_device_send_motion(drag->base.focus_resource, time, sx, sy);
+       }
+}
+
+static void
+data_device_end_drag_grab(struct weston_drag *drag,
+               struct weston_seat *seat)
+{
+       if (drag->icon) {
+               if (weston_view_is_mapped(drag->icon))
+                       weston_view_unmap(drag->icon);
+
+               drag->icon->surface->configure = NULL;
+               weston_surface_set_label_func(drag->icon->surface, NULL);
+               pixman_region32_clear(&drag->icon->surface->pending.input);
+               wl_list_remove(&drag->icon_destroy_listener.link);
+               weston_view_destroy(drag->icon);
+       }
+
+       weston_drag_set_focus(drag, seat, NULL, 0, 0);
+}
+
+static void
+data_device_end_pointer_drag_grab(struct weston_pointer_drag *drag)
+{
+       struct weston_pointer *pointer = drag->grab.pointer;
+       struct weston_keyboard *keyboard = drag->base.keyboard_grab.keyboard;
+
+       data_device_end_drag_grab(&drag->base, pointer->seat);
+       weston_pointer_end_grab(pointer);
+       weston_keyboard_end_grab(keyboard);
+       free(drag);
+}
+
+static void
+drag_grab_button(struct weston_pointer_grab *grab,
+                uint32_t time, uint32_t button, uint32_t state_w)
+{
+       struct weston_pointer_drag *drag =
+               container_of(grab, struct weston_pointer_drag, grab);
+       struct weston_pointer *pointer = drag->grab.pointer;
+       enum wl_pointer_button_state state = state_w;
+       struct weston_data_source *data_source = drag->base.data_source;
+
+       if (data_source &&
+           pointer->grab_button == button &&
+           state == WL_POINTER_BUTTON_STATE_RELEASED) {
+               if (drag->base.focus_resource &&
+                   data_source->accepted &&
+                   data_source->current_dnd_action) {
+                       wl_data_device_send_drop(drag->base.focus_resource);
+
+                       if (wl_resource_get_version(data_source->resource) >=
+                           WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
+                               wl_data_source_send_dnd_drop_performed(data_source->resource);
+
+                       data_source->offer->in_ask =
+                               data_source->current_dnd_action ==
+                               WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
+
+                       data_source->seat = NULL;
+               } else if (wl_resource_get_version(data_source->resource) >=
+                          WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
+                       wl_data_source_send_cancelled(data_source->resource);
+               }
+       }
+
+       if (pointer->button_count == 0 &&
+           state == WL_POINTER_BUTTON_STATE_RELEASED) {
+               if (drag->base.data_source)
+                       wl_list_remove(&drag->base.data_source_listener.link);
+               data_device_end_pointer_drag_grab(drag);
+       }
+}
+
+static void
+drag_grab_axis(struct weston_pointer_grab *grab,
+              uint32_t time, struct weston_pointer_axis_event *event)
+{
+}
+
+static void
+drag_grab_axis_source(struct weston_pointer_grab *grab, uint32_t source)
+{
+}
+
+static void
+drag_grab_frame(struct weston_pointer_grab *grab)
+{
+}
+
+static void
+drag_grab_cancel(struct weston_pointer_grab *grab)
+{
+       struct weston_pointer_drag *drag =
+               container_of(grab, struct weston_pointer_drag, grab);
+
+       if (drag->base.data_source)
+               wl_list_remove(&drag->base.data_source_listener.link);
+
+       data_device_end_pointer_drag_grab(drag);
+}
+
+static const struct weston_pointer_grab_interface pointer_drag_grab_interface = {
+       drag_grab_focus,
+       drag_grab_motion,
+       drag_grab_button,
+       drag_grab_axis,
+       drag_grab_axis_source,
+       drag_grab_frame,
+       drag_grab_cancel,
+};
+
+static void
+drag_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
+               int touch_id, wl_fixed_t sx, wl_fixed_t sy)
+{
+}
+
+static void
+data_device_end_touch_drag_grab(struct weston_touch_drag *drag)
+{
+       struct weston_touch *touch = drag->grab.touch;
+       struct weston_keyboard *keyboard = drag->base.keyboard_grab.keyboard;
+
+       data_device_end_drag_grab(&drag->base, touch->seat);
+       weston_touch_end_grab(touch);
+       weston_keyboard_end_grab(keyboard);
+       free(drag);
+}
+
+static void
+drag_grab_touch_up(struct weston_touch_grab *grab,
+               uint32_t time, int touch_id)
+{
+       struct weston_touch_drag *touch_drag =
+               container_of(grab, struct weston_touch_drag, grab);
+       struct weston_touch *touch = grab->touch;
+
+       if (touch_id != touch->grab_touch_id)
+               return;
+
+       if (touch_drag->base.focus_resource)
+               wl_data_device_send_drop(touch_drag->base.focus_resource);
+       if (touch_drag->base.data_source)
+               wl_list_remove(&touch_drag->base.data_source_listener.link);
+       data_device_end_touch_drag_grab(touch_drag);
+}
+
+static void
+drag_grab_touch_focus(struct weston_touch_drag *drag)
+{
+       struct weston_touch *touch = drag->grab.touch;
+       struct weston_view *view;
+       wl_fixed_t view_x, view_y;
+
+       view = weston_compositor_pick_view(touch->seat->compositor,
+                               touch->grab_x, touch->grab_y,
+                               &view_x, &view_y);
+       if (drag->base.focus != view)
+               weston_drag_set_focus(&drag->base, touch->seat,
+                               view, view_x, view_y);
+}
+
+static void
+drag_grab_touch_motion(struct weston_touch_grab *grab, uint32_t time,
+               int touch_id, wl_fixed_t x, wl_fixed_t y)
+{
+       struct weston_touch_drag *touch_drag =
+               container_of(grab, struct weston_touch_drag, grab);
+       struct weston_touch *touch = grab->touch;
+       wl_fixed_t view_x, view_y;
+       float fx, fy;
+
+       if (touch_id != touch->grab_touch_id)
+               return;
+
+       drag_grab_touch_focus(touch_drag);
+       if (touch_drag->base.icon) {
+               fx = wl_fixed_to_double(touch->grab_x) + touch_drag->base.dx;
+               fy = wl_fixed_to_double(touch->grab_y) + touch_drag->base.dy;
+               weston_view_set_position(touch_drag->base.icon, fx, fy);
+               weston_view_schedule_repaint(touch_drag->base.icon);
+       }
+
+       if (touch_drag->base.focus_resource) {
+               weston_view_from_global_fixed(touch_drag->base.focus,
+                                       touch->grab_x, touch->grab_y,
+                                       &view_x, &view_y);
+               wl_data_device_send_motion(touch_drag->base.focus_resource, time,
+                                       view_x, view_y);
+       }
+}
+
+static void
+drag_grab_touch_frame(struct weston_touch_grab *grab)
+{
+}
+
+static void
+drag_grab_touch_cancel(struct weston_touch_grab *grab)
+{
+       struct weston_touch_drag *touch_drag =
+               container_of(grab, struct weston_touch_drag, grab);
+
+       if (touch_drag->base.data_source)
+               wl_list_remove(&touch_drag->base.data_source_listener.link);
+       data_device_end_touch_drag_grab(touch_drag);
+}
+
+static const struct weston_touch_grab_interface touch_drag_grab_interface = {
+       drag_grab_touch_down,
+       drag_grab_touch_up,
+       drag_grab_touch_motion,
+       drag_grab_touch_frame,
+       drag_grab_touch_cancel
+};
+
+static void
+drag_grab_keyboard_key(struct weston_keyboard_grab *grab,
+                      uint32_t time, uint32_t key, uint32_t state)
+{
+}
+
+static void
+drag_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
+                            uint32_t serial, uint32_t mods_depressed,
+                            uint32_t mods_latched,
+                            uint32_t mods_locked, uint32_t group)
+{
+       struct weston_keyboard *keyboard = grab->keyboard;
+       struct weston_drag *drag =
+               container_of(grab, struct weston_drag, keyboard_grab);
+       uint32_t compositor_action;
+
+       if (mods_depressed & (1 << keyboard->xkb_info->shift_mod))
+               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
+       else if (mods_depressed & (1 << keyboard->xkb_info->ctrl_mod))
+               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
+       else
+               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
+       drag->data_source->compositor_action = compositor_action;
+
+       if (drag->data_source->offer)
+               data_offer_update_action(drag->data_source->offer);
+}
+
+static void
+drag_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
+{
+       struct weston_drag *drag =
+               container_of(grab, struct weston_drag, keyboard_grab);
+       struct weston_pointer *pointer = grab->keyboard->seat->pointer_state;
+       struct weston_touch *touch = grab->keyboard->seat->touch_state;
+
+       if (pointer && pointer->grab->interface == &pointer_drag_grab_interface) {
+               struct weston_touch_drag *touch_drag =
+                       (struct weston_touch_drag *) drag;
+               drag_grab_touch_cancel(&touch_drag->grab);
+       } else if (touch && touch->grab->interface == &touch_drag_grab_interface) {
+               struct weston_pointer_drag *pointer_drag =
+                       (struct weston_pointer_drag *) drag;
+               drag_grab_cancel(&pointer_drag->grab);
+       }
+}
+
+static const struct weston_keyboard_grab_interface keyboard_drag_grab_interface = {
+       drag_grab_keyboard_key,
+       drag_grab_keyboard_modifiers,
+       drag_grab_keyboard_cancel
+};
+
+static void
+destroy_pointer_data_device_source(struct wl_listener *listener, void *data)
+{
+       struct weston_pointer_drag *drag = container_of(listener,
+                       struct weston_pointer_drag, base.data_source_listener);
+
+       data_device_end_pointer_drag_grab(drag);
+}
+
+static void
+handle_drag_icon_destroy(struct wl_listener *listener, void *data)
+{
+       struct weston_drag *drag = container_of(listener, struct weston_drag,
+                                               icon_destroy_listener);
+
+       drag->icon = NULL;
+}
+
+WL_EXPORT int
+weston_pointer_start_drag(struct weston_pointer *pointer,
+                      struct weston_data_source *source,
+                      struct weston_surface *icon,
+                      struct wl_client *client)
+{
+       struct weston_pointer_drag *drag;
+       struct weston_keyboard *keyboard =
+               weston_seat_get_keyboard(pointer->seat);
+
+       drag = zalloc(sizeof *drag);
+       if (drag == NULL)
+               return -1;
+
+       drag->grab.interface = &pointer_drag_grab_interface;
+       drag->base.keyboard_grab.interface = &keyboard_drag_grab_interface;
+       drag->base.client = client;
+       drag->base.data_source = source;
+
+       if (icon) {
+               drag->base.icon = weston_view_create(icon);
+               if (drag->base.icon == NULL) {
+                       free(drag);
+                       return -1;
+               }
+
+               drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
+               wl_signal_add(&icon->destroy_signal,
+                             &drag->base.icon_destroy_listener);
+
+               icon->configure = pointer_drag_surface_configure;
+               icon->configure_private = drag;
+               weston_surface_set_label_func(icon,
+                                       pointer_drag_surface_get_label);
+       } else {
+               drag->base.icon = NULL;
+       }
+
+       if (source) {
+               drag->base.data_source_listener.notify = destroy_pointer_data_device_source;
+               wl_signal_add(&source->destroy_signal,
+                             &drag->base.data_source_listener);
+       }
+
+       weston_pointer_clear_focus(pointer);
+       weston_keyboard_set_focus(keyboard, NULL);
+
+       weston_pointer_start_grab(pointer, &drag->grab);
+       weston_keyboard_start_grab(keyboard, &drag->base.keyboard_grab);
+
+       return 0;
+}
+
+static void
+destroy_touch_data_device_source(struct wl_listener *listener, void *data)
+{
+       struct weston_touch_drag *drag = container_of(listener,
+                       struct weston_touch_drag, base.data_source_listener);
+
+       data_device_end_touch_drag_grab(drag);
+}
+
+WL_EXPORT int
+weston_touch_start_drag(struct weston_touch *touch,
+                      struct weston_data_source *source,
+                      struct weston_surface *icon,
+                      struct wl_client *client)
+{
+       struct weston_touch_drag *drag;
+       struct weston_keyboard *keyboard =
+               weston_seat_get_keyboard(touch->seat);
+
+       drag = zalloc(sizeof *drag);
+       if (drag == NULL)
+               return -1;
+
+       drag->grab.interface = &touch_drag_grab_interface;
+       drag->base.client = client;
+       drag->base.data_source = source;
+
+       if (icon) {
+               drag->base.icon = weston_view_create(icon);
+               if (drag->base.icon == NULL) {
+                       free(drag);
+                       return -1;
+               }
+
+               drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
+               wl_signal_add(&icon->destroy_signal,
+                             &drag->base.icon_destroy_listener);
+
+               icon->configure = touch_drag_surface_configure;
+               icon->configure_private = drag;
+               weston_surface_set_label_func(icon,
+                                       touch_drag_surface_get_label);
+       } else {
+               drag->base.icon = NULL;
+       }
+
+       if (source) {
+               drag->base.data_source_listener.notify = destroy_touch_data_device_source;
+               wl_signal_add(&source->destroy_signal,
+                             &drag->base.data_source_listener);
+       }
+
+       weston_keyboard_set_focus(keyboard, NULL);
+
+       weston_touch_start_grab(touch, &drag->grab);
+       weston_keyboard_start_grab(keyboard, &drag->base.keyboard_grab);
+
+       drag_grab_touch_focus(drag);
+
+       return 0;
+}
+
+static void
+data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
+                      struct wl_resource *source_resource,
+                      struct wl_resource *origin_resource,
+                      struct wl_resource *icon_resource, uint32_t serial)
+{
+       struct weston_seat *seat = wl_resource_get_user_data(resource);
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+       struct weston_touch *touch = weston_seat_get_touch(seat);
+       struct weston_surface *origin = wl_resource_get_user_data(origin_resource);
+       struct weston_data_source *source = NULL;
+       struct weston_surface *icon = NULL;
+       int is_pointer_grab, is_touch_grab;
+       int32_t ret = 0;
+
+       is_pointer_grab = pointer &&
+                         pointer->button_count == 1 &&
+                         pointer->grab_serial == serial &&
+                         pointer->focus &&
+                         pointer->focus->surface == origin;
+
+       is_touch_grab = touch &&
+                       touch->num_tp == 1 &&
+                       touch->grab_serial == serial &&
+                       touch->focus &&
+                       touch->focus->surface == origin;
+
+       if (!is_pointer_grab && !is_touch_grab)
+               return;
+
+       /* FIXME: Check that the data source type array isn't empty. */
+
+       if (source_resource)
+               source = wl_resource_get_user_data(source_resource);
+       if (icon_resource)
+               icon = wl_resource_get_user_data(icon_resource);
+
+       if (icon) {
+               if (weston_surface_set_role(icon, "wl_data_device-icon",
+                                           resource,
+                                           WL_DATA_DEVICE_ERROR_ROLE) < 0)
+                       return;
+       }
+
+       if (is_pointer_grab)
+               ret = weston_pointer_start_drag(pointer, source, icon, client);
+       else if (is_touch_grab)
+               ret = weston_touch_start_drag(touch, source, icon, client);
+
+       if (ret < 0)
+               wl_resource_post_no_memory(resource);
+       else
+               source->seat = seat;
+}
+
+static void
+destroy_selection_data_source(struct wl_listener *listener, void *data)
+{
+       struct weston_seat *seat = container_of(listener, struct weston_seat,
+                                               selection_data_source_listener);
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       struct wl_resource *data_device;
+       struct weston_surface *focus = NULL;
+
+       seat->selection_data_source = NULL;
+
+       if (keyboard)
+               focus = keyboard->focus;
+       if (focus && focus->resource) {
+               data_device = wl_resource_find_for_client(&seat->drag_resource_list,
+                                                         wl_resource_get_client(focus->resource));
+               if (data_device)
+                       wl_data_device_send_selection(data_device, NULL);
+       }
+
+       wl_signal_emit(&seat->selection_signal, seat);
+}
+
+/** \brief Send the selection to the specified client
+ *
+ * This function creates a new wl_data_offer if there is a wl_data_source
+ * currently set as the selection and sends it to the specified client,
+ * followed by the wl_data_device.selection() event.
+ * If there is no current selection the wl_data_device.selection() event
+ * will carry a NULL wl_data_offer.
+ *
+ * If the client does not have a wl_data_device for the specified seat
+ * nothing will be done.
+ *
+ * \param seat The seat owning the wl_data_device used to send the events.
+ * \param client The client to which to send the selection.
+ */
+WL_EXPORT void
+weston_seat_send_selection(struct weston_seat *seat, struct wl_client *client)
+{
+       struct weston_data_offer *offer;
+       struct wl_resource *data_device;
+
+       wl_resource_for_each(data_device, &seat->drag_resource_list) {
+               if (wl_resource_get_client(data_device) != client)
+                   continue;
+
+               if (seat->selection_data_source) {
+                       offer = weston_data_source_send_offer(seat->selection_data_source,
+                                                             data_device);
+                       wl_data_device_send_selection(data_device, offer->resource);
+               } else {
+                       wl_data_device_send_selection(data_device, NULL);
+               }
+       }
+}
+
+WL_EXPORT void
+weston_seat_set_selection(struct weston_seat *seat,
+                         struct weston_data_source *source, uint32_t serial)
+{
+       struct weston_surface *focus = NULL;
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+
+       if (seat->selection_data_source &&
+           seat->selection_serial - serial < UINT32_MAX / 2)
+               return;
+
+       if (seat->selection_data_source) {
+               seat->selection_data_source->cancel(seat->selection_data_source);
+               wl_list_remove(&seat->selection_data_source_listener.link);
+               seat->selection_data_source = NULL;
+       }
+
+       seat->selection_data_source = source;
+       seat->selection_serial = serial;
+
+       if (keyboard)
+               focus = keyboard->focus;
+       if (focus && focus->resource) {
+               weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
+       }
+
+       wl_signal_emit(&seat->selection_signal, seat);
+
+       if (source) {
+               seat->selection_data_source_listener.notify =
+                       destroy_selection_data_source;
+               wl_signal_add(&source->destroy_signal,
+                             &seat->selection_data_source_listener);
+       }
+}
+
+static void
+data_device_set_selection(struct wl_client *client,
+                         struct wl_resource *resource,
+                         struct wl_resource *source_resource, uint32_t serial)
+{
+       struct weston_data_source *source;
+
+       if (!source_resource)
+               return;
+
+       source = wl_resource_get_user_data(source_resource);
+
+       if (source->actions_set) {
+               wl_resource_post_error(source_resource,
+                                      WL_DATA_SOURCE_ERROR_INVALID_SOURCE,
+                                      "cannot set drag-and-drop source as selection");
+               return;
+       }
+
+       /* FIXME: Store serial and check against incoming serial here. */
+       weston_seat_set_selection(wl_resource_get_user_data(resource),
+                                 source, serial);
+}
+static void
+data_device_release(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_data_device_interface data_device_interface = {
+       data_device_start_drag,
+       data_device_set_selection,
+       data_device_release
+};
+
+static void
+destroy_data_source(struct wl_resource *resource)
+{
+       struct weston_data_source *source =
+               wl_resource_get_user_data(resource);
+       char **p;
+
+       wl_signal_emit(&source->destroy_signal, source);
+
+       wl_array_for_each(p, &source->mime_types)
+               free(*p);
+
+       wl_array_release(&source->mime_types);
+
+       free(source);
+}
+
+static void
+client_source_accept(struct weston_data_source *source,
+                    uint32_t time, const char *mime_type)
+{
+       wl_data_source_send_target(source->resource, mime_type);
+}
+
+static void
+client_source_send(struct weston_data_source *source,
+                  const char *mime_type, int32_t fd)
+{
+       wl_data_source_send_send(source->resource, mime_type, fd);
+       close(fd);
+}
+
+static void
+client_source_cancel(struct weston_data_source *source)
+{
+       wl_data_source_send_cancelled(source->resource);
+}
+
+static void
+create_data_source(struct wl_client *client,
+                  struct wl_resource *resource, uint32_t id)
+{
+       struct weston_data_source *source;
+
+       source = malloc(sizeof *source);
+       if (source == NULL) {
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       source->resource =
+               wl_resource_create(client, &wl_data_source_interface,
+                                  wl_resource_get_version(resource), id);
+       if (source->resource == NULL) {
+               free(source);
+               wl_resource_post_no_memory(resource);
+               return;
+       }
+
+       wl_signal_init(&source->destroy_signal);
+       source->accept = client_source_accept;
+       source->send = client_source_send;
+       source->cancel = client_source_cancel;
+       source->offer = NULL;
+       source->accepted = false;
+       source->seat = NULL;
+       source->actions_set = false;
+       source->dnd_actions = 0;
+       source->current_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+       source->compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
+
+       wl_array_init(&source->mime_types);
+
+       wl_resource_set_implementation(source->resource, &data_source_interface,
+                                      source, destroy_data_source);
+}
+
+static void unbind_data_device(struct wl_resource *resource)
+{
+       wl_list_remove(wl_resource_get_link(resource));
+}
+
+static void
+get_data_device(struct wl_client *client,
+               struct wl_resource *manager_resource,
+               uint32_t id, struct wl_resource *seat_resource)
+{
+       struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client,
+                                     &wl_data_device_interface,
+                                     wl_resource_get_version(manager_resource),
+                                     id);
+       if (resource == NULL) {
+               wl_resource_post_no_memory(manager_resource);
+               return;
+       }
+
+       wl_list_insert(&seat->drag_resource_list,
+                      wl_resource_get_link(resource));
+       wl_resource_set_implementation(resource, &data_device_interface,
+                                      seat, unbind_data_device);
+}
+
+static const struct wl_data_device_manager_interface manager_interface = {
+       create_data_source,
+       get_data_device
+};
+
+static void
+bind_manager(struct wl_client *client,
+            void *data, uint32_t version, uint32_t id)
+{
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client,
+                                     &wl_data_device_manager_interface,
+                                     version, id);
+       if (resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_resource_set_implementation(resource, &manager_interface,
+                                      NULL, NULL);
+}
+
+WL_EXPORT void
+wl_data_device_set_keyboard_focus(struct weston_seat *seat)
+{
+       struct weston_surface *focus;
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+
+       if (!keyboard)
+               return;
+
+       focus = keyboard->focus;
+       if (!focus || !focus->resource)
+               return;
+
+       weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
+}
+
+WL_EXPORT int
+wl_data_device_manager_init(struct wl_display *display)
+{
+       if (wl_global_create(display,
+                            &wl_data_device_manager_interface, 3,
+                            NULL, bind_manager) == NULL)
+               return -1;
+
+       return 0;
+}
diff --git a/libweston/dbus.c b/libweston/dbus.c
new file mode 100644 (file)
index 0000000..cadedd9
--- /dev/null
@@ -0,0 +1,407 @@
+/*
+ * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/*
+ * DBus Helpers
+ * This file contains the dbus mainloop integration and several helpers to
+ * make lowlevel libdbus access easier.
+ */
+
+#include "config.h"
+
+#include <dbus/dbus.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/eventfd.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include <wayland-server.h>
+
+#include "compositor.h"
+#include "dbus.h"
+
+/*
+ * DBus Mainloop Integration
+ * weston_dbus_bind() and weston_dbus_unbind() allow to bind an existing
+ * DBusConnection to an existing wl_event_loop object. All dbus dispatching
+ * is then nicely integrated into the wayland event loop.
+ * Note that this only provides basic watch and timeout dispatching. No
+ * remote thread wakeup, signal handling or other dbus insanity is supported.
+ * This is fine as long as you don't use any of the deprecated libdbus
+ * interfaces (like waking up remote threads..). There is really no rational
+ * reason to support these.
+ */
+
+static int weston_dbus_dispatch_watch(int fd, uint32_t mask, void *data)
+{
+       DBusWatch *watch = data;
+       uint32_t flags = 0;
+
+       if (dbus_watch_get_enabled(watch)) {
+               if (mask & WL_EVENT_READABLE)
+                       flags |= DBUS_WATCH_READABLE;
+               if (mask & WL_EVENT_WRITABLE)
+                       flags |= DBUS_WATCH_WRITABLE;
+               if (mask & WL_EVENT_HANGUP)
+                       flags |= DBUS_WATCH_HANGUP;
+               if (mask & WL_EVENT_ERROR)
+                       flags |= DBUS_WATCH_ERROR;
+
+               dbus_watch_handle(watch, flags);
+       }
+
+       return 0;
+}
+
+static dbus_bool_t weston_dbus_add_watch(DBusWatch *watch, void *data)
+{
+       struct wl_event_loop *loop = data;
+       struct wl_event_source *s;
+       int fd;
+       uint32_t mask = 0, flags;
+
+       if (dbus_watch_get_enabled(watch)) {
+               flags = dbus_watch_get_flags(watch);
+               if (flags & DBUS_WATCH_READABLE)
+                       mask |= WL_EVENT_READABLE;
+               if (flags & DBUS_WATCH_WRITABLE)
+                       mask |= WL_EVENT_WRITABLE;
+       }
+
+       fd = dbus_watch_get_unix_fd(watch);
+       s = wl_event_loop_add_fd(loop, fd, mask, weston_dbus_dispatch_watch,
+                                watch);
+       if (!s)
+               return FALSE;
+
+       dbus_watch_set_data(watch, s, NULL);
+       return TRUE;
+}
+
+static void weston_dbus_remove_watch(DBusWatch *watch, void *data)
+{
+       struct wl_event_source *s;
+
+       s = dbus_watch_get_data(watch);
+       if (!s)
+               return;
+
+       wl_event_source_remove(s);
+}
+
+static void weston_dbus_toggle_watch(DBusWatch *watch, void *data)
+{
+       struct wl_event_source *s;
+       uint32_t mask = 0, flags;
+
+       s = dbus_watch_get_data(watch);
+       if (!s)
+               return;
+
+       if (dbus_watch_get_enabled(watch)) {
+               flags = dbus_watch_get_flags(watch);
+               if (flags & DBUS_WATCH_READABLE)
+                       mask |= WL_EVENT_READABLE;
+               if (flags & DBUS_WATCH_WRITABLE)
+                       mask |= WL_EVENT_WRITABLE;
+       }
+
+       wl_event_source_fd_update(s, mask);
+}
+
+static int weston_dbus_dispatch_timeout(void *data)
+{
+       DBusTimeout *timeout = data;
+
+       if (dbus_timeout_get_enabled(timeout))
+               dbus_timeout_handle(timeout);
+
+       return 0;
+}
+
+static int weston_dbus_adjust_timeout(DBusTimeout *timeout,
+                                     struct wl_event_source *s)
+{
+       int64_t t = 0;
+
+       if (dbus_timeout_get_enabled(timeout))
+               t = dbus_timeout_get_interval(timeout);
+
+       return wl_event_source_timer_update(s, t);
+}
+
+static dbus_bool_t weston_dbus_add_timeout(DBusTimeout *timeout, void *data)
+{
+       struct wl_event_loop *loop = data;
+       struct wl_event_source *s;
+       int r;
+
+       s = wl_event_loop_add_timer(loop, weston_dbus_dispatch_timeout,
+                                   timeout);
+       if (!s)
+               return FALSE;
+
+       r = weston_dbus_adjust_timeout(timeout, s);
+       if (r < 0) {
+               wl_event_source_remove(s);
+               return FALSE;
+       }
+
+       dbus_timeout_set_data(timeout, s, NULL);
+       return TRUE;
+}
+
+static void weston_dbus_remove_timeout(DBusTimeout *timeout, void *data)
+{
+       struct wl_event_source *s;
+
+       s = dbus_timeout_get_data(timeout);
+       if (!s)
+               return;
+
+       wl_event_source_remove(s);
+}
+
+static void weston_dbus_toggle_timeout(DBusTimeout *timeout, void *data)
+{
+       struct wl_event_source *s;
+
+       s = dbus_timeout_get_data(timeout);
+       if (!s)
+               return;
+
+       weston_dbus_adjust_timeout(timeout, s);
+}
+
+static int weston_dbus_dispatch(int fd, uint32_t mask, void *data)
+{
+       DBusConnection *c = data;
+       int r;
+
+       do {
+               r = dbus_connection_dispatch(c);
+               if (r == DBUS_DISPATCH_COMPLETE)
+                       r = 0;
+               else if (r == DBUS_DISPATCH_DATA_REMAINS)
+                       r = -EAGAIN;
+               else if (r == DBUS_DISPATCH_NEED_MEMORY)
+                       r = -ENOMEM;
+               else
+                       r = -EIO;
+       } while (r == -EAGAIN);
+
+       if (r)
+               weston_log("cannot dispatch dbus events: %d\n", r);
+
+       return 0;
+}
+
+static int weston_dbus_bind(struct wl_event_loop *loop, DBusConnection *c,
+                           struct wl_event_source **ctx_out)
+{
+       bool b;
+       int r, fd;
+
+       /* Idle events cannot reschedule themselves, therefore we use a dummy
+        * event-fd and mark it for post-dispatch. Hence, the dbus
+        * dispatcher is called after every dispatch-round.
+        * This is required as dbus doesn't allow dispatching events from
+        * within its own event sources. */
+       fd = eventfd(0, EFD_CLOEXEC);
+       if (fd < 0)
+               return -errno;
+
+       *ctx_out = wl_event_loop_add_fd(loop, fd, 0, weston_dbus_dispatch, c);
+       close(fd);
+
+       if (!*ctx_out)
+               return -ENOMEM;
+
+       wl_event_source_check(*ctx_out);
+
+       b = dbus_connection_set_watch_functions(c,
+                                               weston_dbus_add_watch,
+                                               weston_dbus_remove_watch,
+                                               weston_dbus_toggle_watch,
+                                               loop,
+                                               NULL);
+       if (!b) {
+               r = -ENOMEM;
+               goto error;
+       }
+
+       b = dbus_connection_set_timeout_functions(c,
+                                                 weston_dbus_add_timeout,
+                                                 weston_dbus_remove_timeout,
+                                                 weston_dbus_toggle_timeout,
+                                                 loop,
+                                                 NULL);
+       if (!b) {
+               r = -ENOMEM;
+               goto error;
+       }
+
+       dbus_connection_ref(c);
+       return 0;
+
+error:
+       dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
+                                             NULL, NULL);
+       dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
+                                           NULL, NULL);
+       wl_event_source_remove(*ctx_out);
+       *ctx_out = NULL;
+       return r;
+}
+
+static void weston_dbus_unbind(DBusConnection *c, struct wl_event_source *ctx)
+{
+       dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
+                                             NULL, NULL);
+       dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
+                                           NULL, NULL);
+       dbus_connection_unref(c);
+       wl_event_source_remove(ctx);
+}
+
+/*
+ * Convenience Helpers
+ * Several convenience helpers are provided to make using dbus in weston
+ * easier. We don't use any of the gdbus or qdbus helpers as they pull in
+ * huge dependencies and actually are quite awful to use. Instead, we only
+ * use the basic low-level libdbus library.
+ */
+
+int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
+                    DBusConnection **out, struct wl_event_source **ctx_out)
+{
+       DBusConnection *c;
+       int r;
+
+       /* Ihhh, global state.. stupid dbus. */
+       dbus_connection_set_change_sigpipe(FALSE);
+
+       /* This is actually synchronous. It blocks for some authentication and
+        * setup. We just trust the dbus-server here and accept this blocking
+        * call. There is no real reason to complicate things further and make
+        * this asynchronous/non-blocking. A context should be created during
+        * thead/process/app setup, so blocking calls should be fine. */
+       c = dbus_bus_get_private(bus, NULL);
+       if (!c)
+               return -EIO;
+
+       dbus_connection_set_exit_on_disconnect(c, FALSE);
+
+       r = weston_dbus_bind(loop, c, ctx_out);
+       if (r < 0)
+               goto error;
+
+       *out = c;
+       return r;
+
+error:
+       dbus_connection_close(c);
+       dbus_connection_unref(c);
+       return r;
+}
+
+void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx)
+{
+       weston_dbus_unbind(c, ctx);
+       dbus_connection_close(c);
+       dbus_connection_unref(c);
+}
+
+int weston_dbus_add_match(DBusConnection *c, const char *format, ...)
+{
+       DBusError err;
+       int r;
+       va_list list;
+       char *str;
+
+       va_start(list, format);
+       r = vasprintf(&str, format, list);
+       va_end(list);
+
+       if (r < 0)
+               return -ENOMEM;
+
+       dbus_error_init(&err);
+       dbus_bus_add_match(c, str, &err);
+       free(str);
+       if (dbus_error_is_set(&err)) {
+               dbus_error_free(&err);
+               return -EIO;
+       }
+
+       return 0;
+}
+
+int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
+                                const char *iface, const char *member,
+                                const char *path)
+{
+       return weston_dbus_add_match(c,
+                                    "type='signal',"
+                                    "sender='%s',"
+                                    "interface='%s',"
+                                    "member='%s',"
+                                    "path='%s'",
+                                    sender, iface, member, path);
+}
+
+void weston_dbus_remove_match(DBusConnection *c, const char *format, ...)
+{
+       int r;
+       va_list list;
+       char *str;
+
+       va_start(list, format);
+       r = vasprintf(&str, format, list);
+       va_end(list);
+
+       if (r < 0)
+               return;
+
+       dbus_bus_remove_match(c, str, NULL);
+       free(str);
+}
+
+void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
+                                    const char *iface, const char *member,
+                                    const char *path)
+{
+       return weston_dbus_remove_match(c,
+                                       "type='signal',"
+                                       "sender='%s',"
+                                       "interface='%s',"
+                                       "member='%s',"
+                                       "path='%s'",
+                                       sender, iface, member, path);
+}
diff --git a/libweston/dbus.h b/libweston/dbus.h
new file mode 100644 (file)
index 0000000..9bbfa38
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _WESTON_DBUS_H_
+#define _WESTON_DBUS_H_
+
+#include "config.h"
+
+#include <errno.h>
+#include <wayland-server.h>
+
+#include "compositor.h"
+
+#ifdef HAVE_DBUS
+
+#include <dbus/dbus.h>
+
+/*
+ * weston_dbus_open() - Open new dbus connection
+ *
+ * Opens a new dbus connection to the bus given as @bus. It automatically
+ * integrates the new connection into the main-loop @loop. The connection
+ * itself is returned in @out.
+ * This also returns a context source used for dbus dispatching. It is
+ * returned on success in @ctx_out and must be passed to weston_dbus_close()
+ * unchanged. You must not access it from outside of a dbus helper!
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
+                    DBusConnection **out, struct wl_event_source **ctx_out);
+
+/*
+ * weston_dbus_close() - Close dbus connection
+ *
+ * Closes a dbus connection that was previously opened via weston_dbus_open().
+ * It unbinds the connection from the main-loop it was previously bound to,
+ * closes the dbus connection and frees all resources. If you want to access
+ * @c after this call returns, you must hold a dbus-reference to it. But
+ * notice that the connection is closed after this returns so it cannot be
+ * used to spawn new dbus requests.
+ * You must pass the context source returns by weston_dbus_open() as @ctx.
+ */
+void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx);
+
+/*
+ * weston_dbus_add_match() - Add dbus match
+ *
+ * Configure a dbus-match on the given dbus-connection. This match is saved
+ * on the dbus-server as long as the connection is open. See dbus-manual
+ * for information. Compared to the dbus_bus_add_match() this allows a
+ * var-arg formatted match-string.
+ */
+int weston_dbus_add_match(DBusConnection *c, const char *format, ...);
+
+/*
+ * weston_dbus_add_match_signal() - Add dbus signal match
+ *
+ * Same as weston_dbus_add_match() but does the dbus-match formatting for
+ * signals internally.
+ */
+int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
+                                const char *iface, const char *member,
+                                const char *path);
+
+/*
+ * weston_dbus_remove_match() - Remove dbus match
+ *
+ * Remove a previously configured dbus-match from the dbus server. There is
+ * no need to remove dbus-matches if you close the connection, anyway.
+ * Compared to dbus_bus_remove_match() this allows a var-arg formatted
+ * match string.
+ */
+void weston_dbus_remove_match(DBusConnection *c, const char *format, ...);
+
+/*
+ * weston_dbus_remove_match_signal() - Remove dbus signal match
+ *
+ * Same as weston_dbus_remove_match() but does the dbus-match formatting for
+ * signals internally.
+ */
+void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
+                                    const char *iface, const char *member,
+                                    const char *path);
+
+#endif /* HAVE_DBUS */
+
+#endif // _WESTON_DBUS_H_
diff --git a/libweston/gl-renderer.c b/libweston/gl-renderer.c
new file mode 100644 (file)
index 0000000..23c0cd7
--- /dev/null
@@ -0,0 +1,3157 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2015 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <float.h>
+#include <assert.h>
+#include <linux/input.h>
+#include <drm_fourcc.h>
+
+#include "gl-renderer.h"
+#include "vertex-clipping.h"
+#include "linux-dmabuf.h"
+#include "linux-dmabuf-unstable-v1-server-protocol.h"
+
+#include "shared/helpers.h"
+#include "weston-egl-ext.h"
+
+struct gl_shader {
+       GLuint program;
+       GLuint vertex_shader, fragment_shader;
+       GLint proj_uniform;
+       GLint tex_uniforms[3];
+       GLint alpha_uniform;
+       GLint color_uniform;
+       const char *vertex_source, *fragment_source;
+};
+
+#define BUFFER_DAMAGE_COUNT 2
+
+enum gl_border_status {
+       BORDER_STATUS_CLEAN = 0,
+       BORDER_TOP_DIRTY = 1 << GL_RENDERER_BORDER_TOP,
+       BORDER_LEFT_DIRTY = 1 << GL_RENDERER_BORDER_LEFT,
+       BORDER_RIGHT_DIRTY = 1 << GL_RENDERER_BORDER_RIGHT,
+       BORDER_BOTTOM_DIRTY = 1 << GL_RENDERER_BORDER_BOTTOM,
+       BORDER_ALL_DIRTY = 0xf,
+       BORDER_SIZE_CHANGED = 0x10
+};
+
+struct gl_border_image {
+       GLuint tex;
+       int32_t width, height;
+       int32_t tex_width;
+       void *data;
+};
+
+struct gl_output_state {
+       EGLSurface egl_surface;
+       pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
+       int buffer_damage_index;
+       enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];
+       struct gl_border_image borders[4];
+       enum gl_border_status border_status;
+
+       struct weston_matrix output_matrix;
+};
+
+enum buffer_type {
+       BUFFER_TYPE_NULL,
+       BUFFER_TYPE_SOLID, /* internal solid color surfaces without a buffer */
+       BUFFER_TYPE_SHM,
+       BUFFER_TYPE_EGL
+};
+
+struct gl_renderer;
+
+struct egl_image {
+       struct gl_renderer *renderer;
+       EGLImageKHR image;
+       int refcount;
+};
+
+enum import_type {
+       IMPORT_TYPE_INVALID,
+       IMPORT_TYPE_DIRECT,
+       IMPORT_TYPE_GL_CONVERSION
+};
+
+struct dmabuf_image {
+       struct linux_dmabuf_buffer *dmabuf;
+       int num_images;
+       struct egl_image *images[3];
+       struct wl_list link;
+
+       enum import_type import_type;
+       GLenum target;
+       struct gl_shader *shader;
+};
+
+struct yuv_plane_descriptor {
+       int width_divisor;
+       int height_divisor;
+       uint32_t format;
+       int plane_index;
+};
+
+struct yuv_format_descriptor {
+       uint32_t format;
+       int input_planes;
+       int output_planes;
+       int texture_type;
+       struct yuv_plane_descriptor plane[4];
+};
+
+struct gl_surface_state {
+       GLfloat color[4];
+       struct gl_shader *shader;
+
+       GLuint textures[3];
+       int num_textures;
+       bool needs_full_upload;
+       pixman_region32_t texture_damage;
+
+       /* These are only used by SHM surfaces to detect when we need
+        * to do a full upload to specify a new internal texture
+        * format */
+       GLenum gl_format;
+       GLenum gl_pixel_type;
+
+       struct egl_image* images[3];
+       GLenum target;
+       int num_images;
+
+       struct weston_buffer_reference buffer_ref;
+       enum buffer_type buffer_type;
+       int pitch; /* in pixels */
+       int height; /* in pixels */
+       int y_inverted;
+
+       struct weston_surface *surface;
+
+       struct wl_listener surface_destroy_listener;
+       struct wl_listener renderer_destroy_listener;
+};
+
+struct gl_renderer {
+       struct weston_renderer base;
+       int fragment_shader_debug;
+       int fan_debug;
+       struct weston_binding *fragment_binding;
+       struct weston_binding *fan_binding;
+
+       EGLDisplay egl_display;
+       EGLContext egl_context;
+       EGLConfig egl_config;
+
+       struct wl_array vertices;
+       struct wl_array vtxcnt;
+
+       PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
+       PFNEGLCREATEIMAGEKHRPROC create_image;
+       PFNEGLDESTROYIMAGEKHRPROC destroy_image;
+
+#ifdef EGL_EXT_swap_buffers_with_damage
+       PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
+#endif
+
+       PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC create_platform_window;
+
+       int has_unpack_subimage;
+
+       PFNEGLBINDWAYLANDDISPLAYWL bind_display;
+       PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
+       PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
+       int has_bind_display;
+
+       int has_egl_image_external;
+
+       int has_egl_buffer_age;
+
+       int has_configless_context;
+
+       int has_dmabuf_import;
+       struct wl_list dmabuf_images;
+
+       struct gl_shader texture_shader_rgba;
+       struct gl_shader texture_shader_rgbx;
+       struct gl_shader texture_shader_egl_external;
+       struct gl_shader texture_shader_y_uv;
+       struct gl_shader texture_shader_y_u_v;
+       struct gl_shader texture_shader_y_xuxv;
+       struct gl_shader invert_color_shader;
+       struct gl_shader solid_shader;
+       struct gl_shader *current_shader;
+
+       struct wl_signal destroy_signal;
+};
+
+static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
+
+static inline const char *
+dump_format(uint32_t format, char out[4])
+{
+#if BYTE_ORDER == BIG_ENDIAN
+       format = __builtin_bswap32(format);
+#endif
+       memcpy(out, &format, 4);
+       return out;
+}
+
+static inline struct gl_output_state *
+get_output_state(struct weston_output *output)
+{
+       return (struct gl_output_state *)output->renderer_state;
+}
+
+static int
+gl_renderer_create_surface(struct weston_surface *surface);
+
+static inline struct gl_surface_state *
+get_surface_state(struct weston_surface *surface)
+{
+       if (!surface->renderer_state)
+               gl_renderer_create_surface(surface);
+
+       return (struct gl_surface_state *)surface->renderer_state;
+}
+
+static inline struct gl_renderer *
+get_renderer(struct weston_compositor *ec)
+{
+       return (struct gl_renderer *)ec->renderer;
+}
+
+static struct egl_image*
+egl_image_create(struct gl_renderer *gr, EGLenum target,
+                EGLClientBuffer buffer, const EGLint *attribs)
+{
+       struct egl_image *img;
+
+       img = zalloc(sizeof *img);
+       img->renderer = gr;
+       img->refcount = 1;
+       img->image = gr->create_image(gr->egl_display, EGL_NO_CONTEXT,
+                                     target, buffer, attribs);
+
+       if (img->image == EGL_NO_IMAGE_KHR) {
+               free(img);
+               return NULL;
+       }
+
+       return img;
+}
+
+static struct egl_image*
+egl_image_ref(struct egl_image *image)
+{
+       image->refcount++;
+
+       return image;
+}
+
+static int
+egl_image_unref(struct egl_image *image)
+{
+       struct gl_renderer *gr = image->renderer;
+
+       assert(image->refcount > 0);
+
+       image->refcount--;
+       if (image->refcount > 0)
+               return image->refcount;
+
+       gr->destroy_image(gr->egl_display, image->image);
+       free(image);
+
+       return 0;
+}
+
+static struct dmabuf_image*
+dmabuf_image_create(void)
+{
+       struct dmabuf_image *img;
+
+       img = zalloc(sizeof *img);
+       wl_list_init(&img->link);
+
+       return img;
+}
+
+static void
+dmabuf_image_destroy(struct dmabuf_image *image)
+{
+       int i;
+
+       for (i = 0; i < image->num_images; ++i)
+               egl_image_unref(image->images[i]);
+
+       if (image->dmabuf)
+               linux_dmabuf_buffer_set_user_data(image->dmabuf, NULL, NULL);
+
+       wl_list_remove(&image->link);
+}
+
+static const char *
+egl_error_string(EGLint code)
+{
+#define MYERRCODE(x) case x: return #x;
+       switch (code) {
+       MYERRCODE(EGL_SUCCESS)
+       MYERRCODE(EGL_NOT_INITIALIZED)
+       MYERRCODE(EGL_BAD_ACCESS)
+       MYERRCODE(EGL_BAD_ALLOC)
+       MYERRCODE(EGL_BAD_ATTRIBUTE)
+       MYERRCODE(EGL_BAD_CONTEXT)
+       MYERRCODE(EGL_BAD_CONFIG)
+       MYERRCODE(EGL_BAD_CURRENT_SURFACE)
+       MYERRCODE(EGL_BAD_DISPLAY)
+       MYERRCODE(EGL_BAD_SURFACE)
+       MYERRCODE(EGL_BAD_MATCH)
+       MYERRCODE(EGL_BAD_PARAMETER)
+       MYERRCODE(EGL_BAD_NATIVE_PIXMAP)
+       MYERRCODE(EGL_BAD_NATIVE_WINDOW)
+       MYERRCODE(EGL_CONTEXT_LOST)
+       default:
+               return "unknown";
+       }
+#undef MYERRCODE
+}
+
+static void
+gl_renderer_print_egl_error_state(void)
+{
+       EGLint code;
+
+       code = eglGetError();
+       weston_log("EGL error state: %s (0x%04lx)\n",
+               egl_error_string(code), (long)code);
+}
+
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#define min(a, b) (((a) > (b)) ? (b) : (a))
+
+/*
+ * Compute the boundary vertices of the intersection of the global coordinate
+ * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
+ * 'surf_rect' when transformed from surface coordinates into global coordinates.
+ * The vertices are written to 'ex' and 'ey', and the return value is the
+ * number of vertices. Vertices are produced in clockwise winding order.
+ * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
+ * polygon area.
+ */
+static int
+calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
+               pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
+{
+
+       struct clip_context ctx;
+       int i, n;
+       GLfloat min_x, max_x, min_y, max_y;
+       struct polygon8 surf = {
+               { surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
+               { surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
+               4
+       };
+
+       ctx.clip.x1 = rect->x1;
+       ctx.clip.y1 = rect->y1;
+       ctx.clip.x2 = rect->x2;
+       ctx.clip.y2 = rect->y2;
+
+       /* transform surface to screen space: */
+       for (i = 0; i < surf.n; i++)
+               weston_view_to_global_float(ev, surf.x[i], surf.y[i],
+                                           &surf.x[i], &surf.y[i]);
+
+       /* find bounding box: */
+       min_x = max_x = surf.x[0];
+       min_y = max_y = surf.y[0];
+
+       for (i = 1; i < surf.n; i++) {
+               min_x = min(min_x, surf.x[i]);
+               max_x = max(max_x, surf.x[i]);
+               min_y = min(min_y, surf.y[i]);
+               max_y = max(max_y, surf.y[i]);
+       }
+
+       /* First, simple bounding box check to discard early transformed
+        * surface rects that do not intersect with the clip region:
+        */
+       if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
+           (min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
+               return 0;
+
+       /* Simple case, bounding box edges are parallel to surface edges,
+        * there will be only four edges.  We just need to clip the surface
+        * vertices to the clip rect bounds:
+        */
+       if (!ev->transform.enabled)
+               return clip_simple(&ctx, &surf, ex, ey);
+
+       /* Transformed case: use a general polygon clipping algorithm to
+        * clip the surface rectangle with each side of 'rect'.
+        * The algorithm is Sutherland-Hodgman, as explained in
+        * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
+        * but without looking at any of that code.
+        */
+       n = clip_transformed(&ctx, &surf, ex, ey);
+
+       if (n < 3)
+               return 0;
+
+       return n;
+}
+
+static bool
+merge_down(pixman_box32_t *a, pixman_box32_t *b, pixman_box32_t *merge)
+{
+       if (a->x1 == b->x1 && a->x2 == b->x2 && a->y1 == b->y2) {
+               merge->x1 = a->x1;
+               merge->x2 = a->x2;
+               merge->y1 = b->y1;
+               merge->y2 = a->y2;
+               return true;
+       }
+       return false;
+}
+
+static int
+compress_bands(pixman_box32_t *inrects, int nrects,
+                  pixman_box32_t **outrects)
+{
+       bool merged;
+       pixman_box32_t *out, merge_rect;
+       int i, j, nout;
+
+       if (!nrects) {
+               *outrects = NULL;
+               return 0;
+       }
+
+       /* nrects is an upper bound - we're not too worried about
+        * allocating a little extra
+        */
+       out = malloc(sizeof(pixman_box32_t) * nrects);
+       out[0] = inrects[0];
+       nout = 1;
+       for (i = 1; i < nrects; i++) {
+               for (j = 0; j < nout; j++) {
+                       merged = merge_down(&inrects[i], &out[j], &merge_rect);
+                       if (merged) {
+                               out[j] = merge_rect;
+                               break;
+                       }
+               }
+               if (!merged) {
+                       out[nout] = inrects[i];
+                       nout++;
+               }
+       }
+       *outrects = out;
+       return nout;
+}
+
+static int
+texture_region(struct weston_view *ev, pixman_region32_t *region,
+               pixman_region32_t *surf_region)
+{
+       struct gl_surface_state *gs = get_surface_state(ev->surface);
+       struct weston_compositor *ec = ev->surface->compositor;
+       struct gl_renderer *gr = get_renderer(ec);
+       GLfloat *v, inv_width, inv_height;
+       unsigned int *vtxcnt, nvtx = 0;
+       pixman_box32_t *rects, *surf_rects;
+       pixman_box32_t *raw_rects;
+       int i, j, k, nrects, nsurf, raw_nrects;
+       bool used_band_compression;
+       raw_rects = pixman_region32_rectangles(region, &raw_nrects);
+       surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
+
+       if (raw_nrects < 4) {
+               used_band_compression = false;
+               nrects = raw_nrects;
+               rects = raw_rects;
+       } else {
+               nrects = compress_bands(raw_rects, raw_nrects, &rects);
+               used_band_compression = true;
+       }
+       /* worst case we can have 8 vertices per rect (ie. clipped into
+        * an octagon):
+        */
+       v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * 4 * sizeof *v);
+       vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
+
+       inv_width = 1.0 / gs->pitch;
+        inv_height = 1.0 / gs->height;
+
+       for (i = 0; i < nrects; i++) {
+               pixman_box32_t *rect = &rects[i];
+               for (j = 0; j < nsurf; j++) {
+                       pixman_box32_t *surf_rect = &surf_rects[j];
+                       GLfloat sx, sy, bx, by;
+                       GLfloat ex[8], ey[8];          /* edge points in screen space */
+                       int n;
+
+                       /* The transformed surface, after clipping to the clip region,
+                        * can have as many as eight sides, emitted as a triangle-fan.
+                        * The first vertex in the triangle fan can be chosen arbitrarily,
+                        * since the area is guaranteed to be convex.
+                        *
+                        * If a corner of the transformed surface falls outside of the
+                        * clip region, instead of emitting one vertex for the corner
+                        * of the surface, up to two are emitted for two corresponding
+                        * intersection point(s) between the surface and the clip region.
+                        *
+                        * To do this, we first calculate the (up to eight) points that
+                        * form the intersection of the clip rect and the transformed
+                        * surface.
+                        */
+                       n = calculate_edges(ev, rect, surf_rect, ex, ey);
+                       if (n < 3)
+                               continue;
+
+                       /* emit edge points: */
+                       for (k = 0; k < n; k++) {
+                               weston_view_from_global_float(ev, ex[k], ey[k],
+                                                             &sx, &sy);
+                               /* position: */
+                               *(v++) = ex[k];
+                               *(v++) = ey[k];
+                               /* texcoord: */
+                               weston_surface_to_buffer_float(ev->surface,
+                                                              sx, sy,
+                                                              &bx, &by);
+                               *(v++) = bx * inv_width;
+                               if (gs->y_inverted) {
+                                       *(v++) = by * inv_height;
+                               } else {
+                                       *(v++) = (gs->height - by) * inv_height;
+                               }
+                       }
+
+                       vtxcnt[nvtx++] = n;
+               }
+       }
+
+       if (used_band_compression)
+               free(rects);
+       return nvtx;
+}
+
+static void
+triangle_fan_debug(struct weston_view *view, int first, int count)
+{
+       struct weston_compositor *compositor = view->surface->compositor;
+       struct gl_renderer *gr = get_renderer(compositor);
+       int i;
+       GLushort *buffer;
+       GLushort *index;
+       int nelems;
+       static int color_idx = 0;
+       static const GLfloat color[][4] = {
+                       { 1.0, 0.0, 0.0, 1.0 },
+                       { 0.0, 1.0, 0.0, 1.0 },
+                       { 0.0, 0.0, 1.0, 1.0 },
+                       { 1.0, 1.0, 1.0, 1.0 },
+       };
+
+       nelems = (count - 1 + count - 2) * 2;
+
+       buffer = malloc(sizeof(GLushort) * nelems);
+       index = buffer;
+
+       for (i = 1; i < count; i++) {
+               *index++ = first;
+               *index++ = first + i;
+       }
+
+       for (i = 2; i < count; i++) {
+               *index++ = first + i - 1;
+               *index++ = first + i;
+       }
+
+       glUseProgram(gr->solid_shader.program);
+       glUniform4fv(gr->solid_shader.color_uniform, 1,
+                       color[color_idx++ % ARRAY_LENGTH(color)]);
+       glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
+       glUseProgram(gr->current_shader->program);
+       free(buffer);
+}
+
+static void
+repaint_region(struct weston_view *ev, pixman_region32_t *region,
+               pixman_region32_t *surf_region)
+{
+       struct weston_compositor *ec = ev->surface->compositor;
+       struct gl_renderer *gr = get_renderer(ec);
+       GLfloat *v;
+       unsigned int *vtxcnt;
+       int i, first, nfans;
+
+       /* The final region to be painted is the intersection of
+        * 'region' and 'surf_region'. However, 'region' is in the global
+        * coordinates, and 'surf_region' is in the surface-local
+        * coordinates. texture_region() will iterate over all pairs of
+        * rectangles from both regions, compute the intersection
+        * polygon for each pair, and store it as a triangle fan if
+        * it has a non-zero area (at least 3 vertices, actually).
+        */
+       nfans = texture_region(ev, region, surf_region);
+
+       v = gr->vertices.data;
+       vtxcnt = gr->vtxcnt.data;
+
+       /* position: */
+       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
+       glEnableVertexAttribArray(0);
+
+       /* texcoord: */
+       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
+       glEnableVertexAttribArray(1);
+
+       for (i = 0, first = 0; i < nfans; i++) {
+               glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
+               if (gr->fan_debug)
+                       triangle_fan_debug(ev, first, vtxcnt[i]);
+               first += vtxcnt[i];
+       }
+
+       glDisableVertexAttribArray(1);
+       glDisableVertexAttribArray(0);
+
+       gr->vertices.size = 0;
+       gr->vtxcnt.size = 0;
+}
+
+static int
+use_output(struct weston_output *output)
+{
+       static int errored;
+       struct gl_output_state *go = get_output_state(output);
+       struct gl_renderer *gr = get_renderer(output->compositor);
+       EGLBoolean ret;
+
+       ret = eglMakeCurrent(gr->egl_display, go->egl_surface,
+                            go->egl_surface, gr->egl_context);
+
+       if (ret == EGL_FALSE) {
+               if (errored)
+                       return -1;
+               errored = 1;
+               weston_log("Failed to make EGL context current.\n");
+               gl_renderer_print_egl_error_state();
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+shader_init(struct gl_shader *shader, struct gl_renderer *gr,
+                  const char *vertex_source, const char *fragment_source);
+
+static void
+use_shader(struct gl_renderer *gr, struct gl_shader *shader)
+{
+       if (!shader->program) {
+               int ret;
+
+               ret =  shader_init(shader, gr,
+                                  shader->vertex_source,
+                                  shader->fragment_source);
+
+               if (ret < 0)
+                       weston_log("warning: failed to compile shader\n");
+       }
+
+       if (gr->current_shader == shader)
+               return;
+       glUseProgram(shader->program);
+       gr->current_shader = shader;
+}
+
+static void
+shader_uniforms(struct gl_shader *shader,
+               struct weston_view *view,
+               struct weston_output *output)
+{
+       int i;
+       struct gl_surface_state *gs = get_surface_state(view->surface);
+       struct gl_output_state *go = get_output_state(output);
+
+       glUniformMatrix4fv(shader->proj_uniform,
+                          1, GL_FALSE, go->output_matrix.d);
+       glUniform4fv(shader->color_uniform, 1, gs->color);
+       glUniform1f(shader->alpha_uniform, view->alpha);
+
+       for (i = 0; i < gs->num_textures; i++)
+               glUniform1i(shader->tex_uniforms[i], i);
+}
+
+static void
+draw_view(struct weston_view *ev, struct weston_output *output,
+         pixman_region32_t *damage) /* in global coordinates */
+{
+       struct weston_compositor *ec = ev->surface->compositor;
+       struct gl_renderer *gr = get_renderer(ec);
+       struct gl_surface_state *gs = get_surface_state(ev->surface);
+       /* repaint bounding region in global coordinates: */
+       pixman_region32_t repaint;
+       /* opaque region in surface coordinates: */
+       pixman_region32_t surface_opaque;
+       /* non-opaque region in surface coordinates: */
+       pixman_region32_t surface_blend;
+       GLint filter;
+       int i;
+
+       /* In case of a runtime switch of renderers, we may not have received
+        * an attach for this surface since the switch. In that case we don't
+        * have a valid buffer or a proper shader set up so skip rendering. */
+       if (!gs->shader)
+               return;
+
+       pixman_region32_init(&repaint);
+       pixman_region32_intersect(&repaint,
+                                 &ev->transform.boundingbox, damage);
+       pixman_region32_subtract(&repaint, &repaint, &ev->clip);
+
+       if (!pixman_region32_not_empty(&repaint))
+               goto out;
+
+       glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+       if (gr->fan_debug) {
+               use_shader(gr, &gr->solid_shader);
+               shader_uniforms(&gr->solid_shader, ev, output);
+       }
+
+       use_shader(gr, gs->shader);
+       shader_uniforms(gs->shader, ev, output);
+
+       if (ev->transform.enabled || output->zoom.active ||
+           output->current_scale != ev->surface->buffer_viewport.buffer.scale)
+               filter = GL_LINEAR;
+       else
+               filter = GL_NEAREST;
+
+       for (i = 0; i < gs->num_textures; i++) {
+               glActiveTexture(GL_TEXTURE0 + i);
+               glBindTexture(gs->target, gs->textures[i]);
+               glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, filter);
+               glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, filter);
+       }
+
+       /* blended region is whole surface minus opaque region: */
+       pixman_region32_init_rect(&surface_blend, 0, 0,
+                                 ev->surface->width, ev->surface->height);
+       if (ev->geometry.scissor_enabled)
+               pixman_region32_intersect(&surface_blend, &surface_blend,
+                                         &ev->geometry.scissor);
+       pixman_region32_subtract(&surface_blend, &surface_blend,
+                                &ev->surface->opaque);
+
+       /* XXX: Should we be using ev->transform.opaque here? */
+       pixman_region32_init(&surface_opaque);
+       if (ev->geometry.scissor_enabled)
+               pixman_region32_intersect(&surface_opaque,
+                                         &ev->surface->opaque,
+                                         &ev->geometry.scissor);
+       else
+               pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
+
+       if (pixman_region32_not_empty(&surface_opaque)) {
+               if (gs->shader == &gr->texture_shader_rgba) {
+                       /* Special case for RGBA textures with possibly
+                        * bad data in alpha channel: use the shader
+                        * that forces texture alpha = 1.0.
+                        * Xwayland surfaces need this.
+                        */
+                       use_shader(gr, &gr->texture_shader_rgbx);
+                       shader_uniforms(&gr->texture_shader_rgbx, ev, output);
+               }
+
+               if (ev->alpha < 1.0)
+                       glEnable(GL_BLEND);
+               else
+                       glDisable(GL_BLEND);
+
+               repaint_region(ev, &repaint, &surface_opaque);
+       }
+
+       if (pixman_region32_not_empty(&surface_blend)) {
+               use_shader(gr, gs->shader);
+               glEnable(GL_BLEND);
+               repaint_region(ev, &repaint, &surface_blend);
+       }
+
+       pixman_region32_fini(&surface_blend);
+       pixman_region32_fini(&surface_opaque);
+
+out:
+       pixman_region32_fini(&repaint);
+}
+
+static void
+repaint_views(struct weston_output *output, pixman_region32_t *damage)
+{
+       struct weston_compositor *compositor = output->compositor;
+       struct weston_view *view;
+
+       wl_list_for_each_reverse(view, &compositor->view_list, link)
+               if (view->plane == &compositor->primary_plane)
+                       draw_view(view, output, damage);
+}
+
+static void
+draw_output_border_texture(struct gl_output_state *go,
+                          enum gl_renderer_border_side side,
+                          int32_t x, int32_t y,
+                          int32_t width, int32_t height)
+{
+       struct gl_border_image *img = &go->borders[side];
+       static GLushort indices [] = { 0, 1, 3, 3, 1, 2 };
+
+       if (!img->data) {
+               if (img->tex) {
+                       glDeleteTextures(1, &img->tex);
+                       img->tex = 0;
+               }
+
+               return;
+       }
+
+       if (!img->tex) {
+               glGenTextures(1, &img->tex);
+               glBindTexture(GL_TEXTURE_2D, img->tex);
+
+               glTexParameteri(GL_TEXTURE_2D,
+                               GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+               glTexParameteri(GL_TEXTURE_2D,
+                               GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+               glTexParameteri(GL_TEXTURE_2D,
+                               GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               glTexParameteri(GL_TEXTURE_2D,
+                               GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       } else {
+               glBindTexture(GL_TEXTURE_2D, img->tex);
+       }
+
+       if (go->border_status & (1 << side)) {
+#ifdef GL_EXT_unpack_subimage
+               glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
+               glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
+               glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
+#endif
+               glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
+                            img->tex_width, img->height, 0,
+                            GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
+       }
+
+       GLfloat texcoord[] = {
+               0.0f, 0.0f,
+               (GLfloat)img->width / (GLfloat)img->tex_width, 0.0f,
+               (GLfloat)img->width / (GLfloat)img->tex_width, 1.0f,
+               0.0f, 1.0f,
+       };
+
+       GLfloat verts[] = {
+               x, y,
+               x + width, y,
+               x + width, y + height,
+               x, y + height
+       };
+
+       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
+       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
+       glEnableVertexAttribArray(0);
+       glEnableVertexAttribArray(1);
+
+       glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
+
+       glDisableVertexAttribArray(1);
+       glDisableVertexAttribArray(0);
+}
+
+static int
+output_has_borders(struct weston_output *output)
+{
+       struct gl_output_state *go = get_output_state(output);
+
+       return go->borders[GL_RENDERER_BORDER_TOP].data ||
+              go->borders[GL_RENDERER_BORDER_RIGHT].data ||
+              go->borders[GL_RENDERER_BORDER_BOTTOM].data ||
+              go->borders[GL_RENDERER_BORDER_LEFT].data;
+}
+
+static void
+draw_output_borders(struct weston_output *output,
+                   enum gl_border_status border_status)
+{
+       struct gl_output_state *go = get_output_state(output);
+       struct gl_renderer *gr = get_renderer(output->compositor);
+       struct gl_shader *shader = &gr->texture_shader_rgba;
+       struct gl_border_image *top, *bottom, *left, *right;
+       struct weston_matrix matrix;
+       int full_width, full_height;
+
+       if (border_status == BORDER_STATUS_CLEAN)
+               return; /* Clean. Nothing to do. */
+
+       top = &go->borders[GL_RENDERER_BORDER_TOP];
+       bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
+       left = &go->borders[GL_RENDERER_BORDER_LEFT];
+       right = &go->borders[GL_RENDERER_BORDER_RIGHT];
+
+       full_width = output->current_mode->width + left->width + right->width;
+       full_height = output->current_mode->height + top->height + bottom->height;
+
+       glDisable(GL_BLEND);
+       use_shader(gr, shader);
+
+       glViewport(0, 0, full_width, full_height);
+
+       weston_matrix_init(&matrix);
+       weston_matrix_translate(&matrix, -full_width/2.0, -full_height/2.0, 0);
+       weston_matrix_scale(&matrix, 2.0/full_width, -2.0/full_height, 1);
+       glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, matrix.d);
+
+       glUniform1i(shader->tex_uniforms[0], 0);
+       glUniform1f(shader->alpha_uniform, 1);
+       glActiveTexture(GL_TEXTURE0);
+
+       if (border_status & BORDER_TOP_DIRTY)
+               draw_output_border_texture(go, GL_RENDERER_BORDER_TOP,
+                                          0, 0,
+                                          full_width, top->height);
+       if (border_status & BORDER_LEFT_DIRTY)
+               draw_output_border_texture(go, GL_RENDERER_BORDER_LEFT,
+                                          0, top->height,
+                                          left->width, output->current_mode->height);
+       if (border_status & BORDER_RIGHT_DIRTY)
+               draw_output_border_texture(go, GL_RENDERER_BORDER_RIGHT,
+                                          full_width - right->width, top->height,
+                                          right->width, output->current_mode->height);
+       if (border_status & BORDER_BOTTOM_DIRTY)
+               draw_output_border_texture(go, GL_RENDERER_BORDER_BOTTOM,
+                                          0, full_height - bottom->height,
+                                          full_width, bottom->height);
+}
+
+static void
+output_get_border_damage(struct weston_output *output,
+                        enum gl_border_status border_status,
+                        pixman_region32_t *damage)
+{
+       struct gl_output_state *go = get_output_state(output);
+       struct gl_border_image *top, *bottom, *left, *right;
+       int full_width, full_height;
+
+       if (border_status == BORDER_STATUS_CLEAN)
+               return; /* Clean. Nothing to do. */
+
+       top = &go->borders[GL_RENDERER_BORDER_TOP];
+       bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
+       left = &go->borders[GL_RENDERER_BORDER_LEFT];
+       right = &go->borders[GL_RENDERER_BORDER_RIGHT];
+
+       full_width = output->current_mode->width + left->width + right->width;
+       full_height = output->current_mode->height + top->height + bottom->height;
+       if (border_status & BORDER_TOP_DIRTY)
+               pixman_region32_union_rect(damage, damage,
+                                          0, 0,
+                                          full_width, top->height);
+       if (border_status & BORDER_LEFT_DIRTY)
+               pixman_region32_union_rect(damage, damage,
+                                          0, top->height,
+                                          left->width, output->current_mode->height);
+       if (border_status & BORDER_RIGHT_DIRTY)
+               pixman_region32_union_rect(damage, damage,
+                                          full_width - right->width, top->height,
+                                          right->width, output->current_mode->height);
+       if (border_status & BORDER_BOTTOM_DIRTY)
+               pixman_region32_union_rect(damage, damage,
+                                          0, full_height - bottom->height,
+                                          full_width, bottom->height);
+}
+
+static void
+output_get_damage(struct weston_output *output,
+                 pixman_region32_t *buffer_damage, uint32_t *border_damage)
+{
+       struct gl_output_state *go = get_output_state(output);
+       struct gl_renderer *gr = get_renderer(output->compositor);
+       EGLint buffer_age = 0;
+       EGLBoolean ret;
+       int i;
+
+       if (gr->has_egl_buffer_age) {
+               ret = eglQuerySurface(gr->egl_display, go->egl_surface,
+                                     EGL_BUFFER_AGE_EXT, &buffer_age);
+               if (ret == EGL_FALSE) {
+                       weston_log("buffer age query failed.\n");
+                       gl_renderer_print_egl_error_state();
+               }
+       }
+
+       if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT) {
+               pixman_region32_copy(buffer_damage, &output->region);
+               *border_damage = BORDER_ALL_DIRTY;
+       } else {
+               for (i = 0; i < buffer_age - 1; i++)
+                       *border_damage |= go->border_damage[(go->buffer_damage_index + i) % BUFFER_DAMAGE_COUNT];
+
+               if (*border_damage & BORDER_SIZE_CHANGED) {
+                       /* If we've had a resize, we have to do a full
+                        * repaint. */
+                       *border_damage |= BORDER_ALL_DIRTY;
+                       pixman_region32_copy(buffer_damage, &output->region);
+               } else {
+                       for (i = 0; i < buffer_age - 1; i++)
+                               pixman_region32_union(buffer_damage,
+                                                     buffer_damage,
+                                                     &go->buffer_damage[(go->buffer_damage_index + i) % BUFFER_DAMAGE_COUNT]);
+               }
+       }
+}
+
+static void
+output_rotate_damage(struct weston_output *output,
+                    pixman_region32_t *output_damage,
+                    enum gl_border_status border_status)
+{
+       struct gl_output_state *go = get_output_state(output);
+       struct gl_renderer *gr = get_renderer(output->compositor);
+
+       if (!gr->has_egl_buffer_age)
+               return;
+
+       go->buffer_damage_index += BUFFER_DAMAGE_COUNT - 1;
+       go->buffer_damage_index %= BUFFER_DAMAGE_COUNT;
+
+       pixman_region32_copy(&go->buffer_damage[go->buffer_damage_index], output_damage);
+       go->border_damage[go->buffer_damage_index] = border_status;
+}
+
+/* NOTE: We now allow falling back to ARGB gl visuals when XRGB is
+ * unavailable, so we're assuming the background has no transparency
+ * and that everything with a blend, like drop shadows, will have something
+ * opaque (like the background) drawn underneath it.
+ *
+ * Depending on the underlying hardware, violating that assumption could
+ * result in seeing through to another display plane.
+ */
+static void
+gl_renderer_repaint_output(struct weston_output *output,
+                             pixman_region32_t *output_damage)
+{
+       struct gl_output_state *go = get_output_state(output);
+       struct weston_compositor *compositor = output->compositor;
+       struct gl_renderer *gr = get_renderer(compositor);
+       EGLBoolean ret;
+       static int errored;
+#ifdef EGL_EXT_swap_buffers_with_damage
+       int i, nrects, buffer_height;
+       EGLint *egl_damage, *d;
+       pixman_box32_t *rects;
+#endif
+       pixman_region32_t buffer_damage, total_damage;
+       enum gl_border_status border_damage = BORDER_STATUS_CLEAN;
+
+       if (use_output(output) < 0)
+               return;
+
+       /* Calculate the viewport */
+       glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
+                  go->borders[GL_RENDERER_BORDER_BOTTOM].height,
+                  output->current_mode->width,
+                  output->current_mode->height);
+
+       /* Calculate the global GL matrix */
+       go->output_matrix = output->matrix;
+       weston_matrix_translate(&go->output_matrix,
+                               -(output->current_mode->width / 2.0),
+                               -(output->current_mode->height / 2.0), 0);
+       weston_matrix_scale(&go->output_matrix,
+                           2.0 / output->current_mode->width,
+                           -2.0 / output->current_mode->height, 1);
+
+       /* if debugging, redraw everything outside the damage to clean up
+        * debug lines from the previous draw on this buffer:
+        */
+       if (gr->fan_debug) {
+               pixman_region32_t undamaged;
+               pixman_region32_init(&undamaged);
+               pixman_region32_subtract(&undamaged, &output->region,
+                                        output_damage);
+               gr->fan_debug = 0;
+               repaint_views(output, &undamaged);
+               gr->fan_debug = 1;
+               pixman_region32_fini(&undamaged);
+       }
+
+       pixman_region32_init(&total_damage);
+       pixman_region32_init(&buffer_damage);
+
+       output_get_damage(output, &buffer_damage, &border_damage);
+       output_rotate_damage(output, output_damage, go->border_status);
+
+       pixman_region32_union(&total_damage, &buffer_damage, output_damage);
+       border_damage |= go->border_status;
+
+       repaint_views(output, &total_damage);
+
+       pixman_region32_fini(&total_damage);
+       pixman_region32_fini(&buffer_damage);
+
+       draw_output_borders(output, border_damage);
+
+       pixman_region32_copy(&output->previous_damage, output_damage);
+       wl_signal_emit(&output->frame_signal, output);
+
+#ifdef EGL_EXT_swap_buffers_with_damage
+       if (gr->swap_buffers_with_damage) {
+               pixman_region32_init(&buffer_damage);
+               weston_transformed_region(output->width, output->height,
+                                         output->transform,
+                                         output->current_scale,
+                                         output_damage, &buffer_damage);
+
+               if (output_has_borders(output)) {
+                       pixman_region32_translate(&buffer_damage,
+                                                 go->borders[GL_RENDERER_BORDER_LEFT].width,
+                                                 go->borders[GL_RENDERER_BORDER_TOP].height);
+                       output_get_border_damage(output, go->border_status,
+                                                &buffer_damage);
+               }
+
+               rects = pixman_region32_rectangles(&buffer_damage, &nrects);
+               egl_damage = malloc(nrects * 4 * sizeof(EGLint));
+
+               buffer_height = go->borders[GL_RENDERER_BORDER_TOP].height +
+                               output->current_mode->height +
+                               go->borders[GL_RENDERER_BORDER_BOTTOM].height;
+
+               d = egl_damage;
+               for (i = 0; i < nrects; ++i) {
+                       *d++ = rects[i].x1;
+                       *d++ = buffer_height - rects[i].y2;
+                       *d++ = rects[i].x2 - rects[i].x1;
+                       *d++ = rects[i].y2 - rects[i].y1;
+               }
+               ret = gr->swap_buffers_with_damage(gr->egl_display,
+                                                  go->egl_surface,
+                                                  egl_damage, nrects);
+               free(egl_damage);
+               pixman_region32_fini(&buffer_damage);
+       } else {
+               ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
+       }
+#else /* ! defined EGL_EXT_swap_buffers_with_damage */
+       ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
+#endif
+
+       if (ret == EGL_FALSE && !errored) {
+               errored = 1;
+               weston_log("Failed in eglSwapBuffers.\n");
+               gl_renderer_print_egl_error_state();
+       }
+
+       go->border_status = BORDER_STATUS_CLEAN;
+}
+
+static int
+gl_renderer_read_pixels(struct weston_output *output,
+                              pixman_format_code_t format, void *pixels,
+                              uint32_t x, uint32_t y,
+                              uint32_t width, uint32_t height)
+{
+       GLenum gl_format;
+       struct gl_output_state *go = get_output_state(output);
+
+       x += go->borders[GL_RENDERER_BORDER_LEFT].width;
+       y += go->borders[GL_RENDERER_BORDER_BOTTOM].height;
+
+       switch (format) {
+       case PIXMAN_a8r8g8b8:
+               gl_format = GL_BGRA_EXT;
+               break;
+       case PIXMAN_a8b8g8r8:
+               gl_format = GL_RGBA;
+               break;
+       default:
+               return -1;
+       }
+
+       if (use_output(output) < 0)
+               return -1;
+
+       glPixelStorei(GL_PACK_ALIGNMENT, 1);
+       glReadPixels(x, y, width, height, gl_format,
+                    GL_UNSIGNED_BYTE, pixels);
+
+       return 0;
+}
+
+static void
+gl_renderer_flush_damage(struct weston_surface *surface)
+{
+       struct gl_renderer *gr = get_renderer(surface->compositor);
+       struct gl_surface_state *gs = get_surface_state(surface);
+       struct weston_buffer *buffer = gs->buffer_ref.buffer;
+       struct weston_view *view;
+       bool texture_used;
+
+#ifdef GL_EXT_unpack_subimage
+       pixman_box32_t *rectangles;
+       void *data;
+       int i, n;
+#endif
+
+       pixman_region32_union(&gs->texture_damage,
+                             &gs->texture_damage, &surface->damage);
+
+       if (!buffer)
+               return;
+
+       /* Avoid upload, if the texture won't be used this time.
+        * We still accumulate the damage in texture_damage, and
+        * hold the reference to the buffer, in case the surface
+        * migrates back to the primary plane.
+        */
+       texture_used = false;
+       wl_list_for_each(view, &surface->views, surface_link) {
+               if (view->plane == &surface->compositor->primary_plane) {
+                       texture_used = true;
+                       break;
+               }
+       }
+       if (!texture_used)
+               return;
+
+       if (!pixman_region32_not_empty(&gs->texture_damage) &&
+           !gs->needs_full_upload)
+               goto done;
+
+       glBindTexture(GL_TEXTURE_2D, gs->textures[0]);
+
+       if (!gr->has_unpack_subimage) {
+               wl_shm_buffer_begin_access(buffer->shm_buffer);
+               glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
+                            gs->pitch, buffer->height, 0,
+                            gs->gl_format, gs->gl_pixel_type,
+                            wl_shm_buffer_get_data(buffer->shm_buffer));
+               wl_shm_buffer_end_access(buffer->shm_buffer);
+
+               goto done;
+       }
+
+#ifdef GL_EXT_unpack_subimage
+       glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, gs->pitch);
+       data = wl_shm_buffer_get_data(buffer->shm_buffer);
+
+       if (gs->needs_full_upload) {
+               glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
+               glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
+               wl_shm_buffer_begin_access(buffer->shm_buffer);
+               glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
+                            gs->pitch, buffer->height, 0,
+                            gs->gl_format, gs->gl_pixel_type, data);
+               wl_shm_buffer_end_access(buffer->shm_buffer);
+               goto done;
+       }
+
+       rectangles = pixman_region32_rectangles(&gs->texture_damage, &n);
+       wl_shm_buffer_begin_access(buffer->shm_buffer);
+       for (i = 0; i < n; i++) {
+               pixman_box32_t r;
+
+               r = weston_surface_to_buffer_rect(surface, rectangles[i]);
+
+               glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, r.x1);
+               glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, r.y1);
+               glTexSubImage2D(GL_TEXTURE_2D, 0, r.x1, r.y1,
+                               r.x2 - r.x1, r.y2 - r.y1,
+                               gs->gl_format, gs->gl_pixel_type, data);
+       }
+       wl_shm_buffer_end_access(buffer->shm_buffer);
+#endif
+
+done:
+       pixman_region32_fini(&gs->texture_damage);
+       pixman_region32_init(&gs->texture_damage);
+       gs->needs_full_upload = false;
+
+       weston_buffer_reference(&gs->buffer_ref, NULL);
+}
+
+static void
+ensure_textures(struct gl_surface_state *gs, int num_textures)
+{
+       int i;
+
+       if (num_textures <= gs->num_textures)
+               return;
+
+       for (i = gs->num_textures; i < num_textures; i++) {
+               glGenTextures(1, &gs->textures[i]);
+               glBindTexture(gs->target, gs->textures[i]);
+               glTexParameteri(gs->target,
+                               GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+               glTexParameteri(gs->target,
+                               GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+       }
+       gs->num_textures = num_textures;
+       glBindTexture(gs->target, 0);
+}
+
+static void
+gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
+                      struct wl_shm_buffer *shm_buffer)
+{
+       struct weston_compositor *ec = es->compositor;
+       struct gl_renderer *gr = get_renderer(ec);
+       struct gl_surface_state *gs = get_surface_state(es);
+       GLenum gl_format, gl_pixel_type;
+       int pitch;
+
+       buffer->shm_buffer = shm_buffer;
+       buffer->width = wl_shm_buffer_get_width(shm_buffer);
+       buffer->height = wl_shm_buffer_get_height(shm_buffer);
+
+       switch (wl_shm_buffer_get_format(shm_buffer)) {
+       case WL_SHM_FORMAT_XRGB8888:
+               gs->shader = &gr->texture_shader_rgbx;
+               pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
+               gl_format = GL_BGRA_EXT;
+               gl_pixel_type = GL_UNSIGNED_BYTE;
+               break;
+       case WL_SHM_FORMAT_ARGB8888:
+               gs->shader = &gr->texture_shader_rgba;
+               pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
+               gl_format = GL_BGRA_EXT;
+               gl_pixel_type = GL_UNSIGNED_BYTE;
+               break;
+       case WL_SHM_FORMAT_RGB565:
+               gs->shader = &gr->texture_shader_rgbx;
+               pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
+               gl_format = GL_RGB;
+               gl_pixel_type = GL_UNSIGNED_SHORT_5_6_5;
+               break;
+       default:
+               weston_log("warning: unknown shm buffer format: %08x\n",
+                          wl_shm_buffer_get_format(shm_buffer));
+               return;
+       }
+
+       /* Only allocate a texture if it doesn't match existing one.
+        * If a switch from DRM allocated buffer to a SHM buffer is
+        * happening, we need to allocate a new texture buffer. */
+       if (pitch != gs->pitch ||
+           buffer->height != gs->height ||
+           gl_format != gs->gl_format ||
+           gl_pixel_type != gs->gl_pixel_type ||
+           gs->buffer_type != BUFFER_TYPE_SHM) {
+               gs->pitch = pitch;
+               gs->height = buffer->height;
+               gs->target = GL_TEXTURE_2D;
+               gs->gl_format = gl_format;
+               gs->gl_pixel_type = gl_pixel_type;
+               gs->buffer_type = BUFFER_TYPE_SHM;
+               gs->needs_full_upload = true;
+               gs->y_inverted = 1;
+
+               gs->surface = es;
+
+               ensure_textures(gs, 1);
+       }
+}
+
+static void
+gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
+                      uint32_t format)
+{
+       struct weston_compositor *ec = es->compositor;
+       struct gl_renderer *gr = get_renderer(ec);
+       struct gl_surface_state *gs = get_surface_state(es);
+       EGLint attribs[3];
+       int i, num_planes;
+
+       buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
+       gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
+                        EGL_WIDTH, &buffer->width);
+       gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
+                        EGL_HEIGHT, &buffer->height);
+       gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
+                        EGL_WAYLAND_Y_INVERTED_WL, &buffer->y_inverted);
+
+       for (i = 0; i < gs->num_images; i++) {
+               egl_image_unref(gs->images[i]);
+               gs->images[i] = NULL;
+       }
+       gs->num_images = 0;
+       gs->target = GL_TEXTURE_2D;
+       switch (format) {
+       case EGL_TEXTURE_RGB:
+       case EGL_TEXTURE_RGBA:
+       default:
+               num_planes = 1;
+               gs->shader = &gr->texture_shader_rgba;
+               break;
+       case EGL_TEXTURE_EXTERNAL_WL:
+               num_planes = 1;
+               gs->target = GL_TEXTURE_EXTERNAL_OES;
+               gs->shader = &gr->texture_shader_egl_external;
+               break;
+       case EGL_TEXTURE_Y_UV_WL:
+               num_planes = 2;
+               gs->shader = &gr->texture_shader_y_uv;
+               break;
+       case EGL_TEXTURE_Y_U_V_WL:
+               num_planes = 3;
+               gs->shader = &gr->texture_shader_y_u_v;
+               break;
+       case EGL_TEXTURE_Y_XUXV_WL:
+               num_planes = 2;
+               gs->shader = &gr->texture_shader_y_xuxv;
+               break;
+       }
+
+       ensure_textures(gs, num_planes);
+       for (i = 0; i < num_planes; i++) {
+               attribs[0] = EGL_WAYLAND_PLANE_WL;
+               attribs[1] = i;
+               attribs[2] = EGL_NONE;
+               gs->images[i] = egl_image_create(gr,
+                                                EGL_WAYLAND_BUFFER_WL,
+                                                buffer->legacy_buffer,
+                                                attribs);
+               if (!gs->images[i]) {
+                       weston_log("failed to create img for plane %d\n", i);
+                       continue;
+               }
+               gs->num_images++;
+
+               glActiveTexture(GL_TEXTURE0 + i);
+               glBindTexture(gs->target, gs->textures[i]);
+               gr->image_target_texture_2d(gs->target,
+                                           gs->images[i]->image);
+       }
+
+       gs->pitch = buffer->width;
+       gs->height = buffer->height;
+       gs->buffer_type = BUFFER_TYPE_EGL;
+       gs->y_inverted = buffer->y_inverted;
+}
+
+static void
+gl_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
+{
+       struct dmabuf_image *image = dmabuf->user_data;
+
+       dmabuf_image_destroy(image);
+}
+
+static struct egl_image *
+import_simple_dmabuf(struct gl_renderer *gr,
+                     struct dmabuf_attributes *attributes)
+{
+       struct egl_image *image;
+       EGLint attribs[30];
+       int atti = 0;
+
+       /* This requires the Mesa commit in
+        * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or
+        * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652).
+        * Otherwise Mesa closes the fd behind our back and re-importing
+        * will fail.
+        * https://bugs.freedesktop.org/show_bug.cgi?id=76188
+        */
+
+       attribs[atti++] = EGL_WIDTH;
+       attribs[atti++] = attributes->width;
+       attribs[atti++] = EGL_HEIGHT;
+       attribs[atti++] = attributes->height;
+       attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
+       attribs[atti++] = attributes->format;
+       /* XXX: Add modifier here when supported */
+
+       if (attributes->n_planes > 0) {
+               attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
+               attribs[atti++] = attributes->fd[0];
+               attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
+               attribs[atti++] = attributes->offset[0];
+               attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
+               attribs[atti++] = attributes->stride[0];
+       }
+
+       if (attributes->n_planes > 1) {
+               attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
+               attribs[atti++] = attributes->fd[1];
+               attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
+               attribs[atti++] = attributes->offset[1];
+               attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
+               attribs[atti++] = attributes->stride[1];
+       }
+
+       if (attributes->n_planes > 2) {
+               attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
+               attribs[atti++] = attributes->fd[2];
+               attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
+               attribs[atti++] = attributes->offset[2];
+               attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
+               attribs[atti++] = attributes->stride[2];
+       }
+
+       attribs[atti++] = EGL_NONE;
+
+       image = egl_image_create(gr, EGL_LINUX_DMA_BUF_EXT, NULL,
+                                attribs);
+
+       return image;
+}
+
+/* The kernel header drm_fourcc.h defines the DRM formats below.  We duplicate
+ * some of the definitions here so that building Weston won't require
+ * bleeding-edge kernel headers.
+ */
+#ifndef DRM_FORMAT_R8
+#define DRM_FORMAT_R8            fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
+#endif
+
+#ifndef DRM_FORMAT_GR88
+#define DRM_FORMAT_GR88          fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
+#endif
+
+struct yuv_format_descriptor yuv_formats[] = {
+       {
+               .format = DRM_FORMAT_YUYV,
+               .input_planes = 1,
+               .output_planes = 2,
+               .texture_type = EGL_TEXTURE_Y_XUXV_WL,
+               {{
+                       .width_divisor = 1,
+                       .height_divisor = 1,
+                       .format = DRM_FORMAT_GR88,
+                       .plane_index = 0
+               }, {
+                       .width_divisor = 2,
+                       .height_divisor = 1,
+                       .format = DRM_FORMAT_ARGB8888,
+                       .plane_index = 0
+               }}
+       }, {
+               .format = DRM_FORMAT_NV12,
+               .input_planes = 2,
+               .output_planes = 2,
+               .texture_type = EGL_TEXTURE_Y_UV_WL,
+               {{
+                       .width_divisor = 1,
+                       .height_divisor = 1,
+                       .format = DRM_FORMAT_R8,
+                       .plane_index = 0
+               }, {
+                       .width_divisor = 2,
+                       .height_divisor = 2,
+                       .format = DRM_FORMAT_GR88,
+                       .plane_index = 1
+               }}
+       }, {
+               .format = DRM_FORMAT_YUV420,
+               .input_planes = 3,
+               .output_planes = 3,
+               .texture_type = EGL_TEXTURE_Y_U_V_WL,
+               {{
+                       .width_divisor = 1,
+                       .height_divisor = 1,
+                       .format = DRM_FORMAT_R8,
+                       .plane_index = 0
+               }, {
+                       .width_divisor = 2,
+                       .height_divisor = 2,
+                       .format = DRM_FORMAT_R8,
+                       .plane_index = 1
+               }, {
+                       .width_divisor = 2,
+                       .height_divisor = 2,
+                       .format = DRM_FORMAT_R8,
+                       .plane_index = 2
+               }}
+       }
+};
+
+static struct egl_image *
+import_dmabuf_single_plane(struct gl_renderer *gr,
+                           const struct dmabuf_attributes *attributes,
+                           struct yuv_plane_descriptor *descriptor)
+{
+       struct dmabuf_attributes plane;
+       struct egl_image *image;
+       char fmt[4];
+
+       plane.width = attributes->width / descriptor->width_divisor;
+       plane.height = attributes->height / descriptor->height_divisor;
+       plane.format = descriptor->format;
+       plane.n_planes = 1;
+       plane.fd[0] = attributes->fd[descriptor->plane_index];
+       plane.offset[0] = attributes->offset[descriptor->plane_index];
+       plane.stride[0] = attributes->stride[descriptor->plane_index];
+       plane.modifier[0] = attributes->modifier[descriptor->plane_index];
+
+       image = import_simple_dmabuf(gr, &plane);
+       if (!image) {
+               weston_log("Failed to import plane %d as %.4s\n",
+                          descriptor->plane_index,
+                          dump_format(descriptor->format, fmt));
+               return NULL;
+       }
+
+       return image;
+}
+
+static bool
+import_yuv_dmabuf(struct gl_renderer *gr,
+                  struct dmabuf_image *image)
+{
+       unsigned i;
+       int j;
+       int ret;
+       struct yuv_format_descriptor *format = NULL;
+       struct dmabuf_attributes *attributes = &image->dmabuf->attributes;
+       char fmt[4];
+
+       for (i = 0; i < ARRAY_LENGTH(yuv_formats); ++i) {
+               if (yuv_formats[i].format == attributes->format) {
+                       format = &yuv_formats[i];
+                       break;
+               }
+       }
+
+       if (!format) {
+               weston_log("Error during import, and no known conversion for format "
+                          "%.4s in the renderer",
+                          dump_format(attributes->format, fmt));
+               return false;
+       }
+
+       if (attributes->n_planes != format->input_planes) {
+               weston_log("%.4s dmabuf must contain %d plane%s (%d provided)",
+                          dump_format(format->format, fmt),
+                          format->input_planes,
+                          (format->input_planes > 1) ? "s" : "",
+                          attributes->n_planes);
+               return false;
+       }
+
+       for (j = 0; j < format->output_planes; ++j) {
+               image->images[j] = import_dmabuf_single_plane(gr, attributes,
+                                                             &format->plane[j]);
+               if (!image->images[j]) {
+                       while (j) {
+                               ret = egl_image_unref(image->images[--j]);
+                               assert(ret == 0);
+                       }
+                       return false;
+               }
+       }
+
+       image->num_images = format->output_planes;
+
+       switch (format->texture_type) {
+       case EGL_TEXTURE_Y_XUXV_WL:
+               image->shader = &gr->texture_shader_y_xuxv;
+               break;
+       case EGL_TEXTURE_Y_UV_WL:
+               image->shader = &gr->texture_shader_y_uv;
+               break;
+       case EGL_TEXTURE_Y_U_V_WL:
+               image->shader = &gr->texture_shader_y_u_v;
+               break;
+       default:
+               assert(false);
+       }
+
+       return true;
+}
+
+static GLenum
+choose_texture_target(struct dmabuf_attributes *attributes)
+{
+       if (attributes->n_planes > 1)
+               return GL_TEXTURE_EXTERNAL_OES;
+
+       switch (attributes->format & ~DRM_FORMAT_BIG_ENDIAN) {
+       case DRM_FORMAT_YUYV:
+       case DRM_FORMAT_YVYU:
+       case DRM_FORMAT_UYVY:
+       case DRM_FORMAT_VYUY:
+       case DRM_FORMAT_AYUV:
+               return GL_TEXTURE_EXTERNAL_OES;
+       default:
+               return GL_TEXTURE_2D;
+       }
+}
+
+static struct dmabuf_image *
+import_dmabuf(struct gl_renderer *gr,
+             struct linux_dmabuf_buffer *dmabuf)
+{
+       struct egl_image *egl_image;
+       struct dmabuf_image *image;
+
+       image = dmabuf_image_create();
+       image->dmabuf = dmabuf;
+
+       egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
+       if (egl_image) {
+               image->num_images = 1;
+               image->images[0] = egl_image;
+               image->import_type = IMPORT_TYPE_DIRECT;
+               image->target = choose_texture_target(&dmabuf->attributes);
+
+               switch (image->target) {
+               case GL_TEXTURE_2D:
+                       image->shader = &gr->texture_shader_rgba;
+                       break;
+               default:
+                       image->shader = &gr->texture_shader_egl_external;
+               }
+       } else {
+               if (!import_yuv_dmabuf(gr, image)) {
+                       dmabuf_image_destroy(image);
+                       return NULL;
+               }
+               image->import_type = IMPORT_TYPE_GL_CONVERSION;
+               image->target = GL_TEXTURE_2D;
+       }
+
+       return image;
+}
+
+static bool
+gl_renderer_import_dmabuf(struct weston_compositor *ec,
+                         struct linux_dmabuf_buffer *dmabuf)
+{
+       struct gl_renderer *gr = get_renderer(ec);
+       struct dmabuf_image *image;
+       int i;
+
+       assert(gr->has_dmabuf_import);
+
+       for (i = 0; i < dmabuf->attributes.n_planes; i++) {
+               /* EGL import does not have modifiers */
+               if (dmabuf->attributes.modifier[i] != 0)
+                       return false;
+       }
+
+       /* reject all flags we do not recognize or handle */
+       if (dmabuf->attributes.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
+               return false;
+
+       image = import_dmabuf(gr, dmabuf);
+       if (!image)
+               return false;
+
+       wl_list_insert(&gr->dmabuf_images, &image->link);
+       linux_dmabuf_buffer_set_user_data(dmabuf, image,
+               gl_renderer_destroy_dmabuf);
+
+       return true;
+}
+
+static bool
+import_known_dmabuf(struct gl_renderer *gr,
+                    struct dmabuf_image *image)
+{
+       switch (image->import_type) {
+       case IMPORT_TYPE_DIRECT:
+               image->images[0] = import_simple_dmabuf(gr, &image->dmabuf->attributes);
+               if (!image->images[0])
+                       return false;
+               break;
+
+       case IMPORT_TYPE_GL_CONVERSION:
+               if (!import_yuv_dmabuf(gr, image))
+                       return false;
+               break;
+
+       default:
+               weston_log("Invalid import type for dmabuf\n");
+               return false;
+       }
+
+       return true;
+}
+
+static void
+gl_renderer_attach_dmabuf(struct weston_surface *surface,
+                         struct weston_buffer *buffer,
+                         struct linux_dmabuf_buffer *dmabuf)
+{
+       struct gl_renderer *gr = get_renderer(surface->compositor);
+       struct gl_surface_state *gs = get_surface_state(surface);
+       struct dmabuf_image *image;
+       int i;
+       int ret;
+
+       if (!gr->has_dmabuf_import) {
+               linux_dmabuf_buffer_send_server_error(dmabuf,
+                               "EGL dmabuf import not supported");
+               return;
+       }
+
+       buffer->width = dmabuf->attributes.width;
+       buffer->height = dmabuf->attributes.height;
+       buffer->y_inverted =
+               !!(dmabuf->attributes.flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT);
+
+       for (i = 0; i < gs->num_images; i++)
+               egl_image_unref(gs->images[i]);
+       gs->num_images = 0;
+
+       /*
+        * We try to always hold an imported EGLImage from the dmabuf
+        * to prevent the client from preventing re-imports. But, we also
+        * need to re-import every time the contents may change because
+        * GL driver's caching may need flushing.
+        *
+        * Here we release the cache reference which has to be final.
+        */
+       image = linux_dmabuf_buffer_get_user_data(dmabuf);
+
+       /* The dmabuf_image should have been created during the import */
+       assert(image != NULL);
+
+       for (i = 0; i < image->num_images; ++i) {
+               ret = egl_image_unref(image->images[i]);
+               assert(ret == 0);
+       }
+
+       if (!import_known_dmabuf(gr, image)) {
+               linux_dmabuf_buffer_send_server_error(dmabuf, "EGL dmabuf import failed");
+               return;
+       }
+
+       gs->num_images = image->num_images;
+       for (i = 0; i < gs->num_images; ++i)
+               gs->images[i] = egl_image_ref(image->images[i]);
+
+       gs->target = image->target;
+       ensure_textures(gs, gs->num_images);
+       for (i = 0; i < gs->num_images; ++i) {
+               glActiveTexture(GL_TEXTURE0 + i);
+               glBindTexture(gs->target, gs->textures[i]);
+               gr->image_target_texture_2d(gs->target, gs->images[i]->image);
+       }
+
+       gs->shader = image->shader;
+       gs->pitch = buffer->width;
+       gs->height = buffer->height;
+       gs->buffer_type = BUFFER_TYPE_EGL;
+       gs->y_inverted = buffer->y_inverted;
+}
+
+static void
+gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+{
+       struct weston_compositor *ec = es->compositor;
+       struct gl_renderer *gr = get_renderer(ec);
+       struct gl_surface_state *gs = get_surface_state(es);
+       struct wl_shm_buffer *shm_buffer;
+       struct linux_dmabuf_buffer *dmabuf;
+       EGLint format;
+       int i;
+
+       weston_buffer_reference(&gs->buffer_ref, buffer);
+
+       if (!buffer) {
+               for (i = 0; i < gs->num_images; i++) {
+                       egl_image_unref(gs->images[i]);
+                       gs->images[i] = NULL;
+               }
+               gs->num_images = 0;
+               glDeleteTextures(gs->num_textures, gs->textures);
+               gs->num_textures = 0;
+               gs->buffer_type = BUFFER_TYPE_NULL;
+               gs->y_inverted = 1;
+               return;
+       }
+
+       shm_buffer = wl_shm_buffer_get(buffer->resource);
+
+       if (shm_buffer)
+               gl_renderer_attach_shm(es, buffer, shm_buffer);
+       else if (gr->query_buffer(gr->egl_display, (void *) buffer->resource,
+                                 EGL_TEXTURE_FORMAT, &format))
+               gl_renderer_attach_egl(es, buffer, format);
+       else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource)))
+               gl_renderer_attach_dmabuf(es, buffer, dmabuf);
+       else {
+               weston_log("unhandled buffer type!\n");
+               weston_buffer_reference(&gs->buffer_ref, NULL);
+               gs->buffer_type = BUFFER_TYPE_NULL;
+               gs->y_inverted = 1;
+       }
+}
+
+static void
+gl_renderer_surface_set_color(struct weston_surface *surface,
+                float red, float green, float blue, float alpha)
+{
+       struct gl_surface_state *gs = get_surface_state(surface);
+       struct gl_renderer *gr = get_renderer(surface->compositor);
+
+       gs->color[0] = red;
+       gs->color[1] = green;
+       gs->color[2] = blue;
+       gs->color[3] = alpha;
+       gs->buffer_type = BUFFER_TYPE_SOLID;
+       gs->pitch = 1;
+       gs->height = 1;
+
+       gs->shader = &gr->solid_shader;
+}
+
+static void
+gl_renderer_surface_get_content_size(struct weston_surface *surface,
+                                    int *width, int *height)
+{
+       struct gl_surface_state *gs = get_surface_state(surface);
+
+       if (gs->buffer_type == BUFFER_TYPE_NULL) {
+               *width = 0;
+               *height = 0;
+       } else {
+               *width = gs->pitch;
+               *height = gs->height;
+       }
+}
+
+static uint32_t
+pack_color(pixman_format_code_t format, float *c)
+{
+       uint8_t r = round(c[0] * 255.0f);
+       uint8_t g = round(c[1] * 255.0f);
+       uint8_t b = round(c[2] * 255.0f);
+       uint8_t a = round(c[3] * 255.0f);
+
+       switch (format) {
+       case PIXMAN_a8b8g8r8:
+               return (a << 24) | (b << 16) | (g << 8) | r;
+       default:
+               assert(0);
+               return 0;
+       }
+}
+
+static int
+gl_renderer_surface_copy_content(struct weston_surface *surface,
+                                void *target, size_t size,
+                                int src_x, int src_y,
+                                int width, int height)
+{
+       static const GLfloat verts[4 * 2] = {
+               0.0f, 0.0f,
+               1.0f, 0.0f,
+               1.0f, 1.0f,
+               0.0f, 1.0f
+       };
+       static const GLfloat projmat_normal[16] = { /* transpose */
+                2.0f,  0.0f, 0.0f, 0.0f,
+                0.0f,  2.0f, 0.0f, 0.0f,
+                0.0f,  0.0f, 1.0f, 0.0f,
+               -1.0f, -1.0f, 0.0f, 1.0f
+       };
+       static const GLfloat projmat_yinvert[16] = { /* transpose */
+                2.0f,  0.0f, 0.0f, 0.0f,
+                0.0f, -2.0f, 0.0f, 0.0f,
+                0.0f,  0.0f, 1.0f, 0.0f,
+               -1.0f,  1.0f, 0.0f, 1.0f
+       };
+       const pixman_format_code_t format = PIXMAN_a8b8g8r8;
+       const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
+       const GLenum gl_format = GL_RGBA; /* PIXMAN_a8b8g8r8 little-endian */
+       struct gl_renderer *gr = get_renderer(surface->compositor);
+       struct gl_surface_state *gs = get_surface_state(surface);
+       int cw, ch;
+       GLuint fbo;
+       GLuint tex;
+       GLenum status;
+       const GLfloat *proj;
+       int i;
+
+       gl_renderer_surface_get_content_size(surface, &cw, &ch);
+
+       switch (gs->buffer_type) {
+       case BUFFER_TYPE_NULL:
+               return -1;
+       case BUFFER_TYPE_SOLID:
+               *(uint32_t *)target = pack_color(format, gs->color);
+               return 0;
+       case BUFFER_TYPE_SHM:
+               gl_renderer_flush_damage(surface);
+               /* fall through */
+       case BUFFER_TYPE_EGL:
+               break;
+       }
+
+       glGenTextures(1, &tex);
+       glBindTexture(GL_TEXTURE_2D, tex);
+       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cw, ch,
+                    0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
+       glBindTexture(GL_TEXTURE_2D, 0);
+
+       glGenFramebuffers(1, &fbo);
+       glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                              GL_TEXTURE_2D, tex, 0);
+
+       status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+       if (status != GL_FRAMEBUFFER_COMPLETE) {
+               weston_log("%s: fbo error: %#x\n", __func__, status);
+               glDeleteFramebuffers(1, &fbo);
+               glDeleteTextures(1, &tex);
+               return -1;
+       }
+
+       glViewport(0, 0, cw, ch);
+       glDisable(GL_BLEND);
+       use_shader(gr, gs->shader);
+       if (gs->y_inverted)
+               proj = projmat_normal;
+       else
+               proj = projmat_yinvert;
+
+       glUniformMatrix4fv(gs->shader->proj_uniform, 1, GL_FALSE, proj);
+       glUniform1f(gs->shader->alpha_uniform, 1.0f);
+
+       for (i = 0; i < gs->num_textures; i++) {
+               glUniform1i(gs->shader->tex_uniforms[i], i);
+
+               glActiveTexture(GL_TEXTURE0 + i);
+               glBindTexture(gs->target, gs->textures[i]);
+               glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+               glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+       }
+
+       /* position: */
+       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
+       glEnableVertexAttribArray(0);
+
+       /* texcoord: */
+       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, verts);
+       glEnableVertexAttribArray(1);
+
+       glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+       glDisableVertexAttribArray(1);
+       glDisableVertexAttribArray(0);
+
+       glPixelStorei(GL_PACK_ALIGNMENT, bytespp);
+       glReadPixels(src_x, src_y, width, height, gl_format,
+                    GL_UNSIGNED_BYTE, target);
+
+       glDeleteFramebuffers(1, &fbo);
+       glDeleteTextures(1, &tex);
+
+       return 0;
+}
+
+static void
+surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
+{
+       int i;
+
+       wl_list_remove(&gs->surface_destroy_listener.link);
+       wl_list_remove(&gs->renderer_destroy_listener.link);
+
+       gs->surface->renderer_state = NULL;
+
+       glDeleteTextures(gs->num_textures, gs->textures);
+
+       for (i = 0; i < gs->num_images; i++)
+               egl_image_unref(gs->images[i]);
+
+       weston_buffer_reference(&gs->buffer_ref, NULL);
+       pixman_region32_fini(&gs->texture_damage);
+       free(gs);
+}
+
+static void
+surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+       struct gl_surface_state *gs;
+       struct gl_renderer *gr;
+
+       gs = container_of(listener, struct gl_surface_state,
+                         surface_destroy_listener);
+
+       gr = get_renderer(gs->surface->compositor);
+
+       surface_state_destroy(gs, gr);
+}
+
+static void
+surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
+{
+       struct gl_surface_state *gs;
+       struct gl_renderer *gr;
+
+       gr = data;
+
+       gs = container_of(listener, struct gl_surface_state,
+                         renderer_destroy_listener);
+
+       surface_state_destroy(gs, gr);
+}
+
+static int
+gl_renderer_create_surface(struct weston_surface *surface)
+{
+       struct gl_surface_state *gs;
+       struct gl_renderer *gr = get_renderer(surface->compositor);
+
+       gs = zalloc(sizeof *gs);
+       if (gs == NULL)
+               return -1;
+
+       /* A buffer is never attached to solid color surfaces, yet
+        * they still go through texcoord computations. Do not divide
+        * by zero there.
+        */
+       gs->pitch = 1;
+       gs->y_inverted = 1;
+
+       gs->surface = surface;
+
+       pixman_region32_init(&gs->texture_damage);
+       surface->renderer_state = gs;
+
+       gs->surface_destroy_listener.notify =
+               surface_state_handle_surface_destroy;
+       wl_signal_add(&surface->destroy_signal,
+                     &gs->surface_destroy_listener);
+
+       gs->renderer_destroy_listener.notify =
+               surface_state_handle_renderer_destroy;
+       wl_signal_add(&gr->destroy_signal,
+                     &gs->renderer_destroy_listener);
+
+       if (surface->buffer_ref.buffer) {
+               gl_renderer_attach(surface, surface->buffer_ref.buffer);
+               gl_renderer_flush_damage(surface);
+       }
+
+       return 0;
+}
+
+static const char vertex_shader[] =
+       "uniform mat4 proj;\n"
+       "attribute vec2 position;\n"
+       "attribute vec2 texcoord;\n"
+       "varying vec2 v_texcoord;\n"
+       "void main()\n"
+       "{\n"
+       "   gl_Position = proj * vec4(position, 0.0, 1.0);\n"
+       "   v_texcoord = texcoord;\n"
+       "}\n";
+
+/* Declare common fragment shader uniforms */
+#define FRAGMENT_CONVERT_YUV                                           \
+       "  y *= alpha;\n"                                               \
+       "  u *= alpha;\n"                                               \
+       "  v *= alpha;\n"                                               \
+       "  gl_FragColor.r = y + 1.59602678 * v;\n"                      \
+       "  gl_FragColor.g = y - 0.39176229 * u - 0.81296764 * v;\n"     \
+       "  gl_FragColor.b = y + 2.01723214 * u;\n"                      \
+       "  gl_FragColor.a = alpha;\n"
+
+static const char fragment_debug[] =
+       "  gl_FragColor = vec4(0.0, 0.3, 0.0, 0.2) + gl_FragColor * 0.8;\n";
+
+static const char fragment_brace[] =
+       "}\n";
+
+static const char texture_fragment_shader_rgba[] =
+       "precision mediump float;\n"
+       "varying vec2 v_texcoord;\n"
+       "uniform sampler2D tex;\n"
+       "uniform float alpha;\n"
+       "void main()\n"
+       "{\n"
+       "   gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
+       ;
+
+static const char texture_fragment_shader_rgbx[] =
+       "precision mediump float;\n"
+       "varying vec2 v_texcoord;\n"
+       "uniform sampler2D tex;\n"
+       "uniform float alpha;\n"
+       "void main()\n"
+       "{\n"
+       "   gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb\n;"
+       "   gl_FragColor.a = alpha;\n"
+       ;
+
+static const char texture_fragment_shader_egl_external[] =
+       "#extension GL_OES_EGL_image_external : require\n"
+       "precision mediump float;\n"
+       "varying vec2 v_texcoord;\n"
+       "uniform samplerExternalOES tex;\n"
+       "uniform float alpha;\n"
+       "void main()\n"
+       "{\n"
+       "   gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
+       ;
+
+static const char texture_fragment_shader_y_uv[] =
+       "precision mediump float;\n"
+       "uniform sampler2D tex;\n"
+       "uniform sampler2D tex1;\n"
+       "varying vec2 v_texcoord;\n"
+       "uniform float alpha;\n"
+       "void main() {\n"
+       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
+       "  float u = texture2D(tex1, v_texcoord).r - 0.5;\n"
+       "  float v = texture2D(tex1, v_texcoord).g - 0.5;\n"
+       FRAGMENT_CONVERT_YUV
+       ;
+
+static const char texture_fragment_shader_y_u_v[] =
+       "precision mediump float;\n"
+       "uniform sampler2D tex;\n"
+       "uniform sampler2D tex1;\n"
+       "uniform sampler2D tex2;\n"
+       "varying vec2 v_texcoord;\n"
+       "uniform float alpha;\n"
+       "void main() {\n"
+       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
+       "  float u = texture2D(tex1, v_texcoord).x - 0.5;\n"
+       "  float v = texture2D(tex2, v_texcoord).x - 0.5;\n"
+       FRAGMENT_CONVERT_YUV
+       ;
+
+static const char texture_fragment_shader_y_xuxv[] =
+       "precision mediump float;\n"
+       "uniform sampler2D tex;\n"
+       "uniform sampler2D tex1;\n"
+       "varying vec2 v_texcoord;\n"
+       "uniform float alpha;\n"
+       "void main() {\n"
+       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
+       "  float u = texture2D(tex1, v_texcoord).g - 0.5;\n"
+       "  float v = texture2D(tex1, v_texcoord).a - 0.5;\n"
+       FRAGMENT_CONVERT_YUV
+       ;
+
+static const char solid_fragment_shader[] =
+       "precision mediump float;\n"
+       "uniform vec4 color;\n"
+       "uniform float alpha;\n"
+       "void main()\n"
+       "{\n"
+       "   gl_FragColor = alpha * color\n;"
+       ;
+
+static int
+compile_shader(GLenum type, int count, const char **sources)
+{
+       GLuint s;
+       char msg[512];
+       GLint status;
+
+       s = glCreateShader(type);
+       glShaderSource(s, count, sources, NULL);
+       glCompileShader(s);
+       glGetShaderiv(s, GL_COMPILE_STATUS, &status);
+       if (!status) {
+               glGetShaderInfoLog(s, sizeof msg, NULL, msg);
+               weston_log("shader info: %s\n", msg);
+               return GL_NONE;
+       }
+
+       return s;
+}
+
+static int
+shader_init(struct gl_shader *shader, struct gl_renderer *renderer,
+                  const char *vertex_source, const char *fragment_source)
+{
+       char msg[512];
+       GLint status;
+       int count;
+       const char *sources[3];
+
+       shader->vertex_shader =
+               compile_shader(GL_VERTEX_SHADER, 1, &vertex_source);
+
+       if (renderer->fragment_shader_debug) {
+               sources[0] = fragment_source;
+               sources[1] = fragment_debug;
+               sources[2] = fragment_brace;
+               count = 3;
+       } else {
+               sources[0] = fragment_source;
+               sources[1] = fragment_brace;
+               count = 2;
+       }
+
+       shader->fragment_shader =
+               compile_shader(GL_FRAGMENT_SHADER, count, sources);
+
+       shader->program = glCreateProgram();
+       glAttachShader(shader->program, shader->vertex_shader);
+       glAttachShader(shader->program, shader->fragment_shader);
+       glBindAttribLocation(shader->program, 0, "position");
+       glBindAttribLocation(shader->program, 1, "texcoord");
+
+       glLinkProgram(shader->program);
+       glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
+       if (!status) {
+               glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg);
+               weston_log("link info: %s\n", msg);
+               return -1;
+       }
+
+       shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
+       shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
+       shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
+       shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");
+       shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
+       shader->color_uniform = glGetUniformLocation(shader->program, "color");
+
+       return 0;
+}
+
+static void
+shader_release(struct gl_shader *shader)
+{
+       glDeleteShader(shader->vertex_shader);
+       glDeleteShader(shader->fragment_shader);
+       glDeleteProgram(shader->program);
+
+       shader->vertex_shader = 0;
+       shader->fragment_shader = 0;
+       shader->program = 0;
+}
+
+static void
+log_extensions(const char *name, const char *extensions)
+{
+       const char *p, *end;
+       int l;
+       int len;
+
+       l = weston_log("%s:", name);
+       p = extensions;
+       while (*p) {
+               end = strchrnul(p, ' ');
+               len = end - p;
+               if (l + len > 78)
+                       l = weston_log_continue("\n" STAMP_SPACE "%.*s",
+                                               len, p);
+               else
+                       l += weston_log_continue(" %.*s", len, p);
+               for (p = end; isspace(*p); p++)
+                       ;
+       }
+       weston_log_continue("\n");
+}
+
+static void
+log_egl_gl_info(EGLDisplay egldpy)
+{
+       const char *str;
+
+       str = eglQueryString(egldpy, EGL_VERSION);
+       weston_log("EGL version: %s\n", str ? str : "(null)");
+
+       str = eglQueryString(egldpy, EGL_VENDOR);
+       weston_log("EGL vendor: %s\n", str ? str : "(null)");
+
+       str = eglQueryString(egldpy, EGL_CLIENT_APIS);
+       weston_log("EGL client APIs: %s\n", str ? str : "(null)");
+
+       str = eglQueryString(egldpy, EGL_EXTENSIONS);
+       log_extensions("EGL extensions", str ? str : "(null)");
+
+       str = (char *)glGetString(GL_VERSION);
+       weston_log("GL version: %s\n", str ? str : "(null)");
+
+       str = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
+       weston_log("GLSL version: %s\n", str ? str : "(null)");
+
+       str = (char *)glGetString(GL_VENDOR);
+       weston_log("GL vendor: %s\n", str ? str : "(null)");
+
+       str = (char *)glGetString(GL_RENDERER);
+       weston_log("GL renderer: %s\n", str ? str : "(null)");
+
+       str = (char *)glGetString(GL_EXTENSIONS);
+       log_extensions("GL extensions", str ? str : "(null)");
+}
+
+static void
+log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig)
+{
+       EGLint r, g, b, a;
+
+       weston_log("Chosen EGL config details:\n");
+
+       weston_log_continue(STAMP_SPACE "RGBA bits");
+       if (eglGetConfigAttrib(egldpy, eglconfig, EGL_RED_SIZE, &r) &&
+           eglGetConfigAttrib(egldpy, eglconfig, EGL_GREEN_SIZE, &g) &&
+           eglGetConfigAttrib(egldpy, eglconfig, EGL_BLUE_SIZE, &b) &&
+           eglGetConfigAttrib(egldpy, eglconfig, EGL_ALPHA_SIZE, &a))
+               weston_log_continue(": %d %d %d %d\n", r, g, b, a);
+       else
+               weston_log_continue(" unknown\n");
+
+       weston_log_continue(STAMP_SPACE "swap interval range");
+       if (eglGetConfigAttrib(egldpy, eglconfig, EGL_MIN_SWAP_INTERVAL, &a) &&
+           eglGetConfigAttrib(egldpy, eglconfig, EGL_MAX_SWAP_INTERVAL, &b))
+               weston_log_continue(": %d - %d\n", a, b);
+       else
+               weston_log_continue(" unknown\n");
+}
+
+static int
+match_config_to_visual(EGLDisplay egl_display,
+                      EGLint visual_id,
+                      EGLConfig *configs,
+                      int count)
+{
+       int i;
+
+       for (i = 0; i < count; ++i) {
+               EGLint id;
+
+               if (!eglGetConfigAttrib(egl_display,
+                               configs[i], EGL_NATIVE_VISUAL_ID,
+                               &id))
+                       continue;
+
+               if (id == visual_id)
+                       return i;
+       }
+
+       return -1;
+}
+
+static int
+egl_choose_config(struct gl_renderer *gr, const EGLint *attribs,
+                 const EGLint *visual_id, const int n_ids,
+                 EGLConfig *config_out)
+{
+       EGLint count = 0;
+       EGLint matched = 0;
+       EGLConfig *configs;
+       int i, config_index = -1;
+
+       if (!eglGetConfigs(gr->egl_display, NULL, 0, &count) || count < 1) {
+               weston_log("No EGL configs to choose from.\n");
+               return -1;
+       }
+       configs = calloc(count, sizeof *configs);
+       if (!configs)
+               return -1;
+
+       if (!eglChooseConfig(gr->egl_display, attribs, configs,
+                             count, &matched) || !matched) {
+               weston_log("No EGL configs with appropriate attributes.\n");
+               goto out;
+       }
+
+       if (!visual_id)
+               config_index = 0;
+
+       for (i = 0; config_index == -1 && i < n_ids; i++)
+               config_index = match_config_to_visual(gr->egl_display,
+                                                     visual_id[i],
+                                                     configs,
+                                                     matched);
+
+       if (config_index != -1)
+               *config_out = configs[config_index];
+
+out:
+       free(configs);
+       if (config_index == -1)
+               return -1;
+
+       if (i > 1)
+               weston_log("Unable to use first choice EGL config with id"
+                          " 0x%x, succeeded with alternate id 0x%x.\n",
+                          visual_id[0], visual_id[i - 1]);
+       return 0;
+}
+
+static void
+gl_renderer_output_set_border(struct weston_output *output,
+                             enum gl_renderer_border_side side,
+                             int32_t width, int32_t height,
+                             int32_t tex_width, unsigned char *data)
+{
+       struct gl_output_state *go = get_output_state(output);
+
+       if (go->borders[side].width != width ||
+           go->borders[side].height != height)
+               /* In this case, we have to blow everything and do a full
+                * repaint. */
+               go->border_status |= BORDER_SIZE_CHANGED | BORDER_ALL_DIRTY;
+
+       if (data == NULL) {
+               width = 0;
+               height = 0;
+       }
+
+       go->borders[side].width = width;
+       go->borders[side].height = height;
+       go->borders[side].tex_width = tex_width;
+       go->borders[side].data = data;
+       go->border_status |= 1 << side;
+}
+
+static int
+gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface);
+
+static int
+gl_renderer_output_create(struct weston_output *output,
+                         EGLNativeWindowType window_for_legacy,
+                         void *window_for_platform,
+                         const EGLint *attribs,
+                         const EGLint *visual_id,
+                         int n_ids)
+{
+       struct weston_compositor *ec = output->compositor;
+       struct gl_renderer *gr = get_renderer(ec);
+       struct gl_output_state *go;
+       EGLConfig egl_config;
+       int i;
+
+       if (egl_choose_config(gr, attribs, visual_id,
+                             n_ids, &egl_config) == -1) {
+               weston_log("failed to choose EGL config for output\n");
+               return -1;
+       }
+
+       if (egl_config != gr->egl_config &&
+           !gr->has_configless_context) {
+               weston_log("attempted to use a different EGL config for an "
+                          "output but EGL_MESA_configless_context is not "
+                          "supported\n");
+               return -1;
+       }
+
+       go = zalloc(sizeof *go);
+       if (go == NULL)
+               return -1;
+
+       if (gr->create_platform_window) {
+               go->egl_surface =
+                       gr->create_platform_window(gr->egl_display,
+                                                  egl_config,
+                                                  window_for_platform,
+                                                  NULL);
+       } else {
+               go->egl_surface =
+                       eglCreateWindowSurface(gr->egl_display,
+                                              egl_config,
+                                              window_for_legacy, NULL);
+       }
+
+       if (go->egl_surface == EGL_NO_SURFACE) {
+               weston_log("failed to create egl surface\n");
+               free(go);
+               return -1;
+       }
+
+       if (gr->egl_context == NULL)
+               if (gl_renderer_setup(ec, go->egl_surface) < 0) {
+                       free(go);
+                       return -1;
+               }
+
+       for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
+               pixman_region32_init(&go->buffer_damage[i]);
+
+       output->renderer_state = go;
+
+       log_egl_config_info(gr->egl_display, egl_config);
+
+       return 0;
+}
+
+static void
+gl_renderer_output_destroy(struct weston_output *output)
+{
+       struct gl_renderer *gr = get_renderer(output->compositor);
+       struct gl_output_state *go = get_output_state(output);
+       int i;
+
+       for (i = 0; i < 2; i++)
+               pixman_region32_fini(&go->buffer_damage[i]);
+
+       eglDestroySurface(gr->egl_display, go->egl_surface);
+
+       free(go);
+}
+
+static EGLSurface
+gl_renderer_output_surface(struct weston_output *output)
+{
+       return get_output_state(output)->egl_surface;
+}
+
+static void
+gl_renderer_destroy(struct weston_compositor *ec)
+{
+       struct gl_renderer *gr = get_renderer(ec);
+       struct dmabuf_image *image, *next;
+
+       wl_signal_emit(&gr->destroy_signal, gr);
+
+       if (gr->has_bind_display)
+               gr->unbind_display(gr->egl_display, ec->wl_display);
+
+       /* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */
+       eglMakeCurrent(gr->egl_display,
+                      EGL_NO_SURFACE, EGL_NO_SURFACE,
+                      EGL_NO_CONTEXT);
+
+
+       wl_list_for_each_safe(image, next, &gr->dmabuf_images, link)
+               dmabuf_image_destroy(image);
+
+       eglTerminate(gr->egl_display);
+       eglReleaseThread();
+
+       wl_array_release(&gr->vertices);
+       wl_array_release(&gr->vtxcnt);
+
+       if (gr->fragment_binding)
+               weston_binding_destroy(gr->fragment_binding);
+       if (gr->fan_binding)
+               weston_binding_destroy(gr->fan_binding);
+
+       free(gr);
+}
+
+static bool
+check_extension(const char *extensions, const char *extension)
+{
+       size_t extlen = strlen(extension);
+       const char *end = extensions + strlen(extensions);
+
+       while (extensions < end) {
+               size_t n = 0;
+
+               /* Skip whitespaces, if any */
+               if (*extensions == ' ') {
+                       extensions++;
+                       continue;
+               }
+
+               n = strcspn(extensions, " ");
+
+               /* Compare strings */
+               if (n == extlen && strncmp(extension, extensions, n) == 0)
+                       return true; /* Found */
+
+               extensions += n;
+       }
+
+       /* Not found */
+       return false;
+}
+
+static void
+renderer_setup_egl_client_extensions(struct gl_renderer *gr)
+{
+       const char *extensions;
+
+       extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+       if (!extensions) {
+               weston_log("Retrieving EGL client extension string failed.\n");
+               return;
+       }
+
+       if (check_extension(extensions, "EGL_EXT_platform_base"))
+               gr->create_platform_window =
+                       (void *) eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
+       else
+               weston_log("warning: EGL_EXT_platform_base not supported.\n");
+}
+
+static int
+gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
+{
+       struct gl_renderer *gr = get_renderer(ec);
+       const char *extensions;
+       EGLBoolean ret;
+
+       gr->create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
+       gr->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
+       gr->bind_display =
+               (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
+       gr->unbind_display =
+               (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
+       gr->query_buffer =
+               (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
+
+       extensions =
+               (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
+       if (!extensions) {
+               weston_log("Retrieving EGL extension string failed.\n");
+               return -1;
+       }
+
+       if (check_extension(extensions, "EGL_WL_bind_wayland_display"))
+               gr->has_bind_display = 1;
+       if (gr->has_bind_display) {
+               ret = gr->bind_display(gr->egl_display, ec->wl_display);
+               if (!ret)
+                       gr->has_bind_display = 0;
+       }
+
+       if (check_extension(extensions, "EGL_EXT_buffer_age"))
+               gr->has_egl_buffer_age = 1;
+       else
+               weston_log("warning: EGL_EXT_buffer_age not supported. "
+                          "Performance could be affected.\n");
+
+#ifdef EGL_EXT_swap_buffers_with_damage
+       if (check_extension(extensions, "EGL_EXT_swap_buffers_with_damage"))
+               gr->swap_buffers_with_damage =
+                       (void *) eglGetProcAddress("eglSwapBuffersWithDamageEXT");
+       else
+               weston_log("warning: EGL_EXT_swap_buffers_with_damage not "
+                          "supported. Performance could be affected.\n");
+#endif
+
+#ifdef EGL_MESA_configless_context
+       if (check_extension(extensions, "EGL_MESA_configless_context"))
+               gr->has_configless_context = 1;
+#endif
+
+#ifdef EGL_EXT_image_dma_buf_import
+       if (check_extension(extensions, "EGL_EXT_image_dma_buf_import"))
+               gr->has_dmabuf_import = 1;
+#endif
+
+       renderer_setup_egl_client_extensions(gr);
+
+       return 0;
+}
+
+static const EGLint gl_renderer_opaque_attribs[] = {
+       EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+       EGL_RED_SIZE, 1,
+       EGL_GREEN_SIZE, 1,
+       EGL_BLUE_SIZE, 1,
+       EGL_ALPHA_SIZE, 0,
+       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+       EGL_NONE
+};
+
+static const EGLint gl_renderer_alpha_attribs[] = {
+       EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+       EGL_RED_SIZE, 1,
+       EGL_GREEN_SIZE, 1,
+       EGL_BLUE_SIZE, 1,
+       EGL_ALPHA_SIZE, 1,
+       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+       EGL_NONE
+};
+
+/** Checks whether a platform EGL client extension is supported
+ *
+ * \param ec The weston compositor
+ * \param extension_suffix The EGL client extension suffix
+ * \return 1 if supported, 0 if using fallbacks, -1 unsupported
+ *
+ * This function checks whether a specific platform_* extension is supported
+ * by EGL.
+ *
+ * The extension suffix should be the suffix of the platform extension (that
+ * specifies a <platform> argument as defined in EGL_EXT_platform_base). For
+ * example, passing "foo" will check whether either "EGL_KHR_platform_foo",
+ * "EGL_EXT_platform_foo", or "EGL_MESA_platform_foo" is supported.
+ *
+ * The return value is 1:
+ *   - if the supplied EGL client extension is supported.
+ * The return value is 0:
+ *   - if the platform_base client extension isn't supported so will
+ *     fallback to eglGetDisplay and friends.
+ * The return value is -1:
+ *   - if the supplied EGL client extension is not supported.
+ */
+static int
+gl_renderer_supports(struct weston_compositor *ec,
+                    const char *extension_suffix)
+{
+       static const char *extensions = NULL;
+       char s[64];
+
+       if (!extensions) {
+               extensions = (const char *) eglQueryString(
+                       EGL_NO_DISPLAY, EGL_EXTENSIONS);
+
+               if (!extensions)
+                       return 0;
+
+               log_extensions("EGL client extensions",
+                              extensions);
+       }
+
+       if (!check_extension(extensions, "EGL_EXT_platform_base"))
+               return 0;
+
+       snprintf(s, sizeof s, "EGL_KHR_platform_%s", extension_suffix);
+       if (check_extension(extensions, s))
+               return 1;
+
+       snprintf(s, sizeof s, "EGL_EXT_platform_%s", extension_suffix);
+       if (check_extension(extensions, s))
+               return 1;
+
+       snprintf(s, sizeof s, "EGL_MESA_platform_%s", extension_suffix);
+       if (check_extension(extensions, s))
+               return 1;
+
+       /* at this point we definitely have some platform extensions but
+        * haven't found the supplied platform, so chances are it's
+        * not supported. */
+
+       return -1;
+}
+
+static const char *
+platform_to_extension(EGLenum platform)
+{
+       switch (platform) {
+       case EGL_PLATFORM_GBM_KHR:
+               return "gbm";
+       case EGL_PLATFORM_WAYLAND_KHR:
+               return "wayland";
+       case EGL_PLATFORM_X11_KHR:
+               return "x11";
+       default:
+               assert(0 && "bad EGL platform enum");
+       }
+}
+
+static int
+gl_renderer_create(struct weston_compositor *ec, EGLenum platform,
+       void *native_window, const EGLint *attribs,
+       const EGLint *visual_id, int n_ids)
+{
+       struct gl_renderer *gr;
+       EGLint major, minor;
+       int supports = 0;
+
+       if (platform) {
+               supports = gl_renderer_supports(
+                       ec, platform_to_extension(platform));
+               if (supports < 0)
+                       return -1;
+       }
+
+       gr = zalloc(sizeof *gr);
+       if (gr == NULL)
+               return -1;
+
+       gr->base.read_pixels = gl_renderer_read_pixels;
+       gr->base.repaint_output = gl_renderer_repaint_output;
+       gr->base.flush_damage = gl_renderer_flush_damage;
+       gr->base.attach = gl_renderer_attach;
+       gr->base.surface_set_color = gl_renderer_surface_set_color;
+       gr->base.destroy = gl_renderer_destroy;
+       gr->base.surface_get_content_size =
+               gl_renderer_surface_get_content_size;
+       gr->base.surface_copy_content = gl_renderer_surface_copy_content;
+       gr->egl_display = NULL;
+
+       /* extension_suffix is supported */
+       if (supports) {
+               if (!get_platform_display) {
+                       get_platform_display = (void *) eglGetProcAddress(
+                                       "eglGetPlatformDisplayEXT");
+               }
+
+               /* also wrap this in the supports check because
+                * eglGetProcAddress can return non-NULL and still not
+                * support the feature at runtime, so ensure the
+                * appropriate extension checks have been done. */
+               if (get_platform_display && platform) {
+                       gr->egl_display = get_platform_display(platform,
+                                                              native_window,
+                                                              NULL);
+               }
+       }
+
+       if (!gr->egl_display) {
+               weston_log("warning: either no EGL_EXT_platform_base "
+                          "support or specific platform support; "
+                          "falling back to eglGetDisplay.\n");
+               gr->egl_display = eglGetDisplay(native_window);
+       }
+
+       if (gr->egl_display == EGL_NO_DISPLAY) {
+               weston_log("failed to create display\n");
+               goto fail;
+       }
+
+       if (!eglInitialize(gr->egl_display, &major, &minor)) {
+               weston_log("failed to initialize display\n");
+               goto fail_with_error;
+       }
+
+       if (egl_choose_config(gr, attribs, visual_id,
+                             n_ids, &gr->egl_config) < 0) {
+               weston_log("failed to choose EGL config\n");
+               goto fail_terminate;
+       }
+
+       ec->renderer = &gr->base;
+       ec->capabilities |= WESTON_CAP_ROTATION_ANY;
+       ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
+       ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
+
+       if (gl_renderer_setup_egl_extensions(ec) < 0)
+               goto fail_with_error;
+
+       wl_list_init(&gr->dmabuf_images);
+       if (gr->has_dmabuf_import)
+               gr->base.import_dmabuf = gl_renderer_import_dmabuf;
+
+       wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
+
+       wl_signal_init(&gr->destroy_signal);
+
+       return 0;
+
+fail_with_error:
+       gl_renderer_print_egl_error_state();
+fail_terminate:
+       eglTerminate(gr->egl_display);
+fail:
+       free(gr);
+       return -1;
+}
+
+static EGLDisplay
+gl_renderer_display(struct weston_compositor *ec)
+{
+       return get_renderer(ec)->egl_display;
+}
+
+static int
+compile_shaders(struct weston_compositor *ec)
+{
+       struct gl_renderer *gr = get_renderer(ec);
+
+       gr->texture_shader_rgba.vertex_source = vertex_shader;
+       gr->texture_shader_rgba.fragment_source = texture_fragment_shader_rgba;
+
+       gr->texture_shader_rgbx.vertex_source = vertex_shader;
+       gr->texture_shader_rgbx.fragment_source = texture_fragment_shader_rgbx;
+
+       gr->texture_shader_egl_external.vertex_source = vertex_shader;
+       gr->texture_shader_egl_external.fragment_source =
+               texture_fragment_shader_egl_external;
+
+       gr->texture_shader_y_uv.vertex_source = vertex_shader;
+       gr->texture_shader_y_uv.fragment_source = texture_fragment_shader_y_uv;
+
+       gr->texture_shader_y_u_v.vertex_source = vertex_shader;
+       gr->texture_shader_y_u_v.fragment_source =
+               texture_fragment_shader_y_u_v;
+
+       gr->texture_shader_y_xuxv.vertex_source = vertex_shader;
+       gr->texture_shader_y_xuxv.fragment_source =
+               texture_fragment_shader_y_xuxv;
+
+       gr->solid_shader.vertex_source = vertex_shader;
+       gr->solid_shader.fragment_source = solid_fragment_shader;
+
+       return 0;
+}
+
+static void
+fragment_debug_binding(struct weston_keyboard *keyboard, uint32_t time,
+                      uint32_t key, void *data)
+{
+       struct weston_compositor *ec = data;
+       struct gl_renderer *gr = get_renderer(ec);
+       struct weston_output *output;
+
+       gr->fragment_shader_debug ^= 1;
+
+       shader_release(&gr->texture_shader_rgba);
+       shader_release(&gr->texture_shader_rgbx);
+       shader_release(&gr->texture_shader_egl_external);
+       shader_release(&gr->texture_shader_y_uv);
+       shader_release(&gr->texture_shader_y_u_v);
+       shader_release(&gr->texture_shader_y_xuxv);
+       shader_release(&gr->solid_shader);
+
+       /* Force use_shader() to call glUseProgram(), since we need to use
+        * the recompiled version of the shader. */
+       gr->current_shader = NULL;
+
+       wl_list_for_each(output, &ec->output_list, link)
+               weston_output_damage(output);
+}
+
+static void
+fan_debug_repaint_binding(struct weston_keyboard *keyboard, uint32_t time,
+                         uint32_t key, void *data)
+{
+       struct weston_compositor *compositor = data;
+       struct gl_renderer *gr = get_renderer(compositor);
+
+       gr->fan_debug = !gr->fan_debug;
+       weston_compositor_damage_all(compositor);
+}
+
+static int
+gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
+{
+       struct gl_renderer *gr = get_renderer(ec);
+       const char *extensions;
+       EGLConfig context_config;
+       EGLBoolean ret;
+
+       static const EGLint context_attribs[] = {
+               EGL_CONTEXT_CLIENT_VERSION, 2,
+               EGL_NONE
+       };
+
+       if (!eglBindAPI(EGL_OPENGL_ES_API)) {
+               weston_log("failed to bind EGL_OPENGL_ES_API\n");
+               gl_renderer_print_egl_error_state();
+               return -1;
+       }
+
+       context_config = gr->egl_config;
+
+#ifdef EGL_MESA_configless_context
+       if (gr->has_configless_context)
+               context_config = EGL_NO_CONFIG_MESA;
+#endif
+
+       gr->egl_context = eglCreateContext(gr->egl_display, context_config,
+                                          EGL_NO_CONTEXT, context_attribs);
+       if (gr->egl_context == NULL) {
+               weston_log("failed to create context\n");
+               gl_renderer_print_egl_error_state();
+               return -1;
+       }
+
+       ret = eglMakeCurrent(gr->egl_display, egl_surface,
+                            egl_surface, gr->egl_context);
+       if (ret == EGL_FALSE) {
+               weston_log("Failed to make EGL context current.\n");
+               gl_renderer_print_egl_error_state();
+               return -1;
+       }
+
+       log_egl_gl_info(gr->egl_display);
+
+       gr->image_target_texture_2d =
+               (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
+
+       extensions = (const char *) glGetString(GL_EXTENSIONS);
+       if (!extensions) {
+               weston_log("Retrieving GL extension string failed.\n");
+               return -1;
+       }
+
+       if (!check_extension(extensions, "GL_EXT_texture_format_BGRA8888")) {
+               weston_log("GL_EXT_texture_format_BGRA8888 not available\n");
+               return -1;
+       }
+
+       if (check_extension(extensions, "GL_EXT_read_format_bgra"))
+               ec->read_format = PIXMAN_a8r8g8b8;
+       else
+               ec->read_format = PIXMAN_a8b8g8r8;
+
+#ifdef GL_EXT_unpack_subimage
+       if (check_extension(extensions, "GL_EXT_unpack_subimage"))
+               gr->has_unpack_subimage = 1;
+#endif
+
+       if (check_extension(extensions, "GL_OES_EGL_image_external"))
+               gr->has_egl_image_external = 1;
+
+       glActiveTexture(GL_TEXTURE0);
+
+       if (compile_shaders(ec))
+               return -1;
+
+       gr->fragment_binding =
+               weston_compositor_add_debug_binding(ec, KEY_S,
+                                                   fragment_debug_binding,
+                                                   ec);
+       gr->fan_binding =
+               weston_compositor_add_debug_binding(ec, KEY_F,
+                                                   fan_debug_repaint_binding,
+                                                   ec);
+
+       weston_log("GL ES 2 renderer features:\n");
+       weston_log_continue(STAMP_SPACE "read-back format: %s\n",
+               ec->read_format == PIXMAN_a8r8g8b8 ? "BGRA" : "RGBA");
+       weston_log_continue(STAMP_SPACE "wl_shm sub-image to texture: %s\n",
+                           gr->has_unpack_subimage ? "yes" : "no");
+       weston_log_continue(STAMP_SPACE "EGL Wayland extension: %s\n",
+                           gr->has_bind_display ? "yes" : "no");
+
+
+       return 0;
+}
+
+WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
+       .opaque_attribs = gl_renderer_opaque_attribs,
+       .alpha_attribs = gl_renderer_alpha_attribs,
+
+       .create = gl_renderer_create,
+       .display = gl_renderer_display,
+       .output_create = gl_renderer_output_create,
+       .output_destroy = gl_renderer_output_destroy,
+       .output_surface = gl_renderer_output_surface,
+       .output_set_border = gl_renderer_output_set_border,
+       .print_egl_error_state = gl_renderer_print_egl_error_state
+};
diff --git a/libweston/gl-renderer.h b/libweston/gl-renderer.h
new file mode 100644 (file)
index 0000000..71f6b46
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ * Copyright © 2012 John Kåre Alsaker
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "compositor.h"
+
+#ifdef ENABLE_EGL
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+#else
+
+typedef int EGLint;
+typedef int EGLenum;
+typedef void *EGLDisplay;
+typedef void *EGLSurface;
+typedef void *EGLConfig;
+typedef intptr_t EGLNativeDisplayType;
+typedef intptr_t EGLNativeWindowType;
+#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
+
+#endif /* ENABLE_EGL */
+
+#ifndef EGL_EXT_platform_base
+typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
+typedef EGLSurface (*PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+#endif
+
+#ifndef EGL_PLATFORM_GBM_KHR
+#define EGL_PLATFORM_GBM_KHR 0x31D7
+#endif
+
+#ifndef EGL_PLATFORM_WAYLAND_KHR
+#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
+#endif
+
+#ifndef EGL_PLATFORM_X11_KHR
+#define EGL_PLATFORM_X11_KHR 0x31D5
+#endif
+
+#define NO_EGL_PLATFORM 0
+
+enum gl_renderer_border_side {
+       GL_RENDERER_BORDER_TOP = 0,
+       GL_RENDERER_BORDER_LEFT = 1,
+       GL_RENDERER_BORDER_RIGHT = 2,
+       GL_RENDERER_BORDER_BOTTOM = 3,
+};
+
+struct gl_renderer_interface {
+       const EGLint *opaque_attribs;
+       const EGLint *alpha_attribs;
+
+       int (*create)(struct weston_compositor *ec,
+                     EGLenum platform,
+                     void *native_window,
+                     const EGLint *attribs,
+                     const EGLint *visual_id,
+                     const int n_ids);
+
+       EGLDisplay (*display)(struct weston_compositor *ec);
+
+       int (*output_create)(struct weston_output *output,
+                            EGLNativeWindowType window_for_legacy,
+                            void *window_for_platform,
+                            const EGLint *attribs,
+                            const EGLint *visual_id,
+                            const int n_ids);
+
+       void (*output_destroy)(struct weston_output *output);
+
+       EGLSurface (*output_surface)(struct weston_output *output);
+
+       /* Sets the output border.
+        *
+        * The side specifies the side for which we are setting the border.
+        * The width and height are the width and height of the border.
+        * The tex_width patemeter specifies the width of the actual
+        * texture; this may be larger than width if the data is not
+        * tightly packed.
+        *
+        * The top and bottom textures will extend over the sides to the
+        * full width of the bordered window.  The right and left edges,
+        * however, will extend only to the top and bottom of the
+        * compositor surface.  This is demonstrated by the picture below:
+        *
+        * +-----------------------+
+        * |          TOP          |
+        * +-+-------------------+-+
+        * | |                   | |
+        * |L|                   |R|
+        * |E|                   |I|
+        * |F|                   |G|
+        * |T|                   |H|
+        * | |                   |T|
+        * | |                   | |
+        * +-+-------------------+-+
+        * |        BOTTOM         |
+        * +-----------------------+
+        */
+       void (*output_set_border)(struct weston_output *output,
+                                 enum gl_renderer_border_side side,
+                                 int32_t width, int32_t height,
+                                 int32_t tex_width, unsigned char *data);
+
+       void (*print_egl_error_state)(void);
+};
+
diff --git a/libweston/input.c b/libweston/input.c
new file mode 100644 (file)
index 0000000..08378d1
--- /dev/null
@@ -0,0 +1,2765 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <limits.h>
+
+#include "shared/helpers.h"
+#include "shared/os-compatibility.h"
+#include "compositor.h"
+
+static void
+empty_region(pixman_region32_t *region)
+{
+       pixman_region32_fini(region);
+       pixman_region32_init(region);
+}
+
+static struct weston_pointer_client *
+weston_pointer_client_create(struct wl_client *client)
+{
+       struct weston_pointer_client *pointer_client;
+
+       pointer_client = zalloc(sizeof *pointer_client);
+       if (!pointer_client)
+               return NULL;
+
+       pointer_client->client = client;
+       wl_list_init(&pointer_client->pointer_resources);
+
+       return pointer_client;
+}
+
+static void
+weston_pointer_client_destroy(struct weston_pointer_client *pointer_client)
+{
+       free(pointer_client);
+}
+
+static bool
+weston_pointer_client_is_empty(struct weston_pointer_client *pointer_client)
+{
+       return wl_list_empty(&pointer_client->pointer_resources);
+}
+
+static struct weston_pointer_client *
+weston_pointer_get_pointer_client(struct weston_pointer *pointer,
+                                 struct wl_client *client)
+{
+       struct weston_pointer_client *pointer_client;
+
+       wl_list_for_each(pointer_client, &pointer->pointer_clients, link) {
+               if (pointer_client->client == client)
+                       return pointer_client;
+       }
+
+       return NULL;
+}
+
+static struct weston_pointer_client *
+weston_pointer_ensure_pointer_client(struct weston_pointer *pointer,
+                                    struct wl_client *client)
+{
+       struct weston_pointer_client *pointer_client;
+
+       pointer_client = weston_pointer_get_pointer_client(pointer, client);
+       if (pointer_client)
+               return pointer_client;
+
+       pointer_client = weston_pointer_client_create(client);
+       wl_list_insert(&pointer->pointer_clients, &pointer_client->link);
+
+       if (pointer->focus &&
+           pointer->focus->surface->resource &&
+           wl_resource_get_client(pointer->focus->surface->resource) == client) {
+               pointer->focus_client = pointer_client;
+       }
+
+       return pointer_client;
+}
+
+static void
+weston_pointer_cleanup_pointer_client(struct weston_pointer *pointer,
+                                     struct weston_pointer_client *pointer_client)
+{
+       if (weston_pointer_client_is_empty(pointer_client)) {
+               if (pointer->focus_client == pointer_client)
+                       pointer->focus_client = NULL;
+               wl_list_remove(&pointer_client->link);
+               weston_pointer_client_destroy(pointer_client);
+       }
+}
+
+static void
+unbind_pointer_client_resource(struct wl_resource *resource)
+{
+       struct weston_pointer *pointer = wl_resource_get_user_data(resource);
+       struct wl_client *client = wl_resource_get_client(resource);
+       struct weston_pointer_client *pointer_client;
+
+       pointer_client = weston_pointer_get_pointer_client(pointer, client);
+       assert(pointer_client);
+
+       wl_list_remove(wl_resource_get_link(resource));
+       weston_pointer_cleanup_pointer_client(pointer, pointer_client);
+}
+
+static void unbind_resource(struct wl_resource *resource)
+{
+       wl_list_remove(wl_resource_get_link(resource));
+}
+
+WL_EXPORT void
+weston_seat_repick(struct weston_seat *seat)
+{
+       const struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       if (!pointer)
+               return;
+
+       pointer->grab->interface->focus(pointer->grab);
+}
+
+static void
+weston_compositor_idle_inhibit(struct weston_compositor *compositor)
+{
+       weston_compositor_wake(compositor);
+       compositor->idle_inhibit++;
+}
+
+static void
+weston_compositor_idle_release(struct weston_compositor *compositor)
+{
+       compositor->idle_inhibit--;
+       weston_compositor_wake(compositor);
+}
+
+static void
+pointer_focus_view_destroyed(struct wl_listener *listener, void *data)
+{
+       struct weston_pointer *pointer =
+               container_of(listener, struct weston_pointer,
+                            focus_view_listener);
+
+       weston_pointer_clear_focus(pointer);
+}
+
+static void
+pointer_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+       struct weston_pointer *pointer =
+               container_of(listener, struct weston_pointer,
+                            focus_resource_listener);
+
+       weston_pointer_clear_focus(pointer);
+}
+
+static void
+keyboard_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+       struct weston_keyboard *keyboard =
+               container_of(listener, struct weston_keyboard,
+                            focus_resource_listener);
+
+       weston_keyboard_set_focus(keyboard, NULL);
+}
+
+static void
+touch_focus_view_destroyed(struct wl_listener *listener, void *data)
+{
+       struct weston_touch *touch =
+               container_of(listener, struct weston_touch,
+                            focus_view_listener);
+
+       weston_touch_set_focus(touch, NULL);
+}
+
+static void
+touch_focus_resource_destroyed(struct wl_listener *listener, void *data)
+{
+       struct weston_touch *touch =
+               container_of(listener, struct weston_touch,
+                            focus_resource_listener);
+
+       weston_touch_set_focus(touch, NULL);
+}
+
+static void
+move_resources(struct wl_list *destination, struct wl_list *source)
+{
+       wl_list_insert_list(destination, source);
+       wl_list_init(source);
+}
+
+static void
+move_resources_for_client(struct wl_list *destination,
+                         struct wl_list *source,
+                         struct wl_client *client)
+{
+       struct wl_resource *resource, *tmp;
+       wl_resource_for_each_safe(resource, tmp, source) {
+               if (wl_resource_get_client(resource) == client) {
+                       wl_list_remove(wl_resource_get_link(resource));
+                       wl_list_insert(destination,
+                                      wl_resource_get_link(resource));
+               }
+       }
+}
+
+static void
+default_grab_pointer_focus(struct weston_pointer_grab *grab)
+{
+       struct weston_pointer *pointer = grab->pointer;
+       struct weston_view *view;
+       wl_fixed_t sx, sy;
+
+       if (pointer->button_count > 0)
+               return;
+
+       view = weston_compositor_pick_view(pointer->seat->compositor,
+                                          pointer->x, pointer->y,
+                                          &sx, &sy);
+
+       if (pointer->focus != view || pointer->sx != sx || pointer->sy != sy)
+               weston_pointer_set_focus(pointer, view, sx, sy);
+}
+
+static void
+default_grab_pointer_motion(struct weston_pointer_grab *grab, uint32_t time,
+                           struct weston_pointer_motion_event *event)
+{
+       struct weston_pointer *pointer = grab->pointer;
+       struct wl_list *resource_list;
+       struct wl_resource *resource;
+       wl_fixed_t x, y;
+       wl_fixed_t old_sx = pointer->sx;
+       wl_fixed_t old_sy = pointer->sy;
+
+       if (pointer->focus) {
+               weston_pointer_motion_to_abs(pointer, event, &x, &y);
+               weston_view_from_global_fixed(pointer->focus, x, y,
+                                             &pointer->sx, &pointer->sy);
+       }
+
+       weston_pointer_move(pointer, event);
+
+       if (pointer->focus_client &&
+           (old_sx != pointer->sx || old_sy != pointer->sy)) {
+               resource_list = &pointer->focus_client->pointer_resources;
+               wl_resource_for_each(resource, resource_list) {
+                       wl_pointer_send_motion(resource, time,
+                                              pointer->sx, pointer->sy);
+               }
+       }
+}
+
+static void
+default_grab_pointer_button(struct weston_pointer_grab *grab,
+                           uint32_t time, uint32_t button, uint32_t state_w)
+{
+       struct weston_pointer *pointer = grab->pointer;
+       struct weston_compositor *compositor = pointer->seat->compositor;
+       struct weston_view *view;
+       struct wl_resource *resource;
+       uint32_t serial;
+       enum wl_pointer_button_state state = state_w;
+       struct wl_display *display = compositor->wl_display;
+       wl_fixed_t sx, sy;
+       struct wl_list *resource_list = NULL;
+
+       if (pointer->focus_client)
+               resource_list = &pointer->focus_client->pointer_resources;
+       if (resource_list && !wl_list_empty(resource_list)) {
+               resource_list = &pointer->focus_client->pointer_resources;
+               serial = wl_display_next_serial(display);
+               wl_resource_for_each(resource, resource_list)
+                       wl_pointer_send_button(resource,
+                                              serial,
+                                              time,
+                                              button,
+                                              state_w);
+       }
+
+       if (pointer->button_count == 0 &&
+           state == WL_POINTER_BUTTON_STATE_RELEASED) {
+               view = weston_compositor_pick_view(compositor,
+                                                  pointer->x, pointer->y,
+                                                  &sx, &sy);
+
+               weston_pointer_set_focus(pointer, view, sx, sy);
+       }
+}
+
+/** Send wl_pointer.axis events to focused resources.
+ *
+ * \param pointer The pointer where the axis events originates from.
+ * \param time The timestamp of the event
+ * \param axis The axis enum value of the event
+ * \param value The axis value of the event
+ *
+ * For every resource that is currently in focus, send a wl_pointer.axis event
+ * with the passed parameters. The focused resources are the wl_pointer
+ * resources of the client which currently has the surface with pointer focus.
+ */
+WL_EXPORT void
+weston_pointer_send_axis(struct weston_pointer *pointer,
+                        uint32_t time,
+                        struct weston_pointer_axis_event *event)
+{
+       struct wl_resource *resource;
+       struct wl_list *resource_list;
+
+       if (!pointer->focus_client)
+               return;
+
+       resource_list = &pointer->focus_client->pointer_resources;
+       wl_resource_for_each(resource, resource_list) {
+               if (event->has_discrete &&
+                   wl_resource_get_version(resource) >=
+                   WL_POINTER_AXIS_DISCRETE_SINCE_VERSION)
+                       wl_pointer_send_axis_discrete(resource, event->axis,
+                                                     event->discrete);
+
+               if (event->value)
+                       wl_pointer_send_axis(resource, time,
+                                            event->axis,
+                                            wl_fixed_from_double(event->value));
+               else if (wl_resource_get_version(resource) >=
+                        WL_POINTER_AXIS_STOP_SINCE_VERSION)
+                       wl_pointer_send_axis_stop(resource, time,
+                                                 event->axis);
+       }
+}
+
+WL_EXPORT void
+weston_pointer_send_axis_source(struct weston_pointer *pointer, uint32_t source)
+{
+       struct wl_resource *resource;
+       struct wl_list *resource_list;
+
+       if (!pointer->focus_client)
+               return;
+
+       resource_list = &pointer->focus_client->pointer_resources;
+       wl_resource_for_each(resource, resource_list) {
+               if (wl_resource_get_version(resource) >=
+                   WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
+                       wl_pointer_send_axis_source(resource, source);
+               }
+       }
+}
+
+static void
+pointer_send_frame(struct wl_resource *resource)
+{
+       if (wl_resource_get_version(resource) >=
+           WL_POINTER_FRAME_SINCE_VERSION) {
+               wl_pointer_send_frame(resource);
+       }
+}
+
+WL_EXPORT void
+weston_pointer_send_frame(struct weston_pointer *pointer)
+{
+       struct wl_resource *resource;
+       struct wl_list *resource_list;
+
+       if (!pointer->focus_client)
+               return;
+
+       resource_list = &pointer->focus_client->pointer_resources;
+       wl_resource_for_each(resource, resource_list)
+               pointer_send_frame(resource);
+}
+
+static void
+default_grab_pointer_axis(struct weston_pointer_grab *grab,
+                         uint32_t time,
+                         struct weston_pointer_axis_event *event)
+{
+       weston_pointer_send_axis(grab->pointer, time, event);
+}
+
+static void
+default_grab_pointer_axis_source(struct weston_pointer_grab *grab,
+                                uint32_t source)
+{
+       weston_pointer_send_axis_source(grab->pointer, source);
+}
+
+static void
+default_grab_pointer_frame(struct weston_pointer_grab *grab)
+{
+       weston_pointer_send_frame(grab->pointer);
+}
+
+static void
+default_grab_pointer_cancel(struct weston_pointer_grab *grab)
+{
+}
+
+static const struct weston_pointer_grab_interface
+                               default_pointer_grab_interface = {
+       default_grab_pointer_focus,
+       default_grab_pointer_motion,
+       default_grab_pointer_button,
+       default_grab_pointer_axis,
+       default_grab_pointer_axis_source,
+       default_grab_pointer_frame,
+       default_grab_pointer_cancel,
+};
+
+static void
+default_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
+                       int touch_id, wl_fixed_t x, wl_fixed_t y)
+{
+       struct weston_touch *touch = grab->touch;
+       struct wl_display *display = touch->seat->compositor->wl_display;
+       uint32_t serial;
+       struct wl_resource *resource;
+       struct wl_list *resource_list;
+       wl_fixed_t sx, sy;
+
+       if (!touch->focus)
+               return;
+
+       weston_view_from_global_fixed(touch->focus, x, y, &sx, &sy);
+
+       resource_list = &touch->focus_resource_list;
+
+       if (!wl_list_empty(resource_list)) {
+               serial = wl_display_next_serial(display);
+               wl_resource_for_each(resource, resource_list)
+                               wl_touch_send_down(resource, serial, time,
+                                                  touch->focus->surface->resource,
+                                                  touch_id, sx, sy);
+       }
+}
+
+static void
+default_grab_touch_up(struct weston_touch_grab *grab,
+                     uint32_t time, int touch_id)
+{
+       struct weston_touch *touch = grab->touch;
+       struct wl_display *display = touch->seat->compositor->wl_display;
+       uint32_t serial;
+       struct wl_resource *resource;
+       struct wl_list *resource_list;
+
+       resource_list = &touch->focus_resource_list;
+
+       if (!wl_list_empty(resource_list)) {
+               serial = wl_display_next_serial(display);
+               wl_resource_for_each(resource, resource_list)
+                       wl_touch_send_up(resource, serial, time, touch_id);
+       }
+}
+
+static void
+default_grab_touch_motion(struct weston_touch_grab *grab, uint32_t time,
+                         int touch_id, wl_fixed_t x, wl_fixed_t y)
+{
+       struct weston_touch *touch = grab->touch;
+       struct wl_resource *resource;
+       struct wl_list *resource_list;
+       wl_fixed_t sx, sy;
+
+       weston_view_from_global_fixed(touch->focus, x, y, &sx, &sy);
+
+       resource_list = &touch->focus_resource_list;
+
+       wl_resource_for_each(resource, resource_list) {
+               wl_touch_send_motion(resource, time,
+                                    touch_id, sx, sy);
+       }
+}
+
+static void
+default_grab_touch_frame(struct weston_touch_grab *grab)
+{
+       struct wl_resource *resource;
+
+       wl_resource_for_each(resource, &grab->touch->focus_resource_list)
+               wl_touch_send_frame(resource);
+}
+
+static void
+default_grab_touch_cancel(struct weston_touch_grab *grab)
+{
+}
+
+static const struct weston_touch_grab_interface default_touch_grab_interface = {
+       default_grab_touch_down,
+       default_grab_touch_up,
+       default_grab_touch_motion,
+       default_grab_touch_frame,
+       default_grab_touch_cancel,
+};
+
+static void
+default_grab_keyboard_key(struct weston_keyboard_grab *grab,
+                         uint32_t time, uint32_t key, uint32_t state)
+{
+       struct weston_keyboard *keyboard = grab->keyboard;
+       struct wl_resource *resource;
+       struct wl_display *display = keyboard->seat->compositor->wl_display;
+       uint32_t serial;
+       struct wl_list *resource_list;
+
+       resource_list = &keyboard->focus_resource_list;
+       if (!wl_list_empty(resource_list)) {
+               serial = wl_display_next_serial(display);
+               wl_resource_for_each(resource, resource_list)
+                       wl_keyboard_send_key(resource,
+                                            serial,
+                                            time,
+                                            key,
+                                            state);
+       }
+}
+
+static void
+send_modifiers_to_resource(struct weston_keyboard *keyboard,
+                          struct wl_resource *resource,
+                          uint32_t serial)
+{
+       wl_keyboard_send_modifiers(resource,
+                                  serial,
+                                  keyboard->modifiers.mods_depressed,
+                                  keyboard->modifiers.mods_latched,
+                                  keyboard->modifiers.mods_locked,
+                                  keyboard->modifiers.group);
+}
+
+static void
+send_modifiers_to_client_in_list(struct wl_client *client,
+                                struct wl_list *list,
+                                uint32_t serial,
+                                struct weston_keyboard *keyboard)
+{
+       struct wl_resource *resource;
+
+       wl_resource_for_each(resource, list) {
+               if (wl_resource_get_client(resource) == client)
+                       send_modifiers_to_resource(keyboard,
+                                                  resource,
+                                                  serial);
+       }
+}
+
+static struct weston_pointer_client *
+find_pointer_client_for_surface(struct weston_pointer *pointer,
+                               struct weston_surface *surface)
+{
+       struct wl_client *client;
+
+       if (!surface)
+               return NULL;
+
+       if (!surface->resource)
+               return NULL;
+
+       client = wl_resource_get_client(surface->resource);
+       return weston_pointer_get_pointer_client(pointer, client);
+}
+
+static struct weston_pointer_client *
+find_pointer_client_for_view(struct weston_pointer *pointer, struct weston_view *view)
+{
+       if (!view)
+               return NULL;
+
+       return find_pointer_client_for_surface(pointer, view->surface);
+}
+
+static struct wl_resource *
+find_resource_for_surface(struct wl_list *list, struct weston_surface *surface)
+{
+       if (!surface)
+               return NULL;
+
+       if (!surface->resource)
+               return NULL;
+
+       return wl_resource_find_for_client(list, wl_resource_get_client(surface->resource));
+}
+
+static void
+default_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
+                               uint32_t serial, uint32_t mods_depressed,
+                               uint32_t mods_latched,
+                               uint32_t mods_locked, uint32_t group)
+{
+       struct weston_keyboard *keyboard = grab->keyboard;
+       struct weston_pointer *pointer =
+               weston_seat_get_pointer(grab->keyboard->seat);
+       struct wl_resource *resource;
+       struct wl_list *resource_list;
+
+       resource_list = &keyboard->focus_resource_list;
+
+       wl_resource_for_each(resource, resource_list) {
+               wl_keyboard_send_modifiers(resource, serial, mods_depressed,
+                                          mods_latched, mods_locked, group);
+       }
+       if (pointer && pointer->focus && pointer->focus->surface->resource &&
+           pointer->focus->surface != keyboard->focus) {
+               struct wl_client *pointer_client =
+                       wl_resource_get_client(pointer->focus->surface->resource);
+               send_modifiers_to_client_in_list(pointer_client,
+                                                &keyboard->resource_list,
+                                                serial,
+                                                keyboard);
+       }
+}
+
+static void
+default_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
+{
+}
+
+static const struct weston_keyboard_grab_interface
+                               default_keyboard_grab_interface = {
+       default_grab_keyboard_key,
+       default_grab_keyboard_modifiers,
+       default_grab_keyboard_cancel,
+};
+
+static void
+pointer_unmap_sprite(struct weston_pointer *pointer)
+{
+       struct weston_surface *surface = pointer->sprite->surface;
+
+       if (weston_surface_is_mapped(surface))
+               weston_surface_unmap(surface);
+
+       wl_list_remove(&pointer->sprite_destroy_listener.link);
+       surface->configure = NULL;
+       surface->configure_private = NULL;
+       weston_surface_set_label_func(surface, NULL);
+       weston_view_destroy(pointer->sprite);
+       pointer->sprite = NULL;
+}
+
+static void
+pointer_handle_sprite_destroy(struct wl_listener *listener, void *data)
+{
+       struct weston_pointer *pointer =
+               container_of(listener, struct weston_pointer,
+                            sprite_destroy_listener);
+
+       pointer->sprite = NULL;
+}
+
+static void
+weston_pointer_reset_state(struct weston_pointer *pointer)
+{
+       pointer->button_count = 0;
+}
+
+static void
+weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data);
+
+WL_EXPORT struct weston_pointer *
+weston_pointer_create(struct weston_seat *seat)
+{
+       struct weston_pointer *pointer;
+
+       pointer = zalloc(sizeof *pointer);
+       if (pointer == NULL)
+               return NULL;
+
+       wl_list_init(&pointer->pointer_clients);
+       weston_pointer_set_default_grab(pointer,
+                                       seat->compositor->default_pointer_grab);
+       wl_list_init(&pointer->focus_resource_listener.link);
+       pointer->focus_resource_listener.notify = pointer_focus_resource_destroyed;
+       pointer->default_grab.pointer = pointer;
+       pointer->grab = &pointer->default_grab;
+       wl_signal_init(&pointer->motion_signal);
+       wl_signal_init(&pointer->focus_signal);
+       wl_list_init(&pointer->focus_view_listener.link);
+
+       pointer->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
+
+       /* FIXME: Pick better co-ords. */
+       pointer->x = wl_fixed_from_int(100);
+       pointer->y = wl_fixed_from_int(100);
+
+       pointer->output_destroy_listener.notify =
+               weston_pointer_handle_output_destroy;
+       wl_signal_add(&seat->compositor->output_destroyed_signal,
+                     &pointer->output_destroy_listener);
+
+       pointer->sx = wl_fixed_from_int(-1000000);
+       pointer->sy = wl_fixed_from_int(-1000000);
+
+       return pointer;
+}
+
+WL_EXPORT void
+weston_pointer_destroy(struct weston_pointer *pointer)
+{
+       if (pointer->sprite)
+               pointer_unmap_sprite(pointer);
+
+       /* XXX: What about pointer->resource_list? */
+
+       wl_list_remove(&pointer->focus_resource_listener.link);
+       wl_list_remove(&pointer->focus_view_listener.link);
+       wl_list_remove(&pointer->output_destroy_listener.link);
+       free(pointer);
+}
+
+void
+weston_pointer_set_default_grab(struct weston_pointer *pointer,
+               const struct weston_pointer_grab_interface *interface)
+{
+       if (interface)
+               pointer->default_grab.interface = interface;
+       else
+               pointer->default_grab.interface =
+                       &default_pointer_grab_interface;
+}
+
+WL_EXPORT struct weston_keyboard *
+weston_keyboard_create(void)
+{
+       struct weston_keyboard *keyboard;
+
+       keyboard = zalloc(sizeof *keyboard);
+       if (keyboard == NULL)
+           return NULL;
+
+       wl_list_init(&keyboard->resource_list);
+       wl_list_init(&keyboard->focus_resource_list);
+       wl_list_init(&keyboard->focus_resource_listener.link);
+       keyboard->focus_resource_listener.notify = keyboard_focus_resource_destroyed;
+       wl_array_init(&keyboard->keys);
+       keyboard->default_grab.interface = &default_keyboard_grab_interface;
+       keyboard->default_grab.keyboard = keyboard;
+       keyboard->grab = &keyboard->default_grab;
+       wl_signal_init(&keyboard->focus_signal);
+
+       return keyboard;
+}
+
+static void
+weston_xkb_info_destroy(struct weston_xkb_info *xkb_info);
+
+WL_EXPORT void
+weston_keyboard_destroy(struct weston_keyboard *keyboard)
+{
+       /* XXX: What about keyboard->resource_list? */
+
+#ifdef ENABLE_XKBCOMMON
+       if (keyboard->seat->compositor->use_xkbcommon) {
+               xkb_state_unref(keyboard->xkb_state.state);
+               if (keyboard->xkb_info)
+                       weston_xkb_info_destroy(keyboard->xkb_info);
+               xkb_keymap_unref(keyboard->pending_keymap);
+       }
+#endif
+
+       wl_array_release(&keyboard->keys);
+       wl_list_remove(&keyboard->focus_resource_listener.link);
+       free(keyboard);
+}
+
+static void
+weston_touch_reset_state(struct weston_touch *touch)
+{
+       touch->num_tp = 0;
+}
+
+WL_EXPORT struct weston_touch *
+weston_touch_create(void)
+{
+       struct weston_touch *touch;
+
+       touch = zalloc(sizeof *touch);
+       if (touch == NULL)
+               return NULL;
+
+       wl_list_init(&touch->resource_list);
+       wl_list_init(&touch->focus_resource_list);
+       wl_list_init(&touch->focus_view_listener.link);
+       touch->focus_view_listener.notify = touch_focus_view_destroyed;
+       wl_list_init(&touch->focus_resource_listener.link);
+       touch->focus_resource_listener.notify = touch_focus_resource_destroyed;
+       touch->default_grab.interface = &default_touch_grab_interface;
+       touch->default_grab.touch = touch;
+       touch->grab = &touch->default_grab;
+       wl_signal_init(&touch->focus_signal);
+
+       return touch;
+}
+
+WL_EXPORT void
+weston_touch_destroy(struct weston_touch *touch)
+{
+       /* XXX: What about touch->resource_list? */
+
+       wl_list_remove(&touch->focus_view_listener.link);
+       wl_list_remove(&touch->focus_resource_listener.link);
+       free(touch);
+}
+
+static void
+seat_send_updated_caps(struct weston_seat *seat)
+{
+       enum wl_seat_capability caps = 0;
+       struct wl_resource *resource;
+
+       if (seat->pointer_device_count > 0)
+               caps |= WL_SEAT_CAPABILITY_POINTER;
+       if (seat->keyboard_device_count > 0)
+               caps |= WL_SEAT_CAPABILITY_KEYBOARD;
+       if (seat->touch_device_count > 0)
+               caps |= WL_SEAT_CAPABILITY_TOUCH;
+
+       wl_resource_for_each(resource, &seat->base_resource_list) {
+               wl_seat_send_capabilities(resource, caps);
+       }
+       wl_signal_emit(&seat->updated_caps_signal, seat);
+}
+
+
+/** Clear the pointer focus
+ *
+ * \param pointer the pointer to clear focus for.
+ *
+ * This can be used to unset pointer focus and set the co-ordinates to the
+ * arbitrary values we use for the no focus case.
+ *
+ * There's no requirement to use this function.  For example, passing the
+ * results of a weston_compositor_pick_view() directly to
+ * weston_pointer_set_focus() will do the right thing when no view is found.
+ */
+WL_EXPORT void
+weston_pointer_clear_focus(struct weston_pointer *pointer)
+{
+       weston_pointer_set_focus(pointer, NULL,
+                                wl_fixed_from_int(-1000000),
+                                wl_fixed_from_int(-1000000));
+}
+
+WL_EXPORT void
+weston_pointer_set_focus(struct weston_pointer *pointer,
+                        struct weston_view *view,
+                        wl_fixed_t sx, wl_fixed_t sy)
+{
+       struct weston_pointer_client *pointer_client;
+       struct weston_keyboard *kbd = weston_seat_get_keyboard(pointer->seat);
+       struct wl_resource *resource;
+       struct wl_resource *surface_resource;
+       struct wl_display *display = pointer->seat->compositor->wl_display;
+       uint32_t serial;
+       struct wl_list *focus_resource_list;
+       int refocus = 0;
+
+       if ((!pointer->focus && view) ||
+           (pointer->focus && !view) ||
+           (pointer->focus && pointer->focus->surface != view->surface) ||
+           pointer->sx != sx || pointer->sy != sy)
+               refocus = 1;
+
+       if (pointer->focus_client && refocus) {
+               focus_resource_list = &pointer->focus_client->pointer_resources;
+               if (!wl_list_empty(focus_resource_list)) {
+                       serial = wl_display_next_serial(display);
+                       surface_resource = pointer->focus->surface->resource;
+                       wl_resource_for_each(resource, focus_resource_list) {
+                               wl_pointer_send_leave(resource, serial,
+                                                     surface_resource);
+                               pointer_send_frame(resource);
+                       }
+               }
+
+               pointer->focus_client = NULL;
+       }
+
+       pointer_client = find_pointer_client_for_view(pointer, view);
+       if (pointer_client && refocus) {
+               struct wl_client *surface_client = pointer_client->client;
+
+               serial = wl_display_next_serial(display);
+
+               if (kbd && kbd->focus != view->surface)
+                       send_modifiers_to_client_in_list(surface_client,
+                                                        &kbd->resource_list,
+                                                        serial,
+                                                        kbd);
+
+               pointer->focus_client = pointer_client;
+
+               focus_resource_list = &pointer->focus_client->pointer_resources;
+               wl_resource_for_each(resource, focus_resource_list) {
+                       wl_pointer_send_enter(resource,
+                                             serial,
+                                             view->surface->resource,
+                                             sx, sy);
+                       pointer_send_frame(resource);
+               }
+
+               pointer->focus_serial = serial;
+       }
+
+       wl_list_remove(&pointer->focus_view_listener.link);
+       wl_list_init(&pointer->focus_view_listener.link);
+       wl_list_remove(&pointer->focus_resource_listener.link);
+       wl_list_init(&pointer->focus_resource_listener.link);
+       if (view)
+               wl_signal_add(&view->destroy_signal, &pointer->focus_view_listener);
+       if (view && view->surface->resource)
+               wl_resource_add_destroy_listener(view->surface->resource,
+                                                &pointer->focus_resource_listener);
+
+       pointer->focus = view;
+       pointer->focus_view_listener.notify = pointer_focus_view_destroyed;
+       pointer->sx = sx;
+       pointer->sy = sy;
+
+       assert(view || sx == wl_fixed_from_int(-1000000));
+       assert(view || sy == wl_fixed_from_int(-1000000));
+
+       wl_signal_emit(&pointer->focus_signal, pointer);
+}
+
+static void
+send_enter_to_resource_list(struct wl_list *list,
+                           struct weston_keyboard *keyboard,
+                           struct weston_surface *surface,
+                           uint32_t serial)
+{
+       struct wl_resource *resource;
+
+       wl_resource_for_each(resource, list) {
+               send_modifiers_to_resource(keyboard, resource, serial);
+               wl_keyboard_send_enter(resource, serial,
+                                      surface->resource,
+                                      &keyboard->keys);
+       }
+}
+
+WL_EXPORT void
+weston_keyboard_set_focus(struct weston_keyboard *keyboard,
+                         struct weston_surface *surface)
+{
+       struct wl_resource *resource;
+       struct wl_display *display = keyboard->seat->compositor->wl_display;
+       uint32_t serial;
+       struct wl_list *focus_resource_list;
+
+       focus_resource_list = &keyboard->focus_resource_list;
+
+       if (!wl_list_empty(focus_resource_list) && keyboard->focus != surface) {
+               serial = wl_display_next_serial(display);
+               wl_resource_for_each(resource, focus_resource_list) {
+                       wl_keyboard_send_leave(resource, serial,
+                                       keyboard->focus->resource);
+               }
+               move_resources(&keyboard->resource_list, focus_resource_list);
+       }
+
+       if (find_resource_for_surface(&keyboard->resource_list, surface) &&
+           keyboard->focus != surface) {
+               struct wl_client *surface_client =
+                       wl_resource_get_client(surface->resource);
+
+               serial = wl_display_next_serial(display);
+
+               move_resources_for_client(focus_resource_list,
+                                         &keyboard->resource_list,
+                                         surface_client);
+               send_enter_to_resource_list(focus_resource_list,
+                                           keyboard,
+                                           surface,
+                                           serial);
+               keyboard->focus_serial = serial;
+       }
+
+       wl_list_remove(&keyboard->focus_resource_listener.link);
+       wl_list_init(&keyboard->focus_resource_listener.link);
+       if (surface && surface->resource)
+               wl_resource_add_destroy_listener(surface->resource,
+                                                &keyboard->focus_resource_listener);
+
+       keyboard->focus = surface;
+       wl_signal_emit(&keyboard->focus_signal, keyboard);
+}
+
+/* Users of this function must manually manage the keyboard focus */
+WL_EXPORT void
+weston_keyboard_start_grab(struct weston_keyboard *keyboard,
+                          struct weston_keyboard_grab *grab)
+{
+       keyboard->grab = grab;
+       grab->keyboard = keyboard;
+}
+
+WL_EXPORT void
+weston_keyboard_end_grab(struct weston_keyboard *keyboard)
+{
+       keyboard->grab = &keyboard->default_grab;
+}
+
+static void
+weston_keyboard_cancel_grab(struct weston_keyboard *keyboard)
+{
+       keyboard->grab->interface->cancel(keyboard->grab);
+}
+
+WL_EXPORT void
+weston_pointer_start_grab(struct weston_pointer *pointer,
+                         struct weston_pointer_grab *grab)
+{
+       pointer->grab = grab;
+       grab->pointer = pointer;
+       pointer->grab->interface->focus(pointer->grab);
+}
+
+WL_EXPORT void
+weston_pointer_end_grab(struct weston_pointer *pointer)
+{
+       pointer->grab = &pointer->default_grab;
+       pointer->grab->interface->focus(pointer->grab);
+}
+
+static void
+weston_pointer_cancel_grab(struct weston_pointer *pointer)
+{
+       pointer->grab->interface->cancel(pointer->grab);
+}
+
+WL_EXPORT void
+weston_touch_start_grab(struct weston_touch *touch, struct weston_touch_grab *grab)
+{
+       touch->grab = grab;
+       grab->touch = touch;
+}
+
+WL_EXPORT void
+weston_touch_end_grab(struct weston_touch *touch)
+{
+       touch->grab = &touch->default_grab;
+}
+
+static void
+weston_touch_cancel_grab(struct weston_touch *touch)
+{
+       touch->grab->interface->cancel(touch->grab);
+}
+
+static void
+weston_pointer_clamp_for_output(struct weston_pointer *pointer,
+                               struct weston_output *output,
+                               wl_fixed_t *fx, wl_fixed_t *fy)
+{
+       int x, y;
+
+       x = wl_fixed_to_int(*fx);
+       y = wl_fixed_to_int(*fy);
+
+       if (x < output->x)
+               *fx = wl_fixed_from_int(output->x);
+       else if (x >= output->x + output->width)
+               *fx = wl_fixed_from_int(output->x +
+                                       output->width - 1);
+       if (y < output->y)
+               *fy = wl_fixed_from_int(output->y);
+       else if (y >= output->y + output->height)
+               *fy = wl_fixed_from_int(output->y +
+                                       output->height - 1);
+}
+
+WL_EXPORT void
+weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t *fy)
+{
+       struct weston_compositor *ec = pointer->seat->compositor;
+       struct weston_output *output, *prev = NULL;
+       int x, y, old_x, old_y, valid = 0;
+
+       x = wl_fixed_to_int(*fx);
+       y = wl_fixed_to_int(*fy);
+       old_x = wl_fixed_to_int(pointer->x);
+       old_y = wl_fixed_to_int(pointer->y);
+
+       wl_list_for_each(output, &ec->output_list, link) {
+               if (pointer->seat->output && pointer->seat->output != output)
+                       continue;
+               if (pixman_region32_contains_point(&output->region,
+                                                  x, y, NULL))
+                       valid = 1;
+               if (pixman_region32_contains_point(&output->region,
+                                                  old_x, old_y, NULL))
+                       prev = output;
+       }
+
+       if (!prev)
+               prev = pointer->seat->output;
+
+       if (prev && !valid)
+               weston_pointer_clamp_for_output(pointer, prev, fx, fy);
+}
+
+static void
+weston_pointer_move_to(struct weston_pointer *pointer,
+                      wl_fixed_t x, wl_fixed_t y)
+{
+       int32_t ix, iy;
+
+       weston_pointer_clamp (pointer, &x, &y);
+
+       pointer->x = x;
+       pointer->y = y;
+
+       ix = wl_fixed_to_int(x);
+       iy = wl_fixed_to_int(y);
+
+       if (pointer->sprite) {
+               weston_view_set_position(pointer->sprite,
+                                        ix - pointer->hotspot_x,
+                                        iy - pointer->hotspot_y);
+               weston_view_schedule_repaint(pointer->sprite);
+       }
+
+       pointer->grab->interface->focus(pointer->grab);
+       wl_signal_emit(&pointer->motion_signal, pointer);
+}
+
+WL_EXPORT void
+weston_pointer_motion_to_abs(struct weston_pointer *pointer,
+                            struct weston_pointer_motion_event *event,
+                            wl_fixed_t *x, wl_fixed_t *y)
+{
+       if (event->mask & WESTON_POINTER_MOTION_ABS) {
+               *x = wl_fixed_from_double(event->x);
+               *y = wl_fixed_from_double(event->y);
+       } else if (event->mask & WESTON_POINTER_MOTION_REL) {
+               *x = pointer->x + wl_fixed_from_double(event->dx);
+               *y = pointer->y + wl_fixed_from_double(event->dy);
+       } else {
+               assert(!"invalid motion event");
+               *x = *y = 0;
+       }
+}
+
+WL_EXPORT void
+weston_pointer_move(struct weston_pointer *pointer,
+                   struct weston_pointer_motion_event *event)
+{
+       wl_fixed_t x, y;
+
+       weston_pointer_motion_to_abs(pointer, event, &x, &y);
+       weston_pointer_move_to(pointer, x, y);
+}
+
+/** Verify if the pointer is in a valid position and move it if it isn't.
+ */
+static void
+weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data)
+{
+       struct weston_pointer *pointer;
+       struct weston_compositor *ec;
+       struct weston_output *output, *closest = NULL;
+       int x, y, distance, min = INT_MAX;
+       wl_fixed_t fx, fy;
+
+       pointer = container_of(listener, struct weston_pointer,
+                              output_destroy_listener);
+       ec = pointer->seat->compositor;
+
+       x = wl_fixed_to_int(pointer->x);
+       y = wl_fixed_to_int(pointer->y);
+
+       wl_list_for_each(output, &ec->output_list, link) {
+               if (pixman_region32_contains_point(&output->region,
+                                                  x, y, NULL))
+                       return;
+
+               /* Aproximante the distance from the pointer to the center of
+                * the output. */
+               distance = abs(output->x + output->width / 2 - x) +
+                          abs(output->y + output->height / 2 - y);
+               if (distance < min) {
+                       min = distance;
+                       closest = output;
+               }
+       }
+
+       /* Nothing to do if there's no output left. */
+       if (!closest)
+               return;
+
+       fx = pointer->x;
+       fy = pointer->y;
+
+       weston_pointer_clamp_for_output(pointer, closest, &fx, &fy);
+       weston_pointer_move_to(pointer, fx, fy);
+}
+
+WL_EXPORT void
+notify_motion(struct weston_seat *seat,
+             uint32_t time,
+             struct weston_pointer_motion_event *event)
+{
+       struct weston_compositor *ec = seat->compositor;
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       weston_compositor_wake(ec);
+       pointer->grab->interface->motion(pointer->grab, time, event);
+}
+
+static void
+run_modifier_bindings(struct weston_seat *seat, uint32_t old, uint32_t new)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       uint32_t diff;
+       unsigned int i;
+       struct {
+               uint32_t xkb;
+               enum weston_keyboard_modifier weston;
+       } mods[] = {
+               { keyboard->xkb_info->ctrl_mod, MODIFIER_CTRL },
+               { keyboard->xkb_info->alt_mod, MODIFIER_ALT },
+               { keyboard->xkb_info->super_mod, MODIFIER_SUPER },
+               { keyboard->xkb_info->shift_mod, MODIFIER_SHIFT },
+       };
+
+       diff = new & ~old;
+       for (i = 0; i < ARRAY_LENGTH(mods); i++) {
+               if (diff & (1 << mods[i].xkb))
+                       weston_compositor_run_modifier_binding(compositor,
+                                                              keyboard,
+                                                              mods[i].weston,
+                                                              WL_KEYBOARD_KEY_STATE_PRESSED);
+       }
+
+       diff = old & ~new;
+       for (i = 0; i < ARRAY_LENGTH(mods); i++) {
+               if (diff & (1 << mods[i].xkb))
+                       weston_compositor_run_modifier_binding(compositor,
+                                                              keyboard,
+                                                              mods[i].weston,
+                                                              WL_KEYBOARD_KEY_STATE_RELEASED);
+       }
+}
+
+WL_EXPORT void
+notify_motion_absolute(struct weston_seat *seat,
+                      uint32_t time, double x, double y)
+{
+       struct weston_compositor *ec = seat->compositor;
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+       struct weston_pointer_motion_event event = { 0 };
+
+       weston_compositor_wake(ec);
+
+       event = (struct weston_pointer_motion_event) {
+               .mask = WESTON_POINTER_MOTION_ABS,
+               .x = x,
+               .y = y,
+       };
+
+       pointer->grab->interface->motion(pointer->grab, time, &event);
+}
+
+WL_EXPORT void
+weston_surface_activate(struct weston_surface *surface,
+                       struct weston_seat *seat)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+
+       if (keyboard) {
+               weston_keyboard_set_focus(keyboard, surface);
+               wl_data_device_set_keyboard_focus(seat);
+       }
+
+       wl_signal_emit(&compositor->activate_signal, surface);
+}
+
+WL_EXPORT void
+notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
+             enum wl_pointer_button_state state)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
+               weston_compositor_idle_inhibit(compositor);
+               if (pointer->button_count == 0) {
+                       pointer->grab_button = button;
+                       pointer->grab_time = time;
+                       pointer->grab_x = pointer->x;
+                       pointer->grab_y = pointer->y;
+               }
+               pointer->button_count++;
+       } else {
+               weston_compositor_idle_release(compositor);
+               pointer->button_count--;
+       }
+
+       weston_compositor_run_button_binding(compositor, pointer, time, button,
+                                            state);
+
+       pointer->grab->interface->button(pointer->grab, time, button, state);
+
+       if (pointer->button_count == 1)
+               pointer->grab_serial =
+                       wl_display_get_serial(compositor->wl_display);
+}
+
+WL_EXPORT void
+notify_axis(struct weston_seat *seat, uint32_t time,
+           struct weston_pointer_axis_event *event)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       weston_compositor_wake(compositor);
+
+       if (weston_compositor_run_axis_binding(compositor, pointer,
+                                              time, event))
+               return;
+
+       pointer->grab->interface->axis(pointer->grab, time, event);
+}
+
+WL_EXPORT void
+notify_axis_source(struct weston_seat *seat, uint32_t source)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       weston_compositor_wake(compositor);
+
+       pointer->grab->interface->axis_source(pointer->grab, source);
+}
+
+WL_EXPORT void
+notify_pointer_frame(struct weston_seat *seat)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       weston_compositor_wake(compositor);
+
+       pointer->grab->interface->frame(pointer->grab);
+}
+
+WL_EXPORT int
+weston_keyboard_set_locks(struct weston_keyboard *keyboard,
+                         uint32_t mask, uint32_t value)
+{
+#ifdef ENABLE_XKBCOMMON
+       uint32_t serial;
+       xkb_mod_mask_t mods_depressed, mods_latched, mods_locked, group;
+       xkb_mod_mask_t num, caps;
+
+       /* We don't want the leds to go out of sync with the actual state
+        * so if the backend has no way to change the leds don't try to
+        * change the state */
+       if (!keyboard->seat->led_update)
+               return -1;
+
+       mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state,
+                                               XKB_STATE_DEPRESSED);
+       mods_latched = xkb_state_serialize_mods(keyboard->xkb_state.state,
+                                               XKB_STATE_LATCHED);
+       mods_locked = xkb_state_serialize_mods(keyboard->xkb_state.state,
+                                               XKB_STATE_LOCKED);
+       group = xkb_state_serialize_group(keyboard->xkb_state.state,
+                                      XKB_STATE_EFFECTIVE);
+
+       num = (1 << keyboard->xkb_info->mod2_mod);
+       caps = (1 << keyboard->xkb_info->caps_mod);
+       if (mask & WESTON_NUM_LOCK) {
+               if (value & WESTON_NUM_LOCK)
+                       mods_locked |= num;
+               else
+                       mods_locked &= ~num;
+       }
+       if (mask & WESTON_CAPS_LOCK) {
+               if (value & WESTON_CAPS_LOCK)
+                       mods_locked |= caps;
+               else
+                       mods_locked &= ~caps;
+       }
+
+       xkb_state_update_mask(keyboard->xkb_state.state, mods_depressed,
+                             mods_latched, mods_locked, 0, 0, group);
+
+       serial = wl_display_next_serial(
+                               keyboard->seat->compositor->wl_display);
+       notify_modifiers(keyboard->seat, serial);
+
+       return 0;
+#else
+       return -1;
+#endif
+}
+
+#ifdef ENABLE_XKBCOMMON
+WL_EXPORT void
+notify_modifiers(struct weston_seat *seat, uint32_t serial)
+{
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       struct weston_keyboard_grab *grab = keyboard->grab;
+       uint32_t mods_depressed, mods_latched, mods_locked, group;
+       uint32_t mods_lookup;
+       enum weston_led leds = 0;
+       int changed = 0;
+
+       /* Serialize and update our internal state, checking to see if it's
+        * different to the previous state. */
+       mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state,
+                                                 XKB_STATE_MODS_DEPRESSED);
+       mods_latched = xkb_state_serialize_mods(keyboard->xkb_state.state,
+                                               XKB_STATE_MODS_LATCHED);
+       mods_locked = xkb_state_serialize_mods(keyboard->xkb_state.state,
+                                              XKB_STATE_MODS_LOCKED);
+       group = xkb_state_serialize_layout(keyboard->xkb_state.state,
+                                          XKB_STATE_LAYOUT_EFFECTIVE);
+
+       if (mods_depressed != keyboard->modifiers.mods_depressed ||
+           mods_latched != keyboard->modifiers.mods_latched ||
+           mods_locked != keyboard->modifiers.mods_locked ||
+           group != keyboard->modifiers.group)
+               changed = 1;
+
+       run_modifier_bindings(seat, keyboard->modifiers.mods_depressed,
+                             mods_depressed);
+
+       keyboard->modifiers.mods_depressed = mods_depressed;
+       keyboard->modifiers.mods_latched = mods_latched;
+       keyboard->modifiers.mods_locked = mods_locked;
+       keyboard->modifiers.group = group;
+
+       /* And update the modifier_state for bindings. */
+       mods_lookup = mods_depressed | mods_latched;
+       seat->modifier_state = 0;
+       if (mods_lookup & (1 << keyboard->xkb_info->ctrl_mod))
+               seat->modifier_state |= MODIFIER_CTRL;
+       if (mods_lookup & (1 << keyboard->xkb_info->alt_mod))
+               seat->modifier_state |= MODIFIER_ALT;
+       if (mods_lookup & (1 << keyboard->xkb_info->super_mod))
+               seat->modifier_state |= MODIFIER_SUPER;
+       if (mods_lookup & (1 << keyboard->xkb_info->shift_mod))
+               seat->modifier_state |= MODIFIER_SHIFT;
+
+       /* Finally, notify the compositor that LEDs have changed. */
+       if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
+                                         keyboard->xkb_info->num_led))
+               leds |= LED_NUM_LOCK;
+       if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
+                                         keyboard->xkb_info->caps_led))
+               leds |= LED_CAPS_LOCK;
+       if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
+                                         keyboard->xkb_info->scroll_led))
+               leds |= LED_SCROLL_LOCK;
+       if (leds != keyboard->xkb_state.leds && seat->led_update)
+               seat->led_update(seat, leds);
+       keyboard->xkb_state.leds = leds;
+
+       if (changed) {
+               grab->interface->modifiers(grab,
+                                          serial,
+                                          keyboard->modifiers.mods_depressed,
+                                          keyboard->modifiers.mods_latched,
+                                          keyboard->modifiers.mods_locked,
+                                          keyboard->modifiers.group);
+       }
+}
+
+static void
+update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
+                     enum wl_keyboard_key_state state)
+{
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       enum xkb_key_direction direction;
+
+       /* Keyboard modifiers don't exist in raw keyboard mode */
+       if (!seat->compositor->use_xkbcommon)
+               return;
+
+       if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
+               direction = XKB_KEY_DOWN;
+       else
+               direction = XKB_KEY_UP;
+
+       /* Offset the keycode by 8, as the evdev XKB rules reflect X's
+        * broken keycode system, which starts at 8. */
+       xkb_state_update_key(keyboard->xkb_state.state, key + 8, direction);
+
+       notify_modifiers(seat, serial);
+}
+
+static void
+send_keymap(struct wl_resource *resource, struct weston_xkb_info *xkb_info)
+{
+       wl_keyboard_send_keymap(resource,
+                               WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+                               xkb_info->keymap_fd,
+                               xkb_info->keymap_size);
+}
+
+static void
+send_modifiers(struct wl_resource *resource, uint32_t serial, struct weston_keyboard *keyboard)
+{
+       wl_keyboard_send_modifiers(resource, serial,
+                                  keyboard->modifiers.mods_depressed,
+                                  keyboard->modifiers.mods_latched,
+                                  keyboard->modifiers.mods_locked,
+                                  keyboard->modifiers.group);
+}
+
+static struct weston_xkb_info *
+weston_xkb_info_create(struct xkb_keymap *keymap);
+
+static void
+update_keymap(struct weston_seat *seat)
+{
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       struct wl_resource *resource;
+       struct weston_xkb_info *xkb_info;
+       struct xkb_state *state;
+       xkb_mod_mask_t latched_mods;
+       xkb_mod_mask_t locked_mods;
+
+       xkb_info = weston_xkb_info_create(keyboard->pending_keymap);
+
+       xkb_keymap_unref(keyboard->pending_keymap);
+       keyboard->pending_keymap = NULL;
+
+       if (!xkb_info) {
+               weston_log("failed to create XKB info\n");
+               return;
+       }
+
+       state = xkb_state_new(xkb_info->keymap);
+       if (!state) {
+               weston_log("failed to initialise XKB state\n");
+               weston_xkb_info_destroy(xkb_info);
+               return;
+       }
+
+       latched_mods = xkb_state_serialize_mods(keyboard->xkb_state.state,
+                                               XKB_STATE_MODS_LATCHED);
+       locked_mods = xkb_state_serialize_mods(keyboard->xkb_state.state,
+                                              XKB_STATE_MODS_LOCKED);
+       xkb_state_update_mask(state,
+                             0, /* depressed */
+                             latched_mods,
+                             locked_mods,
+                             0, 0, 0);
+
+       weston_xkb_info_destroy(keyboard->xkb_info);
+       keyboard->xkb_info = xkb_info;
+
+       xkb_state_unref(keyboard->xkb_state.state);
+       keyboard->xkb_state.state = state;
+
+       wl_resource_for_each(resource, &keyboard->resource_list)
+               send_keymap(resource, xkb_info);
+       wl_resource_for_each(resource, &keyboard->focus_resource_list)
+               send_keymap(resource, xkb_info);
+
+       notify_modifiers(seat, wl_display_next_serial(seat->compositor->wl_display));
+
+       if (!latched_mods && !locked_mods)
+               return;
+
+       wl_resource_for_each(resource, &keyboard->resource_list)
+               send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), keyboard);
+       wl_resource_for_each(resource, &keyboard->focus_resource_list)
+               send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), keyboard);
+}
+#else
+WL_EXPORT void
+notify_modifiers(struct weston_seat *seat, uint32_t serial)
+{
+}
+
+static void
+update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
+                     enum wl_keyboard_key_state state)
+{
+}
+
+static void
+update_keymap(struct weston_seat *seat)
+{
+}
+#endif
+
+WL_EXPORT void
+notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
+          enum wl_keyboard_key_state state,
+          enum weston_key_state_update update_state)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       struct weston_keyboard_grab *grab = keyboard->grab;
+       uint32_t *k, *end;
+
+       if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+               weston_compositor_idle_inhibit(compositor);
+       } else {
+               weston_compositor_idle_release(compositor);
+       }
+
+       end = keyboard->keys.data + keyboard->keys.size;
+       for (k = keyboard->keys.data; k < end; k++) {
+               if (*k == key) {
+                       /* Ignore server-generated repeats. */
+                       if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
+                               return;
+                       *k = *--end;
+               }
+       }
+       keyboard->keys.size = (void *) end - keyboard->keys.data;
+       if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+               k = wl_array_add(&keyboard->keys, sizeof *k);
+               *k = key;
+       }
+
+       if (grab == &keyboard->default_grab ||
+           grab == &keyboard->input_method_grab) {
+               weston_compositor_run_key_binding(compositor, keyboard, time,
+                                                 key, state);
+               grab = keyboard->grab;
+       }
+
+       grab->interface->key(grab, time, key, state);
+
+       if (keyboard->pending_keymap &&
+           keyboard->keys.size == 0)
+               update_keymap(seat);
+
+       if (update_state == STATE_UPDATE_AUTOMATIC) {
+               update_modifier_state(seat,
+                                     wl_display_get_serial(compositor->wl_display),
+                                     key,
+                                     state);
+       }
+
+       if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+               keyboard->grab_serial =
+                       wl_display_get_serial(compositor->wl_display);
+               keyboard->grab_time = time;
+               keyboard->grab_key = key;
+       }
+}
+
+WL_EXPORT void
+notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
+                    double x, double y)
+{
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       if (output) {
+               weston_pointer_move_to(pointer,
+                                      wl_fixed_from_double(x),
+                                      wl_fixed_from_double(y));
+       } else {
+               /* FIXME: We should call weston_pointer_set_focus(seat,
+                * NULL) here, but somehow that breaks re-entry... */
+       }
+}
+
+static void
+destroy_device_saved_kbd_focus(struct wl_listener *listener, void *data)
+{
+       struct weston_seat *ws;
+
+       ws = container_of(listener, struct weston_seat,
+                         saved_kbd_focus_listener);
+
+       ws->saved_kbd_focus = NULL;
+}
+
+WL_EXPORT void
+notify_keyboard_focus_in(struct weston_seat *seat, struct wl_array *keys,
+                        enum weston_key_state_update update_state)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       struct weston_surface *surface;
+       uint32_t *k, serial;
+
+       serial = wl_display_next_serial(compositor->wl_display);
+       wl_array_copy(&keyboard->keys, keys);
+       wl_array_for_each(k, &keyboard->keys) {
+               weston_compositor_idle_inhibit(compositor);
+               if (update_state == STATE_UPDATE_AUTOMATIC)
+                       update_modifier_state(seat, serial, *k,
+                                             WL_KEYBOARD_KEY_STATE_PRESSED);
+       }
+
+       surface = seat->saved_kbd_focus;
+
+       if (surface) {
+               wl_list_remove(&seat->saved_kbd_focus_listener.link);
+               weston_keyboard_set_focus(keyboard, surface);
+               seat->saved_kbd_focus = NULL;
+       }
+}
+
+WL_EXPORT void
+notify_keyboard_focus_out(struct weston_seat *seat)
+{
+       struct weston_compositor *compositor = seat->compositor;
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+       uint32_t *k, serial;
+
+       serial = wl_display_next_serial(compositor->wl_display);
+       wl_array_for_each(k, &keyboard->keys) {
+               weston_compositor_idle_release(compositor);
+               update_modifier_state(seat, serial, *k,
+                                     WL_KEYBOARD_KEY_STATE_RELEASED);
+       }
+
+       seat->modifier_state = 0;
+
+       if (keyboard->focus) {
+               seat->saved_kbd_focus = keyboard->focus;
+               seat->saved_kbd_focus_listener.notify =
+                       destroy_device_saved_kbd_focus;
+               wl_signal_add(&keyboard->focus->destroy_signal,
+                             &seat->saved_kbd_focus_listener);
+       }
+
+       weston_keyboard_set_focus(keyboard, NULL);
+       weston_keyboard_cancel_grab(keyboard);
+       if (pointer)
+               weston_pointer_cancel_grab(pointer);
+}
+
+WL_EXPORT void
+weston_touch_set_focus(struct weston_touch *touch, struct weston_view *view)
+{
+       struct wl_list *focus_resource_list;
+
+       focus_resource_list = &touch->focus_resource_list;
+
+       if (view && touch->focus &&
+           touch->focus->surface == view->surface) {
+               touch->focus = view;
+               return;
+       }
+
+       wl_list_remove(&touch->focus_resource_listener.link);
+       wl_list_init(&touch->focus_resource_listener.link);
+       wl_list_remove(&touch->focus_view_listener.link);
+       wl_list_init(&touch->focus_view_listener.link);
+
+       if (!wl_list_empty(focus_resource_list)) {
+               move_resources(&touch->resource_list,
+                              focus_resource_list);
+       }
+
+       if (view) {
+               struct wl_client *surface_client;
+
+               if (!view->surface->resource) {
+                       touch->focus = NULL;
+                       return;
+               }
+
+               surface_client = wl_resource_get_client(view->surface->resource);
+               move_resources_for_client(focus_resource_list,
+                                         &touch->resource_list,
+                                         surface_client);
+               wl_resource_add_destroy_listener(view->surface->resource,
+                                                &touch->focus_resource_listener);
+               wl_signal_add(&view->destroy_signal, &touch->focus_view_listener);
+       }
+       touch->focus = view;
+}
+
+/**
+ * notify_touch - emulates button touches and notifies surfaces accordingly.
+ *
+ * It assumes always the correct cycle sequence until it gets here: touch_down
+ * → touch_update → ... → touch_update → touch_end. The driver is responsible
+ * for sending along such order.
+ *
+ */
+WL_EXPORT void
+notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
+             double double_x, double double_y, int touch_type)
+{
+       struct weston_compositor *ec = seat->compositor;
+       struct weston_touch *touch = weston_seat_get_touch(seat);
+       struct weston_touch_grab *grab = touch->grab;
+       struct weston_view *ev;
+       wl_fixed_t sx, sy;
+       wl_fixed_t x = wl_fixed_from_double(double_x);
+       wl_fixed_t y = wl_fixed_from_double(double_y);
+
+       /* Update grab's global coordinates. */
+       if (touch_id == touch->grab_touch_id && touch_type != WL_TOUCH_UP) {
+               touch->grab_x = x;
+               touch->grab_y = y;
+       }
+
+       switch (touch_type) {
+       case WL_TOUCH_DOWN:
+               weston_compositor_idle_inhibit(ec);
+
+               touch->num_tp++;
+
+               /* the first finger down picks the view, and all further go
+                * to that view for the remainder of the touch session i.e.
+                * until all touch points are up again. */
+               if (touch->num_tp == 1) {
+                       ev = weston_compositor_pick_view(ec, x, y, &sx, &sy);
+                       weston_touch_set_focus(touch, ev);
+               } else if (!touch->focus) {
+                       /* Unexpected condition: We have non-initial touch but
+                        * there is no focused surface.
+                        */
+                       weston_log("touch event received with %d points down "
+                                  "but no surface focused\n", touch->num_tp);
+                       return;
+               }
+
+               weston_compositor_run_touch_binding(ec, touch,
+                                                   time, touch_type);
+
+               grab->interface->down(grab, time, touch_id, x, y);
+               if (touch->num_tp == 1) {
+                       touch->grab_serial =
+                               wl_display_get_serial(ec->wl_display);
+                       touch->grab_touch_id = touch_id;
+                       touch->grab_time = time;
+                       touch->grab_x = x;
+                       touch->grab_y = y;
+               }
+
+               break;
+       case WL_TOUCH_MOTION:
+               ev = touch->focus;
+               if (!ev)
+                       break;
+
+               grab->interface->motion(grab, time, touch_id, x, y);
+               break;
+       case WL_TOUCH_UP:
+               if (touch->num_tp == 0) {
+                       /* This can happen if we start out with one or
+                        * more fingers on the touch screen, in which
+                        * case we didn't get the corresponding down
+                        * event. */
+                       weston_log("unmatched touch up event\n");
+                       break;
+               }
+               weston_compositor_idle_release(ec);
+               touch->num_tp--;
+
+               grab->interface->up(grab, time, touch_id);
+               if (touch->num_tp == 0)
+                       weston_touch_set_focus(touch, NULL);
+               break;
+       }
+}
+
+WL_EXPORT void
+notify_touch_frame(struct weston_seat *seat)
+{
+       struct weston_touch *touch = weston_seat_get_touch(seat);
+       struct weston_touch_grab *grab = touch->grab;
+
+       grab->interface->frame(grab);
+}
+
+WL_EXPORT void
+notify_touch_cancel(struct weston_seat *seat)
+{
+       struct weston_touch *touch = weston_seat_get_touch(seat);
+       struct weston_touch_grab *grab = touch->grab;
+
+       grab->interface->cancel(grab);
+}
+
+static int
+pointer_cursor_surface_get_label(struct weston_surface *surface,
+                                char *buf, size_t len)
+{
+       return snprintf(buf, len, "cursor");
+}
+
+static void
+pointer_cursor_surface_configure(struct weston_surface *es,
+                                int32_t dx, int32_t dy)
+{
+       struct weston_pointer *pointer = es->configure_private;
+       int x, y;
+
+       if (es->width == 0)
+               return;
+
+       assert(es == pointer->sprite->surface);
+
+       pointer->hotspot_x -= dx;
+       pointer->hotspot_y -= dy;
+
+       x = wl_fixed_to_int(pointer->x) - pointer->hotspot_x;
+       y = wl_fixed_to_int(pointer->y) - pointer->hotspot_y;
+
+       weston_view_set_position(pointer->sprite, x, y);
+
+       empty_region(&es->pending.input);
+       empty_region(&es->input);
+
+       if (!weston_surface_is_mapped(es)) {
+               weston_layer_entry_insert(&es->compositor->cursor_layer.view_list,
+                                         &pointer->sprite->layer_link);
+               weston_view_update_transform(pointer->sprite);
+       }
+}
+
+static void
+pointer_set_cursor(struct wl_client *client, struct wl_resource *resource,
+                  uint32_t serial, struct wl_resource *surface_resource,
+                  int32_t x, int32_t y)
+{
+       struct weston_pointer *pointer = wl_resource_get_user_data(resource);
+       struct weston_surface *surface = NULL;
+
+       if (surface_resource)
+               surface = wl_resource_get_user_data(surface_resource);
+
+       if (pointer->focus == NULL)
+               return;
+       /* pointer->focus->surface->resource can be NULL. Surfaces like the
+       black_surface used in shell.c for fullscreen don't have
+       a resource, but can still have focus */
+       if (pointer->focus->surface->resource == NULL)
+               return;
+       if (wl_resource_get_client(pointer->focus->surface->resource) != client)
+               return;
+       if (pointer->focus_serial - serial > UINT32_MAX / 2)
+               return;
+
+       if (!surface) {
+               if (pointer->sprite)
+                       pointer_unmap_sprite(pointer);
+               return;
+       }
+
+       if (pointer->sprite && pointer->sprite->surface == surface &&
+           pointer->hotspot_x == x && pointer->hotspot_y == y)
+               return;
+
+       if (!pointer->sprite || pointer->sprite->surface != surface) {
+               if (weston_surface_set_role(surface, "wl_pointer-cursor",
+                                           resource,
+                                           WL_POINTER_ERROR_ROLE) < 0)
+                       return;
+
+               if (pointer->sprite)
+                       pointer_unmap_sprite(pointer);
+
+               wl_signal_add(&surface->destroy_signal,
+                             &pointer->sprite_destroy_listener);
+
+               surface->configure = pointer_cursor_surface_configure;
+               surface->configure_private = pointer;
+               weston_surface_set_label_func(surface,
+                                           pointer_cursor_surface_get_label);
+               pointer->sprite = weston_view_create(surface);
+       }
+
+       pointer->hotspot_x = x;
+       pointer->hotspot_y = y;
+
+       if (surface->buffer_ref.buffer) {
+               pointer_cursor_surface_configure(surface, 0, 0);
+               weston_view_schedule_repaint(pointer->sprite);
+       }
+}
+
+static void
+pointer_release(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_pointer_interface pointer_interface = {
+       pointer_set_cursor,
+       pointer_release
+};
+
+static void
+seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
+                uint32_t id)
+{
+       struct weston_seat *seat = wl_resource_get_user_data(resource);
+       /* We use the pointer_state directly, which means we'll
+        * give a wl_pointer if the seat has ever had one - even though
+        * the spec explicitly states that this request only takes effect
+        * if the seat has the pointer capability.
+        *
+        * This prevents a race between the compositor sending new
+        * capabilities and the client trying to use the old ones.
+        */
+       struct weston_pointer *pointer = seat->pointer_state;
+       struct wl_resource *cr;
+       struct weston_pointer_client *pointer_client;
+
+       if (!pointer)
+               return;
+
+        cr = wl_resource_create(client, &wl_pointer_interface,
+                               wl_resource_get_version(resource), id);
+       if (cr == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       pointer_client = weston_pointer_ensure_pointer_client(pointer, client);
+       if (!pointer_client) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_list_insert(&pointer_client->pointer_resources,
+                      wl_resource_get_link(cr));
+       wl_resource_set_implementation(cr, &pointer_interface, pointer,
+                                      unbind_pointer_client_resource);
+
+       if (pointer->focus && pointer->focus->surface->resource &&
+           wl_resource_get_client(pointer->focus->surface->resource) == client) {
+               wl_fixed_t sx, sy;
+
+               weston_view_from_global_fixed(pointer->focus,
+                                             pointer->x,
+                                             pointer->y,
+                                             &sx, &sy);
+
+               wl_pointer_send_enter(cr,
+                                     pointer->focus_serial,
+                                     pointer->focus->surface->resource,
+                                     sx, sy);
+               pointer_send_frame(cr);
+       }
+}
+
+static void
+keyboard_release(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_keyboard_interface keyboard_interface = {
+       keyboard_release
+};
+
+static bool
+should_send_modifiers_to_client(struct weston_seat *seat,
+                               struct wl_client *client)
+{
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       if (keyboard &&
+           keyboard->focus &&
+           keyboard->focus->resource &&
+           wl_resource_get_client(keyboard->focus->resource) == client)
+               return true;
+
+       if (pointer &&
+           pointer->focus &&
+           pointer->focus->surface->resource &&
+           wl_resource_get_client(pointer->focus->surface->resource) == client)
+               return true;
+
+       return false;
+}
+
+static void
+seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
+                 uint32_t id)
+{
+       struct weston_seat *seat = wl_resource_get_user_data(resource);
+       /* We use the keyboard_state directly, which means we'll
+        * give a wl_keyboard if the seat has ever had one - even though
+        * the spec explicitly states that this request only takes effect
+        * if the seat has the keyboard capability.
+        *
+        * This prevents a race between the compositor sending new
+        * capabilities and the client trying to use the old ones.
+        */
+       struct weston_keyboard *keyboard = seat->keyboard_state;
+       struct wl_resource *cr;
+
+       if (!keyboard)
+               return;
+
+        cr = wl_resource_create(client, &wl_keyboard_interface,
+                               wl_resource_get_version(resource), id);
+       if (cr == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       /* May be moved to focused list later by either
+        * weston_keyboard_set_focus or directly if this client is already
+        * focused */
+       wl_list_insert(&keyboard->resource_list, wl_resource_get_link(cr));
+       wl_resource_set_implementation(cr, &keyboard_interface,
+                                      seat, unbind_resource);
+
+       if (wl_resource_get_version(cr) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
+               wl_keyboard_send_repeat_info(cr,
+                                            seat->compositor->kb_repeat_rate,
+                                            seat->compositor->kb_repeat_delay);
+       }
+
+       if (seat->compositor->use_xkbcommon) {
+               wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
+                                       keyboard->xkb_info->keymap_fd,
+                                       keyboard->xkb_info->keymap_size);
+       } else {
+               int null_fd = open("/dev/null", O_RDONLY);
+               wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP,
+                                       null_fd,
+                                       0);
+               close(null_fd);
+       }
+
+       if (should_send_modifiers_to_client(seat, client)) {
+               send_modifiers_to_resource(keyboard,
+                                          cr,
+                                          keyboard->focus_serial);
+       }
+
+       if (keyboard->focus && keyboard->focus->resource &&
+           wl_resource_get_client(keyboard->focus->resource) == client) {
+               struct weston_surface *surface =
+                       (struct weston_surface *)keyboard->focus;
+
+               wl_list_remove(wl_resource_get_link(cr));
+               wl_list_insert(&keyboard->focus_resource_list,
+                              wl_resource_get_link(cr));
+               wl_keyboard_send_enter(cr,
+                                      keyboard->focus_serial,
+                                      surface->resource,
+                                      &keyboard->keys);
+
+               /* If this is the first keyboard resource for this
+                * client... */
+               if (keyboard->focus_resource_list.prev ==
+                   wl_resource_get_link(cr))
+                       wl_data_device_set_keyboard_focus(seat);
+       }
+}
+
+static void
+touch_release(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_touch_interface touch_interface = {
+       touch_release
+};
+
+static void
+seat_get_touch(struct wl_client *client, struct wl_resource *resource,
+              uint32_t id)
+{
+       struct weston_seat *seat = wl_resource_get_user_data(resource);
+       /* We use the touch_state directly, which means we'll
+        * give a wl_touch if the seat has ever had one - even though
+        * the spec explicitly states that this request only takes effect
+        * if the seat has the touch capability.
+        *
+        * This prevents a race between the compositor sending new
+        * capabilities and the client trying to use the old ones.
+        */
+       struct weston_touch *touch = seat->touch_state;
+       struct wl_resource *cr;
+
+       if (!touch)
+               return;
+
+        cr = wl_resource_create(client, &wl_touch_interface,
+                               wl_resource_get_version(resource), id);
+       if (cr == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       if (touch->focus &&
+           wl_resource_get_client(touch->focus->surface->resource) == client) {
+               wl_list_insert(&touch->focus_resource_list,
+                              wl_resource_get_link(cr));
+       } else {
+               wl_list_insert(&touch->resource_list,
+                              wl_resource_get_link(cr));
+       }
+       wl_resource_set_implementation(cr, &touch_interface,
+                                      seat, unbind_resource);
+}
+
+static void
+seat_release(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_seat_interface seat_interface = {
+       seat_get_pointer,
+       seat_get_keyboard,
+       seat_get_touch,
+       seat_release,
+};
+
+static void
+bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
+{
+       struct weston_seat *seat = data;
+       struct wl_resource *resource;
+       enum wl_seat_capability caps = 0;
+
+       resource = wl_resource_create(client,
+                                     &wl_seat_interface, version, id);
+       wl_list_insert(&seat->base_resource_list, wl_resource_get_link(resource));
+       wl_resource_set_implementation(resource, &seat_interface, data,
+                                      unbind_resource);
+
+       if (weston_seat_get_pointer(seat))
+               caps |= WL_SEAT_CAPABILITY_POINTER;
+       if (weston_seat_get_keyboard(seat))
+               caps |= WL_SEAT_CAPABILITY_KEYBOARD;
+       if (weston_seat_get_touch(seat))
+               caps |= WL_SEAT_CAPABILITY_TOUCH;
+
+       wl_seat_send_capabilities(resource, caps);
+       if (version >= WL_SEAT_NAME_SINCE_VERSION)
+               wl_seat_send_name(resource, seat->seat_name);
+}
+
+#ifdef ENABLE_XKBCOMMON
+WL_EXPORT int
+weston_compositor_set_xkb_rule_names(struct weston_compositor *ec,
+                                    struct xkb_rule_names *names)
+{
+       ec->use_xkbcommon = 1;
+
+       if (ec->xkb_context == NULL) {
+               ec->xkb_context = xkb_context_new(0);
+               if (ec->xkb_context == NULL) {
+                       weston_log("failed to create XKB context\n");
+                       return -1;
+               }
+       }
+
+       if (names)
+               ec->xkb_names = *names;
+       if (!ec->xkb_names.rules)
+               ec->xkb_names.rules = strdup("evdev");
+       if (!ec->xkb_names.model)
+               ec->xkb_names.model = strdup("pc105");
+       if (!ec->xkb_names.layout)
+               ec->xkb_names.layout = strdup("us");
+
+       return 0;
+}
+
+static void
+weston_xkb_info_destroy(struct weston_xkb_info *xkb_info)
+{
+       if (--xkb_info->ref_count > 0)
+               return;
+
+       xkb_keymap_unref(xkb_info->keymap);
+
+       if (xkb_info->keymap_area)
+               munmap(xkb_info->keymap_area, xkb_info->keymap_size);
+       if (xkb_info->keymap_fd >= 0)
+               close(xkb_info->keymap_fd);
+       free(xkb_info);
+}
+
+void
+weston_compositor_xkb_destroy(struct weston_compositor *ec)
+{
+       /*
+        * If we're operating in raw keyboard mode, we never initialized
+        * libxkbcommon so there's no cleanup to do either.
+        */
+       if (!ec->use_xkbcommon)
+               return;
+
+       free((char *) ec->xkb_names.rules);
+       free((char *) ec->xkb_names.model);
+       free((char *) ec->xkb_names.layout);
+       free((char *) ec->xkb_names.variant);
+       free((char *) ec->xkb_names.options);
+
+       if (ec->xkb_info)
+               weston_xkb_info_destroy(ec->xkb_info);
+       xkb_context_unref(ec->xkb_context);
+}
+
+static struct weston_xkb_info *
+weston_xkb_info_create(struct xkb_keymap *keymap)
+{
+       struct weston_xkb_info *xkb_info = zalloc(sizeof *xkb_info);
+       if (xkb_info == NULL)
+               return NULL;
+
+       xkb_info->keymap = xkb_keymap_ref(keymap);
+       xkb_info->ref_count = 1;
+
+       char *keymap_str;
+
+       xkb_info->shift_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
+                                                      XKB_MOD_NAME_SHIFT);
+       xkb_info->caps_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
+                                                     XKB_MOD_NAME_CAPS);
+       xkb_info->ctrl_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
+                                                     XKB_MOD_NAME_CTRL);
+       xkb_info->alt_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
+                                                    XKB_MOD_NAME_ALT);
+       xkb_info->mod2_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
+                                                     "Mod2");
+       xkb_info->mod3_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
+                                                     "Mod3");
+       xkb_info->super_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
+                                                      XKB_MOD_NAME_LOGO);
+       xkb_info->mod5_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
+                                                     "Mod5");
+
+       xkb_info->num_led = xkb_keymap_led_get_index(xkb_info->keymap,
+                                                    XKB_LED_NAME_NUM);
+       xkb_info->caps_led = xkb_keymap_led_get_index(xkb_info->keymap,
+                                                     XKB_LED_NAME_CAPS);
+       xkb_info->scroll_led = xkb_keymap_led_get_index(xkb_info->keymap,
+                                                       XKB_LED_NAME_SCROLL);
+
+       keymap_str = xkb_keymap_get_as_string(xkb_info->keymap,
+                                             XKB_KEYMAP_FORMAT_TEXT_V1);
+       if (keymap_str == NULL) {
+               weston_log("failed to get string version of keymap\n");
+               goto err_keymap;
+       }
+       xkb_info->keymap_size = strlen(keymap_str) + 1;
+
+       xkb_info->keymap_fd = os_create_anonymous_file(xkb_info->keymap_size);
+       if (xkb_info->keymap_fd < 0) {
+               weston_log("creating a keymap file for %lu bytes failed: %m\n",
+                       (unsigned long) xkb_info->keymap_size);
+               goto err_keymap_str;
+       }
+
+       xkb_info->keymap_area = mmap(NULL, xkb_info->keymap_size,
+                                    PROT_READ | PROT_WRITE,
+                                    MAP_SHARED, xkb_info->keymap_fd, 0);
+       if (xkb_info->keymap_area == MAP_FAILED) {
+               weston_log("failed to mmap() %lu bytes\n",
+                       (unsigned long) xkb_info->keymap_size);
+               goto err_dev_zero;
+       }
+       strcpy(xkb_info->keymap_area, keymap_str);
+       free(keymap_str);
+
+       return xkb_info;
+
+err_dev_zero:
+       close(xkb_info->keymap_fd);
+err_keymap_str:
+       free(keymap_str);
+err_keymap:
+       xkb_keymap_unref(xkb_info->keymap);
+       free(xkb_info);
+       return NULL;
+}
+
+static int
+weston_compositor_build_global_keymap(struct weston_compositor *ec)
+{
+       struct xkb_keymap *keymap;
+
+       if (ec->xkb_info != NULL)
+               return 0;
+
+       keymap = xkb_keymap_new_from_names(ec->xkb_context,
+                                          &ec->xkb_names,
+                                          0);
+       if (keymap == NULL) {
+               weston_log("failed to compile global XKB keymap\n");
+               weston_log("  tried rules %s, model %s, layout %s, variant %s, "
+                       "options %s\n",
+                       ec->xkb_names.rules, ec->xkb_names.model,
+                       ec->xkb_names.layout, ec->xkb_names.variant,
+                       ec->xkb_names.options);
+               return -1;
+       }
+
+       ec->xkb_info = weston_xkb_info_create(keymap);
+       xkb_keymap_unref(keymap);
+       if (ec->xkb_info == NULL)
+               return -1;
+
+       return 0;
+}
+#else
+WL_EXPORT int
+weston_compositor_set_xkb_rule_names(struct weston_compositor *ec,
+                                    struct xkb_rule_names *names)
+{
+       return 0;
+}
+
+void
+weston_compositor_xkb_destroy(struct weston_compositor *ec)
+{
+}
+#endif
+
+WL_EXPORT void
+weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap)
+{
+       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
+
+       if (!keyboard || !keymap)
+               return;
+
+#ifdef ENABLE_XKBCOMMON
+       if (!seat->compositor->use_xkbcommon)
+               return;
+
+       xkb_keymap_unref(keyboard->pending_keymap);
+       keyboard->pending_keymap = xkb_keymap_ref(keymap);
+
+       if (keyboard->keys.size == 0)
+               update_keymap(seat);
+#endif
+}
+
+WL_EXPORT int
+weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
+{
+       struct weston_keyboard *keyboard;
+
+       if (seat->keyboard_state) {
+               seat->keyboard_device_count += 1;
+               if (seat->keyboard_device_count == 1)
+                       seat_send_updated_caps(seat);
+               return 0;
+       }
+
+       keyboard = weston_keyboard_create();
+       if (keyboard == NULL) {
+               weston_log("failed to allocate weston keyboard struct\n");
+               return -1;
+       }
+
+#ifdef ENABLE_XKBCOMMON
+       if (seat->compositor->use_xkbcommon) {
+               if (keymap != NULL) {
+                       keyboard->xkb_info = weston_xkb_info_create(keymap);
+                       if (keyboard->xkb_info == NULL)
+                               goto err;
+               } else {
+                       if (weston_compositor_build_global_keymap(seat->compositor) < 0)
+                               goto err;
+                       keyboard->xkb_info = seat->compositor->xkb_info;
+                       keyboard->xkb_info->ref_count++;
+               }
+
+               keyboard->xkb_state.state = xkb_state_new(keyboard->xkb_info->keymap);
+               if (keyboard->xkb_state.state == NULL) {
+                       weston_log("failed to initialise XKB state\n");
+                       goto err;
+               }
+
+               keyboard->xkb_state.leds = 0;
+       }
+#endif
+
+       seat->keyboard_state = keyboard;
+       seat->keyboard_device_count = 1;
+       keyboard->seat = seat;
+
+       seat_send_updated_caps(seat);
+
+       return 0;
+
+err:
+       if (keyboard->xkb_info)
+               weston_xkb_info_destroy(keyboard->xkb_info);
+       free(keyboard);
+
+       return -1;
+}
+
+static void
+weston_keyboard_reset_state(struct weston_keyboard *keyboard)
+{
+       struct weston_seat *seat = keyboard->seat;
+       struct xkb_state *state;
+
+#ifdef ENABLE_XKBCOMMON
+       if (seat->compositor->use_xkbcommon) {
+               state = xkb_state_new(keyboard->xkb_info->keymap);
+               if (!state) {
+                       weston_log("failed to reset XKB state\n");
+                       return;
+               }
+               xkb_state_unref(keyboard->xkb_state.state);
+               keyboard->xkb_state.state = state;
+
+               keyboard->xkb_state.leds = 0;
+       }
+#endif
+
+       seat->modifier_state = 0;
+}
+
+WL_EXPORT void
+weston_seat_release_keyboard(struct weston_seat *seat)
+{
+       seat->keyboard_device_count--;
+       assert(seat->keyboard_device_count >= 0);
+       if (seat->keyboard_device_count == 0) {
+               weston_keyboard_set_focus(seat->keyboard_state, NULL);
+               weston_keyboard_cancel_grab(seat->keyboard_state);
+               weston_keyboard_reset_state(seat->keyboard_state);
+               seat_send_updated_caps(seat);
+       }
+}
+
+WL_EXPORT void
+weston_seat_init_pointer(struct weston_seat *seat)
+{
+       struct weston_pointer *pointer;
+
+       if (seat->pointer_state) {
+               seat->pointer_device_count += 1;
+               if (seat->pointer_device_count == 1)
+                       seat_send_updated_caps(seat);
+               return;
+       }
+
+       pointer = weston_pointer_create(seat);
+       if (pointer == NULL)
+               return;
+
+       seat->pointer_state = pointer;
+       seat->pointer_device_count = 1;
+       pointer->seat = seat;
+
+       seat_send_updated_caps(seat);
+}
+
+WL_EXPORT void
+weston_seat_release_pointer(struct weston_seat *seat)
+{
+       struct weston_pointer *pointer = seat->pointer_state;
+
+       seat->pointer_device_count--;
+       if (seat->pointer_device_count == 0) {
+               weston_pointer_clear_focus(pointer);
+               weston_pointer_cancel_grab(pointer);
+
+               if (pointer->sprite)
+                       pointer_unmap_sprite(pointer);
+
+               weston_pointer_reset_state(pointer);
+               seat_send_updated_caps(seat);
+
+               /* seat->pointer is intentionally not destroyed so that
+                * a newly attached pointer on this seat will retain
+                * the previous cursor co-ordinates.
+                */
+       }
+}
+
+WL_EXPORT void
+weston_seat_init_touch(struct weston_seat *seat)
+{
+       struct weston_touch *touch;
+
+       if (seat->touch_state) {
+               seat->touch_device_count += 1;
+               if (seat->touch_device_count == 1)
+                       seat_send_updated_caps(seat);
+               return;
+       }
+
+       touch = weston_touch_create();
+       if (touch == NULL)
+               return;
+
+       seat->touch_state = touch;
+       seat->touch_device_count = 1;
+       touch->seat = seat;
+
+       seat_send_updated_caps(seat);
+}
+
+WL_EXPORT void
+weston_seat_release_touch(struct weston_seat *seat)
+{
+       seat->touch_device_count--;
+       if (seat->touch_device_count == 0) {
+               weston_touch_set_focus(seat->touch_state, NULL);
+               weston_touch_cancel_grab(seat->touch_state);
+               weston_touch_reset_state(seat->touch_state);
+               seat_send_updated_caps(seat);
+       }
+}
+
+WL_EXPORT void
+weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
+                const char *seat_name)
+{
+       memset(seat, 0, sizeof *seat);
+
+       seat->selection_data_source = NULL;
+       wl_list_init(&seat->base_resource_list);
+       wl_signal_init(&seat->selection_signal);
+       wl_list_init(&seat->drag_resource_list);
+       wl_signal_init(&seat->destroy_signal);
+       wl_signal_init(&seat->updated_caps_signal);
+
+       seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 5,
+                                       seat, bind_seat);
+
+       seat->compositor = ec;
+       seat->modifier_state = 0;
+       seat->seat_name = strdup(seat_name);
+
+       wl_list_insert(ec->seat_list.prev, &seat->link);
+
+       clipboard_create(seat);
+
+       wl_signal_emit(&ec->seat_created_signal, seat);
+}
+
+WL_EXPORT void
+weston_seat_release(struct weston_seat *seat)
+{
+       wl_list_remove(&seat->link);
+
+       if (seat->saved_kbd_focus)
+               wl_list_remove(&seat->saved_kbd_focus_listener.link);
+
+       if (seat->pointer_state)
+               weston_pointer_destroy(seat->pointer_state);
+       if (seat->keyboard_state)
+               weston_keyboard_destroy(seat->keyboard_state);
+       if (seat->touch_state)
+               weston_touch_destroy(seat->touch_state);
+
+       free (seat->seat_name);
+
+       wl_global_destroy(seat->global);
+
+       wl_signal_emit(&seat->destroy_signal, seat);
+}
+
+/** Get a seat's keyboard pointer
+ *
+ * \param seat The seat to query
+ * \return The seat's keyboard pointer, or NULL if no keyboard is present
+ *
+ * The keyboard pointer for a seat isn't freed when all keyboards are removed,
+ * so it should only be used when the seat's keyboard_device_count is greater
+ * than zero.  This function does that test and only returns a pointer
+ * when a keyboard is present.
+ */
+WL_EXPORT struct weston_keyboard *
+weston_seat_get_keyboard(struct weston_seat *seat)
+{
+       if (!seat)
+               return NULL;
+
+       if (seat->keyboard_device_count)
+               return seat->keyboard_state;
+
+       return NULL;
+}
+
+/** Get a seat's pointer pointer
+ *
+ * \param seat The seat to query
+ * \return The seat's pointer pointer, or NULL if no pointer device is present
+ *
+ * The pointer pointer for a seat isn't freed when all mice are removed,
+ * so it should only be used when the seat's pointer_device_count is greater
+ * than zero.  This function does that test and only returns a pointer
+ * when a pointing device is present.
+ */
+WL_EXPORT struct weston_pointer *
+weston_seat_get_pointer(struct weston_seat *seat)
+{
+       if (!seat)
+               return NULL;
+
+       if (seat->pointer_device_count)
+               return seat->pointer_state;
+
+       return NULL;
+}
+
+/** Get a seat's touch pointer
+ *
+ * \param seat The seat to query
+ * \return The seat's touch pointer, or NULL if no touch device is present
+ *
+ * The touch pointer for a seat isn't freed when all touch devices are removed,
+ * so it should only be used when the seat's touch_device_count is greater
+ * than zero.  This function does that test and only returns a pointer
+ * when a touch device is present.
+ */
+WL_EXPORT struct weston_touch *
+weston_seat_get_touch(struct weston_seat *seat)
+{
+       if (!seat)
+               return NULL;
+
+       if (seat->touch_device_count)
+               return seat->touch_state;
+
+       return NULL;
+}
diff --git a/libweston/launcher-direct.c b/libweston/launcher-direct.c
new file mode 100644 (file)
index 0000000..29d9c28
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ * Copyright © 2012 Benjamin Franzke
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "compositor.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include <linux/major.h>
+
+#include "launcher-impl.h"
+
+#define DRM_MAJOR 226
+
+#ifndef KDSKBMUTE
+#define KDSKBMUTE      0x4B51
+#endif
+
+#ifdef HAVE_LIBDRM
+
+#include <xf86drm.h>
+
+static inline int
+is_drm_master(int drm_fd)
+{
+       drm_magic_t magic;
+
+       return drmGetMagic(drm_fd, &magic) == 0 &&
+               drmAuthMagic(drm_fd, magic) == 0;
+}
+
+#else
+
+static inline int
+drmDropMaster(int drm_fd)
+{
+       return 0;
+}
+
+static inline int
+drmSetMaster(int drm_fd)
+{
+       return 0;
+}
+
+static inline int
+is_drm_master(int drm_fd)
+{
+       return 0;
+}
+
+#endif
+
+struct launcher_direct {
+       struct weston_launcher base;
+       struct weston_compositor *compositor;
+       int kb_mode, tty, drm_fd;
+       struct wl_event_source *vt_source;
+};
+
+static int
+vt_handler(int signal_number, void *data)
+{
+       struct launcher_direct *launcher = data;
+       struct weston_compositor *compositor = launcher->compositor;
+
+       if (compositor->session_active) {
+               compositor->session_active = 0;
+               wl_signal_emit(&compositor->session_signal, compositor);
+               drmDropMaster(launcher->drm_fd);
+               ioctl(launcher->tty, VT_RELDISP, 1);
+       } else {
+               ioctl(launcher->tty, VT_RELDISP, VT_ACKACQ);
+               drmSetMaster(launcher->drm_fd);
+               compositor->session_active = 1;
+               wl_signal_emit(&compositor->session_signal, compositor);
+       }
+
+       return 1;
+}
+
+static int
+setup_tty(struct launcher_direct *launcher, int tty)
+{
+       struct wl_event_loop *loop;
+       struct vt_mode mode = { 0 };
+       struct stat buf;
+       char tty_device[32] ="<stdin>";
+       int ret, kd_mode;
+
+       if (tty == 0) {
+               launcher->tty = dup(tty);
+               if (launcher->tty == -1) {
+                       weston_log("couldn't dup stdin: %m\n");
+                       return -1;
+               }
+       } else {
+               snprintf(tty_device, sizeof tty_device, "/dev/tty%d", tty);
+               launcher->tty = open(tty_device, O_RDWR | O_CLOEXEC);
+               if (launcher->tty == -1) {
+                       weston_log("couldn't open tty %s: %m\n", tty_device);
+                       return -1;
+               }
+       }
+
+       if (fstat(launcher->tty, &buf) == -1 ||
+           major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
+               weston_log("%s not a vt\n", tty_device);
+               weston_log("if running weston from ssh, "
+                          "use --tty to specify a tty\n");
+               goto err_close;
+       }
+
+       ret = ioctl(launcher->tty, KDGETMODE, &kd_mode);
+       if (ret) {
+               weston_log("failed to get VT mode: %m\n");
+               return -1;
+       }
+       if (kd_mode != KD_TEXT) {
+               weston_log("%s is already in graphics mode, "
+                          "is another display server running?\n", tty_device);
+               goto err_close;
+       }
+
+       ioctl(launcher->tty, VT_ACTIVATE, minor(buf.st_rdev));
+       ioctl(launcher->tty, VT_WAITACTIVE, minor(buf.st_rdev));
+
+       if (ioctl(launcher->tty, KDGKBMODE, &launcher->kb_mode)) {
+               weston_log("failed to read keyboard mode: %m\n");
+               goto err_close;
+       }
+
+       if (ioctl(launcher->tty, KDSKBMUTE, 1) &&
+           ioctl(launcher->tty, KDSKBMODE, K_OFF)) {
+               weston_log("failed to set K_OFF keyboard mode: %m\n");
+               goto err_close;
+       }
+
+       ret = ioctl(launcher->tty, KDSETMODE, KD_GRAPHICS);
+       if (ret) {
+               weston_log("failed to set KD_GRAPHICS mode on tty: %m\n");
+               goto err_close;
+       }
+
+       /*
+        * SIGRTMIN is used as global VT-acquire+release signal. Note that
+        * SIGRT* must be tested on runtime, as their exact values are not
+        * known at compile-time. POSIX requires 32 of them to be available.
+        */
+       if (SIGRTMIN > SIGRTMAX) {
+               weston_log("not enough RT signals available: %u-%u\n",
+                          SIGRTMIN, SIGRTMAX);
+               ret = -EINVAL;
+               goto err_close;
+       }
+
+       mode.mode = VT_PROCESS;
+       mode.relsig = SIGRTMIN;
+       mode.acqsig = SIGRTMIN;
+       if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0) {
+               weston_log("failed to take control of vt handling\n");
+               goto err_close;
+       }
+
+       loop = wl_display_get_event_loop(launcher->compositor->wl_display);
+       launcher->vt_source =
+               wl_event_loop_add_signal(loop, SIGRTMIN, vt_handler, launcher);
+       if (!launcher->vt_source)
+               goto err_close;
+
+       return 0;
+
+ err_close:
+       close(launcher->tty);
+       return -1;
+}
+
+static int
+launcher_direct_open(struct weston_launcher *launcher_base, const char *path, int flags)
+{
+       struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
+       struct stat s;
+       int fd;
+
+       fd = open(path, flags | O_CLOEXEC);
+       if (fd == -1)
+               return -1;
+
+       if (fstat(fd, &s) == -1) {
+               close(fd);
+               return -1;
+       }
+
+       if (major(s.st_rdev) == DRM_MAJOR) {
+               launcher->drm_fd = fd;
+               if (!is_drm_master(fd)) {
+                       weston_log("drm fd not master\n");
+                       close(fd);
+                       return -1;
+               }
+       }
+
+       return fd;
+}
+
+static void
+launcher_direct_close(struct weston_launcher *launcher_base, int fd)
+{
+       close(fd);
+}
+
+static void
+launcher_direct_restore(struct weston_launcher *launcher_base)
+{
+       struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
+       struct vt_mode mode = { 0 };
+
+       if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
+           ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
+               weston_log("failed to restore kb mode: %m\n");
+
+       if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
+               weston_log("failed to set KD_TEXT mode on tty: %m\n");
+
+       /* We have to drop master before we switch the VT back in
+        * VT_AUTO, so we don't risk switching to a VT with another
+        * display server, that will then fail to set drm master. */
+       drmDropMaster(launcher->drm_fd);
+
+       mode.mode = VT_AUTO;
+       if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
+               weston_log("could not reset vt handling\n");
+}
+
+static int
+launcher_direct_activate_vt(struct weston_launcher *launcher_base, int vt)
+{
+       struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
+       return ioctl(launcher->tty, VT_ACTIVATE, vt);
+}
+
+static int
+launcher_direct_connect(struct weston_launcher **out, struct weston_compositor *compositor,
+                       int tty, const char *seat_id, bool sync_drm)
+{
+       struct launcher_direct *launcher;
+
+       if (geteuid() != 0)
+               return -EINVAL;
+
+       launcher = zalloc(sizeof(*launcher));
+       if (launcher == NULL)
+               return -ENOMEM;
+
+       launcher->base.iface = &launcher_direct_iface;
+       launcher->compositor = compositor;
+
+       if (setup_tty(launcher, tty) == -1) {
+               free(launcher);
+               return -1;
+       }
+
+       * (struct launcher_direct **) out = launcher;
+       return 0;
+}
+
+static void
+launcher_direct_destroy(struct weston_launcher *launcher_base)
+{
+       struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
+
+       launcher_direct_restore(&launcher->base);
+       wl_event_source_remove(launcher->vt_source);
+
+       if (launcher->tty >= 0)
+               close(launcher->tty);
+
+       free(launcher);
+}
+
+struct launcher_interface launcher_direct_iface = {
+       launcher_direct_connect,
+       launcher_direct_destroy,
+       launcher_direct_open,
+       launcher_direct_close,
+       launcher_direct_activate_vt,
+       launcher_direct_restore,
+};
diff --git a/libweston/launcher-impl.h b/libweston/launcher-impl.h
new file mode 100644 (file)
index 0000000..742721b
--- /dev/null
@@ -0,0 +1,45 @@
+/*
+ * Copyright © 2015 Jasper St. Pierre
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "compositor.h"
+
+struct weston_launcher;
+
+struct launcher_interface {
+       int (* connect) (struct weston_launcher **launcher_out, struct weston_compositor *compositor,
+                        int tty, const char *seat_id, bool sync_drm);
+       void (* destroy) (struct weston_launcher *launcher);
+       int (* open) (struct weston_launcher *launcher, const char *path, int flags);
+       void (* close) (struct weston_launcher *launcher, int fd);
+       int (* activate_vt) (struct weston_launcher *launcher, int vt);
+       void (* restore) (struct weston_launcher *launcher);
+};
+
+struct weston_launcher {
+       struct launcher_interface *iface;
+};
+
+extern struct launcher_interface launcher_logind_iface;
+extern struct launcher_interface launcher_weston_launch_iface;
+extern struct launcher_interface launcher_direct_iface;
diff --git a/libweston/launcher-logind.c b/libweston/launcher-logind.c
new file mode 100644 (file)
index 0000000..f755ec3
--- /dev/null
@@ -0,0 +1,839 @@
+/*
+ * Copyright © 2013 David Herrmann
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <systemd/sd-login.h>
+#include <unistd.h>
+
+#include "compositor.h"
+#include "dbus.h"
+#include "launcher-impl.h"
+
+#define DRM_MAJOR 226
+
+struct launcher_logind {
+       struct weston_launcher base;
+       struct weston_compositor *compositor;
+       bool sync_drm;
+       char *seat;
+       char *sid;
+       unsigned int vtnr;
+       int vt;
+       int kb_mode;
+
+       DBusConnection *dbus;
+       struct wl_event_source *dbus_ctx;
+       char *spath;
+       DBusPendingCall *pending_active;
+};
+
+static int
+launcher_logind_take_device(struct launcher_logind *wl, uint32_t major,
+                         uint32_t minor, bool *paused_out)
+{
+       DBusMessage *m, *reply;
+       bool b;
+       int r, fd;
+       dbus_bool_t paused;
+
+       m = dbus_message_new_method_call("org.freedesktop.login1",
+                                        wl->spath,
+                                        "org.freedesktop.login1.Session",
+                                        "TakeDevice");
+       if (!m)
+               return -ENOMEM;
+
+       b = dbus_message_append_args(m,
+                                    DBUS_TYPE_UINT32, &major,
+                                    DBUS_TYPE_UINT32, &minor,
+                                    DBUS_TYPE_INVALID);
+       if (!b) {
+               r = -ENOMEM;
+               goto err_unref;
+       }
+
+       reply = dbus_connection_send_with_reply_and_block(wl->dbus, m,
+                                                         -1, NULL);
+       if (!reply) {
+               r = -ENODEV;
+               goto err_unref;
+       }
+
+       b = dbus_message_get_args(reply, NULL,
+                                 DBUS_TYPE_UNIX_FD, &fd,
+                                 DBUS_TYPE_BOOLEAN, &paused,
+                                 DBUS_TYPE_INVALID);
+       if (!b) {
+               r = -ENODEV;
+               goto err_reply;
+       }
+
+       r = fd;
+       if (paused_out)
+               *paused_out = paused;
+
+err_reply:
+       dbus_message_unref(reply);
+err_unref:
+       dbus_message_unref(m);
+       return r;
+}
+
+static void
+launcher_logind_release_device(struct launcher_logind *wl, uint32_t major,
+                            uint32_t minor)
+{
+       DBusMessage *m;
+       bool b;
+
+       m = dbus_message_new_method_call("org.freedesktop.login1",
+                                        wl->spath,
+                                        "org.freedesktop.login1.Session",
+                                        "ReleaseDevice");
+       if (m) {
+               b = dbus_message_append_args(m,
+                                            DBUS_TYPE_UINT32, &major,
+                                            DBUS_TYPE_UINT32, &minor,
+                                            DBUS_TYPE_INVALID);
+               if (b)
+                       dbus_connection_send(wl->dbus, m, NULL);
+               dbus_message_unref(m);
+       }
+}
+
+static void
+launcher_logind_pause_device_complete(struct launcher_logind *wl, uint32_t major,
+                                   uint32_t minor)
+{
+       DBusMessage *m;
+       bool b;
+
+       m = dbus_message_new_method_call("org.freedesktop.login1",
+                                        wl->spath,
+                                        "org.freedesktop.login1.Session",
+                                        "PauseDeviceComplete");
+       if (m) {
+               b = dbus_message_append_args(m,
+                                            DBUS_TYPE_UINT32, &major,
+                                            DBUS_TYPE_UINT32, &minor,
+                                            DBUS_TYPE_INVALID);
+               if (b)
+                       dbus_connection_send(wl->dbus, m, NULL);
+               dbus_message_unref(m);
+       }
+}
+
+static int
+launcher_logind_open(struct weston_launcher *launcher, const char *path, int flags)
+{
+       struct launcher_logind *wl = wl_container_of(launcher, wl, base);
+       struct stat st;
+       int fl, r, fd;
+
+       r = stat(path, &st);
+       if (r < 0)
+               return -1;
+       if (!S_ISCHR(st.st_mode)) {
+               errno = ENODEV;
+               return -1;
+       }
+
+       fd = launcher_logind_take_device(wl, major(st.st_rdev),
+                                      minor(st.st_rdev), NULL);
+       if (fd < 0)
+               return fd;
+
+       /* Compared to weston_launcher_open() we cannot specify the open-mode
+        * directly. Instead, logind passes us an fd with sane default modes.
+        * For DRM and evdev this means O_RDWR | O_CLOEXEC. If we want
+        * something else, we need to change it afterwards. We currently
+        * only support setting O_NONBLOCK. Changing access-modes is not
+        * possible so accept whatever logind passes us. */
+
+       fl = fcntl(fd, F_GETFL);
+       if (fl < 0) {
+               r = -errno;
+               goto err_close;
+       }
+
+       if (flags & O_NONBLOCK)
+               fl |= O_NONBLOCK;
+
+       r = fcntl(fd, F_SETFL, fl);
+       if (r < 0) {
+               r = -errno;
+               goto err_close;
+       }
+       return fd;
+
+err_close:
+       close(fd);
+       launcher_logind_release_device(wl, major(st.st_rdev),
+                                    minor(st.st_rdev));
+       errno = -r;
+       return -1;
+}
+
+static void
+launcher_logind_close(struct weston_launcher *launcher, int fd)
+{
+       struct launcher_logind *wl = wl_container_of(launcher, wl, base);
+       struct stat st;
+       int r;
+
+       r = fstat(fd, &st);
+       if (r < 0) {
+               weston_log("logind: cannot fstat fd: %m\n");
+               return;
+       }
+
+       if (!S_ISCHR(st.st_mode)) {
+               weston_log("logind: invalid device passed\n");
+               return;
+       }
+
+       launcher_logind_release_device(wl, major(st.st_rdev),
+                                    minor(st.st_rdev));
+}
+
+static void
+launcher_logind_restore(struct weston_launcher *launcher)
+{
+}
+
+static int
+launcher_logind_activate_vt(struct weston_launcher *launcher, int vt)
+{
+       struct launcher_logind *wl = wl_container_of(launcher, wl, base);
+       DBusMessage *m;
+       bool b;
+       int r;
+
+       m = dbus_message_new_method_call("org.freedesktop.login1",
+                                        "/org/freedesktop/login1/seat/self",
+                                        "org.freedesktop.login1.Seat",
+                                        "SwitchTo");
+       if (!m)
+               return -ENOMEM;
+
+       b = dbus_message_append_args(m,
+                                    DBUS_TYPE_UINT32, &vt,
+                                    DBUS_TYPE_INVALID);
+       if (!b) {
+               r = -ENOMEM;
+               goto err_unref;
+       }
+
+       dbus_connection_send(wl->dbus, m, NULL);
+       r = 0;
+
+ err_unref:
+       dbus_message_unref(m);
+       return r;
+}
+
+static void
+launcher_logind_set_active(struct launcher_logind *wl, bool active)
+{
+       if (!wl->compositor->session_active == !active)
+               return;
+
+       wl->compositor->session_active = active;
+
+       wl_signal_emit(&wl->compositor->session_signal,
+                      wl->compositor);
+}
+
+static void
+parse_active(struct launcher_logind *wl, DBusMessage *m, DBusMessageIter *iter)
+{
+       DBusMessageIter sub;
+       dbus_bool_t b;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+               return;
+
+       dbus_message_iter_recurse(iter, &sub);
+
+       if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
+               return;
+
+       dbus_message_iter_get_basic(&sub, &b);
+
+       /* If the backend requested DRM master-device synchronization, we only
+        * wake-up the compositor once the master-device is up and running. For
+        * other backends, we immediately forward the Active-change event. */
+       if (!wl->sync_drm || !b)
+               launcher_logind_set_active(wl, b);
+}
+
+static void
+get_active_cb(DBusPendingCall *pending, void *data)
+{
+       struct launcher_logind *wl = data;
+       DBusMessageIter iter;
+       DBusMessage *m;
+       int type;
+
+       dbus_pending_call_unref(wl->pending_active);
+       wl->pending_active = NULL;
+
+       m = dbus_pending_call_steal_reply(pending);
+       if (!m)
+               return;
+
+       type = dbus_message_get_type(m);
+       if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
+           dbus_message_iter_init(m, &iter))
+               parse_active(wl, m, &iter);
+
+       dbus_message_unref(m);
+}
+
+static void
+launcher_logind_get_active(struct launcher_logind *wl)
+{
+       DBusPendingCall *pending;
+       DBusMessage *m;
+       bool b;
+       const char *iface, *name;
+
+       m = dbus_message_new_method_call("org.freedesktop.login1",
+                                        wl->spath,
+                                        "org.freedesktop.DBus.Properties",
+                                        "Get");
+       if (!m)
+               return;
+
+       iface = "org.freedesktop.login1.Session";
+       name = "Active";
+       b = dbus_message_append_args(m,
+                                    DBUS_TYPE_STRING, &iface,
+                                    DBUS_TYPE_STRING, &name,
+                                    DBUS_TYPE_INVALID);
+       if (!b)
+               goto err_unref;
+
+       b = dbus_connection_send_with_reply(wl->dbus, m, &pending, -1);
+       if (!b)
+               goto err_unref;
+
+       b = dbus_pending_call_set_notify(pending, get_active_cb, wl, NULL);
+       if (!b) {
+               dbus_pending_call_cancel(pending);
+               dbus_pending_call_unref(pending);
+               goto err_unref;
+       }
+
+       if (wl->pending_active) {
+               dbus_pending_call_cancel(wl->pending_active);
+               dbus_pending_call_unref(wl->pending_active);
+       }
+       wl->pending_active = pending;
+       return;
+
+err_unref:
+       dbus_message_unref(m);
+}
+
+static void
+disconnected_dbus(struct launcher_logind *wl)
+{
+       weston_log("logind: dbus connection lost, exiting..\n");
+       launcher_logind_restore(&wl->base);
+       exit(-1);
+}
+
+static void
+session_removed(struct launcher_logind *wl, DBusMessage *m)
+{
+       const char *name, *obj;
+       bool r;
+
+       r = dbus_message_get_args(m, NULL,
+                                 DBUS_TYPE_STRING, &name,
+                                 DBUS_TYPE_OBJECT_PATH, &obj,
+                                 DBUS_TYPE_INVALID);
+       if (!r) {
+               weston_log("logind: cannot parse SessionRemoved dbus signal\n");
+               return;
+       }
+
+       if (!strcmp(name, wl->sid)) {
+               weston_log("logind: our session got closed, exiting..\n");
+               launcher_logind_restore(&wl->base);
+               exit(-1);
+       }
+}
+
+static void
+property_changed(struct launcher_logind *wl, DBusMessage *m)
+{
+       DBusMessageIter iter, sub, entry;
+       const char *interface, *name;
+
+       if (!dbus_message_iter_init(m, &iter) ||
+           dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               goto error;
+
+       dbus_message_iter_get_basic(&iter, &interface);
+
+       if (!dbus_message_iter_next(&iter) ||
+           dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               goto error;
+
+       dbus_message_iter_recurse(&iter, &sub);
+
+       while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY) {
+               dbus_message_iter_recurse(&sub, &entry);
+
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+                       goto error;
+
+               dbus_message_iter_get_basic(&entry, &name);
+               if (!dbus_message_iter_next(&entry))
+                       goto error;
+
+               if (!strcmp(name, "Active")) {
+                       parse_active(wl, m, &entry);
+                       return;
+               }
+
+               dbus_message_iter_next(&sub);
+       }
+
+       if (!dbus_message_iter_next(&iter) ||
+           dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               goto error;
+
+       dbus_message_iter_recurse(&iter, &sub);
+
+       while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
+               dbus_message_iter_get_basic(&sub, &name);
+
+               if (!strcmp(name, "Active")) {
+                       launcher_logind_get_active(wl);
+                       return;
+               }
+
+               dbus_message_iter_next(&sub);
+       }
+
+       return;
+
+error:
+       weston_log("logind: cannot parse PropertiesChanged dbus signal\n");
+}
+
+static void
+device_paused(struct launcher_logind *wl, DBusMessage *m)
+{
+       bool r;
+       const char *type;
+       uint32_t major, minor;
+
+       r = dbus_message_get_args(m, NULL,
+                                 DBUS_TYPE_UINT32, &major,
+                                 DBUS_TYPE_UINT32, &minor,
+                                 DBUS_TYPE_STRING, &type,
+                                 DBUS_TYPE_INVALID);
+       if (!r) {
+               weston_log("logind: cannot parse PauseDevice dbus signal\n");
+               return;
+       }
+
+       /* "pause" means synchronous pausing. Acknowledge it unconditionally
+        * as we support asynchronous device shutdowns, anyway.
+        * "force" means asynchronous pausing.
+        * "gone" means the device is gone. We handle it the same as "force" as
+        * a following udev event will be caught, too.
+        *
+        * If it's our main DRM device, tell the compositor to go asleep. */
+
+       if (!strcmp(type, "pause"))
+               launcher_logind_pause_device_complete(wl, major, minor);
+
+       if (wl->sync_drm && major == DRM_MAJOR)
+               launcher_logind_set_active(wl, false);
+}
+
+static void
+device_resumed(struct launcher_logind *wl, DBusMessage *m)
+{
+       bool r;
+       uint32_t major;
+
+       r = dbus_message_get_args(m, NULL,
+                                 DBUS_TYPE_UINT32, &major,
+                                 /*DBUS_TYPE_UINT32, &minor,
+                                 DBUS_TYPE_UNIX_FD, &fd,*/
+                                 DBUS_TYPE_INVALID);
+       if (!r) {
+               weston_log("logind: cannot parse ResumeDevice dbus signal\n");
+               return;
+       }
+
+       /* DeviceResumed messages provide us a new file-descriptor for
+        * resumed devices. For DRM devices it's the same as before, for evdev
+        * devices it's a new open-file. As we reopen evdev devices, anyway,
+        * there is no need for us to handle this event for evdev. For DRM, we
+        * notify the compositor to wake up. */
+
+       if (wl->sync_drm && major == DRM_MAJOR)
+               launcher_logind_set_active(wl, true);
+}
+
+static DBusHandlerResult
+filter_dbus(DBusConnection *c, DBusMessage *m, void *data)
+{
+       struct launcher_logind *wl = data;
+
+       if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
+               disconnected_dbus(wl);
+       } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Manager",
+                                         "SessionRemoved")) {
+               session_removed(wl, m);
+       } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties",
+                                         "PropertiesChanged")) {
+               property_changed(wl, m);
+       } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
+                                         "PauseDevice")) {
+               device_paused(wl, m);
+       } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
+                                         "ResumeDevice")) {
+               device_resumed(wl, m);
+       }
+
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static int
+launcher_logind_setup_dbus(struct launcher_logind *wl)
+{
+       bool b;
+       int r;
+
+       r = asprintf(&wl->spath, "/org/freedesktop/login1/session/%s",
+                    wl->sid);
+       if (r < 0)
+               return -ENOMEM;
+
+       b = dbus_connection_add_filter(wl->dbus, filter_dbus, wl, NULL);
+       if (!b) {
+               weston_log("logind: cannot add dbus filter\n");
+               r = -ENOMEM;
+               goto err_spath;
+       }
+
+       r = weston_dbus_add_match_signal(wl->dbus,
+                                        "org.freedesktop.login1",
+                                        "org.freedesktop.login1.Manager",
+                                        "SessionRemoved",
+                                        "/org/freedesktop/login1");
+       if (r < 0) {
+               weston_log("logind: cannot add dbus match\n");
+               goto err_spath;
+       }
+
+       r = weston_dbus_add_match_signal(wl->dbus,
+                                       "org.freedesktop.login1",
+                                       "org.freedesktop.login1.Session",
+                                       "PauseDevice",
+                                       wl->spath);
+       if (r < 0) {
+               weston_log("logind: cannot add dbus match\n");
+               goto err_spath;
+       }
+
+       r = weston_dbus_add_match_signal(wl->dbus,
+                                       "org.freedesktop.login1",
+                                       "org.freedesktop.login1.Session",
+                                       "ResumeDevice",
+                                       wl->spath);
+       if (r < 0) {
+               weston_log("logind: cannot add dbus match\n");
+               goto err_spath;
+       }
+
+       r = weston_dbus_add_match_signal(wl->dbus,
+                                       "org.freedesktop.login1",
+                                       "org.freedesktop.DBus.Properties",
+                                       "PropertiesChanged",
+                                       wl->spath);
+       if (r < 0) {
+               weston_log("logind: cannot add dbus match\n");
+               goto err_spath;
+       }
+
+       return 0;
+
+err_spath:
+       /* don't remove any dbus-match as the connection is closed, anyway */
+       free(wl->spath);
+       return r;
+}
+
+static void
+launcher_logind_destroy_dbus(struct launcher_logind *wl)
+{
+       /* don't remove any dbus-match as the connection is closed, anyway */
+       free(wl->spath);
+}
+
+static int
+launcher_logind_take_control(struct launcher_logind *wl)
+{
+       DBusError err;
+       DBusMessage *m, *reply;
+       dbus_bool_t force;
+       bool b;
+       int r;
+
+       dbus_error_init(&err);
+
+       m = dbus_message_new_method_call("org.freedesktop.login1",
+                                        wl->spath,
+                                        "org.freedesktop.login1.Session",
+                                        "TakeControl");
+       if (!m)
+               return -ENOMEM;
+
+       force = false;
+       b = dbus_message_append_args(m,
+                                    DBUS_TYPE_BOOLEAN, &force,
+                                    DBUS_TYPE_INVALID);
+       if (!b) {
+               r = -ENOMEM;
+               goto err_unref;
+       }
+
+       reply = dbus_connection_send_with_reply_and_block(wl->dbus,
+                                                         m, -1, &err);
+       if (!reply) {
+               if (dbus_error_has_name(&err, DBUS_ERROR_UNKNOWN_METHOD))
+                       weston_log("logind: old systemd version detected\n");
+               else
+                       weston_log("logind: cannot take control over session %s\n", wl->sid);
+
+               dbus_error_free(&err);
+               r = -EIO;
+               goto err_unref;
+       }
+
+       dbus_message_unref(reply);
+       dbus_message_unref(m);
+       return 0;
+
+err_unref:
+       dbus_message_unref(m);
+       return r;
+}
+
+static void
+launcher_logind_release_control(struct launcher_logind *wl)
+{
+       DBusMessage *m;
+
+       m = dbus_message_new_method_call("org.freedesktop.login1",
+                                        wl->spath,
+                                        "org.freedesktop.login1.Session",
+                                        "ReleaseControl");
+       if (m) {
+               dbus_connection_send(wl->dbus, m, NULL);
+               dbus_message_unref(m);
+       }
+}
+
+static int
+weston_sd_session_get_vt(const char *sid, unsigned int *out)
+{
+#ifdef HAVE_SYSTEMD_LOGIN_209
+       return sd_session_get_vt(sid, out);
+#else
+       int r;
+       char *tty;
+
+       r = sd_session_get_tty(sid, &tty);
+       if (r < 0)
+               return r;
+
+       r = sscanf(tty, "tty%u", out);
+       free(tty);
+
+       if (r != 1)
+               return -EINVAL;
+
+       return 0;
+#endif
+}
+
+static int
+launcher_logind_activate(struct launcher_logind *wl)
+{
+       DBusMessage *m;
+
+       m = dbus_message_new_method_call("org.freedesktop.login1",
+                                        wl->spath,
+                                        "org.freedesktop.login1.Session",
+                                        "Activate");
+       if (!m)
+               return -ENOMEM;
+
+       dbus_connection_send(wl->dbus, m, NULL);
+       return 0;
+}
+
+static int
+launcher_logind_connect(struct weston_launcher **out, struct weston_compositor *compositor,
+                       int tty, const char *seat_id, bool sync_drm)
+{
+       struct launcher_logind *wl;
+       struct wl_event_loop *loop;
+       char *t;
+       int r;
+
+       wl = zalloc(sizeof(*wl));
+       if (wl == NULL) {
+               r = -ENOMEM;
+               goto err_out;
+       }
+
+       wl->base.iface = &launcher_logind_iface;
+       wl->compositor = compositor;
+       wl->sync_drm = sync_drm;
+
+       wl->seat = strdup(seat_id);
+       if (!wl->seat) {
+               r = -ENOMEM;
+               goto err_wl;
+       }
+
+       r = sd_pid_get_session(getpid(), &wl->sid);
+       if (r < 0) {
+               weston_log("logind: not running in a systemd session\n");
+               goto err_seat;
+       }
+
+       t = NULL;
+       r = sd_session_get_seat(wl->sid, &t);
+       if (r < 0) {
+               weston_log("logind: failed to get session seat\n");
+               free(t);
+               goto err_session;
+       } else if (strcmp(seat_id, t)) {
+               weston_log("logind: weston's seat '%s' differs from session-seat '%s'\n",
+                          seat_id, t);
+               r = -EINVAL;
+               free(t);
+               goto err_session;
+       }
+       free(t);
+
+       r = weston_sd_session_get_vt(wl->sid, &wl->vtnr);
+       if (r < 0) {
+               weston_log("logind: session not running on a VT\n");
+               goto err_session;
+       } else if (tty > 0 && wl->vtnr != (unsigned int )tty) {
+               weston_log("logind: requested VT --tty=%d differs from real session VT %u\n",
+                          tty, wl->vtnr);
+               r = -EINVAL;
+               goto err_session;
+       }
+
+       loop = wl_display_get_event_loop(compositor->wl_display);
+       r = weston_dbus_open(loop, DBUS_BUS_SYSTEM, &wl->dbus, &wl->dbus_ctx);
+       if (r < 0) {
+               weston_log("logind: cannot connect to system dbus\n");
+               goto err_session;
+       }
+
+       r = launcher_logind_setup_dbus(wl);
+       if (r < 0)
+               goto err_dbus;
+
+       r = launcher_logind_take_control(wl);
+       if (r < 0)
+               goto err_dbus_cleanup;
+
+       r = launcher_logind_activate(wl);
+       if (r < 0)
+               goto err_dbus_cleanup;
+
+       weston_log("logind: session control granted\n");
+       * (struct launcher_logind **) out = wl;
+       return 0;
+
+err_dbus_cleanup:
+       launcher_logind_destroy_dbus(wl);
+err_dbus:
+       weston_dbus_close(wl->dbus, wl->dbus_ctx);
+err_session:
+       free(wl->sid);
+err_seat:
+       free(wl->seat);
+err_wl:
+       free(wl);
+err_out:
+       weston_log("logind: cannot setup systemd-logind helper (%d), using legacy fallback\n", r);
+       errno = -r;
+       return -1;
+}
+
+static void
+launcher_logind_destroy(struct weston_launcher *launcher)
+{
+       struct launcher_logind *wl = wl_container_of(launcher, wl, base);
+
+       if (wl->pending_active) {
+               dbus_pending_call_cancel(wl->pending_active);
+               dbus_pending_call_unref(wl->pending_active);
+       }
+
+       launcher_logind_release_control(wl);
+       launcher_logind_destroy_dbus(wl);
+       weston_dbus_close(wl->dbus, wl->dbus_ctx);
+       free(wl->sid);
+       free(wl->seat);
+       free(wl);
+}
+
+struct launcher_interface launcher_logind_iface = {
+       launcher_logind_connect,
+       launcher_logind_destroy,
+       launcher_logind_open,
+       launcher_logind_close,
+       launcher_logind_activate_vt,
+       launcher_logind_restore,
+};
diff --git a/libweston/launcher-util.c b/libweston/launcher-util.c
new file mode 100644 (file)
index 0000000..03b9d63
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright © 2012 Benjamin Franzke
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "compositor.h"
+
+#include "launcher-util.h"
+#include "launcher-impl.h"
+
+#include <unistd.h>
+#include <linux/input.h>
+
+static struct launcher_interface *ifaces[] = {
+#ifdef HAVE_SYSTEMD_LOGIN
+       &launcher_logind_iface,
+#endif
+       &launcher_weston_launch_iface,
+       &launcher_direct_iface,
+       NULL,
+};
+
+WL_EXPORT struct weston_launcher *
+weston_launcher_connect(struct weston_compositor *compositor, int tty,
+                       const char *seat_id, bool sync_drm)
+{
+       struct launcher_interface **it;
+
+       for (it = ifaces; *it != NULL; it++) {
+               struct launcher_interface *iface = *it;
+               struct weston_launcher *launcher;
+
+               if (iface->connect(&launcher, compositor, tty, seat_id, sync_drm) == 0)
+                       return launcher;
+       }
+
+       return NULL;
+}
+
+WL_EXPORT void
+weston_launcher_destroy(struct weston_launcher *launcher)
+{
+       launcher->iface->destroy(launcher);
+}
+
+WL_EXPORT int
+weston_launcher_open(struct weston_launcher *launcher,
+                    const char *path, int flags)
+{
+       return launcher->iface->open(launcher, path, flags);
+}
+
+WL_EXPORT void
+weston_launcher_close(struct weston_launcher *launcher, int fd)
+{
+       launcher->iface->close(launcher, fd);
+}
+
+WL_EXPORT int
+weston_launcher_activate_vt(struct weston_launcher *launcher, int vt)
+{
+       return launcher->iface->activate_vt(launcher, vt);
+}
+
+WL_EXPORT void
+weston_launcher_restore(struct weston_launcher *launcher)
+{
+       launcher->iface->restore(launcher);
+}
+
+
+static void
+switch_vt_binding(struct weston_keyboard *keyboard,
+                 uint32_t time, uint32_t key, void *data)
+{
+       struct weston_compositor *compositor = data;
+
+       weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
+}
+
+WL_EXPORT void
+weston_setup_vt_switch_bindings(struct weston_compositor *compositor)
+{
+       uint32_t key;
+
+       if (compositor->vt_switching == false)
+               return;
+
+       for (key = KEY_F1; key < KEY_F9; key++)
+               weston_compositor_add_key_binding(compositor, key,
+                                                 MODIFIER_CTRL | MODIFIER_ALT,
+                                                 switch_vt_binding,
+                                                 compositor);
+}
diff --git a/libweston/launcher-util.h b/libweston/launcher-util.h
new file mode 100644 (file)
index 0000000..93321ab
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2012 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _WESTON_LAUNCHER_UTIL_H_
+#define _WESTON_LAUNCHER_UTIL_H_
+
+#include "config.h"
+
+#include "compositor.h"
+
+struct weston_launcher;
+
+struct weston_launcher *
+weston_launcher_connect(struct weston_compositor *compositor, int tty,
+                       const char *seat_id, bool sync_drm);
+
+void
+weston_launcher_destroy(struct weston_launcher *launcher);
+
+int
+weston_launcher_open(struct weston_launcher *launcher,
+                    const char *path, int flags);
+
+void
+weston_launcher_close(struct weston_launcher *launcher, int fd);
+
+int
+weston_launcher_activate_vt(struct weston_launcher *launcher, int vt);
+
+void
+weston_launcher_restore(struct weston_launcher *launcher);
+
+void
+weston_setup_vt_switch_bindings(struct weston_compositor *compositor);
+
+#endif
diff --git a/libweston/launcher-weston-launch.c b/libweston/launcher-weston-launch.c
new file mode 100644 (file)
index 0000000..ad919f1
--- /dev/null
@@ -0,0 +1,300 @@
+/*
+ * Copyright © 2012 Benjamin Franzke
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <errno.h>
+#include <signal.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/uio.h>
+#include <sys/ioctl.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <linux/vt.h>
+#include <linux/kd.h>
+#include <linux/major.h>
+
+#include "compositor.h"
+#include "weston-launch.h"
+#include "launcher-impl.h"
+
+#define DRM_MAJOR 226
+
+#ifndef KDSKBMUTE
+#define KDSKBMUTE      0x4B51
+#endif
+
+#ifdef HAVE_LIBDRM
+
+#include <xf86drm.h>
+
+static inline int
+is_drm_master(int drm_fd)
+{
+       drm_magic_t magic;
+
+       return drmGetMagic(drm_fd, &magic) == 0 &&
+               drmAuthMagic(drm_fd, magic) == 0;
+}
+
+#else
+
+static inline int
+drmDropMaster(int drm_fd)
+{
+       return 0;
+}
+
+static inline int
+drmSetMaster(int drm_fd)
+{
+       return 0;
+}
+
+static inline int
+is_drm_master(int drm_fd)
+{
+       return 0;
+}
+
+#endif
+
+
+union cmsg_data { unsigned char b[4]; int fd; };
+
+struct launcher_weston_launch {
+       struct weston_launcher base;
+       struct weston_compositor *compositor;
+       struct wl_event_loop *loop;
+       int fd;
+       struct wl_event_source *source;
+
+       int kb_mode, tty, drm_fd;
+};
+
+static int
+launcher_weston_launch_open(struct weston_launcher *launcher_base,
+                    const char *path, int flags)
+{
+       struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
+       int n, ret;
+       struct msghdr msg;
+       struct cmsghdr *cmsg;
+       struct iovec iov;
+       union cmsg_data *data;
+       char control[CMSG_SPACE(sizeof data->fd)];
+       ssize_t len;
+       struct weston_launcher_open *message;
+
+       n = sizeof(*message) + strlen(path) + 1;
+       message = malloc(n);
+       if (!message)
+               return -1;
+
+       message->header.opcode = WESTON_LAUNCHER_OPEN;
+       message->flags = flags;
+       strcpy(message->path, path);
+
+       do {
+               len = send(launcher->fd, message, n, 0);
+       } while (len < 0 && errno == EINTR);
+       free(message);
+
+       memset(&msg, 0, sizeof msg);
+       iov.iov_base = &ret;
+       iov.iov_len = sizeof ret;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = control;
+       msg.msg_controllen = sizeof control;
+       
+       do {
+               len = recvmsg(launcher->fd, &msg, MSG_CMSG_CLOEXEC);
+       } while (len < 0 && errno == EINTR);
+
+       if (len != sizeof ret ||
+           ret < 0)
+               return -1;
+
+       cmsg = CMSG_FIRSTHDR(&msg);
+       if (!cmsg ||
+           cmsg->cmsg_level != SOL_SOCKET ||
+           cmsg->cmsg_type != SCM_RIGHTS) {
+               fprintf(stderr, "invalid control message\n");
+               return -1;
+       }
+
+       data = (union cmsg_data *) CMSG_DATA(cmsg);
+       if (data->fd == -1) {
+               fprintf(stderr, "missing drm fd in socket request\n");
+               return -1;
+       }
+
+       return data->fd;
+}
+
+static void
+launcher_weston_launch_close(struct weston_launcher *launcher_base, int fd)
+{
+       close(fd);
+}
+
+static void
+launcher_weston_launch_restore(struct weston_launcher *launcher_base)
+{
+       struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
+       struct vt_mode mode = { 0 };
+
+       if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
+           ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
+               weston_log("failed to restore kb mode: %m\n");
+
+       if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
+               weston_log("failed to set KD_TEXT mode on tty: %m\n");
+
+       /* We have to drop master before we switch the VT back in
+        * VT_AUTO, so we don't risk switching to a VT with another
+        * display server, that will then fail to set drm master. */
+       drmDropMaster(launcher->drm_fd);
+
+       mode.mode = VT_AUTO;
+       if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
+               weston_log("could not reset vt handling\n");
+}
+
+static int
+launcher_weston_launch_data(int fd, uint32_t mask, void *data)
+{
+       struct launcher_weston_launch *launcher = data;
+       int len, ret;
+
+       if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
+               weston_log("launcher socket closed, exiting\n");
+               /* Normally the weston-launch will reset the tty, but
+                * in this case it died or something, so do it here so
+                * we don't end up with a stuck vt. */
+               launcher_weston_launch_restore(&launcher->base);
+               exit(-1);
+       }
+
+       do {
+               len = recv(launcher->fd, &ret, sizeof ret, 0);
+       } while (len < 0 && errno == EINTR);
+
+       switch (ret) {
+       case WESTON_LAUNCHER_ACTIVATE:
+               launcher->compositor->session_active = 1;
+               wl_signal_emit(&launcher->compositor->session_signal,
+                              launcher->compositor);
+               break;
+       case WESTON_LAUNCHER_DEACTIVATE:
+               launcher->compositor->session_active = 0;
+               wl_signal_emit(&launcher->compositor->session_signal,
+                              launcher->compositor);
+               break;
+       default:
+               weston_log("unexpected event from weston-launch\n");
+               break;
+       }
+
+       return 1;
+}
+
+static int
+launcher_weston_launch_activate_vt(struct weston_launcher *launcher_base, int vt)
+{
+       struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
+       return ioctl(launcher->tty, VT_ACTIVATE, vt);
+}
+
+static int
+launcher_weston_launch_connect(struct weston_launcher **out, struct weston_compositor *compositor,
+                              int tty, const char *seat_id, bool sync_drm)
+{
+       struct launcher_weston_launch *launcher;
+       struct wl_event_loop *loop;
+
+       launcher = malloc(sizeof *launcher);
+       if (launcher == NULL)
+               return -ENOMEM;
+
+       launcher->base.iface = &launcher_weston_launch_iface;
+       * (struct launcher_weston_launch **) out = launcher;
+       launcher->compositor = compositor;
+       launcher->drm_fd = -1;
+       launcher->fd = weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
+       if (launcher->fd != -1) {
+               launcher->tty = weston_environment_get_fd("WESTON_TTY_FD");
+               /* We don't get a chance to read out the original kb
+                * mode for the tty, so just hard code K_UNICODE here
+                * in case we have to clean if weston-launch dies. */
+               launcher->kb_mode = K_UNICODE;
+
+               loop = wl_display_get_event_loop(compositor->wl_display);
+               launcher->source = wl_event_loop_add_fd(loop, launcher->fd,
+                                                       WL_EVENT_READABLE,
+                                                       launcher_weston_launch_data,
+                                                       launcher);
+               if (launcher->source == NULL) {
+                       free(launcher);
+                       return -ENOMEM;
+               }
+
+               return 0;
+       } else {
+               return -1;
+       }
+}
+
+static void
+launcher_weston_launch_destroy(struct weston_launcher *launcher_base)
+{
+       struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
+
+       if (launcher->fd != -1) {
+               close(launcher->fd);
+               wl_event_source_remove(launcher->source);
+       } else {
+               launcher_weston_launch_restore(&launcher->base);
+       }
+
+       if (launcher->tty >= 0)
+               close(launcher->tty);
+
+       free(launcher);
+}
+
+struct launcher_interface launcher_weston_launch_iface = {
+       launcher_weston_launch_connect,
+       launcher_weston_launch_destroy,
+       launcher_weston_launch_open,
+       launcher_weston_launch_close,
+       launcher_weston_launch_activate_vt,
+       launcher_weston_launch_restore,
+};
diff --git a/libweston/libbacklight.c b/libweston/libbacklight.c
new file mode 100644 (file)
index 0000000..722d66f
--- /dev/null
@@ -0,0 +1,310 @@
+/*
+ * libbacklight - userspace interface to Linux backlight control
+ *
+ * Copyright © 2012 Intel Corporation
+ * Copyright 2010 Red Hat <mjg@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Matthew Garrett <mjg@redhat.com>
+ *    Tiago Vignatti <vignatti@freedesktop.org>
+ */
+
+#include "config.h"
+
+#include "libbacklight.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <linux/types.h>
+#include <dirent.h>
+#include <drm.h>
+#include <fcntl.h>
+#include <malloc.h>
+#include <string.h>
+#include <errno.h>
+
+static long backlight_get(struct backlight *backlight, char *node)
+{
+       char buffer[100];
+       char *path;
+       int fd;
+       long value, ret;
+
+       if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
+               return -ENOMEM;
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               ret = -1;
+               goto out;
+       }
+
+       ret = read(fd, &buffer, sizeof(buffer));
+       if (ret < 1) {
+               ret = -1;
+               goto out;
+       }
+
+       value = strtol(buffer, NULL, 10);
+       ret = value;
+out:
+       if (fd >= 0)
+               close(fd);
+       free(path);
+       return ret;
+}
+
+long backlight_get_brightness(struct backlight *backlight)
+{
+       return backlight_get(backlight, "brightness");
+}
+
+long backlight_get_max_brightness(struct backlight *backlight)
+{
+       return backlight_get(backlight, "max_brightness");
+}
+
+long backlight_get_actual_brightness(struct backlight *backlight)
+{
+       return backlight_get(backlight, "actual_brightness");
+}
+
+long backlight_set_brightness(struct backlight *backlight, long brightness)
+{
+       char *path;
+       char *buffer = NULL;
+       int fd;
+       long ret;
+
+       if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
+               return -ENOMEM;
+
+       fd = open(path, O_RDWR);
+       if (fd < 0) {
+               ret = -1;
+               goto out;
+       }
+
+       ret = read(fd, &buffer, sizeof(buffer));
+       if (ret < 1) {
+               ret = -1;
+               goto out;
+       }
+
+       if (asprintf(&buffer, "%ld", brightness) < 0) {
+               ret = -1;
+               goto out;
+       }
+
+       ret = write(fd, buffer, strlen(buffer));
+       if (ret < 0) {
+               ret = -1;
+               goto out;
+       }
+
+       ret = backlight_get_brightness(backlight);
+       backlight->brightness = ret;
+out:
+       free(buffer);
+       free(path);
+       if (fd >= 0)
+               close(fd);
+       return ret;
+}
+
+void backlight_destroy(struct backlight *backlight)
+{
+       if (!backlight)
+               return;
+
+       if (backlight->path)
+               free(backlight->path);
+
+       free(backlight);
+}
+
+struct backlight *backlight_init(struct udev_device *drm_device,
+                                uint32_t connector_type)
+{
+       const char *syspath = NULL;
+       char *pci_name = NULL;
+       char *chosen_path = NULL;
+       char *path = NULL;
+       DIR *backlights = NULL;
+       struct dirent *entry;
+       enum backlight_type type = 0;
+       char buffer[100];
+       struct backlight *backlight = NULL;
+       int ret;
+
+       if (!drm_device)
+               return NULL;
+
+       syspath = udev_device_get_syspath(drm_device);
+       if (!syspath)
+               return NULL;
+
+       if (asprintf(&path, "%s/%s", syspath, "device") < 0)
+               return NULL;
+
+       ret = readlink(path, buffer, sizeof(buffer) - 1);
+       free(path);
+       if (ret < 0)
+               return NULL;
+
+       buffer[ret] = '\0';
+       pci_name = basename(buffer);
+
+       if (connector_type <= 0)
+               return NULL;
+
+       backlights = opendir("/sys/class/backlight");
+       if (!backlights)
+               return NULL;
+
+       /* Find the "best" backlight for the device. Firmware
+          interfaces are preferred over platform interfaces are
+          preferred over raw interfaces. For raw interfaces we'll
+          check if the device ID in the form of pci match, while
+          for firmware interfaces we require the pci ID to
+          match. It's assumed that platform interfaces always match,
+          since we can't actually associate them with IDs.
+
+          A further awkwardness is that, while it's theoretically
+          possible for an ACPI interface to include support for
+          changing the backlight of external devices, it's unlikely
+          to ever be done. It's effectively impossible for a platform
+          interface to do so. So if we get asked about anything that
+          isn't LVDS or eDP, we pretty much have to require that the
+          control be supplied via a raw interface */
+
+       while ((entry = readdir(backlights))) {
+               char *backlight_path;
+               char *parent;
+               enum backlight_type entry_type;
+               int fd;
+
+               if (entry->d_name[0] == '.')
+                       continue;
+
+               if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
+                            entry->d_name) < 0)
+                       goto err;
+
+               if (asprintf(&path, "%s/%s", backlight_path, "type") < 0) {
+                       free(backlight_path);
+                       goto err;
+               }
+
+               fd = open(path, O_RDONLY);
+
+               if (fd < 0)
+                       goto out;
+
+               ret = read (fd, &buffer, sizeof(buffer));
+               close (fd);
+
+               if (ret < 1)
+                       goto out;
+
+               buffer[ret] = '\0';
+
+               if (!strncmp(buffer, "raw\n", sizeof(buffer)))
+                       entry_type = BACKLIGHT_RAW;
+               else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
+                       entry_type = BACKLIGHT_PLATFORM;
+               else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
+                       entry_type = BACKLIGHT_FIRMWARE;
+               else
+                       goto out;
+
+               if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
+                   connector_type != DRM_MODE_CONNECTOR_eDP) {
+                       /* External displays are assumed to require
+                          gpu control at the moment */
+                       if (entry_type != BACKLIGHT_RAW)
+                               goto out;
+               }
+
+               free (path);
+
+               if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
+                       goto err;
+
+               ret = readlink(path, buffer, sizeof(buffer) - 1);
+
+               if (ret < 0)
+                       goto out;
+
+               buffer[ret] = '\0';
+
+               parent = basename(buffer);
+
+               /* Perform matching for raw and firmware backlights -
+                  platform backlights have to be assumed to match */
+               if (entry_type == BACKLIGHT_RAW ||
+                   entry_type == BACKLIGHT_FIRMWARE) {
+                       if (!(pci_name && !strcmp(pci_name, parent)))
+                               goto out;
+               }
+
+               if (entry_type < type)
+                       goto out;
+
+               type = entry_type;
+
+               if (chosen_path)
+                       free(chosen_path);
+               chosen_path = strdup(backlight_path);
+
+       out:
+               free(backlight_path);
+               free(path);
+       }
+
+       if (!chosen_path)
+               goto err;
+
+       backlight = malloc(sizeof(struct backlight));
+
+       if (!backlight)
+               goto err;
+
+       backlight->path = chosen_path;
+       backlight->type = type;
+
+       backlight->max_brightness = backlight_get_max_brightness(backlight);
+       if (backlight->max_brightness < 0)
+               goto err;
+
+       backlight->brightness = backlight_get_actual_brightness(backlight);
+       if (backlight->brightness < 0)
+               goto err;
+
+       closedir(backlights);
+       return backlight;
+err:
+       closedir(backlights);
+       free (chosen_path);
+       free (backlight);
+       return NULL;
+}
diff --git a/libweston/libbacklight.h b/libweston/libbacklight.h
new file mode 100644 (file)
index 0000000..8717ab1
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * libbacklight - userspace interface to Linux backlight control
+ *
+ * Copyright © 2012 Intel Corporation
+ * Copyright 2010 Red Hat <mjg@redhat.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Matthew Garrett <mjg@redhat.com>
+ *    Tiago Vignatti <vignatti@freedesktop.org>
+ */
+#ifndef LIBBACKLIGHT_H
+#define LIBBACKLIGHT_H
+#include <libudev.h>
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum backlight_type {
+       BACKLIGHT_RAW,
+       BACKLIGHT_PLATFORM,
+       BACKLIGHT_FIRMWARE
+};
+
+struct backlight {
+       char *path;
+       int max_brightness;
+       int brightness;
+       enum backlight_type type;
+};
+
+/*
+ * Find and set up a backlight for a valid udev connector device, i.e. one
+ * matching drm subsytem and with status of connected.
+ */
+struct backlight *backlight_init(struct udev_device *drm_device,
+                                uint32_t connector_type);
+
+/* Free backlight resources */
+void backlight_destroy(struct backlight *backlight);
+
+/* Provide the maximum backlight value */
+long backlight_get_max_brightness(struct backlight *backlight);
+
+/* Provide the cached backlight value */
+long backlight_get_brightness(struct backlight *backlight);
+
+/* Provide the hardware backlight value */
+long backlight_get_actual_brightness(struct backlight *backlight);
+
+/* Set the backlight to a value between 0 and max */
+long backlight_set_brightness(struct backlight *backlight, long brightness);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LIBBACKLIGHT_H */
diff --git a/libweston/libinput-device.c b/libweston/libinput-device.c
new file mode 100644 (file)
index 0000000..62350f2
--- /dev/null
@@ -0,0 +1,593 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ * Copyright © 2013 Jonas Ådahl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <linux/input.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <mtdev.h>
+#include <assert.h>
+#include <libinput.h>
+
+#include "compositor.h"
+#include "libinput-device.h"
+#include "shared/helpers.h"
+
+void
+evdev_led_update(struct evdev_device *device, enum weston_led weston_leds)
+{
+       enum libinput_led leds = 0;
+
+       if (weston_leds & LED_NUM_LOCK)
+               leds |= LIBINPUT_LED_NUM_LOCK;
+       if (weston_leds & LED_CAPS_LOCK)
+               leds |= LIBINPUT_LED_CAPS_LOCK;
+       if (weston_leds & LED_SCROLL_LOCK)
+               leds |= LIBINPUT_LED_SCROLL_LOCK;
+
+       libinput_device_led_update(device->device, leds);
+}
+
+static void
+handle_keyboard_key(struct libinput_device *libinput_device,
+                   struct libinput_event_keyboard *keyboard_event)
+{
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       int key_state =
+               libinput_event_keyboard_get_key_state(keyboard_event);
+       int seat_key_count =
+               libinput_event_keyboard_get_seat_key_count(keyboard_event);
+
+       /* Ignore key events that are not seat wide state changes. */
+       if ((key_state == LIBINPUT_KEY_STATE_PRESSED &&
+            seat_key_count != 1) ||
+           (key_state == LIBINPUT_KEY_STATE_RELEASED &&
+            seat_key_count != 0))
+               return;
+
+       notify_key(device->seat,
+                  libinput_event_keyboard_get_time(keyboard_event),
+                  libinput_event_keyboard_get_key(keyboard_event),
+                  key_state, STATE_UPDATE_AUTOMATIC);
+}
+
+static bool
+handle_pointer_motion(struct libinput_device *libinput_device,
+                     struct libinput_event_pointer *pointer_event)
+{
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       struct weston_pointer_motion_event event = { 0 };
+
+       event = (struct weston_pointer_motion_event) {
+               .mask = WESTON_POINTER_MOTION_REL,
+               .dx = libinput_event_pointer_get_dx(pointer_event),
+               .dy = libinput_event_pointer_get_dy(pointer_event),
+       };
+
+       notify_motion(device->seat,
+                     libinput_event_pointer_get_time(pointer_event),
+                     &event);
+
+       return true;
+}
+
+static bool
+handle_pointer_motion_absolute(
+       struct libinput_device *libinput_device,
+       struct libinput_event_pointer *pointer_event)
+{
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       struct weston_output *output = device->output;
+       uint32_t time;
+       double x, y;
+       uint32_t width, height;
+
+       if (!output)
+               return false;
+
+       time = libinput_event_pointer_get_time(pointer_event);
+       width = device->output->current_mode->width;
+       height = device->output->current_mode->height;
+
+       x = libinput_event_pointer_get_absolute_x_transformed(pointer_event,
+                                                             width);
+       y = libinput_event_pointer_get_absolute_y_transformed(pointer_event,
+                                                             height);
+
+       weston_output_transform_coordinate(device->output, x, y, &x, &y);
+       notify_motion_absolute(device->seat, time, x, y);
+
+       return true;
+}
+
+static bool
+handle_pointer_button(struct libinput_device *libinput_device,
+                     struct libinput_event_pointer *pointer_event)
+{
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       int button_state =
+               libinput_event_pointer_get_button_state(pointer_event);
+       int seat_button_count =
+               libinput_event_pointer_get_seat_button_count(pointer_event);
+
+       /* Ignore button events that are not seat wide state changes. */
+       if ((button_state == LIBINPUT_BUTTON_STATE_PRESSED &&
+            seat_button_count != 1) ||
+           (button_state == LIBINPUT_BUTTON_STATE_RELEASED &&
+            seat_button_count != 0))
+               return false;
+
+       notify_button(device->seat,
+                     libinput_event_pointer_get_time(pointer_event),
+                     libinput_event_pointer_get_button(pointer_event),
+                      button_state);
+
+       return true;
+}
+
+static double
+normalize_scroll(struct libinput_event_pointer *pointer_event,
+                enum libinput_pointer_axis axis)
+{
+       enum libinput_pointer_axis_source source;
+       double value = 0.0;
+
+       source = libinput_event_pointer_get_axis_source(pointer_event);
+       /* libinput < 0.8 sent wheel click events with value 10. Since 0.8
+          the value is the angle of the click in degrees. To keep
+          backwards-compat with existing clients, we just send multiples of
+          the click count.
+        */
+       switch (source) {
+       case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
+               value = 10 * libinput_event_pointer_get_axis_value_discrete(
+                                                                  pointer_event,
+                                                                  axis);
+               break;
+       case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
+       case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
+               value = libinput_event_pointer_get_axis_value(pointer_event,
+                                                             axis);
+               break;
+       }
+
+       return value;
+}
+
+static int32_t
+get_axis_discrete(struct libinput_event_pointer *pointer_event,
+                 enum libinput_pointer_axis axis)
+{
+       enum libinput_pointer_axis_source source;
+
+       source = libinput_event_pointer_get_axis_source(pointer_event);
+
+       if (source != LIBINPUT_POINTER_AXIS_SOURCE_WHEEL)
+               return 0;
+
+       return libinput_event_pointer_get_axis_value_discrete(pointer_event,
+                                                             axis);
+}
+
+static bool
+handle_pointer_axis(struct libinput_device *libinput_device,
+                   struct libinput_event_pointer *pointer_event)
+{
+       static int warned;
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       double vert, horiz;
+       int32_t vert_discrete, horiz_discrete;
+       enum libinput_pointer_axis axis;
+       struct weston_pointer_axis_event weston_event;
+       enum libinput_pointer_axis_source source;
+       uint32_t wl_axis_source;
+       bool has_vert, has_horiz;
+
+       has_vert = libinput_event_pointer_has_axis(pointer_event,
+                                  LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
+       has_horiz = libinput_event_pointer_has_axis(pointer_event,
+                                  LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
+
+       if (!has_vert && !has_horiz)
+               return false;
+
+       source = libinput_event_pointer_get_axis_source(pointer_event);
+       switch (source) {
+       case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
+               wl_axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
+               break;
+       case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
+               wl_axis_source = WL_POINTER_AXIS_SOURCE_FINGER;
+               break;
+       case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
+               wl_axis_source = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
+               break;
+       default:
+               if (warned < 5) {
+                       weston_log("Unknown scroll source %d.\n", source);
+                       warned++;
+               }
+               return false;
+       }
+
+       notify_axis_source(device->seat, wl_axis_source);
+
+       if (has_vert) {
+               axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
+               vert_discrete = get_axis_discrete(pointer_event, axis);
+               vert = normalize_scroll(pointer_event, axis);
+
+               weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
+               weston_event.value = vert;
+               weston_event.discrete = vert_discrete;
+               weston_event.has_discrete = (vert_discrete != 0);
+
+               notify_axis(device->seat,
+                           libinput_event_pointer_get_time(pointer_event),
+                           &weston_event);
+       }
+
+       if (has_horiz) {
+               axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
+               horiz_discrete = get_axis_discrete(pointer_event, axis);
+               horiz = normalize_scroll(pointer_event, axis);
+
+               weston_event.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
+               weston_event.value = horiz;
+               weston_event.discrete = horiz_discrete;
+               weston_event.has_discrete = (horiz_discrete != 0);
+
+               notify_axis(device->seat,
+                           libinput_event_pointer_get_time(pointer_event),
+                           &weston_event);
+       }
+
+       return true;
+}
+
+static void
+handle_touch_with_coords(struct libinput_device *libinput_device,
+                        struct libinput_event_touch *touch_event,
+                        int touch_type)
+{
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       double x;
+       double y;
+       uint32_t width, height;
+       uint32_t time;
+       int32_t slot;
+
+       if (!device->output)
+               return;
+
+       time = libinput_event_touch_get_time(touch_event);
+       slot = libinput_event_touch_get_seat_slot(touch_event);
+
+       width = device->output->current_mode->width;
+       height = device->output->current_mode->height;
+       x =  libinput_event_touch_get_x_transformed(touch_event, width);
+       y =  libinput_event_touch_get_y_transformed(touch_event, height);
+
+       weston_output_transform_coordinate(device->output,
+                                          x, y, &x, &y);
+
+       notify_touch(device->seat, time, slot, x, y, touch_type);
+}
+
+static void
+handle_touch_down(struct libinput_device *device,
+                 struct libinput_event_touch *touch_event)
+{
+       handle_touch_with_coords(device, touch_event, WL_TOUCH_DOWN);
+}
+
+static void
+handle_touch_motion(struct libinput_device *device,
+                   struct libinput_event_touch *touch_event)
+{
+       handle_touch_with_coords(device, touch_event, WL_TOUCH_MOTION);
+}
+
+static void
+handle_touch_up(struct libinput_device *libinput_device,
+               struct libinput_event_touch *touch_event)
+{
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       uint32_t time = libinput_event_touch_get_time(touch_event);
+       int32_t slot = libinput_event_touch_get_seat_slot(touch_event);
+
+       notify_touch(device->seat, time, slot, 0, 0, WL_TOUCH_UP);
+}
+
+static void
+handle_touch_frame(struct libinput_device *libinput_device,
+                  struct libinput_event_touch *touch_event)
+{
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       struct weston_seat *seat = device->seat;
+
+       notify_touch_frame(seat);
+}
+
+int
+evdev_device_process_event(struct libinput_event *event)
+{
+       struct libinput_device *libinput_device =
+               libinput_event_get_device(event);
+       struct evdev_device *device =
+               libinput_device_get_user_data(libinput_device);
+       int handled = 1;
+       bool need_frame = false;
+
+       switch (libinput_event_get_type(event)) {
+       case LIBINPUT_EVENT_KEYBOARD_KEY:
+               handle_keyboard_key(libinput_device,
+                                   libinput_event_get_keyboard_event(event));
+               break;
+       case LIBINPUT_EVENT_POINTER_MOTION:
+               need_frame = handle_pointer_motion(libinput_device,
+                                     libinput_event_get_pointer_event(event));
+               break;
+       case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+               need_frame = handle_pointer_motion_absolute(
+                               libinput_device,
+                               libinput_event_get_pointer_event(event));
+               break;
+       case LIBINPUT_EVENT_POINTER_BUTTON:
+               need_frame = handle_pointer_button(libinput_device,
+                                     libinput_event_get_pointer_event(event));
+               break;
+       case LIBINPUT_EVENT_POINTER_AXIS:
+               need_frame = handle_pointer_axis(
+                                libinput_device,
+                                libinput_event_get_pointer_event(event));
+               break;
+       case LIBINPUT_EVENT_TOUCH_DOWN:
+               handle_touch_down(libinput_device,
+                                 libinput_event_get_touch_event(event));
+               break;
+       case LIBINPUT_EVENT_TOUCH_MOTION:
+               handle_touch_motion(libinput_device,
+                                   libinput_event_get_touch_event(event));
+               break;
+       case LIBINPUT_EVENT_TOUCH_UP:
+               handle_touch_up(libinput_device,
+                               libinput_event_get_touch_event(event));
+               break;
+       case LIBINPUT_EVENT_TOUCH_FRAME:
+               handle_touch_frame(libinput_device,
+                                  libinput_event_get_touch_event(event));
+               break;
+       default:
+               handled = 0;
+               weston_log("unknown libinput event %d\n",
+                          libinput_event_get_type(event));
+       }
+
+       if (need_frame)
+               notify_pointer_frame(device->seat);
+
+       return handled;
+}
+
+static void
+notify_output_destroy(struct wl_listener *listener, void *data)
+{
+       struct evdev_device *device =
+               container_of(listener,
+                            struct evdev_device, output_destroy_listener);
+       struct weston_compositor *c = device->seat->compositor;
+       struct weston_output *output;
+
+       if (!device->output_name && !wl_list_empty(&c->output_list)) {
+               output = container_of(c->output_list.next,
+                                     struct weston_output, link);
+               evdev_device_set_output(device, output);
+       } else {
+               device->output = NULL;
+       }
+}
+
+/**
+ * The WL_CALIBRATION property requires a pixel-specific matrix to be
+ * applied after scaling device coordinates to screen coordinates. libinput
+ * can't do that, so we need to convert the calibration to the normalized
+ * format libinput expects.
+ */
+void
+evdev_device_set_calibration(struct evdev_device *device)
+{
+       struct udev *udev;
+       struct udev_device *udev_device = NULL;
+       const char *sysname = libinput_device_get_sysname(device->device);
+       const char *calibration_values;
+       uint32_t width, height;
+       float calibration[6];
+       enum libinput_config_status status;
+
+       if (!device->output)
+               return;
+
+       width = device->output->width;
+       height = device->output->height;
+       if (width == 0 || height == 0)
+               return;
+
+       /* If libinput has a pre-set calibration matrix, don't override it */
+       if (!libinput_device_config_calibration_has_matrix(device->device) ||
+           libinput_device_config_calibration_get_default_matrix(
+                                                         device->device,
+                                                         calibration) != 0)
+               return;
+
+       udev = udev_new();
+       if (!udev)
+               return;
+
+       udev_device = udev_device_new_from_subsystem_sysname(udev,
+                                                            "input",
+                                                            sysname);
+       if (!udev_device)
+               goto out;
+
+       calibration_values =
+               udev_device_get_property_value(udev_device,
+                                              "WL_CALIBRATION");
+
+       if (!calibration_values || sscanf(calibration_values,
+                                         "%f %f %f %f %f %f",
+                                         &calibration[0],
+                                         &calibration[1],
+                                         &calibration[2],
+                                         &calibration[3],
+                                         &calibration[4],
+                                         &calibration[5]) != 6)
+               goto out;
+
+       weston_log("Applying calibration: %f %f %f %f %f %f "
+                  "(normalized %f %f)\n",
+                   calibration[0],
+                   calibration[1],
+                   calibration[2],
+                   calibration[3],
+                   calibration[4],
+                   calibration[5],
+                   calibration[2] / width,
+                   calibration[5] / height);
+
+       /* normalize to a format libinput can use. There is a chance of
+          this being wrong if the width/height don't match the device
+          width/height but I'm not sure how to fix that */
+       calibration[2] /= width;
+       calibration[5] /= height;
+
+       status = libinput_device_config_calibration_set_matrix(device->device,
+                                                              calibration);
+       if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
+               weston_log("Failed to apply calibration.\n");
+
+out:
+       if (udev_device)
+               udev_device_unref(udev_device);
+       udev_unref(udev);
+}
+
+void
+evdev_device_set_output(struct evdev_device *device,
+                       struct weston_output *output)
+{
+       if (device->output_destroy_listener.notify) {
+               wl_list_remove(&device->output_destroy_listener.link);
+               device->output_destroy_listener.notify = NULL;
+       }
+
+       device->output = output;
+       device->output_destroy_listener.notify = notify_output_destroy;
+       wl_signal_add(&output->destroy_signal,
+                     &device->output_destroy_listener);
+       evdev_device_set_calibration(device);
+}
+
+struct evdev_device *
+evdev_device_create(struct libinput_device *libinput_device,
+                   struct weston_seat *seat)
+{
+       struct evdev_device *device;
+
+       device = zalloc(sizeof *device);
+       if (device == NULL)
+               return NULL;
+
+       device->seat = seat;
+       wl_list_init(&device->link);
+       device->device = libinput_device;
+
+       if (libinput_device_has_capability(libinput_device,
+                                          LIBINPUT_DEVICE_CAP_KEYBOARD)) {
+               weston_seat_init_keyboard(seat, NULL);
+               device->seat_caps |= EVDEV_SEAT_KEYBOARD;
+       }
+       if (libinput_device_has_capability(libinput_device,
+                                          LIBINPUT_DEVICE_CAP_POINTER)) {
+               weston_seat_init_pointer(seat);
+               device->seat_caps |= EVDEV_SEAT_POINTER;
+       }
+       if (libinput_device_has_capability(libinput_device,
+                                          LIBINPUT_DEVICE_CAP_TOUCH)) {
+               weston_seat_init_touch(seat);
+               device->seat_caps |= EVDEV_SEAT_TOUCH;
+       }
+
+       libinput_device_set_user_data(libinput_device, device);
+       libinput_device_ref(libinput_device);
+
+       return device;
+}
+
+void
+evdev_device_destroy(struct evdev_device *device)
+{
+       if (device->seat_caps & EVDEV_SEAT_POINTER)
+               weston_seat_release_pointer(device->seat);
+       if (device->seat_caps & EVDEV_SEAT_KEYBOARD)
+               weston_seat_release_keyboard(device->seat);
+       if (device->seat_caps & EVDEV_SEAT_TOUCH)
+               weston_seat_release_touch(device->seat);
+
+       if (device->output)
+               wl_list_remove(&device->output_destroy_listener.link);
+       wl_list_remove(&device->link);
+       libinput_device_unref(device->device);
+       free(device->devnode);
+       free(device->output_name);
+       free(device);
+}
+
+void
+evdev_notify_keyboard_focus(struct weston_seat *seat,
+                           struct wl_list *evdev_devices)
+{
+       struct wl_array keys;
+
+       if (seat->keyboard_device_count == 0)
+               return;
+
+       wl_array_init(&keys);
+       notify_keyboard_focus_in(seat, &keys, STATE_UPDATE_AUTOMATIC);
+       wl_array_release(&keys);
+}
diff --git a/libweston/libinput-device.h b/libweston/libinput-device.h
new file mode 100644 (file)
index 0000000..5041a4a
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Copyright © 2011, 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _LIBINPUT_DEVICE_H_
+#define _LIBINPUT_DEVICE_H_
+
+#include "config.h"
+
+#include <linux/input.h>
+#include <wayland-util.h>
+#include <libinput.h>
+
+#include "compositor.h"
+
+enum evdev_device_seat_capability {
+       EVDEV_SEAT_POINTER = (1 << 0),
+       EVDEV_SEAT_KEYBOARD = (1 << 1),
+       EVDEV_SEAT_TOUCH = (1 << 2)
+};
+
+struct evdev_device {
+       struct weston_seat *seat;
+       enum evdev_device_seat_capability seat_caps;
+       struct libinput_device *device;
+       struct wl_list link;
+       struct weston_output *output;
+       struct wl_listener output_destroy_listener;
+       char *devnode;
+       char *output_name;
+       int fd;
+};
+
+void
+evdev_led_update(struct evdev_device *device, enum weston_led leds);
+
+struct evdev_device *
+evdev_device_create(struct libinput_device *libinput_device,
+                   struct weston_seat *seat);
+
+int
+evdev_device_process_event(struct libinput_event *event);
+
+void
+evdev_device_set_output(struct evdev_device *device,
+                       struct weston_output *output);
+void
+evdev_device_destroy(struct evdev_device *device);
+
+void
+evdev_notify_keyboard_focus(struct weston_seat *seat,
+                           struct wl_list *evdev_devices);
+void
+evdev_device_set_calibration(struct evdev_device *device);
+
+int
+dispatch_libinput(struct libinput *libinput);
+
+#endif /* _LIBINPUT_DEVICE_H_ */
diff --git a/libweston/libinput-seat.c b/libweston/libinput-seat.c
new file mode 100644 (file)
index 0000000..94e19f5
--- /dev/null
@@ -0,0 +1,416 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ * Copyright © 2013 Jonas Ådahl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libinput.h>
+#include <libudev.h>
+
+#include "compositor.h"
+#include "launcher-util.h"
+#include "libinput-seat.h"
+#include "libinput-device.h"
+#include "shared/helpers.h"
+
+static void
+process_events(struct udev_input *input);
+static struct udev_seat *
+udev_seat_create(struct udev_input *input, const char *seat_name);
+static void
+udev_seat_destroy(struct udev_seat *seat);
+
+static struct udev_seat *
+get_udev_seat(struct udev_input *input, struct libinput_device *device)
+{
+       struct libinput_seat *libinput_seat;
+       const char *seat_name;
+
+       libinput_seat = libinput_device_get_seat(device);
+       seat_name = libinput_seat_get_logical_name(libinput_seat);
+       return udev_seat_get_named(input, seat_name);
+}
+
+static void
+device_added(struct udev_input *input, struct libinput_device *libinput_device)
+{
+       struct weston_compositor *c;
+       struct evdev_device *device;
+       struct weston_output *output;
+       const char *output_name;
+       struct weston_seat *seat;
+       struct udev_seat *udev_seat;
+       struct weston_pointer *pointer;
+
+       c = input->compositor;
+
+       udev_seat = get_udev_seat(input, libinput_device);
+       if (!udev_seat)
+               return;
+
+       seat = &udev_seat->base;
+       device = evdev_device_create(libinput_device, seat);
+       if (device == NULL)
+               return;
+
+       if (input->configure_device != NULL)
+               input->configure_device(c, device->device);
+       evdev_device_set_calibration(device);
+       udev_seat = (struct udev_seat *) seat;
+       wl_list_insert(udev_seat->devices_list.prev, &device->link);
+
+       pointer = weston_seat_get_pointer(seat);
+       if (seat->output && pointer)
+               weston_pointer_clamp(pointer,
+                                    &pointer->x,
+                                    &pointer->y);
+
+       output_name = libinput_device_get_output_name(libinput_device);
+       if (output_name) {
+               device->output_name = strdup(output_name);
+               wl_list_for_each(output, &c->output_list, link)
+                       if (output->name &&
+                           strcmp(output->name, device->output_name) == 0)
+                               evdev_device_set_output(device, output);
+       } else if (device->output == NULL && !wl_list_empty(&c->output_list)) {
+               output = container_of(c->output_list.next,
+                                     struct weston_output, link);
+               evdev_device_set_output(device, output);
+       }
+
+       if (!input->suspended)
+               weston_seat_repick(seat);
+}
+
+static void
+device_removed(struct udev_input *input, struct libinput_device *libinput_device)
+{
+       struct evdev_device *device;
+
+       device = libinput_device_get_user_data(libinput_device);
+       evdev_device_destroy(device);
+}
+
+static void
+udev_seat_remove_devices(struct udev_seat *seat)
+{
+       struct evdev_device *device, *next;
+
+       wl_list_for_each_safe(device, next, &seat->devices_list, link) {
+               evdev_device_destroy(device);
+       }
+}
+
+void
+udev_input_disable(struct udev_input *input)
+{
+       if (input->suspended)
+               return;
+
+       libinput_suspend(input->libinput);
+       process_events(input);
+       input->suspended = 1;
+}
+
+static int
+udev_input_process_event(struct libinput_event *event)
+{
+       struct libinput *libinput = libinput_event_get_context(event);
+       struct libinput_device *libinput_device =
+               libinput_event_get_device(event);
+       struct udev_input *input = libinput_get_user_data(libinput);
+       int handled = 1;
+
+       switch (libinput_event_get_type(event)) {
+       case LIBINPUT_EVENT_DEVICE_ADDED:
+               device_added(input, libinput_device);
+               break;
+       case LIBINPUT_EVENT_DEVICE_REMOVED:
+               device_removed(input, libinput_device);
+               break;
+       default:
+               handled = 0;
+       }
+
+       return handled;
+}
+
+static void
+process_event(struct libinput_event *event)
+{
+       if (udev_input_process_event(event))
+               return;
+       if (evdev_device_process_event(event))
+               return;
+}
+
+static void
+process_events(struct udev_input *input)
+{
+       struct libinput_event *event;
+
+       while ((event = libinput_get_event(input->libinput))) {
+               process_event(event);
+               libinput_event_destroy(event);
+       }
+}
+
+static int
+udev_input_dispatch(struct udev_input *input)
+{
+       if (libinput_dispatch(input->libinput) != 0)
+               weston_log("libinput: Failed to dispatch libinput\n");
+
+       process_events(input);
+
+       return 0;
+}
+
+static int
+libinput_source_dispatch(int fd, uint32_t mask, void *data)
+{
+       struct udev_input *input = data;
+
+       return udev_input_dispatch(input) != 0;
+}
+
+static int
+open_restricted(const char *path, int flags, void *user_data)
+{
+       struct udev_input *input = user_data;
+       struct weston_launcher *launcher = input->compositor->launcher;
+
+       return weston_launcher_open(launcher, path, flags);
+}
+
+static void
+close_restricted(int fd, void *user_data)
+{
+       struct udev_input *input = user_data;
+       struct weston_launcher *launcher = input->compositor->launcher;
+
+       weston_launcher_close(launcher, fd);
+}
+
+const struct libinput_interface libinput_interface = {
+       open_restricted,
+       close_restricted,
+};
+
+int
+udev_input_enable(struct udev_input *input)
+{
+       struct wl_event_loop *loop;
+       struct weston_compositor *c = input->compositor;
+       int fd;
+       struct udev_seat *seat;
+       int devices_found = 0;
+
+       loop = wl_display_get_event_loop(c->wl_display);
+       fd = libinput_get_fd(input->libinput);
+       input->libinput_source =
+               wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
+                                    libinput_source_dispatch, input);
+       if (!input->libinput_source) {
+               return -1;
+       }
+
+       if (input->suspended) {
+               if (libinput_resume(input->libinput) != 0) {
+                       wl_event_source_remove(input->libinput_source);
+                       input->libinput_source = NULL;
+                       return -1;
+               }
+               input->suspended = 0;
+               process_events(input);
+       }
+
+       wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
+               evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
+
+               if (!wl_list_empty(&seat->devices_list))
+                       devices_found = 1;
+       }
+
+       if (devices_found == 0) {
+               weston_log(
+                       "warning: no input devices on entering Weston. "
+                       "Possible causes:\n"
+                       "\t- no permissions to read /dev/input/event*\n"
+                       "\t- seats misconfigured "
+                       "(Weston backend option 'seat', "
+                       "udev device property ID_SEAT)\n");
+               return -1;
+       }
+
+       return 0;
+}
+
+static void
+libinput_log_func(struct libinput *libinput,
+                 enum libinput_log_priority priority,
+                 const char *format, va_list args)
+{
+       weston_vlog(format, args);
+}
+
+int
+udev_input_init(struct udev_input *input, struct weston_compositor *c,
+               struct udev *udev, const char *seat_id,
+               udev_configure_device_t configure_device)
+{
+       enum libinput_log_priority priority = LIBINPUT_LOG_PRIORITY_INFO;
+       const char *log_priority = NULL;
+
+       memset(input, 0, sizeof *input);
+
+       input->compositor = c;
+       input->configure_device = configure_device;
+
+       log_priority = getenv("WESTON_LIBINPUT_LOG_PRIORITY");
+
+       input->libinput = libinput_udev_create_context(&libinput_interface,
+                                                      input, udev);
+       if (!input->libinput) {
+               return -1;
+       }
+
+       libinput_log_set_handler(input->libinput, &libinput_log_func);
+
+       if (log_priority) {
+               if (strcmp(log_priority, "debug") == 0) {
+                       priority = LIBINPUT_LOG_PRIORITY_DEBUG;
+               } else if (strcmp(log_priority, "info") == 0) {
+                       priority = LIBINPUT_LOG_PRIORITY_INFO;
+               } else if (strcmp(log_priority, "error") == 0) {
+                       priority = LIBINPUT_LOG_PRIORITY_ERROR;
+               }
+       }
+
+       libinput_log_set_priority(input->libinput, priority);
+
+       if (libinput_udev_assign_seat(input->libinput, seat_id) != 0) {
+               libinput_unref(input->libinput);
+               return -1;
+       }
+
+       process_events(input);
+
+       return udev_input_enable(input);
+}
+
+void
+udev_input_destroy(struct udev_input *input)
+{
+       struct udev_seat *seat, *next;
+
+       wl_event_source_remove(input->libinput_source);
+       wl_list_for_each_safe(seat, next, &input->compositor->seat_list, base.link)
+               udev_seat_destroy(seat);
+       libinput_unref(input->libinput);
+}
+
+static void
+udev_seat_led_update(struct weston_seat *seat_base, enum weston_led leds)
+{
+       struct udev_seat *seat = (struct udev_seat *) seat_base;
+       struct evdev_device *device;
+
+       wl_list_for_each(device, &seat->devices_list, link)
+               evdev_led_update(device, leds);
+}
+
+static void
+notify_output_create(struct wl_listener *listener, void *data)
+{
+       struct udev_seat *seat = container_of(listener, struct udev_seat,
+                                             output_create_listener);
+       struct evdev_device *device;
+       struct weston_output *output = data;
+
+       wl_list_for_each(device, &seat->devices_list, link) {
+               if (device->output_name &&
+                   strcmp(output->name, device->output_name) == 0) {
+                       evdev_device_set_output(device, output);
+               }
+
+               if (device->output_name == NULL && device->output == NULL)
+                       evdev_device_set_output(device, output);
+       }
+}
+
+static struct udev_seat *
+udev_seat_create(struct udev_input *input, const char *seat_name)
+{
+       struct weston_compositor *c = input->compositor;
+       struct udev_seat *seat;
+
+       seat = zalloc(sizeof *seat);
+       if (!seat)
+               return NULL;
+
+       weston_seat_init(&seat->base, c, seat_name);
+       seat->base.led_update = udev_seat_led_update;
+
+       seat->output_create_listener.notify = notify_output_create;
+       wl_signal_add(&c->output_created_signal,
+                     &seat->output_create_listener);
+
+       wl_list_init(&seat->devices_list);
+
+       return seat;
+}
+
+static void
+udev_seat_destroy(struct udev_seat *seat)
+{
+       struct weston_keyboard *keyboard =
+               weston_seat_get_keyboard(&seat->base);
+
+       if (keyboard)
+               notify_keyboard_focus_out(&seat->base);
+
+       udev_seat_remove_devices(seat);
+       weston_seat_release(&seat->base);
+       wl_list_remove(&seat->output_create_listener.link);
+       free(seat);
+}
+
+struct udev_seat *
+udev_seat_get_named(struct udev_input *input, const char *seat_name)
+{
+       struct udev_seat *seat;
+
+       wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
+               if (strcmp(seat->base.seat_name, seat_name) == 0)
+                       return seat;
+       }
+
+       return udev_seat_create(input, seat_name);
+}
diff --git a/libweston/libinput-seat.h b/libweston/libinput-seat.h
new file mode 100644 (file)
index 0000000..65c9b64
--- /dev/null
@@ -0,0 +1,72 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ * Copyright © 2013 Jonas Ådahl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _LIBINPUT_SEAT_H_
+#define _LIBINPUT_SEAT_H_
+
+#include "config.h"
+
+#include <libudev.h>
+
+#include "compositor.h"
+
+struct libinput_device;
+
+struct udev_seat {
+       struct weston_seat base;
+       struct wl_list devices_list;
+       struct wl_listener output_create_listener;
+};
+
+typedef void (*udev_configure_device_t)(struct weston_compositor *compositor,
+                                       struct libinput_device *device);
+
+struct udev_input {
+       struct libinput *libinput;
+       struct wl_event_source *libinput_source;
+       struct weston_compositor *compositor;
+       int suspended;
+       udev_configure_device_t configure_device;
+};
+
+int
+udev_input_enable(struct udev_input *input);
+void
+udev_input_disable(struct udev_input *input);
+int
+udev_input_init(struct udev_input *input,
+               struct weston_compositor *c,
+               struct udev *udev,
+               const char *seat_id,
+               udev_configure_device_t configure_device);
+void
+udev_input_destroy(struct udev_input *input);
+
+struct udev_seat *
+udev_seat_get_named(struct udev_input *u,
+                   const char *seat_name);
+
+#endif
diff --git a/libweston/libweston.pc.in b/libweston/libweston.pc.in
new file mode 100644 (file)
index 0000000..24fe813
--- /dev/null
@@ -0,0 +1,12 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+pkgincludedir=${includedir}/libweston-@LIBWESTON_ABI_VERSION@
+
+Name: libweston API
+Description: Header files for libweston compositors development
+Version: @WESTON_VERSION@
+Requires.private: wayland-server pixman-1 xkbcommon
+Cflags: -I${pkgincludedir}
+Libs: -L${libdir} -lweston-@LIBWESTON_ABI_VERSION@
diff --git a/libweston/linux-dmabuf.c b/libweston/linux-dmabuf.c
new file mode 100644 (file)
index 0000000..78e77a2
--- /dev/null
@@ -0,0 +1,497 @@
+/*
+ * Copyright © 2014, 2015 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include "compositor.h"
+#include "linux-dmabuf.h"
+#include "linux-dmabuf-unstable-v1-server-protocol.h"
+
+static void
+linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
+{
+       int i;
+
+       for (i = 0; i < buffer->attributes.n_planes; i++) {
+               close(buffer->attributes.fd[i]);
+               buffer->attributes.fd[i] = -1;
+       }
+
+       buffer->attributes.n_planes = 0;
+       free(buffer);
+}
+
+static void
+destroy_params(struct wl_resource *params_resource)
+{
+       struct linux_dmabuf_buffer *buffer;
+
+       buffer = wl_resource_get_user_data(params_resource);
+
+       if (!buffer)
+               return;
+
+       linux_dmabuf_buffer_destroy(buffer);
+}
+
+static void
+params_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+params_add(struct wl_client *client,
+          struct wl_resource *params_resource,
+          int32_t name_fd,
+          uint32_t plane_idx,
+          uint32_t offset,
+          uint32_t stride,
+          uint32_t modifier_hi,
+          uint32_t modifier_lo)
+{
+       struct linux_dmabuf_buffer *buffer;
+
+       buffer = wl_resource_get_user_data(params_resource);
+       if (!buffer) {
+               wl_resource_post_error(params_resource,
+                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
+                       "params was already used to create a wl_buffer");
+               close(name_fd);
+               return;
+       }
+
+       assert(buffer->params_resource == params_resource);
+       assert(!buffer->buffer_resource);
+
+       if (plane_idx >= MAX_DMABUF_PLANES) {
+               wl_resource_post_error(params_resource,
+                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
+                       "plane index %u is too high", plane_idx);
+               close(name_fd);
+               return;
+       }
+
+       if (buffer->attributes.fd[plane_idx] != -1) {
+               wl_resource_post_error(params_resource,
+                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
+                       "a dmabuf has already been added for plane %u",
+                       plane_idx);
+               close(name_fd);
+               return;
+       }
+
+       buffer->attributes.fd[plane_idx] = name_fd;
+       buffer->attributes.offset[plane_idx] = offset;
+       buffer->attributes.stride[plane_idx] = stride;
+       buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
+                                                modifier_lo;
+       buffer->attributes.n_planes++;
+}
+
+static void
+linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
+                              struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
+       linux_dmabuf_wl_buffer_destroy
+};
+
+static void
+destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
+{
+       struct linux_dmabuf_buffer *buffer;
+
+       buffer = wl_resource_get_user_data(resource);
+       assert(buffer->buffer_resource == resource);
+       assert(!buffer->params_resource);
+
+       if (buffer->user_data_destroy_func)
+               buffer->user_data_destroy_func(buffer);
+
+       linux_dmabuf_buffer_destroy(buffer);
+}
+
+static void
+params_create(struct wl_client *client,
+             struct wl_resource *params_resource,
+             int32_t width,
+             int32_t height,
+             uint32_t format,
+             uint32_t flags)
+{
+       struct linux_dmabuf_buffer *buffer;
+       int i;
+
+       buffer = wl_resource_get_user_data(params_resource);
+
+       if (!buffer) {
+               wl_resource_post_error(params_resource,
+                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
+                       "params was already used to create a wl_buffer");
+               return;
+       }
+
+       assert(buffer->params_resource == params_resource);
+       assert(!buffer->buffer_resource);
+
+       /* Switch the linux_dmabuf_buffer object from params resource to
+        * eventually wl_buffer resource.
+        */
+       wl_resource_set_user_data(buffer->params_resource, NULL);
+       buffer->params_resource = NULL;
+
+       if (!buffer->attributes.n_planes) {
+               wl_resource_post_error(params_resource,
+                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+                       "no dmabuf has been added to the params");
+               goto err_out;
+       }
+
+       /* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
+       for (i = 0; i < buffer->attributes.n_planes; i++) {
+               if (buffer->attributes.fd[i] == -1) {
+                       wl_resource_post_error(params_resource,
+                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
+                               "no dmabuf has been added for plane %i", i);
+                       goto err_out;
+               }
+       }
+
+       buffer->attributes.width = width;
+       buffer->attributes.height = height;
+       buffer->attributes.format = format;
+       buffer->attributes.flags = flags;
+
+       if (width < 1 || height < 1) {
+               wl_resource_post_error(params_resource,
+                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
+                       "invalid width %d or height %d", width, height);
+               goto err_out;
+       }
+
+       for (i = 0; i < buffer->attributes.n_planes; i++) {
+               off_t size;
+
+               if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
+                       wl_resource_post_error(params_resource,
+                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+                               "size overflow for plane %i", i);
+                       goto err_out;
+               }
+
+               if (i == 0 &&
+                  (uint64_t) buffer->attributes.offset[i] +
+                  (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
+                       wl_resource_post_error(params_resource,
+                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+                               "size overflow for plane %i", i);
+                       goto err_out;
+               }
+
+               /* Don't report an error as it might be caused
+                * by the kernel not supporting seeking on dmabuf */
+               size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
+               if (size == -1)
+                       continue;
+
+               if (buffer->attributes.offset[i] >= size) {
+                       wl_resource_post_error(params_resource,
+                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+                               "invalid offset %i for plane %i",
+                               buffer->attributes.offset[i], i);
+                       goto err_out;
+               }
+
+               if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
+                       wl_resource_post_error(params_resource,
+                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+                               "invalid stride %i for plane %i",
+                               buffer->attributes.stride[i], i);
+                       goto err_out;
+               }
+
+               /* Only valid for first plane as other planes might be
+                * sub-sampled according to fourcc format */
+               if (i == 0 &&
+                   buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
+                       wl_resource_post_error(params_resource,
+                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
+                               "invalid buffer stride or height for plane %i", i);
+                       goto err_out;
+               }
+       }
+
+       /* XXX: Some additional sanity checks could be done with respect
+        * to the fourcc format. A centralized collection (kernel or
+        * libdrm) would be useful to avoid code duplication for these
+        * checks (e.g. drm_format_num_planes).
+        */
+
+       if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
+               goto err_failed;
+
+       buffer->buffer_resource = wl_resource_create(client,
+                                                    &wl_buffer_interface,
+                                                    1, 0);
+       if (!buffer->buffer_resource) {
+               wl_resource_post_no_memory(params_resource);
+               goto err_buffer;
+       }
+
+       wl_resource_set_implementation(buffer->buffer_resource,
+                                      &linux_dmabuf_buffer_implementation,
+                                      buffer, destroy_linux_dmabuf_wl_buffer);
+
+       zwp_linux_buffer_params_v1_send_created(params_resource,
+                                               buffer->buffer_resource);
+
+       return;
+
+err_buffer:
+       if (buffer->user_data_destroy_func)
+               buffer->user_data_destroy_func(buffer);
+
+err_failed:
+       zwp_linux_buffer_params_v1_send_failed(params_resource);
+
+err_out:
+       linux_dmabuf_buffer_destroy(buffer);
+}
+
+static const struct zwp_linux_buffer_params_v1_interface
+zwp_linux_buffer_params_implementation = {
+       params_destroy,
+       params_add,
+       params_create
+};
+
+static void
+linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+       wl_resource_destroy(resource);
+}
+
+static void
+linux_dmabuf_create_params(struct wl_client *client,
+                          struct wl_resource *linux_dmabuf_resource,
+                          uint32_t params_id)
+{
+       struct weston_compositor *compositor;
+       struct linux_dmabuf_buffer *buffer;
+       uint32_t version;
+       int i;
+
+       version = wl_resource_get_version(linux_dmabuf_resource);
+       compositor = wl_resource_get_user_data(linux_dmabuf_resource);
+
+       buffer = zalloc(sizeof *buffer);
+       if (!buffer)
+               goto err_out;
+
+       for (i = 0; i < MAX_DMABUF_PLANES; i++)
+               buffer->attributes.fd[i] = -1;
+
+       buffer->compositor = compositor;
+       buffer->params_resource =
+               wl_resource_create(client,
+                                  &zwp_linux_buffer_params_v1_interface,
+                                  version, params_id);
+       if (!buffer->params_resource)
+               goto err_dealloc;
+
+       wl_resource_set_implementation(buffer->params_resource,
+                                      &zwp_linux_buffer_params_implementation,
+                                      buffer, destroy_params);
+
+       return;
+
+err_dealloc:
+       free(buffer);
+
+err_out:
+       wl_resource_post_no_memory(linux_dmabuf_resource);
+}
+
+/** Get the linux_dmabuf_buffer from a wl_buffer resource
+ *
+ * If the given wl_buffer resource was created through the linux_dmabuf
+ * protocol interface, returns the linux_dmabuf_buffer object. This can
+ * be used as a type check for a wl_buffer.
+ *
+ * \param resource A wl_buffer resource.
+ * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
+ */
+WL_EXPORT struct linux_dmabuf_buffer *
+linux_dmabuf_buffer_get(struct wl_resource *resource)
+{
+       struct linux_dmabuf_buffer *buffer;
+
+       if (!resource)
+               return NULL;
+
+       if (!wl_resource_instance_of(resource, &wl_buffer_interface,
+                                    &linux_dmabuf_buffer_implementation))
+               return NULL;
+
+       buffer = wl_resource_get_user_data(resource);
+       assert(buffer);
+       assert(!buffer->params_resource);
+       assert(buffer->buffer_resource == resource);
+
+       return buffer;
+}
+
+/** Set renderer-private data
+ *
+ * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
+ * a non-NULL user data with a new non-NULL pointer. This is meant to
+ * protect against renderers fighting over linux_dmabuf_buffer user data
+ * ownership.
+ *
+ * The renderer-private data is usually set from the
+ * weston_renderer::import_dmabuf hook.
+ *
+ * \param buffer The linux_dmabuf_buffer object to set for.
+ * \param data The new renderer-private data pointer.
+ * \param func Destructor function to be called for the renderer-private
+ *             data when the linux_dmabuf_buffer gets destroyed.
+ *
+ * \sa weston_compositor_import_dmabuf
+ */
+WL_EXPORT void
+linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
+                                 void *data,
+                                 dmabuf_user_data_destroy_func func)
+{
+       assert(data == NULL || buffer->user_data == NULL);
+
+       buffer->user_data = data;
+       buffer->user_data_destroy_func = func;
+}
+
+/** Get renderer-private data
+ *
+ * Get the user data from the linux_dmabuf_buffer.
+ *
+ * \param buffer The linux_dmabuf_buffer to query.
+ * \return Renderer-private data pointer.
+ *
+ * \sa linux_dmabuf_buffer_set_user_data
+ */
+WL_EXPORT void *
+linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
+{
+       return buffer->user_data;
+}
+
+static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
+       linux_dmabuf_destroy,
+       linux_dmabuf_create_params
+};
+
+static void
+bind_linux_dmabuf(struct wl_client *client,
+                 void *data, uint32_t version, uint32_t id)
+{
+       struct weston_compositor *compositor = data;
+       struct wl_resource *resource;
+
+       resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
+                                     version, id);
+       if (resource == NULL) {
+               wl_client_post_no_memory(client);
+               return;
+       }
+
+       wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
+                                      compositor, NULL);
+
+       /* EGL_EXT_image_dma_buf_import does not provide a way to query the
+        * supported pixel formats. */
+       /* XXX: send formats */
+}
+
+/** Advertise linux_dmabuf support
+ *
+ * Calling this initializes the zwp_linux_dmabuf protocol support, so that
+ * the interface will be advertised to clients. Essentially it creates a
+ * global. Do not call this function multiple times in the compositor's
+ * lifetime. There is no way to deinit explicitly, globals will be reaped
+ * when the wl_display gets destroyed.
+ *
+ * \param compositor The compositor to init for.
+ * \return Zero on success, -1 on failure.
+ */
+WL_EXPORT int
+linux_dmabuf_setup(struct weston_compositor *compositor)
+{
+       if (!wl_global_create(compositor->wl_display,
+                             &zwp_linux_dmabuf_v1_interface, 1,
+                             compositor, bind_linux_dmabuf))
+               return -1;
+
+       return 0;
+}
+
+/** Resolve an internal compositor error by disconnecting the client.
+ *
+ * This function is used in cases when the dmabuf-based wl_buffer
+ * turns out unusable and there is no fallback path. This is used by
+ * renderers which are the fallback path in the first place.
+ *
+ * It is possible the fault is caused by a compositor bug, the underlying
+ * graphics stack bug or normal behaviour, or perhaps a client mistake.
+ * In any case, the options are to either composite garbage or nothing,
+ * or disconnect the client. This is a helper function for the latter.
+ *
+ * The error is sent as a INVALID_OBJECT error on the client's wl_display.
+ *
+ * \param buffer The linux_dmabuf_buffer that is unusable.
+ * \param msg A custom error message attached to the protocol error.
+ */
+WL_EXPORT void
+linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
+                                     const char *msg)
+{
+       struct wl_client *client;
+       struct wl_resource *display_resource;
+       uint32_t id;
+
+       assert(buffer->buffer_resource);
+       id = wl_resource_get_id(buffer->buffer_resource);
+       client = wl_resource_get_client(buffer->buffer_resource);
+       display_resource = wl_client_get_object(client, 1);
+
+       assert(display_resource);
+       wl_resource_post_error(display_resource,
+                              WL_DISPLAY_ERROR_INVALID_OBJECT,
+                              "linux_dmabuf server error with "
+                              "wl_buffer@%u: %s", id, msg);
+}
diff --git a/libweston/linux-dmabuf.h b/libweston/linux-dmabuf.h
new file mode 100644 (file)
index 0000000..cd30f91
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright © 2014, 2015 Collabora, Ltd.
+ *
+ * Permission to use, copy, modify, distribute, and sell this software and
+ * its documentation for any purpose is hereby granted without fee, provided
+ * that the above copyright notice appear in all copies and that both that
+ * copyright notice and this permission notice appear in supporting
+ * documentation, and that the name of the copyright holders not be used in
+ * advertising or publicity pertaining to distribution of the software
+ * without specific, written prior permission.  The copyright holders make
+ * no representations about the suitability of this software for any
+ * purpose.  It is provided "as is" without express or implied warranty.
+ *
+ * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+ * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
+ * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
+ * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef WESTON_LINUX_DMABUF_H
+#define WESTON_LINUX_DMABUF_H
+
+#include <stdint.h>
+
+#define MAX_DMABUF_PLANES 4
+
+struct linux_dmabuf_buffer;
+typedef void (*dmabuf_user_data_destroy_func)(
+                       struct linux_dmabuf_buffer *buffer);
+
+struct dmabuf_attributes {
+       int32_t width;
+       int32_t height;
+       uint32_t format;
+       uint32_t flags; /* enum zlinux_buffer_params_flags */
+       int n_planes;
+       int fd[MAX_DMABUF_PLANES];
+       uint32_t offset[MAX_DMABUF_PLANES];
+       uint32_t stride[MAX_DMABUF_PLANES];
+       uint64_t modifier[MAX_DMABUF_PLANES];
+};
+
+struct linux_dmabuf_buffer {
+       struct wl_resource *buffer_resource;
+       struct wl_resource *params_resource;
+       struct weston_compositor *compositor;
+       struct dmabuf_attributes attributes;
+
+       void *user_data;
+       dmabuf_user_data_destroy_func user_data_destroy_func;
+
+       /* XXX:
+        *
+        * Add backend private data. This would be for the backend
+        * to do all additional imports it might ever use in advance.
+        * The basic principle, even if not implemented in drivers today,
+        * is that dmabufs are first attached, but the actual allocation
+        * is deferred to first use. This would allow the exporter and all
+        * attachers to agree on how to allocate.
+        *
+        * The DRM backend would use this to create drmFBs for each
+        * dmabuf_buffer, just in case at some point it would become
+        * feasible to scan it out directly. This would improve the
+        * possibilities to successfully scan out, avoiding compositing.
+        */
+};
+
+int
+linux_dmabuf_setup(struct weston_compositor *compositor);
+
+struct linux_dmabuf_buffer *
+linux_dmabuf_buffer_get(struct wl_resource *resource);
+
+void
+linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
+                                 void *data,
+                                 dmabuf_user_data_destroy_func func);
+void *
+linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer);
+
+void
+linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
+                                     const char *msg);
+
+#endif /* WESTON_LINUX_DMABUF_H */
diff --git a/libweston/log.c b/libweston/log.c
new file mode 100644 (file)
index 0000000..7d99a95
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+ * Copyright © 2012 Martin Minarik
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <time.h>
+
+#include <wayland-util.h>
+
+#include "compositor.h"
+
+static log_func_t log_handler = 0;
+static log_func_t log_continue_handler = 0;
+
+/** Install the log handler
+ *
+ * The given functions will be called to output text as passed to the
+ * \a weston_log and \a weston_log_continue functions.
+ *
+ * \param log The log function. This function will be called when
+ *            \a weston_log is called, and should begin a new line,
+ *            with user defined line headers, if any.
+ * \param cont The continue log function. This function will be called
+ *             when \a weston_log_continue is called, and should append
+ *             its output to the current line, without any header or
+ *             other content in between.
+ */
+WL_EXPORT void
+weston_log_set_handler(log_func_t log, log_func_t cont)
+{
+       log_handler = log;
+       log_continue_handler = cont;
+}
+
+WL_EXPORT int
+weston_vlog(const char *fmt, va_list ap)
+{
+       return log_handler(fmt, ap);
+}
+
+WL_EXPORT int
+weston_log(const char *fmt, ...)
+{
+       int l;
+       va_list argp;
+
+       va_start(argp, fmt);
+       l = weston_vlog(fmt, argp);
+       va_end(argp);
+
+       return l;
+}
+
+WL_EXPORT int
+weston_vlog_continue(const char *fmt, va_list argp)
+{
+       return log_continue_handler(fmt, argp);
+}
+
+WL_EXPORT int
+weston_log_continue(const char *fmt, ...)
+{
+       int l;
+       va_list argp;
+
+       va_start(argp, fmt);
+       l = weston_vlog_continue(fmt, argp);
+       va_end(argp);
+
+       return l;
+}
diff --git a/libweston/noop-renderer.c b/libweston/noop-renderer.c
new file mode 100644 (file)
index 0000000..b6499b8
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include "compositor.h"
+
+static int
+noop_renderer_read_pixels(struct weston_output *output,
+                              pixman_format_code_t format, void *pixels,
+                              uint32_t x, uint32_t y,
+                              uint32_t width, uint32_t height)
+{
+       return 0;
+}
+
+static void
+noop_renderer_repaint_output(struct weston_output *output,
+                            pixman_region32_t *output_damage)
+{
+}
+
+static void
+noop_renderer_flush_damage(struct weston_surface *surface)
+{
+}
+
+static void
+noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+{
+       struct wl_shm_buffer *shm_buffer;
+       uint8_t *data;
+       uint32_t size, i, width, height, stride;
+       volatile unsigned char unused = 0; /* volatile so it's not optimized out */
+
+       if (!buffer)
+               return;
+
+       shm_buffer = wl_shm_buffer_get(buffer->resource);
+
+       if (!shm_buffer) {
+               weston_log("No-op renderer supports only SHM buffers\n");
+               return;
+       }
+
+       data = wl_shm_buffer_get_data(shm_buffer);
+       stride = wl_shm_buffer_get_stride(shm_buffer);
+       width = wl_shm_buffer_get_width(shm_buffer);
+       height = wl_shm_buffer_get_height(shm_buffer);
+       size = stride * height;
+
+       /* Access the buffer data to make sure the buffer's client gets killed
+        * if the buffer size is invalid. This makes the bad_buffer test pass.
+        * This can be removed if we start reading the buffer contents
+        * somewhere else, e.g. in repaint_output(). */
+       wl_shm_buffer_begin_access(shm_buffer);
+       for (i = 0; i < size; i++)
+               unused ^= data[i];
+       wl_shm_buffer_end_access(shm_buffer);
+
+       buffer->shm_buffer = shm_buffer;
+       buffer->width = width;
+       buffer->height = height;
+}
+
+static void
+noop_renderer_surface_set_color(struct weston_surface *surface,
+                float red, float green, float blue, float alpha)
+{
+}
+
+static void
+noop_renderer_destroy(struct weston_compositor *ec)
+{
+       free(ec->renderer);
+       ec->renderer = NULL;
+}
+
+WL_EXPORT int
+noop_renderer_init(struct weston_compositor *ec)
+{
+       struct weston_renderer *renderer;
+
+       renderer = malloc(sizeof *renderer);
+       if (renderer == NULL)
+               return -1;
+
+       renderer->read_pixels = noop_renderer_read_pixels;
+       renderer->repaint_output = noop_renderer_repaint_output;
+       renderer->flush_damage = noop_renderer_flush_damage;
+       renderer->attach = noop_renderer_attach;
+       renderer->surface_set_color = noop_renderer_surface_set_color;
+       renderer->destroy = noop_renderer_destroy;
+       ec->renderer = renderer;
+
+       return 0;
+}
diff --git a/libweston/pixman-renderer.c b/libweston/pixman-renderer.c
new file mode 100644 (file)
index 0000000..f66a11e
--- /dev/null
@@ -0,0 +1,931 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
+ * Copyright © 2015 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <assert.h>
+
+#include "pixman-renderer.h"
+#include "shared/helpers.h"
+
+#include <linux/input.h>
+
+struct pixman_output_state {
+       void *shadow_buffer;
+       pixman_image_t *shadow_image;
+       pixman_image_t *hw_buffer;
+};
+
+struct pixman_surface_state {
+       struct weston_surface *surface;
+
+       pixman_image_t *image;
+       struct weston_buffer_reference buffer_ref;
+
+       struct wl_listener buffer_destroy_listener;
+       struct wl_listener surface_destroy_listener;
+       struct wl_listener renderer_destroy_listener;
+};
+
+struct pixman_renderer {
+       struct weston_renderer base;
+
+       int repaint_debug;
+       pixman_image_t *debug_color;
+       struct weston_binding *debug_binding;
+
+       struct wl_signal destroy_signal;
+};
+
+static inline struct pixman_output_state *
+get_output_state(struct weston_output *output)
+{
+       return (struct pixman_output_state *)output->renderer_state;
+}
+
+static int
+pixman_renderer_create_surface(struct weston_surface *surface);
+
+static inline struct pixman_surface_state *
+get_surface_state(struct weston_surface *surface)
+{
+       if (!surface->renderer_state)
+               pixman_renderer_create_surface(surface);
+
+       return (struct pixman_surface_state *)surface->renderer_state;
+}
+
+static inline struct pixman_renderer *
+get_renderer(struct weston_compositor *ec)
+{
+       return (struct pixman_renderer *)ec->renderer;
+}
+
+static int
+pixman_renderer_read_pixels(struct weston_output *output,
+                              pixman_format_code_t format, void *pixels,
+                              uint32_t x, uint32_t y,
+                              uint32_t width, uint32_t height)
+{
+       struct pixman_output_state *po = get_output_state(output);
+       pixman_transform_t transform;
+       pixman_image_t *out_buf;
+
+       if (!po->hw_buffer) {
+               errno = ENODEV;
+               return -1;
+       }
+
+       out_buf = pixman_image_create_bits(format,
+               width,
+               height,
+               pixels,
+               (PIXMAN_FORMAT_BPP(format) / 8) * width);
+
+       /* Caller expects vflipped source image */
+       pixman_transform_init_translate(&transform,
+                                       pixman_int_to_fixed (x),
+                                       pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
+       pixman_transform_scale(&transform, NULL,
+                              pixman_fixed_1,
+                              pixman_fixed_minus_1);
+       pixman_image_set_transform(po->hw_buffer, &transform);
+
+       pixman_image_composite32(PIXMAN_OP_SRC,
+                                po->hw_buffer, /* src */
+                                NULL /* mask */,
+                                out_buf, /* dest */
+                                0, 0, /* src_x, src_y */
+                                0, 0, /* mask_x, mask_y */
+                                0, 0, /* dest_x, dest_y */
+                                pixman_image_get_width (po->hw_buffer), /* width */
+                                pixman_image_get_height (po->hw_buffer) /* height */);
+       pixman_image_set_transform(po->hw_buffer, NULL);
+
+       pixman_image_unref(out_buf);
+
+       return 0;
+}
+
+static void
+region_global_to_output(struct weston_output *output, pixman_region32_t *region)
+{
+       if (output->zoom.active) {
+               weston_matrix_transform_region(region, &output->matrix, region);
+       } else {
+               pixman_region32_translate(region, -output->x, -output->y);
+               weston_transformed_region(output->width, output->height,
+                                         output->transform,
+                                         output->current_scale,
+                                         region, region);
+       }
+}
+
+#define D2F(v) pixman_double_to_fixed((double)v)
+
+static void
+weston_matrix_to_pixman_transform(pixman_transform_t *pt,
+                                 const struct weston_matrix *wm)
+{
+       /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
+        * so we're omitting Z coordinate here. */
+       pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
+       pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
+       pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
+       pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
+       pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
+       pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
+       pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
+       pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
+       pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
+}
+
+static void
+pixman_renderer_compute_transform(pixman_transform_t *transform_out,
+                                 struct weston_view *ev,
+                                 struct weston_output *output)
+{
+       struct weston_matrix matrix;
+
+       /* Set up the source transformation based on the surface
+          position, the output position/transform/scale and the client
+          specified buffer transform/scale */
+       matrix = output->inverse_matrix;
+
+       if (ev->transform.enabled) {
+               weston_matrix_multiply(&matrix, &ev->transform.inverse);
+       } else {
+               weston_matrix_translate(&matrix,
+                                       -ev->geometry.x, -ev->geometry.y, 0);
+       }
+
+       weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
+
+       weston_matrix_to_pixman_transform(transform_out, &matrix);
+}
+
+static bool
+view_transformation_is_translation(struct weston_view *view)
+{
+       if (!view->transform.enabled)
+               return true;
+
+       if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
+               return true;
+
+       return false;
+}
+
+static void
+region_intersect_only_translation(pixman_region32_t *result_global,
+                                 pixman_region32_t *global,
+                                 pixman_region32_t *surf,
+                                 struct weston_view *view)
+{
+       float view_x, view_y;
+
+       assert(view_transformation_is_translation(view));
+
+       /* Convert from surface to global coordinates */
+       pixman_region32_copy(result_global, surf);
+       weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
+       pixman_region32_translate(result_global, (int)view_x, (int)view_y);
+
+       pixman_region32_intersect(result_global, result_global, global);
+}
+
+static void
+composite_whole(pixman_op_t op,
+               pixman_image_t *src,
+               pixman_image_t *mask,
+               pixman_image_t *dest,
+               const pixman_transform_t *transform,
+               pixman_filter_t filter)
+{
+       int32_t dest_width;
+       int32_t dest_height;
+
+       dest_width = pixman_image_get_width(dest);
+       dest_height = pixman_image_get_height(dest);
+
+       pixman_image_set_transform(src, transform);
+       pixman_image_set_filter(src, filter, NULL, 0);
+
+       pixman_image_composite32(op, src, mask, dest,
+                                0, 0, /* src_x, src_y */
+                                0, 0, /* mask_x, mask_y */
+                                0, 0, /* dest_x, dest_y */
+                                dest_width, dest_height);
+}
+
+static void
+composite_clipped(pixman_image_t *src,
+                 pixman_image_t *mask,
+                 pixman_image_t *dest,
+                 const pixman_transform_t *transform,
+                 pixman_filter_t filter,
+                 pixman_region32_t *src_clip)
+{
+       int n_box;
+       pixman_box32_t *boxes;
+       int32_t dest_width;
+       int32_t dest_height;
+       int src_stride;
+       int bitspp;
+       pixman_format_code_t src_format;
+       void *src_data;
+       int i;
+
+       /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
+        * a Pixman image produces (0,0,0,0) instead of discarding the
+        * fragment.
+        */
+
+       dest_width = pixman_image_get_width(dest);
+       dest_height = pixman_image_get_height(dest);
+       src_format = pixman_image_get_format(src);
+       src_stride = pixman_image_get_stride(src);
+       bitspp = PIXMAN_FORMAT_BPP(src_format);
+       src_data = pixman_image_get_data(src);
+
+       assert(src_format);
+
+       /* This would be massive overdraw, except when n_box is 1. */
+       boxes = pixman_region32_rectangles(src_clip, &n_box);
+       for (i = 0; i < n_box; i++) {
+               uint8_t *ptr = src_data;
+               pixman_image_t *boximg;
+               pixman_transform_t adj = *transform;
+
+               ptr += boxes[i].y1 * src_stride;
+               ptr += boxes[i].x1 * bitspp / 8;
+               boximg = pixman_image_create_bits_no_clear(src_format,
+                                       boxes[i].x2 - boxes[i].x1,
+                                       boxes[i].y2 - boxes[i].y1,
+                                       (uint32_t *)ptr, src_stride);
+
+               pixman_transform_translate(&adj, NULL,
+                                          pixman_int_to_fixed(-boxes[i].x1),
+                                          pixman_int_to_fixed(-boxes[i].y1));
+               pixman_image_set_transform(boximg, &adj);
+
+               pixman_image_set_filter(boximg, filter, NULL, 0);
+               pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
+                                        0, 0, /* src_x, src_y */
+                                        0, 0, /* mask_x, mask_y */
+                                        0, 0, /* dest_x, dest_y */
+                                        dest_width, dest_height);
+
+               pixman_image_unref(boximg);
+       }
+
+       if (n_box > 1) {
+               static bool warned = false;
+
+               if (!warned)
+                       weston_log("Pixman-renderer warning: %dx overdraw\n",
+                                  n_box);
+               warned = true;
+       }
+}
+
+/** Paint an intersected region
+ *
+ * \param ev The view to be painted.
+ * \param output The output being painted.
+ * \param repaint_output The region to be painted in output coordinates.
+ * \param source_clip The region of the source image to use, in source image
+ *                    coordinates. If NULL, use the whole source image.
+ * \param pixman_op Compositing operator, either SRC or OVER.
+ */
+static void
+repaint_region(struct weston_view *ev, struct weston_output *output,
+              pixman_region32_t *repaint_output,
+              pixman_region32_t *source_clip,
+              pixman_op_t pixman_op)
+{
+       struct pixman_renderer *pr =
+               (struct pixman_renderer *) output->compositor->renderer;
+       struct pixman_surface_state *ps = get_surface_state(ev->surface);
+       struct pixman_output_state *po = get_output_state(output);
+       struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
+       pixman_transform_t transform;
+       pixman_filter_t filter;
+       pixman_image_t *mask_image;
+       pixman_color_t mask = { 0, };
+
+       /* Clip rendering to the damaged output region */
+       pixman_image_set_clip_region32(po->shadow_image, repaint_output);
+
+       pixman_renderer_compute_transform(&transform, ev, output);
+
+       if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
+               filter = PIXMAN_FILTER_BILINEAR;
+       else
+               filter = PIXMAN_FILTER_NEAREST;
+
+       if (ps->buffer_ref.buffer)
+               wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
+
+       if (ev->alpha < 1.0) {
+               mask.alpha = 0xffff * ev->alpha;
+               mask_image = pixman_image_create_solid_fill(&mask);
+       } else {
+               mask_image = NULL;
+       }
+
+       if (source_clip)
+               composite_clipped(ps->image, mask_image, po->shadow_image,
+                                 &transform, filter, source_clip);
+       else
+               composite_whole(pixman_op, ps->image, mask_image,
+                               po->shadow_image, &transform, filter);
+
+       if (mask_image)
+               pixman_image_unref(mask_image);
+
+       if (ps->buffer_ref.buffer)
+               wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
+
+       if (pr->repaint_debug)
+               pixman_image_composite32(PIXMAN_OP_OVER,
+                                        pr->debug_color, /* src */
+                                        NULL /* mask */,
+                                        po->shadow_image, /* dest */
+                                        0, 0, /* src_x, src_y */
+                                        0, 0, /* mask_x, mask_y */
+                                        0, 0, /* dest_x, dest_y */
+                                        pixman_image_get_width (po->shadow_image), /* width */
+                                        pixman_image_get_height (po->shadow_image) /* height */);
+
+       pixman_image_set_clip_region32 (po->shadow_image, NULL);
+}
+
+static void
+draw_view_translated(struct weston_view *view, struct weston_output *output,
+                    pixman_region32_t *repaint_global)
+{
+       struct weston_surface *surface = view->surface;
+       /* non-opaque region in surface coordinates: */
+       pixman_region32_t surface_blend;
+       /* region to be painted in output coordinates: */
+       pixman_region32_t repaint_output;
+
+       pixman_region32_init(&repaint_output);
+
+       /* Blended region is whole surface minus opaque region,
+        * unless surface alpha forces us to blend all.
+        */
+       pixman_region32_init_rect(&surface_blend, 0, 0,
+                                 surface->width, surface->height);
+
+       if (!(view->alpha < 1.0)) {
+               pixman_region32_subtract(&surface_blend, &surface_blend,
+                                        &surface->opaque);
+
+               if (pixman_region32_not_empty(&surface->opaque)) {
+                       region_intersect_only_translation(&repaint_output,
+                                                         repaint_global,
+                                                         &surface->opaque,
+                                                         view);
+                       region_global_to_output(output, &repaint_output);
+
+                       repaint_region(view, output, &repaint_output, NULL,
+                                      PIXMAN_OP_SRC);
+               }
+       }
+
+       if (pixman_region32_not_empty(&surface_blend)) {
+               region_intersect_only_translation(&repaint_output,
+                                                 repaint_global,
+                                                 &surface_blend, view);
+               region_global_to_output(output, &repaint_output);
+
+               repaint_region(view, output, &repaint_output, NULL,
+                              PIXMAN_OP_OVER);
+       }
+
+       pixman_region32_fini(&surface_blend);
+       pixman_region32_fini(&repaint_output);
+}
+
+static void
+draw_view_source_clipped(struct weston_view *view,
+                        struct weston_output *output,
+                        pixman_region32_t *repaint_global)
+{
+       struct weston_surface *surface = view->surface;
+       pixman_region32_t surf_region;
+       pixman_region32_t buffer_region;
+       pixman_region32_t repaint_output;
+
+       /* Do not bother separating the opaque region from non-opaque.
+        * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
+        * opaque separately has no benefit.
+        */
+
+       pixman_region32_init_rect(&surf_region, 0, 0,
+                                 surface->width, surface->height);
+       if (view->geometry.scissor_enabled)
+               pixman_region32_intersect(&surf_region, &surf_region,
+                                         &view->geometry.scissor);
+
+       pixman_region32_init(&buffer_region);
+       weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
+
+       pixman_region32_init(&repaint_output);
+       pixman_region32_copy(&repaint_output, repaint_global);
+       region_global_to_output(output, &repaint_output);
+
+       repaint_region(view, output, &repaint_output, &buffer_region,
+                      PIXMAN_OP_OVER);
+
+       pixman_region32_fini(&repaint_output);
+       pixman_region32_fini(&buffer_region);
+       pixman_region32_fini(&surf_region);
+}
+
+static void
+draw_view(struct weston_view *ev, struct weston_output *output,
+         pixman_region32_t *damage) /* in global coordinates */
+{
+       struct pixman_surface_state *ps = get_surface_state(ev->surface);
+       /* repaint bounding region in global coordinates: */
+       pixman_region32_t repaint;
+
+       /* No buffer attached */
+       if (!ps->image)
+               return;
+
+       pixman_region32_init(&repaint);
+       pixman_region32_intersect(&repaint,
+                                 &ev->transform.boundingbox, damage);
+       pixman_region32_subtract(&repaint, &repaint, &ev->clip);
+
+       if (!pixman_region32_not_empty(&repaint))
+               goto out;
+
+       if (view_transformation_is_translation(ev)) {
+               /* The simple case: The surface regions opaque, non-opaque,
+                * etc. are convertible to global coordinate space.
+                * There is no need to use a source clip region.
+                * It is possible to paint opaque region as PIXMAN_OP_SRC.
+                * Also the boundingbox is accurate rather than an
+                * approximation.
+                */
+               draw_view_translated(ev, output, &repaint);
+       } else {
+               /* The complex case: the view transformation does not allow
+                * converting opaque etc. regions into global coordinate space.
+                * Therefore we need source clipping to avoid sampling from
+                * unwanted source image areas, unless the source image is
+                * to be used whole. Source clipping does not work with
+                * PIXMAN_OP_SRC.
+                */
+               draw_view_source_clipped(ev, output, &repaint);
+       }
+
+out:
+       pixman_region32_fini(&repaint);
+}
+static void
+repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
+{
+       struct weston_compositor *compositor = output->compositor;
+       struct weston_view *view;
+
+       wl_list_for_each_reverse(view, &compositor->view_list, link)
+               if (view->plane == &compositor->primary_plane)
+                       draw_view(view, output, damage);
+}
+
+static void
+copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
+{
+       struct pixman_output_state *po = get_output_state(output);
+       pixman_region32_t output_region;
+
+       pixman_region32_init(&output_region);
+       pixman_region32_copy(&output_region, region);
+
+       region_global_to_output(output, &output_region);
+
+       pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
+       pixman_region32_fini(&output_region);
+
+       pixman_image_composite32(PIXMAN_OP_SRC,
+                                po->shadow_image, /* src */
+                                NULL /* mask */,
+                                po->hw_buffer, /* dest */
+                                0, 0, /* src_x, src_y */
+                                0, 0, /* mask_x, mask_y */
+                                0, 0, /* dest_x, dest_y */
+                                pixman_image_get_width (po->hw_buffer), /* width */
+                                pixman_image_get_height (po->hw_buffer) /* height */);
+
+       pixman_image_set_clip_region32 (po->hw_buffer, NULL);
+}
+
+static void
+pixman_renderer_repaint_output(struct weston_output *output,
+                            pixman_region32_t *output_damage)
+{
+       struct pixman_output_state *po = get_output_state(output);
+
+       if (!po->hw_buffer)
+               return;
+
+       repaint_surfaces(output, output_damage);
+       copy_to_hw_buffer(output, output_damage);
+
+       pixman_region32_copy(&output->previous_damage, output_damage);
+       wl_signal_emit(&output->frame_signal, output);
+
+       /* Actual flip should be done by caller */
+}
+
+static void
+pixman_renderer_flush_damage(struct weston_surface *surface)
+{
+       /* No-op for pixman renderer */
+}
+
+static void
+buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
+{
+       struct pixman_surface_state *ps;
+
+       ps = container_of(listener, struct pixman_surface_state,
+                         buffer_destroy_listener);
+
+       if (ps->image) {
+               pixman_image_unref(ps->image);
+               ps->image = NULL;
+       }
+
+       ps->buffer_destroy_listener.notify = NULL;
+}
+
+static void
+pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
+{
+       struct pixman_surface_state *ps = get_surface_state(es);
+       struct wl_shm_buffer *shm_buffer;
+       pixman_format_code_t pixman_format;
+
+       weston_buffer_reference(&ps->buffer_ref, buffer);
+
+       if (ps->buffer_destroy_listener.notify) {
+               wl_list_remove(&ps->buffer_destroy_listener.link);
+               ps->buffer_destroy_listener.notify = NULL;
+       }
+
+       if (ps->image) {
+               pixman_image_unref(ps->image);
+               ps->image = NULL;
+       }
+
+       if (!buffer)
+               return;
+
+       shm_buffer = wl_shm_buffer_get(buffer->resource);
+
+       if (! shm_buffer) {
+               weston_log("Pixman renderer supports only SHM buffers\n");
+               weston_buffer_reference(&ps->buffer_ref, NULL);
+               return;
+       }
+
+       switch (wl_shm_buffer_get_format(shm_buffer)) {
+       case WL_SHM_FORMAT_XRGB8888:
+               pixman_format = PIXMAN_x8r8g8b8;
+               break;
+       case WL_SHM_FORMAT_ARGB8888:
+               pixman_format = PIXMAN_a8r8g8b8;
+               break;
+       case WL_SHM_FORMAT_RGB565:
+               pixman_format = PIXMAN_r5g6b5;
+               break;
+       default:
+               weston_log("Unsupported SHM buffer format\n");
+               weston_buffer_reference(&ps->buffer_ref, NULL);
+               return;
+       break;
+       }
+
+       buffer->shm_buffer = shm_buffer;
+       buffer->width = wl_shm_buffer_get_width(shm_buffer);
+       buffer->height = wl_shm_buffer_get_height(shm_buffer);
+
+       ps->image = pixman_image_create_bits(pixman_format,
+               buffer->width, buffer->height,
+               wl_shm_buffer_get_data(shm_buffer),
+               wl_shm_buffer_get_stride(shm_buffer));
+
+       ps->buffer_destroy_listener.notify =
+               buffer_state_handle_buffer_destroy;
+       wl_signal_add(&buffer->destroy_signal,
+                     &ps->buffer_destroy_listener);
+}
+
+static void
+pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
+{
+       wl_list_remove(&ps->surface_destroy_listener.link);
+       wl_list_remove(&ps->renderer_destroy_listener.link);
+       if (ps->buffer_destroy_listener.notify) {
+               wl_list_remove(&ps->buffer_destroy_listener.link);
+               ps->buffer_destroy_listener.notify = NULL;
+       }
+
+       ps->surface->renderer_state = NULL;
+
+       if (ps->image) {
+               pixman_image_unref(ps->image);
+               ps->image = NULL;
+       }
+       weston_buffer_reference(&ps->buffer_ref, NULL);
+       free(ps);
+}
+
+static void
+surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
+{
+       struct pixman_surface_state *ps;
+
+       ps = container_of(listener, struct pixman_surface_state,
+                         surface_destroy_listener);
+
+       pixman_renderer_surface_state_destroy(ps);
+}
+
+static void
+surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
+{
+       struct pixman_surface_state *ps;
+
+       ps = container_of(listener, struct pixman_surface_state,
+                         renderer_destroy_listener);
+
+       pixman_renderer_surface_state_destroy(ps);
+}
+
+static int
+pixman_renderer_create_surface(struct weston_surface *surface)
+{
+       struct pixman_surface_state *ps;
+       struct pixman_renderer *pr = get_renderer(surface->compositor);
+
+       ps = zalloc(sizeof *ps);
+       if (ps == NULL)
+               return -1;
+
+       surface->renderer_state = ps;
+
+       ps->surface = surface;
+
+       ps->surface_destroy_listener.notify =
+               surface_state_handle_surface_destroy;
+       wl_signal_add(&surface->destroy_signal,
+                     &ps->surface_destroy_listener);
+
+       ps->renderer_destroy_listener.notify =
+               surface_state_handle_renderer_destroy;
+       wl_signal_add(&pr->destroy_signal,
+                     &ps->renderer_destroy_listener);
+
+       return 0;
+}
+
+static void
+pixman_renderer_surface_set_color(struct weston_surface *es,
+                float red, float green, float blue, float alpha)
+{
+       struct pixman_surface_state *ps = get_surface_state(es);
+       pixman_color_t color;
+
+       color.red = red * 0xffff;
+       color.green = green * 0xffff;
+       color.blue = blue * 0xffff;
+       color.alpha = alpha * 0xffff;
+
+       if (ps->image) {
+               pixman_image_unref(ps->image);
+               ps->image = NULL;
+       }
+
+       ps->image = pixman_image_create_solid_fill(&color);
+}
+
+static void
+pixman_renderer_destroy(struct weston_compositor *ec)
+{
+       struct pixman_renderer *pr = get_renderer(ec);
+
+       wl_signal_emit(&pr->destroy_signal, pr);
+       weston_binding_destroy(pr->debug_binding);
+       free(pr);
+
+       ec->renderer = NULL;
+}
+
+static void
+pixman_renderer_surface_get_content_size(struct weston_surface *surface,
+                                        int *width, int *height)
+{
+       struct pixman_surface_state *ps = get_surface_state(surface);
+
+       if (ps->image) {
+               *width = pixman_image_get_width(ps->image);
+               *height = pixman_image_get_height(ps->image);
+       } else {
+               *width = 0;
+               *height = 0;
+       }
+}
+
+static int
+pixman_renderer_surface_copy_content(struct weston_surface *surface,
+                                    void *target, size_t size,
+                                    int src_x, int src_y,
+                                    int width, int height)
+{
+       const pixman_format_code_t format = PIXMAN_a8b8g8r8;
+       const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
+       struct pixman_surface_state *ps = get_surface_state(surface);
+       pixman_image_t *out_buf;
+
+       if (!ps->image)
+               return -1;
+
+       out_buf = pixman_image_create_bits(format, width, height,
+                                          target, width * bytespp);
+
+       pixman_image_set_transform(ps->image, NULL);
+       pixman_image_composite32(PIXMAN_OP_SRC,
+                                ps->image,    /* src */
+                                NULL,         /* mask */
+                                out_buf,      /* dest */
+                                src_x, src_y, /* src_x, src_y */
+                                0, 0,         /* mask_x, mask_y */
+                                0, 0,         /* dest_x, dest_y */
+                                width, height);
+
+       pixman_image_unref(out_buf);
+
+       return 0;
+}
+
+static void
+debug_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
+             void *data)
+{
+       struct weston_compositor *ec = data;
+       struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
+
+       pr->repaint_debug ^= 1;
+
+       if (pr->repaint_debug) {
+               pixman_color_t red = {
+                       0x3fff, 0x0000, 0x0000, 0x3fff
+               };
+
+               pr->debug_color = pixman_image_create_solid_fill(&red);
+       } else {
+               pixman_image_unref(pr->debug_color);
+               weston_compositor_damage_all(ec);
+       }
+}
+
+WL_EXPORT int
+pixman_renderer_init(struct weston_compositor *ec)
+{
+       struct pixman_renderer *renderer;
+
+       renderer = zalloc(sizeof *renderer);
+       if (renderer == NULL)
+               return -1;
+
+       renderer->repaint_debug = 0;
+       renderer->debug_color = NULL;
+       renderer->base.read_pixels = pixman_renderer_read_pixels;
+       renderer->base.repaint_output = pixman_renderer_repaint_output;
+       renderer->base.flush_damage = pixman_renderer_flush_damage;
+       renderer->base.attach = pixman_renderer_attach;
+       renderer->base.surface_set_color = pixman_renderer_surface_set_color;
+       renderer->base.destroy = pixman_renderer_destroy;
+       renderer->base.surface_get_content_size =
+               pixman_renderer_surface_get_content_size;
+       renderer->base.surface_copy_content =
+               pixman_renderer_surface_copy_content;
+       ec->renderer = &renderer->base;
+       ec->capabilities |= WESTON_CAP_ROTATION_ANY;
+       ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
+       ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
+
+       renderer->debug_binding =
+               weston_compositor_add_debug_binding(ec, KEY_R,
+                                                   debug_binding, ec);
+
+       wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
+
+       wl_signal_init(&renderer->destroy_signal);
+
+       return 0;
+}
+
+WL_EXPORT void
+pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
+{
+       struct pixman_output_state *po = get_output_state(output);
+
+       if (po->hw_buffer)
+               pixman_image_unref(po->hw_buffer);
+       po->hw_buffer = buffer;
+
+       if (po->hw_buffer) {
+               output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
+               pixman_image_ref(po->hw_buffer);
+       }
+}
+
+WL_EXPORT int
+pixman_renderer_output_create(struct weston_output *output)
+{
+       struct pixman_output_state *po;
+       int w, h;
+
+       po = zalloc(sizeof *po);
+       if (po == NULL)
+               return -1;
+
+       /* set shadow image transformation */
+       w = output->current_mode->width;
+       h = output->current_mode->height;
+
+       po->shadow_buffer = malloc(w * h * 4);
+
+       if (!po->shadow_buffer) {
+               free(po);
+               return -1;
+       }
+
+       po->shadow_image =
+               pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
+                                        po->shadow_buffer, w * 4);
+
+       if (!po->shadow_image) {
+               free(po->shadow_buffer);
+               free(po);
+               return -1;
+       }
+
+       output->renderer_state = po;
+
+       return 0;
+}
+
+WL_EXPORT void
+pixman_renderer_output_destroy(struct weston_output *output)
+{
+       struct pixman_output_state *po = get_output_state(output);
+
+       pixman_image_unref(po->shadow_image);
+
+       if (po->hw_buffer)
+               pixman_image_unref(po->hw_buffer);
+
+       free(po->shadow_buffer);
+
+       po->shadow_buffer = NULL;
+       po->shadow_image = NULL;
+       po->hw_buffer = NULL;
+
+       free(po);
+}
diff --git a/libweston/pixman-renderer.h b/libweston/pixman-renderer.h
new file mode 100644 (file)
index 0000000..1b42f14
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "compositor.h"
+
+int
+pixman_renderer_init(struct weston_compositor *ec);
+
+int
+pixman_renderer_output_create(struct weston_output *output);
+
+void
+pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer);
+
+void
+pixman_renderer_output_destroy(struct weston_output *output);
diff --git a/libweston/screenshooter.c b/libweston/screenshooter.c
new file mode 100644 (file)
index 0000000..fc14ad3
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <linux/input.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
+#include "compositor.h"
+#include "shared/helpers.h"
+
+#include "wcap/wcap-decode.h"
+
+struct screenshooter_frame_listener {
+       struct wl_listener listener;
+       struct weston_buffer *buffer;
+       weston_screenshooter_done_func_t done;
+       void *data;
+};
+
+static void
+copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
+{
+       uint8_t *end;
+
+       end = dst + height * stride;
+       while (dst < end) {
+               memcpy(dst, src, stride);
+               dst += stride;
+               src -= stride;
+       }
+}
+
+static void
+copy_bgra(uint8_t *dst, uint8_t *src, int height, int stride)
+{
+       /* TODO: optimize this out */
+       memcpy(dst, src, height * stride);
+}
+
+static void
+copy_row_swap_RB(void *vdst, void *vsrc, int bytes)
+{
+       uint32_t *dst = vdst;
+       uint32_t *src = vsrc;
+       uint32_t *end = dst + bytes / 4;
+
+       while (dst < end) {
+               uint32_t v = *src++;
+               /*                    A R G B */
+               uint32_t tmp = v & 0xff00ff00;
+               tmp |= (v >> 16) & 0x000000ff;
+               tmp |= (v << 16) & 0x00ff0000;
+               *dst++ = tmp;
+       }
+}
+
+static void
+copy_rgba_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
+{
+       uint8_t *end;
+
+       end = dst + height * stride;
+       while (dst < end) {
+               copy_row_swap_RB(dst, src, stride);
+               dst += stride;
+               src -= stride;
+       }
+}
+
+static void
+copy_rgba(uint8_t *dst, uint8_t *src, int height, int stride)
+{
+       uint8_t *end;
+
+       end = dst + height * stride;
+       while (dst < end) {
+               copy_row_swap_RB(dst, src, stride);
+               dst += stride;
+               src += stride;
+       }
+}
+
+static void
+screenshooter_frame_notify(struct wl_listener *listener, void *data)
+{
+       struct screenshooter_frame_listener *l =
+               container_of(listener,
+                            struct screenshooter_frame_listener, listener);
+       struct weston_output *output = data;
+       struct weston_compositor *compositor = output->compositor;
+       int32_t stride;
+       uint8_t *pixels, *d, *s;
+
+       output->disable_planes--;
+       wl_list_remove(&listener->link);
+       stride = l->buffer->width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8);
+       pixels = malloc(stride * l->buffer->height);
+
+       if (pixels == NULL) {
+               l->done(l->data, WESTON_SCREENSHOOTER_NO_MEMORY);
+               free(l);
+               return;
+       }
+
+       compositor->renderer->read_pixels(output,
+                            compositor->read_format, pixels,
+                            0, 0, output->current_mode->width,
+                            output->current_mode->height);
+
+       stride = wl_shm_buffer_get_stride(l->buffer->shm_buffer);
+
+       d = wl_shm_buffer_get_data(l->buffer->shm_buffer);
+       s = pixels + stride * (l->buffer->height - 1);
+
+       wl_shm_buffer_begin_access(l->buffer->shm_buffer);
+
+       switch (compositor->read_format) {
+       case PIXMAN_a8r8g8b8:
+       case PIXMAN_x8r8g8b8:
+               if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
+                       copy_bgra_yflip(d, s, output->current_mode->height, stride);
+               else
+                       copy_bgra(d, pixels, output->current_mode->height, stride);
+               break;
+       case PIXMAN_x8b8g8r8:
+       case PIXMAN_a8b8g8r8:
+               if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
+                       copy_rgba_yflip(d, s, output->current_mode->height, stride);
+               else
+                       copy_rgba(d, pixels, output->current_mode->height, stride);
+               break;
+       default:
+               break;
+       }
+
+       wl_shm_buffer_end_access(l->buffer->shm_buffer);
+
+       l->done(l->data, WESTON_SCREENSHOOTER_SUCCESS);
+       free(pixels);
+       free(l);
+}
+
+WL_EXPORT int
+weston_screenshooter_shoot(struct weston_output *output,
+                          struct weston_buffer *buffer,
+                          weston_screenshooter_done_func_t done, void *data)
+{
+       struct screenshooter_frame_listener *l;
+
+       if (!wl_shm_buffer_get(buffer->resource)) {
+               done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
+               return -1;
+       }
+
+       buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
+       buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
+       buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
+
+       if (buffer->width < output->current_mode->width ||
+           buffer->height < output->current_mode->height) {
+               done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
+               return -1;
+       }
+
+       l = malloc(sizeof *l);
+       if (l == NULL) {
+               done(data, WESTON_SCREENSHOOTER_NO_MEMORY);
+               return -1;
+       }
+
+       l->buffer = buffer;
+       l->done = done;
+       l->data = data;
+       l->listener.notify = screenshooter_frame_notify;
+       wl_signal_add(&output->frame_signal, &l->listener);
+       output->disable_planes++;
+       weston_output_schedule_repaint(output);
+
+       return 0;
+}
+
+struct weston_recorder {
+       struct weston_output *output;
+       uint32_t *frame, *rect;
+       uint32_t *tmpbuf;
+       uint32_t total;
+       int fd;
+       struct wl_listener frame_listener;
+       int count, destroying;
+};
+
+static uint32_t *
+output_run(uint32_t *p, uint32_t delta, int run)
+{
+       int i;
+
+       while (run > 0) {
+               if (run <= 0xe0) {
+                       *p++ = delta | ((run - 1) << 24);
+                       break;
+               }
+
+               i = 24 - __builtin_clz(run);
+               *p++ = delta | ((i + 0xe0) << 24);
+               run -= 1 << (7 + i);
+       }
+
+       return p;
+}
+
+static uint32_t
+component_delta(uint32_t next, uint32_t prev)
+{
+       unsigned char dr, dg, db;
+
+       dr = (next >> 16) - (prev >> 16);
+       dg = (next >>  8) - (prev >>  8);
+       db = (next >>  0) - (prev >>  0);
+
+       return (dr << 16) | (dg << 8) | (db << 0);
+}
+
+static void
+weston_recorder_destroy(struct weston_recorder *recorder);
+
+static void
+weston_recorder_frame_notify(struct wl_listener *listener, void *data)
+{
+       struct weston_recorder *recorder =
+               container_of(listener, struct weston_recorder, frame_listener);
+       struct weston_output *output = data;
+       struct weston_compositor *compositor = output->compositor;
+       uint32_t msecs = output->frame_time;
+       pixman_box32_t *r;
+       pixman_region32_t damage, transformed_damage;
+       int i, j, k, n, width, height, run, stride;
+       uint32_t delta, prev, *d, *s, *p, next;
+       struct {
+               uint32_t msecs;
+               uint32_t nrects;
+       } header;
+       struct iovec v[2];
+       int do_yflip;
+       int y_orig;
+       uint32_t *outbuf;
+
+       do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
+       if (do_yflip)
+               outbuf = recorder->rect;
+       else
+               outbuf = recorder->tmpbuf;
+
+       pixman_region32_init(&damage);
+       pixman_region32_init(&transformed_damage);
+       pixman_region32_intersect(&damage, &output->region,
+                                 &output->previous_damage);
+       pixman_region32_translate(&damage, -output->x, -output->y);
+       weston_transformed_region(output->width, output->height,
+                                output->transform, output->current_scale,
+                                &damage, &transformed_damage);
+       pixman_region32_fini(&damage);
+
+       r = pixman_region32_rectangles(&transformed_damage, &n);
+       if (n == 0) {
+               pixman_region32_fini(&transformed_damage);
+               return;
+       }
+
+       header.msecs = msecs;
+       header.nrects = n;
+       v[0].iov_base = &header;
+       v[0].iov_len = sizeof header;
+       v[1].iov_base = r;
+       v[1].iov_len = n * sizeof *r;
+       recorder->total += writev(recorder->fd, v, 2);
+       stride = output->current_mode->width;
+
+       for (i = 0; i < n; i++) {
+               width = r[i].x2 - r[i].x1;
+               height = r[i].y2 - r[i].y1;
+
+               if (do_yflip)
+                       y_orig = output->current_mode->height - r[i].y2;
+               else
+                       y_orig = r[i].y1;
+
+               compositor->renderer->read_pixels(output,
+                               compositor->read_format, recorder->rect,
+                               r[i].x1, y_orig, width, height);
+
+               p = outbuf;
+               run = prev = 0; /* quiet gcc */
+               for (j = 0; j < height; j++) {
+                       if (do_yflip)
+                               s = recorder->rect + width * j;
+                       else
+                               s = recorder->rect + width * (height - j - 1);
+                       y_orig = r[i].y2 - j - 1;
+                       d = recorder->frame + stride * y_orig + r[i].x1;
+
+                       for (k = 0; k < width; k++) {
+                               next = *s++;
+                               delta = component_delta(next, *d);
+                               *d++ = next;
+                               if (run == 0 || delta == prev) {
+                                       run++;
+                               } else {
+                                       p = output_run(p, prev, run);
+                                       run = 1;
+                               }
+                               prev = delta;
+                       }
+               }
+
+               p = output_run(p, prev, run);
+
+               recorder->total += write(recorder->fd,
+                                        outbuf, (p - outbuf) * 4);
+
+#if 0
+               fprintf(stderr,
+                       "%dx%d at %d,%d rle from %d to %d bytes (%f) total %dM\n",
+                       width, height, r[i].x1, r[i].y1,
+                       width * height * 4, (int) (p - outbuf) * 4,
+                       (float) (p - outbuf) / (width * height),
+                       recorder->total / 1024 / 1024);
+#endif
+       }
+
+       pixman_region32_fini(&transformed_damage);
+       recorder->count++;
+
+       if (recorder->destroying)
+               weston_recorder_destroy(recorder);
+}
+
+static void
+weston_recorder_free(struct weston_recorder *recorder)
+{
+       if (recorder == NULL)
+               return;
+
+       free(recorder->tmpbuf);
+       free(recorder->rect);
+       free(recorder->frame);
+       free(recorder);
+}
+
+static struct weston_recorder *
+weston_recorder_create(struct weston_output *output, const char *filename)
+{
+       struct weston_compositor *compositor = output->compositor;
+       struct weston_recorder *recorder;
+       int stride, size;
+       struct { uint32_t magic, format, width, height; } header;
+       int do_yflip;
+
+       do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
+
+       recorder = zalloc(sizeof *recorder);
+       if (recorder == NULL) {
+               weston_log("%s: out of memory\n", __func__);
+               return NULL;
+       }
+
+       stride = output->current_mode->width;
+       size = stride * 4 * output->current_mode->height;
+       recorder->frame = zalloc(size);
+       recorder->rect = malloc(size);
+       recorder->output = output;
+
+       if ((recorder->frame == NULL) || (recorder->rect == NULL)) {
+               weston_log("%s: out of memory\n", __func__);
+               goto err_recorder;
+       }
+
+       if (!do_yflip) {
+               recorder->tmpbuf = malloc(size);
+               if (recorder->tmpbuf == NULL) {
+                       weston_log("%s: out of memory\n", __func__);
+                       goto err_recorder;
+               }
+       }
+
+       header.magic = WCAP_HEADER_MAGIC;
+
+       switch (compositor->read_format) {
+       case PIXMAN_x8r8g8b8:
+       case PIXMAN_a8r8g8b8:
+               header.format = WCAP_FORMAT_XRGB8888;
+               break;
+       case PIXMAN_a8b8g8r8:
+               header.format = WCAP_FORMAT_XBGR8888;
+               break;
+       default:
+               weston_log("unknown recorder format\n");
+               goto err_recorder;
+       }
+
+       recorder->fd = open(filename,
+                           O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
+
+       if (recorder->fd < 0) {
+               weston_log("problem opening output file %s: %m\n", filename);
+               goto err_recorder;
+       }
+
+       header.width = output->current_mode->width;
+       header.height = output->current_mode->height;
+       recorder->total += write(recorder->fd, &header, sizeof header);
+
+       recorder->frame_listener.notify = weston_recorder_frame_notify;
+       wl_signal_add(&output->frame_signal, &recorder->frame_listener);
+       output->disable_planes++;
+       weston_output_damage(output);
+
+       return recorder;
+
+err_recorder:
+       weston_recorder_free(recorder);
+       return NULL;
+}
+
+static void
+weston_recorder_destroy(struct weston_recorder *recorder)
+{
+       wl_list_remove(&recorder->frame_listener.link);
+       close(recorder->fd);
+       recorder->output->disable_planes--;
+       weston_recorder_free(recorder);
+}
+
+WL_EXPORT struct weston_recorder *
+weston_recorder_start(struct weston_output *output, const char *filename)
+{
+       struct wl_listener *listener;
+
+       listener = wl_signal_get(&output->frame_signal,
+                                weston_recorder_frame_notify);
+       if (listener) {
+               weston_log("a recorder on output %s is already running\n",
+                          output->name);
+               return NULL;
+       }
+
+       weston_log("starting recorder for output %s, file %s\n",
+                  output->name, filename);
+       return weston_recorder_create(output, filename);
+}
+
+WL_EXPORT void
+weston_recorder_stop(struct weston_recorder *recorder)
+{
+       weston_log("stopping recorder, total file size %dM, %d frames\n",
+                  recorder->total / (1024 * 1024), recorder->count);
+
+       recorder->destroying = 1;
+       weston_output_schedule_repaint(recorder->output);
+}
diff --git a/libweston/spring-tool.c b/libweston/spring-tool.c
new file mode 100644 (file)
index 0000000..1848b3f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include "compositor.h"
+
+WL_EXPORT void
+weston_view_geometry_dirty(struct weston_view *view)
+{
+}
+
+WL_EXPORT int
+weston_log(const char *fmt, ...)
+{
+       return 0;
+}
+
+WL_EXPORT void
+weston_view_schedule_repaint(struct weston_view *view)
+{
+}
+
+WL_EXPORT void
+weston_compositor_schedule_repaint(struct weston_compositor *compositor)
+{
+}
+
+int
+main(int argc, char *argv[])
+{
+       const double k = 300.0;
+       const double current = 0.5;
+       const double target = 1.0;
+       const double friction = 1400;
+
+       struct weston_spring spring;
+       uint32_t time = 0;
+
+       weston_spring_init(&spring, k, current, target);
+       spring.friction = friction;
+       spring.previous = 0.48;
+       spring.timestamp = 0;
+
+       while (!weston_spring_done(&spring)) {
+               printf("\t%d\t%f\n", time, spring.current);
+               weston_spring_update(&spring, time);
+               time += 16;
+       }
+
+       return 0;
+}
diff --git a/libweston/timeline-object.h b/libweston/timeline-object.h
new file mode 100644 (file)
index 0000000..943f979
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright © 2014 Pekka Paalanen <pq@iki.fi>
+ * Copyright © 2014 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_TIMELINE_OBJECT_H
+#define WESTON_TIMELINE_OBJECT_H
+
+/*
+ * This struct can be embedded in objects related to timeline output.
+ * It must be initialized to all-zero. Afterwards, the timeline code
+ * will handle it alone. No clean-up is necessary.
+ */
+struct weston_timeline_object {
+       /*
+        * Timeline series gets bumped every time a new log is opened.
+        * This triggers id allocation and object info emission.
+        * 0 is an invalid series value.
+        */
+       unsigned series;
+
+       /* Object id in the timeline JSON output. 0 is invalid. */
+       unsigned id;
+
+       /*
+        * If non-zero, forces a re-emission of object description.
+        * Should be set to non-zero, when changing long-lived
+        * object state that is not emitted on normal timeline
+        * events.
+        */
+       unsigned force_refresh;
+};
+
+#endif /* WESTON_TIMELINE_OBJECT_H */
diff --git a/libweston/timeline.c b/libweston/timeline.c
new file mode 100644 (file)
index 0000000..cf82428
--- /dev/null
@@ -0,0 +1,292 @@
+/*
+ * Copyright © 2014 Pekka Paalanen <pq@iki.fi>
+ * Copyright © 2014 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <time.h>
+#include <assert.h>
+
+#include "timeline.h"
+#include "compositor.h"
+#include "file-util.h"
+
+struct timeline_log {
+       clock_t clk_id;
+       FILE *file;
+       unsigned series;
+       struct wl_listener compositor_destroy_listener;
+};
+
+WL_EXPORT int weston_timeline_enabled_;
+static struct timeline_log timeline_ = { CLOCK_MONOTONIC, NULL, 0 };
+
+static int
+weston_timeline_do_open(void)
+{
+       const char *prefix = "weston-timeline-";
+       const char *suffix = ".log";
+       char fname[1000];
+
+       timeline_.file = file_create_dated(prefix, suffix,
+                                          fname, sizeof(fname));
+       if (!timeline_.file) {
+               const char *msg;
+
+               switch (errno) {
+               case ETIME:
+                       msg = "failure in datetime formatting";
+                       break;
+               default:
+                       msg = strerror(errno);
+               }
+
+               weston_log("Cannot open '%s*%s' for writing: %s\n",
+                          prefix, suffix, msg);
+               return -1;
+       }
+
+       weston_log("Opened timeline file '%s'\n", fname);
+
+       return 0;
+}
+
+static void
+timeline_notify_destroy(struct wl_listener *listener, void *data)
+{
+       weston_timeline_close();
+}
+
+void
+weston_timeline_open(struct weston_compositor *compositor)
+{
+       if (weston_timeline_enabled_)
+               return;
+
+       if (weston_timeline_do_open() < 0)
+               return;
+
+       timeline_.compositor_destroy_listener.notify = timeline_notify_destroy;
+       wl_signal_add(&compositor->destroy_signal,
+                     &timeline_.compositor_destroy_listener);
+
+       if (++timeline_.series == 0)
+               ++timeline_.series;
+
+       weston_timeline_enabled_ = 1;
+}
+
+void
+weston_timeline_close(void)
+{
+       if (!weston_timeline_enabled_)
+               return;
+
+       weston_timeline_enabled_ = 0;
+
+       wl_list_remove(&timeline_.compositor_destroy_listener.link);
+
+       fclose(timeline_.file);
+       timeline_.file = NULL;
+       weston_log("Timeline log file closed.\n");
+}
+
+struct timeline_emit_context {
+       FILE *cur;
+       FILE *out;
+       unsigned series;
+};
+
+static unsigned
+timeline_new_id(void)
+{
+       static unsigned idc;
+
+       if (++idc == 0)
+               ++idc;
+
+       return idc;
+}
+
+static int
+check_series(struct timeline_emit_context *ctx,
+            struct weston_timeline_object *to)
+{
+       if (to->series == 0 || to->series != ctx->series) {
+               to->series = ctx->series;
+               to->id = timeline_new_id();
+               return 1;
+       }
+
+       if (to->force_refresh) {
+               to->force_refresh = 0;
+               return 1;
+       }
+
+       return 0;
+}
+
+static void
+fprint_quoted_string(FILE *fp, const char *str)
+{
+       if (!str) {
+               fprintf(fp, "null");
+               return;
+       }
+
+       fprintf(fp, "\"%s\"", str);
+}
+
+static int
+emit_weston_output(struct timeline_emit_context *ctx, void *obj)
+{
+       struct weston_output *o = obj;
+
+       if (check_series(ctx, &o->timeline)) {
+               fprintf(ctx->out, "{ \"id\":%u, "
+                       "\"type\":\"weston_output\", \"name\":",
+                       o->timeline.id);
+               fprint_quoted_string(ctx->out, o->name);
+               fprintf(ctx->out, " }\n");
+       }
+
+       fprintf(ctx->cur, "\"wo\":%u", o->timeline.id);
+
+       return 1;
+}
+
+static void
+check_weston_surface_description(struct timeline_emit_context *ctx,
+                                struct weston_surface *s)
+{
+       struct weston_surface *mains;
+       char d[512];
+       char mainstr[32];
+
+       if (!check_series(ctx, &s->timeline))
+               return;
+
+       mains = weston_surface_get_main_surface(s);
+       if (mains != s) {
+               check_weston_surface_description(ctx, mains);
+               if (snprintf(mainstr, sizeof(mainstr),
+                            ", \"main_surface\":%u", mains->timeline.id) < 0)
+                       mainstr[0] = '\0';
+       } else {
+               mainstr[0] = '\0';
+       }
+
+       if (!s->get_label || s->get_label(s, d, sizeof(d)) < 0)
+               d[0] = '\0';
+
+       fprintf(ctx->out, "{ \"id\":%u, "
+               "\"type\":\"weston_surface\", \"desc\":", s->timeline.id);
+       fprint_quoted_string(ctx->out, d[0] ? d : NULL);
+       fprintf(ctx->out, "%s }\n", mainstr);
+}
+
+static int
+emit_weston_surface(struct timeline_emit_context *ctx, void *obj)
+{
+       struct weston_surface *s = obj;
+
+       check_weston_surface_description(ctx, s);
+       fprintf(ctx->cur, "\"ws\":%u", s->timeline.id);
+
+       return 1;
+}
+
+static int
+emit_vblank_timestamp(struct timeline_emit_context *ctx, void *obj)
+{
+       struct timespec *ts = obj;
+
+       fprintf(ctx->cur, "\"vblank\":[%" PRId64 ", %ld]",
+               (int64_t)ts->tv_sec, ts->tv_nsec);
+
+       return 1;
+}
+
+typedef int (*type_func)(struct timeline_emit_context *ctx, void *obj);
+
+static const type_func type_dispatch[] = {
+       [TLT_OUTPUT] = emit_weston_output,
+       [TLT_SURFACE] = emit_weston_surface,
+       [TLT_VBLANK] = emit_vblank_timestamp,
+};
+
+WL_EXPORT void
+weston_timeline_point(const char *name, ...)
+{
+       va_list argp;
+       struct timespec ts;
+       enum timeline_type otype;
+       void *obj;
+       char buf[512];
+       struct timeline_emit_context ctx;
+
+       clock_gettime(timeline_.clk_id, &ts);
+
+       ctx.out = timeline_.file;
+       ctx.cur = fmemopen(buf, sizeof(buf), "w");
+       ctx.series = timeline_.series;
+
+       if (!ctx.cur) {
+               weston_log("Timeline error in fmemopen, closing.\n");
+               weston_timeline_close();
+               return;
+       }
+
+       fprintf(ctx.cur, "{ \"T\":[%" PRId64 ", %ld], \"N\":\"%s\"",
+               (int64_t)ts.tv_sec, ts.tv_nsec, name);
+
+       va_start(argp, name);
+       while (1) {
+               otype = va_arg(argp, enum timeline_type);
+               if (otype == TLT_END)
+                       break;
+
+               obj = va_arg(argp, void *);
+               if (type_dispatch[otype]) {
+                       fprintf(ctx.cur, ", ");
+                       type_dispatch[otype](&ctx, obj);
+               }
+       }
+       va_end(argp);
+
+       fprintf(ctx.cur, " }\n");
+       fflush(ctx.cur);
+       if (ferror(ctx.cur)) {
+               weston_log("Timeline error in constructing entry, closing.\n");
+               weston_timeline_close();
+       } else {
+               fprintf(ctx.out, "%s", buf);
+       }
+
+       fclose(ctx.cur);
+}
diff --git a/libweston/timeline.h b/libweston/timeline.h
new file mode 100644 (file)
index 0000000..b10a815
--- /dev/null
@@ -0,0 +1,65 @@
+/*
+ * Copyright © 2014 Pekka Paalanen <pq@iki.fi>
+ * Copyright © 2014 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_TIMELINE_H
+#define WESTON_TIMELINE_H
+
+extern int weston_timeline_enabled_;
+
+struct weston_compositor;
+
+void
+weston_timeline_open(struct weston_compositor *compositor);
+
+void
+weston_timeline_close(void);
+
+enum timeline_type {
+       TLT_END = 0,
+       TLT_OUTPUT,
+       TLT_SURFACE,
+       TLT_VBLANK,
+};
+
+#define TYPEVERIFY(type, arg) ({                       \
+       typeof(arg) tmp___ = (arg);             \
+       (void)((type)0 == tmp___);              \
+       tmp___; })
+
+#define TLP_END TLT_END, NULL
+#define TLP_OUTPUT(o) TLT_OUTPUT, TYPEVERIFY(struct weston_output *, (o))
+#define TLP_SURFACE(s) TLT_SURFACE, TYPEVERIFY(struct weston_surface *, (s))
+#define TLP_VBLANK(t) TLT_VBLANK, TYPEVERIFY(const struct timespec *, (t))
+
+#define TL_POINT(...) do { \
+       if (weston_timeline_enabled_) \
+               weston_timeline_point(__VA_ARGS__); \
+} while (0)
+
+void
+weston_timeline_point(const char *name, ...);
+
+#endif /* WESTON_TIMELINE_H */
diff --git a/libweston/vaapi-recorder.c b/libweston/vaapi-recorder.c
new file mode 100644 (file)
index 0000000..1228f7d
--- /dev/null
@@ -0,0 +1,1161 @@
+/*
+ * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <assert.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <pthread.h>
+
+#include <va/va.h>
+#include <va/va_drm.h>
+#include <va/va_drmcommon.h>
+#include <va/va_enc_h264.h>
+#include <va/va_vpp.h>
+
+#include "compositor.h"
+#include "vaapi-recorder.h"
+
+#define NAL_REF_IDC_NONE        0
+#define NAL_REF_IDC_LOW         1
+#define NAL_REF_IDC_MEDIUM      2
+#define NAL_REF_IDC_HIGH        3
+
+#define NAL_NON_IDR             1
+#define NAL_IDR                 5
+#define NAL_SPS                 7
+#define NAL_PPS                 8
+#define NAL_SEI                 6
+
+#define SLICE_TYPE_P            0
+#define SLICE_TYPE_B            1
+#define SLICE_TYPE_I            2
+
+#define ENTROPY_MODE_CAVLC      0
+#define ENTROPY_MODE_CABAC      1
+
+#define PROFILE_IDC_BASELINE    66
+#define PROFILE_IDC_MAIN        77
+#define PROFILE_IDC_HIGH        100
+
+struct vaapi_recorder {
+       int drm_fd, output_fd;
+       int width, height;
+       int frame_count;
+
+       int error;
+       int destroying;
+       pthread_t worker_thread;
+       pthread_mutex_t mutex;
+       pthread_cond_t input_cond;
+
+       struct {
+               int valid;
+               int prime_fd, stride;
+       } input;
+
+       VADisplay va_dpy;
+
+       /* video post processing is used for colorspace conversion */
+       struct {
+               VAConfigID cfg;
+               VAContextID ctx;
+               VABufferID pipeline_buf;
+               VASurfaceID output;
+       } vpp;
+
+       struct {
+               VAConfigID cfg;
+               VAContextID ctx;
+               VASurfaceID reference_picture[3];
+
+               int intra_period;
+               int output_size;
+               int constraint_set_flag;
+
+               struct {
+                       VAEncSequenceParameterBufferH264 seq;
+                       VAEncPictureParameterBufferH264 pic;
+                       VAEncSliceParameterBufferH264 slice;
+               } param;
+       } encoder;
+};
+
+static void *
+worker_thread_function(void *);
+
+/* bistream code used for writing the packed headers */
+
+#define BITSTREAM_ALLOCATE_STEPPING     4096
+
+struct bitstream {
+       unsigned int *buffer;
+       int bit_offset;
+       int max_size_in_dword;
+};
+
+static unsigned int
+va_swap32(unsigned int val)
+{
+       unsigned char *pval = (unsigned char *)&val;
+
+       return ((pval[0] << 24) |
+               (pval[1] << 16) |
+               (pval[2] << 8)  |
+               (pval[3] << 0));
+}
+
+static void
+bitstream_start(struct bitstream *bs)
+{
+       bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
+       bs->buffer = calloc(bs->max_size_in_dword * sizeof(unsigned int), 1);
+       bs->bit_offset = 0;
+}
+
+static void
+bitstream_end(struct bitstream *bs)
+{
+       int pos = (bs->bit_offset >> 5);
+       int bit_offset = (bs->bit_offset & 0x1f);
+       int bit_left = 32 - bit_offset;
+
+       if (bit_offset) {
+               bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
+       }
+}
+
+static void
+bitstream_put_ui(struct bitstream *bs, unsigned int val, int size_in_bits)
+{
+       int pos = (bs->bit_offset >> 5);
+       int bit_offset = (bs->bit_offset & 0x1f);
+       int bit_left = 32 - bit_offset;
+
+       if (!size_in_bits)
+               return;
+
+       bs->bit_offset += size_in_bits;
+
+       if (bit_left > size_in_bits) {
+               bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
+               return;
+       }
+
+       size_in_bits -= bit_left;
+       bs->buffer[pos] =
+               (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
+       bs->buffer[pos] = va_swap32(bs->buffer[pos]);
+
+       if (pos + 1 == bs->max_size_in_dword) {
+               bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
+               bs->buffer =
+                       realloc(bs->buffer,
+                               bs->max_size_in_dword * sizeof(unsigned int));
+       }
+
+       bs->buffer[pos + 1] = val;
+}
+
+static void
+bitstream_put_ue(struct bitstream *bs, unsigned int val)
+{
+       int size_in_bits = 0;
+       int tmp_val = ++val;
+
+       while (tmp_val) {
+               tmp_val >>= 1;
+               size_in_bits++;
+       }
+
+       bitstream_put_ui(bs, 0, size_in_bits - 1); /* leading zero */
+       bitstream_put_ui(bs, val, size_in_bits);
+}
+
+static void
+bitstream_put_se(struct bitstream *bs, int val)
+{
+       unsigned int new_val;
+
+       if (val <= 0)
+               new_val = -2 * val;
+       else
+               new_val = 2 * val - 1;
+
+       bitstream_put_ue(bs, new_val);
+}
+
+static void
+bitstream_byte_aligning(struct bitstream *bs, int bit)
+{
+       int bit_offset = (bs->bit_offset & 0x7);
+       int bit_left = 8 - bit_offset;
+       int new_val;
+
+       if (!bit_offset)
+               return;
+
+       if (bit)
+               new_val = (1 << bit_left) - 1;
+       else
+               new_val = 0;
+
+       bitstream_put_ui(bs, new_val, bit_left);
+}
+
+static VAStatus
+encoder_create_config(struct vaapi_recorder *r)
+{
+       VAConfigAttrib attrib[2];
+       VAStatus status;
+
+       /* FIXME: should check if VAEntrypointEncSlice is supported */
+
+       /* FIXME: should check if specified attributes are supported */
+
+       attrib[0].type = VAConfigAttribRTFormat;
+       attrib[0].value = VA_RT_FORMAT_YUV420;
+
+       attrib[1].type = VAConfigAttribRateControl;
+       attrib[1].value = VA_RC_CQP;
+
+       status = vaCreateConfig(r->va_dpy, VAProfileH264Main,
+                               VAEntrypointEncSlice, attrib, 2,
+                               &r->encoder.cfg);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       status = vaCreateContext(r->va_dpy, r->encoder.cfg,
+                                r->width, r->height, VA_PROGRESSIVE, 0, 0,
+                                &r->encoder.ctx);
+       if (status != VA_STATUS_SUCCESS) {
+               vaDestroyConfig(r->va_dpy, r->encoder.cfg);
+               return status;
+       }
+
+       return VA_STATUS_SUCCESS;
+}
+
+static void
+encoder_destroy_config(struct vaapi_recorder *r)
+{
+       vaDestroyContext(r->va_dpy, r->encoder.ctx);
+       vaDestroyConfig(r->va_dpy, r->encoder.cfg);
+}
+
+static void
+encoder_init_seq_parameters(struct vaapi_recorder *r)
+{
+       int width_in_mbs, height_in_mbs;
+       int frame_cropping_flag = 0;
+       int frame_crop_bottom_offset = 0;
+
+       width_in_mbs = (r->width + 15) / 16;
+       height_in_mbs = (r->height + 15) / 16;
+
+       r->encoder.param.seq.level_idc = 41;
+       r->encoder.param.seq.intra_period = r->encoder.intra_period;
+       r->encoder.param.seq.max_num_ref_frames = 4;
+       r->encoder.param.seq.picture_width_in_mbs = width_in_mbs;
+       r->encoder.param.seq.picture_height_in_mbs = height_in_mbs;
+       r->encoder.param.seq.seq_fields.bits.frame_mbs_only_flag = 1;
+
+       /* Tc = num_units_in_tick / time_scale */
+       r->encoder.param.seq.time_scale = 1800;
+       r->encoder.param.seq.num_units_in_tick = 15;
+
+       if (height_in_mbs * 16 - r->height > 0) {
+               frame_cropping_flag = 1;
+               frame_crop_bottom_offset = (height_in_mbs * 16 - r->height) / 2;
+       }
+
+       r->encoder.param.seq.frame_cropping_flag = frame_cropping_flag;
+       r->encoder.param.seq.frame_crop_bottom_offset = frame_crop_bottom_offset;
+
+       r->encoder.param.seq.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
+}
+
+static VABufferID
+encoder_update_seq_parameters(struct vaapi_recorder *r)
+{
+       VABufferID seq_buf;
+       VAStatus status;
+
+       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
+                               VAEncSequenceParameterBufferType,
+                               sizeof(r->encoder.param.seq),
+                               1, &r->encoder.param.seq,
+                               &seq_buf);
+
+       if (status == VA_STATUS_SUCCESS)
+               return seq_buf;
+       else
+               return VA_INVALID_ID;
+}
+
+static void
+encoder_init_pic_parameters(struct vaapi_recorder *r)
+{
+       VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
+
+       pic->pic_init_qp = 0;
+
+       /* ENTROPY_MODE_CABAC */
+       pic->pic_fields.bits.entropy_coding_mode_flag = 1;
+
+       pic->pic_fields.bits.deblocking_filter_control_present_flag = 1;
+}
+
+static VABufferID
+encoder_update_pic_parameters(struct vaapi_recorder *r,
+                             VABufferID output_buf)
+{
+       VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
+       VAStatus status;
+       VABufferID pic_param_buf;
+       VASurfaceID curr_pic, pic0;
+
+       curr_pic = r->encoder.reference_picture[r->frame_count % 2];
+       pic0 = r->encoder.reference_picture[(r->frame_count + 1) % 2];
+
+       pic->CurrPic.picture_id = curr_pic;
+       pic->CurrPic.TopFieldOrderCnt = r->frame_count * 2;
+       pic->ReferenceFrames[0].picture_id = pic0;
+       pic->ReferenceFrames[1].picture_id = r->encoder.reference_picture[2];
+       pic->ReferenceFrames[2].picture_id = VA_INVALID_ID;
+
+       pic->coded_buf = output_buf;
+       pic->frame_num = r->frame_count;
+
+       pic->pic_fields.bits.idr_pic_flag = (r->frame_count == 0);
+       pic->pic_fields.bits.reference_pic_flag = 1;
+
+       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
+                               VAEncPictureParameterBufferType,
+                               sizeof(VAEncPictureParameterBufferH264), 1,
+                               pic, &pic_param_buf);
+
+       if (status == VA_STATUS_SUCCESS)
+               return pic_param_buf;
+       else
+               return VA_INVALID_ID;
+}
+
+static VABufferID
+encoder_update_slice_parameter(struct vaapi_recorder *r, int slice_type)
+{
+       VABufferID slice_param_buf;
+       VAStatus status;
+
+       int width_in_mbs = (r->width + 15) / 16;
+       int height_in_mbs = (r->height + 15) / 16;
+
+       memset(&r->encoder.param.slice, 0, sizeof r->encoder.param.slice);
+
+       r->encoder.param.slice.num_macroblocks = width_in_mbs * height_in_mbs;
+       r->encoder.param.slice.slice_type = slice_type;
+
+       r->encoder.param.slice.slice_alpha_c0_offset_div2 = 2;
+       r->encoder.param.slice.slice_beta_offset_div2 = 2;
+
+       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
+                               VAEncSliceParameterBufferType,
+                               sizeof(r->encoder.param.slice), 1,
+                               &r->encoder.param.slice,
+                               &slice_param_buf);
+
+       if (status == VA_STATUS_SUCCESS)
+               return slice_param_buf;
+       else
+               return VA_INVALID_ID;
+}
+
+static VABufferID
+encoder_update_misc_hdr_parameter(struct vaapi_recorder *r)
+{
+       VAEncMiscParameterBuffer *misc_param;
+       VAEncMiscParameterHRD *hrd;
+       VABufferID buffer;
+       VAStatus status;
+
+       int total_size =
+               sizeof(VAEncMiscParameterBuffer) +
+               sizeof(VAEncMiscParameterRateControl);
+
+       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
+                               VAEncMiscParameterBufferType, total_size,
+                               1, NULL, &buffer);
+       if (status != VA_STATUS_SUCCESS)
+               return VA_INVALID_ID;
+
+       status = vaMapBuffer(r->va_dpy, buffer, (void **) &misc_param);
+       if (status != VA_STATUS_SUCCESS) {
+               vaDestroyBuffer(r->va_dpy, buffer);
+               return VA_INVALID_ID;
+       }
+
+       misc_param->type = VAEncMiscParameterTypeHRD;
+       hrd = (VAEncMiscParameterHRD *) misc_param->data;
+
+       hrd->initial_buffer_fullness = 0;
+       hrd->buffer_size = 0;
+
+       vaUnmapBuffer(r->va_dpy, buffer);
+
+       return buffer;
+}
+
+static int
+setup_encoder(struct vaapi_recorder *r)
+{
+       VAStatus status;
+
+       status = encoder_create_config(r);
+       if (status != VA_STATUS_SUCCESS) {
+               return -1;
+       }
+
+       status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
+                                 r->width, r->height,
+                                 r->encoder.reference_picture, 3,
+                                 NULL, 0);
+       if (status != VA_STATUS_SUCCESS) {
+               encoder_destroy_config(r);
+               return -1;
+       }
+
+       /* VAProfileH264Main */
+       r->encoder.constraint_set_flag |= (1 << 1); /* Annex A.2.2 */
+
+       r->encoder.output_size = r->width * r->height;
+
+       r->encoder.intra_period = 30;
+
+       encoder_init_seq_parameters(r);
+       encoder_init_pic_parameters(r);
+
+       return 0;
+}
+
+static void
+encoder_destroy(struct vaapi_recorder *r)
+{
+       vaDestroySurfaces(r->va_dpy, r->encoder.reference_picture, 3);
+
+       encoder_destroy_config(r);
+}
+
+static void
+nal_start_code_prefix(struct bitstream *bs)
+{
+       bitstream_put_ui(bs, 0x00000001, 32);
+}
+
+static void
+nal_header(struct bitstream *bs, int nal_ref_idc, int nal_unit_type)
+{
+       /* forbidden_zero_bit: 0 */
+       bitstream_put_ui(bs, 0, 1);
+
+       bitstream_put_ui(bs, nal_ref_idc, 2);
+       bitstream_put_ui(bs, nal_unit_type, 5);
+}
+
+static void
+rbsp_trailing_bits(struct bitstream *bs)
+{
+       bitstream_put_ui(bs, 1, 1);
+       bitstream_byte_aligning(bs, 0);
+}
+
+static void sps_rbsp(struct bitstream *bs,
+                    VAEncSequenceParameterBufferH264 *seq,
+                    int constraint_set_flag)
+{
+       int i;
+
+       bitstream_put_ui(bs, PROFILE_IDC_MAIN, 8);
+
+       /* constraint_set[0-3] flag */
+       for (i = 0; i < 4; i++) {
+               int set = (constraint_set_flag & (1 << i)) ? 1 : 0;
+               bitstream_put_ui(bs, set, 1);
+       }
+
+       /* reserved_zero_4bits */
+       bitstream_put_ui(bs, 0, 4);
+       bitstream_put_ui(bs, seq->level_idc, 8);
+       bitstream_put_ue(bs, seq->seq_parameter_set_id);
+
+       bitstream_put_ue(bs, seq->seq_fields.bits.log2_max_frame_num_minus4);
+       bitstream_put_ue(bs, seq->seq_fields.bits.pic_order_cnt_type);
+       bitstream_put_ue(bs,
+                        seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);
+
+       bitstream_put_ue(bs, seq->max_num_ref_frames);
+
+       /* gaps_in_frame_num_value_allowed_flag */
+       bitstream_put_ui(bs, 0, 1);
+
+       /* pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 */
+       bitstream_put_ue(bs, seq->picture_width_in_mbs - 1);
+       bitstream_put_ue(bs, seq->picture_height_in_mbs - 1);
+
+       bitstream_put_ui(bs, seq->seq_fields.bits.frame_mbs_only_flag, 1);
+       bitstream_put_ui(bs, seq->seq_fields.bits.direct_8x8_inference_flag, 1);
+
+       bitstream_put_ui(bs, seq->frame_cropping_flag, 1);
+
+       if (seq->frame_cropping_flag) {
+               bitstream_put_ue(bs, seq->frame_crop_left_offset);
+               bitstream_put_ue(bs, seq->frame_crop_right_offset);
+               bitstream_put_ue(bs, seq->frame_crop_top_offset);
+               bitstream_put_ue(bs, seq->frame_crop_bottom_offset);
+       }
+
+       /* vui_parameters_present_flag */
+       bitstream_put_ui(bs, 1, 1);
+
+       /* aspect_ratio_info_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+       /* overscan_info_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+
+       /* video_signal_type_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+       /* chroma_loc_info_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+
+       /* timing_info_present_flag */
+       bitstream_put_ui(bs, 1, 1);
+       bitstream_put_ui(bs, seq->num_units_in_tick, 32);
+       bitstream_put_ui(bs, seq->time_scale, 32);
+       /* fixed_frame_rate_flag */
+       bitstream_put_ui(bs, 1, 1);
+
+       /* nal_hrd_parameters_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+
+       /* vcl_hrd_parameters_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+
+       /* low_delay_hrd_flag */
+       bitstream_put_ui(bs, 0, 1);
+
+       /* pic_struct_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+       /* bitstream_restriction_flag */
+       bitstream_put_ui(bs, 0, 1);
+
+       rbsp_trailing_bits(bs);
+}
+
+static void pps_rbsp(struct bitstream *bs,
+                    VAEncPictureParameterBufferH264 *pic)
+{
+       /* pic_parameter_set_id, seq_parameter_set_id */
+       bitstream_put_ue(bs, pic->pic_parameter_set_id);
+       bitstream_put_ue(bs, pic->seq_parameter_set_id);
+
+       bitstream_put_ui(bs, pic->pic_fields.bits.entropy_coding_mode_flag, 1);
+
+       /* pic_order_present_flag: 0 */
+       bitstream_put_ui(bs, 0, 1);
+
+       /* num_slice_groups_minus1 */
+       bitstream_put_ue(bs, 0);
+
+       bitstream_put_ue(bs, pic->num_ref_idx_l0_active_minus1);
+       bitstream_put_ue(bs, pic->num_ref_idx_l1_active_minus1);
+
+       bitstream_put_ui(bs, pic->pic_fields.bits.weighted_pred_flag, 1);
+       bitstream_put_ui(bs, pic->pic_fields.bits.weighted_bipred_idc, 2);
+
+       /* pic_init_qp_minus26, pic_init_qs_minus26, chroma_qp_index_offset */
+       bitstream_put_se(bs, pic->pic_init_qp - 26);
+       bitstream_put_se(bs, 0);
+       bitstream_put_se(bs, 0);
+
+       bitstream_put_ui(bs, pic->pic_fields.bits.deblocking_filter_control_present_flag, 1);
+
+       /* constrained_intra_pred_flag, redundant_pic_cnt_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+       bitstream_put_ui(bs, 0, 1);
+
+       bitstream_put_ui(bs, pic->pic_fields.bits.transform_8x8_mode_flag, 1);
+
+       /* pic_scaling_matrix_present_flag */
+       bitstream_put_ui(bs, 0, 1);
+       bitstream_put_se(bs, pic->second_chroma_qp_index_offset );
+
+       rbsp_trailing_bits(bs);
+}
+
+static int
+build_packed_pic_buffer(struct vaapi_recorder *r,
+                       void **header_buffer)
+{
+       struct bitstream bs;
+
+       bitstream_start(&bs);
+       nal_start_code_prefix(&bs);
+       nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
+       pps_rbsp(&bs, &r->encoder.param.pic);
+       bitstream_end(&bs);
+
+       *header_buffer = bs.buffer;
+       return bs.bit_offset;
+}
+
+static int
+build_packed_seq_buffer(struct vaapi_recorder *r,
+                       void **header_buffer)
+{
+       struct bitstream bs;
+
+       bitstream_start(&bs);
+       nal_start_code_prefix(&bs);
+       nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
+       sps_rbsp(&bs, &r->encoder.param.seq, r->encoder.constraint_set_flag);
+       bitstream_end(&bs);
+
+       *header_buffer = bs.buffer;
+       return bs.bit_offset;
+}
+
+static int
+create_packed_header_buffers(struct vaapi_recorder *r, VABufferID *buffers,
+                            VAEncPackedHeaderType type,
+                            void *data, int bit_length)
+{
+       VAEncPackedHeaderParameterBuffer packed_header;
+       VAStatus status;
+
+       packed_header.type = type;
+       packed_header.bit_length = bit_length;
+       packed_header.has_emulation_bytes = 0;
+
+       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
+                               VAEncPackedHeaderParameterBufferType,
+                               sizeof packed_header, 1, &packed_header,
+                               &buffers[0]);
+       if (status != VA_STATUS_SUCCESS)
+               return 0;
+
+       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
+                               VAEncPackedHeaderDataBufferType,
+                               (bit_length + 7) / 8, 1, data, &buffers[1]);
+       if (status != VA_STATUS_SUCCESS) {
+               vaDestroyBuffer(r->va_dpy, buffers[0]);
+               return 0;
+       }
+
+       return 2;
+}
+
+static int
+encoder_prepare_headers(struct vaapi_recorder *r, VABufferID *buffers)
+{
+       VABufferID *p;
+
+       int bit_length;
+       void *data;
+
+       p = buffers;
+
+       bit_length = build_packed_seq_buffer(r, &data);
+       p += create_packed_header_buffers(r, p, VAEncPackedHeaderSequence,
+                                         data, bit_length);
+       free(data);
+
+       bit_length = build_packed_pic_buffer(r, &data);
+       p += create_packed_header_buffers(r, p, VAEncPackedHeaderPicture,
+                                         data, bit_length);
+       free(data);
+
+       return p - buffers;
+}
+
+static VAStatus
+encoder_render_picture(struct vaapi_recorder *r, VASurfaceID input,
+                      VABufferID *buffers, int count)
+{
+       VAStatus status;
+
+       status = vaBeginPicture(r->va_dpy, r->encoder.ctx, input);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       status = vaRenderPicture(r->va_dpy, r->encoder.ctx, buffers, count);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       status = vaEndPicture(r->va_dpy, r->encoder.ctx);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       return vaSyncSurface(r->va_dpy, input);
+}
+
+static VABufferID
+encoder_create_output_buffer(struct vaapi_recorder *r)
+{
+       VABufferID output_buf;
+       VAStatus status;
+
+       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
+                               VAEncCodedBufferType, r->encoder.output_size,
+                               1, NULL, &output_buf);
+       if (status == VA_STATUS_SUCCESS)
+               return output_buf;
+       else
+               return VA_INVALID_ID;
+}
+
+enum output_write_status {
+       OUTPUT_WRITE_SUCCESS,
+       OUTPUT_WRITE_OVERFLOW,
+       OUTPUT_WRITE_FATAL
+};
+
+static enum output_write_status
+encoder_write_output(struct vaapi_recorder *r, VABufferID output_buf)
+{
+       VACodedBufferSegment *segment;
+       VAStatus status;
+       int count;
+
+       status = vaMapBuffer(r->va_dpy, output_buf, (void **) &segment);
+       if (status != VA_STATUS_SUCCESS)
+               return OUTPUT_WRITE_FATAL;
+
+       if (segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
+               r->encoder.output_size *= 2;
+               vaUnmapBuffer(r->va_dpy, output_buf);
+               return OUTPUT_WRITE_OVERFLOW;
+       }
+
+       count = write(r->output_fd, segment->buf, segment->size);
+
+       vaUnmapBuffer(r->va_dpy, output_buf);
+
+       if (count < 0)
+               return OUTPUT_WRITE_FATAL;
+
+       return OUTPUT_WRITE_SUCCESS;
+}
+
+static void
+encoder_encode(struct vaapi_recorder *r, VASurfaceID input)
+{
+       VABufferID output_buf = VA_INVALID_ID;
+
+       VABufferID buffers[8];
+       int count = 0;
+       int i, slice_type;
+       enum output_write_status ret;
+
+       if ((r->frame_count % r->encoder.intra_period) == 0)
+               slice_type = SLICE_TYPE_I;
+       else
+               slice_type = SLICE_TYPE_P;
+
+       buffers[count++] = encoder_update_seq_parameters(r);
+       buffers[count++] = encoder_update_misc_hdr_parameter(r);
+       buffers[count++] = encoder_update_slice_parameter(r, slice_type);
+
+       for (i = 0; i < count; i++)
+               if (buffers[i] == VA_INVALID_ID)
+                       goto bail;
+
+       if (r->frame_count == 0)
+               count += encoder_prepare_headers(r, buffers + count);
+
+       do {
+               output_buf = encoder_create_output_buffer(r);
+               if (output_buf == VA_INVALID_ID)
+                       goto bail;
+
+               buffers[count++] =
+                       encoder_update_pic_parameters(r, output_buf);
+               if (buffers[count - 1] == VA_INVALID_ID)
+                       goto bail;
+
+               encoder_render_picture(r, input, buffers, count);
+               ret = encoder_write_output(r, output_buf);
+
+               vaDestroyBuffer(r->va_dpy, output_buf);
+               output_buf = VA_INVALID_ID;
+
+               vaDestroyBuffer(r->va_dpy, buffers[--count]);
+       } while (ret == OUTPUT_WRITE_OVERFLOW);
+
+       if (ret == OUTPUT_WRITE_FATAL)
+               r->error = errno;
+
+       for (i = 0; i < count; i++)
+               vaDestroyBuffer(r->va_dpy, buffers[i]);
+
+       r->frame_count++;
+       return;
+
+bail:
+       for (i = 0; i < count; i++)
+               vaDestroyBuffer(r->va_dpy, buffers[i]);
+       if (output_buf != VA_INVALID_ID)
+               vaDestroyBuffer(r->va_dpy, output_buf);
+}
+
+
+static int
+setup_vpp(struct vaapi_recorder *r)
+{
+       VAStatus status;
+
+       status = vaCreateConfig(r->va_dpy, VAProfileNone,
+                               VAEntrypointVideoProc, NULL, 0,
+                               &r->vpp.cfg);
+       if (status != VA_STATUS_SUCCESS) {
+               weston_log("vaapi: failed to create VPP config\n");
+               return -1;
+       }
+
+       status = vaCreateContext(r->va_dpy, r->vpp.cfg, r->width, r->height,
+                                0, NULL, 0, &r->vpp.ctx);
+       if (status != VA_STATUS_SUCCESS) {
+               weston_log("vaapi: failed to create VPP context\n");
+               goto err_cfg;
+       }
+
+       status = vaCreateBuffer(r->va_dpy, r->vpp.ctx,
+                               VAProcPipelineParameterBufferType,
+                               sizeof(VAProcPipelineParameterBuffer),
+                               1, NULL, &r->vpp.pipeline_buf);
+       if (status != VA_STATUS_SUCCESS) {
+               weston_log("vaapi: failed to create VPP pipeline buffer\n");
+               goto err_ctx;
+       }
+
+       status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
+                                 r->width, r->height, &r->vpp.output, 1,
+                                 NULL, 0);
+       if (status != VA_STATUS_SUCCESS) {
+               weston_log("vaapi: failed to create YUV surface\n");
+               goto err_buf;
+       }
+
+       return 0;
+
+err_buf:
+       vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
+err_ctx:
+       vaDestroyConfig(r->va_dpy, r->vpp.ctx);
+err_cfg:
+       vaDestroyConfig(r->va_dpy, r->vpp.cfg);
+
+       return -1;
+}
+
+static void
+vpp_destroy(struct vaapi_recorder *r)
+{
+       vaDestroySurfaces(r->va_dpy, &r->vpp.output, 1);
+       vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
+       vaDestroyConfig(r->va_dpy, r->vpp.ctx);
+       vaDestroyConfig(r->va_dpy, r->vpp.cfg);
+}
+
+static int
+setup_worker_thread(struct vaapi_recorder *r)
+{
+       pthread_mutex_init(&r->mutex, NULL);
+       pthread_cond_init(&r->input_cond, NULL);
+       pthread_create(&r->worker_thread, NULL, worker_thread_function, r);
+
+       return 1;
+}
+
+static void
+destroy_worker_thread(struct vaapi_recorder *r)
+{
+       pthread_mutex_lock(&r->mutex);
+
+       /* Make sure the worker thread finishes */
+       r->destroying = 1;
+       pthread_cond_signal(&r->input_cond);
+
+       pthread_mutex_unlock(&r->mutex);
+
+       pthread_join(r->worker_thread, NULL);
+
+       pthread_mutex_destroy(&r->mutex);
+       pthread_cond_destroy(&r->input_cond);
+}
+
+struct vaapi_recorder *
+vaapi_recorder_create(int drm_fd, int width, int height, const char *filename)
+{
+       struct vaapi_recorder *r;
+       VAStatus status;
+       int major, minor;
+       int flags;
+
+       r = zalloc(sizeof *r);
+       if (r == NULL)
+               return NULL;
+
+       r->width = width;
+       r->height = height;
+       r->drm_fd = drm_fd;
+
+       if (setup_worker_thread(r) < 0)
+               goto err_free;
+
+       flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
+       r->output_fd = open(filename, flags, 0644);
+       if (r->output_fd < 0)
+               goto err_thread;
+
+       r->va_dpy = vaGetDisplayDRM(drm_fd);
+       if (!r->va_dpy) {
+               weston_log("failed to create VA display\n");
+               goto err_fd;
+       }
+
+       status = vaInitialize(r->va_dpy, &major, &minor);
+       if (status != VA_STATUS_SUCCESS) {
+               weston_log("vaapi: failed to initialize display\n");
+               goto err_fd;
+       }
+
+       if (setup_vpp(r) < 0) {
+               weston_log("vaapi: failed to initialize VPP pipeline\n");
+               goto err_va_dpy;
+       }
+
+       if (setup_encoder(r) < 0) {
+               goto err_vpp;
+       }
+
+       return r;
+
+err_vpp:
+       vpp_destroy(r);
+err_va_dpy:
+       vaTerminate(r->va_dpy);
+err_fd:
+       close(r->output_fd);
+err_thread:
+       destroy_worker_thread(r);
+err_free:
+       free(r);
+
+       return NULL;
+}
+
+void
+vaapi_recorder_destroy(struct vaapi_recorder *r)
+{
+       destroy_worker_thread(r);
+
+       encoder_destroy(r);
+       vpp_destroy(r);
+
+       vaTerminate(r->va_dpy);
+
+       close(r->output_fd);
+       close(r->drm_fd);
+
+       free(r);
+}
+
+static VAStatus
+create_surface_from_fd(struct vaapi_recorder *r, int prime_fd,
+                      int stride, VASurfaceID *surface)
+{
+       VASurfaceAttrib va_attribs[2];
+       VASurfaceAttribExternalBuffers va_attrib_extbuf;
+       VAStatus status;
+
+       unsigned long buffer_fd = prime_fd;
+
+       va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX;
+       va_attrib_extbuf.width = r->width;
+       va_attrib_extbuf.height = r->height;
+       va_attrib_extbuf.data_size = r->height * stride;
+       va_attrib_extbuf.num_planes = 1;
+       va_attrib_extbuf.pitches[0] = stride;
+       va_attrib_extbuf.offsets[0] = 0;
+       va_attrib_extbuf.buffers = &buffer_fd;
+       va_attrib_extbuf.num_buffers = 1;
+       va_attrib_extbuf.flags = 0;
+       va_attrib_extbuf.private_data = NULL;
+
+       va_attribs[0].type = VASurfaceAttribMemoryType;
+       va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
+       va_attribs[0].value.type = VAGenericValueTypeInteger;
+       va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
+
+       va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
+       va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
+       va_attribs[1].value.type = VAGenericValueTypePointer;
+       va_attribs[1].value.value.p = &va_attrib_extbuf;
+
+       status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_RGB32,
+                                 r->width, r->height, surface, 1,
+                                 va_attribs, 2);
+
+       return status;
+}
+
+static VAStatus
+convert_rgb_to_yuv(struct vaapi_recorder *r, VASurfaceID rgb_surface)
+{
+       VAProcPipelineParameterBuffer *pipeline_param;
+       VAStatus status;
+
+       status = vaMapBuffer(r->va_dpy, r->vpp.pipeline_buf,
+                            (void **) &pipeline_param);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       memset(pipeline_param, 0, sizeof *pipeline_param);
+
+       pipeline_param->surface = rgb_surface;
+       pipeline_param->surface_color_standard  = VAProcColorStandardNone;
+
+       pipeline_param->output_background_color = 0xff000000;
+       pipeline_param->output_color_standard   = VAProcColorStandardNone;
+
+       status = vaUnmapBuffer(r->va_dpy, r->vpp.pipeline_buf);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       status = vaBeginPicture(r->va_dpy, r->vpp.ctx, r->vpp.output);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       status = vaRenderPicture(r->va_dpy, r->vpp.ctx,
+                                &r->vpp.pipeline_buf, 1);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       status = vaEndPicture(r->va_dpy, r->vpp.ctx);
+       if (status != VA_STATUS_SUCCESS)
+               return status;
+
+       return status;
+}
+
+static void
+recorder_frame(struct vaapi_recorder *r)
+{
+       VASurfaceID rgb_surface;
+       VAStatus status;
+
+       status = create_surface_from_fd(r, r->input.prime_fd,
+                                       r->input.stride, &rgb_surface);
+       if (status != VA_STATUS_SUCCESS) {
+               weston_log("[libva recorder] "
+                          "failed to create surface from bo\n");
+               return;
+       }
+
+       close(r->input.prime_fd);
+
+       status = convert_rgb_to_yuv(r, rgb_surface);
+       if (status != VA_STATUS_SUCCESS) {
+               weston_log("[libva recorder] "
+                          "color space conversion failed\n");
+               return;
+       }
+
+       encoder_encode(r, r->vpp.output);
+
+       vaDestroySurfaces(r->va_dpy, &rgb_surface, 1);
+}
+
+static void *
+worker_thread_function(void *data)
+{
+       struct vaapi_recorder *r = data;
+
+       pthread_mutex_lock(&r->mutex);
+
+       while (!r->destroying) {
+               if (!r->input.valid)
+                       pthread_cond_wait(&r->input_cond, &r->mutex);
+
+               /* If the thread is awaken by destroy_worker_thread(),
+                * there might not be valid input */
+               if (!r->input.valid)
+                       continue;
+
+               recorder_frame(r);
+               r->input.valid = 0;
+       }
+
+       pthread_mutex_unlock(&r->mutex);
+
+       return NULL;
+}
+
+int
+vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd, int stride)
+{
+       int ret = 0;
+
+       pthread_mutex_lock(&r->mutex);
+
+       if (r->error) {
+               errno = r->error;
+               ret = -1;
+               goto unlock;
+       }
+
+       /* The mutex is never released while encoding, so this point should
+        * never be reached if input.valid is true. */
+       assert(!r->input.valid);
+
+       r->input.prime_fd = prime_fd;
+       r->input.stride = stride;
+       r->input.valid = 1;
+       pthread_cond_signal(&r->input_cond);
+
+unlock:
+       pthread_mutex_unlock(&r->mutex);
+
+       return ret;
+}
diff --git a/libweston/vaapi-recorder.h b/libweston/vaapi-recorder.h
new file mode 100644 (file)
index 0000000..6b194aa
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _VAAPI_RECORDER_H_
+#define _VAAPI_RECORDER_H_
+
+struct vaapi_recorder;
+
+struct vaapi_recorder *
+vaapi_recorder_create(int drm_fd, int width, int height, const char *filename);
+void
+vaapi_recorder_destroy(struct vaapi_recorder *r);
+int
+vaapi_recorder_frame(struct vaapi_recorder *r, int fd, int stride);
+
+#endif /* _VAAPI_RECORDER_H_ */
diff --git a/libweston/version.h.in b/libweston/version.h.in
new file mode 100644 (file)
index 0000000..b2379d0
--- /dev/null
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WESTON_VERSION_H
+#define WESTON_VERSION_H
+
+#define WESTON_VERSION_MAJOR @WESTON_VERSION_MAJOR@
+#define WESTON_VERSION_MINOR @WESTON_VERSION_MINOR@
+#define WESTON_VERSION_MICRO @WESTON_VERSION_MICRO@
+#define WESTON_VERSION "@WESTON_VERSION@"
+
+/* This macro may not do what you expect.  Weston doesn't guarantee
+ * a stable API between 1.X and 1.Y, and thus this macro will return
+ * FALSE on any WESTON_VERSION_AT_LEAST(1,X,0) if the actual version
+ * is 1.Y.0 and X != Y).  In particular, it fails if X < Y, that is,
+ * 1.3.0 is considered to not be "at least" 1.4.0.
+ *
+ * If you want to test for the version number being 1.3.0 or above or
+ * maybe in a range (eg 1.2.0 to 1.4.0), just use the WESTON_VERSION_*
+ * defines above directly.
+ */
+
+#define WESTON_VERSION_AT_LEAST(major, minor, micro) \
+        (WESTON_VERSION_MAJOR == (major) && \
+         WESTON_VERSION_MINOR == (minor) && \
+         WESTON_VERSION_MICRO >= (micro))
+
+#endif
diff --git a/libweston/vertex-clipping.c b/libweston/vertex-clipping.c
new file mode 100644 (file)
index 0000000..a71e733
--- /dev/null
@@ -0,0 +1,330 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include <assert.h>
+#include <float.h>
+#include <math.h>
+
+#include "vertex-clipping.h"
+
+float
+float_difference(float a, float b)
+{
+       /* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
+       static const float max_diff = 4.0f * FLT_MIN;
+       static const float max_rel_diff = 4.0e-5;
+       float diff = a - b;
+       float adiff = fabsf(diff);
+
+       if (adiff <= max_diff)
+               return 0.0f;
+
+       a = fabsf(a);
+       b = fabsf(b);
+       if (adiff <= (a > b ? a : b) * max_rel_diff)
+               return 0.0f;
+
+       return diff;
+}
+
+/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line x = x_arg.
+ * Compute the y coordinate of the intersection.
+ */
+static float
+clip_intersect_y(float p1x, float p1y, float p2x, float p2y,
+                float x_arg)
+{
+       float a;
+       float diff = float_difference(p1x, p2x);
+
+       /* Practically vertical line segment, yet the end points have already
+        * been determined to be on different sides of the line. Therefore
+        * the line segment is part of the line and intersects everywhere.
+        * Return the end point, so we use the whole line segment.
+        */
+       if (diff == 0.0f)
+               return p2y;
+
+       a = (x_arg - p2x) / diff;
+       return p2y + (p1y - p2y) * a;
+}
+
+/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line y = y_arg.
+ * Compute the x coordinate of the intersection.
+ */
+static float
+clip_intersect_x(float p1x, float p1y, float p2x, float p2y,
+                float y_arg)
+{
+       float a;
+       float diff = float_difference(p1y, p2y);
+
+       /* Practically horizontal line segment, yet the end points have already
+        * been determined to be on different sides of the line. Therefore
+        * the line segment is part of the line and intersects everywhere.
+        * Return the end point, so we use the whole line segment.
+        */
+       if (diff == 0.0f)
+               return p2x;
+
+       a = (y_arg - p2y) / diff;
+       return p2x + (p1x - p2x) * a;
+}
+
+enum path_transition {
+       PATH_TRANSITION_OUT_TO_OUT = 0,
+       PATH_TRANSITION_OUT_TO_IN = 1,
+       PATH_TRANSITION_IN_TO_OUT = 2,
+       PATH_TRANSITION_IN_TO_IN = 3,
+};
+
+static void
+clip_append_vertex(struct clip_context *ctx, float x, float y)
+{
+       *ctx->vertices.x++ = x;
+       *ctx->vertices.y++ = y;
+}
+
+static enum path_transition
+path_transition_left_edge(struct clip_context *ctx, float x, float y)
+{
+       return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
+}
+
+static enum path_transition
+path_transition_right_edge(struct clip_context *ctx, float x, float y)
+{
+       return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
+}
+
+static enum path_transition
+path_transition_top_edge(struct clip_context *ctx, float x, float y)
+{
+       return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
+}
+
+static enum path_transition
+path_transition_bottom_edge(struct clip_context *ctx, float x, float y)
+{
+       return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
+}
+
+static void
+clip_polygon_leftright(struct clip_context *ctx,
+                      enum path_transition transition,
+                      float x, float y, float clip_x)
+{
+       float yi;
+
+       switch (transition) {
+       case PATH_TRANSITION_IN_TO_IN:
+               clip_append_vertex(ctx, x, y);
+               break;
+       case PATH_TRANSITION_IN_TO_OUT:
+               yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
+               clip_append_vertex(ctx, clip_x, yi);
+               break;
+       case PATH_TRANSITION_OUT_TO_IN:
+               yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
+               clip_append_vertex(ctx, clip_x, yi);
+               clip_append_vertex(ctx, x, y);
+               break;
+       case PATH_TRANSITION_OUT_TO_OUT:
+               /* nothing */
+               break;
+       default:
+               assert(0 && "bad enum path_transition");
+       }
+
+       ctx->prev.x = x;
+       ctx->prev.y = y;
+}
+
+static void
+clip_polygon_topbottom(struct clip_context *ctx,
+                      enum path_transition transition,
+                      float x, float y, float clip_y)
+{
+       float xi;
+
+       switch (transition) {
+       case PATH_TRANSITION_IN_TO_IN:
+               clip_append_vertex(ctx, x, y);
+               break;
+       case PATH_TRANSITION_IN_TO_OUT:
+               xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
+               clip_append_vertex(ctx, xi, clip_y);
+               break;
+       case PATH_TRANSITION_OUT_TO_IN:
+               xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
+               clip_append_vertex(ctx, xi, clip_y);
+               clip_append_vertex(ctx, x, y);
+               break;
+       case PATH_TRANSITION_OUT_TO_OUT:
+               /* nothing */
+               break;
+       default:
+               assert(0 && "bad enum path_transition");
+       }
+
+       ctx->prev.x = x;
+       ctx->prev.y = y;
+}
+
+static void
+clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
+                     float *dst_x, float *dst_y)
+{
+       ctx->prev.x = src->x[src->n - 1];
+       ctx->prev.y = src->y[src->n - 1];
+       ctx->vertices.x = dst_x;
+       ctx->vertices.y = dst_y;
+}
+
+static int
+clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
+                 float *dst_x, float *dst_y)
+{
+       enum path_transition trans;
+       int i;
+
+       if (src->n < 2)
+               return 0;
+
+       clip_context_prepare(ctx, src, dst_x, dst_y);
+       for (i = 0; i < src->n; i++) {
+               trans = path_transition_left_edge(ctx, src->x[i], src->y[i]);
+               clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
+                                      ctx->clip.x1);
+       }
+       return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
+                  float *dst_x, float *dst_y)
+{
+       enum path_transition trans;
+       int i;
+
+       if (src->n < 2)
+               return 0;
+
+       clip_context_prepare(ctx, src, dst_x, dst_y);
+       for (i = 0; i < src->n; i++) {
+               trans = path_transition_right_edge(ctx, src->x[i], src->y[i]);
+               clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
+                                      ctx->clip.x2);
+       }
+       return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
+                float *dst_x, float *dst_y)
+{
+       enum path_transition trans;
+       int i;
+
+       if (src->n < 2)
+               return 0;
+
+       clip_context_prepare(ctx, src, dst_x, dst_y);
+       for (i = 0; i < src->n; i++) {
+               trans = path_transition_top_edge(ctx, src->x[i], src->y[i]);
+               clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
+                                      ctx->clip.y1);
+       }
+       return ctx->vertices.x - dst_x;
+}
+
+static int
+clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
+                   float *dst_x, float *dst_y)
+{
+       enum path_transition trans;
+       int i;
+
+       if (src->n < 2)
+               return 0;
+
+       clip_context_prepare(ctx, src, dst_x, dst_y);
+       for (i = 0; i < src->n; i++) {
+               trans = path_transition_bottom_edge(ctx, src->x[i], src->y[i]);
+               clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
+                                      ctx->clip.y2);
+       }
+       return ctx->vertices.x - dst_x;
+}
+
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#define min(a, b) (((a) > (b)) ? (b) : (a))
+#define clip(x, a, b)  min(max(x, a), b)
+
+int
+clip_simple(struct clip_context *ctx,
+           struct polygon8 *surf,
+           float *ex,
+           float *ey)
+{
+       int i;
+       for (i = 0; i < surf->n; i++) {
+               ex[i] = clip(surf->x[i], ctx->clip.x1, ctx->clip.x2);
+               ey[i] = clip(surf->y[i], ctx->clip.y1, ctx->clip.y2);
+       }
+       return surf->n;
+}
+
+int
+clip_transformed(struct clip_context *ctx,
+                struct polygon8 *surf,
+                float *ex,
+                float *ey)
+{
+       struct polygon8 polygon;
+       int i, n;
+
+       polygon.n = clip_polygon_left(ctx, surf, polygon.x, polygon.y);
+       surf->n = clip_polygon_right(ctx, &polygon, surf->x, surf->y);
+       polygon.n = clip_polygon_top(ctx, surf, polygon.x, polygon.y);
+       surf->n = clip_polygon_bottom(ctx, &polygon, surf->x, surf->y);
+
+       /* Get rid of duplicate vertices */
+       ex[0] = surf->x[0];
+       ey[0] = surf->y[0];
+       n = 1;
+       for (i = 1; i < surf->n; i++) {
+               if (float_difference(ex[n - 1], surf->x[i]) == 0.0f &&
+                   float_difference(ey[n - 1], surf->y[i]) == 0.0f)
+                       continue;
+               ex[n] = surf->x[i];
+               ey[n] = surf->y[i];
+               n++;
+       }
+       if (float_difference(ex[n - 1], surf->x[0]) == 0.0f &&
+           float_difference(ey[n - 1], surf->y[0]) == 0.0f)
+               n--;
+
+       return n;
+}
diff --git a/libweston/vertex-clipping.h b/libweston/vertex-clipping.h
new file mode 100644 (file)
index 0000000..0c69902
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _WESTON_VERTEX_CLIPPING_H
+#define _WESTON_VERTEX_CLIPPING_H
+
+struct polygon8 {
+       float x[8];
+       float y[8];
+       int n;
+};
+
+struct clip_context {
+       struct {
+               float x;
+               float y;
+       } prev;
+
+       struct {
+               float x1, y1;
+               float x2, y2;
+       } clip;
+
+       struct {
+               float *x;
+               float *y;
+       } vertices;
+};
+
+float
+float_difference(float a, float b);
+
+int
+clip_simple(struct clip_context *ctx,
+           struct polygon8 *surf,
+           float *ex,
+           float *ey);
+
+int
+clip_transformed(struct clip_context *ctx,
+                struct polygon8 *surf,
+                float *ex,
+                float *ey);\
+
+#endif
diff --git a/libweston/weston-egl-ext.h b/libweston/weston-egl-ext.h
new file mode 100644 (file)
index 0000000..32f6108
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Extensions used by Weston, copied from Mesa's eglmesaext.h, */
+
+#ifndef WESTON_EGL_EXT_H
+#define WESTON_EGL_EXT_H
+
+#ifndef EGL_WL_bind_wayland_display
+#define EGL_WL_bind_wayland_display 1
+
+struct wl_display;
+
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
+#endif
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
+#endif
+
+/*
+ * This is a little different to the tests shipped with EGL implementations,
+ * which wrap the entire thing in #ifndef EGL_WL_bind_wayland_display, then go
+ * on to define both BindWaylandDisplay and QueryWaylandBuffer.
+ *
+ * Unfortunately, some implementations (particularly the version of Mesa shipped
+ * in Ubuntu 12.04) define EGL_WL_bind_wayland_display, but then only provide
+ * prototypes for (Un)BindWaylandDisplay, completely omitting
+ * QueryWaylandBuffer.
+ *
+ * Detect this, and provide our own definitions if necessary.
+ */
+#ifndef EGL_WAYLAND_BUFFER_WL
+#define EGL_WAYLAND_BUFFER_WL          0x31D5 /* eglCreateImageKHR target */
+#define EGL_WAYLAND_PLANE_WL           0x31D6 /* eglCreateImageKHR target */
+
+#define EGL_TEXTURE_Y_U_V_WL            0x31D7
+#define EGL_TEXTURE_Y_UV_WL             0x31D8
+#define EGL_TEXTURE_Y_XUXV_WL           0x31D9
+#define EGL_TEXTURE_EXTERNAL_WL         0x31DA
+
+struct wl_resource;
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
+#endif
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
+#endif
+
+#ifndef EGL_WL_create_wayland_buffer_from_image
+#define EGL_WL_create_wayland_buffer_from_image 1
+
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
+#endif
+typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
+#endif
+
+#ifndef EGL_TEXTURE_EXTERNAL_WL
+#define EGL_TEXTURE_EXTERNAL_WL         0x31DA
+#endif
+
+#ifndef EGL_BUFFER_AGE_EXT
+#define EGL_BUFFER_AGE_EXT              0x313D
+#endif
+
+#ifndef EGL_WAYLAND_Y_INVERTED_WL
+#define EGL_WAYLAND_Y_INVERTED_WL              0x31DB /* eglQueryWaylandBufferWL attribute */
+#endif
+
+/* Mesas gl2ext.h and probably Khronos upstream defined
+ * GL_EXT_unpack_subimage with non _EXT suffixed GL_UNPACK_* tokens.
+ * In case we're using that mess, manually define the _EXT versions
+ * of the tokens here.*/
+#if defined(GL_EXT_unpack_subimage) && !defined(GL_UNPACK_ROW_LENGTH_EXT)
+#define GL_UNPACK_ROW_LENGTH_EXT                                0x0CF2
+#define GL_UNPACK_SKIP_ROWS_EXT                                 0x0CF3
+#define GL_UNPACK_SKIP_PIXELS_EXT                               0x0CF4
+#endif
+
+/* Define needed tokens from EGL_EXT_image_dma_buf_import extension
+ * here to avoid having to add ifdefs everywhere.*/
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_LINUX_DMA_BUF_EXT                                  0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT                               0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT                              0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT                          0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT                           0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT                              0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT                          0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT                           0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT                              0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT                          0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT                           0x327A
+#endif
+
+
+#endif
diff --git a/libweston/weston-launch.c b/libweston/weston-launch.c
new file mode 100644 (file)
index 0000000..9987d8e
--- /dev/null
@@ -0,0 +1,772 @@
+/*
+ * Copyright © 2012 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+#include <poll.h>
+#include <errno.h>
+
+#include <error.h>
+#include <getopt.h>
+
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/socket.h>
+#include <sys/signalfd.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <linux/vt.h>
+#include <linux/major.h>
+#include <linux/kd.h>
+
+#include <pwd.h>
+#include <grp.h>
+#include <security/pam_appl.h>
+
+#ifdef HAVE_SYSTEMD_LOGIN
+#include <systemd/sd-login.h>
+#endif
+
+#include "weston-launch.h"
+
+#define DRM_MAJOR 226
+
+#ifndef KDSKBMUTE
+#define KDSKBMUTE      0x4B51
+#endif
+
+#ifndef EVIOCREVOKE
+#define EVIOCREVOKE _IOW('E', 0x91, int)
+#endif
+
+#define MAX_ARGV_SIZE 256
+
+#ifdef HAVE_LIBDRM
+
+#include <xf86drm.h>
+
+#else
+
+static inline int
+drmDropMaster(int drm_fd)
+{
+       return 0;
+}
+
+static inline int
+drmSetMaster(int drm_fd)
+{
+       return 0;
+}
+
+#endif
+
+struct weston_launch {
+       struct pam_conv pc;
+       pam_handle_t *ph;
+       int tty;
+       int ttynr;
+       int sock[2];
+       int drm_fd;
+       int last_input_fd;
+       int kb_mode;
+       struct passwd *pw;
+
+       int signalfd;
+
+       pid_t child;
+       int verbose;
+       char *new_user;
+};
+
+union cmsg_data { unsigned char b[4]; int fd; };
+
+static gid_t *
+read_groups(void)
+{
+       int n;
+       gid_t *groups;
+
+       n = getgroups(0, NULL);
+
+       if (n < 0) {
+               fprintf(stderr, "Unable to retrieve groups: %m\n");
+               return NULL;
+       }
+
+       groups = malloc(n * sizeof(gid_t));
+       if (!groups)
+               return NULL;
+
+       if (getgroups(n, groups) < 0) {
+               fprintf(stderr, "Unable to retrieve groups: %m\n");
+               free(groups);
+               return NULL;
+       }
+       return groups;
+}
+
+static bool
+weston_launch_allowed(struct weston_launch *wl)
+{
+       struct group *gr;
+       gid_t *groups;
+       int i;
+#ifdef HAVE_SYSTEMD_LOGIN
+       char *session, *seat;
+       int err;
+#endif
+
+       if (getuid() == 0)
+               return true;
+
+       gr = getgrnam("weston-launch");
+       if (gr) {
+               groups = read_groups();
+               if (groups) {
+                       for (i = 0; groups[i]; ++i) {
+                               if (groups[i] == gr->gr_gid) {
+                                       free(groups);
+                                       return true;
+                               }
+                       }
+                       free(groups);
+               }
+       }
+
+#ifdef HAVE_SYSTEMD_LOGIN
+       err = sd_pid_get_session(getpid(), &session);
+       if (err == 0 && session) {
+               if (sd_session_is_active(session) &&
+                   sd_session_get_seat(session, &seat) == 0) {
+                       free(seat);
+                       free(session);
+                       return true;
+               }
+               free(session);
+       }
+#endif
+
+       return false;
+}
+
+static int
+pam_conversation_fn(int msg_count,
+                   const struct pam_message **messages,
+                   struct pam_response **responses,
+                   void *user_data)
+{
+       return PAM_SUCCESS;
+}
+
+static int
+setup_pam(struct weston_launch *wl)
+{
+       int err;
+
+       wl->pc.conv = pam_conversation_fn;
+       wl->pc.appdata_ptr = wl;
+
+       err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
+       if (err != PAM_SUCCESS) {
+               fprintf(stderr, "failed to start pam transaction: %d: %s\n",
+                       err, pam_strerror(wl->ph, err));
+               return -1;
+       }
+
+       err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
+       if (err != PAM_SUCCESS) {
+               fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
+                       err, pam_strerror(wl->ph, err));
+               return -1;
+       }
+
+       err = pam_open_session(wl->ph, 0);
+       if (err != PAM_SUCCESS) {
+               fprintf(stderr, "failed to open pam session: %d: %s\n",
+                       err, pam_strerror(wl->ph, err));
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+setup_launcher_socket(struct weston_launch *wl)
+{
+       if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
+               error(1, errno, "socketpair failed");
+
+       if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
+               error(1, errno, "fcntl failed");
+
+       return 0;
+}
+
+static int
+setup_signals(struct weston_launch *wl)
+{
+       int ret;
+       sigset_t mask;
+       struct sigaction sa;
+
+       memset(&sa, 0, sizeof sa);
+       sa.sa_handler = SIG_DFL;
+       sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
+       ret = sigaction(SIGCHLD, &sa, NULL);
+       assert(ret == 0);
+
+       sa.sa_handler = SIG_IGN;
+       sa.sa_flags = 0;
+       sigaction(SIGHUP, &sa, NULL);
+
+       ret = sigemptyset(&mask);
+       assert(ret == 0);
+       sigaddset(&mask, SIGCHLD);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+       sigaddset(&mask, SIGUSR1);
+       sigaddset(&mask, SIGUSR2);
+       ret = sigprocmask(SIG_BLOCK, &mask, NULL);
+       assert(ret == 0);
+
+       wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
+       if (wl->signalfd < 0)
+               return -errno;
+
+       return 0;
+}
+
+static void
+setenv_fd(const char *env, int fd)
+{
+       char buf[32];
+
+       snprintf(buf, sizeof buf, "%d", fd);
+       setenv(env, buf, 1);
+}
+
+static int
+send_reply(struct weston_launch *wl, int reply)
+{
+       int len;
+
+       do {
+               len = send(wl->sock[0], &reply, sizeof reply, 0);
+       } while (len < 0 && errno == EINTR);
+
+       return len;
+}
+
+static int
+handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
+{
+       int fd = -1, ret = -1;
+       char control[CMSG_SPACE(sizeof(fd))];
+       struct cmsghdr *cmsg;
+       struct stat s;
+       struct msghdr nmsg;
+       struct iovec iov;
+       struct weston_launcher_open *message;
+       union cmsg_data *data;
+
+       message = msg->msg_iov->iov_base;
+       if ((size_t)len < sizeof(*message))
+               goto err0;
+
+       /* Ensure path is null-terminated */
+       ((char *) message)[len-1] = '\0';
+
+       fd = open(message->path, message->flags);
+       if (fd < 0) {
+               fprintf(stderr, "Error opening device %s: %m\n",
+                       message->path);
+               goto err0;
+       }
+
+       if (fstat(fd, &s) < 0) {
+               close(fd);
+               fd = -1;
+               fprintf(stderr, "Failed to stat %s\n", message->path);
+               goto err0;
+       }
+
+       if (major(s.st_rdev) != INPUT_MAJOR &&
+           major(s.st_rdev) != DRM_MAJOR) {
+               close(fd);
+               fd = -1;
+               fprintf(stderr, "Device %s is not an input or drm device\n",
+                       message->path);
+               goto err0;
+       }
+
+err0:
+       memset(&nmsg, 0, sizeof nmsg);
+       nmsg.msg_iov = &iov;
+       nmsg.msg_iovlen = 1;
+       if (fd != -1) {
+               nmsg.msg_control = control;
+               nmsg.msg_controllen = sizeof control;
+               cmsg = CMSG_FIRSTHDR(&nmsg);
+               cmsg->cmsg_level = SOL_SOCKET;
+               cmsg->cmsg_type = SCM_RIGHTS;
+               cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
+               data = (union cmsg_data *) CMSG_DATA(cmsg);
+               data->fd = fd;
+               nmsg.msg_controllen = cmsg->cmsg_len;
+               ret = 0;
+       }
+       iov.iov_base = &ret;
+       iov.iov_len = sizeof ret;
+
+       if (wl->verbose)
+               fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
+                       message->path, ret, fd);
+       do {
+               len = sendmsg(wl->sock[0], &nmsg, 0);
+       } while (len < 0 && errno == EINTR);
+
+       if (len < 0)
+               return -1;
+
+       if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
+               wl->drm_fd = fd;
+       if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
+           wl->last_input_fd < fd)
+               wl->last_input_fd = fd;
+
+       return 0;
+}
+
+static int
+handle_socket_msg(struct weston_launch *wl)
+{
+       char control[CMSG_SPACE(sizeof(int))];
+       char buf[BUFSIZ];
+       struct msghdr msg;
+       struct iovec iov;
+       int ret = -1;
+       ssize_t len;
+       struct weston_launcher_message *message;
+
+       memset(&msg, 0, sizeof(msg));
+       iov.iov_base = buf;
+       iov.iov_len  = sizeof buf;
+       msg.msg_iov = &iov;
+       msg.msg_iovlen = 1;
+       msg.msg_control = control;
+       msg.msg_controllen = sizeof control;
+
+       do {
+               len = recvmsg(wl->sock[0], &msg, 0);
+       } while (len < 0 && errno == EINTR);
+
+       if (len < 1)
+               return -1;
+
+       message = (void *) buf;
+       switch (message->opcode) {
+       case WESTON_LAUNCHER_OPEN:
+               ret = handle_open(wl, &msg, len);
+               break;
+       }
+
+       return ret;
+}
+
+static void
+quit(struct weston_launch *wl, int status)
+{
+       struct vt_mode mode = { 0 };
+       int err;
+
+       close(wl->signalfd);
+       close(wl->sock[0]);
+
+       if (wl->new_user) {
+               err = pam_close_session(wl->ph, 0);
+               if (err)
+                       fprintf(stderr, "pam_close_session failed: %d: %s\n",
+                               err, pam_strerror(wl->ph, err));
+               pam_end(wl->ph, err);
+       }
+
+       if (ioctl(wl->tty, KDSKBMUTE, 0) &&
+           ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
+               fprintf(stderr, "failed to restore keyboard mode: %m\n");
+
+       if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
+               fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
+
+       /* We have to drop master before we switch the VT back in
+        * VT_AUTO, so we don't risk switching to a VT with another
+        * display server, that will then fail to set drm master. */
+       drmDropMaster(wl->drm_fd);
+
+       mode.mode = VT_AUTO;
+       if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
+               fprintf(stderr, "could not reset vt handling\n");
+
+       exit(status);
+}
+
+static void
+close_input_fds(struct weston_launch *wl)
+{
+       struct stat s;
+       int fd;
+
+       for (fd = 3; fd <= wl->last_input_fd; fd++) {
+               if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
+                       /* EVIOCREVOKE may fail if the kernel doesn't
+                        * support it, but all we can do is ignore it. */
+                       ioctl(fd, EVIOCREVOKE, 0);
+                       close(fd);
+               }
+       }
+}
+
+static int
+handle_signal(struct weston_launch *wl)
+{
+       struct signalfd_siginfo sig;
+       int pid, status, ret;
+
+       if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
+               error(0, errno, "reading signalfd failed");
+               return -1;
+       }
+
+       switch (sig.ssi_signo) {
+       case SIGCHLD:
+               pid = waitpid(-1, &status, 0);
+               if (pid == wl->child) {
+                       wl->child = 0;
+                       if (WIFEXITED(status))
+                               ret = WEXITSTATUS(status);
+                       else if (WIFSIGNALED(status))
+                               /*
+                                * If weston dies because of signal N, we
+                                * return 10+N. This is distinct from
+                                * weston-launch dying because of a signal
+                                * (128+N).
+                                */
+                               ret = 10 + WTERMSIG(status);
+                       else
+                               ret = 0;
+                       quit(wl, ret);
+               }
+               break;
+       case SIGTERM:
+       case SIGINT:
+               if (wl->child)
+                       kill(wl->child, sig.ssi_signo);
+               break;
+       case SIGUSR1:
+               send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
+               close_input_fds(wl);
+               drmDropMaster(wl->drm_fd);
+               ioctl(wl->tty, VT_RELDISP, 1);
+               break;
+       case SIGUSR2:
+               ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
+               drmSetMaster(wl->drm_fd);
+               send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
+               break;
+       default:
+               return -1;
+       }
+
+       return 0;
+}
+
+static int
+setup_tty(struct weston_launch *wl, const char *tty)
+{
+       struct stat buf;
+       struct vt_mode mode = { 0 };
+       char *t;
+
+       if (!wl->new_user) {
+               wl->tty = STDIN_FILENO;
+       } else if (tty) {
+               t = ttyname(STDIN_FILENO);
+               if (t && strcmp(t, tty) == 0)
+                       wl->tty = STDIN_FILENO;
+               else
+                       wl->tty = open(tty, O_RDWR | O_NOCTTY);
+       } else {
+               int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
+               char filename[16];
+
+               if (tty0 < 0)
+                       error(1, errno, "could not open tty0");
+
+               if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
+                       error(1, errno, "failed to find non-opened console");
+
+               snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
+               wl->tty = open(filename, O_RDWR | O_NOCTTY);
+               close(tty0);
+       }
+
+       if (wl->tty < 0)
+               error(1, errno, "failed to open tty");
+
+       if (fstat(wl->tty, &buf) == -1 ||
+           major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
+               error(1, 0, "weston-launch must be run from a virtual terminal");
+
+       if (tty) {
+               if (fstat(wl->tty, &buf) < 0)
+                       error(1, errno, "stat %s failed", tty);
+
+               if (major(buf.st_rdev) != TTY_MAJOR)
+                       error(1, 0, "invalid tty device: %s", tty);
+
+               wl->ttynr = minor(buf.st_rdev);
+       }
+
+       if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
+               error(1, errno, "failed to get current keyboard mode: %m\n");
+
+       if (ioctl(wl->tty, KDSKBMUTE, 1) &&
+           ioctl(wl->tty, KDSKBMODE, K_OFF))
+               error(1, errno, "failed to set K_OFF keyboard mode: %m\n");
+
+       if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS))
+               error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
+
+       mode.mode = VT_PROCESS;
+       mode.relsig = SIGUSR1;
+       mode.acqsig = SIGUSR2;
+       if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
+               error(1, errno, "failed to take control of vt handling\n");
+
+       return 0;
+}
+
+static void
+setup_session(struct weston_launch *wl)
+{
+       char **env;
+       char *term;
+       int i;
+
+       if (wl->tty != STDIN_FILENO) {
+               if (setsid() < 0)
+                       error(1, errno, "setsid failed");
+               if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
+                       error(1, errno, "TIOCSCTTY failed - tty is in use");
+       }
+
+       term = getenv("TERM");
+       clearenv();
+       if (term)
+               setenv("TERM", term, 1);
+       setenv("USER", wl->pw->pw_name, 1);
+       setenv("LOGNAME", wl->pw->pw_name, 1);
+       setenv("HOME", wl->pw->pw_dir, 1);
+       setenv("SHELL", wl->pw->pw_shell, 1);
+
+       env = pam_getenvlist(wl->ph);
+       if (env) {
+               for (i = 0; env[i]; ++i) {
+                       if (putenv(env[i]) != 0)
+                               error(0, 0, "putenv %s failed", env[i]);
+               }
+               free(env);
+       }
+}
+
+static void
+drop_privileges(struct weston_launch *wl)
+{
+       if (setgid(wl->pw->pw_gid) < 0 ||
+#ifdef HAVE_INITGROUPS
+           initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
+#endif
+           setuid(wl->pw->pw_uid) < 0)
+               error(1, errno, "dropping privileges failed");
+}
+
+static void
+launch_compositor(struct weston_launch *wl, int argc, char *argv[])
+{
+       char *child_argv[MAX_ARGV_SIZE];
+       sigset_t mask;
+       int i;
+
+       if (wl->verbose)
+               printf("weston-launch: spawned weston with pid: %d\n", getpid());
+       if (wl->new_user)
+               setup_session(wl);
+
+       if (geteuid() == 0)
+               drop_privileges(wl);
+
+       setenv_fd("WESTON_TTY_FD", wl->tty);
+       setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
+
+       unsetenv("DISPLAY");
+
+       /* Do not give our signal mask to the new process. */
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGTERM);
+       sigaddset(&mask, SIGCHLD);
+       sigaddset(&mask, SIGINT);
+       sigprocmask(SIG_UNBLOCK, &mask, NULL);
+
+       child_argv[0] = "/bin/sh";
+       child_argv[1] = "-l";
+       child_argv[2] = "-c";
+       child_argv[3] = BINDIR "/weston \"$@\"";
+       child_argv[4] = "weston";
+       for (i = 0; i < argc; ++i)
+               child_argv[5 + i] = argv[i];
+       child_argv[5 + i] = NULL;
+
+       execv(child_argv[0], child_argv);
+       error(1, errno, "exec failed");
+}
+
+static void
+help(const char *name)
+{
+       fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
+       fprintf(stderr, "  -u, --user      Start session as specified username\n");
+       fprintf(stderr, "  -t, --tty       Start session on alternative tty\n");
+       fprintf(stderr, "  -v, --verbose   Be verbose\n");
+       fprintf(stderr, "  -h, --help      Display this help message\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+       struct weston_launch wl;
+       int i, c;
+       char *tty = NULL;
+       struct option opts[] = {
+               { "user",    required_argument, NULL, 'u' },
+               { "tty",     required_argument, NULL, 't' },
+               { "verbose", no_argument,       NULL, 'v' },
+               { "help",    no_argument,       NULL, 'h' },
+               { 0,         0,                 NULL,  0  }
+       };
+
+       memset(&wl, 0, sizeof wl);
+
+       while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
+               switch (c) {
+               case 'u':
+                       wl.new_user = optarg;
+                       if (getuid() != 0)
+                               error(1, 0, "Permission denied. -u allowed for root only");
+                       break;
+               case 't':
+                       tty = optarg;
+                       break;
+               case 'v':
+                       wl.verbose = 1;
+                       break;
+               case 'h':
+                       help("weston-launch");
+                       exit(EXIT_FAILURE);
+               default:
+                       exit(EXIT_FAILURE);
+               }
+       }
+
+       if ((argc - optind) > (MAX_ARGV_SIZE - 6))
+               error(1, E2BIG, "Too many arguments to pass to weston");
+
+       if (wl.new_user)
+               wl.pw = getpwnam(wl.new_user);
+       else
+               wl.pw = getpwuid(getuid());
+       if (wl.pw == NULL)
+               error(1, errno, "failed to get username");
+
+       if (!weston_launch_allowed(&wl))
+               error(1, 0, "Permission denied. You should either:\n"
+#ifdef HAVE_SYSTEMD_LOGIN
+                     " - run from an active and local (systemd) session.\n"
+#else
+                     " - enable systemd session support for weston-launch.\n"
+#endif
+                     " - or add yourself to the 'weston-launch' group.");
+
+       if (setup_tty(&wl, tty) < 0)
+               exit(EXIT_FAILURE);
+
+       if (wl.new_user && setup_pam(&wl) < 0)
+               exit(EXIT_FAILURE);
+
+       if (setup_launcher_socket(&wl) < 0)
+               exit(EXIT_FAILURE);
+
+       if (setup_signals(&wl) < 0)
+               exit(EXIT_FAILURE);
+
+       wl.child = fork();
+       if (wl.child == -1)
+               error(EXIT_FAILURE, errno, "fork failed");
+
+       if (wl.child == 0)
+               launch_compositor(&wl, argc - optind, argv + optind);
+
+       close(wl.sock[1]);
+       if (wl.tty != STDIN_FILENO)
+               close(wl.tty);
+
+       while (1) {
+               struct pollfd fds[2];
+               int n;
+
+               fds[0].fd = wl.sock[0];
+               fds[0].events = POLLIN;
+               fds[1].fd = wl.signalfd;
+               fds[1].events = POLLIN;
+
+               n = poll(fds, 2, -1);
+               if (n < 0)
+                       error(0, errno, "poll failed");
+               if (fds[0].revents & POLLIN)
+                       handle_socket_msg(&wl);
+               if (fds[1].revents)
+                       handle_signal(&wl);
+       }
+
+       return 0;
+}
diff --git a/libweston/weston-launch.h b/libweston/weston-launch.h
new file mode 100644 (file)
index 0000000..bd974de
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2012 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef _WESTON_LAUNCH_H_
+#define _WESTON_LAUNCH_H_
+
+enum weston_launcher_opcode {
+       WESTON_LAUNCHER_OPEN,
+};
+
+enum weston_launcher_event {
+       WESTON_LAUNCHER_SUCCESS,
+       WESTON_LAUNCHER_ACTIVATE,
+       WESTON_LAUNCHER_DEACTIVATE
+};
+
+struct weston_launcher_message {
+       int opcode;
+};
+
+struct weston_launcher_open {
+       struct weston_launcher_message header;
+       int flags;
+       char path[0];
+};
+
+#endif
diff --git a/libweston/zoom.c b/libweston/zoom.c
new file mode 100644 (file)
index 0000000..08c0693
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ * Copyright © 2012 Scott Moreau
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "compositor.h"
+#include "text-cursor-position-server-protocol.h"
+#include "shared/helpers.h"
+
+static void
+weston_zoom_frame_z(struct weston_animation *animation,
+               struct weston_output *output, uint32_t msecs)
+{
+       if (animation->frame_counter <= 1)
+               output->zoom.spring_z.timestamp = msecs;
+
+       weston_spring_update(&output->zoom.spring_z, msecs);
+
+       if (output->zoom.spring_z.current > output->zoom.max_level)
+               output->zoom.spring_z.current = output->zoom.max_level;
+       else if (output->zoom.spring_z.current < 0.0)
+               output->zoom.spring_z.current = 0.0;
+
+       if (weston_spring_done(&output->zoom.spring_z)) {
+               if (output->zoom.active && output->zoom.level <= 0.0) {
+                       output->zoom.active = false;
+                       output->zoom.seat = NULL;
+                       output->disable_planes--;
+                       wl_list_remove(&output->zoom.motion_listener.link);
+               }
+               output->zoom.spring_z.current = output->zoom.level;
+               wl_list_remove(&animation->link);
+               wl_list_init(&animation->link);
+       }
+
+       output->dirty = 1;
+       weston_output_damage(output);
+}
+
+static void
+zoom_area_center_from_point(struct weston_output *output,
+                           double *x, double *y)
+{
+       float level = output->zoom.spring_z.current;
+
+       *x = (*x - output->x) * level + output->width / 2.;
+       *y = (*y - output->y) * level + output->height / 2.;
+}
+
+static void
+weston_output_update_zoom_transform(struct weston_output *output)
+{
+       double x = output->zoom.current.x; /* global pointer coords */
+       double y = output->zoom.current.y;
+       float level;
+
+       level = output->zoom.spring_z.current;
+
+       if (!output->zoom.active || level > output->zoom.max_level ||
+           level == 0.0f)
+               return;
+
+       zoom_area_center_from_point(output, &x, &y);
+
+       output->zoom.trans_x = x - output->width / 2;
+       output->zoom.trans_y = y - output->height / 2;
+
+       if (output->zoom.trans_x < 0)
+               output->zoom.trans_x = 0;
+       if (output->zoom.trans_y < 0)
+               output->zoom.trans_y = 0;
+       if (output->zoom.trans_x > level * output->width)
+               output->zoom.trans_x = level * output->width;
+       if (output->zoom.trans_y > level * output->height)
+               output->zoom.trans_y = level * output->height;
+}
+
+static void
+weston_zoom_transition(struct weston_output *output)
+{
+       if (output->zoom.level != output->zoom.spring_z.current) {
+               output->zoom.spring_z.target = output->zoom.level;
+               if (wl_list_empty(&output->zoom.animation_z.link)) {
+                       output->zoom.animation_z.frame_counter = 0;
+                       wl_list_insert(output->animation_list.prev,
+                               &output->zoom.animation_z.link);
+               }
+       }
+
+       output->dirty = 1;
+       weston_output_damage(output);
+}
+
+WL_EXPORT void
+weston_output_update_zoom(struct weston_output *output)
+{
+       struct weston_seat *seat = output->zoom.seat;
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       assert(output->zoom.active);
+
+       output->zoom.current.x = wl_fixed_to_double(pointer->x);
+       output->zoom.current.y = wl_fixed_to_double(pointer->y);
+
+       weston_zoom_transition(output);
+       weston_output_update_zoom_transform(output);
+}
+
+static void
+motion(struct wl_listener *listener, void *data)
+{
+       struct weston_output_zoom *zoom =
+               container_of(listener, struct weston_output_zoom, motion_listener);
+       struct weston_output *output =
+               container_of(zoom, struct weston_output, zoom);
+
+       weston_output_update_zoom(output);
+}
+
+WL_EXPORT void
+weston_output_activate_zoom(struct weston_output *output,
+                           struct weston_seat *seat)
+{
+       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
+
+       if (output->zoom.active)
+               return;
+
+       output->zoom.active = true;
+       output->zoom.seat = seat;
+       output->disable_planes++;
+       wl_signal_add(&pointer->motion_signal,
+                     &output->zoom.motion_listener);
+}
+
+WL_EXPORT void
+weston_output_init_zoom(struct weston_output *output)
+{
+       output->zoom.active = false;
+       output->zoom.seat = NULL;
+       output->zoom.increment = 0.07;
+       output->zoom.max_level = 0.95;
+       output->zoom.level = 0.0;
+       output->zoom.trans_x = 0.0;
+       output->zoom.trans_y = 0.0;
+       weston_spring_init(&output->zoom.spring_z, 250.0, 0.0, 0.0);
+       output->zoom.spring_z.friction = 1000;
+       output->zoom.animation_z.frame = weston_zoom_frame_z;
+       wl_list_init(&output->zoom.animation_z.link);
+       output->zoom.motion_listener.notify = motion;
+}
diff --git a/src/animation.c b/src/animation.c
deleted file mode 100644 (file)
index 2c7943f..0000000
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright © 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <stdio.h>
-#include <math.h>
-
-#include <unistd.h>
-#include <fcntl.h>
-
-#include "compositor.h"
-#include "shared/helpers.h"
-
-WL_EXPORT void
-weston_spring_init(struct weston_spring *spring,
-                  double k, double current, double target)
-{
-       spring->k = k;
-       spring->friction = 400.0;
-       spring->current = current;
-       spring->previous = current;
-       spring->target = target;
-       spring->clip = WESTON_SPRING_OVERSHOOT;
-       spring->min = 0.0;
-       spring->max = 1.0;
-}
-
-WL_EXPORT void
-weston_spring_update(struct weston_spring *spring, uint32_t msec)
-{
-       double force, v, current, step;
-
-       /* Limit the number of executions of the loop below by ensuring that
-        * the timestamp for last update of the spring is no more than 1s ago.
-        * This handles the case where time moves backwards or forwards in
-        * large jumps.
-        */
-       if (msec - spring->timestamp > 1000) {
-               weston_log("unexpectedly large timestamp jump (from %u to %u)\n",
-                          spring->timestamp, msec);
-               spring->timestamp = msec - 1000;
-       }
-
-       step = 0.01;
-       while (4 < msec - spring->timestamp) {
-               current = spring->current;
-               v = current - spring->previous;
-               force = spring->k * (spring->target - current) / 10.0 +
-                       (spring->previous - current) - v * spring->friction;
-
-               spring->current =
-                       current + (current - spring->previous) +
-                       force * step * step;
-               spring->previous = current;
-
-               switch (spring->clip) {
-               case WESTON_SPRING_OVERSHOOT:
-                       break;
-
-               case WESTON_SPRING_CLAMP:
-                       if (spring->current > spring->max) {
-                               spring->current = spring->max;
-                               spring->previous = spring->max;
-                       } else if (spring->current < 0.0) {
-                               spring->current = spring->min;
-                               spring->previous = spring->min;
-                       }
-                       break;
-
-               case WESTON_SPRING_BOUNCE:
-                       if (spring->current > spring->max) {
-                               spring->current =
-                                       2 * spring->max - spring->current;
-                               spring->previous =
-                                       2 * spring->max - spring->previous;
-                       } else if (spring->current < spring->min) {
-                               spring->current =
-                                       2 * spring->min - spring->current;
-                               spring->previous =
-                                       2 * spring->min - spring->previous;
-                       }
-                       break;
-               }
-
-               spring->timestamp += 4;
-       }
-}
-
-WL_EXPORT int
-weston_spring_done(struct weston_spring *spring)
-{
-       return fabs(spring->previous - spring->target) < 0.002 &&
-               fabs(spring->current - spring->target) < 0.002;
-}
-
-typedef        void (*weston_view_animation_frame_func_t)(struct weston_view_animation *animation);
-
-struct weston_view_animation {
-       struct weston_view *view;
-       struct weston_animation animation;
-       struct weston_spring spring;
-       struct weston_transform transform;
-       struct wl_listener listener;
-       float start, stop;
-       weston_view_animation_frame_func_t frame;
-       weston_view_animation_frame_func_t reset;
-       weston_view_animation_done_func_t done;
-       void *data;
-       void *private;
-};
-
-WL_EXPORT void
-weston_view_animation_destroy(struct weston_view_animation *animation)
-{
-       wl_list_remove(&animation->animation.link);
-       wl_list_remove(&animation->listener.link);
-       wl_list_remove(&animation->transform.link);
-       if (animation->reset)
-               animation->reset(animation);
-       weston_view_geometry_dirty(animation->view);
-       if (animation->done)
-               animation->done(animation, animation->data);
-       free(animation);
-}
-
-static void
-handle_animation_view_destroy(struct wl_listener *listener, void *data)
-{
-       struct weston_view_animation *animation =
-               container_of(listener,
-                            struct weston_view_animation, listener);
-
-       weston_view_animation_destroy(animation);
-}
-
-static void
-weston_view_animation_frame(struct weston_animation *base,
-                           struct weston_output *output, uint32_t msecs)
-{
-       struct weston_view_animation *animation =
-               container_of(base,
-                            struct weston_view_animation, animation);
-       struct weston_compositor *compositor =
-               animation->view->surface->compositor;
-
-       if (base->frame_counter <= 1)
-               animation->spring.timestamp = msecs;
-
-       weston_spring_update(&animation->spring, msecs);
-
-       if (weston_spring_done(&animation->spring)) {
-               weston_view_schedule_repaint(animation->view);
-               weston_view_animation_destroy(animation);
-               return;
-       }
-
-       if (animation->frame)
-               animation->frame(animation);
-
-       weston_view_geometry_dirty(animation->view);
-       weston_view_schedule_repaint(animation->view);
-
-       /* The view's output_mask will be zero if its position is
-        * offscreen. Animations should always run but as they are also
-        * run off the repaint cycle, if there's nothing to repaint
-        * the animation stops running. Therefore if we catch this situation
-        * and schedule a repaint on all outputs it will be avoided.
-        */
-       if (animation->view->output_mask == 0)
-               weston_compositor_schedule_repaint(compositor);
-}
-
-static struct weston_view_animation *
-weston_view_animation_create(struct weston_view *view,
-                            float start, float stop,
-                            weston_view_animation_frame_func_t frame,
-                            weston_view_animation_frame_func_t reset,
-                            weston_view_animation_done_func_t done,
-                            void *data,
-                            void *private)
-{
-       struct weston_view_animation *animation;
-
-       animation = malloc(sizeof *animation);
-       if (!animation)
-               return NULL;
-
-       animation->view = view;
-       animation->frame = frame;
-       animation->reset = reset;
-       animation->done = done;
-       animation->data = data;
-       animation->start = start;
-       animation->stop = stop;
-       animation->private = private;
-
-       weston_matrix_init(&animation->transform.matrix);
-       wl_list_insert(&view->geometry.transformation_list,
-                      &animation->transform.link);
-
-       animation->animation.frame = weston_view_animation_frame;
-
-       animation->listener.notify = handle_animation_view_destroy;
-       wl_signal_add(&view->destroy_signal, &animation->listener);
-
-       wl_list_insert(&view->output->animation_list,
-                      &animation->animation.link);
-
-       return animation;
-}
-
-static void
-weston_view_animation_run(struct weston_view_animation *animation)
-{
-       animation->animation.frame_counter = 0;
-       weston_view_animation_frame(&animation->animation, NULL, 0);
-}
-
-static void
-reset_alpha(struct weston_view_animation *animation)
-{
-       struct weston_view *view = animation->view;
-
-       view->alpha = animation->stop;
-}
-
-static void
-zoom_frame(struct weston_view_animation *animation)
-{
-       struct weston_view *es = animation->view;
-       float scale;
-
-       scale = animation->start +
-               (animation->stop - animation->start) *
-               animation->spring.current;
-       weston_matrix_init(&animation->transform.matrix);
-       weston_matrix_translate(&animation->transform.matrix,
-                               -0.5f * es->surface->width,
-                               -0.5f * es->surface->height, 0);
-       weston_matrix_scale(&animation->transform.matrix, scale, scale, scale);
-       weston_matrix_translate(&animation->transform.matrix,
-                               0.5f * es->surface->width,
-                               0.5f * es->surface->height, 0);
-
-       es->alpha = animation->spring.current;
-       if (es->alpha > 1.0)
-               es->alpha = 1.0;
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_zoom_run(struct weston_view *view, float start, float stop,
-               weston_view_animation_done_func_t done, void *data)
-{
-       struct weston_view_animation *zoom;
-
-       zoom = weston_view_animation_create(view, start, stop,
-                                           zoom_frame, reset_alpha,
-                                           done, data, NULL);
-
-       if (zoom == NULL)
-               return NULL;
-
-       weston_spring_init(&zoom->spring, 300.0, start, stop);
-       zoom->spring.friction = 1400;
-       zoom->spring.previous = start - (stop - start) * 0.03;
-
-       weston_view_animation_run(zoom);
-
-       return zoom;
-}
-
-static void
-fade_frame(struct weston_view_animation *animation)
-{
-       if (animation->spring.current > 0.999)
-               animation->view->alpha = 1;
-       else if (animation->spring.current < 0.001 )
-               animation->view->alpha = 0;
-       else
-               animation->view->alpha = animation->spring.current;
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_fade_run(struct weston_view *view,
-               float start, float end, float k,
-               weston_view_animation_done_func_t done, void *data)
-{
-       struct weston_view_animation *fade;
-
-       fade = weston_view_animation_create(view, start, end,
-                                           fade_frame, reset_alpha,
-                                           done, data, NULL);
-
-       if (fade == NULL)
-               return NULL;
-
-       weston_spring_init(&fade->spring, 1000.0, start, end);
-       fade->spring.friction = 4000;
-       fade->spring.previous = start - (end - start) * 0.1;
-
-       view->alpha = start;
-
-       weston_view_animation_run(fade);
-
-       return fade;
-}
-
-WL_EXPORT void
-weston_fade_update(struct weston_view_animation *fade, float target)
-{
-       fade->spring.target = target;
-       fade->stop = target;
-}
-
-static void
-stable_fade_frame(struct weston_view_animation *animation)
-{
-       struct weston_view *back_view;
-
-       if (animation->spring.current > 0.999)
-               animation->view->alpha = 1;
-       else if (animation->spring.current < 0.001 )
-               animation->view->alpha = 0;
-       else
-               animation->view->alpha = animation->spring.current;
-
-       back_view = (struct weston_view *) animation->private;
-       back_view->alpha =
-               (animation->spring.target - animation->view->alpha) /
-               (1.0 - animation->view->alpha);
-       weston_view_geometry_dirty(back_view);
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_stable_fade_run(struct weston_view *front_view, float start,
-               struct weston_view *back_view, float end,
-               weston_view_animation_done_func_t done, void *data)
-{
-       struct weston_view_animation *fade;
-
-       fade = weston_view_animation_create(front_view, 0, 0,
-                                           stable_fade_frame, NULL,
-                                           done, data, back_view);
-
-       if (fade == NULL)
-               return NULL;
-
-       weston_spring_init(&fade->spring, 400, start, end);
-       fade->spring.friction = 1150;
-
-       front_view->alpha = start;
-       back_view->alpha = end;
-
-       weston_view_animation_run(fade);
-
-       return fade;
-}
-
-static void
-slide_frame(struct weston_view_animation *animation)
-{
-       float scale;
-
-       scale = animation->start +
-               (animation->stop - animation->start) *
-               animation->spring.current;
-       weston_matrix_init(&animation->transform.matrix);
-       weston_matrix_translate(&animation->transform.matrix, 0, scale, 0);
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_slide_run(struct weston_view *view, float start, float stop,
-                weston_view_animation_done_func_t done, void *data)
-{
-       struct weston_view_animation *animation;
-
-       animation = weston_view_animation_create(view, start, stop,
-                                             slide_frame, NULL, done,
-                                             data, NULL);
-       if (!animation)
-               return NULL;
-
-       weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
-       animation->spring.friction = 600;
-       animation->spring.clip = WESTON_SPRING_BOUNCE;
-
-       weston_view_animation_run(animation);
-
-       return animation;
-}
-
-struct weston_move_animation {
-       int dx;
-       int dy;
-       int reverse;
-       weston_view_animation_done_func_t done;
-};
-
-static void
-move_frame(struct weston_view_animation *animation)
-{
-       struct weston_move_animation *move = animation->private;
-       float scale;
-       float progress = animation->spring.current;
-
-       if (move->reverse)
-               progress = 1.0 - progress;
-
-       scale = animation->start +
-                (animation->stop - animation->start) *
-                progress;
-       weston_matrix_init(&animation->transform.matrix);
-       weston_matrix_scale(&animation->transform.matrix, scale, scale, 1.0f);
-       weston_matrix_translate(&animation->transform.matrix,
-                                move->dx * progress, move->dy * progress,
-                               0);
-}
-
-static void
-move_done(struct weston_view_animation *animation, void *data)
-{
-       struct weston_move_animation *move = animation->private;
-
-       if (move->done)
-               move->done(animation, data);
-
-       free(move);
-}
-
-WL_EXPORT struct weston_view_animation *
-weston_move_scale_run(struct weston_view *view, int dx, int dy,
-                     float start, float end, int reverse,
-                     weston_view_animation_done_func_t done, void *data)
-{
-       struct weston_move_animation *move;
-       struct weston_view_animation *animation;
-
-       move = malloc(sizeof(*move));
-       if (!move)
-               return NULL;
-       move->dx = dx;
-       move->dy = dy;
-       move->reverse = reverse;
-       move->done = done;
-
-       animation = weston_view_animation_create(view, start, end, move_frame,
-                                                NULL, move_done, data, move);
-
-       if (animation == NULL){
-               free(move);
-               return NULL;
-       }
-
-       weston_spring_init(&animation->spring, 400.0, 0.0, 1.0);
-       animation->spring.friction = 1150;
-
-       weston_view_animation_run(animation);
-
-       return animation;
-}
diff --git a/src/bindings.c b/src/bindings.c
deleted file mode 100644 (file)
index cc68cfe..0000000
+++ /dev/null
@@ -1,579 +0,0 @@
-/*
- * Copyright © 2011-2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <linux/input.h>
-
-#include "compositor.h"
-#include "shared/helpers.h"
-
-struct weston_binding {
-       uint32_t key;
-       uint32_t button;
-       uint32_t axis;
-       uint32_t modifier;
-       void *handler;
-       void *data;
-       struct wl_list link;
-};
-
-static struct weston_binding *
-weston_compositor_add_binding(struct weston_compositor *compositor,
-                             uint32_t key, uint32_t button, uint32_t axis,
-                             uint32_t modifier, void *handler, void *data)
-{
-       struct weston_binding *binding;
-
-       binding = malloc(sizeof *binding);
-       if (binding == NULL)
-               return NULL;
-
-       binding->key = key;
-       binding->button = button;
-       binding->axis = axis;
-       binding->modifier = modifier;
-       binding->handler = handler;
-       binding->data = data;
-
-       return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_key_binding(struct weston_compositor *compositor,
-                                 uint32_t key, uint32_t modifier,
-                                 weston_key_binding_handler_t handler,
-                                 void *data)
-{
-       struct weston_binding *binding;
-
-       binding = weston_compositor_add_binding(compositor, key, 0, 0,
-                                               modifier, handler, data);
-       if (binding == NULL)
-               return NULL;
-
-       wl_list_insert(compositor->key_binding_list.prev, &binding->link);
-
-       return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
-                                      uint32_t modifier,
-                                      weston_modifier_binding_handler_t handler,
-                                      void *data)
-{
-       struct weston_binding *binding;
-
-       binding = weston_compositor_add_binding(compositor, 0, 0, 0,
-                                               modifier, handler, data);
-       if (binding == NULL)
-               return NULL;
-
-       wl_list_insert(compositor->modifier_binding_list.prev, &binding->link);
-
-       return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_button_binding(struct weston_compositor *compositor,
-                                    uint32_t button, uint32_t modifier,
-                                    weston_button_binding_handler_t handler,
-                                    void *data)
-{
-       struct weston_binding *binding;
-
-       binding = weston_compositor_add_binding(compositor, 0, button, 0,
-                                               modifier, handler, data);
-       if (binding == NULL)
-               return NULL;
-
-       wl_list_insert(compositor->button_binding_list.prev, &binding->link);
-
-       return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_touch_binding(struct weston_compositor *compositor,
-                                   uint32_t modifier,
-                                   weston_touch_binding_handler_t handler,
-                                   void *data)
-{
-       struct weston_binding *binding;
-
-       binding = weston_compositor_add_binding(compositor, 0, 0, 0,
-                                               modifier, handler, data);
-       if (binding == NULL)
-               return NULL;
-
-       wl_list_insert(compositor->touch_binding_list.prev, &binding->link);
-
-       return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_axis_binding(struct weston_compositor *compositor,
-                                  uint32_t axis, uint32_t modifier,
-                                  weston_axis_binding_handler_t handler,
-                                  void *data)
-{
-       struct weston_binding *binding;
-
-       binding = weston_compositor_add_binding(compositor, 0, 0, axis,
-                                               modifier, handler, data);
-       if (binding == NULL)
-               return NULL;
-
-       wl_list_insert(compositor->axis_binding_list.prev, &binding->link);
-
-       return binding;
-}
-
-WL_EXPORT struct weston_binding *
-weston_compositor_add_debug_binding(struct weston_compositor *compositor,
-                                   uint32_t key,
-                                   weston_key_binding_handler_t handler,
-                                   void *data)
-{
-       struct weston_binding *binding;
-
-       binding = weston_compositor_add_binding(compositor, key, 0, 0, 0,
-                                               handler, data);
-
-       wl_list_insert(compositor->debug_binding_list.prev, &binding->link);
-
-       return binding;
-}
-
-WL_EXPORT void
-weston_binding_destroy(struct weston_binding *binding)
-{
-       wl_list_remove(&binding->link);
-       free(binding);
-}
-
-void
-weston_binding_list_destroy_all(struct wl_list *list)
-{
-       struct weston_binding *binding, *tmp;
-
-       wl_list_for_each_safe(binding, tmp, list, link)
-               weston_binding_destroy(binding);
-}
-
-struct binding_keyboard_grab {
-       uint32_t key;
-       struct weston_keyboard_grab grab;
-};
-
-static void
-binding_key(struct weston_keyboard_grab *grab,
-           uint32_t time, uint32_t key, uint32_t state_w)
-{
-       struct binding_keyboard_grab *b =
-               container_of(grab, struct binding_keyboard_grab, grab);
-       struct wl_resource *resource;
-       enum wl_keyboard_key_state state = state_w;
-       uint32_t serial;
-       struct weston_keyboard *keyboard = grab->keyboard;
-       struct wl_display *display = keyboard->seat->compositor->wl_display;
-
-       if (key == b->key) {
-               if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
-                       weston_keyboard_end_grab(grab->keyboard);
-                       if (keyboard->input_method_resource)
-                               keyboard->grab = &keyboard->input_method_grab;
-                       free(b);
-               } else {
-                       /* Don't send the key press event for the binding key */
-                       return;
-               }
-       }
-       if (!wl_list_empty(&keyboard->focus_resource_list)) {
-               serial = wl_display_next_serial(display);
-               wl_resource_for_each(resource, &keyboard->focus_resource_list) {
-                       wl_keyboard_send_key(resource,
-                                            serial,
-                                            time,
-                                            key,
-                                            state);
-               }
-       }
-}
-
-static void
-binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
-                 uint32_t mods_depressed, uint32_t mods_latched,
-                 uint32_t mods_locked, uint32_t group)
-{
-       struct wl_resource *resource;
-
-       wl_resource_for_each(resource, &grab->keyboard->focus_resource_list) {
-               wl_keyboard_send_modifiers(resource, serial, mods_depressed,
-                                          mods_latched, mods_locked, group);
-       }
-}
-
-static void
-binding_cancel(struct weston_keyboard_grab *grab)
-{
-       struct binding_keyboard_grab *binding_grab =
-               container_of(grab, struct binding_keyboard_grab, grab);
-
-       weston_keyboard_end_grab(grab->keyboard);
-       free(binding_grab);
-}
-
-static const struct weston_keyboard_grab_interface binding_grab = {
-       binding_key,
-       binding_modifiers,
-       binding_cancel,
-};
-
-static void
-install_binding_grab(struct weston_keyboard *keyboard, uint32_t time,
-                    uint32_t key, struct weston_surface *focus)
-{
-       struct binding_keyboard_grab *grab;
-
-       grab = malloc(sizeof *grab);
-       grab->key = key;
-       grab->grab.interface = &binding_grab;
-       weston_keyboard_start_grab(keyboard, &grab->grab);
-
-       /* Notify the surface which had the focus before this binding
-        * triggered that we stole a keypress from under it, by forcing
-        * a wl_keyboard leave/enter pair. The enter event will contain
-        * the pressed key in the keys array, so the client will know
-        * the exact state of the keyboard.
-        * If the old focus surface is different than the new one it
-        * means it was changed in the binding handler, so it received
-        * the enter event already. */
-       if (focus && keyboard->focus == focus) {
-               weston_keyboard_set_focus(keyboard, NULL);
-               weston_keyboard_set_focus(keyboard, focus);
-       }
-}
-
-void
-weston_compositor_run_key_binding(struct weston_compositor *compositor,
-                                 struct weston_keyboard *keyboard,
-                                 uint32_t time, uint32_t key,
-                                 enum wl_keyboard_key_state state)
-{
-       struct weston_binding *b, *tmp;
-       struct weston_surface *focus;
-       struct weston_seat *seat = keyboard->seat;
-
-       if (state == WL_KEYBOARD_KEY_STATE_RELEASED)
-               return;
-
-       /* Invalidate all active modifier bindings. */
-       wl_list_for_each(b, &compositor->modifier_binding_list, link)
-               b->key = key;
-
-       wl_list_for_each_safe(b, tmp, &compositor->key_binding_list, link) {
-               if (b->key == key && b->modifier == seat->modifier_state) {
-                       weston_key_binding_handler_t handler = b->handler;
-                       focus = keyboard->focus;
-                       handler(keyboard, time, key, b->data);
-
-                       /* If this was a key binding and it didn't
-                        * install a keyboard grab, install one now to
-                        * swallow the key press. */
-                       if (keyboard->grab ==
-                           &keyboard->default_grab)
-                               install_binding_grab(keyboard,
-                                                    time,
-                                                    key,
-                                                    focus);
-               }
-       }
-}
-
-void
-weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
-                                      struct weston_keyboard *keyboard,
-                                      enum weston_keyboard_modifier modifier,
-                                      enum wl_keyboard_key_state state)
-{
-       struct weston_binding *b, *tmp;
-
-       if (keyboard->grab != &keyboard->default_grab)
-               return;
-
-       wl_list_for_each_safe(b, tmp, &compositor->modifier_binding_list, link) {
-               weston_modifier_binding_handler_t handler = b->handler;
-
-               if (b->modifier != modifier)
-                       continue;
-
-               /* Prime the modifier binding. */
-               if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-                       b->key = 0;
-                       continue;
-               }
-               /* Ignore the binding if a key was pressed in between. */
-               else if (b->key != 0) {
-                       return;
-               }
-
-               handler(keyboard, modifier, b->data);
-       }
-}
-
-void
-weston_compositor_run_button_binding(struct weston_compositor *compositor,
-                                    struct weston_pointer *pointer,
-                                    uint32_t time, uint32_t button,
-                                    enum wl_pointer_button_state state)
-{
-       struct weston_binding *b, *tmp;
-
-       if (state == WL_POINTER_BUTTON_STATE_RELEASED)
-               return;
-
-       /* Invalidate all active modifier bindings. */
-       wl_list_for_each(b, &compositor->modifier_binding_list, link)
-               b->key = button;
-
-       wl_list_for_each_safe(b, tmp, &compositor->button_binding_list, link) {
-               if (b->button == button &&
-                   b->modifier == pointer->seat->modifier_state) {
-                       weston_button_binding_handler_t handler = b->handler;
-                       handler(pointer, time, button, b->data);
-               }
-       }
-}
-
-void
-weston_compositor_run_touch_binding(struct weston_compositor *compositor,
-                                   struct weston_touch *touch, uint32_t time,
-                                   int touch_type)
-{
-       struct weston_binding *b, *tmp;
-
-       if (touch->num_tp != 1 || touch_type != WL_TOUCH_DOWN)
-               return;
-
-       wl_list_for_each_safe(b, tmp, &compositor->touch_binding_list, link) {
-               if (b->modifier == touch->seat->modifier_state) {
-                       weston_touch_binding_handler_t handler = b->handler;
-                       handler(touch, time, b->data);
-               }
-       }
-}
-
-int
-weston_compositor_run_axis_binding(struct weston_compositor *compositor,
-                                  struct weston_pointer *pointer,
-                                  uint32_t time,
-                                  struct weston_pointer_axis_event *event)
-{
-       struct weston_binding *b, *tmp;
-
-       /* Invalidate all active modifier bindings. */
-       wl_list_for_each(b, &compositor->modifier_binding_list, link)
-               b->key = event->axis;
-
-       wl_list_for_each_safe(b, tmp, &compositor->axis_binding_list, link) {
-               if (b->axis == event->axis &&
-                   b->modifier == pointer->seat->modifier_state) {
-                       weston_axis_binding_handler_t handler = b->handler;
-                       handler(pointer, time, event, b->data);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
-
-int
-weston_compositor_run_debug_binding(struct weston_compositor *compositor,
-                                   struct weston_keyboard *keyboard,
-                                   uint32_t time, uint32_t key,
-                                   enum wl_keyboard_key_state state)
-{
-       weston_key_binding_handler_t handler;
-       struct weston_binding *binding, *tmp;
-       int count = 0;
-
-       wl_list_for_each_safe(binding, tmp, &compositor->debug_binding_list, link) {
-               if (key != binding->key)
-                       continue;
-
-               count++;
-               handler = binding->handler;
-               handler(keyboard, time, key, binding->data);
-       }
-
-       return count;
-}
-
-struct debug_binding_grab {
-       struct weston_keyboard_grab grab;
-       struct weston_seat *seat;
-       uint32_t key[2];
-       int key_released[2];
-};
-
-static void
-debug_binding_key(struct weston_keyboard_grab *grab, uint32_t time,
-                 uint32_t key, uint32_t state)
-{
-       struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
-       struct weston_compositor *ec = db->seat->compositor;
-       struct wl_display *display = ec->wl_display;
-       struct wl_resource *resource;
-       uint32_t serial;
-       int send = 0, terminate = 0;
-       int check_binding = 1;
-       int i;
-       struct wl_list *resource_list;
-
-       if (state == WL_KEYBOARD_KEY_STATE_RELEASED) {
-               /* Do not run bindings on key releases */
-               check_binding = 0;
-
-               for (i = 0; i < 2; i++)
-                       if (key == db->key[i])
-                               db->key_released[i] = 1;
-
-               if (db->key_released[0] && db->key_released[1]) {
-                       /* All key releases been swalled so end the grab */
-                       terminate = 1;
-               } else if (key != db->key[0] && key != db->key[1]) {
-                       /* Should not swallow release of other keys */
-                       send = 1;
-               }
-       } else if (key == db->key[0] && !db->key_released[0]) {
-               /* Do not check bindings for the first press of the binding
-                * key. This allows it to be used as a debug shortcut.
-                * We still need to swallow this event. */
-               check_binding = 0;
-       } else if (db->key[1]) {
-               /* If we already ran a binding don't process another one since
-                * we can't keep track of all the binding keys that were
-                * pressed in order to swallow the release events. */
-               send = 1;
-               check_binding = 0;
-       }
-
-       if (check_binding) {
-               if (weston_compositor_run_debug_binding(ec, grab->keyboard,
-                                                       time, key, state)) {
-                       /* We ran a binding so swallow the press and keep the
-                        * grab to swallow the released too. */
-                       send = 0;
-                       terminate = 0;
-                       db->key[1] = key;
-               } else {
-                       /* Terminate the grab since the key pressed is not a
-                        * debug binding key. */
-                       send = 1;
-                       terminate = 1;
-               }
-       }
-
-       if (send) {
-               serial = wl_display_next_serial(display);
-               resource_list = &grab->keyboard->focus_resource_list;
-               wl_resource_for_each(resource, resource_list) {
-                       wl_keyboard_send_key(resource, serial, time, key, state);
-               }
-       }
-
-       if (terminate) {
-               weston_keyboard_end_grab(grab->keyboard);
-               if (grab->keyboard->input_method_resource)
-                       grab->keyboard->grab = &grab->keyboard->input_method_grab;
-               free(db);
-       }
-}
-
-static void
-debug_binding_modifiers(struct weston_keyboard_grab *grab, uint32_t serial,
-                       uint32_t mods_depressed, uint32_t mods_latched,
-                       uint32_t mods_locked, uint32_t group)
-{
-       struct wl_resource *resource;
-       struct wl_list *resource_list;
-
-       resource_list = &grab->keyboard->focus_resource_list;
-
-       wl_resource_for_each(resource, resource_list) {
-               wl_keyboard_send_modifiers(resource, serial, mods_depressed,
-                                          mods_latched, mods_locked, group);
-       }
-}
-
-static void
-debug_binding_cancel(struct weston_keyboard_grab *grab)
-{
-       struct debug_binding_grab *db = (struct debug_binding_grab *) grab;
-
-       weston_keyboard_end_grab(grab->keyboard);
-       free(db);
-}
-
-struct weston_keyboard_grab_interface debug_binding_keyboard_grab = {
-       debug_binding_key,
-       debug_binding_modifiers,
-       debug_binding_cancel,
-};
-
-static void
-debug_binding(struct weston_keyboard *keyboard, uint32_t time,
-             uint32_t key, void *data)
-{
-       struct debug_binding_grab *grab;
-
-       grab = calloc(1, sizeof *grab);
-       if (!grab)
-               return;
-
-       grab->seat = keyboard->seat;
-       grab->key[0] = key;
-       grab->grab.interface = &debug_binding_keyboard_grab;
-       weston_keyboard_start_grab(keyboard, &grab->grab);
-}
-
-/** Install the trigger binding for debug bindings.
- *
- * \param compositor The compositor.
- * \param mod The modifier.
- *
- * This will add a key binding for modifier+SHIFT+SPACE that will trigger
- * debug key bindings.
- */
-WL_EXPORT void
-weston_install_debug_key_binding(struct weston_compositor *compositor,
-                                uint32_t mod)
-{
-       weston_compositor_add_key_binding(compositor, KEY_SPACE,
-                                         mod | MODIFIER_SHIFT,
-                                         debug_binding, NULL);
-}
diff --git a/src/clipboard.c b/src/clipboard.c
deleted file mode 100644 (file)
index 54a578f..0000000
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <linux/input.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/uio.h>
-
-#include "compositor.h"
-#include "shared/helpers.h"
-
-struct clipboard_source {
-       struct weston_data_source base;
-       struct wl_array contents;
-       struct clipboard *clipboard;
-       struct wl_event_source *event_source;
-       uint32_t serial;
-       int refcount;
-       int fd;
-};
-
-struct clipboard {
-       struct weston_seat *seat;
-       struct wl_listener selection_listener;
-       struct wl_listener destroy_listener;
-       struct clipboard_source *source;
-};
-
-static void clipboard_client_create(struct clipboard_source *source, int fd);
-
-static void
-clipboard_source_unref(struct clipboard_source *source)
-{
-       char **s;
-
-       source->refcount--;
-       if (source->refcount > 0)
-               return;
-
-       if (source->event_source) {
-               wl_event_source_remove(source->event_source);
-               close(source->fd);
-       }
-       wl_signal_emit(&source->base.destroy_signal,
-                      &source->base);
-       s = source->base.mime_types.data;
-       free(*s);
-       wl_array_release(&source->base.mime_types);
-       wl_array_release(&source->contents);
-       free(source);
-}
-
-static int
-clipboard_source_data(int fd, uint32_t mask, void *data)
-{
-       struct clipboard_source *source = data;
-       struct clipboard *clipboard = source->clipboard;
-       char *p;
-       int len, size;
-
-       if (source->contents.alloc - source->contents.size < 1024) {
-               wl_array_add(&source->contents, 1024);
-               source->contents.size -= 1024;
-       }
-
-       p = source->contents.data + source->contents.size;
-       size = source->contents.alloc - source->contents.size;
-       len = read(fd, p, size);
-       if (len == 0) {
-               wl_event_source_remove(source->event_source);
-               close(fd);
-               source->event_source = NULL;
-       } else if (len < 0) {
-               clipboard_source_unref(source);
-               clipboard->source = NULL;
-       } else {
-               source->contents.size += len;
-       }
-
-       return 1;
-}
-
-static void
-clipboard_source_accept(struct weston_data_source *source,
-                       uint32_t time, const char *mime_type)
-{
-}
-
-static void
-clipboard_source_send(struct weston_data_source *base,
-                     const char *mime_type, int32_t fd)
-{
-       struct clipboard_source *source =
-               container_of(base, struct clipboard_source, base);
-       char **s;
-
-       s = source->base.mime_types.data;
-       if (strcmp(mime_type, s[0]) == 0)
-               clipboard_client_create(source, fd);
-       else
-               close(fd);
-}
-
-static void
-clipboard_source_cancel(struct weston_data_source *source)
-{
-}
-
-static struct clipboard_source *
-clipboard_source_create(struct clipboard *clipboard,
-                       const char *mime_type, uint32_t serial, int fd)
-{
-       struct wl_display *display = clipboard->seat->compositor->wl_display;
-       struct wl_event_loop *loop = wl_display_get_event_loop(display);
-       struct clipboard_source *source;
-       char **s;
-
-       source = zalloc(sizeof *source);
-       if (source == NULL)
-               return NULL;
-
-       wl_array_init(&source->contents);
-       wl_array_init(&source->base.mime_types);
-       source->base.resource = NULL;
-       source->base.accept = clipboard_source_accept;
-       source->base.send = clipboard_source_send;
-       source->base.cancel = clipboard_source_cancel;
-       wl_signal_init(&source->base.destroy_signal);
-       source->refcount = 1;
-       source->clipboard = clipboard;
-       source->serial = serial;
-       source->fd = fd;
-
-       s = wl_array_add(&source->base.mime_types, sizeof *s);
-       if (s == NULL)
-               goto err_add;
-       *s = strdup(mime_type);
-       if (*s == NULL)
-               goto err_strdup;
-       source->event_source =
-               wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
-                                    clipboard_source_data, source);
-       if (source->event_source == NULL)
-               goto err_source;
-
-       return source;
-
- err_source:
-       free(*s);
- err_strdup:
-       wl_array_release(&source->base.mime_types);
- err_add:
-       free(source);
-
-       return NULL;
-}
-
-struct clipboard_client {
-       struct wl_event_source *event_source;
-       size_t offset;
-       struct clipboard_source *source;
-};
-
-static int
-clipboard_client_data(int fd, uint32_t mask, void *data)
-{
-       struct clipboard_client *client = data;
-       char *p;
-       size_t size;
-       int len;
-
-       size = client->source->contents.size;
-       p = client->source->contents.data;
-       len = write(fd, p + client->offset, size - client->offset);
-       if (len > 0)
-               client->offset += len;
-
-       if (client->offset == size || len <= 0) {
-               close(fd);
-               wl_event_source_remove(client->event_source);
-               clipboard_source_unref(client->source);
-               free(client);
-       }
-
-       return 1;
-}
-
-static void
-clipboard_client_create(struct clipboard_source *source, int fd)
-{
-       struct weston_seat *seat = source->clipboard->seat;
-       struct clipboard_client *client;
-       struct wl_event_loop *loop =
-               wl_display_get_event_loop(seat->compositor->wl_display);
-
-       client = zalloc(sizeof *client);
-       if (client == NULL)
-               return;
-
-       client->source = source;
-       source->refcount++;
-       client->event_source =
-               wl_event_loop_add_fd(loop, fd, WL_EVENT_WRITABLE,
-                                    clipboard_client_data, client);
-}
-
-static void
-clipboard_set_selection(struct wl_listener *listener, void *data)
-{
-       struct clipboard *clipboard =
-               container_of(listener, struct clipboard, selection_listener);
-       struct weston_seat *seat = data;
-       struct weston_data_source *source = seat->selection_data_source;
-       const char **mime_types;
-       int p[2];
-
-       if (source == NULL) {
-               if (clipboard->source)
-                       weston_seat_set_selection(seat,
-                                                 &clipboard->source->base,
-                                                 clipboard->source->serial);
-               return;
-       } else if (source->accept == clipboard_source_accept) {
-               /* Callback for our data source. */
-               return;
-       }
-
-       if (clipboard->source)
-               clipboard_source_unref(clipboard->source);
-
-       clipboard->source = NULL;
-
-       mime_types = source->mime_types.data;
-
-       if (!mime_types || pipe2(p, O_CLOEXEC) == -1)
-               return;
-
-       source->send(source, mime_types[0], p[1]);
-
-       clipboard->source =
-               clipboard_source_create(clipboard, mime_types[0],
-                                       seat->selection_serial, p[0]);
-       if (clipboard->source == NULL) {
-               close(p[0]);
-               return;
-       }
-}
-
-static void
-clipboard_destroy(struct wl_listener *listener, void *data)
-{
-       struct clipboard *clipboard =
-               container_of(listener, struct clipboard, destroy_listener);
-
-       wl_list_remove(&clipboard->selection_listener.link);
-       wl_list_remove(&clipboard->destroy_listener.link);
-
-       free(clipboard);
-}
-
-struct clipboard *
-clipboard_create(struct weston_seat *seat)
-{
-       struct clipboard *clipboard;
-
-       clipboard = zalloc(sizeof *clipboard);
-       if (clipboard == NULL)
-               return NULL;
-
-       clipboard->seat = seat;
-       clipboard->selection_listener.notify = clipboard_set_selection;
-       clipboard->destroy_listener.notify = clipboard_destroy;
-
-       wl_signal_add(&seat->selection_signal,
-                     &clipboard->selection_listener);
-       wl_signal_add(&seat->destroy_signal,
-                     &clipboard->destroy_listener);
-
-       return clipboard;
-}
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
deleted file mode 100644 (file)
index f903a3b..0000000
+++ /dev/null
@@ -1,3285 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/input.h>
-#include <linux/vt.h>
-#include <assert.h>
-#include <sys/mman.h>
-#include <dlfcn.h>
-#include <time.h>
-
-#include <xf86drm.h>
-#include <xf86drmMode.h>
-#include <drm_fourcc.h>
-
-#include <gbm.h>
-#include <libudev.h>
-
-#include "compositor.h"
-#include "compositor-drm.h"
-#include "shared/helpers.h"
-#include "shared/timespec-util.h"
-#include "gl-renderer.h"
-#include "pixman-renderer.h"
-#include "libbacklight.h"
-#include "libinput-seat.h"
-#include "launcher-util.h"
-#include "vaapi-recorder.h"
-#include "presentation-time-server-protocol.h"
-#include "linux-dmabuf.h"
-
-#ifndef DRM_CAP_TIMESTAMP_MONOTONIC
-#define DRM_CAP_TIMESTAMP_MONOTONIC 0x6
-#endif
-
-#ifndef DRM_CAP_CURSOR_WIDTH
-#define DRM_CAP_CURSOR_WIDTH 0x8
-#endif
-
-#ifndef DRM_CAP_CURSOR_HEIGHT
-#define DRM_CAP_CURSOR_HEIGHT 0x9
-#endif
-
-#ifndef GBM_BO_USE_CURSOR
-#define GBM_BO_USE_CURSOR GBM_BO_USE_CURSOR_64X64
-#endif
-
-struct drm_backend {
-       struct weston_backend base;
-       struct weston_compositor *compositor;
-
-       struct udev *udev;
-       struct wl_event_source *drm_source;
-
-       struct udev_monitor *udev_monitor;
-       struct wl_event_source *udev_drm_source;
-
-       struct {
-               int id;
-               int fd;
-               char *filename;
-       } drm;
-       struct gbm_device *gbm;
-       uint32_t *crtcs;
-       int num_crtcs;
-       uint32_t crtc_allocator;
-       uint32_t connector_allocator;
-       struct wl_listener session_listener;
-       uint32_t gbm_format;
-
-       /* we need these parameters in order to not fail drmModeAddFB2()
-        * due to out of bounds dimensions, and then mistakenly set
-        * sprites_are_broken:
-        */
-       uint32_t min_width, max_width;
-       uint32_t min_height, max_height;
-       int no_addfb2;
-
-       struct wl_list sprite_list;
-       int sprites_are_broken;
-       int sprites_hidden;
-
-       int cursors_are_broken;
-
-       int use_pixman;
-
-       uint32_t prev_state;
-
-       struct udev_input input;
-
-       int32_t cursor_width;
-       int32_t cursor_height;
-
-        /** Callback used to configure the outputs.
-        *
-         * This function will be called by the backend when a new DRM
-         * output needs to be configured.
-         */
-        enum weston_drm_backend_output_mode
-       (*configure_output)(struct weston_compositor *compositor,
-                           bool use_current_mode,
-                           const char *name,
-                           struct weston_drm_backend_output_config *output_config);
-       bool use_current_mode;
-};
-
-struct drm_mode {
-       struct weston_mode base;
-       drmModeModeInfo mode_info;
-};
-
-struct drm_fb {
-       uint32_t fb_id, stride, handle, size;
-       int fd;
-       int is_client_buffer;
-       struct weston_buffer_reference buffer_ref;
-
-       /* Used by gbm fbs */
-       struct gbm_bo *bo;
-
-       /* Used by dumb fbs */
-       void *map;
-};
-
-struct drm_edid {
-       char eisa_id[13];
-       char monitor_name[13];
-       char pnp_id[5];
-       char serial_number[13];
-};
-
-struct drm_output {
-       struct weston_output   base;
-
-       uint32_t crtc_id;
-       int pipe;
-       uint32_t connector_id;
-       drmModeCrtcPtr original_crtc;
-       struct drm_edid edid;
-       drmModePropertyPtr dpms_prop;
-       uint32_t gbm_format;
-
-       enum dpms_enum dpms;
-
-       int vblank_pending;
-       int page_flip_pending;
-       int destroy_pending;
-
-       struct gbm_surface *gbm_surface;
-       struct gbm_bo *gbm_cursor_bo[2];
-       struct weston_plane cursor_plane;
-       struct weston_plane fb_plane;
-       struct weston_view *cursor_view;
-       int current_cursor;
-       struct drm_fb *current, *next;
-       struct backlight *backlight;
-
-       struct drm_fb *dumb[2];
-       pixman_image_t *image[2];
-       int current_image;
-       pixman_region32_t previous_damage;
-
-       struct vaapi_recorder *recorder;
-       struct wl_listener recorder_frame_listener;
-};
-
-/*
- * An output has a primary display plane plus zero or more sprites for
- * blending display contents.
- */
-struct drm_sprite {
-       struct wl_list link;
-
-       struct weston_plane plane;
-
-       struct drm_fb *current, *next;
-       struct drm_output *output;
-       struct drm_backend *backend;
-
-       uint32_t possible_crtcs;
-       uint32_t plane_id;
-       uint32_t count_formats;
-
-       int32_t src_x, src_y;
-       uint32_t src_w, src_h;
-       uint32_t dest_x, dest_y;
-       uint32_t dest_w, dest_h;
-
-       uint32_t formats[];
-};
-
-static struct gl_renderer_interface *gl_renderer;
-
-static const char default_seat[] = "seat0";
-
-static void
-drm_output_set_cursor(struct drm_output *output);
-
-static void
-drm_output_update_msc(struct drm_output *output, unsigned int seq);
-
-static int
-drm_sprite_crtc_supported(struct drm_output *output, uint32_t supported)
-{
-       struct weston_compositor *ec = output->base.compositor;
-       struct drm_backend *b =(struct drm_backend *)ec->backend;
-       int crtc;
-
-       for (crtc = 0; crtc < b->num_crtcs; crtc++) {
-               if (b->crtcs[crtc] != output->crtc_id)
-                       continue;
-
-               if (supported & (1 << crtc))
-                       return -1;
-       }
-
-       return 0;
-}
-
-static void
-drm_fb_destroy_callback(struct gbm_bo *bo, void *data)
-{
-       struct drm_fb *fb = data;
-       struct gbm_device *gbm = gbm_bo_get_device(bo);
-
-       if (fb->fb_id)
-               drmModeRmFB(gbm_device_get_fd(gbm), fb->fb_id);
-
-       weston_buffer_reference(&fb->buffer_ref, NULL);
-
-       free(data);
-}
-
-static struct drm_fb *
-drm_fb_create_dumb(struct drm_backend *b, unsigned width, unsigned height,
-                  uint32_t format)
-{
-       struct drm_fb *fb;
-       int ret;
-       uint32_t bpp, depth;
-
-       struct drm_mode_create_dumb create_arg;
-       struct drm_mode_destroy_dumb destroy_arg;
-       struct drm_mode_map_dumb map_arg;
-
-       fb = zalloc(sizeof *fb);
-       if (!fb)
-               return NULL;
-
-       switch (format) {
-               case GBM_FORMAT_XRGB8888:
-                       bpp = 32;
-                       depth = 24;
-                       break;
-               case GBM_FORMAT_RGB565:
-                       bpp = depth = 16;
-                       break;
-               default:
-                       return NULL;
-       }
-
-       memset(&create_arg, 0, sizeof create_arg);
-       create_arg.bpp = bpp;
-       create_arg.width = width;
-       create_arg.height = height;
-
-       ret = drmIoctl(b->drm.fd, DRM_IOCTL_MODE_CREATE_DUMB, &create_arg);
-       if (ret)
-               goto err_fb;
-
-       fb->handle = create_arg.handle;
-       fb->stride = create_arg.pitch;
-       fb->size = create_arg.size;
-       fb->fd = b->drm.fd;
-
-       ret = -1;
-
-       if (!b->no_addfb2) {
-               uint32_t handles[4], pitches[4], offsets[4];
-
-               handles[0] = fb->handle;
-               pitches[0] = fb->stride;
-               offsets[0] = 0;
-
-               ret = drmModeAddFB2(b->drm.fd, width, height,
-                                   format, handles, pitches, offsets,
-                                   &fb->fb_id, 0);
-               if (ret) {
-                       weston_log("addfb2 failed: %m\n");
-                       b->no_addfb2 = 1;
-               }
-       }
-
-       if (ret) {
-               ret = drmModeAddFB(b->drm.fd, width, height, depth, bpp,
-                                  fb->stride, fb->handle, &fb->fb_id);
-       }
-
-       if (ret)
-               goto err_bo;
-
-       memset(&map_arg, 0, sizeof map_arg);
-       map_arg.handle = fb->handle;
-       ret = drmIoctl(fb->fd, DRM_IOCTL_MODE_MAP_DUMB, &map_arg);
-       if (ret)
-               goto err_add_fb;
-
-       fb->map = mmap(NULL, fb->size, PROT_WRITE,
-                      MAP_SHARED, b->drm.fd, map_arg.offset);
-       if (fb->map == MAP_FAILED)
-               goto err_add_fb;
-
-       return fb;
-
-err_add_fb:
-       drmModeRmFB(b->drm.fd, fb->fb_id);
-err_bo:
-       memset(&destroy_arg, 0, sizeof(destroy_arg));
-       destroy_arg.handle = create_arg.handle;
-       drmIoctl(b->drm.fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
-err_fb:
-       free(fb);
-       return NULL;
-}
-
-static void
-drm_fb_destroy_dumb(struct drm_fb *fb)
-{
-       struct drm_mode_destroy_dumb destroy_arg;
-
-       if (!fb->map)
-               return;
-
-       if (fb->fb_id)
-               drmModeRmFB(fb->fd, fb->fb_id);
-
-       weston_buffer_reference(&fb->buffer_ref, NULL);
-
-       munmap(fb->map, fb->size);
-
-       memset(&destroy_arg, 0, sizeof(destroy_arg));
-       destroy_arg.handle = fb->handle;
-       drmIoctl(fb->fd, DRM_IOCTL_MODE_DESTROY_DUMB, &destroy_arg);
-
-       free(fb);
-}
-
-static struct drm_fb *
-drm_fb_get_from_bo(struct gbm_bo *bo,
-                  struct drm_backend *backend, uint32_t format)
-{
-       struct drm_fb *fb = gbm_bo_get_user_data(bo);
-       uint32_t width, height;
-       uint32_t handles[4], pitches[4], offsets[4];
-       int ret;
-
-       if (fb)
-               return fb;
-
-       fb = zalloc(sizeof *fb);
-       if (fb == NULL)
-               return NULL;
-
-       fb->bo = bo;
-
-       width = gbm_bo_get_width(bo);
-       height = gbm_bo_get_height(bo);
-       fb->stride = gbm_bo_get_stride(bo);
-       fb->handle = gbm_bo_get_handle(bo).u32;
-       fb->size = fb->stride * height;
-       fb->fd = backend->drm.fd;
-
-       if (backend->min_width > width || width > backend->max_width ||
-           backend->min_height > height ||
-           height > backend->max_height) {
-               weston_log("bo geometry out of bounds\n");
-               goto err_free;
-       }
-
-       ret = -1;
-
-       if (format && !backend->no_addfb2) {
-               handles[0] = fb->handle;
-               pitches[0] = fb->stride;
-               offsets[0] = 0;
-
-               ret = drmModeAddFB2(backend->drm.fd, width, height,
-                                   format, handles, pitches, offsets,
-                                   &fb->fb_id, 0);
-               if (ret) {
-                       weston_log("addfb2 failed: %m\n");
-                       backend->no_addfb2 = 1;
-                       backend->sprites_are_broken = 1;
-               }
-       }
-
-       if (ret)
-               ret = drmModeAddFB(backend->drm.fd, width, height, 24, 32,
-                                  fb->stride, fb->handle, &fb->fb_id);
-
-       if (ret) {
-               weston_log("failed to create kms fb: %m\n");
-               goto err_free;
-       }
-
-       gbm_bo_set_user_data(bo, fb, drm_fb_destroy_callback);
-
-       return fb;
-
-err_free:
-       free(fb);
-       return NULL;
-}
-
-static void
-drm_fb_set_buffer(struct drm_fb *fb, struct weston_buffer *buffer)
-{
-       assert(fb->buffer_ref.buffer == NULL);
-
-       fb->is_client_buffer = 1;
-
-       weston_buffer_reference(&fb->buffer_ref, buffer);
-}
-
-static void
-drm_output_release_fb(struct drm_output *output, struct drm_fb *fb)
-{
-       if (!fb)
-               return;
-
-       if (fb->map &&
-            (fb != output->dumb[0] && fb != output->dumb[1])) {
-               drm_fb_destroy_dumb(fb);
-       } else if (fb->bo) {
-               if (fb->is_client_buffer)
-                       gbm_bo_destroy(fb->bo);
-               else
-                       gbm_surface_release_buffer(output->gbm_surface,
-                                                  fb->bo);
-       }
-}
-
-static uint32_t
-drm_output_check_scanout_format(struct drm_output *output,
-                               struct weston_surface *es, struct gbm_bo *bo)
-{
-       uint32_t format;
-       pixman_region32_t r;
-
-       format = gbm_bo_get_format(bo);
-
-       if (format == GBM_FORMAT_ARGB8888) {
-               /* We can scanout an ARGB buffer if the surface's
-                * opaque region covers the whole output, but we have
-                * to use XRGB as the KMS format code. */
-               pixman_region32_init_rect(&r, 0, 0,
-                                         output->base.width,
-                                         output->base.height);
-               pixman_region32_subtract(&r, &r, &es->opaque);
-
-               if (!pixman_region32_not_empty(&r))
-                       format = GBM_FORMAT_XRGB8888;
-
-               pixman_region32_fini(&r);
-       }
-
-       if (output->gbm_format == format)
-               return format;
-
-       return 0;
-}
-
-static struct weston_plane *
-drm_output_prepare_scanout_view(struct drm_output *output,
-                               struct weston_view *ev)
-{
-       struct drm_backend *b =
-               (struct drm_backend *)output->base.compositor->backend;
-       struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
-       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
-       struct gbm_bo *bo;
-       uint32_t format;
-
-       if (ev->geometry.x != output->base.x ||
-           ev->geometry.y != output->base.y ||
-           buffer == NULL || b->gbm == NULL ||
-           buffer->width != output->base.current_mode->width ||
-           buffer->height != output->base.current_mode->height ||
-           output->base.transform != viewport->buffer.transform ||
-           ev->transform.enabled)
-               return NULL;
-
-       if (ev->geometry.scissor_enabled)
-               return NULL;
-
-       bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
-                          buffer->resource, GBM_BO_USE_SCANOUT);
-
-       /* Unable to use the buffer for scanout */
-       if (!bo)
-               return NULL;
-
-       format = drm_output_check_scanout_format(output, ev->surface, bo);
-       if (format == 0) {
-               gbm_bo_destroy(bo);
-               return NULL;
-       }
-
-       output->next = drm_fb_get_from_bo(bo, b, format);
-       if (!output->next) {
-               gbm_bo_destroy(bo);
-               return NULL;
-       }
-
-       drm_fb_set_buffer(output->next, buffer);
-
-       return &output->fb_plane;
-}
-
-static void
-drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
-{
-       struct drm_backend *b =
-               (struct drm_backend *)output->base.compositor->backend;
-       struct gbm_bo *bo;
-
-       output->base.compositor->renderer->repaint_output(&output->base,
-                                                         damage);
-
-       bo = gbm_surface_lock_front_buffer(output->gbm_surface);
-       if (!bo) {
-               weston_log("failed to lock front buffer: %m\n");
-               return;
-       }
-
-       output->next = drm_fb_get_from_bo(bo, b, output->gbm_format);
-       if (!output->next) {
-               weston_log("failed to get drm_fb for bo\n");
-               gbm_surface_release_buffer(output->gbm_surface, bo);
-               return;
-       }
-}
-
-static void
-drm_output_render_pixman(struct drm_output *output, pixman_region32_t *damage)
-{
-       struct weston_compositor *ec = output->base.compositor;
-       pixman_region32_t total_damage, previous_damage;
-
-       pixman_region32_init(&total_damage);
-       pixman_region32_init(&previous_damage);
-
-       pixman_region32_copy(&previous_damage, damage);
-
-       pixman_region32_union(&total_damage, damage, &output->previous_damage);
-       pixman_region32_copy(&output->previous_damage, &previous_damage);
-
-       output->current_image ^= 1;
-
-       output->next = output->dumb[output->current_image];
-       pixman_renderer_output_set_buffer(&output->base,
-                                         output->image[output->current_image]);
-
-       ec->renderer->repaint_output(&output->base, &total_damage);
-
-       pixman_region32_fini(&total_damage);
-       pixman_region32_fini(&previous_damage);
-}
-
-static void
-drm_output_render(struct drm_output *output, pixman_region32_t *damage)
-{
-       struct weston_compositor *c = output->base.compositor;
-       struct drm_backend *b = (struct drm_backend *)c->backend;
-
-       if (b->use_pixman)
-               drm_output_render_pixman(output, damage);
-       else
-               drm_output_render_gl(output, damage);
-
-       pixman_region32_subtract(&c->primary_plane.damage,
-                                &c->primary_plane.damage, damage);
-}
-
-static void
-drm_output_set_gamma(struct weston_output *output_base,
-                    uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b)
-{
-       int rc;
-       struct drm_output *output = (struct drm_output *) output_base;
-       struct drm_backend *backend =
-               (struct drm_backend *) output->base.compositor->backend;
-
-       /* check */
-       if (output_base->gamma_size != size)
-               return;
-       if (!output->original_crtc)
-               return;
-
-       rc = drmModeCrtcSetGamma(backend->drm.fd,
-                                output->crtc_id,
-                                size, r, g, b);
-       if (rc)
-               weston_log("set gamma failed: %m\n");
-}
-
-/* Determine the type of vblank synchronization to use for the output.
- *
- * The pipe parameter indicates which CRTC is in use.  Knowing this, we
- * can determine which vblank sequence type to use for it.  Traditional
- * cards had only two CRTCs, with CRTC 0 using no special flags, and
- * CRTC 1 using DRM_VBLANK_SECONDARY.  The first bit of the pipe
- * parameter indicates this.
- *
- * Bits 1-5 of the pipe parameter are 5 bit wide pipe number between
- * 0-31.  If this is non-zero it indicates we're dealing with a
- * multi-gpu situation and we need to calculate the vblank sync
- * using DRM_BLANK_HIGH_CRTC_MASK.
- */
-static unsigned int
-drm_waitvblank_pipe(struct drm_output *output)
-{
-       if (output->pipe > 1)
-               return (output->pipe << DRM_VBLANK_HIGH_CRTC_SHIFT) &
-                               DRM_VBLANK_HIGH_CRTC_MASK;
-       else if (output->pipe > 0)
-               return DRM_VBLANK_SECONDARY;
-       else
-               return 0;
-}
-
-static int
-drm_output_repaint(struct weston_output *output_base,
-                  pixman_region32_t *damage)
-{
-       struct drm_output *output = (struct drm_output *) output_base;
-       struct drm_backend *backend =
-               (struct drm_backend *)output->base.compositor->backend;
-       struct drm_sprite *s;
-       struct drm_mode *mode;
-       int ret = 0;
-
-       if (output->destroy_pending)
-               return -1;
-
-       if (!output->next)
-               drm_output_render(output, damage);
-       if (!output->next)
-               return -1;
-
-       mode = container_of(output->base.current_mode, struct drm_mode, base);
-       if (!output->current ||
-           output->current->stride != output->next->stride) {
-               ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
-                                    output->next->fb_id, 0, 0,
-                                    &output->connector_id, 1,
-                                    &mode->mode_info);
-               if (ret) {
-                       weston_log("set mode failed: %m\n");
-                       goto err_pageflip;
-               }
-               output_base->set_dpms(output_base, WESTON_DPMS_ON);
-       }
-
-       if (drmModePageFlip(backend->drm.fd, output->crtc_id,
-                           output->next->fb_id,
-                           DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
-               weston_log("queueing pageflip failed: %m\n");
-               goto err_pageflip;
-       }
-
-       output->page_flip_pending = 1;
-
-       drm_output_set_cursor(output);
-
-       /*
-        * Now, update all the sprite surfaces
-        */
-       wl_list_for_each(s, &backend->sprite_list, link) {
-               uint32_t flags = 0, fb_id = 0;
-               drmVBlank vbl = {
-                       .request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT,
-                       .request.sequence = 1,
-               };
-
-               if ((!s->current && !s->next) ||
-                   !drm_sprite_crtc_supported(output, s->possible_crtcs))
-                       continue;
-
-               if (s->next && !backend->sprites_hidden)
-                       fb_id = s->next->fb_id;
-
-               ret = drmModeSetPlane(backend->drm.fd, s->plane_id,
-                                     output->crtc_id, fb_id, flags,
-                                     s->dest_x, s->dest_y,
-                                     s->dest_w, s->dest_h,
-                                     s->src_x, s->src_y,
-                                     s->src_w, s->src_h);
-               if (ret)
-                       weston_log("setplane failed: %d: %s\n",
-                               ret, strerror(errno));
-
-               vbl.request.type |= drm_waitvblank_pipe(output);
-
-               /*
-                * Queue a vblank signal so we know when the surface
-                * becomes active on the display or has been replaced.
-                */
-               vbl.request.signal = (unsigned long)s;
-               ret = drmWaitVBlank(backend->drm.fd, &vbl);
-               if (ret) {
-                       weston_log("vblank event request failed: %d: %s\n",
-                               ret, strerror(errno));
-               }
-
-               s->output = output;
-               output->vblank_pending = 1;
-       }
-
-       return 0;
-
-err_pageflip:
-       output->cursor_view = NULL;
-       if (output->next) {
-               drm_output_release_fb(output, output->next);
-               output->next = NULL;
-       }
-
-       return -1;
-}
-
-static void
-drm_output_start_repaint_loop(struct weston_output *output_base)
-{
-       struct drm_output *output = (struct drm_output *) output_base;
-       struct drm_backend *backend = (struct drm_backend *)
-               output_base->compositor->backend;
-       uint32_t fb_id;
-       struct timespec ts, tnow;
-       struct timespec vbl2now;
-       int64_t refresh_nsec;
-       int ret;
-       drmVBlank vbl = {
-               .request.type = DRM_VBLANK_RELATIVE,
-               .request.sequence = 0,
-               .request.signal = 0,
-       };
-
-       if (output->destroy_pending)
-               return;
-
-       if (!output->current) {
-               /* We can't page flip if there's no mode set */
-               goto finish_frame;
-       }
-
-       /* Try to get current msc and timestamp via instant query */
-       vbl.request.type |= drm_waitvblank_pipe(output);
-       ret = drmWaitVBlank(backend->drm.fd, &vbl);
-
-       /* Error ret or zero timestamp means failure to get valid timestamp */
-       if ((ret == 0) && (vbl.reply.tval_sec > 0 || vbl.reply.tval_usec > 0)) {
-               ts.tv_sec = vbl.reply.tval_sec;
-               ts.tv_nsec = vbl.reply.tval_usec * 1000;
-
-               /* Valid timestamp for most recent vblank - not stale?
-                * Stale ts could happen on Linux 3.17+, so make sure it
-                * is not older than 1 refresh duration since now.
-                */
-               weston_compositor_read_presentation_clock(backend->compositor,
-                                                         &tnow);
-               timespec_sub(&vbl2now, &tnow, &ts);
-               refresh_nsec =
-                       millihz_to_nsec(output->base.current_mode->refresh);
-               if (timespec_to_nsec(&vbl2now) < refresh_nsec) {
-                       drm_output_update_msc(output, vbl.reply.sequence);
-                       weston_output_finish_frame(output_base, &ts,
-                                               WP_PRESENTATION_FEEDBACK_INVALID);
-                       return;
-               }
-       }
-
-       /* Immediate query didn't provide valid timestamp.
-        * Use pageflip fallback.
-        */
-       fb_id = output->current->fb_id;
-
-       if (drmModePageFlip(backend->drm.fd, output->crtc_id, fb_id,
-                           DRM_MODE_PAGE_FLIP_EVENT, output) < 0) {
-               weston_log("queueing pageflip failed: %m\n");
-               goto finish_frame;
-       }
-
-       return;
-
-finish_frame:
-       /* if we cannot page-flip, immediately finish frame */
-       weston_compositor_read_presentation_clock(output_base->compositor, &ts);
-       weston_output_finish_frame(output_base, &ts,
-                                  WP_PRESENTATION_FEEDBACK_INVALID);
-}
-
-static void
-drm_output_update_msc(struct drm_output *output, unsigned int seq)
-{
-       uint64_t msc_hi = output->base.msc >> 32;
-
-       if (seq < (output->base.msc & 0xffffffff))
-               msc_hi++;
-
-       output->base.msc = (msc_hi << 32) + seq;
-}
-
-static void
-vblank_handler(int fd, unsigned int frame, unsigned int sec, unsigned int usec,
-              void *data)
-{
-       struct drm_sprite *s = (struct drm_sprite *)data;
-       struct drm_output *output = s->output;
-       struct timespec ts;
-       uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
-                        WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
-
-       drm_output_update_msc(output, frame);
-       output->vblank_pending = 0;
-
-       drm_output_release_fb(output, s->current);
-       s->current = s->next;
-       s->next = NULL;
-
-       if (!output->page_flip_pending) {
-               ts.tv_sec = sec;
-               ts.tv_nsec = usec * 1000;
-               weston_output_finish_frame(&output->base, &ts, flags);
-       }
-}
-
-static void
-drm_output_destroy(struct weston_output *output_base);
-
-static void
-page_flip_handler(int fd, unsigned int frame,
-                 unsigned int sec, unsigned int usec, void *data)
-{
-       struct drm_output *output = (struct drm_output *) data;
-       struct timespec ts;
-       uint32_t flags = WP_PRESENTATION_FEEDBACK_KIND_VSYNC |
-                        WP_PRESENTATION_FEEDBACK_KIND_HW_COMPLETION |
-                        WP_PRESENTATION_FEEDBACK_KIND_HW_CLOCK;
-
-       drm_output_update_msc(output, frame);
-
-       /* We don't set page_flip_pending on start_repaint_loop, in that case
-        * we just want to page flip to the current buffer to get an accurate
-        * timestamp */
-       if (output->page_flip_pending) {
-               drm_output_release_fb(output, output->current);
-               output->current = output->next;
-               output->next = NULL;
-       }
-
-       output->page_flip_pending = 0;
-
-       if (output->destroy_pending)
-               drm_output_destroy(&output->base);
-       else if (!output->vblank_pending) {
-               ts.tv_sec = sec;
-               ts.tv_nsec = usec * 1000;
-               weston_output_finish_frame(&output->base, &ts, flags);
-
-               /* We can't call this from frame_notify, because the output's
-                * repaint needed flag is cleared just after that */
-               if (output->recorder)
-                       weston_output_schedule_repaint(&output->base);
-       }
-}
-
-static uint32_t
-drm_output_check_sprite_format(struct drm_sprite *s,
-                              struct weston_view *ev, struct gbm_bo *bo)
-{
-       uint32_t i, format;
-
-       format = gbm_bo_get_format(bo);
-
-       if (format == GBM_FORMAT_ARGB8888) {
-               pixman_region32_t r;
-
-               pixman_region32_init_rect(&r, 0, 0,
-                                         ev->surface->width,
-                                         ev->surface->height);
-               pixman_region32_subtract(&r, &r, &ev->surface->opaque);
-
-               if (!pixman_region32_not_empty(&r))
-                       format = GBM_FORMAT_XRGB8888;
-
-               pixman_region32_fini(&r);
-       }
-
-       for (i = 0; i < s->count_formats; i++)
-               if (s->formats[i] == format)
-                       return format;
-
-       return 0;
-}
-
-static int
-drm_view_transform_supported(struct weston_view *ev)
-{
-       return !ev->transform.enabled ||
-               (ev->transform.matrix.type < WESTON_MATRIX_TRANSFORM_ROTATE);
-}
-
-static struct weston_plane *
-drm_output_prepare_overlay_view(struct drm_output *output,
-                               struct weston_view *ev)
-{
-       struct weston_compositor *ec = output->base.compositor;
-       struct drm_backend *b = (struct drm_backend *)ec->backend;
-       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
-       struct wl_resource *buffer_resource;
-       struct drm_sprite *s;
-       struct linux_dmabuf_buffer *dmabuf;
-       int found = 0;
-       struct gbm_bo *bo;
-       pixman_region32_t dest_rect, src_rect;
-       pixman_box32_t *box, tbox;
-       uint32_t format;
-       wl_fixed_t sx1, sy1, sx2, sy2;
-
-       if (b->gbm == NULL)
-               return NULL;
-
-       if (viewport->buffer.transform != output->base.transform)
-               return NULL;
-
-       if (viewport->buffer.scale != output->base.current_scale)
-               return NULL;
-
-       if (b->sprites_are_broken)
-               return NULL;
-
-       if (ev->output_mask != (1u << output->base.id))
-               return NULL;
-
-       if (ev->surface->buffer_ref.buffer == NULL)
-               return NULL;
-       buffer_resource = ev->surface->buffer_ref.buffer->resource;
-
-       if (ev->alpha != 1.0f)
-               return NULL;
-
-       if (wl_shm_buffer_get(buffer_resource))
-               return NULL;
-
-       if (!drm_view_transform_supported(ev))
-               return NULL;
-
-       wl_list_for_each(s, &b->sprite_list, link) {
-               if (!drm_sprite_crtc_supported(output, s->possible_crtcs))
-                       continue;
-
-               if (!s->next) {
-                       found = 1;
-                       break;
-               }
-       }
-
-       /* No sprites available */
-       if (!found)
-               return NULL;
-
-       if ((dmabuf = linux_dmabuf_buffer_get(buffer_resource))) {
-#ifdef HAVE_GBM_FD_IMPORT
-               /* XXX: TODO:
-                *
-                * Use AddFB2 directly, do not go via GBM.
-                * Add support for multiplanar formats.
-                * Both require refactoring in the DRM-backend to
-                * support a mix of gbm_bos and drmfbs.
-                */
-               struct gbm_import_fd_data gbm_dmabuf = {
-                       .fd     = dmabuf->attributes.fd[0],
-                       .width  = dmabuf->attributes.width,
-                       .height = dmabuf->attributes.height,
-                       .stride = dmabuf->attributes.stride[0],
-                       .format = dmabuf->attributes.format
-               };
-
-               if (dmabuf->attributes.n_planes != 1 || dmabuf->attributes.offset[0] != 0)
-                       return NULL;
-
-               bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_FD, &gbm_dmabuf,
-                                  GBM_BO_USE_SCANOUT);
-#else
-               return NULL;
-#endif
-       } else {
-               bo = gbm_bo_import(b->gbm, GBM_BO_IMPORT_WL_BUFFER,
-                                  buffer_resource, GBM_BO_USE_SCANOUT);
-       }
-       if (!bo)
-               return NULL;
-
-       format = drm_output_check_sprite_format(s, ev, bo);
-       if (format == 0) {
-               gbm_bo_destroy(bo);
-               return NULL;
-       }
-
-       s->next = drm_fb_get_from_bo(bo, b, format);
-       if (!s->next) {
-               gbm_bo_destroy(bo);
-               return NULL;
-       }
-
-       drm_fb_set_buffer(s->next, ev->surface->buffer_ref.buffer);
-
-       box = pixman_region32_extents(&ev->transform.boundingbox);
-       s->plane.x = box->x1;
-       s->plane.y = box->y1;
-
-       /*
-        * Calculate the source & dest rects properly based on actual
-        * position (note the caller has called weston_view_update_transform()
-        * for us already).
-        */
-       pixman_region32_init(&dest_rect);
-       pixman_region32_intersect(&dest_rect, &ev->transform.boundingbox,
-                                 &output->base.region);
-       pixman_region32_translate(&dest_rect, -output->base.x, -output->base.y);
-       box = pixman_region32_extents(&dest_rect);
-       tbox = weston_transformed_rect(output->base.width,
-                                      output->base.height,
-                                      output->base.transform,
-                                      output->base.current_scale,
-                                      *box);
-       s->dest_x = tbox.x1;
-       s->dest_y = tbox.y1;
-       s->dest_w = tbox.x2 - tbox.x1;
-       s->dest_h = tbox.y2 - tbox.y1;
-       pixman_region32_fini(&dest_rect);
-
-       pixman_region32_init(&src_rect);
-       pixman_region32_intersect(&src_rect, &ev->transform.boundingbox,
-                                 &output->base.region);
-       box = pixman_region32_extents(&src_rect);
-
-       weston_view_from_global_fixed(ev,
-                                     wl_fixed_from_int(box->x1),
-                                     wl_fixed_from_int(box->y1),
-                                     &sx1, &sy1);
-       weston_view_from_global_fixed(ev,
-                                     wl_fixed_from_int(box->x2),
-                                     wl_fixed_from_int(box->y2),
-                                     &sx2, &sy2);
-
-       if (sx1 < 0)
-               sx1 = 0;
-       if (sy1 < 0)
-               sy1 = 0;
-       if (sx2 > wl_fixed_from_int(ev->surface->width))
-               sx2 = wl_fixed_from_int(ev->surface->width);
-       if (sy2 > wl_fixed_from_int(ev->surface->height))
-               sy2 = wl_fixed_from_int(ev->surface->height);
-
-       tbox.x1 = sx1;
-       tbox.y1 = sy1;
-       tbox.x2 = sx2;
-       tbox.y2 = sy2;
-
-       tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
-                                      wl_fixed_from_int(ev->surface->height),
-                                      viewport->buffer.transform,
-                                      viewport->buffer.scale,
-                                      tbox);
-
-       s->src_x = tbox.x1 << 8;
-       s->src_y = tbox.y1 << 8;
-       s->src_w = (tbox.x2 - tbox.x1) << 8;
-       s->src_h = (tbox.y2 - tbox.y1) << 8;
-       pixman_region32_fini(&src_rect);
-
-       return &s->plane;
-}
-
-static struct weston_plane *
-drm_output_prepare_cursor_view(struct drm_output *output,
-                              struct weston_view *ev)
-{
-       struct drm_backend *b =
-               (struct drm_backend *)output->base.compositor->backend;
-       struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
-       struct wl_shm_buffer *shmbuf;
-
-       if (ev->transform.enabled &&
-           (ev->transform.matrix.type > WESTON_MATRIX_TRANSFORM_TRANSLATE))
-               return NULL;
-       if (b->gbm == NULL)
-               return NULL;
-       if (output->base.transform != WL_OUTPUT_TRANSFORM_NORMAL)
-               return NULL;
-       if (viewport->buffer.scale != output->base.current_scale)
-               return NULL;
-       if (output->cursor_view)
-               return NULL;
-       if (ev->output_mask != (1u << output->base.id))
-               return NULL;
-       if (b->cursors_are_broken)
-               return NULL;
-       if (ev->geometry.scissor_enabled)
-               return NULL;
-       if (ev->surface->buffer_ref.buffer == NULL)
-               return NULL;
-       shmbuf = wl_shm_buffer_get(ev->surface->buffer_ref.buffer->resource);
-       if (!shmbuf)
-               return NULL;
-       if (wl_shm_buffer_get_format(shmbuf) != WL_SHM_FORMAT_ARGB8888)
-               return NULL;
-       if (ev->surface->width > b->cursor_width ||
-           ev->surface->height > b->cursor_height)
-               return NULL;
-
-       output->cursor_view = ev;
-
-       return &output->cursor_plane;
-}
-
-/**
- * Update the image for the current cursor surface
- *
- * @param b DRM backend structure
- * @param bo GBM buffer object to write into
- * @param ev View to use for cursor image
- */
-static void
-cursor_bo_update(struct drm_backend *b, struct gbm_bo *bo,
-                struct weston_view *ev)
-{
-       struct weston_buffer *buffer = ev->surface->buffer_ref.buffer;
-       uint32_t buf[b->cursor_width * b->cursor_height];
-       int32_t stride;
-       uint8_t *s;
-       int i;
-
-       assert(buffer && buffer->shm_buffer);
-       assert(buffer->shm_buffer == wl_shm_buffer_get(buffer->resource));
-       assert(ev->surface->width <= b->cursor_width);
-       assert(ev->surface->height <= b->cursor_height);
-
-       memset(buf, 0, sizeof buf);
-       stride = wl_shm_buffer_get_stride(buffer->shm_buffer);
-       s = wl_shm_buffer_get_data(buffer->shm_buffer);
-
-       wl_shm_buffer_begin_access(buffer->shm_buffer);
-       for (i = 0; i < ev->surface->height; i++)
-               memcpy(buf + i * b->cursor_width,
-                      s + i * stride,
-                      ev->surface->width * 4);
-       wl_shm_buffer_end_access(buffer->shm_buffer);
-
-       if (gbm_bo_write(bo, buf, sizeof buf) < 0)
-               weston_log("failed update cursor: %m\n");
-}
-
-static void
-drm_output_set_cursor(struct drm_output *output)
-{
-       struct weston_view *ev = output->cursor_view;
-       struct weston_buffer *buffer;
-       struct drm_backend *b =
-               (struct drm_backend *) output->base.compositor->backend;
-       EGLint handle;
-       struct gbm_bo *bo;
-       float x, y;
-
-       output->cursor_view = NULL;
-       if (ev == NULL) {
-               drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
-               output->cursor_plane.x = INT32_MIN;
-               output->cursor_plane.y = INT32_MIN;
-               return;
-       }
-
-       buffer = ev->surface->buffer_ref.buffer;
-
-       if (buffer &&
-           pixman_region32_not_empty(&output->cursor_plane.damage)) {
-               pixman_region32_fini(&output->cursor_plane.damage);
-               pixman_region32_init(&output->cursor_plane.damage);
-               output->current_cursor ^= 1;
-               bo = output->gbm_cursor_bo[output->current_cursor];
-
-               cursor_bo_update(b, bo, ev);
-               handle = gbm_bo_get_handle(bo).s32;
-               if (drmModeSetCursor(b->drm.fd, output->crtc_id, handle,
-                               b->cursor_width, b->cursor_height)) {
-                       weston_log("failed to set cursor: %m\n");
-                       b->cursors_are_broken = 1;
-               }
-       }
-
-       weston_view_to_global_float(ev, 0, 0, &x, &y);
-
-       /* From global to output space, output transform is guaranteed to be
-        * NORMAL by drm_output_prepare_cursor_view().
-        */
-       x = (x - output->base.x) * output->base.current_scale;
-       y = (y - output->base.y) * output->base.current_scale;
-
-       if (output->cursor_plane.x != x || output->cursor_plane.y != y) {
-               if (drmModeMoveCursor(b->drm.fd, output->crtc_id, x, y)) {
-                       weston_log("failed to move cursor: %m\n");
-                       b->cursors_are_broken = 1;
-               }
-
-               output->cursor_plane.x = x;
-               output->cursor_plane.y = y;
-       }
-}
-
-static void
-drm_assign_planes(struct weston_output *output_base)
-{
-       struct drm_backend *b =
-               (struct drm_backend *)output_base->compositor->backend;
-       struct drm_output *output = (struct drm_output *)output_base;
-       struct weston_view *ev, *next;
-       pixman_region32_t overlap, surface_overlap;
-       struct weston_plane *primary, *next_plane;
-
-       /*
-        * Find a surface for each sprite in the output using some heuristics:
-        * 1) size
-        * 2) frequency of update
-        * 3) opacity (though some hw might support alpha blending)
-        * 4) clipping (this can be fixed with color keys)
-        *
-        * The idea is to save on blitting since this should save power.
-        * If we can get a large video surface on the sprite for example,
-        * the main display surface may not need to update at all, and
-        * the client buffer can be used directly for the sprite surface
-        * as we do for flipping full screen surfaces.
-        */
-       pixman_region32_init(&overlap);
-       primary = &output_base->compositor->primary_plane;
-
-       wl_list_for_each_safe(ev, next, &output_base->compositor->view_list, link) {
-               struct weston_surface *es = ev->surface;
-
-               /* Test whether this buffer can ever go into a plane:
-                * non-shm, or small enough to be a cursor.
-                *
-                * Also, keep a reference when using the pixman renderer.
-                * That makes it possible to do a seamless switch to the GL
-                * renderer and since the pixman renderer keeps a reference
-                * to the buffer anyway, there is no side effects.
-                */
-               if (b->use_pixman ||
-                   (es->buffer_ref.buffer &&
-                   (!wl_shm_buffer_get(es->buffer_ref.buffer->resource) ||
-                    (ev->surface->width <= b->cursor_width &&
-                     ev->surface->height <= b->cursor_height))))
-                       es->keep_buffer = true;
-               else
-                       es->keep_buffer = false;
-
-               pixman_region32_init(&surface_overlap);
-               pixman_region32_intersect(&surface_overlap, &overlap,
-                                         &ev->transform.boundingbox);
-
-               next_plane = NULL;
-               if (pixman_region32_not_empty(&surface_overlap))
-                       next_plane = primary;
-               if (next_plane == NULL)
-                       next_plane = drm_output_prepare_cursor_view(output, ev);
-               if (next_plane == NULL)
-                       next_plane = drm_output_prepare_scanout_view(output, ev);
-               if (next_plane == NULL)
-                       next_plane = drm_output_prepare_overlay_view(output, ev);
-               if (next_plane == NULL)
-                       next_plane = primary;
-
-               weston_view_move_to_plane(ev, next_plane);
-
-               if (next_plane == primary)
-                       pixman_region32_union(&overlap, &overlap,
-                                             &ev->transform.boundingbox);
-
-               if (next_plane == primary ||
-                   next_plane == &output->cursor_plane) {
-                       /* cursor plane involves a copy */
-                       ev->psf_flags = 0;
-               } else {
-                       /* All other planes are a direct scanout of a
-                        * single client buffer.
-                        */
-                       ev->psf_flags = WP_PRESENTATION_FEEDBACK_KIND_ZERO_COPY;
-               }
-
-               pixman_region32_fini(&surface_overlap);
-       }
-       pixman_region32_fini(&overlap);
-}
-
-static void
-drm_output_fini_pixman(struct drm_output *output);
-
-static void
-drm_output_destroy(struct weston_output *output_base)
-{
-       struct drm_output *output = (struct drm_output *) output_base;
-       struct drm_backend *b =
-               (struct drm_backend *)output->base.compositor->backend;
-       drmModeCrtcPtr origcrtc = output->original_crtc;
-
-       if (output->page_flip_pending) {
-               output->destroy_pending = 1;
-               weston_log("destroy output while page flip pending\n");
-               return;
-       }
-
-       if (output->backlight)
-               backlight_destroy(output->backlight);
-
-       drmModeFreeProperty(output->dpms_prop);
-
-       /* Turn off hardware cursor */
-       drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
-
-       /* Restore original CRTC state */
-       drmModeSetCrtc(b->drm.fd, origcrtc->crtc_id, origcrtc->buffer_id,
-                      origcrtc->x, origcrtc->y,
-                      &output->connector_id, 1, &origcrtc->mode);
-       drmModeFreeCrtc(origcrtc);
-
-       b->crtc_allocator &= ~(1 << output->crtc_id);
-       b->connector_allocator &= ~(1 << output->connector_id);
-
-       if (b->use_pixman) {
-               drm_output_fini_pixman(output);
-       } else {
-               gl_renderer->output_destroy(output_base);
-               gbm_surface_destroy(output->gbm_surface);
-       }
-
-       weston_plane_release(&output->fb_plane);
-       weston_plane_release(&output->cursor_plane);
-
-       weston_output_destroy(&output->base);
-
-       free(output);
-}
-
-/**
- * Find the closest-matching mode for a given target
- *
- * Given a target mode, find the most suitable mode amongst the output's
- * current mode list to use, preferring the current mode if possible, to
- * avoid an expensive mode switch.
- *
- * @param output DRM output
- * @param target_mode Mode to attempt to match
- * @returns Pointer to a mode from the output's mode list
- */
-static struct drm_mode *
-choose_mode (struct drm_output *output, struct weston_mode *target_mode)
-{
-       struct drm_mode *tmp_mode = NULL, *mode;
-
-       if (output->base.current_mode->width == target_mode->width &&
-           output->base.current_mode->height == target_mode->height &&
-           (output->base.current_mode->refresh == target_mode->refresh ||
-            target_mode->refresh == 0))
-               return (struct drm_mode *)output->base.current_mode;
-
-       wl_list_for_each(mode, &output->base.mode_list, base.link) {
-               if (mode->mode_info.hdisplay == target_mode->width &&
-                   mode->mode_info.vdisplay == target_mode->height) {
-                       if (mode->base.refresh == target_mode->refresh ||
-                           target_mode->refresh == 0) {
-                               return mode;
-                       } else if (!tmp_mode)
-                               tmp_mode = mode;
-               }
-       }
-
-       return tmp_mode;
-}
-
-static int
-drm_output_init_egl(struct drm_output *output, struct drm_backend *b);
-static int
-drm_output_init_pixman(struct drm_output *output, struct drm_backend *b);
-
-static int
-drm_output_switch_mode(struct weston_output *output_base, struct weston_mode *mode)
-{
-       struct drm_output *output;
-       struct drm_mode *drm_mode;
-       struct drm_backend *b;
-
-       if (output_base == NULL) {
-               weston_log("output is NULL.\n");
-               return -1;
-       }
-
-       if (mode == NULL) {
-               weston_log("mode is NULL.\n");
-               return -1;
-       }
-
-       b = (struct drm_backend *)output_base->compositor->backend;
-       output = (struct drm_output *)output_base;
-       drm_mode  = choose_mode (output, mode);
-
-       if (!drm_mode) {
-               weston_log("%s, invalid resolution:%dx%d\n", __func__, mode->width, mode->height);
-               return -1;
-       }
-
-       if (&drm_mode->base == output->base.current_mode)
-               return 0;
-
-       output->base.current_mode->flags = 0;
-
-       output->base.current_mode = &drm_mode->base;
-       output->base.current_mode->flags =
-               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-
-       /* reset rendering stuff. */
-       drm_output_release_fb(output, output->current);
-       drm_output_release_fb(output, output->next);
-       output->current = output->next = NULL;
-
-       if (b->use_pixman) {
-               drm_output_fini_pixman(output);
-               if (drm_output_init_pixman(output, b) < 0) {
-                       weston_log("failed to init output pixman state with "
-                                  "new mode\n");
-                       return -1;
-               }
-       } else {
-               gl_renderer->output_destroy(&output->base);
-               gbm_surface_destroy(output->gbm_surface);
-
-               if (drm_output_init_egl(output, b) < 0) {
-                       weston_log("failed to init output egl state with "
-                                  "new mode");
-                       return -1;
-               }
-       }
-
-       return 0;
-}
-
-static int
-on_drm_input(int fd, uint32_t mask, void *data)
-{
-       drmEventContext evctx;
-
-       memset(&evctx, 0, sizeof evctx);
-       evctx.version = DRM_EVENT_CONTEXT_VERSION;
-       evctx.page_flip_handler = page_flip_handler;
-       evctx.vblank_handler = vblank_handler;
-       drmHandleEvent(fd, &evctx);
-
-       return 1;
-}
-
-static int
-init_drm(struct drm_backend *b, struct udev_device *device)
-{
-       const char *filename, *sysnum;
-       uint64_t cap;
-       int fd, ret;
-       clockid_t clk_id;
-
-       sysnum = udev_device_get_sysnum(device);
-       if (sysnum)
-               b->drm.id = atoi(sysnum);
-       if (!sysnum || b->drm.id < 0) {
-               weston_log("cannot get device sysnum\n");
-               return -1;
-       }
-
-       filename = udev_device_get_devnode(device);
-       fd = weston_launcher_open(b->compositor->launcher, filename, O_RDWR);
-       if (fd < 0) {
-               /* Probably permissions error */
-               weston_log("couldn't open %s, skipping\n",
-                       udev_device_get_devnode(device));
-               return -1;
-       }
-
-       weston_log("using %s\n", filename);
-
-       b->drm.fd = fd;
-       b->drm.filename = strdup(filename);
-
-       ret = drmGetCap(fd, DRM_CAP_TIMESTAMP_MONOTONIC, &cap);
-       if (ret == 0 && cap == 1)
-               clk_id = CLOCK_MONOTONIC;
-       else
-               clk_id = CLOCK_REALTIME;
-
-       if (weston_compositor_set_presentation_clock(b->compositor, clk_id) < 0) {
-               weston_log("Error: failed to set presentation clock %d.\n",
-                          clk_id);
-               return -1;
-       }
-
-       ret = drmGetCap(fd, DRM_CAP_CURSOR_WIDTH, &cap);
-       if (ret == 0)
-               b->cursor_width = cap;
-       else
-               b->cursor_width = 64;
-
-       ret = drmGetCap(fd, DRM_CAP_CURSOR_HEIGHT, &cap);
-       if (ret == 0)
-               b->cursor_height = cap;
-       else
-               b->cursor_height = 64;
-
-       return 0;
-}
-
-static struct gbm_device *
-create_gbm_device(int fd)
-{
-       struct gbm_device *gbm;
-
-       gl_renderer = weston_load_module("gl-renderer.so",
-                                        "gl_renderer_interface");
-       if (!gl_renderer)
-               return NULL;
-
-       /* GBM will load a dri driver, but even though they need symbols from
-        * libglapi, in some version of Mesa they are not linked to it. Since
-        * only the gl-renderer module links to it, the call above won't make
-        * these symbols globally available, and loading the DRI driver fails.
-        * Workaround this by dlopen()'ing libglapi with RTLD_GLOBAL. */
-       dlopen("libglapi.so.0", RTLD_LAZY | RTLD_GLOBAL);
-
-       gbm = gbm_create_device(fd);
-
-       return gbm;
-}
-
-/* When initializing EGL, if the preferred buffer format isn't available
- * we may be able to substitute an ARGB format for an XRGB one.
- *
- * This returns 0 if substitution isn't possible, but 0 might be a
- * legitimate format for other EGL platforms, so the caller is
- * responsible for checking for 0 before calling gl_renderer->create().
- *
- * This works around https://bugs.freedesktop.org/show_bug.cgi?id=89689
- * but it's entirely possible we'll see this again on other implementations.
- */
-static int
-fallback_format_for(uint32_t format)
-{
-       switch (format) {
-       case GBM_FORMAT_XRGB8888:
-               return GBM_FORMAT_ARGB8888;
-       case GBM_FORMAT_XRGB2101010:
-               return GBM_FORMAT_ARGB2101010;
-       default:
-               return 0;
-       }
-}
-
-static int
-drm_backend_create_gl_renderer(struct drm_backend *b)
-{
-       EGLint format[3] = {
-               b->gbm_format,
-               fallback_format_for(b->gbm_format),
-               0,
-       };
-       int n_formats = 2;
-
-       if (format[1])
-               n_formats = 3;
-       if (gl_renderer->create(b->compositor,
-                               EGL_PLATFORM_GBM_KHR,
-                               (void *)b->gbm,
-                               gl_renderer->opaque_attribs,
-                               format,
-                               n_formats) < 0) {
-               return -1;
-       }
-
-       return 0;
-}
-
-static int
-init_egl(struct drm_backend *b)
-{
-       b->gbm = create_gbm_device(b->drm.fd);
-
-       if (!b->gbm)
-               return -1;
-
-       if (drm_backend_create_gl_renderer(b) < 0) {
-               gbm_device_destroy(b->gbm);
-               return -1;
-       }
-
-       return 0;
-}
-
-static int
-init_pixman(struct drm_backend *b)
-{
-       return pixman_renderer_init(b->compositor);
-}
-
-/**
- * Add a mode to output's mode list
- *
- * Copy the supplied DRM mode into a Weston mode structure, and add it to the
- * output's mode list.
- *
- * @param output DRM output to add mode to
- * @param info DRM mode structure to add
- * @returns Newly-allocated Weston/DRM mode structure
- */
-static struct drm_mode *
-drm_output_add_mode(struct drm_output *output, const drmModeModeInfo *info)
-{
-       struct drm_mode *mode;
-       uint64_t refresh;
-
-       mode = malloc(sizeof *mode);
-       if (mode == NULL)
-               return NULL;
-
-       mode->base.flags = 0;
-       mode->base.width = info->hdisplay;
-       mode->base.height = info->vdisplay;
-
-       /* Calculate higher precision (mHz) refresh rate */
-       refresh = (info->clock * 1000000LL / info->htotal +
-                  info->vtotal / 2) / info->vtotal;
-
-       if (info->flags & DRM_MODE_FLAG_INTERLACE)
-               refresh *= 2;
-       if (info->flags & DRM_MODE_FLAG_DBLSCAN)
-               refresh /= 2;
-       if (info->vscan > 1)
-           refresh /= info->vscan;
-
-       mode->base.refresh = refresh;
-       mode->mode_info = *info;
-
-       if (info->type & DRM_MODE_TYPE_PREFERRED)
-               mode->base.flags |= WL_OUTPUT_MODE_PREFERRED;
-
-       wl_list_insert(output->base.mode_list.prev, &mode->base.link);
-
-       return mode;
-}
-
-static int
-drm_subpixel_to_wayland(int drm_value)
-{
-       switch (drm_value) {
-       default:
-       case DRM_MODE_SUBPIXEL_UNKNOWN:
-               return WL_OUTPUT_SUBPIXEL_UNKNOWN;
-       case DRM_MODE_SUBPIXEL_NONE:
-               return WL_OUTPUT_SUBPIXEL_NONE;
-       case DRM_MODE_SUBPIXEL_HORIZONTAL_RGB:
-               return WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB;
-       case DRM_MODE_SUBPIXEL_HORIZONTAL_BGR:
-               return WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR;
-       case DRM_MODE_SUBPIXEL_VERTICAL_RGB:
-               return WL_OUTPUT_SUBPIXEL_VERTICAL_RGB;
-       case DRM_MODE_SUBPIXEL_VERTICAL_BGR:
-               return WL_OUTPUT_SUBPIXEL_VERTICAL_BGR;
-       }
-}
-
-/* returns a value between 0-255 range, where higher is brighter */
-static uint32_t
-drm_get_backlight(struct drm_output *output)
-{
-       long brightness, max_brightness, norm;
-
-       brightness = backlight_get_brightness(output->backlight);
-       max_brightness = backlight_get_max_brightness(output->backlight);
-
-       /* convert it on a scale of 0 to 255 */
-       norm = (brightness * 255)/(max_brightness);
-
-       return (uint32_t) norm;
-}
-
-/* values accepted are between 0-255 range */
-static void
-drm_set_backlight(struct weston_output *output_base, uint32_t value)
-{
-       struct drm_output *output = (struct drm_output *) output_base;
-       long max_brightness, new_brightness;
-
-       if (!output->backlight)
-               return;
-
-       if (value > 255)
-               return;
-
-       max_brightness = backlight_get_max_brightness(output->backlight);
-
-       /* get denormalized value */
-       new_brightness = (value * max_brightness) / 255;
-
-       backlight_set_brightness(output->backlight, new_brightness);
-}
-
-static drmModePropertyPtr
-drm_get_prop(int fd, drmModeConnectorPtr connector, const char *name)
-{
-       drmModePropertyPtr props;
-       int i;
-
-       for (i = 0; i < connector->count_props; i++) {
-               props = drmModeGetProperty(fd, connector->props[i]);
-               if (!props)
-                       continue;
-
-               if (!strcmp(props->name, name))
-                       return props;
-
-               drmModeFreeProperty(props);
-       }
-
-       return NULL;
-}
-
-static void
-drm_set_dpms(struct weston_output *output_base, enum dpms_enum level)
-{
-       struct drm_output *output = (struct drm_output *) output_base;
-       struct weston_compositor *ec = output_base->compositor;
-       struct drm_backend *b = (struct drm_backend *)ec->backend;
-       int ret;
-
-       if (!output->dpms_prop)
-               return;
-
-       ret = drmModeConnectorSetProperty(b->drm.fd, output->connector_id,
-                                         output->dpms_prop->prop_id, level);
-       if (ret) {
-               weston_log("DRM: DPMS: failed property set for %s\n",
-                          output->base.name);
-               return;
-       }
-
-       output->dpms = level;
-}
-
-static const char * const connector_type_names[] = {
-       [DRM_MODE_CONNECTOR_Unknown]     = "Unknown",
-       [DRM_MODE_CONNECTOR_VGA]         = "VGA",
-       [DRM_MODE_CONNECTOR_DVII]        = "DVI-I",
-       [DRM_MODE_CONNECTOR_DVID]        = "DVI-D",
-       [DRM_MODE_CONNECTOR_DVIA]        = "DVI-A",
-       [DRM_MODE_CONNECTOR_Composite]   = "Composite",
-       [DRM_MODE_CONNECTOR_SVIDEO]      = "SVIDEO",
-       [DRM_MODE_CONNECTOR_LVDS]        = "LVDS",
-       [DRM_MODE_CONNECTOR_Component]   = "Component",
-       [DRM_MODE_CONNECTOR_9PinDIN]     = "DIN",
-       [DRM_MODE_CONNECTOR_DisplayPort] = "DP",
-       [DRM_MODE_CONNECTOR_HDMIA]       = "HDMI-A",
-       [DRM_MODE_CONNECTOR_HDMIB]       = "HDMI-B",
-       [DRM_MODE_CONNECTOR_TV]          = "TV",
-       [DRM_MODE_CONNECTOR_eDP]         = "eDP",
-#ifdef DRM_MODE_CONNECTOR_DSI
-       [DRM_MODE_CONNECTOR_VIRTUAL]     = "Virtual",
-       [DRM_MODE_CONNECTOR_DSI]         = "DSI",
-#endif
-};
-
-static char *
-make_connector_name(const drmModeConnector *con)
-{
-       char name[32];
-       const char *type_name = NULL;
-
-       if (con->connector_type < ARRAY_LENGTH(connector_type_names))
-               type_name = connector_type_names[con->connector_type];
-
-       if (!type_name)
-               type_name = "UNNAMED";
-
-       snprintf(name, sizeof name, "%s-%d", type_name, con->connector_type_id);
-
-       return strdup(name);
-}
-
-static int
-find_crtc_for_connector(struct drm_backend *b,
-                       drmModeRes *resources, drmModeConnector *connector)
-{
-       drmModeEncoder *encoder;
-       uint32_t possible_crtcs;
-       int i, j;
-
-       for (j = 0; j < connector->count_encoders; j++) {
-               encoder = drmModeGetEncoder(b->drm.fd, connector->encoders[j]);
-               if (encoder == NULL) {
-                       weston_log("Failed to get encoder.\n");
-                       return -1;
-               }
-               possible_crtcs = encoder->possible_crtcs;
-               drmModeFreeEncoder(encoder);
-
-               for (i = 0; i < resources->count_crtcs; i++) {
-                       if (possible_crtcs & (1 << i) &&
-                           !(b->crtc_allocator & (1 << resources->crtcs[i])))
-                               return i;
-               }
-       }
-
-       return -1;
-}
-
-/* Init output state that depends on gl or gbm */
-static int
-drm_output_init_egl(struct drm_output *output, struct drm_backend *b)
-{
-       EGLint format[2] = {
-               output->gbm_format,
-               fallback_format_for(output->gbm_format),
-       };
-       int i, flags, n_formats = 1;
-
-       output->gbm_surface = gbm_surface_create(b->gbm,
-                                            output->base.current_mode->width,
-                                            output->base.current_mode->height,
-                                            format[0],
-                                            GBM_BO_USE_SCANOUT |
-                                            GBM_BO_USE_RENDERING);
-       if (!output->gbm_surface) {
-               weston_log("failed to create gbm surface\n");
-               return -1;
-       }
-
-       if (format[1])
-               n_formats = 2;
-       if (gl_renderer->output_create(&output->base,
-                                      (EGLNativeWindowType)output->gbm_surface,
-                                      output->gbm_surface,
-                                      gl_renderer->opaque_attribs,
-                                      format,
-                                      n_formats) < 0) {
-               weston_log("failed to create gl renderer output state\n");
-               gbm_surface_destroy(output->gbm_surface);
-               return -1;
-       }
-
-       flags = GBM_BO_USE_CURSOR | GBM_BO_USE_WRITE;
-
-       for (i = 0; i < 2; i++) {
-               if (output->gbm_cursor_bo[i])
-                       continue;
-
-               output->gbm_cursor_bo[i] =
-                       gbm_bo_create(b->gbm, b->cursor_width, b->cursor_height,
-                               GBM_FORMAT_ARGB8888, flags);
-       }
-
-       if (output->gbm_cursor_bo[0] == NULL || output->gbm_cursor_bo[1] == NULL) {
-               weston_log("cursor buffers unavailable, using gl cursors\n");
-               b->cursors_are_broken = 1;
-       }
-
-       return 0;
-}
-
-static int
-drm_output_init_pixman(struct drm_output *output, struct drm_backend *b)
-{
-       int w = output->base.current_mode->width;
-       int h = output->base.current_mode->height;
-       uint32_t format = output->gbm_format;
-       uint32_t pixman_format;
-       unsigned int i;
-
-       switch (format) {
-               case GBM_FORMAT_XRGB8888:
-                       pixman_format = PIXMAN_x8r8g8b8;
-                       break;
-               case GBM_FORMAT_RGB565:
-                       pixman_format = PIXMAN_r5g6b5;
-                       break;
-               default:
-                       weston_log("Unsupported pixman format 0x%x\n", format);
-                       return -1;
-       }
-
-       /* FIXME error checking */
-       for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
-               output->dumb[i] = drm_fb_create_dumb(b, w, h, format);
-               if (!output->dumb[i])
-                       goto err;
-
-               output->image[i] =
-                       pixman_image_create_bits(pixman_format, w, h,
-                                                output->dumb[i]->map,
-                                                output->dumb[i]->stride);
-               if (!output->image[i])
-                       goto err;
-       }
-
-       if (pixman_renderer_output_create(&output->base) < 0)
-               goto err;
-
-       pixman_region32_init_rect(&output->previous_damage,
-                                 output->base.x, output->base.y, output->base.width, output->base.height);
-
-       return 0;
-
-err:
-       for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
-               if (output->dumb[i])
-                       drm_fb_destroy_dumb(output->dumb[i]);
-               if (output->image[i])
-                       pixman_image_unref(output->image[i]);
-
-               output->dumb[i] = NULL;
-               output->image[i] = NULL;
-       }
-
-       return -1;
-}
-
-static void
-drm_output_fini_pixman(struct drm_output *output)
-{
-       unsigned int i;
-
-       pixman_renderer_output_destroy(&output->base);
-       pixman_region32_fini(&output->previous_damage);
-
-       for (i = 0; i < ARRAY_LENGTH(output->dumb); i++) {
-               drm_fb_destroy_dumb(output->dumb[i]);
-               pixman_image_unref(output->image[i]);
-               output->dumb[i] = NULL;
-               output->image[i] = NULL;
-       }
-}
-
-static void
-edid_parse_string(const uint8_t *data, char text[])
-{
-       int i;
-       int replaced = 0;
-
-       /* this is always 12 bytes, but we can't guarantee it's null
-        * terminated or not junk. */
-       strncpy(text, (const char *) data, 12);
-
-       /* guarantee our new string is null-terminated */
-       text[12] = '\0';
-
-       /* remove insane chars */
-       for (i = 0; text[i] != '\0'; i++) {
-               if (text[i] == '\n' ||
-                   text[i] == '\r') {
-                       text[i] = '\0';
-                       break;
-               }
-       }
-
-       /* ensure string is printable */
-       for (i = 0; text[i] != '\0'; i++) {
-               if (!isprint(text[i])) {
-                       text[i] = '-';
-                       replaced++;
-               }
-       }
-
-       /* if the string is random junk, ignore the string */
-       if (replaced > 4)
-               text[0] = '\0';
-}
-
-#define EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING       0xfe
-#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME           0xfc
-#define EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER  0xff
-#define EDID_OFFSET_DATA_BLOCKS                                0x36
-#define EDID_OFFSET_LAST_BLOCK                         0x6c
-#define EDID_OFFSET_PNPID                              0x08
-#define EDID_OFFSET_SERIAL                             0x0c
-
-static int
-edid_parse(struct drm_edid *edid, const uint8_t *data, size_t length)
-{
-       int i;
-       uint32_t serial_number;
-
-       /* check header */
-       if (length < 128)
-               return -1;
-       if (data[0] != 0x00 || data[1] != 0xff)
-               return -1;
-
-       /* decode the PNP ID from three 5 bit words packed into 2 bytes
-        * /--08--\/--09--\
-        * 7654321076543210
-        * |\---/\---/\---/
-        * R  C1   C2   C3 */
-       edid->pnp_id[0] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x7c) / 4) - 1;
-       edid->pnp_id[1] = 'A' + ((data[EDID_OFFSET_PNPID + 0] & 0x3) * 8) + ((data[EDID_OFFSET_PNPID + 1] & 0xe0) / 32) - 1;
-       edid->pnp_id[2] = 'A' + (data[EDID_OFFSET_PNPID + 1] & 0x1f) - 1;
-       edid->pnp_id[3] = '\0';
-
-       /* maybe there isn't a ASCII serial number descriptor, so use this instead */
-       serial_number = (uint32_t) data[EDID_OFFSET_SERIAL + 0];
-       serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 1] * 0x100;
-       serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 2] * 0x10000;
-       serial_number += (uint32_t) data[EDID_OFFSET_SERIAL + 3] * 0x1000000;
-       if (serial_number > 0)
-               sprintf(edid->serial_number, "%lu", (unsigned long) serial_number);
-
-       /* parse EDID data */
-       for (i = EDID_OFFSET_DATA_BLOCKS;
-            i <= EDID_OFFSET_LAST_BLOCK;
-            i += 18) {
-               /* ignore pixel clock data */
-               if (data[i] != 0)
-                       continue;
-               if (data[i+2] != 0)
-                       continue;
-
-               /* any useful blocks? */
-               if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_NAME) {
-                       edid_parse_string(&data[i+5],
-                                         edid->monitor_name);
-               } else if (data[i+3] == EDID_DESCRIPTOR_DISPLAY_PRODUCT_SERIAL_NUMBER) {
-                       edid_parse_string(&data[i+5],
-                                         edid->serial_number);
-               } else if (data[i+3] == EDID_DESCRIPTOR_ALPHANUMERIC_DATA_STRING) {
-                       edid_parse_string(&data[i+5],
-                                         edid->eisa_id);
-               }
-       }
-       return 0;
-}
-
-static void
-find_and_parse_output_edid(struct drm_backend *b,
-                          struct drm_output *output,
-                          drmModeConnector *connector)
-{
-       drmModePropertyBlobPtr edid_blob = NULL;
-       drmModePropertyPtr property;
-       int i;
-       int rc;
-
-       for (i = 0; i < connector->count_props && !edid_blob; i++) {
-               property = drmModeGetProperty(b->drm.fd, connector->props[i]);
-               if (!property)
-                       continue;
-               if ((property->flags & DRM_MODE_PROP_BLOB) &&
-                   !strcmp(property->name, "EDID")) {
-                       edid_blob = drmModeGetPropertyBlob(b->drm.fd,
-                                                          connector->prop_values[i]);
-               }
-               drmModeFreeProperty(property);
-       }
-       if (!edid_blob)
-               return;
-
-       rc = edid_parse(&output->edid,
-                       edid_blob->data,
-                       edid_blob->length);
-       if (!rc) {
-               weston_log("EDID data '%s', '%s', '%s'\n",
-                          output->edid.pnp_id,
-                          output->edid.monitor_name,
-                          output->edid.serial_number);
-               if (output->edid.pnp_id[0] != '\0')
-                       output->base.make = output->edid.pnp_id;
-               if (output->edid.monitor_name[0] != '\0')
-                       output->base.model = output->edid.monitor_name;
-               if (output->edid.serial_number[0] != '\0')
-                       output->base.serial_number = output->edid.serial_number;
-       }
-       drmModeFreePropertyBlob(edid_blob);
-}
-
-
-
-static int
-parse_modeline(const char *s, drmModeModeInfo *mode)
-{
-       char hsync[16];
-       char vsync[16];
-       float fclock;
-
-       mode->type = DRM_MODE_TYPE_USERDEF;
-       mode->hskew = 0;
-       mode->vscan = 0;
-       mode->vrefresh = 0;
-       mode->flags = 0;
-
-       if (sscanf(s, "%f %hd %hd %hd %hd %hd %hd %hd %hd %15s %15s",
-                  &fclock,
-                  &mode->hdisplay,
-                  &mode->hsync_start,
-                  &mode->hsync_end,
-                  &mode->htotal,
-                  &mode->vdisplay,
-                  &mode->vsync_start,
-                  &mode->vsync_end,
-                  &mode->vtotal, hsync, vsync) != 11)
-               return -1;
-
-       mode->clock = fclock * 1000;
-       if (strcmp(hsync, "+hsync") == 0)
-               mode->flags |= DRM_MODE_FLAG_PHSYNC;
-       else if (strcmp(hsync, "-hsync") == 0)
-               mode->flags |= DRM_MODE_FLAG_NHSYNC;
-       else
-               return -1;
-
-       if (strcmp(vsync, "+vsync") == 0)
-               mode->flags |= DRM_MODE_FLAG_PVSYNC;
-       else if (strcmp(vsync, "-vsync") == 0)
-               mode->flags |= DRM_MODE_FLAG_NVSYNC;
-       else
-               return -1;
-
-       snprintf(mode->name, sizeof mode->name, "%dx%d@%.3f",
-                mode->hdisplay, mode->vdisplay, fclock);
-
-       return 0;
-}
-
-static void
-setup_output_seat_constraint(struct drm_backend *b,
-                            struct weston_output *output,
-                            const char *s)
-{
-       if (strcmp(s, "") != 0) {
-               struct weston_pointer *pointer;
-               struct udev_seat *seat;
-
-               seat = udev_seat_get_named(&b->input, s);
-               if (!seat)
-                       return;
-
-               seat->base.output = output;
-
-               pointer = weston_seat_get_pointer(&seat->base);
-               if (pointer)
-                       weston_pointer_clamp(pointer,
-                                            &pointer->x,
-                                            &pointer->y);
-       }
-}
-
-static int
-parse_gbm_format(const char *s, uint32_t default_value, uint32_t *gbm_format)
-{
-       int ret = 0;
-
-       if (s == NULL)
-               *gbm_format = default_value;
-       else if (strcmp(s, "xrgb8888") == 0)
-               *gbm_format = GBM_FORMAT_XRGB8888;
-       else if (strcmp(s, "rgb565") == 0)
-               *gbm_format = GBM_FORMAT_RGB565;
-       else if (strcmp(s, "xrgb2101010") == 0)
-               *gbm_format = GBM_FORMAT_XRGB2101010;
-       else {
-               weston_log("fatal: unrecognized pixel format: %s\n", s);
-               ret = -1;
-       }
-
-       return ret;
-}
-
-/**
- * Choose suitable mode for an output
- *
- * Find the most suitable mode to use for initial setup (or reconfiguration on
- * hotplug etc) for a DRM output.
- *
- * @param output DRM output to choose mode for
- * @param kind Strategy and preference to use when choosing mode
- * @param width Desired width for this output
- * @param height Desired height for this output
- * @param current_mode Mode currently being displayed on this output
- * @param modeline Manually-entered mode (may be NULL)
- * @returns A mode from the output's mode list, or NULL if none available
- */
-static struct drm_mode *
-drm_output_choose_initial_mode(struct drm_backend *backend,
-                              struct drm_output *output,
-                              enum weston_drm_backend_output_mode mode,
-                              struct weston_drm_backend_output_config *config,
-                              const drmModeModeInfo *current_mode)
-{
-       struct drm_mode *preferred = NULL;
-       struct drm_mode *current = NULL;
-       struct drm_mode *configured = NULL;
-       struct drm_mode *best = NULL;
-       struct drm_mode *drm_mode;
-       drmModeModeInfo modeline;
-       int32_t width = 0;
-       int32_t height = 0;
-
-       if (mode == WESTON_DRM_BACKEND_OUTPUT_PREFERRED && config->modeline) {
-               if (sscanf(config->modeline, "%dx%d", &width, &height) != 2) {
-                       width = -1;
-
-                       if (parse_modeline(config->modeline, &modeline) == 0) {
-                               configured = drm_output_add_mode(output, &modeline);
-                               if (!configured)
-                                       return NULL;
-                       } else {
-                               weston_log("Invalid modeline \"%s\" for output %s\n",
-                                          config->modeline, output->base.name);
-                       }
-               }
-       }
-
-       wl_list_for_each_reverse(drm_mode, &output->base.mode_list, base.link) {
-               if (width == drm_mode->base.width &&
-                   height == drm_mode->base.height)
-                       configured = drm_mode;
-
-               if (memcmp(current_mode, &drm_mode->mode_info,
-                          sizeof *current_mode) == 0)
-                       current = drm_mode;
-
-               if (drm_mode->base.flags & WL_OUTPUT_MODE_PREFERRED)
-                       preferred = drm_mode;
-
-               best = drm_mode;
-       }
-
-       if (current == NULL && current_mode->clock != 0) {
-               current = drm_output_add_mode(output, current_mode);
-               if (!current)
-                       return NULL;
-       }
-
-       if (mode == WESTON_DRM_BACKEND_OUTPUT_CURRENT)
-               configured = current;
-
-       if (configured)
-               return configured;
-
-       if (preferred)
-               return preferred;
-
-       if (current)
-               return current;
-
-       if (best)
-               return best;
-
-       weston_log("no available modes for %s\n", output->base.name);
-       return NULL;
-}
-
-static int
-connector_get_current_mode(drmModeConnector *connector, int drm_fd,
-                          drmModeModeInfo *mode)
-{
-       drmModeEncoder *encoder;
-       drmModeCrtc *crtc;
-
-       /* Get the current mode on the crtc that's currently driving
-        * this connector. */
-       encoder = drmModeGetEncoder(drm_fd, connector->encoder_id);
-       memset(mode, 0, sizeof *mode);
-       if (encoder != NULL) {
-               crtc = drmModeGetCrtc(drm_fd, encoder->crtc_id);
-               drmModeFreeEncoder(encoder);
-               if (crtc == NULL)
-                       return -1;
-               if (crtc->mode_valid)
-                       *mode = crtc->mode;
-               drmModeFreeCrtc(crtc);
-       }
-
-       return 0;
-}
-
-/**
- * Create and configure a Weston output structure
- *
- * Given a DRM connector, create a matching drm_output structure and add it
- * to Weston's output list.
- *
- * @param b Weston backend structure structure
- * @param resources DRM resources for this device
- * @param connector DRM connector to use for this new output
- * @param x Horizontal offset to use into global co-ordinate space
- * @param y Vertical offset to use into global co-ordinate space
- * @param drm_device udev device pointer
- * @returns 0 on success, or -1 on failure
- */
-static int
-create_output_for_connector(struct drm_backend *b,
-                           drmModeRes *resources,
-                           drmModeConnector *connector,
-                           int x, int y, struct udev_device *drm_device)
-{
-       struct drm_output *output;
-       struct drm_mode *drm_mode, *next, *current;
-       struct weston_mode *m;
-
-       drmModeModeInfo crtc_mode;
-       int i;
-       enum weston_drm_backend_output_mode mode;
-       struct weston_drm_backend_output_config config = {{ 0 }};
-
-       i = find_crtc_for_connector(b, resources, connector);
-       if (i < 0) {
-               weston_log("No usable crtc/encoder pair for connector.\n");
-               return -1;
-       }
-
-       output = zalloc(sizeof *output);
-       if (output == NULL)
-               return -1;
-
-       output->base.subpixel = drm_subpixel_to_wayland(connector->subpixel);
-       output->base.name = make_connector_name(connector);
-       output->base.make = "unknown";
-       output->base.model = "unknown";
-       output->base.serial_number = "unknown";
-       wl_list_init(&output->base.mode_list);
-
-       mode = b->configure_output(b->compositor, b->use_current_mode,
-                                  output->base.name, &config);
-       if (parse_gbm_format(config.gbm_format, b->gbm_format, &output->gbm_format) == -1)
-               output->gbm_format = b->gbm_format;
-
-       setup_output_seat_constraint(b, &output->base,
-                                    config.seat ? config.seat : "");
-       free(config.seat);
-
-       output->crtc_id = resources->crtcs[i];
-       output->pipe = i;
-       b->crtc_allocator |= (1 << output->crtc_id);
-       output->connector_id = connector->connector_id;
-       b->connector_allocator |= (1 << output->connector_id);
-
-       output->original_crtc = drmModeGetCrtc(b->drm.fd, output->crtc_id);
-       output->dpms_prop = drm_get_prop(b->drm.fd, connector, "DPMS");
-
-       if (connector_get_current_mode(connector, b->drm.fd, &crtc_mode) < 0)
-               goto err_free;
-
-       for (i = 0; i < connector->count_modes; i++) {
-               drm_mode = drm_output_add_mode(output, &connector->modes[i]);
-               if (!drm_mode)
-                       goto err_free;
-       }
-
-       if (mode == WESTON_DRM_BACKEND_OUTPUT_OFF) {
-               weston_log("Disabling output %s\n", output->base.name);
-               drmModeSetCrtc(b->drm.fd, output->crtc_id,
-                              0, 0, 0, 0, 0, NULL);
-               goto err_free;
-       }
-
-       current = drm_output_choose_initial_mode(b, output, mode, &config,
-                                                &crtc_mode);
-       if (!current)
-               goto err_free;
-       output->base.current_mode = &current->base;
-       output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
-
-       weston_output_init(&output->base, b->compositor, x, y,
-                          connector->mmWidth, connector->mmHeight,
-                          config.base.transform, config.base.scale);
-
-       if (b->use_pixman) {
-               if (drm_output_init_pixman(output, b) < 0) {
-                       weston_log("Failed to init output pixman state\n");
-                       goto err_output;
-               }
-       } else if (drm_output_init_egl(output, b) < 0) {
-               weston_log("Failed to init output gl state\n");
-               goto err_output;
-       }
-
-       output->backlight = backlight_init(drm_device,
-                                          connector->connector_type);
-       if (output->backlight) {
-               weston_log("Initialized backlight, device %s\n",
-                          output->backlight->path);
-               output->base.set_backlight = drm_set_backlight;
-               output->base.backlight_current = drm_get_backlight(output);
-       } else {
-               weston_log("Failed to initialize backlight\n");
-       }
-
-       weston_compositor_add_output(b->compositor, &output->base);
-
-       find_and_parse_output_edid(b, output, connector);
-       if (connector->connector_type == DRM_MODE_CONNECTOR_LVDS)
-               output->base.connection_internal = 1;
-
-       output->base.start_repaint_loop = drm_output_start_repaint_loop;
-       output->base.repaint = drm_output_repaint;
-       output->base.destroy = drm_output_destroy;
-       output->base.assign_planes = drm_assign_planes;
-       output->base.set_dpms = drm_set_dpms;
-       output->base.switch_mode = drm_output_switch_mode;
-
-       output->base.gamma_size = output->original_crtc->gamma_size;
-       output->base.set_gamma = drm_output_set_gamma;
-
-       weston_plane_init(&output->cursor_plane, b->compositor,
-                         INT32_MIN, INT32_MIN);
-       weston_plane_init(&output->fb_plane, b->compositor, 0, 0);
-
-       weston_compositor_stack_plane(b->compositor, &output->cursor_plane, NULL);
-       weston_compositor_stack_plane(b->compositor, &output->fb_plane,
-                                     &b->compositor->primary_plane);
-
-       weston_log("Output %s, (connector %d, crtc %d)\n",
-                  output->base.name, output->connector_id, output->crtc_id);
-       wl_list_for_each(m, &output->base.mode_list, link)
-               weston_log_continue(STAMP_SPACE "mode %dx%d@%.1f%s%s%s\n",
-                                   m->width, m->height, m->refresh / 1000.0,
-                                   m->flags & WL_OUTPUT_MODE_PREFERRED ?
-                                   ", preferred" : "",
-                                   m->flags & WL_OUTPUT_MODE_CURRENT ?
-                                   ", current" : "",
-                                   connector->count_modes == 0 ?
-                                   ", built-in" : "");
-
-       /* Set native_ fields, so weston_output_mode_switch_to_native() works */
-       output->base.native_mode = output->base.current_mode;
-       output->base.native_scale = output->base.current_scale;
-
-       return 0;
-
-err_output:
-       weston_output_destroy(&output->base);
-err_free:
-       wl_list_for_each_safe(drm_mode, next, &output->base.mode_list,
-                                                       base.link) {
-               wl_list_remove(&drm_mode->base.link);
-               free(drm_mode);
-       }
-
-       drmModeFreeCrtc(output->original_crtc);
-       b->crtc_allocator &= ~(1 << output->crtc_id);
-       b->connector_allocator &= ~(1 << output->connector_id);
-       free(output);
-       free(config.modeline);
-
-       return -1;
-}
-
-static void
-create_sprites(struct drm_backend *b)
-{
-       struct drm_sprite *sprite;
-       drmModePlaneRes *plane_res;
-       drmModePlane *plane;
-       uint32_t i;
-
-       plane_res = drmModeGetPlaneResources(b->drm.fd);
-       if (!plane_res) {
-               weston_log("failed to get plane resources: %s\n",
-                       strerror(errno));
-               return;
-       }
-
-       for (i = 0; i < plane_res->count_planes; i++) {
-               plane = drmModeGetPlane(b->drm.fd, plane_res->planes[i]);
-               if (!plane)
-                       continue;
-
-               sprite = zalloc(sizeof(*sprite) + ((sizeof(uint32_t)) *
-                                                  plane->count_formats));
-               if (!sprite) {
-                       weston_log("%s: out of memory\n",
-                               __func__);
-                       drmModeFreePlane(plane);
-                       continue;
-               }
-
-               sprite->possible_crtcs = plane->possible_crtcs;
-               sprite->plane_id = plane->plane_id;
-               sprite->current = NULL;
-               sprite->next = NULL;
-               sprite->backend = b;
-               sprite->count_formats = plane->count_formats;
-               memcpy(sprite->formats, plane->formats,
-                      plane->count_formats * sizeof(plane->formats[0]));
-               drmModeFreePlane(plane);
-               weston_plane_init(&sprite->plane, b->compositor, 0, 0);
-               weston_compositor_stack_plane(b->compositor, &sprite->plane,
-                                             &b->compositor->primary_plane);
-
-               wl_list_insert(&b->sprite_list, &sprite->link);
-       }
-
-       drmModeFreePlaneResources(plane_res);
-}
-
-static void
-destroy_sprites(struct drm_backend *backend)
-{
-       struct drm_sprite *sprite, *next;
-       struct drm_output *output;
-
-       output = container_of(backend->compositor->output_list.next,
-                             struct drm_output, base.link);
-
-       wl_list_for_each_safe(sprite, next, &backend->sprite_list, link) {
-               drmModeSetPlane(backend->drm.fd,
-                               sprite->plane_id,
-                               output->crtc_id, 0, 0,
-                               0, 0, 0, 0, 0, 0, 0, 0);
-               drm_output_release_fb(output, sprite->current);
-               drm_output_release_fb(output, sprite->next);
-               weston_plane_release(&sprite->plane);
-               free(sprite);
-       }
-}
-
-static int
-create_outputs(struct drm_backend *b, uint32_t option_connector,
-              struct udev_device *drm_device)
-{
-       drmModeConnector *connector;
-       drmModeRes *resources;
-       int i;
-       int x = 0, y = 0;
-
-       resources = drmModeGetResources(b->drm.fd);
-       if (!resources) {
-               weston_log("drmModeGetResources failed\n");
-               return -1;
-       }
-
-       b->crtcs = calloc(resources->count_crtcs, sizeof(uint32_t));
-       if (!b->crtcs) {
-               drmModeFreeResources(resources);
-               return -1;
-       }
-
-       b->min_width  = resources->min_width;
-       b->max_width  = resources->max_width;
-       b->min_height = resources->min_height;
-       b->max_height = resources->max_height;
-
-       b->num_crtcs = resources->count_crtcs;
-       memcpy(b->crtcs, resources->crtcs, sizeof(uint32_t) * b->num_crtcs);
-
-       for (i = 0; i < resources->count_connectors; i++) {
-               connector = drmModeGetConnector(b->drm.fd,
-                                               resources->connectors[i]);
-               if (connector == NULL)
-                       continue;
-
-               if (connector->connection == DRM_MODE_CONNECTED &&
-                   (option_connector == 0 ||
-                    connector->connector_id == option_connector)) {
-                       if (create_output_for_connector(b, resources,
-                                                       connector, x, y,
-                                                       drm_device) < 0) {
-                               drmModeFreeConnector(connector);
-                               continue;
-                       }
-
-                       x += container_of(b->compositor->output_list.prev,
-                                         struct weston_output,
-                                         link)->width;
-               }
-
-               drmModeFreeConnector(connector);
-       }
-
-       if (wl_list_empty(&b->compositor->output_list)) {
-               weston_log("No currently active connector found.\n");
-               drmModeFreeResources(resources);
-               return -1;
-       }
-
-       drmModeFreeResources(resources);
-
-       return 0;
-}
-
-static void
-update_outputs(struct drm_backend *b, struct udev_device *drm_device)
-{
-       drmModeConnector *connector;
-       drmModeRes *resources;
-       struct drm_output *output, *next;
-       int x = 0, y = 0;
-       uint32_t connected = 0, disconnects = 0;
-       int i;
-
-       resources = drmModeGetResources(b->drm.fd);
-       if (!resources) {
-               weston_log("drmModeGetResources failed\n");
-               return;
-       }
-
-       /* collect new connects */
-       for (i = 0; i < resources->count_connectors; i++) {
-               int connector_id = resources->connectors[i];
-
-               connector = drmModeGetConnector(b->drm.fd, connector_id);
-               if (connector == NULL)
-                       continue;
-
-               if (connector->connection != DRM_MODE_CONNECTED) {
-                       drmModeFreeConnector(connector);
-                       continue;
-               }
-
-               connected |= (1 << connector_id);
-
-               if (!(b->connector_allocator & (1 << connector_id))) {
-                       struct weston_output *last =
-                               container_of(b->compositor->output_list.prev,
-                                            struct weston_output, link);
-
-                       /* XXX: not yet needed, we die with 0 outputs */
-                       if (!wl_list_empty(&b->compositor->output_list))
-                               x = last->x + last->width;
-                       else
-                               x = 0;
-                       y = 0;
-                       create_output_for_connector(b, resources,
-                                                   connector, x, y,
-                                                   drm_device);
-                       weston_log("connector %d connected\n", connector_id);
-
-               }
-               drmModeFreeConnector(connector);
-       }
-       drmModeFreeResources(resources);
-
-       disconnects = b->connector_allocator & ~connected;
-       if (disconnects) {
-               wl_list_for_each_safe(output, next, &b->compositor->output_list,
-                                     base.link) {
-                       if (disconnects & (1 << output->connector_id)) {
-                               disconnects &= ~(1 << output->connector_id);
-                               weston_log("connector %d disconnected\n",
-                                      output->connector_id);
-                               drm_output_destroy(&output->base);
-                       }
-               }
-       }
-
-       /* FIXME: handle zero outputs, without terminating */
-       if (b->connector_allocator == 0)
-               weston_compositor_exit(b->compositor);
-}
-
-static int
-udev_event_is_hotplug(struct drm_backend *b, struct udev_device *device)
-{
-       const char *sysnum;
-       const char *val;
-
-       sysnum = udev_device_get_sysnum(device);
-       if (!sysnum || atoi(sysnum) != b->drm.id)
-               return 0;
-
-       val = udev_device_get_property_value(device, "HOTPLUG");
-       if (!val)
-               return 0;
-
-       return strcmp(val, "1") == 0;
-}
-
-static int
-udev_drm_event(int fd, uint32_t mask, void *data)
-{
-       struct drm_backend *b = data;
-       struct udev_device *event;
-
-       event = udev_monitor_receive_device(b->udev_monitor);
-
-       if (udev_event_is_hotplug(b, event))
-               update_outputs(b, event);
-
-       udev_device_unref(event);
-
-       return 1;
-}
-
-static void
-drm_restore(struct weston_compositor *ec)
-{
-       weston_launcher_restore(ec->launcher);
-}
-
-static void
-drm_destroy(struct weston_compositor *ec)
-{
-       struct drm_backend *b = (struct drm_backend *) ec->backend;
-
-       udev_input_destroy(&b->input);
-
-       wl_event_source_remove(b->udev_drm_source);
-       wl_event_source_remove(b->drm_source);
-
-       destroy_sprites(b);
-
-       weston_compositor_shutdown(ec);
-
-       if (b->gbm)
-               gbm_device_destroy(b->gbm);
-
-       weston_launcher_destroy(ec->launcher);
-
-       close(b->drm.fd);
-       free(b);
-}
-
-static void
-drm_backend_set_modes(struct drm_backend *backend)
-{
-       struct drm_output *output;
-       struct drm_mode *drm_mode;
-       int ret;
-
-       wl_list_for_each(output, &backend->compositor->output_list, base.link) {
-               if (!output->current) {
-                       /* If something that would cause the output to
-                        * switch mode happened while in another vt, we
-                        * might not have a current drm_fb. In that case,
-                        * schedule a repaint and let drm_output_repaint
-                        * handle setting the mode. */
-                       weston_output_schedule_repaint(&output->base);
-                       continue;
-               }
-
-               drm_mode = (struct drm_mode *) output->base.current_mode;
-               ret = drmModeSetCrtc(backend->drm.fd, output->crtc_id,
-                                    output->current->fb_id, 0, 0,
-                                    &output->connector_id, 1,
-                                    &drm_mode->mode_info);
-               if (ret < 0) {
-                       weston_log(
-                               "failed to set mode %dx%d for output at %d,%d: %m\n",
-                               drm_mode->base.width, drm_mode->base.height,
-                               output->base.x, output->base.y);
-               }
-       }
-}
-
-static void
-session_notify(struct wl_listener *listener, void *data)
-{
-       struct weston_compositor *compositor = data;
-       struct drm_backend *b = (struct drm_backend *)compositor->backend;
-       struct drm_sprite *sprite;
-       struct drm_output *output;
-
-       if (compositor->session_active) {
-               weston_log("activating session\n");
-               compositor->state = b->prev_state;
-               drm_backend_set_modes(b);
-               weston_compositor_damage_all(compositor);
-               udev_input_enable(&b->input);
-       } else {
-               weston_log("deactivating session\n");
-               udev_input_disable(&b->input);
-
-               b->prev_state = compositor->state;
-               weston_compositor_offscreen(compositor);
-
-               /* If we have a repaint scheduled (either from a
-                * pending pageflip or the idle handler), make sure we
-                * cancel that so we don't try to pageflip when we're
-                * vt switched away.  The OFFSCREEN state will prevent
-                * further attemps at repainting.  When we switch
-                * back, we schedule a repaint, which will process
-                * pending frame callbacks. */
-
-               wl_list_for_each(output, &compositor->output_list, base.link) {
-                       output->base.repaint_needed = 0;
-                       drmModeSetCursor(b->drm.fd, output->crtc_id, 0, 0, 0);
-               }
-
-               output = container_of(compositor->output_list.next,
-                                     struct drm_output, base.link);
-
-               wl_list_for_each(sprite, &b->sprite_list, link)
-                       drmModeSetPlane(b->drm.fd,
-                                       sprite->plane_id,
-                                       output->crtc_id, 0, 0,
-                                       0, 0, 0, 0, 0, 0, 0, 0);
-       };
-}
-
-/*
- * Find primary GPU
- * Some systems may have multiple DRM devices attached to a single seat. This
- * function loops over all devices and tries to find a PCI device with the
- * boot_vga sysfs attribute set to 1.
- * If no such device is found, the first DRM device reported by udev is used.
- */
-static struct udev_device*
-find_primary_gpu(struct drm_backend *b, const char *seat)
-{
-       struct udev_enumerate *e;
-       struct udev_list_entry *entry;
-       const char *path, *device_seat, *id;
-       struct udev_device *device, *drm_device, *pci;
-
-       e = udev_enumerate_new(b->udev);
-       udev_enumerate_add_match_subsystem(e, "drm");
-       udev_enumerate_add_match_sysname(e, "card[0-9]*");
-
-       udev_enumerate_scan_devices(e);
-       drm_device = NULL;
-       udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(e)) {
-               path = udev_list_entry_get_name(entry);
-               device = udev_device_new_from_syspath(b->udev, path);
-               if (!device)
-                       continue;
-               device_seat = udev_device_get_property_value(device, "ID_SEAT");
-               if (!device_seat)
-                       device_seat = default_seat;
-               if (strcmp(device_seat, seat)) {
-                       udev_device_unref(device);
-                       continue;
-               }
-
-               pci = udev_device_get_parent_with_subsystem_devtype(device,
-                                                               "pci", NULL);
-               if (pci) {
-                       id = udev_device_get_sysattr_value(pci, "boot_vga");
-                       if (id && !strcmp(id, "1")) {
-                               if (drm_device)
-                                       udev_device_unref(drm_device);
-                               drm_device = device;
-                               break;
-                       }
-               }
-
-               if (!drm_device)
-                       drm_device = device;
-               else
-                       udev_device_unref(device);
-       }
-
-       udev_enumerate_unref(e);
-       return drm_device;
-}
-
-static void
-planes_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
-              void *data)
-{
-       struct drm_backend *b = data;
-
-       switch (key) {
-       case KEY_C:
-               b->cursors_are_broken ^= 1;
-               break;
-       case KEY_V:
-               b->sprites_are_broken ^= 1;
-               break;
-       case KEY_O:
-               b->sprites_hidden ^= 1;
-               break;
-       default:
-               break;
-       }
-}
-
-#ifdef BUILD_VAAPI_RECORDER
-static void
-recorder_destroy(struct drm_output *output)
-{
-       vaapi_recorder_destroy(output->recorder);
-       output->recorder = NULL;
-
-       output->base.disable_planes--;
-
-       wl_list_remove(&output->recorder_frame_listener.link);
-       weston_log("[libva recorder] done\n");
-}
-
-static void
-recorder_frame_notify(struct wl_listener *listener, void *data)
-{
-       struct drm_output *output;
-       struct drm_backend *b;
-       int fd, ret;
-
-       output = container_of(listener, struct drm_output,
-                             recorder_frame_listener);
-       b = (struct drm_backend *)output->base.compositor->backend;
-
-       if (!output->recorder)
-               return;
-
-       ret = drmPrimeHandleToFD(b->drm.fd, output->current->handle,
-                                DRM_CLOEXEC, &fd);
-       if (ret) {
-               weston_log("[libva recorder] "
-                          "failed to create prime fd for front buffer\n");
-               return;
-       }
-
-       ret = vaapi_recorder_frame(output->recorder, fd,
-                                  output->current->stride);
-       if (ret < 0) {
-               weston_log("[libva recorder] aborted: %m\n");
-               recorder_destroy(output);
-       }
-}
-
-static void *
-create_recorder(struct drm_backend *b, int width, int height,
-               const char *filename)
-{
-       int fd;
-       drm_magic_t magic;
-
-       fd = open(b->drm.filename, O_RDWR | O_CLOEXEC);
-       if (fd < 0)
-               return NULL;
-
-       drmGetMagic(fd, &magic);
-       drmAuthMagic(b->drm.fd, magic);
-
-       return vaapi_recorder_create(fd, width, height, filename);
-}
-
-static void
-recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
-                void *data)
-{
-       struct drm_backend *b = data;
-       struct drm_output *output;
-       int width, height;
-
-       output = container_of(b->compositor->output_list.next,
-                             struct drm_output, base.link);
-
-       if (!output->recorder) {
-               if (output->gbm_format != GBM_FORMAT_XRGB8888) {
-                       weston_log("failed to start vaapi recorder: "
-                                  "output format not supported\n");
-                       return;
-               }
-
-               width = output->base.current_mode->width;
-               height = output->base.current_mode->height;
-
-               output->recorder =
-                       create_recorder(b, width, height, "capture.h264");
-               if (!output->recorder) {
-                       weston_log("failed to create vaapi recorder\n");
-                       return;
-               }
-
-               output->base.disable_planes++;
-
-               output->recorder_frame_listener.notify = recorder_frame_notify;
-               wl_signal_add(&output->base.frame_signal,
-                             &output->recorder_frame_listener);
-
-               weston_output_schedule_repaint(&output->base);
-
-               weston_log("[libva recorder] initialized\n");
-       } else {
-               recorder_destroy(output);
-       }
-}
-#else
-static void
-recorder_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
-                void *data)
-{
-       weston_log("Compiled without libva support\n");
-}
-#endif
-
-static void
-switch_to_gl_renderer(struct drm_backend *b)
-{
-       struct drm_output *output;
-       bool dmabuf_support_inited;
-
-       if (!b->use_pixman)
-               return;
-
-       dmabuf_support_inited = !!b->compositor->renderer->import_dmabuf;
-
-       weston_log("Switching to GL renderer\n");
-
-       b->gbm = create_gbm_device(b->drm.fd);
-       if (!b->gbm) {
-               weston_log("Failed to create gbm device. "
-                          "Aborting renderer switch\n");
-               return;
-       }
-
-       wl_list_for_each(output, &b->compositor->output_list, base.link)
-               pixman_renderer_output_destroy(&output->base);
-
-       b->compositor->renderer->destroy(b->compositor);
-
-       if (drm_backend_create_gl_renderer(b) < 0) {
-               gbm_device_destroy(b->gbm);
-               weston_log("Failed to create GL renderer. Quitting.\n");
-               /* FIXME: we need a function to shutdown cleanly */
-               assert(0);
-       }
-
-       wl_list_for_each(output, &b->compositor->output_list, base.link)
-               drm_output_init_egl(output, b);
-
-       b->use_pixman = 0;
-
-       if (!dmabuf_support_inited && b->compositor->renderer->import_dmabuf) {
-               if (linux_dmabuf_setup(b->compositor) < 0)
-                       weston_log("Error: initializing dmabuf "
-                                  "support failed.\n");
-       }
-}
-
-static void
-renderer_switch_binding(struct weston_keyboard *keyboard, uint32_t time,
-                       uint32_t key, void *data)
-{
-       struct drm_backend *b =
-               (struct drm_backend *) keyboard->seat->compositor;
-
-       switch_to_gl_renderer(b);
-}
-
-static struct drm_backend *
-drm_backend_create(struct weston_compositor *compositor,
-                  struct weston_drm_backend_config *config)
-{
-       struct drm_backend *b;
-       struct udev_device *drm_device;
-       struct wl_event_loop *loop;
-       const char *path;
-       const char *seat_id = default_seat;
-
-       weston_log("initializing drm backend\n");
-
-       b = zalloc(sizeof *b);
-       if (b == NULL)
-               return NULL;
-
-       /*
-        * KMS support for hardware planes cannot properly synchronize
-        * without nuclear page flip. Without nuclear/atomic, hw plane
-        * and cursor plane updates would either tear or cause extra
-        * waits for vblanks which means dropping the compositor framerate
-        * to a fraction. For cursors, it's not so bad, so they are
-        * enabled.
-        *
-        * These can be enabled again when nuclear/atomic support lands.
-        */
-       b->sprites_are_broken = 1;
-       b->compositor = compositor;
-       b->use_pixman = config->use_pixman;
-       b->configure_output = config->configure_output;
-       b->use_current_mode = config->use_current_mode;
-
-       if (parse_gbm_format(config->gbm_format, GBM_FORMAT_XRGB8888, &b->gbm_format) < 0)
-               goto err_compositor;
-
-       if (config->seat_id)
-               seat_id = config->seat_id;
-
-       /* Check if we run drm-backend using weston-launch */
-       compositor->launcher = weston_launcher_connect(compositor, config->tty,
-                                                      seat_id, true);
-       if (compositor->launcher == NULL) {
-               weston_log("fatal: drm backend should be run "
-                          "using weston-launch binary or as root\n");
-               goto err_compositor;
-       }
-
-       b->udev = udev_new();
-       if (b->udev == NULL) {
-               weston_log("failed to initialize udev context\n");
-               goto err_launcher;
-       }
-
-       b->session_listener.notify = session_notify;
-       wl_signal_add(&compositor->session_signal, &b->session_listener);
-
-       drm_device = find_primary_gpu(b, seat_id);
-       if (drm_device == NULL) {
-               weston_log("no drm device found\n");
-               goto err_udev;
-       }
-       path = udev_device_get_syspath(drm_device);
-
-       if (init_drm(b, drm_device) < 0) {
-               weston_log("failed to initialize kms\n");
-               goto err_udev_dev;
-       }
-
-       if (b->use_pixman) {
-               if (init_pixman(b) < 0) {
-                       weston_log("failed to initialize pixman renderer\n");
-                       goto err_udev_dev;
-               }
-       } else {
-               if (init_egl(b) < 0) {
-                       weston_log("failed to initialize egl\n");
-                       goto err_udev_dev;
-               }
-       }
-
-       b->base.destroy = drm_destroy;
-       b->base.restore = drm_restore;
-
-       b->prev_state = WESTON_COMPOSITOR_ACTIVE;
-
-       weston_setup_vt_switch_bindings(compositor);
-
-       wl_list_init(&b->sprite_list);
-       create_sprites(b);
-
-       if (udev_input_init(&b->input,
-                           compositor, b->udev, seat_id,
-                           config->configure_device) < 0) {
-               weston_log("failed to create input devices\n");
-               goto err_sprite;
-       }
-
-       if (create_outputs(b, config->connector, drm_device) < 0) {
-               weston_log("failed to create output for %s\n", path);
-               goto err_udev_input;
-       }
-
-       /* A this point we have some idea of whether or not we have a working
-        * cursor plane. */
-       if (!b->cursors_are_broken)
-               compositor->capabilities |= WESTON_CAP_CURSOR_PLANE;
-
-       path = NULL;
-
-       loop = wl_display_get_event_loop(compositor->wl_display);
-       b->drm_source =
-               wl_event_loop_add_fd(loop, b->drm.fd,
-                                    WL_EVENT_READABLE, on_drm_input, b);
-
-       b->udev_monitor = udev_monitor_new_from_netlink(b->udev, "udev");
-       if (b->udev_monitor == NULL) {
-               weston_log("failed to intialize udev monitor\n");
-               goto err_drm_source;
-       }
-       udev_monitor_filter_add_match_subsystem_devtype(b->udev_monitor,
-                                                       "drm", NULL);
-       b->udev_drm_source =
-               wl_event_loop_add_fd(loop,
-                                    udev_monitor_get_fd(b->udev_monitor),
-                                    WL_EVENT_READABLE, udev_drm_event, b);
-
-       if (udev_monitor_enable_receiving(b->udev_monitor) < 0) {
-               weston_log("failed to enable udev-monitor receiving\n");
-               goto err_udev_monitor;
-       }
-
-       udev_device_unref(drm_device);
-
-       weston_compositor_add_debug_binding(compositor, KEY_O,
-                                           planes_binding, b);
-       weston_compositor_add_debug_binding(compositor, KEY_C,
-                                           planes_binding, b);
-       weston_compositor_add_debug_binding(compositor, KEY_V,
-                                           planes_binding, b);
-       weston_compositor_add_debug_binding(compositor, KEY_Q,
-                                           recorder_binding, b);
-       weston_compositor_add_debug_binding(compositor, KEY_W,
-                                           renderer_switch_binding, b);
-
-       if (compositor->renderer->import_dmabuf) {
-               if (linux_dmabuf_setup(compositor) < 0)
-                       weston_log("Error: initializing dmabuf "
-                                  "support failed.\n");
-       }
-
-       compositor->backend = &b->base;
-
-       return b;
-
-err_udev_monitor:
-       wl_event_source_remove(b->udev_drm_source);
-       udev_monitor_unref(b->udev_monitor);
-err_drm_source:
-       wl_event_source_remove(b->drm_source);
-err_udev_input:
-       udev_input_destroy(&b->input);
-err_sprite:
-       if (b->gbm)
-               gbm_device_destroy(b->gbm);
-       destroy_sprites(b);
-err_udev_dev:
-       udev_device_unref(drm_device);
-err_launcher:
-       weston_launcher_destroy(compositor->launcher);
-err_udev:
-       udev_unref(b->udev);
-err_compositor:
-       weston_compositor_shutdown(compositor);
-       free(b);
-       return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_drm_backend_config *config)
-{
-}
-
-WL_EXPORT int
-backend_init(struct weston_compositor *compositor,
-            struct weston_backend_config *config_base)
-{
-       struct drm_backend *b;
-       struct weston_drm_backend_config config = {{ 0, }};
-
-       if (config_base == NULL ||
-           config_base->struct_version != WESTON_DRM_BACKEND_CONFIG_VERSION ||
-           config_base->struct_size > sizeof(struct weston_drm_backend_config)) {
-               weston_log("drm backend config structure is invalid\n");
-               return -1;
-       }
-
-       config_init_to_defaults(&config);
-       memcpy(&config, config_base, config_base->struct_size);
-
-       b = drm_backend_create(compositor, &config);
-       if (b == NULL)
-               return -1;
-
-       return 0;
-}
diff --git a/src/compositor-drm.h b/src/compositor-drm.h
deleted file mode 100644 (file)
index 1266031..0000000
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2015 Giulio Camuffo
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_COMPOSITOR_DRM_H
-#define WESTON_COMPOSITOR_DRM_H
-
-#include "compositor.h"
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#define WESTON_DRM_BACKEND_CONFIG_VERSION 1
-
-struct libinput_device;
-
-enum weston_drm_backend_output_mode {
-       /** The output is disabled */
-       WESTON_DRM_BACKEND_OUTPUT_OFF,
-       /** The output will use the current active mode */
-       WESTON_DRM_BACKEND_OUTPUT_CURRENT,
-       /** The output will use the preferred mode. A modeline can be provided
-        * by setting weston_backend_output_config::modeline in the form of
-        * "WIDTHxHEIGHT" or in the form of an explicit modeline calculated
-        * using e.g. the cvt tool. If a valid modeline is supplied it will be
-        * used, if invalid or NULL the preferred available mode will be used. */
-       WESTON_DRM_BACKEND_OUTPUT_PREFERRED,
-};
-
-struct weston_drm_backend_output_config {
-       struct weston_backend_output_config base;
-
-       /** The pixel format to be used by the output. Valid values are:
-        * - NULL - The format set at backend creation time will be used;
-        * - "xrgb8888";
-        * - "rgb565"
-        * - "xrgb2101010"
-        */
-       char *gbm_format;
-       /** The seat to be used by the output. Set to NULL to use the
-        * default seat. */
-       char *seat;
-       /** The modeline to be used by the output. Refer to the documentation
-        * of WESTON_DRM_BACKEND_OUTPUT_PREFERRED for details. */
-       char *modeline;
-};
-
-/** The backend configuration struct.
- *
- * weston_drm_backend_config contains the configuration used by a DRM
- * backend.
- */
-struct weston_drm_backend_config {
-       struct weston_backend_config base;
-
-       /** The connector id of the output to be initialized.
-        *
-        * A value of 0 will enable all available outputs.
-        */
-       int connector;
-
-       /** The tty to be used. Set to 0 to use the current tty. */
-       int tty;
-
-       /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
-       bool use_pixman;
-
-       /** The seat to be used for input and output.
-        *
-        * If NULL the default "seat0" will be used.  The backend will
-        * take ownership of the seat_id pointer and will free it on
-        * backend destruction.
-        */
-       char *seat_id;
-
-       /** The pixel format of the framebuffer to be used.
-        *
-        * Valid values are:
-        * - NULL - The default format ("xrgb8888") will be used;
-        * - "xrgb8888";
-        * - "rgb565"
-        * - "xrgb2101010"
-        * The backend will take ownership of the format pointer and will free
-        * it on backend destruction.
-        */
-       char *gbm_format;
-
-       /** Callback used to configure the outputs.
-        *
-        * This function will be called by the backend when a new DRM
-        * output needs to be configured.
-        */
-       enum weston_drm_backend_output_mode
-               (*configure_output)(struct weston_compositor *compositor,
-                                   bool use_current_mode,
-                                   const char *name,
-                                   struct weston_drm_backend_output_config *output_config);
-
-       /** Callback used to configure input devices.
-        *
-        * This function will be called by the backend when a new input device
-        * needs to be configured.
-        * If NULL the device will use the default configuration.
-        */
-       void (*configure_device)(struct weston_compositor *compositor,
-                                struct libinput_device *device);
-       bool use_current_mode;
-};
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* WESTON_COMPOSITOR_DRM_H */
diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
deleted file mode 100644 (file)
index e21ceca..0000000
+++ /dev/null
@@ -1,783 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2011 Intel Corporation
- * Copyright © 2012 Raspberry Pi Foundation
- * Copyright © 2013 Philip Withnall
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <math.h>
-#include <sys/mman.h>
-#include <sys/types.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/fb.h>
-#include <linux/input.h>
-
-#include <libudev.h>
-
-#include "shared/helpers.h"
-#include "compositor.h"
-#include "compositor-fbdev.h"
-#include "launcher-util.h"
-#include "pixman-renderer.h"
-#include "libinput-seat.h"
-#include "presentation-time-server-protocol.h"
-
-struct fbdev_backend {
-       struct weston_backend base;
-       struct weston_compositor *compositor;
-       uint32_t prev_state;
-
-       struct udev *udev;
-       struct udev_input input;
-       uint32_t output_transform;
-       struct wl_listener session_listener;
-};
-
-struct fbdev_screeninfo {
-       unsigned int x_resolution; /* pixels, visible area */
-       unsigned int y_resolution; /* pixels, visible area */
-       unsigned int width_mm; /* visible screen width in mm */
-       unsigned int height_mm; /* visible screen height in mm */
-       unsigned int bits_per_pixel;
-
-       size_t buffer_length; /* length of frame buffer memory in bytes */
-       size_t line_length; /* length of a line in bytes */
-       char id[16]; /* screen identifier */
-
-       pixman_format_code_t pixel_format; /* frame buffer pixel format */
-       unsigned int refresh_rate; /* Hertz */
-};
-
-struct fbdev_output {
-       struct fbdev_backend *backend;
-       struct weston_output base;
-
-       struct weston_mode mode;
-       struct wl_event_source *finish_frame_timer;
-
-       /* Frame buffer details. */
-       char *device;
-       struct fbdev_screeninfo fb_info;
-       void *fb; /* length is fb_info.buffer_length */
-
-       /* pixman details. */
-       pixman_image_t *hw_surface;
-       uint8_t depth;
-};
-
-static const char default_seat[] = "seat0";
-
-static inline struct fbdev_output *
-to_fbdev_output(struct weston_output *base)
-{
-       return container_of(base, struct fbdev_output, base);
-}
-
-static inline struct fbdev_backend *
-to_fbdev_backend(struct weston_compositor *base)
-{
-       return container_of(base->backend, struct fbdev_backend, base);
-}
-
-static void
-fbdev_output_start_repaint_loop(struct weston_output *output)
-{
-       struct timespec ts;
-
-       weston_compositor_read_presentation_clock(output->compositor, &ts);
-       weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
-}
-
-static int
-fbdev_output_repaint(struct weston_output *base, pixman_region32_t *damage)
-{
-       struct fbdev_output *output = to_fbdev_output(base);
-       struct weston_compositor *ec = output->base.compositor;
-
-       /* Repaint the damaged region onto the back buffer. */
-       pixman_renderer_output_set_buffer(base, output->hw_surface);
-       ec->renderer->repaint_output(base, damage);
-
-       /* Update the damage region. */
-       pixman_region32_subtract(&ec->primary_plane.damage,
-                                &ec->primary_plane.damage, damage);
-
-       /* Schedule the end of the frame. We do not sync this to the frame
-        * buffer clock because users who want that should be using the DRM
-        * compositor. FBIO_WAITFORVSYNC blocks and FB_ACTIVATE_VBL requires
-        * panning, which is broken in most kernel drivers.
-        *
-        * Finish the frame synchronised to the specified refresh rate. The
-        * refresh rate is given in mHz and the interval in ms. */
-       wl_event_source_timer_update(output->finish_frame_timer,
-                                    1000000 / output->mode.refresh);
-
-       return 0;
-}
-
-static int
-finish_frame_handler(void *data)
-{
-       struct fbdev_output *output = data;
-       struct timespec ts;
-
-       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
-       weston_output_finish_frame(&output->base, &ts, 0);
-
-       return 1;
-}
-
-static pixman_format_code_t
-calculate_pixman_format(struct fb_var_screeninfo *vinfo,
-                        struct fb_fix_screeninfo *finfo)
-{
-       /* Calculate the pixman format supported by the frame buffer from the
-        * buffer's metadata. Return 0 if no known pixman format is supported
-        * (since this has depth 0 it's guaranteed to not conflict with any
-        * actual pixman format).
-        *
-        * Documentation on the vinfo and finfo structures:
-        *    http://www.mjmwired.net/kernel/Documentation/fb/api.txt
-        *
-        * TODO: Try a bit harder to support other formats, including setting
-        * the preferred format in the hardware. */
-       int type;
-
-       weston_log("Calculating pixman format from:\n"
-                  STAMP_SPACE " - type: %i (aux: %i)\n"
-                  STAMP_SPACE " - visual: %i\n"
-                  STAMP_SPACE " - bpp: %i (grayscale: %i)\n"
-                  STAMP_SPACE " - red: offset: %i, length: %i, MSB: %i\n"
-                  STAMP_SPACE " - green: offset: %i, length: %i, MSB: %i\n"
-                  STAMP_SPACE " - blue: offset: %i, length: %i, MSB: %i\n"
-                  STAMP_SPACE " - transp: offset: %i, length: %i, MSB: %i\n",
-                  finfo->type, finfo->type_aux, finfo->visual,
-                  vinfo->bits_per_pixel, vinfo->grayscale,
-                  vinfo->red.offset, vinfo->red.length, vinfo->red.msb_right,
-                  vinfo->green.offset, vinfo->green.length,
-                  vinfo->green.msb_right,
-                  vinfo->blue.offset, vinfo->blue.length,
-                  vinfo->blue.msb_right,
-                  vinfo->transp.offset, vinfo->transp.length,
-                  vinfo->transp.msb_right);
-
-       /* We only handle packed formats at the moment. */
-       if (finfo->type != FB_TYPE_PACKED_PIXELS)
-               return 0;
-
-       /* We only handle true-colour frame buffers at the moment. */
-       switch(finfo->visual) {
-               case FB_VISUAL_TRUECOLOR:
-               case FB_VISUAL_DIRECTCOLOR:
-                       if (vinfo->grayscale != 0)
-                               return 0;
-               break;
-               default:
-                       return 0;
-       }
-
-       /* We only support formats with MSBs on the left. */
-       if (vinfo->red.msb_right != 0 || vinfo->green.msb_right != 0 ||
-           vinfo->blue.msb_right != 0)
-               return 0;
-
-       /* Work out the format type from the offsets. We only support RGBA and
-        * ARGB at the moment. */
-       type = PIXMAN_TYPE_OTHER;
-
-       if ((vinfo->transp.offset >= vinfo->red.offset ||
-            vinfo->transp.length == 0) &&
-           vinfo->red.offset >= vinfo->green.offset &&
-           vinfo->green.offset >= vinfo->blue.offset)
-               type = PIXMAN_TYPE_ARGB;
-       else if (vinfo->red.offset >= vinfo->green.offset &&
-                vinfo->green.offset >= vinfo->blue.offset &&
-                vinfo->blue.offset >= vinfo->transp.offset)
-               type = PIXMAN_TYPE_RGBA;
-
-       if (type == PIXMAN_TYPE_OTHER)
-               return 0;
-
-       /* Build the format. */
-       return PIXMAN_FORMAT(vinfo->bits_per_pixel, type,
-                            vinfo->transp.length,
-                            vinfo->red.length,
-                            vinfo->green.length,
-                            vinfo->blue.length);
-}
-
-static int
-calculate_refresh_rate(struct fb_var_screeninfo *vinfo)
-{
-       uint64_t quot;
-
-       /* Calculate monitor refresh rate. Default is 60 Hz. Units are mHz. */
-       quot = (vinfo->upper_margin + vinfo->lower_margin + vinfo->yres);
-       quot *= (vinfo->left_margin + vinfo->right_margin + vinfo->xres);
-       quot *= vinfo->pixclock;
-
-       if (quot > 0) {
-               uint64_t refresh_rate;
-
-               refresh_rate = 1000000000000000LLU / quot;
-               if (refresh_rate > 200000)
-                       refresh_rate = 200000; /* cap at 200 Hz */
-
-               return refresh_rate;
-       }
-
-       return 60 * 1000; /* default to 60 Hz */
-}
-
-static int
-fbdev_query_screen_info(struct fbdev_output *output, int fd,
-                        struct fbdev_screeninfo *info)
-{
-       struct fb_var_screeninfo varinfo;
-       struct fb_fix_screeninfo fixinfo;
-
-       /* Probe the device for screen information. */
-       if (ioctl(fd, FBIOGET_FSCREENINFO, &fixinfo) < 0 ||
-           ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
-               return -1;
-       }
-
-       /* Store the pertinent data. */
-       info->x_resolution = varinfo.xres;
-       info->y_resolution = varinfo.yres;
-       info->width_mm = varinfo.width;
-       info->height_mm = varinfo.height;
-       info->bits_per_pixel = varinfo.bits_per_pixel;
-
-       info->buffer_length = fixinfo.smem_len;
-       info->line_length = fixinfo.line_length;
-       strncpy(info->id, fixinfo.id, sizeof(info->id));
-       info->id[sizeof(info->id)-1] = '\0';
-
-       info->pixel_format = calculate_pixman_format(&varinfo, &fixinfo);
-       info->refresh_rate = calculate_refresh_rate(&varinfo);
-
-       if (info->pixel_format == 0) {
-               weston_log("Frame buffer uses an unsupported format.\n");
-               return -1;
-       }
-
-       return 1;
-}
-
-static int
-fbdev_set_screen_info(struct fbdev_output *output, int fd,
-                      struct fbdev_screeninfo *info)
-{
-       struct fb_var_screeninfo varinfo;
-
-       /* Grab the current screen information. */
-       if (ioctl(fd, FBIOGET_VSCREENINFO, &varinfo) < 0) {
-               return -1;
-       }
-
-       /* Update the information. */
-       varinfo.xres = info->x_resolution;
-       varinfo.yres = info->y_resolution;
-       varinfo.width = info->width_mm;
-       varinfo.height = info->height_mm;
-       varinfo.bits_per_pixel = info->bits_per_pixel;
-
-       /* Try to set up an ARGB (x8r8g8b8) pixel format. */
-       varinfo.grayscale = 0;
-       varinfo.transp.offset = 24;
-       varinfo.transp.length = 0;
-       varinfo.transp.msb_right = 0;
-       varinfo.red.offset = 16;
-       varinfo.red.length = 8;
-       varinfo.red.msb_right = 0;
-       varinfo.green.offset = 8;
-       varinfo.green.length = 8;
-       varinfo.green.msb_right = 0;
-       varinfo.blue.offset = 0;
-       varinfo.blue.length = 8;
-       varinfo.blue.msb_right = 0;
-
-       /* Set the device's screen information. */
-       if (ioctl(fd, FBIOPUT_VSCREENINFO, &varinfo) < 0) {
-               return -1;
-       }
-
-       return 1;
-}
-
-static void fbdev_frame_buffer_destroy(struct fbdev_output *output);
-
-/* Returns an FD for the frame buffer device. */
-static int
-fbdev_frame_buffer_open(struct fbdev_output *output, const char *fb_dev,
-                        struct fbdev_screeninfo *screen_info)
-{
-       int fd = -1;
-
-       weston_log("Opening fbdev frame buffer.\n");
-
-       /* Open the frame buffer device. */
-       fd = open(fb_dev, O_RDWR | O_CLOEXEC);
-       if (fd < 0) {
-               weston_log("Failed to open frame buffer device ‘%s’: %s\n",
-                          fb_dev, strerror(errno));
-               return -1;
-       }
-
-       /* Grab the screen info. */
-       if (fbdev_query_screen_info(output, fd, screen_info) < 0) {
-               weston_log("Failed to get frame buffer info: %s\n",
-                          strerror(errno));
-
-               close(fd);
-               return -1;
-       }
-
-       return fd;
-}
-
-/* Closes the FD on success or failure. */
-static int
-fbdev_frame_buffer_map(struct fbdev_output *output, int fd)
-{
-       int retval = -1;
-
-       weston_log("Mapping fbdev frame buffer.\n");
-
-       /* Map the frame buffer. Write-only mode, since we don't want to read
-        * anything back (because it's slow). */
-       output->fb = mmap(NULL, output->fb_info.buffer_length,
-                         PROT_WRITE, MAP_SHARED, fd, 0);
-       if (output->fb == MAP_FAILED) {
-               weston_log("Failed to mmap frame buffer: %s\n",
-                          strerror(errno));
-               goto out_close;
-       }
-
-       /* Create a pixman image to wrap the memory mapped frame buffer. */
-       output->hw_surface =
-               pixman_image_create_bits(output->fb_info.pixel_format,
-                                        output->fb_info.x_resolution,
-                                        output->fb_info.y_resolution,
-                                        output->fb,
-                                        output->fb_info.line_length);
-       if (output->hw_surface == NULL) {
-               weston_log("Failed to create surface for frame buffer.\n");
-               goto out_unmap;
-       }
-
-       /* Success! */
-       retval = 0;
-
-out_unmap:
-       if (retval != 0 && output->fb != NULL)
-               fbdev_frame_buffer_destroy(output);
-
-out_close:
-       if (fd >= 0)
-               close(fd);
-
-       return retval;
-}
-
-static void
-fbdev_frame_buffer_destroy(struct fbdev_output *output)
-{
-       weston_log("Destroying fbdev frame buffer.\n");
-
-       if (munmap(output->fb, output->fb_info.buffer_length) < 0)
-               weston_log("Failed to munmap frame buffer: %s\n",
-                          strerror(errno));
-
-       output->fb = NULL;
-}
-
-static void fbdev_output_destroy(struct weston_output *base);
-static void fbdev_output_disable(struct weston_output *base);
-
-static int
-fbdev_output_create(struct fbdev_backend *backend,
-                    const char *device)
-{
-       struct fbdev_output *output;
-       int fb_fd;
-       struct wl_event_loop *loop;
-
-       weston_log("Creating fbdev output.\n");
-
-       output = zalloc(sizeof *output);
-       if (output == NULL)
-               return -1;
-
-       output->backend = backend;
-       output->device = strdup(device);
-
-       /* Create the frame buffer. */
-       fb_fd = fbdev_frame_buffer_open(output, device, &output->fb_info);
-       if (fb_fd < 0) {
-               weston_log("Creating frame buffer failed.\n");
-               goto out_free;
-       }
-
-       if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
-               weston_log("Mapping frame buffer failed.\n");
-               goto out_free;
-       }
-
-       output->base.start_repaint_loop = fbdev_output_start_repaint_loop;
-       output->base.repaint = fbdev_output_repaint;
-       output->base.destroy = fbdev_output_destroy;
-
-       /* only one static mode in list */
-       output->mode.flags =
-               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-       output->mode.width = output->fb_info.x_resolution;
-       output->mode.height = output->fb_info.y_resolution;
-       output->mode.refresh = output->fb_info.refresh_rate;
-       wl_list_init(&output->base.mode_list);
-       wl_list_insert(&output->base.mode_list, &output->mode.link);
-
-       output->base.current_mode = &output->mode;
-       output->base.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
-       output->base.make = "unknown";
-       output->base.model = output->fb_info.id;
-       output->base.name = strdup("fbdev");
-
-       weston_output_init(&output->base, backend->compositor,
-                          0, 0, output->fb_info.width_mm,
-                          output->fb_info.height_mm,
-                          backend->output_transform,
-                          1);
-
-       if (pixman_renderer_output_create(&output->base) < 0)
-               goto out_hw_surface;
-
-       loop = wl_display_get_event_loop(backend->compositor->wl_display);
-       output->finish_frame_timer =
-               wl_event_loop_add_timer(loop, finish_frame_handler, output);
-
-       weston_compositor_add_output(backend->compositor, &output->base);
-
-       weston_log("fbdev output %d×%d px\n",
-                  output->mode.width, output->mode.height);
-       weston_log_continue(STAMP_SPACE "guessing %d Hz and 96 dpi\n",
-                           output->mode.refresh / 1000);
-
-       return 0;
-
-out_hw_surface:
-       pixman_image_unref(output->hw_surface);
-       output->hw_surface = NULL;
-       weston_output_destroy(&output->base);
-       fbdev_frame_buffer_destroy(output);
-out_free:
-       free(output->device);
-       free(output);
-
-       return -1;
-}
-
-static void
-fbdev_output_destroy(struct weston_output *base)
-{
-       struct fbdev_output *output = to_fbdev_output(base);
-
-       weston_log("Destroying fbdev output.\n");
-
-       /* Close the frame buffer. */
-       fbdev_output_disable(base);
-
-       if (base->renderer_state != NULL)
-               pixman_renderer_output_destroy(base);
-
-       /* Remove the output. */
-       weston_output_destroy(&output->base);
-
-       free(output->device);
-       free(output);
-}
-
-/* strcmp()-style return values. */
-static int
-compare_screen_info (const struct fbdev_screeninfo *a,
-                     const struct fbdev_screeninfo *b)
-{
-       if (a->x_resolution == b->x_resolution &&
-           a->y_resolution == b->y_resolution &&
-           a->width_mm == b->width_mm &&
-           a->height_mm == b->height_mm &&
-           a->bits_per_pixel == b->bits_per_pixel &&
-           a->pixel_format == b->pixel_format &&
-           a->refresh_rate == b->refresh_rate)
-               return 0;
-
-       return 1;
-}
-
-static int
-fbdev_output_reenable(struct fbdev_backend *backend,
-                      struct weston_output *base)
-{
-       struct fbdev_output *output = to_fbdev_output(base);
-       struct fbdev_screeninfo new_screen_info;
-       int fb_fd;
-       char *device;
-
-       weston_log("Re-enabling fbdev output.\n");
-
-       /* Create the frame buffer. */
-       fb_fd = fbdev_frame_buffer_open(output, output->device,
-                                       &new_screen_info);
-       if (fb_fd < 0) {
-               weston_log("Creating frame buffer failed.\n");
-               goto err;
-       }
-
-       /* Check whether the frame buffer details have changed since we were
-        * disabled. */
-       if (compare_screen_info (&output->fb_info, &new_screen_info) != 0) {
-               /* Perform a mode-set to restore the old mode. */
-               if (fbdev_set_screen_info(output, fb_fd,
-                                         &output->fb_info) < 0) {
-                       weston_log("Failed to restore mode settings. "
-                                  "Attempting to re-open output anyway.\n");
-               }
-
-               close(fb_fd);
-
-               /* Remove and re-add the output so that resources depending on
-                * the frame buffer X/Y resolution (such as the shadow buffer)
-                * are re-initialised. */
-               device = strdup(output->device);
-               fbdev_output_destroy(&output->base);
-               fbdev_output_create(backend, device);
-               free(device);
-
-               return 0;
-       }
-
-       /* Map the device if it has the same details as before. */
-       if (fbdev_frame_buffer_map(output, fb_fd) < 0) {
-               weston_log("Mapping frame buffer failed.\n");
-               goto err;
-       }
-
-       return 0;
-
-err:
-       return -1;
-}
-
-/* NOTE: This leaves output->fb_info populated, caching data so that if
- * fbdev_output_reenable() is called again, it can determine whether a mode-set
- * is needed. */
-static void
-fbdev_output_disable(struct weston_output *base)
-{
-       struct fbdev_output *output = to_fbdev_output(base);
-
-       weston_log("Disabling fbdev output.\n");
-
-       if (output->hw_surface != NULL) {
-               pixman_image_unref(output->hw_surface);
-               output->hw_surface = NULL;
-       }
-
-       fbdev_frame_buffer_destroy(output);
-}
-
-static void
-fbdev_backend_destroy(struct weston_compositor *base)
-{
-       struct fbdev_backend *backend = to_fbdev_backend(base);
-
-       udev_input_destroy(&backend->input);
-
-       /* Destroy the output. */
-       weston_compositor_shutdown(base);
-
-       /* Chain up. */
-       weston_launcher_destroy(base->launcher);
-
-       free(backend);
-}
-
-static void
-session_notify(struct wl_listener *listener, void *data)
-{
-       struct weston_compositor *compositor = data;
-       struct fbdev_backend *backend = to_fbdev_backend(compositor);
-       struct weston_output *output;
-
-       if (compositor->session_active) {
-               weston_log("entering VT\n");
-               compositor->state = backend->prev_state;
-
-               wl_list_for_each(output, &compositor->output_list, link) {
-                       fbdev_output_reenable(backend, output);
-               }
-
-               weston_compositor_damage_all(compositor);
-
-               udev_input_enable(&backend->input);
-       } else {
-               weston_log("leaving VT\n");
-               udev_input_disable(&backend->input);
-
-               wl_list_for_each(output, &compositor->output_list, link) {
-                       fbdev_output_disable(output);
-               }
-
-               backend->prev_state = compositor->state;
-               weston_compositor_offscreen(compositor);
-
-               /* If we have a repaint scheduled (from the idle handler), make
-                * sure we cancel that so we don't try to pageflip when we're
-                * vt switched away.  The OFFSCREEN state will prevent
-                * further attempts at repainting.  When we switch
-                * back, we schedule a repaint, which will process
-                * pending frame callbacks. */
-
-               wl_list_for_each(output,
-                                &compositor->output_list, link) {
-                       output->repaint_needed = 0;
-               }
-       }
-}
-
-static void
-fbdev_restore(struct weston_compositor *compositor)
-{
-       weston_launcher_restore(compositor->launcher);
-}
-
-static struct fbdev_backend *
-fbdev_backend_create(struct weston_compositor *compositor,
-                     struct weston_fbdev_backend_config *param)
-{
-       struct fbdev_backend *backend;
-       const char *seat_id = default_seat;
-
-       weston_log("initializing fbdev backend\n");
-
-       backend = zalloc(sizeof *backend);
-       if (backend == NULL)
-               return NULL;
-
-       backend->compositor = compositor;
-       if (weston_compositor_set_presentation_clock_software(
-                                                       compositor) < 0)
-               goto out_compositor;
-
-       backend->udev = udev_new();
-       if (backend->udev == NULL) {
-               weston_log("Failed to initialize udev context.\n");
-               goto out_compositor;
-       }
-
-       /* Set up the TTY. */
-       backend->session_listener.notify = session_notify;
-       wl_signal_add(&compositor->session_signal,
-                     &backend->session_listener);
-       compositor->launcher =
-               weston_launcher_connect(compositor, param->tty, "seat0", false);
-       if (!compositor->launcher) {
-               weston_log("fatal: fbdev backend should be run "
-                          "using weston-launch binary or as root\n");
-               goto out_udev;
-       }
-
-       backend->base.destroy = fbdev_backend_destroy;
-       backend->base.restore = fbdev_restore;
-
-       backend->prev_state = WESTON_COMPOSITOR_ACTIVE;
-       backend->output_transform = param->output_transform;
-
-       weston_setup_vt_switch_bindings(compositor);
-
-       if (pixman_renderer_init(compositor) < 0)
-               goto out_launcher;
-
-       if (fbdev_output_create(backend, param->device) < 0)
-               goto out_launcher;
-
-       udev_input_init(&backend->input, compositor, backend->udev,
-                       seat_id, param->configure_device);
-
-       compositor->backend = &backend->base;
-       return backend;
-
-out_launcher:
-       weston_launcher_destroy(compositor->launcher);
-
-out_udev:
-       udev_unref(backend->udev);
-
-out_compositor:
-       weston_compositor_shutdown(compositor);
-       free(backend);
-
-       return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_fbdev_backend_config *config)
-{
-       /* TODO: Ideally, available frame buffers should be enumerated using
-        * udev, rather than passing a device node in as a parameter. */
-       config->tty = 0; /* default to current tty */
-       config->device = "/dev/fb0"; /* default frame buffer */
-       config->output_transform = WL_OUTPUT_TRANSFORM_NORMAL;
-}
-
-WL_EXPORT int
-backend_init(struct weston_compositor *compositor,
-            struct weston_backend_config *config_base)
-{
-       struct fbdev_backend *b;
-       struct weston_fbdev_backend_config config = {{ 0, }};
-
-       if (config_base == NULL ||
-           config_base->struct_version != WESTON_FBDEV_BACKEND_CONFIG_VERSION ||
-           config_base->struct_size > sizeof(struct weston_fbdev_backend_config)) {
-               weston_log("fbdev backend config structure is invalid\n");
-               return -1;
-       }
-
-       config_init_to_defaults(&config);
-       memcpy(&config, config_base, config_base->struct_size);
-
-       b = fbdev_backend_create(compositor, &config);
-       if (b == NULL)
-               return -1;
-       return 0;
-}
diff --git a/src/compositor-fbdev.h b/src/compositor-fbdev.h
deleted file mode 100644 (file)
index 9b5bf8e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright © 2016 Benoit Gschwind
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_COMPOSITOR_FBDEV_H
-#define WESTON_COMPOSITOR_FBDEV_H
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#include "compositor.h"
-
-#define WESTON_FBDEV_BACKEND_CONFIG_VERSION 1
-
-struct libinput_device;
-
-struct weston_fbdev_backend_config {
-       struct weston_backend_config base;
-
-       int tty;
-       char *device;
-
-       uint32_t output_transform;
-
-       /** Callback used to configure input devices.
-        *
-        * This function will be called by the backend when a new input device
-        * needs to be configured.
-        * If NULL the device will use the default configuration.
-        */
-       void (*configure_device)(struct weston_compositor *compositor,
-                                struct libinput_device *device);
-};
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* WESTON_COMPOSITOR_FBDEV_H */
diff --git a/src/compositor-headless.c b/src/compositor-headless.c
deleted file mode 100644 (file)
index b78c321..0000000
+++ /dev/null
@@ -1,258 +0,0 @@
-/*
- * Copyright © 2010-2011 Benjamin Franzke
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <stdbool.h>
-
-#include "compositor.h"
-#include "compositor-headless.h"
-#include "shared/helpers.h"
-#include "pixman-renderer.h"
-#include "presentation-time-server-protocol.h"
-
-struct headless_backend {
-       struct weston_backend base;
-       struct weston_compositor *compositor;
-
-       struct weston_seat fake_seat;
-       bool use_pixman;
-};
-
-struct headless_output {
-       struct weston_output base;
-
-       struct weston_mode mode;
-       struct wl_event_source *finish_frame_timer;
-       uint32_t *image_buf;
-       pixman_image_t *image;
-};
-
-static void
-headless_output_start_repaint_loop(struct weston_output *output)
-{
-       struct timespec ts;
-
-       weston_compositor_read_presentation_clock(output->compositor, &ts);
-       weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
-}
-
-static int
-finish_frame_handler(void *data)
-{
-       struct headless_output *output = data;
-       struct timespec ts;
-
-       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
-       weston_output_finish_frame(&output->base, &ts, 0);
-
-       return 1;
-}
-
-static int
-headless_output_repaint(struct weston_output *output_base,
-                      pixman_region32_t *damage)
-{
-       struct headless_output *output = (struct headless_output *) output_base;
-       struct weston_compositor *ec = output->base.compositor;
-
-       ec->renderer->repaint_output(&output->base, damage);
-
-       pixman_region32_subtract(&ec->primary_plane.damage,
-                                &ec->primary_plane.damage, damage);
-
-       wl_event_source_timer_update(output->finish_frame_timer, 16);
-
-       return 0;
-}
-
-static void
-headless_output_destroy(struct weston_output *output_base)
-{
-       struct headless_output *output = (struct headless_output *) output_base;
-       struct headless_backend *b =
-                       (struct headless_backend *) output->base.compositor->backend;
-
-       wl_event_source_remove(output->finish_frame_timer);
-
-       if (b->use_pixman) {
-               pixman_renderer_output_destroy(&output->base);
-               pixman_image_unref(output->image);
-               free(output->image_buf);
-       }
-
-       weston_output_destroy(&output->base);
-
-       free(output);
-
-       return;
-}
-
-static int
-headless_backend_create_output(struct headless_backend *b,
-                              struct weston_headless_backend_config *config)
-{
-       struct weston_compositor *c = b->compositor;
-       struct headless_output *output;
-       struct wl_event_loop *loop;
-
-       output = zalloc(sizeof *output);
-       if (output == NULL)
-               return -1;
-
-       output->mode.flags =
-               WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-       output->mode.width = config->width;
-       output->mode.height = config->height;
-       output->mode.refresh = 60000;
-       wl_list_init(&output->base.mode_list);
-       wl_list_insert(&output->base.mode_list, &output->mode.link);
-
-       output->base.current_mode = &output->mode;
-       weston_output_init(&output->base, c, 0, 0, config->width,
-                          config->height, config->transform, 1);
-
-       output->base.make = "weston";
-       output->base.model = "headless";
-
-       loop = wl_display_get_event_loop(c->wl_display);
-       output->finish_frame_timer =
-               wl_event_loop_add_timer(loop, finish_frame_handler, output);
-
-       output->base.start_repaint_loop = headless_output_start_repaint_loop;
-       output->base.repaint = headless_output_repaint;
-       output->base.destroy = headless_output_destroy;
-       output->base.assign_planes = NULL;
-       output->base.set_backlight = NULL;
-       output->base.set_dpms = NULL;
-       output->base.switch_mode = NULL;
-
-       if (b->use_pixman) {
-               output->image_buf = malloc(config->width * config->height * 4);
-               if (!output->image_buf)
-                       return -1;
-
-               output->image = pixman_image_create_bits(PIXMAN_x8r8g8b8,
-                                                        config->width,
-                                                        config->height,
-                                                        output->image_buf,
-                                                        config->width * 4);
-
-               if (pixman_renderer_output_create(&output->base) < 0)
-                       return -1;
-
-               pixman_renderer_output_set_buffer(&output->base,
-                                                 output->image);
-       }
-
-       weston_compositor_add_output(c, &output->base);
-
-       return 0;
-}
-
-static void
-headless_restore(struct weston_compositor *ec)
-{
-}
-
-static void
-headless_destroy(struct weston_compositor *ec)
-{
-       struct headless_backend *b = (struct headless_backend *) ec->backend;
-
-       weston_compositor_shutdown(ec);
-
-       free(b);
-}
-
-static struct headless_backend *
-headless_backend_create(struct weston_compositor *compositor,
-                       struct weston_headless_backend_config *config)
-{
-       struct headless_backend *b;
-
-       b = zalloc(sizeof *b);
-       if (b == NULL)
-               return NULL;
-
-       b->compositor = compositor;
-       if (weston_compositor_set_presentation_clock_software(compositor) < 0)
-               goto err_free;
-
-       b->base.destroy = headless_destroy;
-       b->base.restore = headless_restore;
-
-       b->use_pixman = config->use_pixman;
-       if (b->use_pixman) {
-               pixman_renderer_init(compositor);
-       }
-       if (headless_backend_create_output(b, config) < 0)
-               goto err_input;
-
-       if (!b->use_pixman && noop_renderer_init(compositor) < 0)
-               goto err_input;
-
-       compositor->backend = &b->base;
-       return b;
-
-err_input:
-       weston_compositor_shutdown(compositor);
-err_free:
-       free(b);
-       return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_headless_backend_config *config)
-{
-}
-
-WL_EXPORT int
-backend_init(struct weston_compositor *compositor,
-            struct weston_backend_config *config_base)
-{
-       struct headless_backend *b;
-       struct weston_headless_backend_config config = {{ 0, }};
-
-       if (config_base == NULL ||
-           config_base->struct_version != WESTON_HEADLESS_BACKEND_CONFIG_VERSION ||
-           config_base->struct_size > sizeof(struct weston_headless_backend_config)) {
-               weston_log("headless backend config structure is invalid\n");
-               return -1;
-       }
-
-       config_init_to_defaults(&config);
-       memcpy(&config, config_base, config_base->struct_size);
-
-       b = headless_backend_create(compositor, &config);
-       if (b == NULL)
-               return -1;
-
-       return 0;
-}
diff --git a/src/compositor-headless.h b/src/compositor-headless.h
deleted file mode 100644 (file)
index 79f39c8..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright © 2016 Benoit Gschwind
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_COMPOSITOR_HEADLESS_H
-#define WESTON_COMPOSITOR_HEADLESS_H
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#include "compositor.h"
-
-#define WESTON_HEADLESS_BACKEND_CONFIG_VERSION 1
-
-struct weston_headless_backend_config {
-       struct weston_backend_config base;
-
-       int width;
-       int height;
-
-       /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
-       int use_pixman;
-
-       uint32_t transform;
-};
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* WESTON_COMPOSITOR_HEADLESS_H */
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
deleted file mode 100644 (file)
index d74dd5e..0000000
+++ /dev/null
@@ -1,1331 +0,0 @@
-/*
- * Copyright © 2013 Hardening <rdp.effort@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-#include <linux/input.h>
-
-#if HAVE_FREERDP_VERSION_H
-#include <freerdp/version.h>
-#else
-/* assume it's a early 1.1 version */
-#define FREERDP_VERSION_MAJOR 1
-#define FREERDP_VERSION_MINOR 1
-#define FREERDP_VERSION_REVISION 0
-#endif
-
-#define FREERDP_VERSION_NUMBER ((FREERDP_VERSION_MAJOR * 0x10000) + \
-               (FREERDP_VERSION_MINOR * 0x100) + FREERDP_VERSION_REVISION)
-
-
-#if FREERDP_VERSION_NUMBER >= 0x10201
-#define HAVE_SKIP_COMPRESSION
-#endif
-
-#if FREERDP_VERSION_NUMBER < 0x10202
-#      define FREERDP_CB_RET_TYPE void
-#      define FREERDP_CB_RETURN(V) return
-#      define NSC_RESET(C, W, H)
-#      define RFX_RESET(C, W, H) do { rfx_context_reset(C); C->width = W; C->height = H; } while(0)
-#else
-#if FREERDP_VERSION_MAJOR >= 2
-#      define NSC_RESET(C, W, H) nsc_context_reset(C, W, H)
-#      define RFX_RESET(C, W, H) rfx_context_reset(C, W, H)
-#else
-#      define NSC_RESET(C, W, H) do { nsc_context_reset(C); C->width = W; C->height = H; } while(0)
-#      define RFX_RESET(C, W, H) do { rfx_context_reset(C); C->width = W; C->height = H; } while(0)
-#endif
-#define FREERDP_CB_RET_TYPE BOOL
-#define FREERDP_CB_RETURN(V) return TRUE
-#endif
-
-#include <freerdp/freerdp.h>
-#include <freerdp/listener.h>
-#include <freerdp/update.h>
-#include <freerdp/input.h>
-#include <freerdp/codec/color.h>
-#include <freerdp/codec/rfx.h>
-#include <freerdp/codec/nsc.h>
-#include <freerdp/locale/keyboard.h>
-#include <winpr/input.h>
-
-#include "shared/helpers.h"
-#include "compositor.h"
-#include "compositor-rdp.h"
-#include "pixman-renderer.h"
-
-#define MAX_FREERDP_FDS 32
-#define DEFAULT_AXIS_STEP_DISTANCE 10
-#define RDP_MODE_FREQ 60 * 1000
-
-
-struct rdp_output;
-
-struct rdp_backend {
-       struct weston_backend base;
-       struct weston_compositor *compositor;
-
-       freerdp_listener *listener;
-       struct wl_event_source *listener_events[MAX_FREERDP_FDS];
-       struct rdp_output *output;
-
-       char *server_cert;
-       char *server_key;
-       char *rdp_key;
-       int tls_enabled;
-       int no_clients_resize;
-};
-
-enum peer_item_flags {
-       RDP_PEER_ACTIVATED      = (1 << 0),
-       RDP_PEER_OUTPUT_ENABLED = (1 << 1),
-};
-
-struct rdp_peers_item {
-       int flags;
-       freerdp_peer *peer;
-       struct weston_seat *seat;
-
-       struct wl_list link;
-};
-
-struct rdp_output {
-       struct weston_output base;
-       struct wl_event_source *finish_frame_timer;
-       pixman_image_t *shadow_surface;
-
-       struct wl_list peers;
-};
-
-struct rdp_peer_context {
-       rdpContext _p;
-
-       struct rdp_backend *rdpBackend;
-       struct wl_event_source *events[MAX_FREERDP_FDS];
-       RFX_CONTEXT *rfx_context;
-       wStream *encode_stream;
-       RFX_RECT *rfx_rects;
-       NSC_CONTEXT *nsc_context;
-
-       struct rdp_peers_item item;
-};
-typedef struct rdp_peer_context RdpPeerContext;
-
-static void
-rdp_peer_refresh_rfx(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
-{
-       int width, height, nrects, i;
-       pixman_box32_t *region, *rects;
-       uint32_t *ptr;
-       RFX_RECT *rfxRect;
-       rdpUpdate *update = peer->update;
-       SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
-       RdpPeerContext *context = (RdpPeerContext *)peer->context;
-
-       Stream_Clear(context->encode_stream);
-       Stream_SetPosition(context->encode_stream, 0);
-
-       width = (damage->extents.x2 - damage->extents.x1);
-       height = (damage->extents.y2 - damage->extents.y1);
-
-#ifdef HAVE_SKIP_COMPRESSION
-       cmd->skipCompression = TRUE;
-#else
-       memset(cmd, 0, sizeof(*cmd));
-#endif
-       cmd->destLeft = damage->extents.x1;
-       cmd->destTop = damage->extents.y1;
-       cmd->destRight = damage->extents.x2;
-       cmd->destBottom = damage->extents.y2;
-       cmd->bpp = 32;
-       cmd->codecID = peer->settings->RemoteFxCodecId;
-       cmd->width = width;
-       cmd->height = height;
-
-       ptr = pixman_image_get_data(image) + damage->extents.x1 +
-                               damage->extents.y1 * (pixman_image_get_stride(image) / sizeof(uint32_t));
-
-       rects = pixman_region32_rectangles(damage, &nrects);
-       context->rfx_rects = realloc(context->rfx_rects, nrects * sizeof *rfxRect);
-
-       for (i = 0; i < nrects; i++) {
-               region = &rects[i];
-               rfxRect = &context->rfx_rects[i];
-
-               rfxRect->x = (region->x1 - damage->extents.x1);
-               rfxRect->y = (region->y1 - damage->extents.y1);
-               rfxRect->width = (region->x2 - region->x1);
-               rfxRect->height = (region->y2 - region->y1);
-       }
-
-       rfx_compose_message(context->rfx_context, context->encode_stream, context->rfx_rects, nrects,
-                       (BYTE *)ptr, width, height,
-                       pixman_image_get_stride(image)
-       );
-
-       cmd->bitmapDataLength = Stream_GetPosition(context->encode_stream);
-       cmd->bitmapData = Stream_Buffer(context->encode_stream);
-
-       update->SurfaceBits(update->context, cmd);
-}
-
-
-static void
-rdp_peer_refresh_nsc(pixman_region32_t *damage, pixman_image_t *image, freerdp_peer *peer)
-{
-       int width, height;
-       uint32_t *ptr;
-       rdpUpdate *update = peer->update;
-       SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
-       RdpPeerContext *context = (RdpPeerContext *)peer->context;
-
-       Stream_Clear(context->encode_stream);
-       Stream_SetPosition(context->encode_stream, 0);
-
-       width = (damage->extents.x2 - damage->extents.x1);
-       height = (damage->extents.y2 - damage->extents.y1);
-
-#ifdef HAVE_SKIP_COMPRESSION
-       cmd->skipCompression = TRUE;
-#else
-       memset(cmd, 0, sizeof(*cmd));
-#endif
-       cmd->destLeft = damage->extents.x1;
-       cmd->destTop = damage->extents.y1;
-       cmd->destRight = damage->extents.x2;
-       cmd->destBottom = damage->extents.y2;
-       cmd->bpp = 32;
-       cmd->codecID = peer->settings->NSCodecId;
-       cmd->width = width;
-       cmd->height = height;
-
-       ptr = pixman_image_get_data(image) + damage->extents.x1 +
-                               damage->extents.y1 * (pixman_image_get_stride(image) / sizeof(uint32_t));
-
-       nsc_compose_message(context->nsc_context, context->encode_stream, (BYTE *)ptr,
-                       cmd->width,     cmd->height,
-                       pixman_image_get_stride(image));
-       cmd->bitmapDataLength = Stream_GetPosition(context->encode_stream);
-       cmd->bitmapData = Stream_Buffer(context->encode_stream);
-       update->SurfaceBits(update->context, cmd);
-}
-
-static void
-pixman_image_flipped_subrect(const pixman_box32_t *rect, pixman_image_t *img, BYTE *dest)
-{
-       int stride = pixman_image_get_stride(img);
-       int h;
-       int toCopy = (rect->x2 - rect->x1) * 4;
-       int height = (rect->y2 - rect->y1);
-       const BYTE *src = (const BYTE *)pixman_image_get_data(img);
-       src += ((rect->y2-1) * stride) + (rect->x1 * 4);
-
-       for (h = 0; h < height; h++, src -= stride, dest += toCopy)
-                  memcpy(dest, src, toCopy);
-}
-
-static void
-rdp_peer_refresh_raw(pixman_region32_t *region, pixman_image_t *image, freerdp_peer *peer)
-{
-       rdpUpdate *update = peer->update;
-       SURFACE_BITS_COMMAND *cmd = &update->surface_bits_command;
-       SURFACE_FRAME_MARKER *marker = &update->surface_frame_marker;
-       pixman_box32_t *rect, subrect;
-       int nrects, i;
-       int heightIncrement, remainingHeight, top;
-
-       rect = pixman_region32_rectangles(region, &nrects);
-       if (!nrects)
-               return;
-
-       marker->frameId++;
-       marker->frameAction = SURFACECMD_FRAMEACTION_BEGIN;
-       update->SurfaceFrameMarker(peer->context, marker);
-
-       memset(cmd, 0, sizeof(*cmd));
-       cmd->bpp = 32;
-       cmd->codecID = 0;
-
-       for (i = 0; i < nrects; i++, rect++) {
-               /*weston_log("rect(%d,%d, %d,%d)\n", rect->x1, rect->y1, rect->x2, rect->y2);*/
-               cmd->destLeft = rect->x1;
-               cmd->destRight = rect->x2;
-               cmd->width = rect->x2 - rect->x1;
-
-               heightIncrement = peer->settings->MultifragMaxRequestSize / (16 + cmd->width * 4);
-               remainingHeight = rect->y2 - rect->y1;
-               top = rect->y1;
-
-               subrect.x1 = rect->x1;
-               subrect.x2 = rect->x2;
-
-               while (remainingHeight) {
-                          cmd->height = (remainingHeight > heightIncrement) ? heightIncrement : remainingHeight;
-                          cmd->destTop = top;
-                          cmd->destBottom = top + cmd->height;
-                          cmd->bitmapDataLength = cmd->width * cmd->height * 4;
-                          cmd->bitmapData = (BYTE *)realloc(cmd->bitmapData, cmd->bitmapDataLength);
-
-                          subrect.y1 = top;
-                          subrect.y2 = top + cmd->height;
-                          pixman_image_flipped_subrect(&subrect, image, cmd->bitmapData);
-
-                          /*weston_log("*  sending (%d,%d, %d,%d)\n", subrect.x1, subrect.y1, subrect.x2, subrect.y2); */
-                          update->SurfaceBits(peer->context, cmd);
-
-                          remainingHeight -= cmd->height;
-                          top += cmd->height;
-               }
-       }
-
-       marker->frameAction = SURFACECMD_FRAMEACTION_END;
-       update->SurfaceFrameMarker(peer->context, marker);
-}
-
-static void
-rdp_peer_refresh_region(pixman_region32_t *region, freerdp_peer *peer)
-{
-       RdpPeerContext *context = (RdpPeerContext *)peer->context;
-       struct rdp_output *output = context->rdpBackend->output;
-       rdpSettings *settings = peer->settings;
-
-       if (settings->RemoteFxCodec)
-               rdp_peer_refresh_rfx(region, output->shadow_surface, peer);
-       else if (settings->NSCodec)
-               rdp_peer_refresh_nsc(region, output->shadow_surface, peer);
-       else
-               rdp_peer_refresh_raw(region, output->shadow_surface, peer);
-}
-
-static void
-rdp_output_start_repaint_loop(struct weston_output *output)
-{
-       struct timespec ts;
-
-       weston_compositor_read_presentation_clock(output->compositor, &ts);
-       weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
-}
-
-static int
-rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
-{
-       struct rdp_output *output = container_of(output_base, struct rdp_output, base);
-       struct weston_compositor *ec = output->base.compositor;
-       struct rdp_peers_item *outputPeer;
-
-       pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
-       ec->renderer->repaint_output(&output->base, damage);
-
-       if (pixman_region32_not_empty(damage)) {
-               wl_list_for_each(outputPeer, &output->peers, link) {
-                       if ((outputPeer->flags & RDP_PEER_ACTIVATED) &&
-                                       (outputPeer->flags & RDP_PEER_OUTPUT_ENABLED))
-                       {
-                               rdp_peer_refresh_region(damage, outputPeer->peer);
-                       }
-               }
-       }
-
-       pixman_region32_subtract(&ec->primary_plane.damage,
-                                &ec->primary_plane.damage, damage);
-
-       wl_event_source_timer_update(output->finish_frame_timer, 16);
-       return 0;
-}
-
-static void
-rdp_output_destroy(struct weston_output *output_base)
-{
-       struct rdp_output *output = (struct rdp_output *)output_base;
-
-       wl_event_source_remove(output->finish_frame_timer);
-       free(output);
-}
-
-static int
-finish_frame_handler(void *data)
-{
-       struct rdp_output *output = data;
-       struct timespec ts;
-
-       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
-       weston_output_finish_frame(&output->base, &ts, 0);
-
-       return 1;
-}
-
-static struct weston_mode *
-rdp_insert_new_mode(struct weston_output *output, int width, int height, int rate)
-{
-       struct weston_mode *ret;
-       ret = zalloc(sizeof *ret);
-       if (!ret)
-               return NULL;
-       ret->width = width;
-       ret->height = height;
-       ret->refresh = rate;
-       wl_list_insert(&output->mode_list, &ret->link);
-       return ret;
-}
-
-static struct weston_mode *
-ensure_matching_mode(struct weston_output *output, struct weston_mode *target)
-{
-       struct weston_mode *local;
-
-       wl_list_for_each(local, &output->mode_list, link) {
-               if ((local->width == target->width) && (local->height == target->height))
-                       return local;
-       }
-
-       return rdp_insert_new_mode(output, target->width, target->height, RDP_MODE_FREQ);
-}
-
-static int
-rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode)
-{
-       struct rdp_output *rdpOutput = container_of(output, struct rdp_output, base);
-       struct rdp_peers_item *rdpPeer;
-       rdpSettings *settings;
-       pixman_image_t *new_shadow_buffer;
-       struct weston_mode *local_mode;
-
-       local_mode = ensure_matching_mode(output, target_mode);
-       if (!local_mode) {
-               weston_log("mode %dx%d not available\n", target_mode->width, target_mode->height);
-               return -ENOENT;
-       }
-
-       if (local_mode == output->current_mode)
-               return 0;
-
-       output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
-
-       output->current_mode = local_mode;
-       output->current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
-
-       pixman_renderer_output_destroy(output);
-       pixman_renderer_output_create(output);
-
-       new_shadow_buffer = pixman_image_create_bits(PIXMAN_x8r8g8b8, target_mode->width,
-                       target_mode->height, 0, target_mode->width * 4);
-       pixman_image_composite32(PIXMAN_OP_SRC, rdpOutput->shadow_surface, 0, new_shadow_buffer,
-                       0, 0, 0, 0, 0, 0, target_mode->width, target_mode->height);
-       pixman_image_unref(rdpOutput->shadow_surface);
-       rdpOutput->shadow_surface = new_shadow_buffer;
-
-       wl_list_for_each(rdpPeer, &rdpOutput->peers, link) {
-               settings = rdpPeer->peer->settings;
-               if (settings->DesktopWidth == (UINT32)target_mode->width &&
-                               settings->DesktopHeight == (UINT32)target_mode->height)
-                       continue;
-
-               if (!settings->DesktopResize) {
-                       /* too bad this peer does not support desktop resize */
-                       rdpPeer->peer->Close(rdpPeer->peer);
-               } else {
-                       settings->DesktopWidth = target_mode->width;
-                       settings->DesktopHeight = target_mode->height;
-                       rdpPeer->peer->update->DesktopResize(rdpPeer->peer->context);
-               }
-       }
-       return 0;
-}
-
-static int
-rdp_backend_create_output(struct rdp_backend *b, int width, int height)
-{
-       struct rdp_output *output;
-       struct wl_event_loop *loop;
-       struct weston_mode *currentMode;
-       struct weston_mode initMode;
-
-       output = zalloc(sizeof *output);
-       if (output == NULL)
-               return -1;
-
-       wl_list_init(&output->peers);
-       wl_list_init(&output->base.mode_list);
-
-       initMode.flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
-       initMode.width = width;
-       initMode.height = height;
-       initMode.refresh = RDP_MODE_FREQ;
-
-       currentMode = ensure_matching_mode(&output->base, &initMode);
-       if (!currentMode)
-               goto out_free_output;
-
-       output->base.current_mode = output->base.native_mode = currentMode;
-       weston_output_init(&output->base, b->compositor, 0, 0, width, height,
-                          WL_OUTPUT_TRANSFORM_NORMAL, 1);
-
-       output->base.make = "weston";
-       output->base.model = "rdp";
-       output->shadow_surface = pixman_image_create_bits(PIXMAN_x8r8g8b8,
-                       width, height,
-                   NULL,
-                   width * 4);
-       if (output->shadow_surface == NULL) {
-               weston_log("Failed to create surface for frame buffer.\n");
-               goto out_output;
-       }
-
-       if (pixman_renderer_output_create(&output->base) < 0)
-               goto out_shadow_surface;
-
-       loop = wl_display_get_event_loop(b->compositor->wl_display);
-       output->finish_frame_timer = wl_event_loop_add_timer(loop, finish_frame_handler, output);
-
-       output->base.start_repaint_loop = rdp_output_start_repaint_loop;
-       output->base.repaint = rdp_output_repaint;
-       output->base.destroy = rdp_output_destroy;
-       output->base.assign_planes = NULL;
-       output->base.set_backlight = NULL;
-       output->base.set_dpms = NULL;
-       output->base.switch_mode = rdp_switch_mode;
-       b->output = output;
-
-       weston_compositor_add_output(b->compositor, &output->base);
-       return 0;
-
-out_shadow_surface:
-       pixman_image_unref(output->shadow_surface);
-out_output:
-       weston_output_destroy(&output->base);
-out_free_output:
-       free(output);
-       return -1;
-}
-
-static void
-rdp_restore(struct weston_compositor *ec)
-{
-}
-
-static void
-rdp_destroy(struct weston_compositor *ec)
-{
-       struct rdp_backend *b = (struct rdp_backend *) ec->backend;
-       int i;
-
-       weston_compositor_shutdown(ec);
-       for (i = 0; i < MAX_FREERDP_FDS; i++)
-               if (b->listener_events[i])
-                       wl_event_source_remove(b->listener_events[i]);
-
-       freerdp_listener_free(b->listener);
-
-       free(b->server_cert);
-       free(b->server_key);
-       free(b->rdp_key);
-       free(b);
-}
-
-static
-int rdp_listener_activity(int fd, uint32_t mask, void *data)
-{
-       freerdp_listener* instance = (freerdp_listener *)data;
-
-       if (!(mask & WL_EVENT_READABLE))
-               return 0;
-       if (!instance->CheckFileDescriptor(instance)) {
-               weston_log("failed to check FreeRDP file descriptor\n");
-               return -1;
-       }
-       return 0;
-}
-
-static
-int rdp_implant_listener(struct rdp_backend *b, freerdp_listener* instance)
-{
-       int i, fd;
-       int rcount = 0;
-       void* rfds[MAX_FREERDP_FDS];
-       struct wl_event_loop *loop;
-
-       if (!instance->GetFileDescriptor(instance, rfds, &rcount)) {
-               weston_log("Failed to get FreeRDP file descriptor\n");
-               return -1;
-       }
-
-       loop = wl_display_get_event_loop(b->compositor->wl_display);
-       for (i = 0; i < rcount; i++) {
-               fd = (int)(long)(rfds[i]);
-               b->listener_events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
-                               rdp_listener_activity, instance);
-       }
-
-       for ( ; i < MAX_FREERDP_FDS; i++)
-               b->listener_events[i] = 0;
-       return 0;
-}
-
-
-static FREERDP_CB_RET_TYPE
-rdp_peer_context_new(freerdp_peer* client, RdpPeerContext* context)
-{
-       context->item.peer = client;
-       context->item.flags = RDP_PEER_OUTPUT_ENABLED;
-
-#if FREERDP_VERSION_MAJOR == 1 && FREERDP_VERSION_MINOR == 1
-       context->rfx_context = rfx_context_new();
-#else
-       context->rfx_context = rfx_context_new(TRUE);
-#endif
-       if (!context->rfx_context) {
-               FREERDP_CB_RETURN(FALSE);
-       }
-
-       context->rfx_context->mode = RLGR3;
-       context->rfx_context->width = client->settings->DesktopWidth;
-       context->rfx_context->height = client->settings->DesktopHeight;
-       rfx_context_set_pixel_format(context->rfx_context, RDP_PIXEL_FORMAT_B8G8R8A8);
-
-       context->nsc_context = nsc_context_new();
-       if (!context->nsc_context)
-               goto out_error_nsc;
-
-       nsc_context_set_pixel_format(context->nsc_context, RDP_PIXEL_FORMAT_B8G8R8A8);
-
-       context->encode_stream = Stream_New(NULL, 65536);
-       if (!context->encode_stream)
-               goto out_error_stream;
-
-       FREERDP_CB_RETURN(TRUE);
-
-out_error_nsc:
-       rfx_context_free(context->rfx_context);
-out_error_stream:
-       nsc_context_free(context->nsc_context);
-       FREERDP_CB_RETURN(FALSE);
-}
-
-static void
-rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
-{
-       int i;
-       if (!context)
-               return;
-
-       wl_list_remove(&context->item.link);
-       for (i = 0; i < MAX_FREERDP_FDS; i++) {
-               if (context->events[i])
-                       wl_event_source_remove(context->events[i]);
-       }
-
-       if (context->item.flags & RDP_PEER_ACTIVATED) {
-               weston_seat_release_keyboard(context->item.seat);
-               weston_seat_release_pointer(context->item.seat);
-               /* XXX we should weston_seat_release(context->item.seat); here
-                * but it would crash on reconnect */
-       }
-
-       Stream_Free(context->encode_stream, TRUE);
-       nsc_context_free(context->nsc_context);
-       rfx_context_free(context->rfx_context);
-       free(context->rfx_rects);
-}
-
-
-static int
-rdp_client_activity(int fd, uint32_t mask, void *data)
-{
-       freerdp_peer* client = (freerdp_peer *)data;
-
-       if (!client->CheckFileDescriptor(client)) {
-               weston_log("unable to checkDescriptor for %p\n", client);
-               goto out_clean;
-       }
-       return 0;
-
-out_clean:
-       freerdp_peer_context_free(client);
-       freerdp_peer_free(client);
-       return 0;
-}
-
-static BOOL
-xf_peer_capabilities(freerdp_peer* client)
-{
-       return TRUE;
-}
-
-struct rdp_to_xkb_keyboard_layout {
-       UINT32 rdpLayoutCode;
-       const char *xkbLayout;
-       const char *xkbVariant;
-};
-
-/* table reversed from
-       https://github.com/awakecoding/FreeRDP/blob/master/libfreerdp/locale/xkb_layout_ids.c#L811 */
-static
-struct rdp_to_xkb_keyboard_layout rdp_keyboards[] = {
-       {KBD_ARABIC_101, "ara", 0},
-       {KBD_BULGARIAN, 0, 0},
-       {KBD_CHINESE_TRADITIONAL_US, 0},
-       {KBD_CZECH, "cz", 0},
-       {KBD_CZECH_PROGRAMMERS, "cz", "bksl"},
-       {KBD_CZECH_QWERTY, "cz", "qwerty"},
-       {KBD_DANISH, "dk", 0},
-       {KBD_GERMAN, "de", 0},
-       {KBD_GERMAN_NEO, "de", "neo"},
-       {KBD_GERMAN_IBM, "de", "qwerty"},
-       {KBD_GREEK, "gr", 0},
-       {KBD_GREEK_220, "gr", "simple"},
-       {KBD_GREEK_319, "gr", "extended"},
-       {KBD_GREEK_POLYTONIC, "gr", "polytonic"},
-       {KBD_US, "us", 0},
-       {KBD_US_ENGLISH_TABLE_FOR_IBM_ARABIC_238_L, "ara", "buckwalter"},
-       {KBD_SPANISH, "es", 0},
-       {KBD_SPANISH_VARIATION, "es", "nodeadkeys"},
-       {KBD_FINNISH, "fi", 0},
-       {KBD_FRENCH, "fr", 0},
-       {KBD_HEBREW, "il", 0},
-       {KBD_HUNGARIAN, "hu", 0},
-       {KBD_HUNGARIAN_101_KEY, "hu", "standard"},
-       {KBD_ICELANDIC, "is", 0},
-       {KBD_ITALIAN, "it", 0},
-       {KBD_ITALIAN_142, "it", "nodeadkeys"},
-       {KBD_JAPANESE, "jp", 0},
-       {KBD_JAPANESE_INPUT_SYSTEM_MS_IME2002, "jp", "kana"},
-       {KBD_KOREAN, "kr", 0},
-       {KBD_KOREAN_INPUT_SYSTEM_IME_2000, "kr", "kr104"},
-       {KBD_DUTCH, "nl", 0},
-       {KBD_NORWEGIAN, "no", 0},
-       {KBD_POLISH_PROGRAMMERS, "pl", 0},
-       {KBD_POLISH_214, "pl", "qwertz"},
-       {KBD_ROMANIAN, "ro", 0},
-       {KBD_RUSSIAN, "ru", 0},
-       {KBD_RUSSIAN_TYPEWRITER, "ru", "typewriter"},
-       {KBD_CROATIAN, "hr", 0},
-       {KBD_SLOVAK, "sk", 0},
-       {KBD_SLOVAK_QWERTY, "sk", "qwerty"},
-       {KBD_ALBANIAN, 0, 0},
-       {KBD_SWEDISH, "se", 0},
-       {KBD_THAI_KEDMANEE, "th", 0},
-       {KBD_THAI_KEDMANEE_NON_SHIFTLOCK, "th", "tis"},
-       {KBD_TURKISH_Q, "tr", 0},
-       {KBD_TURKISH_F, "tr", "f"},
-       {KBD_URDU, "in", "urd-phonetic3"},
-       {KBD_UKRAINIAN, "ua", 0},
-       {KBD_BELARUSIAN, "by", 0},
-       {KBD_SLOVENIAN, "si", 0},
-       {KBD_ESTONIAN, "ee", 0},
-       {KBD_LATVIAN, "lv", 0},
-       {KBD_LITHUANIAN_IBM, "lt", "ibm"},
-       {KBD_FARSI, "af", 0},
-       {KBD_VIETNAMESE, "vn", 0},
-       {KBD_ARMENIAN_EASTERN, "am", 0},
-       {KBD_AZERI_LATIN, 0, 0},
-       {KBD_FYRO_MACEDONIAN, "mk", 0},
-       {KBD_GEORGIAN, "ge", 0},
-       {KBD_FAEROESE, 0, 0},
-       {KBD_DEVANAGARI_INSCRIPT, 0, 0},
-       {KBD_MALTESE_47_KEY, 0, 0},
-       {KBD_NORWEGIAN_WITH_SAMI, "no", "smi"},
-       {KBD_KAZAKH, "kz", 0},
-       {KBD_KYRGYZ_CYRILLIC, "kg", "phonetic"},
-       {KBD_TATAR, "ru", "tt"},
-       {KBD_BENGALI, "bd", 0},
-       {KBD_BENGALI_INSCRIPT, "bd", "probhat"},
-       {KBD_PUNJABI, 0, 0},
-       {KBD_GUJARATI, "in", "guj"},
-       {KBD_TAMIL, "in", "tam"},
-       {KBD_TELUGU, "in", "tel"},
-       {KBD_KANNADA, "in", "kan"},
-       {KBD_MALAYALAM, "in", "mal"},
-       {KBD_HINDI_TRADITIONAL, "in", 0},
-       {KBD_MARATHI, 0, 0},
-       {KBD_MONGOLIAN_CYRILLIC, "mn", 0},
-       {KBD_UNITED_KINGDOM_EXTENDED, "gb", "intl"},
-       {KBD_SYRIAC, "syc", 0},
-       {KBD_SYRIAC_PHONETIC, "syc", "syc_phonetic"},
-       {KBD_NEPALI, "np", 0},
-       {KBD_PASHTO, "af", "ps"},
-       {KBD_DIVEHI_PHONETIC, 0, 0},
-       {KBD_LUXEMBOURGISH, 0, 0},
-       {KBD_MAORI, "mao", 0},
-       {KBD_CHINESE_SIMPLIFIED_US, 0, 0},
-       {KBD_SWISS_GERMAN, "ch", "de_nodeadkeys"},
-       {KBD_UNITED_KINGDOM, "gb", 0},
-       {KBD_LATIN_AMERICAN, "latam", 0},
-       {KBD_BELGIAN_FRENCH, "be", 0},
-       {KBD_BELGIAN_PERIOD, "be", "oss_sundeadkeys"},
-       {KBD_PORTUGUESE, "pt", 0},
-       {KBD_SERBIAN_LATIN, "rs", 0},
-       {KBD_AZERI_CYRILLIC, "az", "cyrillic"},
-       {KBD_SWEDISH_WITH_SAMI, "se", "smi"},
-       {KBD_UZBEK_CYRILLIC, "af", "uz"},
-       {KBD_INUKTITUT_LATIN, "ca", "ike"},
-       {KBD_CANADIAN_FRENCH_LEGACY, "ca", "fr-legacy"},
-       {KBD_SERBIAN_CYRILLIC, "rs", 0},
-       {KBD_CANADIAN_FRENCH, "ca", "fr-legacy"},
-       {KBD_SWISS_FRENCH, "ch", "fr"},
-       {KBD_BOSNIAN, "ba", 0},
-       {KBD_IRISH, 0, 0},
-       {KBD_BOSNIAN_CYRILLIC, "ba", "us"},
-       {KBD_UNITED_STATES_DVORAK, "us", "dvorak"},
-       {KBD_PORTUGUESE_BRAZILIAN_ABNT2, "br", "nativo"},
-       {KBD_CANADIAN_MULTILINGUAL_STANDARD, "ca", "multix"},
-       {KBD_GAELIC, "ie", "CloGaelach"},
-
-       {0x00000000, 0, 0},
-};
-
-/* taken from 2.2.7.1.6 Input Capability Set (TS_INPUT_CAPABILITYSET) */
-static char *rdp_keyboard_types[] = {
-       "",     /* 0: unused */
-       "", /* 1: IBM PC/XT or compatible (83-key) keyboard */
-       "", /* 2: Olivetti "ICO" (102-key) keyboard */
-       "", /* 3: IBM PC/AT (84-key) or similar keyboard */
-       "pc102",/* 4: IBM enhanced (101- or 102-key) keyboard */
-       "", /* 5: Nokia 1050 and similar keyboards */
-       "",     /* 6: Nokia 9140 and similar keyboards */
-       ""      /* 7: Japanese keyboard */
-};
-
-static BOOL
-xf_peer_activate(freerdp_peer* client)
-{
-       RdpPeerContext *peerCtx;
-       struct rdp_backend *b;
-       struct rdp_output *output;
-       rdpSettings *settings;
-       rdpPointerUpdate *pointer;
-       struct rdp_peers_item *peersItem;
-       struct xkb_context *xkbContext;
-       struct xkb_rule_names xkbRuleNames;
-       struct xkb_keymap *keymap;
-       struct weston_output *weston_output;
-       int i;
-       pixman_box32_t box;
-       pixman_region32_t damage;
-       char seat_name[50];
-
-
-       peerCtx = (RdpPeerContext *)client->context;
-       b = peerCtx->rdpBackend;
-       peersItem = &peerCtx->item;
-       output = b->output;
-       settings = client->settings;
-
-       if (!settings->SurfaceCommandsEnabled) {
-               weston_log("client doesn't support required SurfaceCommands\n");
-               return FALSE;
-       }
-
-       if (output->base.width != (int)settings->DesktopWidth ||
-                       output->base.height != (int)settings->DesktopHeight)
-       {
-               if (b->no_clients_resize) {
-                       /* RDP peers don't dictate their resolution to weston */
-                       if (!settings->DesktopResize) {
-                               /* peer does not support desktop resize */
-                               weston_log("%s: client doesn't support resizing, closing connection\n", __FUNCTION__);
-                               return FALSE;
-                       } else {
-                               settings->DesktopWidth = output->base.width;
-                               settings->DesktopHeight = output->base.height;
-                               client->update->DesktopResize(client->context);
-                       }
-               } else {
-                       /* ask weston to adjust size */
-                       struct weston_mode new_mode;
-                       struct weston_mode *target_mode;
-                       new_mode.width = (int)settings->DesktopWidth;
-                       new_mode.height = (int)settings->DesktopHeight;
-                       target_mode = ensure_matching_mode(&output->base, &new_mode);
-                       if (!target_mode) {
-                               weston_log("client mode not found\n");
-                               return FALSE;
-                       }
-                       weston_output_mode_set_native(&output->base, target_mode, 1);
-                       output->base.width = new_mode.width;
-                       output->base.height = new_mode.height;
-               }
-       }
-
-       weston_output = &output->base;
-       RFX_RESET(peerCtx->rfx_context, weston_output->width, weston_output->height);
-       NSC_RESET(peerCtx->nsc_context, weston_output->width, weston_output->height);
-
-       if (peersItem->flags & RDP_PEER_ACTIVATED)
-               return TRUE;
-
-       /* when here it's the first reactivation, we need to setup a little more */
-       weston_log("kbd_layout:0x%x kbd_type:0x%x kbd_subType:0x%x kbd_functionKeys:0x%x\n",
-                       settings->KeyboardLayout, settings->KeyboardType, settings->KeyboardSubType,
-                       settings->KeyboardFunctionKey);
-
-       memset(&xkbRuleNames, 0, sizeof(xkbRuleNames));
-       if (settings->KeyboardType <= 7)
-               xkbRuleNames.model = rdp_keyboard_types[settings->KeyboardType];
-       for (i = 0; rdp_keyboards[i].rdpLayoutCode; i++) {
-               if (rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) {
-                       xkbRuleNames.layout = rdp_keyboards[i].xkbLayout;
-                       xkbRuleNames.variant = rdp_keyboards[i].xkbVariant;
-                       weston_log("%s: matching layout=%s variant=%s\n", __FUNCTION__,
-                                       xkbRuleNames.layout, xkbRuleNames.variant);
-                       break;
-               }
-       }
-
-       keymap = NULL;
-       if (xkbRuleNames.layout) {
-               xkbContext = xkb_context_new(0);
-               if (!xkbContext) {
-                       weston_log("unable to create a xkb_context\n");
-                       return FALSE;
-               }
-
-               keymap = xkb_keymap_new_from_names(xkbContext, &xkbRuleNames, 0);
-       }
-
-       if (settings->ClientHostname)
-               snprintf(seat_name, sizeof(seat_name), "RDP %s", settings->ClientHostname);
-       else
-               snprintf(seat_name, sizeof(seat_name), "RDP peer @%s", settings->ClientAddress);
-
-       peersItem->seat = zalloc(sizeof(*peersItem->seat));
-       if (!peersItem->seat) {
-               xkb_keymap_unref(keymap);
-               weston_log("unable to create a weston_seat\n");
-               return FALSE;
-       }
-
-       weston_seat_init(peersItem->seat, b->compositor, seat_name);
-       weston_seat_init_keyboard(peersItem->seat, keymap);
-       weston_seat_init_pointer(peersItem->seat);
-
-       peersItem->flags |= RDP_PEER_ACTIVATED;
-
-       /* disable pointer on the client side */
-       pointer = client->update->pointer;
-       pointer->pointer_system.type = SYSPTR_NULL;
-       pointer->PointerSystem(client->context, &pointer->pointer_system);
-
-       /* sends a full refresh */
-       box.x1 = 0;
-       box.y1 = 0;
-       box.x2 = output->base.width;
-       box.y2 = output->base.height;
-       pixman_region32_init_with_extents(&damage, &box);
-
-       rdp_peer_refresh_region(&damage, client);
-
-       pixman_region32_fini(&damage);
-
-       return TRUE;
-}
-
-static BOOL xf_peer_post_connect(freerdp_peer *client)
-{
-       return TRUE;
-}
-
-static FREERDP_CB_RET_TYPE
-xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
-{
-       RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
-       struct rdp_output *output;
-       uint32_t button = 0;
-       bool need_frame = false;
-
-       if (flags & PTR_FLAGS_MOVE) {
-               output = peerContext->rdpBackend->output;
-               if (x < output->base.width && y < output->base.height) {
-                       notify_motion_absolute(peerContext->item.seat, weston_compositor_get_time(),
-                                       x, y);
-                       need_frame = true;
-               }
-       }
-
-       if (flags & PTR_FLAGS_BUTTON1)
-               button = BTN_LEFT;
-       else if (flags & PTR_FLAGS_BUTTON2)
-               button = BTN_RIGHT;
-       else if (flags & PTR_FLAGS_BUTTON3)
-               button = BTN_MIDDLE;
-
-       if (button) {
-               notify_button(peerContext->item.seat, weston_compositor_get_time(), button,
-                       (flags & PTR_FLAGS_DOWN) ? WL_POINTER_BUTTON_STATE_PRESSED : WL_POINTER_BUTTON_STATE_RELEASED
-               );
-               need_frame = true;
-       }
-
-       if (flags & PTR_FLAGS_WHEEL) {
-               struct weston_pointer_axis_event weston_event;
-               double value;
-
-               /* DEFAULT_AXIS_STEP_DISTANCE is stolen from compositor-x11.c
-                * The RDP specs says the lower bits of flags contains the "the number of rotation
-                * units the mouse wheel was rotated".
-                *
-                * https://blogs.msdn.microsoft.com/oldnewthing/20130123-00/?p=5473 explains the 120 value
-                */
-               value = (flags & 0xff) / 120.0;
-               if (flags & PTR_FLAGS_WHEEL_NEGATIVE)
-                       value = -value;
-
-               weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
-               weston_event.value = DEFAULT_AXIS_STEP_DISTANCE * value;
-               weston_event.discrete = (int)value;
-               weston_event.has_discrete = true;
-
-               notify_axis(peerContext->item.seat, weston_compositor_get_time(),
-                           &weston_event);
-               need_frame = true;
-       }
-
-       if (need_frame)
-               notify_pointer_frame(peerContext->item.seat);
-
-       FREERDP_CB_RETURN(TRUE);
-}
-
-static FREERDP_CB_RET_TYPE
-xf_extendedMouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y)
-{
-       RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
-       struct rdp_output *output;
-
-       output = peerContext->rdpBackend->output;
-       if (x < output->base.width && y < output->base.height) {
-               notify_motion_absolute(peerContext->item.seat, weston_compositor_get_time(),
-                               x, y);
-       }
-
-       FREERDP_CB_RETURN(TRUE);
-}
-
-
-static FREERDP_CB_RET_TYPE
-xf_input_synchronize_event(rdpInput *input, UINT32 flags)
-{
-       freerdp_peer *client = input->context->peer;
-       RdpPeerContext *peerCtx = (RdpPeerContext *)input->context;
-       struct rdp_output *output = peerCtx->rdpBackend->output;
-       pixman_box32_t box;
-       pixman_region32_t damage;
-
-       /* sends a full refresh */
-       box.x1 = 0;
-       box.y1 = 0;
-       box.x2 = output->base.width;
-       box.y2 = output->base.height;
-       pixman_region32_init_with_extents(&damage, &box);
-
-       rdp_peer_refresh_region(&damage, client);
-
-       pixman_region32_fini(&damage);
-       FREERDP_CB_RETURN(TRUE);
-}
-
-
-static FREERDP_CB_RET_TYPE
-xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
-{
-       uint32_t scan_code, vk_code, full_code;
-       enum wl_keyboard_key_state keyState;
-       RdpPeerContext *peerContext = (RdpPeerContext *)input->context;
-       int notify = 0;
-
-       if (!(peerContext->item.flags & RDP_PEER_ACTIVATED))
-               FREERDP_CB_RETURN(TRUE);
-
-       if (flags & KBD_FLAGS_DOWN) {
-               keyState = WL_KEYBOARD_KEY_STATE_PRESSED;
-               notify = 1;
-       } else if (flags & KBD_FLAGS_RELEASE) {
-               keyState = WL_KEYBOARD_KEY_STATE_RELEASED;
-               notify = 1;
-       }
-
-       if (notify) {
-               full_code = code;
-               if (flags & KBD_FLAGS_EXTENDED)
-                       full_code |= KBD_FLAGS_EXTENDED;
-
-               vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, 4);
-               if (flags & KBD_FLAGS_EXTENDED)
-                       vk_code |= KBDEXT;
-
-               scan_code = GetKeycodeFromVirtualKeyCode(vk_code, KEYCODE_TYPE_EVDEV);
-
-               /*weston_log("code=%x ext=%d vk_code=%x scan_code=%x\n", code, (flags & KBD_FLAGS_EXTENDED) ? 1 : 0,
-                               vk_code, scan_code);*/
-               notify_key(peerContext->item.seat, weston_compositor_get_time(),
-                                       scan_code - 8, keyState, STATE_UPDATE_AUTOMATIC);
-       }
-
-       FREERDP_CB_RETURN(TRUE);
-}
-
-static FREERDP_CB_RET_TYPE
-xf_input_unicode_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
-{
-       weston_log("Client sent a unicode keyboard event (flags:0x%X code:0x%X)\n", flags, code);
-       FREERDP_CB_RETURN(TRUE);
-}
-
-
-static FREERDP_CB_RET_TYPE
-xf_suppress_output(rdpContext *context, BYTE allow, RECTANGLE_16 *area)
-{
-       RdpPeerContext *peerContext = (RdpPeerContext *)context;
-
-       if (allow)
-               peerContext->item.flags |= RDP_PEER_OUTPUT_ENABLED;
-       else
-               peerContext->item.flags &= (~RDP_PEER_OUTPUT_ENABLED);
-
-       FREERDP_CB_RETURN(TRUE);
-}
-
-static int
-rdp_peer_init(freerdp_peer *client, struct rdp_backend *b)
-{
-       int rcount = 0;
-       void *rfds[MAX_FREERDP_FDS];
-       int i, fd;
-       struct wl_event_loop *loop;
-       rdpSettings     *settings;
-       rdpInput *input;
-       RdpPeerContext *peerCtx;
-
-       client->ContextSize = sizeof(RdpPeerContext);
-       client->ContextNew = (psPeerContextNew)rdp_peer_context_new;
-       client->ContextFree = (psPeerContextFree)rdp_peer_context_free;
-       freerdp_peer_context_new(client);
-
-       peerCtx = (RdpPeerContext *) client->context;
-       peerCtx->rdpBackend = b;
-
-       settings = client->settings;
-       /* configure security settings */
-       if (b->rdp_key)
-               settings->RdpKeyFile = strdup(b->rdp_key);
-       if (b->tls_enabled) {
-               settings->CertificateFile = strdup(b->server_cert);
-               settings->PrivateKeyFile = strdup(b->server_key);
-       } else {
-               settings->TlsSecurity = FALSE;
-       }
-       settings->NlaSecurity = FALSE;
-
-       if (!client->Initialize(client)) {
-               weston_log("peer initialization failed\n");
-               goto error_initialize;
-       }
-
-       settings->OsMajorType = OSMAJORTYPE_UNIX;
-       settings->OsMinorType = OSMINORTYPE_PSEUDO_XSERVER;
-       settings->ColorDepth = 32;
-       settings->RefreshRect = TRUE;
-       settings->RemoteFxCodec = TRUE;
-       settings->NSCodec = TRUE;
-       settings->FrameMarkerCommandEnabled = TRUE;
-       settings->SurfaceFrameMarkerEnabled = TRUE;
-
-       client->Capabilities = xf_peer_capabilities;
-       client->PostConnect = xf_peer_post_connect;
-       client->Activate = xf_peer_activate;
-
-       client->update->SuppressOutput = xf_suppress_output;
-
-       input = client->input;
-       input->SynchronizeEvent = xf_input_synchronize_event;
-       input->MouseEvent = xf_mouseEvent;
-       input->ExtendedMouseEvent = xf_extendedMouseEvent;
-       input->KeyboardEvent = xf_input_keyboard_event;
-       input->UnicodeKeyboardEvent = xf_input_unicode_keyboard_event;
-
-       if (!client->GetFileDescriptor(client, rfds, &rcount)) {
-               weston_log("unable to retrieve client fds\n");
-               goto error_initialize;
-       }
-
-       loop = wl_display_get_event_loop(b->compositor->wl_display);
-       for (i = 0; i < rcount; i++) {
-               fd = (int)(long)(rfds[i]);
-
-               peerCtx->events[i] = wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
-                               rdp_client_activity, client);
-       }
-       for ( ; i < MAX_FREERDP_FDS; i++)
-               peerCtx->events[i] = 0;
-
-       wl_list_insert(&b->output->peers, &peerCtx->item.link);
-       return 0;
-
-error_initialize:
-       client->Close(client);
-       return -1;
-}
-
-
-static FREERDP_CB_RET_TYPE
-rdp_incoming_peer(freerdp_listener *instance, freerdp_peer *client)
-{
-       struct rdp_backend *b = (struct rdp_backend *)instance->param4;
-       if (rdp_peer_init(client, b) < 0) {
-               weston_log("error when treating incoming peer\n");
-               FREERDP_CB_RETURN(FALSE);
-       }
-
-       FREERDP_CB_RETURN(TRUE);
-}
-
-static struct rdp_backend *
-rdp_backend_create(struct weston_compositor *compositor,
-                  struct weston_rdp_backend_config *config)
-{
-       struct rdp_backend *b;
-       char *fd_str;
-       int fd;
-
-       b = zalloc(sizeof *b);
-       if (b == NULL)
-               return NULL;
-
-       b->compositor = compositor;
-       b->base.destroy = rdp_destroy;
-       b->base.restore = rdp_restore;
-       b->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL;
-       b->no_clients_resize = config->no_clients_resize;
-
-       /* activate TLS only if certificate/key are available */
-       if (config->server_cert && config->server_key) {
-               weston_log("TLS support activated\n");
-               b->server_cert = strdup(config->server_cert);
-               b->server_key = strdup(config->server_key);
-               if (!b->server_cert || !b->server_key)
-                       goto err_free_strings;
-               b->tls_enabled = 1;
-       }
-
-       if (weston_compositor_set_presentation_clock_software(compositor) < 0)
-               goto err_compositor;
-
-       if (pixman_renderer_init(compositor) < 0)
-               goto err_compositor;
-
-       if (rdp_backend_create_output(b, config->width, config->height) < 0)
-               goto err_compositor;
-
-       compositor->capabilities |= WESTON_CAP_ARBITRARY_MODES;
-
-       if (!config->env_socket) {
-               b->listener = freerdp_listener_new();
-               b->listener->PeerAccepted = rdp_incoming_peer;
-               b->listener->param4 = b;
-               if (!b->listener->Open(b->listener, config->bind_address, config->port)) {
-                       weston_log("unable to bind rdp socket\n");
-                       goto err_listener;
-               }
-
-               if (rdp_implant_listener(b, b->listener) < 0)
-                       goto err_compositor;
-       } else {
-               /* get the socket from RDP_FD var */
-               fd_str = getenv("RDP_FD");
-               if (!fd_str) {
-                       weston_log("RDP_FD env variable not set\n");
-                       goto err_output;
-               }
-
-               fd = strtoul(fd_str, NULL, 10);
-               if (rdp_peer_init(freerdp_peer_new(fd), b))
-                       goto err_output;
-       }
-
-       compositor->backend = &b->base;
-       return b;
-
-err_listener:
-       freerdp_listener_free(b->listener);
-err_output:
-       weston_output_destroy(&b->output->base);
-err_compositor:
-       weston_compositor_shutdown(compositor);
-err_free_strings:
-       free(b->rdp_key);
-       free(b->server_cert);
-       free(b->server_key);
-       free(b);
-       return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_rdp_backend_config *config)
-{
-       config->width = 640;
-       config->height = 480;
-       config->bind_address = NULL;
-       config->port = 3389;
-       config->rdp_key = NULL;
-       config->server_cert = NULL;
-       config->server_key = NULL;
-       config->env_socket = 0;
-       config->no_clients_resize = 0;
-}
-
-WL_EXPORT int
-backend_init(struct weston_compositor *compositor,
-            struct weston_backend_config *config_base)
-{
-       struct rdp_backend *b;
-       struct weston_rdp_backend_config config = {{ 0, }};
-       int major, minor, revision;
-
-       freerdp_get_version(&major, &minor, &revision);
-       weston_log("using FreeRDP version %d.%d.%d\n", major, minor, revision);
-
-       if (config_base == NULL ||
-           config_base->struct_version != WESTON_RDP_BACKEND_CONFIG_VERSION ||
-           config_base->struct_size > sizeof(struct weston_rdp_backend_config)) {
-               weston_log("RDP backend config structure is invalid\n");
-               return -1;
-       }
-
-       config_init_to_defaults(&config);
-       memcpy(&config, config_base, config_base->struct_size);
-
-       if (!config.rdp_key && (!config.server_cert || !config.server_key)) {
-               weston_log("the RDP compositor requires keys and an optional certificate for RDP or TLS security ("
-                               "--rdp4-key or --rdp-tls-cert/--rdp-tls-key)\n");
-               return -1;
-       }
-
-       b = rdp_backend_create(compositor, &config);
-       if (b == NULL)
-               return -1;
-       return 0;
-}
diff --git a/src/compositor-rdp.h b/src/compositor-rdp.h
deleted file mode 100644 (file)
index dfa1759..0000000
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * Copyright © 2016 Benoit Gschwind
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_COMPOSITOR_RDP_H
-#define WESTON_COMPOSITOR_RDP_H
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#include "compositor.h"
-
-#define WESTON_RDP_BACKEND_CONFIG_VERSION 1
-
-struct weston_rdp_backend_config {
-       struct weston_backend_config base;
-       int width;
-       int height;
-       char *bind_address;
-       int port;
-       char *rdp_key;
-       char *server_cert;
-       char *server_key;
-       int env_socket;
-       int no_clients_resize;
-};
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* WESTON_COMPOSITOR_RDP_H */
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
deleted file mode 100644 (file)
index 1343e21..0000000
+++ /dev/null
@@ -1,2348 +0,0 @@
-/*
- * Copyright © 2010-2011 Benjamin Franzke
- * Copyright © 2013 Jason Ekstrand
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stddef.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/mman.h>
-#include <linux/input.h>
-
-#include <wayland-client.h>
-#include <wayland-egl.h>
-#include <wayland-cursor.h>
-
-#include "compositor.h"
-#include "compositor-wayland.h"
-#include "gl-renderer.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 "fullscreen-shell-unstable-v1-client-protocol.h"
-#include "presentation-time-server-protocol.h"
-#include "linux-dmabuf.h"
-
-#define WINDOW_TITLE "Weston Compositor"
-
-struct wayland_backend {
-       struct weston_backend base;
-       struct weston_compositor *compositor;
-
-       struct {
-               struct wl_display *wl_display;
-               struct wl_registry *registry;
-               struct wl_compositor *compositor;
-               struct wl_shell *shell;
-               struct zwp_fullscreen_shell_v1 *fshell;
-               struct wl_shm *shm;
-
-               struct wl_list output_list;
-
-               struct wl_event_source *wl_source;
-               uint32_t event_mask;
-       } parent;
-
-       int use_pixman;
-       int sprawl_across_outputs;
-
-       struct theme *theme;
-       cairo_device_t *frame_device;
-       struct wl_cursor_theme *cursor_theme;
-       struct wl_cursor *cursor;
-
-       struct wl_list input_list;
-};
-
-struct wayland_output {
-       struct weston_output base;
-
-       struct {
-               int draw_initial_frame;
-               struct wl_surface *surface;
-
-               struct wl_output *output;
-               uint32_t global_id;
-
-               struct wl_shell_surface *shell_surface;
-               int configure_width, configure_height;
-       } parent;
-
-       int keyboard_count;
-
-       char *name;
-       struct frame *frame;
-
-       struct {
-               struct wl_egl_window *egl_window;
-               struct {
-                       cairo_surface_t *top;
-                       cairo_surface_t *left;
-                       cairo_surface_t *right;
-                       cairo_surface_t *bottom;
-               } border;
-       } gl;
-
-       struct {
-               struct wl_list buffers;
-               struct wl_list free_buffers;
-       } shm;
-
-       struct weston_mode mode;
-       uint32_t scale;
-};
-
-struct wayland_parent_output {
-       struct wayland_output *output;
-       struct wl_list link;
-
-       struct wl_output *global;
-       uint32_t id;
-
-       struct {
-               char *make;
-               char *model;
-               int32_t width, height;
-               uint32_t subpixel;
-       } physical;
-
-       int32_t x, y;
-       uint32_t transform;
-       uint32_t scale;
-
-       struct wl_list mode_list;
-       struct weston_mode *preferred_mode;
-       struct weston_mode *current_mode;
-};
-
-struct wayland_shm_buffer {
-       struct wayland_output *output;
-       struct wl_list link;
-       struct wl_list free_link;
-
-       struct wl_buffer *buffer;
-       void *data;
-       size_t size;
-       pixman_region32_t damage;
-       int frame_damaged;
-
-       pixman_image_t *pm_image;
-       cairo_surface_t *c_surface;
-};
-
-struct wayland_input {
-       struct weston_seat base;
-       struct wayland_backend *backend;
-       struct wl_list link;
-
-       struct {
-               struct wl_seat *seat;
-               struct wl_pointer *pointer;
-               struct wl_keyboard *keyboard;
-               struct wl_touch *touch;
-
-               struct {
-                       struct wl_surface *surface;
-                       int32_t hx, hy;
-               } cursor;
-       } parent;
-
-       enum weston_key_state_update keyboard_state_update;
-       uint32_t key_serial;
-       uint32_t enter_serial;
-       uint32_t touch_points;
-       bool touch_active;
-       bool has_focus;
-       int seat_version;
-
-       struct wayland_output *output;
-       struct wayland_output *touch_focus;
-       struct wayland_output *keyboard_focus;
-
-       struct weston_pointer_axis_event vert, horiz;
-};
-
-struct gl_renderer_interface *gl_renderer;
-
-static void
-wayland_shm_buffer_destroy(struct wayland_shm_buffer *buffer)
-{
-       cairo_surface_destroy(buffer->c_surface);
-       pixman_image_unref(buffer->pm_image);
-
-       wl_buffer_destroy(buffer->buffer);
-       munmap(buffer->data, buffer->size);
-
-       pixman_region32_fini(&buffer->damage);
-
-       wl_list_remove(&buffer->link);
-       wl_list_remove(&buffer->free_link);
-       free(buffer);
-}
-
-static void
-buffer_release(void *data, struct wl_buffer *buffer)
-{
-       struct wayland_shm_buffer *sb = data;
-
-       if (sb->output) {
-               wl_list_insert(&sb->output->shm.free_buffers, &sb->free_link);
-       } else {
-               wayland_shm_buffer_destroy(sb);
-       }
-}
-
-static const struct wl_buffer_listener buffer_listener = {
-       buffer_release
-};
-
-static struct wayland_shm_buffer *
-wayland_output_get_shm_buffer(struct wayland_output *output)
-{
-       struct wayland_backend *b =
-               (struct wayland_backend *) output->base.compositor->backend;
-       struct wl_shm *shm = b->parent.shm;
-       struct wayland_shm_buffer *sb;
-
-       struct wl_shm_pool *pool;
-       int width, height, stride;
-       int32_t fx, fy;
-       int fd;
-       unsigned char *data;
-
-       if (!wl_list_empty(&output->shm.free_buffers)) {
-               sb = container_of(output->shm.free_buffers.next,
-                                 struct wayland_shm_buffer, free_link);
-               wl_list_remove(&sb->free_link);
-               wl_list_init(&sb->free_link);
-
-               return sb;
-       }
-
-       if (output->frame) {
-               width = frame_width(output->frame);
-               height = frame_height(output->frame);
-       } else {
-               width = output->base.current_mode->width;
-               height = output->base.current_mode->height;
-       }
-
-       stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, width);
-
-       fd = os_create_anonymous_file(height * stride);
-       if (fd < 0) {
-               weston_log("could not create an anonymous file buffer: %m\n");
-               return NULL;
-       }
-
-       data = mmap(NULL, height * stride, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
-       if (data == MAP_FAILED) {
-               weston_log("could not mmap %d memory for data: %m\n", height * stride);
-               close(fd);
-               return NULL;
-       }
-
-       sb = zalloc(sizeof *sb);
-       if (sb == NULL) {
-               weston_log("could not zalloc %zu memory for sb: %m\n", sizeof *sb);
-               close(fd);
-               free(data);
-               return NULL;
-       }
-
-       sb->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);
-       sb->frame_damaged = 1;
-
-       sb->data = data;
-       sb->size = height * stride;
-
-       pool = wl_shm_create_pool(shm, fd, sb->size);
-
-       sb->buffer = wl_shm_pool_create_buffer(pool, 0,
-                                              width, height,
-                                              stride,
-                                              WL_SHM_FORMAT_ARGB8888);
-       wl_buffer_add_listener(sb->buffer, &buffer_listener, sb);
-       wl_shm_pool_destroy(pool);
-       close(fd);
-
-       memset(data, 0, sb->size);
-
-       sb->c_surface =
-               cairo_image_surface_create_for_data(data, CAIRO_FORMAT_ARGB32,
-                                                   width, height, stride);
-
-       fx = 0;
-       fy = 0;
-       if (output->frame)
-               frame_interior(output->frame, &fx, &fy, 0, 0);
-       sb->pm_image =
-               pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height,
-                                        (uint32_t *)(data + fy * stride) + fx,
-                                        stride);
-
-       return sb;
-}
-
-static void
-frame_done(void *data, struct wl_callback *callback, uint32_t time)
-{
-       struct weston_output *output = data;
-       struct timespec ts;
-
-       wl_callback_destroy(callback);
-
-       /* XXX: use the presentation extension for proper timings */
-
-       /*
-        * This is the fallback case, where Presentation extension is not
-        * available from the parent compositor. We do not know the base for
-        * 'time', so we cannot feed it to finish_frame(). Do the only thing
-        * 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);
-}
-
-static const struct wl_callback_listener frame_listener = {
-       frame_done
-};
-
-static void
-draw_initial_frame(struct wayland_output *output)
-{
-       struct wayland_shm_buffer *sb;
-
-       sb = wayland_output_get_shm_buffer(output);
-
-       /* If we are rendering with GL, then orphan it so that it gets
-        * destroyed immediately */
-       if (output->gl.egl_window)
-               sb->output = NULL;
-
-       wl_surface_attach(output->parent.surface, sb->buffer, 0, 0);
-       wl_surface_damage(output->parent.surface, 0, 0,
-                         output->base.current_mode->width,
-                         output->base.current_mode->height);
-}
-
-static void
-wayland_output_update_gl_border(struct wayland_output *output)
-{
-       int32_t ix, iy, iwidth, iheight, fwidth, fheight;
-       cairo_t *cr;
-
-       if (!output->frame)
-               return;
-       if (!(frame_status(output->frame) & FRAME_STATUS_REPAINT))
-               return;
-
-       fwidth = frame_width(output->frame);
-       fheight = frame_height(output->frame);
-       frame_interior(output->frame, &ix, &iy, &iwidth, &iheight);
-
-       if (!output->gl.border.top)
-               output->gl.border.top =
-                       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                                  fwidth, iy);
-       cr = cairo_create(output->gl.border.top);
-       frame_repaint(output->frame, cr);
-       cairo_destroy(cr);
-       gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_TOP,
-                                      fwidth, iy,
-                                      cairo_image_surface_get_stride(output->gl.border.top) / 4,
-                                      cairo_image_surface_get_data(output->gl.border.top));
-
-
-       if (!output->gl.border.left)
-               output->gl.border.left =
-                       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                                  ix, 1);
-       cr = cairo_create(output->gl.border.left);
-       cairo_translate(cr, 0, -iy);
-       frame_repaint(output->frame, cr);
-       cairo_destroy(cr);
-       gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_LEFT,
-                                      ix, 1,
-                                      cairo_image_surface_get_stride(output->gl.border.left) / 4,
-                                      cairo_image_surface_get_data(output->gl.border.left));
-
-
-       if (!output->gl.border.right)
-               output->gl.border.right =
-                       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                                  fwidth - (ix + iwidth), 1);
-       cr = cairo_create(output->gl.border.right);
-       cairo_translate(cr, -(iwidth + ix), -iy);
-       frame_repaint(output->frame, cr);
-       cairo_destroy(cr);
-       gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_RIGHT,
-                                      fwidth - (ix + iwidth), 1,
-                                      cairo_image_surface_get_stride(output->gl.border.right) / 4,
-                                      cairo_image_surface_get_data(output->gl.border.right));
-
-
-       if (!output->gl.border.bottom)
-               output->gl.border.bottom =
-                       cairo_image_surface_create(CAIRO_FORMAT_ARGB32,
-                                                  fwidth, fheight - (iy + iheight));
-       cr = cairo_create(output->gl.border.bottom);
-       cairo_translate(cr, 0, -(iy + iheight));
-       frame_repaint(output->frame, cr);
-       cairo_destroy(cr);
-       gl_renderer->output_set_border(&output->base, GL_RENDERER_BORDER_BOTTOM,
-                                      fwidth, fheight - (iy + iheight),
-                                      cairo_image_surface_get_stride(output->gl.border.bottom) / 4,
-                                      cairo_image_surface_get_data(output->gl.border.bottom));
-}
-
-static void
-wayland_output_start_repaint_loop(struct weston_output *output_base)
-{
-       struct wayland_output *output = (struct wayland_output *) output_base;
-       struct wayland_backend *wb =
-               (struct wayland_backend *)output->base.compositor->backend;
-       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
-        * loop. If the surface doesn't end up in the render loop, the frame
-        * 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;
-
-               draw_initial_frame(output);
-       }
-
-       callback = wl_surface_frame(output->parent.surface);
-       wl_callback_add_listener(callback, &frame_listener, output);
-       wl_surface_commit(output->parent.surface);
-       wl_display_flush(wb->parent.wl_display);
-}
-
-static int
-wayland_output_repaint_gl(struct weston_output *output_base,
-                         pixman_region32_t *damage)
-{
-       struct wayland_output *output = (struct 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);
-
-       wayland_output_update_gl_border(output);
-
-       ec->renderer->repaint_output(&output->base, damage);
-
-       pixman_region32_subtract(&ec->primary_plane.damage,
-                                &ec->primary_plane.damage, damage);
-       return 0;
-}
-
-static void
-wayland_output_update_shm_border(struct wayland_shm_buffer *buffer)
-{
-       int32_t ix, iy, iwidth, iheight, fwidth, fheight;
-       cairo_t *cr;
-
-       if (!buffer->output->frame || !buffer->frame_damaged)
-               return;
-
-       cr = cairo_create(buffer->c_surface);
-
-       frame_interior(buffer->output->frame, &ix, &iy, &iwidth, &iheight);
-       fwidth = frame_width(buffer->output->frame);
-       fheight = frame_height(buffer->output->frame);
-
-       /* Set the clip so we don't unnecisaraly damage the surface */
-       cairo_move_to(cr, ix, iy);
-       cairo_rel_line_to(cr, iwidth, 0);
-       cairo_rel_line_to(cr, 0, iheight);
-       cairo_rel_line_to(cr, -iwidth, 0);
-       cairo_line_to(cr, ix, iy);
-       cairo_line_to(cr, 0, iy);
-       cairo_line_to(cr, 0, fheight);
-       cairo_line_to(cr, fwidth, fheight);
-       cairo_line_to(cr, fwidth, 0);
-       cairo_line_to(cr, 0, 0);
-       cairo_line_to(cr, 0, iy);
-       cairo_close_path(cr);
-       cairo_clip(cr);
-
-       /* Draw using a pattern so that the final result gets clipped */
-       cairo_push_group(cr);
-       frame_repaint(buffer->output->frame, cr);
-       cairo_pop_group_to_source(cr);
-       cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
-       cairo_paint(cr);
-
-       cairo_destroy(cr);
-}
-
-static void
-wayland_shm_buffer_attach(struct wayland_shm_buffer *sb)
-{
-       pixman_region32_t damage;
-       pixman_box32_t *rects;
-       int32_t ix, iy, iwidth, iheight, fwidth, fheight;
-       int i, n;
-
-       pixman_region32_init(&damage);
-       weston_transformed_region(sb->output->base.width,
-                                 sb->output->base.height,
-                                 sb->output->base.transform,
-                                 sb->output->base.current_scale,
-                                 &sb->damage, &damage);
-
-       if (sb->output->frame) {
-               frame_interior(sb->output->frame, &ix, &iy, &iwidth, &iheight);
-               fwidth = frame_width(sb->output->frame);
-               fheight = frame_height(sb->output->frame);
-
-               pixman_region32_translate(&damage, ix, iy);
-
-               if (sb->frame_damaged) {
-                       pixman_region32_union_rect(&damage, &damage,
-                                                  0, 0, fwidth, iy);
-                       pixman_region32_union_rect(&damage, &damage,
-                                                  0, iy, ix, iheight);
-                       pixman_region32_union_rect(&damage, &damage,
-                                                  ix + iwidth, iy,
-                                                  fwidth - (ix + iwidth), iheight);
-                       pixman_region32_union_rect(&damage, &damage,
-                                                  0, iy + iheight,
-                                                  fwidth, fheight - (iy + iheight));
-               }
-       }
-
-       rects = pixman_region32_rectangles(&damage, &n);
-       wl_surface_attach(sb->output->parent.surface, sb->buffer, 0, 0);
-       for (i = 0; i < n; ++i)
-               wl_surface_damage(sb->output->parent.surface, rects[i].x1,
-                                 rects[i].y1, rects[i].x2 - rects[i].x1,
-                                 rects[i].y2 - rects[i].y1);
-
-       if (sb->output->frame)
-               pixman_region32_fini(&damage);
-}
-
-static int
-wayland_output_repaint_pixman(struct weston_output *output_base,
-                             pixman_region32_t *damage)
-{
-       struct wayland_output *output = (struct wayland_output *) output_base;
-       struct wayland_backend *b =
-               (struct wayland_backend *)output->base.compositor->backend;
-       struct wl_callback *callback;
-       struct wayland_shm_buffer *sb;
-
-       if (output->frame) {
-               if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
-                       wl_list_for_each(sb, &output->shm.buffers, link)
-                               sb->frame_damaged = 1;
-       }
-
-       wl_list_for_each(sb, &output->shm.buffers, link)
-               pixman_region32_union(&sb->damage, &sb->damage, damage);
-
-       sb = wayland_output_get_shm_buffer(output);
-
-       wayland_output_update_shm_border(sb);
-       pixman_renderer_output_set_buffer(output_base, sb->pm_image);
-       b->compositor->renderer->repaint_output(output_base, &sb->damage);
-
-       wayland_shm_buffer_attach(sb);
-
-       callback = wl_surface_frame(output->parent.surface);
-       wl_callback_add_listener(callback, &frame_listener, output);
-       wl_surface_commit(output->parent.surface);
-       wl_display_flush(b->parent.wl_display);
-
-       pixman_region32_fini(&sb->damage);
-       pixman_region32_init(&sb->damage);
-       sb->frame_damaged = 0;
-
-       pixman_region32_subtract(&b->compositor->primary_plane.damage,
-                                &b->compositor->primary_plane.damage, damage);
-       return 0;
-}
-
-static void
-wayland_output_destroy(struct weston_output *output_base)
-{
-       struct wayland_output *output = (struct wayland_output *) output_base;
-       struct wayland_backend *b =
-               (struct wayland_backend *) output->base.compositor->backend;
-
-       if (b->use_pixman) {
-               pixman_renderer_output_destroy(output_base);
-       } else {
-               gl_renderer->output_destroy(output_base);
-       }
-
-       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);
-
-       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);
-
-       weston_output_destroy(&output->base);
-       free(output);
-
-       return;
-}
-
-static const struct wl_shell_surface_listener shell_surface_listener;
-
-static int
-wayland_output_init_gl_renderer(struct wayland_output *output)
-{
-       int32_t fwidth = 0, fheight = 0;
-
-       if (output->frame) {
-               fwidth = frame_width(output->frame);
-               fheight = frame_height(output->frame);
-       } else {
-               fwidth = output->base.current_mode->width;
-               fheight = output->base.current_mode->height;
-       }
-
-       output->gl.egl_window =
-               wl_egl_window_create(output->parent.surface,
-                                    fwidth, fheight);
-       if (!output->gl.egl_window) {
-               weston_log("failure to create wl_egl_window\n");
-               return -1;
-       }
-
-       if (gl_renderer->output_create(&output->base,
-                                      output->gl.egl_window,
-                                      output->gl.egl_window,
-                                      gl_renderer->alpha_attribs,
-                                      NULL,
-                                      0) < 0)
-               goto cleanup_window;
-
-       return 0;
-
-cleanup_window:
-       wl_egl_window_destroy(output->gl.egl_window);
-       return -1;
-}
-
-static int
-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_backend *b =
-               (struct wayland_backend *)output->base.compositor->backend;
-       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(b->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(b->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(b->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(b->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, 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_set_windowed(struct wayland_output *output)
-{
-       struct wayland_backend *b =
-               (struct wayland_backend *)output->base.compositor->backend;
-       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);
-                       return -1;
-               }
-       }
-       output->frame = frame_create(b->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)
-{
-       struct wayland_backend *b =
-               (struct wayland_backend *)output->base.compositor->backend;
-
-       if (output->frame) {
-               frame_destroy(output->frame);
-               output->frame = NULL;
-       }
-
-       wayland_output_resize_surface(output);
-
-       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);
-       }
-}
-
-static struct weston_mode *
-wayland_output_choose_mode(struct wayland_output *output,
-                          struct weston_mode *ref_mode)
-{
-       struct weston_mode *mode;
-
-       /* First look for an exact match */
-       wl_list_for_each(mode, &output->base.mode_list, link)
-               if (mode->width == ref_mode->width &&
-                   mode->height == ref_mode->height &&
-                   mode->refresh == ref_mode->refresh)
-                       return mode;
-
-       /* If we can't find an exact match, ignore refresh and try again */
-       wl_list_for_each(mode, &output->base.mode_list, link)
-               if (mode->width == ref_mode->width &&
-                   mode->height == ref_mode->height)
-                       return mode;
-
-       /* Yeah, we failed */
-       return NULL;
-}
-
-enum mode_status {
-       MODE_STATUS_UNKNOWN,
-       MODE_STATUS_SUCCESS,
-       MODE_STATUS_FAIL,
-       MODE_STATUS_CANCEL,
-};
-
-static void
-mode_feedback_successful(void *data,
-                        struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
-{
-       enum mode_status *value = data;
-
-       printf("Mode switch successful\n");
-
-       *value = MODE_STATUS_SUCCESS;
-}
-
-static void
-mode_feedback_failed(void *data, struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
-{
-       enum mode_status *value = data;
-
-       printf("Mode switch failed\n");
-
-       *value = MODE_STATUS_FAIL;
-}
-
-static void
-mode_feedback_cancelled(void *data, struct zwp_fullscreen_shell_mode_feedback_v1 *fb)
-{
-       enum mode_status *value = data;
-
-       printf("Mode switch cancelled\n");
-
-       *value = MODE_STATUS_CANCEL;
-}
-
-struct zwp_fullscreen_shell_mode_feedback_v1_listener mode_feedback_listener = {
-       mode_feedback_successful,
-       mode_feedback_failed,
-       mode_feedback_cancelled,
-};
-
-static int
-wayland_output_switch_mode(struct weston_output *output_base,
-                          struct weston_mode *mode)
-{
-       struct wayland_output *output = (struct wayland_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");
-               return -1;
-       }
-
-       if (mode == NULL) {
-               weston_log("mode is NULL.\n");
-               return -1;
-       }
-
-       b = (struct wayland_backend *)output_base->compositor->backend;
-
-       if (output->parent.shell_surface || !b->parent.fshell)
-               return -1;
-
-       mode = wayland_output_choose_mode(output, mode);
-       if (mode == NULL)
-               return -1;
-
-       if (output->base.current_mode == mode)
-               return 0;
-
-       old_mode = output->base.current_mode;
-       old_surface = output->parent.surface;
-       output->base.current_mode = mode;
-       output->parent.surface =
-               wl_compositor_create_surface(b->parent.compositor);
-       wl_surface_set_user_data(output->parent.surface, output);
-
-       /* 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);
-
-       /* 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);
-               output->parent.surface = old_surface;
-               wayland_output_resize_surface(output);
-
-               return -1;
-       }
-
-       old_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
-       output->base.current_mode->flags |= WL_OUTPUT_MODE_CURRENT;
-
-       if (b->use_pixman) {
-               pixman_renderer_output_destroy(output_base);
-               if (wayland_output_init_pixman_renderer(output) < 0)
-                       goto err_output;
-       } 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;
-       }
-       wl_surface_destroy(old_surface);
-
-       weston_output_schedule_repaint(&output->base);
-
-       return 0;
-
-err_output:
-       /* XXX */
-       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)
-{
-       struct wayland_output *output;
-       int output_width, output_height;
-
-       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 = "wayland";
-       output->base.model = "none";
-
-       output_width = width * scale;
-       output_height = height * scale;
-
-       output->parent.surface =
-               wl_compositor_create_surface(b->parent.compositor);
-       if (!output->parent.surface)
-               goto err_name;
-       wl_surface_set_user_data(output->parent.surface, output);
-
-       output->parent.draw_initial_frame = 1;
-
-       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;
-               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;
-       }
-
-       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;
-
-       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;
-       } else {
-               if (wayland_output_init_gl_renderer(output) < 0)
-                       goto err_output;
-               output->base.repaint = wayland_output_repaint_gl;
-       }
-
-       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);
-
-       return output;
-
-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);
-
-       /* FIXME: cleanup weston_output */
-       free(output);
-
-       return NULL;
-}
-
-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)
-{
-       struct wayland_output *output;
-
-       output = wayland_output_create(b, x, y, oc->width, oc->height, oc->name,
-                                      fullscreen, oc->transform, oc->scale);
-
-       return output;
-}
-
-static struct wayland_output *
-wayland_output_create_for_parent_output(struct wayland_backend *b,
-                                       struct wayland_parent_output *poutput)
-{
-       struct wayland_output *output;
-       struct weston_mode *mode;
-       int32_t x;
-
-       if (poutput->current_mode) {
-               mode = poutput->current_mode;
-       } else if (poutput->preferred_mode) {
-               mode = poutput->preferred_mode;
-       } else if (!wl_list_empty(&poutput->mode_list)) {
-               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;
-       }
-
-       output = wayland_output_create(b, x, 0, mode->width, mode->height,
-                                      NULL, 0,
-                                      WL_OUTPUT_TRANSFORM_NORMAL, 1);
-       if (!output)
-               return NULL;
-
-       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);
-
-       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));
-       }
-
-       return output;
-}
-
-static void
-shell_surface_ping(void *data, struct wl_shell_surface *shell_surface,
-                  uint32_t serial)
-{
-       wl_shell_surface_pong(shell_surface, serial);
-}
-
-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 */
-}
-
-static void
-shell_surface_popup_done(void *data, struct wl_shell_surface *shell_surface)
-{
-}
-
-static const struct wl_shell_surface_listener shell_surface_listener = {
-       shell_surface_ping,
-       shell_surface_configure,
-       shell_surface_popup_done
-};
-
-/* Events received from the wayland-server this compositor is client of: */
-
-/* parent input interface */
-static void
-input_set_cursor(struct wayland_input *input)
-{
-
-       struct wl_buffer *buffer;
-       struct wl_cursor_image *image;
-
-       if (!input->backend->cursor)
-               return; /* Couldn't load the cursor. Can't set it */
-
-       image = input->backend->cursor->images[0];
-       buffer = wl_cursor_image_get_buffer(image);
-       if (!buffer)
-               return;
-
-       wl_pointer_set_cursor(input->parent.pointer, input->enter_serial,
-                             input->parent.cursor.surface,
-                             image->hotspot_x, image->hotspot_y);
-
-       wl_surface_attach(input->parent.cursor.surface, buffer, 0, 0);
-       wl_surface_damage(input->parent.cursor.surface, 0, 0,
-                         image->width, image->height);
-       wl_surface_commit(input->parent.cursor.surface);
-}
-
-static void
-input_handle_pointer_enter(void *data, struct wl_pointer *pointer,
-                          uint32_t serial, struct wl_surface *surface,
-                          wl_fixed_t fixed_x, wl_fixed_t fixed_y)
-{
-       struct wayland_input *input = data;
-       int32_t fx, fy;
-       enum theme_location location;
-       double x, y;
-
-       x = wl_fixed_to_double(fixed_x);
-       y = wl_fixed_to_double(fixed_y);
-
-       /* XXX: If we get a modifier event immediately before the focus,
-        *      we should try to keep the same serial. */
-       input->enter_serial = serial;
-       input->output = wl_surface_get_user_data(surface);
-
-       if (input->output->frame) {
-               location = frame_pointer_enter(input->output->frame, input,
-                                              x, y);
-               frame_interior(input->output->frame, &fx, &fy, NULL, NULL);
-               x -= fx;
-               y -= fy;
-
-               if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&input->output->base);
-       } else {
-               location = THEME_LOCATION_CLIENT_AREA;
-       }
-
-       weston_output_transform_coordinate(&input->output->base, x, y, &x, &y);
-
-       if (location == THEME_LOCATION_CLIENT_AREA) {
-               input->has_focus = true;
-               notify_pointer_focus(&input->base, &input->output->base, x, y);
-               wl_pointer_set_cursor(input->parent.pointer,
-                                     input->enter_serial, NULL, 0, 0);
-       } else {
-               input->has_focus = false;
-               notify_pointer_focus(&input->base, NULL, 0, 0);
-               input_set_cursor(input);
-       }
-}
-
-static void
-input_handle_pointer_leave(void *data, struct wl_pointer *pointer,
-                          uint32_t serial, struct wl_surface *surface)
-{
-       struct wayland_input *input = data;
-
-       if (!input->output)
-               return;
-
-       if (input->output->frame) {
-               frame_pointer_leave(input->output->frame, input);
-
-               if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&input->output->base);
-       }
-
-       notify_pointer_focus(&input->base, NULL, 0, 0);
-       input->output = NULL;
-       input->has_focus = false;
-}
-
-static void
-input_handle_motion(void *data, struct wl_pointer *pointer,
-                   uint32_t time, wl_fixed_t fixed_x, wl_fixed_t fixed_y)
-{
-       struct wayland_input *input = data;
-       int32_t fx, fy;
-       enum theme_location location;
-       bool want_frame = false;
-       double x, y;
-
-       if (!input->output)
-               return;
-
-       x = wl_fixed_to_double(fixed_x);
-       y = wl_fixed_to_double(fixed_y);
-
-       if (input->output->frame) {
-               location = frame_pointer_motion(input->output->frame, input,
-                                               x, y);
-               frame_interior(input->output->frame, &fx, &fy, NULL, NULL);
-               x -= fx;
-               y -= fy;
-
-               if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&input->output->base);
-       } else {
-               location = THEME_LOCATION_CLIENT_AREA;
-       }
-
-       weston_output_transform_coordinate(&input->output->base, x, y, &x, &y);
-
-       if (input->has_focus && location != THEME_LOCATION_CLIENT_AREA) {
-               input_set_cursor(input);
-               notify_pointer_focus(&input->base, NULL, 0, 0);
-               input->has_focus = false;
-               want_frame = true;
-       } else if (!input->has_focus &&
-                  location == THEME_LOCATION_CLIENT_AREA) {
-               wl_pointer_set_cursor(input->parent.pointer,
-                                     input->enter_serial, NULL, 0, 0);
-               notify_pointer_focus(&input->base, &input->output->base, x, y);
-               input->has_focus = true;
-               want_frame = true;
-       }
-
-       if (location == THEME_LOCATION_CLIENT_AREA) {
-               notify_motion_absolute(&input->base, time, x, y);
-               want_frame = true;
-       }
-
-       if (want_frame && input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
-               notify_pointer_frame(&input->base);
-}
-
-static void
-input_handle_button(void *data, struct wl_pointer *pointer,
-                   uint32_t serial, uint32_t time, uint32_t button,
-                   uint32_t state_w)
-{
-       struct wayland_input *input = data;
-       enum wl_pointer_button_state state = state_w;
-       enum frame_button_state fstate;
-       enum theme_location location;
-
-       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);
-
-               if (frame_status(input->output->frame) & FRAME_STATUS_MOVE) {
-
-                       wl_shell_surface_move(input->output->parent.shell_surface,
-                                             input->parent.seat, serial);
-                       frame_status_clear(input->output->frame,
-                                          FRAME_STATUS_MOVE);
-                       return;
-               }
-
-               if (frame_status(input->output->frame) & FRAME_STATUS_CLOSE) {
-                       wayland_output_destroy(&input->output->base);
-                       input->output = NULL;
-                       input->keyboard_focus = NULL;
-
-                       if (wl_list_empty(&input->backend->compositor->output_list))
-                               weston_compositor_exit(input->backend->compositor);
-
-                       return;
-               }
-
-               if (frame_status(input->output->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&input->output->base);
-       } else {
-               location = THEME_LOCATION_CLIENT_AREA;
-       }
-
-       if (location == THEME_LOCATION_CLIENT_AREA) {
-               notify_button(&input->base, time, button, state);
-               if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
-                       notify_pointer_frame(&input->base);
-       }
-}
-
-static void
-input_handle_axis(void *data, struct wl_pointer *pointer,
-                 uint32_t time, uint32_t axis, wl_fixed_t value)
-{
-       struct wayland_input *input = data;
-       struct weston_pointer_axis_event weston_event;
-
-       weston_event.axis = axis;
-       weston_event.value = wl_fixed_to_double(value);
-
-       if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL &&
-           input->vert.has_discrete) {
-               weston_event.has_discrete = true;
-               weston_event.discrete = input->vert.discrete;
-               input->vert.has_discrete = false;
-       } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL &&
-                  input->horiz.has_discrete) {
-               weston_event.has_discrete = true;
-               weston_event.discrete = input->horiz.discrete;
-               input->horiz.has_discrete = false;
-       }
-
-       notify_axis(&input->base, time, &weston_event);
-
-       if (input->seat_version < WL_POINTER_FRAME_SINCE_VERSION)
-               notify_pointer_frame(&input->base);
-}
-
-static void
-input_handle_frame(void *data, struct wl_pointer *pointer)
-{
-       struct wayland_input *input = data;
-
-       notify_pointer_frame(&input->base);
-}
-
-static void
-input_handle_axis_source(void *data, struct wl_pointer *pointer,
-                        uint32_t source)
-{
-       struct wayland_input *input = data;
-
-       notify_axis_source(&input->base, source);
-}
-
-static void
-input_handle_axis_stop(void *data, struct wl_pointer *pointer,
-                      uint32_t time, uint32_t axis)
-{
-       struct wayland_input *input = data;
-       struct weston_pointer_axis_event weston_event;
-
-       weston_event.axis = axis;
-       weston_event.value = 0;
-
-       notify_axis(&input->base, time, &weston_event);
-}
-
-static void
-input_handle_axis_discrete(void *data, struct wl_pointer *pointer,
-                          uint32_t axis, int32_t discrete)
-{
-       struct wayland_input *input = data;
-
-       if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
-               input->vert.has_discrete = true;
-               input->vert.discrete = discrete;
-       } else if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
-               input->horiz.has_discrete = true;
-               input->horiz.discrete = discrete;
-       }
-}
-
-static const struct wl_pointer_listener pointer_listener = {
-       input_handle_pointer_enter,
-       input_handle_pointer_leave,
-       input_handle_motion,
-       input_handle_button,
-       input_handle_axis,
-       input_handle_frame,
-       input_handle_axis_source,
-       input_handle_axis_stop,
-       input_handle_axis_discrete,
-};
-
-static void
-input_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
-                   int fd, uint32_t size)
-{
-       struct wayland_input *input = data;
-       struct xkb_keymap *keymap;
-       char *map_str;
-
-       if (!data) {
-               close(fd);
-               return;
-       }
-
-       if (format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
-               map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
-               if (map_str == MAP_FAILED) {
-                       weston_log("mmap failed: %m\n");
-                       goto error;
-               }
-
-               keymap = xkb_keymap_new_from_string(input->backend->compositor->xkb_context,
-                                                   map_str,
-                                                   XKB_KEYMAP_FORMAT_TEXT_V1,
-                                                   0);
-               munmap(map_str, size);
-
-               if (!keymap) {
-                       weston_log("failed to compile keymap\n");
-                       goto error;
-               }
-
-               input->keyboard_state_update = STATE_UPDATE_NONE;
-       } else if (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) {
-               weston_log("No keymap provided; falling back to defalt\n");
-               keymap = NULL;
-               input->keyboard_state_update = STATE_UPDATE_AUTOMATIC;
-       } else {
-               weston_log("Invalid keymap\n");
-               goto error;
-       }
-
-       close(fd);
-
-       if (weston_seat_get_keyboard(&input->base))
-               weston_seat_update_keymap(&input->base, keymap);
-       else
-               weston_seat_init_keyboard(&input->base, keymap);
-
-       xkb_keymap_unref(keymap);
-
-       return;
-
-error:
-       wl_keyboard_release(input->parent.keyboard);
-       close(fd);
-}
-
-static void
-input_handle_keyboard_enter(void *data,
-                           struct wl_keyboard *keyboard,
-                           uint32_t serial,
-                           struct wl_surface *surface,
-                           struct wl_array *keys)
-{
-       struct wayland_input *input = data;
-       struct wayland_output *focus;
-
-       focus = input->keyboard_focus;
-       if (focus) {
-               /* This shouldn't happen */
-               focus->keyboard_count--;
-               if (!focus->keyboard_count && focus->frame)
-                       frame_unset_flag(focus->frame, FRAME_FLAG_ACTIVE);
-               if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&focus->base);
-       }
-
-       input->keyboard_focus = wl_surface_get_user_data(surface);
-       input->keyboard_focus->keyboard_count++;
-
-       focus = input->keyboard_focus;
-       if (focus->frame) {
-               frame_set_flag(focus->frame, FRAME_FLAG_ACTIVE);
-               if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&focus->base);
-       }
-
-
-       /* XXX: If we get a modifier event immediately before the focus,
-        *      we should try to keep the same serial. */
-       notify_keyboard_focus_in(&input->base, keys,
-                                STATE_UPDATE_AUTOMATIC);
-}
-
-static void
-input_handle_keyboard_leave(void *data,
-                           struct wl_keyboard *keyboard,
-                           uint32_t serial,
-                           struct wl_surface *surface)
-{
-       struct wayland_input *input = data;
-       struct wayland_output *focus;
-
-       notify_keyboard_focus_out(&input->base);
-
-       focus = input->keyboard_focus;
-       if (!focus)
-               return;
-
-       focus->keyboard_count--;
-       if (!focus->keyboard_count && focus->frame) {
-               frame_unset_flag(focus->frame, FRAME_FLAG_ACTIVE);
-               if (frame_status(focus->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&focus->base);
-       }
-
-       input->keyboard_focus = NULL;
-}
-
-static void
-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;
-
-       input->key_serial = serial;
-       notify_key(&input->base, time, key,
-                  state ? WL_KEYBOARD_KEY_STATE_PRESSED :
-                          WL_KEYBOARD_KEY_STATE_RELEASED,
-                  input->keyboard_state_update);
-}
-
-static void
-input_handle_modifiers(void *data, struct wl_keyboard *wl_keyboard,
-                      uint32_t serial_in, uint32_t mods_depressed,
-                      uint32_t mods_latched, uint32_t mods_locked,
-                      uint32_t group)
-{
-       struct weston_keyboard *keyboard;
-       struct wayland_input *input = data;
-       struct wayland_backend *b = input->backend;
-       uint32_t serial_out;
-
-       /* If we get a key event followed by a modifier event with the
-        * same serial number, then we try to preserve those semantics by
-        * reusing the same serial number on the way out too. */
-       if (serial_in == input->key_serial)
-               serial_out = wl_display_get_serial(b->compositor->wl_display);
-       else
-               serial_out = wl_display_next_serial(b->compositor->wl_display);
-
-       keyboard = weston_seat_get_keyboard(&input->base);
-       xkb_state_update_mask(keyboard->xkb_state.state,
-                             mods_depressed, mods_latched,
-                             mods_locked, 0, 0, group);
-       notify_modifiers(&input->base, serial_out);
-}
-
-static void
-input_handle_repeat_info(void *data, struct wl_keyboard *keyboard,
-                        int32_t rate, int32_t delay)
-{
-       struct wayland_input *input = data;
-       struct wayland_backend *b = input->backend;
-
-       b->compositor->kb_repeat_rate = rate;
-       b->compositor->kb_repeat_delay = delay;
-}
-
-static const struct wl_keyboard_listener keyboard_listener = {
-       input_handle_keymap,
-       input_handle_keyboard_enter,
-       input_handle_keyboard_leave,
-       input_handle_key,
-       input_handle_modifiers,
-       input_handle_repeat_info,
-};
-
-static void
-input_handle_touch_down(void *data, struct wl_touch *wl_touch,
-                       uint32_t serial, uint32_t time,
-                       struct wl_surface *surface, int32_t id,
-                       wl_fixed_t fixed_x, wl_fixed_t fixed_y)
-{
-       struct wayland_input *input = data;
-       struct wayland_output *output;
-       enum theme_location location;
-       bool first_touch;
-       int32_t fx, fy;
-       double x, y;
-
-       x = wl_fixed_to_double(fixed_x);
-       y = wl_fixed_to_double(fixed_y);
-
-       first_touch = (input->touch_points == 0);
-       input->touch_points++;
-
-       input->touch_focus = wl_surface_get_user_data(surface);
-       output = input->touch_focus;
-       if (!first_touch && !input->touch_active)
-               return;
-
-       if (output->frame) {
-               location = frame_touch_down(output->frame, input, id, x, y);
-
-               frame_interior(output->frame, &fx, &fy, NULL, NULL);
-               x -= fx;
-               y -= fy;
-
-               if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&output->base);
-
-               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);
-                       frame_status_clear(output->frame,
-                                          FRAME_STATUS_MOVE);
-                       return;
-               }
-
-               if (first_touch && location != THEME_LOCATION_CLIENT_AREA)
-                       return;
-       }
-
-       weston_output_transform_coordinate(&output->base, x, y, &x, &y);
-
-       notify_touch(&input->base, time, id, x, y, WL_TOUCH_DOWN);
-       input->touch_active = true;
-}
-
-static void
-input_handle_touch_up(void *data, struct wl_touch *wl_touch,
-                     uint32_t serial, uint32_t time, int32_t id)
-{
-       struct wayland_input *input = data;
-       struct wayland_output *output = input->touch_focus;
-       bool active = input->touch_active;
-
-       input->touch_points--;
-       if (input->touch_points == 0) {
-               input->touch_focus = NULL;
-               input->touch_active = false;
-       }
-
-       if (!output)
-               return;
-
-       if (output->frame) {
-               frame_touch_up(output->frame, input, id);
-
-               if (frame_status(output->frame) & FRAME_STATUS_CLOSE) {
-                       wayland_output_destroy(&output->base);
-                       input->touch_focus = NULL;
-                       input->keyboard_focus = NULL;
-                       if (wl_list_empty(&input->backend->compositor->output_list))
-                               weston_compositor_exit(input->backend->compositor);
-
-                       return;
-               }
-               if (frame_status(output->frame) & FRAME_STATUS_REPAINT)
-                       weston_output_schedule_repaint(&output->base);
-       }
-
-       if (active)
-               notify_touch(&input->base, time, id, 0, 0, WL_TOUCH_UP);
-}
-
-static void
-input_handle_touch_motion(void *data, struct wl_touch *wl_touch,
-                        uint32_t time, int32_t id,
-                        wl_fixed_t fixed_x, wl_fixed_t fixed_y)
-{
-       struct wayland_input *input = data;
-       struct wayland_output *output = input->touch_focus;
-       int32_t fx, fy;
-       double x, y;
-
-       x = wl_fixed_to_double(fixed_x);
-       y = wl_fixed_to_double(fixed_y);
-
-       if (!output || !input->touch_active)
-               return;
-
-       if (output->frame) {
-               frame_interior(output->frame, &fx, &fy, NULL, NULL);
-               x -= fx;
-               y -= fy;
-       }
-
-       weston_output_transform_coordinate(&output->base, x, y, &x, &y);
-
-       notify_touch(&input->base, time, id, x, y, WL_TOUCH_MOTION);
-}
-
-static void
-input_handle_touch_frame(void *data, struct wl_touch *wl_touch)
-{
-       struct wayland_input *input = data;
-
-       if (!input->touch_focus || !input->touch_active)
-               return;
-
-       notify_touch_frame(&input->base);
-}
-
-static void
-input_handle_touch_cancel(void *data, struct wl_touch *wl_touch)
-{
-       struct wayland_input *input = data;
-
-       if (!input->touch_focus || !input->touch_active)
-               return;
-
-       notify_touch_cancel(&input->base);
-}
-
-static const struct wl_touch_listener touch_listener = {
-       input_handle_touch_down,
-       input_handle_touch_up,
-       input_handle_touch_motion,
-       input_handle_touch_frame,
-       input_handle_touch_cancel,
-};
-
-
-static void
-input_handle_capabilities(void *data, struct wl_seat *seat,
-                         enum wl_seat_capability caps)
-{
-       struct wayland_input *input = data;
-
-       if ((caps & WL_SEAT_CAPABILITY_POINTER) && !input->parent.pointer) {
-               input->parent.pointer = wl_seat_get_pointer(seat);
-               wl_pointer_set_user_data(input->parent.pointer, input);
-               wl_pointer_add_listener(input->parent.pointer,
-                                       &pointer_listener, input);
-               weston_seat_init_pointer(&input->base);
-       } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && input->parent.pointer) {
-               if (input->seat_version >= WL_POINTER_RELEASE_SINCE_VERSION)
-                       wl_pointer_release(input->parent.pointer);
-               else
-                       wl_pointer_destroy(input->parent.pointer);
-               input->parent.pointer = NULL;
-               weston_seat_release_pointer(&input->base);
-       }
-
-       if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !input->parent.keyboard) {
-               input->parent.keyboard = wl_seat_get_keyboard(seat);
-               wl_keyboard_set_user_data(input->parent.keyboard, input);
-               wl_keyboard_add_listener(input->parent.keyboard,
-                                        &keyboard_listener, input);
-       } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && input->parent.keyboard) {
-               if (input->seat_version >= WL_KEYBOARD_RELEASE_SINCE_VERSION)
-                       wl_keyboard_release(input->parent.keyboard);
-               else
-                       wl_keyboard_destroy(input->parent.keyboard);
-               input->parent.keyboard = NULL;
-               weston_seat_release_keyboard(&input->base);
-       }
-
-       if ((caps & WL_SEAT_CAPABILITY_TOUCH) && !input->parent.touch) {
-               input->parent.touch = wl_seat_get_touch(seat);
-               wl_touch_set_user_data(input->parent.touch, input);
-               wl_touch_add_listener(input->parent.touch,
-                                     &touch_listener, input);
-               weston_seat_init_touch(&input->base);
-       } else if (!(caps & WL_SEAT_CAPABILITY_TOUCH) && input->parent.touch) {
-               if (input->seat_version >= WL_TOUCH_RELEASE_SINCE_VERSION)
-                       wl_touch_release(input->parent.touch);
-               else
-                       wl_touch_destroy(input->parent.touch);
-               input->parent.touch = NULL;
-               weston_seat_release_touch(&input->base);
-       }
-}
-
-static void
-input_handle_name(void *data, struct wl_seat *seat,
-                 const char *name)
-{
-}
-
-static const struct wl_seat_listener seat_listener = {
-       input_handle_capabilities,
-       input_handle_name,
-};
-
-static void
-display_add_seat(struct wayland_backend *b, uint32_t id, uint32_t available_version)
-{
-       struct wayland_input *input;
-       uint32_t version = MIN(available_version, 4);
-
-       input = zalloc(sizeof *input);
-       if (input == NULL)
-               return;
-
-       weston_seat_init(&input->base, b->compositor, "default");
-       input->backend = b;
-       input->parent.seat = wl_registry_bind(b->parent.registry, id,
-                                             &wl_seat_interface, version);
-       input->seat_version = version;
-       wl_list_insert(b->input_list.prev, &input->link);
-
-       wl_seat_add_listener(input->parent.seat, &seat_listener, input);
-       wl_seat_set_user_data(input->parent.seat, input);
-
-       input->parent.cursor.surface =
-               wl_compositor_create_surface(b->parent.compositor);
-
-       input->vert.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
-       input->horiz.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
-}
-
-static void
-wayland_parent_output_geometry(void *data, struct wl_output *output_proxy,
-                              int32_t x, int32_t y,
-                              int32_t physical_width, int32_t physical_height,
-                              int32_t subpixel, const char *make,
-                              const char *model, int32_t transform)
-{
-       struct wayland_parent_output *output = data;
-
-       output->x = x;
-       output->y = y;
-       output->physical.width = physical_width;
-       output->physical.height = physical_height;
-       output->physical.subpixel = subpixel;
-
-       free(output->physical.make);
-       output->physical.make = strdup(make);
-       free(output->physical.model);
-       output->physical.model = strdup(model);
-
-       output->transform = transform;
-}
-
-static struct weston_mode *
-find_mode(struct wl_list *list, int32_t width, int32_t height, uint32_t refresh)
-{
-       struct weston_mode *mode;
-
-       wl_list_for_each(mode, list, link) {
-               if (mode->width == width && mode->height == height &&
-                   mode->refresh == refresh)
-                       return mode;
-       }
-
-       mode = zalloc(sizeof *mode);
-       if (!mode)
-               return NULL;
-
-       mode->width = width;
-       mode->height = height;
-       mode->refresh = refresh;
-       wl_list_insert(list, &mode->link);
-
-       return mode;
-}
-
-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_mode *mode;
-
-       if (output->output) {
-               mode = find_mode(&output->output->base.mode_list,
-                                width, height, refresh);
-               if (!mode)
-                       return;
-               mode->flags = flags;
-               /* Do a mode-switch on current mode change? */
-       } else {
-               mode = find_mode(&output->mode_list, width, height, refresh);
-               if (!mode)
-                       return;
-               mode->flags = flags;
-               if (flags & WL_OUTPUT_MODE_CURRENT)
-                       output->current_mode = mode;
-               if (flags & WL_OUTPUT_MODE_PREFERRED)
-                       output->preferred_mode = mode;
-       }
-}
-
-static const struct wl_output_listener output_listener = {
-       wayland_parent_output_geometry,
-       wayland_parent_output_mode
-};
-
-static void
-wayland_backend_register_output(struct wayland_backend *b, uint32_t id)
-{
-       struct wayland_parent_output *output;
-
-       output = zalloc(sizeof *output);
-       if (!output)
-               return;
-
-       output->id = id;
-       output->global = wl_registry_bind(b->parent.registry, id,
-                                         &wl_output_interface, 1);
-       if (!output->global) {
-               free(output);
-               return;
-       }
-
-       wl_output_add_listener(output->global, &output_listener, output);
-
-       output->scale = 0;
-       output->transform = WL_OUTPUT_TRANSFORM_NORMAL;
-       output->physical.subpixel = WL_OUTPUT_SUBPIXEL_UNKNOWN;
-       wl_list_init(&output->mode_list);
-       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);
-       }
-}
-
-static void
-wayland_parent_output_destroy(struct wayland_parent_output *output)
-{
-       struct weston_mode *mode, *next;
-
-       if (output->output)
-               wayland_output_destroy(&output->output->base);
-
-       wl_output_destroy(output->global);
-       free(output->physical.make);
-       free(output->physical.model);
-
-       wl_list_for_each_safe(mode, next, &output->mode_list, link) {
-               wl_list_remove(&mode->link);
-               free(mode);
-       }
-}
-
-static void
-registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
-                      const char *interface, uint32_t version)
-{
-       struct wayland_backend *b = data;
-
-       if (strcmp(interface, "wl_compositor") == 0) {
-               b->parent.compositor =
-                       wl_registry_bind(registry, name,
-                                        &wl_compositor_interface, 1);
-       } else if (strcmp(interface, "wl_shell") == 0) {
-               b->parent.shell =
-                       wl_registry_bind(registry, name,
-                                        &wl_shell_interface, 1);
-       } else if (strcmp(interface, "zwp_fullscreen_shell_v1") == 0) {
-               b->parent.fshell =
-                       wl_registry_bind(registry, name,
-                                        &zwp_fullscreen_shell_v1_interface, 1);
-       } else if (strcmp(interface, "wl_seat") == 0) {
-               display_add_seat(b, name, version);
-       } else if (strcmp(interface, "wl_output") == 0) {
-               wayland_backend_register_output(b, name);
-       } else if (strcmp(interface, "wl_shm") == 0) {
-               b->parent.shm =
-                       wl_registry_bind(registry, name, &wl_shm_interface, 1);
-       }
-}
-
-static void
-registry_handle_global_remove(void *data, struct wl_registry *registry,
-                             uint32_t name)
-{
-       struct wayland_backend *b = data;
-       struct wayland_parent_output *output;
-
-       wl_list_for_each(output, &b->parent.output_list, link)
-               if (output->id == name)
-                       wayland_parent_output_destroy(output);
-}
-
-static const struct wl_registry_listener registry_listener = {
-       registry_handle_global,
-       registry_handle_global_remove
-};
-
-static int
-wayland_backend_handle_event(int fd, uint32_t mask, void *data)
-{
-       struct wayland_backend *b = data;
-       int count = 0;
-
-       if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
-               weston_compositor_exit(b->compositor);
-               return 0;
-       }
-
-       if (mask & WL_EVENT_READABLE)
-               count = wl_display_dispatch(b->parent.wl_display);
-       if (mask & WL_EVENT_WRITABLE)
-               wl_display_flush(b->parent.wl_display);
-
-       if (mask == 0) {
-               count = wl_display_dispatch_pending(b->parent.wl_display);
-               wl_display_flush(b->parent.wl_display);
-       }
-
-       return count;
-}
-
-static void
-wayland_restore(struct weston_compositor *ec)
-{
-}
-
-static void
-wayland_destroy(struct weston_compositor *ec)
-{
-       struct wayland_backend *b = (struct wayland_backend *) ec->backend;
-
-       weston_compositor_shutdown(ec);
-
-       if (b->parent.shm)
-               wl_shm_destroy(b->parent.shm);
-
-       free(b);
-}
-
-static const char *left_ptrs[] = {
-       "left_ptr",
-       "default",
-       "top_left_arrow",
-       "left-arrow"
-};
-
-static void
-create_cursor(struct wayland_backend *b,
-             struct weston_wayland_backend_config *config)
-{
-       unsigned int i;
-
-       b->cursor_theme = wl_cursor_theme_load(config->cursor_theme,
-                                              config->cursor_size,
-                                              b->parent.shm);
-       if (!b->cursor_theme) {
-               fprintf(stderr, "could not load cursor theme\n");
-               return;
-       }
-
-       b->cursor = NULL;
-       for (i = 0; !b->cursor && i < ARRAY_LENGTH(left_ptrs); ++i)
-               b->cursor = wl_cursor_theme_get_cursor(b->cursor_theme,
-                                                      left_ptrs[i]);
-       if (!b->cursor) {
-               fprintf(stderr, "could not load left cursor\n");
-               return;
-       }
-}
-
-static void
-fullscreen_binding(struct weston_keyboard *keyboard, uint32_t time,
-                  uint32_t key, void *data)
-{
-       struct wayland_backend *b = data;
-       struct wayland_input *input = NULL;
-
-       wl_list_for_each(input, &b->input_list, link)
-               if (&input->base == keyboard->seat)
-                       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_backend *
-wayland_backend_create(struct weston_compositor *compositor,
-                      struct weston_wayland_backend_config *new_config)
-{
-       struct wayland_backend *b;
-       struct wl_event_loop *loop;
-       int fd;
-
-       b = zalloc(sizeof *b);
-       if (b == NULL)
-               return NULL;
-
-       b->compositor = compositor;
-       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");
-               goto err_compositor;
-       }
-
-       wl_list_init(&b->parent.output_list);
-       wl_list_init(&b->input_list);
-       b->parent.registry = wl_display_get_registry(b->parent.wl_display);
-       wl_registry_add_listener(b->parent.registry, &registry_listener, b);
-       wl_display_roundtrip(b->parent.wl_display);
-
-       create_cursor(b, new_config);
-
-       b->use_pixman = new_config->use_pixman;
-
-       if (!b->use_pixman) {
-               gl_renderer = weston_load_module("gl-renderer.so",
-                                                "gl_renderer_interface");
-               if (!gl_renderer)
-                       b->use_pixman = 1;
-       }
-
-       if (!b->use_pixman) {
-               if (gl_renderer->create(compositor,
-                                       EGL_PLATFORM_WAYLAND_KHR,
-                                       b->parent.wl_display,
-                                       gl_renderer->alpha_attribs,
-                                       NULL,
-                                       0) < 0) {
-                       weston_log("Failed to initialize the GL renderer; "
-                                  "falling back to pixman.\n");
-                       b->use_pixman = 1;
-               }
-       }
-
-       if (b->use_pixman) {
-               if (pixman_renderer_init(compositor) < 0) {
-                       weston_log("Failed to initialize pixman renderer\n");
-                       goto err_display;
-               }
-       }
-
-       b->base.destroy = wayland_destroy;
-       b->base.restore = wayland_restore;
-
-       loop = wl_display_get_event_loop(compositor->wl_display);
-
-       fd = wl_display_get_fd(b->parent.wl_display);
-       b->parent.wl_source =
-               wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
-                                    wayland_backend_handle_event, b);
-       if (b->parent.wl_source == NULL)
-               goto err_display;
-
-       wl_event_source_check(b->parent.wl_source);
-
-       if (compositor->renderer->import_dmabuf) {
-               if (linux_dmabuf_setup(compositor) < 0)
-                       weston_log("Error: initializing dmabuf "
-                                  "support failed.\n");
-       }
-
-       compositor->backend = &b->base;
-       return b;
-err_display:
-       wl_display_disconnect(b->parent.wl_display);
-err_compositor:
-       weston_compositor_shutdown(compositor);
-       free(b);
-       return NULL;
-}
-
-static void
-wayland_backend_destroy(struct wayland_backend *b)
-{
-       wl_display_disconnect(b->parent.wl_display);
-
-       if (b->theme)
-               theme_destroy(b->theme);
-       if (b->frame_device)
-               cairo_device_destroy(b->frame_device);
-       wl_cursor_theme_destroy(b->cursor_theme);
-
-       weston_compositor_shutdown(b->compositor);
-       free(b);
-}
-
-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)
-{
-       struct wayland_backend *b;
-       struct wayland_output *output;
-       struct wayland_parent_output *poutput;
-       struct weston_wayland_backend_config new_config;
-       int x, count;
-
-       if (config_base == NULL ||
-           config_base->struct_version != WESTON_WAYLAND_BACKEND_CONFIG_VERSION ||
-           config_base->struct_size > sizeof(struct weston_wayland_backend_config)) {
-               weston_log("wayland backend config structure is invalid\n");
-               return -1;
-       }
-
-       config_init_to_defaults(&new_config);
-       memcpy(&new_config, config_base, config_base->struct_size);
-
-       b = wayland_backend_create(compositor, &new_config);
-
-       if (!b)
-               return -1;
-
-       if (new_config.sprawl || b->parent.fshell) {
-               b->sprawl_across_outputs = 1;
-               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);
-
-               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)
-                       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;
-
-               x += output->base.width;
-       }
-
-       weston_compositor_add_key_binding(compositor, KEY_F,
-                                         MODIFIER_CTRL | MODIFIER_ALT,
-                                         fullscreen_binding, b);
-       return 0;
-
-err_outputs:
-       wayland_backend_destroy(b);
-       return -1;
-}
diff --git a/src/compositor-wayland.h b/src/compositor-wayland.h
deleted file mode 100644 (file)
index de69b98..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * Copyright © 2016 Benoit Gschwind
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_COMPOSITOR_WAYLAND_H
-#define WESTON_COMPOSITOR_WAYLAND_H
-
-#include "compositor.h"
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#define WESTON_WAYLAND_BACKEND_CONFIG_VERSION 1
-
-struct weston_wayland_backend_output_config {
-       int width;
-       int height;
-       char *name;
-       uint32_t transform;
-       int32_t scale;
-};
-
-struct weston_wayland_backend_config {
-       struct weston_backend_config base;
-       int use_pixman;
-       int sprawl;
-       char *display_name;
-       int fullscreen;
-       char *cursor_theme;
-       int cursor_size;
-       int num_outputs;
-       struct weston_wayland_backend_output_config *outputs;
-};
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* WESTON_COMPOSITOR_WAYLAND_H */
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
deleted file mode 100644 (file)
index 5e46e68..0000000
+++ /dev/null
@@ -1,1720 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2010-2011 Intel Corporation
- * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <errno.h>
-#include <sys/time.h>
-#include <sys/shm.h>
-#include <linux/input.h>
-
-#include <xcb/xcb.h>
-#include <xcb/shm.h>
-#ifdef HAVE_XCB_XKB
-#include <xcb/xkb.h>
-#endif
-
-#include <X11/Xlib.h>
-#include <X11/Xlib-xcb.h>
-
-#include <xkbcommon/xkbcommon.h>
-
-#include "compositor.h"
-#include "compositor-x11.h"
-#include "shared/config-parser.h"
-#include "shared/helpers.h"
-#include "shared/image-loader.h"
-#include "gl-renderer.h"
-#include "pixman-renderer.h"
-#include "presentation-time-server-protocol.h"
-#include "linux-dmabuf.h"
-
-#define DEFAULT_AXIS_STEP_DISTANCE 10
-
-struct x11_backend {
-       struct weston_backend    base;
-       struct weston_compositor *compositor;
-
-       Display                 *dpy;
-       xcb_connection_t        *conn;
-       xcb_screen_t            *screen;
-       xcb_cursor_t             null_cursor;
-       struct wl_array          keys;
-       struct wl_event_source  *xcb_source;
-       struct xkb_keymap       *xkb_keymap;
-       unsigned int             has_xkb;
-       uint8_t                  xkb_event_base;
-       int                      use_pixman;
-
-       int                      has_net_wm_state_fullscreen;
-
-       /* We could map multi-pointer X to multiple wayland seats, but
-        * for now we only support core X input. */
-       struct weston_seat               core_seat;
-       double                           prev_x;
-       double                           prev_y;
-
-       struct {
-               xcb_atom_t               wm_protocols;
-               xcb_atom_t               wm_normal_hints;
-               xcb_atom_t               wm_size_hints;
-               xcb_atom_t               wm_delete_window;
-               xcb_atom_t               wm_class;
-               xcb_atom_t               net_wm_name;
-               xcb_atom_t               net_supporting_wm_check;
-               xcb_atom_t               net_supported;
-               xcb_atom_t               net_wm_icon;
-               xcb_atom_t               net_wm_state;
-               xcb_atom_t               net_wm_state_fullscreen;
-               xcb_atom_t               string;
-               xcb_atom_t               utf8_string;
-               xcb_atom_t               cardinal;
-               xcb_atom_t               xkb_names;
-       } atom;
-};
-
-struct x11_output {
-       struct weston_output    base;
-
-       xcb_window_t            window;
-       struct weston_mode      mode;
-       struct wl_event_source *finish_frame_timer;
-
-       xcb_gc_t                gc;
-       xcb_shm_seg_t           segment;
-       pixman_image_t         *hw_surface;
-       int                     shm_id;
-       void                   *buf;
-       uint8_t                 depth;
-       int32_t                 scale;
-};
-
-struct window_delete_data {
-       struct x11_backend      *backend;
-       xcb_window_t            window;
-};
-
-struct gl_renderer_interface *gl_renderer;
-
-static xcb_screen_t *
-x11_compositor_get_default_screen(struct x11_backend *b)
-{
-       xcb_screen_iterator_t iter;
-       int i, screen_nbr = XDefaultScreen(b->dpy);
-
-       iter = xcb_setup_roots_iterator(xcb_get_setup(b->conn));
-       for (i = 0; iter.rem; xcb_screen_next(&iter), i++)
-               if (i == screen_nbr)
-                       return iter.data;
-
-       return xcb_setup_roots_iterator(xcb_get_setup(b->conn)).data;
-}
-
-static struct xkb_keymap *
-x11_backend_get_keymap(struct x11_backend *b)
-{
-       xcb_get_property_cookie_t cookie;
-       xcb_get_property_reply_t *reply;
-       struct xkb_rule_names names;
-       struct xkb_keymap *ret;
-       const char *value_all, *value_part;
-       int length_all, length_part;
-
-       memset(&names, 0, sizeof(names));
-
-       cookie = xcb_get_property(b->conn, 0, b->screen->root,
-                                 b->atom.xkb_names, b->atom.string, 0, 1024);
-       reply = xcb_get_property_reply(b->conn, cookie, NULL);
-       if (reply == NULL)
-               return NULL;
-
-       value_all = xcb_get_property_value(reply);
-       length_all = xcb_get_property_value_length(reply);
-       value_part = value_all;
-
-#define copy_prop_value(to) \
-       length_part = strlen(value_part); \
-       if (value_part + length_part < (value_all + length_all) && \
-           length_part > 0) \
-               names.to = value_part; \
-       value_part += length_part + 1;
-
-       copy_prop_value(rules);
-       copy_prop_value(model);
-       copy_prop_value(layout);
-       copy_prop_value(variant);
-       copy_prop_value(options);
-#undef copy_prop_value
-
-       ret = xkb_keymap_new_from_names(b->compositor->xkb_context, &names, 0);
-
-       free(reply);
-       return ret;
-}
-
-static uint32_t
-get_xkb_mod_mask(struct x11_backend *b, uint32_t in)
-{
-       struct weston_keyboard *keyboard =
-               weston_seat_get_keyboard(&b->core_seat);
-       struct weston_xkb_info *info = keyboard->xkb_info;
-       uint32_t ret = 0;
-
-       if ((in & ShiftMask) && info->shift_mod != XKB_MOD_INVALID)
-               ret |= (1 << info->shift_mod);
-       if ((in & LockMask) && info->caps_mod != XKB_MOD_INVALID)
-               ret |= (1 << info->caps_mod);
-       if ((in & ControlMask) && info->ctrl_mod != XKB_MOD_INVALID)
-               ret |= (1 << info->ctrl_mod);
-       if ((in & Mod1Mask) && info->alt_mod != XKB_MOD_INVALID)
-               ret |= (1 << info->alt_mod);
-       if ((in & Mod2Mask) && info->mod2_mod != XKB_MOD_INVALID)
-               ret |= (1 << info->mod2_mod);
-       if ((in & Mod3Mask) && info->mod3_mod != XKB_MOD_INVALID)
-               ret |= (1 << info->mod3_mod);
-       if ((in & Mod4Mask) && info->super_mod != XKB_MOD_INVALID)
-               ret |= (1 << info->super_mod);
-       if ((in & Mod5Mask) && info->mod5_mod != XKB_MOD_INVALID)
-               ret |= (1 << info->mod5_mod);
-
-       return ret;
-}
-
-static void
-x11_backend_setup_xkb(struct x11_backend *b)
-{
-#ifndef HAVE_XCB_XKB
-       weston_log("XCB-XKB not available during build\n");
-       b->has_xkb = 0;
-       b->xkb_event_base = 0;
-       return;
-#else
-       struct weston_keyboard *keyboard;
-       const xcb_query_extension_reply_t *ext;
-       xcb_generic_error_t *error;
-       xcb_void_cookie_t select;
-       xcb_xkb_use_extension_cookie_t use_ext;
-       xcb_xkb_use_extension_reply_t *use_ext_reply;
-       xcb_xkb_per_client_flags_cookie_t pcf;
-       xcb_xkb_per_client_flags_reply_t *pcf_reply;
-       xcb_xkb_get_state_cookie_t state;
-       xcb_xkb_get_state_reply_t *state_reply;
-       uint32_t values[1] = { XCB_EVENT_MASK_PROPERTY_CHANGE };
-
-       b->has_xkb = 0;
-       b->xkb_event_base = 0;
-
-       ext = xcb_get_extension_data(b->conn, &xcb_xkb_id);
-       if (!ext) {
-               weston_log("XKB extension not available on host X11 server\n");
-               return;
-       }
-       b->xkb_event_base = ext->first_event;
-
-       select = xcb_xkb_select_events_checked(b->conn,
-                                              XCB_XKB_ID_USE_CORE_KBD,
-                                              XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
-                                              0,
-                                              XCB_XKB_EVENT_TYPE_STATE_NOTIFY,
-                                              0,
-                                              0,
-                                              NULL);
-       error = xcb_request_check(b->conn, select);
-       if (error) {
-               weston_log("error: failed to select for XKB state events\n");
-               free(error);
-               return;
-       }
-
-       use_ext = xcb_xkb_use_extension(b->conn,
-                                       XCB_XKB_MAJOR_VERSION,
-                                       XCB_XKB_MINOR_VERSION);
-       use_ext_reply = xcb_xkb_use_extension_reply(b->conn, use_ext, NULL);
-       if (!use_ext_reply) {
-               weston_log("couldn't start using XKB extension\n");
-               return;
-       }
-
-       if (!use_ext_reply->supported) {
-               weston_log("XKB extension version on the server is too old "
-                          "(want %d.%d, has %d.%d)\n",
-                          XCB_XKB_MAJOR_VERSION, XCB_XKB_MINOR_VERSION,
-                          use_ext_reply->serverMajor, use_ext_reply->serverMinor);
-               free(use_ext_reply);
-               return;
-       }
-       free(use_ext_reply);
-
-       pcf = xcb_xkb_per_client_flags(b->conn,
-                                      XCB_XKB_ID_USE_CORE_KBD,
-                                      XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
-                                      XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT,
-                                      0,
-                                      0,
-                                      0);
-       pcf_reply = xcb_xkb_per_client_flags_reply(b->conn, pcf, NULL);
-       if (!pcf_reply ||
-           !(pcf_reply->value & XCB_XKB_PER_CLIENT_FLAG_DETECTABLE_AUTO_REPEAT)) {
-               weston_log("failed to set XKB per-client flags, not using "
-                          "detectable repeat\n");
-               free(pcf_reply);
-               return;
-       }
-       free(pcf_reply);
-
-       state = xcb_xkb_get_state(b->conn, XCB_XKB_ID_USE_CORE_KBD);
-       state_reply = xcb_xkb_get_state_reply(b->conn, state, NULL);
-       if (!state_reply) {
-               weston_log("failed to get initial XKB state\n");
-               return;
-       }
-
-       keyboard = weston_seat_get_keyboard(&b->core_seat);
-       xkb_state_update_mask(keyboard->xkb_state.state,
-                             get_xkb_mod_mask(b, state_reply->baseMods),
-                             get_xkb_mod_mask(b, state_reply->latchedMods),
-                             get_xkb_mod_mask(b, state_reply->lockedMods),
-                             0,
-                             0,
-                             state_reply->group);
-
-       free(state_reply);
-
-       xcb_change_window_attributes(b->conn, b->screen->root,
-                                    XCB_CW_EVENT_MASK, values);
-
-       b->has_xkb = 1;
-#endif
-}
-
-#ifdef HAVE_XCB_XKB
-static void
-update_xkb_keymap(struct x11_backend *b)
-{
-       struct xkb_keymap *keymap;
-
-       keymap = x11_backend_get_keymap(b);
-       if (!keymap) {
-               weston_log("failed to get XKB keymap\n");
-               return;
-       }
-       weston_seat_update_keymap(&b->core_seat, keymap);
-       xkb_keymap_unref(keymap);
-}
-#endif
-
-static int
-x11_input_create(struct x11_backend *b, int no_input)
-{
-       struct xkb_keymap *keymap;
-
-       weston_seat_init(&b->core_seat, b->compositor, "default");
-
-       if (no_input)
-               return 0;
-
-       weston_seat_init_pointer(&b->core_seat);
-
-       keymap = x11_backend_get_keymap(b);
-       if (weston_seat_init_keyboard(&b->core_seat, keymap) < 0)
-               return -1;
-       xkb_keymap_unref(keymap);
-
-       x11_backend_setup_xkb(b);
-
-       return 0;
-}
-
-static void
-x11_input_destroy(struct x11_backend *b)
-{
-       weston_seat_release(&b->core_seat);
-}
-
-static void
-x11_output_start_repaint_loop(struct weston_output *output)
-{
-       struct timespec ts;
-
-       weston_compositor_read_presentation_clock(output->compositor, &ts);
-       weston_output_finish_frame(output, &ts, WP_PRESENTATION_FEEDBACK_INVALID);
-}
-
-static int
-x11_output_repaint_gl(struct weston_output *output_base,
-                     pixman_region32_t *damage)
-{
-       struct x11_output *output = (struct x11_output *)output_base;
-       struct weston_compositor *ec = output->base.compositor;
-
-       ec->renderer->repaint_output(output_base, damage);
-
-       pixman_region32_subtract(&ec->primary_plane.damage,
-                                &ec->primary_plane.damage, damage);
-
-       wl_event_source_timer_update(output->finish_frame_timer, 10);
-       return 0;
-}
-
-static void
-set_clip_for_output(struct weston_output *output_base, pixman_region32_t *region)
-{
-       struct x11_output *output = (struct x11_output *)output_base;
-       struct weston_compositor *ec = output->base.compositor;
-       struct x11_backend *b = (struct x11_backend *)ec->backend;
-       pixman_region32_t transformed_region;
-       pixman_box32_t *rects;
-       xcb_rectangle_t *output_rects;
-       xcb_void_cookie_t cookie;
-       int nrects, i;
-       xcb_generic_error_t *err;
-
-       pixman_region32_init(&transformed_region);
-       pixman_region32_copy(&transformed_region, region);
-       pixman_region32_translate(&transformed_region,
-                                 -output_base->x, -output_base->y);
-       weston_transformed_region(output_base->width, output_base->height,
-                                 output_base->transform,
-                                 output_base->current_scale,
-                                 &transformed_region, &transformed_region);
-
-       rects = pixman_region32_rectangles(&transformed_region, &nrects);
-       output_rects = calloc(nrects, sizeof(xcb_rectangle_t));
-
-       if (output_rects == NULL) {
-               pixman_region32_fini(&transformed_region);
-               return;
-       }
-
-       for (i = 0; i < nrects; i++) {
-               output_rects[i].x = rects[i].x1;
-               output_rects[i].y = rects[i].y1;
-               output_rects[i].width = rects[i].x2 - rects[i].x1;
-               output_rects[i].height = rects[i].y2 - rects[i].y1;
-       }
-
-       pixman_region32_fini(&transformed_region);
-
-       cookie = xcb_set_clip_rectangles_checked(b->conn, XCB_CLIP_ORDERING_UNSORTED,
-                                       output->gc,
-                                       0, 0, nrects,
-                                       output_rects);
-       err = xcb_request_check(b->conn, cookie);
-       if (err != NULL) {
-               weston_log("Failed to set clip rects, err: %d\n", err->error_code);
-               free(err);
-       }
-       free(output_rects);
-}
-
-
-static int
-x11_output_repaint_shm(struct weston_output *output_base,
-                      pixman_region32_t *damage)
-{
-       struct x11_output *output = (struct x11_output *)output_base;
-       struct weston_compositor *ec = output->base.compositor;
-       struct x11_backend *b = (struct x11_backend *)ec->backend;
-       xcb_void_cookie_t cookie;
-       xcb_generic_error_t *err;
-
-       pixman_renderer_output_set_buffer(output_base, output->hw_surface);
-       ec->renderer->repaint_output(output_base, damage);
-
-       pixman_region32_subtract(&ec->primary_plane.damage,
-                                &ec->primary_plane.damage, damage);
-       set_clip_for_output(output_base, damage);
-       cookie = xcb_shm_put_image_checked(b->conn, output->window, output->gc,
-                                       pixman_image_get_width(output->hw_surface),
-                                       pixman_image_get_height(output->hw_surface),
-                                       0, 0,
-                                       pixman_image_get_width(output->hw_surface),
-                                       pixman_image_get_height(output->hw_surface),
-                                       0, 0, output->depth, XCB_IMAGE_FORMAT_Z_PIXMAP,
-                                       0, output->segment, 0);
-       err = xcb_request_check(b->conn, cookie);
-       if (err != NULL) {
-               weston_log("Failed to put shm image, err: %d\n", err->error_code);
-               free(err);
-       }
-
-       wl_event_source_timer_update(output->finish_frame_timer, 10);
-       return 0;
-}
-
-static int
-finish_frame_handler(void *data)
-{
-       struct x11_output *output = data;
-       struct timespec ts;
-
-       weston_compositor_read_presentation_clock(output->base.compositor, &ts);
-       weston_output_finish_frame(&output->base, &ts, 0);
-
-       return 1;
-}
-
-static void
-x11_output_deinit_shm(struct x11_backend *b, struct x11_output *output)
-{
-       xcb_void_cookie_t cookie;
-       xcb_generic_error_t *err;
-       xcb_free_gc(b->conn, output->gc);
-
-       pixman_image_unref(output->hw_surface);
-       output->hw_surface = NULL;
-       cookie = xcb_shm_detach_checked(b->conn, output->segment);
-       err = xcb_request_check(b->conn, cookie);
-       if (err) {
-               weston_log("xcb_shm_detach failed, error %d\n", err->error_code);
-               free(err);
-       }
-       shmdt(output->buf);
-}
-
-static void
-x11_output_destroy(struct weston_output *output_base)
-{
-       struct x11_output *output = (struct x11_output *)output_base;
-       struct x11_backend *backend =
-               (struct x11_backend *)output->base.compositor->backend;
-
-       wl_event_source_remove(output->finish_frame_timer);
-
-       if (backend->use_pixman) {
-               pixman_renderer_output_destroy(output_base);
-               x11_output_deinit_shm(backend, output);
-       } else
-               gl_renderer->output_destroy(output_base);
-
-       xcb_destroy_window(backend->conn, output->window);
-
-       weston_output_destroy(&output->base);
-
-       free(output);
-}
-
-static void
-x11_output_set_wm_protocols(struct x11_backend *b,
-                           struct x11_output *output)
-{
-       xcb_atom_t list[1];
-
-       list[0] = b->atom.wm_delete_window;
-       xcb_change_property (b->conn,
-                            XCB_PROP_MODE_REPLACE,
-                            output->window,
-                            b->atom.wm_protocols,
-                            XCB_ATOM_ATOM,
-                            32,
-                            ARRAY_LENGTH(list),
-                            list);
-}
-
-struct wm_normal_hints {
-       uint32_t flags;
-       uint32_t pad[4];
-       int32_t min_width, min_height;
-       int32_t max_width, max_height;
-       int32_t width_inc, height_inc;
-       int32_t min_aspect_x, min_aspect_y;
-       int32_t max_aspect_x, max_aspect_y;
-       int32_t base_width, base_height;
-       int32_t win_gravity;
-};
-
-#define WM_NORMAL_HINTS_MIN_SIZE       16
-#define WM_NORMAL_HINTS_MAX_SIZE       32
-
-static void
-x11_output_set_icon(struct x11_backend *b,
-                   struct x11_output *output, const char *filename)
-{
-       uint32_t *icon;
-       int32_t width, height;
-       pixman_image_t *image;
-
-       image = load_image(filename);
-       if (!image)
-               return;
-       width = pixman_image_get_width(image);
-       height = pixman_image_get_height(image);
-       icon = malloc(width * height * 4 + 8);
-       if (!icon) {
-               pixman_image_unref(image);
-               return;
-       }
-
-       icon[0] = width;
-       icon[1] = height;
-       memcpy(icon + 2, pixman_image_get_data(image), width * height * 4);
-       xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
-                           b->atom.net_wm_icon, b->atom.cardinal, 32,
-                           width * height + 2, icon);
-       free(icon);
-       pixman_image_unref(image);
-}
-
-static void
-x11_output_wait_for_map(struct x11_backend *b, struct x11_output *output)
-{
-       xcb_map_notify_event_t *map_notify;
-       xcb_configure_notify_event_t *configure_notify;
-       xcb_generic_event_t *event;
-       int mapped = 0, configured = 0;
-       uint8_t response_type;
-
-       /* This isn't the nicest way to do this.  Ideally, we could
-        * just go back to the main loop and once we get the configure
-        * notify, we add the output to the compositor.  While we do
-        * support output hotplug, we can't start up with no outputs.
-        * We could add the output and then resize once we get the
-        * configure notify, but we don't want to start up and
-        * immediately resize the output.
-        *
-        * Also, some window managers don't give us our final
-        * fullscreen size before map_notify, so if we don't get a
-        * configure_notify before map_notify, we just wait for the
-        * first one and hope that's our size. */
-
-       xcb_flush(b->conn);
-
-       while (!mapped || !configured) {
-               event = xcb_wait_for_event(b->conn);
-               response_type = event->response_type & ~0x80;
-
-               switch (response_type) {
-               case XCB_MAP_NOTIFY:
-                       map_notify = (xcb_map_notify_event_t *) event;
-                       if (map_notify->window == output->window)
-                               mapped = 1;
-                       break;
-
-               case XCB_CONFIGURE_NOTIFY:
-                       configure_notify =
-                               (xcb_configure_notify_event_t *) event;
-
-
-                       if (configure_notify->width % output->scale != 0 ||
-                           configure_notify->height % output->scale != 0)
-                               weston_log("Resolution is not a multiple of screen size, rounding\n");
-                       output->mode.width = configure_notify->width;
-                       output->mode.height = configure_notify->height;
-                       configured = 1;
-                       break;
-               }
-       }
-}
-
-static xcb_visualtype_t *
-find_visual_by_id(xcb_screen_t *screen,
-                  xcb_visualid_t id)
-{
-       xcb_depth_iterator_t i;
-       xcb_visualtype_iterator_t j;
-       for (i = xcb_screen_allowed_depths_iterator(screen);
-            i.rem;
-            xcb_depth_next(&i)) {
-               for (j = xcb_depth_visuals_iterator(i.data);
-                    j.rem;
-                    xcb_visualtype_next(&j)) {
-                       if (j.data->visual_id == id)
-                               return j.data;
-               }
-       }
-       return 0;
-}
-
-static uint8_t
-get_depth_of_visual(xcb_screen_t *screen,
-                  xcb_visualid_t id)
-{
-       xcb_depth_iterator_t i;
-       xcb_visualtype_iterator_t j;
-       for (i = xcb_screen_allowed_depths_iterator(screen);
-            i.rem;
-            xcb_depth_next(&i)) {
-               for (j = xcb_depth_visuals_iterator(i.data);
-                    j.rem;
-                    xcb_visualtype_next(&j)) {
-                       if (j.data->visual_id == id)
-                               return i.data->depth;
-               }
-       }
-       return 0;
-}
-
-static int
-x11_output_init_shm(struct x11_backend *b, struct x11_output *output,
-       int width, int height)
-{
-       xcb_visualtype_t *visual_type;
-       xcb_screen_t *screen;
-       xcb_format_iterator_t fmt;
-       xcb_void_cookie_t cookie;
-       xcb_generic_error_t *err;
-       const xcb_query_extension_reply_t *ext;
-       int bitsperpixel = 0;
-       pixman_format_code_t pixman_format;
-
-       /* Check if SHM is available */
-       ext = xcb_get_extension_data(b->conn, &xcb_shm_id);
-       if (ext == NULL || !ext->present) {
-               /* SHM is missing */
-               weston_log("SHM extension is not available\n");
-               errno = ENOENT;
-               return -1;
-       }
-
-       screen = x11_compositor_get_default_screen(b);
-       visual_type = find_visual_by_id(screen, screen->root_visual);
-       if (!visual_type) {
-               weston_log("Failed to lookup visual for root window\n");
-               errno = ENOENT;
-               return -1;
-       }
-       weston_log("Found visual, bits per value: %d, red_mask: %.8x, green_mask: %.8x, blue_mask: %.8x\n",
-               visual_type->bits_per_rgb_value,
-               visual_type->red_mask,
-               visual_type->green_mask,
-               visual_type->blue_mask);
-       output->depth = get_depth_of_visual(screen, screen->root_visual);
-       weston_log("Visual depth is %d\n", output->depth);
-
-       for (fmt = xcb_setup_pixmap_formats_iterator(xcb_get_setup(b->conn));
-            fmt.rem;
-            xcb_format_next(&fmt)) {
-               if (fmt.data->depth == output->depth) {
-                       bitsperpixel = fmt.data->bits_per_pixel;
-                       break;
-               }
-       }
-       weston_log("Found format for depth %d, bpp: %d\n",
-               output->depth, bitsperpixel);
-
-       if  (bitsperpixel == 32 &&
-            visual_type->red_mask == 0xff0000 &&
-            visual_type->green_mask == 0x00ff00 &&
-            visual_type->blue_mask == 0x0000ff) {
-               weston_log("Will use x8r8g8b8 format for SHM surfaces\n");
-               pixman_format = PIXMAN_x8r8g8b8;
-       } else if (bitsperpixel == 16 &&
-                  visual_type->red_mask == 0x00f800 &&
-                  visual_type->green_mask == 0x0007e0 &&
-                  visual_type->blue_mask == 0x00001f) {
-               weston_log("Will use r5g6b5 format for SHM surfaces\n");
-               pixman_format = PIXMAN_r5g6b5;
-       } else {
-               weston_log("Can't find appropriate format for SHM pixmap\n");
-               errno = ENOTSUP;
-               return -1;
-       }
-
-
-       /* Create SHM segment and attach it */
-       output->shm_id = shmget(IPC_PRIVATE, width * height * (bitsperpixel / 8), IPC_CREAT | S_IRWXU);
-       if (output->shm_id == -1) {
-               weston_log("x11shm: failed to allocate SHM segment\n");
-               return -1;
-       }
-       output->buf = shmat(output->shm_id, NULL, 0 /* read/write */);
-       if (-1 == (long)output->buf) {
-               weston_log("x11shm: failed to attach SHM segment\n");
-               return -1;
-       }
-       output->segment = xcb_generate_id(b->conn);
-       cookie = xcb_shm_attach_checked(b->conn, output->segment, output->shm_id, 1);
-       err = xcb_request_check(b->conn, cookie);
-       if (err) {
-               weston_log("x11shm: xcb_shm_attach error %d, op code %d, resource id %d\n",
-                          err->error_code, err->major_code, err->minor_code);
-               free(err);
-               return -1;
-       }
-
-       shmctl(output->shm_id, IPC_RMID, NULL);
-
-       /* Now create pixman image */
-       output->hw_surface = pixman_image_create_bits(pixman_format, width, height, output->buf,
-               width * (bitsperpixel / 8));
-
-       output->gc = xcb_generate_id(b->conn);
-       xcb_create_gc(b->conn, output->gc, output->window, 0, NULL);
-
-       return 0;
-}
-
-static struct x11_output *
-x11_backend_create_output(struct x11_backend *b, int x, int y,
-                            int width, int height, int fullscreen,
-                            int no_input, char *configured_name,
-                            uint32_t transform, int32_t scale)
-{
-       static const char name[] = "Weston Compositor";
-       static const char class[] = "weston-1\0Weston Compositor";
-       char title[32];
-       struct x11_output *output;
-       xcb_screen_t *screen;
-       struct wm_normal_hints normal_hints;
-       struct wl_event_loop *loop;
-       int output_width, output_height, width_mm, height_mm;
-       int ret;
-       uint32_t mask = XCB_CW_EVENT_MASK | XCB_CW_CURSOR;
-       xcb_atom_t atom_list[1];
-       uint32_t values[2] = {
-               XCB_EVENT_MASK_EXPOSURE |
-               XCB_EVENT_MASK_STRUCTURE_NOTIFY,
-               0
-       };
-
-       output_width = width * scale;
-       output_height = height * scale;
-
-       if (configured_name)
-               sprintf(title, "%s - %s", name, configured_name);
-       else
-               strcpy(title, name);
-
-       if (!no_input)
-               values[0] |=
-                       XCB_EVENT_MASK_KEY_PRESS |
-                       XCB_EVENT_MASK_KEY_RELEASE |
-                       XCB_EVENT_MASK_BUTTON_PRESS |
-                       XCB_EVENT_MASK_BUTTON_RELEASE |
-                       XCB_EVENT_MASK_POINTER_MOTION |
-                       XCB_EVENT_MASK_ENTER_WINDOW |
-                       XCB_EVENT_MASK_LEAVE_WINDOW |
-                       XCB_EVENT_MASK_KEYMAP_STATE |
-                       XCB_EVENT_MASK_FOCUS_CHANGE;
-
-       output = zalloc(sizeof *output);
-       if (output == NULL) {
-               perror("zalloc");
-               return NULL;
-       }
-
-       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);
-
-       values[1] = b->null_cursor;
-       output->window = xcb_generate_id(b->conn);
-       screen = x11_compositor_get_default_screen(b);
-       xcb_create_window(b->conn,
-                         XCB_COPY_FROM_PARENT,
-                         output->window,
-                         screen->root,
-                         0, 0,
-                         output_width, output_height,
-                         0,
-                         XCB_WINDOW_CLASS_INPUT_OUTPUT,
-                         screen->root_visual,
-                         mask, values);
-
-       if (fullscreen) {
-               atom_list[0] = b->atom.net_wm_state_fullscreen;
-               xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE,
-                                   output->window,
-                                   b->atom.net_wm_state,
-                                   XCB_ATOM_ATOM, 32,
-                                   ARRAY_LENGTH(atom_list), atom_list);
-       } else {
-               /* Don't resize me. */
-               memset(&normal_hints, 0, sizeof normal_hints);
-               normal_hints.flags =
-                       WM_NORMAL_HINTS_MAX_SIZE | WM_NORMAL_HINTS_MIN_SIZE;
-               normal_hints.min_width = output_width;
-               normal_hints.min_height = output_height;
-               normal_hints.max_width = output_width;
-               normal_hints.max_height = output_height;
-               xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
-                                   b->atom.wm_normal_hints,
-                                   b->atom.wm_size_hints, 32,
-                                   sizeof normal_hints / 4,
-                                   (uint8_t *) &normal_hints);
-       }
-
-       /* Set window name.  Don't bother with non-EWMH WMs. */
-       xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
-                           b->atom.net_wm_name, b->atom.utf8_string, 8,
-                           strlen(title), title);
-       xcb_change_property(b->conn, XCB_PROP_MODE_REPLACE, output->window,
-                           b->atom.wm_class, b->atom.string, 8,
-                           sizeof class, class);
-
-       x11_output_set_icon(b, output, DATADIR "/weston/wayland.png");
-
-       x11_output_set_wm_protocols(b, output);
-
-       xcb_map_window(b->conn, output->window);
-
-       if (fullscreen)
-               x11_output_wait_for_map(b, output);
-
-       output->base.start_repaint_loop = x11_output_start_repaint_loop;
-       if (b->use_pixman)
-               output->base.repaint = x11_output_repaint_shm;
-       else
-               output->base.repaint = x11_output_repaint_gl;
-       output->base.destroy = x11_output_destroy;
-       output->base.assign_planes = NULL;
-       output->base.set_backlight = NULL;
-       output->base.set_dpms = NULL;
-       output->base.switch_mode = NULL;
-       output->base.current_mode = &output->mode;
-       output->base.make = "weston-X11";
-       output->base.model = "none";
-
-       if (configured_name)
-               output->base.name = strdup(configured_name);
-
-       width_mm = width * b->screen->width_in_millimeters /
-               b->screen->width_in_pixels;
-       height_mm = height * b->screen->height_in_millimeters /
-               b->screen->height_in_pixels;
-       weston_output_init(&output->base, b->compositor,
-                          x, y, width_mm, height_mm, transform, scale);
-
-       if (b->use_pixman) {
-               if (x11_output_init_shm(b, output,
-                                       output->mode.width,
-                                       output->mode.height) < 0) {
-                       weston_log("Failed to initialize SHM for the X11 output\n");
-                       return NULL;
-               }
-               if (pixman_renderer_output_create(&output->base) < 0) {
-                       weston_log("Failed to create pixman renderer for output\n");
-                       x11_output_deinit_shm(b, output);
-                       return NULL;
-               }
-       } else {
-               /* eglCreatePlatformWindowSurfaceEXT takes a Window*
-                * but eglCreateWindowSurface takes a Window. */
-               Window xid = (Window) output->window;
-
-               ret = gl_renderer->output_create(&output->base,
-                                                (EGLNativeWindowType) output->window,
-                                                &xid,
-                                                gl_renderer->opaque_attribs,
-                                                NULL,
-                                                0);
-               if (ret < 0)
-                       return NULL;
-       }
-
-       loop = wl_display_get_event_loop(b->compositor->wl_display);
-       output->finish_frame_timer =
-               wl_event_loop_add_timer(loop, finish_frame_handler, output);
-
-       weston_compositor_add_output(b->compositor, &output->base);
-
-       weston_log("x11 output %dx%d, window id %d\n",
-                  width, height, output->window);
-
-       return output;
-}
-
-static struct x11_output *
-x11_backend_find_output(struct x11_backend *b, xcb_window_t window)
-{
-       struct x11_output *output;
-
-       wl_list_for_each(output, &b->compositor->output_list, base.link) {
-               if (output->window == window)
-                       return output;
-       }
-
-       return NULL;
-}
-
-static void
-x11_backend_delete_window(struct x11_backend *b, xcb_window_t window)
-{
-       struct x11_output *output;
-
-       output = x11_backend_find_output(b, window);
-       if (output)
-               x11_output_destroy(&output->base);
-
-       xcb_flush(b->conn);
-
-       if (wl_list_empty(&b->compositor->output_list))
-               weston_compositor_exit(b->compositor);
-}
-
-static void delete_cb(void *data)
-{
-       struct window_delete_data *wd = data;
-
-       x11_backend_delete_window(wd->backend, wd->window);
-       free(wd);
-}
-
-#ifdef HAVE_XCB_XKB
-static void
-update_xkb_state(struct x11_backend *b, xcb_xkb_state_notify_event_t *state)
-{
-       struct weston_keyboard *keyboard =
-               weston_seat_get_keyboard(&b->core_seat);
-
-       xkb_state_update_mask(keyboard->xkb_state.state,
-                             get_xkb_mod_mask(b, state->baseMods),
-                             get_xkb_mod_mask(b, state->latchedMods),
-                             get_xkb_mod_mask(b, state->lockedMods),
-                             0,
-                             0,
-                             state->group);
-
-       notify_modifiers(&b->core_seat,
-                        wl_display_next_serial(b->compositor->wl_display));
-}
-#endif
-
-/**
- * This is monumentally unpleasant.  If we don't have XCB-XKB bindings,
- * the best we can do (given that XCB also lacks XI2 support), is to take
- * the state from the core key events.  Unfortunately that only gives us
- * the effective (i.e. union of depressed/latched/locked) state, and we
- * need the granularity.
- *
- * So we still update the state with every key event we see, but also use
- * the state field from X11 events as a mask so we don't get any stuck
- * modifiers.
- */
-static void
-update_xkb_state_from_core(struct x11_backend *b, uint16_t x11_mask)
-{
-       uint32_t mask = get_xkb_mod_mask(b, x11_mask);
-       struct weston_keyboard *keyboard
-               = weston_seat_get_keyboard(&b->core_seat);
-
-       xkb_state_update_mask(keyboard->xkb_state.state,
-                             keyboard->modifiers.mods_depressed & mask,
-                             keyboard->modifiers.mods_latched & mask,
-                             keyboard->modifiers.mods_locked & mask,
-                             0,
-                             0,
-                             (x11_mask >> 13) & 3);
-       notify_modifiers(&b->core_seat,
-                        wl_display_next_serial(b->compositor->wl_display));
-}
-
-static void
-x11_backend_deliver_button_event(struct x11_backend *b,
-                                xcb_generic_event_t *event, int state)
-{
-       xcb_button_press_event_t *button_event =
-               (xcb_button_press_event_t *) event;
-       uint32_t button;
-       struct x11_output *output;
-       struct weston_pointer_axis_event weston_event;
-
-       output = x11_backend_find_output(b, button_event->event);
-       if (!output)
-               return;
-
-       if (state)
-               xcb_grab_pointer(b->conn, 0, output->window,
-                                XCB_EVENT_MASK_BUTTON_PRESS |
-                                XCB_EVENT_MASK_BUTTON_RELEASE |
-                                XCB_EVENT_MASK_POINTER_MOTION |
-                                XCB_EVENT_MASK_ENTER_WINDOW |
-                                XCB_EVENT_MASK_LEAVE_WINDOW,
-                                XCB_GRAB_MODE_ASYNC,
-                                XCB_GRAB_MODE_ASYNC,
-                                output->window, XCB_CURSOR_NONE,
-                                button_event->time);
-       else
-               xcb_ungrab_pointer(b->conn, button_event->time);
-
-       if (!b->has_xkb)
-               update_xkb_state_from_core(b, button_event->state);
-
-       switch (button_event->detail) {
-       case 1:
-               button = BTN_LEFT;
-               break;
-       case 2:
-               button = BTN_MIDDLE;
-               break;
-       case 3:
-               button = BTN_RIGHT;
-               break;
-       case 4:
-               /* Axis are measured in pixels, but the xcb events are discrete
-                * steps. Therefore move the axis by some pixels every step. */
-               if (state) {
-                       weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
-                       weston_event.discrete = -1;
-                       weston_event.has_discrete = true;
-                       weston_event.axis =
-                               WL_POINTER_AXIS_VERTICAL_SCROLL;
-                       notify_axis(&b->core_seat,
-                                   weston_compositor_get_time(),
-                                   &weston_event);
-                       notify_pointer_frame(&b->core_seat);
-               }
-               return;
-       case 5:
-               if (state) {
-                       weston_event.value = DEFAULT_AXIS_STEP_DISTANCE;
-                       weston_event.discrete = 1;
-                       weston_event.has_discrete = true;
-                       weston_event.axis =
-                               WL_POINTER_AXIS_VERTICAL_SCROLL;
-                       notify_axis(&b->core_seat,
-                                   weston_compositor_get_time(),
-                                   &weston_event);
-                       notify_pointer_frame(&b->core_seat);
-               }
-               return;
-       case 6:
-               if (state) {
-                       weston_event.value = -DEFAULT_AXIS_STEP_DISTANCE;
-                       weston_event.discrete = -1;
-                       weston_event.has_discrete = true;
-                       weston_event.axis =
-                               WL_POINTER_AXIS_HORIZONTAL_SCROLL;
-                       notify_axis(&b->core_seat,
-                                   weston_compositor_get_time(),
-                                   &weston_event);
-                       notify_pointer_frame(&b->core_seat);
-               }
-               return;
-       case 7:
-               if (state) {
-                       weston_event.value = DEFAULT_AXIS_STEP_DISTANCE;
-                       weston_event.discrete = 1;
-                       weston_event.has_discrete = true;
-                       weston_event.axis =
-                               WL_POINTER_AXIS_HORIZONTAL_SCROLL;
-                       notify_axis(&b->core_seat,
-                                   weston_compositor_get_time(),
-                                   &weston_event);
-                       notify_pointer_frame(&b->core_seat);
-               }
-               return;
-       default:
-               button = button_event->detail + BTN_SIDE - 8;
-               break;
-       }
-
-       notify_button(&b->core_seat,
-                     weston_compositor_get_time(), button,
-                     state ? WL_POINTER_BUTTON_STATE_PRESSED :
-                             WL_POINTER_BUTTON_STATE_RELEASED);
-       notify_pointer_frame(&b->core_seat);
-}
-
-static void
-x11_backend_deliver_motion_event(struct x11_backend *b,
-                                xcb_generic_event_t *event)
-{
-       struct x11_output *output;
-       double x, y;
-       struct weston_pointer_motion_event motion_event = { 0 };
-       xcb_motion_notify_event_t *motion_notify =
-                       (xcb_motion_notify_event_t *) event;
-
-       if (!b->has_xkb)
-               update_xkb_state_from_core(b, motion_notify->state);
-       output = x11_backend_find_output(b, motion_notify->event);
-       if (!output)
-               return;
-
-       weston_output_transform_coordinate(&output->base,
-                                          motion_notify->event_x,
-                                          motion_notify->event_y,
-                                          &x, &y);
-
-       motion_event = (struct weston_pointer_motion_event) {
-               .mask = WESTON_POINTER_MOTION_REL,
-               .dx = x - b->prev_x,
-               .dy = y - b->prev_y
-       };
-
-       notify_motion(&b->core_seat, weston_compositor_get_time(),
-                     &motion_event);
-       notify_pointer_frame(&b->core_seat);
-
-       b->prev_x = x;
-       b->prev_y = y;
-}
-
-static void
-x11_backend_deliver_enter_event(struct x11_backend *b,
-                               xcb_generic_event_t *event)
-{
-       struct x11_output *output;
-       double x, y;
-
-       xcb_enter_notify_event_t *enter_notify =
-                       (xcb_enter_notify_event_t *) event;
-       if (enter_notify->state >= Button1Mask)
-               return;
-       if (!b->has_xkb)
-               update_xkb_state_from_core(b, enter_notify->state);
-       output = x11_backend_find_output(b, enter_notify->event);
-       if (!output)
-               return;
-
-       weston_output_transform_coordinate(&output->base,
-                                          enter_notify->event_x,
-                                          enter_notify->event_y, &x, &y);
-
-       notify_pointer_focus(&b->core_seat, &output->base, x, y);
-
-       b->prev_x = x;
-       b->prev_y = y;
-}
-
-static int
-x11_backend_next_event(struct x11_backend *b,
-                      xcb_generic_event_t **event, uint32_t mask)
-{
-       if (mask & WL_EVENT_READABLE) {
-               *event = xcb_poll_for_event(b->conn);
-       } else {
-#ifdef HAVE_XCB_POLL_FOR_QUEUED_EVENT
-               *event = xcb_poll_for_queued_event(b->conn);
-#else
-               *event = xcb_poll_for_event(b->conn);
-#endif
-       }
-
-       return *event != NULL;
-}
-
-static int
-x11_backend_handle_event(int fd, uint32_t mask, void *data)
-{
-       struct x11_backend *b = data;
-       struct x11_output *output;
-       xcb_generic_event_t *event, *prev;
-       xcb_client_message_event_t *client_message;
-       xcb_enter_notify_event_t *enter_notify;
-       xcb_key_press_event_t *key_press, *key_release;
-       xcb_keymap_notify_event_t *keymap_notify;
-       xcb_focus_in_event_t *focus_in;
-       xcb_expose_event_t *expose;
-       xcb_atom_t atom;
-       xcb_window_t window;
-       uint32_t *k;
-       uint32_t i, set;
-       uint8_t response_type;
-       int count;
-
-       prev = NULL;
-       count = 0;
-       while (x11_backend_next_event(b, &event, mask)) {
-               response_type = event->response_type & ~0x80;
-
-               switch (prev ? prev->response_type & ~0x80 : 0x80) {
-               case XCB_KEY_RELEASE:
-                       /* Suppress key repeat events; this is only used if we
-                        * don't have XCB XKB support. */
-                       key_release = (xcb_key_press_event_t *) prev;
-                       key_press = (xcb_key_press_event_t *) event;
-                       if (response_type == XCB_KEY_PRESS &&
-                           key_release->time == key_press->time &&
-                           key_release->detail == key_press->detail) {
-                               /* Don't deliver the held key release
-                                * event or the new key press event. */
-                               free(event);
-                               free(prev);
-                               prev = NULL;
-                               continue;
-                       } else {
-                               /* Deliver the held key release now
-                                * and fall through and handle the new
-                                * event below. */
-                               update_xkb_state_from_core(b, key_release->state);
-                               notify_key(&b->core_seat,
-                                          weston_compositor_get_time(),
-                                          key_release->detail - 8,
-                                          WL_KEYBOARD_KEY_STATE_RELEASED,
-                                          STATE_UPDATE_AUTOMATIC);
-                               free(prev);
-                               prev = NULL;
-                               break;
-                       }
-
-               case XCB_FOCUS_IN:
-                       assert(response_type == XCB_KEYMAP_NOTIFY);
-                       keymap_notify = (xcb_keymap_notify_event_t *) event;
-                       b->keys.size = 0;
-                       for (i = 0; i < ARRAY_LENGTH(keymap_notify->keys) * 8; i++) {
-                               set = keymap_notify->keys[i >> 3] &
-                                       (1 << (i & 7));
-                               if (set) {
-                                       k = wl_array_add(&b->keys, sizeof *k);
-                                       *k = i;
-                               }
-                       }
-
-                       /* Unfortunately the state only comes with the enter
-                        * event, rather than with the focus event.  I'm not
-                        * sure of the exact semantics around it and whether
-                        * we can ensure that we get both? */
-                       notify_keyboard_focus_in(&b->core_seat, &b->keys,
-                                                STATE_UPDATE_AUTOMATIC);
-
-                       free(prev);
-                       prev = NULL;
-                       break;
-
-               default:
-                       /* No previous event held */
-                       break;
-               }
-
-               switch (response_type) {
-               case XCB_KEY_PRESS:
-                       key_press = (xcb_key_press_event_t *) event;
-                       if (!b->has_xkb)
-                               update_xkb_state_from_core(b, key_press->state);
-                       notify_key(&b->core_seat,
-                                  weston_compositor_get_time(),
-                                  key_press->detail - 8,
-                                  WL_KEYBOARD_KEY_STATE_PRESSED,
-                                  b->has_xkb ? STATE_UPDATE_NONE :
-                                               STATE_UPDATE_AUTOMATIC);
-                       break;
-               case XCB_KEY_RELEASE:
-                       /* If we don't have XKB, we need to use the lame
-                        * autorepeat detection above. */
-                       if (!b->has_xkb) {
-                               prev = event;
-                               break;
-                       }
-                       key_release = (xcb_key_press_event_t *) event;
-                       notify_key(&b->core_seat,
-                                  weston_compositor_get_time(),
-                                  key_release->detail - 8,
-                                  WL_KEYBOARD_KEY_STATE_RELEASED,
-                                  STATE_UPDATE_NONE);
-                       break;
-               case XCB_BUTTON_PRESS:
-                       x11_backend_deliver_button_event(b, event, 1);
-                       break;
-               case XCB_BUTTON_RELEASE:
-                       x11_backend_deliver_button_event(b, event, 0);
-                       break;
-               case XCB_MOTION_NOTIFY:
-                       x11_backend_deliver_motion_event(b, event);
-                       break;
-
-               case XCB_EXPOSE:
-                       expose = (xcb_expose_event_t *) event;
-                       output = x11_backend_find_output(b, expose->window);
-                       if (!output)
-                               break;
-
-                       weston_output_damage(&output->base);
-                       weston_output_schedule_repaint(&output->base);
-                       break;
-
-               case XCB_ENTER_NOTIFY:
-                       x11_backend_deliver_enter_event(b, event);
-                       break;
-
-               case XCB_LEAVE_NOTIFY:
-                       enter_notify = (xcb_enter_notify_event_t *) event;
-                       if (enter_notify->state >= Button1Mask)
-                               break;
-                       if (!b->has_xkb)
-                               update_xkb_state_from_core(b, enter_notify->state);
-                       notify_pointer_focus(&b->core_seat, NULL, 0, 0);
-                       break;
-
-               case XCB_CLIENT_MESSAGE:
-                       client_message = (xcb_client_message_event_t *) event;
-                       atom = client_message->data.data32[0];
-                       window = client_message->window;
-                       if (atom == b->atom.wm_delete_window) {
-                               struct wl_event_loop *loop;
-                               struct window_delete_data *data = malloc(sizeof *data);
-
-                               /* if malloc failed we should at least try to
-                                * delete the window, even if it may result in
-                                * a crash.
-                                */
-                               if (!data) {
-                                       x11_backend_delete_window(b, window);
-                                       break;
-                               }
-                               data->backend = b;
-                               data->window = window;
-                               loop = wl_display_get_event_loop(b->compositor->wl_display);
-                               wl_event_loop_add_idle(loop, delete_cb, data);
-                       }
-                       break;
-
-               case XCB_FOCUS_IN:
-                       focus_in = (xcb_focus_in_event_t *) event;
-                       if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED)
-                               break;
-
-                       prev = event;
-                       break;
-
-               case XCB_FOCUS_OUT:
-                       focus_in = (xcb_focus_in_event_t *) event;
-                       if (focus_in->mode == XCB_NOTIFY_MODE_WHILE_GRABBED ||
-                           focus_in->mode == XCB_NOTIFY_MODE_UNGRAB)
-                               break;
-                       notify_keyboard_focus_out(&b->core_seat);
-                       break;
-
-               default:
-                       break;
-               }
-
-#ifdef HAVE_XCB_XKB
-               if (b->has_xkb) {
-                       if (response_type == b->xkb_event_base) {
-                               xcb_xkb_state_notify_event_t *state =
-                                       (xcb_xkb_state_notify_event_t *) event;
-                               if (state->xkbType == XCB_XKB_STATE_NOTIFY)
-                                       update_xkb_state(b, state);
-                       } else if (response_type == XCB_PROPERTY_NOTIFY) {
-                               xcb_property_notify_event_t *prop_notify =
-                                       (xcb_property_notify_event_t *) event;
-                               if (prop_notify->window == b->screen->root &&
-                                   prop_notify->atom == b->atom.xkb_names &&
-                                   prop_notify->state == XCB_PROPERTY_NEW_VALUE)
-                                       update_xkb_keymap(b);
-                       }
-               }
-#endif
-
-               count++;
-               if (prev != event)
-                       free (event);
-       }
-
-       switch (prev ? prev->response_type & ~0x80 : 0x80) {
-       case XCB_KEY_RELEASE:
-               key_release = (xcb_key_press_event_t *) prev;
-               update_xkb_state_from_core(b, key_release->state);
-               notify_key(&b->core_seat,
-                          weston_compositor_get_time(),
-                          key_release->detail - 8,
-                          WL_KEYBOARD_KEY_STATE_RELEASED,
-                          STATE_UPDATE_AUTOMATIC);
-               free(prev);
-               prev = NULL;
-               break;
-       default:
-               break;
-       }
-
-       return count;
-}
-
-#define F(field) offsetof(struct x11_backend, field)
-
-static void
-x11_backend_get_resources(struct x11_backend *b)
-{
-       static const struct { const char *name; int offset; } atoms[] = {
-               { "WM_PROTOCOLS",       F(atom.wm_protocols) },
-               { "WM_NORMAL_HINTS",    F(atom.wm_normal_hints) },
-               { "WM_SIZE_HINTS",      F(atom.wm_size_hints) },
-               { "WM_DELETE_WINDOW",   F(atom.wm_delete_window) },
-               { "WM_CLASS",           F(atom.wm_class) },
-               { "_NET_WM_NAME",       F(atom.net_wm_name) },
-               { "_NET_WM_ICON",       F(atom.net_wm_icon) },
-               { "_NET_WM_STATE",      F(atom.net_wm_state) },
-               { "_NET_WM_STATE_FULLSCREEN", F(atom.net_wm_state_fullscreen) },
-               { "_NET_SUPPORTING_WM_CHECK",
-                                       F(atom.net_supporting_wm_check) },
-               { "_NET_SUPPORTED",     F(atom.net_supported) },
-               { "STRING",             F(atom.string) },
-               { "UTF8_STRING",        F(atom.utf8_string) },
-               { "CARDINAL",           F(atom.cardinal) },
-               { "_XKB_RULES_NAMES",   F(atom.xkb_names) },
-       };
-
-       xcb_intern_atom_cookie_t cookies[ARRAY_LENGTH(atoms)];
-       xcb_intern_atom_reply_t *reply;
-       xcb_pixmap_t pixmap;
-       xcb_gc_t gc;
-       unsigned int i;
-       uint8_t data[] = { 0, 0, 0, 0 };
-
-       for (i = 0; i < ARRAY_LENGTH(atoms); i++)
-               cookies[i] = xcb_intern_atom (b->conn, 0,
-                                             strlen(atoms[i].name),
-                                             atoms[i].name);
-
-       for (i = 0; i < ARRAY_LENGTH(atoms); i++) {
-               reply = xcb_intern_atom_reply (b->conn, cookies[i], NULL);
-               *(xcb_atom_t *) ((char *) b + atoms[i].offset) = reply->atom;
-               free(reply);
-       }
-
-       pixmap = xcb_generate_id(b->conn);
-       gc = xcb_generate_id(b->conn);
-       xcb_create_pixmap(b->conn, 1, pixmap, b->screen->root, 1, 1);
-       xcb_create_gc(b->conn, gc, pixmap, 0, NULL);
-       xcb_put_image(b->conn, XCB_IMAGE_FORMAT_XY_PIXMAP,
-                     pixmap, gc, 1, 1, 0, 0, 0, 32, sizeof data, data);
-       b->null_cursor = xcb_generate_id(b->conn);
-       xcb_create_cursor (b->conn, b->null_cursor,
-                          pixmap, pixmap, 0, 0, 0,  0, 0, 0,  1, 1);
-       xcb_free_gc(b->conn, gc);
-       xcb_free_pixmap(b->conn, pixmap);
-}
-
-static void
-x11_backend_get_wm_info(struct x11_backend *c)
-{
-       xcb_get_property_cookie_t cookie;
-       xcb_get_property_reply_t *reply;
-       xcb_atom_t *atom;
-       unsigned int i;
-
-       cookie = xcb_get_property(c->conn, 0, c->screen->root,
-                                 c->atom.net_supported,
-                                 XCB_ATOM_ATOM, 0, 1024);
-       reply = xcb_get_property_reply(c->conn, cookie, NULL);
-       if (reply == NULL)
-               return;
-
-       atom = (xcb_atom_t *) xcb_get_property_value(reply);
-
-       for (i = 0; i < reply->value_len; i++) {
-               if (atom[i] == c->atom.net_wm_state_fullscreen)
-                       c->has_net_wm_state_fullscreen = 1;
-       }
-
-       free(reply);
-}
-
-static void
-x11_restore(struct weston_compositor *ec)
-{
-}
-
-static void
-x11_destroy(struct weston_compositor *ec)
-{
-       struct x11_backend *backend = (struct x11_backend *)ec->backend;
-
-       wl_event_source_remove(backend->xcb_source);
-       x11_input_destroy(backend);
-
-       weston_compositor_shutdown(ec); /* destroys outputs, too */
-
-       XCloseDisplay(backend->dpy);
-       free(backend);
-}
-
-static int
-init_gl_renderer(struct x11_backend *b)
-{
-       int ret;
-
-       gl_renderer = weston_load_module("gl-renderer.so",
-                                        "gl_renderer_interface");
-       if (!gl_renderer)
-               return -1;
-
-       ret = gl_renderer->create(b->compositor, EGL_PLATFORM_X11_KHR, (void *) b->dpy,
-                                 gl_renderer->opaque_attribs, NULL, 0);
-
-       return ret;
-}
-
-static struct x11_backend *
-x11_backend_create(struct weston_compositor *compositor,
-                  struct weston_x11_backend_config *config)
-{
-       struct x11_backend *b;
-       struct x11_output *output;
-       struct wl_event_loop *loop;
-       int x = 0;
-       unsigned i;
-
-       b = zalloc(sizeof *b);
-       if (b == NULL)
-               return NULL;
-
-       b->compositor = compositor;
-       if (weston_compositor_set_presentation_clock_software(compositor) < 0)
-               goto err_free;
-
-       b->dpy = XOpenDisplay(NULL);
-       if (b->dpy == NULL)
-               goto err_free;
-
-       b->conn = XGetXCBConnection(b->dpy);
-       XSetEventQueueOwner(b->dpy, XCBOwnsEventQueue);
-
-       if (xcb_connection_has_error(b->conn))
-               goto err_xdisplay;
-
-       b->screen = x11_compositor_get_default_screen(b);
-       wl_array_init(&b->keys);
-
-       x11_backend_get_resources(b);
-       x11_backend_get_wm_info(b);
-
-       if (!b->has_net_wm_state_fullscreen && config->fullscreen) {
-               weston_log("Can not fullscreen without window manager support"
-                          "(need _NET_WM_STATE_FULLSCREEN)\n");
-               config->fullscreen = 0;
-       }
-
-       b->use_pixman = config->use_pixman;
-       if (b->use_pixman) {
-               if (pixman_renderer_init(compositor) < 0) {
-                       weston_log("Failed to initialize pixman renderer for X11 backend\n");
-                       goto err_xdisplay;
-               }
-       }
-       else if (init_gl_renderer(b) < 0) {
-               goto err_xdisplay;
-       }
-       weston_log("Using %s renderer\n", config->use_pixman ? "pixman" : "gl");
-
-       b->base.destroy = x11_destroy;
-       b->base.restore = x11_restore;
-
-       if (x11_input_create(b, config->no_input) < 0) {
-               weston_log("Failed to create X11 input\n");
-               goto err_renderer;
-       }
-
-       for (i = 0; i < config->num_outputs; ++i) {
-               struct weston_x11_backend_output_config *output_iterator =
-                       &config->outputs[i];
-
-               if (output_iterator->name == NULL) {
-                       continue;
-               }
-
-               if (output_iterator->width < 1) {
-                       weston_log("Invalid width \"%d\" for output %s\n",
-                                  output_iterator->width, output_iterator->name);
-                       goto err_x11_input;
-               }
-
-               if (output_iterator->height < 1) {
-                       weston_log("Invalid height \"%d\" for output %s\n",
-                                  output_iterator->height, output_iterator->name);
-                       goto err_x11_input;
-               }
-
-               output = x11_backend_create_output(b,
-                                                  x,
-                                                  0,
-                                                  output_iterator->width,
-                                                  output_iterator->height,
-                                                  config->fullscreen,
-                                                  config->no_input,
-                                                  output_iterator->name,
-                                                  output_iterator->transform,
-                                                  output_iterator->scale);
-               if (output == NULL) {
-                       weston_log("Failed to create configured x11 output\n");
-                       goto err_x11_input;
-               }
-
-               x = pixman_region32_extents(&output->base.region)->x2;
-       }
-
-       loop = wl_display_get_event_loop(compositor->wl_display);
-       b->xcb_source =
-               wl_event_loop_add_fd(loop,
-                                    xcb_get_file_descriptor(b->conn),
-                                    WL_EVENT_READABLE,
-                                    x11_backend_handle_event, b);
-       wl_event_source_check(b->xcb_source);
-
-       if (compositor->renderer->import_dmabuf) {
-               if (linux_dmabuf_setup(compositor) < 0)
-                       weston_log("Error: initializing dmabuf "
-                                  "support failed.\n");
-       }
-
-       compositor->backend = &b->base;
-
-       return b;
-
-err_x11_input:
-       x11_input_destroy(b);
-err_renderer:
-       compositor->renderer->destroy(compositor);
-err_xdisplay:
-       XCloseDisplay(b->dpy);
-err_free:
-       free(b);
-       return NULL;
-}
-
-static void
-config_init_to_defaults(struct weston_x11_backend_config *config)
-{
-}
-
-WL_EXPORT int
-backend_init(struct weston_compositor *compositor,
-            struct weston_backend_config *config_base)
-{
-       struct x11_backend *b;
-       struct weston_x11_backend_config config = {{ 0, }};
-
-       if (config_base == NULL ||
-           config_base->struct_version != WESTON_X11_BACKEND_CONFIG_VERSION ||
-           config_base->struct_size > sizeof(struct weston_x11_backend_config)) {
-               weston_log("X11 backend config structure is invalid\n");
-               return -1;
-       }
-
-       config_init_to_defaults(&config);
-       memcpy(&config, config_base, config_base->struct_size);
-
-       b = x11_backend_create(compositor, &config);
-       if (b == NULL)
-               return -1;
-
-       return 0;
-}
diff --git a/src/compositor-x11.h b/src/compositor-x11.h
deleted file mode 100644 (file)
index 8363a76..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright © 2016 Benoit Gschwind
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_COMPOSITOR_X11_H
-#define WESTON_COMPOSITOR_X11_H
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#include "compositor.h"
-
-#define WESTON_X11_BACKEND_CONFIG_VERSION 1
-
-struct weston_x11_backend_output_config {
-       int width;
-       int height;
-       char *name;
-       uint32_t transform;
-       int32_t scale;
-};
-
-struct weston_x11_backend_config {
-       struct weston_backend_config base;
-
-       bool fullscreen;
-       bool no_input;
-
-       /** Whether to use the pixman renderer instead of the OpenGL ES renderer. */
-       bool use_pixman;
-
-       uint32_t num_outputs;
-       struct weston_x11_backend_output_config *outputs;
-};
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif /* WESTON_COMPOSITOR_X11_H_ */
diff --git a/src/compositor.c b/src/compositor.c
deleted file mode 100644 (file)
index 37d94ec..0000000
+++ /dev/null
@@ -1,5015 +0,0 @@
-/*
- * Copyright © 2010-2011 Intel Corporation
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2012-2015 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <fcntl.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <stdint.h>
-#include <limits.h>
-#include <stdarg.h>
-#include <assert.h>
-#include <sys/ioctl.h>
-#include <sys/mman.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/utsname.h>
-#include <sys/stat.h>
-#include <unistd.h>
-#include <math.h>
-#include <linux/input.h>
-#include <dlfcn.h>
-#include <signal.h>
-#include <setjmp.h>
-#include <sys/time.h>
-#include <time.h>
-#include <errno.h>
-
-#include "timeline.h"
-
-#include "compositor.h"
-#include "viewporter-server-protocol.h"
-#include "presentation-time-server-protocol.h"
-#include "shared/helpers.h"
-#include "shared/os-compatibility.h"
-#include "shared/timespec-util.h"
-#include "git-version.h"
-#include "version.h"
-
-#define DEFAULT_REPAINT_WINDOW 7 /* milliseconds */
-
-static void
-weston_output_transform_scale_init(struct weston_output *output,
-                                  uint32_t transform, uint32_t scale);
-
-static void
-weston_compositor_build_view_list(struct weston_compositor *compositor);
-
-static void weston_mode_switch_finish(struct weston_output *output,
-                                     int mode_changed,
-                                     int scale_changed)
-{
-       struct weston_seat *seat;
-       struct wl_resource *resource;
-       pixman_region32_t old_output_region;
-       int version;
-
-       pixman_region32_init(&old_output_region);
-       pixman_region32_copy(&old_output_region, &output->region);
-
-       /* Update output region and transformation matrix */
-       weston_output_transform_scale_init(output, output->transform, output->current_scale);
-
-       pixman_region32_init(&output->previous_damage);
-       pixman_region32_init_rect(&output->region, output->x, output->y,
-                                 output->width, output->height);
-
-       weston_output_update_matrix(output);
-
-       /* If a pointer falls outside the outputs new geometry, move it to its
-        * lower-right corner */
-       wl_list_for_each(seat, &output->compositor->seat_list, link) {
-               struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-               int32_t x, y;
-
-               if (!pointer)
-                       continue;
-
-               x = wl_fixed_to_int(pointer->x);
-               y = wl_fixed_to_int(pointer->y);
-
-               if (!pixman_region32_contains_point(&old_output_region,
-                                                   x, y, NULL) ||
-                   pixman_region32_contains_point(&output->region,
-                                                  x, y, NULL))
-                       continue;
-
-               if (x >= output->x + output->width)
-                       x = output->x + output->width - 1;
-               if (y >= output->y + output->height)
-                       y = output->y + output->height - 1;
-
-               pointer->x = wl_fixed_from_int(x);
-               pointer->y = wl_fixed_from_int(y);
-       }
-
-       pixman_region32_fini(&old_output_region);
-
-       if (!mode_changed && !scale_changed)
-               return;
-
-       /* notify clients of the changes */
-       wl_resource_for_each(resource, &output->resource_list) {
-               if (mode_changed) {
-                       wl_output_send_mode(resource,
-                                           output->current_mode->flags,
-                                           output->current_mode->width,
-                                           output->current_mode->height,
-                                           output->current_mode->refresh);
-               }
-
-               version = wl_resource_get_version(resource);
-               if (version >= WL_OUTPUT_SCALE_SINCE_VERSION && scale_changed)
-                       wl_output_send_scale(resource, output->current_scale);
-
-               if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
-                       wl_output_send_done(resource);
-       }
-}
-
-
-static void
-weston_compositor_reflow_outputs(struct weston_compositor *compositor,
-                               struct weston_output *resized_output, int delta_width);
-
-WL_EXPORT int
-weston_output_mode_set_native(struct weston_output *output,
-                             struct weston_mode *mode,
-                             int32_t scale)
-{
-       int ret;
-       int mode_changed = 0, scale_changed = 0;
-       int32_t old_width;
-
-       if (!output->switch_mode)
-               return -1;
-
-       if (!output->original_mode) {
-               mode_changed = 1;
-               ret = output->switch_mode(output, mode);
-               if (ret < 0)
-                       return ret;
-               if (output->current_scale != scale) {
-                       scale_changed = 1;
-                       output->current_scale = scale;
-               }
-       }
-
-       old_width = output->width;
-       output->native_mode = mode;
-       output->native_scale = scale;
-
-       weston_mode_switch_finish(output, mode_changed, scale_changed);
-
-       if (mode_changed || scale_changed) {
-               weston_compositor_reflow_outputs(output->compositor, output, output->width - old_width);
-
-               wl_signal_emit(&output->compositor->output_resized_signal, output);
-       }
-       return 0;
-}
-
-WL_EXPORT int
-weston_output_mode_switch_to_native(struct weston_output *output)
-{
-       int ret;
-       int mode_changed = 0, scale_changed = 0;
-
-       if (!output->switch_mode)
-               return -1;
-
-       if (!output->original_mode) {
-               weston_log("already in the native mode\n");
-               return -1;
-       }
-       /* the non fullscreen clients haven't seen a mode set since we
-        * switched into a temporary, so we need to notify them if the
-        * mode at that time is different from the native mode now.
-        */
-       mode_changed = (output->original_mode != output->native_mode);
-       scale_changed = (output->original_scale != output->native_scale);
-
-       ret = output->switch_mode(output, output->native_mode);
-       if (ret < 0)
-               return ret;
-
-       output->current_scale = output->native_scale;
-
-       output->original_mode = NULL;
-       output->original_scale = 0;
-
-       weston_mode_switch_finish(output, mode_changed, scale_changed);
-
-       return 0;
-}
-
-WL_EXPORT int
-weston_output_mode_switch_to_temporary(struct weston_output *output,
-                                      struct weston_mode *mode,
-                                      int32_t scale)
-{
-       int ret;
-
-       if (!output->switch_mode)
-               return -1;
-
-       /* original_mode is the last mode non full screen clients have seen,
-        * so we shouldn't change it if we already have one set.
-        */
-       if (!output->original_mode) {
-               output->original_mode = output->native_mode;
-               output->original_scale = output->native_scale;
-       }
-       ret = output->switch_mode(output, mode);
-       if (ret < 0)
-               return ret;
-
-       output->current_scale = scale;
-
-       weston_mode_switch_finish(output, 0, 0);
-
-       return 0;
-}
-
-static void
-region_init_infinite(pixman_region32_t *region)
-{
-       pixman_region32_init_rect(region, INT32_MIN, INT32_MIN,
-                                 UINT32_MAX, UINT32_MAX);
-}
-
-static struct weston_subsurface *
-weston_surface_to_subsurface(struct weston_surface *surface);
-
-WL_EXPORT struct weston_view *
-weston_view_create(struct weston_surface *surface)
-{
-       struct weston_view *view;
-
-       view = zalloc(sizeof *view);
-       if (view == NULL)
-               return NULL;
-
-       view->surface = surface;
-
-       /* Assign to surface */
-       wl_list_insert(&surface->views, &view->surface_link);
-
-       wl_signal_init(&view->destroy_signal);
-       wl_list_init(&view->link);
-       wl_list_init(&view->layer_link.link);
-
-       pixman_region32_init(&view->clip);
-
-       view->alpha = 1.0;
-       pixman_region32_init(&view->transform.opaque);
-
-       wl_list_init(&view->geometry.transformation_list);
-       wl_list_insert(&view->geometry.transformation_list,
-                      &view->transform.position.link);
-       weston_matrix_init(&view->transform.position.matrix);
-       wl_list_init(&view->geometry.child_list);
-       pixman_region32_init(&view->geometry.scissor);
-       pixman_region32_init(&view->transform.boundingbox);
-       view->transform.dirty = 1;
-
-       return view;
-}
-
-struct weston_frame_callback {
-       struct wl_resource *resource;
-       struct wl_list link;
-};
-
-struct weston_presentation_feedback {
-       struct wl_resource *resource;
-
-       /* XXX: could use just wl_resource_get_link() instead */
-       struct wl_list link;
-
-       /* The per-surface feedback flags */
-       uint32_t psf_flags;
-};
-
-static void
-weston_presentation_feedback_discard(
-               struct weston_presentation_feedback *feedback)
-{
-       wp_presentation_feedback_send_discarded(feedback->resource);
-       wl_resource_destroy(feedback->resource);
-}
-
-static void
-weston_presentation_feedback_discard_list(struct wl_list *list)
-{
-       struct weston_presentation_feedback *feedback, *tmp;
-
-       wl_list_for_each_safe(feedback, tmp, list, link)
-               weston_presentation_feedback_discard(feedback);
-}
-
-static void
-weston_presentation_feedback_present(
-               struct weston_presentation_feedback *feedback,
-               struct weston_output *output,
-               uint32_t refresh_nsec,
-               const struct timespec *ts,
-               uint64_t seq,
-               uint32_t flags)
-{
-       struct wl_client *client = wl_resource_get_client(feedback->resource);
-       struct wl_resource *o;
-       uint64_t secs;
-
-       wl_resource_for_each(o, &output->resource_list) {
-               if (wl_resource_get_client(o) != client)
-                       continue;
-
-               wp_presentation_feedback_send_sync_output(feedback->resource, o);
-       }
-
-       secs = ts->tv_sec;
-       wp_presentation_feedback_send_presented(feedback->resource,
-                                               secs >> 32, secs & 0xffffffff,
-                                               ts->tv_nsec,
-                                               refresh_nsec,
-                                               seq >> 32, seq & 0xffffffff,
-                                               flags | feedback->psf_flags);
-       wl_resource_destroy(feedback->resource);
-}
-
-static void
-weston_presentation_feedback_present_list(struct wl_list *list,
-                                         struct weston_output *output,
-                                         uint32_t refresh_nsec,
-                                         const struct timespec *ts,
-                                         uint64_t seq,
-                                         uint32_t flags)
-{
-       struct weston_presentation_feedback *feedback, *tmp;
-
-       assert(!(flags & WP_PRESENTATION_FEEDBACK_INVALID) ||
-              wl_list_empty(list));
-
-       wl_list_for_each_safe(feedback, tmp, list, link)
-               weston_presentation_feedback_present(feedback, output,
-                                                    refresh_nsec, ts, seq,
-                                                    flags);
-}
-
-static void
-surface_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
-{
-       struct weston_surface_state *state =
-               container_of(listener, struct weston_surface_state,
-                            buffer_destroy_listener);
-
-       state->buffer = NULL;
-}
-
-static void
-weston_surface_state_init(struct weston_surface_state *state)
-{
-       state->newly_attached = 0;
-       state->buffer = NULL;
-       state->buffer_destroy_listener.notify =
-               surface_state_handle_buffer_destroy;
-       state->sx = 0;
-       state->sy = 0;
-
-       pixman_region32_init(&state->damage_surface);
-       pixman_region32_init(&state->damage_buffer);
-       pixman_region32_init(&state->opaque);
-       region_init_infinite(&state->input);
-
-       wl_list_init(&state->frame_callback_list);
-       wl_list_init(&state->feedback_list);
-
-       state->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
-       state->buffer_viewport.buffer.scale = 1;
-       state->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
-       state->buffer_viewport.surface.width = -1;
-       state->buffer_viewport.changed = 0;
-}
-
-static void
-weston_surface_state_fini(struct weston_surface_state *state)
-{
-       struct weston_frame_callback *cb, *next;
-
-       wl_list_for_each_safe(cb, next,
-                             &state->frame_callback_list, link)
-               wl_resource_destroy(cb->resource);
-
-       weston_presentation_feedback_discard_list(&state->feedback_list);
-
-       pixman_region32_fini(&state->input);
-       pixman_region32_fini(&state->opaque);
-       pixman_region32_fini(&state->damage_surface);
-       pixman_region32_fini(&state->damage_buffer);
-
-       if (state->buffer)
-               wl_list_remove(&state->buffer_destroy_listener.link);
-       state->buffer = NULL;
-}
-
-static void
-weston_surface_state_set_buffer(struct weston_surface_state *state,
-                               struct weston_buffer *buffer)
-{
-       if (state->buffer == buffer)
-               return;
-
-       if (state->buffer)
-               wl_list_remove(&state->buffer_destroy_listener.link);
-       state->buffer = buffer;
-       if (state->buffer)
-               wl_signal_add(&state->buffer->destroy_signal,
-                             &state->buffer_destroy_listener);
-}
-
-WL_EXPORT struct weston_surface *
-weston_surface_create(struct weston_compositor *compositor)
-{
-       struct weston_surface *surface;
-
-       surface = zalloc(sizeof *surface);
-       if (surface == NULL)
-               return NULL;
-
-       wl_signal_init(&surface->destroy_signal);
-
-       surface->compositor = compositor;
-       surface->ref_count = 1;
-
-       surface->buffer_viewport.buffer.transform = WL_OUTPUT_TRANSFORM_NORMAL;
-       surface->buffer_viewport.buffer.scale = 1;
-       surface->buffer_viewport.buffer.src_width = wl_fixed_from_int(-1);
-       surface->buffer_viewport.surface.width = -1;
-
-       weston_surface_state_init(&surface->pending);
-
-       pixman_region32_init(&surface->damage);
-       pixman_region32_init(&surface->opaque);
-       region_init_infinite(&surface->input);
-
-       wl_list_init(&surface->views);
-
-       wl_list_init(&surface->frame_callback_list);
-       wl_list_init(&surface->feedback_list);
-
-       wl_list_init(&surface->subsurface_list);
-       wl_list_init(&surface->subsurface_list_pending);
-
-       weston_matrix_init(&surface->buffer_to_surface_matrix);
-       weston_matrix_init(&surface->surface_to_buffer_matrix);
-
-       return surface;
-}
-
-WL_EXPORT void
-weston_surface_set_color(struct weston_surface *surface,
-                float red, float green, float blue, float alpha)
-{
-       surface->compositor->renderer->surface_set_color(surface, red, green, blue, alpha);
-}
-
-WL_EXPORT void
-weston_view_to_global_float(struct weston_view *view,
-                           float sx, float sy, float *x, float *y)
-{
-       if (view->transform.enabled) {
-               struct weston_vector v = { { sx, sy, 0.0f, 1.0f } };
-
-               weston_matrix_transform(&view->transform.matrix, &v);
-
-               if (fabsf(v.f[3]) < 1e-6) {
-                       weston_log("warning: numerical instability in "
-                               "%s(), divisor = %g\n", __func__,
-                               v.f[3]);
-                       *x = 0;
-                       *y = 0;
-                       return;
-               }
-
-               *x = v.f[0] / v.f[3];
-               *y = v.f[1] / v.f[3];
-       } else {
-               *x = sx + view->geometry.x;
-               *y = sy + view->geometry.y;
-       }
-}
-
-WL_EXPORT void
-weston_transformed_coord(int width, int height,
-                        enum wl_output_transform transform,
-                        int32_t scale,
-                        float sx, float sy, float *bx, float *by)
-{
-       switch (transform) {
-       case WL_OUTPUT_TRANSFORM_NORMAL:
-       default:
-               *bx = sx;
-               *by = sy;
-               break;
-       case WL_OUTPUT_TRANSFORM_FLIPPED:
-               *bx = width - sx;
-               *by = sy;
-               break;
-       case WL_OUTPUT_TRANSFORM_90:
-               *bx = height - sy;
-               *by = sx;
-               break;
-       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
-               *bx = height - sy;
-               *by = width - sx;
-               break;
-       case WL_OUTPUT_TRANSFORM_180:
-               *bx = width - sx;
-               *by = height - sy;
-               break;
-       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
-               *bx = sx;
-               *by = height - sy;
-               break;
-       case WL_OUTPUT_TRANSFORM_270:
-               *bx = sy;
-               *by = width - sx;
-               break;
-       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
-               *bx = sy;
-               *by = sx;
-               break;
-       }
-
-       *bx *= scale;
-       *by *= scale;
-}
-
-WL_EXPORT pixman_box32_t
-weston_transformed_rect(int width, int height,
-                       enum wl_output_transform transform,
-                       int32_t scale,
-                       pixman_box32_t rect)
-{
-       float x1, x2, y1, y2;
-
-       pixman_box32_t ret;
-
-       weston_transformed_coord(width, height, transform, scale,
-                                rect.x1, rect.y1, &x1, &y1);
-       weston_transformed_coord(width, height, transform, scale,
-                                rect.x2, rect.y2, &x2, &y2);
-
-       if (x1 <= x2) {
-               ret.x1 = x1;
-               ret.x2 = x2;
-       } else {
-               ret.x1 = x2;
-               ret.x2 = x1;
-       }
-
-       if (y1 <= y2) {
-               ret.y1 = y1;
-               ret.y2 = y2;
-       } else {
-               ret.y1 = y2;
-               ret.y2 = y1;
-       }
-
-       return ret;
-}
-
-/** Transform a region by a matrix, restricted to axis-aligned transformations
- *
- * Warning: This function does not work for projective, affine, or matrices
- * that encode arbitrary rotations. Only 90-degree step rotations are
- * supported.
- */
-WL_EXPORT void
-weston_matrix_transform_region(pixman_region32_t *dest,
-                              struct weston_matrix *matrix,
-                              pixman_region32_t *src)
-{
-       pixman_box32_t *src_rects, *dest_rects;
-       int nrects, i;
-
-       src_rects = pixman_region32_rectangles(src, &nrects);
-       dest_rects = malloc(nrects * sizeof(*dest_rects));
-       if (!dest_rects)
-               return;
-
-       for (i = 0; i < nrects; i++) {
-               struct weston_vector vec1 = {{
-                       src_rects[i].x1, src_rects[i].y1, 0, 1
-               }};
-               weston_matrix_transform(matrix, &vec1);
-               vec1.f[0] /= vec1.f[3];
-               vec1.f[1] /= vec1.f[3];
-
-               struct weston_vector vec2 = {{
-                       src_rects[i].x2, src_rects[i].y2, 0, 1
-               }};
-               weston_matrix_transform(matrix, &vec2);
-               vec2.f[0] /= vec2.f[3];
-               vec2.f[1] /= vec2.f[3];
-
-               if (vec1.f[0] < vec2.f[0]) {
-                       dest_rects[i].x1 = floor(vec1.f[0]);
-                       dest_rects[i].x2 = ceil(vec2.f[0]);
-               } else {
-                       dest_rects[i].x1 = floor(vec2.f[0]);
-                       dest_rects[i].x2 = ceil(vec1.f[0]);
-               }
-
-               if (vec1.f[1] < vec2.f[1]) {
-                       dest_rects[i].y1 = floor(vec1.f[1]);
-                       dest_rects[i].y2 = ceil(vec2.f[1]);
-               } else {
-                       dest_rects[i].y1 = floor(vec2.f[1]);
-                       dest_rects[i].y2 = ceil(vec1.f[1]);
-               }
-       }
-
-       pixman_region32_clear(dest);
-       pixman_region32_init_rects(dest, dest_rects, nrects);
-       free(dest_rects);
-}
-
-WL_EXPORT void
-weston_transformed_region(int width, int height,
-                         enum wl_output_transform transform,
-                         int32_t scale,
-                         pixman_region32_t *src, pixman_region32_t *dest)
-{
-       pixman_box32_t *src_rects, *dest_rects;
-       int nrects, i;
-
-       if (transform == WL_OUTPUT_TRANSFORM_NORMAL && scale == 1) {
-               if (src != dest)
-                       pixman_region32_copy(dest, src);
-               return;
-       }
-
-       src_rects = pixman_region32_rectangles(src, &nrects);
-       dest_rects = malloc(nrects * sizeof(*dest_rects));
-       if (!dest_rects)
-               return;
-
-       if (transform == WL_OUTPUT_TRANSFORM_NORMAL) {
-               memcpy(dest_rects, src_rects, nrects * sizeof(*dest_rects));
-       } else {
-               for (i = 0; i < nrects; i++) {
-                       switch (transform) {
-                       default:
-                       case WL_OUTPUT_TRANSFORM_NORMAL:
-                               dest_rects[i].x1 = src_rects[i].x1;
-                               dest_rects[i].y1 = src_rects[i].y1;
-                               dest_rects[i].x2 = src_rects[i].x2;
-                               dest_rects[i].y2 = src_rects[i].y2;
-                               break;
-                       case WL_OUTPUT_TRANSFORM_90:
-                               dest_rects[i].x1 = height - src_rects[i].y2;
-                               dest_rects[i].y1 = src_rects[i].x1;
-                               dest_rects[i].x2 = height - src_rects[i].y1;
-                               dest_rects[i].y2 = src_rects[i].x2;
-                               break;
-                       case WL_OUTPUT_TRANSFORM_180:
-                               dest_rects[i].x1 = width - src_rects[i].x2;
-                               dest_rects[i].y1 = height - src_rects[i].y2;
-                               dest_rects[i].x2 = width - src_rects[i].x1;
-                               dest_rects[i].y2 = height - src_rects[i].y1;
-                               break;
-                       case WL_OUTPUT_TRANSFORM_270:
-                               dest_rects[i].x1 = src_rects[i].y1;
-                               dest_rects[i].y1 = width - src_rects[i].x2;
-                               dest_rects[i].x2 = src_rects[i].y2;
-                               dest_rects[i].y2 = width - src_rects[i].x1;
-                               break;
-                       case WL_OUTPUT_TRANSFORM_FLIPPED:
-                               dest_rects[i].x1 = width - src_rects[i].x2;
-                               dest_rects[i].y1 = src_rects[i].y1;
-                               dest_rects[i].x2 = width - src_rects[i].x1;
-                               dest_rects[i].y2 = src_rects[i].y2;
-                               break;
-                       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
-                               dest_rects[i].x1 = height - src_rects[i].y2;
-                               dest_rects[i].y1 = width - src_rects[i].x2;
-                               dest_rects[i].x2 = height - src_rects[i].y1;
-                               dest_rects[i].y2 = width - src_rects[i].x1;
-                               break;
-                       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
-                               dest_rects[i].x1 = src_rects[i].x1;
-                               dest_rects[i].y1 = height - src_rects[i].y2;
-                               dest_rects[i].x2 = src_rects[i].x2;
-                               dest_rects[i].y2 = height - src_rects[i].y1;
-                               break;
-                       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
-                               dest_rects[i].x1 = src_rects[i].y1;
-                               dest_rects[i].y1 = src_rects[i].x1;
-                               dest_rects[i].x2 = src_rects[i].y2;
-                               dest_rects[i].y2 = src_rects[i].x2;
-                               break;
-                       }
-               }
-       }
-
-       if (scale != 1) {
-               for (i = 0; i < nrects; i++) {
-                       dest_rects[i].x1 *= scale;
-                       dest_rects[i].x2 *= scale;
-                       dest_rects[i].y1 *= scale;
-                       dest_rects[i].y2 *= scale;
-               }
-       }
-
-       pixman_region32_clear(dest);
-       pixman_region32_init_rects(dest, dest_rects, nrects);
-       free(dest_rects);
-}
-
-static void
-viewport_surface_to_buffer(struct weston_surface *surface,
-                          float sx, float sy, float *bx, float *by)
-{
-       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
-       double src_width, src_height;
-       double src_x, src_y;
-
-       if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
-               if (vp->surface.width == -1) {
-                       *bx = sx;
-                       *by = sy;
-                       return;
-               }
-
-               src_x = 0.0;
-               src_y = 0.0;
-               src_width = surface->width_from_buffer;
-               src_height = surface->height_from_buffer;
-       } else {
-               src_x = wl_fixed_to_double(vp->buffer.src_x);
-               src_y = wl_fixed_to_double(vp->buffer.src_y);
-               src_width = wl_fixed_to_double(vp->buffer.src_width);
-               src_height = wl_fixed_to_double(vp->buffer.src_height);
-       }
-
-       *bx = sx * src_width / surface->width + src_x;
-       *by = sy * src_height / surface->height + src_y;
-}
-
-WL_EXPORT void
-weston_surface_to_buffer_float(struct weston_surface *surface,
-                              float sx, float sy, float *bx, float *by)
-{
-       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
-
-       /* first transform coordinates if the viewport is set */
-       viewport_surface_to_buffer(surface, sx, sy, bx, by);
-
-       weston_transformed_coord(surface->width_from_buffer,
-                                surface->height_from_buffer,
-                                vp->buffer.transform, vp->buffer.scale,
-                                *bx, *by, bx, by);
-}
-
-/** Transform a rectangle from surface coordinates to buffer coordinates
- *
- * \param surface The surface to fetch wp_viewport and buffer transformation
- * from.
- * \param rect The rectangle to transform.
- * \return The transformed rectangle.
- *
- * Viewport and buffer transformations can only do translation, scaling,
- * and rotations in 90-degree steps. Therefore the only loss in the
- * conversion is coordinate rounding.
- *
- * However, some coordinate rounding takes place as an intermediate
- * step before the buffer scale factor is applied, so the rectangle
- * boundary may not be exactly as expected.
- *
- * This is OK for damage tracking since a little extra coverage is
- * not a problem.
- */
-WL_EXPORT pixman_box32_t
-weston_surface_to_buffer_rect(struct weston_surface *surface,
-                             pixman_box32_t rect)
-{
-       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
-       float xf, yf;
-
-       /* first transform box coordinates if the viewport is set */
-       viewport_surface_to_buffer(surface, rect.x1, rect.y1, &xf, &yf);
-       rect.x1 = floorf(xf);
-       rect.y1 = floorf(yf);
-
-       viewport_surface_to_buffer(surface, rect.x2, rect.y2, &xf, &yf);
-       rect.x2 = ceilf(xf);
-       rect.y2 = ceilf(yf);
-
-       return weston_transformed_rect(surface->width_from_buffer,
-                                      surface->height_from_buffer,
-                                      vp->buffer.transform, vp->buffer.scale,
-                                      rect);
-}
-
-/** Transform a region from surface coordinates to buffer coordinates
- *
- * \param surface The surface to fetch wp_viewport and buffer transformation
- * from.
- * \param surface_region[in] The region in surface coordinates.
- * \param buffer_region[out] The region converted to buffer coordinates.
- *
- * Buffer_region must be init'd, but will be completely overwritten.
- *
- * Viewport and buffer transformations can only do translation, scaling,
- * and rotations in 90-degree steps. Therefore the only loss in the
- * conversion is from the coordinate rounding that takes place in
- * \ref weston_surface_to_buffer_rect.
- */
-WL_EXPORT void
-weston_surface_to_buffer_region(struct weston_surface *surface,
-                               pixman_region32_t *surface_region,
-                               pixman_region32_t *buffer_region)
-{
-       pixman_box32_t *src_rects, *dest_rects;
-       int nrects, i;
-
-       src_rects = pixman_region32_rectangles(surface_region, &nrects);
-       dest_rects = malloc(nrects * sizeof(*dest_rects));
-       if (!dest_rects)
-               return;
-
-       for (i = 0; i < nrects; i++) {
-               dest_rects[i] = weston_surface_to_buffer_rect(surface,
-                                                             src_rects[i]);
-       }
-
-       pixman_region32_fini(buffer_region);
-       pixman_region32_init_rects(buffer_region, dest_rects, nrects);
-       free(dest_rects);
-}
-
-WL_EXPORT void
-weston_view_move_to_plane(struct weston_view *view,
-                            struct weston_plane *plane)
-{
-       if (view->plane == plane)
-               return;
-
-       weston_view_damage_below(view);
-       view->plane = plane;
-       weston_surface_damage(view->surface);
-}
-
-/** Inflict damage on the plane where the view is visible.
- *
- * \param view The view that causes the damage.
- *
- * If the view is currently on a plane (including the primary plane),
- * take the view's boundingbox, subtract all the opaque views that cover it,
- * and add the remaining region as damage to the plane. This corresponds
- * to the damage inflicted to the plane if this view disappeared.
- *
- * A repaint is scheduled for this view.
- *
- * The region of all opaque views covering this view is stored in
- * weston_view::clip and updated by view_accumulate_damage() during
- * weston_output_repaint(). Specifically, that region matches the
- * scenegraph as it was last painted.
- */
-WL_EXPORT void
-weston_view_damage_below(struct weston_view *view)
-{
-       pixman_region32_t damage;
-
-       pixman_region32_init(&damage);
-       pixman_region32_subtract(&damage, &view->transform.boundingbox,
-                                &view->clip);
-       if (view->plane)
-               pixman_region32_union(&view->plane->damage,
-                                     &view->plane->damage, &damage);
-       pixman_region32_fini(&damage);
-       weston_view_schedule_repaint(view);
-}
-
-/**
- * \param es    The surface
- * \param mask  The new set of outputs for the surface
- *
- * Sets the surface's set of outputs to the ones specified by
- * the new output mask provided.  Identifies the outputs that
- * have changed, the posts enter and leave events for these
- * outputs as appropriate.
- */
-static void
-weston_surface_update_output_mask(struct weston_surface *es, uint32_t mask)
-{
-       uint32_t different = es->output_mask ^ mask;
-       uint32_t entered = mask & different;
-       uint32_t left = es->output_mask & different;
-       struct weston_output *output;
-       struct wl_resource *resource = NULL;
-       struct wl_client *client;
-
-       es->output_mask = mask;
-       if (es->resource == NULL)
-               return;
-       if (different == 0)
-               return;
-
-       client = wl_resource_get_client(es->resource);
-
-       wl_list_for_each(output, &es->compositor->output_list, link) {
-               if (1u << output->id & different)
-                       resource =
-                               wl_resource_find_for_client(&output->resource_list,
-                                                        client);
-               if (resource == NULL)
-                       continue;
-               if (1u << output->id & entered)
-                       wl_surface_send_enter(es->resource, resource);
-               if (1u << output->id & left)
-                       wl_surface_send_leave(es->resource, resource);
-       }
-}
-
-/** Recalculate which output(s) the surface has views displayed on
- *
- * \param es  The surface to remap to outputs
- *
- * Finds the output that is showing the largest amount of one
- * of the surface's various views.  This output becomes the
- * surface's primary output for vsync and frame callback purposes.
- *
- * Also notes all outputs of all of the surface's views
- * in the output_mask for the surface.
- */
-static void
-weston_surface_assign_output(struct weston_surface *es)
-{
-       struct weston_output *new_output;
-       struct weston_view *view;
-       pixman_region32_t region;
-       uint32_t max, area, mask;
-       pixman_box32_t *e;
-
-       new_output = NULL;
-       max = 0;
-       mask = 0;
-       pixman_region32_init(&region);
-       wl_list_for_each(view, &es->views, surface_link) {
-               if (!view->output)
-                       continue;
-
-               pixman_region32_intersect(&region, &view->transform.boundingbox,
-                                         &view->output->region);
-
-               e = pixman_region32_extents(&region);
-               area = (e->x2 - e->x1) * (e->y2 - e->y1);
-
-               mask |= view->output_mask;
-
-               if (area >= max) {
-                       new_output = view->output;
-                       max = area;
-               }
-       }
-       pixman_region32_fini(&region);
-
-       es->output = new_output;
-       weston_surface_update_output_mask(es, mask);
-}
-
-/** Recalculate which output(s) the view is displayed on
- *
- * \param ev  The view to remap to outputs
- *
- * Identifies the set of outputs that the view is visible on,
- * noting them into the output_mask.  The output that the view
- * is most visible on is set as the view's primary output.
- *
- * Also does the same for the view's surface.  See
- * weston_surface_assign_output().
- */
-static void
-weston_view_assign_output(struct weston_view *ev)
-{
-       struct weston_compositor *ec = ev->surface->compositor;
-       struct weston_output *output, *new_output;
-       pixman_region32_t region;
-       uint32_t max, area, mask;
-       pixman_box32_t *e;
-
-       new_output = NULL;
-       max = 0;
-       mask = 0;
-       pixman_region32_init(&region);
-       wl_list_for_each(output, &ec->output_list, link) {
-               if (output->destroying)
-                       continue;
-
-               pixman_region32_intersect(&region, &ev->transform.boundingbox,
-                                         &output->region);
-
-               e = pixman_region32_extents(&region);
-               area = (e->x2 - e->x1) * (e->y2 - e->y1);
-
-               if (area > 0)
-                       mask |= 1u << output->id;
-
-               if (area >= max) {
-                       new_output = output;
-                       max = area;
-               }
-       }
-       pixman_region32_fini(&region);
-
-       ev->output = new_output;
-       ev->output_mask = mask;
-
-       weston_surface_assign_output(ev->surface);
-}
-
-static void
-weston_view_to_view_map(struct weston_view *from, struct weston_view *to,
-                       int from_x, int from_y, int *to_x, int *to_y)
-{
-       float x, y;
-
-       weston_view_to_global_float(from, from_x, from_y, &x, &y);
-       weston_view_from_global_float(to, x, y, &x, &y);
-
-       *to_x = round(x);
-       *to_y = round(y);
-}
-
-static void
-weston_view_transfer_scissor(struct weston_view *from, struct weston_view *to)
-{
-       pixman_box32_t *a;
-       pixman_box32_t b;
-
-       a = pixman_region32_extents(&from->geometry.scissor);
-
-       weston_view_to_view_map(from, to, a->x1, a->y1, &b.x1, &b.y1);
-       weston_view_to_view_map(from, to, a->x2, a->y2, &b.x2, &b.y2);
-
-       pixman_region32_fini(&to->geometry.scissor);
-       pixman_region32_init_with_extents(&to->geometry.scissor, &b);
-}
-
-static void
-view_compute_bbox(struct weston_view *view, const pixman_box32_t *inbox,
-                 pixman_region32_t *bbox)
-{
-       float min_x = HUGE_VALF,  min_y = HUGE_VALF;
-       float max_x = -HUGE_VALF, max_y = -HUGE_VALF;
-       int32_t s[4][2] = {
-               { inbox->x1, inbox->y1 },
-               { inbox->x1, inbox->y2 },
-               { inbox->x2, inbox->y1 },
-               { inbox->x2, inbox->y2 },
-       };
-       float int_x, int_y;
-       int i;
-
-       if (inbox->x1 == inbox->x2 || inbox->y1 == inbox->y2) {
-               /* avoid rounding empty bbox to 1x1 */
-               pixman_region32_init(bbox);
-               return;
-       }
-
-       for (i = 0; i < 4; ++i) {
-               float x, y;
-               weston_view_to_global_float(view, s[i][0], s[i][1], &x, &y);
-               if (x < min_x)
-                       min_x = x;
-               if (x > max_x)
-                       max_x = x;
-               if (y < min_y)
-                       min_y = y;
-               if (y > max_y)
-                       max_y = y;
-       }
-
-       int_x = floorf(min_x);
-       int_y = floorf(min_y);
-       pixman_region32_init_rect(bbox, int_x, int_y,
-                                 ceilf(max_x) - int_x, ceilf(max_y) - int_y);
-}
-
-static void
-weston_view_update_transform_disable(struct weston_view *view)
-{
-       view->transform.enabled = 0;
-
-       /* round off fractions when not transformed */
-       view->geometry.x = roundf(view->geometry.x);
-       view->geometry.y = roundf(view->geometry.y);
-
-       /* Otherwise identity matrix, but with x and y translation. */
-       view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
-       view->transform.position.matrix.d[12] = view->geometry.x;
-       view->transform.position.matrix.d[13] = view->geometry.y;
-
-       view->transform.matrix = view->transform.position.matrix;
-
-       view->transform.inverse = view->transform.position.matrix;
-       view->transform.inverse.d[12] = -view->geometry.x;
-       view->transform.inverse.d[13] = -view->geometry.y;
-
-       pixman_region32_init_rect(&view->transform.boundingbox,
-                                 0, 0,
-                                 view->surface->width,
-                                 view->surface->height);
-       if (view->geometry.scissor_enabled)
-               pixman_region32_intersect(&view->transform.boundingbox,
-                                         &view->transform.boundingbox,
-                                         &view->geometry.scissor);
-
-       pixman_region32_translate(&view->transform.boundingbox,
-                                 view->geometry.x, view->geometry.y);
-
-       if (view->alpha == 1.0) {
-               pixman_region32_copy(&view->transform.opaque,
-                                    &view->surface->opaque);
-               pixman_region32_translate(&view->transform.opaque,
-                                         view->geometry.x,
-                                         view->geometry.y);
-       }
-}
-
-static int
-weston_view_update_transform_enable(struct weston_view *view)
-{
-       struct weston_view *parent = view->geometry.parent;
-       struct weston_matrix *matrix = &view->transform.matrix;
-       struct weston_matrix *inverse = &view->transform.inverse;
-       struct weston_transform *tform;
-       pixman_region32_t surfregion;
-       const pixman_box32_t *surfbox;
-
-       view->transform.enabled = 1;
-
-       /* Otherwise identity matrix, but with x and y translation. */
-       view->transform.position.matrix.type = WESTON_MATRIX_TRANSFORM_TRANSLATE;
-       view->transform.position.matrix.d[12] = view->geometry.x;
-       view->transform.position.matrix.d[13] = view->geometry.y;
-
-       weston_matrix_init(matrix);
-       wl_list_for_each(tform, &view->geometry.transformation_list, link)
-               weston_matrix_multiply(matrix, &tform->matrix);
-
-       if (parent)
-               weston_matrix_multiply(matrix, &parent->transform.matrix);
-
-       if (weston_matrix_invert(inverse, matrix) < 0) {
-               /* Oops, bad total transformation, not invertible */
-               weston_log("error: weston_view %p"
-                       " transformation not invertible.\n", view);
-               return -1;
-       }
-
-       pixman_region32_init_rect(&surfregion, 0, 0,
-                                 view->surface->width, view->surface->height);
-       if (view->geometry.scissor_enabled)
-               pixman_region32_intersect(&surfregion, &surfregion,
-                                         &view->geometry.scissor);
-       surfbox = pixman_region32_extents(&surfregion);
-
-       view_compute_bbox(view, surfbox, &view->transform.boundingbox);
-       pixman_region32_fini(&surfregion);
-
-       return 0;
-}
-
-static struct weston_layer *
-get_view_layer(struct weston_view *view)
-{
-       if (view->parent_view)
-               return get_view_layer(view->parent_view);
-       return view->layer_link.layer;
-}
-
-WL_EXPORT void
-weston_view_update_transform(struct weston_view *view)
-{
-       struct weston_view *parent = view->geometry.parent;
-       struct weston_layer *layer;
-       pixman_region32_t mask;
-
-       if (!view->transform.dirty)
-               return;
-
-       if (parent)
-               weston_view_update_transform(parent);
-
-       view->transform.dirty = 0;
-
-       weston_view_damage_below(view);
-
-       pixman_region32_fini(&view->transform.boundingbox);
-       pixman_region32_fini(&view->transform.opaque);
-       pixman_region32_init(&view->transform.opaque);
-
-       /* transform.position is always in transformation_list */
-       if (view->geometry.transformation_list.next ==
-           &view->transform.position.link &&
-           view->geometry.transformation_list.prev ==
-           &view->transform.position.link &&
-           !parent) {
-               weston_view_update_transform_disable(view);
-       } else {
-               if (weston_view_update_transform_enable(view) < 0)
-                       weston_view_update_transform_disable(view);
-       }
-
-       layer = get_view_layer(view);
-       if (layer) {
-               pixman_region32_init_with_extents(&mask, &layer->mask);
-               pixman_region32_intersect(&view->transform.boundingbox,
-                                         &view->transform.boundingbox, &mask);
-               pixman_region32_intersect(&view->transform.opaque,
-                                         &view->transform.opaque, &mask);
-               pixman_region32_fini(&mask);
-       }
-
-       if (parent) {
-               if (parent->geometry.scissor_enabled) {
-                       view->geometry.scissor_enabled = true;
-                       weston_view_transfer_scissor(parent, view);
-               } else {
-                       view->geometry.scissor_enabled = false;
-               }
-       }
-
-       weston_view_damage_below(view);
-
-       weston_view_assign_output(view);
-
-       wl_signal_emit(&view->surface->compositor->transform_signal,
-                      view->surface);
-}
-
-WL_EXPORT void
-weston_view_geometry_dirty(struct weston_view *view)
-{
-       struct weston_view *child;
-
-       /*
-        * The invariant: if view->geometry.dirty, then all views
-        * in view->geometry.child_list have geometry.dirty too.
-        * Corollary: if not parent->geometry.dirty, then all ancestors
-        * are not dirty.
-        */
-
-       if (view->transform.dirty)
-               return;
-
-       view->transform.dirty = 1;
-
-       wl_list_for_each(child, &view->geometry.child_list,
-                        geometry.parent_link)
-               weston_view_geometry_dirty(child);
-}
-
-WL_EXPORT void
-weston_view_to_global_fixed(struct weston_view *view,
-                           wl_fixed_t vx, wl_fixed_t vy,
-                           wl_fixed_t *x, wl_fixed_t *y)
-{
-       float xf, yf;
-
-       weston_view_to_global_float(view,
-                                   wl_fixed_to_double(vx),
-                                   wl_fixed_to_double(vy),
-                                   &xf, &yf);
-       *x = wl_fixed_from_double(xf);
-       *y = wl_fixed_from_double(yf);
-}
-
-WL_EXPORT void
-weston_view_from_global_float(struct weston_view *view,
-                             float x, float y, float *vx, float *vy)
-{
-       if (view->transform.enabled) {
-               struct weston_vector v = { { x, y, 0.0f, 1.0f } };
-
-               weston_matrix_transform(&view->transform.inverse, &v);
-
-               if (fabsf(v.f[3]) < 1e-6) {
-                       weston_log("warning: numerical instability in "
-                               "weston_view_from_global(), divisor = %g\n",
-                               v.f[3]);
-                       *vx = 0;
-                       *vy = 0;
-                       return;
-               }
-
-               *vx = v.f[0] / v.f[3];
-               *vy = v.f[1] / v.f[3];
-       } else {
-               *vx = x - view->geometry.x;
-               *vy = y - view->geometry.y;
-       }
-}
-
-WL_EXPORT void
-weston_view_from_global_fixed(struct weston_view *view,
-                             wl_fixed_t x, wl_fixed_t y,
-                             wl_fixed_t *vx, wl_fixed_t *vy)
-{
-       float vxf, vyf;
-
-       weston_view_from_global_float(view,
-                                     wl_fixed_to_double(x),
-                                     wl_fixed_to_double(y),
-                                     &vxf, &vyf);
-       *vx = wl_fixed_from_double(vxf);
-       *vy = wl_fixed_from_double(vyf);
-}
-
-WL_EXPORT void
-weston_view_from_global(struct weston_view *view,
-                       int32_t x, int32_t y, int32_t *vx, int32_t *vy)
-{
-       float vxf, vyf;
-
-       weston_view_from_global_float(view, x, y, &vxf, &vyf);
-       *vx = floorf(vxf);
-       *vy = floorf(vyf);
-}
-
-/**
- * \param surface  The surface to be repainted
- *
- * Marks the output(s) that the surface is shown on as needing to be
- * repainted.  See weston_output_schedule_repaint().
- */
-WL_EXPORT void
-weston_surface_schedule_repaint(struct weston_surface *surface)
-{
-       struct weston_output *output;
-
-       wl_list_for_each(output, &surface->compositor->output_list, link)
-               if (surface->output_mask & (1u << output->id))
-                       weston_output_schedule_repaint(output);
-}
-
-/**
- * \param view  The view to be repainted
- *
- * Marks the output(s) that the view is shown on as needing to be
- * repainted.  See weston_output_schedule_repaint().
- */
-WL_EXPORT void
-weston_view_schedule_repaint(struct weston_view *view)
-{
-       struct weston_output *output;
-
-       wl_list_for_each(output, &view->surface->compositor->output_list, link)
-               if (view->output_mask & (1u << output->id))
-                       weston_output_schedule_repaint(output);
-}
-
-/**
- * XXX: This function does it the wrong way.
- * surface->damage is the damage from the client, and causes
- * surface_flush_damage() to copy pixels. No window management action can
- * cause damage to the client-provided content, warranting re-upload!
- *
- * Instead of surface->damage, this function should record the damage
- * with all the views for this surface to avoid extraneous texture
- * uploads.
- */
-WL_EXPORT void
-weston_surface_damage(struct weston_surface *surface)
-{
-       pixman_region32_union_rect(&surface->damage, &surface->damage,
-                                  0, 0, surface->width,
-                                  surface->height);
-
-       weston_surface_schedule_repaint(surface);
-}
-
-WL_EXPORT void
-weston_view_set_position(struct weston_view *view, float x, float y)
-{
-       if (view->geometry.x == x && view->geometry.y == y)
-               return;
-
-       view->geometry.x = x;
-       view->geometry.y = y;
-       weston_view_geometry_dirty(view);
-}
-
-static void
-transform_parent_handle_parent_destroy(struct wl_listener *listener,
-                                      void *data)
-{
-       struct weston_view *view =
-               container_of(listener, struct weston_view,
-                            geometry.parent_destroy_listener);
-
-       weston_view_set_transform_parent(view, NULL);
-}
-
-WL_EXPORT void
-weston_view_set_transform_parent(struct weston_view *view,
-                                struct weston_view *parent)
-{
-       if (view->geometry.parent) {
-               wl_list_remove(&view->geometry.parent_destroy_listener.link);
-               wl_list_remove(&view->geometry.parent_link);
-
-               if (!parent)
-                       view->geometry.scissor_enabled = false;
-       }
-
-       view->geometry.parent = parent;
-
-       view->geometry.parent_destroy_listener.notify =
-               transform_parent_handle_parent_destroy;
-       if (parent) {
-               wl_signal_add(&parent->destroy_signal,
-                             &view->geometry.parent_destroy_listener);
-               wl_list_insert(&parent->geometry.child_list,
-                              &view->geometry.parent_link);
-       }
-
-       weston_view_geometry_dirty(view);
-}
-
-/** Set a clip mask rectangle on a view
- *
- * \param view The view to set the clip mask on.
- * \param x Top-left corner X coordinate of the clip rectangle.
- * \param y Top-left corner Y coordinate of the clip rectangle.
- * \param width Width of the clip rectangle, non-negative.
- * \param height Height of the clip rectangle, non-negative.
- *
- * A shell may set a clip mask rectangle on a view. Everything outside
- * the rectangle is cut away for input and output purposes: it is
- * not drawn and cannot be hit by hit-test based input like pointer
- * motion or touch-downs. Everything inside the rectangle will behave
- * normally. Clients are unaware of clipping.
- *
- * The rectangle is set in surface-local coordinates. Setting a clip
- * mask rectangle does not affect the view position, the view is positioned
- * as it would be without a clip. The clip also does not change
- * weston_surface::width,height.
- *
- * The clip mask rectangle is part of transformation inheritance
- * (weston_view_set_transform_parent()). A clip set in the root of the
- * transformation inheritance tree will affect all views in the tree.
- * A clip can be set only on the root view. Attempting to set a clip
- * on view that has a transformation parent will fail. Assigning a parent
- * to a view that has a clip set will cause the clip to be forgotten.
- *
- * Because the clip mask is an axis-aligned rectangle, it poses restrictions
- * on the additional transformations in the child views. These transformations
- * may not rotate the coordinate axes, i.e., only translation and scaling
- * are allowed. Violating this restriction causes the clipping to malfunction.
- * Furthermore, using scaling may cause rounding errors in child clipping.
- *
- * The clip mask rectangle is not automatically adjusted based on
- * wl_surface.attach dx and dy arguments.
- *
- * A clip mask rectangle can be set only if the compositor capability
- * WESTON_CAP_VIEW_CLIP_MASK is present.
- *
- * This function sets the clip mask rectangle and schedules a repaint for
- * the view.
- */
-WL_EXPORT void
-weston_view_set_mask(struct weston_view *view,
-                    int x, int y, int width, int height)
-{
-       struct weston_compositor *compositor = view->surface->compositor;
-
-       if (!(compositor->capabilities & WESTON_CAP_VIEW_CLIP_MASK)) {
-               weston_log("%s not allowed without capability!\n", __func__);
-               return;
-       }
-
-       if (view->geometry.parent) {
-               weston_log("view %p has a parent, clip forbidden!\n", view);
-               return;
-       }
-
-       if (width < 0 || height < 0) {
-               weston_log("%s: illegal args %d, %d, %d, %d\n", __func__,
-                          x, y, width, height);
-               return;
-       }
-
-       pixman_region32_fini(&view->geometry.scissor);
-       pixman_region32_init_rect(&view->geometry.scissor, x, y, width, height);
-       view->geometry.scissor_enabled = true;
-       weston_view_geometry_dirty(view);
-       weston_view_schedule_repaint(view);
-}
-
-/** Remove the clip mask from a view
- *
- * \param view The view to remove the clip mask from.
- *
- * Removed the clip mask rectangle and schedules a repaint.
- *
- * \sa weston_view_set_mask
- */
-WL_EXPORT void
-weston_view_set_mask_infinite(struct weston_view *view)
-{
-       view->geometry.scissor_enabled = false;
-       weston_view_geometry_dirty(view);
-       weston_view_schedule_repaint(view);
-}
-
-WL_EXPORT bool
-weston_view_is_mapped(struct weston_view *view)
-{
-       if (view->output)
-               return true;
-       else
-               return false;
-}
-
-WL_EXPORT bool
-weston_surface_is_mapped(struct weston_surface *surface)
-{
-       if (surface->output)
-               return true;
-       else
-               return false;
-}
-
-static void
-surface_set_size(struct weston_surface *surface, int32_t width, int32_t height)
-{
-       struct weston_view *view;
-
-       if (surface->width == width && surface->height == height)
-               return;
-
-       surface->width = width;
-       surface->height = height;
-
-       wl_list_for_each(view, &surface->views, surface_link)
-               weston_view_geometry_dirty(view);
-}
-
-WL_EXPORT void
-weston_surface_set_size(struct weston_surface *surface,
-                       int32_t width, int32_t height)
-{
-       assert(!surface->resource);
-       surface_set_size(surface, width, height);
-}
-
-static int
-fixed_round_up_to_int(wl_fixed_t f)
-{
-       return wl_fixed_to_int(wl_fixed_from_int(1) - 1 + f);
-}
-
-static void
-convert_size_by_transform_scale(int32_t *width_out, int32_t *height_out,
-                               int32_t width, int32_t height,
-                               uint32_t transform,
-                               int32_t scale)
-{
-       assert(scale > 0);
-
-       switch (transform) {
-       case WL_OUTPUT_TRANSFORM_NORMAL:
-       case WL_OUTPUT_TRANSFORM_180:
-       case WL_OUTPUT_TRANSFORM_FLIPPED:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
-               *width_out = width / scale;
-               *height_out = height / scale;
-               break;
-       case WL_OUTPUT_TRANSFORM_90:
-       case WL_OUTPUT_TRANSFORM_270:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
-               *width_out = height / scale;
-               *height_out = width / scale;
-               break;
-       default:
-               assert(0 && "invalid transform");
-       }
-}
-
-static void
-weston_surface_calculate_size_from_buffer(struct weston_surface *surface)
-{
-       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
-
-       if (!surface->buffer_ref.buffer) {
-               surface->width_from_buffer = 0;
-               surface->height_from_buffer = 0;
-               return;
-       }
-
-       convert_size_by_transform_scale(&surface->width_from_buffer,
-                                       &surface->height_from_buffer,
-                                       surface->buffer_ref.buffer->width,
-                                       surface->buffer_ref.buffer->height,
-                                       vp->buffer.transform,
-                                       vp->buffer.scale);
-}
-
-static void
-weston_surface_update_size(struct weston_surface *surface)
-{
-       struct weston_buffer_viewport *vp = &surface->buffer_viewport;
-       int32_t width, height;
-
-       width = surface->width_from_buffer;
-       height = surface->height_from_buffer;
-
-       if (width != 0 && vp->surface.width != -1) {
-               surface_set_size(surface,
-                                vp->surface.width, vp->surface.height);
-               return;
-       }
-
-       if (width != 0 && vp->buffer.src_width != wl_fixed_from_int(-1)) {
-               int32_t w = fixed_round_up_to_int(vp->buffer.src_width);
-               int32_t h = fixed_round_up_to_int(vp->buffer.src_height);
-
-               surface_set_size(surface, w ?: 1, h ?: 1);
-               return;
-       }
-
-       surface_set_size(surface, width, height);
-}
-
-WL_EXPORT uint32_t
-weston_compositor_get_time(void)
-{
-       struct timeval tv;
-
-       gettimeofday(&tv, NULL);
-
-       return tv.tv_sec * 1000 + tv.tv_usec / 1000;
-}
-
-WL_EXPORT struct weston_view *
-weston_compositor_pick_view(struct weston_compositor *compositor,
-                           wl_fixed_t x, wl_fixed_t y,
-                           wl_fixed_t *vx, wl_fixed_t *vy)
-{
-       struct weston_view *view;
-       wl_fixed_t view_x, view_y;
-       int view_ix, view_iy;
-       int ix = wl_fixed_to_int(x);
-       int iy = wl_fixed_to_int(y);
-
-       wl_list_for_each(view, &compositor->view_list, link) {
-               if (!pixman_region32_contains_point(
-                               &view->transform.boundingbox, ix, iy, NULL))
-                       continue;
-
-               weston_view_from_global_fixed(view, x, y, &view_x, &view_y);
-               view_ix = wl_fixed_to_int(view_x);
-               view_iy = wl_fixed_to_int(view_y);
-
-               if (!pixman_region32_contains_point(&view->surface->input,
-                                                   view_ix, view_iy, NULL))
-                       continue;
-
-               if (view->geometry.scissor_enabled &&
-                   !pixman_region32_contains_point(&view->geometry.scissor,
-                                                   view_ix, view_iy, NULL))
-                       continue;
-
-               *vx = view_x;
-               *vy = view_y;
-               return view;
-       }
-
-       *vx = wl_fixed_from_int(-1000000);
-       *vy = wl_fixed_from_int(-1000000);
-       return NULL;
-}
-
-static void
-weston_compositor_repick(struct weston_compositor *compositor)
-{
-       struct weston_seat *seat;
-
-       if (!compositor->session_active)
-               return;
-
-       wl_list_for_each(seat, &compositor->seat_list, link)
-               weston_seat_repick(seat);
-}
-
-WL_EXPORT void
-weston_view_unmap(struct weston_view *view)
-{
-       struct weston_seat *seat;
-
-       if (!weston_view_is_mapped(view))
-               return;
-
-       weston_view_damage_below(view);
-       view->output = NULL;
-       view->plane = NULL;
-       weston_layer_entry_remove(&view->layer_link);
-       wl_list_remove(&view->link);
-       wl_list_init(&view->link);
-       view->output_mask = 0;
-       weston_surface_assign_output(view->surface);
-
-       if (weston_surface_is_mapped(view->surface))
-               return;
-
-       wl_list_for_each(seat, &view->surface->compositor->seat_list, link) {
-               struct weston_touch *touch = weston_seat_get_touch(seat);
-               struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-               struct weston_keyboard *keyboard =
-                       weston_seat_get_keyboard(seat);
-
-               if (keyboard && keyboard->focus == view->surface)
-                       weston_keyboard_set_focus(keyboard, NULL);
-               if (pointer && pointer->focus == view)
-                       weston_pointer_clear_focus(pointer);
-               if (touch && touch->focus == view)
-                       weston_touch_set_focus(touch, NULL);
-       }
-}
-
-WL_EXPORT void
-weston_surface_unmap(struct weston_surface *surface)
-{
-       struct weston_view *view;
-
-       wl_list_for_each(view, &surface->views, surface_link)
-               weston_view_unmap(view);
-       surface->output = NULL;
-}
-
-static void
-weston_surface_reset_pending_buffer(struct weston_surface *surface)
-{
-       weston_surface_state_set_buffer(&surface->pending, NULL);
-       surface->pending.sx = 0;
-       surface->pending.sy = 0;
-       surface->pending.newly_attached = 0;
-       surface->pending.buffer_viewport.changed = 0;
-}
-
-WL_EXPORT void
-weston_view_destroy(struct weston_view *view)
-{
-       wl_signal_emit(&view->destroy_signal, view);
-
-       assert(wl_list_empty(&view->geometry.child_list));
-
-       if (weston_view_is_mapped(view)) {
-               weston_view_unmap(view);
-               weston_compositor_build_view_list(view->surface->compositor);
-       }
-
-       wl_list_remove(&view->link);
-       weston_layer_entry_remove(&view->layer_link);
-
-       pixman_region32_fini(&view->clip);
-       pixman_region32_fini(&view->geometry.scissor);
-       pixman_region32_fini(&view->transform.boundingbox);
-       pixman_region32_fini(&view->transform.opaque);
-
-       weston_view_set_transform_parent(view, NULL);
-
-       wl_list_remove(&view->surface_link);
-
-       free(view);
-}
-
-WL_EXPORT void
-weston_surface_destroy(struct weston_surface *surface)
-{
-       struct weston_frame_callback *cb, *next;
-       struct weston_view *ev, *nv;
-
-       if (--surface->ref_count > 0)
-               return;
-
-       assert(surface->resource == NULL);
-
-       wl_signal_emit(&surface->destroy_signal, surface);
-
-       assert(wl_list_empty(&surface->subsurface_list_pending));
-       assert(wl_list_empty(&surface->subsurface_list));
-
-       wl_list_for_each_safe(ev, nv, &surface->views, surface_link)
-               weston_view_destroy(ev);
-
-       weston_surface_state_fini(&surface->pending);
-
-       weston_buffer_reference(&surface->buffer_ref, NULL);
-
-       pixman_region32_fini(&surface->damage);
-       pixman_region32_fini(&surface->opaque);
-       pixman_region32_fini(&surface->input);
-
-       wl_list_for_each_safe(cb, next, &surface->frame_callback_list, link)
-               wl_resource_destroy(cb->resource);
-
-       weston_presentation_feedback_discard_list(&surface->feedback_list);
-
-       free(surface);
-}
-
-static void
-destroy_surface(struct wl_resource *resource)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-
-       assert(surface);
-
-       /* Set the resource to NULL, since we don't want to leave a
-        * dangling pointer if the surface was refcounted and survives
-        * the weston_surface_destroy() call. */
-       surface->resource = NULL;
-
-       if (surface->viewport_resource)
-               wl_resource_set_user_data(surface->viewport_resource, NULL);
-
-       weston_surface_destroy(surface);
-}
-
-static void
-weston_buffer_destroy_handler(struct wl_listener *listener, void *data)
-{
-       struct weston_buffer *buffer =
-               container_of(listener, struct weston_buffer, destroy_listener);
-
-       wl_signal_emit(&buffer->destroy_signal, buffer);
-       free(buffer);
-}
-
-WL_EXPORT struct weston_buffer *
-weston_buffer_from_resource(struct wl_resource *resource)
-{
-       struct weston_buffer *buffer;
-       struct wl_listener *listener;
-
-       listener = wl_resource_get_destroy_listener(resource,
-                                                   weston_buffer_destroy_handler);
-
-       if (listener)
-               return container_of(listener, struct weston_buffer,
-                                   destroy_listener);
-
-       buffer = zalloc(sizeof *buffer);
-       if (buffer == NULL)
-               return NULL;
-
-       buffer->resource = resource;
-       wl_signal_init(&buffer->destroy_signal);
-       buffer->destroy_listener.notify = weston_buffer_destroy_handler;
-       buffer->y_inverted = 1;
-       wl_resource_add_destroy_listener(resource, &buffer->destroy_listener);
-
-       return buffer;
-}
-
-static void
-weston_buffer_reference_handle_destroy(struct wl_listener *listener,
-                                      void *data)
-{
-       struct weston_buffer_reference *ref =
-               container_of(listener, struct weston_buffer_reference,
-                            destroy_listener);
-
-       assert((struct weston_buffer *)data == ref->buffer);
-       ref->buffer = NULL;
-}
-
-WL_EXPORT void
-weston_buffer_reference(struct weston_buffer_reference *ref,
-                       struct weston_buffer *buffer)
-{
-       if (ref->buffer && buffer != ref->buffer) {
-               ref->buffer->busy_count--;
-               if (ref->buffer->busy_count == 0) {
-                       assert(wl_resource_get_client(ref->buffer->resource));
-                       wl_resource_queue_event(ref->buffer->resource,
-                                               WL_BUFFER_RELEASE);
-               }
-               wl_list_remove(&ref->destroy_listener.link);
-       }
-
-       if (buffer && buffer != ref->buffer) {
-               buffer->busy_count++;
-               wl_signal_add(&buffer->destroy_signal,
-                             &ref->destroy_listener);
-       }
-
-       ref->buffer = buffer;
-       ref->destroy_listener.notify = weston_buffer_reference_handle_destroy;
-}
-
-static void
-weston_surface_attach(struct weston_surface *surface,
-                     struct weston_buffer *buffer)
-{
-       weston_buffer_reference(&surface->buffer_ref, buffer);
-
-       if (!buffer) {
-               if (weston_surface_is_mapped(surface))
-                       weston_surface_unmap(surface);
-       }
-
-       surface->compositor->renderer->attach(surface, buffer);
-
-       weston_surface_calculate_size_from_buffer(surface);
-       weston_presentation_feedback_discard_list(&surface->feedback_list);
-}
-
-WL_EXPORT void
-weston_compositor_damage_all(struct weston_compositor *compositor)
-{
-       struct weston_output *output;
-
-       wl_list_for_each(output, &compositor->output_list, link)
-               weston_output_damage(output);
-}
-
-WL_EXPORT void
-weston_output_damage(struct weston_output *output)
-{
-       struct weston_compositor *compositor = output->compositor;
-
-       pixman_region32_union(&compositor->primary_plane.damage,
-                             &compositor->primary_plane.damage,
-                             &output->region);
-       weston_output_schedule_repaint(output);
-}
-
-static void
-surface_flush_damage(struct weston_surface *surface)
-{
-       if (surface->buffer_ref.buffer &&
-           wl_shm_buffer_get(surface->buffer_ref.buffer->resource))
-               surface->compositor->renderer->flush_damage(surface);
-
-       if (weston_timeline_enabled_ &&
-           pixman_region32_not_empty(&surface->damage))
-               TL_POINT("core_flush_damage", TLP_SURFACE(surface),
-                        TLP_OUTPUT(surface->output), TLP_END);
-
-       pixman_region32_clear(&surface->damage);
-}
-
-static void
-view_accumulate_damage(struct weston_view *view,
-                      pixman_region32_t *opaque)
-{
-       pixman_region32_t damage;
-
-       pixman_region32_init(&damage);
-       if (view->transform.enabled) {
-               pixman_box32_t *extents;
-
-               extents = pixman_region32_extents(&view->surface->damage);
-               view_compute_bbox(view, extents, &damage);
-       } else {
-               pixman_region32_copy(&damage, &view->surface->damage);
-               pixman_region32_translate(&damage,
-                                         view->geometry.x, view->geometry.y);
-       }
-
-       pixman_region32_intersect(&damage, &damage,
-                                 &view->transform.boundingbox);
-       pixman_region32_subtract(&damage, &damage, opaque);
-       pixman_region32_union(&view->plane->damage,
-                             &view->plane->damage, &damage);
-       pixman_region32_fini(&damage);
-       pixman_region32_copy(&view->clip, opaque);
-       pixman_region32_union(opaque, opaque, &view->transform.opaque);
-}
-
-static void
-compositor_accumulate_damage(struct weston_compositor *ec)
-{
-       struct weston_plane *plane;
-       struct weston_view *ev;
-       pixman_region32_t opaque, clip;
-
-       pixman_region32_init(&clip);
-
-       wl_list_for_each(plane, &ec->plane_list, link) {
-               pixman_region32_copy(&plane->clip, &clip);
-
-               pixman_region32_init(&opaque);
-
-               wl_list_for_each(ev, &ec->view_list, link) {
-                       if (ev->plane != plane)
-                               continue;
-
-                       view_accumulate_damage(ev, &opaque);
-               }
-
-               pixman_region32_union(&clip, &clip, &opaque);
-               pixman_region32_fini(&opaque);
-       }
-
-       pixman_region32_fini(&clip);
-
-       wl_list_for_each(ev, &ec->view_list, link)
-               ev->surface->touched = false;
-
-       wl_list_for_each(ev, &ec->view_list, link) {
-               if (ev->surface->touched)
-                       continue;
-               ev->surface->touched = true;
-
-               surface_flush_damage(ev->surface);
-
-               /* Both the renderer and the backend have seen the buffer
-                * by now. If renderer needs the buffer, it has its own
-                * reference set. If the backend wants to keep the buffer
-                * around for migrating the surface into a non-primary plane
-                * later, keep_buffer is true. Otherwise, drop the core
-                * reference now, and allow early buffer release. This enables
-                * clients to use single-buffering.
-                */
-               if (!ev->surface->keep_buffer)
-                       weston_buffer_reference(&ev->surface->buffer_ref, NULL);
-       }
-}
-
-static void
-surface_stash_subsurface_views(struct weston_surface *surface)
-{
-       struct weston_subsurface *sub;
-
-       wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
-               if (sub->surface == surface)
-                       continue;
-
-               wl_list_insert_list(&sub->unused_views, &sub->surface->views);
-               wl_list_init(&sub->surface->views);
-
-               surface_stash_subsurface_views(sub->surface);
-       }
-}
-
-static void
-surface_free_unused_subsurface_views(struct weston_surface *surface)
-{
-       struct weston_subsurface *sub;
-       struct weston_view *view, *nv;
-
-       wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
-               if (sub->surface == surface)
-                       continue;
-
-               wl_list_for_each_safe(view, nv, &sub->unused_views, surface_link) {
-                       weston_view_unmap (view);
-                       weston_view_destroy(view);
-               }
-
-               surface_free_unused_subsurface_views(sub->surface);
-       }
-}
-
-static void
-view_list_add_subsurface_view(struct weston_compositor *compositor,
-                             struct weston_subsurface *sub,
-                             struct weston_view *parent)
-{
-       struct weston_subsurface *child;
-       struct weston_view *view = NULL, *iv;
-
-       if (!weston_surface_is_mapped(sub->surface))
-               return;
-
-       wl_list_for_each(iv, &sub->unused_views, surface_link) {
-               if (iv->geometry.parent == parent) {
-                       view = iv;
-                       break;
-               }
-       }
-
-       if (view) {
-               /* Put it back in the surface's list of views */
-               wl_list_remove(&view->surface_link);
-               wl_list_insert(&sub->surface->views, &view->surface_link);
-       } else {
-               view = weston_view_create(sub->surface);
-               weston_view_set_position(view,
-                                        sub->position.x,
-                                        sub->position.y);
-               weston_view_set_transform_parent(view, parent);
-       }
-
-       view->parent_view = parent;
-       weston_view_update_transform(view);
-
-       if (wl_list_empty(&sub->surface->subsurface_list)) {
-               wl_list_insert(compositor->view_list.prev, &view->link);
-               return;
-       }
-
-       wl_list_for_each(child, &sub->surface->subsurface_list, parent_link) {
-               if (child->surface == sub->surface)
-                       wl_list_insert(compositor->view_list.prev, &view->link);
-               else
-                       view_list_add_subsurface_view(compositor, child, view);
-       }
-}
-
-static void
-view_list_add(struct weston_compositor *compositor,
-             struct weston_view *view)
-{
-       struct weston_subsurface *sub;
-
-       weston_view_update_transform(view);
-
-       if (wl_list_empty(&view->surface->subsurface_list)) {
-               wl_list_insert(compositor->view_list.prev, &view->link);
-               return;
-       }
-
-       wl_list_for_each(sub, &view->surface->subsurface_list, parent_link) {
-               if (sub->surface == view->surface)
-                       wl_list_insert(compositor->view_list.prev, &view->link);
-               else
-                       view_list_add_subsurface_view(compositor, sub, view);
-       }
-}
-
-static void
-weston_compositor_build_view_list(struct weston_compositor *compositor)
-{
-       struct weston_view *view;
-       struct weston_layer *layer;
-
-       wl_list_for_each(layer, &compositor->layer_list, link)
-               wl_list_for_each(view, &layer->view_list.link, layer_link.link)
-                       surface_stash_subsurface_views(view->surface);
-
-       wl_list_init(&compositor->view_list);
-       wl_list_for_each(layer, &compositor->layer_list, link) {
-               wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
-                       view_list_add(compositor, view);
-               }
-       }
-
-       wl_list_for_each(layer, &compositor->layer_list, link)
-               wl_list_for_each(view, &layer->view_list.link, layer_link.link)
-                       surface_free_unused_subsurface_views(view->surface);
-}
-
-static void
-weston_output_take_feedback_list(struct weston_output *output,
-                                struct weston_surface *surface)
-{
-       struct weston_view *view;
-       struct weston_presentation_feedback *feedback;
-       uint32_t flags = 0xffffffff;
-
-       if (wl_list_empty(&surface->feedback_list))
-               return;
-
-       /* All views must have the flag for the flag to survive. */
-       wl_list_for_each(view, &surface->views, surface_link) {
-               /* ignore views that are not on this output at all */
-               if (view->output_mask & (1u << output->id))
-                       flags &= view->psf_flags;
-       }
-
-       wl_list_for_each(feedback, &surface->feedback_list, link)
-               feedback->psf_flags = flags;
-
-       wl_list_insert_list(&output->feedback_list, &surface->feedback_list);
-       wl_list_init(&surface->feedback_list);
-}
-
-static int
-weston_output_repaint(struct weston_output *output)
-{
-       struct weston_compositor *ec = output->compositor;
-       struct weston_view *ev;
-       struct weston_animation *animation, *next;
-       struct weston_frame_callback *cb, *cnext;
-       struct wl_list frame_callback_list;
-       pixman_region32_t output_damage;
-       int r;
-
-       if (output->destroying)
-               return 0;
-
-       TL_POINT("core_repaint_begin", TLP_OUTPUT(output), TLP_END);
-
-       /* Rebuild the surface list and update surface transforms up front. */
-       weston_compositor_build_view_list(ec);
-
-       if (output->assign_planes && !output->disable_planes) {
-               output->assign_planes(output);
-       } else {
-               wl_list_for_each(ev, &ec->view_list, link) {
-                       weston_view_move_to_plane(ev, &ec->primary_plane);
-                       ev->psf_flags = 0;
-               }
-       }
-
-       wl_list_init(&frame_callback_list);
-       wl_list_for_each(ev, &ec->view_list, link) {
-               /* Note: This operation is safe to do multiple times on the
-                * same surface.
-                */
-               if (ev->surface->output == output) {
-                       wl_list_insert_list(&frame_callback_list,
-                                           &ev->surface->frame_callback_list);
-                       wl_list_init(&ev->surface->frame_callback_list);
-
-                       weston_output_take_feedback_list(output, ev->surface);
-               }
-       }
-
-       compositor_accumulate_damage(ec);
-
-       pixman_region32_init(&output_damage);
-       pixman_region32_intersect(&output_damage,
-                                 &ec->primary_plane.damage, &output->region);
-       pixman_region32_subtract(&output_damage,
-                                &output_damage, &ec->primary_plane.clip);
-
-       if (output->dirty)
-               weston_output_update_matrix(output);
-
-       r = output->repaint(output, &output_damage);
-
-       pixman_region32_fini(&output_damage);
-
-       output->repaint_needed = 0;
-
-       weston_compositor_repick(ec);
-
-       wl_list_for_each_safe(cb, cnext, &frame_callback_list, link) {
-               wl_callback_send_done(cb->resource, output->frame_time);
-               wl_resource_destroy(cb->resource);
-       }
-
-       wl_list_for_each_safe(animation, next, &output->animation_list, link) {
-               animation->frame_counter++;
-               animation->frame(animation, output, output->frame_time);
-       }
-
-       TL_POINT("core_repaint_posted", TLP_OUTPUT(output), TLP_END);
-
-       return r;
-}
-
-static void
-weston_output_schedule_repaint_reset(struct weston_output *output)
-{
-       output->repaint_scheduled = 0;
-       TL_POINT("core_repaint_exit_loop", TLP_OUTPUT(output), TLP_END);
-}
-
-static int
-output_repaint_timer_handler(void *data)
-{
-       struct weston_output *output = data;
-       struct weston_compositor *compositor = output->compositor;
-
-       if (output->repaint_needed &&
-           compositor->state != WESTON_COMPOSITOR_SLEEPING &&
-           compositor->state != WESTON_COMPOSITOR_OFFSCREEN &&
-           weston_output_repaint(output) == 0)
-               return 0;
-
-       weston_output_schedule_repaint_reset(output);
-
-       return 0;
-}
-
-WL_EXPORT void
-weston_output_finish_frame(struct weston_output *output,
-                          const struct timespec *stamp,
-                          uint32_t presented_flags)
-{
-       struct weston_compositor *compositor = output->compositor;
-       int32_t refresh_nsec;
-       struct timespec now;
-       struct timespec gone;
-       int msec;
-
-       TL_POINT("core_repaint_finished", TLP_OUTPUT(output),
-                TLP_VBLANK(stamp), TLP_END);
-
-       refresh_nsec = millihz_to_nsec(output->current_mode->refresh);
-       weston_presentation_feedback_present_list(&output->feedback_list,
-                                                 output, refresh_nsec, stamp,
-                                                 output->msc,
-                                                 presented_flags);
-
-       output->frame_time = stamp->tv_sec * 1000 + stamp->tv_nsec / 1000000;
-
-       weston_compositor_read_presentation_clock(compositor, &now);
-       timespec_sub(&gone, &now, stamp);
-       msec = (refresh_nsec - timespec_to_nsec(&gone)) / 1000000; /* floor */
-       msec -= compositor->repaint_msec;
-
-       if (msec < -1000 || msec > 1000) {
-               static bool warned;
-
-               if (!warned)
-                       weston_log("Warning: computed repaint delay is "
-                                  "insane: %d msec\n", msec);
-               warned = true;
-
-               msec = 0;
-       }
-
-       /* Called from restart_repaint_loop and restart happens already after
-        * the deadline given by repaint_msec? In that case we delay until
-        * the deadline of the next frame, to give clients a more predictable
-        * timing of the repaint cycle to lock on. */
-       if (presented_flags == WP_PRESENTATION_FEEDBACK_INVALID && msec < 0)
-               msec += refresh_nsec / 1000000;
-
-       if (msec < 1)
-               output_repaint_timer_handler(output);
-       else
-               wl_event_source_timer_update(output->repaint_timer, msec);
-}
-
-static void
-idle_repaint(void *data)
-{
-       struct weston_output *output = data;
-
-       output->start_repaint_loop(output);
-}
-
-WL_EXPORT void
-weston_layer_entry_insert(struct weston_layer_entry *list,
-                         struct weston_layer_entry *entry)
-{
-       wl_list_insert(&list->link, &entry->link);
-       entry->layer = list->layer;
-}
-
-WL_EXPORT void
-weston_layer_entry_remove(struct weston_layer_entry *entry)
-{
-       wl_list_remove(&entry->link);
-       wl_list_init(&entry->link);
-       entry->layer = NULL;
-}
-
-WL_EXPORT void
-weston_layer_init(struct weston_layer *layer, struct wl_list *below)
-{
-       wl_list_init(&layer->view_list.link);
-       layer->view_list.layer = layer;
-       weston_layer_set_mask_infinite(layer);
-       if (below != NULL)
-               wl_list_insert(below, &layer->link);
-}
-
-WL_EXPORT void
-weston_layer_set_mask(struct weston_layer *layer,
-                     int x, int y, int width, int height)
-{
-       struct weston_view *view;
-
-       layer->mask.x1 = x;
-       layer->mask.x2 = x + width;
-       layer->mask.y1 = y;
-       layer->mask.y2 = y + height;
-
-       wl_list_for_each(view, &layer->view_list.link, layer_link.link) {
-               weston_view_geometry_dirty(view);
-       }
-}
-
-WL_EXPORT void
-weston_layer_set_mask_infinite(struct weston_layer *layer)
-{
-       weston_layer_set_mask(layer, INT32_MIN, INT32_MIN,
-                                    UINT32_MAX, UINT32_MAX);
-}
-
-WL_EXPORT void
-weston_output_schedule_repaint(struct weston_output *output)
-{
-       struct weston_compositor *compositor = output->compositor;
-       struct wl_event_loop *loop;
-
-       if (compositor->state == WESTON_COMPOSITOR_SLEEPING ||
-           compositor->state == WESTON_COMPOSITOR_OFFSCREEN)
-               return;
-
-       if (!output->repaint_needed)
-               TL_POINT("core_repaint_req", TLP_OUTPUT(output), TLP_END);
-
-       loop = wl_display_get_event_loop(compositor->wl_display);
-       output->repaint_needed = 1;
-       if (output->repaint_scheduled)
-               return;
-
-       wl_event_loop_add_idle(loop, idle_repaint, output);
-       output->repaint_scheduled = 1;
-       TL_POINT("core_repaint_enter_loop", TLP_OUTPUT(output), TLP_END);
-}
-
-WL_EXPORT void
-weston_compositor_schedule_repaint(struct weston_compositor *compositor)
-{
-       struct weston_output *output;
-
-       wl_list_for_each(output, &compositor->output_list, link)
-               weston_output_schedule_repaint(output);
-}
-
-static void
-surface_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-surface_attach(struct wl_client *client,
-              struct wl_resource *resource,
-              struct wl_resource *buffer_resource, int32_t sx, int32_t sy)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-       struct weston_buffer *buffer = NULL;
-
-       if (buffer_resource) {
-               buffer = weston_buffer_from_resource(buffer_resource);
-               if (buffer == NULL) {
-                       wl_client_post_no_memory(client);
-                       return;
-               }
-       }
-
-       /* Attach, attach, without commit in between does not send
-        * wl_buffer.release. */
-       weston_surface_state_set_buffer(&surface->pending, buffer);
-
-       surface->pending.sx = sx;
-       surface->pending.sy = sy;
-       surface->pending.newly_attached = 1;
-}
-
-static void
-surface_damage(struct wl_client *client,
-              struct wl_resource *resource,
-              int32_t x, int32_t y, int32_t width, int32_t height)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-
-       if (width <= 0 || height <= 0)
-               return;
-
-       pixman_region32_union_rect(&surface->pending.damage_surface,
-                                  &surface->pending.damage_surface,
-                                  x, y, width, height);
-}
-
-static void
-surface_damage_buffer(struct wl_client *client,
-                     struct wl_resource *resource,
-                     int32_t x, int32_t y, int32_t width, int32_t height)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-
-       if (width <= 0 || height <= 0)
-               return;
-
-       pixman_region32_union_rect(&surface->pending.damage_buffer,
-                                  &surface->pending.damage_buffer,
-                                  x, y, width, height);
-}
-
-static void
-destroy_frame_callback(struct wl_resource *resource)
-{
-       struct weston_frame_callback *cb = wl_resource_get_user_data(resource);
-
-       wl_list_remove(&cb->link);
-       free(cb);
-}
-
-static void
-surface_frame(struct wl_client *client,
-             struct wl_resource *resource, uint32_t callback)
-{
-       struct weston_frame_callback *cb;
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-
-       cb = malloc(sizeof *cb);
-       if (cb == NULL) {
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-
-       cb->resource = wl_resource_create(client, &wl_callback_interface, 1,
-                                         callback);
-       if (cb->resource == NULL) {
-               free(cb);
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-
-       wl_resource_set_implementation(cb->resource, NULL, cb,
-                                      destroy_frame_callback);
-
-       wl_list_insert(surface->pending.frame_callback_list.prev, &cb->link);
-}
-
-static void
-surface_set_opaque_region(struct wl_client *client,
-                         struct wl_resource *resource,
-                         struct wl_resource *region_resource)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-       struct weston_region *region;
-
-       if (region_resource) {
-               region = wl_resource_get_user_data(region_resource);
-               pixman_region32_copy(&surface->pending.opaque,
-                                    &region->region);
-       } else {
-               pixman_region32_clear(&surface->pending.opaque);
-       }
-}
-
-static void
-surface_set_input_region(struct wl_client *client,
-                        struct wl_resource *resource,
-                        struct wl_resource *region_resource)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-       struct weston_region *region;
-
-       if (region_resource) {
-               region = wl_resource_get_user_data(region_resource);
-               pixman_region32_copy(&surface->pending.input,
-                                    &region->region);
-       } else {
-               pixman_region32_fini(&surface->pending.input);
-               region_init_infinite(&surface->pending.input);
-       }
-}
-
-static void
-weston_surface_commit_subsurface_order(struct weston_surface *surface)
-{
-       struct weston_subsurface *sub;
-
-       wl_list_for_each_reverse(sub, &surface->subsurface_list_pending,
-                                parent_link_pending) {
-               wl_list_remove(&sub->parent_link);
-               wl_list_insert(&surface->subsurface_list, &sub->parent_link);
-       }
-}
-
-static void
-weston_surface_build_buffer_matrix(const struct weston_surface *surface,
-                                  struct weston_matrix *matrix)
-{
-       const struct weston_buffer_viewport *vp = &surface->buffer_viewport;
-       double src_width, src_height, dest_width, dest_height;
-
-       weston_matrix_init(matrix);
-
-       if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
-               src_width = surface->width_from_buffer;
-               src_height = surface->height_from_buffer;
-       } else {
-               src_width = wl_fixed_to_double(vp->buffer.src_width);
-               src_height = wl_fixed_to_double(vp->buffer.src_height);
-       }
-
-       if (vp->surface.width == -1) {
-               dest_width = src_width;
-               dest_height = src_height;
-       } else {
-               dest_width = vp->surface.width;
-               dest_height = vp->surface.height;
-       }
-
-       if (src_width != dest_width || src_height != dest_height)
-               weston_matrix_scale(matrix,
-                                   src_width / dest_width,
-                                   src_height / dest_height, 1);
-
-       if (vp->buffer.src_width != wl_fixed_from_int(-1))
-               weston_matrix_translate(matrix,
-                                       wl_fixed_to_double(vp->buffer.src_x),
-                                       wl_fixed_to_double(vp->buffer.src_y),
-                                       0);
-
-       switch (vp->buffer.transform) {
-       case WL_OUTPUT_TRANSFORM_FLIPPED:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
-               weston_matrix_scale(matrix, -1, 1, 1);
-               weston_matrix_translate(matrix,
-                                       surface->width_from_buffer, 0, 0);
-               break;
-       }
-
-       switch (vp->buffer.transform) {
-       default:
-       case WL_OUTPUT_TRANSFORM_NORMAL:
-       case WL_OUTPUT_TRANSFORM_FLIPPED:
-               break;
-       case WL_OUTPUT_TRANSFORM_90:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
-               weston_matrix_rotate_xy(matrix, 0, 1);
-               weston_matrix_translate(matrix,
-                                       surface->height_from_buffer, 0, 0);
-               break;
-       case WL_OUTPUT_TRANSFORM_180:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
-               weston_matrix_rotate_xy(matrix, -1, 0);
-               weston_matrix_translate(matrix,
-                                       surface->width_from_buffer,
-                                       surface->height_from_buffer, 0);
-               break;
-       case WL_OUTPUT_TRANSFORM_270:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
-               weston_matrix_rotate_xy(matrix, 0, -1);
-               weston_matrix_translate(matrix,
-                                       0, surface->width_from_buffer, 0);
-               break;
-       }
-
-       weston_matrix_scale(matrix, vp->buffer.scale, vp->buffer.scale, 1);
-}
-
-/**
- * Compute a + b > c while being safe to overflows.
- */
-static bool
-fixed_sum_gt(wl_fixed_t a, wl_fixed_t b, wl_fixed_t c)
-{
-       return (int64_t)a + (int64_t)b > (int64_t)c;
-}
-
-static bool
-weston_surface_is_pending_viewport_source_valid(
-       const struct weston_surface *surface)
-{
-       const struct weston_surface_state *pend = &surface->pending;
-       const struct weston_buffer_viewport *vp = &pend->buffer_viewport;
-       int width_from_buffer = 0;
-       int height_from_buffer = 0;
-       wl_fixed_t w;
-       wl_fixed_t h;
-
-       /* If viewport source rect is not set, it is always ok. */
-       if (vp->buffer.src_width == wl_fixed_from_int(-1))
-               return true;
-
-       if (pend->newly_attached) {
-               if (pend->buffer) {
-                       convert_size_by_transform_scale(&width_from_buffer,
-                                                       &height_from_buffer,
-                                                       pend->buffer->width,
-                                                       pend->buffer->height,
-                                                       vp->buffer.transform,
-                                                       vp->buffer.scale);
-               } else {
-                       /* No buffer: viewport is irrelevant. */
-                       return true;
-               }
-       } else {
-               width_from_buffer = surface->width_from_buffer;
-               height_from_buffer = surface->height_from_buffer;
-       }
-
-       assert((width_from_buffer == 0) == (height_from_buffer == 0));
-       assert(width_from_buffer >= 0 && height_from_buffer >= 0);
-
-       /* No buffer: viewport is irrelevant. */
-       if (width_from_buffer == 0 || height_from_buffer == 0)
-               return true;
-
-       /* overflow checks for wl_fixed_from_int() */
-       if (width_from_buffer > wl_fixed_to_int(INT32_MAX))
-               return false;
-       if (height_from_buffer > wl_fixed_to_int(INT32_MAX))
-               return false;
-
-       w = wl_fixed_from_int(width_from_buffer);
-       h = wl_fixed_from_int(height_from_buffer);
-
-       if (fixed_sum_gt(vp->buffer.src_x, vp->buffer.src_width, w))
-               return false;
-       if (fixed_sum_gt(vp->buffer.src_y, vp->buffer.src_height, h))
-               return false;
-
-       return true;
-}
-
-static bool
-fixed_is_integer(wl_fixed_t v)
-{
-       return (v & 0xff) == 0;
-}
-
-static bool
-weston_surface_is_pending_viewport_dst_size_int(
-       const struct weston_surface *surface)
-{
-       const struct weston_buffer_viewport *vp =
-               &surface->pending.buffer_viewport;
-
-       if (vp->surface.width != -1) {
-               assert(vp->surface.width > 0 && vp->surface.height > 0);
-               return true;
-       }
-
-       return fixed_is_integer(vp->buffer.src_width) &&
-              fixed_is_integer(vp->buffer.src_height);
-}
-
-/* Translate pending damage in buffer co-ordinates to surface
- * co-ordinates and union it with a pixman_region32_t.
- * This should only be called after the buffer is attached.
- */
-static void
-apply_damage_buffer(pixman_region32_t *dest,
-                   struct weston_surface *surface,
-                   struct weston_surface_state *state)
-{
-       struct weston_buffer *buffer = surface->buffer_ref.buffer;
-
-       /* wl_surface.damage_buffer needs to be clipped to the buffer,
-        * translated into surface co-ordinates and unioned with
-        * any other surface damage.
-        * None of this makes sense if there is no buffer though.
-        */
-       if (buffer && pixman_region32_not_empty(&state->damage_buffer)) {
-               pixman_region32_t buffer_damage;
-
-               pixman_region32_intersect_rect(&state->damage_buffer,
-                                              &state->damage_buffer,
-                                              0, 0, buffer->width,
-                                              buffer->height);
-               pixman_region32_init(&buffer_damage);
-               weston_matrix_transform_region(&buffer_damage,
-                                              &surface->buffer_to_surface_matrix,
-                                              &state->damage_buffer);
-               pixman_region32_union(dest, dest, &buffer_damage);
-               pixman_region32_fini(&buffer_damage);
-       }
-       /* We should clear this on commit even if there was no buffer */
-       pixman_region32_clear(&state->damage_buffer);
-}
-
-static void
-weston_surface_commit_state(struct weston_surface *surface,
-                           struct weston_surface_state *state)
-{
-       struct weston_view *view;
-       pixman_region32_t opaque;
-
-       /* wl_surface.set_buffer_transform */
-       /* wl_surface.set_buffer_scale */
-       /* wp_viewport.set_source */
-       /* wp_viewport.set_destination */
-       surface->buffer_viewport = state->buffer_viewport;
-
-       /* wl_surface.attach */
-       if (state->newly_attached)
-               weston_surface_attach(surface, state->buffer);
-       weston_surface_state_set_buffer(state, NULL);
-
-       weston_surface_build_buffer_matrix(surface,
-                                          &surface->surface_to_buffer_matrix);
-       weston_matrix_invert(&surface->buffer_to_surface_matrix,
-                            &surface->surface_to_buffer_matrix);
-
-       if (state->newly_attached || state->buffer_viewport.changed) {
-               weston_surface_update_size(surface);
-               if (surface->configure)
-                       surface->configure(surface, state->sx, state->sy);
-       }
-
-       state->sx = 0;
-       state->sy = 0;
-       state->newly_attached = 0;
-       state->buffer_viewport.changed = 0;
-
-       /* wl_surface.damage and wl_surface.damage_buffer */
-       if (weston_timeline_enabled_ &&
-           (pixman_region32_not_empty(&state->damage_surface) ||
-            pixman_region32_not_empty(&state->damage_buffer)))
-               TL_POINT("core_commit_damage", TLP_SURFACE(surface), TLP_END);
-
-       pixman_region32_union(&surface->damage, &surface->damage,
-                             &state->damage_surface);
-
-       apply_damage_buffer(&surface->damage, surface, state);
-
-       pixman_region32_intersect_rect(&surface->damage, &surface->damage,
-                                      0, 0, surface->width, surface->height);
-       pixman_region32_clear(&state->damage_surface);
-
-       /* wl_surface.set_opaque_region */
-       pixman_region32_init(&opaque);
-       pixman_region32_intersect_rect(&opaque, &state->opaque,
-                                      0, 0, surface->width, surface->height);
-
-       if (!pixman_region32_equal(&opaque, &surface->opaque)) {
-               pixman_region32_copy(&surface->opaque, &opaque);
-               wl_list_for_each(view, &surface->views, surface_link)
-                       weston_view_geometry_dirty(view);
-       }
-
-       pixman_region32_fini(&opaque);
-
-       /* wl_surface.set_input_region */
-       pixman_region32_intersect_rect(&surface->input, &state->input,
-                                      0, 0, surface->width, surface->height);
-
-       /* wl_surface.frame */
-       wl_list_insert_list(&surface->frame_callback_list,
-                           &state->frame_callback_list);
-       wl_list_init(&state->frame_callback_list);
-
-       /* XXX:
-        * What should happen with a feedback request, if there
-        * is no wl_buffer attached for this commit?
-        */
-
-       /* presentation.feedback */
-       wl_list_insert_list(&surface->feedback_list,
-                           &state->feedback_list);
-       wl_list_init(&state->feedback_list);
-}
-
-static void
-weston_surface_commit(struct weston_surface *surface)
-{
-       weston_surface_commit_state(surface, &surface->pending);
-
-       weston_surface_commit_subsurface_order(surface);
-
-       weston_surface_schedule_repaint(surface);
-}
-
-static void
-weston_subsurface_commit(struct weston_subsurface *sub);
-
-static void
-weston_subsurface_parent_commit(struct weston_subsurface *sub,
-                               int parent_is_synchronized);
-
-static void
-surface_commit(struct wl_client *client, struct wl_resource *resource)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-       struct weston_subsurface *sub = weston_surface_to_subsurface(surface);
-
-       if (!weston_surface_is_pending_viewport_source_valid(surface)) {
-               assert(surface->viewport_resource);
-
-               wl_resource_post_error(surface->viewport_resource,
-                       WP_VIEWPORT_ERROR_OUT_OF_BUFFER,
-                       "wl_surface@%d has viewport source outside buffer",
-                       wl_resource_get_id(resource));
-               return;
-       }
-
-       if (!weston_surface_is_pending_viewport_dst_size_int(surface)) {
-               assert(surface->viewport_resource);
-
-               wl_resource_post_error(surface->viewport_resource,
-                       WP_VIEWPORT_ERROR_BAD_SIZE,
-                       "wl_surface@%d viewport dst size not integer",
-                       wl_resource_get_id(resource));
-               return;
-       }
-
-       if (sub) {
-               weston_subsurface_commit(sub);
-               return;
-       }
-
-       weston_surface_commit(surface);
-
-       wl_list_for_each(sub, &surface->subsurface_list, parent_link) {
-               if (sub->surface != surface)
-                       weston_subsurface_parent_commit(sub, 0);
-       }
-}
-
-static void
-surface_set_buffer_transform(struct wl_client *client,
-                            struct wl_resource *resource, int transform)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-
-       /* if wl_output.transform grows more members this will need to be updated. */
-       if (transform < 0 ||
-           transform > WL_OUTPUT_TRANSFORM_FLIPPED_270) {
-               wl_resource_post_error(resource,
-                       WL_SURFACE_ERROR_INVALID_TRANSFORM,
-                       "buffer transform must be a valid transform "
-                       "('%d' specified)", transform);
-               return;
-       }
-
-       surface->pending.buffer_viewport.buffer.transform = transform;
-       surface->pending.buffer_viewport.changed = 1;
-}
-
-static void
-surface_set_buffer_scale(struct wl_client *client,
-                        struct wl_resource *resource,
-                        int32_t scale)
-{
-       struct weston_surface *surface = wl_resource_get_user_data(resource);
-
-       if (scale < 1) {
-               wl_resource_post_error(resource,
-                       WL_SURFACE_ERROR_INVALID_SCALE,
-                       "buffer scale must be at least one "
-                       "('%d' specified)", scale);
-               return;
-       }
-
-       surface->pending.buffer_viewport.buffer.scale = scale;
-       surface->pending.buffer_viewport.changed = 1;
-}
-
-static const struct wl_surface_interface surface_interface = {
-       surface_destroy,
-       surface_attach,
-       surface_damage,
-       surface_frame,
-       surface_set_opaque_region,
-       surface_set_input_region,
-       surface_commit,
-       surface_set_buffer_transform,
-       surface_set_buffer_scale,
-       surface_damage_buffer
-};
-
-static void
-compositor_create_surface(struct wl_client *client,
-                         struct wl_resource *resource, uint32_t id)
-{
-       struct weston_compositor *ec = wl_resource_get_user_data(resource);
-       struct weston_surface *surface;
-
-       surface = weston_surface_create(ec);
-       if (surface == NULL) {
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-
-       surface->resource =
-               wl_resource_create(client, &wl_surface_interface,
-                                  wl_resource_get_version(resource), id);
-       if (surface->resource == NULL) {
-               weston_surface_destroy(surface);
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-       wl_resource_set_implementation(surface->resource, &surface_interface,
-                                      surface, destroy_surface);
-
-       wl_signal_emit(&ec->create_surface_signal, surface);
-}
-
-static void
-destroy_region(struct wl_resource *resource)
-{
-       struct weston_region *region = wl_resource_get_user_data(resource);
-
-       pixman_region32_fini(&region->region);
-       free(region);
-}
-
-static void
-region_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-region_add(struct wl_client *client, struct wl_resource *resource,
-          int32_t x, int32_t y, int32_t width, int32_t height)
-{
-       struct weston_region *region = wl_resource_get_user_data(resource);
-
-       pixman_region32_union_rect(&region->region, &region->region,
-                                  x, y, width, height);
-}
-
-static void
-region_subtract(struct wl_client *client, struct wl_resource *resource,
-               int32_t x, int32_t y, int32_t width, int32_t height)
-{
-       struct weston_region *region = wl_resource_get_user_data(resource);
-       pixman_region32_t rect;
-
-       pixman_region32_init_rect(&rect, x, y, width, height);
-       pixman_region32_subtract(&region->region, &region->region, &rect);
-       pixman_region32_fini(&rect);
-}
-
-static const struct wl_region_interface region_interface = {
-       region_destroy,
-       region_add,
-       region_subtract
-};
-
-static void
-compositor_create_region(struct wl_client *client,
-                        struct wl_resource *resource, uint32_t id)
-{
-       struct weston_region *region;
-
-       region = malloc(sizeof *region);
-       if (region == NULL) {
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-
-       pixman_region32_init(&region->region);
-
-       region->resource =
-               wl_resource_create(client, &wl_region_interface, 1, id);
-       if (region->resource == NULL) {
-               free(region);
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-       wl_resource_set_implementation(region->resource, &region_interface,
-                                      region, destroy_region);
-}
-
-static const struct wl_compositor_interface compositor_interface = {
-       compositor_create_surface,
-       compositor_create_region
-};
-
-static void
-weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
-{
-       struct weston_surface *surface = sub->surface;
-
-       weston_surface_commit_state(surface, &sub->cached);
-       weston_buffer_reference(&sub->cached_buffer_ref, NULL);
-
-       weston_surface_commit_subsurface_order(surface);
-
-       weston_surface_schedule_repaint(surface);
-
-       sub->has_cached_data = 0;
-}
-
-static void
-weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
-{
-       struct weston_surface *surface = sub->surface;
-
-       /*
-        * If this commit would cause the surface to move by the
-        * attach(dx, dy) parameters, the old damage region must be
-        * translated to correspond to the new surface coordinate system
-        * origin.
-        */
-       pixman_region32_translate(&sub->cached.damage_surface,
-                                 -surface->pending.sx, -surface->pending.sy);
-       pixman_region32_union(&sub->cached.damage_surface,
-                             &sub->cached.damage_surface,
-                             &surface->pending.damage_surface);
-       pixman_region32_clear(&surface->pending.damage_surface);
-
-       if (surface->pending.newly_attached) {
-               sub->cached.newly_attached = 1;
-               weston_surface_state_set_buffer(&sub->cached,
-                                               surface->pending.buffer);
-               weston_buffer_reference(&sub->cached_buffer_ref,
-                                       surface->pending.buffer);
-               weston_presentation_feedback_discard_list(
-                                       &sub->cached.feedback_list);
-       }
-       sub->cached.sx += surface->pending.sx;
-       sub->cached.sy += surface->pending.sy;
-
-       apply_damage_buffer(&sub->cached.damage_surface, surface, &surface->pending);
-
-       sub->cached.buffer_viewport.changed |=
-               surface->pending.buffer_viewport.changed;
-       sub->cached.buffer_viewport.buffer =
-               surface->pending.buffer_viewport.buffer;
-       sub->cached.buffer_viewport.surface =
-               surface->pending.buffer_viewport.surface;
-
-       weston_surface_reset_pending_buffer(surface);
-
-       pixman_region32_copy(&sub->cached.opaque, &surface->pending.opaque);
-
-       pixman_region32_copy(&sub->cached.input, &surface->pending.input);
-
-       wl_list_insert_list(&sub->cached.frame_callback_list,
-                           &surface->pending.frame_callback_list);
-       wl_list_init(&surface->pending.frame_callback_list);
-
-       wl_list_insert_list(&sub->cached.feedback_list,
-                           &surface->pending.feedback_list);
-       wl_list_init(&surface->pending.feedback_list);
-
-       sub->has_cached_data = 1;
-}
-
-static bool
-weston_subsurface_is_synchronized(struct weston_subsurface *sub)
-{
-       while (sub) {
-               if (sub->synchronized)
-                       return true;
-
-               if (!sub->parent)
-                       return false;
-
-               sub = weston_surface_to_subsurface(sub->parent);
-       }
-
-       return false;
-}
-
-static void
-weston_subsurface_commit(struct weston_subsurface *sub)
-{
-       struct weston_surface *surface = sub->surface;
-       struct weston_subsurface *tmp;
-
-       /* Recursive check for effectively synchronized. */
-       if (weston_subsurface_is_synchronized(sub)) {
-               weston_subsurface_commit_to_cache(sub);
-       } else {
-               if (sub->has_cached_data) {
-                       /* flush accumulated state from cache */
-                       weston_subsurface_commit_to_cache(sub);
-                       weston_subsurface_commit_from_cache(sub);
-               } else {
-                       weston_surface_commit(surface);
-               }
-
-               wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
-                       if (tmp->surface != surface)
-                               weston_subsurface_parent_commit(tmp, 0);
-               }
-       }
-}
-
-static void
-weston_subsurface_synchronized_commit(struct weston_subsurface *sub)
-{
-       struct weston_surface *surface = sub->surface;
-       struct weston_subsurface *tmp;
-
-       /* From now on, commit_from_cache the whole sub-tree, regardless of
-        * the synchronized mode of each child. This sub-surface or some
-        * of its ancestors were synchronized, so we are synchronized
-        * all the way down.
-        */
-
-       if (sub->has_cached_data)
-               weston_subsurface_commit_from_cache(sub);
-
-       wl_list_for_each(tmp, &surface->subsurface_list, parent_link) {
-               if (tmp->surface != surface)
-                       weston_subsurface_parent_commit(tmp, 1);
-       }
-}
-
-static void
-weston_subsurface_parent_commit(struct weston_subsurface *sub,
-                               int parent_is_synchronized)
-{
-       struct weston_view *view;
-       if (sub->position.set) {
-               wl_list_for_each(view, &sub->surface->views, surface_link)
-                       weston_view_set_position(view,
-                                                sub->position.x,
-                                                sub->position.y);
-
-               sub->position.set = 0;
-       }
-
-       if (parent_is_synchronized || sub->synchronized)
-               weston_subsurface_synchronized_commit(sub);
-}
-
-static int
-subsurface_get_label(struct weston_surface *surface, char *buf, size_t len)
-{
-       return snprintf(buf, len, "sub-surface");
-}
-
-static void
-subsurface_configure(struct weston_surface *surface, int32_t dx, int32_t dy)
-{
-       struct weston_compositor *compositor = surface->compositor;
-       struct weston_view *view;
-
-       wl_list_for_each(view, &surface->views, surface_link)
-               weston_view_set_position(view,
-                                        view->geometry.x + dx,
-                                        view->geometry.y + dy);
-
-       /* No need to check parent mappedness, because if parent is not
-        * mapped, parent is not in a visible layer, so this sub-surface
-        * will not be drawn either.
-        */
-       if (!weston_surface_is_mapped(surface)) {
-               struct weston_output *output;
-
-               /* Cannot call weston_view_update_transform(),
-                * because that would call it also for the parent surface,
-                * which might not be mapped yet. That would lead to
-                * inconsistent state, where the window could never be
-                * mapped.
-                *
-                * Instead just assign any output, to make
-                * weston_surface_is_mapped() return true, so that when the
-                * parent surface does get mapped, this one will get
-                * included, too. See view_list_add().
-                */
-               assert(!wl_list_empty(&compositor->output_list));
-               output = container_of(compositor->output_list.next,
-                                     struct weston_output, link);
-
-               surface->output = output;
-               weston_surface_update_output_mask(surface, 1u << output->id);
-       }
-}
-
-static struct weston_subsurface *
-weston_surface_to_subsurface(struct weston_surface *surface)
-{
-       if (surface->configure == subsurface_configure)
-               return surface->configure_private;
-
-       return NULL;
-}
-
-WL_EXPORT struct weston_surface *
-weston_surface_get_main_surface(struct weston_surface *surface)
-{
-       struct weston_subsurface *sub;
-
-       while (surface && (sub = weston_surface_to_subsurface(surface)))
-               surface = sub->parent;
-
-       return surface;
-}
-
-WL_EXPORT int
-weston_surface_set_role(struct weston_surface *surface,
-                       const char *role_name,
-                       struct wl_resource *error_resource,
-                       uint32_t error_code)
-{
-       assert(role_name);
-
-       if (surface->role_name == NULL ||
-           surface->role_name == role_name ||
-           strcmp(surface->role_name, role_name) == 0) {
-               surface->role_name = role_name;
-
-               return 0;
-       }
-
-       wl_resource_post_error(error_resource, error_code,
-                              "Cannot assign role %s to wl_surface@%d,"
-                              " already has role %s\n",
-                              role_name,
-                              wl_resource_get_id(surface->resource),
-                              surface->role_name);
-       return -1;
-}
-
-WL_EXPORT void
-weston_surface_set_label_func(struct weston_surface *surface,
-                             int (*desc)(struct weston_surface *,
-                                         char *, size_t))
-{
-       surface->get_label = desc;
-       surface->timeline.force_refresh = 1;
-}
-
-/** Get the size of surface contents
- *
- * \param surface The surface to query.
- * \param width Returns the width of raw contents.
- * \param height Returns the height of raw contents.
- *
- * Retrieves the raw surface content size in pixels for the given surface.
- * This is the whole content size in buffer pixels. If the surface
- * has no content or the renderer does not implement this feature,
- * zeroes are returned.
- *
- * This function is used to determine the buffer size needed for
- * a weston_surface_copy_content() call.
- */
-WL_EXPORT void
-weston_surface_get_content_size(struct weston_surface *surface,
-                               int *width, int *height)
-{
-       struct weston_renderer *rer = surface->compositor->renderer;
-
-       if (!rer->surface_get_content_size) {
-               *width = 0;
-               *height = 0;
-               return;
-       }
-
-       rer->surface_get_content_size(surface, width, height);
-}
-
-/** Copy surface contents to system memory.
- *
- * \param surface The surface to copy from.
- * \param target Pointer to the target memory buffer.
- * \param size Size of the target buffer in bytes.
- * \param src_x X location on contents to copy from.
- * \param src_y Y location on contents to copy from.
- * \param width Width in pixels of the area to copy.
- * \param height Height in pixels of the area to copy.
- * \return 0 for success, -1 for failure.
- *
- * Surface contents are maintained by the renderer. They can be in a
- * reserved weston_buffer or as a copy, e.g. a GL texture, or something
- * else.
- *
- * Surface contents are copied into memory pointed to by target,
- * which has size bytes of space available. The target memory
- * may be larger than needed, but being smaller returns an error.
- * The extra bytes in target may or may not be written; their content is
- * unspecified. Size must be large enough to hold the image.
- *
- * The image in the target memory will be arranged in rows from
- * top to bottom, and pixels on a row from left to right. The pixel
- * format is PIXMAN_a8b8g8r8, 4 bytes per pixel, and stride is exactly
- * width * 4.
- *
- * Parameters src_x and src_y define the upper-left corner in buffer
- * coordinates (pixels) to copy from. Parameters width and height
- * define the size of the area to copy in pixels.
- *
- * The rectangle defined by src_x, src_y, width, height must fit in
- * the surface contents. Otherwise an error is returned.
- *
- * Use surface_get_data_size to determine the content size; the
- * needed target buffer size and rectangle limits.
- *
- * CURRENT IMPLEMENTATION RESTRICTIONS:
- * - the machine must be little-endian due to Pixman formats.
- *
- * NOTE: Pixman formats are premultiplied.
- */
-WL_EXPORT int
-weston_surface_copy_content(struct weston_surface *surface,
-                           void *target, size_t size,
-                           int src_x, int src_y,
-                           int width, int height)
-{
-       struct weston_renderer *rer = surface->compositor->renderer;
-       int cw, ch;
-       const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
-
-       if (!rer->surface_copy_content)
-               return -1;
-
-       weston_surface_get_content_size(surface, &cw, &ch);
-
-       if (src_x < 0 || src_y < 0)
-               return -1;
-
-       if (width <= 0 || height <= 0)
-               return -1;
-
-       if (src_x + width > cw || src_y + height > ch)
-               return -1;
-
-       if (width * bytespp * height > size)
-               return -1;
-
-       return rer->surface_copy_content(surface, target, size,
-                                        src_x, src_y, width, height);
-}
-
-static void
-subsurface_set_position(struct wl_client *client,
-                       struct wl_resource *resource, int32_t x, int32_t y)
-{
-       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-
-       if (!sub)
-               return;
-
-       sub->position.x = x;
-       sub->position.y = y;
-       sub->position.set = 1;
-}
-
-static struct weston_subsurface *
-subsurface_from_surface(struct weston_surface *surface)
-{
-       struct weston_subsurface *sub;
-
-       sub = weston_surface_to_subsurface(surface);
-       if (sub)
-               return sub;
-
-       wl_list_for_each(sub, &surface->subsurface_list, parent_link)
-               if (sub->surface == surface)
-                       return sub;
-
-       return NULL;
-}
-
-static struct weston_subsurface *
-subsurface_sibling_check(struct weston_subsurface *sub,
-                        struct weston_surface *surface,
-                        const char *request)
-{
-       struct weston_subsurface *sibling;
-
-       sibling = subsurface_from_surface(surface);
-
-       if (!sibling) {
-               wl_resource_post_error(sub->resource,
-                       WL_SUBSURFACE_ERROR_BAD_SURFACE,
-                       "%s: wl_surface@%d is not a parent or sibling",
-                       request, wl_resource_get_id(surface->resource));
-               return NULL;
-       }
-
-       if (sibling->parent != sub->parent) {
-               wl_resource_post_error(sub->resource,
-                       WL_SUBSURFACE_ERROR_BAD_SURFACE,
-                       "%s: wl_surface@%d has a different parent",
-                       request, wl_resource_get_id(surface->resource));
-               return NULL;
-       }
-
-       return sibling;
-}
-
-static void
-subsurface_place_above(struct wl_client *client,
-                      struct wl_resource *resource,
-                      struct wl_resource *sibling_resource)
-{
-       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-       struct weston_surface *surface =
-               wl_resource_get_user_data(sibling_resource);
-       struct weston_subsurface *sibling;
-
-       if (!sub)
-               return;
-
-       sibling = subsurface_sibling_check(sub, surface, "place_above");
-       if (!sibling)
-               return;
-
-       wl_list_remove(&sub->parent_link_pending);
-       wl_list_insert(sibling->parent_link_pending.prev,
-                      &sub->parent_link_pending);
-}
-
-static void
-subsurface_place_below(struct wl_client *client,
-                      struct wl_resource *resource,
-                      struct wl_resource *sibling_resource)
-{
-       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-       struct weston_surface *surface =
-               wl_resource_get_user_data(sibling_resource);
-       struct weston_subsurface *sibling;
-
-       if (!sub)
-               return;
-
-       sibling = subsurface_sibling_check(sub, surface, "place_below");
-       if (!sibling)
-               return;
-
-       wl_list_remove(&sub->parent_link_pending);
-       wl_list_insert(&sibling->parent_link_pending,
-                      &sub->parent_link_pending);
-}
-
-static void
-subsurface_set_sync(struct wl_client *client, struct wl_resource *resource)
-{
-       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-
-       if (sub)
-               sub->synchronized = 1;
-}
-
-static void
-subsurface_set_desync(struct wl_client *client, struct wl_resource *resource)
-{
-       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-
-       if (sub && sub->synchronized) {
-               sub->synchronized = 0;
-
-               /* If sub became effectively desynchronized, flush. */
-               if (!weston_subsurface_is_synchronized(sub))
-                       weston_subsurface_synchronized_commit(sub);
-       }
-}
-
-static void
-weston_subsurface_unlink_parent(struct weston_subsurface *sub)
-{
-       wl_list_remove(&sub->parent_link);
-       wl_list_remove(&sub->parent_link_pending);
-       wl_list_remove(&sub->parent_destroy_listener.link);
-       sub->parent = NULL;
-}
-
-static void
-weston_subsurface_destroy(struct weston_subsurface *sub);
-
-static void
-subsurface_handle_surface_destroy(struct wl_listener *listener, void *data)
-{
-       struct weston_subsurface *sub =
-               container_of(listener, struct weston_subsurface,
-                            surface_destroy_listener);
-       assert(data == sub->surface);
-
-       /* The protocol object (wl_resource) is left inert. */
-       if (sub->resource)
-               wl_resource_set_user_data(sub->resource, NULL);
-
-       weston_subsurface_destroy(sub);
-}
-
-static void
-subsurface_handle_parent_destroy(struct wl_listener *listener, void *data)
-{
-       struct weston_subsurface *sub =
-               container_of(listener, struct weston_subsurface,
-                            parent_destroy_listener);
-       assert(data == sub->parent);
-       assert(sub->surface != sub->parent);
-
-       if (weston_surface_is_mapped(sub->surface))
-               weston_surface_unmap(sub->surface);
-
-       weston_subsurface_unlink_parent(sub);
-}
-
-static void
-subsurface_resource_destroy(struct wl_resource *resource)
-{
-       struct weston_subsurface *sub = wl_resource_get_user_data(resource);
-
-       if (sub)
-               weston_subsurface_destroy(sub);
-}
-
-static void
-subsurface_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-weston_subsurface_link_parent(struct weston_subsurface *sub,
-                             struct weston_surface *parent)
-{
-       sub->parent = parent;
-       sub->parent_destroy_listener.notify = subsurface_handle_parent_destroy;
-       wl_signal_add(&parent->destroy_signal,
-                     &sub->parent_destroy_listener);
-
-       wl_list_insert(&parent->subsurface_list, &sub->parent_link);
-       wl_list_insert(&parent->subsurface_list_pending,
-                      &sub->parent_link_pending);
-}
-
-static void
-weston_subsurface_link_surface(struct weston_subsurface *sub,
-                              struct weston_surface *surface)
-{
-       sub->surface = surface;
-       sub->surface_destroy_listener.notify =
-               subsurface_handle_surface_destroy;
-       wl_signal_add(&surface->destroy_signal,
-                     &sub->surface_destroy_listener);
-}
-
-static void
-weston_subsurface_destroy(struct weston_subsurface *sub)
-{
-       struct weston_view *view, *next;
-
-       assert(sub->surface);
-
-       if (sub->resource) {
-               assert(weston_surface_to_subsurface(sub->surface) == sub);
-               assert(sub->parent_destroy_listener.notify ==
-                      subsurface_handle_parent_destroy);
-
-               wl_list_for_each_safe(view, next, &sub->surface->views, surface_link) {
-                       weston_view_unmap(view);
-                       weston_view_destroy(view);
-               }
-
-               if (sub->parent)
-                       weston_subsurface_unlink_parent(sub);
-
-               weston_surface_state_fini(&sub->cached);
-               weston_buffer_reference(&sub->cached_buffer_ref, NULL);
-
-               sub->surface->configure = NULL;
-               sub->surface->configure_private = NULL;
-               weston_surface_set_label_func(sub->surface, NULL);
-       } else {
-               /* the dummy weston_subsurface for the parent itself */
-               assert(sub->parent_destroy_listener.notify == NULL);
-               wl_list_remove(&sub->parent_link);
-               wl_list_remove(&sub->parent_link_pending);
-       }
-
-       wl_list_remove(&sub->surface_destroy_listener.link);
-       free(sub);
-}
-
-static const struct wl_subsurface_interface subsurface_implementation = {
-       subsurface_destroy,
-       subsurface_set_position,
-       subsurface_place_above,
-       subsurface_place_below,
-       subsurface_set_sync,
-       subsurface_set_desync
-};
-
-static struct weston_subsurface *
-weston_subsurface_create(uint32_t id, struct weston_surface *surface,
-                        struct weston_surface *parent)
-{
-       struct weston_subsurface *sub;
-       struct wl_client *client = wl_resource_get_client(surface->resource);
-
-       sub = zalloc(sizeof *sub);
-       if (sub == NULL)
-               return NULL;
-
-       wl_list_init(&sub->unused_views);
-
-       sub->resource =
-               wl_resource_create(client, &wl_subsurface_interface, 1, id);
-       if (!sub->resource) {
-               free(sub);
-               return NULL;
-       }
-
-       wl_resource_set_implementation(sub->resource,
-                                      &subsurface_implementation,
-                                      sub, subsurface_resource_destroy);
-       weston_subsurface_link_surface(sub, surface);
-       weston_subsurface_link_parent(sub, parent);
-       weston_surface_state_init(&sub->cached);
-       sub->cached_buffer_ref.buffer = NULL;
-       sub->synchronized = 1;
-
-       return sub;
-}
-
-/* Create a dummy subsurface for having the parent itself in its
- * sub-surface lists. Makes stacking order manipulation easy.
- */
-static struct weston_subsurface *
-weston_subsurface_create_for_parent(struct weston_surface *parent)
-{
-       struct weston_subsurface *sub;
-
-       sub = zalloc(sizeof *sub);
-       if (sub == NULL)
-               return NULL;
-
-       weston_subsurface_link_surface(sub, parent);
-       sub->parent = parent;
-       wl_list_insert(&parent->subsurface_list, &sub->parent_link);
-       wl_list_insert(&parent->subsurface_list_pending,
-                      &sub->parent_link_pending);
-
-       return sub;
-}
-
-static void
-subcompositor_get_subsurface(struct wl_client *client,
-                            struct wl_resource *resource,
-                            uint32_t id,
-                            struct wl_resource *surface_resource,
-                            struct wl_resource *parent_resource)
-{
-       struct weston_surface *surface =
-               wl_resource_get_user_data(surface_resource);
-       struct weston_surface *parent =
-               wl_resource_get_user_data(parent_resource);
-       struct weston_subsurface *sub;
-       static const char where[] = "get_subsurface: wl_subsurface@";
-
-       if (surface == parent) {
-               wl_resource_post_error(resource,
-                       WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
-                       "%s%d: wl_surface@%d cannot be its own parent",
-                       where, id, wl_resource_get_id(surface_resource));
-               return;
-       }
-
-       if (weston_surface_to_subsurface(surface)) {
-               wl_resource_post_error(resource,
-                       WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
-                       "%s%d: wl_surface@%d is already a sub-surface",
-                       where, id, wl_resource_get_id(surface_resource));
-               return;
-       }
-
-       if (weston_surface_set_role(surface, "wl_subsurface", resource,
-                                   WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE) < 0)
-               return;
-
-       if (weston_surface_get_main_surface(parent) == surface) {
-               wl_resource_post_error(resource,
-                       WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE,
-                       "%s%d: wl_surface@%d is an ancestor of parent",
-                       where, id, wl_resource_get_id(surface_resource));
-               return;
-       }
-
-       /* make sure the parent is in its own list */
-       if (wl_list_empty(&parent->subsurface_list)) {
-               if (!weston_subsurface_create_for_parent(parent)) {
-                       wl_resource_post_no_memory(resource);
-                       return;
-               }
-       }
-
-       sub = weston_subsurface_create(id, surface, parent);
-       if (!sub) {
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-
-       surface->configure = subsurface_configure;
-       surface->configure_private = sub;
-       weston_surface_set_label_func(surface, subsurface_get_label);
-}
-
-static void
-subcompositor_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static const struct wl_subcompositor_interface subcompositor_interface = {
-       subcompositor_destroy,
-       subcompositor_get_subsurface
-};
-
-static void
-bind_subcompositor(struct wl_client *client,
-                  void *data, uint32_t version, uint32_t id)
-{
-       struct weston_compositor *compositor = data;
-       struct wl_resource *resource;
-
-       resource =
-               wl_resource_create(client, &wl_subcompositor_interface, 1, id);
-       if (resource == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-       wl_resource_set_implementation(resource, &subcompositor_interface,
-                                      compositor, NULL);
-}
-
-/** Set a DPMS mode on all of the compositor's outputs
- *
- * \param compositor The compositor instance
- * \param state The DPMS state the outputs will be set to
- */
-static void
-weston_compositor_dpms(struct weston_compositor *compositor,
-                      enum dpms_enum state)
-{
-        struct weston_output *output;
-
-        wl_list_for_each(output, &compositor->output_list, link)
-               if (output->set_dpms)
-                       output->set_dpms(output, state);
-}
-
-/** Restores the compositor to active status
- *
- * \param compositor The compositor instance
- *
- * If the compositor was in a sleeping mode, all outputs are powered
- * back on via DPMS.  Otherwise if the compositor was inactive
- * (idle/locked, offscreen, or sleeping) then the compositor's wake
- * signal will fire.
- *
- * Restarts the idle timer.
- */
-WL_EXPORT void
-weston_compositor_wake(struct weston_compositor *compositor)
-{
-       uint32_t old_state = compositor->state;
-
-       /* The state needs to be changed before emitting the wake
-        * signal because that may try to schedule a repaint which
-        * will not work if the compositor is still sleeping */
-       compositor->state = WESTON_COMPOSITOR_ACTIVE;
-
-       switch (old_state) {
-       case WESTON_COMPOSITOR_SLEEPING:
-               weston_compositor_dpms(compositor, WESTON_DPMS_ON);
-               /* fall through */
-       case WESTON_COMPOSITOR_IDLE:
-       case WESTON_COMPOSITOR_OFFSCREEN:
-               wl_signal_emit(&compositor->wake_signal, compositor);
-               /* fall through */
-       default:
-               wl_event_source_timer_update(compositor->idle_source,
-                                            compositor->idle_time * 1000);
-       }
-}
-
-/** Turns off rendering and frame events for the compositor.
- *
- * \param compositor The compositor instance
- *
- * This is used for example to prevent further rendering while the
- * compositor is shutting down.
- *
- * \note When offscreen state is entered, outputs will be powered
- * back on if they were sleeping (in DPMS off mode), even though
- * no rendering will be performed.
- *
- * Stops the idle timer.
- */
-WL_EXPORT void
-weston_compositor_offscreen(struct weston_compositor *compositor)
-{
-       switch (compositor->state) {
-       case WESTON_COMPOSITOR_OFFSCREEN:
-               return;
-       case WESTON_COMPOSITOR_SLEEPING:
-               weston_compositor_dpms(compositor, WESTON_DPMS_ON);
-               /* fall through */
-       default:
-               compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
-               wl_event_source_timer_update(compositor->idle_source, 0);
-       }
-}
-
-/** Powers down all attached output devices
- *
- * \param compositor The compositor instance
- *
- * Causes rendering to the outputs to cease, and no frame events to be
- * sent.  Only powers down the outputs if the compositor is not already
- * in sleep mode.
- *
- * Stops the idle timer.
- */
-WL_EXPORT void
-weston_compositor_sleep(struct weston_compositor *compositor)
-{
-       if (compositor->state == WESTON_COMPOSITOR_SLEEPING)
-               return;
-
-       wl_event_source_timer_update(compositor->idle_source, 0);
-       compositor->state = WESTON_COMPOSITOR_SLEEPING;
-       weston_compositor_dpms(compositor, WESTON_DPMS_OFF);
-}
-
-/** Sets compositor to idle mode
- *
- * \param data The compositor instance
- *
- * This is called when the idle timer fires.  Once the compositor is in
- * idle mode it requires a wake action (e.g. via
- * weston_compositor_wake()) to restore it.  The compositor's
- * idle_signal will be triggered when the idle event occurs.
- *
- * Idleness can be inhibited by setting the compositor's idle_inhibit
- * property.
- */
-static int
-idle_handler(void *data)
-{
-       struct weston_compositor *compositor = data;
-
-       if (compositor->idle_inhibit)
-               return 1;
-
-       compositor->state = WESTON_COMPOSITOR_IDLE;
-       wl_signal_emit(&compositor->idle_signal, compositor);
-
-       return 1;
-}
-
-WL_EXPORT void
-weston_plane_init(struct weston_plane *plane,
-                       struct weston_compositor *ec,
-                       int32_t x, int32_t y)
-{
-       pixman_region32_init(&plane->damage);
-       pixman_region32_init(&plane->clip);
-       plane->x = x;
-       plane->y = y;
-       plane->compositor = ec;
-
-       /* Init the link so that the call to wl_list_remove() when releasing
-        * the plane without ever stacking doesn't lead to a crash */
-       wl_list_init(&plane->link);
-}
-
-WL_EXPORT void
-weston_plane_release(struct weston_plane *plane)
-{
-       struct weston_view *view;
-
-       pixman_region32_fini(&plane->damage);
-       pixman_region32_fini(&plane->clip);
-
-       wl_list_for_each(view, &plane->compositor->view_list, link) {
-               if (view->plane == plane)
-                       view->plane = NULL;
-       }
-
-       wl_list_remove(&plane->link);
-}
-
-WL_EXPORT void
-weston_compositor_stack_plane(struct weston_compositor *ec,
-                             struct weston_plane *plane,
-                             struct weston_plane *above)
-{
-       if (above)
-               wl_list_insert(above->link.prev, &plane->link);
-       else
-               wl_list_insert(&ec->plane_list, &plane->link);
-}
-
-static void unbind_resource(struct wl_resource *resource)
-{
-       wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void
-bind_output(struct wl_client *client,
-           void *data, uint32_t version, uint32_t id)
-{
-       struct weston_output *output = data;
-       struct weston_mode *mode;
-       struct wl_resource *resource;
-
-       resource = wl_resource_create(client, &wl_output_interface,
-                                     version, id);
-       if (resource == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       wl_list_insert(&output->resource_list, wl_resource_get_link(resource));
-       wl_resource_set_implementation(resource, NULL, data, unbind_resource);
-
-       wl_output_send_geometry(resource,
-                               output->x,
-                               output->y,
-                               output->mm_width,
-                               output->mm_height,
-                               output->subpixel,
-                               output->make, output->model,
-                               output->transform);
-       if (version >= WL_OUTPUT_SCALE_SINCE_VERSION)
-               wl_output_send_scale(resource,
-                                    output->current_scale);
-
-       wl_list_for_each (mode, &output->mode_list, link) {
-               wl_output_send_mode(resource,
-                                   mode->flags,
-                                   mode->width,
-                                   mode->height,
-                                   mode->refresh);
-       }
-
-       if (version >= WL_OUTPUT_DONE_SINCE_VERSION)
-               wl_output_send_done(resource);
-}
-
-/* Move other outputs when one is resized so the space remains contiguous. */
-static void
-weston_compositor_reflow_outputs(struct weston_compositor *compositor,
-                               struct weston_output *resized_output, int delta_width)
-{
-       struct weston_output *output;
-       bool start_resizing = false;
-
-       if (!delta_width)
-               return;
-
-       wl_list_for_each(output, &compositor->output_list, link) {
-               if (output == resized_output) {
-                       start_resizing = true;
-                       continue;
-               }
-
-               if (start_resizing) {
-                       weston_output_move(output, output->x + delta_width, output->y);
-                       output->dirty = 1;
-               }
-       }
-}
-
-WL_EXPORT void
-weston_output_destroy(struct weston_output *output)
-{
-       struct wl_resource *resource;
-       struct weston_view *view;
-
-       output->destroying = 1;
-
-       wl_list_for_each(view, &output->compositor->view_list, link) {
-               if (view->output_mask & (1u << output->id))
-                       weston_view_assign_output(view);
-       }
-
-       wl_event_source_remove(output->repaint_timer);
-
-       weston_presentation_feedback_discard_list(&output->feedback_list);
-
-       weston_compositor_reflow_outputs(output->compositor, output, output->width);
-       wl_list_remove(&output->link);
-
-       wl_signal_emit(&output->compositor->output_destroyed_signal, output);
-       wl_signal_emit(&output->destroy_signal, output);
-
-       free(output->name);
-       pixman_region32_fini(&output->region);
-       pixman_region32_fini(&output->previous_damage);
-       output->compositor->output_id_pool &= ~(1u << output->id);
-
-       wl_resource_for_each(resource, &output->resource_list) {
-               wl_resource_set_destructor(resource, NULL);
-       }
-
-       wl_global_destroy(output->global);
-}
-
-WL_EXPORT void
-weston_output_update_matrix(struct weston_output *output)
-{
-       float magnification;
-
-       weston_matrix_init(&output->matrix);
-       weston_matrix_translate(&output->matrix, -output->x, -output->y, 0);
-
-       if (output->zoom.active) {
-               magnification = 1 / (1 - output->zoom.spring_z.current);
-               weston_output_update_zoom(output);
-               weston_matrix_translate(&output->matrix, -output->zoom.trans_x,
-                                       -output->zoom.trans_y, 0);
-               weston_matrix_scale(&output->matrix, magnification,
-                                   magnification, 1.0);
-       }
-
-       switch (output->transform) {
-       case WL_OUTPUT_TRANSFORM_FLIPPED:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
-               weston_matrix_translate(&output->matrix, -output->width, 0, 0);
-               weston_matrix_scale(&output->matrix, -1, 1, 1);
-               break;
-       }
-
-       switch (output->transform) {
-       default:
-       case WL_OUTPUT_TRANSFORM_NORMAL:
-       case WL_OUTPUT_TRANSFORM_FLIPPED:
-               break;
-       case WL_OUTPUT_TRANSFORM_90:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_90:
-               weston_matrix_translate(&output->matrix, 0, -output->height, 0);
-               weston_matrix_rotate_xy(&output->matrix, 0, 1);
-               break;
-       case WL_OUTPUT_TRANSFORM_180:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_180:
-               weston_matrix_translate(&output->matrix,
-                                       -output->width, -output->height, 0);
-               weston_matrix_rotate_xy(&output->matrix, -1, 0);
-               break;
-       case WL_OUTPUT_TRANSFORM_270:
-       case WL_OUTPUT_TRANSFORM_FLIPPED_270:
-               weston_matrix_translate(&output->matrix, -output->width, 0, 0);
-               weston_matrix_rotate_xy(&output->matrix, 0, -1);
-               break;
-       }
-
-       if (output->current_scale != 1)
-               weston_matrix_scale(&output->matrix,
-                                   output->current_scale,
-                                   output->current_scale, 1);
-
-       output->dirty = 0;
-
-       weston_matrix_invert(&output->inverse_matrix, &output->matrix);
-}
-
-static void
-weston_output_transform_scale_init(struct weston_output *output, uint32_t transform, uint32_t scale)
-{
-       output->transform = transform;
-       output->native_scale = scale;
-       output->current_scale = scale;
-
-       convert_size_by_transform_scale(&output->width, &output->height,
-                                       output->current_mode->width,
-                                       output->current_mode->height,
-                                       transform, scale);
-}
-
-static void
-weston_output_init_geometry(struct weston_output *output, int x, int y)
-{
-       output->x = x;
-       output->y = y;
-
-       pixman_region32_init(&output->previous_damage);
-       pixman_region32_init_rect(&output->region, x, y,
-                                 output->width,
-                                 output->height);
-}
-
-WL_EXPORT void
-weston_output_move(struct weston_output *output, int x, int y)
-{
-       struct wl_resource *resource;
-
-       output->move_x = x - output->x;
-       output->move_y = y - output->y;
-
-       if (output->move_x == 0 && output->move_y == 0)
-               return;
-
-       weston_output_init_geometry(output, x, y);
-
-       output->dirty = 1;
-
-       /* Move views on this output. */
-       wl_signal_emit(&output->compositor->output_moved_signal, output);
-
-       /* Notify clients of the change for output position. */
-       wl_resource_for_each(resource, &output->resource_list) {
-               wl_output_send_geometry(resource,
-                                       output->x,
-                                       output->y,
-                                       output->mm_width,
-                                       output->mm_height,
-                                       output->subpixel,
-                                       output->make,
-                                       output->model,
-                                       output->transform);
-
-               if (wl_resource_get_version(resource) >= WL_OUTPUT_DONE_SINCE_VERSION)
-                       wl_output_send_done(resource);
-       }
-}
-
-/** Initialize a weston_output object's parameters
- *
- * \param output     The weston_output object to initialize
- * \param c          The output's compositor
- * \param x          x coordinate for the output in global coordinate space
- * \param y          y coordinate for the output in global coordinate space
- * \param mm_width   Physical width of the output as reported by the backend
- * \param mm_height  Physical height of the output as reported by the backend
- * \param transform  Rotation of the output
- * \param scale      Native scaling factor for the output
- *
- * Sets up the transformation, zoom, and geometry of the output using
- * the input properties.
- *
- * Establishes a repaint timer for the output with the relevant display
- * object's event loop.  See output_repaint_timer_handler().
- *
- * The output is assigned an ID.  Weston can support up to 32 distinct
- * outputs, with IDs numbered from 0-31; the compositor's output_id_pool
- * is referred to and used to find the first available ID number, and
- * then this ID is marked as used in output_id_pool.
- *
- * The output is also assigned a Wayland global with the wl_output
- * external interface.
- */
-WL_EXPORT void
-weston_output_init(struct weston_output *output, struct weston_compositor *c,
-                  int x, int y, int mm_width, int mm_height, uint32_t transform,
-                  int32_t scale)
-{
-       struct wl_event_loop *loop;
-
-       /* Verify we haven't reached the limit of 32 available output IDs */
-       assert(ffs(~c->output_id_pool) > 0);
-
-       output->compositor = c;
-       output->x = x;
-       output->y = y;
-       output->mm_width = mm_width;
-       output->mm_height = mm_height;
-       output->dirty = 1;
-       output->original_scale = scale;
-
-       weston_output_transform_scale_init(output, transform, scale);
-       weston_output_init_zoom(output);
-
-       weston_output_init_geometry(output, x, y);
-       weston_output_damage(output);
-
-       wl_signal_init(&output->frame_signal);
-       wl_signal_init(&output->destroy_signal);
-       wl_list_init(&output->animation_list);
-       wl_list_init(&output->resource_list);
-       wl_list_init(&output->feedback_list);
-       wl_list_init(&output->link);
-
-       loop = wl_display_get_event_loop(c->wl_display);
-       output->repaint_timer = wl_event_loop_add_timer(loop,
-                                       output_repaint_timer_handler, output);
-
-       /* Invert the output id pool and look for the lowest numbered
-        * switch (the least significant bit).  Take that bit's position
-        * as our ID, and mark it used in the compositor's output_id_pool.
-        */
-       output->id = ffs(~output->compositor->output_id_pool) - 1;
-       output->compositor->output_id_pool |= 1u << output->id;
-
-       output->global =
-               wl_global_create(c->wl_display, &wl_output_interface, 2,
-                                output, bind_output);
-}
-
-/** Adds an output to the compositor's output list and
- *  send the compositor's output_created signal.
- *
- * \param compositor The compositor instance.
- * \param output The output to be added.
- */
-WL_EXPORT void
-weston_compositor_add_output(struct weston_compositor *compositor,
-                             struct weston_output *output)
-{
-       wl_list_insert(compositor->output_list.prev, &output->link);
-       wl_signal_emit(&compositor->output_created_signal, output);
-}
-
-WL_EXPORT void
-weston_output_transform_coordinate(struct weston_output *output,
-                                  double device_x, double device_y,
-                                  double *x, double *y)
-{
-       struct weston_vector p = { {
-               device_x,
-               device_y,
-               0.0,
-               1.0 } };
-
-       weston_matrix_transform(&output->inverse_matrix, &p);
-
-       *x = p.f[0] / p.f[3];
-       *y = p.f[1] / p.f[3];
-}
-
-static void
-destroy_viewport(struct wl_resource *resource)
-{
-       struct weston_surface *surface =
-               wl_resource_get_user_data(resource);
-
-       if (!surface)
-               return;
-
-       surface->viewport_resource = NULL;
-       surface->pending.buffer_viewport.buffer.src_width =
-               wl_fixed_from_int(-1);
-       surface->pending.buffer_viewport.surface.width = -1;
-       surface->pending.buffer_viewport.changed = 1;
-}
-
-static void
-viewport_destroy(struct wl_client *client,
-                struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-viewport_set_source(struct wl_client *client,
-                   struct wl_resource *resource,
-                   wl_fixed_t src_x,
-                   wl_fixed_t src_y,
-                   wl_fixed_t src_width,
-                   wl_fixed_t src_height)
-{
-       struct weston_surface *surface =
-               wl_resource_get_user_data(resource);
-
-       if (!surface) {
-               wl_resource_post_error(resource,
-                       WP_VIEWPORT_ERROR_NO_SURFACE,
-                       "wl_surface for this viewport is no longer exists");
-               return;
-       }
-
-       assert(surface->viewport_resource == resource);
-       assert(surface->resource);
-
-       if (src_width == wl_fixed_from_int(-1) &&
-           src_height == wl_fixed_from_int(-1) &&
-           src_x == wl_fixed_from_int(-1) &&
-           src_y == wl_fixed_from_int(-1)) {
-               /* unset source rect */
-               surface->pending.buffer_viewport.buffer.src_width =
-                       wl_fixed_from_int(-1);
-               surface->pending.buffer_viewport.changed = 1;
-               return;
-       }
-
-       if (src_width <= 0 || src_height <= 0 || src_x < 0 || src_y < 0) {
-               wl_resource_post_error(resource,
-                       WP_VIEWPORT_ERROR_BAD_VALUE,
-                       "wl_surface@%d viewport source "
-                       "w=%f <= 0, h=%f <= 0, x=%f < 0, or y=%f < 0",
-                       wl_resource_get_id(surface->resource),
-                       wl_fixed_to_double(src_width),
-                       wl_fixed_to_double(src_height),
-                       wl_fixed_to_double(src_x),
-                       wl_fixed_to_double(src_y));
-               return;
-       }
-
-       surface->pending.buffer_viewport.buffer.src_x = src_x;
-       surface->pending.buffer_viewport.buffer.src_y = src_y;
-       surface->pending.buffer_viewport.buffer.src_width = src_width;
-       surface->pending.buffer_viewport.buffer.src_height = src_height;
-       surface->pending.buffer_viewport.changed = 1;
-}
-
-static void
-viewport_set_destination(struct wl_client *client,
-                        struct wl_resource *resource,
-                        int32_t dst_width,
-                        int32_t dst_height)
-{
-       struct weston_surface *surface =
-               wl_resource_get_user_data(resource);
-
-       if (!surface) {
-               wl_resource_post_error(resource,
-                       WP_VIEWPORT_ERROR_NO_SURFACE,
-                       "wl_surface for this viewport no longer exists");
-               return;
-       }
-
-       assert(surface->viewport_resource == resource);
-
-       if (dst_width == -1 && dst_height == -1) {
-               /* unset destination size */
-               surface->pending.buffer_viewport.surface.width = -1;
-               surface->pending.buffer_viewport.changed = 1;
-               return;
-       }
-
-       if (dst_width <= 0 || dst_height <= 0) {
-               wl_resource_post_error(resource,
-                       WP_VIEWPORT_ERROR_BAD_VALUE,
-                       "destination size must be positive (%dx%d)",
-                       dst_width, dst_height);
-               return;
-       }
-
-       surface->pending.buffer_viewport.surface.width = dst_width;
-       surface->pending.buffer_viewport.surface.height = dst_height;
-       surface->pending.buffer_viewport.changed = 1;
-}
-
-static const struct wp_viewport_interface viewport_interface = {
-       viewport_destroy,
-       viewport_set_source,
-       viewport_set_destination
-};
-
-static void
-viewporter_destroy(struct wl_client *client,
-                  struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-viewporter_get_viewport(struct wl_client *client,
-                       struct wl_resource *viewporter,
-                       uint32_t id,
-                       struct wl_resource *surface_resource)
-{
-       int version = wl_resource_get_version(viewporter);
-       struct weston_surface *surface =
-               wl_resource_get_user_data(surface_resource);
-       struct wl_resource *resource;
-
-       if (surface->viewport_resource) {
-               wl_resource_post_error(viewporter,
-                       WP_VIEWPORTER_ERROR_VIEWPORT_EXISTS,
-                       "a viewport for that surface already exists");
-               return;
-       }
-
-       resource = wl_resource_create(client, &wp_viewport_interface,
-                                     version, id);
-       if (resource == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       wl_resource_set_implementation(resource, &viewport_interface,
-                                      surface, destroy_viewport);
-
-       surface->viewport_resource = resource;
-}
-
-static const struct wp_viewporter_interface viewporter_interface = {
-       viewporter_destroy,
-       viewporter_get_viewport
-};
-
-static void
-bind_viewporter(struct wl_client *client,
-               void *data, uint32_t version, uint32_t id)
-{
-       struct wl_resource *resource;
-
-       resource = wl_resource_create(client, &wp_viewporter_interface,
-                                     version, id);
-       if (resource == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       wl_resource_set_implementation(resource, &viewporter_interface,
-                                      NULL, NULL);
-}
-
-static void
-destroy_presentation_feedback(struct wl_resource *feedback_resource)
-{
-       struct weston_presentation_feedback *feedback;
-
-       feedback = wl_resource_get_user_data(feedback_resource);
-
-       wl_list_remove(&feedback->link);
-       free(feedback);
-}
-
-static void
-presentation_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-presentation_feedback(struct wl_client *client,
-                     struct wl_resource *presentation_resource,
-                     struct wl_resource *surface_resource,
-                     uint32_t callback)
-{
-       struct weston_surface *surface;
-       struct weston_presentation_feedback *feedback;
-
-       surface = wl_resource_get_user_data(surface_resource);
-
-       feedback = zalloc(sizeof *feedback);
-       if (feedback == NULL)
-               goto err_calloc;
-
-       feedback->resource = wl_resource_create(client,
-                                       &wp_presentation_feedback_interface,
-                                       1, callback);
-       if (!feedback->resource)
-               goto err_create;
-
-       wl_resource_set_implementation(feedback->resource, NULL, feedback,
-                                      destroy_presentation_feedback);
-
-       wl_list_insert(&surface->pending.feedback_list, &feedback->link);
-
-       return;
-
-err_create:
-       free(feedback);
-
-err_calloc:
-       wl_client_post_no_memory(client);
-}
-
-static const struct wp_presentation_interface presentation_implementation = {
-       presentation_destroy,
-       presentation_feedback
-};
-
-static void
-bind_presentation(struct wl_client *client,
-                 void *data, uint32_t version, uint32_t id)
-{
-       struct weston_compositor *compositor = data;
-       struct wl_resource *resource;
-
-       resource = wl_resource_create(client, &wp_presentation_interface,
-                                     version, id);
-       if (resource == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       wl_resource_set_implementation(resource, &presentation_implementation,
-                                      compositor, NULL);
-       wp_presentation_send_clock_id(resource, compositor->presentation_clock);
-}
-
-static void
-compositor_bind(struct wl_client *client,
-               void *data, uint32_t version, uint32_t id)
-{
-       struct weston_compositor *compositor = data;
-       struct wl_resource *resource;
-
-       resource = wl_resource_create(client, &wl_compositor_interface,
-                                     version, id);
-       if (resource == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       wl_resource_set_implementation(resource, &compositor_interface,
-                                      compositor, NULL);
-}
-
-WL_EXPORT int
-weston_environment_get_fd(const char *env)
-{
-       char *e, *end;
-       int fd, flags;
-
-       e = getenv(env);
-       if (!e)
-               return -1;
-       fd = strtol(e, &end, 0);
-       if (*end != '\0')
-               return -1;
-
-       flags = fcntl(fd, F_GETFD);
-       if (flags == -1)
-               return -1;
-
-       fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
-       unsetenv(env);
-
-       return fd;
-}
-
-static void
-timeline_key_binding_handler(struct weston_keyboard *keyboard, uint32_t time,
-                            uint32_t key, void *data)
-{
-       struct weston_compositor *compositor = data;
-
-       if (weston_timeline_enabled_)
-               weston_timeline_close();
-       else
-               weston_timeline_open(compositor);
-}
-
-/** Create the compositor.
- *
- * This functions creates and initializes a compositor instance.
- *
- * \param display The Wayland display to be used.
- * \param user_data A pointer to an object that can later be retrieved
- * using the \ref weston_compositor_get_user_data function.
- * \return The compositor instance on success or NULL on failure.
- */
-WL_EXPORT struct weston_compositor *
-weston_compositor_create(struct wl_display *display, void *user_data)
-{
-       struct weston_compositor *ec;
-       struct wl_event_loop *loop;
-
-       ec = zalloc(sizeof *ec);
-       if (!ec)
-               return NULL;
-
-       ec->wl_display = display;
-       ec->user_data = user_data;
-       wl_signal_init(&ec->destroy_signal);
-       wl_signal_init(&ec->create_surface_signal);
-       wl_signal_init(&ec->activate_signal);
-       wl_signal_init(&ec->transform_signal);
-       wl_signal_init(&ec->kill_signal);
-       wl_signal_init(&ec->idle_signal);
-       wl_signal_init(&ec->wake_signal);
-       wl_signal_init(&ec->show_input_panel_signal);
-       wl_signal_init(&ec->hide_input_panel_signal);
-       wl_signal_init(&ec->update_input_panel_signal);
-       wl_signal_init(&ec->seat_created_signal);
-       wl_signal_init(&ec->output_created_signal);
-       wl_signal_init(&ec->output_destroyed_signal);
-       wl_signal_init(&ec->output_moved_signal);
-       wl_signal_init(&ec->output_resized_signal);
-       wl_signal_init(&ec->session_signal);
-       ec->session_active = 1;
-
-       ec->output_id_pool = 0;
-       ec->repaint_msec = DEFAULT_REPAINT_WINDOW;
-
-       if (!wl_global_create(ec->wl_display, &wl_compositor_interface, 4,
-                             ec, compositor_bind))
-               goto fail;
-
-       if (!wl_global_create(ec->wl_display, &wl_subcompositor_interface, 1,
-                             ec, bind_subcompositor))
-               goto fail;
-
-       if (!wl_global_create(ec->wl_display, &wp_viewporter_interface, 1,
-                             ec, bind_viewporter))
-               goto fail;
-
-       if (!wl_global_create(ec->wl_display, &wp_presentation_interface, 1,
-                             ec, bind_presentation))
-               goto fail;
-
-       wl_list_init(&ec->view_list);
-       wl_list_init(&ec->plane_list);
-       wl_list_init(&ec->layer_list);
-       wl_list_init(&ec->seat_list);
-       wl_list_init(&ec->output_list);
-       wl_list_init(&ec->key_binding_list);
-       wl_list_init(&ec->modifier_binding_list);
-       wl_list_init(&ec->button_binding_list);
-       wl_list_init(&ec->touch_binding_list);
-       wl_list_init(&ec->axis_binding_list);
-       wl_list_init(&ec->debug_binding_list);
-
-       weston_plane_init(&ec->primary_plane, ec, 0, 0);
-       weston_compositor_stack_plane(ec, &ec->primary_plane, NULL);
-
-       wl_data_device_manager_init(ec->wl_display);
-
-       wl_display_init_shm(ec->wl_display);
-
-       loop = wl_display_get_event_loop(ec->wl_display);
-       ec->idle_source = wl_event_loop_add_timer(loop, idle_handler, ec);
-
-       weston_layer_init(&ec->fade_layer, &ec->layer_list);
-       weston_layer_init(&ec->cursor_layer, &ec->fade_layer.link);
-
-       weston_compositor_add_debug_binding(ec, KEY_T,
-                                           timeline_key_binding_handler, ec);
-
-       return ec;
-
-fail:
-       free(ec);
-       return NULL;
-}
-
-WL_EXPORT void
-weston_compositor_shutdown(struct weston_compositor *ec)
-{
-       struct weston_output *output, *next;
-
-       wl_event_source_remove(ec->idle_source);
-
-       /* Destroy all outputs associated with this compositor */
-       wl_list_for_each_safe(output, next, &ec->output_list, link)
-               output->destroy(output);
-
-       if (ec->renderer)
-               ec->renderer->destroy(ec);
-
-       weston_binding_list_destroy_all(&ec->key_binding_list);
-       weston_binding_list_destroy_all(&ec->modifier_binding_list);
-       weston_binding_list_destroy_all(&ec->button_binding_list);
-       weston_binding_list_destroy_all(&ec->touch_binding_list);
-       weston_binding_list_destroy_all(&ec->axis_binding_list);
-       weston_binding_list_destroy_all(&ec->debug_binding_list);
-
-       weston_plane_release(&ec->primary_plane);
-}
-
-WL_EXPORT void
-weston_compositor_exit_with_code(struct weston_compositor *compositor,
-                                int exit_code)
-{
-       if (compositor->exit_code == EXIT_SUCCESS)
-               compositor->exit_code = exit_code;
-
-       weston_compositor_exit(compositor);
-}
-
-WL_EXPORT void
-weston_compositor_set_default_pointer_grab(struct weston_compositor *ec,
-                       const struct weston_pointer_grab_interface *interface)
-{
-       struct weston_seat *seat;
-
-       ec->default_pointer_grab = interface;
-       wl_list_for_each(seat, &ec->seat_list, link) {
-               struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-               if (pointer)
-                       weston_pointer_set_default_grab(pointer, interface);
-       }
-}
-
-WL_EXPORT int
-weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
-                                        clockid_t clk_id)
-{
-       struct timespec ts;
-
-       if (clock_gettime(clk_id, &ts) < 0)
-               return -1;
-
-       compositor->presentation_clock = clk_id;
-
-       return 0;
-}
-
-/*
- * For choosing the software clock, when the display hardware or API
- * does not expose a compatible presentation timestamp.
- */
-WL_EXPORT int
-weston_compositor_set_presentation_clock_software(
-                                       struct weston_compositor *compositor)
-{
-       /* In order of preference */
-       static const clockid_t clocks[] = {
-               CLOCK_MONOTONIC_RAW,    /* no jumps, no crawling */
-               CLOCK_MONOTONIC_COARSE, /* no jumps, may crawl, fast & coarse */
-               CLOCK_MONOTONIC,        /* no jumps, may crawl */
-               CLOCK_REALTIME_COARSE,  /* may jump and crawl, fast & coarse */
-               CLOCK_REALTIME          /* may jump and crawl */
-       };
-       unsigned i;
-
-       for (i = 0; i < ARRAY_LENGTH(clocks); i++)
-               if (weston_compositor_set_presentation_clock(compositor,
-                                                            clocks[i]) == 0)
-                       return 0;
-
-       weston_log("Error: no suitable presentation clock available.\n");
-
-       return -1;
-}
-
-/** Read the current time from the Presentation clock
- *
- * \param compositor
- * \param ts[out] The current time.
- *
- * \note Reading the current time in user space is always imprecise to some
- * degree.
- *
- * This function is never meant to fail. If reading the clock does fail,
- * an error message is logged and a zero time is returned. Callers are not
- * supposed to detect or react to failures.
- */
-WL_EXPORT void
-weston_compositor_read_presentation_clock(
-                       const struct weston_compositor *compositor,
-                       struct timespec *ts)
-{
-       static bool warned;
-       int ret;
-
-       ret = clock_gettime(compositor->presentation_clock, ts);
-       if (ret < 0) {
-               ts->tv_sec = 0;
-               ts->tv_nsec = 0;
-
-               if (!warned)
-                       weston_log("Error: failure to read "
-                                  "the presentation clock %#x: '%m' (%d)\n",
-                                  compositor->presentation_clock, errno);
-               warned = true;
-       }
-}
-
-/** Import dmabuf buffer into current renderer
- *
- * \param compositor
- * \param buffer the dmabuf buffer to import
- * \return true on usable buffers, false otherwise
- *
- * This function tests that the linux_dmabuf_buffer is usable
- * for the current renderer. Returns false on unusable buffers. Usually
- * usability is tested by importing the dmabufs for composition.
- *
- * This hook is also used for detecting if the renderer supports
- * dmabufs at all. If the renderer hook is NULL, dmabufs are not
- * supported.
- * */
-WL_EXPORT bool
-weston_compositor_import_dmabuf(struct weston_compositor *compositor,
-                               struct linux_dmabuf_buffer *buffer)
-{
-       struct weston_renderer *renderer;
-
-       renderer = compositor->renderer;
-
-       if (renderer->import_dmabuf == NULL)
-               return false;
-
-       return renderer->import_dmabuf(compositor, buffer);
-}
-
-WL_EXPORT void
-weston_version(int *major, int *minor, int *micro)
-{
-       *major = WESTON_VERSION_MAJOR;
-       *minor = WESTON_VERSION_MINOR;
-       *micro = WESTON_VERSION_MICRO;
-}
-
-WL_EXPORT void *
-weston_load_module(const char *name, const char *entrypoint)
-{
-       const char *builddir = getenv("WESTON_BUILD_DIR");
-       char path[PATH_MAX];
-       void *module, *init;
-
-       if (name == NULL)
-               return NULL;
-
-       if (name[0] != '/') {
-               if (builddir)
-                       snprintf(path, sizeof path, "%s/.libs/%s", builddir, name);
-               else
-                       snprintf(path, sizeof path, "%s/%s", LIBWESTON_MODULEDIR, name);
-       } else {
-               snprintf(path, sizeof path, "%s", name);
-       }
-
-       module = dlopen(path, RTLD_NOW | RTLD_NOLOAD);
-       if (module) {
-               weston_log("Module '%s' already loaded\n", path);
-               dlclose(module);
-               return NULL;
-       }
-
-       weston_log("Loading module '%s'\n", path);
-       module = dlopen(path, RTLD_NOW);
-       if (!module) {
-               weston_log("Failed to load module: %s\n", dlerror());
-               return NULL;
-       }
-
-       init = dlsym(module, entrypoint);
-       if (!init) {
-               weston_log("Failed to lookup init function: %s\n", dlerror());
-               dlclose(module);
-               return NULL;
-       }
-
-       return init;
-}
-
-
-/** Destroys the compositor.
- *
- * This function cleans up the compositor state and destroys it.
- *
- * \param compositor The compositor to be destroyed.
- */
-WL_EXPORT void
-weston_compositor_destroy(struct weston_compositor *compositor)
-{
-       /* prevent further rendering while shutting down */
-       compositor->state = WESTON_COMPOSITOR_OFFSCREEN;
-
-       wl_signal_emit(&compositor->destroy_signal, compositor);
-
-       weston_compositor_xkb_destroy(compositor);
-
-       if (compositor->backend)
-               compositor->backend->destroy(compositor);
-       free(compositor);
-}
-
-/** Instruct the compositor to exit.
- *
- * This functions does not directly destroy the compositor object, it merely
- * command it to start the tear down process. It is not guaranteed that the
- * tear down will happen immediately.
- *
- * \param compositor The compositor to tear down.
- */
-WL_EXPORT void
-weston_compositor_exit(struct weston_compositor *compositor)
-{
-       compositor->exit(compositor);
-}
-
-/** Return the user data stored in the compositor.
- *
- * This function returns the user data pointer set with user_data parameter
- * to the \ref weston_compositor_create function.
- */
-WL_EXPORT void *
-weston_compositor_get_user_data(struct weston_compositor *compositor)
-{
-       return compositor->user_data;
-}
-
-static const char * const backend_map[] = {
-       [WESTON_BACKEND_DRM] =          "drm-backend.so",
-       [WESTON_BACKEND_FBDEV] =        "fbdev-backend.so",
-       [WESTON_BACKEND_HEADLESS] =     "headless-backend.so",
-       [WESTON_BACKEND_RDP] =          "rdp-backend.so",
-       [WESTON_BACKEND_WAYLAND] =      "wayland-backend.so",
-       [WESTON_BACKEND_X11] =          "x11-backend.so",
-};
-
-/** Load a backend into a weston_compositor
- *
- * A backend must be loaded to make a weston_compositor work. A backend
- * provides input and output capabilities, and determines the renderer to use.
- *
- * \param compositor A compositor that has not had a backend loaded yet.
- * \param backend Name of the backend file.
- * \param config_base A pointer to a backend-specific configuration
- * structure's 'base' member.
- *
- * \return 0 on success, or -1 on error.
- */
-WL_EXPORT int
-weston_compositor_load_backend(struct weston_compositor *compositor,
-                              enum weston_compositor_backend backend,
-                              struct weston_backend_config *config_base)
-{
-       int (*backend_init)(struct weston_compositor *c,
-                           struct weston_backend_config *config_base);
-
-       if (backend < 0 || backend >= ARRAY_LENGTH(backend_map))
-               return -1;
-
-       backend_init = weston_load_module(backend_map[backend], "backend_init");
-       if (!backend_init)
-               return -1;
-
-       return backend_init(compositor, config_base);
-}
diff --git a/src/compositor.h b/src/compositor.h
deleted file mode 100644 (file)
index 9e5155c..0000000
+++ /dev/null
@@ -1,1724 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- * Copyright © 2012 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _WAYLAND_SYSTEM_COMPOSITOR_H_
-#define _WAYLAND_SYSTEM_COMPOSITOR_H_
-
-#ifdef  __cplusplus
-extern "C" {
-#endif
-
-#include <stdbool.h>
-#include <time.h>
-#include <pixman.h>
-#include <xkbcommon/xkbcommon.h>
-
-#define WL_HIDE_DEPRECATED
-#include <wayland-server.h>
-
-#include "version.h"
-#include "matrix.h"
-#include "config-parser.h"
-#include "zalloc.h"
-#include "timeline-object.h"
-
-struct weston_transform {
-       struct weston_matrix matrix;
-       struct wl_list link;
-};
-
-struct weston_surface;
-struct weston_buffer;
-struct shell_surface;
-struct weston_seat;
-struct weston_output;
-struct input_method;
-struct weston_pointer;
-struct linux_dmabuf_buffer;
-struct weston_recorder;
-
-enum weston_keyboard_modifier {
-       MODIFIER_CTRL = (1 << 0),
-       MODIFIER_ALT = (1 << 1),
-       MODIFIER_SUPER = (1 << 2),
-       MODIFIER_SHIFT = (1 << 3),
-};
-
-enum weston_keyboard_locks {
-       WESTON_NUM_LOCK = (1 << 0),
-       WESTON_CAPS_LOCK = (1 << 1),
-};
-
-enum weston_led {
-       LED_NUM_LOCK = (1 << 0),
-       LED_CAPS_LOCK = (1 << 1),
-       LED_SCROLL_LOCK = (1 << 2),
-};
-
-struct weston_mode {
-       uint32_t flags;
-       int32_t width, height;
-       uint32_t refresh;
-       struct wl_list link;
-};
-
-struct weston_shell_client {
-       void (*send_configure)(struct weston_surface *surface, int32_t width, int32_t height);
-       void (*send_position)(struct weston_surface *surface, int32_t x, int32_t y);
-};
-
-struct weston_shell_interface {
-       void *shell;                    /* either desktop or tablet */
-
-       struct shell_surface *(*create_shell_surface)(void *shell,
-                                                     struct weston_surface *surface,
-                                                     const struct weston_shell_client *client);
-       void (*set_toplevel)(struct shell_surface *shsurf);
-
-       void (*set_transient)(struct shell_surface *shsurf,
-                             struct weston_surface *parent,
-                             int x, int y, uint32_t flags);
-       void (*set_fullscreen)(struct shell_surface *shsurf,
-                              uint32_t method,
-                              uint32_t framerate,
-                              struct weston_output *output);
-       void (*set_xwayland)(struct shell_surface *shsurf,
-                              int x, int y, uint32_t flags);
-       int (*move)(struct shell_surface *shsurf, struct weston_pointer *pointer);
-       int (*resize)(struct shell_surface *shsurf,
-                     struct weston_pointer *pointer, uint32_t edges);
-       void (*set_title)(struct shell_surface *shsurf,
-                         const char *title);
-       void (*set_window_geometry)(struct shell_surface *shsurf,
-                                   int32_t x, int32_t y,
-                                   int32_t width, int32_t height);
-       void (*set_maximized)(struct shell_surface *shsurf);
-       void (*set_pid)(struct shell_surface *shsurf, pid_t pid);
-       void (*get_output_work_area)(void *shell, struct weston_output *output, pixman_rectangle32_t *area);
-};
-
-struct weston_animation {
-       void (*frame)(struct weston_animation *animation,
-                     struct weston_output *output, uint32_t msecs);
-       int frame_counter;
-       struct wl_list link;
-};
-
-enum {
-       WESTON_SPRING_OVERSHOOT,
-       WESTON_SPRING_CLAMP,
-       WESTON_SPRING_BOUNCE
-};
-
-struct weston_spring {
-       double k;
-       double friction;
-       double current;
-       double target;
-       double previous;
-       double min, max;
-       uint32_t timestamp;
-       uint32_t clip;
-};
-
-struct weston_output_zoom {
-       bool active;
-       float increment;
-       float level;
-       float max_level;
-       float trans_x, trans_y;
-       struct {
-               double x, y;
-       } current;
-       struct weston_seat *seat;
-       struct weston_animation animation_z;
-       struct weston_spring spring_z;
-       struct wl_listener motion_listener;
-};
-
-/* bit compatible with drm definitions. */
-enum dpms_enum {
-       WESTON_DPMS_ON,
-       WESTON_DPMS_STANDBY,
-       WESTON_DPMS_SUSPEND,
-       WESTON_DPMS_OFF
-};
-
-struct weston_output {
-       uint32_t id;
-       char *name;
-
-       void *renderer_state;
-
-       struct wl_list link;
-       struct wl_list resource_list;
-       struct wl_global *global;
-       struct weston_compositor *compositor;
-
-       /** From global to output buffer coordinates. */
-       struct weston_matrix matrix;
-       /** From output buffer to global coordinates. */
-       struct weston_matrix inverse_matrix;
-
-       struct wl_list animation_list;
-       int32_t x, y, width, height;
-       int32_t mm_width, mm_height;
-
-       /** Output area in global coordinates, simple rect */
-       pixman_region32_t region;
-
-       pixman_region32_t previous_damage;
-       int repaint_needed;
-       int repaint_scheduled;
-       struct wl_event_source *repaint_timer;
-       struct weston_output_zoom zoom;
-       int dirty;
-       struct wl_signal frame_signal;
-       struct wl_signal destroy_signal;
-       int move_x, move_y;
-       uint32_t frame_time; /* presentation timestamp in milliseconds */
-       uint64_t msc;        /* media stream counter */
-       int disable_planes;
-       int destroying;
-       struct wl_list feedback_list;
-
-       char *make, *model, *serial_number;
-       uint32_t subpixel;
-       uint32_t transform;
-       int32_t native_scale;
-       int32_t current_scale;
-       int32_t original_scale;
-
-       struct weston_mode *native_mode;
-       struct weston_mode *current_mode;
-       struct weston_mode *original_mode;
-       struct wl_list mode_list;
-
-       void (*start_repaint_loop)(struct weston_output *output);
-       int (*repaint)(struct weston_output *output,
-                       pixman_region32_t *damage);
-       void (*destroy)(struct weston_output *output);
-       void (*assign_planes)(struct weston_output *output);
-       int (*switch_mode)(struct weston_output *output, struct weston_mode *mode);
-
-       /* backlight values are on 0-255 range, where higher is brighter */
-       int32_t backlight_current;
-       void (*set_backlight)(struct weston_output *output, uint32_t value);
-       void (*set_dpms)(struct weston_output *output, enum dpms_enum level);
-
-       int connection_internal;
-       uint16_t gamma_size;
-       void (*set_gamma)(struct weston_output *output,
-                         uint16_t size,
-                         uint16_t *r,
-                         uint16_t *g,
-                         uint16_t *b);
-
-       struct weston_timeline_object timeline;
-};
-
-enum weston_pointer_motion_mask {
-       WESTON_POINTER_MOTION_ABS = 1 << 0,
-       WESTON_POINTER_MOTION_REL = 1 << 1,
-};
-
-struct weston_pointer_motion_event {
-       uint32_t mask;
-       double x;
-       double y;
-       double dx;
-       double dy;
-};
-
-struct weston_pointer_axis_event {
-       uint32_t axis;
-       double value;
-       bool has_discrete;
-       int32_t discrete;
-};
-
-struct weston_pointer_grab;
-struct weston_pointer_grab_interface {
-       void (*focus)(struct weston_pointer_grab *grab);
-       void (*motion)(struct weston_pointer_grab *grab, uint32_t time,
-                      struct weston_pointer_motion_event *event);
-       void (*button)(struct weston_pointer_grab *grab,
-                      uint32_t time, uint32_t button, uint32_t state);
-       void (*axis)(struct weston_pointer_grab *grab,
-                    uint32_t time,
-                    struct weston_pointer_axis_event *event);
-       void (*axis_source)(struct weston_pointer_grab *grab, uint32_t source);
-       void (*frame)(struct weston_pointer_grab *grab);
-       void (*cancel)(struct weston_pointer_grab *grab);
-};
-
-struct weston_pointer_grab {
-       const struct weston_pointer_grab_interface *interface;
-       struct weston_pointer *pointer;
-};
-
-struct weston_keyboard_grab;
-struct weston_keyboard_grab_interface {
-       void (*key)(struct weston_keyboard_grab *grab, uint32_t time,
-                   uint32_t key, uint32_t state);
-       void (*modifiers)(struct weston_keyboard_grab *grab, uint32_t serial,
-                         uint32_t mods_depressed, uint32_t mods_latched,
-                         uint32_t mods_locked, uint32_t group);
-       void (*cancel)(struct weston_keyboard_grab *grab);
-};
-
-struct weston_keyboard_grab {
-       const struct weston_keyboard_grab_interface *interface;
-       struct weston_keyboard *keyboard;
-};
-
-struct weston_touch_grab;
-struct weston_touch_grab_interface {
-       void (*down)(struct weston_touch_grab *grab,
-                       uint32_t time,
-                       int touch_id,
-                       wl_fixed_t sx,
-                       wl_fixed_t sy);
-       void (*up)(struct weston_touch_grab *grab,
-                       uint32_t time,
-                       int touch_id);
-       void (*motion)(struct weston_touch_grab *grab,
-                       uint32_t time,
-                       int touch_id,
-                       wl_fixed_t sx,
-                       wl_fixed_t sy);
-       void (*frame)(struct weston_touch_grab *grab);
-       void (*cancel)(struct weston_touch_grab *grab);
-};
-
-struct weston_touch_grab {
-       const struct weston_touch_grab_interface *interface;
-       struct weston_touch *touch;
-};
-
-struct weston_data_offer {
-       struct wl_resource *resource;
-       struct weston_data_source *source;
-       struct wl_listener source_destroy_listener;
-       uint32_t dnd_actions;
-       enum wl_data_device_manager_dnd_action preferred_dnd_action;
-       bool in_ask;
-};
-
-struct weston_data_source {
-       struct wl_resource *resource;
-       struct wl_signal destroy_signal;
-       struct wl_array mime_types;
-       struct weston_data_offer *offer;
-       struct weston_seat *seat;
-       bool accepted;
-       bool actions_set;
-       uint32_t dnd_actions;
-       enum wl_data_device_manager_dnd_action current_dnd_action;
-       enum wl_data_device_manager_dnd_action compositor_action;
-
-       void (*accept)(struct weston_data_source *source,
-                      uint32_t serial, const char *mime_type);
-       void (*send)(struct weston_data_source *source,
-                    const char *mime_type, int32_t fd);
-       void (*cancel)(struct weston_data_source *source);
-};
-
-struct weston_pointer_client {
-       struct wl_list link;
-       struct wl_client *client;
-       struct wl_list pointer_resources;
-};
-
-struct weston_pointer {
-       struct weston_seat *seat;
-
-       struct wl_list pointer_clients;
-
-       struct weston_view *focus;
-       struct weston_pointer_client *focus_client;
-       uint32_t focus_serial;
-       struct wl_listener focus_view_listener;
-       struct wl_listener focus_resource_listener;
-       struct wl_signal focus_signal;
-       struct wl_signal motion_signal;
-
-       struct weston_view *sprite;
-       struct wl_listener sprite_destroy_listener;
-       int32_t hotspot_x, hotspot_y;
-
-       struct weston_pointer_grab *grab;
-       struct weston_pointer_grab default_grab;
-       wl_fixed_t grab_x, grab_y;
-       uint32_t grab_button;
-       uint32_t grab_serial;
-       uint32_t grab_time;
-
-       wl_fixed_t x, y;
-       wl_fixed_t sx, sy;
-       uint32_t button_count;
-
-       struct wl_listener output_destroy_listener;
-};
-
-
-struct weston_touch {
-       struct weston_seat *seat;
-
-       struct wl_list resource_list;
-       struct wl_list focus_resource_list;
-       struct weston_view *focus;
-       struct wl_listener focus_view_listener;
-       struct wl_listener focus_resource_listener;
-       uint32_t focus_serial;
-       struct wl_signal focus_signal;
-
-       uint32_t num_tp;
-
-       struct weston_touch_grab *grab;
-       struct weston_touch_grab default_grab;
-       int grab_touch_id;
-       wl_fixed_t grab_x, grab_y;
-       uint32_t grab_serial;
-       uint32_t grab_time;
-};
-
-void
-weston_pointer_motion_to_abs(struct weston_pointer *pointer,
-                            struct weston_pointer_motion_event *event,
-                            wl_fixed_t *x, wl_fixed_t *y);
-
-struct weston_pointer *
-weston_pointer_create(struct weston_seat *seat);
-void
-weston_pointer_destroy(struct weston_pointer *pointer);
-void
-weston_pointer_send_axis(struct weston_pointer *pointer,
-                        uint32_t time,
-                        struct weston_pointer_axis_event *event);
-void
-weston_pointer_send_axis_source(struct weston_pointer *pointer,
-                               uint32_t source);
-void
-weston_pointer_send_frame(struct weston_pointer *pointer);
-
-void
-weston_pointer_set_focus(struct weston_pointer *pointer,
-                        struct weston_view *view,
-                        wl_fixed_t sx, wl_fixed_t sy);
-void
-weston_pointer_clear_focus(struct weston_pointer *pointer);
-void
-weston_pointer_start_grab(struct weston_pointer *pointer,
-                         struct weston_pointer_grab *grab);
-void
-weston_pointer_end_grab(struct weston_pointer *pointer);
-void
-weston_pointer_clamp(struct weston_pointer *pointer,
-                           wl_fixed_t *fx, wl_fixed_t *fy);
-void
-weston_pointer_move(struct weston_pointer *pointer,
-                   struct weston_pointer_motion_event *event);
-void
-weston_pointer_set_default_grab(struct weston_pointer *pointer,
-               const struct weston_pointer_grab_interface *interface);
-
-struct weston_keyboard *
-weston_keyboard_create(void);
-void
-weston_keyboard_destroy(struct weston_keyboard *keyboard);
-void
-weston_keyboard_set_focus(struct weston_keyboard *keyboard,
-                         struct weston_surface *surface);
-void
-weston_keyboard_start_grab(struct weston_keyboard *device,
-                          struct weston_keyboard_grab *grab);
-void
-weston_keyboard_end_grab(struct weston_keyboard *keyboard);
-int
-/*
- * 'mask' and 'value' should be a bitwise mask of one or more
- * valued of the weston_keyboard_locks enum.
- */
-weston_keyboard_set_locks(struct weston_keyboard *keyboard,
-                         uint32_t mask, uint32_t value);
-
-struct weston_touch *
-weston_touch_create(void);
-void
-weston_touch_destroy(struct weston_touch *touch);
-void
-weston_touch_set_focus(struct weston_touch *touch,
-                      struct weston_view *view);
-void
-weston_touch_start_grab(struct weston_touch *device,
-                       struct weston_touch_grab *grab);
-void
-weston_touch_end_grab(struct weston_touch *touch);
-
-void
-wl_data_device_set_keyboard_focus(struct weston_seat *seat);
-
-int
-wl_data_device_manager_init(struct wl_display *display);
-
-
-void
-weston_seat_set_selection(struct weston_seat *seat,
-                         struct weston_data_source *source, uint32_t serial);
-void
-weston_seat_send_selection(struct weston_seat *seat, struct wl_client *client);
-
-int
-weston_pointer_start_drag(struct weston_pointer *pointer,
-                      struct weston_data_source *source,
-                      struct weston_surface *icon,
-                      struct wl_client *client);
-int
-weston_touch_start_drag(struct weston_touch *touch,
-                       struct weston_data_source *source,
-                       struct weston_surface *icon,
-                       struct wl_client *client);
-
-struct weston_xkb_info {
-       struct xkb_keymap *keymap;
-       int keymap_fd;
-       size_t keymap_size;
-       char *keymap_area;
-       int32_t ref_count;
-       xkb_mod_index_t shift_mod;
-       xkb_mod_index_t caps_mod;
-       xkb_mod_index_t ctrl_mod;
-       xkb_mod_index_t alt_mod;
-       xkb_mod_index_t mod2_mod;
-       xkb_mod_index_t mod3_mod;
-       xkb_mod_index_t super_mod;
-       xkb_mod_index_t mod5_mod;
-       xkb_led_index_t num_led;
-       xkb_led_index_t caps_led;
-       xkb_led_index_t scroll_led;
-};
-
-struct weston_keyboard {
-       struct weston_seat *seat;
-
-       struct wl_list resource_list;
-       struct wl_list focus_resource_list;
-       struct weston_surface *focus;
-       struct wl_listener focus_resource_listener;
-       uint32_t focus_serial;
-       struct wl_signal focus_signal;
-
-       struct weston_keyboard_grab *grab;
-       struct weston_keyboard_grab default_grab;
-       uint32_t grab_key;
-       uint32_t grab_serial;
-       uint32_t grab_time;
-
-       struct wl_array keys;
-
-       struct {
-               uint32_t mods_depressed;
-               uint32_t mods_latched;
-               uint32_t mods_locked;
-               uint32_t group;
-       } modifiers;
-
-       struct weston_keyboard_grab input_method_grab;
-       struct wl_resource *input_method_resource;
-
-       struct weston_xkb_info *xkb_info;
-       struct {
-               struct xkb_state *state;
-               enum weston_led leds;
-       } xkb_state;
-       struct xkb_keymap *pending_keymap;
-};
-
-struct weston_seat {
-       struct wl_list base_resource_list;
-
-       struct wl_global *global;
-       struct weston_pointer *pointer_state;
-       struct weston_keyboard *keyboard_state;
-       struct weston_touch *touch_state;
-       int pointer_device_count;
-       int keyboard_device_count;
-       int touch_device_count;
-
-       struct weston_output *output; /* constraint */
-
-       struct wl_signal destroy_signal;
-       struct wl_signal updated_caps_signal;
-
-       struct weston_compositor *compositor;
-       struct wl_list link;
-       enum weston_keyboard_modifier modifier_state;
-       struct weston_surface *saved_kbd_focus;
-       struct wl_listener saved_kbd_focus_listener;
-       struct wl_list drag_resource_list;
-
-       uint32_t selection_serial;
-       struct weston_data_source *selection_data_source;
-       struct wl_listener selection_data_source_listener;
-       struct wl_signal selection_signal;
-
-       void (*led_update)(struct weston_seat *ws, enum weston_led leds);
-
-       struct input_method *input_method;
-       char *seat_name;
-};
-
-enum {
-       WESTON_COMPOSITOR_ACTIVE,       /* normal rendering and events */
-       WESTON_COMPOSITOR_IDLE,         /* shell->unlock called on activity */
-       WESTON_COMPOSITOR_OFFSCREEN,    /* no rendering, no frame events */
-       WESTON_COMPOSITOR_SLEEPING      /* same as offscreen, but also set dpms
-                                         * to off */
-};
-
-struct weston_layer_entry {
-       struct wl_list link;
-       struct weston_layer *layer;
-};
-
-struct weston_layer {
-       struct weston_layer_entry view_list;
-       struct wl_list link;
-       pixman_box32_t mask;
-};
-
-struct weston_plane {
-       struct weston_compositor *compositor;
-       pixman_region32_t damage; /**< in global coords */
-       pixman_region32_t clip;
-       int32_t x, y;
-       struct wl_list link;
-};
-
-struct weston_renderer {
-       int (*read_pixels)(struct weston_output *output,
-                              pixman_format_code_t format, void *pixels,
-                              uint32_t x, uint32_t y,
-                              uint32_t width, uint32_t height);
-       void (*repaint_output)(struct weston_output *output,
-                              pixman_region32_t *output_damage);
-       void (*flush_damage)(struct weston_surface *surface);
-       void (*attach)(struct weston_surface *es, struct weston_buffer *buffer);
-       void (*surface_set_color)(struct weston_surface *surface,
-                              float red, float green,
-                              float blue, float alpha);
-       void (*destroy)(struct weston_compositor *ec);
-
-
-       /** See weston_surface_get_content_size() */
-       void (*surface_get_content_size)(struct weston_surface *surface,
-                                        int *width, int *height);
-
-       /** See weston_surface_copy_content() */
-       int (*surface_copy_content)(struct weston_surface *surface,
-                                   void *target, size_t size,
-                                   int src_x, int src_y,
-                                   int width, int height);
-
-       /** See weston_compositor_import_dmabuf() */
-       bool (*import_dmabuf)(struct weston_compositor *ec,
-                             struct linux_dmabuf_buffer *buffer);
-};
-
-enum weston_capability {
-       /* backend/renderer supports arbitrary rotation */
-       WESTON_CAP_ROTATION_ANY                 = 0x0001,
-
-       /* screencaptures need to be y-flipped */
-       WESTON_CAP_CAPTURE_YFLIP                = 0x0002,
-
-       /* backend/renderer has a separate cursor plane */
-       WESTON_CAP_CURSOR_PLANE                 = 0x0004,
-
-       /* backend supports setting arbitrary resolutions */
-       WESTON_CAP_ARBITRARY_MODES              = 0x0008,
-
-       /* renderer supports weston_view_set_mask() clipping */
-       WESTON_CAP_VIEW_CLIP_MASK               = 0x0010,
-};
-
-/* Configuration struct for an output.
- *
- * This struct is used to pass the configuration for an output
- * to the compositor backend when creating a new output.
- * The backend can subclass this struct to handle backend
- * specific data.
- */
-struct weston_backend_output_config {
-       uint32_t transform;
-       uint32_t width;
-       uint32_t height;
-       uint32_t scale;
-};
-
-/* Configuration struct for a backend.
- *
- * This struct carries the configuration for a backend, and it's
- * passed to the backend's init entry point. The backend will
- * likely want to subclass this in order to handle backend specific
- * data.
- *
- * NOTE: Alternate designs were proposed (Feb 2016) for using opaque
- * structures[1] and for section+key/value getter/setters[2].  The rationale
- * for selecting the transparent structure design is based on several
- * assumptions[3] which may require re-evaluating the design choice if they
- * fail to hold.
- *
- * 1: https://lists.freedesktop.org/archives/wayland-devel/2016-February/026989.html
- * 2: https://lists.freedesktop.org/archives/wayland-devel/2016-February/026929.html
- * 3: https://lists.freedesktop.org/archives/wayland-devel/2016-February/027228.html
- */
-struct weston_backend_config {
-   /** Major version for the backend-specific config struct
-    *
-    * This version must match exactly what the backend expects, otherwise
-    * the struct is incompatible.
-    */
-   uint32_t struct_version;
-
-   /** Minor version of the backend-specific config struct
-    *
-    * This must be set to sizeof(struct backend-specific config).
-    * If the value here is smaller than what the backend expects, the
-    * extra config members will assume their default values.
-    *
-    * A value greater than what the backend expects is incompatible.
-    */
-   size_t struct_size;
-};
-
-struct weston_backend {
-       void (*destroy)(struct weston_compositor *compositor);
-       void (*restore)(struct weston_compositor *compositor);
-};
-
-struct weston_compositor {
-       struct wl_signal destroy_signal;
-
-       struct wl_display *wl_display;
-       struct weston_shell_interface shell_interface;
-
-       /* surface signals */
-       struct wl_signal create_surface_signal;
-       struct wl_signal activate_signal;
-       struct wl_signal transform_signal;
-
-       struct wl_signal kill_signal;
-       struct wl_signal idle_signal;
-       struct wl_signal wake_signal;
-
-       struct wl_signal show_input_panel_signal;
-       struct wl_signal hide_input_panel_signal;
-       struct wl_signal update_input_panel_signal;
-
-       struct wl_signal seat_created_signal;
-       struct wl_signal output_created_signal;
-       struct wl_signal output_destroyed_signal;
-       struct wl_signal output_moved_signal;
-       struct wl_signal output_resized_signal; /* callback argument: resized output */
-
-       struct wl_signal session_signal;
-       int session_active;
-
-       struct weston_layer fade_layer;
-       struct weston_layer cursor_layer;
-
-       struct wl_list output_list;
-       struct wl_list seat_list;
-       struct wl_list layer_list;
-       struct wl_list view_list;       /* struct weston_view::link */
-       struct wl_list plane_list;
-       struct wl_list key_binding_list;
-       struct wl_list modifier_binding_list;
-       struct wl_list button_binding_list;
-       struct wl_list touch_binding_list;
-       struct wl_list axis_binding_list;
-       struct wl_list debug_binding_list;
-
-       uint32_t state;
-       struct wl_event_source *idle_source;
-       uint32_t idle_inhibit;
-       int idle_time;                  /* timeout, s */
-
-       const struct weston_pointer_grab_interface *default_pointer_grab;
-
-       /* Repaint state. */
-       struct weston_plane primary_plane;
-       uint32_t capabilities; /* combination of enum weston_capability */
-
-       struct weston_renderer *renderer;
-
-       pixman_format_code_t read_format;
-
-       struct weston_backend *backend;
-
-       struct weston_launcher *launcher;
-
-       uint32_t output_id_pool;
-
-       struct xkb_rule_names xkb_names;
-       struct xkb_context *xkb_context;
-       struct weston_xkb_info *xkb_info;
-
-       /* Raw keyboard processing (no libxkbcommon initialization or handling) */
-       int use_xkbcommon;
-
-       int32_t kb_repeat_rate;
-       int32_t kb_repeat_delay;
-
-       bool vt_switching;
-
-       clockid_t presentation_clock;
-       int32_t repaint_msec;
-
-       int exit_code;
-
-       void *user_data;
-       void (*exit)(struct weston_compositor *c);
-};
-
-struct weston_buffer {
-       struct wl_resource *resource;
-       struct wl_signal destroy_signal;
-       struct wl_listener destroy_listener;
-
-       union {
-               struct wl_shm_buffer *shm_buffer;
-               void *legacy_buffer;
-       };
-       int32_t width, height;
-       uint32_t busy_count;
-       int y_inverted;
-};
-
-struct weston_buffer_reference {
-       struct weston_buffer *buffer;
-       struct wl_listener destroy_listener;
-};
-
-struct weston_buffer_viewport {
-       struct {
-               /* wl_surface.set_buffer_transform */
-               uint32_t transform;
-
-               /* wl_surface.set_scaling_factor */
-               int32_t scale;
-
-               /*
-                * If src_width != wl_fixed_from_int(-1),
-                * then and only then src_* are used.
-                */
-               wl_fixed_t src_x, src_y;
-               wl_fixed_t src_width, src_height;
-       } buffer;
-
-       struct {
-               /*
-                * If width == -1, the size is inferred from the buffer.
-                */
-               int32_t width, height;
-       } surface;
-
-       int changed;
-};
-
-struct weston_region {
-       struct wl_resource *resource;
-       pixman_region32_t region;
-};
-
-/* Using weston_view transformations
- *
- * To add a transformation to a view, create a struct weston_transform, and
- * add it to the list view->geometry.transformation_list. Whenever you
- * change the list, anything under view->geometry, or anything in the
- * weston_transforms linked into the list, you must call
- * weston_view_geometry_dirty().
- *
- * The order in the list defines the order of transformations. Let the list
- * contain the transformation matrices M1, ..., Mn as head to tail. The
- * transformation is applied to view-local coordinate vector p as
- *    P = Mn * ... * M2 * M1 * p
- * to produce the global coordinate vector P. The total transform
- *    Mn * ... * M2 * M1
- * is cached in view->transform.matrix, and the inverse of it in
- * view->transform.inverse.
- *
- * The list always contains view->transform.position transformation, which
- * is the translation by view->geometry.x and y.
- *
- * If you want to apply a transformation in local coordinates, add your
- * weston_transform to the head of the list. If you want to apply a
- * transformation in global coordinates, add it to the tail of the list.
- *
- * If view->geometry.parent is set, the total transformation of this
- * view will be the parent's total transformation and this transformation
- * combined:
- *    Mparent * Mn * ... * M2 * M1
- */
-
-struct weston_view {
-       struct weston_surface *surface;
-       struct wl_list surface_link;
-       struct wl_signal destroy_signal;
-
-       struct wl_list link;             /* weston_compositor::view_list */
-       struct weston_layer_entry layer_link; /* part of geometry */
-       struct weston_plane *plane;
-
-       /* For weston_layer inheritance from another view */
-       struct weston_view *parent_view;
-
-       pixman_region32_t clip;          /* See weston_view_damage_below() */
-       float alpha;                     /* part of geometry, see below */
-
-       void *renderer_state;
-
-       /* Surface geometry state, mutable.
-        * If you change anything, call weston_surface_geometry_dirty().
-        * That includes the transformations referenced from the list.
-        */
-       struct {
-               float x, y; /* surface translation on display */
-
-               /* struct weston_transform */
-               struct wl_list transformation_list;
-
-               /* managed by weston_surface_set_transform_parent() */
-               struct weston_view *parent;
-               struct wl_listener parent_destroy_listener;
-               struct wl_list child_list; /* geometry.parent_link */
-               struct wl_list parent_link;
-
-               /* managed by weston_view_set_mask() */
-               bool scissor_enabled;
-               pixman_region32_t scissor; /* always a simple rect */
-       } geometry;
-
-       /* State derived from geometry state, read-only.
-        * This is updated by weston_view_update_transform().
-        */
-       struct {
-               int dirty;
-
-               /* Approximations in global coordinates:
-                * - boundingbox is guaranteed to include the whole view in
-                *   the smallest possible single rectangle.
-                * - opaque is guaranteed to be fully opaque, though not
-                *   necessarily include all opaque areas.
-                */
-               pixman_region32_t boundingbox;
-               pixman_region32_t opaque;
-
-               /* matrix and inverse are used only if enabled = 1.
-                * If enabled = 0, use x, y, width, height directly.
-                */
-               int enabled;
-               struct weston_matrix matrix;
-               struct weston_matrix inverse;
-
-               struct weston_transform position; /* matrix from x, y */
-       } transform;
-
-       /*
-        * The primary output for this view.
-        * Used for picking the output for driving internal animations on the
-        * view, inheriting the primary output for related views in shells, etc.
-        */
-       struct weston_output *output;
-
-       /*
-        * A more complete representation of all outputs this surface is
-        * displayed on.
-        */
-       uint32_t output_mask;
-
-       /* Per-surface Presentation feedback flags, controlled by backend. */
-       uint32_t psf_flags;
-};
-
-struct weston_surface_state {
-       /* wl_surface.attach */
-       int newly_attached;
-       struct weston_buffer *buffer;
-       struct wl_listener buffer_destroy_listener;
-       int32_t sx;
-       int32_t sy;
-
-       /* wl_surface.damage */
-       pixman_region32_t damage_surface;
-       /* wl_surface.damage_buffer */
-       pixman_region32_t damage_buffer;
-
-       /* wl_surface.set_opaque_region */
-       pixman_region32_t opaque;
-
-       /* wl_surface.set_input_region */
-       pixman_region32_t input;
-
-       /* wl_surface.frame */
-       struct wl_list frame_callback_list;
-
-       /* presentation.feedback */
-       struct wl_list feedback_list;
-
-       /* wl_surface.set_buffer_transform */
-       /* wl_surface.set_scaling_factor */
-       /* wp_viewport.set_source */
-       /* wp_viewport.set_destination */
-       struct weston_buffer_viewport buffer_viewport;
-};
-
-struct weston_surface {
-       struct wl_resource *resource;
-       struct wl_signal destroy_signal; /* callback argument: this surface */
-       struct weston_compositor *compositor;
-
-       /** Damage in local coordinates from the client, for tex upload. */
-       pixman_region32_t damage;
-
-       pixman_region32_t opaque;        /* part of geometry, see below */
-       pixman_region32_t input;
-       int32_t width, height;
-       int32_t ref_count;
-
-       /* Not for long-term storage.  This exists for book-keeping while
-        * iterating over surfaces and views
-        */
-       bool touched;
-
-       void *renderer_state;
-
-       struct wl_list views;
-
-       /*
-        * Which output to vsync this surface to.
-        * Used to determine whether to send or queue frame events, and for
-        * other client-visible syncing/throttling tied to the output
-        * repaint cycle.
-        */
-       struct weston_output *output;
-
-       /*
-        * A more complete representation of all outputs this surface is
-        * displayed on.
-        */
-       uint32_t output_mask;
-
-       struct wl_list frame_callback_list;
-       struct wl_list feedback_list;
-
-       struct weston_buffer_reference buffer_ref;
-       struct weston_buffer_viewport buffer_viewport;
-       int32_t width_from_buffer; /* before applying viewport */
-       int32_t height_from_buffer;
-       bool keep_buffer; /* for backends to prevent early release */
-
-       /* wp_viewport resource for this surface */
-       struct wl_resource *viewport_resource;
-
-       /* All the pending state, that wl_surface.commit will apply. */
-       struct weston_surface_state pending;
-
-       /* Matrices representating of the full transformation between
-        * buffer and surface coordinates.  These matrices are updated
-        * using the weston_surface_build_buffer_matrix function. */
-       struct weston_matrix buffer_to_surface_matrix;
-       struct weston_matrix surface_to_buffer_matrix;
-
-       /*
-        * If non-NULL, this function will be called on
-        * wl_surface::commit after a new buffer has been set up for
-        * this surface. The integer params are the sx and sy
-        * parameters supplied to wl_surface::attach.
-        */
-       void (*configure)(struct weston_surface *es, int32_t sx, int32_t sy);
-       void *configure_private;
-       int (*get_label)(struct weston_surface *surface, char *buf, size_t len);
-
-       /* Parent's list of its sub-surfaces, weston_subsurface:parent_link.
-        * Contains also the parent itself as a dummy weston_subsurface,
-        * if the list is not empty.
-        */
-       struct wl_list subsurface_list; /* weston_subsurface::parent_link */
-       struct wl_list subsurface_list_pending; /* ...::parent_link_pending */
-
-       /*
-        * For tracking protocol role assignments. Different roles may
-        * have the same configure hook, e.g. in shell.c. Configure hook
-        * may get reset, this will not.
-        * XXX: map configure functions 1:1 to roles, and never reset it,
-        * and replace role_name with configure.
-        */
-       const char *role_name;
-
-       struct weston_timeline_object timeline;
-};
-
-struct weston_subsurface {
-       struct wl_resource *resource;
-
-       /* guaranteed to be valid and non-NULL */
-       struct weston_surface *surface;
-       struct wl_listener surface_destroy_listener;
-
-       /* can be NULL */
-       struct weston_surface *parent;
-       struct wl_listener parent_destroy_listener;
-       struct wl_list parent_link;
-       struct wl_list parent_link_pending;
-
-       struct {
-               int32_t x;
-               int32_t y;
-               int set;
-       } position;
-
-       int has_cached_data;
-       struct weston_surface_state cached;
-       struct weston_buffer_reference cached_buffer_ref;
-
-       int synchronized;
-
-       /* Used for constructing the view tree */
-       struct wl_list unused_views;
-};
-
-enum weston_key_state_update {
-       STATE_UPDATE_AUTOMATIC,
-       STATE_UPDATE_NONE,
-};
-
-void
-weston_version(int *major, int *minor, int *micro);
-
-void
-weston_view_update_transform(struct weston_view *view);
-
-void
-weston_view_geometry_dirty(struct weston_view *view);
-
-void
-weston_view_to_global_fixed(struct weston_view *view,
-                           wl_fixed_t sx, wl_fixed_t sy,
-                           wl_fixed_t *x, wl_fixed_t *y);
-void
-weston_view_to_global_float(struct weston_view *view,
-                           float sx, float sy, float *x, float *y);
-
-void
-weston_view_from_global_float(struct weston_view *view,
-                             float x, float y, float *vx, float *vy);
-void
-weston_view_from_global(struct weston_view *view,
-                       int32_t x, int32_t y, int32_t *vx, int32_t *vy);
-void
-weston_view_from_global_fixed(struct weston_view *view,
-                             wl_fixed_t x, wl_fixed_t y,
-                             wl_fixed_t *vx, wl_fixed_t *vy);
-
-void
-weston_surface_to_buffer_float(struct weston_surface *surface,
-                              float x, float y, float *bx, float *by);
-pixman_box32_t
-weston_surface_to_buffer_rect(struct weston_surface *surface,
-                             pixman_box32_t rect);
-
-void
-weston_surface_to_buffer_region(struct weston_surface *surface,
-                               pixman_region32_t *surface_region,
-                               pixman_region32_t *buffer_region);
-
-void
-weston_spring_init(struct weston_spring *spring,
-                  double k, double current, double target);
-void
-weston_spring_update(struct weston_spring *spring, uint32_t msec);
-int
-weston_spring_done(struct weston_spring *spring);
-
-void
-weston_surface_activate(struct weston_surface *surface,
-                       struct weston_seat *seat);
-void
-notify_motion(struct weston_seat *seat, uint32_t time,
-             struct weston_pointer_motion_event *event);
-void
-notify_motion_absolute(struct weston_seat *seat, uint32_t time,
-                      double x, double y);
-void
-notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
-             enum wl_pointer_button_state state);
-void
-notify_axis(struct weston_seat *seat, uint32_t time,
-           struct weston_pointer_axis_event *event);
-void
-notify_axis_source(struct weston_seat *seat, uint32_t source);
-
-void
-notify_pointer_frame(struct weston_seat *seat);
-
-void
-notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
-          enum wl_keyboard_key_state state,
-          enum weston_key_state_update update_state);
-void
-notify_modifiers(struct weston_seat *seat, uint32_t serial);
-
-void
-notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
-                    double x, double y);
-
-void
-notify_keyboard_focus_in(struct weston_seat *seat, struct wl_array *keys,
-                        enum weston_key_state_update update_state);
-void
-notify_keyboard_focus_out(struct weston_seat *seat);
-
-void
-notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
-            double x, double y, int touch_type);
-void
-notify_touch_frame(struct weston_seat *seat);
-
-void
-notify_touch_cancel(struct weston_seat *seat);
-
-void
-weston_layer_entry_insert(struct weston_layer_entry *list,
-                         struct weston_layer_entry *entry);
-void
-weston_layer_entry_remove(struct weston_layer_entry *entry);
-void
-weston_layer_init(struct weston_layer *layer, struct wl_list *below);
-
-void
-weston_layer_set_mask(struct weston_layer *layer, int x, int y, int width, int height);
-
-void
-weston_layer_set_mask_infinite(struct weston_layer *layer);
-
-void
-weston_plane_init(struct weston_plane *plane,
-                       struct weston_compositor *ec,
-                       int32_t x, int32_t y);
-void
-weston_plane_release(struct weston_plane *plane);
-
-void
-weston_compositor_stack_plane(struct weston_compositor *ec,
-                             struct weston_plane *plane,
-                             struct weston_plane *above);
-
-/* An invalid flag in presented_flags to catch logic errors. */
-#define WP_PRESENTATION_FEEDBACK_INVALID (1U << 31)
-
-void
-weston_output_finish_frame(struct weston_output *output,
-                          const struct timespec *stamp,
-                          uint32_t presented_flags);
-void
-weston_output_schedule_repaint(struct weston_output *output);
-void
-weston_output_damage(struct weston_output *output);
-void
-weston_compositor_schedule_repaint(struct weston_compositor *compositor);
-void
-weston_compositor_fade(struct weston_compositor *compositor, float tint);
-void
-weston_compositor_damage_all(struct weston_compositor *compositor);
-void
-weston_compositor_unlock(struct weston_compositor *compositor);
-void
-weston_compositor_wake(struct weston_compositor *compositor);
-void
-weston_compositor_offscreen(struct weston_compositor *compositor);
-void
-weston_compositor_sleep(struct weston_compositor *compositor);
-struct weston_view *
-weston_compositor_pick_view(struct weston_compositor *compositor,
-                           wl_fixed_t x, wl_fixed_t y,
-                           wl_fixed_t *sx, wl_fixed_t *sy);
-
-
-struct weston_binding;
-typedef void (*weston_key_binding_handler_t)(struct weston_keyboard *keyboard,
-                                            uint32_t time, uint32_t key,
-                                            void *data);
-struct weston_binding *
-weston_compositor_add_key_binding(struct weston_compositor *compositor,
-                                 uint32_t key,
-                                 enum weston_keyboard_modifier modifier,
-                                 weston_key_binding_handler_t binding,
-                                 void *data);
-
-typedef void (*weston_modifier_binding_handler_t)(struct weston_keyboard *keyboard,
-                                                 enum weston_keyboard_modifier modifier,
-                                                 void *data);
-struct weston_binding *
-weston_compositor_add_modifier_binding(struct weston_compositor *compositor,
-                                      enum weston_keyboard_modifier modifier,
-                                      weston_modifier_binding_handler_t binding,
-                                      void *data);
-
-typedef void (*weston_button_binding_handler_t)(struct weston_pointer *pointer,
-                                               uint32_t time, uint32_t button,
-                                               void *data);
-struct weston_binding *
-weston_compositor_add_button_binding(struct weston_compositor *compositor,
-                                    uint32_t button,
-                                    enum weston_keyboard_modifier modifier,
-                                    weston_button_binding_handler_t binding,
-                                    void *data);
-
-typedef void (*weston_touch_binding_handler_t)(struct weston_touch *touch,
-                                              uint32_t time,
-                                              void *data);
-struct weston_binding *
-weston_compositor_add_touch_binding(struct weston_compositor *compositor,
-                                   enum weston_keyboard_modifier modifier,
-                                   weston_touch_binding_handler_t binding,
-                                   void *data);
-
-typedef void (*weston_axis_binding_handler_t)(struct weston_pointer *pointer,
-                                             uint32_t time,
-                                             struct weston_pointer_axis_event *event,
-                                             void *data);
-struct weston_binding *
-weston_compositor_add_axis_binding(struct weston_compositor *compositor,
-                                  uint32_t axis,
-                                  enum weston_keyboard_modifier modifier,
-                                  weston_axis_binding_handler_t binding,
-                                  void *data);
-struct weston_binding *
-weston_compositor_add_debug_binding(struct weston_compositor *compositor,
-                                   uint32_t key,
-                                   weston_key_binding_handler_t binding,
-                                   void *data);
-void
-weston_binding_destroy(struct weston_binding *binding);
-
-void
-weston_install_debug_key_binding(struct weston_compositor *compositor,
-                                uint32_t mod);
-
-void
-weston_binding_list_destroy_all(struct wl_list *list);
-
-void
-weston_compositor_run_key_binding(struct weston_compositor *compositor,
-                                 struct weston_keyboard *keyboard,
-                                 uint32_t time,
-                                 uint32_t key,
-                                 enum wl_keyboard_key_state state);
-
-void
-weston_compositor_run_modifier_binding(struct weston_compositor *compositor,
-                                      struct weston_keyboard *keyboard,
-                                      enum weston_keyboard_modifier modifier,
-                                      enum wl_keyboard_key_state state);
-void
-weston_compositor_run_button_binding(struct weston_compositor *compositor,
-                                    struct weston_pointer *pointer, uint32_t time,
-                                    uint32_t button,
-                                    enum wl_pointer_button_state value);
-void
-weston_compositor_run_touch_binding(struct weston_compositor *compositor,
-                                   struct weston_touch *touch, uint32_t time,
-                                   int touch_type);
-int
-weston_compositor_run_axis_binding(struct weston_compositor *compositor,
-                                  struct weston_pointer *pointer, uint32_t time,
-                                  struct weston_pointer_axis_event *event);
-int
-weston_compositor_run_debug_binding(struct weston_compositor *compositor,
-                                   struct weston_keyboard *keyboard, uint32_t time,
-                                   uint32_t key,
-                                   enum wl_keyboard_key_state state);
-
-void
-weston_compositor_set_default_pointer_grab(struct weston_compositor *compositor,
-                       const struct weston_pointer_grab_interface *interface);
-
-int
-weston_environment_get_fd(const char *env);
-
-struct wl_list *
-weston_compositor_top(struct weston_compositor *compositor);
-
-struct weston_surface *
-weston_surface_create(struct weston_compositor *compositor);
-
-struct weston_view *
-weston_view_create(struct weston_surface *surface);
-
-void
-weston_view_destroy(struct weston_view *view);
-
-void
-weston_view_set_position(struct weston_view *view,
-                        float x, float y);
-
-void
-weston_view_set_transform_parent(struct weston_view *view,
-                                struct weston_view *parent);
-
-void
-weston_view_set_mask(struct weston_view *view,
-                    int x, int y, int width, int height);
-
-void
-weston_view_set_mask_infinite(struct weston_view *view);
-
-bool
-weston_view_is_mapped(struct weston_view *view);
-
-void
-weston_view_schedule_repaint(struct weston_view *view);
-
-bool
-weston_surface_is_mapped(struct weston_surface *surface);
-
-void
-weston_surface_set_size(struct weston_surface *surface,
-                       int32_t width, int32_t height);
-
-void
-weston_surface_schedule_repaint(struct weston_surface *surface);
-
-void
-weston_surface_damage(struct weston_surface *surface);
-
-void
-weston_view_damage_below(struct weston_view *view);
-
-void
-weston_view_move_to_plane(struct weston_view *view,
-                         struct weston_plane *plane);
-void
-weston_view_unmap(struct weston_view *view);
-
-void
-weston_surface_unmap(struct weston_surface *surface);
-
-struct weston_surface *
-weston_surface_get_main_surface(struct weston_surface *surface);
-
-int
-weston_surface_set_role(struct weston_surface *surface,
-                       const char *role_name,
-                       struct wl_resource *error_resource,
-                       uint32_t error_code);
-
-void
-weston_surface_set_label_func(struct weston_surface *surface,
-                             int (*desc)(struct weston_surface *,
-                                         char *, size_t));
-
-void
-weston_surface_get_content_size(struct weston_surface *surface,
-                               int *width, int *height);
-
-int
-weston_surface_copy_content(struct weston_surface *surface,
-                           void *target, size_t size,
-                           int src_x, int src_y,
-                           int width, int height);
-
-struct weston_buffer *
-weston_buffer_from_resource(struct wl_resource *resource);
-
-void
-weston_buffer_reference(struct weston_buffer_reference *ref,
-                       struct weston_buffer *buffer);
-
-uint32_t
-weston_compositor_get_time(void);
-
-void
-weston_compositor_destroy(struct weston_compositor *ec);
-struct weston_compositor *
-weston_compositor_create(struct wl_display *display, void *user_data);
-
-enum weston_compositor_backend {
-       WESTON_BACKEND_DRM,
-       WESTON_BACKEND_FBDEV,
-       WESTON_BACKEND_HEADLESS,
-       WESTON_BACKEND_RDP,
-       WESTON_BACKEND_WAYLAND,
-       WESTON_BACKEND_X11,
-};
-
-int
-weston_compositor_load_backend(struct weston_compositor *compositor,
-                              enum weston_compositor_backend backend,
-                              struct weston_backend_config *config_base);
-void
-weston_compositor_exit(struct weston_compositor *ec);
-void *
-weston_compositor_get_user_data(struct weston_compositor *compositor);
-int
-weston_compositor_set_presentation_clock(struct weston_compositor *compositor,
-                                        clockid_t clk_id);
-int
-weston_compositor_set_presentation_clock_software(
-                                       struct weston_compositor *compositor);
-void
-weston_compositor_read_presentation_clock(
-                       const struct weston_compositor *compositor,
-                       struct timespec *ts);
-
-bool
-weston_compositor_import_dmabuf(struct weston_compositor *compositor,
-                               struct linux_dmabuf_buffer *buffer);
-
-void
-weston_compositor_shutdown(struct weston_compositor *ec);
-void
-weston_compositor_exit_with_code(struct weston_compositor *compositor,
-                                int exit_code);
-void
-weston_output_init_zoom(struct weston_output *output);
-void
-weston_output_update_zoom(struct weston_output *output);
-void
-weston_output_activate_zoom(struct weston_output *output,
-                           struct weston_seat *seat);
-void
-weston_output_update_matrix(struct weston_output *output);
-void
-weston_output_move(struct weston_output *output, int x, int y);
-void
-weston_output_init(struct weston_output *output, struct weston_compositor *c,
-                  int x, int y, int width, int height, uint32_t transform, int32_t scale);
-void
-weston_compositor_add_output(struct weston_compositor *compositor,
-                             struct weston_output *output);
-void
-weston_output_destroy(struct weston_output *output);
-void
-weston_output_transform_coordinate(struct weston_output *output,
-                                  double device_x, double device_y,
-                                  double *x, double *y);
-
-void
-weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
-                const char *seat_name);
-void
-weston_seat_init_pointer(struct weston_seat *seat);
-void
-weston_seat_release_pointer(struct weston_seat *seat);
-int
-weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap);
-void
-weston_seat_release_keyboard(struct weston_seat *seat);
-void
-weston_seat_init_touch(struct weston_seat *seat);
-void
-weston_seat_release_touch(struct weston_seat *seat);
-void
-weston_seat_repick(struct weston_seat *seat);
-void
-weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap);
-
-void
-weston_seat_release(struct weston_seat *seat);
-int
-weston_compositor_set_xkb_rule_names(struct weston_compositor *ec,
-                                    struct xkb_rule_names *names);
-void
-weston_compositor_xkb_destroy(struct weston_compositor *ec);
-
-/* String literal of spaces, the same width as the timestamp. */
-#define STAMP_SPACE "               "
-
-typedef int (*log_func_t)(const char *fmt, va_list ap);
-void
-weston_log_set_handler(log_func_t log, log_func_t cont);
-int
-weston_vlog(const char *fmt, va_list ap);
-int
-weston_vlog_continue(const char *fmt, va_list ap);
-int
-weston_log(const char *fmt, ...)
-       __attribute__ ((format (printf, 1, 2)));
-int
-weston_log_continue(const char *fmt, ...)
-       __attribute__ ((format (printf, 1, 2)));
-
-enum {
-       TTY_ENTER_VT,
-       TTY_LEAVE_VT
-};
-
-struct tty *
-tty_create(struct weston_compositor *compositor, int tty_nr);
-
-void
-tty_destroy(struct tty *tty);
-
-void
-tty_reset(struct tty *tty);
-
-int
-tty_activate_vt(struct tty *tty, int vt);
-
-enum weston_screenshooter_outcome {
-       WESTON_SCREENSHOOTER_SUCCESS,
-       WESTON_SCREENSHOOTER_NO_MEMORY,
-       WESTON_SCREENSHOOTER_BAD_BUFFER
-};
-
-typedef void (*weston_screenshooter_done_func_t)(void *data,
-                               enum weston_screenshooter_outcome outcome);
-int
-weston_screenshooter_shoot(struct weston_output *output, struct weston_buffer *buffer,
-                          weston_screenshooter_done_func_t done, void *data);
-struct weston_recorder *
-weston_recorder_start(struct weston_output *output, const char *filename);
-void
-weston_recorder_stop(struct weston_recorder *recorder);
-
-struct clipboard *
-clipboard_create(struct weston_seat *seat);
-
-struct text_backend;
-
-struct text_backend *
-text_backend_init(struct weston_compositor *ec);
-
-void
-text_backend_destroy(struct text_backend *text_backend);
-
-struct weston_view_animation;
-typedef        void (*weston_view_animation_done_func_t)(struct weston_view_animation *animation, void *data);
-
-void
-weston_view_animation_destroy(struct weston_view_animation *animation);
-
-struct weston_view_animation *
-weston_zoom_run(struct weston_view *view, float start, float stop,
-               weston_view_animation_done_func_t done, void *data);
-
-struct weston_view_animation *
-weston_fade_run(struct weston_view *view,
-               float start, float end, float k,
-               weston_view_animation_done_func_t done, void *data);
-
-struct weston_view_animation *
-weston_move_scale_run(struct weston_view *view, int dx, int dy,
-                     float start, float end, int reverse,
-                     weston_view_animation_done_func_t done, void *data);
-
-void
-weston_fade_update(struct weston_view_animation *fade, float target);
-
-struct weston_view_animation *
-weston_stable_fade_run(struct weston_view *front_view, float start,
-                      struct weston_view *back_view, float end,
-                      weston_view_animation_done_func_t done, void *data);
-
-struct weston_view_animation *
-weston_slide_run(struct weston_view *view, float start, float stop,
-                weston_view_animation_done_func_t done, void *data);
-
-void
-weston_surface_set_color(struct weston_surface *surface,
-                        float red, float green, float blue, float alpha);
-
-void
-weston_surface_destroy(struct weston_surface *surface);
-
-int
-weston_output_mode_set_native(struct weston_output *output,
-                             struct weston_mode *mode,
-                             int32_t scale);
-int
-weston_output_mode_switch_to_temporary(struct weston_output *output,
-                                      struct weston_mode *mode,
-                                      int32_t scale);
-int
-weston_output_mode_switch_to_native(struct weston_output *output);
-
-int
-noop_renderer_init(struct weston_compositor *ec);
-
-int
-backend_init(struct weston_compositor *c,
-            struct weston_backend_config *config_base);
-int
-module_init(struct weston_compositor *compositor,
-           int *argc, char *argv[]);
-
-void
-weston_transformed_coord(int width, int height,
-                        enum wl_output_transform transform,
-                        int32_t scale,
-                        float sx, float sy, float *bx, float *by);
-pixman_box32_t
-weston_transformed_rect(int width, int height,
-                       enum wl_output_transform transform,
-                       int32_t scale,
-                       pixman_box32_t rect);
-void
-weston_matrix_transform_region(pixman_region32_t *dest,
-                               struct weston_matrix *matrix,
-                               pixman_region32_t *src);
-void
-weston_transformed_region(int width, int height,
-                         enum wl_output_transform transform,
-                         int32_t scale,
-                         pixman_region32_t *src, pixman_region32_t *dest);
-
-void *
-weston_load_module(const char *name, const char *entrypoint);
-
-int
-weston_parse_transform(const char *transform, uint32_t *out);
-
-const char *
-weston_transform_to_string(uint32_t output_transform);
-
-struct weston_keyboard *
-weston_seat_get_keyboard(struct weston_seat *seat);
-
-struct weston_pointer *
-weston_seat_get_pointer(struct weston_seat *seat);
-
-struct weston_touch *
-weston_seat_get_touch(struct weston_seat *seat);
-
-#ifdef  __cplusplus
-}
-#endif
-
-#endif
diff --git a/src/data-device.c b/src/data-device.c
deleted file mode 100644 (file)
index f04f030..0000000
+++ /dev/null
@@ -1,1340 +0,0 @@
-/*
- * Copyright © 2011 Kristian Høgsberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <assert.h>
-
-#include "compositor.h"
-#include "shared/helpers.h"
-
-struct weston_drag {
-       struct wl_client *client;
-       struct weston_data_source *data_source;
-       struct wl_listener data_source_listener;
-       struct weston_view *focus;
-       struct wl_resource *focus_resource;
-       struct wl_listener focus_listener;
-       struct weston_view *icon;
-       struct wl_listener icon_destroy_listener;
-       int32_t dx, dy;
-       struct weston_keyboard_grab keyboard_grab;
-};
-
-struct weston_pointer_drag {
-       struct weston_drag  base;
-       struct weston_pointer_grab grab;
-};
-
-struct weston_touch_drag {
-       struct weston_drag base;
-       struct weston_touch_grab grab;
-};
-
-#define ALL_ACTIONS (WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY | \
-                    WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE | \
-                    WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK)
-
-static void
-data_offer_accept(struct wl_client *client, struct wl_resource *resource,
-                 uint32_t serial, const char *mime_type)
-{
-       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
-       /* Protect against untimely calls from older data offers */
-       if (!offer->source || offer != offer->source->offer)
-               return;
-
-       /* FIXME: Check that client is currently focused by the input
-        * device that is currently dragging this data source.  Should
-        * this be a wl_data_device request? */
-
-       offer->source->accept(offer->source, serial, mime_type);
-       offer->source->accepted = mime_type != NULL;
-}
-
-static void
-data_offer_receive(struct wl_client *client, struct wl_resource *resource,
-                  const char *mime_type, int32_t fd)
-{
-       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
-       if (offer->source && offer == offer->source->offer)
-               offer->source->send(offer->source, mime_type, fd);
-       else
-               close(fd);
-}
-
-static void
-data_offer_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-data_source_notify_finish(struct weston_data_source *source)
-{
-       if (!source->actions_set)
-               return;
-
-       if (source->offer->in_ask &&
-           wl_resource_get_version(source->resource) >=
-           WL_DATA_SOURCE_ACTION_SINCE_VERSION) {
-               wl_data_source_send_action(source->resource,
-                                          source->current_dnd_action);
-       }
-
-       if (wl_resource_get_version(source->resource) >=
-           WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
-               wl_data_source_send_dnd_finished(source->resource);
-       }
-
-       source->offer = NULL;
-}
-
-static uint32_t
-data_offer_choose_action(struct weston_data_offer *offer)
-{
-       uint32_t available_actions, preferred_action = 0;
-       uint32_t source_actions, offer_actions;
-
-       if (wl_resource_get_version(offer->resource) >=
-           WL_DATA_OFFER_ACTION_SINCE_VERSION) {
-               offer_actions = offer->dnd_actions;
-               preferred_action = offer->preferred_dnd_action;
-       } else {
-               offer_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
-       }
-
-       if (wl_resource_get_version(offer->source->resource) >=
-           WL_DATA_SOURCE_ACTION_SINCE_VERSION)
-               source_actions = offer->source->dnd_actions;
-       else
-               source_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
-
-       available_actions = offer_actions & source_actions;
-
-       if (!available_actions)
-               return WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
-       if (offer->source->seat &&
-           offer->source->compositor_action & available_actions)
-               return offer->source->compositor_action;
-
-       /* If the dest side has a preferred DnD action, use it */
-       if ((preferred_action & available_actions) != 0)
-               return preferred_action;
-
-       /* Use the first found action, in bit order */
-       return 1 << (ffs(available_actions) - 1);
-}
-
-static void
-data_offer_update_action(struct weston_data_offer *offer)
-{
-       uint32_t action;
-
-       if (!offer->source)
-               return;
-
-       action = data_offer_choose_action(offer);
-
-       if (offer->source->current_dnd_action == action)
-               return;
-
-       offer->source->current_dnd_action = action;
-
-       if (offer->in_ask)
-               return;
-
-       if (wl_resource_get_version(offer->source->resource) >=
-           WL_DATA_SOURCE_ACTION_SINCE_VERSION)
-               wl_data_source_send_action(offer->source->resource, action);
-
-       if (wl_resource_get_version(offer->resource) >=
-           WL_DATA_OFFER_ACTION_SINCE_VERSION)
-               wl_data_offer_send_action(offer->resource, action);
-}
-
-static void
-data_offer_set_actions(struct wl_client *client,
-                      struct wl_resource *resource,
-                      uint32_t dnd_actions, uint32_t preferred_action)
-{
-       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
-       if (dnd_actions & ~ALL_ACTIONS) {
-               wl_resource_post_error(offer->resource,
-                                      WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK,
-                                      "invalid action mask %x", dnd_actions);
-               return;
-       }
-
-       if (preferred_action &&
-           (!(preferred_action & dnd_actions) ||
-            __builtin_popcount(preferred_action) > 1)) {
-               wl_resource_post_error(offer->resource,
-                                      WL_DATA_OFFER_ERROR_INVALID_ACTION,
-                                      "invalid action %x", preferred_action);
-               return;
-       }
-
-       offer->dnd_actions = dnd_actions;
-       offer->preferred_dnd_action = preferred_action;
-       data_offer_update_action(offer);
-}
-
-static void
-data_offer_finish(struct wl_client *client, struct wl_resource *resource)
-{
-       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
-       if (!offer->source || offer->source->offer != offer)
-               return;
-
-       /* Disallow finish while we have a grab driving drag-and-drop, or
-        * if the negotiation is not at the right stage
-        */
-       if (offer->source->seat ||
-           !offer->source->accepted) {
-               wl_resource_post_error(offer->resource,
-                                      WL_DATA_OFFER_ERROR_INVALID_FINISH,
-                                      "premature finish request");
-               return;
-       }
-
-       switch (offer->source->current_dnd_action) {
-       case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
-       case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
-               wl_resource_post_error(offer->resource,
-                                      WL_DATA_OFFER_ERROR_INVALID_OFFER,
-                                      "offer finished with an invalid action");
-               return;
-       default:
-               break;
-       }
-
-       data_source_notify_finish(offer->source);
-}
-
-static const struct wl_data_offer_interface data_offer_interface = {
-       data_offer_accept,
-       data_offer_receive,
-       data_offer_destroy,
-       data_offer_finish,
-       data_offer_set_actions,
-};
-
-static void
-destroy_data_offer(struct wl_resource *resource)
-{
-       struct weston_data_offer *offer = wl_resource_get_user_data(resource);
-
-       if (!offer->source)
-               goto out;
-
-       wl_list_remove(&offer->source_destroy_listener.link);
-
-       if (offer->source->offer != offer)
-               goto out;
-
-       /* If the drag destination has version < 3, wl_data_offer.finish
-        * won't be called, so do this here as a safety net, because
-        * we still want the version >=3 drag source to be happy.
-        */
-       if (wl_resource_get_version(offer->resource) <
-           WL_DATA_OFFER_ACTION_SINCE_VERSION) {
-               data_source_notify_finish(offer->source);
-       } else if (offer->source->resource &&
-                  wl_resource_get_version(offer->source->resource) >=
-                  WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
-               wl_data_source_send_cancelled(offer->source->resource);
-       }
-
-       offer->source->offer = NULL;
-out:
-       free(offer);
-}
-
-static void
-destroy_offer_data_source(struct wl_listener *listener, void *data)
-{
-       struct weston_data_offer *offer;
-
-       offer = container_of(listener, struct weston_data_offer,
-                            source_destroy_listener);
-
-       offer->source = NULL;
-}
-
-static struct weston_data_offer *
-weston_data_source_send_offer(struct weston_data_source *source,
-                             struct wl_resource *target)
-{
-       struct weston_data_offer *offer;
-       char **p;
-
-       offer = malloc(sizeof *offer);
-       if (offer == NULL)
-               return NULL;
-
-       offer->resource =
-               wl_resource_create(wl_resource_get_client(target),
-                                  &wl_data_offer_interface,
-                                  wl_resource_get_version(target), 0);
-       if (offer->resource == NULL) {
-               free(offer);
-               return NULL;
-       }
-
-       wl_resource_set_implementation(offer->resource, &data_offer_interface,
-                                      offer, destroy_data_offer);
-
-       offer->in_ask = false;
-       offer->dnd_actions = 0;
-       offer->preferred_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-       offer->source = source;
-       offer->source_destroy_listener.notify = destroy_offer_data_source;
-       wl_signal_add(&source->destroy_signal,
-                     &offer->source_destroy_listener);
-
-       wl_data_device_send_data_offer(target, offer->resource);
-
-       wl_array_for_each(p, &source->mime_types)
-               wl_data_offer_send_offer(offer->resource, *p);
-
-       source->offer = offer;
-       source->accepted = false;
-
-       return offer;
-}
-
-static void
-data_source_offer(struct wl_client *client,
-                 struct wl_resource *resource,
-                 const char *type)
-{
-       struct weston_data_source *source =
-               wl_resource_get_user_data(resource);
-       char **p;
-
-       p = wl_array_add(&source->mime_types, sizeof *p);
-       if (p)
-               *p = strdup(type);
-       if (!p || !*p)
-               wl_resource_post_no_memory(resource);
-}
-
-static void
-data_source_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-data_source_set_actions(struct wl_client *client,
-                       struct wl_resource *resource,
-                       uint32_t dnd_actions)
-{
-       struct weston_data_source *source =
-               wl_resource_get_user_data(resource);
-
-       if (source->actions_set) {
-               wl_resource_post_error(source->resource,
-                                      WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
-                                      "cannot set actions more than once");
-               return;
-       }
-
-       if (dnd_actions & ~ALL_ACTIONS) {
-               wl_resource_post_error(source->resource,
-                                      WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
-                                      "invalid action mask %x", dnd_actions);
-               return;
-       }
-
-       if (source->seat) {
-               wl_resource_post_error(source->resource,
-                                      WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK,
-                                      "invalid action change after "
-                                      "wl_data_device.start_drag");
-               return;
-       }
-
-       source->dnd_actions = dnd_actions;
-       source->actions_set = true;
-}
-
-static struct wl_data_source_interface data_source_interface = {
-       data_source_offer,
-       data_source_destroy,
-       data_source_set_actions
-};
-
-static void
-drag_surface_configure(struct weston_drag *drag,
-                      struct weston_pointer *pointer,
-                      struct weston_touch *touch,
-                      struct weston_surface *es,
-                      int32_t sx, int32_t sy)
-{
-       struct weston_layer_entry *list;
-       float fx, fy;
-
-       assert((pointer != NULL && touch == NULL) ||
-                       (pointer == NULL && touch != NULL));
-
-       if (!weston_surface_is_mapped(es) && es->buffer_ref.buffer) {
-               if (pointer && pointer->sprite &&
-                       weston_view_is_mapped(pointer->sprite))
-                       list = &pointer->sprite->layer_link;
-               else
-                       list = &es->compositor->cursor_layer.view_list;
-
-               weston_layer_entry_remove(&drag->icon->layer_link);
-               weston_layer_entry_insert(list, &drag->icon->layer_link);
-               weston_view_update_transform(drag->icon);
-               pixman_region32_clear(&es->pending.input);
-       }
-
-       drag->dx += sx;
-       drag->dy += sy;
-
-       /* init to 0 for avoiding a compile warning */
-       fx = fy = 0;
-       if (pointer) {
-               fx = wl_fixed_to_double(pointer->x) + drag->dx;
-               fy = wl_fixed_to_double(pointer->y) + drag->dy;
-       } else if (touch) {
-               fx = wl_fixed_to_double(touch->grab_x) + drag->dx;
-               fy = wl_fixed_to_double(touch->grab_y) + drag->dy;
-       }
-       weston_view_set_position(drag->icon, fx, fy);
-}
-
-static int
-pointer_drag_surface_get_label(struct weston_surface *surface,
-                              char *buf, size_t len)
-{
-       return snprintf(buf, len, "pointer drag icon");
-}
-
-static void
-pointer_drag_surface_configure(struct weston_surface *es,
-                              int32_t sx, int32_t sy)
-{
-       struct weston_pointer_drag *drag = es->configure_private;
-       struct weston_pointer *pointer = drag->grab.pointer;
-
-       assert(es->configure == pointer_drag_surface_configure);
-
-       drag_surface_configure(&drag->base, pointer, NULL, es, sx, sy);
-}
-
-static int
-touch_drag_surface_get_label(struct weston_surface *surface,
-                            char *buf, size_t len)
-{
-       return snprintf(buf, len, "touch drag icon");
-}
-
-static void
-touch_drag_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
-{
-       struct weston_touch_drag *drag = es->configure_private;
-       struct weston_touch *touch = drag->grab.touch;
-
-       assert(es->configure == touch_drag_surface_configure);
-
-       drag_surface_configure(&drag->base, NULL, touch, es, sx, sy);
-}
-
-static void
-destroy_drag_focus(struct wl_listener *listener, void *data)
-{
-       struct weston_drag *drag =
-               container_of(listener, struct weston_drag, focus_listener);
-
-       drag->focus_resource = NULL;
-}
-
-static void
-weston_drag_set_focus(struct weston_drag *drag,
-                       struct weston_seat *seat,
-                       struct weston_view *view,
-                       wl_fixed_t sx, wl_fixed_t sy)
-{
-       struct wl_resource *resource, *offer_resource = NULL;
-       struct wl_display *display = seat->compositor->wl_display;
-       struct weston_data_offer *offer;
-       uint32_t serial;
-
-       if (drag->focus && view && drag->focus->surface == view->surface) {
-               drag->focus = view;
-               return;
-       }
-
-       if (drag->focus_resource) {
-               wl_data_device_send_leave(drag->focus_resource);
-               wl_list_remove(&drag->focus_listener.link);
-               drag->focus_resource = NULL;
-               drag->focus = NULL;
-       }
-
-       if (!view || !view->surface->resource)
-               return;
-
-       if (!drag->data_source &&
-           wl_resource_get_client(view->surface->resource) != drag->client)
-               return;
-
-       if (drag->data_source &&
-           drag->data_source->offer) {
-               /* Unlink the offer from the source */
-               offer = drag->data_source->offer;
-               offer->source = NULL;
-               drag->data_source->offer = NULL;
-               wl_list_remove(&offer->source_destroy_listener.link);
-       }
-
-       resource = wl_resource_find_for_client(&seat->drag_resource_list,
-                                              wl_resource_get_client(view->surface->resource));
-       if (!resource)
-               return;
-
-       serial = wl_display_next_serial(display);
-
-       if (drag->data_source) {
-               drag->data_source->accepted = false;
-               offer = weston_data_source_send_offer(drag->data_source, resource);
-               if (offer == NULL)
-                       return;
-
-               data_offer_update_action(offer);
-
-               offer_resource = offer->resource;
-               if (wl_resource_get_version (offer_resource) >=
-                   WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION) {
-                       wl_data_offer_send_source_actions (offer_resource,
-                                                          drag->data_source->dnd_actions);
-               }
-       }
-
-       wl_data_device_send_enter(resource, serial, view->surface->resource,
-                                 sx, sy, offer_resource);
-
-       drag->focus = view;
-       drag->focus_listener.notify = destroy_drag_focus;
-       wl_resource_add_destroy_listener(resource, &drag->focus_listener);
-       drag->focus_resource = resource;
-}
-
-static void
-drag_grab_focus(struct weston_pointer_grab *grab)
-{
-       struct weston_pointer_drag *drag =
-               container_of(grab, struct weston_pointer_drag, grab);
-       struct weston_pointer *pointer = grab->pointer;
-       struct weston_view *view;
-       wl_fixed_t sx, sy;
-
-       view = weston_compositor_pick_view(pointer->seat->compositor,
-                                          pointer->x, pointer->y,
-                                          &sx, &sy);
-       if (drag->base.focus != view)
-               weston_drag_set_focus(&drag->base, pointer->seat, view, sx, sy);
-}
-
-static void
-drag_grab_motion(struct weston_pointer_grab *grab, uint32_t time,
-                struct weston_pointer_motion_event *event)
-{
-       struct weston_pointer_drag *drag =
-               container_of(grab, struct weston_pointer_drag, grab);
-       struct weston_pointer *pointer = drag->grab.pointer;
-       float fx, fy;
-       wl_fixed_t sx, sy;
-
-       weston_pointer_move(pointer, event);
-
-       if (drag->base.icon) {
-               fx = wl_fixed_to_double(pointer->x) + drag->base.dx;
-               fy = wl_fixed_to_double(pointer->y) + drag->base.dy;
-               weston_view_set_position(drag->base.icon, fx, fy);
-               weston_view_schedule_repaint(drag->base.icon);
-       }
-
-       if (drag->base.focus_resource) {
-               weston_view_from_global_fixed(drag->base.focus,
-                                             pointer->x, pointer->y,
-                                             &sx, &sy);
-
-               wl_data_device_send_motion(drag->base.focus_resource, time, sx, sy);
-       }
-}
-
-static void
-data_device_end_drag_grab(struct weston_drag *drag,
-               struct weston_seat *seat)
-{
-       if (drag->icon) {
-               if (weston_view_is_mapped(drag->icon))
-                       weston_view_unmap(drag->icon);
-
-               drag->icon->surface->configure = NULL;
-               weston_surface_set_label_func(drag->icon->surface, NULL);
-               pixman_region32_clear(&drag->icon->surface->pending.input);
-               wl_list_remove(&drag->icon_destroy_listener.link);
-               weston_view_destroy(drag->icon);
-       }
-
-       weston_drag_set_focus(drag, seat, NULL, 0, 0);
-}
-
-static void
-data_device_end_pointer_drag_grab(struct weston_pointer_drag *drag)
-{
-       struct weston_pointer *pointer = drag->grab.pointer;
-       struct weston_keyboard *keyboard = drag->base.keyboard_grab.keyboard;
-
-       data_device_end_drag_grab(&drag->base, pointer->seat);
-       weston_pointer_end_grab(pointer);
-       weston_keyboard_end_grab(keyboard);
-       free(drag);
-}
-
-static void
-drag_grab_button(struct weston_pointer_grab *grab,
-                uint32_t time, uint32_t button, uint32_t state_w)
-{
-       struct weston_pointer_drag *drag =
-               container_of(grab, struct weston_pointer_drag, grab);
-       struct weston_pointer *pointer = drag->grab.pointer;
-       enum wl_pointer_button_state state = state_w;
-       struct weston_data_source *data_source = drag->base.data_source;
-
-       if (data_source &&
-           pointer->grab_button == button &&
-           state == WL_POINTER_BUTTON_STATE_RELEASED) {
-               if (drag->base.focus_resource &&
-                   data_source->accepted &&
-                   data_source->current_dnd_action) {
-                       wl_data_device_send_drop(drag->base.focus_resource);
-
-                       if (wl_resource_get_version(data_source->resource) >=
-                           WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION)
-                               wl_data_source_send_dnd_drop_performed(data_source->resource);
-
-                       data_source->offer->in_ask =
-                               data_source->current_dnd_action ==
-                               WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK;
-
-                       data_source->seat = NULL;
-               } else if (wl_resource_get_version(data_source->resource) >=
-                          WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION) {
-                       wl_data_source_send_cancelled(data_source->resource);
-               }
-       }
-
-       if (pointer->button_count == 0 &&
-           state == WL_POINTER_BUTTON_STATE_RELEASED) {
-               if (drag->base.data_source)
-                       wl_list_remove(&drag->base.data_source_listener.link);
-               data_device_end_pointer_drag_grab(drag);
-       }
-}
-
-static void
-drag_grab_axis(struct weston_pointer_grab *grab,
-              uint32_t time, struct weston_pointer_axis_event *event)
-{
-}
-
-static void
-drag_grab_axis_source(struct weston_pointer_grab *grab, uint32_t source)
-{
-}
-
-static void
-drag_grab_frame(struct weston_pointer_grab *grab)
-{
-}
-
-static void
-drag_grab_cancel(struct weston_pointer_grab *grab)
-{
-       struct weston_pointer_drag *drag =
-               container_of(grab, struct weston_pointer_drag, grab);
-
-       if (drag->base.data_source)
-               wl_list_remove(&drag->base.data_source_listener.link);
-
-       data_device_end_pointer_drag_grab(drag);
-}
-
-static const struct weston_pointer_grab_interface pointer_drag_grab_interface = {
-       drag_grab_focus,
-       drag_grab_motion,
-       drag_grab_button,
-       drag_grab_axis,
-       drag_grab_axis_source,
-       drag_grab_frame,
-       drag_grab_cancel,
-};
-
-static void
-drag_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
-               int touch_id, wl_fixed_t sx, wl_fixed_t sy)
-{
-}
-
-static void
-data_device_end_touch_drag_grab(struct weston_touch_drag *drag)
-{
-       struct weston_touch *touch = drag->grab.touch;
-       struct weston_keyboard *keyboard = drag->base.keyboard_grab.keyboard;
-
-       data_device_end_drag_grab(&drag->base, touch->seat);
-       weston_touch_end_grab(touch);
-       weston_keyboard_end_grab(keyboard);
-       free(drag);
-}
-
-static void
-drag_grab_touch_up(struct weston_touch_grab *grab,
-               uint32_t time, int touch_id)
-{
-       struct weston_touch_drag *touch_drag =
-               container_of(grab, struct weston_touch_drag, grab);
-       struct weston_touch *touch = grab->touch;
-
-       if (touch_id != touch->grab_touch_id)
-               return;
-
-       if (touch_drag->base.focus_resource)
-               wl_data_device_send_drop(touch_drag->base.focus_resource);
-       if (touch_drag->base.data_source)
-               wl_list_remove(&touch_drag->base.data_source_listener.link);
-       data_device_end_touch_drag_grab(touch_drag);
-}
-
-static void
-drag_grab_touch_focus(struct weston_touch_drag *drag)
-{
-       struct weston_touch *touch = drag->grab.touch;
-       struct weston_view *view;
-       wl_fixed_t view_x, view_y;
-
-       view = weston_compositor_pick_view(touch->seat->compositor,
-                               touch->grab_x, touch->grab_y,
-                               &view_x, &view_y);
-       if (drag->base.focus != view)
-               weston_drag_set_focus(&drag->base, touch->seat,
-                               view, view_x, view_y);
-}
-
-static void
-drag_grab_touch_motion(struct weston_touch_grab *grab, uint32_t time,
-               int touch_id, wl_fixed_t x, wl_fixed_t y)
-{
-       struct weston_touch_drag *touch_drag =
-               container_of(grab, struct weston_touch_drag, grab);
-       struct weston_touch *touch = grab->touch;
-       wl_fixed_t view_x, view_y;
-       float fx, fy;
-
-       if (touch_id != touch->grab_touch_id)
-               return;
-
-       drag_grab_touch_focus(touch_drag);
-       if (touch_drag->base.icon) {
-               fx = wl_fixed_to_double(touch->grab_x) + touch_drag->base.dx;
-               fy = wl_fixed_to_double(touch->grab_y) + touch_drag->base.dy;
-               weston_view_set_position(touch_drag->base.icon, fx, fy);
-               weston_view_schedule_repaint(touch_drag->base.icon);
-       }
-
-       if (touch_drag->base.focus_resource) {
-               weston_view_from_global_fixed(touch_drag->base.focus,
-                                       touch->grab_x, touch->grab_y,
-                                       &view_x, &view_y);
-               wl_data_device_send_motion(touch_drag->base.focus_resource, time,
-                                       view_x, view_y);
-       }
-}
-
-static void
-drag_grab_touch_frame(struct weston_touch_grab *grab)
-{
-}
-
-static void
-drag_grab_touch_cancel(struct weston_touch_grab *grab)
-{
-       struct weston_touch_drag *touch_drag =
-               container_of(grab, struct weston_touch_drag, grab);
-
-       if (touch_drag->base.data_source)
-               wl_list_remove(&touch_drag->base.data_source_listener.link);
-       data_device_end_touch_drag_grab(touch_drag);
-}
-
-static const struct weston_touch_grab_interface touch_drag_grab_interface = {
-       drag_grab_touch_down,
-       drag_grab_touch_up,
-       drag_grab_touch_motion,
-       drag_grab_touch_frame,
-       drag_grab_touch_cancel
-};
-
-static void
-drag_grab_keyboard_key(struct weston_keyboard_grab *grab,
-                      uint32_t time, uint32_t key, uint32_t state)
-{
-}
-
-static void
-drag_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
-                            uint32_t serial, uint32_t mods_depressed,
-                            uint32_t mods_latched,
-                            uint32_t mods_locked, uint32_t group)
-{
-       struct weston_keyboard *keyboard = grab->keyboard;
-       struct weston_drag *drag =
-               container_of(grab, struct weston_drag, keyboard_grab);
-       uint32_t compositor_action;
-
-       if (mods_depressed & (1 << keyboard->xkb_info->shift_mod))
-               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE;
-       else if (mods_depressed & (1 << keyboard->xkb_info->ctrl_mod))
-               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
-       else
-               compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
-       drag->data_source->compositor_action = compositor_action;
-
-       if (drag->data_source->offer)
-               data_offer_update_action(drag->data_source->offer);
-}
-
-static void
-drag_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
-{
-       struct weston_drag *drag =
-               container_of(grab, struct weston_drag, keyboard_grab);
-       struct weston_pointer *pointer = grab->keyboard->seat->pointer_state;
-       struct weston_touch *touch = grab->keyboard->seat->touch_state;
-
-       if (pointer && pointer->grab->interface == &pointer_drag_grab_interface) {
-               struct weston_touch_drag *touch_drag =
-                       (struct weston_touch_drag *) drag;
-               drag_grab_touch_cancel(&touch_drag->grab);
-       } else if (touch && touch->grab->interface == &touch_drag_grab_interface) {
-               struct weston_pointer_drag *pointer_drag =
-                       (struct weston_pointer_drag *) drag;
-               drag_grab_cancel(&pointer_drag->grab);
-       }
-}
-
-static const struct weston_keyboard_grab_interface keyboard_drag_grab_interface = {
-       drag_grab_keyboard_key,
-       drag_grab_keyboard_modifiers,
-       drag_grab_keyboard_cancel
-};
-
-static void
-destroy_pointer_data_device_source(struct wl_listener *listener, void *data)
-{
-       struct weston_pointer_drag *drag = container_of(listener,
-                       struct weston_pointer_drag, base.data_source_listener);
-
-       data_device_end_pointer_drag_grab(drag);
-}
-
-static void
-handle_drag_icon_destroy(struct wl_listener *listener, void *data)
-{
-       struct weston_drag *drag = container_of(listener, struct weston_drag,
-                                               icon_destroy_listener);
-
-       drag->icon = NULL;
-}
-
-WL_EXPORT int
-weston_pointer_start_drag(struct weston_pointer *pointer,
-                      struct weston_data_source *source,
-                      struct weston_surface *icon,
-                      struct wl_client *client)
-{
-       struct weston_pointer_drag *drag;
-       struct weston_keyboard *keyboard =
-               weston_seat_get_keyboard(pointer->seat);
-
-       drag = zalloc(sizeof *drag);
-       if (drag == NULL)
-               return -1;
-
-       drag->grab.interface = &pointer_drag_grab_interface;
-       drag->base.keyboard_grab.interface = &keyboard_drag_grab_interface;
-       drag->base.client = client;
-       drag->base.data_source = source;
-
-       if (icon) {
-               drag->base.icon = weston_view_create(icon);
-               if (drag->base.icon == NULL) {
-                       free(drag);
-                       return -1;
-               }
-
-               drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
-               wl_signal_add(&icon->destroy_signal,
-                             &drag->base.icon_destroy_listener);
-
-               icon->configure = pointer_drag_surface_configure;
-               icon->configure_private = drag;
-               weston_surface_set_label_func(icon,
-                                       pointer_drag_surface_get_label);
-       } else {
-               drag->base.icon = NULL;
-       }
-
-       if (source) {
-               drag->base.data_source_listener.notify = destroy_pointer_data_device_source;
-               wl_signal_add(&source->destroy_signal,
-                             &drag->base.data_source_listener);
-       }
-
-       weston_pointer_clear_focus(pointer);
-       weston_keyboard_set_focus(keyboard, NULL);
-
-       weston_pointer_start_grab(pointer, &drag->grab);
-       weston_keyboard_start_grab(keyboard, &drag->base.keyboard_grab);
-
-       return 0;
-}
-
-static void
-destroy_touch_data_device_source(struct wl_listener *listener, void *data)
-{
-       struct weston_touch_drag *drag = container_of(listener,
-                       struct weston_touch_drag, base.data_source_listener);
-
-       data_device_end_touch_drag_grab(drag);
-}
-
-WL_EXPORT int
-weston_touch_start_drag(struct weston_touch *touch,
-                      struct weston_data_source *source,
-                      struct weston_surface *icon,
-                      struct wl_client *client)
-{
-       struct weston_touch_drag *drag;
-       struct weston_keyboard *keyboard =
-               weston_seat_get_keyboard(touch->seat);
-
-       drag = zalloc(sizeof *drag);
-       if (drag == NULL)
-               return -1;
-
-       drag->grab.interface = &touch_drag_grab_interface;
-       drag->base.client = client;
-       drag->base.data_source = source;
-
-       if (icon) {
-               drag->base.icon = weston_view_create(icon);
-               if (drag->base.icon == NULL) {
-                       free(drag);
-                       return -1;
-               }
-
-               drag->base.icon_destroy_listener.notify = handle_drag_icon_destroy;
-               wl_signal_add(&icon->destroy_signal,
-                             &drag->base.icon_destroy_listener);
-
-               icon->configure = touch_drag_surface_configure;
-               icon->configure_private = drag;
-               weston_surface_set_label_func(icon,
-                                       touch_drag_surface_get_label);
-       } else {
-               drag->base.icon = NULL;
-       }
-
-       if (source) {
-               drag->base.data_source_listener.notify = destroy_touch_data_device_source;
-               wl_signal_add(&source->destroy_signal,
-                             &drag->base.data_source_listener);
-       }
-
-       weston_keyboard_set_focus(keyboard, NULL);
-
-       weston_touch_start_grab(touch, &drag->grab);
-       weston_keyboard_start_grab(keyboard, &drag->base.keyboard_grab);
-
-       drag_grab_touch_focus(drag);
-
-       return 0;
-}
-
-static void
-data_device_start_drag(struct wl_client *client, struct wl_resource *resource,
-                      struct wl_resource *source_resource,
-                      struct wl_resource *origin_resource,
-                      struct wl_resource *icon_resource, uint32_t serial)
-{
-       struct weston_seat *seat = wl_resource_get_user_data(resource);
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-       struct weston_touch *touch = weston_seat_get_touch(seat);
-       struct weston_surface *origin = wl_resource_get_user_data(origin_resource);
-       struct weston_data_source *source = NULL;
-       struct weston_surface *icon = NULL;
-       int is_pointer_grab, is_touch_grab;
-       int32_t ret = 0;
-
-       is_pointer_grab = pointer &&
-                         pointer->button_count == 1 &&
-                         pointer->grab_serial == serial &&
-                         pointer->focus &&
-                         pointer->focus->surface == origin;
-
-       is_touch_grab = touch &&
-                       touch->num_tp == 1 &&
-                       touch->grab_serial == serial &&
-                       touch->focus &&
-                       touch->focus->surface == origin;
-
-       if (!is_pointer_grab && !is_touch_grab)
-               return;
-
-       /* FIXME: Check that the data source type array isn't empty. */
-
-       if (source_resource)
-               source = wl_resource_get_user_data(source_resource);
-       if (icon_resource)
-               icon = wl_resource_get_user_data(icon_resource);
-
-       if (icon) {
-               if (weston_surface_set_role(icon, "wl_data_device-icon",
-                                           resource,
-                                           WL_DATA_DEVICE_ERROR_ROLE) < 0)
-                       return;
-       }
-
-       if (is_pointer_grab)
-               ret = weston_pointer_start_drag(pointer, source, icon, client);
-       else if (is_touch_grab)
-               ret = weston_touch_start_drag(touch, source, icon, client);
-
-       if (ret < 0)
-               wl_resource_post_no_memory(resource);
-       else
-               source->seat = seat;
-}
-
-static void
-destroy_selection_data_source(struct wl_listener *listener, void *data)
-{
-       struct weston_seat *seat = container_of(listener, struct weston_seat,
-                                               selection_data_source_listener);
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       struct wl_resource *data_device;
-       struct weston_surface *focus = NULL;
-
-       seat->selection_data_source = NULL;
-
-       if (keyboard)
-               focus = keyboard->focus;
-       if (focus && focus->resource) {
-               data_device = wl_resource_find_for_client(&seat->drag_resource_list,
-                                                         wl_resource_get_client(focus->resource));
-               if (data_device)
-                       wl_data_device_send_selection(data_device, NULL);
-       }
-
-       wl_signal_emit(&seat->selection_signal, seat);
-}
-
-/** \brief Send the selection to the specified client
- *
- * This function creates a new wl_data_offer if there is a wl_data_source
- * currently set as the selection and sends it to the specified client,
- * followed by the wl_data_device.selection() event.
- * If there is no current selection the wl_data_device.selection() event
- * will carry a NULL wl_data_offer.
- *
- * If the client does not have a wl_data_device for the specified seat
- * nothing will be done.
- *
- * \param seat The seat owning the wl_data_device used to send the events.
- * \param client The client to which to send the selection.
- */
-WL_EXPORT void
-weston_seat_send_selection(struct weston_seat *seat, struct wl_client *client)
-{
-       struct weston_data_offer *offer;
-       struct wl_resource *data_device;
-
-       wl_resource_for_each(data_device, &seat->drag_resource_list) {
-               if (wl_resource_get_client(data_device) != client)
-                   continue;
-
-               if (seat->selection_data_source) {
-                       offer = weston_data_source_send_offer(seat->selection_data_source,
-                                                             data_device);
-                       wl_data_device_send_selection(data_device, offer->resource);
-               } else {
-                       wl_data_device_send_selection(data_device, NULL);
-               }
-       }
-}
-
-WL_EXPORT void
-weston_seat_set_selection(struct weston_seat *seat,
-                         struct weston_data_source *source, uint32_t serial)
-{
-       struct weston_surface *focus = NULL;
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-
-       if (seat->selection_data_source &&
-           seat->selection_serial - serial < UINT32_MAX / 2)
-               return;
-
-       if (seat->selection_data_source) {
-               seat->selection_data_source->cancel(seat->selection_data_source);
-               wl_list_remove(&seat->selection_data_source_listener.link);
-               seat->selection_data_source = NULL;
-       }
-
-       seat->selection_data_source = source;
-       seat->selection_serial = serial;
-
-       if (keyboard)
-               focus = keyboard->focus;
-       if (focus && focus->resource) {
-               weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
-       }
-
-       wl_signal_emit(&seat->selection_signal, seat);
-
-       if (source) {
-               seat->selection_data_source_listener.notify =
-                       destroy_selection_data_source;
-               wl_signal_add(&source->destroy_signal,
-                             &seat->selection_data_source_listener);
-       }
-}
-
-static void
-data_device_set_selection(struct wl_client *client,
-                         struct wl_resource *resource,
-                         struct wl_resource *source_resource, uint32_t serial)
-{
-       struct weston_data_source *source;
-
-       if (!source_resource)
-               return;
-
-       source = wl_resource_get_user_data(source_resource);
-
-       if (source->actions_set) {
-               wl_resource_post_error(source_resource,
-                                      WL_DATA_SOURCE_ERROR_INVALID_SOURCE,
-                                      "cannot set drag-and-drop source as selection");
-               return;
-       }
-
-       /* FIXME: Store serial and check against incoming serial here. */
-       weston_seat_set_selection(wl_resource_get_user_data(resource),
-                                 source, serial);
-}
-static void
-data_device_release(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static const struct wl_data_device_interface data_device_interface = {
-       data_device_start_drag,
-       data_device_set_selection,
-       data_device_release
-};
-
-static void
-destroy_data_source(struct wl_resource *resource)
-{
-       struct weston_data_source *source =
-               wl_resource_get_user_data(resource);
-       char **p;
-
-       wl_signal_emit(&source->destroy_signal, source);
-
-       wl_array_for_each(p, &source->mime_types)
-               free(*p);
-
-       wl_array_release(&source->mime_types);
-
-       free(source);
-}
-
-static void
-client_source_accept(struct weston_data_source *source,
-                    uint32_t time, const char *mime_type)
-{
-       wl_data_source_send_target(source->resource, mime_type);
-}
-
-static void
-client_source_send(struct weston_data_source *source,
-                  const char *mime_type, int32_t fd)
-{
-       wl_data_source_send_send(source->resource, mime_type, fd);
-       close(fd);
-}
-
-static void
-client_source_cancel(struct weston_data_source *source)
-{
-       wl_data_source_send_cancelled(source->resource);
-}
-
-static void
-create_data_source(struct wl_client *client,
-                  struct wl_resource *resource, uint32_t id)
-{
-       struct weston_data_source *source;
-
-       source = malloc(sizeof *source);
-       if (source == NULL) {
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-
-       source->resource =
-               wl_resource_create(client, &wl_data_source_interface,
-                                  wl_resource_get_version(resource), id);
-       if (source->resource == NULL) {
-               free(source);
-               wl_resource_post_no_memory(resource);
-               return;
-       }
-
-       wl_signal_init(&source->destroy_signal);
-       source->accept = client_source_accept;
-       source->send = client_source_send;
-       source->cancel = client_source_cancel;
-       source->offer = NULL;
-       source->accepted = false;
-       source->seat = NULL;
-       source->actions_set = false;
-       source->dnd_actions = 0;
-       source->current_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-       source->compositor_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
-       wl_array_init(&source->mime_types);
-
-       wl_resource_set_implementation(source->resource, &data_source_interface,
-                                      source, destroy_data_source);
-}
-
-static void unbind_data_device(struct wl_resource *resource)
-{
-       wl_list_remove(wl_resource_get_link(resource));
-}
-
-static void
-get_data_device(struct wl_client *client,
-               struct wl_resource *manager_resource,
-               uint32_t id, struct wl_resource *seat_resource)
-{
-       struct weston_seat *seat = wl_resource_get_user_data(seat_resource);
-       struct wl_resource *resource;
-
-       resource = wl_resource_create(client,
-                                     &wl_data_device_interface,
-                                     wl_resource_get_version(manager_resource),
-                                     id);
-       if (resource == NULL) {
-               wl_resource_post_no_memory(manager_resource);
-               return;
-       }
-
-       wl_list_insert(&seat->drag_resource_list,
-                      wl_resource_get_link(resource));
-       wl_resource_set_implementation(resource, &data_device_interface,
-                                      seat, unbind_data_device);
-}
-
-static const struct wl_data_device_manager_interface manager_interface = {
-       create_data_source,
-       get_data_device
-};
-
-static void
-bind_manager(struct wl_client *client,
-            void *data, uint32_t version, uint32_t id)
-{
-       struct wl_resource *resource;
-
-       resource = wl_resource_create(client,
-                                     &wl_data_device_manager_interface,
-                                     version, id);
-       if (resource == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       wl_resource_set_implementation(resource, &manager_interface,
-                                      NULL, NULL);
-}
-
-WL_EXPORT void
-wl_data_device_set_keyboard_focus(struct weston_seat *seat)
-{
-       struct weston_surface *focus;
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-
-       if (!keyboard)
-               return;
-
-       focus = keyboard->focus;
-       if (!focus || !focus->resource)
-               return;
-
-       weston_seat_send_selection(seat, wl_resource_get_client(focus->resource));
-}
-
-WL_EXPORT int
-wl_data_device_manager_init(struct wl_display *display)
-{
-       if (wl_global_create(display,
-                            &wl_data_device_manager_interface, 3,
-                            NULL, bind_manager) == NULL)
-               return -1;
-
-       return 0;
-}
diff --git a/src/dbus.c b/src/dbus.c
deleted file mode 100644 (file)
index cadedd9..0000000
+++ /dev/null
@@ -1,407 +0,0 @@
-/*
- * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-/*
- * DBus Helpers
- * This file contains the dbus mainloop integration and several helpers to
- * make lowlevel libdbus access easier.
- */
-
-#include "config.h"
-
-#include <dbus/dbus.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/epoll.h>
-#include <sys/eventfd.h>
-#include <sys/timerfd.h>
-#include <unistd.h>
-#include <wayland-server.h>
-
-#include "compositor.h"
-#include "dbus.h"
-
-/*
- * DBus Mainloop Integration
- * weston_dbus_bind() and weston_dbus_unbind() allow to bind an existing
- * DBusConnection to an existing wl_event_loop object. All dbus dispatching
- * is then nicely integrated into the wayland event loop.
- * Note that this only provides basic watch and timeout dispatching. No
- * remote thread wakeup, signal handling or other dbus insanity is supported.
- * This is fine as long as you don't use any of the deprecated libdbus
- * interfaces (like waking up remote threads..). There is really no rational
- * reason to support these.
- */
-
-static int weston_dbus_dispatch_watch(int fd, uint32_t mask, void *data)
-{
-       DBusWatch *watch = data;
-       uint32_t flags = 0;
-
-       if (dbus_watch_get_enabled(watch)) {
-               if (mask & WL_EVENT_READABLE)
-                       flags |= DBUS_WATCH_READABLE;
-               if (mask & WL_EVENT_WRITABLE)
-                       flags |= DBUS_WATCH_WRITABLE;
-               if (mask & WL_EVENT_HANGUP)
-                       flags |= DBUS_WATCH_HANGUP;
-               if (mask & WL_EVENT_ERROR)
-                       flags |= DBUS_WATCH_ERROR;
-
-               dbus_watch_handle(watch, flags);
-       }
-
-       return 0;
-}
-
-static dbus_bool_t weston_dbus_add_watch(DBusWatch *watch, void *data)
-{
-       struct wl_event_loop *loop = data;
-       struct wl_event_source *s;
-       int fd;
-       uint32_t mask = 0, flags;
-
-       if (dbus_watch_get_enabled(watch)) {
-               flags = dbus_watch_get_flags(watch);
-               if (flags & DBUS_WATCH_READABLE)
-                       mask |= WL_EVENT_READABLE;
-               if (flags & DBUS_WATCH_WRITABLE)
-                       mask |= WL_EVENT_WRITABLE;
-       }
-
-       fd = dbus_watch_get_unix_fd(watch);
-       s = wl_event_loop_add_fd(loop, fd, mask, weston_dbus_dispatch_watch,
-                                watch);
-       if (!s)
-               return FALSE;
-
-       dbus_watch_set_data(watch, s, NULL);
-       return TRUE;
-}
-
-static void weston_dbus_remove_watch(DBusWatch *watch, void *data)
-{
-       struct wl_event_source *s;
-
-       s = dbus_watch_get_data(watch);
-       if (!s)
-               return;
-
-       wl_event_source_remove(s);
-}
-
-static void weston_dbus_toggle_watch(DBusWatch *watch, void *data)
-{
-       struct wl_event_source *s;
-       uint32_t mask = 0, flags;
-
-       s = dbus_watch_get_data(watch);
-       if (!s)
-               return;
-
-       if (dbus_watch_get_enabled(watch)) {
-               flags = dbus_watch_get_flags(watch);
-               if (flags & DBUS_WATCH_READABLE)
-                       mask |= WL_EVENT_READABLE;
-               if (flags & DBUS_WATCH_WRITABLE)
-                       mask |= WL_EVENT_WRITABLE;
-       }
-
-       wl_event_source_fd_update(s, mask);
-}
-
-static int weston_dbus_dispatch_timeout(void *data)
-{
-       DBusTimeout *timeout = data;
-
-       if (dbus_timeout_get_enabled(timeout))
-               dbus_timeout_handle(timeout);
-
-       return 0;
-}
-
-static int weston_dbus_adjust_timeout(DBusTimeout *timeout,
-                                     struct wl_event_source *s)
-{
-       int64_t t = 0;
-
-       if (dbus_timeout_get_enabled(timeout))
-               t = dbus_timeout_get_interval(timeout);
-
-       return wl_event_source_timer_update(s, t);
-}
-
-static dbus_bool_t weston_dbus_add_timeout(DBusTimeout *timeout, void *data)
-{
-       struct wl_event_loop *loop = data;
-       struct wl_event_source *s;
-       int r;
-
-       s = wl_event_loop_add_timer(loop, weston_dbus_dispatch_timeout,
-                                   timeout);
-       if (!s)
-               return FALSE;
-
-       r = weston_dbus_adjust_timeout(timeout, s);
-       if (r < 0) {
-               wl_event_source_remove(s);
-               return FALSE;
-       }
-
-       dbus_timeout_set_data(timeout, s, NULL);
-       return TRUE;
-}
-
-static void weston_dbus_remove_timeout(DBusTimeout *timeout, void *data)
-{
-       struct wl_event_source *s;
-
-       s = dbus_timeout_get_data(timeout);
-       if (!s)
-               return;
-
-       wl_event_source_remove(s);
-}
-
-static void weston_dbus_toggle_timeout(DBusTimeout *timeout, void *data)
-{
-       struct wl_event_source *s;
-
-       s = dbus_timeout_get_data(timeout);
-       if (!s)
-               return;
-
-       weston_dbus_adjust_timeout(timeout, s);
-}
-
-static int weston_dbus_dispatch(int fd, uint32_t mask, void *data)
-{
-       DBusConnection *c = data;
-       int r;
-
-       do {
-               r = dbus_connection_dispatch(c);
-               if (r == DBUS_DISPATCH_COMPLETE)
-                       r = 0;
-               else if (r == DBUS_DISPATCH_DATA_REMAINS)
-                       r = -EAGAIN;
-               else if (r == DBUS_DISPATCH_NEED_MEMORY)
-                       r = -ENOMEM;
-               else
-                       r = -EIO;
-       } while (r == -EAGAIN);
-
-       if (r)
-               weston_log("cannot dispatch dbus events: %d\n", r);
-
-       return 0;
-}
-
-static int weston_dbus_bind(struct wl_event_loop *loop, DBusConnection *c,
-                           struct wl_event_source **ctx_out)
-{
-       bool b;
-       int r, fd;
-
-       /* Idle events cannot reschedule themselves, therefore we use a dummy
-        * event-fd and mark it for post-dispatch. Hence, the dbus
-        * dispatcher is called after every dispatch-round.
-        * This is required as dbus doesn't allow dispatching events from
-        * within its own event sources. */
-       fd = eventfd(0, EFD_CLOEXEC);
-       if (fd < 0)
-               return -errno;
-
-       *ctx_out = wl_event_loop_add_fd(loop, fd, 0, weston_dbus_dispatch, c);
-       close(fd);
-
-       if (!*ctx_out)
-               return -ENOMEM;
-
-       wl_event_source_check(*ctx_out);
-
-       b = dbus_connection_set_watch_functions(c,
-                                               weston_dbus_add_watch,
-                                               weston_dbus_remove_watch,
-                                               weston_dbus_toggle_watch,
-                                               loop,
-                                               NULL);
-       if (!b) {
-               r = -ENOMEM;
-               goto error;
-       }
-
-       b = dbus_connection_set_timeout_functions(c,
-                                                 weston_dbus_add_timeout,
-                                                 weston_dbus_remove_timeout,
-                                                 weston_dbus_toggle_timeout,
-                                                 loop,
-                                                 NULL);
-       if (!b) {
-               r = -ENOMEM;
-               goto error;
-       }
-
-       dbus_connection_ref(c);
-       return 0;
-
-error:
-       dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
-                                             NULL, NULL);
-       dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
-                                           NULL, NULL);
-       wl_event_source_remove(*ctx_out);
-       *ctx_out = NULL;
-       return r;
-}
-
-static void weston_dbus_unbind(DBusConnection *c, struct wl_event_source *ctx)
-{
-       dbus_connection_set_timeout_functions(c, NULL, NULL, NULL,
-                                             NULL, NULL);
-       dbus_connection_set_watch_functions(c, NULL, NULL, NULL,
-                                           NULL, NULL);
-       dbus_connection_unref(c);
-       wl_event_source_remove(ctx);
-}
-
-/*
- * Convenience Helpers
- * Several convenience helpers are provided to make using dbus in weston
- * easier. We don't use any of the gdbus or qdbus helpers as they pull in
- * huge dependencies and actually are quite awful to use. Instead, we only
- * use the basic low-level libdbus library.
- */
-
-int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
-                    DBusConnection **out, struct wl_event_source **ctx_out)
-{
-       DBusConnection *c;
-       int r;
-
-       /* Ihhh, global state.. stupid dbus. */
-       dbus_connection_set_change_sigpipe(FALSE);
-
-       /* This is actually synchronous. It blocks for some authentication and
-        * setup. We just trust the dbus-server here and accept this blocking
-        * call. There is no real reason to complicate things further and make
-        * this asynchronous/non-blocking. A context should be created during
-        * thead/process/app setup, so blocking calls should be fine. */
-       c = dbus_bus_get_private(bus, NULL);
-       if (!c)
-               return -EIO;
-
-       dbus_connection_set_exit_on_disconnect(c, FALSE);
-
-       r = weston_dbus_bind(loop, c, ctx_out);
-       if (r < 0)
-               goto error;
-
-       *out = c;
-       return r;
-
-error:
-       dbus_connection_close(c);
-       dbus_connection_unref(c);
-       return r;
-}
-
-void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx)
-{
-       weston_dbus_unbind(c, ctx);
-       dbus_connection_close(c);
-       dbus_connection_unref(c);
-}
-
-int weston_dbus_add_match(DBusConnection *c, const char *format, ...)
-{
-       DBusError err;
-       int r;
-       va_list list;
-       char *str;
-
-       va_start(list, format);
-       r = vasprintf(&str, format, list);
-       va_end(list);
-
-       if (r < 0)
-               return -ENOMEM;
-
-       dbus_error_init(&err);
-       dbus_bus_add_match(c, str, &err);
-       free(str);
-       if (dbus_error_is_set(&err)) {
-               dbus_error_free(&err);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
-                                const char *iface, const char *member,
-                                const char *path)
-{
-       return weston_dbus_add_match(c,
-                                    "type='signal',"
-                                    "sender='%s',"
-                                    "interface='%s',"
-                                    "member='%s',"
-                                    "path='%s'",
-                                    sender, iface, member, path);
-}
-
-void weston_dbus_remove_match(DBusConnection *c, const char *format, ...)
-{
-       int r;
-       va_list list;
-       char *str;
-
-       va_start(list, format);
-       r = vasprintf(&str, format, list);
-       va_end(list);
-
-       if (r < 0)
-               return;
-
-       dbus_bus_remove_match(c, str, NULL);
-       free(str);
-}
-
-void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
-                                    const char *iface, const char *member,
-                                    const char *path)
-{
-       return weston_dbus_remove_match(c,
-                                       "type='signal',"
-                                       "sender='%s',"
-                                       "interface='%s',"
-                                       "member='%s',"
-                                       "path='%s'",
-                                       sender, iface, member, path);
-}
diff --git a/src/dbus.h b/src/dbus.h
deleted file mode 100644 (file)
index 9bbfa38..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright © 2013 David Herrmann <dh.herrmann@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _WESTON_DBUS_H_
-#define _WESTON_DBUS_H_
-
-#include "config.h"
-
-#include <errno.h>
-#include <wayland-server.h>
-
-#include "compositor.h"
-
-#ifdef HAVE_DBUS
-
-#include <dbus/dbus.h>
-
-/*
- * weston_dbus_open() - Open new dbus connection
- *
- * Opens a new dbus connection to the bus given as @bus. It automatically
- * integrates the new connection into the main-loop @loop. The connection
- * itself is returned in @out.
- * This also returns a context source used for dbus dispatching. It is
- * returned on success in @ctx_out and must be passed to weston_dbus_close()
- * unchanged. You must not access it from outside of a dbus helper!
- *
- * Returns 0 on success, negative error code on failure.
- */
-int weston_dbus_open(struct wl_event_loop *loop, DBusBusType bus,
-                    DBusConnection **out, struct wl_event_source **ctx_out);
-
-/*
- * weston_dbus_close() - Close dbus connection
- *
- * Closes a dbus connection that was previously opened via weston_dbus_open().
- * It unbinds the connection from the main-loop it was previously bound to,
- * closes the dbus connection and frees all resources. If you want to access
- * @c after this call returns, you must hold a dbus-reference to it. But
- * notice that the connection is closed after this returns so it cannot be
- * used to spawn new dbus requests.
- * You must pass the context source returns by weston_dbus_open() as @ctx.
- */
-void weston_dbus_close(DBusConnection *c, struct wl_event_source *ctx);
-
-/*
- * weston_dbus_add_match() - Add dbus match
- *
- * Configure a dbus-match on the given dbus-connection. This match is saved
- * on the dbus-server as long as the connection is open. See dbus-manual
- * for information. Compared to the dbus_bus_add_match() this allows a
- * var-arg formatted match-string.
- */
-int weston_dbus_add_match(DBusConnection *c, const char *format, ...);
-
-/*
- * weston_dbus_add_match_signal() - Add dbus signal match
- *
- * Same as weston_dbus_add_match() but does the dbus-match formatting for
- * signals internally.
- */
-int weston_dbus_add_match_signal(DBusConnection *c, const char *sender,
-                                const char *iface, const char *member,
-                                const char *path);
-
-/*
- * weston_dbus_remove_match() - Remove dbus match
- *
- * Remove a previously configured dbus-match from the dbus server. There is
- * no need to remove dbus-matches if you close the connection, anyway.
- * Compared to dbus_bus_remove_match() this allows a var-arg formatted
- * match string.
- */
-void weston_dbus_remove_match(DBusConnection *c, const char *format, ...);
-
-/*
- * weston_dbus_remove_match_signal() - Remove dbus signal match
- *
- * Same as weston_dbus_remove_match() but does the dbus-match formatting for
- * signals internally.
- */
-void weston_dbus_remove_match_signal(DBusConnection *c, const char *sender,
-                                    const char *iface, const char *member,
-                                    const char *path);
-
-#endif /* HAVE_DBUS */
-
-#endif // _WESTON_DBUS_H_
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
deleted file mode 100644 (file)
index 23c0cd7..0000000
+++ /dev/null
@@ -1,3157 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- * Copyright © 2015 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <GLES2/gl2.h>
-#include <GLES2/gl2ext.h>
-
-#include <stdbool.h>
-#include <stdlib.h>
-#include <string.h>
-#include <ctype.h>
-#include <float.h>
-#include <assert.h>
-#include <linux/input.h>
-#include <drm_fourcc.h>
-
-#include "gl-renderer.h"
-#include "vertex-clipping.h"
-#include "linux-dmabuf.h"
-#include "linux-dmabuf-unstable-v1-server-protocol.h"
-
-#include "shared/helpers.h"
-#include "weston-egl-ext.h"
-
-struct gl_shader {
-       GLuint program;
-       GLuint vertex_shader, fragment_shader;
-       GLint proj_uniform;
-       GLint tex_uniforms[3];
-       GLint alpha_uniform;
-       GLint color_uniform;
-       const char *vertex_source, *fragment_source;
-};
-
-#define BUFFER_DAMAGE_COUNT 2
-
-enum gl_border_status {
-       BORDER_STATUS_CLEAN = 0,
-       BORDER_TOP_DIRTY = 1 << GL_RENDERER_BORDER_TOP,
-       BORDER_LEFT_DIRTY = 1 << GL_RENDERER_BORDER_LEFT,
-       BORDER_RIGHT_DIRTY = 1 << GL_RENDERER_BORDER_RIGHT,
-       BORDER_BOTTOM_DIRTY = 1 << GL_RENDERER_BORDER_BOTTOM,
-       BORDER_ALL_DIRTY = 0xf,
-       BORDER_SIZE_CHANGED = 0x10
-};
-
-struct gl_border_image {
-       GLuint tex;
-       int32_t width, height;
-       int32_t tex_width;
-       void *data;
-};
-
-struct gl_output_state {
-       EGLSurface egl_surface;
-       pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
-       int buffer_damage_index;
-       enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];
-       struct gl_border_image borders[4];
-       enum gl_border_status border_status;
-
-       struct weston_matrix output_matrix;
-};
-
-enum buffer_type {
-       BUFFER_TYPE_NULL,
-       BUFFER_TYPE_SOLID, /* internal solid color surfaces without a buffer */
-       BUFFER_TYPE_SHM,
-       BUFFER_TYPE_EGL
-};
-
-struct gl_renderer;
-
-struct egl_image {
-       struct gl_renderer *renderer;
-       EGLImageKHR image;
-       int refcount;
-};
-
-enum import_type {
-       IMPORT_TYPE_INVALID,
-       IMPORT_TYPE_DIRECT,
-       IMPORT_TYPE_GL_CONVERSION
-};
-
-struct dmabuf_image {
-       struct linux_dmabuf_buffer *dmabuf;
-       int num_images;
-       struct egl_image *images[3];
-       struct wl_list link;
-
-       enum import_type import_type;
-       GLenum target;
-       struct gl_shader *shader;
-};
-
-struct yuv_plane_descriptor {
-       int width_divisor;
-       int height_divisor;
-       uint32_t format;
-       int plane_index;
-};
-
-struct yuv_format_descriptor {
-       uint32_t format;
-       int input_planes;
-       int output_planes;
-       int texture_type;
-       struct yuv_plane_descriptor plane[4];
-};
-
-struct gl_surface_state {
-       GLfloat color[4];
-       struct gl_shader *shader;
-
-       GLuint textures[3];
-       int num_textures;
-       bool needs_full_upload;
-       pixman_region32_t texture_damage;
-
-       /* These are only used by SHM surfaces to detect when we need
-        * to do a full upload to specify a new internal texture
-        * format */
-       GLenum gl_format;
-       GLenum gl_pixel_type;
-
-       struct egl_image* images[3];
-       GLenum target;
-       int num_images;
-
-       struct weston_buffer_reference buffer_ref;
-       enum buffer_type buffer_type;
-       int pitch; /* in pixels */
-       int height; /* in pixels */
-       int y_inverted;
-
-       struct weston_surface *surface;
-
-       struct wl_listener surface_destroy_listener;
-       struct wl_listener renderer_destroy_listener;
-};
-
-struct gl_renderer {
-       struct weston_renderer base;
-       int fragment_shader_debug;
-       int fan_debug;
-       struct weston_binding *fragment_binding;
-       struct weston_binding *fan_binding;
-
-       EGLDisplay egl_display;
-       EGLContext egl_context;
-       EGLConfig egl_config;
-
-       struct wl_array vertices;
-       struct wl_array vtxcnt;
-
-       PFNGLEGLIMAGETARGETTEXTURE2DOESPROC image_target_texture_2d;
-       PFNEGLCREATEIMAGEKHRPROC create_image;
-       PFNEGLDESTROYIMAGEKHRPROC destroy_image;
-
-#ifdef EGL_EXT_swap_buffers_with_damage
-       PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
-#endif
-
-       PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC create_platform_window;
-
-       int has_unpack_subimage;
-
-       PFNEGLBINDWAYLANDDISPLAYWL bind_display;
-       PFNEGLUNBINDWAYLANDDISPLAYWL unbind_display;
-       PFNEGLQUERYWAYLANDBUFFERWL query_buffer;
-       int has_bind_display;
-
-       int has_egl_image_external;
-
-       int has_egl_buffer_age;
-
-       int has_configless_context;
-
-       int has_dmabuf_import;
-       struct wl_list dmabuf_images;
-
-       struct gl_shader texture_shader_rgba;
-       struct gl_shader texture_shader_rgbx;
-       struct gl_shader texture_shader_egl_external;
-       struct gl_shader texture_shader_y_uv;
-       struct gl_shader texture_shader_y_u_v;
-       struct gl_shader texture_shader_y_xuxv;
-       struct gl_shader invert_color_shader;
-       struct gl_shader solid_shader;
-       struct gl_shader *current_shader;
-
-       struct wl_signal destroy_signal;
-};
-
-static PFNEGLGETPLATFORMDISPLAYEXTPROC get_platform_display = NULL;
-
-static inline const char *
-dump_format(uint32_t format, char out[4])
-{
-#if BYTE_ORDER == BIG_ENDIAN
-       format = __builtin_bswap32(format);
-#endif
-       memcpy(out, &format, 4);
-       return out;
-}
-
-static inline struct gl_output_state *
-get_output_state(struct weston_output *output)
-{
-       return (struct gl_output_state *)output->renderer_state;
-}
-
-static int
-gl_renderer_create_surface(struct weston_surface *surface);
-
-static inline struct gl_surface_state *
-get_surface_state(struct weston_surface *surface)
-{
-       if (!surface->renderer_state)
-               gl_renderer_create_surface(surface);
-
-       return (struct gl_surface_state *)surface->renderer_state;
-}
-
-static inline struct gl_renderer *
-get_renderer(struct weston_compositor *ec)
-{
-       return (struct gl_renderer *)ec->renderer;
-}
-
-static struct egl_image*
-egl_image_create(struct gl_renderer *gr, EGLenum target,
-                EGLClientBuffer buffer, const EGLint *attribs)
-{
-       struct egl_image *img;
-
-       img = zalloc(sizeof *img);
-       img->renderer = gr;
-       img->refcount = 1;
-       img->image = gr->create_image(gr->egl_display, EGL_NO_CONTEXT,
-                                     target, buffer, attribs);
-
-       if (img->image == EGL_NO_IMAGE_KHR) {
-               free(img);
-               return NULL;
-       }
-
-       return img;
-}
-
-static struct egl_image*
-egl_image_ref(struct egl_image *image)
-{
-       image->refcount++;
-
-       return image;
-}
-
-static int
-egl_image_unref(struct egl_image *image)
-{
-       struct gl_renderer *gr = image->renderer;
-
-       assert(image->refcount > 0);
-
-       image->refcount--;
-       if (image->refcount > 0)
-               return image->refcount;
-
-       gr->destroy_image(gr->egl_display, image->image);
-       free(image);
-
-       return 0;
-}
-
-static struct dmabuf_image*
-dmabuf_image_create(void)
-{
-       struct dmabuf_image *img;
-
-       img = zalloc(sizeof *img);
-       wl_list_init(&img->link);
-
-       return img;
-}
-
-static void
-dmabuf_image_destroy(struct dmabuf_image *image)
-{
-       int i;
-
-       for (i = 0; i < image->num_images; ++i)
-               egl_image_unref(image->images[i]);
-
-       if (image->dmabuf)
-               linux_dmabuf_buffer_set_user_data(image->dmabuf, NULL, NULL);
-
-       wl_list_remove(&image->link);
-}
-
-static const char *
-egl_error_string(EGLint code)
-{
-#define MYERRCODE(x) case x: return #x;
-       switch (code) {
-       MYERRCODE(EGL_SUCCESS)
-       MYERRCODE(EGL_NOT_INITIALIZED)
-       MYERRCODE(EGL_BAD_ACCESS)
-       MYERRCODE(EGL_BAD_ALLOC)
-       MYERRCODE(EGL_BAD_ATTRIBUTE)
-       MYERRCODE(EGL_BAD_CONTEXT)
-       MYERRCODE(EGL_BAD_CONFIG)
-       MYERRCODE(EGL_BAD_CURRENT_SURFACE)
-       MYERRCODE(EGL_BAD_DISPLAY)
-       MYERRCODE(EGL_BAD_SURFACE)
-       MYERRCODE(EGL_BAD_MATCH)
-       MYERRCODE(EGL_BAD_PARAMETER)
-       MYERRCODE(EGL_BAD_NATIVE_PIXMAP)
-       MYERRCODE(EGL_BAD_NATIVE_WINDOW)
-       MYERRCODE(EGL_CONTEXT_LOST)
-       default:
-               return "unknown";
-       }
-#undef MYERRCODE
-}
-
-static void
-gl_renderer_print_egl_error_state(void)
-{
-       EGLint code;
-
-       code = eglGetError();
-       weston_log("EGL error state: %s (0x%04lx)\n",
-               egl_error_string(code), (long)code);
-}
-
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-#define min(a, b) (((a) > (b)) ? (b) : (a))
-
-/*
- * Compute the boundary vertices of the intersection of the global coordinate
- * aligned rectangle 'rect', and an arbitrary quadrilateral produced from
- * 'surf_rect' when transformed from surface coordinates into global coordinates.
- * The vertices are written to 'ex' and 'ey', and the return value is the
- * number of vertices. Vertices are produced in clockwise winding order.
- * Guarantees to produce either zero vertices, or 3-8 vertices with non-zero
- * polygon area.
- */
-static int
-calculate_edges(struct weston_view *ev, pixman_box32_t *rect,
-               pixman_box32_t *surf_rect, GLfloat *ex, GLfloat *ey)
-{
-
-       struct clip_context ctx;
-       int i, n;
-       GLfloat min_x, max_x, min_y, max_y;
-       struct polygon8 surf = {
-               { surf_rect->x1, surf_rect->x2, surf_rect->x2, surf_rect->x1 },
-               { surf_rect->y1, surf_rect->y1, surf_rect->y2, surf_rect->y2 },
-               4
-       };
-
-       ctx.clip.x1 = rect->x1;
-       ctx.clip.y1 = rect->y1;
-       ctx.clip.x2 = rect->x2;
-       ctx.clip.y2 = rect->y2;
-
-       /* transform surface to screen space: */
-       for (i = 0; i < surf.n; i++)
-               weston_view_to_global_float(ev, surf.x[i], surf.y[i],
-                                           &surf.x[i], &surf.y[i]);
-
-       /* find bounding box: */
-       min_x = max_x = surf.x[0];
-       min_y = max_y = surf.y[0];
-
-       for (i = 1; i < surf.n; i++) {
-               min_x = min(min_x, surf.x[i]);
-               max_x = max(max_x, surf.x[i]);
-               min_y = min(min_y, surf.y[i]);
-               max_y = max(max_y, surf.y[i]);
-       }
-
-       /* First, simple bounding box check to discard early transformed
-        * surface rects that do not intersect with the clip region:
-        */
-       if ((min_x >= ctx.clip.x2) || (max_x <= ctx.clip.x1) ||
-           (min_y >= ctx.clip.y2) || (max_y <= ctx.clip.y1))
-               return 0;
-
-       /* Simple case, bounding box edges are parallel to surface edges,
-        * there will be only four edges.  We just need to clip the surface
-        * vertices to the clip rect bounds:
-        */
-       if (!ev->transform.enabled)
-               return clip_simple(&ctx, &surf, ex, ey);
-
-       /* Transformed case: use a general polygon clipping algorithm to
-        * clip the surface rectangle with each side of 'rect'.
-        * The algorithm is Sutherland-Hodgman, as explained in
-        * http://www.codeguru.com/cpp/misc/misc/graphics/article.php/c8965/Polygon-Clipping.htm
-        * but without looking at any of that code.
-        */
-       n = clip_transformed(&ctx, &surf, ex, ey);
-
-       if (n < 3)
-               return 0;
-
-       return n;
-}
-
-static bool
-merge_down(pixman_box32_t *a, pixman_box32_t *b, pixman_box32_t *merge)
-{
-       if (a->x1 == b->x1 && a->x2 == b->x2 && a->y1 == b->y2) {
-               merge->x1 = a->x1;
-               merge->x2 = a->x2;
-               merge->y1 = b->y1;
-               merge->y2 = a->y2;
-               return true;
-       }
-       return false;
-}
-
-static int
-compress_bands(pixman_box32_t *inrects, int nrects,
-                  pixman_box32_t **outrects)
-{
-       bool merged;
-       pixman_box32_t *out, merge_rect;
-       int i, j, nout;
-
-       if (!nrects) {
-               *outrects = NULL;
-               return 0;
-       }
-
-       /* nrects is an upper bound - we're not too worried about
-        * allocating a little extra
-        */
-       out = malloc(sizeof(pixman_box32_t) * nrects);
-       out[0] = inrects[0];
-       nout = 1;
-       for (i = 1; i < nrects; i++) {
-               for (j = 0; j < nout; j++) {
-                       merged = merge_down(&inrects[i], &out[j], &merge_rect);
-                       if (merged) {
-                               out[j] = merge_rect;
-                               break;
-                       }
-               }
-               if (!merged) {
-                       out[nout] = inrects[i];
-                       nout++;
-               }
-       }
-       *outrects = out;
-       return nout;
-}
-
-static int
-texture_region(struct weston_view *ev, pixman_region32_t *region,
-               pixman_region32_t *surf_region)
-{
-       struct gl_surface_state *gs = get_surface_state(ev->surface);
-       struct weston_compositor *ec = ev->surface->compositor;
-       struct gl_renderer *gr = get_renderer(ec);
-       GLfloat *v, inv_width, inv_height;
-       unsigned int *vtxcnt, nvtx = 0;
-       pixman_box32_t *rects, *surf_rects;
-       pixman_box32_t *raw_rects;
-       int i, j, k, nrects, nsurf, raw_nrects;
-       bool used_band_compression;
-       raw_rects = pixman_region32_rectangles(region, &raw_nrects);
-       surf_rects = pixman_region32_rectangles(surf_region, &nsurf);
-
-       if (raw_nrects < 4) {
-               used_band_compression = false;
-               nrects = raw_nrects;
-               rects = raw_rects;
-       } else {
-               nrects = compress_bands(raw_rects, raw_nrects, &rects);
-               used_band_compression = true;
-       }
-       /* worst case we can have 8 vertices per rect (ie. clipped into
-        * an octagon):
-        */
-       v = wl_array_add(&gr->vertices, nrects * nsurf * 8 * 4 * sizeof *v);
-       vtxcnt = wl_array_add(&gr->vtxcnt, nrects * nsurf * sizeof *vtxcnt);
-
-       inv_width = 1.0 / gs->pitch;
-        inv_height = 1.0 / gs->height;
-
-       for (i = 0; i < nrects; i++) {
-               pixman_box32_t *rect = &rects[i];
-               for (j = 0; j < nsurf; j++) {
-                       pixman_box32_t *surf_rect = &surf_rects[j];
-                       GLfloat sx, sy, bx, by;
-                       GLfloat ex[8], ey[8];          /* edge points in screen space */
-                       int n;
-
-                       /* The transformed surface, after clipping to the clip region,
-                        * can have as many as eight sides, emitted as a triangle-fan.
-                        * The first vertex in the triangle fan can be chosen arbitrarily,
-                        * since the area is guaranteed to be convex.
-                        *
-                        * If a corner of the transformed surface falls outside of the
-                        * clip region, instead of emitting one vertex for the corner
-                        * of the surface, up to two are emitted for two corresponding
-                        * intersection point(s) between the surface and the clip region.
-                        *
-                        * To do this, we first calculate the (up to eight) points that
-                        * form the intersection of the clip rect and the transformed
-                        * surface.
-                        */
-                       n = calculate_edges(ev, rect, surf_rect, ex, ey);
-                       if (n < 3)
-                               continue;
-
-                       /* emit edge points: */
-                       for (k = 0; k < n; k++) {
-                               weston_view_from_global_float(ev, ex[k], ey[k],
-                                                             &sx, &sy);
-                               /* position: */
-                               *(v++) = ex[k];
-                               *(v++) = ey[k];
-                               /* texcoord: */
-                               weston_surface_to_buffer_float(ev->surface,
-                                                              sx, sy,
-                                                              &bx, &by);
-                               *(v++) = bx * inv_width;
-                               if (gs->y_inverted) {
-                                       *(v++) = by * inv_height;
-                               } else {
-                                       *(v++) = (gs->height - by) * inv_height;
-                               }
-                       }
-
-                       vtxcnt[nvtx++] = n;
-               }
-       }
-
-       if (used_band_compression)
-               free(rects);
-       return nvtx;
-}
-
-static void
-triangle_fan_debug(struct weston_view *view, int first, int count)
-{
-       struct weston_compositor *compositor = view->surface->compositor;
-       struct gl_renderer *gr = get_renderer(compositor);
-       int i;
-       GLushort *buffer;
-       GLushort *index;
-       int nelems;
-       static int color_idx = 0;
-       static const GLfloat color[][4] = {
-                       { 1.0, 0.0, 0.0, 1.0 },
-                       { 0.0, 1.0, 0.0, 1.0 },
-                       { 0.0, 0.0, 1.0, 1.0 },
-                       { 1.0, 1.0, 1.0, 1.0 },
-       };
-
-       nelems = (count - 1 + count - 2) * 2;
-
-       buffer = malloc(sizeof(GLushort) * nelems);
-       index = buffer;
-
-       for (i = 1; i < count; i++) {
-               *index++ = first;
-               *index++ = first + i;
-       }
-
-       for (i = 2; i < count; i++) {
-               *index++ = first + i - 1;
-               *index++ = first + i;
-       }
-
-       glUseProgram(gr->solid_shader.program);
-       glUniform4fv(gr->solid_shader.color_uniform, 1,
-                       color[color_idx++ % ARRAY_LENGTH(color)]);
-       glDrawElements(GL_LINES, nelems, GL_UNSIGNED_SHORT, buffer);
-       glUseProgram(gr->current_shader->program);
-       free(buffer);
-}
-
-static void
-repaint_region(struct weston_view *ev, pixman_region32_t *region,
-               pixman_region32_t *surf_region)
-{
-       struct weston_compositor *ec = ev->surface->compositor;
-       struct gl_renderer *gr = get_renderer(ec);
-       GLfloat *v;
-       unsigned int *vtxcnt;
-       int i, first, nfans;
-
-       /* The final region to be painted is the intersection of
-        * 'region' and 'surf_region'. However, 'region' is in the global
-        * coordinates, and 'surf_region' is in the surface-local
-        * coordinates. texture_region() will iterate over all pairs of
-        * rectangles from both regions, compute the intersection
-        * polygon for each pair, and store it as a triangle fan if
-        * it has a non-zero area (at least 3 vertices, actually).
-        */
-       nfans = texture_region(ev, region, surf_region);
-
-       v = gr->vertices.data;
-       vtxcnt = gr->vtxcnt.data;
-
-       /* position: */
-       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[0]);
-       glEnableVertexAttribArray(0);
-
-       /* texcoord: */
-       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 4 * sizeof *v, &v[2]);
-       glEnableVertexAttribArray(1);
-
-       for (i = 0, first = 0; i < nfans; i++) {
-               glDrawArrays(GL_TRIANGLE_FAN, first, vtxcnt[i]);
-               if (gr->fan_debug)
-                       triangle_fan_debug(ev, first, vtxcnt[i]);
-               first += vtxcnt[i];
-       }
-
-       glDisableVertexAttribArray(1);
-       glDisableVertexAttribArray(0);
-
-       gr->vertices.size = 0;
-       gr->vtxcnt.size = 0;
-}
-
-static int
-use_output(struct weston_output *output)
-{
-       static int errored;
-       struct gl_output_state *go = get_output_state(output);
-       struct gl_renderer *gr = get_renderer(output->compositor);
-       EGLBoolean ret;
-
-       ret = eglMakeCurrent(gr->egl_display, go->egl_surface,
-                            go->egl_surface, gr->egl_context);
-
-       if (ret == EGL_FALSE) {
-               if (errored)
-                       return -1;
-               errored = 1;
-               weston_log("Failed to make EGL context current.\n");
-               gl_renderer_print_egl_error_state();
-               return -1;
-       }
-
-       return 0;
-}
-
-static int
-shader_init(struct gl_shader *shader, struct gl_renderer *gr,
-                  const char *vertex_source, const char *fragment_source);
-
-static void
-use_shader(struct gl_renderer *gr, struct gl_shader *shader)
-{
-       if (!shader->program) {
-               int ret;
-
-               ret =  shader_init(shader, gr,
-                                  shader->vertex_source,
-                                  shader->fragment_source);
-
-               if (ret < 0)
-                       weston_log("warning: failed to compile shader\n");
-       }
-
-       if (gr->current_shader == shader)
-               return;
-       glUseProgram(shader->program);
-       gr->current_shader = shader;
-}
-
-static void
-shader_uniforms(struct gl_shader *shader,
-               struct weston_view *view,
-               struct weston_output *output)
-{
-       int i;
-       struct gl_surface_state *gs = get_surface_state(view->surface);
-       struct gl_output_state *go = get_output_state(output);
-
-       glUniformMatrix4fv(shader->proj_uniform,
-                          1, GL_FALSE, go->output_matrix.d);
-       glUniform4fv(shader->color_uniform, 1, gs->color);
-       glUniform1f(shader->alpha_uniform, view->alpha);
-
-       for (i = 0; i < gs->num_textures; i++)
-               glUniform1i(shader->tex_uniforms[i], i);
-}
-
-static void
-draw_view(struct weston_view *ev, struct weston_output *output,
-         pixman_region32_t *damage) /* in global coordinates */
-{
-       struct weston_compositor *ec = ev->surface->compositor;
-       struct gl_renderer *gr = get_renderer(ec);
-       struct gl_surface_state *gs = get_surface_state(ev->surface);
-       /* repaint bounding region in global coordinates: */
-       pixman_region32_t repaint;
-       /* opaque region in surface coordinates: */
-       pixman_region32_t surface_opaque;
-       /* non-opaque region in surface coordinates: */
-       pixman_region32_t surface_blend;
-       GLint filter;
-       int i;
-
-       /* In case of a runtime switch of renderers, we may not have received
-        * an attach for this surface since the switch. In that case we don't
-        * have a valid buffer or a proper shader set up so skip rendering. */
-       if (!gs->shader)
-               return;
-
-       pixman_region32_init(&repaint);
-       pixman_region32_intersect(&repaint,
-                                 &ev->transform.boundingbox, damage);
-       pixman_region32_subtract(&repaint, &repaint, &ev->clip);
-
-       if (!pixman_region32_not_empty(&repaint))
-               goto out;
-
-       glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
-
-       if (gr->fan_debug) {
-               use_shader(gr, &gr->solid_shader);
-               shader_uniforms(&gr->solid_shader, ev, output);
-       }
-
-       use_shader(gr, gs->shader);
-       shader_uniforms(gs->shader, ev, output);
-
-       if (ev->transform.enabled || output->zoom.active ||
-           output->current_scale != ev->surface->buffer_viewport.buffer.scale)
-               filter = GL_LINEAR;
-       else
-               filter = GL_NEAREST;
-
-       for (i = 0; i < gs->num_textures; i++) {
-               glActiveTexture(GL_TEXTURE0 + i);
-               glBindTexture(gs->target, gs->textures[i]);
-               glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, filter);
-               glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, filter);
-       }
-
-       /* blended region is whole surface minus opaque region: */
-       pixman_region32_init_rect(&surface_blend, 0, 0,
-                                 ev->surface->width, ev->surface->height);
-       if (ev->geometry.scissor_enabled)
-               pixman_region32_intersect(&surface_blend, &surface_blend,
-                                         &ev->geometry.scissor);
-       pixman_region32_subtract(&surface_blend, &surface_blend,
-                                &ev->surface->opaque);
-
-       /* XXX: Should we be using ev->transform.opaque here? */
-       pixman_region32_init(&surface_opaque);
-       if (ev->geometry.scissor_enabled)
-               pixman_region32_intersect(&surface_opaque,
-                                         &ev->surface->opaque,
-                                         &ev->geometry.scissor);
-       else
-               pixman_region32_copy(&surface_opaque, &ev->surface->opaque);
-
-       if (pixman_region32_not_empty(&surface_opaque)) {
-               if (gs->shader == &gr->texture_shader_rgba) {
-                       /* Special case for RGBA textures with possibly
-                        * bad data in alpha channel: use the shader
-                        * that forces texture alpha = 1.0.
-                        * Xwayland surfaces need this.
-                        */
-                       use_shader(gr, &gr->texture_shader_rgbx);
-                       shader_uniforms(&gr->texture_shader_rgbx, ev, output);
-               }
-
-               if (ev->alpha < 1.0)
-                       glEnable(GL_BLEND);
-               else
-                       glDisable(GL_BLEND);
-
-               repaint_region(ev, &repaint, &surface_opaque);
-       }
-
-       if (pixman_region32_not_empty(&surface_blend)) {
-               use_shader(gr, gs->shader);
-               glEnable(GL_BLEND);
-               repaint_region(ev, &repaint, &surface_blend);
-       }
-
-       pixman_region32_fini(&surface_blend);
-       pixman_region32_fini(&surface_opaque);
-
-out:
-       pixman_region32_fini(&repaint);
-}
-
-static void
-repaint_views(struct weston_output *output, pixman_region32_t *damage)
-{
-       struct weston_compositor *compositor = output->compositor;
-       struct weston_view *view;
-
-       wl_list_for_each_reverse(view, &compositor->view_list, link)
-               if (view->plane == &compositor->primary_plane)
-                       draw_view(view, output, damage);
-}
-
-static void
-draw_output_border_texture(struct gl_output_state *go,
-                          enum gl_renderer_border_side side,
-                          int32_t x, int32_t y,
-                          int32_t width, int32_t height)
-{
-       struct gl_border_image *img = &go->borders[side];
-       static GLushort indices [] = { 0, 1, 3, 3, 1, 2 };
-
-       if (!img->data) {
-               if (img->tex) {
-                       glDeleteTextures(1, &img->tex);
-                       img->tex = 0;
-               }
-
-               return;
-       }
-
-       if (!img->tex) {
-               glGenTextures(1, &img->tex);
-               glBindTexture(GL_TEXTURE_2D, img->tex);
-
-               glTexParameteri(GL_TEXTURE_2D,
-                               GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-               glTexParameteri(GL_TEXTURE_2D,
-                               GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-               glTexParameteri(GL_TEXTURE_2D,
-                               GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-               glTexParameteri(GL_TEXTURE_2D,
-                               GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-       } else {
-               glBindTexture(GL_TEXTURE_2D, img->tex);
-       }
-
-       if (go->border_status & (1 << side)) {
-#ifdef GL_EXT_unpack_subimage
-               glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0);
-               glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
-               glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
-#endif
-               glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
-                            img->tex_width, img->height, 0,
-                            GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
-       }
-
-       GLfloat texcoord[] = {
-               0.0f, 0.0f,
-               (GLfloat)img->width / (GLfloat)img->tex_width, 0.0f,
-               (GLfloat)img->width / (GLfloat)img->tex_width, 1.0f,
-               0.0f, 1.0f,
-       };
-
-       GLfloat verts[] = {
-               x, y,
-               x + width, y,
-               x + width, y + height,
-               x, y + height
-       };
-
-       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
-       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, texcoord);
-       glEnableVertexAttribArray(0);
-       glEnableVertexAttribArray(1);
-
-       glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_SHORT, indices);
-
-       glDisableVertexAttribArray(1);
-       glDisableVertexAttribArray(0);
-}
-
-static int
-output_has_borders(struct weston_output *output)
-{
-       struct gl_output_state *go = get_output_state(output);
-
-       return go->borders[GL_RENDERER_BORDER_TOP].data ||
-              go->borders[GL_RENDERER_BORDER_RIGHT].data ||
-              go->borders[GL_RENDERER_BORDER_BOTTOM].data ||
-              go->borders[GL_RENDERER_BORDER_LEFT].data;
-}
-
-static void
-draw_output_borders(struct weston_output *output,
-                   enum gl_border_status border_status)
-{
-       struct gl_output_state *go = get_output_state(output);
-       struct gl_renderer *gr = get_renderer(output->compositor);
-       struct gl_shader *shader = &gr->texture_shader_rgba;
-       struct gl_border_image *top, *bottom, *left, *right;
-       struct weston_matrix matrix;
-       int full_width, full_height;
-
-       if (border_status == BORDER_STATUS_CLEAN)
-               return; /* Clean. Nothing to do. */
-
-       top = &go->borders[GL_RENDERER_BORDER_TOP];
-       bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
-       left = &go->borders[GL_RENDERER_BORDER_LEFT];
-       right = &go->borders[GL_RENDERER_BORDER_RIGHT];
-
-       full_width = output->current_mode->width + left->width + right->width;
-       full_height = output->current_mode->height + top->height + bottom->height;
-
-       glDisable(GL_BLEND);
-       use_shader(gr, shader);
-
-       glViewport(0, 0, full_width, full_height);
-
-       weston_matrix_init(&matrix);
-       weston_matrix_translate(&matrix, -full_width/2.0, -full_height/2.0, 0);
-       weston_matrix_scale(&matrix, 2.0/full_width, -2.0/full_height, 1);
-       glUniformMatrix4fv(shader->proj_uniform, 1, GL_FALSE, matrix.d);
-
-       glUniform1i(shader->tex_uniforms[0], 0);
-       glUniform1f(shader->alpha_uniform, 1);
-       glActiveTexture(GL_TEXTURE0);
-
-       if (border_status & BORDER_TOP_DIRTY)
-               draw_output_border_texture(go, GL_RENDERER_BORDER_TOP,
-                                          0, 0,
-                                          full_width, top->height);
-       if (border_status & BORDER_LEFT_DIRTY)
-               draw_output_border_texture(go, GL_RENDERER_BORDER_LEFT,
-                                          0, top->height,
-                                          left->width, output->current_mode->height);
-       if (border_status & BORDER_RIGHT_DIRTY)
-               draw_output_border_texture(go, GL_RENDERER_BORDER_RIGHT,
-                                          full_width - right->width, top->height,
-                                          right->width, output->current_mode->height);
-       if (border_status & BORDER_BOTTOM_DIRTY)
-               draw_output_border_texture(go, GL_RENDERER_BORDER_BOTTOM,
-                                          0, full_height - bottom->height,
-                                          full_width, bottom->height);
-}
-
-static void
-output_get_border_damage(struct weston_output *output,
-                        enum gl_border_status border_status,
-                        pixman_region32_t *damage)
-{
-       struct gl_output_state *go = get_output_state(output);
-       struct gl_border_image *top, *bottom, *left, *right;
-       int full_width, full_height;
-
-       if (border_status == BORDER_STATUS_CLEAN)
-               return; /* Clean. Nothing to do. */
-
-       top = &go->borders[GL_RENDERER_BORDER_TOP];
-       bottom = &go->borders[GL_RENDERER_BORDER_BOTTOM];
-       left = &go->borders[GL_RENDERER_BORDER_LEFT];
-       right = &go->borders[GL_RENDERER_BORDER_RIGHT];
-
-       full_width = output->current_mode->width + left->width + right->width;
-       full_height = output->current_mode->height + top->height + bottom->height;
-       if (border_status & BORDER_TOP_DIRTY)
-               pixman_region32_union_rect(damage, damage,
-                                          0, 0,
-                                          full_width, top->height);
-       if (border_status & BORDER_LEFT_DIRTY)
-               pixman_region32_union_rect(damage, damage,
-                                          0, top->height,
-                                          left->width, output->current_mode->height);
-       if (border_status & BORDER_RIGHT_DIRTY)
-               pixman_region32_union_rect(damage, damage,
-                                          full_width - right->width, top->height,
-                                          right->width, output->current_mode->height);
-       if (border_status & BORDER_BOTTOM_DIRTY)
-               pixman_region32_union_rect(damage, damage,
-                                          0, full_height - bottom->height,
-                                          full_width, bottom->height);
-}
-
-static void
-output_get_damage(struct weston_output *output,
-                 pixman_region32_t *buffer_damage, uint32_t *border_damage)
-{
-       struct gl_output_state *go = get_output_state(output);
-       struct gl_renderer *gr = get_renderer(output->compositor);
-       EGLint buffer_age = 0;
-       EGLBoolean ret;
-       int i;
-
-       if (gr->has_egl_buffer_age) {
-               ret = eglQuerySurface(gr->egl_display, go->egl_surface,
-                                     EGL_BUFFER_AGE_EXT, &buffer_age);
-               if (ret == EGL_FALSE) {
-                       weston_log("buffer age query failed.\n");
-                       gl_renderer_print_egl_error_state();
-               }
-       }
-
-       if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT) {
-               pixman_region32_copy(buffer_damage, &output->region);
-               *border_damage = BORDER_ALL_DIRTY;
-       } else {
-               for (i = 0; i < buffer_age - 1; i++)
-                       *border_damage |= go->border_damage[(go->buffer_damage_index + i) % BUFFER_DAMAGE_COUNT];
-
-               if (*border_damage & BORDER_SIZE_CHANGED) {
-                       /* If we've had a resize, we have to do a full
-                        * repaint. */
-                       *border_damage |= BORDER_ALL_DIRTY;
-                       pixman_region32_copy(buffer_damage, &output->region);
-               } else {
-                       for (i = 0; i < buffer_age - 1; i++)
-                               pixman_region32_union(buffer_damage,
-                                                     buffer_damage,
-                                                     &go->buffer_damage[(go->buffer_damage_index + i) % BUFFER_DAMAGE_COUNT]);
-               }
-       }
-}
-
-static void
-output_rotate_damage(struct weston_output *output,
-                    pixman_region32_t *output_damage,
-                    enum gl_border_status border_status)
-{
-       struct gl_output_state *go = get_output_state(output);
-       struct gl_renderer *gr = get_renderer(output->compositor);
-
-       if (!gr->has_egl_buffer_age)
-               return;
-
-       go->buffer_damage_index += BUFFER_DAMAGE_COUNT - 1;
-       go->buffer_damage_index %= BUFFER_DAMAGE_COUNT;
-
-       pixman_region32_copy(&go->buffer_damage[go->buffer_damage_index], output_damage);
-       go->border_damage[go->buffer_damage_index] = border_status;
-}
-
-/* NOTE: We now allow falling back to ARGB gl visuals when XRGB is
- * unavailable, so we're assuming the background has no transparency
- * and that everything with a blend, like drop shadows, will have something
- * opaque (like the background) drawn underneath it.
- *
- * Depending on the underlying hardware, violating that assumption could
- * result in seeing through to another display plane.
- */
-static void
-gl_renderer_repaint_output(struct weston_output *output,
-                             pixman_region32_t *output_damage)
-{
-       struct gl_output_state *go = get_output_state(output);
-       struct weston_compositor *compositor = output->compositor;
-       struct gl_renderer *gr = get_renderer(compositor);
-       EGLBoolean ret;
-       static int errored;
-#ifdef EGL_EXT_swap_buffers_with_damage
-       int i, nrects, buffer_height;
-       EGLint *egl_damage, *d;
-       pixman_box32_t *rects;
-#endif
-       pixman_region32_t buffer_damage, total_damage;
-       enum gl_border_status border_damage = BORDER_STATUS_CLEAN;
-
-       if (use_output(output) < 0)
-               return;
-
-       /* Calculate the viewport */
-       glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
-                  go->borders[GL_RENDERER_BORDER_BOTTOM].height,
-                  output->current_mode->width,
-                  output->current_mode->height);
-
-       /* Calculate the global GL matrix */
-       go->output_matrix = output->matrix;
-       weston_matrix_translate(&go->output_matrix,
-                               -(output->current_mode->width / 2.0),
-                               -(output->current_mode->height / 2.0), 0);
-       weston_matrix_scale(&go->output_matrix,
-                           2.0 / output->current_mode->width,
-                           -2.0 / output->current_mode->height, 1);
-
-       /* if debugging, redraw everything outside the damage to clean up
-        * debug lines from the previous draw on this buffer:
-        */
-       if (gr->fan_debug) {
-               pixman_region32_t undamaged;
-               pixman_region32_init(&undamaged);
-               pixman_region32_subtract(&undamaged, &output->region,
-                                        output_damage);
-               gr->fan_debug = 0;
-               repaint_views(output, &undamaged);
-               gr->fan_debug = 1;
-               pixman_region32_fini(&undamaged);
-       }
-
-       pixman_region32_init(&total_damage);
-       pixman_region32_init(&buffer_damage);
-
-       output_get_damage(output, &buffer_damage, &border_damage);
-       output_rotate_damage(output, output_damage, go->border_status);
-
-       pixman_region32_union(&total_damage, &buffer_damage, output_damage);
-       border_damage |= go->border_status;
-
-       repaint_views(output, &total_damage);
-
-       pixman_region32_fini(&total_damage);
-       pixman_region32_fini(&buffer_damage);
-
-       draw_output_borders(output, border_damage);
-
-       pixman_region32_copy(&output->previous_damage, output_damage);
-       wl_signal_emit(&output->frame_signal, output);
-
-#ifdef EGL_EXT_swap_buffers_with_damage
-       if (gr->swap_buffers_with_damage) {
-               pixman_region32_init(&buffer_damage);
-               weston_transformed_region(output->width, output->height,
-                                         output->transform,
-                                         output->current_scale,
-                                         output_damage, &buffer_damage);
-
-               if (output_has_borders(output)) {
-                       pixman_region32_translate(&buffer_damage,
-                                                 go->borders[GL_RENDERER_BORDER_LEFT].width,
-                                                 go->borders[GL_RENDERER_BORDER_TOP].height);
-                       output_get_border_damage(output, go->border_status,
-                                                &buffer_damage);
-               }
-
-               rects = pixman_region32_rectangles(&buffer_damage, &nrects);
-               egl_damage = malloc(nrects * 4 * sizeof(EGLint));
-
-               buffer_height = go->borders[GL_RENDERER_BORDER_TOP].height +
-                               output->current_mode->height +
-                               go->borders[GL_RENDERER_BORDER_BOTTOM].height;
-
-               d = egl_damage;
-               for (i = 0; i < nrects; ++i) {
-                       *d++ = rects[i].x1;
-                       *d++ = buffer_height - rects[i].y2;
-                       *d++ = rects[i].x2 - rects[i].x1;
-                       *d++ = rects[i].y2 - rects[i].y1;
-               }
-               ret = gr->swap_buffers_with_damage(gr->egl_display,
-                                                  go->egl_surface,
-                                                  egl_damage, nrects);
-               free(egl_damage);
-               pixman_region32_fini(&buffer_damage);
-       } else {
-               ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
-       }
-#else /* ! defined EGL_EXT_swap_buffers_with_damage */
-       ret = eglSwapBuffers(gr->egl_display, go->egl_surface);
-#endif
-
-       if (ret == EGL_FALSE && !errored) {
-               errored = 1;
-               weston_log("Failed in eglSwapBuffers.\n");
-               gl_renderer_print_egl_error_state();
-       }
-
-       go->border_status = BORDER_STATUS_CLEAN;
-}
-
-static int
-gl_renderer_read_pixels(struct weston_output *output,
-                              pixman_format_code_t format, void *pixels,
-                              uint32_t x, uint32_t y,
-                              uint32_t width, uint32_t height)
-{
-       GLenum gl_format;
-       struct gl_output_state *go = get_output_state(output);
-
-       x += go->borders[GL_RENDERER_BORDER_LEFT].width;
-       y += go->borders[GL_RENDERER_BORDER_BOTTOM].height;
-
-       switch (format) {
-       case PIXMAN_a8r8g8b8:
-               gl_format = GL_BGRA_EXT;
-               break;
-       case PIXMAN_a8b8g8r8:
-               gl_format = GL_RGBA;
-               break;
-       default:
-               return -1;
-       }
-
-       if (use_output(output) < 0)
-               return -1;
-
-       glPixelStorei(GL_PACK_ALIGNMENT, 1);
-       glReadPixels(x, y, width, height, gl_format,
-                    GL_UNSIGNED_BYTE, pixels);
-
-       return 0;
-}
-
-static void
-gl_renderer_flush_damage(struct weston_surface *surface)
-{
-       struct gl_renderer *gr = get_renderer(surface->compositor);
-       struct gl_surface_state *gs = get_surface_state(surface);
-       struct weston_buffer *buffer = gs->buffer_ref.buffer;
-       struct weston_view *view;
-       bool texture_used;
-
-#ifdef GL_EXT_unpack_subimage
-       pixman_box32_t *rectangles;
-       void *data;
-       int i, n;
-#endif
-
-       pixman_region32_union(&gs->texture_damage,
-                             &gs->texture_damage, &surface->damage);
-
-       if (!buffer)
-               return;
-
-       /* Avoid upload, if the texture won't be used this time.
-        * We still accumulate the damage in texture_damage, and
-        * hold the reference to the buffer, in case the surface
-        * migrates back to the primary plane.
-        */
-       texture_used = false;
-       wl_list_for_each(view, &surface->views, surface_link) {
-               if (view->plane == &surface->compositor->primary_plane) {
-                       texture_used = true;
-                       break;
-               }
-       }
-       if (!texture_used)
-               return;
-
-       if (!pixman_region32_not_empty(&gs->texture_damage) &&
-           !gs->needs_full_upload)
-               goto done;
-
-       glBindTexture(GL_TEXTURE_2D, gs->textures[0]);
-
-       if (!gr->has_unpack_subimage) {
-               wl_shm_buffer_begin_access(buffer->shm_buffer);
-               glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
-                            gs->pitch, buffer->height, 0,
-                            gs->gl_format, gs->gl_pixel_type,
-                            wl_shm_buffer_get_data(buffer->shm_buffer));
-               wl_shm_buffer_end_access(buffer->shm_buffer);
-
-               goto done;
-       }
-
-#ifdef GL_EXT_unpack_subimage
-       glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, gs->pitch);
-       data = wl_shm_buffer_get_data(buffer->shm_buffer);
-
-       if (gs->needs_full_upload) {
-               glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
-               glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
-               wl_shm_buffer_begin_access(buffer->shm_buffer);
-               glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
-                            gs->pitch, buffer->height, 0,
-                            gs->gl_format, gs->gl_pixel_type, data);
-               wl_shm_buffer_end_access(buffer->shm_buffer);
-               goto done;
-       }
-
-       rectangles = pixman_region32_rectangles(&gs->texture_damage, &n);
-       wl_shm_buffer_begin_access(buffer->shm_buffer);
-       for (i = 0; i < n; i++) {
-               pixman_box32_t r;
-
-               r = weston_surface_to_buffer_rect(surface, rectangles[i]);
-
-               glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, r.x1);
-               glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, r.y1);
-               glTexSubImage2D(GL_TEXTURE_2D, 0, r.x1, r.y1,
-                               r.x2 - r.x1, r.y2 - r.y1,
-                               gs->gl_format, gs->gl_pixel_type, data);
-       }
-       wl_shm_buffer_end_access(buffer->shm_buffer);
-#endif
-
-done:
-       pixman_region32_fini(&gs->texture_damage);
-       pixman_region32_init(&gs->texture_damage);
-       gs->needs_full_upload = false;
-
-       weston_buffer_reference(&gs->buffer_ref, NULL);
-}
-
-static void
-ensure_textures(struct gl_surface_state *gs, int num_textures)
-{
-       int i;
-
-       if (num_textures <= gs->num_textures)
-               return;
-
-       for (i = gs->num_textures; i < num_textures; i++) {
-               glGenTextures(1, &gs->textures[i]);
-               glBindTexture(gs->target, gs->textures[i]);
-               glTexParameteri(gs->target,
-                               GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
-               glTexParameteri(gs->target,
-                               GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
-       }
-       gs->num_textures = num_textures;
-       glBindTexture(gs->target, 0);
-}
-
-static void
-gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
-                      struct wl_shm_buffer *shm_buffer)
-{
-       struct weston_compositor *ec = es->compositor;
-       struct gl_renderer *gr = get_renderer(ec);
-       struct gl_surface_state *gs = get_surface_state(es);
-       GLenum gl_format, gl_pixel_type;
-       int pitch;
-
-       buffer->shm_buffer = shm_buffer;
-       buffer->width = wl_shm_buffer_get_width(shm_buffer);
-       buffer->height = wl_shm_buffer_get_height(shm_buffer);
-
-       switch (wl_shm_buffer_get_format(shm_buffer)) {
-       case WL_SHM_FORMAT_XRGB8888:
-               gs->shader = &gr->texture_shader_rgbx;
-               pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
-               gl_format = GL_BGRA_EXT;
-               gl_pixel_type = GL_UNSIGNED_BYTE;
-               break;
-       case WL_SHM_FORMAT_ARGB8888:
-               gs->shader = &gr->texture_shader_rgba;
-               pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
-               gl_format = GL_BGRA_EXT;
-               gl_pixel_type = GL_UNSIGNED_BYTE;
-               break;
-       case WL_SHM_FORMAT_RGB565:
-               gs->shader = &gr->texture_shader_rgbx;
-               pitch = wl_shm_buffer_get_stride(shm_buffer) / 2;
-               gl_format = GL_RGB;
-               gl_pixel_type = GL_UNSIGNED_SHORT_5_6_5;
-               break;
-       default:
-               weston_log("warning: unknown shm buffer format: %08x\n",
-                          wl_shm_buffer_get_format(shm_buffer));
-               return;
-       }
-
-       /* Only allocate a texture if it doesn't match existing one.
-        * If a switch from DRM allocated buffer to a SHM buffer is
-        * happening, we need to allocate a new texture buffer. */
-       if (pitch != gs->pitch ||
-           buffer->height != gs->height ||
-           gl_format != gs->gl_format ||
-           gl_pixel_type != gs->gl_pixel_type ||
-           gs->buffer_type != BUFFER_TYPE_SHM) {
-               gs->pitch = pitch;
-               gs->height = buffer->height;
-               gs->target = GL_TEXTURE_2D;
-               gs->gl_format = gl_format;
-               gs->gl_pixel_type = gl_pixel_type;
-               gs->buffer_type = BUFFER_TYPE_SHM;
-               gs->needs_full_upload = true;
-               gs->y_inverted = 1;
-
-               gs->surface = es;
-
-               ensure_textures(gs, 1);
-       }
-}
-
-static void
-gl_renderer_attach_egl(struct weston_surface *es, struct weston_buffer *buffer,
-                      uint32_t format)
-{
-       struct weston_compositor *ec = es->compositor;
-       struct gl_renderer *gr = get_renderer(ec);
-       struct gl_surface_state *gs = get_surface_state(es);
-       EGLint attribs[3];
-       int i, num_planes;
-
-       buffer->legacy_buffer = (struct wl_buffer *)buffer->resource;
-       gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
-                        EGL_WIDTH, &buffer->width);
-       gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
-                        EGL_HEIGHT, &buffer->height);
-       gr->query_buffer(gr->egl_display, buffer->legacy_buffer,
-                        EGL_WAYLAND_Y_INVERTED_WL, &buffer->y_inverted);
-
-       for (i = 0; i < gs->num_images; i++) {
-               egl_image_unref(gs->images[i]);
-               gs->images[i] = NULL;
-       }
-       gs->num_images = 0;
-       gs->target = GL_TEXTURE_2D;
-       switch (format) {
-       case EGL_TEXTURE_RGB:
-       case EGL_TEXTURE_RGBA:
-       default:
-               num_planes = 1;
-               gs->shader = &gr->texture_shader_rgba;
-               break;
-       case EGL_TEXTURE_EXTERNAL_WL:
-               num_planes = 1;
-               gs->target = GL_TEXTURE_EXTERNAL_OES;
-               gs->shader = &gr->texture_shader_egl_external;
-               break;
-       case EGL_TEXTURE_Y_UV_WL:
-               num_planes = 2;
-               gs->shader = &gr->texture_shader_y_uv;
-               break;
-       case EGL_TEXTURE_Y_U_V_WL:
-               num_planes = 3;
-               gs->shader = &gr->texture_shader_y_u_v;
-               break;
-       case EGL_TEXTURE_Y_XUXV_WL:
-               num_planes = 2;
-               gs->shader = &gr->texture_shader_y_xuxv;
-               break;
-       }
-
-       ensure_textures(gs, num_planes);
-       for (i = 0; i < num_planes; i++) {
-               attribs[0] = EGL_WAYLAND_PLANE_WL;
-               attribs[1] = i;
-               attribs[2] = EGL_NONE;
-               gs->images[i] = egl_image_create(gr,
-                                                EGL_WAYLAND_BUFFER_WL,
-                                                buffer->legacy_buffer,
-                                                attribs);
-               if (!gs->images[i]) {
-                       weston_log("failed to create img for plane %d\n", i);
-                       continue;
-               }
-               gs->num_images++;
-
-               glActiveTexture(GL_TEXTURE0 + i);
-               glBindTexture(gs->target, gs->textures[i]);
-               gr->image_target_texture_2d(gs->target,
-                                           gs->images[i]->image);
-       }
-
-       gs->pitch = buffer->width;
-       gs->height = buffer->height;
-       gs->buffer_type = BUFFER_TYPE_EGL;
-       gs->y_inverted = buffer->y_inverted;
-}
-
-static void
-gl_renderer_destroy_dmabuf(struct linux_dmabuf_buffer *dmabuf)
-{
-       struct dmabuf_image *image = dmabuf->user_data;
-
-       dmabuf_image_destroy(image);
-}
-
-static struct egl_image *
-import_simple_dmabuf(struct gl_renderer *gr,
-                     struct dmabuf_attributes *attributes)
-{
-       struct egl_image *image;
-       EGLint attribs[30];
-       int atti = 0;
-
-       /* This requires the Mesa commit in
-        * Mesa 10.3 (08264e5dad4df448e7718e782ad9077902089a07) or
-        * Mesa 10.2.7 (55d28925e6109a4afd61f109e845a8a51bd17652).
-        * Otherwise Mesa closes the fd behind our back and re-importing
-        * will fail.
-        * https://bugs.freedesktop.org/show_bug.cgi?id=76188
-        */
-
-       attribs[atti++] = EGL_WIDTH;
-       attribs[atti++] = attributes->width;
-       attribs[atti++] = EGL_HEIGHT;
-       attribs[atti++] = attributes->height;
-       attribs[atti++] = EGL_LINUX_DRM_FOURCC_EXT;
-       attribs[atti++] = attributes->format;
-       /* XXX: Add modifier here when supported */
-
-       if (attributes->n_planes > 0) {
-               attribs[atti++] = EGL_DMA_BUF_PLANE0_FD_EXT;
-               attribs[atti++] = attributes->fd[0];
-               attribs[atti++] = EGL_DMA_BUF_PLANE0_OFFSET_EXT;
-               attribs[atti++] = attributes->offset[0];
-               attribs[atti++] = EGL_DMA_BUF_PLANE0_PITCH_EXT;
-               attribs[atti++] = attributes->stride[0];
-       }
-
-       if (attributes->n_planes > 1) {
-               attribs[atti++] = EGL_DMA_BUF_PLANE1_FD_EXT;
-               attribs[atti++] = attributes->fd[1];
-               attribs[atti++] = EGL_DMA_BUF_PLANE1_OFFSET_EXT;
-               attribs[atti++] = attributes->offset[1];
-               attribs[atti++] = EGL_DMA_BUF_PLANE1_PITCH_EXT;
-               attribs[atti++] = attributes->stride[1];
-       }
-
-       if (attributes->n_planes > 2) {
-               attribs[atti++] = EGL_DMA_BUF_PLANE2_FD_EXT;
-               attribs[atti++] = attributes->fd[2];
-               attribs[atti++] = EGL_DMA_BUF_PLANE2_OFFSET_EXT;
-               attribs[atti++] = attributes->offset[2];
-               attribs[atti++] = EGL_DMA_BUF_PLANE2_PITCH_EXT;
-               attribs[atti++] = attributes->stride[2];
-       }
-
-       attribs[atti++] = EGL_NONE;
-
-       image = egl_image_create(gr, EGL_LINUX_DMA_BUF_EXT, NULL,
-                                attribs);
-
-       return image;
-}
-
-/* The kernel header drm_fourcc.h defines the DRM formats below.  We duplicate
- * some of the definitions here so that building Weston won't require
- * bleeding-edge kernel headers.
- */
-#ifndef DRM_FORMAT_R8
-#define DRM_FORMAT_R8            fourcc_code('R', '8', ' ', ' ') /* [7:0] R */
-#endif
-
-#ifndef DRM_FORMAT_GR88
-#define DRM_FORMAT_GR88          fourcc_code('G', 'R', '8', '8') /* [15:0] G:R 8:8 little endian */
-#endif
-
-struct yuv_format_descriptor yuv_formats[] = {
-       {
-               .format = DRM_FORMAT_YUYV,
-               .input_planes = 1,
-               .output_planes = 2,
-               .texture_type = EGL_TEXTURE_Y_XUXV_WL,
-               {{
-                       .width_divisor = 1,
-                       .height_divisor = 1,
-                       .format = DRM_FORMAT_GR88,
-                       .plane_index = 0
-               }, {
-                       .width_divisor = 2,
-                       .height_divisor = 1,
-                       .format = DRM_FORMAT_ARGB8888,
-                       .plane_index = 0
-               }}
-       }, {
-               .format = DRM_FORMAT_NV12,
-               .input_planes = 2,
-               .output_planes = 2,
-               .texture_type = EGL_TEXTURE_Y_UV_WL,
-               {{
-                       .width_divisor = 1,
-                       .height_divisor = 1,
-                       .format = DRM_FORMAT_R8,
-                       .plane_index = 0
-               }, {
-                       .width_divisor = 2,
-                       .height_divisor = 2,
-                       .format = DRM_FORMAT_GR88,
-                       .plane_index = 1
-               }}
-       }, {
-               .format = DRM_FORMAT_YUV420,
-               .input_planes = 3,
-               .output_planes = 3,
-               .texture_type = EGL_TEXTURE_Y_U_V_WL,
-               {{
-                       .width_divisor = 1,
-                       .height_divisor = 1,
-                       .format = DRM_FORMAT_R8,
-                       .plane_index = 0
-               }, {
-                       .width_divisor = 2,
-                       .height_divisor = 2,
-                       .format = DRM_FORMAT_R8,
-                       .plane_index = 1
-               }, {
-                       .width_divisor = 2,
-                       .height_divisor = 2,
-                       .format = DRM_FORMAT_R8,
-                       .plane_index = 2
-               }}
-       }
-};
-
-static struct egl_image *
-import_dmabuf_single_plane(struct gl_renderer *gr,
-                           const struct dmabuf_attributes *attributes,
-                           struct yuv_plane_descriptor *descriptor)
-{
-       struct dmabuf_attributes plane;
-       struct egl_image *image;
-       char fmt[4];
-
-       plane.width = attributes->width / descriptor->width_divisor;
-       plane.height = attributes->height / descriptor->height_divisor;
-       plane.format = descriptor->format;
-       plane.n_planes = 1;
-       plane.fd[0] = attributes->fd[descriptor->plane_index];
-       plane.offset[0] = attributes->offset[descriptor->plane_index];
-       plane.stride[0] = attributes->stride[descriptor->plane_index];
-       plane.modifier[0] = attributes->modifier[descriptor->plane_index];
-
-       image = import_simple_dmabuf(gr, &plane);
-       if (!image) {
-               weston_log("Failed to import plane %d as %.4s\n",
-                          descriptor->plane_index,
-                          dump_format(descriptor->format, fmt));
-               return NULL;
-       }
-
-       return image;
-}
-
-static bool
-import_yuv_dmabuf(struct gl_renderer *gr,
-                  struct dmabuf_image *image)
-{
-       unsigned i;
-       int j;
-       int ret;
-       struct yuv_format_descriptor *format = NULL;
-       struct dmabuf_attributes *attributes = &image->dmabuf->attributes;
-       char fmt[4];
-
-       for (i = 0; i < ARRAY_LENGTH(yuv_formats); ++i) {
-               if (yuv_formats[i].format == attributes->format) {
-                       format = &yuv_formats[i];
-                       break;
-               }
-       }
-
-       if (!format) {
-               weston_log("Error during import, and no known conversion for format "
-                          "%.4s in the renderer",
-                          dump_format(attributes->format, fmt));
-               return false;
-       }
-
-       if (attributes->n_planes != format->input_planes) {
-               weston_log("%.4s dmabuf must contain %d plane%s (%d provided)",
-                          dump_format(format->format, fmt),
-                          format->input_planes,
-                          (format->input_planes > 1) ? "s" : "",
-                          attributes->n_planes);
-               return false;
-       }
-
-       for (j = 0; j < format->output_planes; ++j) {
-               image->images[j] = import_dmabuf_single_plane(gr, attributes,
-                                                             &format->plane[j]);
-               if (!image->images[j]) {
-                       while (j) {
-                               ret = egl_image_unref(image->images[--j]);
-                               assert(ret == 0);
-                       }
-                       return false;
-               }
-       }
-
-       image->num_images = format->output_planes;
-
-       switch (format->texture_type) {
-       case EGL_TEXTURE_Y_XUXV_WL:
-               image->shader = &gr->texture_shader_y_xuxv;
-               break;
-       case EGL_TEXTURE_Y_UV_WL:
-               image->shader = &gr->texture_shader_y_uv;
-               break;
-       case EGL_TEXTURE_Y_U_V_WL:
-               image->shader = &gr->texture_shader_y_u_v;
-               break;
-       default:
-               assert(false);
-       }
-
-       return true;
-}
-
-static GLenum
-choose_texture_target(struct dmabuf_attributes *attributes)
-{
-       if (attributes->n_planes > 1)
-               return GL_TEXTURE_EXTERNAL_OES;
-
-       switch (attributes->format & ~DRM_FORMAT_BIG_ENDIAN) {
-       case DRM_FORMAT_YUYV:
-       case DRM_FORMAT_YVYU:
-       case DRM_FORMAT_UYVY:
-       case DRM_FORMAT_VYUY:
-       case DRM_FORMAT_AYUV:
-               return GL_TEXTURE_EXTERNAL_OES;
-       default:
-               return GL_TEXTURE_2D;
-       }
-}
-
-static struct dmabuf_image *
-import_dmabuf(struct gl_renderer *gr,
-             struct linux_dmabuf_buffer *dmabuf)
-{
-       struct egl_image *egl_image;
-       struct dmabuf_image *image;
-
-       image = dmabuf_image_create();
-       image->dmabuf = dmabuf;
-
-       egl_image = import_simple_dmabuf(gr, &dmabuf->attributes);
-       if (egl_image) {
-               image->num_images = 1;
-               image->images[0] = egl_image;
-               image->import_type = IMPORT_TYPE_DIRECT;
-               image->target = choose_texture_target(&dmabuf->attributes);
-
-               switch (image->target) {
-               case GL_TEXTURE_2D:
-                       image->shader = &gr->texture_shader_rgba;
-                       break;
-               default:
-                       image->shader = &gr->texture_shader_egl_external;
-               }
-       } else {
-               if (!import_yuv_dmabuf(gr, image)) {
-                       dmabuf_image_destroy(image);
-                       return NULL;
-               }
-               image->import_type = IMPORT_TYPE_GL_CONVERSION;
-               image->target = GL_TEXTURE_2D;
-       }
-
-       return image;
-}
-
-static bool
-gl_renderer_import_dmabuf(struct weston_compositor *ec,
-                         struct linux_dmabuf_buffer *dmabuf)
-{
-       struct gl_renderer *gr = get_renderer(ec);
-       struct dmabuf_image *image;
-       int i;
-
-       assert(gr->has_dmabuf_import);
-
-       for (i = 0; i < dmabuf->attributes.n_planes; i++) {
-               /* EGL import does not have modifiers */
-               if (dmabuf->attributes.modifier[i] != 0)
-                       return false;
-       }
-
-       /* reject all flags we do not recognize or handle */
-       if (dmabuf->attributes.flags & ~ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT)
-               return false;
-
-       image = import_dmabuf(gr, dmabuf);
-       if (!image)
-               return false;
-
-       wl_list_insert(&gr->dmabuf_images, &image->link);
-       linux_dmabuf_buffer_set_user_data(dmabuf, image,
-               gl_renderer_destroy_dmabuf);
-
-       return true;
-}
-
-static bool
-import_known_dmabuf(struct gl_renderer *gr,
-                    struct dmabuf_image *image)
-{
-       switch (image->import_type) {
-       case IMPORT_TYPE_DIRECT:
-               image->images[0] = import_simple_dmabuf(gr, &image->dmabuf->attributes);
-               if (!image->images[0])
-                       return false;
-               break;
-
-       case IMPORT_TYPE_GL_CONVERSION:
-               if (!import_yuv_dmabuf(gr, image))
-                       return false;
-               break;
-
-       default:
-               weston_log("Invalid import type for dmabuf\n");
-               return false;
-       }
-
-       return true;
-}
-
-static void
-gl_renderer_attach_dmabuf(struct weston_surface *surface,
-                         struct weston_buffer *buffer,
-                         struct linux_dmabuf_buffer *dmabuf)
-{
-       struct gl_renderer *gr = get_renderer(surface->compositor);
-       struct gl_surface_state *gs = get_surface_state(surface);
-       struct dmabuf_image *image;
-       int i;
-       int ret;
-
-       if (!gr->has_dmabuf_import) {
-               linux_dmabuf_buffer_send_server_error(dmabuf,
-                               "EGL dmabuf import not supported");
-               return;
-       }
-
-       buffer->width = dmabuf->attributes.width;
-       buffer->height = dmabuf->attributes.height;
-       buffer->y_inverted =
-               !!(dmabuf->attributes.flags & ZWP_LINUX_BUFFER_PARAMS_V1_FLAGS_Y_INVERT);
-
-       for (i = 0; i < gs->num_images; i++)
-               egl_image_unref(gs->images[i]);
-       gs->num_images = 0;
-
-       /*
-        * We try to always hold an imported EGLImage from the dmabuf
-        * to prevent the client from preventing re-imports. But, we also
-        * need to re-import every time the contents may change because
-        * GL driver's caching may need flushing.
-        *
-        * Here we release the cache reference which has to be final.
-        */
-       image = linux_dmabuf_buffer_get_user_data(dmabuf);
-
-       /* The dmabuf_image should have been created during the import */
-       assert(image != NULL);
-
-       for (i = 0; i < image->num_images; ++i) {
-               ret = egl_image_unref(image->images[i]);
-               assert(ret == 0);
-       }
-
-       if (!import_known_dmabuf(gr, image)) {
-               linux_dmabuf_buffer_send_server_error(dmabuf, "EGL dmabuf import failed");
-               return;
-       }
-
-       gs->num_images = image->num_images;
-       for (i = 0; i < gs->num_images; ++i)
-               gs->images[i] = egl_image_ref(image->images[i]);
-
-       gs->target = image->target;
-       ensure_textures(gs, gs->num_images);
-       for (i = 0; i < gs->num_images; ++i) {
-               glActiveTexture(GL_TEXTURE0 + i);
-               glBindTexture(gs->target, gs->textures[i]);
-               gr->image_target_texture_2d(gs->target, gs->images[i]->image);
-       }
-
-       gs->shader = image->shader;
-       gs->pitch = buffer->width;
-       gs->height = buffer->height;
-       gs->buffer_type = BUFFER_TYPE_EGL;
-       gs->y_inverted = buffer->y_inverted;
-}
-
-static void
-gl_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
-{
-       struct weston_compositor *ec = es->compositor;
-       struct gl_renderer *gr = get_renderer(ec);
-       struct gl_surface_state *gs = get_surface_state(es);
-       struct wl_shm_buffer *shm_buffer;
-       struct linux_dmabuf_buffer *dmabuf;
-       EGLint format;
-       int i;
-
-       weston_buffer_reference(&gs->buffer_ref, buffer);
-
-       if (!buffer) {
-               for (i = 0; i < gs->num_images; i++) {
-                       egl_image_unref(gs->images[i]);
-                       gs->images[i] = NULL;
-               }
-               gs->num_images = 0;
-               glDeleteTextures(gs->num_textures, gs->textures);
-               gs->num_textures = 0;
-               gs->buffer_type = BUFFER_TYPE_NULL;
-               gs->y_inverted = 1;
-               return;
-       }
-
-       shm_buffer = wl_shm_buffer_get(buffer->resource);
-
-       if (shm_buffer)
-               gl_renderer_attach_shm(es, buffer, shm_buffer);
-       else if (gr->query_buffer(gr->egl_display, (void *) buffer->resource,
-                                 EGL_TEXTURE_FORMAT, &format))
-               gl_renderer_attach_egl(es, buffer, format);
-       else if ((dmabuf = linux_dmabuf_buffer_get(buffer->resource)))
-               gl_renderer_attach_dmabuf(es, buffer, dmabuf);
-       else {
-               weston_log("unhandled buffer type!\n");
-               weston_buffer_reference(&gs->buffer_ref, NULL);
-               gs->buffer_type = BUFFER_TYPE_NULL;
-               gs->y_inverted = 1;
-       }
-}
-
-static void
-gl_renderer_surface_set_color(struct weston_surface *surface,
-                float red, float green, float blue, float alpha)
-{
-       struct gl_surface_state *gs = get_surface_state(surface);
-       struct gl_renderer *gr = get_renderer(surface->compositor);
-
-       gs->color[0] = red;
-       gs->color[1] = green;
-       gs->color[2] = blue;
-       gs->color[3] = alpha;
-       gs->buffer_type = BUFFER_TYPE_SOLID;
-       gs->pitch = 1;
-       gs->height = 1;
-
-       gs->shader = &gr->solid_shader;
-}
-
-static void
-gl_renderer_surface_get_content_size(struct weston_surface *surface,
-                                    int *width, int *height)
-{
-       struct gl_surface_state *gs = get_surface_state(surface);
-
-       if (gs->buffer_type == BUFFER_TYPE_NULL) {
-               *width = 0;
-               *height = 0;
-       } else {
-               *width = gs->pitch;
-               *height = gs->height;
-       }
-}
-
-static uint32_t
-pack_color(pixman_format_code_t format, float *c)
-{
-       uint8_t r = round(c[0] * 255.0f);
-       uint8_t g = round(c[1] * 255.0f);
-       uint8_t b = round(c[2] * 255.0f);
-       uint8_t a = round(c[3] * 255.0f);
-
-       switch (format) {
-       case PIXMAN_a8b8g8r8:
-               return (a << 24) | (b << 16) | (g << 8) | r;
-       default:
-               assert(0);
-               return 0;
-       }
-}
-
-static int
-gl_renderer_surface_copy_content(struct weston_surface *surface,
-                                void *target, size_t size,
-                                int src_x, int src_y,
-                                int width, int height)
-{
-       static const GLfloat verts[4 * 2] = {
-               0.0f, 0.0f,
-               1.0f, 0.0f,
-               1.0f, 1.0f,
-               0.0f, 1.0f
-       };
-       static const GLfloat projmat_normal[16] = { /* transpose */
-                2.0f,  0.0f, 0.0f, 0.0f,
-                0.0f,  2.0f, 0.0f, 0.0f,
-                0.0f,  0.0f, 1.0f, 0.0f,
-               -1.0f, -1.0f, 0.0f, 1.0f
-       };
-       static const GLfloat projmat_yinvert[16] = { /* transpose */
-                2.0f,  0.0f, 0.0f, 0.0f,
-                0.0f, -2.0f, 0.0f, 0.0f,
-                0.0f,  0.0f, 1.0f, 0.0f,
-               -1.0f,  1.0f, 0.0f, 1.0f
-       };
-       const pixman_format_code_t format = PIXMAN_a8b8g8r8;
-       const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
-       const GLenum gl_format = GL_RGBA; /* PIXMAN_a8b8g8r8 little-endian */
-       struct gl_renderer *gr = get_renderer(surface->compositor);
-       struct gl_surface_state *gs = get_surface_state(surface);
-       int cw, ch;
-       GLuint fbo;
-       GLuint tex;
-       GLenum status;
-       const GLfloat *proj;
-       int i;
-
-       gl_renderer_surface_get_content_size(surface, &cw, &ch);
-
-       switch (gs->buffer_type) {
-       case BUFFER_TYPE_NULL:
-               return -1;
-       case BUFFER_TYPE_SOLID:
-               *(uint32_t *)target = pack_color(format, gs->color);
-               return 0;
-       case BUFFER_TYPE_SHM:
-               gl_renderer_flush_damage(surface);
-               /* fall through */
-       case BUFFER_TYPE_EGL:
-               break;
-       }
-
-       glGenTextures(1, &tex);
-       glBindTexture(GL_TEXTURE_2D, tex);
-       glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cw, ch,
-                    0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-       glBindTexture(GL_TEXTURE_2D, 0);
-
-       glGenFramebuffers(1, &fbo);
-       glBindFramebuffer(GL_FRAMEBUFFER, fbo);
-       glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
-                              GL_TEXTURE_2D, tex, 0);
-
-       status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
-       if (status != GL_FRAMEBUFFER_COMPLETE) {
-               weston_log("%s: fbo error: %#x\n", __func__, status);
-               glDeleteFramebuffers(1, &fbo);
-               glDeleteTextures(1, &tex);
-               return -1;
-       }
-
-       glViewport(0, 0, cw, ch);
-       glDisable(GL_BLEND);
-       use_shader(gr, gs->shader);
-       if (gs->y_inverted)
-               proj = projmat_normal;
-       else
-               proj = projmat_yinvert;
-
-       glUniformMatrix4fv(gs->shader->proj_uniform, 1, GL_FALSE, proj);
-       glUniform1f(gs->shader->alpha_uniform, 1.0f);
-
-       for (i = 0; i < gs->num_textures; i++) {
-               glUniform1i(gs->shader->tex_uniforms[i], i);
-
-               glActiveTexture(GL_TEXTURE0 + i);
-               glBindTexture(gs->target, gs->textures[i]);
-               glTexParameteri(gs->target, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
-               glTexParameteri(gs->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
-       }
-
-       /* position: */
-       glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, verts);
-       glEnableVertexAttribArray(0);
-
-       /* texcoord: */
-       glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, verts);
-       glEnableVertexAttribArray(1);
-
-       glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
-
-       glDisableVertexAttribArray(1);
-       glDisableVertexAttribArray(0);
-
-       glPixelStorei(GL_PACK_ALIGNMENT, bytespp);
-       glReadPixels(src_x, src_y, width, height, gl_format,
-                    GL_UNSIGNED_BYTE, target);
-
-       glDeleteFramebuffers(1, &fbo);
-       glDeleteTextures(1, &tex);
-
-       return 0;
-}
-
-static void
-surface_state_destroy(struct gl_surface_state *gs, struct gl_renderer *gr)
-{
-       int i;
-
-       wl_list_remove(&gs->surface_destroy_listener.link);
-       wl_list_remove(&gs->renderer_destroy_listener.link);
-
-       gs->surface->renderer_state = NULL;
-
-       glDeleteTextures(gs->num_textures, gs->textures);
-
-       for (i = 0; i < gs->num_images; i++)
-               egl_image_unref(gs->images[i]);
-
-       weston_buffer_reference(&gs->buffer_ref, NULL);
-       pixman_region32_fini(&gs->texture_damage);
-       free(gs);
-}
-
-static void
-surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
-{
-       struct gl_surface_state *gs;
-       struct gl_renderer *gr;
-
-       gs = container_of(listener, struct gl_surface_state,
-                         surface_destroy_listener);
-
-       gr = get_renderer(gs->surface->compositor);
-
-       surface_state_destroy(gs, gr);
-}
-
-static void
-surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
-{
-       struct gl_surface_state *gs;
-       struct gl_renderer *gr;
-
-       gr = data;
-
-       gs = container_of(listener, struct gl_surface_state,
-                         renderer_destroy_listener);
-
-       surface_state_destroy(gs, gr);
-}
-
-static int
-gl_renderer_create_surface(struct weston_surface *surface)
-{
-       struct gl_surface_state *gs;
-       struct gl_renderer *gr = get_renderer(surface->compositor);
-
-       gs = zalloc(sizeof *gs);
-       if (gs == NULL)
-               return -1;
-
-       /* A buffer is never attached to solid color surfaces, yet
-        * they still go through texcoord computations. Do not divide
-        * by zero there.
-        */
-       gs->pitch = 1;
-       gs->y_inverted = 1;
-
-       gs->surface = surface;
-
-       pixman_region32_init(&gs->texture_damage);
-       surface->renderer_state = gs;
-
-       gs->surface_destroy_listener.notify =
-               surface_state_handle_surface_destroy;
-       wl_signal_add(&surface->destroy_signal,
-                     &gs->surface_destroy_listener);
-
-       gs->renderer_destroy_listener.notify =
-               surface_state_handle_renderer_destroy;
-       wl_signal_add(&gr->destroy_signal,
-                     &gs->renderer_destroy_listener);
-
-       if (surface->buffer_ref.buffer) {
-               gl_renderer_attach(surface, surface->buffer_ref.buffer);
-               gl_renderer_flush_damage(surface);
-       }
-
-       return 0;
-}
-
-static const char vertex_shader[] =
-       "uniform mat4 proj;\n"
-       "attribute vec2 position;\n"
-       "attribute vec2 texcoord;\n"
-       "varying vec2 v_texcoord;\n"
-       "void main()\n"
-       "{\n"
-       "   gl_Position = proj * vec4(position, 0.0, 1.0);\n"
-       "   v_texcoord = texcoord;\n"
-       "}\n";
-
-/* Declare common fragment shader uniforms */
-#define FRAGMENT_CONVERT_YUV                                           \
-       "  y *= alpha;\n"                                               \
-       "  u *= alpha;\n"                                               \
-       "  v *= alpha;\n"                                               \
-       "  gl_FragColor.r = y + 1.59602678 * v;\n"                      \
-       "  gl_FragColor.g = y - 0.39176229 * u - 0.81296764 * v;\n"     \
-       "  gl_FragColor.b = y + 2.01723214 * u;\n"                      \
-       "  gl_FragColor.a = alpha;\n"
-
-static const char fragment_debug[] =
-       "  gl_FragColor = vec4(0.0, 0.3, 0.0, 0.2) + gl_FragColor * 0.8;\n";
-
-static const char fragment_brace[] =
-       "}\n";
-
-static const char texture_fragment_shader_rgba[] =
-       "precision mediump float;\n"
-       "varying vec2 v_texcoord;\n"
-       "uniform sampler2D tex;\n"
-       "uniform float alpha;\n"
-       "void main()\n"
-       "{\n"
-       "   gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
-       ;
-
-static const char texture_fragment_shader_rgbx[] =
-       "precision mediump float;\n"
-       "varying vec2 v_texcoord;\n"
-       "uniform sampler2D tex;\n"
-       "uniform float alpha;\n"
-       "void main()\n"
-       "{\n"
-       "   gl_FragColor.rgb = alpha * texture2D(tex, v_texcoord).rgb\n;"
-       "   gl_FragColor.a = alpha;\n"
-       ;
-
-static const char texture_fragment_shader_egl_external[] =
-       "#extension GL_OES_EGL_image_external : require\n"
-       "precision mediump float;\n"
-       "varying vec2 v_texcoord;\n"
-       "uniform samplerExternalOES tex;\n"
-       "uniform float alpha;\n"
-       "void main()\n"
-       "{\n"
-       "   gl_FragColor = alpha * texture2D(tex, v_texcoord)\n;"
-       ;
-
-static const char texture_fragment_shader_y_uv[] =
-       "precision mediump float;\n"
-       "uniform sampler2D tex;\n"
-       "uniform sampler2D tex1;\n"
-       "varying vec2 v_texcoord;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
-       "  float u = texture2D(tex1, v_texcoord).r - 0.5;\n"
-       "  float v = texture2D(tex1, v_texcoord).g - 0.5;\n"
-       FRAGMENT_CONVERT_YUV
-       ;
-
-static const char texture_fragment_shader_y_u_v[] =
-       "precision mediump float;\n"
-       "uniform sampler2D tex;\n"
-       "uniform sampler2D tex1;\n"
-       "uniform sampler2D tex2;\n"
-       "varying vec2 v_texcoord;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
-       "  float u = texture2D(tex1, v_texcoord).x - 0.5;\n"
-       "  float v = texture2D(tex2, v_texcoord).x - 0.5;\n"
-       FRAGMENT_CONVERT_YUV
-       ;
-
-static const char texture_fragment_shader_y_xuxv[] =
-       "precision mediump float;\n"
-       "uniform sampler2D tex;\n"
-       "uniform sampler2D tex1;\n"
-       "varying vec2 v_texcoord;\n"
-       "uniform float alpha;\n"
-       "void main() {\n"
-       "  float y = 1.16438356 * (texture2D(tex, v_texcoord).x - 0.0625);\n"
-       "  float u = texture2D(tex1, v_texcoord).g - 0.5;\n"
-       "  float v = texture2D(tex1, v_texcoord).a - 0.5;\n"
-       FRAGMENT_CONVERT_YUV
-       ;
-
-static const char solid_fragment_shader[] =
-       "precision mediump float;\n"
-       "uniform vec4 color;\n"
-       "uniform float alpha;\n"
-       "void main()\n"
-       "{\n"
-       "   gl_FragColor = alpha * color\n;"
-       ;
-
-static int
-compile_shader(GLenum type, int count, const char **sources)
-{
-       GLuint s;
-       char msg[512];
-       GLint status;
-
-       s = glCreateShader(type);
-       glShaderSource(s, count, sources, NULL);
-       glCompileShader(s);
-       glGetShaderiv(s, GL_COMPILE_STATUS, &status);
-       if (!status) {
-               glGetShaderInfoLog(s, sizeof msg, NULL, msg);
-               weston_log("shader info: %s\n", msg);
-               return GL_NONE;
-       }
-
-       return s;
-}
-
-static int
-shader_init(struct gl_shader *shader, struct gl_renderer *renderer,
-                  const char *vertex_source, const char *fragment_source)
-{
-       char msg[512];
-       GLint status;
-       int count;
-       const char *sources[3];
-
-       shader->vertex_shader =
-               compile_shader(GL_VERTEX_SHADER, 1, &vertex_source);
-
-       if (renderer->fragment_shader_debug) {
-               sources[0] = fragment_source;
-               sources[1] = fragment_debug;
-               sources[2] = fragment_brace;
-               count = 3;
-       } else {
-               sources[0] = fragment_source;
-               sources[1] = fragment_brace;
-               count = 2;
-       }
-
-       shader->fragment_shader =
-               compile_shader(GL_FRAGMENT_SHADER, count, sources);
-
-       shader->program = glCreateProgram();
-       glAttachShader(shader->program, shader->vertex_shader);
-       glAttachShader(shader->program, shader->fragment_shader);
-       glBindAttribLocation(shader->program, 0, "position");
-       glBindAttribLocation(shader->program, 1, "texcoord");
-
-       glLinkProgram(shader->program);
-       glGetProgramiv(shader->program, GL_LINK_STATUS, &status);
-       if (!status) {
-               glGetProgramInfoLog(shader->program, sizeof msg, NULL, msg);
-               weston_log("link info: %s\n", msg);
-               return -1;
-       }
-
-       shader->proj_uniform = glGetUniformLocation(shader->program, "proj");
-       shader->tex_uniforms[0] = glGetUniformLocation(shader->program, "tex");
-       shader->tex_uniforms[1] = glGetUniformLocation(shader->program, "tex1");
-       shader->tex_uniforms[2] = glGetUniformLocation(shader->program, "tex2");
-       shader->alpha_uniform = glGetUniformLocation(shader->program, "alpha");
-       shader->color_uniform = glGetUniformLocation(shader->program, "color");
-
-       return 0;
-}
-
-static void
-shader_release(struct gl_shader *shader)
-{
-       glDeleteShader(shader->vertex_shader);
-       glDeleteShader(shader->fragment_shader);
-       glDeleteProgram(shader->program);
-
-       shader->vertex_shader = 0;
-       shader->fragment_shader = 0;
-       shader->program = 0;
-}
-
-static void
-log_extensions(const char *name, const char *extensions)
-{
-       const char *p, *end;
-       int l;
-       int len;
-
-       l = weston_log("%s:", name);
-       p = extensions;
-       while (*p) {
-               end = strchrnul(p, ' ');
-               len = end - p;
-               if (l + len > 78)
-                       l = weston_log_continue("\n" STAMP_SPACE "%.*s",
-                                               len, p);
-               else
-                       l += weston_log_continue(" %.*s", len, p);
-               for (p = end; isspace(*p); p++)
-                       ;
-       }
-       weston_log_continue("\n");
-}
-
-static void
-log_egl_gl_info(EGLDisplay egldpy)
-{
-       const char *str;
-
-       str = eglQueryString(egldpy, EGL_VERSION);
-       weston_log("EGL version: %s\n", str ? str : "(null)");
-
-       str = eglQueryString(egldpy, EGL_VENDOR);
-       weston_log("EGL vendor: %s\n", str ? str : "(null)");
-
-       str = eglQueryString(egldpy, EGL_CLIENT_APIS);
-       weston_log("EGL client APIs: %s\n", str ? str : "(null)");
-
-       str = eglQueryString(egldpy, EGL_EXTENSIONS);
-       log_extensions("EGL extensions", str ? str : "(null)");
-
-       str = (char *)glGetString(GL_VERSION);
-       weston_log("GL version: %s\n", str ? str : "(null)");
-
-       str = (char *)glGetString(GL_SHADING_LANGUAGE_VERSION);
-       weston_log("GLSL version: %s\n", str ? str : "(null)");
-
-       str = (char *)glGetString(GL_VENDOR);
-       weston_log("GL vendor: %s\n", str ? str : "(null)");
-
-       str = (char *)glGetString(GL_RENDERER);
-       weston_log("GL renderer: %s\n", str ? str : "(null)");
-
-       str = (char *)glGetString(GL_EXTENSIONS);
-       log_extensions("GL extensions", str ? str : "(null)");
-}
-
-static void
-log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig)
-{
-       EGLint r, g, b, a;
-
-       weston_log("Chosen EGL config details:\n");
-
-       weston_log_continue(STAMP_SPACE "RGBA bits");
-       if (eglGetConfigAttrib(egldpy, eglconfig, EGL_RED_SIZE, &r) &&
-           eglGetConfigAttrib(egldpy, eglconfig, EGL_GREEN_SIZE, &g) &&
-           eglGetConfigAttrib(egldpy, eglconfig, EGL_BLUE_SIZE, &b) &&
-           eglGetConfigAttrib(egldpy, eglconfig, EGL_ALPHA_SIZE, &a))
-               weston_log_continue(": %d %d %d %d\n", r, g, b, a);
-       else
-               weston_log_continue(" unknown\n");
-
-       weston_log_continue(STAMP_SPACE "swap interval range");
-       if (eglGetConfigAttrib(egldpy, eglconfig, EGL_MIN_SWAP_INTERVAL, &a) &&
-           eglGetConfigAttrib(egldpy, eglconfig, EGL_MAX_SWAP_INTERVAL, &b))
-               weston_log_continue(": %d - %d\n", a, b);
-       else
-               weston_log_continue(" unknown\n");
-}
-
-static int
-match_config_to_visual(EGLDisplay egl_display,
-                      EGLint visual_id,
-                      EGLConfig *configs,
-                      int count)
-{
-       int i;
-
-       for (i = 0; i < count; ++i) {
-               EGLint id;
-
-               if (!eglGetConfigAttrib(egl_display,
-                               configs[i], EGL_NATIVE_VISUAL_ID,
-                               &id))
-                       continue;
-
-               if (id == visual_id)
-                       return i;
-       }
-
-       return -1;
-}
-
-static int
-egl_choose_config(struct gl_renderer *gr, const EGLint *attribs,
-                 const EGLint *visual_id, const int n_ids,
-                 EGLConfig *config_out)
-{
-       EGLint count = 0;
-       EGLint matched = 0;
-       EGLConfig *configs;
-       int i, config_index = -1;
-
-       if (!eglGetConfigs(gr->egl_display, NULL, 0, &count) || count < 1) {
-               weston_log("No EGL configs to choose from.\n");
-               return -1;
-       }
-       configs = calloc(count, sizeof *configs);
-       if (!configs)
-               return -1;
-
-       if (!eglChooseConfig(gr->egl_display, attribs, configs,
-                             count, &matched) || !matched) {
-               weston_log("No EGL configs with appropriate attributes.\n");
-               goto out;
-       }
-
-       if (!visual_id)
-               config_index = 0;
-
-       for (i = 0; config_index == -1 && i < n_ids; i++)
-               config_index = match_config_to_visual(gr->egl_display,
-                                                     visual_id[i],
-                                                     configs,
-                                                     matched);
-
-       if (config_index != -1)
-               *config_out = configs[config_index];
-
-out:
-       free(configs);
-       if (config_index == -1)
-               return -1;
-
-       if (i > 1)
-               weston_log("Unable to use first choice EGL config with id"
-                          " 0x%x, succeeded with alternate id 0x%x.\n",
-                          visual_id[0], visual_id[i - 1]);
-       return 0;
-}
-
-static void
-gl_renderer_output_set_border(struct weston_output *output,
-                             enum gl_renderer_border_side side,
-                             int32_t width, int32_t height,
-                             int32_t tex_width, unsigned char *data)
-{
-       struct gl_output_state *go = get_output_state(output);
-
-       if (go->borders[side].width != width ||
-           go->borders[side].height != height)
-               /* In this case, we have to blow everything and do a full
-                * repaint. */
-               go->border_status |= BORDER_SIZE_CHANGED | BORDER_ALL_DIRTY;
-
-       if (data == NULL) {
-               width = 0;
-               height = 0;
-       }
-
-       go->borders[side].width = width;
-       go->borders[side].height = height;
-       go->borders[side].tex_width = tex_width;
-       go->borders[side].data = data;
-       go->border_status |= 1 << side;
-}
-
-static int
-gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface);
-
-static int
-gl_renderer_output_create(struct weston_output *output,
-                         EGLNativeWindowType window_for_legacy,
-                         void *window_for_platform,
-                         const EGLint *attribs,
-                         const EGLint *visual_id,
-                         int n_ids)
-{
-       struct weston_compositor *ec = output->compositor;
-       struct gl_renderer *gr = get_renderer(ec);
-       struct gl_output_state *go;
-       EGLConfig egl_config;
-       int i;
-
-       if (egl_choose_config(gr, attribs, visual_id,
-                             n_ids, &egl_config) == -1) {
-               weston_log("failed to choose EGL config for output\n");
-               return -1;
-       }
-
-       if (egl_config != gr->egl_config &&
-           !gr->has_configless_context) {
-               weston_log("attempted to use a different EGL config for an "
-                          "output but EGL_MESA_configless_context is not "
-                          "supported\n");
-               return -1;
-       }
-
-       go = zalloc(sizeof *go);
-       if (go == NULL)
-               return -1;
-
-       if (gr->create_platform_window) {
-               go->egl_surface =
-                       gr->create_platform_window(gr->egl_display,
-                                                  egl_config,
-                                                  window_for_platform,
-                                                  NULL);
-       } else {
-               go->egl_surface =
-                       eglCreateWindowSurface(gr->egl_display,
-                                              egl_config,
-                                              window_for_legacy, NULL);
-       }
-
-       if (go->egl_surface == EGL_NO_SURFACE) {
-               weston_log("failed to create egl surface\n");
-               free(go);
-               return -1;
-       }
-
-       if (gr->egl_context == NULL)
-               if (gl_renderer_setup(ec, go->egl_surface) < 0) {
-                       free(go);
-                       return -1;
-               }
-
-       for (i = 0; i < BUFFER_DAMAGE_COUNT; i++)
-               pixman_region32_init(&go->buffer_damage[i]);
-
-       output->renderer_state = go;
-
-       log_egl_config_info(gr->egl_display, egl_config);
-
-       return 0;
-}
-
-static void
-gl_renderer_output_destroy(struct weston_output *output)
-{
-       struct gl_renderer *gr = get_renderer(output->compositor);
-       struct gl_output_state *go = get_output_state(output);
-       int i;
-
-       for (i = 0; i < 2; i++)
-               pixman_region32_fini(&go->buffer_damage[i]);
-
-       eglDestroySurface(gr->egl_display, go->egl_surface);
-
-       free(go);
-}
-
-static EGLSurface
-gl_renderer_output_surface(struct weston_output *output)
-{
-       return get_output_state(output)->egl_surface;
-}
-
-static void
-gl_renderer_destroy(struct weston_compositor *ec)
-{
-       struct gl_renderer *gr = get_renderer(ec);
-       struct dmabuf_image *image, *next;
-
-       wl_signal_emit(&gr->destroy_signal, gr);
-
-       if (gr->has_bind_display)
-               gr->unbind_display(gr->egl_display, ec->wl_display);
-
-       /* Work around crash in egl_dri2.c's dri2_make_current() - when does this apply? */
-       eglMakeCurrent(gr->egl_display,
-                      EGL_NO_SURFACE, EGL_NO_SURFACE,
-                      EGL_NO_CONTEXT);
-
-
-       wl_list_for_each_safe(image, next, &gr->dmabuf_images, link)
-               dmabuf_image_destroy(image);
-
-       eglTerminate(gr->egl_display);
-       eglReleaseThread();
-
-       wl_array_release(&gr->vertices);
-       wl_array_release(&gr->vtxcnt);
-
-       if (gr->fragment_binding)
-               weston_binding_destroy(gr->fragment_binding);
-       if (gr->fan_binding)
-               weston_binding_destroy(gr->fan_binding);
-
-       free(gr);
-}
-
-static bool
-check_extension(const char *extensions, const char *extension)
-{
-       size_t extlen = strlen(extension);
-       const char *end = extensions + strlen(extensions);
-
-       while (extensions < end) {
-               size_t n = 0;
-
-               /* Skip whitespaces, if any */
-               if (*extensions == ' ') {
-                       extensions++;
-                       continue;
-               }
-
-               n = strcspn(extensions, " ");
-
-               /* Compare strings */
-               if (n == extlen && strncmp(extension, extensions, n) == 0)
-                       return true; /* Found */
-
-               extensions += n;
-       }
-
-       /* Not found */
-       return false;
-}
-
-static void
-renderer_setup_egl_client_extensions(struct gl_renderer *gr)
-{
-       const char *extensions;
-
-       extensions = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
-       if (!extensions) {
-               weston_log("Retrieving EGL client extension string failed.\n");
-               return;
-       }
-
-       if (check_extension(extensions, "EGL_EXT_platform_base"))
-               gr->create_platform_window =
-                       (void *) eglGetProcAddress("eglCreatePlatformWindowSurfaceEXT");
-       else
-               weston_log("warning: EGL_EXT_platform_base not supported.\n");
-}
-
-static int
-gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
-{
-       struct gl_renderer *gr = get_renderer(ec);
-       const char *extensions;
-       EGLBoolean ret;
-
-       gr->create_image = (void *) eglGetProcAddress("eglCreateImageKHR");
-       gr->destroy_image = (void *) eglGetProcAddress("eglDestroyImageKHR");
-       gr->bind_display =
-               (void *) eglGetProcAddress("eglBindWaylandDisplayWL");
-       gr->unbind_display =
-               (void *) eglGetProcAddress("eglUnbindWaylandDisplayWL");
-       gr->query_buffer =
-               (void *) eglGetProcAddress("eglQueryWaylandBufferWL");
-
-       extensions =
-               (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
-       if (!extensions) {
-               weston_log("Retrieving EGL extension string failed.\n");
-               return -1;
-       }
-
-       if (check_extension(extensions, "EGL_WL_bind_wayland_display"))
-               gr->has_bind_display = 1;
-       if (gr->has_bind_display) {
-               ret = gr->bind_display(gr->egl_display, ec->wl_display);
-               if (!ret)
-                       gr->has_bind_display = 0;
-       }
-
-       if (check_extension(extensions, "EGL_EXT_buffer_age"))
-               gr->has_egl_buffer_age = 1;
-       else
-               weston_log("warning: EGL_EXT_buffer_age not supported. "
-                          "Performance could be affected.\n");
-
-#ifdef EGL_EXT_swap_buffers_with_damage
-       if (check_extension(extensions, "EGL_EXT_swap_buffers_with_damage"))
-               gr->swap_buffers_with_damage =
-                       (void *) eglGetProcAddress("eglSwapBuffersWithDamageEXT");
-       else
-               weston_log("warning: EGL_EXT_swap_buffers_with_damage not "
-                          "supported. Performance could be affected.\n");
-#endif
-
-#ifdef EGL_MESA_configless_context
-       if (check_extension(extensions, "EGL_MESA_configless_context"))
-               gr->has_configless_context = 1;
-#endif
-
-#ifdef EGL_EXT_image_dma_buf_import
-       if (check_extension(extensions, "EGL_EXT_image_dma_buf_import"))
-               gr->has_dmabuf_import = 1;
-#endif
-
-       renderer_setup_egl_client_extensions(gr);
-
-       return 0;
-}
-
-static const EGLint gl_renderer_opaque_attribs[] = {
-       EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-       EGL_RED_SIZE, 1,
-       EGL_GREEN_SIZE, 1,
-       EGL_BLUE_SIZE, 1,
-       EGL_ALPHA_SIZE, 0,
-       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-       EGL_NONE
-};
-
-static const EGLint gl_renderer_alpha_attribs[] = {
-       EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
-       EGL_RED_SIZE, 1,
-       EGL_GREEN_SIZE, 1,
-       EGL_BLUE_SIZE, 1,
-       EGL_ALPHA_SIZE, 1,
-       EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
-       EGL_NONE
-};
-
-/** Checks whether a platform EGL client extension is supported
- *
- * \param ec The weston compositor
- * \param extension_suffix The EGL client extension suffix
- * \return 1 if supported, 0 if using fallbacks, -1 unsupported
- *
- * This function checks whether a specific platform_* extension is supported
- * by EGL.
- *
- * The extension suffix should be the suffix of the platform extension (that
- * specifies a <platform> argument as defined in EGL_EXT_platform_base). For
- * example, passing "foo" will check whether either "EGL_KHR_platform_foo",
- * "EGL_EXT_platform_foo", or "EGL_MESA_platform_foo" is supported.
- *
- * The return value is 1:
- *   - if the supplied EGL client extension is supported.
- * The return value is 0:
- *   - if the platform_base client extension isn't supported so will
- *     fallback to eglGetDisplay and friends.
- * The return value is -1:
- *   - if the supplied EGL client extension is not supported.
- */
-static int
-gl_renderer_supports(struct weston_compositor *ec,
-                    const char *extension_suffix)
-{
-       static const char *extensions = NULL;
-       char s[64];
-
-       if (!extensions) {
-               extensions = (const char *) eglQueryString(
-                       EGL_NO_DISPLAY, EGL_EXTENSIONS);
-
-               if (!extensions)
-                       return 0;
-
-               log_extensions("EGL client extensions",
-                              extensions);
-       }
-
-       if (!check_extension(extensions, "EGL_EXT_platform_base"))
-               return 0;
-
-       snprintf(s, sizeof s, "EGL_KHR_platform_%s", extension_suffix);
-       if (check_extension(extensions, s))
-               return 1;
-
-       snprintf(s, sizeof s, "EGL_EXT_platform_%s", extension_suffix);
-       if (check_extension(extensions, s))
-               return 1;
-
-       snprintf(s, sizeof s, "EGL_MESA_platform_%s", extension_suffix);
-       if (check_extension(extensions, s))
-               return 1;
-
-       /* at this point we definitely have some platform extensions but
-        * haven't found the supplied platform, so chances are it's
-        * not supported. */
-
-       return -1;
-}
-
-static const char *
-platform_to_extension(EGLenum platform)
-{
-       switch (platform) {
-       case EGL_PLATFORM_GBM_KHR:
-               return "gbm";
-       case EGL_PLATFORM_WAYLAND_KHR:
-               return "wayland";
-       case EGL_PLATFORM_X11_KHR:
-               return "x11";
-       default:
-               assert(0 && "bad EGL platform enum");
-       }
-}
-
-static int
-gl_renderer_create(struct weston_compositor *ec, EGLenum platform,
-       void *native_window, const EGLint *attribs,
-       const EGLint *visual_id, int n_ids)
-{
-       struct gl_renderer *gr;
-       EGLint major, minor;
-       int supports = 0;
-
-       if (platform) {
-               supports = gl_renderer_supports(
-                       ec, platform_to_extension(platform));
-               if (supports < 0)
-                       return -1;
-       }
-
-       gr = zalloc(sizeof *gr);
-       if (gr == NULL)
-               return -1;
-
-       gr->base.read_pixels = gl_renderer_read_pixels;
-       gr->base.repaint_output = gl_renderer_repaint_output;
-       gr->base.flush_damage = gl_renderer_flush_damage;
-       gr->base.attach = gl_renderer_attach;
-       gr->base.surface_set_color = gl_renderer_surface_set_color;
-       gr->base.destroy = gl_renderer_destroy;
-       gr->base.surface_get_content_size =
-               gl_renderer_surface_get_content_size;
-       gr->base.surface_copy_content = gl_renderer_surface_copy_content;
-       gr->egl_display = NULL;
-
-       /* extension_suffix is supported */
-       if (supports) {
-               if (!get_platform_display) {
-                       get_platform_display = (void *) eglGetProcAddress(
-                                       "eglGetPlatformDisplayEXT");
-               }
-
-               /* also wrap this in the supports check because
-                * eglGetProcAddress can return non-NULL and still not
-                * support the feature at runtime, so ensure the
-                * appropriate extension checks have been done. */
-               if (get_platform_display && platform) {
-                       gr->egl_display = get_platform_display(platform,
-                                                              native_window,
-                                                              NULL);
-               }
-       }
-
-       if (!gr->egl_display) {
-               weston_log("warning: either no EGL_EXT_platform_base "
-                          "support or specific platform support; "
-                          "falling back to eglGetDisplay.\n");
-               gr->egl_display = eglGetDisplay(native_window);
-       }
-
-       if (gr->egl_display == EGL_NO_DISPLAY) {
-               weston_log("failed to create display\n");
-               goto fail;
-       }
-
-       if (!eglInitialize(gr->egl_display, &major, &minor)) {
-               weston_log("failed to initialize display\n");
-               goto fail_with_error;
-       }
-
-       if (egl_choose_config(gr, attribs, visual_id,
-                             n_ids, &gr->egl_config) < 0) {
-               weston_log("failed to choose EGL config\n");
-               goto fail_terminate;
-       }
-
-       ec->renderer = &gr->base;
-       ec->capabilities |= WESTON_CAP_ROTATION_ANY;
-       ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
-       ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
-
-       if (gl_renderer_setup_egl_extensions(ec) < 0)
-               goto fail_with_error;
-
-       wl_list_init(&gr->dmabuf_images);
-       if (gr->has_dmabuf_import)
-               gr->base.import_dmabuf = gl_renderer_import_dmabuf;
-
-       wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
-
-       wl_signal_init(&gr->destroy_signal);
-
-       return 0;
-
-fail_with_error:
-       gl_renderer_print_egl_error_state();
-fail_terminate:
-       eglTerminate(gr->egl_display);
-fail:
-       free(gr);
-       return -1;
-}
-
-static EGLDisplay
-gl_renderer_display(struct weston_compositor *ec)
-{
-       return get_renderer(ec)->egl_display;
-}
-
-static int
-compile_shaders(struct weston_compositor *ec)
-{
-       struct gl_renderer *gr = get_renderer(ec);
-
-       gr->texture_shader_rgba.vertex_source = vertex_shader;
-       gr->texture_shader_rgba.fragment_source = texture_fragment_shader_rgba;
-
-       gr->texture_shader_rgbx.vertex_source = vertex_shader;
-       gr->texture_shader_rgbx.fragment_source = texture_fragment_shader_rgbx;
-
-       gr->texture_shader_egl_external.vertex_source = vertex_shader;
-       gr->texture_shader_egl_external.fragment_source =
-               texture_fragment_shader_egl_external;
-
-       gr->texture_shader_y_uv.vertex_source = vertex_shader;
-       gr->texture_shader_y_uv.fragment_source = texture_fragment_shader_y_uv;
-
-       gr->texture_shader_y_u_v.vertex_source = vertex_shader;
-       gr->texture_shader_y_u_v.fragment_source =
-               texture_fragment_shader_y_u_v;
-
-       gr->texture_shader_y_xuxv.vertex_source = vertex_shader;
-       gr->texture_shader_y_xuxv.fragment_source =
-               texture_fragment_shader_y_xuxv;
-
-       gr->solid_shader.vertex_source = vertex_shader;
-       gr->solid_shader.fragment_source = solid_fragment_shader;
-
-       return 0;
-}
-
-static void
-fragment_debug_binding(struct weston_keyboard *keyboard, uint32_t time,
-                      uint32_t key, void *data)
-{
-       struct weston_compositor *ec = data;
-       struct gl_renderer *gr = get_renderer(ec);
-       struct weston_output *output;
-
-       gr->fragment_shader_debug ^= 1;
-
-       shader_release(&gr->texture_shader_rgba);
-       shader_release(&gr->texture_shader_rgbx);
-       shader_release(&gr->texture_shader_egl_external);
-       shader_release(&gr->texture_shader_y_uv);
-       shader_release(&gr->texture_shader_y_u_v);
-       shader_release(&gr->texture_shader_y_xuxv);
-       shader_release(&gr->solid_shader);
-
-       /* Force use_shader() to call glUseProgram(), since we need to use
-        * the recompiled version of the shader. */
-       gr->current_shader = NULL;
-
-       wl_list_for_each(output, &ec->output_list, link)
-               weston_output_damage(output);
-}
-
-static void
-fan_debug_repaint_binding(struct weston_keyboard *keyboard, uint32_t time,
-                         uint32_t key, void *data)
-{
-       struct weston_compositor *compositor = data;
-       struct gl_renderer *gr = get_renderer(compositor);
-
-       gr->fan_debug = !gr->fan_debug;
-       weston_compositor_damage_all(compositor);
-}
-
-static int
-gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
-{
-       struct gl_renderer *gr = get_renderer(ec);
-       const char *extensions;
-       EGLConfig context_config;
-       EGLBoolean ret;
-
-       static const EGLint context_attribs[] = {
-               EGL_CONTEXT_CLIENT_VERSION, 2,
-               EGL_NONE
-       };
-
-       if (!eglBindAPI(EGL_OPENGL_ES_API)) {
-               weston_log("failed to bind EGL_OPENGL_ES_API\n");
-               gl_renderer_print_egl_error_state();
-               return -1;
-       }
-
-       context_config = gr->egl_config;
-
-#ifdef EGL_MESA_configless_context
-       if (gr->has_configless_context)
-               context_config = EGL_NO_CONFIG_MESA;
-#endif
-
-       gr->egl_context = eglCreateContext(gr->egl_display, context_config,
-                                          EGL_NO_CONTEXT, context_attribs);
-       if (gr->egl_context == NULL) {
-               weston_log("failed to create context\n");
-               gl_renderer_print_egl_error_state();
-               return -1;
-       }
-
-       ret = eglMakeCurrent(gr->egl_display, egl_surface,
-                            egl_surface, gr->egl_context);
-       if (ret == EGL_FALSE) {
-               weston_log("Failed to make EGL context current.\n");
-               gl_renderer_print_egl_error_state();
-               return -1;
-       }
-
-       log_egl_gl_info(gr->egl_display);
-
-       gr->image_target_texture_2d =
-               (void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
-
-       extensions = (const char *) glGetString(GL_EXTENSIONS);
-       if (!extensions) {
-               weston_log("Retrieving GL extension string failed.\n");
-               return -1;
-       }
-
-       if (!check_extension(extensions, "GL_EXT_texture_format_BGRA8888")) {
-               weston_log("GL_EXT_texture_format_BGRA8888 not available\n");
-               return -1;
-       }
-
-       if (check_extension(extensions, "GL_EXT_read_format_bgra"))
-               ec->read_format = PIXMAN_a8r8g8b8;
-       else
-               ec->read_format = PIXMAN_a8b8g8r8;
-
-#ifdef GL_EXT_unpack_subimage
-       if (check_extension(extensions, "GL_EXT_unpack_subimage"))
-               gr->has_unpack_subimage = 1;
-#endif
-
-       if (check_extension(extensions, "GL_OES_EGL_image_external"))
-               gr->has_egl_image_external = 1;
-
-       glActiveTexture(GL_TEXTURE0);
-
-       if (compile_shaders(ec))
-               return -1;
-
-       gr->fragment_binding =
-               weston_compositor_add_debug_binding(ec, KEY_S,
-                                                   fragment_debug_binding,
-                                                   ec);
-       gr->fan_binding =
-               weston_compositor_add_debug_binding(ec, KEY_F,
-                                                   fan_debug_repaint_binding,
-                                                   ec);
-
-       weston_log("GL ES 2 renderer features:\n");
-       weston_log_continue(STAMP_SPACE "read-back format: %s\n",
-               ec->read_format == PIXMAN_a8r8g8b8 ? "BGRA" : "RGBA");
-       weston_log_continue(STAMP_SPACE "wl_shm sub-image to texture: %s\n",
-                           gr->has_unpack_subimage ? "yes" : "no");
-       weston_log_continue(STAMP_SPACE "EGL Wayland extension: %s\n",
-                           gr->has_bind_display ? "yes" : "no");
-
-
-       return 0;
-}
-
-WL_EXPORT struct gl_renderer_interface gl_renderer_interface = {
-       .opaque_attribs = gl_renderer_opaque_attribs,
-       .alpha_attribs = gl_renderer_alpha_attribs,
-
-       .create = gl_renderer_create,
-       .display = gl_renderer_display,
-       .output_create = gl_renderer_output_create,
-       .output_destroy = gl_renderer_output_destroy,
-       .output_surface = gl_renderer_output_surface,
-       .output_set_border = gl_renderer_output_set_border,
-       .print_egl_error_state = gl_renderer_print_egl_error_state
-};
diff --git a/src/gl-renderer.h b/src/gl-renderer.h
deleted file mode 100644 (file)
index 71f6b46..0000000
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright © 2012 John Kåre Alsaker
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include "compositor.h"
-
-#ifdef ENABLE_EGL
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-
-#else
-
-typedef int EGLint;
-typedef int EGLenum;
-typedef void *EGLDisplay;
-typedef void *EGLSurface;
-typedef void *EGLConfig;
-typedef intptr_t EGLNativeDisplayType;
-typedef intptr_t EGLNativeWindowType;
-#define EGL_DEFAULT_DISPLAY ((EGLNativeDisplayType)0)
-
-#endif /* ENABLE_EGL */
-
-#ifndef EGL_EXT_platform_base
-typedef EGLDisplay (*PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
-typedef EGLSurface (*PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
-#endif
-
-#ifndef EGL_PLATFORM_GBM_KHR
-#define EGL_PLATFORM_GBM_KHR 0x31D7
-#endif
-
-#ifndef EGL_PLATFORM_WAYLAND_KHR
-#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
-#endif
-
-#ifndef EGL_PLATFORM_X11_KHR
-#define EGL_PLATFORM_X11_KHR 0x31D5
-#endif
-
-#define NO_EGL_PLATFORM 0
-
-enum gl_renderer_border_side {
-       GL_RENDERER_BORDER_TOP = 0,
-       GL_RENDERER_BORDER_LEFT = 1,
-       GL_RENDERER_BORDER_RIGHT = 2,
-       GL_RENDERER_BORDER_BOTTOM = 3,
-};
-
-struct gl_renderer_interface {
-       const EGLint *opaque_attribs;
-       const EGLint *alpha_attribs;
-
-       int (*create)(struct weston_compositor *ec,
-                     EGLenum platform,
-                     void *native_window,
-                     const EGLint *attribs,
-                     const EGLint *visual_id,
-                     const int n_ids);
-
-       EGLDisplay (*display)(struct weston_compositor *ec);
-
-       int (*output_create)(struct weston_output *output,
-                            EGLNativeWindowType window_for_legacy,
-                            void *window_for_platform,
-                            const EGLint *attribs,
-                            const EGLint *visual_id,
-                            const int n_ids);
-
-       void (*output_destroy)(struct weston_output *output);
-
-       EGLSurface (*output_surface)(struct weston_output *output);
-
-       /* Sets the output border.
-        *
-        * The side specifies the side for which we are setting the border.
-        * The width and height are the width and height of the border.
-        * The tex_width patemeter specifies the width of the actual
-        * texture; this may be larger than width if the data is not
-        * tightly packed.
-        *
-        * The top and bottom textures will extend over the sides to the
-        * full width of the bordered window.  The right and left edges,
-        * however, will extend only to the top and bottom of the
-        * compositor surface.  This is demonstrated by the picture below:
-        *
-        * +-----------------------+
-        * |          TOP          |
-        * +-+-------------------+-+
-        * | |                   | |
-        * |L|                   |R|
-        * |E|                   |I|
-        * |F|                   |G|
-        * |T|                   |H|
-        * | |                   |T|
-        * | |                   | |
-        * +-+-------------------+-+
-        * |        BOTTOM         |
-        * +-----------------------+
-        */
-       void (*output_set_border)(struct weston_output *output,
-                                 enum gl_renderer_border_side side,
-                                 int32_t width, int32_t height,
-                                 int32_t tex_width, unsigned char *data);
-
-       void (*print_egl_error_state)(void);
-};
-
diff --git a/src/input.c b/src/input.c
deleted file mode 100644 (file)
index 08378d1..0000000
+++ /dev/null
@@ -1,2765 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <sys/mman.h>
-#include <assert.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <limits.h>
-
-#include "shared/helpers.h"
-#include "shared/os-compatibility.h"
-#include "compositor.h"
-
-static void
-empty_region(pixman_region32_t *region)
-{
-       pixman_region32_fini(region);
-       pixman_region32_init(region);
-}
-
-static struct weston_pointer_client *
-weston_pointer_client_create(struct wl_client *client)
-{
-       struct weston_pointer_client *pointer_client;
-
-       pointer_client = zalloc(sizeof *pointer_client);
-       if (!pointer_client)
-               return NULL;
-
-       pointer_client->client = client;
-       wl_list_init(&pointer_client->pointer_resources);
-
-       return pointer_client;
-}
-
-static void
-weston_pointer_client_destroy(struct weston_pointer_client *pointer_client)
-{
-       free(pointer_client);
-}
-
-static bool
-weston_pointer_client_is_empty(struct weston_pointer_client *pointer_client)
-{
-       return wl_list_empty(&pointer_client->pointer_resources);
-}
-
-static struct weston_pointer_client *
-weston_pointer_get_pointer_client(struct weston_pointer *pointer,
-                                 struct wl_client *client)
-{
-       struct weston_pointer_client *pointer_client;
-
-       wl_list_for_each(pointer_client, &pointer->pointer_clients, link) {
-               if (pointer_client->client == client)
-                       return pointer_client;
-       }
-
-       return NULL;
-}
-
-static struct weston_pointer_client *
-weston_pointer_ensure_pointer_client(struct weston_pointer *pointer,
-                                    struct wl_client *client)
-{
-       struct weston_pointer_client *pointer_client;
-
-       pointer_client = weston_pointer_get_pointer_client(pointer, client);
-       if (pointer_client)
-               return pointer_client;
-
-       pointer_client = weston_pointer_client_create(client);
-       wl_list_insert(&pointer->pointer_clients, &pointer_client->link);
-
-       if (pointer->focus &&
-           pointer->focus->surface->resource &&
-           wl_resource_get_client(pointer->focus->surface->resource) == client) {
-               pointer->focus_client = pointer_client;
-       }
-
-       return pointer_client;
-}
-
-static void
-weston_pointer_cleanup_pointer_client(struct weston_pointer *pointer,
-                                     struct weston_pointer_client *pointer_client)
-{
-       if (weston_pointer_client_is_empty(pointer_client)) {
-               if (pointer->focus_client == pointer_client)
-                       pointer->focus_client = NULL;
-               wl_list_remove(&pointer_client->link);
-               weston_pointer_client_destroy(pointer_client);
-       }
-}
-
-static void
-unbind_pointer_client_resource(struct wl_resource *resource)
-{
-       struct weston_pointer *pointer = wl_resource_get_user_data(resource);
-       struct wl_client *client = wl_resource_get_client(resource);
-       struct weston_pointer_client *pointer_client;
-
-       pointer_client = weston_pointer_get_pointer_client(pointer, client);
-       assert(pointer_client);
-
-       wl_list_remove(wl_resource_get_link(resource));
-       weston_pointer_cleanup_pointer_client(pointer, pointer_client);
-}
-
-static void unbind_resource(struct wl_resource *resource)
-{
-       wl_list_remove(wl_resource_get_link(resource));
-}
-
-WL_EXPORT void
-weston_seat_repick(struct weston_seat *seat)
-{
-       const struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       if (!pointer)
-               return;
-
-       pointer->grab->interface->focus(pointer->grab);
-}
-
-static void
-weston_compositor_idle_inhibit(struct weston_compositor *compositor)
-{
-       weston_compositor_wake(compositor);
-       compositor->idle_inhibit++;
-}
-
-static void
-weston_compositor_idle_release(struct weston_compositor *compositor)
-{
-       compositor->idle_inhibit--;
-       weston_compositor_wake(compositor);
-}
-
-static void
-pointer_focus_view_destroyed(struct wl_listener *listener, void *data)
-{
-       struct weston_pointer *pointer =
-               container_of(listener, struct weston_pointer,
-                            focus_view_listener);
-
-       weston_pointer_clear_focus(pointer);
-}
-
-static void
-pointer_focus_resource_destroyed(struct wl_listener *listener, void *data)
-{
-       struct weston_pointer *pointer =
-               container_of(listener, struct weston_pointer,
-                            focus_resource_listener);
-
-       weston_pointer_clear_focus(pointer);
-}
-
-static void
-keyboard_focus_resource_destroyed(struct wl_listener *listener, void *data)
-{
-       struct weston_keyboard *keyboard =
-               container_of(listener, struct weston_keyboard,
-                            focus_resource_listener);
-
-       weston_keyboard_set_focus(keyboard, NULL);
-}
-
-static void
-touch_focus_view_destroyed(struct wl_listener *listener, void *data)
-{
-       struct weston_touch *touch =
-               container_of(listener, struct weston_touch,
-                            focus_view_listener);
-
-       weston_touch_set_focus(touch, NULL);
-}
-
-static void
-touch_focus_resource_destroyed(struct wl_listener *listener, void *data)
-{
-       struct weston_touch *touch =
-               container_of(listener, struct weston_touch,
-                            focus_resource_listener);
-
-       weston_touch_set_focus(touch, NULL);
-}
-
-static void
-move_resources(struct wl_list *destination, struct wl_list *source)
-{
-       wl_list_insert_list(destination, source);
-       wl_list_init(source);
-}
-
-static void
-move_resources_for_client(struct wl_list *destination,
-                         struct wl_list *source,
-                         struct wl_client *client)
-{
-       struct wl_resource *resource, *tmp;
-       wl_resource_for_each_safe(resource, tmp, source) {
-               if (wl_resource_get_client(resource) == client) {
-                       wl_list_remove(wl_resource_get_link(resource));
-                       wl_list_insert(destination,
-                                      wl_resource_get_link(resource));
-               }
-       }
-}
-
-static void
-default_grab_pointer_focus(struct weston_pointer_grab *grab)
-{
-       struct weston_pointer *pointer = grab->pointer;
-       struct weston_view *view;
-       wl_fixed_t sx, sy;
-
-       if (pointer->button_count > 0)
-               return;
-
-       view = weston_compositor_pick_view(pointer->seat->compositor,
-                                          pointer->x, pointer->y,
-                                          &sx, &sy);
-
-       if (pointer->focus != view || pointer->sx != sx || pointer->sy != sy)
-               weston_pointer_set_focus(pointer, view, sx, sy);
-}
-
-static void
-default_grab_pointer_motion(struct weston_pointer_grab *grab, uint32_t time,
-                           struct weston_pointer_motion_event *event)
-{
-       struct weston_pointer *pointer = grab->pointer;
-       struct wl_list *resource_list;
-       struct wl_resource *resource;
-       wl_fixed_t x, y;
-       wl_fixed_t old_sx = pointer->sx;
-       wl_fixed_t old_sy = pointer->sy;
-
-       if (pointer->focus) {
-               weston_pointer_motion_to_abs(pointer, event, &x, &y);
-               weston_view_from_global_fixed(pointer->focus, x, y,
-                                             &pointer->sx, &pointer->sy);
-       }
-
-       weston_pointer_move(pointer, event);
-
-       if (pointer->focus_client &&
-           (old_sx != pointer->sx || old_sy != pointer->sy)) {
-               resource_list = &pointer->focus_client->pointer_resources;
-               wl_resource_for_each(resource, resource_list) {
-                       wl_pointer_send_motion(resource, time,
-                                              pointer->sx, pointer->sy);
-               }
-       }
-}
-
-static void
-default_grab_pointer_button(struct weston_pointer_grab *grab,
-                           uint32_t time, uint32_t button, uint32_t state_w)
-{
-       struct weston_pointer *pointer = grab->pointer;
-       struct weston_compositor *compositor = pointer->seat->compositor;
-       struct weston_view *view;
-       struct wl_resource *resource;
-       uint32_t serial;
-       enum wl_pointer_button_state state = state_w;
-       struct wl_display *display = compositor->wl_display;
-       wl_fixed_t sx, sy;
-       struct wl_list *resource_list = NULL;
-
-       if (pointer->focus_client)
-               resource_list = &pointer->focus_client->pointer_resources;
-       if (resource_list && !wl_list_empty(resource_list)) {
-               resource_list = &pointer->focus_client->pointer_resources;
-               serial = wl_display_next_serial(display);
-               wl_resource_for_each(resource, resource_list)
-                       wl_pointer_send_button(resource,
-                                              serial,
-                                              time,
-                                              button,
-                                              state_w);
-       }
-
-       if (pointer->button_count == 0 &&
-           state == WL_POINTER_BUTTON_STATE_RELEASED) {
-               view = weston_compositor_pick_view(compositor,
-                                                  pointer->x, pointer->y,
-                                                  &sx, &sy);
-
-               weston_pointer_set_focus(pointer, view, sx, sy);
-       }
-}
-
-/** Send wl_pointer.axis events to focused resources.
- *
- * \param pointer The pointer where the axis events originates from.
- * \param time The timestamp of the event
- * \param axis The axis enum value of the event
- * \param value The axis value of the event
- *
- * For every resource that is currently in focus, send a wl_pointer.axis event
- * with the passed parameters. The focused resources are the wl_pointer
- * resources of the client which currently has the surface with pointer focus.
- */
-WL_EXPORT void
-weston_pointer_send_axis(struct weston_pointer *pointer,
-                        uint32_t time,
-                        struct weston_pointer_axis_event *event)
-{
-       struct wl_resource *resource;
-       struct wl_list *resource_list;
-
-       if (!pointer->focus_client)
-               return;
-
-       resource_list = &pointer->focus_client->pointer_resources;
-       wl_resource_for_each(resource, resource_list) {
-               if (event->has_discrete &&
-                   wl_resource_get_version(resource) >=
-                   WL_POINTER_AXIS_DISCRETE_SINCE_VERSION)
-                       wl_pointer_send_axis_discrete(resource, event->axis,
-                                                     event->discrete);
-
-               if (event->value)
-                       wl_pointer_send_axis(resource, time,
-                                            event->axis,
-                                            wl_fixed_from_double(event->value));
-               else if (wl_resource_get_version(resource) >=
-                        WL_POINTER_AXIS_STOP_SINCE_VERSION)
-                       wl_pointer_send_axis_stop(resource, time,
-                                                 event->axis);
-       }
-}
-
-WL_EXPORT void
-weston_pointer_send_axis_source(struct weston_pointer *pointer, uint32_t source)
-{
-       struct wl_resource *resource;
-       struct wl_list *resource_list;
-
-       if (!pointer->focus_client)
-               return;
-
-       resource_list = &pointer->focus_client->pointer_resources;
-       wl_resource_for_each(resource, resource_list) {
-               if (wl_resource_get_version(resource) >=
-                   WL_POINTER_AXIS_SOURCE_SINCE_VERSION) {
-                       wl_pointer_send_axis_source(resource, source);
-               }
-       }
-}
-
-static void
-pointer_send_frame(struct wl_resource *resource)
-{
-       if (wl_resource_get_version(resource) >=
-           WL_POINTER_FRAME_SINCE_VERSION) {
-               wl_pointer_send_frame(resource);
-       }
-}
-
-WL_EXPORT void
-weston_pointer_send_frame(struct weston_pointer *pointer)
-{
-       struct wl_resource *resource;
-       struct wl_list *resource_list;
-
-       if (!pointer->focus_client)
-               return;
-
-       resource_list = &pointer->focus_client->pointer_resources;
-       wl_resource_for_each(resource, resource_list)
-               pointer_send_frame(resource);
-}
-
-static void
-default_grab_pointer_axis(struct weston_pointer_grab *grab,
-                         uint32_t time,
-                         struct weston_pointer_axis_event *event)
-{
-       weston_pointer_send_axis(grab->pointer, time, event);
-}
-
-static void
-default_grab_pointer_axis_source(struct weston_pointer_grab *grab,
-                                uint32_t source)
-{
-       weston_pointer_send_axis_source(grab->pointer, source);
-}
-
-static void
-default_grab_pointer_frame(struct weston_pointer_grab *grab)
-{
-       weston_pointer_send_frame(grab->pointer);
-}
-
-static void
-default_grab_pointer_cancel(struct weston_pointer_grab *grab)
-{
-}
-
-static const struct weston_pointer_grab_interface
-                               default_pointer_grab_interface = {
-       default_grab_pointer_focus,
-       default_grab_pointer_motion,
-       default_grab_pointer_button,
-       default_grab_pointer_axis,
-       default_grab_pointer_axis_source,
-       default_grab_pointer_frame,
-       default_grab_pointer_cancel,
-};
-
-static void
-default_grab_touch_down(struct weston_touch_grab *grab, uint32_t time,
-                       int touch_id, wl_fixed_t x, wl_fixed_t y)
-{
-       struct weston_touch *touch = grab->touch;
-       struct wl_display *display = touch->seat->compositor->wl_display;
-       uint32_t serial;
-       struct wl_resource *resource;
-       struct wl_list *resource_list;
-       wl_fixed_t sx, sy;
-
-       if (!touch->focus)
-               return;
-
-       weston_view_from_global_fixed(touch->focus, x, y, &sx, &sy);
-
-       resource_list = &touch->focus_resource_list;
-
-       if (!wl_list_empty(resource_list)) {
-               serial = wl_display_next_serial(display);
-               wl_resource_for_each(resource, resource_list)
-                               wl_touch_send_down(resource, serial, time,
-                                                  touch->focus->surface->resource,
-                                                  touch_id, sx, sy);
-       }
-}
-
-static void
-default_grab_touch_up(struct weston_touch_grab *grab,
-                     uint32_t time, int touch_id)
-{
-       struct weston_touch *touch = grab->touch;
-       struct wl_display *display = touch->seat->compositor->wl_display;
-       uint32_t serial;
-       struct wl_resource *resource;
-       struct wl_list *resource_list;
-
-       resource_list = &touch->focus_resource_list;
-
-       if (!wl_list_empty(resource_list)) {
-               serial = wl_display_next_serial(display);
-               wl_resource_for_each(resource, resource_list)
-                       wl_touch_send_up(resource, serial, time, touch_id);
-       }
-}
-
-static void
-default_grab_touch_motion(struct weston_touch_grab *grab, uint32_t time,
-                         int touch_id, wl_fixed_t x, wl_fixed_t y)
-{
-       struct weston_touch *touch = grab->touch;
-       struct wl_resource *resource;
-       struct wl_list *resource_list;
-       wl_fixed_t sx, sy;
-
-       weston_view_from_global_fixed(touch->focus, x, y, &sx, &sy);
-
-       resource_list = &touch->focus_resource_list;
-
-       wl_resource_for_each(resource, resource_list) {
-               wl_touch_send_motion(resource, time,
-                                    touch_id, sx, sy);
-       }
-}
-
-static void
-default_grab_touch_frame(struct weston_touch_grab *grab)
-{
-       struct wl_resource *resource;
-
-       wl_resource_for_each(resource, &grab->touch->focus_resource_list)
-               wl_touch_send_frame(resource);
-}
-
-static void
-default_grab_touch_cancel(struct weston_touch_grab *grab)
-{
-}
-
-static const struct weston_touch_grab_interface default_touch_grab_interface = {
-       default_grab_touch_down,
-       default_grab_touch_up,
-       default_grab_touch_motion,
-       default_grab_touch_frame,
-       default_grab_touch_cancel,
-};
-
-static void
-default_grab_keyboard_key(struct weston_keyboard_grab *grab,
-                         uint32_t time, uint32_t key, uint32_t state)
-{
-       struct weston_keyboard *keyboard = grab->keyboard;
-       struct wl_resource *resource;
-       struct wl_display *display = keyboard->seat->compositor->wl_display;
-       uint32_t serial;
-       struct wl_list *resource_list;
-
-       resource_list = &keyboard->focus_resource_list;
-       if (!wl_list_empty(resource_list)) {
-               serial = wl_display_next_serial(display);
-               wl_resource_for_each(resource, resource_list)
-                       wl_keyboard_send_key(resource,
-                                            serial,
-                                            time,
-                                            key,
-                                            state);
-       }
-}
-
-static void
-send_modifiers_to_resource(struct weston_keyboard *keyboard,
-                          struct wl_resource *resource,
-                          uint32_t serial)
-{
-       wl_keyboard_send_modifiers(resource,
-                                  serial,
-                                  keyboard->modifiers.mods_depressed,
-                                  keyboard->modifiers.mods_latched,
-                                  keyboard->modifiers.mods_locked,
-                                  keyboard->modifiers.group);
-}
-
-static void
-send_modifiers_to_client_in_list(struct wl_client *client,
-                                struct wl_list *list,
-                                uint32_t serial,
-                                struct weston_keyboard *keyboard)
-{
-       struct wl_resource *resource;
-
-       wl_resource_for_each(resource, list) {
-               if (wl_resource_get_client(resource) == client)
-                       send_modifiers_to_resource(keyboard,
-                                                  resource,
-                                                  serial);
-       }
-}
-
-static struct weston_pointer_client *
-find_pointer_client_for_surface(struct weston_pointer *pointer,
-                               struct weston_surface *surface)
-{
-       struct wl_client *client;
-
-       if (!surface)
-               return NULL;
-
-       if (!surface->resource)
-               return NULL;
-
-       client = wl_resource_get_client(surface->resource);
-       return weston_pointer_get_pointer_client(pointer, client);
-}
-
-static struct weston_pointer_client *
-find_pointer_client_for_view(struct weston_pointer *pointer, struct weston_view *view)
-{
-       if (!view)
-               return NULL;
-
-       return find_pointer_client_for_surface(pointer, view->surface);
-}
-
-static struct wl_resource *
-find_resource_for_surface(struct wl_list *list, struct weston_surface *surface)
-{
-       if (!surface)
-               return NULL;
-
-       if (!surface->resource)
-               return NULL;
-
-       return wl_resource_find_for_client(list, wl_resource_get_client(surface->resource));
-}
-
-static void
-default_grab_keyboard_modifiers(struct weston_keyboard_grab *grab,
-                               uint32_t serial, uint32_t mods_depressed,
-                               uint32_t mods_latched,
-                               uint32_t mods_locked, uint32_t group)
-{
-       struct weston_keyboard *keyboard = grab->keyboard;
-       struct weston_pointer *pointer =
-               weston_seat_get_pointer(grab->keyboard->seat);
-       struct wl_resource *resource;
-       struct wl_list *resource_list;
-
-       resource_list = &keyboard->focus_resource_list;
-
-       wl_resource_for_each(resource, resource_list) {
-               wl_keyboard_send_modifiers(resource, serial, mods_depressed,
-                                          mods_latched, mods_locked, group);
-       }
-       if (pointer && pointer->focus && pointer->focus->surface->resource &&
-           pointer->focus->surface != keyboard->focus) {
-               struct wl_client *pointer_client =
-                       wl_resource_get_client(pointer->focus->surface->resource);
-               send_modifiers_to_client_in_list(pointer_client,
-                                                &keyboard->resource_list,
-                                                serial,
-                                                keyboard);
-       }
-}
-
-static void
-default_grab_keyboard_cancel(struct weston_keyboard_grab *grab)
-{
-}
-
-static const struct weston_keyboard_grab_interface
-                               default_keyboard_grab_interface = {
-       default_grab_keyboard_key,
-       default_grab_keyboard_modifiers,
-       default_grab_keyboard_cancel,
-};
-
-static void
-pointer_unmap_sprite(struct weston_pointer *pointer)
-{
-       struct weston_surface *surface = pointer->sprite->surface;
-
-       if (weston_surface_is_mapped(surface))
-               weston_surface_unmap(surface);
-
-       wl_list_remove(&pointer->sprite_destroy_listener.link);
-       surface->configure = NULL;
-       surface->configure_private = NULL;
-       weston_surface_set_label_func(surface, NULL);
-       weston_view_destroy(pointer->sprite);
-       pointer->sprite = NULL;
-}
-
-static void
-pointer_handle_sprite_destroy(struct wl_listener *listener, void *data)
-{
-       struct weston_pointer *pointer =
-               container_of(listener, struct weston_pointer,
-                            sprite_destroy_listener);
-
-       pointer->sprite = NULL;
-}
-
-static void
-weston_pointer_reset_state(struct weston_pointer *pointer)
-{
-       pointer->button_count = 0;
-}
-
-static void
-weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data);
-
-WL_EXPORT struct weston_pointer *
-weston_pointer_create(struct weston_seat *seat)
-{
-       struct weston_pointer *pointer;
-
-       pointer = zalloc(sizeof *pointer);
-       if (pointer == NULL)
-               return NULL;
-
-       wl_list_init(&pointer->pointer_clients);
-       weston_pointer_set_default_grab(pointer,
-                                       seat->compositor->default_pointer_grab);
-       wl_list_init(&pointer->focus_resource_listener.link);
-       pointer->focus_resource_listener.notify = pointer_focus_resource_destroyed;
-       pointer->default_grab.pointer = pointer;
-       pointer->grab = &pointer->default_grab;
-       wl_signal_init(&pointer->motion_signal);
-       wl_signal_init(&pointer->focus_signal);
-       wl_list_init(&pointer->focus_view_listener.link);
-
-       pointer->sprite_destroy_listener.notify = pointer_handle_sprite_destroy;
-
-       /* FIXME: Pick better co-ords. */
-       pointer->x = wl_fixed_from_int(100);
-       pointer->y = wl_fixed_from_int(100);
-
-       pointer->output_destroy_listener.notify =
-               weston_pointer_handle_output_destroy;
-       wl_signal_add(&seat->compositor->output_destroyed_signal,
-                     &pointer->output_destroy_listener);
-
-       pointer->sx = wl_fixed_from_int(-1000000);
-       pointer->sy = wl_fixed_from_int(-1000000);
-
-       return pointer;
-}
-
-WL_EXPORT void
-weston_pointer_destroy(struct weston_pointer *pointer)
-{
-       if (pointer->sprite)
-               pointer_unmap_sprite(pointer);
-
-       /* XXX: What about pointer->resource_list? */
-
-       wl_list_remove(&pointer->focus_resource_listener.link);
-       wl_list_remove(&pointer->focus_view_listener.link);
-       wl_list_remove(&pointer->output_destroy_listener.link);
-       free(pointer);
-}
-
-void
-weston_pointer_set_default_grab(struct weston_pointer *pointer,
-               const struct weston_pointer_grab_interface *interface)
-{
-       if (interface)
-               pointer->default_grab.interface = interface;
-       else
-               pointer->default_grab.interface =
-                       &default_pointer_grab_interface;
-}
-
-WL_EXPORT struct weston_keyboard *
-weston_keyboard_create(void)
-{
-       struct weston_keyboard *keyboard;
-
-       keyboard = zalloc(sizeof *keyboard);
-       if (keyboard == NULL)
-           return NULL;
-
-       wl_list_init(&keyboard->resource_list);
-       wl_list_init(&keyboard->focus_resource_list);
-       wl_list_init(&keyboard->focus_resource_listener.link);
-       keyboard->focus_resource_listener.notify = keyboard_focus_resource_destroyed;
-       wl_array_init(&keyboard->keys);
-       keyboard->default_grab.interface = &default_keyboard_grab_interface;
-       keyboard->default_grab.keyboard = keyboard;
-       keyboard->grab = &keyboard->default_grab;
-       wl_signal_init(&keyboard->focus_signal);
-
-       return keyboard;
-}
-
-static void
-weston_xkb_info_destroy(struct weston_xkb_info *xkb_info);
-
-WL_EXPORT void
-weston_keyboard_destroy(struct weston_keyboard *keyboard)
-{
-       /* XXX: What about keyboard->resource_list? */
-
-#ifdef ENABLE_XKBCOMMON
-       if (keyboard->seat->compositor->use_xkbcommon) {
-               xkb_state_unref(keyboard->xkb_state.state);
-               if (keyboard->xkb_info)
-                       weston_xkb_info_destroy(keyboard->xkb_info);
-               xkb_keymap_unref(keyboard->pending_keymap);
-       }
-#endif
-
-       wl_array_release(&keyboard->keys);
-       wl_list_remove(&keyboard->focus_resource_listener.link);
-       free(keyboard);
-}
-
-static void
-weston_touch_reset_state(struct weston_touch *touch)
-{
-       touch->num_tp = 0;
-}
-
-WL_EXPORT struct weston_touch *
-weston_touch_create(void)
-{
-       struct weston_touch *touch;
-
-       touch = zalloc(sizeof *touch);
-       if (touch == NULL)
-               return NULL;
-
-       wl_list_init(&touch->resource_list);
-       wl_list_init(&touch->focus_resource_list);
-       wl_list_init(&touch->focus_view_listener.link);
-       touch->focus_view_listener.notify = touch_focus_view_destroyed;
-       wl_list_init(&touch->focus_resource_listener.link);
-       touch->focus_resource_listener.notify = touch_focus_resource_destroyed;
-       touch->default_grab.interface = &default_touch_grab_interface;
-       touch->default_grab.touch = touch;
-       touch->grab = &touch->default_grab;
-       wl_signal_init(&touch->focus_signal);
-
-       return touch;
-}
-
-WL_EXPORT void
-weston_touch_destroy(struct weston_touch *touch)
-{
-       /* XXX: What about touch->resource_list? */
-
-       wl_list_remove(&touch->focus_view_listener.link);
-       wl_list_remove(&touch->focus_resource_listener.link);
-       free(touch);
-}
-
-static void
-seat_send_updated_caps(struct weston_seat *seat)
-{
-       enum wl_seat_capability caps = 0;
-       struct wl_resource *resource;
-
-       if (seat->pointer_device_count > 0)
-               caps |= WL_SEAT_CAPABILITY_POINTER;
-       if (seat->keyboard_device_count > 0)
-               caps |= WL_SEAT_CAPABILITY_KEYBOARD;
-       if (seat->touch_device_count > 0)
-               caps |= WL_SEAT_CAPABILITY_TOUCH;
-
-       wl_resource_for_each(resource, &seat->base_resource_list) {
-               wl_seat_send_capabilities(resource, caps);
-       }
-       wl_signal_emit(&seat->updated_caps_signal, seat);
-}
-
-
-/** Clear the pointer focus
- *
- * \param pointer the pointer to clear focus for.
- *
- * This can be used to unset pointer focus and set the co-ordinates to the
- * arbitrary values we use for the no focus case.
- *
- * There's no requirement to use this function.  For example, passing the
- * results of a weston_compositor_pick_view() directly to
- * weston_pointer_set_focus() will do the right thing when no view is found.
- */
-WL_EXPORT void
-weston_pointer_clear_focus(struct weston_pointer *pointer)
-{
-       weston_pointer_set_focus(pointer, NULL,
-                                wl_fixed_from_int(-1000000),
-                                wl_fixed_from_int(-1000000));
-}
-
-WL_EXPORT void
-weston_pointer_set_focus(struct weston_pointer *pointer,
-                        struct weston_view *view,
-                        wl_fixed_t sx, wl_fixed_t sy)
-{
-       struct weston_pointer_client *pointer_client;
-       struct weston_keyboard *kbd = weston_seat_get_keyboard(pointer->seat);
-       struct wl_resource *resource;
-       struct wl_resource *surface_resource;
-       struct wl_display *display = pointer->seat->compositor->wl_display;
-       uint32_t serial;
-       struct wl_list *focus_resource_list;
-       int refocus = 0;
-
-       if ((!pointer->focus && view) ||
-           (pointer->focus && !view) ||
-           (pointer->focus && pointer->focus->surface != view->surface) ||
-           pointer->sx != sx || pointer->sy != sy)
-               refocus = 1;
-
-       if (pointer->focus_client && refocus) {
-               focus_resource_list = &pointer->focus_client->pointer_resources;
-               if (!wl_list_empty(focus_resource_list)) {
-                       serial = wl_display_next_serial(display);
-                       surface_resource = pointer->focus->surface->resource;
-                       wl_resource_for_each(resource, focus_resource_list) {
-                               wl_pointer_send_leave(resource, serial,
-                                                     surface_resource);
-                               pointer_send_frame(resource);
-                       }
-               }
-
-               pointer->focus_client = NULL;
-       }
-
-       pointer_client = find_pointer_client_for_view(pointer, view);
-       if (pointer_client && refocus) {
-               struct wl_client *surface_client = pointer_client->client;
-
-               serial = wl_display_next_serial(display);
-
-               if (kbd && kbd->focus != view->surface)
-                       send_modifiers_to_client_in_list(surface_client,
-                                                        &kbd->resource_list,
-                                                        serial,
-                                                        kbd);
-
-               pointer->focus_client = pointer_client;
-
-               focus_resource_list = &pointer->focus_client->pointer_resources;
-               wl_resource_for_each(resource, focus_resource_list) {
-                       wl_pointer_send_enter(resource,
-                                             serial,
-                                             view->surface->resource,
-                                             sx, sy);
-                       pointer_send_frame(resource);
-               }
-
-               pointer->focus_serial = serial;
-       }
-
-       wl_list_remove(&pointer->focus_view_listener.link);
-       wl_list_init(&pointer->focus_view_listener.link);
-       wl_list_remove(&pointer->focus_resource_listener.link);
-       wl_list_init(&pointer->focus_resource_listener.link);
-       if (view)
-               wl_signal_add(&view->destroy_signal, &pointer->focus_view_listener);
-       if (view && view->surface->resource)
-               wl_resource_add_destroy_listener(view->surface->resource,
-                                                &pointer->focus_resource_listener);
-
-       pointer->focus = view;
-       pointer->focus_view_listener.notify = pointer_focus_view_destroyed;
-       pointer->sx = sx;
-       pointer->sy = sy;
-
-       assert(view || sx == wl_fixed_from_int(-1000000));
-       assert(view || sy == wl_fixed_from_int(-1000000));
-
-       wl_signal_emit(&pointer->focus_signal, pointer);
-}
-
-static void
-send_enter_to_resource_list(struct wl_list *list,
-                           struct weston_keyboard *keyboard,
-                           struct weston_surface *surface,
-                           uint32_t serial)
-{
-       struct wl_resource *resource;
-
-       wl_resource_for_each(resource, list) {
-               send_modifiers_to_resource(keyboard, resource, serial);
-               wl_keyboard_send_enter(resource, serial,
-                                      surface->resource,
-                                      &keyboard->keys);
-       }
-}
-
-WL_EXPORT void
-weston_keyboard_set_focus(struct weston_keyboard *keyboard,
-                         struct weston_surface *surface)
-{
-       struct wl_resource *resource;
-       struct wl_display *display = keyboard->seat->compositor->wl_display;
-       uint32_t serial;
-       struct wl_list *focus_resource_list;
-
-       focus_resource_list = &keyboard->focus_resource_list;
-
-       if (!wl_list_empty(focus_resource_list) && keyboard->focus != surface) {
-               serial = wl_display_next_serial(display);
-               wl_resource_for_each(resource, focus_resource_list) {
-                       wl_keyboard_send_leave(resource, serial,
-                                       keyboard->focus->resource);
-               }
-               move_resources(&keyboard->resource_list, focus_resource_list);
-       }
-
-       if (find_resource_for_surface(&keyboard->resource_list, surface) &&
-           keyboard->focus != surface) {
-               struct wl_client *surface_client =
-                       wl_resource_get_client(surface->resource);
-
-               serial = wl_display_next_serial(display);
-
-               move_resources_for_client(focus_resource_list,
-                                         &keyboard->resource_list,
-                                         surface_client);
-               send_enter_to_resource_list(focus_resource_list,
-                                           keyboard,
-                                           surface,
-                                           serial);
-               keyboard->focus_serial = serial;
-       }
-
-       wl_list_remove(&keyboard->focus_resource_listener.link);
-       wl_list_init(&keyboard->focus_resource_listener.link);
-       if (surface && surface->resource)
-               wl_resource_add_destroy_listener(surface->resource,
-                                                &keyboard->focus_resource_listener);
-
-       keyboard->focus = surface;
-       wl_signal_emit(&keyboard->focus_signal, keyboard);
-}
-
-/* Users of this function must manually manage the keyboard focus */
-WL_EXPORT void
-weston_keyboard_start_grab(struct weston_keyboard *keyboard,
-                          struct weston_keyboard_grab *grab)
-{
-       keyboard->grab = grab;
-       grab->keyboard = keyboard;
-}
-
-WL_EXPORT void
-weston_keyboard_end_grab(struct weston_keyboard *keyboard)
-{
-       keyboard->grab = &keyboard->default_grab;
-}
-
-static void
-weston_keyboard_cancel_grab(struct weston_keyboard *keyboard)
-{
-       keyboard->grab->interface->cancel(keyboard->grab);
-}
-
-WL_EXPORT void
-weston_pointer_start_grab(struct weston_pointer *pointer,
-                         struct weston_pointer_grab *grab)
-{
-       pointer->grab = grab;
-       grab->pointer = pointer;
-       pointer->grab->interface->focus(pointer->grab);
-}
-
-WL_EXPORT void
-weston_pointer_end_grab(struct weston_pointer *pointer)
-{
-       pointer->grab = &pointer->default_grab;
-       pointer->grab->interface->focus(pointer->grab);
-}
-
-static void
-weston_pointer_cancel_grab(struct weston_pointer *pointer)
-{
-       pointer->grab->interface->cancel(pointer->grab);
-}
-
-WL_EXPORT void
-weston_touch_start_grab(struct weston_touch *touch, struct weston_touch_grab *grab)
-{
-       touch->grab = grab;
-       grab->touch = touch;
-}
-
-WL_EXPORT void
-weston_touch_end_grab(struct weston_touch *touch)
-{
-       touch->grab = &touch->default_grab;
-}
-
-static void
-weston_touch_cancel_grab(struct weston_touch *touch)
-{
-       touch->grab->interface->cancel(touch->grab);
-}
-
-static void
-weston_pointer_clamp_for_output(struct weston_pointer *pointer,
-                               struct weston_output *output,
-                               wl_fixed_t *fx, wl_fixed_t *fy)
-{
-       int x, y;
-
-       x = wl_fixed_to_int(*fx);
-       y = wl_fixed_to_int(*fy);
-
-       if (x < output->x)
-               *fx = wl_fixed_from_int(output->x);
-       else if (x >= output->x + output->width)
-               *fx = wl_fixed_from_int(output->x +
-                                       output->width - 1);
-       if (y < output->y)
-               *fy = wl_fixed_from_int(output->y);
-       else if (y >= output->y + output->height)
-               *fy = wl_fixed_from_int(output->y +
-                                       output->height - 1);
-}
-
-WL_EXPORT void
-weston_pointer_clamp(struct weston_pointer *pointer, wl_fixed_t *fx, wl_fixed_t *fy)
-{
-       struct weston_compositor *ec = pointer->seat->compositor;
-       struct weston_output *output, *prev = NULL;
-       int x, y, old_x, old_y, valid = 0;
-
-       x = wl_fixed_to_int(*fx);
-       y = wl_fixed_to_int(*fy);
-       old_x = wl_fixed_to_int(pointer->x);
-       old_y = wl_fixed_to_int(pointer->y);
-
-       wl_list_for_each(output, &ec->output_list, link) {
-               if (pointer->seat->output && pointer->seat->output != output)
-                       continue;
-               if (pixman_region32_contains_point(&output->region,
-                                                  x, y, NULL))
-                       valid = 1;
-               if (pixman_region32_contains_point(&output->region,
-                                                  old_x, old_y, NULL))
-                       prev = output;
-       }
-
-       if (!prev)
-               prev = pointer->seat->output;
-
-       if (prev && !valid)
-               weston_pointer_clamp_for_output(pointer, prev, fx, fy);
-}
-
-static void
-weston_pointer_move_to(struct weston_pointer *pointer,
-                      wl_fixed_t x, wl_fixed_t y)
-{
-       int32_t ix, iy;
-
-       weston_pointer_clamp (pointer, &x, &y);
-
-       pointer->x = x;
-       pointer->y = y;
-
-       ix = wl_fixed_to_int(x);
-       iy = wl_fixed_to_int(y);
-
-       if (pointer->sprite) {
-               weston_view_set_position(pointer->sprite,
-                                        ix - pointer->hotspot_x,
-                                        iy - pointer->hotspot_y);
-               weston_view_schedule_repaint(pointer->sprite);
-       }
-
-       pointer->grab->interface->focus(pointer->grab);
-       wl_signal_emit(&pointer->motion_signal, pointer);
-}
-
-WL_EXPORT void
-weston_pointer_motion_to_abs(struct weston_pointer *pointer,
-                            struct weston_pointer_motion_event *event,
-                            wl_fixed_t *x, wl_fixed_t *y)
-{
-       if (event->mask & WESTON_POINTER_MOTION_ABS) {
-               *x = wl_fixed_from_double(event->x);
-               *y = wl_fixed_from_double(event->y);
-       } else if (event->mask & WESTON_POINTER_MOTION_REL) {
-               *x = pointer->x + wl_fixed_from_double(event->dx);
-               *y = pointer->y + wl_fixed_from_double(event->dy);
-       } else {
-               assert(!"invalid motion event");
-               *x = *y = 0;
-       }
-}
-
-WL_EXPORT void
-weston_pointer_move(struct weston_pointer *pointer,
-                   struct weston_pointer_motion_event *event)
-{
-       wl_fixed_t x, y;
-
-       weston_pointer_motion_to_abs(pointer, event, &x, &y);
-       weston_pointer_move_to(pointer, x, y);
-}
-
-/** Verify if the pointer is in a valid position and move it if it isn't.
- */
-static void
-weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data)
-{
-       struct weston_pointer *pointer;
-       struct weston_compositor *ec;
-       struct weston_output *output, *closest = NULL;
-       int x, y, distance, min = INT_MAX;
-       wl_fixed_t fx, fy;
-
-       pointer = container_of(listener, struct weston_pointer,
-                              output_destroy_listener);
-       ec = pointer->seat->compositor;
-
-       x = wl_fixed_to_int(pointer->x);
-       y = wl_fixed_to_int(pointer->y);
-
-       wl_list_for_each(output, &ec->output_list, link) {
-               if (pixman_region32_contains_point(&output->region,
-                                                  x, y, NULL))
-                       return;
-
-               /* Aproximante the distance from the pointer to the center of
-                * the output. */
-               distance = abs(output->x + output->width / 2 - x) +
-                          abs(output->y + output->height / 2 - y);
-               if (distance < min) {
-                       min = distance;
-                       closest = output;
-               }
-       }
-
-       /* Nothing to do if there's no output left. */
-       if (!closest)
-               return;
-
-       fx = pointer->x;
-       fy = pointer->y;
-
-       weston_pointer_clamp_for_output(pointer, closest, &fx, &fy);
-       weston_pointer_move_to(pointer, fx, fy);
-}
-
-WL_EXPORT void
-notify_motion(struct weston_seat *seat,
-             uint32_t time,
-             struct weston_pointer_motion_event *event)
-{
-       struct weston_compositor *ec = seat->compositor;
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       weston_compositor_wake(ec);
-       pointer->grab->interface->motion(pointer->grab, time, event);
-}
-
-static void
-run_modifier_bindings(struct weston_seat *seat, uint32_t old, uint32_t new)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       uint32_t diff;
-       unsigned int i;
-       struct {
-               uint32_t xkb;
-               enum weston_keyboard_modifier weston;
-       } mods[] = {
-               { keyboard->xkb_info->ctrl_mod, MODIFIER_CTRL },
-               { keyboard->xkb_info->alt_mod, MODIFIER_ALT },
-               { keyboard->xkb_info->super_mod, MODIFIER_SUPER },
-               { keyboard->xkb_info->shift_mod, MODIFIER_SHIFT },
-       };
-
-       diff = new & ~old;
-       for (i = 0; i < ARRAY_LENGTH(mods); i++) {
-               if (diff & (1 << mods[i].xkb))
-                       weston_compositor_run_modifier_binding(compositor,
-                                                              keyboard,
-                                                              mods[i].weston,
-                                                              WL_KEYBOARD_KEY_STATE_PRESSED);
-       }
-
-       diff = old & ~new;
-       for (i = 0; i < ARRAY_LENGTH(mods); i++) {
-               if (diff & (1 << mods[i].xkb))
-                       weston_compositor_run_modifier_binding(compositor,
-                                                              keyboard,
-                                                              mods[i].weston,
-                                                              WL_KEYBOARD_KEY_STATE_RELEASED);
-       }
-}
-
-WL_EXPORT void
-notify_motion_absolute(struct weston_seat *seat,
-                      uint32_t time, double x, double y)
-{
-       struct weston_compositor *ec = seat->compositor;
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-       struct weston_pointer_motion_event event = { 0 };
-
-       weston_compositor_wake(ec);
-
-       event = (struct weston_pointer_motion_event) {
-               .mask = WESTON_POINTER_MOTION_ABS,
-               .x = x,
-               .y = y,
-       };
-
-       pointer->grab->interface->motion(pointer->grab, time, &event);
-}
-
-WL_EXPORT void
-weston_surface_activate(struct weston_surface *surface,
-                       struct weston_seat *seat)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-
-       if (keyboard) {
-               weston_keyboard_set_focus(keyboard, surface);
-               wl_data_device_set_keyboard_focus(seat);
-       }
-
-       wl_signal_emit(&compositor->activate_signal, surface);
-}
-
-WL_EXPORT void
-notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
-             enum wl_pointer_button_state state)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
-               weston_compositor_idle_inhibit(compositor);
-               if (pointer->button_count == 0) {
-                       pointer->grab_button = button;
-                       pointer->grab_time = time;
-                       pointer->grab_x = pointer->x;
-                       pointer->grab_y = pointer->y;
-               }
-               pointer->button_count++;
-       } else {
-               weston_compositor_idle_release(compositor);
-               pointer->button_count--;
-       }
-
-       weston_compositor_run_button_binding(compositor, pointer, time, button,
-                                            state);
-
-       pointer->grab->interface->button(pointer->grab, time, button, state);
-
-       if (pointer->button_count == 1)
-               pointer->grab_serial =
-                       wl_display_get_serial(compositor->wl_display);
-}
-
-WL_EXPORT void
-notify_axis(struct weston_seat *seat, uint32_t time,
-           struct weston_pointer_axis_event *event)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       weston_compositor_wake(compositor);
-
-       if (weston_compositor_run_axis_binding(compositor, pointer,
-                                              time, event))
-               return;
-
-       pointer->grab->interface->axis(pointer->grab, time, event);
-}
-
-WL_EXPORT void
-notify_axis_source(struct weston_seat *seat, uint32_t source)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       weston_compositor_wake(compositor);
-
-       pointer->grab->interface->axis_source(pointer->grab, source);
-}
-
-WL_EXPORT void
-notify_pointer_frame(struct weston_seat *seat)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       weston_compositor_wake(compositor);
-
-       pointer->grab->interface->frame(pointer->grab);
-}
-
-WL_EXPORT int
-weston_keyboard_set_locks(struct weston_keyboard *keyboard,
-                         uint32_t mask, uint32_t value)
-{
-#ifdef ENABLE_XKBCOMMON
-       uint32_t serial;
-       xkb_mod_mask_t mods_depressed, mods_latched, mods_locked, group;
-       xkb_mod_mask_t num, caps;
-
-       /* We don't want the leds to go out of sync with the actual state
-        * so if the backend has no way to change the leds don't try to
-        * change the state */
-       if (!keyboard->seat->led_update)
-               return -1;
-
-       mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state,
-                                               XKB_STATE_DEPRESSED);
-       mods_latched = xkb_state_serialize_mods(keyboard->xkb_state.state,
-                                               XKB_STATE_LATCHED);
-       mods_locked = xkb_state_serialize_mods(keyboard->xkb_state.state,
-                                               XKB_STATE_LOCKED);
-       group = xkb_state_serialize_group(keyboard->xkb_state.state,
-                                      XKB_STATE_EFFECTIVE);
-
-       num = (1 << keyboard->xkb_info->mod2_mod);
-       caps = (1 << keyboard->xkb_info->caps_mod);
-       if (mask & WESTON_NUM_LOCK) {
-               if (value & WESTON_NUM_LOCK)
-                       mods_locked |= num;
-               else
-                       mods_locked &= ~num;
-       }
-       if (mask & WESTON_CAPS_LOCK) {
-               if (value & WESTON_CAPS_LOCK)
-                       mods_locked |= caps;
-               else
-                       mods_locked &= ~caps;
-       }
-
-       xkb_state_update_mask(keyboard->xkb_state.state, mods_depressed,
-                             mods_latched, mods_locked, 0, 0, group);
-
-       serial = wl_display_next_serial(
-                               keyboard->seat->compositor->wl_display);
-       notify_modifiers(keyboard->seat, serial);
-
-       return 0;
-#else
-       return -1;
-#endif
-}
-
-#ifdef ENABLE_XKBCOMMON
-WL_EXPORT void
-notify_modifiers(struct weston_seat *seat, uint32_t serial)
-{
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       struct weston_keyboard_grab *grab = keyboard->grab;
-       uint32_t mods_depressed, mods_latched, mods_locked, group;
-       uint32_t mods_lookup;
-       enum weston_led leds = 0;
-       int changed = 0;
-
-       /* Serialize and update our internal state, checking to see if it's
-        * different to the previous state. */
-       mods_depressed = xkb_state_serialize_mods(keyboard->xkb_state.state,
-                                                 XKB_STATE_MODS_DEPRESSED);
-       mods_latched = xkb_state_serialize_mods(keyboard->xkb_state.state,
-                                               XKB_STATE_MODS_LATCHED);
-       mods_locked = xkb_state_serialize_mods(keyboard->xkb_state.state,
-                                              XKB_STATE_MODS_LOCKED);
-       group = xkb_state_serialize_layout(keyboard->xkb_state.state,
-                                          XKB_STATE_LAYOUT_EFFECTIVE);
-
-       if (mods_depressed != keyboard->modifiers.mods_depressed ||
-           mods_latched != keyboard->modifiers.mods_latched ||
-           mods_locked != keyboard->modifiers.mods_locked ||
-           group != keyboard->modifiers.group)
-               changed = 1;
-
-       run_modifier_bindings(seat, keyboard->modifiers.mods_depressed,
-                             mods_depressed);
-
-       keyboard->modifiers.mods_depressed = mods_depressed;
-       keyboard->modifiers.mods_latched = mods_latched;
-       keyboard->modifiers.mods_locked = mods_locked;
-       keyboard->modifiers.group = group;
-
-       /* And update the modifier_state for bindings. */
-       mods_lookup = mods_depressed | mods_latched;
-       seat->modifier_state = 0;
-       if (mods_lookup & (1 << keyboard->xkb_info->ctrl_mod))
-               seat->modifier_state |= MODIFIER_CTRL;
-       if (mods_lookup & (1 << keyboard->xkb_info->alt_mod))
-               seat->modifier_state |= MODIFIER_ALT;
-       if (mods_lookup & (1 << keyboard->xkb_info->super_mod))
-               seat->modifier_state |= MODIFIER_SUPER;
-       if (mods_lookup & (1 << keyboard->xkb_info->shift_mod))
-               seat->modifier_state |= MODIFIER_SHIFT;
-
-       /* Finally, notify the compositor that LEDs have changed. */
-       if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
-                                         keyboard->xkb_info->num_led))
-               leds |= LED_NUM_LOCK;
-       if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
-                                         keyboard->xkb_info->caps_led))
-               leds |= LED_CAPS_LOCK;
-       if (xkb_state_led_index_is_active(keyboard->xkb_state.state,
-                                         keyboard->xkb_info->scroll_led))
-               leds |= LED_SCROLL_LOCK;
-       if (leds != keyboard->xkb_state.leds && seat->led_update)
-               seat->led_update(seat, leds);
-       keyboard->xkb_state.leds = leds;
-
-       if (changed) {
-               grab->interface->modifiers(grab,
-                                          serial,
-                                          keyboard->modifiers.mods_depressed,
-                                          keyboard->modifiers.mods_latched,
-                                          keyboard->modifiers.mods_locked,
-                                          keyboard->modifiers.group);
-       }
-}
-
-static void
-update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
-                     enum wl_keyboard_key_state state)
-{
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       enum xkb_key_direction direction;
-
-       /* Keyboard modifiers don't exist in raw keyboard mode */
-       if (!seat->compositor->use_xkbcommon)
-               return;
-
-       if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
-               direction = XKB_KEY_DOWN;
-       else
-               direction = XKB_KEY_UP;
-
-       /* Offset the keycode by 8, as the evdev XKB rules reflect X's
-        * broken keycode system, which starts at 8. */
-       xkb_state_update_key(keyboard->xkb_state.state, key + 8, direction);
-
-       notify_modifiers(seat, serial);
-}
-
-static void
-send_keymap(struct wl_resource *resource, struct weston_xkb_info *xkb_info)
-{
-       wl_keyboard_send_keymap(resource,
-                               WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
-                               xkb_info->keymap_fd,
-                               xkb_info->keymap_size);
-}
-
-static void
-send_modifiers(struct wl_resource *resource, uint32_t serial, struct weston_keyboard *keyboard)
-{
-       wl_keyboard_send_modifiers(resource, serial,
-                                  keyboard->modifiers.mods_depressed,
-                                  keyboard->modifiers.mods_latched,
-                                  keyboard->modifiers.mods_locked,
-                                  keyboard->modifiers.group);
-}
-
-static struct weston_xkb_info *
-weston_xkb_info_create(struct xkb_keymap *keymap);
-
-static void
-update_keymap(struct weston_seat *seat)
-{
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       struct wl_resource *resource;
-       struct weston_xkb_info *xkb_info;
-       struct xkb_state *state;
-       xkb_mod_mask_t latched_mods;
-       xkb_mod_mask_t locked_mods;
-
-       xkb_info = weston_xkb_info_create(keyboard->pending_keymap);
-
-       xkb_keymap_unref(keyboard->pending_keymap);
-       keyboard->pending_keymap = NULL;
-
-       if (!xkb_info) {
-               weston_log("failed to create XKB info\n");
-               return;
-       }
-
-       state = xkb_state_new(xkb_info->keymap);
-       if (!state) {
-               weston_log("failed to initialise XKB state\n");
-               weston_xkb_info_destroy(xkb_info);
-               return;
-       }
-
-       latched_mods = xkb_state_serialize_mods(keyboard->xkb_state.state,
-                                               XKB_STATE_MODS_LATCHED);
-       locked_mods = xkb_state_serialize_mods(keyboard->xkb_state.state,
-                                              XKB_STATE_MODS_LOCKED);
-       xkb_state_update_mask(state,
-                             0, /* depressed */
-                             latched_mods,
-                             locked_mods,
-                             0, 0, 0);
-
-       weston_xkb_info_destroy(keyboard->xkb_info);
-       keyboard->xkb_info = xkb_info;
-
-       xkb_state_unref(keyboard->xkb_state.state);
-       keyboard->xkb_state.state = state;
-
-       wl_resource_for_each(resource, &keyboard->resource_list)
-               send_keymap(resource, xkb_info);
-       wl_resource_for_each(resource, &keyboard->focus_resource_list)
-               send_keymap(resource, xkb_info);
-
-       notify_modifiers(seat, wl_display_next_serial(seat->compositor->wl_display));
-
-       if (!latched_mods && !locked_mods)
-               return;
-
-       wl_resource_for_each(resource, &keyboard->resource_list)
-               send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), keyboard);
-       wl_resource_for_each(resource, &keyboard->focus_resource_list)
-               send_modifiers(resource, wl_display_get_serial(seat->compositor->wl_display), keyboard);
-}
-#else
-WL_EXPORT void
-notify_modifiers(struct weston_seat *seat, uint32_t serial)
-{
-}
-
-static void
-update_modifier_state(struct weston_seat *seat, uint32_t serial, uint32_t key,
-                     enum wl_keyboard_key_state state)
-{
-}
-
-static void
-update_keymap(struct weston_seat *seat)
-{
-}
-#endif
-
-WL_EXPORT void
-notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
-          enum wl_keyboard_key_state state,
-          enum weston_key_state_update update_state)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       struct weston_keyboard_grab *grab = keyboard->grab;
-       uint32_t *k, *end;
-
-       if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-               weston_compositor_idle_inhibit(compositor);
-       } else {
-               weston_compositor_idle_release(compositor);
-       }
-
-       end = keyboard->keys.data + keyboard->keys.size;
-       for (k = keyboard->keys.data; k < end; k++) {
-               if (*k == key) {
-                       /* Ignore server-generated repeats. */
-                       if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
-                               return;
-                       *k = *--end;
-               }
-       }
-       keyboard->keys.size = (void *) end - keyboard->keys.data;
-       if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-               k = wl_array_add(&keyboard->keys, sizeof *k);
-               *k = key;
-       }
-
-       if (grab == &keyboard->default_grab ||
-           grab == &keyboard->input_method_grab) {
-               weston_compositor_run_key_binding(compositor, keyboard, time,
-                                                 key, state);
-               grab = keyboard->grab;
-       }
-
-       grab->interface->key(grab, time, key, state);
-
-       if (keyboard->pending_keymap &&
-           keyboard->keys.size == 0)
-               update_keymap(seat);
-
-       if (update_state == STATE_UPDATE_AUTOMATIC) {
-               update_modifier_state(seat,
-                                     wl_display_get_serial(compositor->wl_display),
-                                     key,
-                                     state);
-       }
-
-       if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
-               keyboard->grab_serial =
-                       wl_display_get_serial(compositor->wl_display);
-               keyboard->grab_time = time;
-               keyboard->grab_key = key;
-       }
-}
-
-WL_EXPORT void
-notify_pointer_focus(struct weston_seat *seat, struct weston_output *output,
-                    double x, double y)
-{
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       if (output) {
-               weston_pointer_move_to(pointer,
-                                      wl_fixed_from_double(x),
-                                      wl_fixed_from_double(y));
-       } else {
-               /* FIXME: We should call weston_pointer_set_focus(seat,
-                * NULL) here, but somehow that breaks re-entry... */
-       }
-}
-
-static void
-destroy_device_saved_kbd_focus(struct wl_listener *listener, void *data)
-{
-       struct weston_seat *ws;
-
-       ws = container_of(listener, struct weston_seat,
-                         saved_kbd_focus_listener);
-
-       ws->saved_kbd_focus = NULL;
-}
-
-WL_EXPORT void
-notify_keyboard_focus_in(struct weston_seat *seat, struct wl_array *keys,
-                        enum weston_key_state_update update_state)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       struct weston_surface *surface;
-       uint32_t *k, serial;
-
-       serial = wl_display_next_serial(compositor->wl_display);
-       wl_array_copy(&keyboard->keys, keys);
-       wl_array_for_each(k, &keyboard->keys) {
-               weston_compositor_idle_inhibit(compositor);
-               if (update_state == STATE_UPDATE_AUTOMATIC)
-                       update_modifier_state(seat, serial, *k,
-                                             WL_KEYBOARD_KEY_STATE_PRESSED);
-       }
-
-       surface = seat->saved_kbd_focus;
-
-       if (surface) {
-               wl_list_remove(&seat->saved_kbd_focus_listener.link);
-               weston_keyboard_set_focus(keyboard, surface);
-               seat->saved_kbd_focus = NULL;
-       }
-}
-
-WL_EXPORT void
-notify_keyboard_focus_out(struct weston_seat *seat)
-{
-       struct weston_compositor *compositor = seat->compositor;
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-       uint32_t *k, serial;
-
-       serial = wl_display_next_serial(compositor->wl_display);
-       wl_array_for_each(k, &keyboard->keys) {
-               weston_compositor_idle_release(compositor);
-               update_modifier_state(seat, serial, *k,
-                                     WL_KEYBOARD_KEY_STATE_RELEASED);
-       }
-
-       seat->modifier_state = 0;
-
-       if (keyboard->focus) {
-               seat->saved_kbd_focus = keyboard->focus;
-               seat->saved_kbd_focus_listener.notify =
-                       destroy_device_saved_kbd_focus;
-               wl_signal_add(&keyboard->focus->destroy_signal,
-                             &seat->saved_kbd_focus_listener);
-       }
-
-       weston_keyboard_set_focus(keyboard, NULL);
-       weston_keyboard_cancel_grab(keyboard);
-       if (pointer)
-               weston_pointer_cancel_grab(pointer);
-}
-
-WL_EXPORT void
-weston_touch_set_focus(struct weston_touch *touch, struct weston_view *view)
-{
-       struct wl_list *focus_resource_list;
-
-       focus_resource_list = &touch->focus_resource_list;
-
-       if (view && touch->focus &&
-           touch->focus->surface == view->surface) {
-               touch->focus = view;
-               return;
-       }
-
-       wl_list_remove(&touch->focus_resource_listener.link);
-       wl_list_init(&touch->focus_resource_listener.link);
-       wl_list_remove(&touch->focus_view_listener.link);
-       wl_list_init(&touch->focus_view_listener.link);
-
-       if (!wl_list_empty(focus_resource_list)) {
-               move_resources(&touch->resource_list,
-                              focus_resource_list);
-       }
-
-       if (view) {
-               struct wl_client *surface_client;
-
-               if (!view->surface->resource) {
-                       touch->focus = NULL;
-                       return;
-               }
-
-               surface_client = wl_resource_get_client(view->surface->resource);
-               move_resources_for_client(focus_resource_list,
-                                         &touch->resource_list,
-                                         surface_client);
-               wl_resource_add_destroy_listener(view->surface->resource,
-                                                &touch->focus_resource_listener);
-               wl_signal_add(&view->destroy_signal, &touch->focus_view_listener);
-       }
-       touch->focus = view;
-}
-
-/**
- * notify_touch - emulates button touches and notifies surfaces accordingly.
- *
- * It assumes always the correct cycle sequence until it gets here: touch_down
- * → touch_update → ... → touch_update → touch_end. The driver is responsible
- * for sending along such order.
- *
- */
-WL_EXPORT void
-notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
-             double double_x, double double_y, int touch_type)
-{
-       struct weston_compositor *ec = seat->compositor;
-       struct weston_touch *touch = weston_seat_get_touch(seat);
-       struct weston_touch_grab *grab = touch->grab;
-       struct weston_view *ev;
-       wl_fixed_t sx, sy;
-       wl_fixed_t x = wl_fixed_from_double(double_x);
-       wl_fixed_t y = wl_fixed_from_double(double_y);
-
-       /* Update grab's global coordinates. */
-       if (touch_id == touch->grab_touch_id && touch_type != WL_TOUCH_UP) {
-               touch->grab_x = x;
-               touch->grab_y = y;
-       }
-
-       switch (touch_type) {
-       case WL_TOUCH_DOWN:
-               weston_compositor_idle_inhibit(ec);
-
-               touch->num_tp++;
-
-               /* the first finger down picks the view, and all further go
-                * to that view for the remainder of the touch session i.e.
-                * until all touch points are up again. */
-               if (touch->num_tp == 1) {
-                       ev = weston_compositor_pick_view(ec, x, y, &sx, &sy);
-                       weston_touch_set_focus(touch, ev);
-               } else if (!touch->focus) {
-                       /* Unexpected condition: We have non-initial touch but
-                        * there is no focused surface.
-                        */
-                       weston_log("touch event received with %d points down "
-                                  "but no surface focused\n", touch->num_tp);
-                       return;
-               }
-
-               weston_compositor_run_touch_binding(ec, touch,
-                                                   time, touch_type);
-
-               grab->interface->down(grab, time, touch_id, x, y);
-               if (touch->num_tp == 1) {
-                       touch->grab_serial =
-                               wl_display_get_serial(ec->wl_display);
-                       touch->grab_touch_id = touch_id;
-                       touch->grab_time = time;
-                       touch->grab_x = x;
-                       touch->grab_y = y;
-               }
-
-               break;
-       case WL_TOUCH_MOTION:
-               ev = touch->focus;
-               if (!ev)
-                       break;
-
-               grab->interface->motion(grab, time, touch_id, x, y);
-               break;
-       case WL_TOUCH_UP:
-               if (touch->num_tp == 0) {
-                       /* This can happen if we start out with one or
-                        * more fingers on the touch screen, in which
-                        * case we didn't get the corresponding down
-                        * event. */
-                       weston_log("unmatched touch up event\n");
-                       break;
-               }
-               weston_compositor_idle_release(ec);
-               touch->num_tp--;
-
-               grab->interface->up(grab, time, touch_id);
-               if (touch->num_tp == 0)
-                       weston_touch_set_focus(touch, NULL);
-               break;
-       }
-}
-
-WL_EXPORT void
-notify_touch_frame(struct weston_seat *seat)
-{
-       struct weston_touch *touch = weston_seat_get_touch(seat);
-       struct weston_touch_grab *grab = touch->grab;
-
-       grab->interface->frame(grab);
-}
-
-WL_EXPORT void
-notify_touch_cancel(struct weston_seat *seat)
-{
-       struct weston_touch *touch = weston_seat_get_touch(seat);
-       struct weston_touch_grab *grab = touch->grab;
-
-       grab->interface->cancel(grab);
-}
-
-static int
-pointer_cursor_surface_get_label(struct weston_surface *surface,
-                                char *buf, size_t len)
-{
-       return snprintf(buf, len, "cursor");
-}
-
-static void
-pointer_cursor_surface_configure(struct weston_surface *es,
-                                int32_t dx, int32_t dy)
-{
-       struct weston_pointer *pointer = es->configure_private;
-       int x, y;
-
-       if (es->width == 0)
-               return;
-
-       assert(es == pointer->sprite->surface);
-
-       pointer->hotspot_x -= dx;
-       pointer->hotspot_y -= dy;
-
-       x = wl_fixed_to_int(pointer->x) - pointer->hotspot_x;
-       y = wl_fixed_to_int(pointer->y) - pointer->hotspot_y;
-
-       weston_view_set_position(pointer->sprite, x, y);
-
-       empty_region(&es->pending.input);
-       empty_region(&es->input);
-
-       if (!weston_surface_is_mapped(es)) {
-               weston_layer_entry_insert(&es->compositor->cursor_layer.view_list,
-                                         &pointer->sprite->layer_link);
-               weston_view_update_transform(pointer->sprite);
-       }
-}
-
-static void
-pointer_set_cursor(struct wl_client *client, struct wl_resource *resource,
-                  uint32_t serial, struct wl_resource *surface_resource,
-                  int32_t x, int32_t y)
-{
-       struct weston_pointer *pointer = wl_resource_get_user_data(resource);
-       struct weston_surface *surface = NULL;
-
-       if (surface_resource)
-               surface = wl_resource_get_user_data(surface_resource);
-
-       if (pointer->focus == NULL)
-               return;
-       /* pointer->focus->surface->resource can be NULL. Surfaces like the
-       black_surface used in shell.c for fullscreen don't have
-       a resource, but can still have focus */
-       if (pointer->focus->surface->resource == NULL)
-               return;
-       if (wl_resource_get_client(pointer->focus->surface->resource) != client)
-               return;
-       if (pointer->focus_serial - serial > UINT32_MAX / 2)
-               return;
-
-       if (!surface) {
-               if (pointer->sprite)
-                       pointer_unmap_sprite(pointer);
-               return;
-       }
-
-       if (pointer->sprite && pointer->sprite->surface == surface &&
-           pointer->hotspot_x == x && pointer->hotspot_y == y)
-               return;
-
-       if (!pointer->sprite || pointer->sprite->surface != surface) {
-               if (weston_surface_set_role(surface, "wl_pointer-cursor",
-                                           resource,
-                                           WL_POINTER_ERROR_ROLE) < 0)
-                       return;
-
-               if (pointer->sprite)
-                       pointer_unmap_sprite(pointer);
-
-               wl_signal_add(&surface->destroy_signal,
-                             &pointer->sprite_destroy_listener);
-
-               surface->configure = pointer_cursor_surface_configure;
-               surface->configure_private = pointer;
-               weston_surface_set_label_func(surface,
-                                           pointer_cursor_surface_get_label);
-               pointer->sprite = weston_view_create(surface);
-       }
-
-       pointer->hotspot_x = x;
-       pointer->hotspot_y = y;
-
-       if (surface->buffer_ref.buffer) {
-               pointer_cursor_surface_configure(surface, 0, 0);
-               weston_view_schedule_repaint(pointer->sprite);
-       }
-}
-
-static void
-pointer_release(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static const struct wl_pointer_interface pointer_interface = {
-       pointer_set_cursor,
-       pointer_release
-};
-
-static void
-seat_get_pointer(struct wl_client *client, struct wl_resource *resource,
-                uint32_t id)
-{
-       struct weston_seat *seat = wl_resource_get_user_data(resource);
-       /* We use the pointer_state directly, which means we'll
-        * give a wl_pointer if the seat has ever had one - even though
-        * the spec explicitly states that this request only takes effect
-        * if the seat has the pointer capability.
-        *
-        * This prevents a race between the compositor sending new
-        * capabilities and the client trying to use the old ones.
-        */
-       struct weston_pointer *pointer = seat->pointer_state;
-       struct wl_resource *cr;
-       struct weston_pointer_client *pointer_client;
-
-       if (!pointer)
-               return;
-
-        cr = wl_resource_create(client, &wl_pointer_interface,
-                               wl_resource_get_version(resource), id);
-       if (cr == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       pointer_client = weston_pointer_ensure_pointer_client(pointer, client);
-       if (!pointer_client) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       wl_list_insert(&pointer_client->pointer_resources,
-                      wl_resource_get_link(cr));
-       wl_resource_set_implementation(cr, &pointer_interface, pointer,
-                                      unbind_pointer_client_resource);
-
-       if (pointer->focus && pointer->focus->surface->resource &&
-           wl_resource_get_client(pointer->focus->surface->resource) == client) {
-               wl_fixed_t sx, sy;
-
-               weston_view_from_global_fixed(pointer->focus,
-                                             pointer->x,
-                                             pointer->y,
-                                             &sx, &sy);
-
-               wl_pointer_send_enter(cr,
-                                     pointer->focus_serial,
-                                     pointer->focus->surface->resource,
-                                     sx, sy);
-               pointer_send_frame(cr);
-       }
-}
-
-static void
-keyboard_release(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static const struct wl_keyboard_interface keyboard_interface = {
-       keyboard_release
-};
-
-static bool
-should_send_modifiers_to_client(struct weston_seat *seat,
-                               struct wl_client *client)
-{
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       if (keyboard &&
-           keyboard->focus &&
-           keyboard->focus->resource &&
-           wl_resource_get_client(keyboard->focus->resource) == client)
-               return true;
-
-       if (pointer &&
-           pointer->focus &&
-           pointer->focus->surface->resource &&
-           wl_resource_get_client(pointer->focus->surface->resource) == client)
-               return true;
-
-       return false;
-}
-
-static void
-seat_get_keyboard(struct wl_client *client, struct wl_resource *resource,
-                 uint32_t id)
-{
-       struct weston_seat *seat = wl_resource_get_user_data(resource);
-       /* We use the keyboard_state directly, which means we'll
-        * give a wl_keyboard if the seat has ever had one - even though
-        * the spec explicitly states that this request only takes effect
-        * if the seat has the keyboard capability.
-        *
-        * This prevents a race between the compositor sending new
-        * capabilities and the client trying to use the old ones.
-        */
-       struct weston_keyboard *keyboard = seat->keyboard_state;
-       struct wl_resource *cr;
-
-       if (!keyboard)
-               return;
-
-        cr = wl_resource_create(client, &wl_keyboard_interface,
-                               wl_resource_get_version(resource), id);
-       if (cr == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       /* May be moved to focused list later by either
-        * weston_keyboard_set_focus or directly if this client is already
-        * focused */
-       wl_list_insert(&keyboard->resource_list, wl_resource_get_link(cr));
-       wl_resource_set_implementation(cr, &keyboard_interface,
-                                      seat, unbind_resource);
-
-       if (wl_resource_get_version(cr) >= WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION) {
-               wl_keyboard_send_repeat_info(cr,
-                                            seat->compositor->kb_repeat_rate,
-                                            seat->compositor->kb_repeat_delay);
-       }
-
-       if (seat->compositor->use_xkbcommon) {
-               wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1,
-                                       keyboard->xkb_info->keymap_fd,
-                                       keyboard->xkb_info->keymap_size);
-       } else {
-               int null_fd = open("/dev/null", O_RDONLY);
-               wl_keyboard_send_keymap(cr, WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP,
-                                       null_fd,
-                                       0);
-               close(null_fd);
-       }
-
-       if (should_send_modifiers_to_client(seat, client)) {
-               send_modifiers_to_resource(keyboard,
-                                          cr,
-                                          keyboard->focus_serial);
-       }
-
-       if (keyboard->focus && keyboard->focus->resource &&
-           wl_resource_get_client(keyboard->focus->resource) == client) {
-               struct weston_surface *surface =
-                       (struct weston_surface *)keyboard->focus;
-
-               wl_list_remove(wl_resource_get_link(cr));
-               wl_list_insert(&keyboard->focus_resource_list,
-                              wl_resource_get_link(cr));
-               wl_keyboard_send_enter(cr,
-                                      keyboard->focus_serial,
-                                      surface->resource,
-                                      &keyboard->keys);
-
-               /* If this is the first keyboard resource for this
-                * client... */
-               if (keyboard->focus_resource_list.prev ==
-                   wl_resource_get_link(cr))
-                       wl_data_device_set_keyboard_focus(seat);
-       }
-}
-
-static void
-touch_release(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static const struct wl_touch_interface touch_interface = {
-       touch_release
-};
-
-static void
-seat_get_touch(struct wl_client *client, struct wl_resource *resource,
-              uint32_t id)
-{
-       struct weston_seat *seat = wl_resource_get_user_data(resource);
-       /* We use the touch_state directly, which means we'll
-        * give a wl_touch if the seat has ever had one - even though
-        * the spec explicitly states that this request only takes effect
-        * if the seat has the touch capability.
-        *
-        * This prevents a race between the compositor sending new
-        * capabilities and the client trying to use the old ones.
-        */
-       struct weston_touch *touch = seat->touch_state;
-       struct wl_resource *cr;
-
-       if (!touch)
-               return;
-
-        cr = wl_resource_create(client, &wl_touch_interface,
-                               wl_resource_get_version(resource), id);
-       if (cr == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       if (touch->focus &&
-           wl_resource_get_client(touch->focus->surface->resource) == client) {
-               wl_list_insert(&touch->focus_resource_list,
-                              wl_resource_get_link(cr));
-       } else {
-               wl_list_insert(&touch->resource_list,
-                              wl_resource_get_link(cr));
-       }
-       wl_resource_set_implementation(cr, &touch_interface,
-                                      seat, unbind_resource);
-}
-
-static void
-seat_release(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static const struct wl_seat_interface seat_interface = {
-       seat_get_pointer,
-       seat_get_keyboard,
-       seat_get_touch,
-       seat_release,
-};
-
-static void
-bind_seat(struct wl_client *client, void *data, uint32_t version, uint32_t id)
-{
-       struct weston_seat *seat = data;
-       struct wl_resource *resource;
-       enum wl_seat_capability caps = 0;
-
-       resource = wl_resource_create(client,
-                                     &wl_seat_interface, version, id);
-       wl_list_insert(&seat->base_resource_list, wl_resource_get_link(resource));
-       wl_resource_set_implementation(resource, &seat_interface, data,
-                                      unbind_resource);
-
-       if (weston_seat_get_pointer(seat))
-               caps |= WL_SEAT_CAPABILITY_POINTER;
-       if (weston_seat_get_keyboard(seat))
-               caps |= WL_SEAT_CAPABILITY_KEYBOARD;
-       if (weston_seat_get_touch(seat))
-               caps |= WL_SEAT_CAPABILITY_TOUCH;
-
-       wl_seat_send_capabilities(resource, caps);
-       if (version >= WL_SEAT_NAME_SINCE_VERSION)
-               wl_seat_send_name(resource, seat->seat_name);
-}
-
-#ifdef ENABLE_XKBCOMMON
-WL_EXPORT int
-weston_compositor_set_xkb_rule_names(struct weston_compositor *ec,
-                                    struct xkb_rule_names *names)
-{
-       ec->use_xkbcommon = 1;
-
-       if (ec->xkb_context == NULL) {
-               ec->xkb_context = xkb_context_new(0);
-               if (ec->xkb_context == NULL) {
-                       weston_log("failed to create XKB context\n");
-                       return -1;
-               }
-       }
-
-       if (names)
-               ec->xkb_names = *names;
-       if (!ec->xkb_names.rules)
-               ec->xkb_names.rules = strdup("evdev");
-       if (!ec->xkb_names.model)
-               ec->xkb_names.model = strdup("pc105");
-       if (!ec->xkb_names.layout)
-               ec->xkb_names.layout = strdup("us");
-
-       return 0;
-}
-
-static void
-weston_xkb_info_destroy(struct weston_xkb_info *xkb_info)
-{
-       if (--xkb_info->ref_count > 0)
-               return;
-
-       xkb_keymap_unref(xkb_info->keymap);
-
-       if (xkb_info->keymap_area)
-               munmap(xkb_info->keymap_area, xkb_info->keymap_size);
-       if (xkb_info->keymap_fd >= 0)
-               close(xkb_info->keymap_fd);
-       free(xkb_info);
-}
-
-void
-weston_compositor_xkb_destroy(struct weston_compositor *ec)
-{
-       /*
-        * If we're operating in raw keyboard mode, we never initialized
-        * libxkbcommon so there's no cleanup to do either.
-        */
-       if (!ec->use_xkbcommon)
-               return;
-
-       free((char *) ec->xkb_names.rules);
-       free((char *) ec->xkb_names.model);
-       free((char *) ec->xkb_names.layout);
-       free((char *) ec->xkb_names.variant);
-       free((char *) ec->xkb_names.options);
-
-       if (ec->xkb_info)
-               weston_xkb_info_destroy(ec->xkb_info);
-       xkb_context_unref(ec->xkb_context);
-}
-
-static struct weston_xkb_info *
-weston_xkb_info_create(struct xkb_keymap *keymap)
-{
-       struct weston_xkb_info *xkb_info = zalloc(sizeof *xkb_info);
-       if (xkb_info == NULL)
-               return NULL;
-
-       xkb_info->keymap = xkb_keymap_ref(keymap);
-       xkb_info->ref_count = 1;
-
-       char *keymap_str;
-
-       xkb_info->shift_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
-                                                      XKB_MOD_NAME_SHIFT);
-       xkb_info->caps_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
-                                                     XKB_MOD_NAME_CAPS);
-       xkb_info->ctrl_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
-                                                     XKB_MOD_NAME_CTRL);
-       xkb_info->alt_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
-                                                    XKB_MOD_NAME_ALT);
-       xkb_info->mod2_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
-                                                     "Mod2");
-       xkb_info->mod3_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
-                                                     "Mod3");
-       xkb_info->super_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
-                                                      XKB_MOD_NAME_LOGO);
-       xkb_info->mod5_mod = xkb_keymap_mod_get_index(xkb_info->keymap,
-                                                     "Mod5");
-
-       xkb_info->num_led = xkb_keymap_led_get_index(xkb_info->keymap,
-                                                    XKB_LED_NAME_NUM);
-       xkb_info->caps_led = xkb_keymap_led_get_index(xkb_info->keymap,
-                                                     XKB_LED_NAME_CAPS);
-       xkb_info->scroll_led = xkb_keymap_led_get_index(xkb_info->keymap,
-                                                       XKB_LED_NAME_SCROLL);
-
-       keymap_str = xkb_keymap_get_as_string(xkb_info->keymap,
-                                             XKB_KEYMAP_FORMAT_TEXT_V1);
-       if (keymap_str == NULL) {
-               weston_log("failed to get string version of keymap\n");
-               goto err_keymap;
-       }
-       xkb_info->keymap_size = strlen(keymap_str) + 1;
-
-       xkb_info->keymap_fd = os_create_anonymous_file(xkb_info->keymap_size);
-       if (xkb_info->keymap_fd < 0) {
-               weston_log("creating a keymap file for %lu bytes failed: %m\n",
-                       (unsigned long) xkb_info->keymap_size);
-               goto err_keymap_str;
-       }
-
-       xkb_info->keymap_area = mmap(NULL, xkb_info->keymap_size,
-                                    PROT_READ | PROT_WRITE,
-                                    MAP_SHARED, xkb_info->keymap_fd, 0);
-       if (xkb_info->keymap_area == MAP_FAILED) {
-               weston_log("failed to mmap() %lu bytes\n",
-                       (unsigned long) xkb_info->keymap_size);
-               goto err_dev_zero;
-       }
-       strcpy(xkb_info->keymap_area, keymap_str);
-       free(keymap_str);
-
-       return xkb_info;
-
-err_dev_zero:
-       close(xkb_info->keymap_fd);
-err_keymap_str:
-       free(keymap_str);
-err_keymap:
-       xkb_keymap_unref(xkb_info->keymap);
-       free(xkb_info);
-       return NULL;
-}
-
-static int
-weston_compositor_build_global_keymap(struct weston_compositor *ec)
-{
-       struct xkb_keymap *keymap;
-
-       if (ec->xkb_info != NULL)
-               return 0;
-
-       keymap = xkb_keymap_new_from_names(ec->xkb_context,
-                                          &ec->xkb_names,
-                                          0);
-       if (keymap == NULL) {
-               weston_log("failed to compile global XKB keymap\n");
-               weston_log("  tried rules %s, model %s, layout %s, variant %s, "
-                       "options %s\n",
-                       ec->xkb_names.rules, ec->xkb_names.model,
-                       ec->xkb_names.layout, ec->xkb_names.variant,
-                       ec->xkb_names.options);
-               return -1;
-       }
-
-       ec->xkb_info = weston_xkb_info_create(keymap);
-       xkb_keymap_unref(keymap);
-       if (ec->xkb_info == NULL)
-               return -1;
-
-       return 0;
-}
-#else
-WL_EXPORT int
-weston_compositor_set_xkb_rule_names(struct weston_compositor *ec,
-                                    struct xkb_rule_names *names)
-{
-       return 0;
-}
-
-void
-weston_compositor_xkb_destroy(struct weston_compositor *ec)
-{
-}
-#endif
-
-WL_EXPORT void
-weston_seat_update_keymap(struct weston_seat *seat, struct xkb_keymap *keymap)
-{
-       struct weston_keyboard *keyboard = weston_seat_get_keyboard(seat);
-
-       if (!keyboard || !keymap)
-               return;
-
-#ifdef ENABLE_XKBCOMMON
-       if (!seat->compositor->use_xkbcommon)
-               return;
-
-       xkb_keymap_unref(keyboard->pending_keymap);
-       keyboard->pending_keymap = xkb_keymap_ref(keymap);
-
-       if (keyboard->keys.size == 0)
-               update_keymap(seat);
-#endif
-}
-
-WL_EXPORT int
-weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
-{
-       struct weston_keyboard *keyboard;
-
-       if (seat->keyboard_state) {
-               seat->keyboard_device_count += 1;
-               if (seat->keyboard_device_count == 1)
-                       seat_send_updated_caps(seat);
-               return 0;
-       }
-
-       keyboard = weston_keyboard_create();
-       if (keyboard == NULL) {
-               weston_log("failed to allocate weston keyboard struct\n");
-               return -1;
-       }
-
-#ifdef ENABLE_XKBCOMMON
-       if (seat->compositor->use_xkbcommon) {
-               if (keymap != NULL) {
-                       keyboard->xkb_info = weston_xkb_info_create(keymap);
-                       if (keyboard->xkb_info == NULL)
-                               goto err;
-               } else {
-                       if (weston_compositor_build_global_keymap(seat->compositor) < 0)
-                               goto err;
-                       keyboard->xkb_info = seat->compositor->xkb_info;
-                       keyboard->xkb_info->ref_count++;
-               }
-
-               keyboard->xkb_state.state = xkb_state_new(keyboard->xkb_info->keymap);
-               if (keyboard->xkb_state.state == NULL) {
-                       weston_log("failed to initialise XKB state\n");
-                       goto err;
-               }
-
-               keyboard->xkb_state.leds = 0;
-       }
-#endif
-
-       seat->keyboard_state = keyboard;
-       seat->keyboard_device_count = 1;
-       keyboard->seat = seat;
-
-       seat_send_updated_caps(seat);
-
-       return 0;
-
-err:
-       if (keyboard->xkb_info)
-               weston_xkb_info_destroy(keyboard->xkb_info);
-       free(keyboard);
-
-       return -1;
-}
-
-static void
-weston_keyboard_reset_state(struct weston_keyboard *keyboard)
-{
-       struct weston_seat *seat = keyboard->seat;
-       struct xkb_state *state;
-
-#ifdef ENABLE_XKBCOMMON
-       if (seat->compositor->use_xkbcommon) {
-               state = xkb_state_new(keyboard->xkb_info->keymap);
-               if (!state) {
-                       weston_log("failed to reset XKB state\n");
-                       return;
-               }
-               xkb_state_unref(keyboard->xkb_state.state);
-               keyboard->xkb_state.state = state;
-
-               keyboard->xkb_state.leds = 0;
-       }
-#endif
-
-       seat->modifier_state = 0;
-}
-
-WL_EXPORT void
-weston_seat_release_keyboard(struct weston_seat *seat)
-{
-       seat->keyboard_device_count--;
-       assert(seat->keyboard_device_count >= 0);
-       if (seat->keyboard_device_count == 0) {
-               weston_keyboard_set_focus(seat->keyboard_state, NULL);
-               weston_keyboard_cancel_grab(seat->keyboard_state);
-               weston_keyboard_reset_state(seat->keyboard_state);
-               seat_send_updated_caps(seat);
-       }
-}
-
-WL_EXPORT void
-weston_seat_init_pointer(struct weston_seat *seat)
-{
-       struct weston_pointer *pointer;
-
-       if (seat->pointer_state) {
-               seat->pointer_device_count += 1;
-               if (seat->pointer_device_count == 1)
-                       seat_send_updated_caps(seat);
-               return;
-       }
-
-       pointer = weston_pointer_create(seat);
-       if (pointer == NULL)
-               return;
-
-       seat->pointer_state = pointer;
-       seat->pointer_device_count = 1;
-       pointer->seat = seat;
-
-       seat_send_updated_caps(seat);
-}
-
-WL_EXPORT void
-weston_seat_release_pointer(struct weston_seat *seat)
-{
-       struct weston_pointer *pointer = seat->pointer_state;
-
-       seat->pointer_device_count--;
-       if (seat->pointer_device_count == 0) {
-               weston_pointer_clear_focus(pointer);
-               weston_pointer_cancel_grab(pointer);
-
-               if (pointer->sprite)
-                       pointer_unmap_sprite(pointer);
-
-               weston_pointer_reset_state(pointer);
-               seat_send_updated_caps(seat);
-
-               /* seat->pointer is intentionally not destroyed so that
-                * a newly attached pointer on this seat will retain
-                * the previous cursor co-ordinates.
-                */
-       }
-}
-
-WL_EXPORT void
-weston_seat_init_touch(struct weston_seat *seat)
-{
-       struct weston_touch *touch;
-
-       if (seat->touch_state) {
-               seat->touch_device_count += 1;
-               if (seat->touch_device_count == 1)
-                       seat_send_updated_caps(seat);
-               return;
-       }
-
-       touch = weston_touch_create();
-       if (touch == NULL)
-               return;
-
-       seat->touch_state = touch;
-       seat->touch_device_count = 1;
-       touch->seat = seat;
-
-       seat_send_updated_caps(seat);
-}
-
-WL_EXPORT void
-weston_seat_release_touch(struct weston_seat *seat)
-{
-       seat->touch_device_count--;
-       if (seat->touch_device_count == 0) {
-               weston_touch_set_focus(seat->touch_state, NULL);
-               weston_touch_cancel_grab(seat->touch_state);
-               weston_touch_reset_state(seat->touch_state);
-               seat_send_updated_caps(seat);
-       }
-}
-
-WL_EXPORT void
-weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
-                const char *seat_name)
-{
-       memset(seat, 0, sizeof *seat);
-
-       seat->selection_data_source = NULL;
-       wl_list_init(&seat->base_resource_list);
-       wl_signal_init(&seat->selection_signal);
-       wl_list_init(&seat->drag_resource_list);
-       wl_signal_init(&seat->destroy_signal);
-       wl_signal_init(&seat->updated_caps_signal);
-
-       seat->global = wl_global_create(ec->wl_display, &wl_seat_interface, 5,
-                                       seat, bind_seat);
-
-       seat->compositor = ec;
-       seat->modifier_state = 0;
-       seat->seat_name = strdup(seat_name);
-
-       wl_list_insert(ec->seat_list.prev, &seat->link);
-
-       clipboard_create(seat);
-
-       wl_signal_emit(&ec->seat_created_signal, seat);
-}
-
-WL_EXPORT void
-weston_seat_release(struct weston_seat *seat)
-{
-       wl_list_remove(&seat->link);
-
-       if (seat->saved_kbd_focus)
-               wl_list_remove(&seat->saved_kbd_focus_listener.link);
-
-       if (seat->pointer_state)
-               weston_pointer_destroy(seat->pointer_state);
-       if (seat->keyboard_state)
-               weston_keyboard_destroy(seat->keyboard_state);
-       if (seat->touch_state)
-               weston_touch_destroy(seat->touch_state);
-
-       free (seat->seat_name);
-
-       wl_global_destroy(seat->global);
-
-       wl_signal_emit(&seat->destroy_signal, seat);
-}
-
-/** Get a seat's keyboard pointer
- *
- * \param seat The seat to query
- * \return The seat's keyboard pointer, or NULL if no keyboard is present
- *
- * The keyboard pointer for a seat isn't freed when all keyboards are removed,
- * so it should only be used when the seat's keyboard_device_count is greater
- * than zero.  This function does that test and only returns a pointer
- * when a keyboard is present.
- */
-WL_EXPORT struct weston_keyboard *
-weston_seat_get_keyboard(struct weston_seat *seat)
-{
-       if (!seat)
-               return NULL;
-
-       if (seat->keyboard_device_count)
-               return seat->keyboard_state;
-
-       return NULL;
-}
-
-/** Get a seat's pointer pointer
- *
- * \param seat The seat to query
- * \return The seat's pointer pointer, or NULL if no pointer device is present
- *
- * The pointer pointer for a seat isn't freed when all mice are removed,
- * so it should only be used when the seat's pointer_device_count is greater
- * than zero.  This function does that test and only returns a pointer
- * when a pointing device is present.
- */
-WL_EXPORT struct weston_pointer *
-weston_seat_get_pointer(struct weston_seat *seat)
-{
-       if (!seat)
-               return NULL;
-
-       if (seat->pointer_device_count)
-               return seat->pointer_state;
-
-       return NULL;
-}
-
-/** Get a seat's touch pointer
- *
- * \param seat The seat to query
- * \return The seat's touch pointer, or NULL if no touch device is present
- *
- * The touch pointer for a seat isn't freed when all touch devices are removed,
- * so it should only be used when the seat's touch_device_count is greater
- * than zero.  This function does that test and only returns a pointer
- * when a touch device is present.
- */
-WL_EXPORT struct weston_touch *
-weston_seat_get_touch(struct weston_seat *seat)
-{
-       if (!seat)
-               return NULL;
-
-       if (seat->touch_device_count)
-               return seat->touch_state;
-
-       return NULL;
-}
diff --git a/src/launcher-direct.c b/src/launcher-direct.c
deleted file mode 100644 (file)
index 29d9c28..0000000
+++ /dev/null
@@ -1,315 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- * Copyright © 2013 Intel Corporation
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holders not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  The copyright holders make
- * no representations about the suitability of this software for any
- * purpose.  It is provided "as is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include "compositor.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <linux/vt.h>
-#include <linux/kd.h>
-#include <linux/major.h>
-
-#include "launcher-impl.h"
-
-#define DRM_MAJOR 226
-
-#ifndef KDSKBMUTE
-#define KDSKBMUTE      0x4B51
-#endif
-
-#ifdef HAVE_LIBDRM
-
-#include <xf86drm.h>
-
-static inline int
-is_drm_master(int drm_fd)
-{
-       drm_magic_t magic;
-
-       return drmGetMagic(drm_fd, &magic) == 0 &&
-               drmAuthMagic(drm_fd, magic) == 0;
-}
-
-#else
-
-static inline int
-drmDropMaster(int drm_fd)
-{
-       return 0;
-}
-
-static inline int
-drmSetMaster(int drm_fd)
-{
-       return 0;
-}
-
-static inline int
-is_drm_master(int drm_fd)
-{
-       return 0;
-}
-
-#endif
-
-struct launcher_direct {
-       struct weston_launcher base;
-       struct weston_compositor *compositor;
-       int kb_mode, tty, drm_fd;
-       struct wl_event_source *vt_source;
-};
-
-static int
-vt_handler(int signal_number, void *data)
-{
-       struct launcher_direct *launcher = data;
-       struct weston_compositor *compositor = launcher->compositor;
-
-       if (compositor->session_active) {
-               compositor->session_active = 0;
-               wl_signal_emit(&compositor->session_signal, compositor);
-               drmDropMaster(launcher->drm_fd);
-               ioctl(launcher->tty, VT_RELDISP, 1);
-       } else {
-               ioctl(launcher->tty, VT_RELDISP, VT_ACKACQ);
-               drmSetMaster(launcher->drm_fd);
-               compositor->session_active = 1;
-               wl_signal_emit(&compositor->session_signal, compositor);
-       }
-
-       return 1;
-}
-
-static int
-setup_tty(struct launcher_direct *launcher, int tty)
-{
-       struct wl_event_loop *loop;
-       struct vt_mode mode = { 0 };
-       struct stat buf;
-       char tty_device[32] ="<stdin>";
-       int ret, kd_mode;
-
-       if (tty == 0) {
-               launcher->tty = dup(tty);
-               if (launcher->tty == -1) {
-                       weston_log("couldn't dup stdin: %m\n");
-                       return -1;
-               }
-       } else {
-               snprintf(tty_device, sizeof tty_device, "/dev/tty%d", tty);
-               launcher->tty = open(tty_device, O_RDWR | O_CLOEXEC);
-               if (launcher->tty == -1) {
-                       weston_log("couldn't open tty %s: %m\n", tty_device);
-                       return -1;
-               }
-       }
-
-       if (fstat(launcher->tty, &buf) == -1 ||
-           major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0) {
-               weston_log("%s not a vt\n", tty_device);
-               weston_log("if running weston from ssh, "
-                          "use --tty to specify a tty\n");
-               goto err_close;
-       }
-
-       ret = ioctl(launcher->tty, KDGETMODE, &kd_mode);
-       if (ret) {
-               weston_log("failed to get VT mode: %m\n");
-               return -1;
-       }
-       if (kd_mode != KD_TEXT) {
-               weston_log("%s is already in graphics mode, "
-                          "is another display server running?\n", tty_device);
-               goto err_close;
-       }
-
-       ioctl(launcher->tty, VT_ACTIVATE, minor(buf.st_rdev));
-       ioctl(launcher->tty, VT_WAITACTIVE, minor(buf.st_rdev));
-
-       if (ioctl(launcher->tty, KDGKBMODE, &launcher->kb_mode)) {
-               weston_log("failed to read keyboard mode: %m\n");
-               goto err_close;
-       }
-
-       if (ioctl(launcher->tty, KDSKBMUTE, 1) &&
-           ioctl(launcher->tty, KDSKBMODE, K_OFF)) {
-               weston_log("failed to set K_OFF keyboard mode: %m\n");
-               goto err_close;
-       }
-
-       ret = ioctl(launcher->tty, KDSETMODE, KD_GRAPHICS);
-       if (ret) {
-               weston_log("failed to set KD_GRAPHICS mode on tty: %m\n");
-               goto err_close;
-       }
-
-       /*
-        * SIGRTMIN is used as global VT-acquire+release signal. Note that
-        * SIGRT* must be tested on runtime, as their exact values are not
-        * known at compile-time. POSIX requires 32 of them to be available.
-        */
-       if (SIGRTMIN > SIGRTMAX) {
-               weston_log("not enough RT signals available: %u-%u\n",
-                          SIGRTMIN, SIGRTMAX);
-               ret = -EINVAL;
-               goto err_close;
-       }
-
-       mode.mode = VT_PROCESS;
-       mode.relsig = SIGRTMIN;
-       mode.acqsig = SIGRTMIN;
-       if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0) {
-               weston_log("failed to take control of vt handling\n");
-               goto err_close;
-       }
-
-       loop = wl_display_get_event_loop(launcher->compositor->wl_display);
-       launcher->vt_source =
-               wl_event_loop_add_signal(loop, SIGRTMIN, vt_handler, launcher);
-       if (!launcher->vt_source)
-               goto err_close;
-
-       return 0;
-
- err_close:
-       close(launcher->tty);
-       return -1;
-}
-
-static int
-launcher_direct_open(struct weston_launcher *launcher_base, const char *path, int flags)
-{
-       struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
-       struct stat s;
-       int fd;
-
-       fd = open(path, flags | O_CLOEXEC);
-       if (fd == -1)
-               return -1;
-
-       if (fstat(fd, &s) == -1) {
-               close(fd);
-               return -1;
-       }
-
-       if (major(s.st_rdev) == DRM_MAJOR) {
-               launcher->drm_fd = fd;
-               if (!is_drm_master(fd)) {
-                       weston_log("drm fd not master\n");
-                       close(fd);
-                       return -1;
-               }
-       }
-
-       return fd;
-}
-
-static void
-launcher_direct_close(struct weston_launcher *launcher_base, int fd)
-{
-       close(fd);
-}
-
-static void
-launcher_direct_restore(struct weston_launcher *launcher_base)
-{
-       struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
-       struct vt_mode mode = { 0 };
-
-       if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
-           ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
-               weston_log("failed to restore kb mode: %m\n");
-
-       if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
-               weston_log("failed to set KD_TEXT mode on tty: %m\n");
-
-       /* We have to drop master before we switch the VT back in
-        * VT_AUTO, so we don't risk switching to a VT with another
-        * display server, that will then fail to set drm master. */
-       drmDropMaster(launcher->drm_fd);
-
-       mode.mode = VT_AUTO;
-       if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
-               weston_log("could not reset vt handling\n");
-}
-
-static int
-launcher_direct_activate_vt(struct weston_launcher *launcher_base, int vt)
-{
-       struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
-       return ioctl(launcher->tty, VT_ACTIVATE, vt);
-}
-
-static int
-launcher_direct_connect(struct weston_launcher **out, struct weston_compositor *compositor,
-                       int tty, const char *seat_id, bool sync_drm)
-{
-       struct launcher_direct *launcher;
-
-       if (geteuid() != 0)
-               return -EINVAL;
-
-       launcher = zalloc(sizeof(*launcher));
-       if (launcher == NULL)
-               return -ENOMEM;
-
-       launcher->base.iface = &launcher_direct_iface;
-       launcher->compositor = compositor;
-
-       if (setup_tty(launcher, tty) == -1) {
-               free(launcher);
-               return -1;
-       }
-
-       * (struct launcher_direct **) out = launcher;
-       return 0;
-}
-
-static void
-launcher_direct_destroy(struct weston_launcher *launcher_base)
-{
-       struct launcher_direct *launcher = wl_container_of(launcher_base, launcher, base);
-
-       launcher_direct_restore(&launcher->base);
-       wl_event_source_remove(launcher->vt_source);
-
-       if (launcher->tty >= 0)
-               close(launcher->tty);
-
-       free(launcher);
-}
-
-struct launcher_interface launcher_direct_iface = {
-       launcher_direct_connect,
-       launcher_direct_destroy,
-       launcher_direct_open,
-       launcher_direct_close,
-       launcher_direct_activate_vt,
-       launcher_direct_restore,
-};
diff --git a/src/launcher-impl.h b/src/launcher-impl.h
deleted file mode 100644 (file)
index 742721b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright © 2015 Jasper St. Pierre
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holders not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  The copyright holders make
- * no representations about the suitability of this software for any
- * purpose.  It is provided "as is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include "compositor.h"
-
-struct weston_launcher;
-
-struct launcher_interface {
-       int (* connect) (struct weston_launcher **launcher_out, struct weston_compositor *compositor,
-                        int tty, const char *seat_id, bool sync_drm);
-       void (* destroy) (struct weston_launcher *launcher);
-       int (* open) (struct weston_launcher *launcher, const char *path, int flags);
-       void (* close) (struct weston_launcher *launcher, int fd);
-       int (* activate_vt) (struct weston_launcher *launcher, int vt);
-       void (* restore) (struct weston_launcher *launcher);
-};
-
-struct weston_launcher {
-       struct launcher_interface *iface;
-};
-
-extern struct launcher_interface launcher_logind_iface;
-extern struct launcher_interface launcher_weston_launch_iface;
-extern struct launcher_interface launcher_direct_iface;
diff --git a/src/launcher-logind.c b/src/launcher-logind.c
deleted file mode 100644 (file)
index f755ec3..0000000
+++ /dev/null
@@ -1,839 +0,0 @@
-/*
- * Copyright © 2013 David Herrmann
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <signal.h>
-#include <stdarg.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <systemd/sd-login.h>
-#include <unistd.h>
-
-#include "compositor.h"
-#include "dbus.h"
-#include "launcher-impl.h"
-
-#define DRM_MAJOR 226
-
-struct launcher_logind {
-       struct weston_launcher base;
-       struct weston_compositor *compositor;
-       bool sync_drm;
-       char *seat;
-       char *sid;
-       unsigned int vtnr;
-       int vt;
-       int kb_mode;
-
-       DBusConnection *dbus;
-       struct wl_event_source *dbus_ctx;
-       char *spath;
-       DBusPendingCall *pending_active;
-};
-
-static int
-launcher_logind_take_device(struct launcher_logind *wl, uint32_t major,
-                         uint32_t minor, bool *paused_out)
-{
-       DBusMessage *m, *reply;
-       bool b;
-       int r, fd;
-       dbus_bool_t paused;
-
-       m = dbus_message_new_method_call("org.freedesktop.login1",
-                                        wl->spath,
-                                        "org.freedesktop.login1.Session",
-                                        "TakeDevice");
-       if (!m)
-               return -ENOMEM;
-
-       b = dbus_message_append_args(m,
-                                    DBUS_TYPE_UINT32, &major,
-                                    DBUS_TYPE_UINT32, &minor,
-                                    DBUS_TYPE_INVALID);
-       if (!b) {
-               r = -ENOMEM;
-               goto err_unref;
-       }
-
-       reply = dbus_connection_send_with_reply_and_block(wl->dbus, m,
-                                                         -1, NULL);
-       if (!reply) {
-               r = -ENODEV;
-               goto err_unref;
-       }
-
-       b = dbus_message_get_args(reply, NULL,
-                                 DBUS_TYPE_UNIX_FD, &fd,
-                                 DBUS_TYPE_BOOLEAN, &paused,
-                                 DBUS_TYPE_INVALID);
-       if (!b) {
-               r = -ENODEV;
-               goto err_reply;
-       }
-
-       r = fd;
-       if (paused_out)
-               *paused_out = paused;
-
-err_reply:
-       dbus_message_unref(reply);
-err_unref:
-       dbus_message_unref(m);
-       return r;
-}
-
-static void
-launcher_logind_release_device(struct launcher_logind *wl, uint32_t major,
-                            uint32_t minor)
-{
-       DBusMessage *m;
-       bool b;
-
-       m = dbus_message_new_method_call("org.freedesktop.login1",
-                                        wl->spath,
-                                        "org.freedesktop.login1.Session",
-                                        "ReleaseDevice");
-       if (m) {
-               b = dbus_message_append_args(m,
-                                            DBUS_TYPE_UINT32, &major,
-                                            DBUS_TYPE_UINT32, &minor,
-                                            DBUS_TYPE_INVALID);
-               if (b)
-                       dbus_connection_send(wl->dbus, m, NULL);
-               dbus_message_unref(m);
-       }
-}
-
-static void
-launcher_logind_pause_device_complete(struct launcher_logind *wl, uint32_t major,
-                                   uint32_t minor)
-{
-       DBusMessage *m;
-       bool b;
-
-       m = dbus_message_new_method_call("org.freedesktop.login1",
-                                        wl->spath,
-                                        "org.freedesktop.login1.Session",
-                                        "PauseDeviceComplete");
-       if (m) {
-               b = dbus_message_append_args(m,
-                                            DBUS_TYPE_UINT32, &major,
-                                            DBUS_TYPE_UINT32, &minor,
-                                            DBUS_TYPE_INVALID);
-               if (b)
-                       dbus_connection_send(wl->dbus, m, NULL);
-               dbus_message_unref(m);
-       }
-}
-
-static int
-launcher_logind_open(struct weston_launcher *launcher, const char *path, int flags)
-{
-       struct launcher_logind *wl = wl_container_of(launcher, wl, base);
-       struct stat st;
-       int fl, r, fd;
-
-       r = stat(path, &st);
-       if (r < 0)
-               return -1;
-       if (!S_ISCHR(st.st_mode)) {
-               errno = ENODEV;
-               return -1;
-       }
-
-       fd = launcher_logind_take_device(wl, major(st.st_rdev),
-                                      minor(st.st_rdev), NULL);
-       if (fd < 0)
-               return fd;
-
-       /* Compared to weston_launcher_open() we cannot specify the open-mode
-        * directly. Instead, logind passes us an fd with sane default modes.
-        * For DRM and evdev this means O_RDWR | O_CLOEXEC. If we want
-        * something else, we need to change it afterwards. We currently
-        * only support setting O_NONBLOCK. Changing access-modes is not
-        * possible so accept whatever logind passes us. */
-
-       fl = fcntl(fd, F_GETFL);
-       if (fl < 0) {
-               r = -errno;
-               goto err_close;
-       }
-
-       if (flags & O_NONBLOCK)
-               fl |= O_NONBLOCK;
-
-       r = fcntl(fd, F_SETFL, fl);
-       if (r < 0) {
-               r = -errno;
-               goto err_close;
-       }
-       return fd;
-
-err_close:
-       close(fd);
-       launcher_logind_release_device(wl, major(st.st_rdev),
-                                    minor(st.st_rdev));
-       errno = -r;
-       return -1;
-}
-
-static void
-launcher_logind_close(struct weston_launcher *launcher, int fd)
-{
-       struct launcher_logind *wl = wl_container_of(launcher, wl, base);
-       struct stat st;
-       int r;
-
-       r = fstat(fd, &st);
-       if (r < 0) {
-               weston_log("logind: cannot fstat fd: %m\n");
-               return;
-       }
-
-       if (!S_ISCHR(st.st_mode)) {
-               weston_log("logind: invalid device passed\n");
-               return;
-       }
-
-       launcher_logind_release_device(wl, major(st.st_rdev),
-                                    minor(st.st_rdev));
-}
-
-static void
-launcher_logind_restore(struct weston_launcher *launcher)
-{
-}
-
-static int
-launcher_logind_activate_vt(struct weston_launcher *launcher, int vt)
-{
-       struct launcher_logind *wl = wl_container_of(launcher, wl, base);
-       DBusMessage *m;
-       bool b;
-       int r;
-
-       m = dbus_message_new_method_call("org.freedesktop.login1",
-                                        "/org/freedesktop/login1/seat/self",
-                                        "org.freedesktop.login1.Seat",
-                                        "SwitchTo");
-       if (!m)
-               return -ENOMEM;
-
-       b = dbus_message_append_args(m,
-                                    DBUS_TYPE_UINT32, &vt,
-                                    DBUS_TYPE_INVALID);
-       if (!b) {
-               r = -ENOMEM;
-               goto err_unref;
-       }
-
-       dbus_connection_send(wl->dbus, m, NULL);
-       r = 0;
-
- err_unref:
-       dbus_message_unref(m);
-       return r;
-}
-
-static void
-launcher_logind_set_active(struct launcher_logind *wl, bool active)
-{
-       if (!wl->compositor->session_active == !active)
-               return;
-
-       wl->compositor->session_active = active;
-
-       wl_signal_emit(&wl->compositor->session_signal,
-                      wl->compositor);
-}
-
-static void
-parse_active(struct launcher_logind *wl, DBusMessage *m, DBusMessageIter *iter)
-{
-       DBusMessageIter sub;
-       dbus_bool_t b;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
-               return;
-
-       dbus_message_iter_recurse(iter, &sub);
-
-       if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-               return;
-
-       dbus_message_iter_get_basic(&sub, &b);
-
-       /* If the backend requested DRM master-device synchronization, we only
-        * wake-up the compositor once the master-device is up and running. For
-        * other backends, we immediately forward the Active-change event. */
-       if (!wl->sync_drm || !b)
-               launcher_logind_set_active(wl, b);
-}
-
-static void
-get_active_cb(DBusPendingCall *pending, void *data)
-{
-       struct launcher_logind *wl = data;
-       DBusMessageIter iter;
-       DBusMessage *m;
-       int type;
-
-       dbus_pending_call_unref(wl->pending_active);
-       wl->pending_active = NULL;
-
-       m = dbus_pending_call_steal_reply(pending);
-       if (!m)
-               return;
-
-       type = dbus_message_get_type(m);
-       if (type == DBUS_MESSAGE_TYPE_METHOD_RETURN &&
-           dbus_message_iter_init(m, &iter))
-               parse_active(wl, m, &iter);
-
-       dbus_message_unref(m);
-}
-
-static void
-launcher_logind_get_active(struct launcher_logind *wl)
-{
-       DBusPendingCall *pending;
-       DBusMessage *m;
-       bool b;
-       const char *iface, *name;
-
-       m = dbus_message_new_method_call("org.freedesktop.login1",
-                                        wl->spath,
-                                        "org.freedesktop.DBus.Properties",
-                                        "Get");
-       if (!m)
-               return;
-
-       iface = "org.freedesktop.login1.Session";
-       name = "Active";
-       b = dbus_message_append_args(m,
-                                    DBUS_TYPE_STRING, &iface,
-                                    DBUS_TYPE_STRING, &name,
-                                    DBUS_TYPE_INVALID);
-       if (!b)
-               goto err_unref;
-
-       b = dbus_connection_send_with_reply(wl->dbus, m, &pending, -1);
-       if (!b)
-               goto err_unref;
-
-       b = dbus_pending_call_set_notify(pending, get_active_cb, wl, NULL);
-       if (!b) {
-               dbus_pending_call_cancel(pending);
-               dbus_pending_call_unref(pending);
-               goto err_unref;
-       }
-
-       if (wl->pending_active) {
-               dbus_pending_call_cancel(wl->pending_active);
-               dbus_pending_call_unref(wl->pending_active);
-       }
-       wl->pending_active = pending;
-       return;
-
-err_unref:
-       dbus_message_unref(m);
-}
-
-static void
-disconnected_dbus(struct launcher_logind *wl)
-{
-       weston_log("logind: dbus connection lost, exiting..\n");
-       launcher_logind_restore(&wl->base);
-       exit(-1);
-}
-
-static void
-session_removed(struct launcher_logind *wl, DBusMessage *m)
-{
-       const char *name, *obj;
-       bool r;
-
-       r = dbus_message_get_args(m, NULL,
-                                 DBUS_TYPE_STRING, &name,
-                                 DBUS_TYPE_OBJECT_PATH, &obj,
-                                 DBUS_TYPE_INVALID);
-       if (!r) {
-               weston_log("logind: cannot parse SessionRemoved dbus signal\n");
-               return;
-       }
-
-       if (!strcmp(name, wl->sid)) {
-               weston_log("logind: our session got closed, exiting..\n");
-               launcher_logind_restore(&wl->base);
-               exit(-1);
-       }
-}
-
-static void
-property_changed(struct launcher_logind *wl, DBusMessage *m)
-{
-       DBusMessageIter iter, sub, entry;
-       const char *interface, *name;
-
-       if (!dbus_message_iter_init(m, &iter) ||
-           dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               goto error;
-
-       dbus_message_iter_get_basic(&iter, &interface);
-
-       if (!dbus_message_iter_next(&iter) ||
-           dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
-               goto error;
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_DICT_ENTRY) {
-               dbus_message_iter_recurse(&sub, &entry);
-
-               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
-                       goto error;
-
-               dbus_message_iter_get_basic(&entry, &name);
-               if (!dbus_message_iter_next(&entry))
-                       goto error;
-
-               if (!strcmp(name, "Active")) {
-                       parse_active(wl, m, &entry);
-                       return;
-               }
-
-               dbus_message_iter_next(&sub);
-       }
-
-       if (!dbus_message_iter_next(&iter) ||
-           dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
-               goto error;
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       while (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_STRING) {
-               dbus_message_iter_get_basic(&sub, &name);
-
-               if (!strcmp(name, "Active")) {
-                       launcher_logind_get_active(wl);
-                       return;
-               }
-
-               dbus_message_iter_next(&sub);
-       }
-
-       return;
-
-error:
-       weston_log("logind: cannot parse PropertiesChanged dbus signal\n");
-}
-
-static void
-device_paused(struct launcher_logind *wl, DBusMessage *m)
-{
-       bool r;
-       const char *type;
-       uint32_t major, minor;
-
-       r = dbus_message_get_args(m, NULL,
-                                 DBUS_TYPE_UINT32, &major,
-                                 DBUS_TYPE_UINT32, &minor,
-                                 DBUS_TYPE_STRING, &type,
-                                 DBUS_TYPE_INVALID);
-       if (!r) {
-               weston_log("logind: cannot parse PauseDevice dbus signal\n");
-               return;
-       }
-
-       /* "pause" means synchronous pausing. Acknowledge it unconditionally
-        * as we support asynchronous device shutdowns, anyway.
-        * "force" means asynchronous pausing.
-        * "gone" means the device is gone. We handle it the same as "force" as
-        * a following udev event will be caught, too.
-        *
-        * If it's our main DRM device, tell the compositor to go asleep. */
-
-       if (!strcmp(type, "pause"))
-               launcher_logind_pause_device_complete(wl, major, minor);
-
-       if (wl->sync_drm && major == DRM_MAJOR)
-               launcher_logind_set_active(wl, false);
-}
-
-static void
-device_resumed(struct launcher_logind *wl, DBusMessage *m)
-{
-       bool r;
-       uint32_t major;
-
-       r = dbus_message_get_args(m, NULL,
-                                 DBUS_TYPE_UINT32, &major,
-                                 /*DBUS_TYPE_UINT32, &minor,
-                                 DBUS_TYPE_UNIX_FD, &fd,*/
-                                 DBUS_TYPE_INVALID);
-       if (!r) {
-               weston_log("logind: cannot parse ResumeDevice dbus signal\n");
-               return;
-       }
-
-       /* DeviceResumed messages provide us a new file-descriptor for
-        * resumed devices. For DRM devices it's the same as before, for evdev
-        * devices it's a new open-file. As we reopen evdev devices, anyway,
-        * there is no need for us to handle this event for evdev. For DRM, we
-        * notify the compositor to wake up. */
-
-       if (wl->sync_drm && major == DRM_MAJOR)
-               launcher_logind_set_active(wl, true);
-}
-
-static DBusHandlerResult
-filter_dbus(DBusConnection *c, DBusMessage *m, void *data)
-{
-       struct launcher_logind *wl = data;
-
-       if (dbus_message_is_signal(m, DBUS_INTERFACE_LOCAL, "Disconnected")) {
-               disconnected_dbus(wl);
-       } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Manager",
-                                         "SessionRemoved")) {
-               session_removed(wl, m);
-       } else if (dbus_message_is_signal(m, "org.freedesktop.DBus.Properties",
-                                         "PropertiesChanged")) {
-               property_changed(wl, m);
-       } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
-                                         "PauseDevice")) {
-               device_paused(wl, m);
-       } else if (dbus_message_is_signal(m, "org.freedesktop.login1.Session",
-                                         "ResumeDevice")) {
-               device_resumed(wl, m);
-       }
-
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static int
-launcher_logind_setup_dbus(struct launcher_logind *wl)
-{
-       bool b;
-       int r;
-
-       r = asprintf(&wl->spath, "/org/freedesktop/login1/session/%s",
-                    wl->sid);
-       if (r < 0)
-               return -ENOMEM;
-
-       b = dbus_connection_add_filter(wl->dbus, filter_dbus, wl, NULL);
-       if (!b) {
-               weston_log("logind: cannot add dbus filter\n");
-               r = -ENOMEM;
-               goto err_spath;
-       }
-
-       r = weston_dbus_add_match_signal(wl->dbus,
-                                        "org.freedesktop.login1",
-                                        "org.freedesktop.login1.Manager",
-                                        "SessionRemoved",
-                                        "/org/freedesktop/login1");
-       if (r < 0) {
-               weston_log("logind: cannot add dbus match\n");
-               goto err_spath;
-       }
-
-       r = weston_dbus_add_match_signal(wl->dbus,
-                                       "org.freedesktop.login1",
-                                       "org.freedesktop.login1.Session",
-                                       "PauseDevice",
-                                       wl->spath);
-       if (r < 0) {
-               weston_log("logind: cannot add dbus match\n");
-               goto err_spath;
-       }
-
-       r = weston_dbus_add_match_signal(wl->dbus,
-                                       "org.freedesktop.login1",
-                                       "org.freedesktop.login1.Session",
-                                       "ResumeDevice",
-                                       wl->spath);
-       if (r < 0) {
-               weston_log("logind: cannot add dbus match\n");
-               goto err_spath;
-       }
-
-       r = weston_dbus_add_match_signal(wl->dbus,
-                                       "org.freedesktop.login1",
-                                       "org.freedesktop.DBus.Properties",
-                                       "PropertiesChanged",
-                                       wl->spath);
-       if (r < 0) {
-               weston_log("logind: cannot add dbus match\n");
-               goto err_spath;
-       }
-
-       return 0;
-
-err_spath:
-       /* don't remove any dbus-match as the connection is closed, anyway */
-       free(wl->spath);
-       return r;
-}
-
-static void
-launcher_logind_destroy_dbus(struct launcher_logind *wl)
-{
-       /* don't remove any dbus-match as the connection is closed, anyway */
-       free(wl->spath);
-}
-
-static int
-launcher_logind_take_control(struct launcher_logind *wl)
-{
-       DBusError err;
-       DBusMessage *m, *reply;
-       dbus_bool_t force;
-       bool b;
-       int r;
-
-       dbus_error_init(&err);
-
-       m = dbus_message_new_method_call("org.freedesktop.login1",
-                                        wl->spath,
-                                        "org.freedesktop.login1.Session",
-                                        "TakeControl");
-       if (!m)
-               return -ENOMEM;
-
-       force = false;
-       b = dbus_message_append_args(m,
-                                    DBUS_TYPE_BOOLEAN, &force,
-                                    DBUS_TYPE_INVALID);
-       if (!b) {
-               r = -ENOMEM;
-               goto err_unref;
-       }
-
-       reply = dbus_connection_send_with_reply_and_block(wl->dbus,
-                                                         m, -1, &err);
-       if (!reply) {
-               if (dbus_error_has_name(&err, DBUS_ERROR_UNKNOWN_METHOD))
-                       weston_log("logind: old systemd version detected\n");
-               else
-                       weston_log("logind: cannot take control over session %s\n", wl->sid);
-
-               dbus_error_free(&err);
-               r = -EIO;
-               goto err_unref;
-       }
-
-       dbus_message_unref(reply);
-       dbus_message_unref(m);
-       return 0;
-
-err_unref:
-       dbus_message_unref(m);
-       return r;
-}
-
-static void
-launcher_logind_release_control(struct launcher_logind *wl)
-{
-       DBusMessage *m;
-
-       m = dbus_message_new_method_call("org.freedesktop.login1",
-                                        wl->spath,
-                                        "org.freedesktop.login1.Session",
-                                        "ReleaseControl");
-       if (m) {
-               dbus_connection_send(wl->dbus, m, NULL);
-               dbus_message_unref(m);
-       }
-}
-
-static int
-weston_sd_session_get_vt(const char *sid, unsigned int *out)
-{
-#ifdef HAVE_SYSTEMD_LOGIN_209
-       return sd_session_get_vt(sid, out);
-#else
-       int r;
-       char *tty;
-
-       r = sd_session_get_tty(sid, &tty);
-       if (r < 0)
-               return r;
-
-       r = sscanf(tty, "tty%u", out);
-       free(tty);
-
-       if (r != 1)
-               return -EINVAL;
-
-       return 0;
-#endif
-}
-
-static int
-launcher_logind_activate(struct launcher_logind *wl)
-{
-       DBusMessage *m;
-
-       m = dbus_message_new_method_call("org.freedesktop.login1",
-                                        wl->spath,
-                                        "org.freedesktop.login1.Session",
-                                        "Activate");
-       if (!m)
-               return -ENOMEM;
-
-       dbus_connection_send(wl->dbus, m, NULL);
-       return 0;
-}
-
-static int
-launcher_logind_connect(struct weston_launcher **out, struct weston_compositor *compositor,
-                       int tty, const char *seat_id, bool sync_drm)
-{
-       struct launcher_logind *wl;
-       struct wl_event_loop *loop;
-       char *t;
-       int r;
-
-       wl = zalloc(sizeof(*wl));
-       if (wl == NULL) {
-               r = -ENOMEM;
-               goto err_out;
-       }
-
-       wl->base.iface = &launcher_logind_iface;
-       wl->compositor = compositor;
-       wl->sync_drm = sync_drm;
-
-       wl->seat = strdup(seat_id);
-       if (!wl->seat) {
-               r = -ENOMEM;
-               goto err_wl;
-       }
-
-       r = sd_pid_get_session(getpid(), &wl->sid);
-       if (r < 0) {
-               weston_log("logind: not running in a systemd session\n");
-               goto err_seat;
-       }
-
-       t = NULL;
-       r = sd_session_get_seat(wl->sid, &t);
-       if (r < 0) {
-               weston_log("logind: failed to get session seat\n");
-               free(t);
-               goto err_session;
-       } else if (strcmp(seat_id, t)) {
-               weston_log("logind: weston's seat '%s' differs from session-seat '%s'\n",
-                          seat_id, t);
-               r = -EINVAL;
-               free(t);
-               goto err_session;
-       }
-       free(t);
-
-       r = weston_sd_session_get_vt(wl->sid, &wl->vtnr);
-       if (r < 0) {
-               weston_log("logind: session not running on a VT\n");
-               goto err_session;
-       } else if (tty > 0 && wl->vtnr != (unsigned int )tty) {
-               weston_log("logind: requested VT --tty=%d differs from real session VT %u\n",
-                          tty, wl->vtnr);
-               r = -EINVAL;
-               goto err_session;
-       }
-
-       loop = wl_display_get_event_loop(compositor->wl_display);
-       r = weston_dbus_open(loop, DBUS_BUS_SYSTEM, &wl->dbus, &wl->dbus_ctx);
-       if (r < 0) {
-               weston_log("logind: cannot connect to system dbus\n");
-               goto err_session;
-       }
-
-       r = launcher_logind_setup_dbus(wl);
-       if (r < 0)
-               goto err_dbus;
-
-       r = launcher_logind_take_control(wl);
-       if (r < 0)
-               goto err_dbus_cleanup;
-
-       r = launcher_logind_activate(wl);
-       if (r < 0)
-               goto err_dbus_cleanup;
-
-       weston_log("logind: session control granted\n");
-       * (struct launcher_logind **) out = wl;
-       return 0;
-
-err_dbus_cleanup:
-       launcher_logind_destroy_dbus(wl);
-err_dbus:
-       weston_dbus_close(wl->dbus, wl->dbus_ctx);
-err_session:
-       free(wl->sid);
-err_seat:
-       free(wl->seat);
-err_wl:
-       free(wl);
-err_out:
-       weston_log("logind: cannot setup systemd-logind helper (%d), using legacy fallback\n", r);
-       errno = -r;
-       return -1;
-}
-
-static void
-launcher_logind_destroy(struct weston_launcher *launcher)
-{
-       struct launcher_logind *wl = wl_container_of(launcher, wl, base);
-
-       if (wl->pending_active) {
-               dbus_pending_call_cancel(wl->pending_active);
-               dbus_pending_call_unref(wl->pending_active);
-       }
-
-       launcher_logind_release_control(wl);
-       launcher_logind_destroy_dbus(wl);
-       weston_dbus_close(wl->dbus, wl->dbus_ctx);
-       free(wl->sid);
-       free(wl->seat);
-       free(wl);
-}
-
-struct launcher_interface launcher_logind_iface = {
-       launcher_logind_connect,
-       launcher_logind_destroy,
-       launcher_logind_open,
-       launcher_logind_close,
-       launcher_logind_activate_vt,
-       launcher_logind_restore,
-};
diff --git a/src/launcher-util.c b/src/launcher-util.c
deleted file mode 100644 (file)
index 03b9d63..0000000
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include "compositor.h"
-
-#include "launcher-util.h"
-#include "launcher-impl.h"
-
-#include <unistd.h>
-#include <linux/input.h>
-
-static struct launcher_interface *ifaces[] = {
-#ifdef HAVE_SYSTEMD_LOGIN
-       &launcher_logind_iface,
-#endif
-       &launcher_weston_launch_iface,
-       &launcher_direct_iface,
-       NULL,
-};
-
-WL_EXPORT struct weston_launcher *
-weston_launcher_connect(struct weston_compositor *compositor, int tty,
-                       const char *seat_id, bool sync_drm)
-{
-       struct launcher_interface **it;
-
-       for (it = ifaces; *it != NULL; it++) {
-               struct launcher_interface *iface = *it;
-               struct weston_launcher *launcher;
-
-               if (iface->connect(&launcher, compositor, tty, seat_id, sync_drm) == 0)
-                       return launcher;
-       }
-
-       return NULL;
-}
-
-WL_EXPORT void
-weston_launcher_destroy(struct weston_launcher *launcher)
-{
-       launcher->iface->destroy(launcher);
-}
-
-WL_EXPORT int
-weston_launcher_open(struct weston_launcher *launcher,
-                    const char *path, int flags)
-{
-       return launcher->iface->open(launcher, path, flags);
-}
-
-WL_EXPORT void
-weston_launcher_close(struct weston_launcher *launcher, int fd)
-{
-       launcher->iface->close(launcher, fd);
-}
-
-WL_EXPORT int
-weston_launcher_activate_vt(struct weston_launcher *launcher, int vt)
-{
-       return launcher->iface->activate_vt(launcher, vt);
-}
-
-WL_EXPORT void
-weston_launcher_restore(struct weston_launcher *launcher)
-{
-       launcher->iface->restore(launcher);
-}
-
-
-static void
-switch_vt_binding(struct weston_keyboard *keyboard,
-                 uint32_t time, uint32_t key, void *data)
-{
-       struct weston_compositor *compositor = data;
-
-       weston_launcher_activate_vt(compositor->launcher, key - KEY_F1 + 1);
-}
-
-WL_EXPORT void
-weston_setup_vt_switch_bindings(struct weston_compositor *compositor)
-{
-       uint32_t key;
-
-       if (compositor->vt_switching == false)
-               return;
-
-       for (key = KEY_F1; key < KEY_F9; key++)
-               weston_compositor_add_key_binding(compositor, key,
-                                                 MODIFIER_CTRL | MODIFIER_ALT,
-                                                 switch_vt_binding,
-                                                 compositor);
-}
diff --git a/src/launcher-util.h b/src/launcher-util.h
deleted file mode 100644 (file)
index 93321ab..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _WESTON_LAUNCHER_UTIL_H_
-#define _WESTON_LAUNCHER_UTIL_H_
-
-#include "config.h"
-
-#include "compositor.h"
-
-struct weston_launcher;
-
-struct weston_launcher *
-weston_launcher_connect(struct weston_compositor *compositor, int tty,
-                       const char *seat_id, bool sync_drm);
-
-void
-weston_launcher_destroy(struct weston_launcher *launcher);
-
-int
-weston_launcher_open(struct weston_launcher *launcher,
-                    const char *path, int flags);
-
-void
-weston_launcher_close(struct weston_launcher *launcher, int fd);
-
-int
-weston_launcher_activate_vt(struct weston_launcher *launcher, int vt);
-
-void
-weston_launcher_restore(struct weston_launcher *launcher);
-
-void
-weston_setup_vt_switch_bindings(struct weston_compositor *compositor);
-
-#endif
diff --git a/src/launcher-weston-launch.c b/src/launcher-weston-launch.c
deleted file mode 100644 (file)
index ad919f1..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- * Copyright © 2013 Intel Corporation
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holders not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  The copyright holders make
- * no representations about the suitability of this software for any
- * purpose.  It is provided "as is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <errno.h>
-#include <signal.h>
-#include <sys/socket.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/uio.h>
-#include <sys/ioctl.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <linux/vt.h>
-#include <linux/kd.h>
-#include <linux/major.h>
-
-#include "compositor.h"
-#include "weston-launch.h"
-#include "launcher-impl.h"
-
-#define DRM_MAJOR 226
-
-#ifndef KDSKBMUTE
-#define KDSKBMUTE      0x4B51
-#endif
-
-#ifdef HAVE_LIBDRM
-
-#include <xf86drm.h>
-
-static inline int
-is_drm_master(int drm_fd)
-{
-       drm_magic_t magic;
-
-       return drmGetMagic(drm_fd, &magic) == 0 &&
-               drmAuthMagic(drm_fd, magic) == 0;
-}
-
-#else
-
-static inline int
-drmDropMaster(int drm_fd)
-{
-       return 0;
-}
-
-static inline int
-drmSetMaster(int drm_fd)
-{
-       return 0;
-}
-
-static inline int
-is_drm_master(int drm_fd)
-{
-       return 0;
-}
-
-#endif
-
-
-union cmsg_data { unsigned char b[4]; int fd; };
-
-struct launcher_weston_launch {
-       struct weston_launcher base;
-       struct weston_compositor *compositor;
-       struct wl_event_loop *loop;
-       int fd;
-       struct wl_event_source *source;
-
-       int kb_mode, tty, drm_fd;
-};
-
-static int
-launcher_weston_launch_open(struct weston_launcher *launcher_base,
-                    const char *path, int flags)
-{
-       struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
-       int n, ret;
-       struct msghdr msg;
-       struct cmsghdr *cmsg;
-       struct iovec iov;
-       union cmsg_data *data;
-       char control[CMSG_SPACE(sizeof data->fd)];
-       ssize_t len;
-       struct weston_launcher_open *message;
-
-       n = sizeof(*message) + strlen(path) + 1;
-       message = malloc(n);
-       if (!message)
-               return -1;
-
-       message->header.opcode = WESTON_LAUNCHER_OPEN;
-       message->flags = flags;
-       strcpy(message->path, path);
-
-       do {
-               len = send(launcher->fd, message, n, 0);
-       } while (len < 0 && errno == EINTR);
-       free(message);
-
-       memset(&msg, 0, sizeof msg);
-       iov.iov_base = &ret;
-       iov.iov_len = sizeof ret;
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       msg.msg_control = control;
-       msg.msg_controllen = sizeof control;
-       
-       do {
-               len = recvmsg(launcher->fd, &msg, MSG_CMSG_CLOEXEC);
-       } while (len < 0 && errno == EINTR);
-
-       if (len != sizeof ret ||
-           ret < 0)
-               return -1;
-
-       cmsg = CMSG_FIRSTHDR(&msg);
-       if (!cmsg ||
-           cmsg->cmsg_level != SOL_SOCKET ||
-           cmsg->cmsg_type != SCM_RIGHTS) {
-               fprintf(stderr, "invalid control message\n");
-               return -1;
-       }
-
-       data = (union cmsg_data *) CMSG_DATA(cmsg);
-       if (data->fd == -1) {
-               fprintf(stderr, "missing drm fd in socket request\n");
-               return -1;
-       }
-
-       return data->fd;
-}
-
-static void
-launcher_weston_launch_close(struct weston_launcher *launcher_base, int fd)
-{
-       close(fd);
-}
-
-static void
-launcher_weston_launch_restore(struct weston_launcher *launcher_base)
-{
-       struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
-       struct vt_mode mode = { 0 };
-
-       if (ioctl(launcher->tty, KDSKBMUTE, 0) &&
-           ioctl(launcher->tty, KDSKBMODE, launcher->kb_mode))
-               weston_log("failed to restore kb mode: %m\n");
-
-       if (ioctl(launcher->tty, KDSETMODE, KD_TEXT))
-               weston_log("failed to set KD_TEXT mode on tty: %m\n");
-
-       /* We have to drop master before we switch the VT back in
-        * VT_AUTO, so we don't risk switching to a VT with another
-        * display server, that will then fail to set drm master. */
-       drmDropMaster(launcher->drm_fd);
-
-       mode.mode = VT_AUTO;
-       if (ioctl(launcher->tty, VT_SETMODE, &mode) < 0)
-               weston_log("could not reset vt handling\n");
-}
-
-static int
-launcher_weston_launch_data(int fd, uint32_t mask, void *data)
-{
-       struct launcher_weston_launch *launcher = data;
-       int len, ret;
-
-       if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
-               weston_log("launcher socket closed, exiting\n");
-               /* Normally the weston-launch will reset the tty, but
-                * in this case it died or something, so do it here so
-                * we don't end up with a stuck vt. */
-               launcher_weston_launch_restore(&launcher->base);
-               exit(-1);
-       }
-
-       do {
-               len = recv(launcher->fd, &ret, sizeof ret, 0);
-       } while (len < 0 && errno == EINTR);
-
-       switch (ret) {
-       case WESTON_LAUNCHER_ACTIVATE:
-               launcher->compositor->session_active = 1;
-               wl_signal_emit(&launcher->compositor->session_signal,
-                              launcher->compositor);
-               break;
-       case WESTON_LAUNCHER_DEACTIVATE:
-               launcher->compositor->session_active = 0;
-               wl_signal_emit(&launcher->compositor->session_signal,
-                              launcher->compositor);
-               break;
-       default:
-               weston_log("unexpected event from weston-launch\n");
-               break;
-       }
-
-       return 1;
-}
-
-static int
-launcher_weston_launch_activate_vt(struct weston_launcher *launcher_base, int vt)
-{
-       struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
-       return ioctl(launcher->tty, VT_ACTIVATE, vt);
-}
-
-static int
-launcher_weston_launch_connect(struct weston_launcher **out, struct weston_compositor *compositor,
-                              int tty, const char *seat_id, bool sync_drm)
-{
-       struct launcher_weston_launch *launcher;
-       struct wl_event_loop *loop;
-
-       launcher = malloc(sizeof *launcher);
-       if (launcher == NULL)
-               return -ENOMEM;
-
-       launcher->base.iface = &launcher_weston_launch_iface;
-       * (struct launcher_weston_launch **) out = launcher;
-       launcher->compositor = compositor;
-       launcher->drm_fd = -1;
-       launcher->fd = weston_environment_get_fd("WESTON_LAUNCHER_SOCK");
-       if (launcher->fd != -1) {
-               launcher->tty = weston_environment_get_fd("WESTON_TTY_FD");
-               /* We don't get a chance to read out the original kb
-                * mode for the tty, so just hard code K_UNICODE here
-                * in case we have to clean if weston-launch dies. */
-               launcher->kb_mode = K_UNICODE;
-
-               loop = wl_display_get_event_loop(compositor->wl_display);
-               launcher->source = wl_event_loop_add_fd(loop, launcher->fd,
-                                                       WL_EVENT_READABLE,
-                                                       launcher_weston_launch_data,
-                                                       launcher);
-               if (launcher->source == NULL) {
-                       free(launcher);
-                       return -ENOMEM;
-               }
-
-               return 0;
-       } else {
-               return -1;
-       }
-}
-
-static void
-launcher_weston_launch_destroy(struct weston_launcher *launcher_base)
-{
-       struct launcher_weston_launch *launcher = wl_container_of(launcher_base, launcher, base);
-
-       if (launcher->fd != -1) {
-               close(launcher->fd);
-               wl_event_source_remove(launcher->source);
-       } else {
-               launcher_weston_launch_restore(&launcher->base);
-       }
-
-       if (launcher->tty >= 0)
-               close(launcher->tty);
-
-       free(launcher);
-}
-
-struct launcher_interface launcher_weston_launch_iface = {
-       launcher_weston_launch_connect,
-       launcher_weston_launch_destroy,
-       launcher_weston_launch_open,
-       launcher_weston_launch_close,
-       launcher_weston_launch_activate_vt,
-       launcher_weston_launch_restore,
-};
diff --git a/src/libbacklight.c b/src/libbacklight.c
deleted file mode 100644 (file)
index 722d66f..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- * libbacklight - userspace interface to Linux backlight control
- *
- * Copyright © 2012 Intel Corporation
- * Copyright 2010 Red Hat <mjg@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Matthew Garrett <mjg@redhat.com>
- *    Tiago Vignatti <vignatti@freedesktop.org>
- */
-
-#include "config.h"
-
-#include "libbacklight.h"
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <linux/types.h>
-#include <dirent.h>
-#include <drm.h>
-#include <fcntl.h>
-#include <malloc.h>
-#include <string.h>
-#include <errno.h>
-
-static long backlight_get(struct backlight *backlight, char *node)
-{
-       char buffer[100];
-       char *path;
-       int fd;
-       long value, ret;
-
-       if (asprintf(&path, "%s/%s", backlight->path, node) < 0)
-               return -ENOMEM;
-       fd = open(path, O_RDONLY);
-       if (fd < 0) {
-               ret = -1;
-               goto out;
-       }
-
-       ret = read(fd, &buffer, sizeof(buffer));
-       if (ret < 1) {
-               ret = -1;
-               goto out;
-       }
-
-       value = strtol(buffer, NULL, 10);
-       ret = value;
-out:
-       if (fd >= 0)
-               close(fd);
-       free(path);
-       return ret;
-}
-
-long backlight_get_brightness(struct backlight *backlight)
-{
-       return backlight_get(backlight, "brightness");
-}
-
-long backlight_get_max_brightness(struct backlight *backlight)
-{
-       return backlight_get(backlight, "max_brightness");
-}
-
-long backlight_get_actual_brightness(struct backlight *backlight)
-{
-       return backlight_get(backlight, "actual_brightness");
-}
-
-long backlight_set_brightness(struct backlight *backlight, long brightness)
-{
-       char *path;
-       char *buffer = NULL;
-       int fd;
-       long ret;
-
-       if (asprintf(&path, "%s/%s", backlight->path, "brightness") < 0)
-               return -ENOMEM;
-
-       fd = open(path, O_RDWR);
-       if (fd < 0) {
-               ret = -1;
-               goto out;
-       }
-
-       ret = read(fd, &buffer, sizeof(buffer));
-       if (ret < 1) {
-               ret = -1;
-               goto out;
-       }
-
-       if (asprintf(&buffer, "%ld", brightness) < 0) {
-               ret = -1;
-               goto out;
-       }
-
-       ret = write(fd, buffer, strlen(buffer));
-       if (ret < 0) {
-               ret = -1;
-               goto out;
-       }
-
-       ret = backlight_get_brightness(backlight);
-       backlight->brightness = ret;
-out:
-       free(buffer);
-       free(path);
-       if (fd >= 0)
-               close(fd);
-       return ret;
-}
-
-void backlight_destroy(struct backlight *backlight)
-{
-       if (!backlight)
-               return;
-
-       if (backlight->path)
-               free(backlight->path);
-
-       free(backlight);
-}
-
-struct backlight *backlight_init(struct udev_device *drm_device,
-                                uint32_t connector_type)
-{
-       const char *syspath = NULL;
-       char *pci_name = NULL;
-       char *chosen_path = NULL;
-       char *path = NULL;
-       DIR *backlights = NULL;
-       struct dirent *entry;
-       enum backlight_type type = 0;
-       char buffer[100];
-       struct backlight *backlight = NULL;
-       int ret;
-
-       if (!drm_device)
-               return NULL;
-
-       syspath = udev_device_get_syspath(drm_device);
-       if (!syspath)
-               return NULL;
-
-       if (asprintf(&path, "%s/%s", syspath, "device") < 0)
-               return NULL;
-
-       ret = readlink(path, buffer, sizeof(buffer) - 1);
-       free(path);
-       if (ret < 0)
-               return NULL;
-
-       buffer[ret] = '\0';
-       pci_name = basename(buffer);
-
-       if (connector_type <= 0)
-               return NULL;
-
-       backlights = opendir("/sys/class/backlight");
-       if (!backlights)
-               return NULL;
-
-       /* Find the "best" backlight for the device. Firmware
-          interfaces are preferred over platform interfaces are
-          preferred over raw interfaces. For raw interfaces we'll
-          check if the device ID in the form of pci match, while
-          for firmware interfaces we require the pci ID to
-          match. It's assumed that platform interfaces always match,
-          since we can't actually associate them with IDs.
-
-          A further awkwardness is that, while it's theoretically
-          possible for an ACPI interface to include support for
-          changing the backlight of external devices, it's unlikely
-          to ever be done. It's effectively impossible for a platform
-          interface to do so. So if we get asked about anything that
-          isn't LVDS or eDP, we pretty much have to require that the
-          control be supplied via a raw interface */
-
-       while ((entry = readdir(backlights))) {
-               char *backlight_path;
-               char *parent;
-               enum backlight_type entry_type;
-               int fd;
-
-               if (entry->d_name[0] == '.')
-                       continue;
-
-               if (asprintf(&backlight_path, "%s/%s", "/sys/class/backlight",
-                            entry->d_name) < 0)
-                       goto err;
-
-               if (asprintf(&path, "%s/%s", backlight_path, "type") < 0) {
-                       free(backlight_path);
-                       goto err;
-               }
-
-               fd = open(path, O_RDONLY);
-
-               if (fd < 0)
-                       goto out;
-
-               ret = read (fd, &buffer, sizeof(buffer));
-               close (fd);
-
-               if (ret < 1)
-                       goto out;
-
-               buffer[ret] = '\0';
-
-               if (!strncmp(buffer, "raw\n", sizeof(buffer)))
-                       entry_type = BACKLIGHT_RAW;
-               else if (!strncmp(buffer, "platform\n", sizeof(buffer)))
-                       entry_type = BACKLIGHT_PLATFORM;
-               else if (!strncmp(buffer, "firmware\n", sizeof(buffer)))
-                       entry_type = BACKLIGHT_FIRMWARE;
-               else
-                       goto out;
-
-               if (connector_type != DRM_MODE_CONNECTOR_LVDS &&
-                   connector_type != DRM_MODE_CONNECTOR_eDP) {
-                       /* External displays are assumed to require
-                          gpu control at the moment */
-                       if (entry_type != BACKLIGHT_RAW)
-                               goto out;
-               }
-
-               free (path);
-
-               if (asprintf(&path, "%s/%s", backlight_path, "device") < 0)
-                       goto err;
-
-               ret = readlink(path, buffer, sizeof(buffer) - 1);
-
-               if (ret < 0)
-                       goto out;
-
-               buffer[ret] = '\0';
-
-               parent = basename(buffer);
-
-               /* Perform matching for raw and firmware backlights -
-                  platform backlights have to be assumed to match */
-               if (entry_type == BACKLIGHT_RAW ||
-                   entry_type == BACKLIGHT_FIRMWARE) {
-                       if (!(pci_name && !strcmp(pci_name, parent)))
-                               goto out;
-               }
-
-               if (entry_type < type)
-                       goto out;
-
-               type = entry_type;
-
-               if (chosen_path)
-                       free(chosen_path);
-               chosen_path = strdup(backlight_path);
-
-       out:
-               free(backlight_path);
-               free(path);
-       }
-
-       if (!chosen_path)
-               goto err;
-
-       backlight = malloc(sizeof(struct backlight));
-
-       if (!backlight)
-               goto err;
-
-       backlight->path = chosen_path;
-       backlight->type = type;
-
-       backlight->max_brightness = backlight_get_max_brightness(backlight);
-       if (backlight->max_brightness < 0)
-               goto err;
-
-       backlight->brightness = backlight_get_actual_brightness(backlight);
-       if (backlight->brightness < 0)
-               goto err;
-
-       closedir(backlights);
-       return backlight;
-err:
-       closedir(backlights);
-       free (chosen_path);
-       free (backlight);
-       return NULL;
-}
diff --git a/src/libbacklight.h b/src/libbacklight.h
deleted file mode 100644 (file)
index 8717ab1..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * libbacklight - userspace interface to Linux backlight control
- *
- * Copyright © 2012 Intel Corporation
- * Copyright 2010 Red Hat <mjg@redhat.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a
- * copy of this software and associated documentation files (the "Software"),
- * to deal in the Software without restriction, including without limitation
- * the rights to use, copy, modify, merge, publish, distribute, sublicense,
- * and/or sell copies of the Software, and to permit persons to whom the
- * Software is furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice (including the next
- * paragraph) shall be included in all copies or substantial portions of the
- * Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
- * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
- * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
- * DEALINGS IN THE SOFTWARE.
- *
- * Authors:
- *    Matthew Garrett <mjg@redhat.com>
- *    Tiago Vignatti <vignatti@freedesktop.org>
- */
-#ifndef LIBBACKLIGHT_H
-#define LIBBACKLIGHT_H
-#include <libudev.h>
-#include <stdint.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-enum backlight_type {
-       BACKLIGHT_RAW,
-       BACKLIGHT_PLATFORM,
-       BACKLIGHT_FIRMWARE
-};
-
-struct backlight {
-       char *path;
-       int max_brightness;
-       int brightness;
-       enum backlight_type type;
-};
-
-/*
- * Find and set up a backlight for a valid udev connector device, i.e. one
- * matching drm subsytem and with status of connected.
- */
-struct backlight *backlight_init(struct udev_device *drm_device,
-                                uint32_t connector_type);
-
-/* Free backlight resources */
-void backlight_destroy(struct backlight *backlight);
-
-/* Provide the maximum backlight value */
-long backlight_get_max_brightness(struct backlight *backlight);
-
-/* Provide the cached backlight value */
-long backlight_get_brightness(struct backlight *backlight);
-
-/* Provide the hardware backlight value */
-long backlight_get_actual_brightness(struct backlight *backlight);
-
-/* Set the backlight to a value between 0 and max */
-long backlight_set_brightness(struct backlight *backlight, long brightness);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* LIBBACKLIGHT_H */
diff --git a/src/libinput-device.c b/src/libinput-device.c
deleted file mode 100644 (file)
index 62350f2..0000000
+++ /dev/null
@@ -1,593 +0,0 @@
-/*
- * Copyright © 2010 Intel Corporation
- * Copyright © 2013 Jonas Ådahl
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <linux/input.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <mtdev.h>
-#include <assert.h>
-#include <libinput.h>
-
-#include "compositor.h"
-#include "libinput-device.h"
-#include "shared/helpers.h"
-
-void
-evdev_led_update(struct evdev_device *device, enum weston_led weston_leds)
-{
-       enum libinput_led leds = 0;
-
-       if (weston_leds & LED_NUM_LOCK)
-               leds |= LIBINPUT_LED_NUM_LOCK;
-       if (weston_leds & LED_CAPS_LOCK)
-               leds |= LIBINPUT_LED_CAPS_LOCK;
-       if (weston_leds & LED_SCROLL_LOCK)
-               leds |= LIBINPUT_LED_SCROLL_LOCK;
-
-       libinput_device_led_update(device->device, leds);
-}
-
-static void
-handle_keyboard_key(struct libinput_device *libinput_device,
-                   struct libinput_event_keyboard *keyboard_event)
-{
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       int key_state =
-               libinput_event_keyboard_get_key_state(keyboard_event);
-       int seat_key_count =
-               libinput_event_keyboard_get_seat_key_count(keyboard_event);
-
-       /* Ignore key events that are not seat wide state changes. */
-       if ((key_state == LIBINPUT_KEY_STATE_PRESSED &&
-            seat_key_count != 1) ||
-           (key_state == LIBINPUT_KEY_STATE_RELEASED &&
-            seat_key_count != 0))
-               return;
-
-       notify_key(device->seat,
-                  libinput_event_keyboard_get_time(keyboard_event),
-                  libinput_event_keyboard_get_key(keyboard_event),
-                  key_state, STATE_UPDATE_AUTOMATIC);
-}
-
-static bool
-handle_pointer_motion(struct libinput_device *libinput_device,
-                     struct libinput_event_pointer *pointer_event)
-{
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       struct weston_pointer_motion_event event = { 0 };
-
-       event = (struct weston_pointer_motion_event) {
-               .mask = WESTON_POINTER_MOTION_REL,
-               .dx = libinput_event_pointer_get_dx(pointer_event),
-               .dy = libinput_event_pointer_get_dy(pointer_event),
-       };
-
-       notify_motion(device->seat,
-                     libinput_event_pointer_get_time(pointer_event),
-                     &event);
-
-       return true;
-}
-
-static bool
-handle_pointer_motion_absolute(
-       struct libinput_device *libinput_device,
-       struct libinput_event_pointer *pointer_event)
-{
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       struct weston_output *output = device->output;
-       uint32_t time;
-       double x, y;
-       uint32_t width, height;
-
-       if (!output)
-               return false;
-
-       time = libinput_event_pointer_get_time(pointer_event);
-       width = device->output->current_mode->width;
-       height = device->output->current_mode->height;
-
-       x = libinput_event_pointer_get_absolute_x_transformed(pointer_event,
-                                                             width);
-       y = libinput_event_pointer_get_absolute_y_transformed(pointer_event,
-                                                             height);
-
-       weston_output_transform_coordinate(device->output, x, y, &x, &y);
-       notify_motion_absolute(device->seat, time, x, y);
-
-       return true;
-}
-
-static bool
-handle_pointer_button(struct libinput_device *libinput_device,
-                     struct libinput_event_pointer *pointer_event)
-{
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       int button_state =
-               libinput_event_pointer_get_button_state(pointer_event);
-       int seat_button_count =
-               libinput_event_pointer_get_seat_button_count(pointer_event);
-
-       /* Ignore button events that are not seat wide state changes. */
-       if ((button_state == LIBINPUT_BUTTON_STATE_PRESSED &&
-            seat_button_count != 1) ||
-           (button_state == LIBINPUT_BUTTON_STATE_RELEASED &&
-            seat_button_count != 0))
-               return false;
-
-       notify_button(device->seat,
-                     libinput_event_pointer_get_time(pointer_event),
-                     libinput_event_pointer_get_button(pointer_event),
-                      button_state);
-
-       return true;
-}
-
-static double
-normalize_scroll(struct libinput_event_pointer *pointer_event,
-                enum libinput_pointer_axis axis)
-{
-       enum libinput_pointer_axis_source source;
-       double value = 0.0;
-
-       source = libinput_event_pointer_get_axis_source(pointer_event);
-       /* libinput < 0.8 sent wheel click events with value 10. Since 0.8
-          the value is the angle of the click in degrees. To keep
-          backwards-compat with existing clients, we just send multiples of
-          the click count.
-        */
-       switch (source) {
-       case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
-               value = 10 * libinput_event_pointer_get_axis_value_discrete(
-                                                                  pointer_event,
-                                                                  axis);
-               break;
-       case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
-       case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
-               value = libinput_event_pointer_get_axis_value(pointer_event,
-                                                             axis);
-               break;
-       }
-
-       return value;
-}
-
-static int32_t
-get_axis_discrete(struct libinput_event_pointer *pointer_event,
-                 enum libinput_pointer_axis axis)
-{
-       enum libinput_pointer_axis_source source;
-
-       source = libinput_event_pointer_get_axis_source(pointer_event);
-
-       if (source != LIBINPUT_POINTER_AXIS_SOURCE_WHEEL)
-               return 0;
-
-       return libinput_event_pointer_get_axis_value_discrete(pointer_event,
-                                                             axis);
-}
-
-static bool
-handle_pointer_axis(struct libinput_device *libinput_device,
-                   struct libinput_event_pointer *pointer_event)
-{
-       static int warned;
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       double vert, horiz;
-       int32_t vert_discrete, horiz_discrete;
-       enum libinput_pointer_axis axis;
-       struct weston_pointer_axis_event weston_event;
-       enum libinput_pointer_axis_source source;
-       uint32_t wl_axis_source;
-       bool has_vert, has_horiz;
-
-       has_vert = libinput_event_pointer_has_axis(pointer_event,
-                                  LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL);
-       has_horiz = libinput_event_pointer_has_axis(pointer_event,
-                                  LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL);
-
-       if (!has_vert && !has_horiz)
-               return false;
-
-       source = libinput_event_pointer_get_axis_source(pointer_event);
-       switch (source) {
-       case LIBINPUT_POINTER_AXIS_SOURCE_WHEEL:
-               wl_axis_source = WL_POINTER_AXIS_SOURCE_WHEEL;
-               break;
-       case LIBINPUT_POINTER_AXIS_SOURCE_FINGER:
-               wl_axis_source = WL_POINTER_AXIS_SOURCE_FINGER;
-               break;
-       case LIBINPUT_POINTER_AXIS_SOURCE_CONTINUOUS:
-               wl_axis_source = WL_POINTER_AXIS_SOURCE_CONTINUOUS;
-               break;
-       default:
-               if (warned < 5) {
-                       weston_log("Unknown scroll source %d.\n", source);
-                       warned++;
-               }
-               return false;
-       }
-
-       notify_axis_source(device->seat, wl_axis_source);
-
-       if (has_vert) {
-               axis = LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL;
-               vert_discrete = get_axis_discrete(pointer_event, axis);
-               vert = normalize_scroll(pointer_event, axis);
-
-               weston_event.axis = WL_POINTER_AXIS_VERTICAL_SCROLL;
-               weston_event.value = vert;
-               weston_event.discrete = vert_discrete;
-               weston_event.has_discrete = (vert_discrete != 0);
-
-               notify_axis(device->seat,
-                           libinput_event_pointer_get_time(pointer_event),
-                           &weston_event);
-       }
-
-       if (has_horiz) {
-               axis = LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL;
-               horiz_discrete = get_axis_discrete(pointer_event, axis);
-               horiz = normalize_scroll(pointer_event, axis);
-
-               weston_event.axis = WL_POINTER_AXIS_HORIZONTAL_SCROLL;
-               weston_event.value = horiz;
-               weston_event.discrete = horiz_discrete;
-               weston_event.has_discrete = (horiz_discrete != 0);
-
-               notify_axis(device->seat,
-                           libinput_event_pointer_get_time(pointer_event),
-                           &weston_event);
-       }
-
-       return true;
-}
-
-static void
-handle_touch_with_coords(struct libinput_device *libinput_device,
-                        struct libinput_event_touch *touch_event,
-                        int touch_type)
-{
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       double x;
-       double y;
-       uint32_t width, height;
-       uint32_t time;
-       int32_t slot;
-
-       if (!device->output)
-               return;
-
-       time = libinput_event_touch_get_time(touch_event);
-       slot = libinput_event_touch_get_seat_slot(touch_event);
-
-       width = device->output->current_mode->width;
-       height = device->output->current_mode->height;
-       x =  libinput_event_touch_get_x_transformed(touch_event, width);
-       y =  libinput_event_touch_get_y_transformed(touch_event, height);
-
-       weston_output_transform_coordinate(device->output,
-                                          x, y, &x, &y);
-
-       notify_touch(device->seat, time, slot, x, y, touch_type);
-}
-
-static void
-handle_touch_down(struct libinput_device *device,
-                 struct libinput_event_touch *touch_event)
-{
-       handle_touch_with_coords(device, touch_event, WL_TOUCH_DOWN);
-}
-
-static void
-handle_touch_motion(struct libinput_device *device,
-                   struct libinput_event_touch *touch_event)
-{
-       handle_touch_with_coords(device, touch_event, WL_TOUCH_MOTION);
-}
-
-static void
-handle_touch_up(struct libinput_device *libinput_device,
-               struct libinput_event_touch *touch_event)
-{
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       uint32_t time = libinput_event_touch_get_time(touch_event);
-       int32_t slot = libinput_event_touch_get_seat_slot(touch_event);
-
-       notify_touch(device->seat, time, slot, 0, 0, WL_TOUCH_UP);
-}
-
-static void
-handle_touch_frame(struct libinput_device *libinput_device,
-                  struct libinput_event_touch *touch_event)
-{
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       struct weston_seat *seat = device->seat;
-
-       notify_touch_frame(seat);
-}
-
-int
-evdev_device_process_event(struct libinput_event *event)
-{
-       struct libinput_device *libinput_device =
-               libinput_event_get_device(event);
-       struct evdev_device *device =
-               libinput_device_get_user_data(libinput_device);
-       int handled = 1;
-       bool need_frame = false;
-
-       switch (libinput_event_get_type(event)) {
-       case LIBINPUT_EVENT_KEYBOARD_KEY:
-               handle_keyboard_key(libinput_device,
-                                   libinput_event_get_keyboard_event(event));
-               break;
-       case LIBINPUT_EVENT_POINTER_MOTION:
-               need_frame = handle_pointer_motion(libinput_device,
-                                     libinput_event_get_pointer_event(event));
-               break;
-       case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
-               need_frame = handle_pointer_motion_absolute(
-                               libinput_device,
-                               libinput_event_get_pointer_event(event));
-               break;
-       case LIBINPUT_EVENT_POINTER_BUTTON:
-               need_frame = handle_pointer_button(libinput_device,
-                                     libinput_event_get_pointer_event(event));
-               break;
-       case LIBINPUT_EVENT_POINTER_AXIS:
-               need_frame = handle_pointer_axis(
-                                libinput_device,
-                                libinput_event_get_pointer_event(event));
-               break;
-       case LIBINPUT_EVENT_TOUCH_DOWN:
-               handle_touch_down(libinput_device,
-                                 libinput_event_get_touch_event(event));
-               break;
-       case LIBINPUT_EVENT_TOUCH_MOTION:
-               handle_touch_motion(libinput_device,
-                                   libinput_event_get_touch_event(event));
-               break;
-       case LIBINPUT_EVENT_TOUCH_UP:
-               handle_touch_up(libinput_device,
-                               libinput_event_get_touch_event(event));
-               break;
-       case LIBINPUT_EVENT_TOUCH_FRAME:
-               handle_touch_frame(libinput_device,
-                                  libinput_event_get_touch_event(event));
-               break;
-       default:
-               handled = 0;
-               weston_log("unknown libinput event %d\n",
-                          libinput_event_get_type(event));
-       }
-
-       if (need_frame)
-               notify_pointer_frame(device->seat);
-
-       return handled;
-}
-
-static void
-notify_output_destroy(struct wl_listener *listener, void *data)
-{
-       struct evdev_device *device =
-               container_of(listener,
-                            struct evdev_device, output_destroy_listener);
-       struct weston_compositor *c = device->seat->compositor;
-       struct weston_output *output;
-
-       if (!device->output_name && !wl_list_empty(&c->output_list)) {
-               output = container_of(c->output_list.next,
-                                     struct weston_output, link);
-               evdev_device_set_output(device, output);
-       } else {
-               device->output = NULL;
-       }
-}
-
-/**
- * The WL_CALIBRATION property requires a pixel-specific matrix to be
- * applied after scaling device coordinates to screen coordinates. libinput
- * can't do that, so we need to convert the calibration to the normalized
- * format libinput expects.
- */
-void
-evdev_device_set_calibration(struct evdev_device *device)
-{
-       struct udev *udev;
-       struct udev_device *udev_device = NULL;
-       const char *sysname = libinput_device_get_sysname(device->device);
-       const char *calibration_values;
-       uint32_t width, height;
-       float calibration[6];
-       enum libinput_config_status status;
-
-       if (!device->output)
-               return;
-
-       width = device->output->width;
-       height = device->output->height;
-       if (width == 0 || height == 0)
-               return;
-
-       /* If libinput has a pre-set calibration matrix, don't override it */
-       if (!libinput_device_config_calibration_has_matrix(device->device) ||
-           libinput_device_config_calibration_get_default_matrix(
-                                                         device->device,
-                                                         calibration) != 0)
-               return;
-
-       udev = udev_new();
-       if (!udev)
-               return;
-
-       udev_device = udev_device_new_from_subsystem_sysname(udev,
-                                                            "input",
-                                                            sysname);
-       if (!udev_device)
-               goto out;
-
-       calibration_values =
-               udev_device_get_property_value(udev_device,
-                                              "WL_CALIBRATION");
-
-       if (!calibration_values || sscanf(calibration_values,
-                                         "%f %f %f %f %f %f",
-                                         &calibration[0],
-                                         &calibration[1],
-                                         &calibration[2],
-                                         &calibration[3],
-                                         &calibration[4],
-                                         &calibration[5]) != 6)
-               goto out;
-
-       weston_log("Applying calibration: %f %f %f %f %f %f "
-                  "(normalized %f %f)\n",
-                   calibration[0],
-                   calibration[1],
-                   calibration[2],
-                   calibration[3],
-                   calibration[4],
-                   calibration[5],
-                   calibration[2] / width,
-                   calibration[5] / height);
-
-       /* normalize to a format libinput can use. There is a chance of
-          this being wrong if the width/height don't match the device
-          width/height but I'm not sure how to fix that */
-       calibration[2] /= width;
-       calibration[5] /= height;
-
-       status = libinput_device_config_calibration_set_matrix(device->device,
-                                                              calibration);
-       if (status != LIBINPUT_CONFIG_STATUS_SUCCESS)
-               weston_log("Failed to apply calibration.\n");
-
-out:
-       if (udev_device)
-               udev_device_unref(udev_device);
-       udev_unref(udev);
-}
-
-void
-evdev_device_set_output(struct evdev_device *device,
-                       struct weston_output *output)
-{
-       if (device->output_destroy_listener.notify) {
-               wl_list_remove(&device->output_destroy_listener.link);
-               device->output_destroy_listener.notify = NULL;
-       }
-
-       device->output = output;
-       device->output_destroy_listener.notify = notify_output_destroy;
-       wl_signal_add(&output->destroy_signal,
-                     &device->output_destroy_listener);
-       evdev_device_set_calibration(device);
-}
-
-struct evdev_device *
-evdev_device_create(struct libinput_device *libinput_device,
-                   struct weston_seat *seat)
-{
-       struct evdev_device *device;
-
-       device = zalloc(sizeof *device);
-       if (device == NULL)
-               return NULL;
-
-       device->seat = seat;
-       wl_list_init(&device->link);
-       device->device = libinput_device;
-
-       if (libinput_device_has_capability(libinput_device,
-                                          LIBINPUT_DEVICE_CAP_KEYBOARD)) {
-               weston_seat_init_keyboard(seat, NULL);
-               device->seat_caps |= EVDEV_SEAT_KEYBOARD;
-       }
-       if (libinput_device_has_capability(libinput_device,
-                                          LIBINPUT_DEVICE_CAP_POINTER)) {
-               weston_seat_init_pointer(seat);
-               device->seat_caps |= EVDEV_SEAT_POINTER;
-       }
-       if (libinput_device_has_capability(libinput_device,
-                                          LIBINPUT_DEVICE_CAP_TOUCH)) {
-               weston_seat_init_touch(seat);
-               device->seat_caps |= EVDEV_SEAT_TOUCH;
-       }
-
-       libinput_device_set_user_data(libinput_device, device);
-       libinput_device_ref(libinput_device);
-
-       return device;
-}
-
-void
-evdev_device_destroy(struct evdev_device *device)
-{
-       if (device->seat_caps & EVDEV_SEAT_POINTER)
-               weston_seat_release_pointer(device->seat);
-       if (device->seat_caps & EVDEV_SEAT_KEYBOARD)
-               weston_seat_release_keyboard(device->seat);
-       if (device->seat_caps & EVDEV_SEAT_TOUCH)
-               weston_seat_release_touch(device->seat);
-
-       if (device->output)
-               wl_list_remove(&device->output_destroy_listener.link);
-       wl_list_remove(&device->link);
-       libinput_device_unref(device->device);
-       free(device->devnode);
-       free(device->output_name);
-       free(device);
-}
-
-void
-evdev_notify_keyboard_focus(struct weston_seat *seat,
-                           struct wl_list *evdev_devices)
-{
-       struct wl_array keys;
-
-       if (seat->keyboard_device_count == 0)
-               return;
-
-       wl_array_init(&keys);
-       notify_keyboard_focus_in(seat, &keys, STATE_UPDATE_AUTOMATIC);
-       wl_array_release(&keys);
-}
diff --git a/src/libinput-device.h b/src/libinput-device.h
deleted file mode 100644 (file)
index 5041a4a..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- * Copyright © 2011, 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _LIBINPUT_DEVICE_H_
-#define _LIBINPUT_DEVICE_H_
-
-#include "config.h"
-
-#include <linux/input.h>
-#include <wayland-util.h>
-#include <libinput.h>
-
-#include "compositor.h"
-
-enum evdev_device_seat_capability {
-       EVDEV_SEAT_POINTER = (1 << 0),
-       EVDEV_SEAT_KEYBOARD = (1 << 1),
-       EVDEV_SEAT_TOUCH = (1 << 2)
-};
-
-struct evdev_device {
-       struct weston_seat *seat;
-       enum evdev_device_seat_capability seat_caps;
-       struct libinput_device *device;
-       struct wl_list link;
-       struct weston_output *output;
-       struct wl_listener output_destroy_listener;
-       char *devnode;
-       char *output_name;
-       int fd;
-};
-
-void
-evdev_led_update(struct evdev_device *device, enum weston_led leds);
-
-struct evdev_device *
-evdev_device_create(struct libinput_device *libinput_device,
-                   struct weston_seat *seat);
-
-int
-evdev_device_process_event(struct libinput_event *event);
-
-void
-evdev_device_set_output(struct evdev_device *device,
-                       struct weston_output *output);
-void
-evdev_device_destroy(struct evdev_device *device);
-
-void
-evdev_notify_keyboard_focus(struct weston_seat *seat,
-                           struct wl_list *evdev_devices);
-void
-evdev_device_set_calibration(struct evdev_device *device);
-
-int
-dispatch_libinput(struct libinput *libinput);
-
-#endif /* _LIBINPUT_DEVICE_H_ */
diff --git a/src/libinput-seat.c b/src/libinput-seat.c
deleted file mode 100644 (file)
index 94e19f5..0000000
+++ /dev/null
@@ -1,416 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- * Copyright © 2013 Jonas Ådahl
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <libinput.h>
-#include <libudev.h>
-
-#include "compositor.h"
-#include "launcher-util.h"
-#include "libinput-seat.h"
-#include "libinput-device.h"
-#include "shared/helpers.h"
-
-static void
-process_events(struct udev_input *input);
-static struct udev_seat *
-udev_seat_create(struct udev_input *input, const char *seat_name);
-static void
-udev_seat_destroy(struct udev_seat *seat);
-
-static struct udev_seat *
-get_udev_seat(struct udev_input *input, struct libinput_device *device)
-{
-       struct libinput_seat *libinput_seat;
-       const char *seat_name;
-
-       libinput_seat = libinput_device_get_seat(device);
-       seat_name = libinput_seat_get_logical_name(libinput_seat);
-       return udev_seat_get_named(input, seat_name);
-}
-
-static void
-device_added(struct udev_input *input, struct libinput_device *libinput_device)
-{
-       struct weston_compositor *c;
-       struct evdev_device *device;
-       struct weston_output *output;
-       const char *output_name;
-       struct weston_seat *seat;
-       struct udev_seat *udev_seat;
-       struct weston_pointer *pointer;
-
-       c = input->compositor;
-
-       udev_seat = get_udev_seat(input, libinput_device);
-       if (!udev_seat)
-               return;
-
-       seat = &udev_seat->base;
-       device = evdev_device_create(libinput_device, seat);
-       if (device == NULL)
-               return;
-
-       if (input->configure_device != NULL)
-               input->configure_device(c, device->device);
-       evdev_device_set_calibration(device);
-       udev_seat = (struct udev_seat *) seat;
-       wl_list_insert(udev_seat->devices_list.prev, &device->link);
-
-       pointer = weston_seat_get_pointer(seat);
-       if (seat->output && pointer)
-               weston_pointer_clamp(pointer,
-                                    &pointer->x,
-                                    &pointer->y);
-
-       output_name = libinput_device_get_output_name(libinput_device);
-       if (output_name) {
-               device->output_name = strdup(output_name);
-               wl_list_for_each(output, &c->output_list, link)
-                       if (output->name &&
-                           strcmp(output->name, device->output_name) == 0)
-                               evdev_device_set_output(device, output);
-       } else if (device->output == NULL && !wl_list_empty(&c->output_list)) {
-               output = container_of(c->output_list.next,
-                                     struct weston_output, link);
-               evdev_device_set_output(device, output);
-       }
-
-       if (!input->suspended)
-               weston_seat_repick(seat);
-}
-
-static void
-device_removed(struct udev_input *input, struct libinput_device *libinput_device)
-{
-       struct evdev_device *device;
-
-       device = libinput_device_get_user_data(libinput_device);
-       evdev_device_destroy(device);
-}
-
-static void
-udev_seat_remove_devices(struct udev_seat *seat)
-{
-       struct evdev_device *device, *next;
-
-       wl_list_for_each_safe(device, next, &seat->devices_list, link) {
-               evdev_device_destroy(device);
-       }
-}
-
-void
-udev_input_disable(struct udev_input *input)
-{
-       if (input->suspended)
-               return;
-
-       libinput_suspend(input->libinput);
-       process_events(input);
-       input->suspended = 1;
-}
-
-static int
-udev_input_process_event(struct libinput_event *event)
-{
-       struct libinput *libinput = libinput_event_get_context(event);
-       struct libinput_device *libinput_device =
-               libinput_event_get_device(event);
-       struct udev_input *input = libinput_get_user_data(libinput);
-       int handled = 1;
-
-       switch (libinput_event_get_type(event)) {
-       case LIBINPUT_EVENT_DEVICE_ADDED:
-               device_added(input, libinput_device);
-               break;
-       case LIBINPUT_EVENT_DEVICE_REMOVED:
-               device_removed(input, libinput_device);
-               break;
-       default:
-               handled = 0;
-       }
-
-       return handled;
-}
-
-static void
-process_event(struct libinput_event *event)
-{
-       if (udev_input_process_event(event))
-               return;
-       if (evdev_device_process_event(event))
-               return;
-}
-
-static void
-process_events(struct udev_input *input)
-{
-       struct libinput_event *event;
-
-       while ((event = libinput_get_event(input->libinput))) {
-               process_event(event);
-               libinput_event_destroy(event);
-       }
-}
-
-static int
-udev_input_dispatch(struct udev_input *input)
-{
-       if (libinput_dispatch(input->libinput) != 0)
-               weston_log("libinput: Failed to dispatch libinput\n");
-
-       process_events(input);
-
-       return 0;
-}
-
-static int
-libinput_source_dispatch(int fd, uint32_t mask, void *data)
-{
-       struct udev_input *input = data;
-
-       return udev_input_dispatch(input) != 0;
-}
-
-static int
-open_restricted(const char *path, int flags, void *user_data)
-{
-       struct udev_input *input = user_data;
-       struct weston_launcher *launcher = input->compositor->launcher;
-
-       return weston_launcher_open(launcher, path, flags);
-}
-
-static void
-close_restricted(int fd, void *user_data)
-{
-       struct udev_input *input = user_data;
-       struct weston_launcher *launcher = input->compositor->launcher;
-
-       weston_launcher_close(launcher, fd);
-}
-
-const struct libinput_interface libinput_interface = {
-       open_restricted,
-       close_restricted,
-};
-
-int
-udev_input_enable(struct udev_input *input)
-{
-       struct wl_event_loop *loop;
-       struct weston_compositor *c = input->compositor;
-       int fd;
-       struct udev_seat *seat;
-       int devices_found = 0;
-
-       loop = wl_display_get_event_loop(c->wl_display);
-       fd = libinput_get_fd(input->libinput);
-       input->libinput_source =
-               wl_event_loop_add_fd(loop, fd, WL_EVENT_READABLE,
-                                    libinput_source_dispatch, input);
-       if (!input->libinput_source) {
-               return -1;
-       }
-
-       if (input->suspended) {
-               if (libinput_resume(input->libinput) != 0) {
-                       wl_event_source_remove(input->libinput_source);
-                       input->libinput_source = NULL;
-                       return -1;
-               }
-               input->suspended = 0;
-               process_events(input);
-       }
-
-       wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
-               evdev_notify_keyboard_focus(&seat->base, &seat->devices_list);
-
-               if (!wl_list_empty(&seat->devices_list))
-                       devices_found = 1;
-       }
-
-       if (devices_found == 0) {
-               weston_log(
-                       "warning: no input devices on entering Weston. "
-                       "Possible causes:\n"
-                       "\t- no permissions to read /dev/input/event*\n"
-                       "\t- seats misconfigured "
-                       "(Weston backend option 'seat', "
-                       "udev device property ID_SEAT)\n");
-               return -1;
-       }
-
-       return 0;
-}
-
-static void
-libinput_log_func(struct libinput *libinput,
-                 enum libinput_log_priority priority,
-                 const char *format, va_list args)
-{
-       weston_vlog(format, args);
-}
-
-int
-udev_input_init(struct udev_input *input, struct weston_compositor *c,
-               struct udev *udev, const char *seat_id,
-               udev_configure_device_t configure_device)
-{
-       enum libinput_log_priority priority = LIBINPUT_LOG_PRIORITY_INFO;
-       const char *log_priority = NULL;
-
-       memset(input, 0, sizeof *input);
-
-       input->compositor = c;
-       input->configure_device = configure_device;
-
-       log_priority = getenv("WESTON_LIBINPUT_LOG_PRIORITY");
-
-       input->libinput = libinput_udev_create_context(&libinput_interface,
-                                                      input, udev);
-       if (!input->libinput) {
-               return -1;
-       }
-
-       libinput_log_set_handler(input->libinput, &libinput_log_func);
-
-       if (log_priority) {
-               if (strcmp(log_priority, "debug") == 0) {
-                       priority = LIBINPUT_LOG_PRIORITY_DEBUG;
-               } else if (strcmp(log_priority, "info") == 0) {
-                       priority = LIBINPUT_LOG_PRIORITY_INFO;
-               } else if (strcmp(log_priority, "error") == 0) {
-                       priority = LIBINPUT_LOG_PRIORITY_ERROR;
-               }
-       }
-
-       libinput_log_set_priority(input->libinput, priority);
-
-       if (libinput_udev_assign_seat(input->libinput, seat_id) != 0) {
-               libinput_unref(input->libinput);
-               return -1;
-       }
-
-       process_events(input);
-
-       return udev_input_enable(input);
-}
-
-void
-udev_input_destroy(struct udev_input *input)
-{
-       struct udev_seat *seat, *next;
-
-       wl_event_source_remove(input->libinput_source);
-       wl_list_for_each_safe(seat, next, &input->compositor->seat_list, base.link)
-               udev_seat_destroy(seat);
-       libinput_unref(input->libinput);
-}
-
-static void
-udev_seat_led_update(struct weston_seat *seat_base, enum weston_led leds)
-{
-       struct udev_seat *seat = (struct udev_seat *) seat_base;
-       struct evdev_device *device;
-
-       wl_list_for_each(device, &seat->devices_list, link)
-               evdev_led_update(device, leds);
-}
-
-static void
-notify_output_create(struct wl_listener *listener, void *data)
-{
-       struct udev_seat *seat = container_of(listener, struct udev_seat,
-                                             output_create_listener);
-       struct evdev_device *device;
-       struct weston_output *output = data;
-
-       wl_list_for_each(device, &seat->devices_list, link) {
-               if (device->output_name &&
-                   strcmp(output->name, device->output_name) == 0) {
-                       evdev_device_set_output(device, output);
-               }
-
-               if (device->output_name == NULL && device->output == NULL)
-                       evdev_device_set_output(device, output);
-       }
-}
-
-static struct udev_seat *
-udev_seat_create(struct udev_input *input, const char *seat_name)
-{
-       struct weston_compositor *c = input->compositor;
-       struct udev_seat *seat;
-
-       seat = zalloc(sizeof *seat);
-       if (!seat)
-               return NULL;
-
-       weston_seat_init(&seat->base, c, seat_name);
-       seat->base.led_update = udev_seat_led_update;
-
-       seat->output_create_listener.notify = notify_output_create;
-       wl_signal_add(&c->output_created_signal,
-                     &seat->output_create_listener);
-
-       wl_list_init(&seat->devices_list);
-
-       return seat;
-}
-
-static void
-udev_seat_destroy(struct udev_seat *seat)
-{
-       struct weston_keyboard *keyboard =
-               weston_seat_get_keyboard(&seat->base);
-
-       if (keyboard)
-               notify_keyboard_focus_out(&seat->base);
-
-       udev_seat_remove_devices(seat);
-       weston_seat_release(&seat->base);
-       wl_list_remove(&seat->output_create_listener.link);
-       free(seat);
-}
-
-struct udev_seat *
-udev_seat_get_named(struct udev_input *input, const char *seat_name)
-{
-       struct udev_seat *seat;
-
-       wl_list_for_each(seat, &input->compositor->seat_list, base.link) {
-               if (strcmp(seat->base.seat_name, seat_name) == 0)
-                       return seat;
-       }
-
-       return udev_seat_create(input, seat_name);
-}
diff --git a/src/libinput-seat.h b/src/libinput-seat.h
deleted file mode 100644 (file)
index 65c9b64..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- * Copyright © 2013 Jonas Ådahl
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _LIBINPUT_SEAT_H_
-#define _LIBINPUT_SEAT_H_
-
-#include "config.h"
-
-#include <libudev.h>
-
-#include "compositor.h"
-
-struct libinput_device;
-
-struct udev_seat {
-       struct weston_seat base;
-       struct wl_list devices_list;
-       struct wl_listener output_create_listener;
-};
-
-typedef void (*udev_configure_device_t)(struct weston_compositor *compositor,
-                                       struct libinput_device *device);
-
-struct udev_input {
-       struct libinput *libinput;
-       struct wl_event_source *libinput_source;
-       struct weston_compositor *compositor;
-       int suspended;
-       udev_configure_device_t configure_device;
-};
-
-int
-udev_input_enable(struct udev_input *input);
-void
-udev_input_disable(struct udev_input *input);
-int
-udev_input_init(struct udev_input *input,
-               struct weston_compositor *c,
-               struct udev *udev,
-               const char *seat_id,
-               udev_configure_device_t configure_device);
-void
-udev_input_destroy(struct udev_input *input);
-
-struct udev_seat *
-udev_seat_get_named(struct udev_input *u,
-                   const char *seat_name);
-
-#endif
diff --git a/src/libweston.pc.in b/src/libweston.pc.in
deleted file mode 100644 (file)
index 24fe813..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-prefix=@prefix@
-exec_prefix=@exec_prefix@
-libdir=@libdir@
-includedir=@includedir@
-pkgincludedir=${includedir}/libweston-@LIBWESTON_ABI_VERSION@
-
-Name: libweston API
-Description: Header files for libweston compositors development
-Version: @WESTON_VERSION@
-Requires.private: wayland-server pixman-1 xkbcommon
-Cflags: -I${pkgincludedir}
-Libs: -L${libdir} -lweston-@LIBWESTON_ABI_VERSION@
diff --git a/src/linux-dmabuf.c b/src/linux-dmabuf.c
deleted file mode 100644 (file)
index 78e77a2..0000000
+++ /dev/null
@@ -1,497 +0,0 @@
-/*
- * Copyright © 2014, 2015 Collabora, Ltd.
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holders not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  The copyright holders make
- * no representations about the suitability of this software for any
- * purpose.  It is provided "as is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <unistd.h>
-#include <sys/types.h>
-
-#include "compositor.h"
-#include "linux-dmabuf.h"
-#include "linux-dmabuf-unstable-v1-server-protocol.h"
-
-static void
-linux_dmabuf_buffer_destroy(struct linux_dmabuf_buffer *buffer)
-{
-       int i;
-
-       for (i = 0; i < buffer->attributes.n_planes; i++) {
-               close(buffer->attributes.fd[i]);
-               buffer->attributes.fd[i] = -1;
-       }
-
-       buffer->attributes.n_planes = 0;
-       free(buffer);
-}
-
-static void
-destroy_params(struct wl_resource *params_resource)
-{
-       struct linux_dmabuf_buffer *buffer;
-
-       buffer = wl_resource_get_user_data(params_resource);
-
-       if (!buffer)
-               return;
-
-       linux_dmabuf_buffer_destroy(buffer);
-}
-
-static void
-params_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-params_add(struct wl_client *client,
-          struct wl_resource *params_resource,
-          int32_t name_fd,
-          uint32_t plane_idx,
-          uint32_t offset,
-          uint32_t stride,
-          uint32_t modifier_hi,
-          uint32_t modifier_lo)
-{
-       struct linux_dmabuf_buffer *buffer;
-
-       buffer = wl_resource_get_user_data(params_resource);
-       if (!buffer) {
-               wl_resource_post_error(params_resource,
-                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
-                       "params was already used to create a wl_buffer");
-               close(name_fd);
-               return;
-       }
-
-       assert(buffer->params_resource == params_resource);
-       assert(!buffer->buffer_resource);
-
-       if (plane_idx >= MAX_DMABUF_PLANES) {
-               wl_resource_post_error(params_resource,
-                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_IDX,
-                       "plane index %u is too high", plane_idx);
-               close(name_fd);
-               return;
-       }
-
-       if (buffer->attributes.fd[plane_idx] != -1) {
-               wl_resource_post_error(params_resource,
-                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_PLANE_SET,
-                       "a dmabuf has already been added for plane %u",
-                       plane_idx);
-               close(name_fd);
-               return;
-       }
-
-       buffer->attributes.fd[plane_idx] = name_fd;
-       buffer->attributes.offset[plane_idx] = offset;
-       buffer->attributes.stride[plane_idx] = stride;
-       buffer->attributes.modifier[plane_idx] = ((uint64_t)modifier_hi << 32) |
-                                                modifier_lo;
-       buffer->attributes.n_planes++;
-}
-
-static void
-linux_dmabuf_wl_buffer_destroy(struct wl_client *client,
-                              struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static const struct wl_buffer_interface linux_dmabuf_buffer_implementation = {
-       linux_dmabuf_wl_buffer_destroy
-};
-
-static void
-destroy_linux_dmabuf_wl_buffer(struct wl_resource *resource)
-{
-       struct linux_dmabuf_buffer *buffer;
-
-       buffer = wl_resource_get_user_data(resource);
-       assert(buffer->buffer_resource == resource);
-       assert(!buffer->params_resource);
-
-       if (buffer->user_data_destroy_func)
-               buffer->user_data_destroy_func(buffer);
-
-       linux_dmabuf_buffer_destroy(buffer);
-}
-
-static void
-params_create(struct wl_client *client,
-             struct wl_resource *params_resource,
-             int32_t width,
-             int32_t height,
-             uint32_t format,
-             uint32_t flags)
-{
-       struct linux_dmabuf_buffer *buffer;
-       int i;
-
-       buffer = wl_resource_get_user_data(params_resource);
-
-       if (!buffer) {
-               wl_resource_post_error(params_resource,
-                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_ALREADY_USED,
-                       "params was already used to create a wl_buffer");
-               return;
-       }
-
-       assert(buffer->params_resource == params_resource);
-       assert(!buffer->buffer_resource);
-
-       /* Switch the linux_dmabuf_buffer object from params resource to
-        * eventually wl_buffer resource.
-        */
-       wl_resource_set_user_data(buffer->params_resource, NULL);
-       buffer->params_resource = NULL;
-
-       if (!buffer->attributes.n_planes) {
-               wl_resource_post_error(params_resource,
-                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
-                       "no dmabuf has been added to the params");
-               goto err_out;
-       }
-
-       /* Check for holes in the dmabufs set (e.g. [0, 1, 3]) */
-       for (i = 0; i < buffer->attributes.n_planes; i++) {
-               if (buffer->attributes.fd[i] == -1) {
-                       wl_resource_post_error(params_resource,
-                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INCOMPLETE,
-                               "no dmabuf has been added for plane %i", i);
-                       goto err_out;
-               }
-       }
-
-       buffer->attributes.width = width;
-       buffer->attributes.height = height;
-       buffer->attributes.format = format;
-       buffer->attributes.flags = flags;
-
-       if (width < 1 || height < 1) {
-               wl_resource_post_error(params_resource,
-                       ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_INVALID_DIMENSIONS,
-                       "invalid width %d or height %d", width, height);
-               goto err_out;
-       }
-
-       for (i = 0; i < buffer->attributes.n_planes; i++) {
-               off_t size;
-
-               if ((uint64_t) buffer->attributes.offset[i] + buffer->attributes.stride[i] > UINT32_MAX) {
-                       wl_resource_post_error(params_resource,
-                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
-                               "size overflow for plane %i", i);
-                       goto err_out;
-               }
-
-               if (i == 0 &&
-                  (uint64_t) buffer->attributes.offset[i] +
-                  (uint64_t) buffer->attributes.stride[i] * height > UINT32_MAX) {
-                       wl_resource_post_error(params_resource,
-                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
-                               "size overflow for plane %i", i);
-                       goto err_out;
-               }
-
-               /* Don't report an error as it might be caused
-                * by the kernel not supporting seeking on dmabuf */
-               size = lseek(buffer->attributes.fd[i], 0, SEEK_END);
-               if (size == -1)
-                       continue;
-
-               if (buffer->attributes.offset[i] >= size) {
-                       wl_resource_post_error(params_resource,
-                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
-                               "invalid offset %i for plane %i",
-                               buffer->attributes.offset[i], i);
-                       goto err_out;
-               }
-
-               if (buffer->attributes.offset[i] + buffer->attributes.stride[i] > size) {
-                       wl_resource_post_error(params_resource,
-                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
-                               "invalid stride %i for plane %i",
-                               buffer->attributes.stride[i], i);
-                       goto err_out;
-               }
-
-               /* Only valid for first plane as other planes might be
-                * sub-sampled according to fourcc format */
-               if (i == 0 &&
-                   buffer->attributes.offset[i] + buffer->attributes.stride[i] * height > size) {
-                       wl_resource_post_error(params_resource,
-                               ZWP_LINUX_BUFFER_PARAMS_V1_ERROR_OUT_OF_BOUNDS,
-                               "invalid buffer stride or height for plane %i", i);
-                       goto err_out;
-               }
-       }
-
-       /* XXX: Some additional sanity checks could be done with respect
-        * to the fourcc format. A centralized collection (kernel or
-        * libdrm) would be useful to avoid code duplication for these
-        * checks (e.g. drm_format_num_planes).
-        */
-
-       if (!weston_compositor_import_dmabuf(buffer->compositor, buffer))
-               goto err_failed;
-
-       buffer->buffer_resource = wl_resource_create(client,
-                                                    &wl_buffer_interface,
-                                                    1, 0);
-       if (!buffer->buffer_resource) {
-               wl_resource_post_no_memory(params_resource);
-               goto err_buffer;
-       }
-
-       wl_resource_set_implementation(buffer->buffer_resource,
-                                      &linux_dmabuf_buffer_implementation,
-                                      buffer, destroy_linux_dmabuf_wl_buffer);
-
-       zwp_linux_buffer_params_v1_send_created(params_resource,
-                                               buffer->buffer_resource);
-
-       return;
-
-err_buffer:
-       if (buffer->user_data_destroy_func)
-               buffer->user_data_destroy_func(buffer);
-
-err_failed:
-       zwp_linux_buffer_params_v1_send_failed(params_resource);
-
-err_out:
-       linux_dmabuf_buffer_destroy(buffer);
-}
-
-static const struct zwp_linux_buffer_params_v1_interface
-zwp_linux_buffer_params_implementation = {
-       params_destroy,
-       params_add,
-       params_create
-};
-
-static void
-linux_dmabuf_destroy(struct wl_client *client, struct wl_resource *resource)
-{
-       wl_resource_destroy(resource);
-}
-
-static void
-linux_dmabuf_create_params(struct wl_client *client,
-                          struct wl_resource *linux_dmabuf_resource,
-                          uint32_t params_id)
-{
-       struct weston_compositor *compositor;
-       struct linux_dmabuf_buffer *buffer;
-       uint32_t version;
-       int i;
-
-       version = wl_resource_get_version(linux_dmabuf_resource);
-       compositor = wl_resource_get_user_data(linux_dmabuf_resource);
-
-       buffer = zalloc(sizeof *buffer);
-       if (!buffer)
-               goto err_out;
-
-       for (i = 0; i < MAX_DMABUF_PLANES; i++)
-               buffer->attributes.fd[i] = -1;
-
-       buffer->compositor = compositor;
-       buffer->params_resource =
-               wl_resource_create(client,
-                                  &zwp_linux_buffer_params_v1_interface,
-                                  version, params_id);
-       if (!buffer->params_resource)
-               goto err_dealloc;
-
-       wl_resource_set_implementation(buffer->params_resource,
-                                      &zwp_linux_buffer_params_implementation,
-                                      buffer, destroy_params);
-
-       return;
-
-err_dealloc:
-       free(buffer);
-
-err_out:
-       wl_resource_post_no_memory(linux_dmabuf_resource);
-}
-
-/** Get the linux_dmabuf_buffer from a wl_buffer resource
- *
- * If the given wl_buffer resource was created through the linux_dmabuf
- * protocol interface, returns the linux_dmabuf_buffer object. This can
- * be used as a type check for a wl_buffer.
- *
- * \param resource A wl_buffer resource.
- * \return The linux_dmabuf_buffer if it exists, or NULL otherwise.
- */
-WL_EXPORT struct linux_dmabuf_buffer *
-linux_dmabuf_buffer_get(struct wl_resource *resource)
-{
-       struct linux_dmabuf_buffer *buffer;
-
-       if (!resource)
-               return NULL;
-
-       if (!wl_resource_instance_of(resource, &wl_buffer_interface,
-                                    &linux_dmabuf_buffer_implementation))
-               return NULL;
-
-       buffer = wl_resource_get_user_data(resource);
-       assert(buffer);
-       assert(!buffer->params_resource);
-       assert(buffer->buffer_resource == resource);
-
-       return buffer;
-}
-
-/** Set renderer-private data
- *
- * Set the user data for the linux_dmabuf_buffer. It is invalid to overwrite
- * a non-NULL user data with a new non-NULL pointer. This is meant to
- * protect against renderers fighting over linux_dmabuf_buffer user data
- * ownership.
- *
- * The renderer-private data is usually set from the
- * weston_renderer::import_dmabuf hook.
- *
- * \param buffer The linux_dmabuf_buffer object to set for.
- * \param data The new renderer-private data pointer.
- * \param func Destructor function to be called for the renderer-private
- *             data when the linux_dmabuf_buffer gets destroyed.
- *
- * \sa weston_compositor_import_dmabuf
- */
-WL_EXPORT void
-linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
-                                 void *data,
-                                 dmabuf_user_data_destroy_func func)
-{
-       assert(data == NULL || buffer->user_data == NULL);
-
-       buffer->user_data = data;
-       buffer->user_data_destroy_func = func;
-}
-
-/** Get renderer-private data
- *
- * Get the user data from the linux_dmabuf_buffer.
- *
- * \param buffer The linux_dmabuf_buffer to query.
- * \return Renderer-private data pointer.
- *
- * \sa linux_dmabuf_buffer_set_user_data
- */
-WL_EXPORT void *
-linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer)
-{
-       return buffer->user_data;
-}
-
-static const struct zwp_linux_dmabuf_v1_interface linux_dmabuf_implementation = {
-       linux_dmabuf_destroy,
-       linux_dmabuf_create_params
-};
-
-static void
-bind_linux_dmabuf(struct wl_client *client,
-                 void *data, uint32_t version, uint32_t id)
-{
-       struct weston_compositor *compositor = data;
-       struct wl_resource *resource;
-
-       resource = wl_resource_create(client, &zwp_linux_dmabuf_v1_interface,
-                                     version, id);
-       if (resource == NULL) {
-               wl_client_post_no_memory(client);
-               return;
-       }
-
-       wl_resource_set_implementation(resource, &linux_dmabuf_implementation,
-                                      compositor, NULL);
-
-       /* EGL_EXT_image_dma_buf_import does not provide a way to query the
-        * supported pixel formats. */
-       /* XXX: send formats */
-}
-
-/** Advertise linux_dmabuf support
- *
- * Calling this initializes the zwp_linux_dmabuf protocol support, so that
- * the interface will be advertised to clients. Essentially it creates a
- * global. Do not call this function multiple times in the compositor's
- * lifetime. There is no way to deinit explicitly, globals will be reaped
- * when the wl_display gets destroyed.
- *
- * \param compositor The compositor to init for.
- * \return Zero on success, -1 on failure.
- */
-WL_EXPORT int
-linux_dmabuf_setup(struct weston_compositor *compositor)
-{
-       if (!wl_global_create(compositor->wl_display,
-                             &zwp_linux_dmabuf_v1_interface, 1,
-                             compositor, bind_linux_dmabuf))
-               return -1;
-
-       return 0;
-}
-
-/** Resolve an internal compositor error by disconnecting the client.
- *
- * This function is used in cases when the dmabuf-based wl_buffer
- * turns out unusable and there is no fallback path. This is used by
- * renderers which are the fallback path in the first place.
- *
- * It is possible the fault is caused by a compositor bug, the underlying
- * graphics stack bug or normal behaviour, or perhaps a client mistake.
- * In any case, the options are to either composite garbage or nothing,
- * or disconnect the client. This is a helper function for the latter.
- *
- * The error is sent as a INVALID_OBJECT error on the client's wl_display.
- *
- * \param buffer The linux_dmabuf_buffer that is unusable.
- * \param msg A custom error message attached to the protocol error.
- */
-WL_EXPORT void
-linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
-                                     const char *msg)
-{
-       struct wl_client *client;
-       struct wl_resource *display_resource;
-       uint32_t id;
-
-       assert(buffer->buffer_resource);
-       id = wl_resource_get_id(buffer->buffer_resource);
-       client = wl_resource_get_client(buffer->buffer_resource);
-       display_resource = wl_client_get_object(client, 1);
-
-       assert(display_resource);
-       wl_resource_post_error(display_resource,
-                              WL_DISPLAY_ERROR_INVALID_OBJECT,
-                              "linux_dmabuf server error with "
-                              "wl_buffer@%u: %s", id, msg);
-}
diff --git a/src/linux-dmabuf.h b/src/linux-dmabuf.h
deleted file mode 100644 (file)
index cd30f91..0000000
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright © 2014, 2015 Collabora, Ltd.
- *
- * Permission to use, copy, modify, distribute, and sell this software and
- * its documentation for any purpose is hereby granted without fee, provided
- * that the above copyright notice appear in all copies and that both that
- * copyright notice and this permission notice appear in supporting
- * documentation, and that the name of the copyright holders not be used in
- * advertising or publicity pertaining to distribution of the software
- * without specific, written prior permission.  The copyright holders make
- * no representations about the suitability of this software for any
- * purpose.  It is provided "as is" without express or implied warranty.
- *
- * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
- * SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
- * FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
- * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
- * RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF
- * CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef WESTON_LINUX_DMABUF_H
-#define WESTON_LINUX_DMABUF_H
-
-#include <stdint.h>
-
-#define MAX_DMABUF_PLANES 4
-
-struct linux_dmabuf_buffer;
-typedef void (*dmabuf_user_data_destroy_func)(
-                       struct linux_dmabuf_buffer *buffer);
-
-struct dmabuf_attributes {
-       int32_t width;
-       int32_t height;
-       uint32_t format;
-       uint32_t flags; /* enum zlinux_buffer_params_flags */
-       int n_planes;
-       int fd[MAX_DMABUF_PLANES];
-       uint32_t offset[MAX_DMABUF_PLANES];
-       uint32_t stride[MAX_DMABUF_PLANES];
-       uint64_t modifier[MAX_DMABUF_PLANES];
-};
-
-struct linux_dmabuf_buffer {
-       struct wl_resource *buffer_resource;
-       struct wl_resource *params_resource;
-       struct weston_compositor *compositor;
-       struct dmabuf_attributes attributes;
-
-       void *user_data;
-       dmabuf_user_data_destroy_func user_data_destroy_func;
-
-       /* XXX:
-        *
-        * Add backend private data. This would be for the backend
-        * to do all additional imports it might ever use in advance.
-        * The basic principle, even if not implemented in drivers today,
-        * is that dmabufs are first attached, but the actual allocation
-        * is deferred to first use. This would allow the exporter and all
-        * attachers to agree on how to allocate.
-        *
-        * The DRM backend would use this to create drmFBs for each
-        * dmabuf_buffer, just in case at some point it would become
-        * feasible to scan it out directly. This would improve the
-        * possibilities to successfully scan out, avoiding compositing.
-        */
-};
-
-int
-linux_dmabuf_setup(struct weston_compositor *compositor);
-
-struct linux_dmabuf_buffer *
-linux_dmabuf_buffer_get(struct wl_resource *resource);
-
-void
-linux_dmabuf_buffer_set_user_data(struct linux_dmabuf_buffer *buffer,
-                                 void *data,
-                                 dmabuf_user_data_destroy_func func);
-void *
-linux_dmabuf_buffer_get_user_data(struct linux_dmabuf_buffer *buffer);
-
-void
-linux_dmabuf_buffer_send_server_error(struct linux_dmabuf_buffer *buffer,
-                                     const char *msg);
-
-#endif /* WESTON_LINUX_DMABUF_H */
diff --git a/src/log.c b/src/log.c
deleted file mode 100644 (file)
index 7d99a95..0000000
--- a/src/log.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Copyright © 2012 Martin Minarik
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <stdarg.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/time.h>
-#include <time.h>
-
-#include <wayland-util.h>
-
-#include "compositor.h"
-
-static log_func_t log_handler = 0;
-static log_func_t log_continue_handler = 0;
-
-/** Install the log handler
- *
- * The given functions will be called to output text as passed to the
- * \a weston_log and \a weston_log_continue functions.
- *
- * \param log The log function. This function will be called when
- *            \a weston_log is called, and should begin a new line,
- *            with user defined line headers, if any.
- * \param cont The continue log function. This function will be called
- *             when \a weston_log_continue is called, and should append
- *             its output to the current line, without any header or
- *             other content in between.
- */
-WL_EXPORT void
-weston_log_set_handler(log_func_t log, log_func_t cont)
-{
-       log_handler = log;
-       log_continue_handler = cont;
-}
-
-WL_EXPORT int
-weston_vlog(const char *fmt, va_list ap)
-{
-       return log_handler(fmt, ap);
-}
-
-WL_EXPORT int
-weston_log(const char *fmt, ...)
-{
-       int l;
-       va_list argp;
-
-       va_start(argp, fmt);
-       l = weston_vlog(fmt, argp);
-       va_end(argp);
-
-       return l;
-}
-
-WL_EXPORT int
-weston_vlog_continue(const char *fmt, va_list argp)
-{
-       return log_continue_handler(fmt, argp);
-}
-
-WL_EXPORT int
-weston_log_continue(const char *fmt, ...)
-{
-       int l;
-       va_list argp;
-
-       va_start(argp, fmt);
-       l = weston_vlog_continue(fmt, argp);
-       va_end(argp);
-
-       return l;
-}
diff --git a/src/noop-renderer.c b/src/noop-renderer.c
deleted file mode 100644 (file)
index b6499b8..0000000
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-
-#include "compositor.h"
-
-static int
-noop_renderer_read_pixels(struct weston_output *output,
-                              pixman_format_code_t format, void *pixels,
-                              uint32_t x, uint32_t y,
-                              uint32_t width, uint32_t height)
-{
-       return 0;
-}
-
-static void
-noop_renderer_repaint_output(struct weston_output *output,
-                            pixman_region32_t *output_damage)
-{
-}
-
-static void
-noop_renderer_flush_damage(struct weston_surface *surface)
-{
-}
-
-static void
-noop_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
-{
-       struct wl_shm_buffer *shm_buffer;
-       uint8_t *data;
-       uint32_t size, i, width, height, stride;
-       volatile unsigned char unused = 0; /* volatile so it's not optimized out */
-
-       if (!buffer)
-               return;
-
-       shm_buffer = wl_shm_buffer_get(buffer->resource);
-
-       if (!shm_buffer) {
-               weston_log("No-op renderer supports only SHM buffers\n");
-               return;
-       }
-
-       data = wl_shm_buffer_get_data(shm_buffer);
-       stride = wl_shm_buffer_get_stride(shm_buffer);
-       width = wl_shm_buffer_get_width(shm_buffer);
-       height = wl_shm_buffer_get_height(shm_buffer);
-       size = stride * height;
-
-       /* Access the buffer data to make sure the buffer's client gets killed
-        * if the buffer size is invalid. This makes the bad_buffer test pass.
-        * This can be removed if we start reading the buffer contents
-        * somewhere else, e.g. in repaint_output(). */
-       wl_shm_buffer_begin_access(shm_buffer);
-       for (i = 0; i < size; i++)
-               unused ^= data[i];
-       wl_shm_buffer_end_access(shm_buffer);
-
-       buffer->shm_buffer = shm_buffer;
-       buffer->width = width;
-       buffer->height = height;
-}
-
-static void
-noop_renderer_surface_set_color(struct weston_surface *surface,
-                float red, float green, float blue, float alpha)
-{
-}
-
-static void
-noop_renderer_destroy(struct weston_compositor *ec)
-{
-       free(ec->renderer);
-       ec->renderer = NULL;
-}
-
-WL_EXPORT int
-noop_renderer_init(struct weston_compositor *ec)
-{
-       struct weston_renderer *renderer;
-
-       renderer = malloc(sizeof *renderer);
-       if (renderer == NULL)
-               return -1;
-
-       renderer->read_pixels = noop_renderer_read_pixels;
-       renderer->repaint_output = noop_renderer_repaint_output;
-       renderer->flush_damage = noop_renderer_flush_damage;
-       renderer->attach = noop_renderer_attach;
-       renderer->surface_set_color = noop_renderer_surface_set_color;
-       renderer->destroy = noop_renderer_destroy;
-       ec->renderer = renderer;
-
-       return 0;
-}
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
deleted file mode 100644 (file)
index f66a11e..0000000
+++ /dev/null
@@ -1,931 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
- * Copyright © 2015 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <errno.h>
-#include <stdlib.h>
-#include <assert.h>
-
-#include "pixman-renderer.h"
-#include "shared/helpers.h"
-
-#include <linux/input.h>
-
-struct pixman_output_state {
-       void *shadow_buffer;
-       pixman_image_t *shadow_image;
-       pixman_image_t *hw_buffer;
-};
-
-struct pixman_surface_state {
-       struct weston_surface *surface;
-
-       pixman_image_t *image;
-       struct weston_buffer_reference buffer_ref;
-
-       struct wl_listener buffer_destroy_listener;
-       struct wl_listener surface_destroy_listener;
-       struct wl_listener renderer_destroy_listener;
-};
-
-struct pixman_renderer {
-       struct weston_renderer base;
-
-       int repaint_debug;
-       pixman_image_t *debug_color;
-       struct weston_binding *debug_binding;
-
-       struct wl_signal destroy_signal;
-};
-
-static inline struct pixman_output_state *
-get_output_state(struct weston_output *output)
-{
-       return (struct pixman_output_state *)output->renderer_state;
-}
-
-static int
-pixman_renderer_create_surface(struct weston_surface *surface);
-
-static inline struct pixman_surface_state *
-get_surface_state(struct weston_surface *surface)
-{
-       if (!surface->renderer_state)
-               pixman_renderer_create_surface(surface);
-
-       return (struct pixman_surface_state *)surface->renderer_state;
-}
-
-static inline struct pixman_renderer *
-get_renderer(struct weston_compositor *ec)
-{
-       return (struct pixman_renderer *)ec->renderer;
-}
-
-static int
-pixman_renderer_read_pixels(struct weston_output *output,
-                              pixman_format_code_t format, void *pixels,
-                              uint32_t x, uint32_t y,
-                              uint32_t width, uint32_t height)
-{
-       struct pixman_output_state *po = get_output_state(output);
-       pixman_transform_t transform;
-       pixman_image_t *out_buf;
-
-       if (!po->hw_buffer) {
-               errno = ENODEV;
-               return -1;
-       }
-
-       out_buf = pixman_image_create_bits(format,
-               width,
-               height,
-               pixels,
-               (PIXMAN_FORMAT_BPP(format) / 8) * width);
-
-       /* Caller expects vflipped source image */
-       pixman_transform_init_translate(&transform,
-                                       pixman_int_to_fixed (x),
-                                       pixman_int_to_fixed (y - pixman_image_get_height (po->hw_buffer)));
-       pixman_transform_scale(&transform, NULL,
-                              pixman_fixed_1,
-                              pixman_fixed_minus_1);
-       pixman_image_set_transform(po->hw_buffer, &transform);
-
-       pixman_image_composite32(PIXMAN_OP_SRC,
-                                po->hw_buffer, /* src */
-                                NULL /* mask */,
-                                out_buf, /* dest */
-                                0, 0, /* src_x, src_y */
-                                0, 0, /* mask_x, mask_y */
-                                0, 0, /* dest_x, dest_y */
-                                pixman_image_get_width (po->hw_buffer), /* width */
-                                pixman_image_get_height (po->hw_buffer) /* height */);
-       pixman_image_set_transform(po->hw_buffer, NULL);
-
-       pixman_image_unref(out_buf);
-
-       return 0;
-}
-
-static void
-region_global_to_output(struct weston_output *output, pixman_region32_t *region)
-{
-       if (output->zoom.active) {
-               weston_matrix_transform_region(region, &output->matrix, region);
-       } else {
-               pixman_region32_translate(region, -output->x, -output->y);
-               weston_transformed_region(output->width, output->height,
-                                         output->transform,
-                                         output->current_scale,
-                                         region, region);
-       }
-}
-
-#define D2F(v) pixman_double_to_fixed((double)v)
-
-static void
-weston_matrix_to_pixman_transform(pixman_transform_t *pt,
-                                 const struct weston_matrix *wm)
-{
-       /* Pixman supports only 2D transform matrix, but Weston uses 3D, *
-        * so we're omitting Z coordinate here. */
-       pt->matrix[0][0] = pixman_double_to_fixed(wm->d[0]);
-       pt->matrix[0][1] = pixman_double_to_fixed(wm->d[4]);
-       pt->matrix[0][2] = pixman_double_to_fixed(wm->d[12]);
-       pt->matrix[1][0] = pixman_double_to_fixed(wm->d[1]);
-       pt->matrix[1][1] = pixman_double_to_fixed(wm->d[5]);
-       pt->matrix[1][2] = pixman_double_to_fixed(wm->d[13]);
-       pt->matrix[2][0] = pixman_double_to_fixed(wm->d[3]);
-       pt->matrix[2][1] = pixman_double_to_fixed(wm->d[7]);
-       pt->matrix[2][2] = pixman_double_to_fixed(wm->d[15]);
-}
-
-static void
-pixman_renderer_compute_transform(pixman_transform_t *transform_out,
-                                 struct weston_view *ev,
-                                 struct weston_output *output)
-{
-       struct weston_matrix matrix;
-
-       /* Set up the source transformation based on the surface
-          position, the output position/transform/scale and the client
-          specified buffer transform/scale */
-       matrix = output->inverse_matrix;
-
-       if (ev->transform.enabled) {
-               weston_matrix_multiply(&matrix, &ev->transform.inverse);
-       } else {
-               weston_matrix_translate(&matrix,
-                                       -ev->geometry.x, -ev->geometry.y, 0);
-       }
-
-       weston_matrix_multiply(&matrix, &ev->surface->surface_to_buffer_matrix);
-
-       weston_matrix_to_pixman_transform(transform_out, &matrix);
-}
-
-static bool
-view_transformation_is_translation(struct weston_view *view)
-{
-       if (!view->transform.enabled)
-               return true;
-
-       if (view->transform.matrix.type <= WESTON_MATRIX_TRANSFORM_TRANSLATE)
-               return true;
-
-       return false;
-}
-
-static void
-region_intersect_only_translation(pixman_region32_t *result_global,
-                                 pixman_region32_t *global,
-                                 pixman_region32_t *surf,
-                                 struct weston_view *view)
-{
-       float view_x, view_y;
-
-       assert(view_transformation_is_translation(view));
-
-       /* Convert from surface to global coordinates */
-       pixman_region32_copy(result_global, surf);
-       weston_view_to_global_float(view, 0, 0, &view_x, &view_y);
-       pixman_region32_translate(result_global, (int)view_x, (int)view_y);
-
-       pixman_region32_intersect(result_global, result_global, global);
-}
-
-static void
-composite_whole(pixman_op_t op,
-               pixman_image_t *src,
-               pixman_image_t *mask,
-               pixman_image_t *dest,
-               const pixman_transform_t *transform,
-               pixman_filter_t filter)
-{
-       int32_t dest_width;
-       int32_t dest_height;
-
-       dest_width = pixman_image_get_width(dest);
-       dest_height = pixman_image_get_height(dest);
-
-       pixman_image_set_transform(src, transform);
-       pixman_image_set_filter(src, filter, NULL, 0);
-
-       pixman_image_composite32(op, src, mask, dest,
-                                0, 0, /* src_x, src_y */
-                                0, 0, /* mask_x, mask_y */
-                                0, 0, /* dest_x, dest_y */
-                                dest_width, dest_height);
-}
-
-static void
-composite_clipped(pixman_image_t *src,
-                 pixman_image_t *mask,
-                 pixman_image_t *dest,
-                 const pixman_transform_t *transform,
-                 pixman_filter_t filter,
-                 pixman_region32_t *src_clip)
-{
-       int n_box;
-       pixman_box32_t *boxes;
-       int32_t dest_width;
-       int32_t dest_height;
-       int src_stride;
-       int bitspp;
-       pixman_format_code_t src_format;
-       void *src_data;
-       int i;
-
-       /* Hardcoded to use PIXMAN_OP_OVER, because sampling outside of
-        * a Pixman image produces (0,0,0,0) instead of discarding the
-        * fragment.
-        */
-
-       dest_width = pixman_image_get_width(dest);
-       dest_height = pixman_image_get_height(dest);
-       src_format = pixman_image_get_format(src);
-       src_stride = pixman_image_get_stride(src);
-       bitspp = PIXMAN_FORMAT_BPP(src_format);
-       src_data = pixman_image_get_data(src);
-
-       assert(src_format);
-
-       /* This would be massive overdraw, except when n_box is 1. */
-       boxes = pixman_region32_rectangles(src_clip, &n_box);
-       for (i = 0; i < n_box; i++) {
-               uint8_t *ptr = src_data;
-               pixman_image_t *boximg;
-               pixman_transform_t adj = *transform;
-
-               ptr += boxes[i].y1 * src_stride;
-               ptr += boxes[i].x1 * bitspp / 8;
-               boximg = pixman_image_create_bits_no_clear(src_format,
-                                       boxes[i].x2 - boxes[i].x1,
-                                       boxes[i].y2 - boxes[i].y1,
-                                       (uint32_t *)ptr, src_stride);
-
-               pixman_transform_translate(&adj, NULL,
-                                          pixman_int_to_fixed(-boxes[i].x1),
-                                          pixman_int_to_fixed(-boxes[i].y1));
-               pixman_image_set_transform(boximg, &adj);
-
-               pixman_image_set_filter(boximg, filter, NULL, 0);
-               pixman_image_composite32(PIXMAN_OP_OVER, boximg, mask, dest,
-                                        0, 0, /* src_x, src_y */
-                                        0, 0, /* mask_x, mask_y */
-                                        0, 0, /* dest_x, dest_y */
-                                        dest_width, dest_height);
-
-               pixman_image_unref(boximg);
-       }
-
-       if (n_box > 1) {
-               static bool warned = false;
-
-               if (!warned)
-                       weston_log("Pixman-renderer warning: %dx overdraw\n",
-                                  n_box);
-               warned = true;
-       }
-}
-
-/** Paint an intersected region
- *
- * \param ev The view to be painted.
- * \param output The output being painted.
- * \param repaint_output The region to be painted in output coordinates.
- * \param source_clip The region of the source image to use, in source image
- *                    coordinates. If NULL, use the whole source image.
- * \param pixman_op Compositing operator, either SRC or OVER.
- */
-static void
-repaint_region(struct weston_view *ev, struct weston_output *output,
-              pixman_region32_t *repaint_output,
-              pixman_region32_t *source_clip,
-              pixman_op_t pixman_op)
-{
-       struct pixman_renderer *pr =
-               (struct pixman_renderer *) output->compositor->renderer;
-       struct pixman_surface_state *ps = get_surface_state(ev->surface);
-       struct pixman_output_state *po = get_output_state(output);
-       struct weston_buffer_viewport *vp = &ev->surface->buffer_viewport;
-       pixman_transform_t transform;
-       pixman_filter_t filter;
-       pixman_image_t *mask_image;
-       pixman_color_t mask = { 0, };
-
-       /* Clip rendering to the damaged output region */
-       pixman_image_set_clip_region32(po->shadow_image, repaint_output);
-
-       pixman_renderer_compute_transform(&transform, ev, output);
-
-       if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
-               filter = PIXMAN_FILTER_BILINEAR;
-       else
-               filter = PIXMAN_FILTER_NEAREST;
-
-       if (ps->buffer_ref.buffer)
-               wl_shm_buffer_begin_access(ps->buffer_ref.buffer->shm_buffer);
-
-       if (ev->alpha < 1.0) {
-               mask.alpha = 0xffff * ev->alpha;
-               mask_image = pixman_image_create_solid_fill(&mask);
-       } else {
-               mask_image = NULL;
-       }
-
-       if (source_clip)
-               composite_clipped(ps->image, mask_image, po->shadow_image,
-                                 &transform, filter, source_clip);
-       else
-               composite_whole(pixman_op, ps->image, mask_image,
-                               po->shadow_image, &transform, filter);
-
-       if (mask_image)
-               pixman_image_unref(mask_image);
-
-       if (ps->buffer_ref.buffer)
-               wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
-
-       if (pr->repaint_debug)
-               pixman_image_composite32(PIXMAN_OP_OVER,
-                                        pr->debug_color, /* src */
-                                        NULL /* mask */,
-                                        po->shadow_image, /* dest */
-                                        0, 0, /* src_x, src_y */
-                                        0, 0, /* mask_x, mask_y */
-                                        0, 0, /* dest_x, dest_y */
-                                        pixman_image_get_width (po->shadow_image), /* width */
-                                        pixman_image_get_height (po->shadow_image) /* height */);
-
-       pixman_image_set_clip_region32 (po->shadow_image, NULL);
-}
-
-static void
-draw_view_translated(struct weston_view *view, struct weston_output *output,
-                    pixman_region32_t *repaint_global)
-{
-       struct weston_surface *surface = view->surface;
-       /* non-opaque region in surface coordinates: */
-       pixman_region32_t surface_blend;
-       /* region to be painted in output coordinates: */
-       pixman_region32_t repaint_output;
-
-       pixman_region32_init(&repaint_output);
-
-       /* Blended region is whole surface minus opaque region,
-        * unless surface alpha forces us to blend all.
-        */
-       pixman_region32_init_rect(&surface_blend, 0, 0,
-                                 surface->width, surface->height);
-
-       if (!(view->alpha < 1.0)) {
-               pixman_region32_subtract(&surface_blend, &surface_blend,
-                                        &surface->opaque);
-
-               if (pixman_region32_not_empty(&surface->opaque)) {
-                       region_intersect_only_translation(&repaint_output,
-                                                         repaint_global,
-                                                         &surface->opaque,
-                                                         view);
-                       region_global_to_output(output, &repaint_output);
-
-                       repaint_region(view, output, &repaint_output, NULL,
-                                      PIXMAN_OP_SRC);
-               }
-       }
-
-       if (pixman_region32_not_empty(&surface_blend)) {
-               region_intersect_only_translation(&repaint_output,
-                                                 repaint_global,
-                                                 &surface_blend, view);
-               region_global_to_output(output, &repaint_output);
-
-               repaint_region(view, output, &repaint_output, NULL,
-                              PIXMAN_OP_OVER);
-       }
-
-       pixman_region32_fini(&surface_blend);
-       pixman_region32_fini(&repaint_output);
-}
-
-static void
-draw_view_source_clipped(struct weston_view *view,
-                        struct weston_output *output,
-                        pixman_region32_t *repaint_global)
-{
-       struct weston_surface *surface = view->surface;
-       pixman_region32_t surf_region;
-       pixman_region32_t buffer_region;
-       pixman_region32_t repaint_output;
-
-       /* Do not bother separating the opaque region from non-opaque.
-        * Source clipping requires PIXMAN_OP_OVER in all cases, so painting
-        * opaque separately has no benefit.
-        */
-
-       pixman_region32_init_rect(&surf_region, 0, 0,
-                                 surface->width, surface->height);
-       if (view->geometry.scissor_enabled)
-               pixman_region32_intersect(&surf_region, &surf_region,
-                                         &view->geometry.scissor);
-
-       pixman_region32_init(&buffer_region);
-       weston_surface_to_buffer_region(surface, &surf_region, &buffer_region);
-
-       pixman_region32_init(&repaint_output);
-       pixman_region32_copy(&repaint_output, repaint_global);
-       region_global_to_output(output, &repaint_output);
-
-       repaint_region(view, output, &repaint_output, &buffer_region,
-                      PIXMAN_OP_OVER);
-
-       pixman_region32_fini(&repaint_output);
-       pixman_region32_fini(&buffer_region);
-       pixman_region32_fini(&surf_region);
-}
-
-static void
-draw_view(struct weston_view *ev, struct weston_output *output,
-         pixman_region32_t *damage) /* in global coordinates */
-{
-       struct pixman_surface_state *ps = get_surface_state(ev->surface);
-       /* repaint bounding region in global coordinates: */
-       pixman_region32_t repaint;
-
-       /* No buffer attached */
-       if (!ps->image)
-               return;
-
-       pixman_region32_init(&repaint);
-       pixman_region32_intersect(&repaint,
-                                 &ev->transform.boundingbox, damage);
-       pixman_region32_subtract(&repaint, &repaint, &ev->clip);
-
-       if (!pixman_region32_not_empty(&repaint))
-               goto out;
-
-       if (view_transformation_is_translation(ev)) {
-               /* The simple case: The surface regions opaque, non-opaque,
-                * etc. are convertible to global coordinate space.
-                * There is no need to use a source clip region.
-                * It is possible to paint opaque region as PIXMAN_OP_SRC.
-                * Also the boundingbox is accurate rather than an
-                * approximation.
-                */
-               draw_view_translated(ev, output, &repaint);
-       } else {
-               /* The complex case: the view transformation does not allow
-                * converting opaque etc. regions into global coordinate space.
-                * Therefore we need source clipping to avoid sampling from
-                * unwanted source image areas, unless the source image is
-                * to be used whole. Source clipping does not work with
-                * PIXMAN_OP_SRC.
-                */
-               draw_view_source_clipped(ev, output, &repaint);
-       }
-
-out:
-       pixman_region32_fini(&repaint);
-}
-static void
-repaint_surfaces(struct weston_output *output, pixman_region32_t *damage)
-{
-       struct weston_compositor *compositor = output->compositor;
-       struct weston_view *view;
-
-       wl_list_for_each_reverse(view, &compositor->view_list, link)
-               if (view->plane == &compositor->primary_plane)
-                       draw_view(view, output, damage);
-}
-
-static void
-copy_to_hw_buffer(struct weston_output *output, pixman_region32_t *region)
-{
-       struct pixman_output_state *po = get_output_state(output);
-       pixman_region32_t output_region;
-
-       pixman_region32_init(&output_region);
-       pixman_region32_copy(&output_region, region);
-
-       region_global_to_output(output, &output_region);
-
-       pixman_image_set_clip_region32 (po->hw_buffer, &output_region);
-       pixman_region32_fini(&output_region);
-
-       pixman_image_composite32(PIXMAN_OP_SRC,
-                                po->shadow_image, /* src */
-                                NULL /* mask */,
-                                po->hw_buffer, /* dest */
-                                0, 0, /* src_x, src_y */
-                                0, 0, /* mask_x, mask_y */
-                                0, 0, /* dest_x, dest_y */
-                                pixman_image_get_width (po->hw_buffer), /* width */
-                                pixman_image_get_height (po->hw_buffer) /* height */);
-
-       pixman_image_set_clip_region32 (po->hw_buffer, NULL);
-}
-
-static void
-pixman_renderer_repaint_output(struct weston_output *output,
-                            pixman_region32_t *output_damage)
-{
-       struct pixman_output_state *po = get_output_state(output);
-
-       if (!po->hw_buffer)
-               return;
-
-       repaint_surfaces(output, output_damage);
-       copy_to_hw_buffer(output, output_damage);
-
-       pixman_region32_copy(&output->previous_damage, output_damage);
-       wl_signal_emit(&output->frame_signal, output);
-
-       /* Actual flip should be done by caller */
-}
-
-static void
-pixman_renderer_flush_damage(struct weston_surface *surface)
-{
-       /* No-op for pixman renderer */
-}
-
-static void
-buffer_state_handle_buffer_destroy(struct wl_listener *listener, void *data)
-{
-       struct pixman_surface_state *ps;
-
-       ps = container_of(listener, struct pixman_surface_state,
-                         buffer_destroy_listener);
-
-       if (ps->image) {
-               pixman_image_unref(ps->image);
-               ps->image = NULL;
-       }
-
-       ps->buffer_destroy_listener.notify = NULL;
-}
-
-static void
-pixman_renderer_attach(struct weston_surface *es, struct weston_buffer *buffer)
-{
-       struct pixman_surface_state *ps = get_surface_state(es);
-       struct wl_shm_buffer *shm_buffer;
-       pixman_format_code_t pixman_format;
-
-       weston_buffer_reference(&ps->buffer_ref, buffer);
-
-       if (ps->buffer_destroy_listener.notify) {
-               wl_list_remove(&ps->buffer_destroy_listener.link);
-               ps->buffer_destroy_listener.notify = NULL;
-       }
-
-       if (ps->image) {
-               pixman_image_unref(ps->image);
-               ps->image = NULL;
-       }
-
-       if (!buffer)
-               return;
-
-       shm_buffer = wl_shm_buffer_get(buffer->resource);
-
-       if (! shm_buffer) {
-               weston_log("Pixman renderer supports only SHM buffers\n");
-               weston_buffer_reference(&ps->buffer_ref, NULL);
-               return;
-       }
-
-       switch (wl_shm_buffer_get_format(shm_buffer)) {
-       case WL_SHM_FORMAT_XRGB8888:
-               pixman_format = PIXMAN_x8r8g8b8;
-               break;
-       case WL_SHM_FORMAT_ARGB8888:
-               pixman_format = PIXMAN_a8r8g8b8;
-               break;
-       case WL_SHM_FORMAT_RGB565:
-               pixman_format = PIXMAN_r5g6b5;
-               break;
-       default:
-               weston_log("Unsupported SHM buffer format\n");
-               weston_buffer_reference(&ps->buffer_ref, NULL);
-               return;
-       break;
-       }
-
-       buffer->shm_buffer = shm_buffer;
-       buffer->width = wl_shm_buffer_get_width(shm_buffer);
-       buffer->height = wl_shm_buffer_get_height(shm_buffer);
-
-       ps->image = pixman_image_create_bits(pixman_format,
-               buffer->width, buffer->height,
-               wl_shm_buffer_get_data(shm_buffer),
-               wl_shm_buffer_get_stride(shm_buffer));
-
-       ps->buffer_destroy_listener.notify =
-               buffer_state_handle_buffer_destroy;
-       wl_signal_add(&buffer->destroy_signal,
-                     &ps->buffer_destroy_listener);
-}
-
-static void
-pixman_renderer_surface_state_destroy(struct pixman_surface_state *ps)
-{
-       wl_list_remove(&ps->surface_destroy_listener.link);
-       wl_list_remove(&ps->renderer_destroy_listener.link);
-       if (ps->buffer_destroy_listener.notify) {
-               wl_list_remove(&ps->buffer_destroy_listener.link);
-               ps->buffer_destroy_listener.notify = NULL;
-       }
-
-       ps->surface->renderer_state = NULL;
-
-       if (ps->image) {
-               pixman_image_unref(ps->image);
-               ps->image = NULL;
-       }
-       weston_buffer_reference(&ps->buffer_ref, NULL);
-       free(ps);
-}
-
-static void
-surface_state_handle_surface_destroy(struct wl_listener *listener, void *data)
-{
-       struct pixman_surface_state *ps;
-
-       ps = container_of(listener, struct pixman_surface_state,
-                         surface_destroy_listener);
-
-       pixman_renderer_surface_state_destroy(ps);
-}
-
-static void
-surface_state_handle_renderer_destroy(struct wl_listener *listener, void *data)
-{
-       struct pixman_surface_state *ps;
-
-       ps = container_of(listener, struct pixman_surface_state,
-                         renderer_destroy_listener);
-
-       pixman_renderer_surface_state_destroy(ps);
-}
-
-static int
-pixman_renderer_create_surface(struct weston_surface *surface)
-{
-       struct pixman_surface_state *ps;
-       struct pixman_renderer *pr = get_renderer(surface->compositor);
-
-       ps = zalloc(sizeof *ps);
-       if (ps == NULL)
-               return -1;
-
-       surface->renderer_state = ps;
-
-       ps->surface = surface;
-
-       ps->surface_destroy_listener.notify =
-               surface_state_handle_surface_destroy;
-       wl_signal_add(&surface->destroy_signal,
-                     &ps->surface_destroy_listener);
-
-       ps->renderer_destroy_listener.notify =
-               surface_state_handle_renderer_destroy;
-       wl_signal_add(&pr->destroy_signal,
-                     &ps->renderer_destroy_listener);
-
-       return 0;
-}
-
-static void
-pixman_renderer_surface_set_color(struct weston_surface *es,
-                float red, float green, float blue, float alpha)
-{
-       struct pixman_surface_state *ps = get_surface_state(es);
-       pixman_color_t color;
-
-       color.red = red * 0xffff;
-       color.green = green * 0xffff;
-       color.blue = blue * 0xffff;
-       color.alpha = alpha * 0xffff;
-
-       if (ps->image) {
-               pixman_image_unref(ps->image);
-               ps->image = NULL;
-       }
-
-       ps->image = pixman_image_create_solid_fill(&color);
-}
-
-static void
-pixman_renderer_destroy(struct weston_compositor *ec)
-{
-       struct pixman_renderer *pr = get_renderer(ec);
-
-       wl_signal_emit(&pr->destroy_signal, pr);
-       weston_binding_destroy(pr->debug_binding);
-       free(pr);
-
-       ec->renderer = NULL;
-}
-
-static void
-pixman_renderer_surface_get_content_size(struct weston_surface *surface,
-                                        int *width, int *height)
-{
-       struct pixman_surface_state *ps = get_surface_state(surface);
-
-       if (ps->image) {
-               *width = pixman_image_get_width(ps->image);
-               *height = pixman_image_get_height(ps->image);
-       } else {
-               *width = 0;
-               *height = 0;
-       }
-}
-
-static int
-pixman_renderer_surface_copy_content(struct weston_surface *surface,
-                                    void *target, size_t size,
-                                    int src_x, int src_y,
-                                    int width, int height)
-{
-       const pixman_format_code_t format = PIXMAN_a8b8g8r8;
-       const size_t bytespp = 4; /* PIXMAN_a8b8g8r8 */
-       struct pixman_surface_state *ps = get_surface_state(surface);
-       pixman_image_t *out_buf;
-
-       if (!ps->image)
-               return -1;
-
-       out_buf = pixman_image_create_bits(format, width, height,
-                                          target, width * bytespp);
-
-       pixman_image_set_transform(ps->image, NULL);
-       pixman_image_composite32(PIXMAN_OP_SRC,
-                                ps->image,    /* src */
-                                NULL,         /* mask */
-                                out_buf,      /* dest */
-                                src_x, src_y, /* src_x, src_y */
-                                0, 0,         /* mask_x, mask_y */
-                                0, 0,         /* dest_x, dest_y */
-                                width, height);
-
-       pixman_image_unref(out_buf);
-
-       return 0;
-}
-
-static void
-debug_binding(struct weston_keyboard *keyboard, uint32_t time, uint32_t key,
-             void *data)
-{
-       struct weston_compositor *ec = data;
-       struct pixman_renderer *pr = (struct pixman_renderer *) ec->renderer;
-
-       pr->repaint_debug ^= 1;
-
-       if (pr->repaint_debug) {
-               pixman_color_t red = {
-                       0x3fff, 0x0000, 0x0000, 0x3fff
-               };
-
-               pr->debug_color = pixman_image_create_solid_fill(&red);
-       } else {
-               pixman_image_unref(pr->debug_color);
-               weston_compositor_damage_all(ec);
-       }
-}
-
-WL_EXPORT int
-pixman_renderer_init(struct weston_compositor *ec)
-{
-       struct pixman_renderer *renderer;
-
-       renderer = zalloc(sizeof *renderer);
-       if (renderer == NULL)
-               return -1;
-
-       renderer->repaint_debug = 0;
-       renderer->debug_color = NULL;
-       renderer->base.read_pixels = pixman_renderer_read_pixels;
-       renderer->base.repaint_output = pixman_renderer_repaint_output;
-       renderer->base.flush_damage = pixman_renderer_flush_damage;
-       renderer->base.attach = pixman_renderer_attach;
-       renderer->base.surface_set_color = pixman_renderer_surface_set_color;
-       renderer->base.destroy = pixman_renderer_destroy;
-       renderer->base.surface_get_content_size =
-               pixman_renderer_surface_get_content_size;
-       renderer->base.surface_copy_content =
-               pixman_renderer_surface_copy_content;
-       ec->renderer = &renderer->base;
-       ec->capabilities |= WESTON_CAP_ROTATION_ANY;
-       ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
-       ec->capabilities |= WESTON_CAP_VIEW_CLIP_MASK;
-
-       renderer->debug_binding =
-               weston_compositor_add_debug_binding(ec, KEY_R,
-                                                   debug_binding, ec);
-
-       wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
-
-       wl_signal_init(&renderer->destroy_signal);
-
-       return 0;
-}
-
-WL_EXPORT void
-pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer)
-{
-       struct pixman_output_state *po = get_output_state(output);
-
-       if (po->hw_buffer)
-               pixman_image_unref(po->hw_buffer);
-       po->hw_buffer = buffer;
-
-       if (po->hw_buffer) {
-               output->compositor->read_format = pixman_image_get_format(po->hw_buffer);
-               pixman_image_ref(po->hw_buffer);
-       }
-}
-
-WL_EXPORT int
-pixman_renderer_output_create(struct weston_output *output)
-{
-       struct pixman_output_state *po;
-       int w, h;
-
-       po = zalloc(sizeof *po);
-       if (po == NULL)
-               return -1;
-
-       /* set shadow image transformation */
-       w = output->current_mode->width;
-       h = output->current_mode->height;
-
-       po->shadow_buffer = malloc(w * h * 4);
-
-       if (!po->shadow_buffer) {
-               free(po);
-               return -1;
-       }
-
-       po->shadow_image =
-               pixman_image_create_bits(PIXMAN_x8r8g8b8, w, h,
-                                        po->shadow_buffer, w * 4);
-
-       if (!po->shadow_image) {
-               free(po->shadow_buffer);
-               free(po);
-               return -1;
-       }
-
-       output->renderer_state = po;
-
-       return 0;
-}
-
-WL_EXPORT void
-pixman_renderer_output_destroy(struct weston_output *output)
-{
-       struct pixman_output_state *po = get_output_state(output);
-
-       pixman_image_unref(po->shadow_image);
-
-       if (po->hw_buffer)
-               pixman_image_unref(po->hw_buffer);
-
-       free(po->shadow_buffer);
-
-       po->shadow_buffer = NULL;
-       po->shadow_image = NULL;
-       po->hw_buffer = NULL;
-
-       free(po);
-}
diff --git a/src/pixman-renderer.h b/src/pixman-renderer.h
deleted file mode 100644 (file)
index 1b42f14..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright © 2013 Vasily Khoruzhick <anarsoul@gmail.com>
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include "compositor.h"
-
-int
-pixman_renderer_init(struct weston_compositor *ec);
-
-int
-pixman_renderer_output_create(struct weston_output *output);
-
-void
-pixman_renderer_output_set_buffer(struct weston_output *output, pixman_image_t *buffer);
-
-void
-pixman_renderer_output_destroy(struct weston_output *output);
diff --git a/src/screenshooter.c b/src/screenshooter.c
deleted file mode 100644 (file)
index fc14ad3..0000000
+++ /dev/null
@@ -1,487 +0,0 @@
-/*
- * Copyright © 2008-2011 Kristian Høgsberg
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <linux/input.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/uio.h>
-
-#include "compositor.h"
-#include "shared/helpers.h"
-
-#include "wcap/wcap-decode.h"
-
-struct screenshooter_frame_listener {
-       struct wl_listener listener;
-       struct weston_buffer *buffer;
-       weston_screenshooter_done_func_t done;
-       void *data;
-};
-
-static void
-copy_bgra_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
-{
-       uint8_t *end;
-
-       end = dst + height * stride;
-       while (dst < end) {
-               memcpy(dst, src, stride);
-               dst += stride;
-               src -= stride;
-       }
-}
-
-static void
-copy_bgra(uint8_t *dst, uint8_t *src, int height, int stride)
-{
-       /* TODO: optimize this out */
-       memcpy(dst, src, height * stride);
-}
-
-static void
-copy_row_swap_RB(void *vdst, void *vsrc, int bytes)
-{
-       uint32_t *dst = vdst;
-       uint32_t *src = vsrc;
-       uint32_t *end = dst + bytes / 4;
-
-       while (dst < end) {
-               uint32_t v = *src++;
-               /*                    A R G B */
-               uint32_t tmp = v & 0xff00ff00;
-               tmp |= (v >> 16) & 0x000000ff;
-               tmp |= (v << 16) & 0x00ff0000;
-               *dst++ = tmp;
-       }
-}
-
-static void
-copy_rgba_yflip(uint8_t *dst, uint8_t *src, int height, int stride)
-{
-       uint8_t *end;
-
-       end = dst + height * stride;
-       while (dst < end) {
-               copy_row_swap_RB(dst, src, stride);
-               dst += stride;
-               src -= stride;
-       }
-}
-
-static void
-copy_rgba(uint8_t *dst, uint8_t *src, int height, int stride)
-{
-       uint8_t *end;
-
-       end = dst + height * stride;
-       while (dst < end) {
-               copy_row_swap_RB(dst, src, stride);
-               dst += stride;
-               src += stride;
-       }
-}
-
-static void
-screenshooter_frame_notify(struct wl_listener *listener, void *data)
-{
-       struct screenshooter_frame_listener *l =
-               container_of(listener,
-                            struct screenshooter_frame_listener, listener);
-       struct weston_output *output = data;
-       struct weston_compositor *compositor = output->compositor;
-       int32_t stride;
-       uint8_t *pixels, *d, *s;
-
-       output->disable_planes--;
-       wl_list_remove(&listener->link);
-       stride = l->buffer->width * (PIXMAN_FORMAT_BPP(compositor->read_format) / 8);
-       pixels = malloc(stride * l->buffer->height);
-
-       if (pixels == NULL) {
-               l->done(l->data, WESTON_SCREENSHOOTER_NO_MEMORY);
-               free(l);
-               return;
-       }
-
-       compositor->renderer->read_pixels(output,
-                            compositor->read_format, pixels,
-                            0, 0, output->current_mode->width,
-                            output->current_mode->height);
-
-       stride = wl_shm_buffer_get_stride(l->buffer->shm_buffer);
-
-       d = wl_shm_buffer_get_data(l->buffer->shm_buffer);
-       s = pixels + stride * (l->buffer->height - 1);
-
-       wl_shm_buffer_begin_access(l->buffer->shm_buffer);
-
-       switch (compositor->read_format) {
-       case PIXMAN_a8r8g8b8:
-       case PIXMAN_x8r8g8b8:
-               if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
-                       copy_bgra_yflip(d, s, output->current_mode->height, stride);
-               else
-                       copy_bgra(d, pixels, output->current_mode->height, stride);
-               break;
-       case PIXMAN_x8b8g8r8:
-       case PIXMAN_a8b8g8r8:
-               if (compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP)
-                       copy_rgba_yflip(d, s, output->current_mode->height, stride);
-               else
-                       copy_rgba(d, pixels, output->current_mode->height, stride);
-               break;
-       default:
-               break;
-       }
-
-       wl_shm_buffer_end_access(l->buffer->shm_buffer);
-
-       l->done(l->data, WESTON_SCREENSHOOTER_SUCCESS);
-       free(pixels);
-       free(l);
-}
-
-WL_EXPORT int
-weston_screenshooter_shoot(struct weston_output *output,
-                          struct weston_buffer *buffer,
-                          weston_screenshooter_done_func_t done, void *data)
-{
-       struct screenshooter_frame_listener *l;
-
-       if (!wl_shm_buffer_get(buffer->resource)) {
-               done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
-               return -1;
-       }
-
-       buffer->shm_buffer = wl_shm_buffer_get(buffer->resource);
-       buffer->width = wl_shm_buffer_get_width(buffer->shm_buffer);
-       buffer->height = wl_shm_buffer_get_height(buffer->shm_buffer);
-
-       if (buffer->width < output->current_mode->width ||
-           buffer->height < output->current_mode->height) {
-               done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
-               return -1;
-       }
-
-       l = malloc(sizeof *l);
-       if (l == NULL) {
-               done(data, WESTON_SCREENSHOOTER_NO_MEMORY);
-               return -1;
-       }
-
-       l->buffer = buffer;
-       l->done = done;
-       l->data = data;
-       l->listener.notify = screenshooter_frame_notify;
-       wl_signal_add(&output->frame_signal, &l->listener);
-       output->disable_planes++;
-       weston_output_schedule_repaint(output);
-
-       return 0;
-}
-
-struct weston_recorder {
-       struct weston_output *output;
-       uint32_t *frame, *rect;
-       uint32_t *tmpbuf;
-       uint32_t total;
-       int fd;
-       struct wl_listener frame_listener;
-       int count, destroying;
-};
-
-static uint32_t *
-output_run(uint32_t *p, uint32_t delta, int run)
-{
-       int i;
-
-       while (run > 0) {
-               if (run <= 0xe0) {
-                       *p++ = delta | ((run - 1) << 24);
-                       break;
-               }
-
-               i = 24 - __builtin_clz(run);
-               *p++ = delta | ((i + 0xe0) << 24);
-               run -= 1 << (7 + i);
-       }
-
-       return p;
-}
-
-static uint32_t
-component_delta(uint32_t next, uint32_t prev)
-{
-       unsigned char dr, dg, db;
-
-       dr = (next >> 16) - (prev >> 16);
-       dg = (next >>  8) - (prev >>  8);
-       db = (next >>  0) - (prev >>  0);
-
-       return (dr << 16) | (dg << 8) | (db << 0);
-}
-
-static void
-weston_recorder_destroy(struct weston_recorder *recorder);
-
-static void
-weston_recorder_frame_notify(struct wl_listener *listener, void *data)
-{
-       struct weston_recorder *recorder =
-               container_of(listener, struct weston_recorder, frame_listener);
-       struct weston_output *output = data;
-       struct weston_compositor *compositor = output->compositor;
-       uint32_t msecs = output->frame_time;
-       pixman_box32_t *r;
-       pixman_region32_t damage, transformed_damage;
-       int i, j, k, n, width, height, run, stride;
-       uint32_t delta, prev, *d, *s, *p, next;
-       struct {
-               uint32_t msecs;
-               uint32_t nrects;
-       } header;
-       struct iovec v[2];
-       int do_yflip;
-       int y_orig;
-       uint32_t *outbuf;
-
-       do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
-       if (do_yflip)
-               outbuf = recorder->rect;
-       else
-               outbuf = recorder->tmpbuf;
-
-       pixman_region32_init(&damage);
-       pixman_region32_init(&transformed_damage);
-       pixman_region32_intersect(&damage, &output->region,
-                                 &output->previous_damage);
-       pixman_region32_translate(&damage, -output->x, -output->y);
-       weston_transformed_region(output->width, output->height,
-                                output->transform, output->current_scale,
-                                &damage, &transformed_damage);
-       pixman_region32_fini(&damage);
-
-       r = pixman_region32_rectangles(&transformed_damage, &n);
-       if (n == 0) {
-               pixman_region32_fini(&transformed_damage);
-               return;
-       }
-
-       header.msecs = msecs;
-       header.nrects = n;
-       v[0].iov_base = &header;
-       v[0].iov_len = sizeof header;
-       v[1].iov_base = r;
-       v[1].iov_len = n * sizeof *r;
-       recorder->total += writev(recorder->fd, v, 2);
-       stride = output->current_mode->width;
-
-       for (i = 0; i < n; i++) {
-               width = r[i].x2 - r[i].x1;
-               height = r[i].y2 - r[i].y1;
-
-               if (do_yflip)
-                       y_orig = output->current_mode->height - r[i].y2;
-               else
-                       y_orig = r[i].y1;
-
-               compositor->renderer->read_pixels(output,
-                               compositor->read_format, recorder->rect,
-                               r[i].x1, y_orig, width, height);
-
-               p = outbuf;
-               run = prev = 0; /* quiet gcc */
-               for (j = 0; j < height; j++) {
-                       if (do_yflip)
-                               s = recorder->rect + width * j;
-                       else
-                               s = recorder->rect + width * (height - j - 1);
-                       y_orig = r[i].y2 - j - 1;
-                       d = recorder->frame + stride * y_orig + r[i].x1;
-
-                       for (k = 0; k < width; k++) {
-                               next = *s++;
-                               delta = component_delta(next, *d);
-                               *d++ = next;
-                               if (run == 0 || delta == prev) {
-                                       run++;
-                               } else {
-                                       p = output_run(p, prev, run);
-                                       run = 1;
-                               }
-                               prev = delta;
-                       }
-               }
-
-               p = output_run(p, prev, run);
-
-               recorder->total += write(recorder->fd,
-                                        outbuf, (p - outbuf) * 4);
-
-#if 0
-               fprintf(stderr,
-                       "%dx%d at %d,%d rle from %d to %d bytes (%f) total %dM\n",
-                       width, height, r[i].x1, r[i].y1,
-                       width * height * 4, (int) (p - outbuf) * 4,
-                       (float) (p - outbuf) / (width * height),
-                       recorder->total / 1024 / 1024);
-#endif
-       }
-
-       pixman_region32_fini(&transformed_damage);
-       recorder->count++;
-
-       if (recorder->destroying)
-               weston_recorder_destroy(recorder);
-}
-
-static void
-weston_recorder_free(struct weston_recorder *recorder)
-{
-       if (recorder == NULL)
-               return;
-
-       free(recorder->tmpbuf);
-       free(recorder->rect);
-       free(recorder->frame);
-       free(recorder);
-}
-
-static struct weston_recorder *
-weston_recorder_create(struct weston_output *output, const char *filename)
-{
-       struct weston_compositor *compositor = output->compositor;
-       struct weston_recorder *recorder;
-       int stride, size;
-       struct { uint32_t magic, format, width, height; } header;
-       int do_yflip;
-
-       do_yflip = !!(compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
-
-       recorder = zalloc(sizeof *recorder);
-       if (recorder == NULL) {
-               weston_log("%s: out of memory\n", __func__);
-               return NULL;
-       }
-
-       stride = output->current_mode->width;
-       size = stride * 4 * output->current_mode->height;
-       recorder->frame = zalloc(size);
-       recorder->rect = malloc(size);
-       recorder->output = output;
-
-       if ((recorder->frame == NULL) || (recorder->rect == NULL)) {
-               weston_log("%s: out of memory\n", __func__);
-               goto err_recorder;
-       }
-
-       if (!do_yflip) {
-               recorder->tmpbuf = malloc(size);
-               if (recorder->tmpbuf == NULL) {
-                       weston_log("%s: out of memory\n", __func__);
-                       goto err_recorder;
-               }
-       }
-
-       header.magic = WCAP_HEADER_MAGIC;
-
-       switch (compositor->read_format) {
-       case PIXMAN_x8r8g8b8:
-       case PIXMAN_a8r8g8b8:
-               header.format = WCAP_FORMAT_XRGB8888;
-               break;
-       case PIXMAN_a8b8g8r8:
-               header.format = WCAP_FORMAT_XBGR8888;
-               break;
-       default:
-               weston_log("unknown recorder format\n");
-               goto err_recorder;
-       }
-
-       recorder->fd = open(filename,
-                           O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC, 0644);
-
-       if (recorder->fd < 0) {
-               weston_log("problem opening output file %s: %m\n", filename);
-               goto err_recorder;
-       }
-
-       header.width = output->current_mode->width;
-       header.height = output->current_mode->height;
-       recorder->total += write(recorder->fd, &header, sizeof header);
-
-       recorder->frame_listener.notify = weston_recorder_frame_notify;
-       wl_signal_add(&output->frame_signal, &recorder->frame_listener);
-       output->disable_planes++;
-       weston_output_damage(output);
-
-       return recorder;
-
-err_recorder:
-       weston_recorder_free(recorder);
-       return NULL;
-}
-
-static void
-weston_recorder_destroy(struct weston_recorder *recorder)
-{
-       wl_list_remove(&recorder->frame_listener.link);
-       close(recorder->fd);
-       recorder->output->disable_planes--;
-       weston_recorder_free(recorder);
-}
-
-WL_EXPORT struct weston_recorder *
-weston_recorder_start(struct weston_output *output, const char *filename)
-{
-       struct wl_listener *listener;
-
-       listener = wl_signal_get(&output->frame_signal,
-                                weston_recorder_frame_notify);
-       if (listener) {
-               weston_log("a recorder on output %s is already running\n",
-                          output->name);
-               return NULL;
-       }
-
-       weston_log("starting recorder for output %s, file %s\n",
-                  output->name, filename);
-       return weston_recorder_create(output, filename);
-}
-
-WL_EXPORT void
-weston_recorder_stop(struct weston_recorder *recorder)
-{
-       weston_log("stopping recorder, total file size %dM, %d frames\n",
-                  recorder->total / (1024 * 1024), recorder->count);
-
-       recorder->destroying = 1;
-       weston_output_schedule_repaint(recorder->output);
-}
diff --git a/src/spring-tool.c b/src/spring-tool.c
deleted file mode 100644 (file)
index 1848b3f..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Copyright © 2011 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include "compositor.h"
-
-WL_EXPORT void
-weston_view_geometry_dirty(struct weston_view *view)
-{
-}
-
-WL_EXPORT int
-weston_log(const char *fmt, ...)
-{
-       return 0;
-}
-
-WL_EXPORT void
-weston_view_schedule_repaint(struct weston_view *view)
-{
-}
-
-WL_EXPORT void
-weston_compositor_schedule_repaint(struct weston_compositor *compositor)
-{
-}
-
-int
-main(int argc, char *argv[])
-{
-       const double k = 300.0;
-       const double current = 0.5;
-       const double target = 1.0;
-       const double friction = 1400;
-
-       struct weston_spring spring;
-       uint32_t time = 0;
-
-       weston_spring_init(&spring, k, current, target);
-       spring.friction = friction;
-       spring.previous = 0.48;
-       spring.timestamp = 0;
-
-       while (!weston_spring_done(&spring)) {
-               printf("\t%d\t%f\n", time, spring.current);
-               weston_spring_update(&spring, time);
-               time += 16;
-       }
-
-       return 0;
-}
diff --git a/src/timeline-object.h b/src/timeline-object.h
deleted file mode 100644 (file)
index 943f979..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright © 2014 Pekka Paalanen <pq@iki.fi>
- * Copyright © 2014 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_TIMELINE_OBJECT_H
-#define WESTON_TIMELINE_OBJECT_H
-
-/*
- * This struct can be embedded in objects related to timeline output.
- * It must be initialized to all-zero. Afterwards, the timeline code
- * will handle it alone. No clean-up is necessary.
- */
-struct weston_timeline_object {
-       /*
-        * Timeline series gets bumped every time a new log is opened.
-        * This triggers id allocation and object info emission.
-        * 0 is an invalid series value.
-        */
-       unsigned series;
-
-       /* Object id in the timeline JSON output. 0 is invalid. */
-       unsigned id;
-
-       /*
-        * If non-zero, forces a re-emission of object description.
-        * Should be set to non-zero, when changing long-lived
-        * object state that is not emitted on normal timeline
-        * events.
-        */
-       unsigned force_refresh;
-};
-
-#endif /* WESTON_TIMELINE_OBJECT_H */
diff --git a/src/timeline.c b/src/timeline.c
deleted file mode 100644 (file)
index cf82428..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*
- * Copyright © 2014 Pekka Paalanen <pq@iki.fi>
- * Copyright © 2014 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <time.h>
-#include <assert.h>
-
-#include "timeline.h"
-#include "compositor.h"
-#include "file-util.h"
-
-struct timeline_log {
-       clock_t clk_id;
-       FILE *file;
-       unsigned series;
-       struct wl_listener compositor_destroy_listener;
-};
-
-WL_EXPORT int weston_timeline_enabled_;
-static struct timeline_log timeline_ = { CLOCK_MONOTONIC, NULL, 0 };
-
-static int
-weston_timeline_do_open(void)
-{
-       const char *prefix = "weston-timeline-";
-       const char *suffix = ".log";
-       char fname[1000];
-
-       timeline_.file = file_create_dated(prefix, suffix,
-                                          fname, sizeof(fname));
-       if (!timeline_.file) {
-               const char *msg;
-
-               switch (errno) {
-               case ETIME:
-                       msg = "failure in datetime formatting";
-                       break;
-               default:
-                       msg = strerror(errno);
-               }
-
-               weston_log("Cannot open '%s*%s' for writing: %s\n",
-                          prefix, suffix, msg);
-               return -1;
-       }
-
-       weston_log("Opened timeline file '%s'\n", fname);
-
-       return 0;
-}
-
-static void
-timeline_notify_destroy(struct wl_listener *listener, void *data)
-{
-       weston_timeline_close();
-}
-
-void
-weston_timeline_open(struct weston_compositor *compositor)
-{
-       if (weston_timeline_enabled_)
-               return;
-
-       if (weston_timeline_do_open() < 0)
-               return;
-
-       timeline_.compositor_destroy_listener.notify = timeline_notify_destroy;
-       wl_signal_add(&compositor->destroy_signal,
-                     &timeline_.compositor_destroy_listener);
-
-       if (++timeline_.series == 0)
-               ++timeline_.series;
-
-       weston_timeline_enabled_ = 1;
-}
-
-void
-weston_timeline_close(void)
-{
-       if (!weston_timeline_enabled_)
-               return;
-
-       weston_timeline_enabled_ = 0;
-
-       wl_list_remove(&timeline_.compositor_destroy_listener.link);
-
-       fclose(timeline_.file);
-       timeline_.file = NULL;
-       weston_log("Timeline log file closed.\n");
-}
-
-struct timeline_emit_context {
-       FILE *cur;
-       FILE *out;
-       unsigned series;
-};
-
-static unsigned
-timeline_new_id(void)
-{
-       static unsigned idc;
-
-       if (++idc == 0)
-               ++idc;
-
-       return idc;
-}
-
-static int
-check_series(struct timeline_emit_context *ctx,
-            struct weston_timeline_object *to)
-{
-       if (to->series == 0 || to->series != ctx->series) {
-               to->series = ctx->series;
-               to->id = timeline_new_id();
-               return 1;
-       }
-
-       if (to->force_refresh) {
-               to->force_refresh = 0;
-               return 1;
-       }
-
-       return 0;
-}
-
-static void
-fprint_quoted_string(FILE *fp, const char *str)
-{
-       if (!str) {
-               fprintf(fp, "null");
-               return;
-       }
-
-       fprintf(fp, "\"%s\"", str);
-}
-
-static int
-emit_weston_output(struct timeline_emit_context *ctx, void *obj)
-{
-       struct weston_output *o = obj;
-
-       if (check_series(ctx, &o->timeline)) {
-               fprintf(ctx->out, "{ \"id\":%u, "
-                       "\"type\":\"weston_output\", \"name\":",
-                       o->timeline.id);
-               fprint_quoted_string(ctx->out, o->name);
-               fprintf(ctx->out, " }\n");
-       }
-
-       fprintf(ctx->cur, "\"wo\":%u", o->timeline.id);
-
-       return 1;
-}
-
-static void
-check_weston_surface_description(struct timeline_emit_context *ctx,
-                                struct weston_surface *s)
-{
-       struct weston_surface *mains;
-       char d[512];
-       char mainstr[32];
-
-       if (!check_series(ctx, &s->timeline))
-               return;
-
-       mains = weston_surface_get_main_surface(s);
-       if (mains != s) {
-               check_weston_surface_description(ctx, mains);
-               if (snprintf(mainstr, sizeof(mainstr),
-                            ", \"main_surface\":%u", mains->timeline.id) < 0)
-                       mainstr[0] = '\0';
-       } else {
-               mainstr[0] = '\0';
-       }
-
-       if (!s->get_label || s->get_label(s, d, sizeof(d)) < 0)
-               d[0] = '\0';
-
-       fprintf(ctx->out, "{ \"id\":%u, "
-               "\"type\":\"weston_surface\", \"desc\":", s->timeline.id);
-       fprint_quoted_string(ctx->out, d[0] ? d : NULL);
-       fprintf(ctx->out, "%s }\n", mainstr);
-}
-
-static int
-emit_weston_surface(struct timeline_emit_context *ctx, void *obj)
-{
-       struct weston_surface *s = obj;
-
-       check_weston_surface_description(ctx, s);
-       fprintf(ctx->cur, "\"ws\":%u", s->timeline.id);
-
-       return 1;
-}
-
-static int
-emit_vblank_timestamp(struct timeline_emit_context *ctx, void *obj)
-{
-       struct timespec *ts = obj;
-
-       fprintf(ctx->cur, "\"vblank\":[%" PRId64 ", %ld]",
-               (int64_t)ts->tv_sec, ts->tv_nsec);
-
-       return 1;
-}
-
-typedef int (*type_func)(struct timeline_emit_context *ctx, void *obj);
-
-static const type_func type_dispatch[] = {
-       [TLT_OUTPUT] = emit_weston_output,
-       [TLT_SURFACE] = emit_weston_surface,
-       [TLT_VBLANK] = emit_vblank_timestamp,
-};
-
-WL_EXPORT void
-weston_timeline_point(const char *name, ...)
-{
-       va_list argp;
-       struct timespec ts;
-       enum timeline_type otype;
-       void *obj;
-       char buf[512];
-       struct timeline_emit_context ctx;
-
-       clock_gettime(timeline_.clk_id, &ts);
-
-       ctx.out = timeline_.file;
-       ctx.cur = fmemopen(buf, sizeof(buf), "w");
-       ctx.series = timeline_.series;
-
-       if (!ctx.cur) {
-               weston_log("Timeline error in fmemopen, closing.\n");
-               weston_timeline_close();
-               return;
-       }
-
-       fprintf(ctx.cur, "{ \"T\":[%" PRId64 ", %ld], \"N\":\"%s\"",
-               (int64_t)ts.tv_sec, ts.tv_nsec, name);
-
-       va_start(argp, name);
-       while (1) {
-               otype = va_arg(argp, enum timeline_type);
-               if (otype == TLT_END)
-                       break;
-
-               obj = va_arg(argp, void *);
-               if (type_dispatch[otype]) {
-                       fprintf(ctx.cur, ", ");
-                       type_dispatch[otype](&ctx, obj);
-               }
-       }
-       va_end(argp);
-
-       fprintf(ctx.cur, " }\n");
-       fflush(ctx.cur);
-       if (ferror(ctx.cur)) {
-               weston_log("Timeline error in constructing entry, closing.\n");
-               weston_timeline_close();
-       } else {
-               fprintf(ctx.out, "%s", buf);
-       }
-
-       fclose(ctx.cur);
-}
diff --git a/src/timeline.h b/src/timeline.h
deleted file mode 100644 (file)
index b10a815..0000000
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * Copyright © 2014 Pekka Paalanen <pq@iki.fi>
- * Copyright © 2014 Collabora, Ltd.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_TIMELINE_H
-#define WESTON_TIMELINE_H
-
-extern int weston_timeline_enabled_;
-
-struct weston_compositor;
-
-void
-weston_timeline_open(struct weston_compositor *compositor);
-
-void
-weston_timeline_close(void);
-
-enum timeline_type {
-       TLT_END = 0,
-       TLT_OUTPUT,
-       TLT_SURFACE,
-       TLT_VBLANK,
-};
-
-#define TYPEVERIFY(type, arg) ({                       \
-       typeof(arg) tmp___ = (arg);             \
-       (void)((type)0 == tmp___);              \
-       tmp___; })
-
-#define TLP_END TLT_END, NULL
-#define TLP_OUTPUT(o) TLT_OUTPUT, TYPEVERIFY(struct weston_output *, (o))
-#define TLP_SURFACE(s) TLT_SURFACE, TYPEVERIFY(struct weston_surface *, (s))
-#define TLP_VBLANK(t) TLT_VBLANK, TYPEVERIFY(const struct timespec *, (t))
-
-#define TL_POINT(...) do { \
-       if (weston_timeline_enabled_) \
-               weston_timeline_point(__VA_ARGS__); \
-} while (0)
-
-void
-weston_timeline_point(const char *name, ...);
-
-#endif /* WESTON_TIMELINE_H */
diff --git a/src/vaapi-recorder.c b/src/vaapi-recorder.c
deleted file mode 100644 (file)
index 1228f7d..0000000
+++ /dev/null
@@ -1,1161 +0,0 @@
-/*
- * Copyright (c) 2012 Intel Corporation. All Rights Reserved.
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdlib.h>
-#include <stdint.h>
-#include <string.h>
-#include <unistd.h>
-#include <assert.h>
-#include <errno.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <pthread.h>
-
-#include <va/va.h>
-#include <va/va_drm.h>
-#include <va/va_drmcommon.h>
-#include <va/va_enc_h264.h>
-#include <va/va_vpp.h>
-
-#include "compositor.h"
-#include "vaapi-recorder.h"
-
-#define NAL_REF_IDC_NONE        0
-#define NAL_REF_IDC_LOW         1
-#define NAL_REF_IDC_MEDIUM      2
-#define NAL_REF_IDC_HIGH        3
-
-#define NAL_NON_IDR             1
-#define NAL_IDR                 5
-#define NAL_SPS                 7
-#define NAL_PPS                 8
-#define NAL_SEI                 6
-
-#define SLICE_TYPE_P            0
-#define SLICE_TYPE_B            1
-#define SLICE_TYPE_I            2
-
-#define ENTROPY_MODE_CAVLC      0
-#define ENTROPY_MODE_CABAC      1
-
-#define PROFILE_IDC_BASELINE    66
-#define PROFILE_IDC_MAIN        77
-#define PROFILE_IDC_HIGH        100
-
-struct vaapi_recorder {
-       int drm_fd, output_fd;
-       int width, height;
-       int frame_count;
-
-       int error;
-       int destroying;
-       pthread_t worker_thread;
-       pthread_mutex_t mutex;
-       pthread_cond_t input_cond;
-
-       struct {
-               int valid;
-               int prime_fd, stride;
-       } input;
-
-       VADisplay va_dpy;
-
-       /* video post processing is used for colorspace conversion */
-       struct {
-               VAConfigID cfg;
-               VAContextID ctx;
-               VABufferID pipeline_buf;
-               VASurfaceID output;
-       } vpp;
-
-       struct {
-               VAConfigID cfg;
-               VAContextID ctx;
-               VASurfaceID reference_picture[3];
-
-               int intra_period;
-               int output_size;
-               int constraint_set_flag;
-
-               struct {
-                       VAEncSequenceParameterBufferH264 seq;
-                       VAEncPictureParameterBufferH264 pic;
-                       VAEncSliceParameterBufferH264 slice;
-               } param;
-       } encoder;
-};
-
-static void *
-worker_thread_function(void *);
-
-/* bistream code used for writing the packed headers */
-
-#define BITSTREAM_ALLOCATE_STEPPING     4096
-
-struct bitstream {
-       unsigned int *buffer;
-       int bit_offset;
-       int max_size_in_dword;
-};
-
-static unsigned int
-va_swap32(unsigned int val)
-{
-       unsigned char *pval = (unsigned char *)&val;
-
-       return ((pval[0] << 24) |
-               (pval[1] << 16) |
-               (pval[2] << 8)  |
-               (pval[3] << 0));
-}
-
-static void
-bitstream_start(struct bitstream *bs)
-{
-       bs->max_size_in_dword = BITSTREAM_ALLOCATE_STEPPING;
-       bs->buffer = calloc(bs->max_size_in_dword * sizeof(unsigned int), 1);
-       bs->bit_offset = 0;
-}
-
-static void
-bitstream_end(struct bitstream *bs)
-{
-       int pos = (bs->bit_offset >> 5);
-       int bit_offset = (bs->bit_offset & 0x1f);
-       int bit_left = 32 - bit_offset;
-
-       if (bit_offset) {
-               bs->buffer[pos] = va_swap32((bs->buffer[pos] << bit_left));
-       }
-}
-
-static void
-bitstream_put_ui(struct bitstream *bs, unsigned int val, int size_in_bits)
-{
-       int pos = (bs->bit_offset >> 5);
-       int bit_offset = (bs->bit_offset & 0x1f);
-       int bit_left = 32 - bit_offset;
-
-       if (!size_in_bits)
-               return;
-
-       bs->bit_offset += size_in_bits;
-
-       if (bit_left > size_in_bits) {
-               bs->buffer[pos] = (bs->buffer[pos] << size_in_bits | val);
-               return;
-       }
-
-       size_in_bits -= bit_left;
-       bs->buffer[pos] =
-               (bs->buffer[pos] << bit_left) | (val >> size_in_bits);
-       bs->buffer[pos] = va_swap32(bs->buffer[pos]);
-
-       if (pos + 1 == bs->max_size_in_dword) {
-               bs->max_size_in_dword += BITSTREAM_ALLOCATE_STEPPING;
-               bs->buffer =
-                       realloc(bs->buffer,
-                               bs->max_size_in_dword * sizeof(unsigned int));
-       }
-
-       bs->buffer[pos + 1] = val;
-}
-
-static void
-bitstream_put_ue(struct bitstream *bs, unsigned int val)
-{
-       int size_in_bits = 0;
-       int tmp_val = ++val;
-
-       while (tmp_val) {
-               tmp_val >>= 1;
-               size_in_bits++;
-       }
-
-       bitstream_put_ui(bs, 0, size_in_bits - 1); /* leading zero */
-       bitstream_put_ui(bs, val, size_in_bits);
-}
-
-static void
-bitstream_put_se(struct bitstream *bs, int val)
-{
-       unsigned int new_val;
-
-       if (val <= 0)
-               new_val = -2 * val;
-       else
-               new_val = 2 * val - 1;
-
-       bitstream_put_ue(bs, new_val);
-}
-
-static void
-bitstream_byte_aligning(struct bitstream *bs, int bit)
-{
-       int bit_offset = (bs->bit_offset & 0x7);
-       int bit_left = 8 - bit_offset;
-       int new_val;
-
-       if (!bit_offset)
-               return;
-
-       if (bit)
-               new_val = (1 << bit_left) - 1;
-       else
-               new_val = 0;
-
-       bitstream_put_ui(bs, new_val, bit_left);
-}
-
-static VAStatus
-encoder_create_config(struct vaapi_recorder *r)
-{
-       VAConfigAttrib attrib[2];
-       VAStatus status;
-
-       /* FIXME: should check if VAEntrypointEncSlice is supported */
-
-       /* FIXME: should check if specified attributes are supported */
-
-       attrib[0].type = VAConfigAttribRTFormat;
-       attrib[0].value = VA_RT_FORMAT_YUV420;
-
-       attrib[1].type = VAConfigAttribRateControl;
-       attrib[1].value = VA_RC_CQP;
-
-       status = vaCreateConfig(r->va_dpy, VAProfileH264Main,
-                               VAEntrypointEncSlice, attrib, 2,
-                               &r->encoder.cfg);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       status = vaCreateContext(r->va_dpy, r->encoder.cfg,
-                                r->width, r->height, VA_PROGRESSIVE, 0, 0,
-                                &r->encoder.ctx);
-       if (status != VA_STATUS_SUCCESS) {
-               vaDestroyConfig(r->va_dpy, r->encoder.cfg);
-               return status;
-       }
-
-       return VA_STATUS_SUCCESS;
-}
-
-static void
-encoder_destroy_config(struct vaapi_recorder *r)
-{
-       vaDestroyContext(r->va_dpy, r->encoder.ctx);
-       vaDestroyConfig(r->va_dpy, r->encoder.cfg);
-}
-
-static void
-encoder_init_seq_parameters(struct vaapi_recorder *r)
-{
-       int width_in_mbs, height_in_mbs;
-       int frame_cropping_flag = 0;
-       int frame_crop_bottom_offset = 0;
-
-       width_in_mbs = (r->width + 15) / 16;
-       height_in_mbs = (r->height + 15) / 16;
-
-       r->encoder.param.seq.level_idc = 41;
-       r->encoder.param.seq.intra_period = r->encoder.intra_period;
-       r->encoder.param.seq.max_num_ref_frames = 4;
-       r->encoder.param.seq.picture_width_in_mbs = width_in_mbs;
-       r->encoder.param.seq.picture_height_in_mbs = height_in_mbs;
-       r->encoder.param.seq.seq_fields.bits.frame_mbs_only_flag = 1;
-
-       /* Tc = num_units_in_tick / time_scale */
-       r->encoder.param.seq.time_scale = 1800;
-       r->encoder.param.seq.num_units_in_tick = 15;
-
-       if (height_in_mbs * 16 - r->height > 0) {
-               frame_cropping_flag = 1;
-               frame_crop_bottom_offset = (height_in_mbs * 16 - r->height) / 2;
-       }
-
-       r->encoder.param.seq.frame_cropping_flag = frame_cropping_flag;
-       r->encoder.param.seq.frame_crop_bottom_offset = frame_crop_bottom_offset;
-
-       r->encoder.param.seq.seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4 = 2;
-}
-
-static VABufferID
-encoder_update_seq_parameters(struct vaapi_recorder *r)
-{
-       VABufferID seq_buf;
-       VAStatus status;
-
-       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
-                               VAEncSequenceParameterBufferType,
-                               sizeof(r->encoder.param.seq),
-                               1, &r->encoder.param.seq,
-                               &seq_buf);
-
-       if (status == VA_STATUS_SUCCESS)
-               return seq_buf;
-       else
-               return VA_INVALID_ID;
-}
-
-static void
-encoder_init_pic_parameters(struct vaapi_recorder *r)
-{
-       VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
-
-       pic->pic_init_qp = 0;
-
-       /* ENTROPY_MODE_CABAC */
-       pic->pic_fields.bits.entropy_coding_mode_flag = 1;
-
-       pic->pic_fields.bits.deblocking_filter_control_present_flag = 1;
-}
-
-static VABufferID
-encoder_update_pic_parameters(struct vaapi_recorder *r,
-                             VABufferID output_buf)
-{
-       VAEncPictureParameterBufferH264 *pic = &r->encoder.param.pic;
-       VAStatus status;
-       VABufferID pic_param_buf;
-       VASurfaceID curr_pic, pic0;
-
-       curr_pic = r->encoder.reference_picture[r->frame_count % 2];
-       pic0 = r->encoder.reference_picture[(r->frame_count + 1) % 2];
-
-       pic->CurrPic.picture_id = curr_pic;
-       pic->CurrPic.TopFieldOrderCnt = r->frame_count * 2;
-       pic->ReferenceFrames[0].picture_id = pic0;
-       pic->ReferenceFrames[1].picture_id = r->encoder.reference_picture[2];
-       pic->ReferenceFrames[2].picture_id = VA_INVALID_ID;
-
-       pic->coded_buf = output_buf;
-       pic->frame_num = r->frame_count;
-
-       pic->pic_fields.bits.idr_pic_flag = (r->frame_count == 0);
-       pic->pic_fields.bits.reference_pic_flag = 1;
-
-       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
-                               VAEncPictureParameterBufferType,
-                               sizeof(VAEncPictureParameterBufferH264), 1,
-                               pic, &pic_param_buf);
-
-       if (status == VA_STATUS_SUCCESS)
-               return pic_param_buf;
-       else
-               return VA_INVALID_ID;
-}
-
-static VABufferID
-encoder_update_slice_parameter(struct vaapi_recorder *r, int slice_type)
-{
-       VABufferID slice_param_buf;
-       VAStatus status;
-
-       int width_in_mbs = (r->width + 15) / 16;
-       int height_in_mbs = (r->height + 15) / 16;
-
-       memset(&r->encoder.param.slice, 0, sizeof r->encoder.param.slice);
-
-       r->encoder.param.slice.num_macroblocks = width_in_mbs * height_in_mbs;
-       r->encoder.param.slice.slice_type = slice_type;
-
-       r->encoder.param.slice.slice_alpha_c0_offset_div2 = 2;
-       r->encoder.param.slice.slice_beta_offset_div2 = 2;
-
-       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
-                               VAEncSliceParameterBufferType,
-                               sizeof(r->encoder.param.slice), 1,
-                               &r->encoder.param.slice,
-                               &slice_param_buf);
-
-       if (status == VA_STATUS_SUCCESS)
-               return slice_param_buf;
-       else
-               return VA_INVALID_ID;
-}
-
-static VABufferID
-encoder_update_misc_hdr_parameter(struct vaapi_recorder *r)
-{
-       VAEncMiscParameterBuffer *misc_param;
-       VAEncMiscParameterHRD *hrd;
-       VABufferID buffer;
-       VAStatus status;
-
-       int total_size =
-               sizeof(VAEncMiscParameterBuffer) +
-               sizeof(VAEncMiscParameterRateControl);
-
-       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
-                               VAEncMiscParameterBufferType, total_size,
-                               1, NULL, &buffer);
-       if (status != VA_STATUS_SUCCESS)
-               return VA_INVALID_ID;
-
-       status = vaMapBuffer(r->va_dpy, buffer, (void **) &misc_param);
-       if (status != VA_STATUS_SUCCESS) {
-               vaDestroyBuffer(r->va_dpy, buffer);
-               return VA_INVALID_ID;
-       }
-
-       misc_param->type = VAEncMiscParameterTypeHRD;
-       hrd = (VAEncMiscParameterHRD *) misc_param->data;
-
-       hrd->initial_buffer_fullness = 0;
-       hrd->buffer_size = 0;
-
-       vaUnmapBuffer(r->va_dpy, buffer);
-
-       return buffer;
-}
-
-static int
-setup_encoder(struct vaapi_recorder *r)
-{
-       VAStatus status;
-
-       status = encoder_create_config(r);
-       if (status != VA_STATUS_SUCCESS) {
-               return -1;
-       }
-
-       status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
-                                 r->width, r->height,
-                                 r->encoder.reference_picture, 3,
-                                 NULL, 0);
-       if (status != VA_STATUS_SUCCESS) {
-               encoder_destroy_config(r);
-               return -1;
-       }
-
-       /* VAProfileH264Main */
-       r->encoder.constraint_set_flag |= (1 << 1); /* Annex A.2.2 */
-
-       r->encoder.output_size = r->width * r->height;
-
-       r->encoder.intra_period = 30;
-
-       encoder_init_seq_parameters(r);
-       encoder_init_pic_parameters(r);
-
-       return 0;
-}
-
-static void
-encoder_destroy(struct vaapi_recorder *r)
-{
-       vaDestroySurfaces(r->va_dpy, r->encoder.reference_picture, 3);
-
-       encoder_destroy_config(r);
-}
-
-static void
-nal_start_code_prefix(struct bitstream *bs)
-{
-       bitstream_put_ui(bs, 0x00000001, 32);
-}
-
-static void
-nal_header(struct bitstream *bs, int nal_ref_idc, int nal_unit_type)
-{
-       /* forbidden_zero_bit: 0 */
-       bitstream_put_ui(bs, 0, 1);
-
-       bitstream_put_ui(bs, nal_ref_idc, 2);
-       bitstream_put_ui(bs, nal_unit_type, 5);
-}
-
-static void
-rbsp_trailing_bits(struct bitstream *bs)
-{
-       bitstream_put_ui(bs, 1, 1);
-       bitstream_byte_aligning(bs, 0);
-}
-
-static void sps_rbsp(struct bitstream *bs,
-                    VAEncSequenceParameterBufferH264 *seq,
-                    int constraint_set_flag)
-{
-       int i;
-
-       bitstream_put_ui(bs, PROFILE_IDC_MAIN, 8);
-
-       /* constraint_set[0-3] flag */
-       for (i = 0; i < 4; i++) {
-               int set = (constraint_set_flag & (1 << i)) ? 1 : 0;
-               bitstream_put_ui(bs, set, 1);
-       }
-
-       /* reserved_zero_4bits */
-       bitstream_put_ui(bs, 0, 4);
-       bitstream_put_ui(bs, seq->level_idc, 8);
-       bitstream_put_ue(bs, seq->seq_parameter_set_id);
-
-       bitstream_put_ue(bs, seq->seq_fields.bits.log2_max_frame_num_minus4);
-       bitstream_put_ue(bs, seq->seq_fields.bits.pic_order_cnt_type);
-       bitstream_put_ue(bs,
-                        seq->seq_fields.bits.log2_max_pic_order_cnt_lsb_minus4);
-
-       bitstream_put_ue(bs, seq->max_num_ref_frames);
-
-       /* gaps_in_frame_num_value_allowed_flag */
-       bitstream_put_ui(bs, 0, 1);
-
-       /* pic_width_in_mbs_minus1, pic_height_in_map_units_minus1 */
-       bitstream_put_ue(bs, seq->picture_width_in_mbs - 1);
-       bitstream_put_ue(bs, seq->picture_height_in_mbs - 1);
-
-       bitstream_put_ui(bs, seq->seq_fields.bits.frame_mbs_only_flag, 1);
-       bitstream_put_ui(bs, seq->seq_fields.bits.direct_8x8_inference_flag, 1);
-
-       bitstream_put_ui(bs, seq->frame_cropping_flag, 1);
-
-       if (seq->frame_cropping_flag) {
-               bitstream_put_ue(bs, seq->frame_crop_left_offset);
-               bitstream_put_ue(bs, seq->frame_crop_right_offset);
-               bitstream_put_ue(bs, seq->frame_crop_top_offset);
-               bitstream_put_ue(bs, seq->frame_crop_bottom_offset);
-       }
-
-       /* vui_parameters_present_flag */
-       bitstream_put_ui(bs, 1, 1);
-
-       /* aspect_ratio_info_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-       /* overscan_info_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-
-       /* video_signal_type_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-       /* chroma_loc_info_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-
-       /* timing_info_present_flag */
-       bitstream_put_ui(bs, 1, 1);
-       bitstream_put_ui(bs, seq->num_units_in_tick, 32);
-       bitstream_put_ui(bs, seq->time_scale, 32);
-       /* fixed_frame_rate_flag */
-       bitstream_put_ui(bs, 1, 1);
-
-       /* nal_hrd_parameters_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-
-       /* vcl_hrd_parameters_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-
-       /* low_delay_hrd_flag */
-       bitstream_put_ui(bs, 0, 1);
-
-       /* pic_struct_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-       /* bitstream_restriction_flag */
-       bitstream_put_ui(bs, 0, 1);
-
-       rbsp_trailing_bits(bs);
-}
-
-static void pps_rbsp(struct bitstream *bs,
-                    VAEncPictureParameterBufferH264 *pic)
-{
-       /* pic_parameter_set_id, seq_parameter_set_id */
-       bitstream_put_ue(bs, pic->pic_parameter_set_id);
-       bitstream_put_ue(bs, pic->seq_parameter_set_id);
-
-       bitstream_put_ui(bs, pic->pic_fields.bits.entropy_coding_mode_flag, 1);
-
-       /* pic_order_present_flag: 0 */
-       bitstream_put_ui(bs, 0, 1);
-
-       /* num_slice_groups_minus1 */
-       bitstream_put_ue(bs, 0);
-
-       bitstream_put_ue(bs, pic->num_ref_idx_l0_active_minus1);
-       bitstream_put_ue(bs, pic->num_ref_idx_l1_active_minus1);
-
-       bitstream_put_ui(bs, pic->pic_fields.bits.weighted_pred_flag, 1);
-       bitstream_put_ui(bs, pic->pic_fields.bits.weighted_bipred_idc, 2);
-
-       /* pic_init_qp_minus26, pic_init_qs_minus26, chroma_qp_index_offset */
-       bitstream_put_se(bs, pic->pic_init_qp - 26);
-       bitstream_put_se(bs, 0);
-       bitstream_put_se(bs, 0);
-
-       bitstream_put_ui(bs, pic->pic_fields.bits.deblocking_filter_control_present_flag, 1);
-
-       /* constrained_intra_pred_flag, redundant_pic_cnt_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-       bitstream_put_ui(bs, 0, 1);
-
-       bitstream_put_ui(bs, pic->pic_fields.bits.transform_8x8_mode_flag, 1);
-
-       /* pic_scaling_matrix_present_flag */
-       bitstream_put_ui(bs, 0, 1);
-       bitstream_put_se(bs, pic->second_chroma_qp_index_offset );
-
-       rbsp_trailing_bits(bs);
-}
-
-static int
-build_packed_pic_buffer(struct vaapi_recorder *r,
-                       void **header_buffer)
-{
-       struct bitstream bs;
-
-       bitstream_start(&bs);
-       nal_start_code_prefix(&bs);
-       nal_header(&bs, NAL_REF_IDC_HIGH, NAL_PPS);
-       pps_rbsp(&bs, &r->encoder.param.pic);
-       bitstream_end(&bs);
-
-       *header_buffer = bs.buffer;
-       return bs.bit_offset;
-}
-
-static int
-build_packed_seq_buffer(struct vaapi_recorder *r,
-                       void **header_buffer)
-{
-       struct bitstream bs;
-
-       bitstream_start(&bs);
-       nal_start_code_prefix(&bs);
-       nal_header(&bs, NAL_REF_IDC_HIGH, NAL_SPS);
-       sps_rbsp(&bs, &r->encoder.param.seq, r->encoder.constraint_set_flag);
-       bitstream_end(&bs);
-
-       *header_buffer = bs.buffer;
-       return bs.bit_offset;
-}
-
-static int
-create_packed_header_buffers(struct vaapi_recorder *r, VABufferID *buffers,
-                            VAEncPackedHeaderType type,
-                            void *data, int bit_length)
-{
-       VAEncPackedHeaderParameterBuffer packed_header;
-       VAStatus status;
-
-       packed_header.type = type;
-       packed_header.bit_length = bit_length;
-       packed_header.has_emulation_bytes = 0;
-
-       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
-                               VAEncPackedHeaderParameterBufferType,
-                               sizeof packed_header, 1, &packed_header,
-                               &buffers[0]);
-       if (status != VA_STATUS_SUCCESS)
-               return 0;
-
-       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
-                               VAEncPackedHeaderDataBufferType,
-                               (bit_length + 7) / 8, 1, data, &buffers[1]);
-       if (status != VA_STATUS_SUCCESS) {
-               vaDestroyBuffer(r->va_dpy, buffers[0]);
-               return 0;
-       }
-
-       return 2;
-}
-
-static int
-encoder_prepare_headers(struct vaapi_recorder *r, VABufferID *buffers)
-{
-       VABufferID *p;
-
-       int bit_length;
-       void *data;
-
-       p = buffers;
-
-       bit_length = build_packed_seq_buffer(r, &data);
-       p += create_packed_header_buffers(r, p, VAEncPackedHeaderSequence,
-                                         data, bit_length);
-       free(data);
-
-       bit_length = build_packed_pic_buffer(r, &data);
-       p += create_packed_header_buffers(r, p, VAEncPackedHeaderPicture,
-                                         data, bit_length);
-       free(data);
-
-       return p - buffers;
-}
-
-static VAStatus
-encoder_render_picture(struct vaapi_recorder *r, VASurfaceID input,
-                      VABufferID *buffers, int count)
-{
-       VAStatus status;
-
-       status = vaBeginPicture(r->va_dpy, r->encoder.ctx, input);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       status = vaRenderPicture(r->va_dpy, r->encoder.ctx, buffers, count);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       status = vaEndPicture(r->va_dpy, r->encoder.ctx);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       return vaSyncSurface(r->va_dpy, input);
-}
-
-static VABufferID
-encoder_create_output_buffer(struct vaapi_recorder *r)
-{
-       VABufferID output_buf;
-       VAStatus status;
-
-       status = vaCreateBuffer(r->va_dpy, r->encoder.ctx,
-                               VAEncCodedBufferType, r->encoder.output_size,
-                               1, NULL, &output_buf);
-       if (status == VA_STATUS_SUCCESS)
-               return output_buf;
-       else
-               return VA_INVALID_ID;
-}
-
-enum output_write_status {
-       OUTPUT_WRITE_SUCCESS,
-       OUTPUT_WRITE_OVERFLOW,
-       OUTPUT_WRITE_FATAL
-};
-
-static enum output_write_status
-encoder_write_output(struct vaapi_recorder *r, VABufferID output_buf)
-{
-       VACodedBufferSegment *segment;
-       VAStatus status;
-       int count;
-
-       status = vaMapBuffer(r->va_dpy, output_buf, (void **) &segment);
-       if (status != VA_STATUS_SUCCESS)
-               return OUTPUT_WRITE_FATAL;
-
-       if (segment->status & VA_CODED_BUF_STATUS_SLICE_OVERFLOW_MASK) {
-               r->encoder.output_size *= 2;
-               vaUnmapBuffer(r->va_dpy, output_buf);
-               return OUTPUT_WRITE_OVERFLOW;
-       }
-
-       count = write(r->output_fd, segment->buf, segment->size);
-
-       vaUnmapBuffer(r->va_dpy, output_buf);
-
-       if (count < 0)
-               return OUTPUT_WRITE_FATAL;
-
-       return OUTPUT_WRITE_SUCCESS;
-}
-
-static void
-encoder_encode(struct vaapi_recorder *r, VASurfaceID input)
-{
-       VABufferID output_buf = VA_INVALID_ID;
-
-       VABufferID buffers[8];
-       int count = 0;
-       int i, slice_type;
-       enum output_write_status ret;
-
-       if ((r->frame_count % r->encoder.intra_period) == 0)
-               slice_type = SLICE_TYPE_I;
-       else
-               slice_type = SLICE_TYPE_P;
-
-       buffers[count++] = encoder_update_seq_parameters(r);
-       buffers[count++] = encoder_update_misc_hdr_parameter(r);
-       buffers[count++] = encoder_update_slice_parameter(r, slice_type);
-
-       for (i = 0; i < count; i++)
-               if (buffers[i] == VA_INVALID_ID)
-                       goto bail;
-
-       if (r->frame_count == 0)
-               count += encoder_prepare_headers(r, buffers + count);
-
-       do {
-               output_buf = encoder_create_output_buffer(r);
-               if (output_buf == VA_INVALID_ID)
-                       goto bail;
-
-               buffers[count++] =
-                       encoder_update_pic_parameters(r, output_buf);
-               if (buffers[count - 1] == VA_INVALID_ID)
-                       goto bail;
-
-               encoder_render_picture(r, input, buffers, count);
-               ret = encoder_write_output(r, output_buf);
-
-               vaDestroyBuffer(r->va_dpy, output_buf);
-               output_buf = VA_INVALID_ID;
-
-               vaDestroyBuffer(r->va_dpy, buffers[--count]);
-       } while (ret == OUTPUT_WRITE_OVERFLOW);
-
-       if (ret == OUTPUT_WRITE_FATAL)
-               r->error = errno;
-
-       for (i = 0; i < count; i++)
-               vaDestroyBuffer(r->va_dpy, buffers[i]);
-
-       r->frame_count++;
-       return;
-
-bail:
-       for (i = 0; i < count; i++)
-               vaDestroyBuffer(r->va_dpy, buffers[i]);
-       if (output_buf != VA_INVALID_ID)
-               vaDestroyBuffer(r->va_dpy, output_buf);
-}
-
-
-static int
-setup_vpp(struct vaapi_recorder *r)
-{
-       VAStatus status;
-
-       status = vaCreateConfig(r->va_dpy, VAProfileNone,
-                               VAEntrypointVideoProc, NULL, 0,
-                               &r->vpp.cfg);
-       if (status != VA_STATUS_SUCCESS) {
-               weston_log("vaapi: failed to create VPP config\n");
-               return -1;
-       }
-
-       status = vaCreateContext(r->va_dpy, r->vpp.cfg, r->width, r->height,
-                                0, NULL, 0, &r->vpp.ctx);
-       if (status != VA_STATUS_SUCCESS) {
-               weston_log("vaapi: failed to create VPP context\n");
-               goto err_cfg;
-       }
-
-       status = vaCreateBuffer(r->va_dpy, r->vpp.ctx,
-                               VAProcPipelineParameterBufferType,
-                               sizeof(VAProcPipelineParameterBuffer),
-                               1, NULL, &r->vpp.pipeline_buf);
-       if (status != VA_STATUS_SUCCESS) {
-               weston_log("vaapi: failed to create VPP pipeline buffer\n");
-               goto err_ctx;
-       }
-
-       status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_YUV420,
-                                 r->width, r->height, &r->vpp.output, 1,
-                                 NULL, 0);
-       if (status != VA_STATUS_SUCCESS) {
-               weston_log("vaapi: failed to create YUV surface\n");
-               goto err_buf;
-       }
-
-       return 0;
-
-err_buf:
-       vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
-err_ctx:
-       vaDestroyConfig(r->va_dpy, r->vpp.ctx);
-err_cfg:
-       vaDestroyConfig(r->va_dpy, r->vpp.cfg);
-
-       return -1;
-}
-
-static void
-vpp_destroy(struct vaapi_recorder *r)
-{
-       vaDestroySurfaces(r->va_dpy, &r->vpp.output, 1);
-       vaDestroyBuffer(r->va_dpy, r->vpp.pipeline_buf);
-       vaDestroyConfig(r->va_dpy, r->vpp.ctx);
-       vaDestroyConfig(r->va_dpy, r->vpp.cfg);
-}
-
-static int
-setup_worker_thread(struct vaapi_recorder *r)
-{
-       pthread_mutex_init(&r->mutex, NULL);
-       pthread_cond_init(&r->input_cond, NULL);
-       pthread_create(&r->worker_thread, NULL, worker_thread_function, r);
-
-       return 1;
-}
-
-static void
-destroy_worker_thread(struct vaapi_recorder *r)
-{
-       pthread_mutex_lock(&r->mutex);
-
-       /* Make sure the worker thread finishes */
-       r->destroying = 1;
-       pthread_cond_signal(&r->input_cond);
-
-       pthread_mutex_unlock(&r->mutex);
-
-       pthread_join(r->worker_thread, NULL);
-
-       pthread_mutex_destroy(&r->mutex);
-       pthread_cond_destroy(&r->input_cond);
-}
-
-struct vaapi_recorder *
-vaapi_recorder_create(int drm_fd, int width, int height, const char *filename)
-{
-       struct vaapi_recorder *r;
-       VAStatus status;
-       int major, minor;
-       int flags;
-
-       r = zalloc(sizeof *r);
-       if (r == NULL)
-               return NULL;
-
-       r->width = width;
-       r->height = height;
-       r->drm_fd = drm_fd;
-
-       if (setup_worker_thread(r) < 0)
-               goto err_free;
-
-       flags = O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC;
-       r->output_fd = open(filename, flags, 0644);
-       if (r->output_fd < 0)
-               goto err_thread;
-
-       r->va_dpy = vaGetDisplayDRM(drm_fd);
-       if (!r->va_dpy) {
-               weston_log("failed to create VA display\n");
-               goto err_fd;
-       }
-
-       status = vaInitialize(r->va_dpy, &major, &minor);
-       if (status != VA_STATUS_SUCCESS) {
-               weston_log("vaapi: failed to initialize display\n");
-               goto err_fd;
-       }
-
-       if (setup_vpp(r) < 0) {
-               weston_log("vaapi: failed to initialize VPP pipeline\n");
-               goto err_va_dpy;
-       }
-
-       if (setup_encoder(r) < 0) {
-               goto err_vpp;
-       }
-
-       return r;
-
-err_vpp:
-       vpp_destroy(r);
-err_va_dpy:
-       vaTerminate(r->va_dpy);
-err_fd:
-       close(r->output_fd);
-err_thread:
-       destroy_worker_thread(r);
-err_free:
-       free(r);
-
-       return NULL;
-}
-
-void
-vaapi_recorder_destroy(struct vaapi_recorder *r)
-{
-       destroy_worker_thread(r);
-
-       encoder_destroy(r);
-       vpp_destroy(r);
-
-       vaTerminate(r->va_dpy);
-
-       close(r->output_fd);
-       close(r->drm_fd);
-
-       free(r);
-}
-
-static VAStatus
-create_surface_from_fd(struct vaapi_recorder *r, int prime_fd,
-                      int stride, VASurfaceID *surface)
-{
-       VASurfaceAttrib va_attribs[2];
-       VASurfaceAttribExternalBuffers va_attrib_extbuf;
-       VAStatus status;
-
-       unsigned long buffer_fd = prime_fd;
-
-       va_attrib_extbuf.pixel_format = VA_FOURCC_BGRX;
-       va_attrib_extbuf.width = r->width;
-       va_attrib_extbuf.height = r->height;
-       va_attrib_extbuf.data_size = r->height * stride;
-       va_attrib_extbuf.num_planes = 1;
-       va_attrib_extbuf.pitches[0] = stride;
-       va_attrib_extbuf.offsets[0] = 0;
-       va_attrib_extbuf.buffers = &buffer_fd;
-       va_attrib_extbuf.num_buffers = 1;
-       va_attrib_extbuf.flags = 0;
-       va_attrib_extbuf.private_data = NULL;
-
-       va_attribs[0].type = VASurfaceAttribMemoryType;
-       va_attribs[0].flags = VA_SURFACE_ATTRIB_SETTABLE;
-       va_attribs[0].value.type = VAGenericValueTypeInteger;
-       va_attribs[0].value.value.i = VA_SURFACE_ATTRIB_MEM_TYPE_DRM_PRIME;
-
-       va_attribs[1].type = VASurfaceAttribExternalBufferDescriptor;
-       va_attribs[1].flags = VA_SURFACE_ATTRIB_SETTABLE;
-       va_attribs[1].value.type = VAGenericValueTypePointer;
-       va_attribs[1].value.value.p = &va_attrib_extbuf;
-
-       status = vaCreateSurfaces(r->va_dpy, VA_RT_FORMAT_RGB32,
-                                 r->width, r->height, surface, 1,
-                                 va_attribs, 2);
-
-       return status;
-}
-
-static VAStatus
-convert_rgb_to_yuv(struct vaapi_recorder *r, VASurfaceID rgb_surface)
-{
-       VAProcPipelineParameterBuffer *pipeline_param;
-       VAStatus status;
-
-       status = vaMapBuffer(r->va_dpy, r->vpp.pipeline_buf,
-                            (void **) &pipeline_param);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       memset(pipeline_param, 0, sizeof *pipeline_param);
-
-       pipeline_param->surface = rgb_surface;
-       pipeline_param->surface_color_standard  = VAProcColorStandardNone;
-
-       pipeline_param->output_background_color = 0xff000000;
-       pipeline_param->output_color_standard   = VAProcColorStandardNone;
-
-       status = vaUnmapBuffer(r->va_dpy, r->vpp.pipeline_buf);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       status = vaBeginPicture(r->va_dpy, r->vpp.ctx, r->vpp.output);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       status = vaRenderPicture(r->va_dpy, r->vpp.ctx,
-                                &r->vpp.pipeline_buf, 1);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       status = vaEndPicture(r->va_dpy, r->vpp.ctx);
-       if (status != VA_STATUS_SUCCESS)
-               return status;
-
-       return status;
-}
-
-static void
-recorder_frame(struct vaapi_recorder *r)
-{
-       VASurfaceID rgb_surface;
-       VAStatus status;
-
-       status = create_surface_from_fd(r, r->input.prime_fd,
-                                       r->input.stride, &rgb_surface);
-       if (status != VA_STATUS_SUCCESS) {
-               weston_log("[libva recorder] "
-                          "failed to create surface from bo\n");
-               return;
-       }
-
-       close(r->input.prime_fd);
-
-       status = convert_rgb_to_yuv(r, rgb_surface);
-       if (status != VA_STATUS_SUCCESS) {
-               weston_log("[libva recorder] "
-                          "color space conversion failed\n");
-               return;
-       }
-
-       encoder_encode(r, r->vpp.output);
-
-       vaDestroySurfaces(r->va_dpy, &rgb_surface, 1);
-}
-
-static void *
-worker_thread_function(void *data)
-{
-       struct vaapi_recorder *r = data;
-
-       pthread_mutex_lock(&r->mutex);
-
-       while (!r->destroying) {
-               if (!r->input.valid)
-                       pthread_cond_wait(&r->input_cond, &r->mutex);
-
-               /* If the thread is awaken by destroy_worker_thread(),
-                * there might not be valid input */
-               if (!r->input.valid)
-                       continue;
-
-               recorder_frame(r);
-               r->input.valid = 0;
-       }
-
-       pthread_mutex_unlock(&r->mutex);
-
-       return NULL;
-}
-
-int
-vaapi_recorder_frame(struct vaapi_recorder *r, int prime_fd, int stride)
-{
-       int ret = 0;
-
-       pthread_mutex_lock(&r->mutex);
-
-       if (r->error) {
-               errno = r->error;
-               ret = -1;
-               goto unlock;
-       }
-
-       /* The mutex is never released while encoding, so this point should
-        * never be reached if input.valid is true. */
-       assert(!r->input.valid);
-
-       r->input.prime_fd = prime_fd;
-       r->input.stride = stride;
-       r->input.valid = 1;
-       pthread_cond_signal(&r->input_cond);
-
-unlock:
-       pthread_mutex_unlock(&r->mutex);
-
-       return ret;
-}
diff --git a/src/vaapi-recorder.h b/src/vaapi-recorder.h
deleted file mode 100644 (file)
index 6b194aa..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _VAAPI_RECORDER_H_
-#define _VAAPI_RECORDER_H_
-
-struct vaapi_recorder;
-
-struct vaapi_recorder *
-vaapi_recorder_create(int drm_fd, int width, int height, const char *filename);
-void
-vaapi_recorder_destroy(struct vaapi_recorder *r);
-int
-vaapi_recorder_frame(struct vaapi_recorder *r, int fd, int stride);
-
-#endif /* _VAAPI_RECORDER_H_ */
diff --git a/src/version.h.in b/src/version.h.in
deleted file mode 100644 (file)
index b2379d0..0000000
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright © 2013 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef WESTON_VERSION_H
-#define WESTON_VERSION_H
-
-#define WESTON_VERSION_MAJOR @WESTON_VERSION_MAJOR@
-#define WESTON_VERSION_MINOR @WESTON_VERSION_MINOR@
-#define WESTON_VERSION_MICRO @WESTON_VERSION_MICRO@
-#define WESTON_VERSION "@WESTON_VERSION@"
-
-/* This macro may not do what you expect.  Weston doesn't guarantee
- * a stable API between 1.X and 1.Y, and thus this macro will return
- * FALSE on any WESTON_VERSION_AT_LEAST(1,X,0) if the actual version
- * is 1.Y.0 and X != Y).  In particular, it fails if X < Y, that is,
- * 1.3.0 is considered to not be "at least" 1.4.0.
- *
- * If you want to test for the version number being 1.3.0 or above or
- * maybe in a range (eg 1.2.0 to 1.4.0), just use the WESTON_VERSION_*
- * defines above directly.
- */
-
-#define WESTON_VERSION_AT_LEAST(major, minor, micro) \
-        (WESTON_VERSION_MAJOR == (major) && \
-         WESTON_VERSION_MINOR == (minor) && \
-         WESTON_VERSION_MICRO >= (micro))
-
-#endif
diff --git a/src/vertex-clipping.c b/src/vertex-clipping.c
deleted file mode 100644 (file)
index a71e733..0000000
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#include <assert.h>
-#include <float.h>
-#include <math.h>
-
-#include "vertex-clipping.h"
-
-float
-float_difference(float a, float b)
-{
-       /* http://www.altdevblogaday.com/2012/02/22/comparing-floating-point-numbers-2012-edition/ */
-       static const float max_diff = 4.0f * FLT_MIN;
-       static const float max_rel_diff = 4.0e-5;
-       float diff = a - b;
-       float adiff = fabsf(diff);
-
-       if (adiff <= max_diff)
-               return 0.0f;
-
-       a = fabsf(a);
-       b = fabsf(b);
-       if (adiff <= (a > b ? a : b) * max_rel_diff)
-               return 0.0f;
-
-       return diff;
-}
-
-/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line x = x_arg.
- * Compute the y coordinate of the intersection.
- */
-static float
-clip_intersect_y(float p1x, float p1y, float p2x, float p2y,
-                float x_arg)
-{
-       float a;
-       float diff = float_difference(p1x, p2x);
-
-       /* Practically vertical line segment, yet the end points have already
-        * been determined to be on different sides of the line. Therefore
-        * the line segment is part of the line and intersects everywhere.
-        * Return the end point, so we use the whole line segment.
-        */
-       if (diff == 0.0f)
-               return p2y;
-
-       a = (x_arg - p2x) / diff;
-       return p2y + (p1y - p2y) * a;
-}
-
-/* A line segment (p1x, p1y)-(p2x, p2y) intersects the line y = y_arg.
- * Compute the x coordinate of the intersection.
- */
-static float
-clip_intersect_x(float p1x, float p1y, float p2x, float p2y,
-                float y_arg)
-{
-       float a;
-       float diff = float_difference(p1y, p2y);
-
-       /* Practically horizontal line segment, yet the end points have already
-        * been determined to be on different sides of the line. Therefore
-        * the line segment is part of the line and intersects everywhere.
-        * Return the end point, so we use the whole line segment.
-        */
-       if (diff == 0.0f)
-               return p2x;
-
-       a = (y_arg - p2y) / diff;
-       return p2x + (p1x - p2x) * a;
-}
-
-enum path_transition {
-       PATH_TRANSITION_OUT_TO_OUT = 0,
-       PATH_TRANSITION_OUT_TO_IN = 1,
-       PATH_TRANSITION_IN_TO_OUT = 2,
-       PATH_TRANSITION_IN_TO_IN = 3,
-};
-
-static void
-clip_append_vertex(struct clip_context *ctx, float x, float y)
-{
-       *ctx->vertices.x++ = x;
-       *ctx->vertices.y++ = y;
-}
-
-static enum path_transition
-path_transition_left_edge(struct clip_context *ctx, float x, float y)
-{
-       return ((ctx->prev.x >= ctx->clip.x1) << 1) | (x >= ctx->clip.x1);
-}
-
-static enum path_transition
-path_transition_right_edge(struct clip_context *ctx, float x, float y)
-{
-       return ((ctx->prev.x < ctx->clip.x2) << 1) | (x < ctx->clip.x2);
-}
-
-static enum path_transition
-path_transition_top_edge(struct clip_context *ctx, float x, float y)
-{
-       return ((ctx->prev.y >= ctx->clip.y1) << 1) | (y >= ctx->clip.y1);
-}
-
-static enum path_transition
-path_transition_bottom_edge(struct clip_context *ctx, float x, float y)
-{
-       return ((ctx->prev.y < ctx->clip.y2) << 1) | (y < ctx->clip.y2);
-}
-
-static void
-clip_polygon_leftright(struct clip_context *ctx,
-                      enum path_transition transition,
-                      float x, float y, float clip_x)
-{
-       float yi;
-
-       switch (transition) {
-       case PATH_TRANSITION_IN_TO_IN:
-               clip_append_vertex(ctx, x, y);
-               break;
-       case PATH_TRANSITION_IN_TO_OUT:
-               yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
-               clip_append_vertex(ctx, clip_x, yi);
-               break;
-       case PATH_TRANSITION_OUT_TO_IN:
-               yi = clip_intersect_y(ctx->prev.x, ctx->prev.y, x, y, clip_x);
-               clip_append_vertex(ctx, clip_x, yi);
-               clip_append_vertex(ctx, x, y);
-               break;
-       case PATH_TRANSITION_OUT_TO_OUT:
-               /* nothing */
-               break;
-       default:
-               assert(0 && "bad enum path_transition");
-       }
-
-       ctx->prev.x = x;
-       ctx->prev.y = y;
-}
-
-static void
-clip_polygon_topbottom(struct clip_context *ctx,
-                      enum path_transition transition,
-                      float x, float y, float clip_y)
-{
-       float xi;
-
-       switch (transition) {
-       case PATH_TRANSITION_IN_TO_IN:
-               clip_append_vertex(ctx, x, y);
-               break;
-       case PATH_TRANSITION_IN_TO_OUT:
-               xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
-               clip_append_vertex(ctx, xi, clip_y);
-               break;
-       case PATH_TRANSITION_OUT_TO_IN:
-               xi = clip_intersect_x(ctx->prev.x, ctx->prev.y, x, y, clip_y);
-               clip_append_vertex(ctx, xi, clip_y);
-               clip_append_vertex(ctx, x, y);
-               break;
-       case PATH_TRANSITION_OUT_TO_OUT:
-               /* nothing */
-               break;
-       default:
-               assert(0 && "bad enum path_transition");
-       }
-
-       ctx->prev.x = x;
-       ctx->prev.y = y;
-}
-
-static void
-clip_context_prepare(struct clip_context *ctx, const struct polygon8 *src,
-                     float *dst_x, float *dst_y)
-{
-       ctx->prev.x = src->x[src->n - 1];
-       ctx->prev.y = src->y[src->n - 1];
-       ctx->vertices.x = dst_x;
-       ctx->vertices.y = dst_y;
-}
-
-static int
-clip_polygon_left(struct clip_context *ctx, const struct polygon8 *src,
-                 float *dst_x, float *dst_y)
-{
-       enum path_transition trans;
-       int i;
-
-       if (src->n < 2)
-               return 0;
-
-       clip_context_prepare(ctx, src, dst_x, dst_y);
-       for (i = 0; i < src->n; i++) {
-               trans = path_transition_left_edge(ctx, src->x[i], src->y[i]);
-               clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
-                                      ctx->clip.x1);
-       }
-       return ctx->vertices.x - dst_x;
-}
-
-static int
-clip_polygon_right(struct clip_context *ctx, const struct polygon8 *src,
-                  float *dst_x, float *dst_y)
-{
-       enum path_transition trans;
-       int i;
-
-       if (src->n < 2)
-               return 0;
-
-       clip_context_prepare(ctx, src, dst_x, dst_y);
-       for (i = 0; i < src->n; i++) {
-               trans = path_transition_right_edge(ctx, src->x[i], src->y[i]);
-               clip_polygon_leftright(ctx, trans, src->x[i], src->y[i],
-                                      ctx->clip.x2);
-       }
-       return ctx->vertices.x - dst_x;
-}
-
-static int
-clip_polygon_top(struct clip_context *ctx, const struct polygon8 *src,
-                float *dst_x, float *dst_y)
-{
-       enum path_transition trans;
-       int i;
-
-       if (src->n < 2)
-               return 0;
-
-       clip_context_prepare(ctx, src, dst_x, dst_y);
-       for (i = 0; i < src->n; i++) {
-               trans = path_transition_top_edge(ctx, src->x[i], src->y[i]);
-               clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
-                                      ctx->clip.y1);
-       }
-       return ctx->vertices.x - dst_x;
-}
-
-static int
-clip_polygon_bottom(struct clip_context *ctx, const struct polygon8 *src,
-                   float *dst_x, float *dst_y)
-{
-       enum path_transition trans;
-       int i;
-
-       if (src->n < 2)
-               return 0;
-
-       clip_context_prepare(ctx, src, dst_x, dst_y);
-       for (i = 0; i < src->n; i++) {
-               trans = path_transition_bottom_edge(ctx, src->x[i], src->y[i]);
-               clip_polygon_topbottom(ctx, trans, src->x[i], src->y[i],
-                                      ctx->clip.y2);
-       }
-       return ctx->vertices.x - dst_x;
-}
-
-#define max(a, b) (((a) > (b)) ? (a) : (b))
-#define min(a, b) (((a) > (b)) ? (b) : (a))
-#define clip(x, a, b)  min(max(x, a), b)
-
-int
-clip_simple(struct clip_context *ctx,
-           struct polygon8 *surf,
-           float *ex,
-           float *ey)
-{
-       int i;
-       for (i = 0; i < surf->n; i++) {
-               ex[i] = clip(surf->x[i], ctx->clip.x1, ctx->clip.x2);
-               ey[i] = clip(surf->y[i], ctx->clip.y1, ctx->clip.y2);
-       }
-       return surf->n;
-}
-
-int
-clip_transformed(struct clip_context *ctx,
-                struct polygon8 *surf,
-                float *ex,
-                float *ey)
-{
-       struct polygon8 polygon;
-       int i, n;
-
-       polygon.n = clip_polygon_left(ctx, surf, polygon.x, polygon.y);
-       surf->n = clip_polygon_right(ctx, &polygon, surf->x, surf->y);
-       polygon.n = clip_polygon_top(ctx, surf, polygon.x, polygon.y);
-       surf->n = clip_polygon_bottom(ctx, &polygon, surf->x, surf->y);
-
-       /* Get rid of duplicate vertices */
-       ex[0] = surf->x[0];
-       ey[0] = surf->y[0];
-       n = 1;
-       for (i = 1; i < surf->n; i++) {
-               if (float_difference(ex[n - 1], surf->x[i]) == 0.0f &&
-                   float_difference(ey[n - 1], surf->y[i]) == 0.0f)
-                       continue;
-               ex[n] = surf->x[i];
-               ey[n] = surf->y[i];
-               n++;
-       }
-       if (float_difference(ex[n - 1], surf->x[0]) == 0.0f &&
-           float_difference(ey[n - 1], surf->y[0]) == 0.0f)
-               n--;
-
-       return n;
-}
diff --git a/src/vertex-clipping.h b/src/vertex-clipping.h
deleted file mode 100644 (file)
index 0c69902..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- * Copyright © 2012 Intel Corporation
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-#ifndef _WESTON_VERTEX_CLIPPING_H
-#define _WESTON_VERTEX_CLIPPING_H
-
-struct polygon8 {
-       float x[8];
-       float y[8];
-       int n;
-};
-
-struct clip_context {
-       struct {
-               float x;
-               float y;
-       } prev;
-
-       struct {
-               float x1, y1;
-               float x2, y2;
-       } clip;
-
-       struct {
-               float *x;
-               float *y;
-       } vertices;
-};
-
-float
-float_difference(float a, float b);
-
-int
-clip_simple(struct clip_context *ctx,
-           struct polygon8 *surf,
-           float *ex,
-           float *ey);
-
-int
-clip_transformed(struct clip_context *ctx,
-                struct polygon8 *surf,
-                float *ex,
-                float *ey);\
-
-#endif
diff --git a/src/weston-egl-ext.h b/src/weston-egl-ext.h
deleted file mode 100644 (file)
index 32f6108..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
- * All Rights Reserved.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-/* Extensions used by Weston, copied from Mesa's eglmesaext.h, */
-
-#ifndef WESTON_EGL_EXT_H
-#define WESTON_EGL_EXT_H
-
-#ifndef EGL_WL_bind_wayland_display
-#define EGL_WL_bind_wayland_display 1
-
-struct wl_display;
-
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
-EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL(EGLDisplay dpy, struct wl_display *display);
-#endif
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWL) (EGLDisplay dpy, struct wl_display *display);
-#endif
-
-/*
- * This is a little different to the tests shipped with EGL implementations,
- * which wrap the entire thing in #ifndef EGL_WL_bind_wayland_display, then go
- * on to define both BindWaylandDisplay and QueryWaylandBuffer.
- *
- * Unfortunately, some implementations (particularly the version of Mesa shipped
- * in Ubuntu 12.04) define EGL_WL_bind_wayland_display, but then only provide
- * prototypes for (Un)BindWaylandDisplay, completely omitting
- * QueryWaylandBuffer.
- *
- * Detect this, and provide our own definitions if necessary.
- */
-#ifndef EGL_WAYLAND_BUFFER_WL
-#define EGL_WAYLAND_BUFFER_WL          0x31D5 /* eglCreateImageKHR target */
-#define EGL_WAYLAND_PLANE_WL           0x31D6 /* eglCreateImageKHR target */
-
-#define EGL_TEXTURE_Y_U_V_WL            0x31D7
-#define EGL_TEXTURE_Y_UV_WL             0x31D8
-#define EGL_TEXTURE_Y_XUXV_WL           0x31D9
-#define EGL_TEXTURE_EXTERNAL_WL         0x31DA
-
-struct wl_resource;
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL(EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
-#endif
-typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWL) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
-#endif
-
-#ifndef EGL_WL_create_wayland_buffer_from_image
-#define EGL_WL_create_wayland_buffer_from_image 1
-
-#ifdef EGL_EGLEXT_PROTOTYPES
-EGLAPI struct wl_buffer * EGLAPIENTRY eglCreateWaylandBufferFromImageWL(EGLDisplay dpy, EGLImageKHR image);
-#endif
-typedef struct wl_buffer * (EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL) (EGLDisplay dpy, EGLImageKHR image);
-#endif
-
-#ifndef EGL_TEXTURE_EXTERNAL_WL
-#define EGL_TEXTURE_EXTERNAL_WL         0x31DA
-#endif
-
-#ifndef EGL_BUFFER_AGE_EXT
-#define EGL_BUFFER_AGE_EXT              0x313D
-#endif
-
-#ifndef EGL_WAYLAND_Y_INVERTED_WL
-#define EGL_WAYLAND_Y_INVERTED_WL              0x31DB /* eglQueryWaylandBufferWL attribute */
-#endif
-
-/* Mesas gl2ext.h and probably Khronos upstream defined
- * GL_EXT_unpack_subimage with non _EXT suffixed GL_UNPACK_* tokens.
- * In case we're using that mess, manually define the _EXT versions
- * of the tokens here.*/
-#if defined(GL_EXT_unpack_subimage) && !defined(GL_UNPACK_ROW_LENGTH_EXT)
-#define GL_UNPACK_ROW_LENGTH_EXT                                0x0CF2
-#define GL_UNPACK_SKIP_ROWS_EXT                                 0x0CF3
-#define GL_UNPACK_SKIP_PIXELS_EXT                               0x0CF4
-#endif
-
-/* Define needed tokens from EGL_EXT_image_dma_buf_import extension
- * here to avoid having to add ifdefs everywhere.*/
-#ifndef EGL_EXT_image_dma_buf_import
-#define EGL_LINUX_DMA_BUF_EXT                                  0x3270
-#define EGL_LINUX_DRM_FOURCC_EXT                               0x3271
-#define EGL_DMA_BUF_PLANE0_FD_EXT                              0x3272
-#define EGL_DMA_BUF_PLANE0_OFFSET_EXT                          0x3273
-#define EGL_DMA_BUF_PLANE0_PITCH_EXT                           0x3274
-#define EGL_DMA_BUF_PLANE1_FD_EXT                              0x3275
-#define EGL_DMA_BUF_PLANE1_OFFSET_EXT                          0x3276
-#define EGL_DMA_BUF_PLANE1_PITCH_EXT                           0x3277
-#define EGL_DMA_BUF_PLANE2_FD_EXT                              0x3278
-#define EGL_DMA_BUF_PLANE2_OFFSET_EXT                          0x3279
-#define EGL_DMA_BUF_PLANE2_PITCH_EXT                           0x327A
-#endif
-
-
-#endif
diff --git a/src/weston-launch.c b/src/weston-launch.c
deleted file mode 100644 (file)
index 9987d8e..0000000
+++ /dev/null
@@ -1,772 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include <poll.h>
-#include <errno.h>
-
-#include <error.h>
-#include <getopt.h>
-
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/socket.h>
-#include <sys/signalfd.h>
-#include <signal.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#include <linux/vt.h>
-#include <linux/major.h>
-#include <linux/kd.h>
-
-#include <pwd.h>
-#include <grp.h>
-#include <security/pam_appl.h>
-
-#ifdef HAVE_SYSTEMD_LOGIN
-#include <systemd/sd-login.h>
-#endif
-
-#include "weston-launch.h"
-
-#define DRM_MAJOR 226
-
-#ifndef KDSKBMUTE
-#define KDSKBMUTE      0x4B51
-#endif
-
-#ifndef EVIOCREVOKE
-#define EVIOCREVOKE _IOW('E', 0x91, int)
-#endif
-
-#define MAX_ARGV_SIZE 256
-
-#ifdef HAVE_LIBDRM
-
-#include <xf86drm.h>
-
-#else
-
-static inline int
-drmDropMaster(int drm_fd)
-{
-       return 0;
-}
-
-static inline int
-drmSetMaster(int drm_fd)
-{
-       return 0;
-}
-
-#endif
-
-struct weston_launch {
-       struct pam_conv pc;
-       pam_handle_t *ph;
-       int tty;
-       int ttynr;
-       int sock[2];
-       int drm_fd;
-       int last_input_fd;
-       int kb_mode;
-       struct passwd *pw;
-
-       int signalfd;
-
-       pid_t child;
-       int verbose;
-       char *new_user;
-};
-
-union cmsg_data { unsigned char b[4]; int fd; };
-
-static gid_t *
-read_groups(void)
-{
-       int n;
-       gid_t *groups;
-
-       n = getgroups(0, NULL);
-
-       if (n < 0) {
-               fprintf(stderr, "Unable to retrieve groups: %m\n");
-               return NULL;
-       }
-
-       groups = malloc(n * sizeof(gid_t));
-       if (!groups)
-               return NULL;
-
-       if (getgroups(n, groups) < 0) {
-               fprintf(stderr, "Unable to retrieve groups: %m\n");
-               free(groups);
-               return NULL;
-       }
-       return groups;
-}
-
-static bool
-weston_launch_allowed(struct weston_launch *wl)
-{
-       struct group *gr;
-       gid_t *groups;
-       int i;
-#ifdef HAVE_SYSTEMD_LOGIN
-       char *session, *seat;
-       int err;
-#endif
-
-       if (getuid() == 0)
-               return true;
-
-       gr = getgrnam("weston-launch");
-       if (gr) {
-               groups = read_groups();
-               if (groups) {
-                       for (i = 0; groups[i]; ++i) {
-                               if (groups[i] == gr->gr_gid) {
-                                       free(groups);
-                                       return true;
-                               }
-                       }
-                       free(groups);
-               }
-       }
-
-#ifdef HAVE_SYSTEMD_LOGIN
-       err = sd_pid_get_session(getpid(), &session);
-       if (err == 0 && session) {
-               if (sd_session_is_active(session) &&
-                   sd_session_get_seat(session, &seat) == 0) {
-                       free(seat);
-                       free(session);
-                       return true;
-               }
-               free(session);
-       }
-#endif
-
-       return false;
-}
-
-static int
-pam_conversation_fn(int msg_count,
-                   const struct pam_message **messages,
-                   struct pam_response **responses,
-                   void *user_data)
-{
-       return PAM_SUCCESS;
-}
-
-static int
-setup_pam(struct weston_launch *wl)
-{
-       int err;
-
-       wl->pc.conv = pam_conversation_fn;
-       wl->pc.appdata_ptr = wl;
-
-       err = pam_start("login", wl->pw->pw_name, &wl->pc, &wl->ph);
-       if (err != PAM_SUCCESS) {
-               fprintf(stderr, "failed to start pam transaction: %d: %s\n",
-                       err, pam_strerror(wl->ph, err));
-               return -1;
-       }
-
-       err = pam_set_item(wl->ph, PAM_TTY, ttyname(wl->tty));
-       if (err != PAM_SUCCESS) {
-               fprintf(stderr, "failed to set PAM_TTY item: %d: %s\n",
-                       err, pam_strerror(wl->ph, err));
-               return -1;
-       }
-
-       err = pam_open_session(wl->ph, 0);
-       if (err != PAM_SUCCESS) {
-               fprintf(stderr, "failed to open pam session: %d: %s\n",
-                       err, pam_strerror(wl->ph, err));
-               return -1;
-       }
-
-       return 0;
-}
-
-static int
-setup_launcher_socket(struct weston_launch *wl)
-{
-       if (socketpair(AF_LOCAL, SOCK_SEQPACKET, 0, wl->sock) < 0)
-               error(1, errno, "socketpair failed");
-
-       if (fcntl(wl->sock[0], F_SETFD, FD_CLOEXEC) < 0)
-               error(1, errno, "fcntl failed");
-
-       return 0;
-}
-
-static int
-setup_signals(struct weston_launch *wl)
-{
-       int ret;
-       sigset_t mask;
-       struct sigaction sa;
-
-       memset(&sa, 0, sizeof sa);
-       sa.sa_handler = SIG_DFL;
-       sa.sa_flags = SA_NOCLDSTOP | SA_RESTART;
-       ret = sigaction(SIGCHLD, &sa, NULL);
-       assert(ret == 0);
-
-       sa.sa_handler = SIG_IGN;
-       sa.sa_flags = 0;
-       sigaction(SIGHUP, &sa, NULL);
-
-       ret = sigemptyset(&mask);
-       assert(ret == 0);
-       sigaddset(&mask, SIGCHLD);
-       sigaddset(&mask, SIGINT);
-       sigaddset(&mask, SIGTERM);
-       sigaddset(&mask, SIGUSR1);
-       sigaddset(&mask, SIGUSR2);
-       ret = sigprocmask(SIG_BLOCK, &mask, NULL);
-       assert(ret == 0);
-
-       wl->signalfd = signalfd(-1, &mask, SFD_NONBLOCK | SFD_CLOEXEC);
-       if (wl->signalfd < 0)
-               return -errno;
-
-       return 0;
-}
-
-static void
-setenv_fd(const char *env, int fd)
-{
-       char buf[32];
-
-       snprintf(buf, sizeof buf, "%d", fd);
-       setenv(env, buf, 1);
-}
-
-static int
-send_reply(struct weston_launch *wl, int reply)
-{
-       int len;
-
-       do {
-               len = send(wl->sock[0], &reply, sizeof reply, 0);
-       } while (len < 0 && errno == EINTR);
-
-       return len;
-}
-
-static int
-handle_open(struct weston_launch *wl, struct msghdr *msg, ssize_t len)
-{
-       int fd = -1, ret = -1;
-       char control[CMSG_SPACE(sizeof(fd))];
-       struct cmsghdr *cmsg;
-       struct stat s;
-       struct msghdr nmsg;
-       struct iovec iov;
-       struct weston_launcher_open *message;
-       union cmsg_data *data;
-
-       message = msg->msg_iov->iov_base;
-       if ((size_t)len < sizeof(*message))
-               goto err0;
-
-       /* Ensure path is null-terminated */
-       ((char *) message)[len-1] = '\0';
-
-       fd = open(message->path, message->flags);
-       if (fd < 0) {
-               fprintf(stderr, "Error opening device %s: %m\n",
-                       message->path);
-               goto err0;
-       }
-
-       if (fstat(fd, &s) < 0) {
-               close(fd);
-               fd = -1;
-               fprintf(stderr, "Failed to stat %s\n", message->path);
-               goto err0;
-       }
-
-       if (major(s.st_rdev) != INPUT_MAJOR &&
-           major(s.st_rdev) != DRM_MAJOR) {
-               close(fd);
-               fd = -1;
-               fprintf(stderr, "Device %s is not an input or drm device\n",
-                       message->path);
-               goto err0;
-       }
-
-err0:
-       memset(&nmsg, 0, sizeof nmsg);
-       nmsg.msg_iov = &iov;
-       nmsg.msg_iovlen = 1;
-       if (fd != -1) {
-               nmsg.msg_control = control;
-               nmsg.msg_controllen = sizeof control;
-               cmsg = CMSG_FIRSTHDR(&nmsg);
-               cmsg->cmsg_level = SOL_SOCKET;
-               cmsg->cmsg_type = SCM_RIGHTS;
-               cmsg->cmsg_len = CMSG_LEN(sizeof(fd));
-               data = (union cmsg_data *) CMSG_DATA(cmsg);
-               data->fd = fd;
-               nmsg.msg_controllen = cmsg->cmsg_len;
-               ret = 0;
-       }
-       iov.iov_base = &ret;
-       iov.iov_len = sizeof ret;
-
-       if (wl->verbose)
-               fprintf(stderr, "weston-launch: opened %s: ret: %d, fd: %d\n",
-                       message->path, ret, fd);
-       do {
-               len = sendmsg(wl->sock[0], &nmsg, 0);
-       } while (len < 0 && errno == EINTR);
-
-       if (len < 0)
-               return -1;
-
-       if (fd != -1 && major(s.st_rdev) == DRM_MAJOR)
-               wl->drm_fd = fd;
-       if (fd != -1 && major(s.st_rdev) == INPUT_MAJOR &&
-           wl->last_input_fd < fd)
-               wl->last_input_fd = fd;
-
-       return 0;
-}
-
-static int
-handle_socket_msg(struct weston_launch *wl)
-{
-       char control[CMSG_SPACE(sizeof(int))];
-       char buf[BUFSIZ];
-       struct msghdr msg;
-       struct iovec iov;
-       int ret = -1;
-       ssize_t len;
-       struct weston_launcher_message *message;
-
-       memset(&msg, 0, sizeof(msg));
-       iov.iov_base = buf;
-       iov.iov_len  = sizeof buf;
-       msg.msg_iov = &iov;
-       msg.msg_iovlen = 1;
-       msg.msg_control = control;
-       msg.msg_controllen = sizeof control;
-
-       do {
-               len = recvmsg(wl->sock[0], &msg, 0);
-       } while (len < 0 && errno == EINTR);
-
-       if (len < 1)
-               return -1;
-
-       message = (void *) buf;
-       switch (message->opcode) {
-       case WESTON_LAUNCHER_OPEN:
-               ret = handle_open(wl, &msg, len);
-               break;
-       }
-
-       return ret;
-}
-
-static void
-quit(struct weston_launch *wl, int status)
-{
-       struct vt_mode mode = { 0 };
-       int err;
-
-       close(wl->signalfd);
-       close(wl->sock[0]);
-
-       if (wl->new_user) {
-               err = pam_close_session(wl->ph, 0);
-               if (err)
-                       fprintf(stderr, "pam_close_session failed: %d: %s\n",
-                               err, pam_strerror(wl->ph, err));
-               pam_end(wl->ph, err);
-       }
-
-       if (ioctl(wl->tty, KDSKBMUTE, 0) &&
-           ioctl(wl->tty, KDSKBMODE, wl->kb_mode))
-               fprintf(stderr, "failed to restore keyboard mode: %m\n");
-
-       if (ioctl(wl->tty, KDSETMODE, KD_TEXT))
-               fprintf(stderr, "failed to set KD_TEXT mode on tty: %m\n");
-
-       /* We have to drop master before we switch the VT back in
-        * VT_AUTO, so we don't risk switching to a VT with another
-        * display server, that will then fail to set drm master. */
-       drmDropMaster(wl->drm_fd);
-
-       mode.mode = VT_AUTO;
-       if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
-               fprintf(stderr, "could not reset vt handling\n");
-
-       exit(status);
-}
-
-static void
-close_input_fds(struct weston_launch *wl)
-{
-       struct stat s;
-       int fd;
-
-       for (fd = 3; fd <= wl->last_input_fd; fd++) {
-               if (fstat(fd, &s) == 0 && major(s.st_rdev) == INPUT_MAJOR) {
-                       /* EVIOCREVOKE may fail if the kernel doesn't
-                        * support it, but all we can do is ignore it. */
-                       ioctl(fd, EVIOCREVOKE, 0);
-                       close(fd);
-               }
-       }
-}
-
-static int
-handle_signal(struct weston_launch *wl)
-{
-       struct signalfd_siginfo sig;
-       int pid, status, ret;
-
-       if (read(wl->signalfd, &sig, sizeof sig) != sizeof sig) {
-               error(0, errno, "reading signalfd failed");
-               return -1;
-       }
-
-       switch (sig.ssi_signo) {
-       case SIGCHLD:
-               pid = waitpid(-1, &status, 0);
-               if (pid == wl->child) {
-                       wl->child = 0;
-                       if (WIFEXITED(status))
-                               ret = WEXITSTATUS(status);
-                       else if (WIFSIGNALED(status))
-                               /*
-                                * If weston dies because of signal N, we
-                                * return 10+N. This is distinct from
-                                * weston-launch dying because of a signal
-                                * (128+N).
-                                */
-                               ret = 10 + WTERMSIG(status);
-                       else
-                               ret = 0;
-                       quit(wl, ret);
-               }
-               break;
-       case SIGTERM:
-       case SIGINT:
-               if (wl->child)
-                       kill(wl->child, sig.ssi_signo);
-               break;
-       case SIGUSR1:
-               send_reply(wl, WESTON_LAUNCHER_DEACTIVATE);
-               close_input_fds(wl);
-               drmDropMaster(wl->drm_fd);
-               ioctl(wl->tty, VT_RELDISP, 1);
-               break;
-       case SIGUSR2:
-               ioctl(wl->tty, VT_RELDISP, VT_ACKACQ);
-               drmSetMaster(wl->drm_fd);
-               send_reply(wl, WESTON_LAUNCHER_ACTIVATE);
-               break;
-       default:
-               return -1;
-       }
-
-       return 0;
-}
-
-static int
-setup_tty(struct weston_launch *wl, const char *tty)
-{
-       struct stat buf;
-       struct vt_mode mode = { 0 };
-       char *t;
-
-       if (!wl->new_user) {
-               wl->tty = STDIN_FILENO;
-       } else if (tty) {
-               t = ttyname(STDIN_FILENO);
-               if (t && strcmp(t, tty) == 0)
-                       wl->tty = STDIN_FILENO;
-               else
-                       wl->tty = open(tty, O_RDWR | O_NOCTTY);
-       } else {
-               int tty0 = open("/dev/tty0", O_WRONLY | O_CLOEXEC);
-               char filename[16];
-
-               if (tty0 < 0)
-                       error(1, errno, "could not open tty0");
-
-               if (ioctl(tty0, VT_OPENQRY, &wl->ttynr) < 0 || wl->ttynr == -1)
-                       error(1, errno, "failed to find non-opened console");
-
-               snprintf(filename, sizeof filename, "/dev/tty%d", wl->ttynr);
-               wl->tty = open(filename, O_RDWR | O_NOCTTY);
-               close(tty0);
-       }
-
-       if (wl->tty < 0)
-               error(1, errno, "failed to open tty");
-
-       if (fstat(wl->tty, &buf) == -1 ||
-           major(buf.st_rdev) != TTY_MAJOR || minor(buf.st_rdev) == 0)
-               error(1, 0, "weston-launch must be run from a virtual terminal");
-
-       if (tty) {
-               if (fstat(wl->tty, &buf) < 0)
-                       error(1, errno, "stat %s failed", tty);
-
-               if (major(buf.st_rdev) != TTY_MAJOR)
-                       error(1, 0, "invalid tty device: %s", tty);
-
-               wl->ttynr = minor(buf.st_rdev);
-       }
-
-       if (ioctl(wl->tty, KDGKBMODE, &wl->kb_mode))
-               error(1, errno, "failed to get current keyboard mode: %m\n");
-
-       if (ioctl(wl->tty, KDSKBMUTE, 1) &&
-           ioctl(wl->tty, KDSKBMODE, K_OFF))
-               error(1, errno, "failed to set K_OFF keyboard mode: %m\n");
-
-       if (ioctl(wl->tty, KDSETMODE, KD_GRAPHICS))
-               error(1, errno, "failed to set KD_GRAPHICS mode on tty: %m\n");
-
-       mode.mode = VT_PROCESS;
-       mode.relsig = SIGUSR1;
-       mode.acqsig = SIGUSR2;
-       if (ioctl(wl->tty, VT_SETMODE, &mode) < 0)
-               error(1, errno, "failed to take control of vt handling\n");
-
-       return 0;
-}
-
-static void
-setup_session(struct weston_launch *wl)
-{
-       char **env;
-       char *term;
-       int i;
-
-       if (wl->tty != STDIN_FILENO) {
-               if (setsid() < 0)
-                       error(1, errno, "setsid failed");
-               if (ioctl(wl->tty, TIOCSCTTY, 0) < 0)
-                       error(1, errno, "TIOCSCTTY failed - tty is in use");
-       }
-
-       term = getenv("TERM");
-       clearenv();
-       if (term)
-               setenv("TERM", term, 1);
-       setenv("USER", wl->pw->pw_name, 1);
-       setenv("LOGNAME", wl->pw->pw_name, 1);
-       setenv("HOME", wl->pw->pw_dir, 1);
-       setenv("SHELL", wl->pw->pw_shell, 1);
-
-       env = pam_getenvlist(wl->ph);
-       if (env) {
-               for (i = 0; env[i]; ++i) {
-                       if (putenv(env[i]) != 0)
-                               error(0, 0, "putenv %s failed", env[i]);
-               }
-               free(env);
-       }
-}
-
-static void
-drop_privileges(struct weston_launch *wl)
-{
-       if (setgid(wl->pw->pw_gid) < 0 ||
-#ifdef HAVE_INITGROUPS
-           initgroups(wl->pw->pw_name, wl->pw->pw_gid) < 0 ||
-#endif
-           setuid(wl->pw->pw_uid) < 0)
-               error(1, errno, "dropping privileges failed");
-}
-
-static void
-launch_compositor(struct weston_launch *wl, int argc, char *argv[])
-{
-       char *child_argv[MAX_ARGV_SIZE];
-       sigset_t mask;
-       int i;
-
-       if (wl->verbose)
-               printf("weston-launch: spawned weston with pid: %d\n", getpid());
-       if (wl->new_user)
-               setup_session(wl);
-
-       if (geteuid() == 0)
-               drop_privileges(wl);
-
-       setenv_fd("WESTON_TTY_FD", wl->tty);
-       setenv_fd("WESTON_LAUNCHER_SOCK", wl->sock[1]);
-
-       unsetenv("DISPLAY");
-
-       /* Do not give our signal mask to the new process. */
-       sigemptyset(&mask);
-       sigaddset(&mask, SIGTERM);
-       sigaddset(&mask, SIGCHLD);
-       sigaddset(&mask, SIGINT);
-       sigprocmask(SIG_UNBLOCK, &mask, NULL);
-
-       child_argv[0] = "/bin/sh";
-       child_argv[1] = "-l";
-       child_argv[2] = "-c";
-       child_argv[3] = BINDIR "/weston \"$@\"";
-       child_argv[4] = "weston";
-       for (i = 0; i < argc; ++i)
-               child_argv[5 + i] = argv[i];
-       child_argv[5 + i] = NULL;
-
-       execv(child_argv[0], child_argv);
-       error(1, errno, "exec failed");
-}
-
-static void
-help(const char *name)
-{
-       fprintf(stderr, "Usage: %s [args...] [-- [weston args..]]\n", name);
-       fprintf(stderr, "  -u, --user      Start session as specified username\n");
-       fprintf(stderr, "  -t, --tty       Start session on alternative tty\n");
-       fprintf(stderr, "  -v, --verbose   Be verbose\n");
-       fprintf(stderr, "  -h, --help      Display this help message\n");
-}
-
-int
-main(int argc, char *argv[])
-{
-       struct weston_launch wl;
-       int i, c;
-       char *tty = NULL;
-       struct option opts[] = {
-               { "user",    required_argument, NULL, 'u' },
-               { "tty",     required_argument, NULL, 't' },
-               { "verbose", no_argument,       NULL, 'v' },
-               { "help",    no_argument,       NULL, 'h' },
-               { 0,         0,                 NULL,  0  }
-       };
-
-       memset(&wl, 0, sizeof wl);
-
-       while ((c = getopt_long(argc, argv, "u:t::vh", opts, &i)) != -1) {
-               switch (c) {
-               case 'u':
-                       wl.new_user = optarg;
-                       if (getuid() != 0)
-                               error(1, 0, "Permission denied. -u allowed for root only");
-                       break;
-               case 't':
-                       tty = optarg;
-                       break;
-               case 'v':
-                       wl.verbose = 1;
-                       break;
-               case 'h':
-                       help("weston-launch");
-                       exit(EXIT_FAILURE);
-               default:
-                       exit(EXIT_FAILURE);
-               }
-       }
-
-       if ((argc - optind) > (MAX_ARGV_SIZE - 6))
-               error(1, E2BIG, "Too many arguments to pass to weston");
-
-       if (wl.new_user)
-               wl.pw = getpwnam(wl.new_user);
-       else
-               wl.pw = getpwuid(getuid());
-       if (wl.pw == NULL)
-               error(1, errno, "failed to get username");
-
-       if (!weston_launch_allowed(&wl))
-               error(1, 0, "Permission denied. You should either:\n"
-#ifdef HAVE_SYSTEMD_LOGIN
-                     " - run from an active and local (systemd) session.\n"
-#else
-                     " - enable systemd session support for weston-launch.\n"
-#endif
-                     " - or add yourself to the 'weston-launch' group.");
-
-       if (setup_tty(&wl, tty) < 0)
-               exit(EXIT_FAILURE);
-
-       if (wl.new_user && setup_pam(&wl) < 0)
-               exit(EXIT_FAILURE);
-
-       if (setup_launcher_socket(&wl) < 0)
-               exit(EXIT_FAILURE);
-
-       if (setup_signals(&wl) < 0)
-               exit(EXIT_FAILURE);
-
-       wl.child = fork();
-       if (wl.child == -1)
-               error(EXIT_FAILURE, errno, "fork failed");
-
-       if (wl.child == 0)
-               launch_compositor(&wl, argc - optind, argv + optind);
-
-       close(wl.sock[1]);
-       if (wl.tty != STDIN_FILENO)
-               close(wl.tty);
-
-       while (1) {
-               struct pollfd fds[2];
-               int n;
-
-               fds[0].fd = wl.sock[0];
-               fds[0].events = POLLIN;
-               fds[1].fd = wl.signalfd;
-               fds[1].events = POLLIN;
-
-               n = poll(fds, 2, -1);
-               if (n < 0)
-                       error(0, errno, "poll failed");
-               if (fds[0].revents & POLLIN)
-                       handle_socket_msg(&wl);
-               if (fds[1].revents)
-                       handle_signal(&wl);
-       }
-
-       return 0;
-}
diff --git a/src/weston-launch.h b/src/weston-launch.h
deleted file mode 100644 (file)
index bd974de..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Copyright © 2012 Benjamin Franzke
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#ifndef _WESTON_LAUNCH_H_
-#define _WESTON_LAUNCH_H_
-
-enum weston_launcher_opcode {
-       WESTON_LAUNCHER_OPEN,
-};
-
-enum weston_launcher_event {
-       WESTON_LAUNCHER_SUCCESS,
-       WESTON_LAUNCHER_ACTIVATE,
-       WESTON_LAUNCHER_DEACTIVATE
-};
-
-struct weston_launcher_message {
-       int opcode;
-};
-
-struct weston_launcher_open {
-       struct weston_launcher_message header;
-       int flags;
-       char path[0];
-};
-
-#endif
diff --git a/src/zoom.c b/src/zoom.c
deleted file mode 100644 (file)
index 08c0693..0000000
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright © 2012 Scott Moreau
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice (including the
- * next paragraph) shall be included in all copies or substantial
- * portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
- * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
- * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-#include "config.h"
-
-#include <assert.h>
-#include <stdlib.h>
-#include <stdbool.h>
-
-#include "compositor.h"
-#include "text-cursor-position-server-protocol.h"
-#include "shared/helpers.h"
-
-static void
-weston_zoom_frame_z(struct weston_animation *animation,
-               struct weston_output *output, uint32_t msecs)
-{
-       if (animation->frame_counter <= 1)
-               output->zoom.spring_z.timestamp = msecs;
-
-       weston_spring_update(&output->zoom.spring_z, msecs);
-
-       if (output->zoom.spring_z.current > output->zoom.max_level)
-               output->zoom.spring_z.current = output->zoom.max_level;
-       else if (output->zoom.spring_z.current < 0.0)
-               output->zoom.spring_z.current = 0.0;
-
-       if (weston_spring_done(&output->zoom.spring_z)) {
-               if (output->zoom.active && output->zoom.level <= 0.0) {
-                       output->zoom.active = false;
-                       output->zoom.seat = NULL;
-                       output->disable_planes--;
-                       wl_list_remove(&output->zoom.motion_listener.link);
-               }
-               output->zoom.spring_z.current = output->zoom.level;
-               wl_list_remove(&animation->link);
-               wl_list_init(&animation->link);
-       }
-
-       output->dirty = 1;
-       weston_output_damage(output);
-}
-
-static void
-zoom_area_center_from_point(struct weston_output *output,
-                           double *x, double *y)
-{
-       float level = output->zoom.spring_z.current;
-
-       *x = (*x - output->x) * level + output->width / 2.;
-       *y = (*y - output->y) * level + output->height / 2.;
-}
-
-static void
-weston_output_update_zoom_transform(struct weston_output *output)
-{
-       double x = output->zoom.current.x; /* global pointer coords */
-       double y = output->zoom.current.y;
-       float level;
-
-       level = output->zoom.spring_z.current;
-
-       if (!output->zoom.active || level > output->zoom.max_level ||
-           level == 0.0f)
-               return;
-
-       zoom_area_center_from_point(output, &x, &y);
-
-       output->zoom.trans_x = x - output->width / 2;
-       output->zoom.trans_y = y - output->height / 2;
-
-       if (output->zoom.trans_x < 0)
-               output->zoom.trans_x = 0;
-       if (output->zoom.trans_y < 0)
-               output->zoom.trans_y = 0;
-       if (output->zoom.trans_x > level * output->width)
-               output->zoom.trans_x = level * output->width;
-       if (output->zoom.trans_y > level * output->height)
-               output->zoom.trans_y = level * output->height;
-}
-
-static void
-weston_zoom_transition(struct weston_output *output)
-{
-       if (output->zoom.level != output->zoom.spring_z.current) {
-               output->zoom.spring_z.target = output->zoom.level;
-               if (wl_list_empty(&output->zoom.animation_z.link)) {
-                       output->zoom.animation_z.frame_counter = 0;
-                       wl_list_insert(output->animation_list.prev,
-                               &output->zoom.animation_z.link);
-               }
-       }
-
-       output->dirty = 1;
-       weston_output_damage(output);
-}
-
-WL_EXPORT void
-weston_output_update_zoom(struct weston_output *output)
-{
-       struct weston_seat *seat = output->zoom.seat;
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       assert(output->zoom.active);
-
-       output->zoom.current.x = wl_fixed_to_double(pointer->x);
-       output->zoom.current.y = wl_fixed_to_double(pointer->y);
-
-       weston_zoom_transition(output);
-       weston_output_update_zoom_transform(output);
-}
-
-static void
-motion(struct wl_listener *listener, void *data)
-{
-       struct weston_output_zoom *zoom =
-               container_of(listener, struct weston_output_zoom, motion_listener);
-       struct weston_output *output =
-               container_of(zoom, struct weston_output, zoom);
-
-       weston_output_update_zoom(output);
-}
-
-WL_EXPORT void
-weston_output_activate_zoom(struct weston_output *output,
-                           struct weston_seat *seat)
-{
-       struct weston_pointer *pointer = weston_seat_get_pointer(seat);
-
-       if (output->zoom.active)
-               return;
-
-       output->zoom.active = true;
-       output->zoom.seat = seat;
-       output->disable_planes++;
-       wl_signal_add(&pointer->motion_signal,
-                     &output->zoom.motion_listener);
-}
-
-WL_EXPORT void
-weston_output_init_zoom(struct weston_output *output)
-{
-       output->zoom.active = false;
-       output->zoom.seat = NULL;
-       output->zoom.increment = 0.07;
-       output->zoom.max_level = 0.95;
-       output->zoom.level = 0.0;
-       output->zoom.trans_x = 0.0;
-       output->zoom.trans_y = 0.0;
-       weston_spring_init(&output->zoom.spring_z, 250.0, 0.0, 0.0);
-       output->zoom.spring_z.friction = 1000;
-       output->zoom.animation_z.frame = weston_zoom_frame_z;
-       wl_list_init(&output->zoom.animation_z.link);
-       output->zoom.motion_listener.notify = motion;
-}
index f5e296cb5b3254642000c271b88206c3f0ad80f1..bc36ad13c04298ff27ac080eed6840a79444862d 100644 (file)
@@ -31,7 +31,7 @@
 #include <string.h>
 #include <stdbool.h>
 
-#include "src/compositor.h"
+#include "compositor.h"
 #include "ivi-shell/ivi-layout-export.h"
 #include "ivi-shell/ivi-layout-private.h"
 #include "ivi-test.h"
index 4cae3c597c2a1be331939b349a8bd81b8546045a..1a28c6ee897b3ec444028bc9c696e6493e47cb1b 100644 (file)
@@ -32,7 +32,7 @@
 #include <string.h>
 #include <assert.h>
 
-#include "src/compositor.h"
+#include "compositor.h"
 #include "compositor/weston.h"
 #include "weston-test-server-protocol.h"
 #include "ivi-test.h"
index 11b2455d3970da376b9335564c24e074a37670df..b0a1d1cb013336feb1710fa40674f3b003225a64 100644 (file)
@@ -27,7 +27,7 @@
 
 #include <assert.h>
 
-#include "src/compositor.h"
+#include "compositor.h"
 
 static void
 surface_to_from_global(void *data)
index 55c324be0b5f4d3b19b4cacbd427a0e4d48f37bb..243f8dc32808b520f060512d111559126326919c 100644 (file)
@@ -28,7 +28,7 @@
 #include <stdio.h>
 #include <assert.h>
 
-#include "src/compositor.h"
+#include "compositor.h"
 
 static void
 surface_transform(void *data)
index 8a4e5a6b9ff2366a731e09f443fd91e287d11d3b..ce876ceca14bdc3357795df74debbe75cbc125fb 100644 (file)
@@ -31,7 +31,7 @@
 #include "weston-test-runner.h"
 
 #include "shared/helpers.h"
-#include "src/vertex-clipping.h"
+#include "vertex-clipping.h"
 
 #define BOUNDING_BOX_TOP_Y 100.0f
 #define BOUNDING_BOX_LEFT_X 50.0f
index 26b2ae09bd0adbd6de0d5773aa4cd12e76759e75..1793744c580bb67f3f8e2175ac242ff76a7567e3 100644 (file)
 #include <unistd.h>
 #include <string.h>
 
-#include "src/compositor.h"
+#include "compositor.h"
 #include "compositor/weston.h"
 #include "weston-test-server-protocol.h"
 
 #ifdef ENABLE_EGL
 #include <EGL/egl.h>
 #include <EGL/eglext.h>
-#include "src/weston-egl-ext.h"
+#include "weston-egl-ext.h"
 #endif /* ENABLE_EGL */
 
 #include "shared/helpers.h"