summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNobuhiko Tanibata <NOBUHIKO_TANIBATA@xddp.denso.co.jp>2014-04-19 22:15:20 +0900
committerNobuhiko Tanibata <NOBUHIKO_TANIBATA@xddp.denso.co.jp>2014-04-19 22:15:20 +0900
commit2991da5687fa2828d551fd7b2388d9648a19ecc2 (patch)
tree56aff659352fa256c7a8f78c21835e213978d0c9
parentef9195febc0e67a116b2f1d093cbcbeb629c92b4 (diff)
downloadweston-2991da5687fa2828d551fd7b2388d9648a19ecc2.tar.gz
1.4.91
Change-Id: Ibfed4937c6083937d2b29154e0485c1caf8365a1
-rw-r--r--.gitignore58
-rw-r--r--Makefile.am1014
-rw-r--r--README5
-rw-r--r--clients/calibrator.c2
-rw-r--r--clients/clickdot.c2
-rw-r--r--clients/cliptest.c2
-rw-r--r--clients/dnd.c2
-rw-r--r--clients/eventdemo.c2
-rw-r--r--clients/flower.c2
-rw-r--r--clients/fullscreen.c271
-rw-r--r--clients/image.c2
-rw-r--r--clients/keyboard.c2
-rw-r--r--clients/nested-client.c2
-rw-r--r--clients/nested.c4
-rw-r--r--clients/resizor.c2
-rw-r--r--clients/scaler.c145
-rw-r--r--clients/simple-egl.c159
-rw-r--r--clients/simple-shm.c100
-rw-r--r--clients/smoke.c2
-rw-r--r--clients/stacking.c12
-rw-r--r--clients/subsurfaces.c2
-rw-r--r--clients/terminal.c12
-rw-r--r--clients/transformed.c23
-rw-r--r--clients/window.c641
-rw-r--r--clients/window.h26
-rw-r--r--clients/wscreensaver.h2
-rw-r--r--configure.ac79
-rw-r--r--desktop-shell/exposay.c142
-rw-r--r--desktop-shell/input-panel.c2
-rw-r--r--desktop-shell/shell.c838
-rw-r--r--desktop-shell/shell.h77
-rw-r--r--fullscreen-shell/fullscreen-shell.c830
-rw-r--r--man/weston.ini.man19
-rw-r--r--man/weston.man4
-rw-r--r--protocol/fullscreen-shell.xml206
-rw-r--r--protocol/scaler.xml86
-rw-r--r--protocol/xdg-shell.xml288
-rw-r--r--shared/cairo-util.h3
-rw-r--r--shared/frame.c8
-rw-r--r--shared/os-compatibility.h4
-rw-r--r--src/animation.c10
-rw-r--r--src/compositor-drm.c90
-rw-r--r--src/compositor-fbdev.c8
-rw-r--r--src/compositor-headless.c30
-rw-r--r--src/compositor-rdp.c201
-rw-r--r--src/compositor-rpi.c26
-rw-r--r--src/compositor-wayland.c552
-rw-r--r--src/compositor-x11.c26
-rw-r--r--src/compositor.c421
-rw-r--r--src/compositor.h69
-rw-r--r--src/gl-renderer.c468
-rw-r--r--src/gl-renderer.h4
-rw-r--r--src/input.c96
-rw-r--r--src/libinput-device.c364
-rw-r--r--src/libinput-device.h75
-rw-r--r--src/libinput-seat.c353
-rw-r--r--src/libinput-seat.h62
-rw-r--r--src/logind-util.c1
-rw-r--r--src/noop-renderer.c33
-rw-r--r--src/pixman-renderer.c86
-rw-r--r--src/screen-share.c1084
-rw-r--r--src/screenshooter.c82
-rw-r--r--src/udev-input.h34
-rw-r--r--src/udev-seat.c23
-rw-r--r--src/udev-seat.h5
-rw-r--r--src/vaapi-recorder.c2
-rw-r--r--src/version.h.in12
-rw-r--r--tests/.gitignore17
-rw-r--r--tests/README99
-rw-r--r--tests/bad-buffer-test.c2
-rw-r--r--tests/buffer-count-test.c31
-rw-r--r--tests/button-test.c2
-rw-r--r--tests/config-parser-test.c2
-rw-r--r--tests/main.c300
-rw-r--r--tests/matrix-test.c2
-rw-r--r--tests/setbacklight.c2
-rw-r--r--tests/subsurface-test.c2
-rw-r--r--tests/surface-global-test.c2
-rw-r--r--tests/text-test.c2
-rw-r--r--tests/vertex-clip-test.c3
-rw-r--r--tests/wcap-decode.c152
-rw-r--r--tests/wcap-decode.h63
-rw-r--r--tests/weston-test-client-helper.c8
-rw-r--r--tests/weston-test-client-helper.h2
-rw-r--r--tests/weston-test-runner.c41
-rw-r--r--tests/weston-test-runner.h2
-rw-r--r--tests/weston-test.c6
-rwxr-xr-xtests/weston-tests-env12
-rw-r--r--weston.ini.in2
-rw-r--r--xwayland/dnd.c1
-rw-r--r--xwayland/launcher.c106
-rw-r--r--xwayland/window-manager.c193
-rw-r--r--xwayland/xwayland.h9
93 files changed, 8474 insertions, 1888 deletions
diff --git a/.gitignore b/.gitignore
index 111c56c9..e0a73c03 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,22 +10,17 @@
ctags
cscope.out
.libs
+.dirstamp
/aclocal.m4
/autom4te.cache
-/compile
-/config.guess
+/build-aux/
/config.h
/config.h.in
/config.log
/config.mk
/config.status
-/config.sub
/configure
-/depcomp
-/install-sh
/libtool
-/ltmain.sh
-/missing
/stamp-h1
/test-driver
/weston.ini
@@ -33,3 +28,52 @@ Makefile
Makefile.in
TAGS
protocol/.*.valid
+protocol/*.[ch]
+
+weston-calibrator
+weston-clickdot
+weston-cliptest
+weston-dnd
+weston-editor
+weston-eventdemo
+weston-flower
+weston-fullscreen
+weston-gears
+weston-image
+weston-nested
+weston-nested-client
+weston-resizor
+weston-scaler
+weston-simple-egl
+weston-simple-shm
+weston-simple-touch
+weston-smoke
+weston-stacking
+weston-subsurfaces
+weston-transformed
+weston-view
+
+weston-keyboard
+libtoytoolkit.a
+weston-desktop-shell
+weston-info
+weston-screensaver
+weston-screenshooter
+weston-tablet-shell
+weston-terminal
+weston-multi-resource
+weston-simple-im
+git-version.h
+version.h
+weston
+weston-launch
+spring-tool
+
+*.weston
+*.test
+wcap-decode
+matrix-test
+setbacklight
+weston.1
+weston-drm.7
+weston.ini.5
diff --git a/Makefile.am b/Makefile.am
index f22c5429..a247c3d4 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,26 +1,14 @@
-if BUILD_WCAP_TOOLS
-wcap_subdir = wcap
-endif
-
-if ENABLE_XWAYLAND
-xwayland_subdir = xwayland
-endif
-
-SUBDIRS = \
- shared \
- src \
- $(xwayland_subdir) \
- desktop-shell \
- clients \
- data \
- protocol \
- tests \
- $(wcap_subdir) \
- man
+bin_PROGRAMS =
+noinst_PROGRAMS =
+libexec_PROGRAMS =
+moduledir = $(libdir)/weston
+module_LTLIBRARIES =
+noinst_LTLIBRARIES =
+BUILT_SOURCES =
DISTCHECK_CONFIGURE_FLAGS = --disable-setuid-install
-EXTRA_DIST = weston.ini.in wayland-scanner.mk
+EXTRA_DIST = weston.ini.in
weston.ini : $(srcdir)/weston.ini.in
$(AM_V_GEN)$(SED) \
@@ -31,4 +19,988 @@ weston.ini : $(srcdir)/weston.ini.in
all-local : weston.ini
-CLEANFILES = weston.ini
+AM_CFLAGS = $(GCC_CFLAGS)
+
+AM_CPPFLAGS = \
+ -I$(top_srcdir)/src \
+ -I$(top_builddir)/src \
+ -I$(top_builddir)/clients \
+ -I$(top_builddir)/tests \
+ -I$(top_srcdir)/shared \
+ -I$(top_builddir)/protocol \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"' \
+ -DBINDIR='"$(bindir)"'
+
+CLEANFILES = weston.ini $(BUILT_SOURCES)
+
+bin_PROGRAMS += weston
+
+weston_LDFLAGS = -export-dynamic
+weston_CPPFLAGS = $(AM_CPPFLAGS) -DIN_WESTON
+weston_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(LIBUNWIND_CFLAGS)
+weston_LDADD = $(COMPOSITOR_LIBS) $(LIBUNWIND_LIBS) \
+ $(DLOPEN_LIBS) -lm libshared.la
+
+weston_SOURCES = \
+ src/git-version.h \
+ src/log.c \
+ src/compositor.c \
+ src/compositor.h \
+ src/input.c \
+ src/data-device.c \
+ src/screenshooter.c \
+ src/clipboard.c \
+ src/zoom.c \
+ src/text-backend.c \
+ src/bindings.c \
+ src/animation.c \
+ src/noop-renderer.c \
+ src/pixman-renderer.c \
+ src/pixman-renderer.h \
+ shared/matrix.c \
+ shared/matrix.h \
+ shared/zalloc.h \
+ src/weston-egl-ext.h
+
+nodist_weston_SOURCES = \
+ protocol/screenshooter-protocol.c \
+ protocol/screenshooter-server-protocol.h \
+ protocol/text-cursor-position-protocol.c \
+ protocol/text-cursor-position-server-protocol.h \
+ protocol/text-protocol.c \
+ protocol/text-server-protocol.h \
+ protocol/input-method-protocol.c \
+ protocol/input-method-server-protocol.h \
+ protocol/workspaces-protocol.c \
+ protocol/workspaces-server-protocol.h \
+ protocol/scaler-protocol.c \
+ protocol/scaler-server-protocol.h
+
+BUILT_SOURCES += $(nodist_weston_SOURCES)
+
+# Track this dependency explicitly instead of using BUILT_SOURCES. We
+# 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
+
+noinst_LTLIBRARIES += \
+ libsession-helper.la
+
+libsession_helper_la_SOURCES = \
+ src/weston-launch.h \
+ src/launcher-util.c \
+ src/launcher-util.h
+libsession_helper_la_CFLAGS = $(GCC_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/logind-util.h \
+ src/logind-util.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
+ $(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 :
+ $(AM_V_GEN)echo "#define BUILD_ID \"unknown (not built from git or tarball)\"" > $@
+
+endif
+
+.FORCE :
+
+if BUILD_WESTON_LAUNCH
+bin_PROGRAMS += weston-launch
+weston_launch_SOURCES = src/weston-launch.c src/weston-launch.h
+weston_launch_CPPFLAGS = -DBINDIR='"$(bindir)"'
+weston_launch_CFLAGS= \
+ $(GCC_CFLAGS) \
+ $(PAM_CFLAGS) \
+ $(SYSTEMD_LOGIN_CFLAGS) \
+ $(LIBDRM_CFLAGS)
+weston_launch_LDADD = $(PAM_LIBS) $(SYSTEMD_LOGIN_LIBS) $(LIBDRM_LIBS)
+
+if ENABLE_SETUID_INSTALL
+install-exec-hook:
+ chown root $(DESTDIR)$(bindir)/weston-launch
+ chmod u+s $(DESTDIR)$(bindir)/weston-launch
+endif
+
+endif # BUILD_WESTON_LAUNCH
+
+pkgconfigdir = $(libdir)/pkgconfig
+pkgconfig_DATA = src/weston.pc
+
+westonincludedir = $(includedir)/weston
+westoninclude_HEADERS = \
+ src/version.h \
+ src/compositor.h \
+ shared/matrix.h \
+ shared/config-parser.h \
+ shared/zalloc.h
+
+if ENABLE_EGL
+module_LTLIBRARIES += gl-renderer.la
+gl_renderer_la_LDFLAGS = -module -avoid-version
+gl_renderer_la_LIBADD = $(COMPOSITOR_LIBS) $(EGL_LIBS)
+gl_renderer_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $(GCC_CFLAGS)
+gl_renderer_la_SOURCES = \
+ src/gl-renderer.h \
+ src/gl-renderer.c \
+ src/vertex-clipping.c \
+ src/vertex-clipping.h
+endif
+
+if ENABLE_X11_COMPOSITOR
+module_LTLIBRARIES += x11-backend.la
+x11_backend_la_LDFLAGS = -module -avoid-version
+x11_backend_la_LIBADD = $(COMPOSITOR_LIBS) $(X11_COMPOSITOR_LIBS) \
+ libshared-cairo.la
+x11_backend_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $(PIXMAN_CFLAGS) \
+ $(CAIRO_CFLAGS) \
+ $(X11_COMPOSITOR_CFLAGS) \
+ $(GCC_CFLAGS)
+x11_backend_la_SOURCES = src/compositor-x11.c
+endif
+
+INPUT_BACKEND_SOURCES = src/udev-input.h
+
+if ENABLE_LIBINPUT_BACKEND
+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
+else
+INPUT_BACKEND_SOURCES += \
+ src/filter.c \
+ src/filter.h \
+ src/udev-seat.c \
+ src/udev-seat.h \
+ src/evdev.c \
+ src/evdev.h \
+ src/evdev-touchpad.c
+endif
+
+if ENABLE_DRM_COMPOSITOR
+module_LTLIBRARIES += drm-backend.la
+drm_backend_la_LDFLAGS = -module -avoid-version
+drm_backend_la_LIBADD = \
+ $(COMPOSITOR_LIBS) \
+ $(DRM_COMPOSITOR_LIBS) \
+ $(INPUT_BACKEND_LIBS) \
+ libshared.la -lrt \
+ libsession-helper.la
+drm_backend_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $(DRM_COMPOSITOR_CFLAGS) \
+ $(GCC_CFLAGS)
+drm_backend_la_SOURCES = \
+ src/compositor-drm.c \
+ $(INPUT_BACKEND_SOURCES) \
+ src/libbacklight.c \
+ src/libbacklight.h
+
+if ENABLE_VAAPI_RECORDER
+drm_backend_la_SOURCES += src/vaapi-recorder.c src/vaapi-recorder.h
+drm_backend_la_LIBADD += $(LIBVA_LIBS)
+drm_backend_la_CFLAGS += $(LIBVA_CFLAGS)
+endif
+endif
+
+if ENABLE_WAYLAND_COMPOSITOR
+module_LTLIBRARIES += wayland-backend.la
+wayland_backend_la_LDFLAGS = -module -avoid-version
+wayland_backend_la_LIBADD = \
+ $(COMPOSITOR_LIBS) \
+ $(WAYLAND_COMPOSITOR_LIBS) \
+ libshared-cairo.la
+wayland_backend_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $(PIXMAN_CFLAGS) \
+ $(CAIRO_CFLAGS) \
+ $(WAYLAND_COMPOSITOR_CFLAGS) \
+ $(GCC_CFLAGS)
+wayland_backend_la_SOURCES = src/compositor-wayland.c
+nodist_wayland_backend_la_SOURCES = \
+ protocol/fullscreen-shell-protocol.c \
+ protocol/fullscreen-shell-client-protocol.h
+endif
+
+if ENABLE_RPI_COMPOSITOR
+if INSTALL_RPI_COMPOSITOR
+module_LTLIBRARIES += rpi-backend.la
+else
+noinst_LTLIBRARIES += rpi-backend.la
+endif
+
+rpi_backend_la_LDFLAGS = -module -avoid-version
+rpi_backend_la_LIBADD = $(COMPOSITOR_LIBS) \
+ $(RPI_COMPOSITOR_LIBS) \
+ $(RPI_BCM_HOST_LIBS) \
+ $(INPUT_BACKEND_LIBS) \
+ libsession-helper.la \
+ libshared.la
+rpi_backend_la_CFLAGS = \
+ $(GCC_CFLAGS) \
+ $(COMPOSITOR_CFLAGS) \
+ $(RPI_COMPOSITOR_CFLAGS) \
+ $(RPI_BCM_HOST_CFLAGS)
+rpi_backend_la_SOURCES = \
+ src/compositor-rpi.c \
+ src/rpi-renderer.c \
+ src/rpi-renderer.h \
+ src/rpi-bcm-stubs.h \
+ $(INPUT_BACKEND_SOURCES)
+
+if ENABLE_EGL
+rpi_backend_la_LIBADD += $(EGL_LIBS)
+rpi_backend_la_CFLAGS += $(EGL_CFLAGS)
+endif
+
+endif
+
+if ENABLE_HEADLESS_COMPOSITOR
+module_LTLIBRARIES += headless-backend.la
+headless_backend_la_LDFLAGS = -module -avoid-version
+headless_backend_la_LIBADD = $(COMPOSITOR_LIBS) libshared.la
+headless_backend_la_CFLAGS = $(COMPOSITOR_CFLAGS) $(GCC_CFLAGS)
+headless_backend_la_SOURCES = src/compositor-headless.c
+endif
+
+if ENABLE_FBDEV_COMPOSITOR
+module_LTLIBRARIES += fbdev-backend.la
+fbdev_backend_la_LDFLAGS = -module -avoid-version
+fbdev_backend_la_LIBADD = \
+ $(COMPOSITOR_LIBS) \
+ $(FBDEV_COMPOSITOR_LIBS) \
+ $(INPUT_BACKEND_LIBS) \
+ libsession-helper.la \
+ libshared.la
+fbdev_backend_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(EGL_CFLAGS) \
+ $(FBDEV_COMPOSITOR_CFLAGS) \
+ $(PIXMAN_CFLAGS) \
+ $(GCC_CFLAGS)
+fbdev_backend_la_SOURCES = \
+ src/compositor-fbdev.c \
+ $(INPUT_BACKEND_SOURCES)
+endif
+
+if ENABLE_RDP_COMPOSITOR
+module_LTLIBRARIES += rdp-backend.la
+rdp_backend_la_LDFLAGS = -module -avoid-version
+rdp_backend_la_LIBADD = $(COMPOSITOR_LIBS) \
+ $(RDP_COMPOSITOR_LIBS) \
+ libshared.la
+rdp_backend_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(RDP_COMPOSITOR_CFLAGS) \
+ $(GCC_CFLAGS)
+rdp_backend_la_SOURCES = src/compositor-rdp.c
+endif
+
+if HAVE_LCMS
+module_LTLIBRARIES += cms-static.la
+cms_static_la_LDFLAGS = -module -avoid-version
+cms_static_la_LIBADD = $(COMPOSITOR_LIBS) $(LCMS_LIBS) libshared.la
+cms_static_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(LCMS_CFLAGS)
+cms_static_la_SOURCES = \
+ src/cms-static.c \
+ src/cms-helper.c \
+ src/cms-helper.h
+if ENABLE_COLORD
+module_LTLIBRARIES += cms-colord.la
+cms_colord_la_LDFLAGS = -module -avoid-version
+cms_colord_la_LIBADD = $(COMPOSITOR_LIBS) $(COLORD_LIBS)
+cms_colord_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS) $(COLORD_CFLAGS)
+cms_colord_la_SOURCES = \
+ src/cms-colord.c \
+ src/cms-helper.c \
+ src/cms-helper.h
+endif
+endif
+
+noinst_PROGRAMS += spring-tool
+spring_tool_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+spring_tool_LDADD = $(COMPOSITOR_LIBS) -lm
+spring_tool_SOURCES = \
+ src/spring-tool.c \
+ src/animation.c \
+ shared/matrix.c \
+ shared/matrix.h \
+ src/compositor.h
+
+if BUILD_CLIENTS
+
+bin_PROGRAMS += weston-terminal weston-info
+
+libexec_PROGRAMS += \
+ weston-desktop-shell \
+ weston-screenshooter \
+ weston-keyboard \
+ weston-simple-im
+
+demo_clients = \
+ weston-flower \
+ weston-image \
+ weston-cliptest \
+ weston-dnd \
+ weston-smoke \
+ weston-resizor \
+ weston-eventdemo \
+ weston-clickdot \
+ weston-transformed \
+ weston-fullscreen \
+ weston-stacking \
+ weston-calibrator \
+ weston-scaler
+
+if INSTALL_DEMO_CLIENTS
+bin_PROGRAMS += $(demo_clients)
+else
+noinst_PROGRAMS += $(demo_clients)
+endif
+
+
+if BUILD_SIMPLE_CLIENTS
+demo_clients += \
+ weston-simple-shm \
+ weston-simple-touch \
+ weston-multi-resource
+
+weston_simple_shm_SOURCES = clients/simple-shm.c
+nodist_weston_simple_shm_SOURCES = \
+ protocol/xdg-shell-protocol.c \
+ protocol/xdg-shell-client-protocol.h \
+ protocol/fullscreen-shell-protocol.c \
+ protocol/fullscreen-shell-client-protocol.h
+weston_simple_shm_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS)
+weston_simple_shm_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la
+
+weston_simple_touch_SOURCES = clients/simple-touch.c
+weston_simple_touch_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS)
+weston_simple_touch_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la
+
+weston_multi_resource_SOURCES = clients/multi-resource.c
+weston_multi_resource_CFLAGS = $(AM_CFLAGS) $(SIMPLE_CLIENT_CFLAGS)
+weston_multi_resource_LDADD = $(SIMPLE_CLIENT_LIBS) libshared.la -lm
+endif
+
+if BUILD_SIMPLE_EGL_CLIENTS
+demo_clients += weston-simple-egl
+weston_simple_egl_SOURCES = clients/simple-egl.c
+nodist_weston_simple_egl_SOURCES = \
+ protocol/xdg-shell-protocol.c \
+ protocol/xdg-shell-client-protocol.h
+weston_simple_egl_CFLAGS = $(AM_CFLAGS) $(SIMPLE_EGL_CLIENT_CFLAGS)
+weston_simple_egl_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
+endif
+
+noinst_LTLIBRARIES += libtoytoolkit.la
+
+libtoytoolkit_la_SOURCES = \
+ clients/window.c \
+ clients/window.h
+
+nodist_libtoytoolkit_la_SOURCES = \
+ protocol/text-cursor-position-protocol.c \
+ protocol/text-cursor-position-client-protocol.h \
+ protocol/scaler-protocol.c \
+ protocol/scaler-client-protocol.h \
+ protocol/workspaces-protocol.c \
+ protocol/workspaces-client-protocol.h \
+ protocol/xdg-shell-protocol.c \
+ protocol/xdg-shell-client-protocol.h
+
+BUILT_SOURCES += $(nodist_libtoytoolkit_la_SOURCES)
+
+
+libtoytoolkit_la_LIBADD = \
+ $(CLIENT_LIBS) \
+ $(CAIRO_EGL_LIBS) \
+ libshared-cairo.la -lrt -lm
+libtoytoolkit_la_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) $(CAIRO_EGL_CFLAGS)
+
+weston_flower_SOURCES = clients/flower.c
+weston_flower_LDADD = libtoytoolkit.la
+weston_flower_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_screenshooter_SOURCES = \
+ clients/screenshot.c
+nodist_weston_screenshooter_SOURCES = \
+ protocol/screenshooter-protocol.c \
+ protocol/screenshooter-client-protocol.h
+weston_screenshooter_LDADD = $(CLIENT_LIBS) libshared.la
+weston_screenshooter_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_terminal_SOURCES = clients/terminal.c
+weston_terminal_LDADD = libtoytoolkit.la -lutil
+weston_terminal_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_image_SOURCES = clients/image.c
+weston_image_LDADD = libtoytoolkit.la
+weston_image_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_cliptest_SOURCES = clients/cliptest.c
+weston_cliptest_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+weston_cliptest_LDADD = libtoytoolkit.la
+
+weston_dnd_SOURCES = clients/dnd.c
+weston_dnd_LDADD = libtoytoolkit.la
+weston_dnd_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_smoke_SOURCES = clients/smoke.c
+weston_smoke_LDADD = libtoytoolkit.la
+weston_smoke_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_resizor_SOURCES = clients/resizor.c
+weston_resizor_LDADD = libtoytoolkit.la
+weston_resizor_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_scaler_SOURCES = clients/scaler.c
+weston_scaler_LDADD = libtoytoolkit.la
+weston_scaler_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+if HAVE_CAIRO_GLESV2
+demo_clients += weston-nested weston-nested-client
+
+weston_nested_SOURCES = clients/nested.c
+weston_nested_LDADD = libtoytoolkit.la $(SERVER_LIBS)
+weston_nested_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_nested_client_SOURCES = clients/nested-client.c
+weston_nested_client_LDADD = $(SIMPLE_EGL_CLIENT_LIBS) -lm
+weston_nested_client_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+endif
+
+weston_eventdemo_SOURCES = clients/eventdemo.c
+weston_eventdemo_LDADD = libtoytoolkit.la
+weston_eventdemo_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_clickdot_SOURCES = clients/clickdot.c
+weston_clickdot_LDADD = libtoytoolkit.la
+weston_clickdot_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_transformed_SOURCES = clients/transformed.c
+weston_transformed_LDADD = libtoytoolkit.la
+weston_transformed_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_fullscreen_SOURCES = clients/fullscreen.c
+nodist_weston_fullscreen_SOURCES = \
+ protocol/fullscreen-shell-protocol.c \
+ protocol/fullscreen-shell-client-protocol.h
+weston_fullscreen_LDADD = libtoytoolkit.la
+weston_fullscreen_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_stacking_SOURCES = clients/stacking.c
+weston_stacking_LDADD = libtoytoolkit.la
+weston_stacking_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_calibrator_SOURCES = clients/calibrator.c \
+ shared/matrix.c \
+ shared/matrix.h
+weston_calibrator_LDADD = libtoytoolkit.la
+weston_calibrator_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+if BUILD_SUBSURFACES_CLIENT
+demo_clients += weston-subsurfaces
+weston_subsurfaces_SOURCES = clients/subsurfaces.c
+weston_subsurfaces_CFLAGS = \
+ $(AM_CFLAGS) \
+ $(SIMPLE_EGL_CLIENT_CFLAGS) \
+ $(CLIENT_CFLAGS)
+weston_subsurfaces_LDADD = libtoytoolkit.la $(SIMPLE_EGL_CLIENT_LIBS) -lm
+endif
+
+if HAVE_PANGO
+demo_clients += weston-editor
+weston_editor_SOURCES = clients/editor.c
+nodist_weston_editor_SOURCES = \
+ protocol/text-protocol.c \
+ protocol/text-client-protocol.h
+weston_editor_LDADD = libtoytoolkit.la $(PANGO_LIBS)
+weston_editor_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS) $(PANGO_CFLAGS)
+endif
+
+weston_keyboard_SOURCES = clients/keyboard.c
+nodist_weston_keyboard_SOURCES = \
+ protocol/desktop-shell-client-protocol.h \
+ protocol/desktop-shell-protocol.c \
+ protocol/input-method-protocol.c \
+ protocol/input-method-client-protocol.h
+weston_keyboard_LDADD = libtoytoolkit.la
+weston_keyboard_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_simple_im_SOURCES = clients/weston-simple-im.c
+nodist_weston_simple_im_SOURCES = \
+ protocol/input-method-protocol.c \
+ protocol/input-method-client-protocol.h
+weston_simple_im_LDADD = $(CLIENT_LIBS)
+weston_simple_im_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_info_SOURCES = clients/weston-info.c
+weston_info_LDADD = $(WESTON_INFO_LIBS) libshared.la
+weston_info_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+weston_desktop_shell_SOURCES = clients/desktop-shell.c
+nodist_weston_desktop_shell_SOURCES = \
+ protocol/desktop-shell-client-protocol.h \
+ protocol/desktop-shell-protocol.c
+weston_desktop_shell_LDADD = libtoytoolkit.la
+weston_desktop_shell_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+if BUILD_FULL_GL_CLIENTS
+demo_clients += weston-gears
+weston_gears_SOURCES = clients/gears.c
+weston_gears_LDADD = libtoytoolkit.la
+weston_gears_CFLAGS = $(AM_CFLAGS) $(CLIENT_CFLAGS)
+
+if HAVE_GLU
+libexec_PROGRAMS += weston-screensaver
+weston_screensaver_SOURCES = \
+ clients/wscreensaver.c \
+ clients/wscreensaver.h \
+ clients/wscreensaver-glue.c \
+ clients/wscreensaver-glue.h \
+ clients/glmatrix.c \
+ clients/matrix3.xpm
+nodist_weston_screensaver_SOURCES = \
+ protocol/desktop-shell-client-protocol.h \
+ protocol/desktop-shell-protocol.c
+
+weston_screensaver_LDADD = libtoytoolkit.la $(GLU_LIBS)
+weston_screensaver_CFLAGS = $(AM_CFLAGS) $(GLU_CFLAGS) $(CLIENT_CFLAGS)
+
+endif
+
+endif
+
+endif
+
+BUILT_SOURCES += \
+ protocol/screenshooter-protocol.c \
+ protocol/screenshooter-client-protocol.h \
+ protocol/text-cursor-position-client-protocol.h \
+ protocol/text-cursor-position-protocol.c \
+ protocol/text-protocol.c \
+ protocol/text-client-protocol.h \
+ protocol/input-method-protocol.c \
+ protocol/input-method-client-protocol.h \
+ protocol/desktop-shell-client-protocol.h \
+ protocol/desktop-shell-protocol.c \
+ protocol/scaler-client-protocol.h \
+ protocol/scaler-protocol.c \
+ protocol/workspaces-client-protocol.h \
+ protocol/workspaces-protocol.c \
+ protocol/fullscreen-shell-protocol.c \
+ protocol/fullscreen-shell-client-protocol.h \
+ protocol/xdg-shell-protocol.c \
+ protocol/xdg-shell-client-protocol.h
+
+
+westondatadir = $(datadir)/weston
+dist_westondata_DATA = \
+ data/wayland.svg \
+ data/wayland.png \
+ data/pattern.png \
+ data/terminal.png \
+ data/border.png \
+ data/icon_window.png \
+ data/sign_close.png \
+ data/sign_maximize.png \
+ data/sign_minimize.png
+
+
+if BUILD_WCAP_TOOLS
+bin_PROGRAMS += wcap-decode
+
+wcap_decode_SOURCES = \
+ wcap/main.c \
+ wcap/wcap-decode.c \
+ wcap/wcap-decode.h
+
+wcap_decode_CFLAGS = $(GCC_CFLAGS) $(WCAP_CFLAGS)
+wcap_decode_LDADD = $(WCAP_LIBS)
+endif
+
+
+if ENABLE_DESKTOP_SHELL
+
+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_builddir)/desktop-shell \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"' \
+ -DIN_WESTON
+
+desktop_shell_la_LDFLAGS = -module -avoid-version
+desktop_shell_la_LIBADD = $(COMPOSITOR_LIBS) libshared.la
+desktop_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+desktop_shell_la_SOURCES = \
+ desktop-shell/shell.h \
+ desktop-shell/shell.c \
+ desktop-shell/exposay.c \
+ desktop-shell/input-panel.c
+nodist_desktop_shell_la_SOURCES = \
+ protocol/desktop-shell-protocol.c \
+ protocol/desktop-shell-server-protocol.h \
+ protocol/xdg-shell-protocol.c \
+ protocol/xdg-shell-server-protocol.h
+
+BUILT_SOURCES += $(nodist_desktop_shell_la_SOURCES)
+endif
+
+if ENABLE_FULLSCREEN_SHELL
+
+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 \
+ -DIN_WESTON
+
+fullscreen_shell_la_LDFLAGS = -module -avoid-version
+fullscreen_shell_la_LIBADD = $(COMPOSITOR_LIBS)
+fullscreen_shell_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+fullscreen_shell_la_SOURCES = \
+ fullscreen-shell/fullscreen-shell.c
+nodist_fullscreen_shell_la_SOURCES = \
+ protocol/fullscreen-shell-protocol.c \
+ protocol/fullscreen-shell-server-protocol.h
+
+BUILT_SOURCES += $(nodist_fullscreen_shell_la_SOURCES)
+endif
+
+if ENABLE_SCREEN_SHARING
+
+module_LTLIBRARIES += screen-share.la
+
+screen_share_la_CPPFLAGS = $(AM_CPPFLAGS) -DBINDIR='"$(bindir)"'
+screen_share_la_LDFLAGS = -module -avoid-version
+screen_share_la_LIBADD = \
+ $(COMPOSITOR_LIBS) \
+ $(SCREEN_SHARE_LIBS) \
+ libshared-cairo.la
+screen_share_la_CFLAGS = \
+ $(COMPOSITOR_CFLAGS) \
+ $(SCREEN_SHARE_CFLAGS) \
+ $(GCC_CFLAGS)
+screen_share_la_SOURCES = \
+ src/screen-share.c
+nodist_screen_share_la_SOURCES = \
+ protocol/fullscreen-shell-protocol.c \
+ protocol/fullscreen-shell-client-protocol.h
+
+endif
+
+if ENABLE_XWAYLAND
+
+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_builddir)/xwayland \
+ -DDATADIR='"$(datadir)"' \
+ -DMODULEDIR='"$(moduledir)"' \
+ -DLIBEXECDIR='"$(libexecdir)"' \
+ -DXSERVER_PATH='"@XSERVER_PATH@"'
+
+xwayland_la_LDFLAGS = -module -avoid-version
+xwayland_la_LIBADD = \
+ $(XWAYLAND_LIBS) \
+ $(top_builddir)/libshared-cairo.la
+xwayland_la_CFLAGS = \
+ $(GCC_CFLAGS) \
+ $(COMPOSITOR_CFLAGS) \
+ $(PIXMAN_CFLAGS) \
+ $(CAIRO_CFLAGS)
+xwayland_la_SOURCES = \
+ xwayland/xwayland.h \
+ xwayland/window-manager.c \
+ xwayland/selection.c \
+ xwayland/dnd.c \
+ xwayland/launcher.c \
+ xwayland/hash.c \
+ xwayland/hash.h
+endif
+
+
+#
+# Shared utilities
+#
+
+noinst_LTLIBRARIES += libshared.la libshared-cairo.la
+
+libshared_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+
+libshared_la_SOURCES = \
+ shared/config-parser.c \
+ shared/option-parser.c \
+ shared/config-parser.h \
+ shared/os-compatibility.c \
+ shared/os-compatibility.h
+
+libshared_cairo_la_CFLAGS = \
+ -DDATADIR='"$(datadir)"' \
+ $(GCC_CFLAGS) \
+ $(COMPOSITOR_CFLAGS) \
+ $(PIXMAN_CFLAGS) \
+ $(CAIRO_CFLAGS) \
+ $(PNG_CFLAGS) \
+ $(WEBP_CFLAGS)
+
+libshared_cairo_la_LIBADD = \
+ $(PIXMAN_LIBS) \
+ $(CAIRO_LIBS) \
+ $(PNG_LIBS) \
+ $(WEBP_LIBS) \
+ $(JPEG_LIBS)
+
+libshared_cairo_la_SOURCES = \
+ $(libshared_la_SOURCES) \
+ shared/image-loader.c \
+ shared/image-loader.h \
+ shared/cairo-util.c \
+ shared/frame.c \
+ shared/cairo-util.h
+
+
+#
+# tests subdirectory
+#
+
+TESTS = $(shared_tests) $(module_tests) $(weston_tests)
+
+shared_tests = \
+ config-parser.test \
+ vertex-clip.test
+
+module_tests = \
+ surface-test.la \
+ surface-global-test.la
+
+weston_tests = \
+ bad_buffer.weston \
+ keyboard.weston \
+ event.weston \
+ button.weston \
+ text.weston \
+ subsurface.weston
+
+
+AM_TESTS_ENVIRONMENT = \
+ abs_builddir='$(abs_builddir)'; export abs_builddir;
+
+TEST_EXTENSIONS = .la .weston
+LA_LOG_COMPILER = $(srcdir)/tests/weston-tests-env
+WESTON_LOG_COMPILER = $(srcdir)/tests/weston-tests-env
+
+clean-local:
+ -rm -rf tests/logs
+
+# To remove when automake 1.11 support is dropped
+export abs_builddir
+
+noinst_LTLIBRARIES += \
+ weston-test.la \
+ $(module_tests) \
+ libtest-runner.la \
+ libtest-client.la
+
+noinst_PROGRAMS += \
+ $(setbacklight) \
+ $(shared_tests) \
+ $(weston_tests) \
+ matrix-test
+
+test_module_ldflags = \
+ -module -avoid-version -rpath $(libdir) $(COMPOSITOR_LIBS)
+
+surface_global_test_la_SOURCES = tests/surface-global-test.c
+surface_global_test_la_LDFLAGS = $(test_module_ldflags)
+surface_global_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+
+surface_test_la_SOURCES = tests/surface-test.c
+surface_test_la_LDFLAGS = $(test_module_ldflags)
+surface_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+
+weston_test_la_LIBADD = $(COMPOSITOR_LIBS) libshared.la
+weston_test_la_LDFLAGS = $(test_module_ldflags)
+weston_test_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+weston_test_la_SOURCES = tests/weston-test.c
+nodist_weston_test_la_SOURCES = \
+ protocol/wayland-test-protocol.c \
+ protocol/wayland-test-server-protocol.h
+
+if ENABLE_EGL
+weston_test_la_CFLAGS += $(EGL_TESTS_CFLAGS)
+weston_test_la_LDFLAGS += $(EGL_TESTS_LIBS)
+endif
+
+libtest_runner_la_SOURCES = \
+ tests/weston-test-runner.c \
+ tests/weston-test-runner.h
+libtest_runner_la_CFLAGS = $(GCC_CFLAGS) $(COMPOSITOR_CFLAGS)
+
+config_parser_test_SOURCES = tests/config-parser-test.c
+config_parser_test_LDADD = libshared.la libtest-runner.la $(COMPOSITOR_LIBS)
+
+vertex_clip_test_SOURCES = \
+ tests/vertex-clip-test.c \
+ src/vertex-clipping.c \
+ src/vertex-clipping.h
+vertex_clip_test_LDADD = libtest-runner.la -lm -lrt
+
+libtest_client_la_SOURCES = \
+ tests/weston-test-client-helper.c \
+ tests/weston-test-client-helper.h
+nodist_libtest_client_la_SOURCES = \
+ protocol/wayland-test-protocol.c \
+ protocol/wayland-test-client-protocol.h
+libtest_client_la_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS)
+libtest_client_la_LIBADD = $(TEST_CLIENT_LIBS) libshared.la libtest-runner.la
+
+bad_buffer_weston_SOURCES = tests/bad-buffer-test.c
+bad_buffer_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS)
+bad_buffer_weston_LDADD = libtest-client.la
+
+keyboard_weston_SOURCES = tests/keyboard-test.c
+keyboard_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS)
+keyboard_weston_LDADD = libtest-client.la
+
+event_weston_SOURCES = tests/event-test.c
+event_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS)
+event_weston_LDADD = libtest-client.la
+
+button_weston_SOURCES = tests/button-test.c
+button_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS)
+button_weston_LDADD = libtest-client.la
+
+text_weston_SOURCES = tests/text-test.c
+nodist_text_weston_SOURCES = \
+ protocol/text-protocol.c \
+ protocol/text-client-protocol.h
+text_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS)
+text_weston_LDADD = libtest-client.la
+
+subsurface_weston_SOURCES = tests/subsurface-test.c
+subsurface_weston_CFLAGS = $(AM_CFLAGS) $(TEST_CLIENT_CFLAGS)
+subsurface_weston_LDADD = libtest-client.la
+
+if ENABLE_EGL
+weston_tests += buffer-count.weston
+buffer_count_weston_SOURCES = tests/buffer-count-test.c
+buffer_count_weston_CFLAGS = $(GCC_CFLAGS) $(EGL_TESTS_CFLAGS)
+buffer_count_weston_LDADD = libtest-client.la $(EGL_TESTS_LIBS)
+endif
+
+if ENABLE_XWAYLAND_TEST
+weston_tests += xwayland.weston
+xwayland_weston_SOURCES = tests/xwayland-test.c
+xwayland_weston_CFLAGS = $(GCC_CFLAGS) $(XWAYLAND_TEST_CFLAGS)
+xwayland_weston_LDADD = libtest-client.la $(XWAYLAND_TEST_LIBS)
+endif
+
+matrix_test_SOURCES = \
+ tests/matrix-test.c \
+ shared/matrix.c \
+ shared/matrix.h
+matrix_test_CPPFLAGS = -DUNIT_TEST
+matrix_test_LDADD = -lm -lrt
+
+if BUILD_SETBACKLIGHT
+noinst_PROGRAMS += setbacklight
+setbacklight_SOURCES = \
+ tests/setbacklight.c \
+ src/libbacklight.c \
+ src/libbacklight.h
+setbacklight_CFLAGS = $(AM_CFLAGS) $(SETBACKLIGHT_CFLAGS)
+setbacklight_LDADD = $(SETBACKLIGHT_LIBS)
+endif
+
+EXTRA_DIST += tests/weston-tests-env
+
+BUILT_SOURCES += \
+ protocol/wayland-test-protocol.c \
+ protocol/wayland-test-server-protocol.h \
+ protocol/wayland-test-client-protocol.h \
+ protocol/text-protocol.c \
+ protocol/text-client-protocol.h
+
+EXTRA_DIST += \
+ protocol/desktop-shell.xml \
+ protocol/screenshooter.xml \
+ protocol/text.xml \
+ protocol/input-method.xml \
+ protocol/workspaces.xml \
+ protocol/text-cursor-position.xml \
+ protocol/wayland-test.xml \
+ protocol/xdg-shell.xml \
+ protocol/fullscreen-shell.xml \
+ protocol/scaler.xml
+
+man_MANS = weston.1 weston.ini.5
+
+if ENABLE_DRM_COMPOSITOR
+man_MANS += weston-drm.7
+endif
+
+MAN_SUBSTS = \
+ -e 's|__weston_native_backend__|$(WESTON_NATIVE_BACKEND)|g' \
+ -e 's|__weston_modules_dir__|$(pkglibdir)|g' \
+ -e 's|__weston_shell_client__|$(WESTON_SHELL_CLIENT)|g' \
+ -e 's|__version__|$(PACKAGE_VERSION)|g'
+
+SUFFIXES = .1 .5 .7 .man
+
+%.1 %.5 %.7 : man/%.man
+ $(AM_V_GEN)$(SED) $(MAN_SUBSTS) < $< > $@
+
+EXTRA_DIST += \
+ man/weston.man \
+ man/weston-drm.man \
+ man/weston.ini.man
+
+CLEANFILES += $(man_MANS)
+
+
+protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml
+ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code < $< > $@
+
+protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml
+ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header < $< > $@
+
+protocol/%-client-protocol.h : $(top_srcdir)/protocol/%.xml
+ $(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header < $< > $@
diff --git a/README b/README
index b3be4c99..3821e5d0 100644
--- a/README
+++ b/README
@@ -11,5 +11,8 @@ shell. Finally, weston also provides integration with the Xorg server
and can pull X clients into the Wayland desktop and act as a X window
manager.
-Refer to http://wayland.freedesktop.org/building.html for buiding
+Refer to http://wayland.freedesktop.org/building.html for building
weston and its dependencies.
+
+The test suite can be invoked via `make check`; see
+http://wayland.freedesktop.org/testing.html for additional details.
diff --git a/clients/calibrator.c b/clients/calibrator.c
index 783cdecc..1eb117f0 100644
--- a/clients/calibrator.c
+++ b/clients/calibrator.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/clickdot.c b/clients/clickdot.c
index c300fa54..e09cb142 100644
--- a/clients/clickdot.c
+++ b/clients/clickdot.c
@@ -22,6 +22,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/cliptest.c b/clients/cliptest.c
index 89c3ca73..3cee343f 100644
--- a/clients/cliptest.c
+++ b/clients/cliptest.c
@@ -30,6 +30,8 @@
* surface transform disable key: r
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/dnd.c b/clients/dnd.c
index 00739c31..a463d6f6 100644
--- a/clients/dnd.c
+++ b/clients/dnd.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <assert.h>
#include <stdint.h>
#include <stdio.h>
diff --git a/clients/eventdemo.c b/clients/eventdemo.c
index 029b1d8b..5ec68296 100644
--- a/clients/eventdemo.c
+++ b/clients/eventdemo.c
@@ -30,6 +30,8 @@
* \author Tim Wiederhake
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/flower.c b/clients/flower.c
index 389f8bee..87694450 100644
--- a/clients/flower.c
+++ b/clients/flower.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/fullscreen.c b/clients/fullscreen.c
index 034a3528..fa8028a9 100644
--- a/clients/fullscreen.c
+++ b/clients/fullscreen.c
@@ -21,6 +21,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -32,15 +34,26 @@
#include <linux/input.h>
#include <wayland-client.h>
#include "window.h"
+#include "fullscreen-shell-client-protocol.h"
+
+struct fs_output {
+ struct wl_list link;
+ struct output *output;
+};
struct fullscreen {
struct display *display;
struct window *window;
struct widget *widget;
+ struct _wl_fullscreen_shell *fshell;
+ enum _wl_fullscreen_shell_present_method present_method;
int width, height;
int fullscreen;
float pointer_x, pointer_y;
- enum wl_shell_surface_fullscreen_method fullscreen_method;
+ int focussed, draw_cursor;
+
+ struct wl_list output_list;
+ struct fs_output *current_output;
};
static void
@@ -114,7 +127,7 @@ redraw_handler(struct widget *widget, void *data)
cairo_t *cr;
int i;
double x, y, border;
- const char *method_name[] = { "default", "scale", "driver", "fill" };
+ const char *method_name[] = { "default", "center", "zoom", "zoom_crop", "stretch"};
surface = window_get_surface(fullscreen->window);
if (surface == NULL ||
@@ -140,17 +153,33 @@ redraw_handler(struct widget *widget, void *data)
allocation.y + 25);
cairo_set_source_rgb(cr, 1, 1, 1);
- draw_string(cr,
- "Surface size: %d, %d\n"
- "Scale: %d, transform: %d\n"
- "Pointer: %f,%f\n"
- "Fullscreen: %d, method: %s\n"
- "Keys: (s)cale, (t)ransform, si(z)e, (m)ethod, (f)ullscreen, (q)uit\n",
- fullscreen->width, fullscreen->height,
- window_get_buffer_scale (fullscreen->window),
- window_get_buffer_transform (fullscreen->window),
- fullscreen->pointer_x, fullscreen->pointer_y,
- fullscreen->fullscreen, method_name[fullscreen->fullscreen_method]);
+ if (fullscreen->fshell) {
+ draw_string(cr,
+ "Surface size: %d, %d\n"
+ "Scale: %d, transform: %d\n"
+ "Pointer: %f,%f\n"
+ "Output: %s, present method: %s\n"
+ "Keys: (s)cale, (t)ransform, si(z)e, (m)ethod,\n"
+ " (o)utput, modes(w)itch, (q)uit\n",
+ fullscreen->width, fullscreen->height,
+ window_get_buffer_scale (fullscreen->window),
+ window_get_buffer_transform (fullscreen->window),
+ fullscreen->pointer_x, fullscreen->pointer_y,
+ method_name[fullscreen->present_method],
+ fullscreen->current_output ? output_get_model(fullscreen->current_output->output): "null");
+ } else {
+ draw_string(cr,
+ "Surface size: %d, %d\n"
+ "Scale: %d, transform: %d\n"
+ "Pointer: %f,%f\n"
+ "Fullscreen: %d\n"
+ "Keys: (s)cale, (t)ransform, si(z)e, (f)ullscreen, (q)uit\n",
+ fullscreen->width, fullscreen->height,
+ window_get_buffer_scale (fullscreen->window),
+ window_get_buffer_transform (fullscreen->window),
+ fullscreen->pointer_x, fullscreen->pointer_y,
+ fullscreen->fullscreen);
+ }
y = 100;
i = 0;
@@ -160,7 +189,8 @@ redraw_handler(struct widget *widget, void *data)
x = 50;
cairo_set_line_width (cr, border);
while (x + 70 < fullscreen->width) {
- if (fullscreen->pointer_x >= x && fullscreen->pointer_x < x + 50 &&
+ if (fullscreen->focussed &&
+ fullscreen->pointer_x >= x && fullscreen->pointer_x < x + 50 &&
fullscreen->pointer_y >= y && fullscreen->pointer_y < y + 40) {
cairo_set_source_rgb(cr, 1, 0, 0);
cairo_rectangle(cr,
@@ -179,6 +209,44 @@ redraw_handler(struct widget *widget, void *data)
y += 50;
}
+ if (fullscreen->focussed && fullscreen->draw_cursor) {
+ cairo_set_source_rgb(cr, 1, 1, 1);
+ cairo_set_line_width (cr, 8);
+ cairo_move_to(cr,
+ fullscreen->pointer_x - 12,
+ fullscreen->pointer_y - 12);
+ cairo_line_to(cr,
+ fullscreen->pointer_x + 12,
+ fullscreen->pointer_y + 12);
+ cairo_stroke(cr);
+
+ cairo_move_to(cr,
+ fullscreen->pointer_x + 12,
+ fullscreen->pointer_y - 12);
+ cairo_line_to(cr,
+ fullscreen->pointer_x - 12,
+ fullscreen->pointer_y + 12);
+ cairo_stroke(cr);
+
+ cairo_set_source_rgb(cr, 0, 0, 0);
+ cairo_set_line_width (cr, 4);
+ cairo_move_to(cr,
+ fullscreen->pointer_x - 10,
+ fullscreen->pointer_y - 10);
+ cairo_line_to(cr,
+ fullscreen->pointer_x + 10,
+ fullscreen->pointer_y + 10);
+ cairo_stroke(cr);
+
+ cairo_move_to(cr,
+ fullscreen->pointer_x + 10,
+ fullscreen->pointer_y - 10);
+ cairo_line_to(cr,
+ fullscreen->pointer_x - 10,
+ fullscreen->pointer_y + 10);
+ cairo_stroke(cr);
+ }
+
cairo_destroy(cr);
}
@@ -190,6 +258,8 @@ key_handler(struct window *window, struct input *input, uint32_t time,
struct fullscreen *fullscreen = data;
int transform, scale;
static int current_size = 0;
+ struct fs_output *fsout;
+ struct wl_output *wl_output;
int widths[] = { 640, 320, 800, 400 };
int heights[] = { 480, 240, 600, 300 };
@@ -223,13 +293,68 @@ key_handler(struct window *window, struct input *input, uint32_t time,
break;
case XKB_KEY_m:
- fullscreen->fullscreen_method = (fullscreen->fullscreen_method + 1) % 4;
- window_set_fullscreen_method(fullscreen->window,
- fullscreen->fullscreen_method);
+ if (!fullscreen->fshell)
+ break;
+
+ wl_output = NULL;
+ if (fullscreen->current_output)
+ wl_output = output_get_wl_output(fullscreen->current_output->output);
+ fullscreen->present_method = (fullscreen->present_method + 1) % 5;
+ _wl_fullscreen_shell_present_surface(fullscreen->fshell,
+ window_get_wl_surface(fullscreen->window),
+ fullscreen->present_method,
+ wl_output);
+ window_schedule_redraw(window);
+ break;
+
+ case XKB_KEY_o:
+ if (!fullscreen->fshell)
+ break;
+
+ fsout = fullscreen->current_output;
+ wl_output = fsout ? output_get_wl_output(fsout->output) : NULL;
+
+ /* Clear the current presentation */
+ _wl_fullscreen_shell_present_surface(fullscreen->fshell, NULL,
+ 0, wl_output);
+
+ if (fullscreen->current_output) {
+ if (fullscreen->current_output->link.next == &fullscreen->output_list)
+ fsout = NULL;
+ else
+ fsout = wl_container_of(fullscreen->current_output->link.next,
+ fsout, link);
+ } else {
+ fsout = wl_container_of(fullscreen->output_list.next,
+ fsout, link);
+ }
+
+ fullscreen->current_output = fsout;
+ wl_output = fsout ? output_get_wl_output(fsout->output) : NULL;
+ _wl_fullscreen_shell_present_surface(fullscreen->fshell,
+ window_get_wl_surface(fullscreen->window),
+ fullscreen->present_method,
+ wl_output);
+ window_schedule_redraw(window);
+ break;
+
+ case XKB_KEY_w:
+ if (!fullscreen->fshell || !fullscreen->current_output)
+ break;
+
+ wl_output = NULL;
+ if (fullscreen->current_output)
+ wl_output = output_get_wl_output(fullscreen->current_output->output);
+ _wl_fullscreen_shell_mode_feedback_destroy(
+ _wl_fullscreen_shell_present_surface_for_mode(fullscreen->fshell,
+ window_get_wl_surface(fullscreen->window),
+ wl_output, 0));
window_schedule_redraw(window);
break;
case XKB_KEY_f:
+ if (fullscreen->fshell)
+ break;
fullscreen->fullscreen ^= 1;
window_set_fullscreen(window, fullscreen->fullscreen);
break;
@@ -253,9 +378,37 @@ motion_handler(struct widget *widget,
fullscreen->pointer_y = y;
widget_schedule_redraw(widget);
- return 0;
+
+ return fullscreen->draw_cursor ? CURSOR_BLANK : CURSOR_LEFT_PTR;
+}
+
+static int
+enter_handler(struct widget *widget,
+ struct input *input,
+ float x, float y, void *data)
+{
+ struct fullscreen *fullscreen = data;
+
+ fullscreen->focussed++;
+
+ fullscreen->pointer_x = x;
+ fullscreen->pointer_y = y;
+
+ widget_schedule_redraw(widget);
+
+ return fullscreen->draw_cursor ? CURSOR_BLANK : CURSOR_LEFT_PTR;
}
+static void
+leave_handler(struct widget *widget,
+ struct input *input, void *data)
+{
+ struct fullscreen *fullscreen = data;
+
+ fullscreen->focussed--;
+
+ widget_schedule_redraw(widget);
+}
static void
button_handler(struct widget *widget,
@@ -287,6 +440,25 @@ touch_handler(struct widget *widget, struct input *input,
}
static void
+fshell_capability_handler(void *data, struct _wl_fullscreen_shell *fshell,
+ uint32_t capability)
+{
+ struct fullscreen *fullscreen = data;
+
+ switch (capability) {
+ case _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE:
+ fullscreen->draw_cursor = 0;
+ break;
+ default:
+ break;
+ }
+}
+
+struct _wl_fullscreen_shell_listener fullscreen_shell_listener = {
+ fshell_capability_handler
+};
+
+static void
usage(int error_code)
{
fprintf(stderr, "Usage: fullscreen [OPTIONS]\n\n"
@@ -297,6 +469,38 @@ usage(int error_code)
exit(error_code);
}
+static void
+output_handler(struct output *output, void *data)
+{
+ struct fullscreen *fullscreen = data;
+ struct fs_output *fsout;
+
+ /* If we've already seen this one, don't add it to the list */
+ wl_list_for_each(fsout, &fullscreen->output_list, link)
+ if (fsout->output == output)
+ return;
+
+ fsout = calloc(1, sizeof *fsout);
+ fsout->output = output;
+ wl_list_insert(&fullscreen->output_list, &fsout->link);
+}
+
+static void
+global_handler(struct display *display, uint32_t id, const char *interface,
+ uint32_t version, void *data)
+{
+ struct fullscreen *fullscreen = data;
+
+ if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
+ fullscreen->fshell = display_bind(display, id,
+ &_wl_fullscreen_shell_interface,
+ 1);
+ _wl_fullscreen_shell_add_listener(fullscreen->fshell,
+ &fullscreen_shell_listener,
+ fullscreen);
+ }
+}
+
int main(int argc, char *argv[])
{
struct fullscreen fullscreen;
@@ -306,8 +510,10 @@ int main(int argc, char *argv[])
fullscreen.width = 640;
fullscreen.height = 480;
fullscreen.fullscreen = 0;
- fullscreen.fullscreen_method =
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
+ fullscreen.focussed = 0;
+ fullscreen.present_method = _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT;
+ wl_list_init(&fullscreen.output_list);
+ fullscreen.current_output = NULL;
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-w") == 0) {
@@ -333,21 +539,38 @@ int main(int argc, char *argv[])
}
fullscreen.display = d;
- fullscreen.window = window_create(d);
+ fullscreen.fshell = NULL;
+ display_set_user_data(fullscreen.display, &fullscreen);
+ display_set_global_handler(fullscreen.display, global_handler);
+ display_set_output_configure_handler(fullscreen.display, output_handler);
+
+ if (fullscreen.fshell) {
+ fullscreen.window = window_create_custom(d);
+ _wl_fullscreen_shell_present_surface(fullscreen.fshell,
+ window_get_wl_surface(fullscreen.window),
+ fullscreen.present_method,
+ NULL);
+ /* If we get the CURSOR_PLANE capability, we'll change this */
+ fullscreen.draw_cursor = 1;
+ } else {
+ fullscreen.window = window_create(d);
+ fullscreen.draw_cursor = 0;
+ }
+
fullscreen.widget =
window_add_widget(fullscreen.window, &fullscreen);
window_set_title(fullscreen.window, "Fullscreen");
- window_set_fullscreen_method(fullscreen.window,
- fullscreen.fullscreen_method);
widget_set_transparent(fullscreen.widget, 0);
- widget_set_default_cursor(fullscreen.widget, CURSOR_LEFT_PTR);
+ widget_set_default_cursor(fullscreen.widget, CURSOR_LEFT_PTR);
widget_set_resize_handler(fullscreen.widget, resize_handler);
widget_set_redraw_handler(fullscreen.widget, redraw_handler);
widget_set_button_handler(fullscreen.widget, button_handler);
widget_set_motion_handler(fullscreen.widget, motion_handler);
+ widget_set_enter_handler(fullscreen.widget, enter_handler);
+ widget_set_leave_handler(fullscreen.widget, leave_handler);
widget_set_touch_down_handler(fullscreen.widget, touch_handler);
diff --git a/clients/image.c b/clients/image.c
index 3a52c220..054979d9 100644
--- a/clients/image.c
+++ b/clients/image.c
@@ -21,6 +21,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/keyboard.c b/clients/keyboard.c
index 6876cdec..11fe21d4 100644
--- a/clients/keyboard.c
+++ b/clients/keyboard.c
@@ -21,6 +21,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/clients/nested-client.c b/clients/nested-client.c
index 1161a992..7f237e66 100644
--- a/clients/nested-client.c
+++ b/clients/nested-client.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
diff --git a/clients/nested.c b/clients/nested.c
index d75e953a..44389e40 100644
--- a/clients/nested.c
+++ b/clients/nested.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -976,6 +978,8 @@ ss_surface_init(struct nested_surface *surface)
nested,
SUBSURFACE_SYNCHRONIZED);
+ widget_set_use_cairo(ss_surface->widget, 0);
+
ss_surface->surface = widget_get_wl_surface(ss_surface->widget);
ss_surface->subsurface = widget_get_wl_subsurface(ss_surface->widget);
diff --git a/clients/resizor.c b/clients/resizor.c
index b5ea55f6..029042fd 100644
--- a/clients/resizor.c
+++ b/clients/resizor.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/scaler.c b/clients/scaler.c
index 97530961..f94e714b 100644
--- a/clients/scaler.c
+++ b/clients/scaler.c
@@ -21,8 +21,11 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdio.h>
#include <string.h>
+#include <assert.h>
#include <cairo.h>
#include <linux/input.h>
@@ -47,10 +50,73 @@ struct box {
int width, height;
struct wl_scaler *scaler;
+ int scaler_version;
struct wl_viewport *viewport;
+
+ enum {
+ MODE_NO_VIEWPORT,
+ MODE_SRC_ONLY,
+ MODE_DST_ONLY,
+ MODE_SRC_DST
+ } mode;
};
static void
+set_my_viewport(struct box *box)
+{
+ wl_fixed_t src_x, src_y, src_width, src_height;
+ int32_t dst_width = SURFACE_WIDTH;
+ int32_t dst_height = SURFACE_HEIGHT;
+
+ if (box->mode == MODE_NO_VIEWPORT)
+ return;
+
+ /* Cut the green border in half, take white border fully in,
+ * and black border fully out. The borders are 1px wide in buffer.
+ *
+ * The gl-renderer uses linear texture sampling, this means the
+ * top and left edges go to 100% green, bottom goes to 50% blue/black,
+ * right edge has thick white sliding to 50% red.
+ */
+ src_x = wl_fixed_from_double((RECT_X + 0.5) / BUFFER_SCALE);
+ src_y = wl_fixed_from_double((RECT_Y + 0.5) / BUFFER_SCALE);
+ src_width = wl_fixed_from_double((RECT_W - 0.5) / BUFFER_SCALE);
+ src_height = wl_fixed_from_double((RECT_H - 0.5) / BUFFER_SCALE);
+
+ if (box->scaler_version < 2 && box->mode != MODE_SRC_DST) {
+ fprintf(stderr, "Error: server's wl_scaler interface version "
+ "%d does not support this mode.\n",
+ box->scaler_version);
+ exit(1);
+ }
+
+ switch (box->mode){
+ case MODE_SRC_ONLY:
+ wl_viewport_set_source(box->viewport, src_x, src_y,
+ src_width, src_height);
+ break;
+ case MODE_DST_ONLY:
+ wl_viewport_set_destination(box->viewport,
+ dst_width, dst_height);
+ break;
+ case MODE_SRC_DST:
+ if (box->scaler_version < 2) {
+ wl_viewport_set(box->viewport,
+ src_x, src_y, src_width, src_height,
+ dst_width, dst_height);
+ } else {
+ wl_viewport_set_source(box->viewport, src_x, src_y,
+ src_width, src_height);
+ wl_viewport_set_destination(box->viewport,
+ dst_width, dst_height);
+ }
+ break;
+ default:
+ assert(!"not reached");
+ }
+}
+
+static void
resize_handler(struct widget *widget,
int32_t width, int32_t height, void *data)
{
@@ -120,30 +186,18 @@ global_handler(struct display *display, uint32_t name,
const char *interface, uint32_t version, void *data)
{
struct box *box = data;
- wl_fixed_t src_x, src_y, src_width, src_height;
-
- /* Cut the green border in half, take white border fully in,
- * and black border fully out. The borders are 1px wide in buffer.
- *
- * The gl-renderer uses linear texture sampling, this means the
- * top and left edges go to 100% green, bottom goes to 50% blue/black,
- * right edge has thick white sliding to 50% red.
- */
- src_x = wl_fixed_from_double((RECT_X + 0.5) / BUFFER_SCALE);
- src_y = wl_fixed_from_double((RECT_Y + 0.5) / BUFFER_SCALE);
- src_width = wl_fixed_from_double((RECT_W - 0.5) / BUFFER_SCALE);
- src_height = wl_fixed_from_double((RECT_H - 0.5) / BUFFER_SCALE);
if (strcmp(interface, "wl_scaler") == 0) {
+ box->scaler_version = version < 2 ? version : 2;
+
box->scaler = display_bind(display, name,
- &wl_scaler_interface, 1);
+ &wl_scaler_interface,
+ box->scaler_version);
box->viewport = wl_scaler_get_viewport(box->scaler,
widget_get_wl_surface(box->widget));
- wl_viewport_set(box->viewport,
- src_x, src_y, src_width, src_height,
- SURFACE_WIDTH, SURFACE_HEIGHT); /* dst */
+ set_my_viewport(box);
}
}
@@ -173,12 +227,52 @@ touch_down_handler(struct widget *widget, struct input *input,
display_get_serial(box->display));
}
+static void
+usage(const char *progname)
+{
+ fprintf(stderr, "Usage: %s [mode]\n"
+ "where 'mode' is one of\n"
+ " -b\tset both src and dst in viewport (default)\n"
+ " -d\tset only dst in viewport\n"
+ " -s\tset only src in viewport\n"
+ " -n\tdo not set viewport at all\n\n",
+ progname);
+
+ fprintf(stderr, "Expected output with output_scale=1:\n");
+
+ fprintf(stderr, "Mode -n:\n"
+ " window size %dx%d px\n"
+ " Red box with a blue box in the upper left part.\n"
+ " The blue box has white right edge, black bottom edge,\n"
+ " and thin green left and top edges that can really\n"
+ " be seen only when zoomed in.\n\n",
+ BUFFER_WIDTH / BUFFER_SCALE, BUFFER_HEIGHT / BUFFER_SCALE);
+
+ fprintf(stderr, "Mode -b:\n"
+ " window size %dx%d px\n"
+ " Blue box with green top and left edge,\n"
+ " thick white right edge with a hint of red,\n"
+ " and a hint of black in bottom edge.\n\n",
+ SURFACE_WIDTH, SURFACE_HEIGHT);
+
+ fprintf(stderr, "Mode -s:\n"
+ " window size %.0fx%.0f px\n"
+ " The same as mode -b, but scaled a lot smaller.\n\n",
+ RECT_W / BUFFER_SCALE, RECT_H / BUFFER_SCALE);
+
+ fprintf(stderr, "Mode -d:\n"
+ " window size %dx%d px\n"
+ " This is horizontally squashed version of the -n mode.\n\n",
+ SURFACE_WIDTH, SURFACE_HEIGHT);
+}
+
int
main(int argc, char *argv[])
{
struct box box;
struct display *d;
struct timeval tv;
+ int i;
d = display_create(&argc, argv);
if (d == NULL) {
@@ -186,6 +280,23 @@ main(int argc, char *argv[])
return -1;
}
+ box.mode = MODE_SRC_DST;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp("-s", argv[i]) == 0)
+ box.mode = MODE_SRC_ONLY;
+ else if (strcmp("-d", argv[i]) == 0)
+ box.mode = MODE_DST_ONLY;
+ else if (strcmp("-b", argv[i]) == 0)
+ box.mode = MODE_SRC_DST;
+ else if (strcmp("-n", argv[i]) == 0)
+ box.mode = MODE_NO_VIEWPORT;
+ else {
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
gettimeofday(&tv, NULL);
srandom(tv.tv_usec);
diff --git a/clients/simple-egl.c b/clients/simple-egl.c
index 2c009ee2..0d4673b5 100644
--- a/clients/simple-egl.c
+++ b/clients/simple-egl.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -38,6 +40,8 @@
#include <EGL/egl.h>
#include <EGL/eglext.h>
+#include "xdg-shell-client-protocol.h"
+
#ifndef EGL_EXT_swap_buffers_with_damage
#define EGL_EXT_swap_buffers_with_damage 1
typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC)(EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
@@ -55,7 +59,7 @@ struct display {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
- struct wl_shell *shell;
+ struct xdg_shell *shell;
struct wl_seat *seat;
struct wl_pointer *pointer;
struct wl_touch *touch;
@@ -90,10 +94,10 @@ struct window {
uint32_t benchmark_time, frames;
struct wl_egl_window *native;
struct wl_surface *surface;
- struct wl_shell_surface *shell_surface;
+ struct xdg_surface *xdg_surface;
EGLSurface egl_surface;
struct wl_callback *callback;
- int fullscreen, configured, opaque, buffer_size, frame_sync;
+ int fullscreen, opaque, buffer_size, frame_sync;
};
static const char *vert_shader_text =
@@ -263,15 +267,8 @@ init_gl(struct window *window)
}
static void
-handle_ping(void *data, struct wl_shell_surface *shell_surface,
- uint32_t serial)
-{
- wl_shell_surface_pong(shell_surface, serial);
-}
-
-static void
-handle_configure(void *data, struct wl_shell_surface *shell_surface,
- uint32_t edges, int32_t width, int32_t height)
+handle_surface_configure(void *data, struct xdg_surface *surface,
+ int32_t width, int32_t height)
{
struct window *window = data;
@@ -286,56 +283,51 @@ handle_configure(void *data, struct wl_shell_surface *shell_surface,
}
static void
-handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
-{
-}
-
-static const struct wl_shell_surface_listener shell_surface_listener = {
- handle_ping,
- handle_configure,
- handle_popup_done
-};
-
-static void
-configure_callback(void *data, struct wl_callback *callback, uint32_t time)
+handle_surface_change_state(void *data, struct xdg_surface *xdg_surface,
+ uint32_t state,
+ uint32_t value,
+ uint32_t serial)
{
struct window *window = data;
- wl_callback_destroy(callback);
+ switch (state) {
+ case XDG_SURFACE_STATE_FULLSCREEN:
+ window->fullscreen = value;
- window->configured = 1;
-}
+ if (!value)
+ handle_surface_configure(window, window->xdg_surface,
+ window->window_size.width,
+ window->window_size.height);
+ break;
+ }
-static struct wl_callback_listener configure_callback_listener = {
- configure_callback,
-};
+ xdg_surface_ack_change_state(xdg_surface, state, value, serial);
+}
static void
-set_fullscreen(struct window *window, int fullscreen)
+handle_surface_activated(void *data, struct xdg_surface *xdg_surface)
{
- struct wl_callback *callback;
-
- window->fullscreen = fullscreen;
- window->configured = 0;
+}
- if (fullscreen) {
- wl_shell_surface_set_fullscreen(window->shell_surface,
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
- 0, NULL);
- callback = wl_display_sync(window->display->display);
- wl_callback_add_listener(callback,
- &configure_callback_listener,
- window);
+static void
+handle_surface_deactivated(void *data, struct xdg_surface *xdg_surface)
+{
+}
- } else {
- wl_shell_surface_set_toplevel(window->shell_surface);
- handle_configure(window, window->shell_surface, 0,
- window->window_size.width,
- window->window_size.height);
- window->configured = 1;
- }
+static void
+handle_surface_delete(void *data, struct xdg_surface *xdg_surface)
+{
+ running = 0;
}
+static const struct xdg_surface_listener xdg_surface_listener = {
+ handle_surface_configure,
+ handle_surface_change_state,
+ handle_surface_activated,
+ handle_surface_deactivated,
+ handle_surface_delete,
+};
+
static void
create_surface(struct window *window)
{
@@ -343,11 +335,11 @@ create_surface(struct window *window)
EGLBoolean ret;
window->surface = wl_compositor_create_surface(display->compositor);
- window->shell_surface = wl_shell_get_shell_surface(display->shell,
- window->surface);
+ window->xdg_surface = xdg_shell_get_xdg_surface(display->shell,
+ window->surface);
- wl_shell_surface_add_listener(window->shell_surface,
- &shell_surface_listener, window);
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
window->native =
wl_egl_window_create(window->surface,
@@ -358,7 +350,7 @@ create_surface(struct window *window)
display->egl.conf,
window->native, NULL);
- wl_shell_surface_set_title(window->shell_surface, "simple-egl");
+ xdg_surface_set_title(window->xdg_surface, "simple-egl");
ret = eglMakeCurrent(window->display->egl.dpy, window->egl_surface,
window->egl_surface, window->display->egl.ctx);
@@ -367,7 +359,9 @@ create_surface(struct window *window)
if (!window->frame_sync)
eglSwapInterval(display->egl.dpy, 0);
- set_fullscreen(window, window->fullscreen);
+ xdg_surface_request_change_state(window->xdg_surface,
+ XDG_SURFACE_STATE_FULLSCREEN,
+ window->fullscreen, 0);
}
static void
@@ -381,7 +375,7 @@ destroy_surface(struct window *window)
eglDestroySurface(window->display->egl.dpy, window->egl_surface);
wl_egl_window_destroy(window->native);
- wl_shell_surface_destroy(window->shell_surface);
+ xdg_surface_destroy(window->xdg_surface);
wl_surface_destroy(window->surface);
if (window->callback)
@@ -412,7 +406,7 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
{ 0, 0, 1, 0 },
{ 0, 0, 0, 1 }
};
- static const int32_t speed_div = 5, benchmark_interval = 5;
+ static const uint32_t speed_div = 5, benchmark_interval = 5;
struct wl_region *region;
EGLint rect[4];
EGLint buffer_age = 0;
@@ -424,9 +418,6 @@ redraw(void *data, struct wl_callback *callback, uint32_t time)
if (callback)
wl_callback_destroy(callback);
- if (!window->configured)
- return;
-
gettimeofday(&tv, NULL);
time = tv.tv_sec * 1000 + tv.tv_usec / 1000;
if (window->frames == 0)
@@ -512,6 +503,8 @@ pointer_handle_enter(void *data, struct wl_pointer *pointer,
else if (cursor) {
image = display->default_cursor->images[0];
buffer = wl_cursor_image_get_buffer(image);
+ if (!buffer)
+ return;
wl_pointer_set_cursor(pointer, serial,
display->cursor_surface,
image->hotspot_x,
@@ -543,8 +536,8 @@ pointer_handle_button(void *data, struct wl_pointer *wl_pointer,
struct display *display = data;
if (button == BTN_LEFT && state == WL_POINTER_BUTTON_STATE_PRESSED)
- wl_shell_surface_move(display->window->shell_surface,
- display->seat, serial);
+ xdg_surface_move(display->window->xdg_surface,
+ display->seat, serial);
}
static void
@@ -568,7 +561,7 @@ touch_handle_down(void *data, struct wl_touch *wl_touch,
{
struct display *d = (struct display *)data;
- wl_shell_surface_move(d->window->shell_surface, d->seat, serial);
+ xdg_surface_move(d->window->xdg_surface, d->seat, serial);
}
static void
@@ -628,7 +621,9 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
struct display *d = data;
if (key == KEY_F11 && state)
- set_fullscreen(d->window, d->window->fullscreen ^ 1);
+ xdg_surface_request_change_state(d->window->xdg_surface,
+ XDG_SURFACE_STATE_FULLSCREEN,
+ !d->window->fullscreen, 0);
else if (key == KEY_ESC && state)
running = 0;
}
@@ -686,6 +681,22 @@ static const struct wl_seat_listener seat_listener = {
};
static void
+xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
+{
+ xdg_shell_pong(shell, serial);
+}
+
+static const struct xdg_shell_listener xdg_shell_listener = {
+ xdg_shell_ping,
+};
+
+#define XDG_VERSION 3 /* The version of xdg-shell that we implement */
+#ifdef static_assert
+static_assert(XDG_VERSION == XDG_SHELL_VERSION_CURRENT,
+ "Interface version doesn't match implementation version");
+#endif
+
+static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t name, const char *interface, uint32_t version)
{
@@ -695,9 +706,11 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->compositor =
wl_registry_bind(registry, name,
&wl_compositor_interface, 1);
- } else if (strcmp(interface, "wl_shell") == 0) {
+ } else if (strcmp(interface, "xdg_shell") == 0) {
d->shell = wl_registry_bind(registry, name,
- &wl_shell_interface, 1);
+ &xdg_shell_interface, 1);
+ xdg_shell_add_listener(d->shell, &xdg_shell_listener, d);
+ xdg_shell_use_unstable_version(d->shell, XDG_VERSION);
} else if (strcmp(interface, "wl_seat") == 0) {
d->seat = wl_registry_bind(registry, name,
&wl_seat_interface, 1);
@@ -706,8 +719,16 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->shm = wl_registry_bind(registry, name,
&wl_shm_interface, 1);
d->cursor_theme = wl_cursor_theme_load(NULL, 32, d->shm);
+ if (!d->cursor_theme) {
+ fprintf(stderr, "unable to load default theme\n");
+ return;
+ }
d->default_cursor =
wl_cursor_theme_get_cursor(d->cursor_theme, "left_ptr");
+ if (!d->default_cursor) {
+ fprintf(stderr, "unable to load default left pointer\n");
+ // TODO: abort ?
+ }
}
}
@@ -798,8 +819,6 @@ main(int argc, char **argv)
* queued up as a side effect. */
while (running && ret != -1) {
wl_display_dispatch_pending(display.display);
- while (!window.configured)
- wl_display_dispatch(display.display);
redraw(&window, NULL, 0);
}
@@ -813,7 +832,7 @@ main(int argc, char **argv)
wl_cursor_theme_destroy(display.cursor_theme);
if (display.shell)
- wl_shell_destroy(display.shell);
+ xdg_shell_destroy(display.shell);
if (display.compositor)
wl_compositor_destroy(display.compositor);
diff --git a/clients/simple-shm.c b/clients/simple-shm.c
index 81bb54ea..2087a0e6 100644
--- a/clients/simple-shm.c
+++ b/clients/simple-shm.c
@@ -34,12 +34,15 @@
#include <wayland-client.h>
#include "../shared/os-compatibility.h"
+#include "xdg-shell-client-protocol.h"
+#include "fullscreen-shell-client-protocol.h"
struct display {
struct wl_display *display;
struct wl_registry *registry;
struct wl_compositor *compositor;
- struct wl_shell *shell;
+ struct xdg_shell *shell;
+ struct _wl_fullscreen_shell *fshell;
struct wl_shm *shm;
uint32_t formats;
};
@@ -54,12 +57,14 @@ struct window {
struct display *display;
int width, height;
struct wl_surface *surface;
- struct wl_shell_surface *shell_surface;
+ struct xdg_surface *xdg_surface;
struct buffer buffers[2];
struct buffer *prev_buffer;
struct wl_callback *callback;
};
+static int running = 1;
+
static void
buffer_release(void *data, struct wl_buffer *buffer)
{
@@ -111,27 +116,41 @@ create_shm_buffer(struct display *display, struct buffer *buffer,
}
static void
-handle_ping(void *data, struct wl_shell_surface *shell_surface,
- uint32_t serial)
+handle_configure(void *data, struct xdg_surface *surface,
+ int32_t width, int32_t height)
+{
+}
+
+static void
+handle_change_state(void *data, struct xdg_surface *xdg_surface,
+ uint32_t state,
+ uint32_t value,
+ uint32_t serial)
{
- wl_shell_surface_pong(shell_surface, serial);
}
static void
-handle_configure(void *data, struct wl_shell_surface *shell_surface,
- uint32_t edges, int32_t width, int32_t height)
+handle_activated(void *data, struct xdg_surface *xdg_surface)
{
}
static void
-handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
+handle_deactivated(void *data, struct xdg_surface *xdg_surface)
{
}
-static const struct wl_shell_surface_listener shell_surface_listener = {
- handle_ping,
+static void
+handle_delete(void *data, struct xdg_surface *xdg_surface)
+{
+ running = 0;
+}
+
+static const struct xdg_surface_listener xdg_surface_listener = {
handle_configure,
- handle_popup_done
+ handle_change_state,
+ handle_activated,
+ handle_deactivated,
+ handle_delete,
};
static struct window *
@@ -148,16 +167,26 @@ create_window(struct display *display, int width, int height)
window->width = width;
window->height = height;
window->surface = wl_compositor_create_surface(display->compositor);
- window->shell_surface = wl_shell_get_shell_surface(display->shell,
- window->surface);
- if (window->shell_surface)
- wl_shell_surface_add_listener(window->shell_surface,
- &shell_surface_listener, window);
+ if (display->shell) {
+ window->xdg_surface =
+ xdg_shell_get_xdg_surface(display->shell,
+ window->surface);
- wl_shell_surface_set_title(window->shell_surface, "simple-shm");
+ assert(window->xdg_surface);
- wl_shell_surface_set_toplevel(window->shell_surface);
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+
+ xdg_surface_set_title(window->xdg_surface, "simple-shm");
+ } else if (display->fshell) {
+ _wl_fullscreen_shell_present_surface(display->fshell,
+ window->surface,
+ _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT,
+ NULL);
+ } else {
+ assert(0);
+ }
return window;
}
@@ -173,7 +202,8 @@ destroy_window(struct window *window)
if (window->buffers[1].buffer)
wl_buffer_destroy(window->buffers[1].buffer);
- wl_shell_surface_destroy(window->shell_surface);
+ if (window->xdg_surface)
+ xdg_surface_destroy(window->xdg_surface);
wl_surface_destroy(window->surface);
free(window);
}
@@ -301,6 +331,22 @@ struct wl_shm_listener shm_listener = {
};
static void
+xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
+{
+ xdg_shell_pong(shell, serial);
+}
+
+static const struct xdg_shell_listener xdg_shell_listener = {
+ xdg_shell_ping,
+};
+
+#define XDG_VERSION 3 /* The version of xdg-shell that we implement */
+#ifdef static_assert
+static_assert(XDG_VERSION == XDG_SHELL_VERSION_CURRENT,
+ "Interface version doesn't match implementation version");
+#endif
+
+static void
registry_handle_global(void *data, struct wl_registry *registry,
uint32_t id, const char *interface, uint32_t version)
{
@@ -310,9 +356,14 @@ registry_handle_global(void *data, struct wl_registry *registry,
d->compositor =
wl_registry_bind(registry,
id, &wl_compositor_interface, 1);
- } else if (strcmp(interface, "wl_shell") == 0) {
+ } else if (strcmp(interface, "xdg_shell") == 0) {
d->shell = wl_registry_bind(registry,
- id, &wl_shell_interface, 1);
+ id, &xdg_shell_interface, 1);
+ xdg_shell_use_unstable_version(d->shell, XDG_VERSION);
+ xdg_shell_add_listener(d->shell, &xdg_shell_listener, d);
+ } else if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
+ d->fshell = wl_registry_bind(registry,
+ id, &_wl_fullscreen_shell_interface, 1);
} else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry,
id, &wl_shm_interface, 1);
@@ -373,7 +424,10 @@ destroy_display(struct display *display)
wl_shm_destroy(display->shm);
if (display->shell)
- wl_shell_destroy(display->shell);
+ xdg_shell_destroy(display->shell);
+
+ if (display->fshell)
+ _wl_fullscreen_shell_release(display->fshell);
if (display->compositor)
wl_compositor_destroy(display->compositor);
@@ -384,8 +438,6 @@ destroy_display(struct display *display)
free(display);
}
-static int running = 1;
-
static void
signal_int(int signum)
{
diff --git a/clients/smoke.c b/clients/smoke.c
index dd5f4bd4..5d976af1 100644
--- a/clients/smoke.c
+++ b/clients/smoke.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/stacking.c b/clients/stacking.c
index 544094c6..347c598d 100644
--- a/clients/stacking.c
+++ b/clients/stacking.c
@@ -63,12 +63,8 @@ new_window(struct stacking *stacking, struct window *parent_window)
struct window *new_window;
struct widget *new_widget;
- if (parent_window == NULL) {
- new_window = window_create(stacking->display);
- } else {
- new_window = window_create_transient(stacking->display,
- parent_window, 50, 50, 0);
- }
+ new_window = window_create(stacking->display);
+ window_set_transient_for(new_window, parent_window);
new_widget = window_frame_create(new_window, new_window);
@@ -234,7 +230,7 @@ draw_string(cairo_t *cr,
static void
set_window_background_colour(cairo_t *cr, struct window *window)
{
- if (window_is_transient(window))
+ if (window_get_transient_for(window))
cairo_set_source_rgba(cr, 0.0, 1.0, 0.0, 0.4);
else if (window_is_maximized(window))
cairo_set_source_rgba(cr, 1.0, 1.0, 0.0, 0.6);
@@ -280,7 +276,7 @@ redraw_handler(struct widget *widget, void *data)
" (n)ew window, (p)opup,\n"
" (q)uit, (t)ransient window\n",
window, window_is_fullscreen(window),
- window_is_maximized(window), window_is_transient(window));
+ window_is_maximized(window), window_get_transient_for(window) ? 1 : 0);
cairo_destroy(cr);
}
diff --git a/clients/subsurfaces.c b/clients/subsurfaces.c
index 45cc44b4..66a10f25 100644
--- a/clients/subsurfaces.c
+++ b/clients/subsurfaces.c
@@ -22,6 +22,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
diff --git a/clients/terminal.c b/clients/terminal.c
index f3646fe3..beec877f 100644
--- a/clients/terminal.c
+++ b/clients/terminal.c
@@ -465,6 +465,7 @@ struct terminal {
double average_width;
cairo_scaled_font_t *font_normal, *font_bold;
uint32_t hide_cursor_serial;
+ int size_in_title;
struct wl_data_source *selection;
uint32_t click_time;
@@ -850,6 +851,7 @@ resize_handler(struct widget *widget,
widget_set_size(terminal->widget, width, height);
if (asprintf(&p, "%s — [%dx%d]", terminal->title, columns, rows) > 0) {
window_set_title(terminal->window, p);
+ terminal->size_in_title = 1;
free(p);
}
}
@@ -2740,7 +2742,10 @@ enter_handler(struct widget *widget,
struct terminal *terminal = data;
/* Reset title to get rid of resizing '[WxH]' in titlebar */
- window_set_title(terminal->window, terminal->title);
+ if (terminal->size_in_title) {
+ window_set_title(terminal->window, terminal->title);
+ terminal->size_in_title = 0;
+ }
return CURSOR_IBEAM;
}
@@ -2958,8 +2963,9 @@ terminal_run(struct terminal *terminal, const char *path)
display_watch_fd(terminal->display, terminal->master,
EPOLLIN | EPOLLHUP, &terminal->io_task);
- window_set_fullscreen(terminal->window, option_fullscreen);
- if (!window_is_fullscreen(terminal->window))
+ if (option_fullscreen)
+ window_set_fullscreen(terminal->window, 1);
+ else
terminal_resize(terminal, 80, 24);
return 0;
diff --git a/clients/transformed.c b/clients/transformed.c
index bbc1dc02..4b1cb056 100644
--- a/clients/transformed.c
+++ b/clients/transformed.c
@@ -21,6 +21,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
@@ -38,7 +40,6 @@ struct transformed {
struct widget *widget;
int width, height;
int fullscreen;
- enum wl_shell_surface_fullscreen_method fullscreen_method;
};
static void
@@ -100,16 +101,6 @@ fullscreen_handler(struct window *window, void *data)
}
static void
-resize_handler(struct widget *widget, int width, int height, void *data)
-{
- struct transformed *transformed = data;
-
- if (transformed->fullscreen_method !=
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT)
- widget_set_size(widget, transformed->width, transformed->height);
-}
-
-static void
redraw_handler(struct widget *widget, void *data)
{
struct transformed *transformed = data;
@@ -251,14 +242,9 @@ int main(int argc, char *argv[])
transformed.width = 500;
transformed.height = 250;
transformed.fullscreen = 0;
- transformed.fullscreen_method =
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
for (i = 1; i < argc; i++) {
- if (strcmp(argv[i], "-d") == 0) {
- transformed.fullscreen_method =
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER;
- } else if (strcmp(argv[i], "-w") == 0) {
+ if (strcmp(argv[i], "-w") == 0) {
if (++i >= argc)
usage(EXIT_FAILURE);
@@ -286,13 +272,10 @@ int main(int argc, char *argv[])
window_add_widget(transformed.window, &transformed);
window_set_title(transformed.window, "Transformed");
- window_set_fullscreen_method(transformed.window,
- transformed.fullscreen_method);
widget_set_transparent(transformed.widget, 0);
widget_set_default_cursor(transformed.widget, CURSOR_BLANK);
- widget_set_resize_handler(transformed.widget, resize_handler);
widget_set_redraw_handler(transformed.widget, redraw_handler);
widget_set_button_handler(transformed.widget, button_handler);
diff --git a/clients/window.c b/clients/window.c
index d8d79d04..e770a040 100644
--- a/clients/window.c
+++ b/clients/window.c
@@ -65,6 +65,7 @@ typedef void *EGLContext;
#include <linux/input.h>
#include <wayland-client.h>
#include "../shared/cairo-util.h"
+#include "xdg-shell-client-protocol.h"
#include "text-cursor-position-client-protocol.h"
#include "workspaces-client-protocol.h"
#include "../shared/os-compatibility.h"
@@ -85,11 +86,11 @@ struct display {
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_subcompositor *subcompositor;
- struct wl_shell *shell;
struct wl_shm *shm;
struct wl_data_device_manager *data_device_manager;
struct text_cursor_position *text_cursor_position;
struct workspace_manager *workspace_manager;
+ struct xdg_shell *xdg_shell;
EGLDisplay dpy;
EGLConfig argb_config;
EGLContext argb_ctx;
@@ -134,16 +135,6 @@ struct display {
int seat_version;
};
-enum {
- TYPE_NONE,
- TYPE_TOPLEVEL,
- TYPE_FULLSCREEN,
- TYPE_MAXIMIZED,
- TYPE_TRANSIENT,
- TYPE_MENU,
- TYPE_CUSTOM
-};
-
struct window_output {
struct output *output;
struct wl_list link;
@@ -227,18 +218,17 @@ struct window {
struct rectangle min_allocation;
struct rectangle pending_allocation;
int x, y;
- int resize_edges;
int redraw_needed;
int redraw_task_scheduled;
struct task redraw_task;
int resize_needed;
- int saved_type;
- int type;
- int focus_count;
+ int custom;
+ int focused;
int resizing;
- int fullscreen_method;
- int configure_requests;
+
+ int fullscreen;
+ int maximized;
enum preferred_format preferred_format;
@@ -251,7 +241,10 @@ struct window {
window_output_handler_t output_handler;
struct surface *main_surface;
- struct wl_shell_surface *shell_surface;
+ struct xdg_surface *xdg_surface;
+ struct xdg_popup *xdg_popup;
+
+ struct window *transient_for;
struct window_frame *frame;
@@ -355,6 +348,8 @@ struct output {
struct wl_list link;
int transform;
int scale;
+ char *make;
+ char *model;
display_output_handler_t destroy_handler;
void *user_data;
@@ -382,7 +377,6 @@ struct menu {
struct tooltip {
struct widget *parent;
- struct window *window;
struct widget *widget;
char *entry;
struct task tooltip_task;
@@ -402,22 +396,6 @@ enum {
CURSOR_UNSET
};
-enum window_location {
- WINDOW_INTERIOR = 0,
- WINDOW_RESIZING_TOP = 1,
- WINDOW_RESIZING_BOTTOM = 2,
- WINDOW_RESIZING_LEFT = 4,
- WINDOW_RESIZING_TOP_LEFT = 5,
- WINDOW_RESIZING_BOTTOM_LEFT = 6,
- WINDOW_RESIZING_RIGHT = 8,
- WINDOW_RESIZING_TOP_RIGHT = 9,
- WINDOW_RESIZING_BOTTOM_RIGHT = 10,
- WINDOW_RESIZING_MASK = 15,
- WINDOW_EXTERIOR = 16,
- WINDOW_TITLEBAR = 17,
- WINDOW_CLIENT_AREA = 18,
-};
-
static const cairo_user_data_key_t shm_surface_data_key;
/* #define DEBUG */
@@ -1303,6 +1281,10 @@ create_cursors(struct display *display)
weston_config_destroy(config);
display->cursor_theme = wl_cursor_theme_load(theme, size, display->shm);
+ if (!display->cursor_theme) {
+ fprintf(stderr, "could not load theme '%s'\n", theme);
+ return;
+ }
free(theme);
display->cursors =
xmalloc(ARRAY_LENGTH(cursors) * sizeof display->cursors[0]);
@@ -1367,28 +1349,16 @@ surface_flush(struct surface *surface)
int
window_has_focus(struct window *window)
{
- return window->focus_count > 0;
+ return window->focused;
}
static void
-window_flush(struct window *window)
+window_close(struct window *window)
{
- struct surface *surface;
-
- if (window->type == TYPE_NONE) {
- window->type = TYPE_TOPLEVEL;
- if (window->shell_surface)
- wl_shell_surface_set_toplevel(window->shell_surface);
- }
-
- wl_list_for_each(surface, &window->subsurface_list, link) {
- if (surface == window->main_surface)
- continue;
-
- surface_flush(surface);
- }
-
- surface_flush(window->main_surface);
+ if (window->close_handler)
+ window->close_handler(window->user_data);
+ else
+ display_exit(window->display);
}
struct display *
@@ -1398,7 +1368,7 @@ window_get_display(struct window *window)
}
static void
-surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags)
+surface_create_surface(struct surface *surface, uint32_t flags)
{
struct display *display = surface->window->display;
struct rectangle allocation = surface->allocation;
@@ -1418,7 +1388,7 @@ surface_create_surface(struct surface *surface, int dx, int dy, uint32_t flags)
flags, &allocation);
surface->cairo_surface = surface->toysurface->prepare(
- surface->toysurface, dx, dy,
+ surface->toysurface, 0, 0,
allocation.width, allocation.height, flags,
surface->buffer_transform, surface->buffer_scale);
}
@@ -1428,8 +1398,6 @@ window_create_main_surface(struct window *window)
{
struct surface *surface = window->main_surface;
uint32_t flags = 0;
- int dx = 0;
- int dy = 0;
if (window->resizing)
flags |= SURFACE_HINT_RESIZE;
@@ -1437,17 +1405,7 @@ window_create_main_surface(struct window *window)
if (window->preferred_format == WINDOW_PREFERRED_FORMAT_RGB565)
flags |= SURFACE_HINT_RGB565;
- if (window->resize_edges & WINDOW_RESIZING_LEFT)
- dx = surface->server_allocation.width -
- surface->allocation.width;
-
- if (window->resize_edges & WINDOW_RESIZING_TOP)
- dy = surface->server_allocation.height -
- surface->allocation.height;
-
- window->resize_edges = 0;
-
- surface_create_surface(surface, dx, dy, flags);
+ surface_create_surface(surface, flags);
}
int
@@ -1552,8 +1510,10 @@ window_destroy(struct window *window)
if (window->frame)
window_frame_destroy(window->frame);
- if (window->shell_surface)
- wl_shell_surface_destroy(window->shell_surface);
+ if (window->xdg_surface)
+ xdg_surface_destroy(window->xdg_surface);
+ if (window->xdg_popup)
+ xdg_popup_destroy(window->xdg_popup);
surface_destroy(window->main_surface);
@@ -1717,7 +1677,7 @@ widget_get_cairo_surface(struct widget *widget)
if (surface == window->main_surface)
window_create_main_surface(window);
else
- surface_create_surface(surface, 0, 0, 0);
+ surface_create_surface(surface, 0);
}
return surface->cairo_surface;
@@ -1977,6 +1937,7 @@ tooltip_redraw_handler(struct widget *widget, void *data)
int32_t width, height;
cr = widget_cairo_create(widget);
+ cairo_translate(cr, widget->allocation.x, widget->allocation.y);
cairo_set_operator(cr, CAIRO_OPERATOR_SOURCE);
cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
cairo_paint(cr);
@@ -1996,7 +1957,7 @@ tooltip_redraw_handler(struct widget *widget, void *data)
}
static cairo_text_extents_t
-get_text_extents(struct tooltip *tooltip)
+get_text_extents(struct display *display, struct tooltip *tooltip)
{
cairo_t *cr;
cairo_text_extents_t extents;
@@ -2005,7 +1966,7 @@ get_text_extents(struct tooltip *tooltip)
* created yet, and parent does not have a valid surface
* outside repaint, either.
*/
- cr = cairo_create(tooltip->window->display->dummy_surface);
+ cr = cairo_create(display->dummy_surface);
cairo_text_extents(cr, tooltip->entry, &extents);
cairo_destroy(cr);
@@ -2017,7 +1978,6 @@ window_create_tooltip(struct tooltip *tooltip)
{
struct widget *parent = tooltip->parent;
struct display *display = parent->window->display;
- struct window *window;
const int offset_y = 27;
const int margin = 3;
cairo_text_extents_t extents;
@@ -2025,18 +1985,13 @@ window_create_tooltip(struct tooltip *tooltip)
if (tooltip->widget)
return 0;
- window = window_create_transient(display, parent->window, tooltip->x,
- tooltip->y + offset_y,
- WL_SHELL_SURFACE_TRANSIENT_INACTIVE);
- if (!window)
- return -1;
+ tooltip->widget = window_add_subsurface(parent->window, tooltip, SUBSURFACE_DESYNCHRONIZED);
- tooltip->window = window;
- tooltip->widget = window_add_widget(tooltip->window, tooltip);
-
- extents = get_text_extents(tooltip);
+ extents = get_text_extents(display, tooltip);
widget_set_redraw_handler(tooltip->widget, tooltip_redraw_handler);
- window_schedule_resize(window, extents.width + 20, 20 + margin * 2);
+ widget_set_allocation(tooltip->widget,
+ tooltip->x, tooltip->y + offset_y,
+ extents.width + 20, 20 + margin * 2);
return 0;
}
@@ -2052,9 +2007,7 @@ widget_destroy_tooltip(struct widget *parent)
if (tooltip->widget) {
widget_destroy(tooltip->widget);
- window_destroy(tooltip->window);
tooltip->widget = NULL;
- tooltip->window = NULL;
}
close(tooltip->tooltip_fd);
@@ -2118,7 +2071,6 @@ widget_set_tooltip(struct widget *parent, char *entry, float x, float y)
parent->tooltip = tooltip;
tooltip->parent = parent;
tooltip->widget = NULL;
- tooltip->window = NULL;
tooltip->x = x;
tooltip->y = y;
tooltip->entry = strdup(entry);
@@ -2162,13 +2114,13 @@ frame_resize_handler(struct widget *widget,
struct rectangle input;
struct rectangle opaque;
- if (widget->window->type == TYPE_FULLSCREEN) {
+ if (widget->window->fullscreen) {
interior.x = 0;
interior.y = 0;
interior.width = width;
interior.height = height;
} else {
- if (widget->window->type == TYPE_MAXIMIZED) {
+ if (widget->window->maximized) {
frame_set_flag(frame->frame, FRAME_FLAG_MAXIMIZED);
} else {
frame_unset_flag(frame->frame, FRAME_FLAG_MAXIMIZED);
@@ -2186,7 +2138,7 @@ frame_resize_handler(struct widget *widget,
child->resize_handler(child, interior.width, interior.height,
child->user_data);
- if (widget->window->type == TYPE_FULLSCREEN) {
+ if (widget->window->fullscreen) {
width = child->allocation.width;
height = child->allocation.height;
} else {
@@ -2202,7 +2154,7 @@ frame_resize_handler(struct widget *widget,
widget->surface->input_region =
wl_compositor_create_region(widget->window->display->compositor);
- if (widget->window->type != TYPE_FULLSCREEN) {
+ if (!widget->window->fullscreen) {
frame_input_rect(frame->frame, &input.x, &input.y,
&input.width, &input.height);
wl_region_add(widget->surface->input_region,
@@ -2214,7 +2166,7 @@ frame_resize_handler(struct widget *widget,
widget_set_allocation(widget, 0, 0, width, height);
if (child->opaque) {
- if (widget->window->type != TYPE_FULLSCREEN) {
+ if (!widget->window->fullscreen) {
frame_opaque_rect(frame->frame, &opaque.x, &opaque.y,
&opaque.width, &opaque.height);
@@ -2238,10 +2190,10 @@ frame_redraw_handler(struct widget *widget, void *data)
struct window_frame *frame = data;
struct window *window = widget->window;
- if (window->type == TYPE_FULLSCREEN)
+ if (window->fullscreen)
return;
- if (window->focus_count) {
+ if (window->focused) {
frame_set_flag(frame->frame, FRAME_FLAG_ACTIVE);
} else {
frame_unset_flag(frame->frame, FRAME_FLAG_ACTIVE);
@@ -2260,7 +2212,7 @@ frame_get_pointer_image_for_location(struct window_frame *frame,
{
struct window *window = frame->widget->window;
- if (window->type != TYPE_TOPLEVEL)
+ if (window->custom)
return CURSOR_LEFT_PTR;
switch (location) {
@@ -2295,10 +2247,7 @@ frame_menu_func(struct window *window,
switch (index) {
case 0: /* close */
- if (window->close_handler)
- window->close_handler(window->user_data);
- else
- display_exit(window->display);
+ window_close(window);
break;
case 1: /* move to workspace above */
display = window->display;
@@ -2398,8 +2347,10 @@ frame_handle_status(struct window_frame *frame, struct input *input,
if (status & FRAME_STATUS_REPAINT)
widget_schedule_redraw(frame->widget);
- if (status & FRAME_STATUS_MINIMIZE)
- fprintf(stderr,"Minimize stub\n");
+ if (status & FRAME_STATUS_MINIMIZE) {
+ window_set_minimized(window);
+ frame_status_clear(frame->frame, FRAME_STATUS_MINIMIZE);
+ }
if (status & FRAME_STATUS_MENU) {
window_show_frame_menu(window, input, time);
@@ -2407,35 +2358,32 @@ frame_handle_status(struct window_frame *frame, struct input *input,
}
if (status & FRAME_STATUS_MAXIMIZE) {
- window_set_maximized(window, window->type != TYPE_MAXIMIZED);
+ window_set_maximized(window, !window->maximized);
frame_status_clear(frame->frame, FRAME_STATUS_MAXIMIZE);
}
if (status & FRAME_STATUS_CLOSE) {
- if (window->close_handler)
- window->close_handler(window->user_data);
- else
- display_exit(window->display);
+ window_close(window);
return;
}
- if ((status & FRAME_STATUS_MOVE) && window->shell_surface) {
+ if ((status & FRAME_STATUS_MOVE) && window->xdg_surface) {
input_ungrab(input);
- wl_shell_surface_move(window->shell_surface,
- input_get_seat(input),
- window->display->serial);
+ xdg_surface_move(window->xdg_surface,
+ input_get_seat(input),
+ window->display->serial);
frame_status_clear(frame->frame, FRAME_STATUS_MOVE);
}
- if ((status & FRAME_STATUS_RESIZE) && window->shell_surface) {
+ if ((status & FRAME_STATUS_RESIZE) && window->xdg_surface) {
input_ungrab(input);
window->resizing = 1;
- wl_shell_surface_resize(window->shell_surface,
- input_get_seat(input),
- window->display->serial,
- location);
+ xdg_surface_resize(window->xdg_surface,
+ input_get_seat(input),
+ window->display->serial,
+ location);
frame_status_clear(frame->frame, FRAME_STATUS_RESIZE);
}
@@ -2483,7 +2431,7 @@ window_frame_create(struct window *window, void *data)
struct window_frame *frame;
uint32_t buttons;
- if (window->type == TYPE_CUSTOM) {
+ if (window->custom) {
buttons = FRAME_BUTTON_NONE;
} else {
buttons = FRAME_BUTTON_ALL;
@@ -2518,9 +2466,9 @@ window_frame_set_child_size(struct widget *widget, int child_width,
struct theme *t = display->theme;
int decoration_width, decoration_height;
int width, height;
- int margin = widget->window->type == TYPE_MAXIMIZED ? 0 : t->margin;
+ int margin = widget->window->maximized ? 0 : t->margin;
- if (widget->window->type != TYPE_FULLSCREEN) {
+ if (!widget->window->fullscreen) {
decoration_width = (t->width + margin) * 2;
decoration_height = t->width +
t->titlebar_height + margin * 2;
@@ -2795,7 +2743,6 @@ input_remove_keyboard_focus(struct input *input)
if (!window)
return;
- window->focus_count--;
if (window->keyboard_focus_handler)
(*window->keyboard_focus_handler)(window, NULL,
window->user_data);
@@ -2894,7 +2841,6 @@ keyboard_handle_enter(void *data, struct wl_keyboard *keyboard,
input->keyboard_focus = wl_surface_get_user_data(surface);
window = input->keyboard_focus;
- window->focus_count++;
if (window->keyboard_focus_handler)
(*window->keyboard_focus_handler)(window,
input, window->user_data);
@@ -2937,8 +2883,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
if (sym == XKB_KEY_F5 && input->modifiers == MOD_ALT_MASK) {
if (state == WL_KEYBOARD_KEY_STATE_PRESSED)
- window_set_maximized(window,
- window->type != TYPE_MAXIMIZED);
+ window_set_maximized(window, !window->maximized);
} else if (sym == XKB_KEY_F11 &&
window->fullscreen_handler &&
state == WL_KEYBOARD_KEY_STATE_PRESSED) {
@@ -2946,10 +2891,7 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
} else if (sym == XKB_KEY_F4 &&
input->modifiers == MOD_ALT_MASK &&
state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- if (window->close_handler)
- window->close_handler(window->user_data);
- else
- display_exit(window->display);
+ window_close(window);
} else if (window->key_handler) {
(*window->key_handler)(window, input, time, key,
sym, state, window->user_data);
@@ -2962,7 +2904,8 @@ keyboard_handle_key(void *data, struct wl_keyboard *keyboard,
its.it_value.tv_sec = 0;
its.it_value.tv_nsec = 0;
timerfd_settime(input->repeat_timer_fd, 0, &its, NULL);
- } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
+ } else if (state == WL_KEYBOARD_KEY_STATE_PRESSED &&
+ xkb_keymap_key_repeats(input->xkb.keymap, code)) {
input->repeat_sym = sym;
input->repeat_key = key;
input->repeat_time = time;
@@ -3458,13 +3401,13 @@ input_set_pointer_image_index(struct input *input, int index)
if (!buffer)
return;
- wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial,
- input->pointer_surface,
- image->hotspot_x, image->hotspot_y);
wl_surface_attach(input->pointer_surface, buffer, 0, 0);
wl_surface_damage(input->pointer_surface, 0, 0,
image->width, image->height);
wl_surface_commit(input->pointer_surface);
+ wl_pointer_set_cursor(input->pointer, input->pointer_enter_serial,
+ input->pointer_surface,
+ image->hotspot_x, image->hotspot_y);
}
static const struct wl_callback_listener pointer_surface_listener;
@@ -3564,7 +3507,8 @@ void
input_set_selection(struct input *input,
struct wl_data_source *source, uint32_t time)
{
- wl_data_device_set_selection(input->data_device, source, time);
+ if (input->data_device)
+ wl_data_device_set_selection(input->data_device, source, time);
}
void
@@ -3668,10 +3612,10 @@ input_receive_selection_data_to_fd(struct input *input,
void
window_move(struct window *window, struct input *input, uint32_t serial)
{
- if (!window->shell_surface)
+ if (!window->xdg_surface)
return;
- wl_shell_surface_move(window->shell_surface, input->seat, serial);
+ xdg_surface_move(window->xdg_surface, input->seat, serial);
}
static void
@@ -3800,6 +3744,9 @@ window_do_resize(struct window *window)
surface_set_synchronized(surface);
surface_resize(surface);
}
+
+ if (!window->fullscreen && !window->maximized)
+ window->saved_allocation = window->pending_allocation;
}
static void
@@ -3880,52 +3827,137 @@ widget_schedule_resize(struct widget *widget, int32_t width, int32_t height)
}
static void
-handle_ping(void *data, struct wl_shell_surface *shell_surface,
- uint32_t serial)
+handle_surface_configure(void *data, struct xdg_surface *xdg_surface,
+ int32_t width, int32_t height)
{
- wl_shell_surface_pong(shell_surface, serial);
+ struct window *window = data;
+
+ window_schedule_resize(window, width, height);
}
static void
-handle_configure(void *data, struct wl_shell_surface *shell_surface,
- uint32_t edges, int32_t width, int32_t height)
+handle_surface_change_state(void *data, struct xdg_surface *xdg_surface,
+ uint32_t state,
+ uint32_t value,
+ uint32_t serial)
{
struct window *window = data;
- window->resize_edges = edges;
- window_schedule_resize(window, width, height);
+ switch (state) {
+ case XDG_SURFACE_STATE_MAXIMIZED:
+ window->maximized = value;
+ break;
+ case XDG_SURFACE_STATE_FULLSCREEN:
+ window->fullscreen = value;
+ break;
+ }
+
+ if (!window->fullscreen && !window->maximized)
+ window_schedule_resize(window,
+ window->saved_allocation.width,
+ window->saved_allocation.height);
+
+ xdg_surface_ack_change_state(xdg_surface, state, value, serial);
+ window_schedule_redraw(window);
}
static void
-menu_destroy(struct menu *menu)
+handle_surface_activated(void *data, struct xdg_surface *xdg_surface)
{
- widget_destroy(menu->widget);
- window_destroy(menu->window);
- frame_destroy(menu->frame);
- free(menu);
+ struct window *window = data;
+ window->focused = 1;
}
static void
-handle_popup_done(void *data, struct wl_shell_surface *shell_surface)
+handle_surface_deactivated(void *data, struct xdg_surface *xdg_surface)
{
struct window *window = data;
- struct menu *menu = window->main_surface->widget->user_data;
-
- /* FIXME: Need more context in this event, at least the input
- * device. Or just use wl_callback. And this really needs to
- * be a window vfunc that the menu can set. And we need the
- * time. */
+ window->focused = 0;
+}
- input_ungrab(menu->input);
- menu_destroy(menu);
+static void
+handle_surface_delete(void *data, struct xdg_surface *xdg_surface)
+{
+ struct window *window = data;
+ window_close(window);
}
-static const struct wl_shell_surface_listener shell_surface_listener = {
- handle_ping,
- handle_configure,
- handle_popup_done
+static const struct xdg_surface_listener xdg_surface_listener = {
+ handle_surface_configure,
+ handle_surface_change_state,
+ handle_surface_activated,
+ handle_surface_deactivated,
+ handle_surface_delete,
};
+static void
+window_sync_transient_for(struct window *window)
+{
+ struct wl_surface *parent_surface;
+
+ if (!window->xdg_surface)
+ return;
+
+ if (window->transient_for)
+ parent_surface = window->transient_for->main_surface->surface;
+ else
+ parent_surface = NULL;
+
+ xdg_surface_set_transient_for(window->xdg_surface, parent_surface);
+}
+
+static void
+window_sync_margin(struct window *window)
+{
+ int margin;
+
+ if (!window->xdg_surface)
+ return;
+
+ if (!window->frame)
+ return;
+
+ margin = frame_get_shadow_margin(window->frame->frame);
+
+ /* Shadow size is the same on every side. */
+ xdg_surface_set_margin(window->xdg_surface,
+ margin,
+ margin,
+ margin,
+ margin);
+}
+
+static void
+window_flush(struct window *window)
+{
+ struct surface *surface;
+
+ if (!window->custom) {
+ if (window->xdg_surface) {
+ window_sync_transient_for(window);
+ window_sync_margin(window);
+ }
+ }
+
+ wl_list_for_each(surface, &window->subsurface_list, link) {
+ if (surface == window->main_surface)
+ continue;
+
+ surface_flush(surface);
+ }
+
+ surface_flush(window->main_surface);
+}
+
+static void
+menu_destroy(struct menu *menu)
+{
+ widget_destroy(menu->widget);
+ window_destroy(menu->window);
+ frame_destroy(menu->frame);
+ free(menu);
+}
+
void
window_get_allocation(struct window *window,
struct rectangle *allocation)
@@ -4057,8 +4089,6 @@ idle_redraw(struct task *task, uint32_t events)
static void
window_schedule_redraw_task(struct window *window)
{
- if (window->configure_requests)
- return;
if (!window->redraw_task_scheduled) {
window->redraw_task.run = idle_redraw;
display_defer(window->display, &window->redraw_task);
@@ -4082,117 +4112,52 @@ window_schedule_redraw(struct window *window)
int
window_is_fullscreen(struct window *window)
{
- return window->type == TYPE_FULLSCREEN;
-}
-
-int
-window_is_transient(struct window *window)
-{
- return window->type == TYPE_TRANSIENT;
-}
-
-static void
-configure_request_completed(void *data, struct wl_callback *callback, uint32_t time)
-{
- struct window *window = data;
-
- wl_callback_destroy(callback);
- window->configure_requests--;
-
- if (!window->configure_requests)
- window_schedule_redraw(window);
-}
-
-static struct wl_callback_listener configure_request_listener = {
- configure_request_completed,
-};
-
-static void
-window_defer_redraw_until_configure(struct window* window)
-{
- struct wl_callback *callback;
-
- if (window->redraw_task_scheduled) {
- wl_list_remove(&window->redraw_task.link);
- window->redraw_task_scheduled = 0;
- }
-
- callback = wl_display_sync(window->display->display);
- wl_callback_add_listener(callback, &configure_request_listener, window);
- window->configure_requests++;
+ return window->fullscreen;
}
void
window_set_fullscreen(struct window *window, int fullscreen)
{
- if (!window->display->shell)
+ if (!window->xdg_surface)
return;
- if ((window->type == TYPE_FULLSCREEN) == fullscreen)
+ if (window->fullscreen == fullscreen)
return;
- if (fullscreen) {
- window->saved_type = window->type;
- if (window->type == TYPE_TOPLEVEL) {
- window->saved_allocation = window->main_surface->allocation;
- }
- window->type = TYPE_FULLSCREEN;
- wl_shell_surface_set_fullscreen(window->shell_surface,
- window->fullscreen_method,
- 0, NULL);
- window_defer_redraw_until_configure (window);
- } else {
- if (window->saved_type == TYPE_MAXIMIZED) {
- window_set_maximized(window, 1);
- } else {
- window->type = TYPE_TOPLEVEL;
- wl_shell_surface_set_toplevel(window->shell_surface);
- window_schedule_resize(window,
- window->saved_allocation.width,
- window->saved_allocation.height);
- }
-
- }
-}
-
-void
-window_set_fullscreen_method(struct window *window,
- enum wl_shell_surface_fullscreen_method method)
-{
- window->fullscreen_method = method;
+ xdg_surface_request_change_state(window->xdg_surface,
+ XDG_SURFACE_STATE_FULLSCREEN,
+ fullscreen ? 1 : 0,
+ 0);
}
int
window_is_maximized(struct window *window)
{
- return window->type == TYPE_MAXIMIZED;
+ return window->maximized;
}
void
window_set_maximized(struct window *window, int maximized)
{
- if (!window->display->shell)
+ if (!window->xdg_surface)
return;
- if ((window->type == TYPE_MAXIMIZED) == maximized)
+ if (window->maximized == maximized)
return;
- if (window->type == TYPE_TOPLEVEL) {
- window->saved_allocation = window->main_surface->allocation;
- wl_shell_surface_set_maximized(window->shell_surface, NULL);
- window->type = TYPE_MAXIMIZED;
- window_defer_redraw_until_configure(window);
- } else if (window->type == TYPE_FULLSCREEN) {
- wl_shell_surface_set_maximized(window->shell_surface, NULL);
- window->type = TYPE_MAXIMIZED;
- window_defer_redraw_until_configure(window);
- } else {
- wl_shell_surface_set_toplevel(window->shell_surface);
- window->type = TYPE_TOPLEVEL;
- window_schedule_resize(window,
- window->saved_allocation.width,
- window->saved_allocation.height);
- }
+ xdg_surface_request_change_state(window->xdg_surface,
+ XDG_SURFACE_STATE_MAXIMIZED,
+ maximized ? 1 : 0,
+ 0);
+}
+
+void
+window_set_minimized(struct window *window)
+{
+ if (!window->xdg_surface)
+ return;
+
+ xdg_surface_set_minimized(window->xdg_surface);
}
void
@@ -4263,8 +4228,8 @@ window_set_title(struct window *window, const char *title)
frame_set_title(window->frame->frame, title);
widget_schedule_redraw(window->frame->widget);
}
- if (window->shell_surface)
- wl_shell_surface_set_title(window->shell_surface, title);
+ if (window->xdg_surface)
+ xdg_surface_set_title(window->xdg_surface, title);
}
const char *
@@ -4377,7 +4342,7 @@ surface_create(struct window *window)
}
static struct window *
-window_create_internal(struct display *display, int type)
+window_create_internal(struct display *display, int custom)
{
struct window *window;
struct surface *surface;
@@ -4389,16 +4354,9 @@ window_create_internal(struct display *display, int type)
surface = surface_create(window);
window->main_surface = surface;
- if (type != TYPE_CUSTOM && display->shell) {
- window->shell_surface =
- wl_shell_get_shell_surface(display->shell,
- surface->surface);
- fail_on_null(window->shell_surface);
- }
+ assert(custom || display->xdg_shell);
- window->type = type;
- window->fullscreen_method = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
- window->configure_requests = 0;
+ window->custom = custom;
window->preferred_format = WINDOW_PREFERRED_FORMAT_NONE;
if (display->argb_device)
@@ -4414,12 +4372,6 @@ window_create_internal(struct display *display, int type)
wl_list_insert(display->window_list.prev, &window->link);
wl_list_init(&window->redraw_task.link);
- if (window->shell_surface) {
- wl_shell_surface_set_user_data(window->shell_surface, window);
- wl_shell_surface_add_listener(window->shell_surface,
- &shell_surface_listener, window);
- }
-
wl_list_init (&window->window_output_list);
return window;
@@ -4428,33 +4380,40 @@ window_create_internal(struct display *display, int type)
struct window *
window_create(struct display *display)
{
- return window_create_internal(display, TYPE_NONE);
+ struct window *window;
+
+ window = window_create_internal(display, 0);
+
+ window->xdg_surface =
+ xdg_shell_get_xdg_surface(window->display->xdg_shell,
+ window->main_surface->surface);
+ fail_on_null(window->xdg_surface);
+
+ xdg_surface_set_user_data(window->xdg_surface, window);
+ xdg_surface_add_listener(window->xdg_surface,
+ &xdg_surface_listener, window);
+
+ return window;
}
struct window *
window_create_custom(struct display *display)
{
- return window_create_internal(display, TYPE_CUSTOM);
+ return window_create_internal(display, 1);
}
-struct window *
-window_create_transient(struct display *display, struct window *parent,
- int32_t x, int32_t y, uint32_t flags)
+void
+window_set_transient_for(struct window *window,
+ struct window *parent_window)
{
- struct window *window;
-
- window = window_create_internal(parent->display, TYPE_TRANSIENT);
-
- window->x = x;
- window->y = y;
-
- if (display->shell)
- wl_shell_surface_set_transient(
- window->shell_surface,
- parent->main_surface->surface,
- window->x, window->y, flags);
+ window->transient_for = parent_window;
+ window_sync_transient_for(window);
+}
- return window;
+struct window *
+window_get_transient_for(struct window *window)
+{
+ return window->transient_for;
}
static void
@@ -4567,6 +4526,20 @@ menu_redraw_handler(struct widget *widget, void *data)
cairo_destroy(cr);
}
+static void
+handle_popup_popup_done(void *data, struct xdg_popup *xdg_popup, uint32_t serial)
+{
+ struct window *window = data;
+ struct menu *menu = window->main_surface->widget->user_data;
+
+ input_ungrab(menu->input);
+ menu_destroy(menu);
+}
+
+static const struct xdg_popup_listener xdg_popup_listener = {
+ handle_popup_popup_done,
+};
+
void
window_show_menu(struct display *display,
struct input *input, uint32_t time, struct window *parent,
@@ -4581,7 +4554,7 @@ window_show_menu(struct display *display,
if (!menu)
return;
- window = window_create_internal(parent->display, TYPE_MENU);
+ window = window_create_internal(parent->display, 0);
if (!window) {
free(menu);
return;
@@ -4602,7 +4575,6 @@ window_show_menu(struct display *display,
menu->time = time;
menu->func = func;
menu->input = input;
- window->type = TYPE_MENU;
window->x = x;
window->y = y;
@@ -4621,10 +4593,20 @@ window_show_menu(struct display *display,
frame_height(menu->frame));
frame_interior(menu->frame, &ix, &iy, NULL, NULL);
- wl_shell_surface_set_popup(window->shell_surface, input->seat,
- display_get_serial(window->display),
- parent->main_surface->surface,
- window->x - ix, window->y - iy, 0);
+
+ window->xdg_popup = xdg_shell_get_xdg_popup(display->xdg_shell,
+ window->main_surface->surface,
+ parent->main_surface->surface,
+ input->seat,
+ display_get_serial(window->display),
+ window->x - ix,
+ window->y - iy,
+ 0);
+ fail_on_null(window->xdg_popup);
+
+ xdg_popup_set_user_data(window->xdg_popup, window);
+ xdg_popup_add_listener(window->xdg_popup,
+ &xdg_popup_listener, window);
}
void
@@ -4633,6 +4615,12 @@ window_set_buffer_type(struct window *window, enum window_buffer_type type)
window->main_surface->buffer_type = type;
}
+enum window_buffer_type
+window_get_buffer_type(struct window *window)
+{
+ return window->main_surface->buffer_type;
+}
+
void
window_set_preferred_format(struct window *window,
enum preferred_format format)
@@ -4650,6 +4638,7 @@ window_add_subsurface(struct window *window, void *data,
struct wl_subcompositor *subcompo = window->display->subcompositor;
surface = surface_create(window);
+ surface->buffer_type = window_get_buffer_type(window);
widget = widget_create(window, surface, data);
wl_list_init(&widget->link);
surface->widget = widget;
@@ -4671,6 +4660,9 @@ window_add_subsurface(struct window *window, void *data,
assert(!"bad enum subsurface_mode");
}
+ window->resize_needed = 1;
+ window_schedule_redraw(window);
+
return widget;
}
@@ -4690,6 +4682,14 @@ display_handle_geometry(void *data,
output->allocation.x = x;
output->allocation.y = y;
output->transform = transform;
+
+ if (output->make)
+ free(output->make);
+ output->make = strdup(make);
+
+ if (output->model)
+ free(output->model);
+ output->model = strdup(model);
}
static void
@@ -4877,6 +4877,18 @@ output_get_scale(struct output *output)
return output->scale;
}
+const char *
+output_get_make(struct output *output)
+{
+ return output->make;
+}
+
+const char *
+output_get_model(struct output *output)
+{
+ return output->model;
+}
+
static void
fini_xkb(struct input *input)
{
@@ -4904,11 +4916,14 @@ display_add_input(struct display *d, uint32_t id)
wl_seat_add_listener(input->seat, &seat_listener, input);
wl_seat_set_user_data(input->seat, input);
- input->data_device =
- wl_data_device_manager_get_data_device(d->data_device_manager,
- input->seat);
- wl_data_device_add_listener(input->data_device, &data_device_listener,
- input);
+ if (d->data_device_manager) {
+ input->data_device =
+ wl_data_device_manager_get_data_device(d->data_device_manager,
+ input->seat);
+ wl_data_device_add_listener(input->data_device,
+ &data_device_listener,
+ input);
+ }
input->pointer_surface = wl_compositor_create_surface(d->compositor);
@@ -4931,7 +4946,8 @@ input_destroy(struct input *input)
if (input->selection_offer)
data_offer_destroy(input->selection_offer);
- wl_data_device_destroy(input->data_device);
+ if (input->data_device)
+ wl_data_device_destroy(input->data_device);
if (input->display->seat_version >= 3) {
if (input->pointer)
@@ -4976,6 +4992,22 @@ struct wl_shm_listener shm_listener = {
};
static void
+xdg_shell_ping(void *data, struct xdg_shell *shell, uint32_t serial)
+{
+ xdg_shell_pong(shell, serial);
+}
+
+static const struct xdg_shell_listener xdg_shell_listener = {
+ xdg_shell_ping,
+};
+
+#define XDG_VERSION 3 /* The version of xdg-shell that we implement */
+#ifdef static_assert
+static_assert(XDG_VERSION == XDG_SHELL_VERSION_CURRENT,
+ "Interface version doesn't match implementation version");
+#endif
+
+static void
registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
const char *interface, uint32_t version)
{
@@ -4996,9 +5028,6 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
} else if (strcmp(interface, "wl_seat") == 0) {
d->seat_version = version;
display_add_input(d, id);
- } else if (strcmp(interface, "wl_shell") == 0) {
- d->shell = wl_registry_bind(registry,
- id, &wl_shell_interface, 1);
} else if (strcmp(interface, "wl_shm") == 0) {
d->shm = wl_registry_bind(registry, id, &wl_shm_interface, 1);
wl_shm_add_listener(d->shm, &shm_listener, d);
@@ -5006,6 +5035,11 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
d->data_device_manager =
wl_registry_bind(registry, id,
&wl_data_device_manager_interface, 1);
+ } else if (strcmp(interface, "xdg_shell") == 0) {
+ d->xdg_shell = wl_registry_bind(registry, id,
+ &xdg_shell_interface, 1);
+ xdg_shell_use_unstable_version(d->xdg_shell, XDG_VERSION);
+ xdg_shell_add_listener(d->xdg_shell, &xdg_shell_listener, d);
} else if (strcmp(interface, "text_cursor_position") == 0) {
d->text_cursor_position =
wl_registry_bind(registry, id,
@@ -5312,8 +5346,8 @@ display_destroy(struct display *display)
if (display->subcompositor)
wl_subcompositor_destroy(display->subcompositor);
- if (display->shell)
- wl_shell_destroy(display->shell);
+ if (display->xdg_shell)
+ xdg_shell_destroy(display->xdg_shell);
if (display->shm)
wl_shm_destroy(display->shm);
@@ -5396,7 +5430,10 @@ display_get_egl_display(struct display *d)
struct wl_data_source *
display_create_data_source(struct display *display)
{
- return wl_data_device_manager_create_data_source(display->data_device_manager);
+ if (display->data_device_manager)
+ return wl_data_device_manager_create_data_source(display->data_device_manager);
+ else
+ return NULL;
}
EGLConfig
diff --git a/clients/window.h b/clients/window.h
index dec133fc..4e4ccc1d 100644
--- a/clients/window.h
+++ b/clients/window.h
@@ -23,6 +23,8 @@
#ifndef _WINDOW_H_
#define _WINDOW_H_
+#include "config.h"
+
#include <xkbcommon/xkbcommon.h>
#include <wayland-client.h>
#include <cairo.h>
@@ -270,11 +272,13 @@ typedef void (*widget_axis_handler_t)(struct widget *widget,
struct window *
window_create(struct display *display);
struct window *
-window_create_transient(struct display *display, struct window *parent,
- int32_t x, int32_t y, uint32_t flags);
-struct window *
window_create_custom(struct display *display);
+void
+window_set_transient_for(struct window *window, struct window *parent_window);
+struct window *
+window_get_transient_for(struct window *window);
+
int
window_has_focus(struct window *window);
@@ -362,8 +366,8 @@ display_surface_damage(struct display *display, cairo_surface_t *cairo_surface,
void
window_set_buffer_type(struct window *window, enum window_buffer_type type);
-int
-window_is_transient(struct window *window);
+enum window_buffer_type
+window_get_buffer_type(struct window *window);
int
window_is_fullscreen(struct window *window);
@@ -371,9 +375,6 @@ window_is_fullscreen(struct window *window);
void
window_set_fullscreen(struct window *window, int fullscreen);
-void
-window_set_fullscreen_method(struct window *window,
- enum wl_shell_surface_fullscreen_method method);
int
window_is_maximized(struct window *window);
@@ -381,6 +382,9 @@ void
window_set_maximized(struct window *window, int maximized);
void
+window_set_minimized(struct window *window);
+
+void
window_set_user_data(struct window *window, void *data);
void *
@@ -603,6 +607,12 @@ output_get_transform(struct output *output);
uint32_t
output_get_scale(struct output *output);
+const char *
+output_get_make(struct output *output);
+
+const char *
+output_get_model(struct output *output);
+
void
keysym_modifiers_add(struct wl_array *modifiers_map,
const char *name);
diff --git a/clients/wscreensaver.h b/clients/wscreensaver.h
index e2749d97..f85b94c6 100644
--- a/clients/wscreensaver.h
+++ b/clients/wscreensaver.h
@@ -23,6 +23,8 @@
#ifndef WSCREENSAVER_H
#define WSCREENSAVER_H
+#include "config.h"
+
#define MESA_EGL_NO_X11_HEADERS
#include <EGL/egl.h>
diff --git a/configure.ac b/configure.ac
index cce18500..4cfab8b2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,6 +1,6 @@
m4_define([weston_major_version], [1])
m4_define([weston_minor_version], [4])
-m4_define([weston_micro_version], [0])
+m4_define([weston_micro_version], [91])
m4_define([weston_version],
[weston_major_version.weston_minor_version.weston_micro_version])
@@ -16,12 +16,13 @@ AC_SUBST([WESTON_VERSION_MINOR], [weston_minor_version])
AC_SUBST([WESTON_VERSION_MICRO], [weston_micro_version])
AC_SUBST([WESTON_VERSION], [weston_version])
+AC_CONFIG_AUX_DIR([build-aux])
AC_CONFIG_HEADERS([config.h])
AC_USE_SYSTEM_EXTENSIONS
AC_SYS_LARGEFILE
-AM_INIT_AUTOMAKE([1.11 parallel-tests foreign no-dist-gzip dist-xz color-tests])
+AM_INIT_AUTOMAKE([1.11 parallel-tests foreign no-dist-gzip dist-xz color-tests subdir-objects])
AM_SILENT_RULES([yes])
@@ -98,7 +99,7 @@ if test x$enable_xwayland = xyes; then
AC_ARG_WITH(xserver-path, AS_HELP_STRING([--with-xserver-path=PATH],
[Path to X server]), [XSERVER_PATH="$withval"],
- [XSERVER_PATH="$bindir/Xorg"])
+ [XSERVER_PATH="$bindir/Xwayland"])
AC_SUBST([XSERVER_PATH])
if test x$enable_xwayland_test = xyes; then
PKG_CHECK_MODULES([XWAYLAND_TEST], xcb xcb-dri2 libdrm)
@@ -152,6 +153,16 @@ if test x$enable_drm_compositor = xyes; then
PKG_CHECK_MODULES(DRM_COMPOSITOR, [libudev >= 136 libdrm >= 2.4.30 gbm mtdev >= 1.1.0])
fi
+
+AC_ARG_ENABLE(libinput-backend, [ --enable-libinput-backend],,
+ enable_libinput_backend=no)
+AM_CONDITIONAL([ENABLE_LIBINPUT_BACKEND], [test x$enable_libinput_backend = xyes])
+if test x$enable_libinput_backend = xyes; then
+ AC_DEFINE([BUILD_LIBINPUT_BACKEND], [1], [Build the libinput input device backend])
+ PKG_CHECK_MODULES(LIBINPUT_BACKEND, [libinput >= 0.1.0])
+fi
+
+
PKG_CHECK_MODULES(COMPOSITOR, [$COMPOSITOR_MODULES])
AC_ARG_ENABLE(wayland-compositor, [ --enable-wayland-compositor],,
@@ -211,6 +222,18 @@ if test x$enable_rdp_compositor = xyes; then
CPPFLAGS="$SAVED_CPPFLAGS"
fi
+AC_ARG_ENABLE([screen-sharing], [--enable-screen-sharing],,
+ enable_screen_sharing=no)
+AM_CONDITIONAL([ENABLE_SCREEN_SHARING],
+ [test x$enable_screen_sharing = xyes])
+if test x$enable_screen_sharing = xyes; then
+ PKG_CHECK_MODULES(SCREEN_SHARE, [wayland-client])
+
+ if test x$enable_rdp_compositor != xyes; then
+ AC_MSG_WARN([The screen-share.so module requires the RDP backend.])
+ fi
+fi
+
AC_ARG_WITH(cairo,
AS_HELP_STRING([--with-cairo=@<:@image|gl|glesv2@:>@]
[Which Cairo renderer to use for the clients]),
@@ -303,9 +326,6 @@ if test x$enable_clients = xyes; then
PKG_CHECK_MODULES(SERVER, [wayland-server])
PKG_CHECK_MODULES(WESTON_INFO, [wayland-client])
- PKG_CHECK_MODULES(POPPLER, [poppler-glib glib-2.0 gobject-2.0 gio-2.0 ],
- [have_poppler=yes], [have_poppler=no])
-
# Only check for cairo-egl if a GL or GLES renderer requested
AS_IF([test "x$cairo_modules" = "xcairo-gl" -o "x$cairo_modules" = "xcairo-glesv2"], [
PKG_CHECK_MODULES(CAIRO_EGL, [wayland-egl egl >= 7.10 cairo-egl >= 1.11.3 $cairo_modules],
@@ -352,9 +372,6 @@ if test x$enable_egl = xyes; then
fi
AM_CONDITIONAL(HAVE_GLU, test "x$have_glu" = "xyes")
-
-AM_CONDITIONAL(HAVE_POPPLER, test "x$have_poppler" = "xyes")
-
AM_CONDITIONAL(HAVE_PANGO, test "x$have_pango" = "xyes")
AM_CONDITIONAL(HAVE_CAIRO_GLESV2,
@@ -368,6 +385,13 @@ AM_CONDITIONAL(BUILD_SUBSURFACES_CLIENT,
AM_CONDITIONAL(ENABLE_DESKTOP_SHELL, true)
+AC_ARG_ENABLE(fullscreen-shell,
+ AS_HELP_STRING([--disable-fullscreen-shell],
+ [do not build fullscreen-shell server plugin]),,
+ enable_fullscreen_shell=yes)
+AM_CONDITIONAL(ENABLE_FULLSCREEN_SHELL,
+ test "x$enable_fullscreen_shell" = "xyes")
+
# CMS modules
AC_ARG_ENABLE(colord,
AS_HELP_STRING([--disable-colord],
@@ -417,16 +441,13 @@ if test x$enable_wcap_tools = xyes; then
WCAP_LIBS="$WCAP_LIBS -lm"
fi
-AC_CHECK_PROG(RSVG_CONVERT, rsvg-convert, rsvg-convert)
-AM_CONDITIONAL(HAVE_RSVG_CONVERT, test -n "$RSVG_CONVERT")
-
PKG_CHECK_MODULES(SETBACKLIGHT, [libudev libdrm], enable_setbacklight=yes, enable_setbacklight=no)
AM_CONDITIONAL(BUILD_SETBACKLIGHT, test "x$enable_setbacklight" = "xyes")
if test "x$GCC" = "xyes"; then
GCC_CFLAGS="-Wall -Wextra -Wno-unused-parameter \
-Wno-missing-field-initializers -g -fvisibility=hidden \
- -Wstrict-prototypes -Wmissing-prototypes"
+ -Wstrict-prototypes -Wmissing-prototypes -Wsign-compare"
fi
AC_SUBST(GCC_CFLAGS)
@@ -483,29 +504,11 @@ if test x$wayland_scanner = x; then
fi
PKG_CHECK_MODULES(WAYLAND_SCANNER, wayland-scanner)
-AC_PATH_PROG(XMLLINT, xmllint)
-AC_ARG_WITH([dtddir],
- AS_HELP_STRING([--with-dtddir],
- [Directory containing the Wayland
- protocol DTD @<:@default=from pkgconfig@:>@]),
- [dtddir="$withval"],
- [dtddir=$($PKG_CONFIG --variable=pkgdatadir wayland-scanner)])
-AC_SUBST([dtddir])
-AM_CONDITIONAL([HAVE_XMLLINT], [test "x$XMLLINT" != "x" -a "x$dtddir" != "x"])
-
-AC_CONFIG_FILES([Makefile
- shared/Makefile
- src/Makefile
- xwayland/Makefile
- desktop-shell/Makefile
- src/version.h
- src/weston.pc
- clients/Makefile
- wcap/Makefile
- data/Makefile
- protocol/Makefile
- man/Makefile
- tests/Makefile])
+
+AC_CONFIG_FILES([Makefile src/version.h src/weston.pc])
+
+AM_CONDITIONAL([HAVE_GIT_REPO], [test -f $srcdir/.git/logs/HEAD])
+
AC_OUTPUT
AC_MSG_RESULT([
@@ -520,6 +523,7 @@ AC_MSG_RESULT([
dbus ${enable_dbus}
Build wcap utility ${enable_wcap_tools}
+ Build Fullscreen Shell ${enable_fullscreen_shell}
weston-launch utility ${enable_weston_launch}
systemd-login support ${have_systemd_login}
@@ -531,6 +535,9 @@ AC_MSG_RESULT([
RPI Compositor ${enable_rpi_compositor}
FBDEV Compositor ${enable_fbdev_compositor}
RDP Compositor ${enable_rdp_compositor}
+ Screen Sharing ${enable_screen_sharing}
+
+ libinput Backend ${enable_libinput_backend}
Raspberry Pi BCM headers ${have_bcm_host}
diff --git a/desktop-shell/exposay.c b/desktop-shell/exposay.c
index fe7a3a71..9c649e77 100644
--- a/desktop-shell/exposay.c
+++ b/desktop-shell/exposay.c
@@ -30,8 +30,10 @@
struct exposay_surface {
struct desktop_shell *shell;
+ struct exposay_output *eoutput;
struct weston_surface *surface;
struct weston_view *view;
+ struct wl_listener view_destroy_listener;
struct wl_list link;
int x;
@@ -56,6 +58,20 @@ static void exposay_set_state(struct desktop_shell *shell,
static void exposay_check_state(struct desktop_shell *shell);
static void
+exposay_surface_destroy(struct exposay_surface *esurface)
+{
+ wl_list_remove(&esurface->link);
+ wl_list_remove(&esurface->view_destroy_listener.link);
+
+ if (esurface->shell->exposay.focus_current == esurface->view)
+ esurface->shell->exposay.focus_current = NULL;
+ if (esurface->shell->exposay.focus_prev == esurface->view)
+ esurface->shell->exposay.focus_prev = NULL;
+
+ free(esurface);
+}
+
+static void
exposay_in_flight_inc(struct desktop_shell *shell)
{
shell->exposay.in_flight++;
@@ -109,8 +125,7 @@ exposay_animate_out_done(struct weston_view_animation *animation, void *data)
struct exposay_surface *esurface = data;
struct desktop_shell *shell = esurface->shell;
- wl_list_remove(&esurface->link);
- free(esurface);
+ exposay_surface_destroy(esurface);
exposay_in_flight_dec(shell);
}
@@ -138,8 +153,12 @@ exposay_highlight_surface(struct desktop_shell *shell,
{
struct weston_view *view = esurface->view;
+ if (shell->exposay.focus_current == view)
+ return;
+
shell->exposay.row_current = esurface->row;
shell->exposay.column_current = esurface->column;
+ shell->exposay.cur_output = esurface->eoutput;
activate(shell, view->surface, shell->exposay.seat);
shell->exposay.focus_current = view;
@@ -174,36 +193,46 @@ exposay_pick(struct desktop_shell *shell, int x, int y)
}
}
+static void
+handle_view_destroy(struct wl_listener *listener, void *data)
+{
+ struct exposay_surface *esurface = container_of(listener,
+ struct exposay_surface,
+ view_destroy_listener);
+
+ exposay_surface_destroy(esurface);
+}
+
/* Pretty lame layout for now; just tries to make a square. Should take
* aspect ratio into account really. Also needs to be notified of surface
* addition and removal and adjust layout/animate accordingly. */
static enum exposay_layout_state
-exposay_layout(struct desktop_shell *shell)
+exposay_layout(struct desktop_shell *shell, struct shell_output *shell_output)
{
struct workspace *workspace = shell->exposay.workspace;
- struct weston_compositor *compositor = shell->compositor;
- struct weston_output *output = get_default_output(compositor);
+ struct weston_output *output = shell_output->output;
+ struct exposay_output *eoutput = &shell_output->eoutput;
struct weston_view *view;
struct exposay_surface *esurface, *highlight = NULL;
int w, h;
int i;
int last_row_removed = 0;
- wl_list_init(&shell->exposay.surface_list);
-
- shell->exposay.num_surfaces = 0;
+ eoutput->num_surfaces = 0;
wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
if (!get_shell_surface(view->surface))
continue;
- shell->exposay.num_surfaces++;
+ if (view->output != output)
+ continue;
+ eoutput->num_surfaces++;
}
- if (shell->exposay.num_surfaces == 0) {
- shell->exposay.grid_size = 0;
- shell->exposay.hpadding_outer = 0;
- shell->exposay.vpadding_outer = 0;
- shell->exposay.padding_inner = 0;
- shell->exposay.surface_size = 0;
+ if (eoutput->num_surfaces == 0) {
+ eoutput->grid_size = 0;
+ eoutput->hpadding_outer = 0;
+ eoutput->vpadding_outer = 0;
+ eoutput->padding_inner = 0;
+ eoutput->surface_size = 0;
return EXPOSAY_LAYOUT_OVERVIEW;
}
@@ -219,37 +248,39 @@ exposay_layout(struct desktop_shell *shell)
* XXX: Surely there has to be a better way to express this maths,
* right?!
*/
- shell->exposay.grid_size = floor(sqrtf(shell->exposay.num_surfaces));
- if (pow(shell->exposay.grid_size, 2) != shell->exposay.num_surfaces)
- shell->exposay.grid_size++;
- last_row_removed = pow(shell->exposay.grid_size, 2) - shell->exposay.num_surfaces;
+ eoutput->grid_size = floor(sqrtf(eoutput->num_surfaces));
+ if (pow(eoutput->grid_size, 2) != eoutput->num_surfaces)
+ eoutput->grid_size++;
+ last_row_removed = pow(eoutput->grid_size, 2) - eoutput->num_surfaces;
- shell->exposay.hpadding_outer = (output->width / 10);
- shell->exposay.vpadding_outer = (output->height / 10);
- shell->exposay.padding_inner = 80;
+ eoutput->hpadding_outer = (output->width / 10);
+ eoutput->vpadding_outer = (output->height / 10);
+ eoutput->padding_inner = 80;
- w = output->width - (shell->exposay.hpadding_outer * 2);
- w -= shell->exposay.padding_inner * (shell->exposay.grid_size - 1);
- w /= shell->exposay.grid_size;
+ w = output->width - (eoutput->hpadding_outer * 2);
+ w -= eoutput->padding_inner * (eoutput->grid_size - 1);
+ w /= eoutput->grid_size;
- h = output->height - (shell->exposay.vpadding_outer * 2);
- h -= shell->exposay.padding_inner * (shell->exposay.grid_size - 1);
- h /= shell->exposay.grid_size;
+ h = output->height - (eoutput->vpadding_outer * 2);
+ h -= eoutput->padding_inner * (eoutput->grid_size - 1);
+ h /= eoutput->grid_size;
- shell->exposay.surface_size = (w < h) ? w : h;
- if (shell->exposay.surface_size > (output->width / 2))
- shell->exposay.surface_size = output->width / 2;
- if (shell->exposay.surface_size > (output->height / 2))
- shell->exposay.surface_size = output->height / 2;
+ eoutput->surface_size = (w < h) ? w : h;
+ if (eoutput->surface_size > (output->width / 2))
+ eoutput->surface_size = output->width / 2;
+ if (eoutput->surface_size > (output->height / 2))
+ eoutput->surface_size = output->height / 2;
i = 0;
wl_list_for_each(view, &workspace->layer.view_list, layer_link) {
int pad;
- pad = shell->exposay.surface_size + shell->exposay.padding_inner;
+ pad = eoutput->surface_size + eoutput->padding_inner;
if (!get_shell_surface(view->surface))
continue;
+ if (view->output != output)
+ continue;
esurface = malloc(sizeof(*esurface));
if (!esurface) {
@@ -260,23 +291,27 @@ exposay_layout(struct desktop_shell *shell)
wl_list_insert(&shell->exposay.surface_list, &esurface->link);
esurface->shell = shell;
+ esurface->eoutput = eoutput;
esurface->view = view;
- esurface->row = i / shell->exposay.grid_size;
- esurface->column = i % shell->exposay.grid_size;
+ esurface->view_destroy_listener.notify = handle_view_destroy;
+ wl_signal_add(&view->destroy_signal, &esurface->view_destroy_listener);
+
+ esurface->row = i / eoutput->grid_size;
+ esurface->column = i % eoutput->grid_size;
- esurface->x = shell->exposay.hpadding_outer;
+ esurface->x = output->x + eoutput->hpadding_outer;
esurface->x += pad * esurface->column;
- esurface->y = shell->exposay.vpadding_outer;
+ esurface->y = output->y + eoutput->vpadding_outer;
esurface->y += pad * esurface->row;
- if (esurface->row == shell->exposay.grid_size - 1)
- esurface->x += (shell->exposay.surface_size + shell->exposay.padding_inner) * last_row_removed / 2;
+ if (esurface->row == eoutput->grid_size - 1)
+ esurface->x += (eoutput->surface_size + eoutput->padding_inner) * last_row_removed / 2;
if (view->surface->width > view->surface->height)
- esurface->scale = shell->exposay.surface_size / (float) view->surface->width;
+ esurface->scale = eoutput->surface_size / (float) view->surface->width;
else
- esurface->scale = shell->exposay.surface_size / (float) view->surface->height;
+ esurface->scale = eoutput->surface_size / (float) view->surface->height;
esurface->width = view->surface->width * esurface->scale;
esurface->height = view->surface->height * esurface->scale;
@@ -364,7 +399,8 @@ exposay_maybe_move(struct desktop_shell *shell, int row, int column)
struct exposay_surface *esurface;
wl_list_for_each(esurface, &shell->exposay.surface_list, link) {
- if (esurface->row != row || esurface->column != column)
+ if (esurface->eoutput != shell->exposay.cur_output ||
+ esurface->row != row || esurface->column != column)
continue;
exposay_highlight_surface(shell, esurface);
@@ -402,10 +438,10 @@ exposay_key(struct weston_keyboard_grab *grab, uint32_t time, uint32_t key,
* has fewer items than all the others. */
if (!exposay_maybe_move(shell, shell->exposay.row_current + 1,
shell->exposay.column_current) &&
- shell->exposay.row_current < (shell->exposay.grid_size - 1)) {
+ shell->exposay.row_current < (shell->exposay.cur_output->grid_size - 1)) {
exposay_maybe_move(shell, shell->exposay.row_current + 1,
- (shell->exposay.num_surfaces %
- shell->exposay.grid_size) - 1);
+ (shell->exposay.cur_output->num_surfaces %
+ shell->exposay.cur_output->grid_size) - 1);
}
break;
case KEY_LEFT:
@@ -518,6 +554,8 @@ static enum exposay_layout_state
exposay_transition_active(struct desktop_shell *shell)
{
struct weston_seat *seat = shell->exposay.seat;
+ struct shell_output *shell_output;
+ bool animate = false;
shell->exposay.workspace = get_current_workspace(shell);
shell->exposay.focus_prev = get_default_view (seat->keyboard->focus);
@@ -537,7 +575,17 @@ exposay_transition_active(struct desktop_shell *shell)
weston_pointer_set_focus(seat->pointer, NULL,
seat->pointer->x, seat->pointer->y);
- return exposay_layout(shell);
+ wl_list_for_each(shell_output, &shell->output_list, link) {
+ enum exposay_layout_state state;
+
+ state = exposay_layout(shell, shell_output);
+
+ if (state == EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW)
+ animate = true;
+ }
+
+ return animate ? EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW
+ : EXPOSAY_LAYOUT_OVERVIEW;
}
static void
diff --git a/desktop-shell/input-panel.c b/desktop-shell/input-panel.c
index c08a403f..12fe686f 100644
--- a/desktop-shell/input-panel.c
+++ b/desktop-shell/input-panel.c
@@ -63,7 +63,7 @@ show_input_panels(struct wl_listener *listener, void *data)
shell->showing_input_panels = true;
if (!shell->locked)
- wl_list_insert(&shell->panel_layer.link,
+ wl_list_insert(&shell->compositor->cursor_layer.link,
&shell->input_panel_layer.link);
wl_list_for_each_safe(ipsurf, next,
diff --git a/desktop-shell/shell.c b/desktop-shell/shell.c
index c2755433..466ea937 100644
--- a/desktop-shell/shell.c
+++ b/desktop-shell/shell.c
@@ -56,13 +56,6 @@ struct focus_state {
struct wl_listener surface_destroy_listener;
};
-struct shell_output {
- struct desktop_shell *shell;
- struct weston_output *output;
- struct wl_listener destroy_listener;
- struct wl_list link;
-};
-
enum shell_surface_type {
SHELL_SURFACE_NONE,
SHELL_SURFACE_TOPLEVEL,
@@ -70,11 +63,6 @@ enum shell_surface_type {
SHELL_SURFACE_XWAYLAND
};
-struct ping_timer {
- struct wl_event_source *source;
- uint32_t serial;
-};
-
/*
* Surface stacking and ordering.
*
@@ -84,9 +72,9 @@ struct ping_timer {
* in the following order (top-most first):
* • Lock layer (only ever displayed on its own)
* • Cursor layer
+ * • Input panel layer
* • Fullscreen layer
* • Panel layer
- * • Input panel layer
* • Workspace layers
* • Background layer
*
@@ -121,6 +109,8 @@ struct shell_surface {
struct weston_view *view;
int32_t last_width, last_height;
struct wl_listener surface_destroy_listener;
+ struct wl_listener resource_destroy_listener;
+
struct weston_surface *parent;
struct wl_list children_list; /* child surfaces of this one */
struct wl_list children_link; /* sibling surfaces of this one */
@@ -134,6 +124,7 @@ struct shell_surface {
bool saved_size_valid;
bool saved_rotation_valid;
int unresponsive, grabbed;
+ uint32_t resize_edges;
struct {
struct weston_transform transform;
@@ -159,8 +150,6 @@ struct shell_surface {
struct weston_view *black_view;
} fullscreen;
- struct ping_timer *ping_timer;
-
struct weston_transform workspace_transform;
struct weston_output *fullscreen_output;
@@ -174,8 +163,11 @@ struct shell_surface {
bool maximized;
bool fullscreen;
bool relative;
- } state, next_state; /* surface states */
+ } state, next_state, requested_state; /* surface states */
bool state_changed;
+ bool state_requested;
+
+ int focus_count;
};
struct shell_grab {
@@ -214,6 +206,7 @@ struct rotate_grab {
struct shell_seat {
struct weston_seat *seat;
struct wl_listener seat_destroy_listener;
+ struct weston_surface *focused_surface;
struct {
struct weston_pointer_grab grab;
@@ -223,6 +216,16 @@ struct shell_seat {
} popup_grab;
};
+struct shell_client {
+ struct wl_resource *resource;
+ struct wl_client *client;
+ struct desktop_shell *shell;
+ struct wl_listener destroy_listener;
+ struct wl_event_source *ping_timer;
+ uint32_t ping_serial;
+ int unresponsive;
+};
+
void
set_alpha_if_fullscreen(struct shell_surface *shsurf)
{
@@ -230,6 +233,9 @@ set_alpha_if_fullscreen(struct shell_surface *shsurf)
shsurf->fullscreen.black_view->alpha = 0.25;
}
+static struct shell_client *
+get_shell_client(struct wl_client *client);
+
static struct desktop_shell *
shell_surface_get_shell(struct shell_surface *shsurf);
@@ -344,6 +350,7 @@ shell_grab_end(struct shell_grab *grab)
if (grab->shsurf) {
wl_list_remove(&grab->shsurf_destroy_listener.link);
grab->shsurf->grabbed = 0;
+ grab->shsurf->resize_edges = 0;
}
weston_pointer_end_grab(grab->grab.pointer);
@@ -1688,6 +1695,7 @@ surface_resize(struct shell_surface *shsurf,
surface_subsurfaces_boundingbox(shsurf->surface, NULL, NULL,
&resize->width, &resize->height);
+ shsurf->resize_edges = edges;
shell_grab_start(&resize->base, &resize_grab_interface, shsurf,
seat->pointer, edges);
@@ -1728,9 +1736,6 @@ shell_surface_resize(struct wl_client *client, struct wl_resource *resource,
}
static void
-end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer);
-
-static void
busy_cursor_grab_focus(struct weston_pointer_grab *base)
{
struct shell_grab *grab = (struct shell_grab *) base;
@@ -1742,8 +1747,10 @@ busy_cursor_grab_focus(struct weston_pointer_grab *base)
pointer->x, pointer->y,
&sx, &sy);
- if (!grab->shsurf || grab->shsurf->surface != view->surface)
- end_busy_cursor(grab->shsurf, pointer);
+ if (!grab->shsurf || grab->shsurf->surface != view->surface) {
+ shell_grab_end(grab);
+ free(grab);
+ }
}
static void
@@ -1791,6 +1798,9 @@ set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
{
struct shell_grab *grab;
+ if (pointer->grab->interface == &busy_cursor_grab_interface)
+ return;
+
grab = malloc(sizeof *grab);
if (!grab)
return;
@@ -1800,80 +1810,97 @@ set_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
}
static void
-end_busy_cursor(struct shell_surface *shsurf, struct weston_pointer *pointer)
+end_busy_cursor(struct weston_compositor *compositor, struct wl_client *client)
{
- struct shell_grab *grab = (struct shell_grab *) pointer->grab;
+ struct shell_grab *grab;
+ struct weston_seat *seat;
- if (grab->grab.interface == &busy_cursor_grab_interface &&
- grab->shsurf == shsurf) {
- shell_grab_end(grab);
- free(grab);
+ wl_list_for_each(seat, &compositor->seat_list, link) {
+ if (seat->pointer == NULL)
+ continue;
+
+ grab = (struct shell_grab *) seat->pointer->grab;
+ if (grab->grab.interface == &busy_cursor_grab_interface &&
+ wl_resource_get_client(grab->shsurf->resource) == client) {
+ shell_grab_end(grab);
+ free(grab);
+ }
}
}
static void
-ping_timer_destroy(struct shell_surface *shsurf)
-{
- if (!shsurf || !shsurf->ping_timer)
- return;
-
- if (shsurf->ping_timer->source)
- wl_event_source_remove(shsurf->ping_timer->source);
-
- free(shsurf->ping_timer);
- shsurf->ping_timer = NULL;
-}
+handle_shell_client_destroy(struct wl_listener *listener, void *data);
static int
-ping_timeout_handler(void *data)
+xdg_ping_timeout_handler(void *data)
{
- struct shell_surface *shsurf = data;
+ struct shell_client *sc = data;
struct weston_seat *seat;
+ struct shell_surface *shsurf;
/* Client is not responding */
- shsurf->unresponsive = 1;
-
- wl_list_for_each(seat, &shsurf->surface->compositor->seat_list, link)
- if (seat->pointer && seat->pointer->focus &&
- seat->pointer->focus->surface == shsurf->surface)
+ sc->unresponsive = 1;
+ wl_list_for_each(seat, &sc->shell->compositor->seat_list, link) {
+ if (seat->pointer == NULL || seat->pointer->focus == NULL)
+ continue;
+ if (seat->pointer->focus->surface->resource == NULL)
+ continue;
+
+ shsurf = get_shell_surface(seat->pointer->focus->surface);
+ if (shsurf &&
+ wl_resource_get_client(shsurf->resource) == sc->client)
set_busy_cursor(shsurf, seat->pointer);
+ }
return 1;
}
static void
+handle_xdg_ping(struct shell_surface *shsurf, uint32_t serial)
+{
+ struct weston_compositor *compositor = shsurf->shell->compositor;
+ struct wl_client *client = wl_resource_get_client(shsurf->resource);
+ struct shell_client *sc;
+ struct wl_event_loop *loop;
+ static const int ping_timeout = 200;
+
+ sc = get_shell_client(client);
+ if (sc->unresponsive) {
+ xdg_ping_timeout_handler(sc);
+ return;
+ }
+
+ sc->ping_serial = serial;
+ loop = wl_display_get_event_loop(compositor->wl_display);
+ if (sc->ping_timer == NULL)
+ sc->ping_timer =
+ wl_event_loop_add_timer(loop,
+ xdg_ping_timeout_handler, sc);
+ if (sc->ping_timer == NULL)
+ return;
+
+ wl_event_source_timer_update(sc->ping_timer, ping_timeout);
+
+ if (shell_surface_is_xdg_surface(shsurf) ||
+ shell_surface_is_xdg_popup(shsurf))
+ xdg_shell_send_ping(sc->resource, serial);
+ else if (shell_surface_is_wl_shell_surface(shsurf))
+ wl_shell_surface_send_ping(shsurf->resource, serial);
+}
+
+static void
ping_handler(struct weston_surface *surface, uint32_t serial)
{
struct shell_surface *shsurf = get_shell_surface(surface);
- struct wl_event_loop *loop;
- int ping_timeout = 200;
if (!shsurf)
return;
if (!shsurf->resource)
return;
-
if (shsurf->surface == shsurf->shell->grab_surface)
return;
- if (!shsurf->ping_timer) {
- shsurf->ping_timer = malloc(sizeof *shsurf->ping_timer);
- if (!shsurf->ping_timer)
- return;
-
- shsurf->ping_timer->serial = serial;
- loop = wl_display_get_event_loop(surface->compositor->wl_display);
- shsurf->ping_timer->source =
- wl_event_loop_add_timer(loop, ping_timeout_handler, shsurf);
- wl_event_source_timer_update(shsurf->ping_timer->source, ping_timeout);
-
- if (shell_surface_is_wl_shell_surface(shsurf))
- wl_shell_surface_send_ping(shsurf->resource, serial);
- else if (shell_surface_is_xdg_surface(shsurf))
- xdg_surface_send_ping(shsurf->resource, serial);
- else if (shell_surface_is_xdg_popup(shsurf))
- xdg_popup_send_ping(shsurf->resource, serial);
- }
+ handle_xdg_ping(shsurf, serial);
}
static void
@@ -1882,21 +1909,14 @@ handle_pointer_focus(struct wl_listener *listener, void *data)
struct weston_pointer *pointer = data;
struct weston_view *view = pointer->focus;
struct weston_compositor *compositor;
- struct shell_surface *shsurf;
uint32_t serial;
if (!view)
return;
compositor = view->surface->compositor;
- shsurf = get_shell_surface(view->surface);
-
- if (shsurf && shsurf->unresponsive) {
- set_busy_cursor(shsurf, pointer);
- } else {
- serial = wl_display_next_serial(compositor->wl_display);
- ping_handler(view->surface, serial);
- }
+ serial = wl_display_next_serial(compositor->wl_display);
+ ping_handler(view->surface, serial);
}
static void
@@ -1913,49 +1933,92 @@ create_pointer_focus_listener(struct weston_seat *seat)
}
static void
-xdg_surface_set_transient_for(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *parent_resource)
+shell_surface_lose_keyboard_focus(struct shell_surface *shsurf)
{
- struct shell_surface *shsurf = wl_resource_get_user_data(resource);
- struct weston_surface *parent;
+ if (--shsurf->focus_count == 0)
+ if (shell_surface_is_xdg_surface(shsurf))
+ xdg_surface_send_deactivated(shsurf->resource);
+}
- if (parent_resource)
- parent = wl_resource_get_user_data(parent_resource);
- else
- parent = NULL;
+static void
+shell_surface_gain_keyboard_focus(struct shell_surface *shsurf)
+{
+ if (shsurf->focus_count++ == 0)
+ if (shell_surface_is_xdg_surface(shsurf))
+ xdg_surface_send_activated(shsurf->resource);
+}
- shell_surface_set_parent(shsurf, parent);
+static void
+handle_keyboard_focus(struct wl_listener *listener, void *data)
+{
+ struct weston_keyboard *keyboard = data;
+ struct shell_seat *seat = get_shell_seat(keyboard->seat);
+
+ if (seat->focused_surface) {
+ struct shell_surface *shsurf = get_shell_surface(seat->focused_surface);
+ if (shsurf)
+ shell_surface_lose_keyboard_focus(shsurf);
+ }
+
+ seat->focused_surface = keyboard->focus;
+
+ if (seat->focused_surface) {
+ struct shell_surface *shsurf = get_shell_surface(seat->focused_surface);
+ if (shsurf)
+ shell_surface_gain_keyboard_focus(shsurf);
+ }
}
static void
-surface_pong(struct shell_surface *shsurf, uint32_t serial)
+create_keyboard_focus_listener(struct weston_seat *seat)
{
- struct weston_compositor *ec = shsurf->surface->compositor;
- struct weston_seat *seat;
+ struct wl_listener *listener;
- if (shsurf->ping_timer == NULL)
- /* Just ignore unsolicited pong. */
+ if (!seat->keyboard)
return;
- if (shsurf->ping_timer->serial == serial) {
- shsurf->unresponsive = 0;
- wl_list_for_each(seat, &ec->seat_list, link) {
- if(seat->pointer)
- end_busy_cursor(shsurf, seat->pointer);
- }
- ping_timer_destroy(shsurf);
- }
+ listener = malloc(sizeof *listener);
+ listener->notify = handle_keyboard_focus;
+ wl_signal_add(&seat->keyboard->focus_signal, listener);
+}
+
+static struct shell_client *
+get_shell_client(struct wl_client *client)
+{
+ struct wl_listener *listener;
+
+ listener = wl_client_get_destroy_listener(client,
+ handle_shell_client_destroy);
+ if (listener == NULL)
+ return NULL;
+
+ return container_of(listener, struct shell_client, destroy_listener);
}
static void
-shell_surface_pong(struct wl_client *client, struct wl_resource *resource,
- uint32_t serial)
+shell_client_pong(struct shell_client *sc, uint32_t serial)
{
- struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ if (sc->ping_serial != serial)
+ return;
+
+ sc->unresponsive = 0;
+ end_busy_cursor(sc->shell->compositor, sc->client);
- surface_pong(shsurf, serial);
+ if (sc->ping_timer) {
+ wl_event_source_remove(sc->ping_timer);
+ sc->ping_timer = NULL;
+ }
+
+}
+
+static void
+shell_surface_pong(struct wl_client *client,
+ struct wl_resource *resource, uint32_t serial)
+{
+ struct shell_client *sc;
+ sc = get_shell_client(client);
+ shell_client_pong(sc, serial);
}
static void
@@ -2228,8 +2291,6 @@ set_fullscreen(struct shell_surface *shsurf,
shsurf->fullscreen.type = method;
shsurf->fullscreen.framerate = framerate;
- shsurf->next_state.fullscreen = true;
- shsurf->state_changed = true;
shsurf->type = SHELL_SURFACE_TOPLEVEL;
shsurf->client->send_configure(shsurf->surface, 0,
@@ -2298,6 +2359,9 @@ shell_surface_set_fullscreen(struct wl_client *client,
surface_clear_next_states(shsurf);
set_fullscreen(shsurf, method, framerate, output);
+
+ shsurf->next_state.fullscreen = true;
+ shsurf->state_changed = true;
}
static void
@@ -2356,8 +2420,6 @@ set_maximized(struct shell_surface *shsurf,
shsurf->output->width,
shsurf->output->height - panel_height);
- shsurf->next_state.maximized = true;
- shsurf->state_changed = true;
shsurf->type = SHELL_SURFACE_TOPLEVEL;
}
@@ -2383,6 +2445,53 @@ unset_maximized(struct shell_surface *shsurf)
}
static void
+set_minimized(struct weston_surface *surface, uint32_t is_true)
+{
+ struct shell_surface *shsurf;
+ struct workspace *current_ws;
+ struct weston_seat *seat;
+ struct weston_surface *focus;
+ struct weston_view *view;
+
+ view = get_default_view(surface);
+ if (!view)
+ return;
+
+ assert(weston_surface_get_main_surface(view->surface) == view->surface);
+
+ shsurf = get_shell_surface(surface);
+ current_ws = get_current_workspace(shsurf->shell);
+
+ wl_list_remove(&view->layer_link);
+ /* hide or show, depending on the state */
+ if (is_true) {
+ wl_list_insert(&shsurf->shell->minimized_layer.view_list, &view->layer_link);
+
+ drop_focus_state(shsurf->shell, current_ws, view->surface);
+ wl_list_for_each(seat, &shsurf->shell->compositor->seat_list, link) {
+ if (!seat->keyboard)
+ continue;
+ focus = weston_surface_get_main_surface(seat->keyboard->focus);
+ if (focus == view->surface)
+ weston_keyboard_set_focus(seat->keyboard, NULL);
+ }
+ }
+ else {
+ wl_list_insert(&current_ws->layer.view_list, &view->layer_link);
+
+ wl_list_for_each(seat, &shsurf->shell->compositor->seat_list, link) {
+ if (!seat->keyboard)
+ continue;
+ activate(shsurf->shell, view->surface, seat);
+ }
+ }
+
+ shell_surface_update_child_surface_layers(shsurf);
+
+ weston_view_damage_below(view);
+}
+
+static void
shell_surface_set_maximized(struct wl_client *client,
struct wl_resource *resource,
struct wl_resource *output_resource)
@@ -2399,6 +2508,9 @@ shell_surface_set_maximized(struct wl_client *client,
surface_clear_next_states(shsurf);
set_maximized(shsurf, output);
+
+ shsurf->next_state.maximized = true;
+ shsurf->state_changed = true;
}
/* This is only ever called from set_surface_type(), so there’s no need to
@@ -2596,11 +2708,11 @@ shell_configure_fullscreen(struct shell_surface *shsurf)
case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
if (shell_surface_is_top_fullscreen(shsurf)) {
struct weston_mode mode = {0,
- surf_width * surface->buffer_viewport.scale,
- surf_height * surface->buffer_viewport.scale,
+ surf_width * surface->buffer_viewport.buffer.scale,
+ surf_height * surface->buffer_viewport.buffer.scale,
shsurf->fullscreen.framerate};
- if (weston_output_switch_mode(output, &mode, surface->buffer_viewport.scale,
+ if (weston_output_switch_mode(output, &mode, surface->buffer_viewport.buffer.scale,
WESTON_MODE_SWITCH_SET_TEMPORARY) == 0) {
weston_view_set_position(shsurf->view,
output->x - surf_x,
@@ -2921,16 +3033,13 @@ destroy_shell_surface(struct shell_surface *shsurf)
*/
wl_list_remove(&shsurf->surface_destroy_listener.link);
shsurf->surface->configure = NULL;
- ping_timer_destroy(shsurf);
free(shsurf->title);
weston_view_destroy(shsurf->view);
wl_list_remove(&shsurf->children_link);
- wl_list_for_each_safe(child, next, &shsurf->children_list, children_link) {
- wl_list_remove(&child->children_link);
- child->parent = NULL;
- }
+ wl_list_for_each_safe(child, next, &shsurf->children_list, children_link)
+ shell_surface_set_parent(child, NULL);
wl_list_remove(&shsurf->link);
free(shsurf);
@@ -2941,7 +3050,9 @@ shell_destroy_shell_surface(struct wl_resource *resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
- destroy_shell_surface(shsurf);
+ if (!wl_list_empty(&shsurf->popup.grab_link))
+ remove_popup_grab(shsurf);
+ shsurf->resource = NULL;
}
static void
@@ -2958,9 +3069,33 @@ shell_handle_surface_destroy(struct wl_listener *listener, void *data)
}
static void
-shell_surface_configure(struct weston_surface *, int32_t, int32_t);
+fade_out_done(struct weston_view_animation *animation, void *data)
+{
+ struct shell_surface *shsurf = data;
+
+ weston_surface_destroy(shsurf->surface);
+}
+
static void
-shell_surface_output_destroyed(struct weston_surface *);
+handle_resource_destroy(struct wl_listener *listener, void *data)
+{
+ struct shell_surface *shsurf =
+ container_of(listener, struct shell_surface,
+ resource_destroy_listener);
+
+ shsurf->surface->ref_count++;
+
+ pixman_region32_fini(&shsurf->surface->pending.input);
+ pixman_region32_init(&shsurf->surface->pending.input);
+ pixman_region32_fini(&shsurf->surface->input);
+ pixman_region32_init(&shsurf->surface->input);
+ if (weston_surface_is_mapped(shsurf->surface))
+ weston_fade_run(shsurf->view, 1.0, 0.0, 300.0,
+ fade_out_done, shsurf);
+}
+
+static void
+shell_surface_configure(struct weston_surface *, int32_t, int32_t);
struct shell_surface *
get_shell_surface(struct weston_surface *surface)
@@ -2997,7 +3132,10 @@ create_common_surface(void *shell, struct weston_surface *surface,
surface->configure = shell_surface_configure;
surface->configure_private = shsurf;
- surface->output_destroyed = shell_surface_output_destroyed;
+
+ shsurf->resource_destroy_listener.notify = handle_resource_destroy;
+ wl_resource_add_destroy_listener(surface->resource,
+ &shsurf->resource_destroy_listener);
shsurf->shell = (struct desktop_shell *) shell;
shsurf->unresponsive = 0;
@@ -3008,7 +3146,6 @@ create_common_surface(void *shell, struct weston_surface *surface,
shsurf->fullscreen.type = WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT;
shsurf->fullscreen.framerate = 0;
shsurf->fullscreen.black_view = NULL;
- shsurf->ping_timer = NULL;
wl_list_init(&shsurf->fullscreen.transform.link);
wl_signal_init(&shsurf->destroy_signal);
@@ -3087,9 +3224,13 @@ shell_get_shell_surface(struct wl_client *client,
static bool
shell_surface_is_wl_shell_surface(struct shell_surface *shsurf)
{
- return wl_resource_instance_of(shsurf->resource,
- &wl_shell_surface_interface,
- &shell_surface_implementation);
+ /* A shell surface without a resource is created from xwayland
+ * and is considered a wl_shell surface for now. */
+
+ return shsurf->resource == NULL ||
+ wl_resource_instance_of(shsurf->resource,
+ &wl_shell_surface_interface,
+ &shell_surface_implementation);
}
static const struct wl_shell_interface shell_implementation = {
@@ -3107,13 +3248,31 @@ xdg_surface_destroy(struct wl_client *client,
}
static void
-xdg_surface_pong(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t serial)
+xdg_surface_set_transient_for(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *parent_resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ struct weston_surface *parent;
+
+ if (parent_resource)
+ parent = wl_resource_get_user_data(parent_resource);
+ else
+ parent = NULL;
- surface_pong(shsurf, serial);
+ shell_surface_set_parent(shsurf, parent);
+}
+
+static void
+xdg_surface_set_margin(struct wl_client *client,
+ struct wl_resource *resource,
+ int32_t left,
+ int32_t right,
+ int32_t top,
+ int32_t bottom)
+{
+ /* Do nothing, Weston doesn't try to constrain or place
+ * surfaces in any special manner... */
}
static void
@@ -3168,103 +3327,97 @@ xdg_surface_set_output(struct wl_client *client,
}
static void
-xdg_surface_set_fullscreen(struct wl_client *client,
- struct wl_resource *resource)
+xdg_surface_change_state(struct shell_surface *shsurf,
+ uint32_t state, uint32_t value, uint32_t serial)
{
- struct shell_surface *shsurf = wl_resource_get_user_data(resource);
+ xdg_surface_send_change_state(shsurf->resource, state, value, serial);
+ shsurf->state_requested = true;
- if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
- return;
+ switch (state) {
+ case XDG_SURFACE_STATE_MAXIMIZED:
+ shsurf->requested_state.maximized = value;
+ if (value)
+ set_maximized(shsurf, NULL);
+ break;
+ case XDG_SURFACE_STATE_FULLSCREEN:
+ shsurf->requested_state.fullscreen = value;
- if (!shsurf->next_state.fullscreen)
- set_fullscreen(shsurf,
- WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
- 0, shsurf->recommended_output);
+ if (value)
+ set_fullscreen(shsurf,
+ WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT,
+ 0, shsurf->recommended_output);
+ break;
+ }
}
static void
-xdg_surface_unset_fullscreen(struct wl_client *client,
- struct wl_resource *resource)
+xdg_surface_request_change_state(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t state,
+ uint32_t value,
+ uint32_t serial)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
- int32_t width, height;
+
+ /* The client can't know what the current state is, so we need
+ to always send a state change in response. */
if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
return;
- if (!shsurf->next_state.fullscreen)
+ switch (state) {
+ case XDG_SURFACE_STATE_MAXIMIZED:
+ case XDG_SURFACE_STATE_FULLSCREEN:
+ break;
+ default:
+ /* send error? ignore? send change state with value 0? */
return;
-
- shsurf->next_state.fullscreen = false;
- shsurf->state_changed = true;
-
- if (shsurf->saved_size_valid) {
- width = shsurf->saved_width;
- height = shsurf->saved_height;
- shsurf->saved_size_valid = false;
- } else {
- width = shsurf->surface->width;
- height = shsurf->surface->height;
}
- shsurf->client->send_configure(shsurf->surface, 0, width, height);
+ xdg_surface_change_state(shsurf, state, value, serial);
}
static void
-xdg_surface_set_maximized(struct wl_client *client,
- struct wl_resource *resource)
+xdg_surface_ack_change_state(struct wl_client *client,
+ struct wl_resource *resource,
+ uint32_t state,
+ uint32_t value,
+ uint32_t serial)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
- if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
- return;
-
- if (!shsurf->next_state.maximized)
- set_maximized(shsurf, NULL);
+ if (shsurf->state_requested) {
+ shsurf->next_state = shsurf->requested_state;
+ shsurf->state_changed = true;
+ shsurf->state_requested = false;
+ }
}
static void
-xdg_surface_unset_maximized(struct wl_client *client,
+xdg_surface_set_minimized(struct wl_client *client,
struct wl_resource *resource)
{
struct shell_surface *shsurf = wl_resource_get_user_data(resource);
- int32_t width, height;
if (shsurf->type != SHELL_SURFACE_TOPLEVEL)
return;
- if (!shsurf->next_state.maximized)
- return;
-
- shsurf->next_state.maximized = false;
- shsurf->state_changed = true;
-
- if (shsurf->saved_size_valid) {
- width = shsurf->saved_width;
- height = shsurf->saved_height;
- shsurf->saved_size_valid = false;
- } else {
- width = shsurf->surface->width;
- height = shsurf->surface->height;
- }
-
- shsurf->client->send_configure(shsurf->surface, 0, width, height);
+ /* apply compositor's own minimization logic (hide) */
+ set_minimized(shsurf->surface, 1);
}
static const struct xdg_surface_interface xdg_surface_implementation = {
xdg_surface_destroy,
xdg_surface_set_transient_for,
+ xdg_surface_set_margin,
xdg_surface_set_title,
xdg_surface_set_app_id,
- xdg_surface_pong,
xdg_surface_move,
xdg_surface_resize,
xdg_surface_set_output,
- xdg_surface_set_fullscreen,
- xdg_surface_unset_fullscreen,
- xdg_surface_set_maximized,
- xdg_surface_unset_maximized,
- NULL /* set_minimized */
+ xdg_surface_request_change_state,
+ xdg_surface_ack_change_state,
+ xdg_surface_set_minimized
};
static void
@@ -3275,7 +3428,7 @@ xdg_send_configure(struct weston_surface *surface,
assert(shsurf);
- xdg_surface_send_configure(shsurf->resource, edges, width, height);
+ xdg_surface_send_configure(shsurf->resource, width, height);
}
static const struct weston_shell_client xdg_client = {
@@ -3315,13 +3468,14 @@ xdg_get_xdg_surface(struct wl_client *client,
{
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_client *sc = wl_resource_get_user_data(resource);
+ struct desktop_shell *shell = sc->shell;
struct shell_surface *shsurf;
if (get_shell_surface(surface)) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
- "desktop_shell::get_shell_surface already requested");
+ "xdg_shell::get_xdg_surface already requested");
return;
}
@@ -3344,9 +3498,10 @@ xdg_get_xdg_surface(struct wl_client *client,
static bool
shell_surface_is_xdg_surface(struct shell_surface *shsurf)
{
- return wl_resource_instance_of(shsurf->resource,
- &xdg_surface_interface,
- &xdg_surface_implementation);
+ return shsurf->resource &&
+ wl_resource_instance_of(shsurf->resource,
+ &xdg_surface_interface,
+ &xdg_surface_implementation);
}
/* xdg-popup implementation */
@@ -3358,19 +3513,8 @@ xdg_popup_destroy(struct wl_client *client,
wl_resource_destroy(resource);
}
-static void
-xdg_popup_pong(struct wl_client *client,
- struct wl_resource *resource,
- uint32_t serial)
-{
- struct shell_surface *shsurf = wl_resource_get_user_data(resource);
-
- surface_pong(shsurf, serial);
-}
-
static const struct xdg_popup_interface xdg_popup_implementation = {
xdg_popup_destroy,
- xdg_popup_pong
};
static void
@@ -3416,7 +3560,8 @@ xdg_get_xdg_popup(struct wl_client *client,
{
struct weston_surface *surface =
wl_resource_get_user_data(surface_resource);
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_client *sc = wl_resource_get_user_data(resource);
+ struct desktop_shell *shell = sc->shell;
struct shell_surface *shsurf;
struct weston_surface *parent;
struct shell_seat *seat;
@@ -3424,7 +3569,7 @@ xdg_get_xdg_popup(struct wl_client *client,
if (get_shell_surface(surface)) {
wl_resource_post_error(surface_resource,
WL_DISPLAY_ERROR_INVALID_OBJECT,
- "desktop_shell::get_shell_surface already requested");
+ "xdg_shell::get_xdg_popup already requested");
return;
}
@@ -3454,6 +3599,15 @@ xdg_get_xdg_popup(struct wl_client *client,
shsurf, shell_destroy_shell_surface);
}
+static void
+xdg_pong(struct wl_client *client,
+ struct wl_resource *resource, uint32_t serial)
+{
+ struct shell_client *sc = wl_resource_get_user_data(resource);
+
+ shell_client_pong(sc, serial);
+}
+
static bool
shell_surface_is_xdg_popup(struct shell_surface *shsurf)
{
@@ -3465,7 +3619,8 @@ shell_surface_is_xdg_popup(struct shell_surface *shsurf)
static const struct xdg_shell_interface xdg_implementation = {
xdg_use_unstable_version,
xdg_get_xdg_surface,
- xdg_get_xdg_popup
+ xdg_get_xdg_popup,
+ xdg_pong
};
static int
@@ -3475,7 +3630,7 @@ xdg_shell_unversioned_dispatch(const void *implementation,
union wl_argument *args)
{
struct wl_resource *resource = _target;
- struct desktop_shell *shell = wl_resource_get_user_data(resource);
+ struct shell_client *sc = wl_resource_get_user_data(resource);
if (opcode != 0) {
wl_resource_post_error(resource,
@@ -3484,7 +3639,7 @@ xdg_shell_unversioned_dispatch(const void *implementation,
return 0;
}
-#define XDG_SERVER_VERSION 1
+#define XDG_SERVER_VERSION 3
static_assert(XDG_SERVER_VERSION == XDG_SHELL_VERSION_CURRENT,
"shell implementation doesn't match protocol version");
@@ -3499,7 +3654,7 @@ xdg_shell_unversioned_dispatch(const void *implementation,
}
wl_resource_set_implementation(resource, &xdg_implementation,
- shell, NULL);
+ sc, NULL);
return 1;
}
@@ -3733,18 +3888,19 @@ resume_desktop(struct desktop_shell *shell)
terminate_screensaver(shell);
wl_list_remove(&shell->lock_layer.link);
- wl_list_insert(&shell->compositor->cursor_layer.link,
- &shell->fullscreen_layer.link);
- wl_list_insert(&shell->fullscreen_layer.link,
- &shell->panel_layer.link);
if (shell->showing_input_panels) {
- wl_list_insert(&shell->panel_layer.link,
+ wl_list_insert(&shell->compositor->cursor_layer.link,
&shell->input_panel_layer.link);
wl_list_insert(&shell->input_panel_layer.link,
- &ws->layer.link);
+ &shell->fullscreen_layer.link);
} else {
- wl_list_insert(&shell->panel_layer.link, &ws->layer.link);
+ wl_list_insert(&shell->compositor->cursor_layer.link,
+ &shell->fullscreen_layer.link);
}
+ wl_list_insert(&shell->fullscreen_layer.link,
+ &shell->panel_layer.link);
+ wl_list_insert(&shell->panel_layer.link,
+ &ws->layer.link),
restore_focus_state(shell, get_current_workspace(shell));
@@ -3832,9 +3988,10 @@ move_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *dat
static void
maximize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
{
- struct weston_surface *focus = seat->pointer->focus->surface;
+ struct weston_surface *focus = seat->keyboard->focus;
struct weston_surface *surface;
struct shell_surface *shsurf;
+ uint32_t serial;
surface = weston_surface_get_main_surface(focus);
if (surface == NULL)
@@ -3847,18 +4004,18 @@ maximize_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void
if (!shell_surface_is_xdg_surface(shsurf))
return;
- if (shsurf->state.maximized)
- xdg_surface_send_request_unset_maximized(shsurf->resource);
- else
- xdg_surface_send_request_set_maximized(shsurf->resource);
+ serial = wl_display_next_serial(seat->compositor->wl_display);
+ xdg_surface_change_state(shsurf, XDG_SURFACE_STATE_MAXIMIZED,
+ !shsurf->state.maximized, serial);
}
static void
fullscreen_binding(struct weston_seat *seat, uint32_t time, uint32_t button, void *data)
{
- struct weston_surface *focus = seat->pointer->focus->surface;
+ struct weston_surface *focus = seat->keyboard->focus;
struct weston_surface *surface;
struct shell_surface *shsurf;
+ uint32_t serial;
surface = weston_surface_get_main_surface(focus);
if (surface == NULL)
@@ -3871,10 +4028,9 @@ fullscreen_binding(struct weston_seat *seat, uint32_t time, uint32_t button, voi
if (!shell_surface_is_xdg_surface(shsurf))
return;
- if (shsurf->state.fullscreen)
- xdg_surface_send_request_unset_fullscreen(shsurf->resource);
- else
- xdg_surface_send_request_set_fullscreen(shsurf->resource);
+ serial = wl_display_next_serial(seat->compositor->wl_display);
+ xdg_surface_change_state(shsurf, XDG_SURFACE_STATE_FULLSCREEN,
+ !shsurf->state.fullscreen, serial);
}
static void
@@ -4248,14 +4404,14 @@ activate(struct desktop_shell *shell, struct weston_surface *es,
else
restore_all_output_modes(shell->compositor);
+ /* Update the surface’s layer. This brings it to the top of the stacking
+ * order as appropriate. */
+ shell_surface_update_layer(shsurf);
+
if (shell->focus_animation_type != ANIMATION_NONE) {
ws = get_current_workspace(shell);
animate_focus_change(shell, ws, get_default_view(old_es), get_default_view(es));
}
-
- /* Update the surface’s layer. This brings it to the top of the stacking
- * order as appropriate. */
- shell_surface_update_layer(shsurf);
}
/* no-op func for checking black surface */
@@ -4681,10 +4837,6 @@ map(struct desktop_shell *shell, struct shell_surface *shsurf,
}
}
- if ((shsurf->type == SHELL_SURFACE_XWAYLAND || shsurf->state.relative) &&
- shsurf->transient.flags == WL_SHELL_SURFACE_TRANSIENT_INACTIVE) {
- }
-
switch (shsurf->type) {
/* XXX: xwayland's using the same fields for transient type */
case SHELL_SURFACE_XWAYLAND:
@@ -4788,11 +4940,22 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
} else if (type_changed || sx != 0 || sy != 0 ||
shsurf->last_width != es->width ||
shsurf->last_height != es->height) {
- shsurf->last_width = es->width;
- shsurf->last_height = es->height;
float from_x, from_y;
float to_x, to_y;
+ if (shsurf->resize_edges) {
+ sx = 0;
+ sy = 0;
+ }
+
+ if (shsurf->resize_edges & WL_SHELL_SURFACE_RESIZE_LEFT)
+ sx = shsurf->last_width - es->width;
+ if (shsurf->resize_edges & WL_SHELL_SURFACE_RESIZE_TOP)
+ sy = shsurf->last_height - es->height;
+
+ shsurf->last_width = es->width;
+ shsurf->last_height = es->height;
+
weston_view_to_global_float(shsurf->view, 0, 0, &from_x, &from_y);
weston_view_to_global_float(shsurf->view, sx, sy, &to_x, &to_y);
configure(shell, es,
@@ -4801,19 +4964,6 @@ shell_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
}
}
-static void
-shell_surface_output_destroyed(struct weston_surface *es)
-{
- struct shell_surface *shsurf = get_shell_surface(es);
-
- assert(shsurf);
-
- shsurf->saved_position_valid = false;
- shsurf->next_state.maximized = false;
- shsurf->next_state.fullscreen = false;
- shsurf->state_changed = true;
-}
-
static void launch_desktop_shell_process(void *data);
static void
@@ -4875,14 +5025,53 @@ launch_desktop_shell_process(void *data)
}
static void
+handle_shell_client_destroy(struct wl_listener *listener, void *data)
+{
+ struct shell_client *sc =
+ container_of(listener, struct shell_client, destroy_listener);
+
+ if (sc->ping_timer)
+ wl_event_source_remove(sc->ping_timer);
+ free(sc);
+}
+
+static struct shell_client *
+shell_client_create(struct wl_client *client, struct desktop_shell *shell,
+ const struct wl_interface *interface, uint32_t id)
+{
+ struct shell_client *sc;
+
+ sc = zalloc(sizeof *sc);
+ if (sc == NULL) {
+ wl_client_post_no_memory(client);
+ return NULL;
+ }
+
+ sc->resource = wl_resource_create(client, interface, 1, id);
+ if (sc->resource == NULL) {
+ free(sc);
+ wl_client_post_no_memory(client);
+ return NULL;
+ }
+
+ sc->client = client;
+ sc->shell = shell;
+ sc->destroy_listener.notify = handle_shell_client_destroy;
+ wl_client_add_destroy_listener(client, &sc->destroy_listener);
+
+ return sc;
+}
+
+static void
bind_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct desktop_shell *shell = data;
- struct wl_resource *resource;
+ struct shell_client *sc;
- resource = wl_resource_create(client, &wl_shell_interface, 1, id);
- if (resource)
- wl_resource_set_implementation(resource, &shell_implementation,
+ sc = shell_client_create(client, shell, &wl_shell_interface, id);
+ if (sc)
+ wl_resource_set_implementation(sc->resource,
+ &shell_implementation,
shell, NULL);
}
@@ -4890,13 +5079,13 @@ static void
bind_xdg_shell(struct wl_client *client, void *data, uint32_t version, uint32_t id)
{
struct desktop_shell *shell = data;
- struct wl_resource *resource;
+ struct shell_client *sc;
- resource = wl_resource_create(client, &xdg_shell_interface, 1, id);
- if (resource)
- wl_resource_set_dispatcher(resource,
+ sc = shell_client_create(client, shell, &xdg_shell_interface, id);
+ if (sc)
+ wl_resource_set_dispatcher(sc->resource,
xdg_shell_unversioned_dispatch,
- NULL, shell, NULL);
+ NULL, sc, NULL);
}
static void
@@ -5025,6 +5214,7 @@ struct switcher {
struct weston_surface *current;
struct wl_listener listener;
struct weston_keyboard_grab grab;
+ struct wl_array minimized_array;
};
static void
@@ -5035,6 +5225,16 @@ switcher_next(struct switcher *switcher)
struct shell_surface *shsurf;
struct workspace *ws = get_current_workspace(switcher->shell);
+ /* temporary re-display minimized surfaces */
+ struct weston_view *tmp;
+ struct weston_view **minimized;
+ wl_list_for_each_safe(view, tmp, &switcher->shell->minimized_layer.view_list, layer_link) {
+ wl_list_remove(&view->layer_link);
+ wl_list_insert(&ws->layer.view_list, &view->layer_link);
+ minimized = wl_array_add(&switcher->minimized_array, sizeof *minimized);
+ *minimized = view;
+ }
+
wl_list_for_each(view, &ws->layer.view_list, layer_link) {
shsurf = get_shell_surface(view->surface);
if (shsurf &&
@@ -5106,6 +5306,19 @@ switcher_destroy(struct switcher *switcher)
weston_keyboard_end_grab(keyboard);
if (keyboard->input_method_resource)
keyboard->grab = &keyboard->input_method_grab;
+
+ /* re-hide surfaces that were temporary shown during the switch */
+ struct weston_view **minimized;
+ wl_array_for_each(minimized, &switcher->minimized_array) {
+ /* with the exception of the current selected */
+ if ((*minimized)->surface != switcher->current) {
+ wl_list_remove(&(*minimized)->layer_link);
+ wl_list_insert(&switcher->shell->minimized_layer.view_list, &(*minimized)->layer_link);
+ weston_view_damage_below(*minimized);
+ }
+ }
+ wl_array_release(&switcher->minimized_array);
+
free(switcher);
}
@@ -5158,6 +5371,7 @@ switcher_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
switcher->current = NULL;
switcher->listener.notify = switcher_handle_surface_destroy;
wl_list_init(&switcher->listener.link);
+ wl_array_init(&switcher->minimized_array);
restore_all_output_modes(shell->compositor);
lower_fullscreen_layer(switcher->shell);
@@ -5433,11 +5647,81 @@ workspace_move_surface_down_binding(struct weston_seat *seat, uint32_t time,
}
static void
+shell_reposition_view_on_output_destroy(struct weston_view *view)
+{
+ struct weston_output *output, *first_output;
+ struct weston_compositor *ec = view->surface->compositor;
+ struct shell_surface *shsurf;
+ float x, y;
+ int visible;
+
+ x = view->geometry.x;
+ y = view->geometry.y;
+
+ /* At this point the destroyed output is not in the list anymore.
+ * If the view is still visible somewhere, we leave where it is,
+ * otherwise, move it to the first output. */
+ visible = 0;
+ wl_list_for_each(output, &ec->output_list, link) {
+ if (pixman_region32_contains_point(&output->region,
+ x, y, NULL)) {
+ visible = 1;
+ break;
+ }
+ }
+
+ if (!visible) {
+ first_output = container_of(ec->output_list.next,
+ struct weston_output, link);
+
+ x = first_output->x + first_output->width / 4;
+ y = first_output->y + first_output->height / 4;
+ }
+
+ weston_view_set_position(view, x, y);
+
+ shsurf = get_shell_surface(view->surface);
+
+ if (shsurf) {
+ shsurf->saved_position_valid = false;
+ shsurf->next_state.maximized = false;
+ shsurf->next_state.fullscreen = false;
+ shsurf->state_changed = true;
+ }
+}
+
+static void
+shell_reposition_views_on_output_destroy(struct shell_output *shell_output)
+{
+ struct desktop_shell *shell = shell_output->shell;
+ struct weston_output *output = shell_output->output;
+ struct weston_layer *layer;
+ struct weston_view *view;
+
+ /* Move all views in the layers owned by the shell */
+ wl_list_for_each(layer, shell->fullscreen_layer.link.prev, link) {
+ wl_list_for_each(view, &layer->view_list, layer_link) {
+ if (view->output != output)
+ continue;
+
+ shell_reposition_view_on_output_destroy(view);
+ }
+
+ /* We don't start from the beggining of the layer list, so
+ * make sure we don't wrap around it. */
+ if (layer == &shell->background_layer)
+ break;
+ }
+}
+
+static void
handle_output_destroy(struct wl_listener *listener, void *data)
{
struct shell_output *output_listener =
container_of(listener, struct shell_output, destroy_listener);
+ shell_reposition_views_on_output_destroy(output_listener);
+
wl_list_remove(&output_listener->destroy_listener.link);
wl_list_remove(&output_listener->link);
free(output_listener);
@@ -5472,6 +5756,37 @@ handle_output_create(struct wl_listener *listener, void *data)
}
static void
+handle_output_move(struct wl_listener *listener, void *data)
+{
+ struct desktop_shell *shell;
+ struct weston_output *output;
+ struct weston_layer *layer;
+ struct weston_view *view;
+ float x, y;
+
+ shell = container_of(listener, struct desktop_shell,
+ output_move_listener);
+ output = data;
+
+ /* Move all views in the layers owned by the shell */
+ wl_list_for_each(layer, shell->fullscreen_layer.link.prev, link) {
+ wl_list_for_each(view, &layer->view_list, layer_link) {
+ if (view->output != output)
+ continue;
+
+ x = view->geometry.x + output->move_x;
+ y = view->geometry.y + output->move_y;
+ weston_view_set_position(view, x, y);
+ }
+
+ /* We don't start from the beggining of the layer list, so
+ * make sure we don't wrap around it. */
+ if (layer == &shell->background_layer)
+ break;
+ }
+}
+
+static void
setup_output_destroy_handler(struct weston_compositor *ec,
struct desktop_shell *shell)
{
@@ -5484,6 +5799,9 @@ setup_output_destroy_handler(struct weston_compositor *ec,
shell->output_create_listener.notify = handle_output_create;
wl_signal_add(&ec->output_created_signal,
&shell->output_create_listener);
+
+ shell->output_move_listener.notify = handle_output_move;
+ wl_signal_add(&ec->output_moved_signal, &shell->output_move_listener);
}
static void
@@ -5534,6 +5852,9 @@ shell_add_bindings(struct weston_compositor *ec, struct desktop_shell *shell)
weston_compositor_add_button_binding(ec, BTN_LEFT, 0,
click_to_activate_binding,
shell);
+ weston_compositor_add_button_binding(ec, BTN_RIGHT, 0,
+ click_to_activate_binding,
+ shell);
weston_compositor_add_touch_binding(ec, 0,
touch_to_activate_binding,
shell);
@@ -5633,7 +5954,6 @@ module_init(struct weston_compositor *ec,
shell->wake_listener.notify = wake_handler;
wl_signal_add(&ec->wake_signal, &shell->wake_listener);
- ec->ping_handler = ping_handler;
ec->shell_interface.shell = shell;
ec->shell_interface.create_shell_surface = create_shell_surface;
ec->shell_interface.get_primary_view = get_primary_view;
@@ -5673,6 +5993,8 @@ module_init(struct weston_compositor *ec,
}
activate_workspace(shell, 0);
+ weston_layer_init(&shell->minimized_layer, NULL);
+
wl_list_init(&shell->workspaces.anim_sticky_list);
wl_list_init(&shell->workspaces.animation.link);
shell->workspaces.animation.frame = animate_workspace_change_frame;
@@ -5708,8 +6030,12 @@ module_init(struct weston_compositor *ec,
shell->screensaver.timer =
wl_event_loop_add_timer(loop, screensaver_timeout, shell);
- wl_list_for_each(seat, &ec->seat_list, link)
+ wl_list_for_each(seat, &ec->seat_list, link) {
create_pointer_focus_listener(seat);
+ create_keyboard_focus_listener(seat);
+ }
+
+ screenshooter_create(ec);
shell_add_bindings(ec, shell);
diff --git a/desktop-shell/shell.h b/desktop-shell/shell.h
index dbb28543..5d127c6d 100644
--- a/desktop-shell/shell.h
+++ b/desktop-shell/shell.h
@@ -52,6 +52,41 @@ enum exposay_layout_state {
EXPOSAY_LAYOUT_ANIMATE_TO_OVERVIEW, /* in transition to all windows */
};
+struct exposay_output {
+ int num_surfaces;
+ int grid_size;
+ int surface_size;
+
+ int hpadding_outer;
+ int vpadding_outer;
+ int padding_inner;
+};
+
+struct exposay {
+ /* XXX: Make these exposay_surfaces. */
+ struct weston_view *focus_prev;
+ struct weston_view *focus_current;
+ struct weston_view *clicked;
+ struct workspace *workspace;
+ struct weston_seat *seat;
+
+ struct wl_list surface_list;
+
+ struct weston_keyboard_grab grab_kbd;
+ struct weston_pointer_grab grab_ptr;
+
+ enum exposay_target_state state_target;
+ enum exposay_layout_state state_cur;
+ int in_flight; /* number of animations still running */
+
+ int row_current;
+ int column_current;
+ struct exposay_output *cur_output;
+
+ bool mod_pressed;
+ bool mod_invalid;
+};
+
struct focus_surface {
struct weston_surface *surface;
struct weston_view *view;
@@ -69,6 +104,14 @@ struct workspace {
struct weston_view_animation *focus_animation;
};
+struct shell_output {
+ struct desktop_shell *shell;
+ struct weston_output *output;
+ struct exposay_output eoutput;
+ struct wl_listener destroy_listener;
+ struct wl_list link;
+};
+
struct desktop_shell {
struct weston_compositor *compositor;
@@ -146,36 +189,7 @@ struct desktop_shell {
struct wl_event_source *startup_timer;
} fade;
- struct exposay {
- /* XXX: Make these exposay_surfaces. */
- struct weston_view *focus_prev;
- struct weston_view *focus_current;
- struct weston_view *clicked;
- struct workspace *workspace;
- struct weston_seat *seat;
- struct wl_list surface_list;
-
- struct weston_keyboard_grab grab_kbd;
- struct weston_pointer_grab grab_ptr;
-
- enum exposay_target_state state_target;
- enum exposay_layout_state state_cur;
- int in_flight; /* number of animations still running */
-
- int num_surfaces;
- int grid_size;
- int surface_size;
-
- int hpadding_outer;
- int vpadding_outer;
- int padding_inner;
-
- int row_current;
- int column_current;
-
- bool mod_pressed;
- bool mod_invalid;
- } exposay;
+ struct exposay exposay;
uint32_t binding_modifier;
uint32_t exposay_modifier;
@@ -183,7 +197,10 @@ struct desktop_shell {
enum animation_type startup_animation_type;
enum animation_type focus_animation_type;
+ struct weston_layer minimized_layer;
+
struct wl_listener output_create_listener;
+ struct wl_listener output_move_listener;
struct wl_list output_list;
char *client;
diff --git a/fullscreen-shell/fullscreen-shell.c b/fullscreen-shell/fullscreen-shell.c
new file mode 100644
index 00000000..a8dad8e6
--- /dev/null
+++ b/fullscreen-shell/fullscreen-shell.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright © 2013 Jason Ekstrand
+ *
+ * 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 <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+
+#include "compositor.h"
+#include "fullscreen-shell-server-protocol.h"
+
+struct fullscreen_shell {
+ struct wl_client *client;
+ struct wl_listener client_destroyed;
+ struct weston_compositor *compositor;
+
+ struct weston_layer layer;
+ struct wl_list output_list;
+ struct wl_listener output_created_listener;
+
+ struct wl_listener seat_created_listener;
+};
+
+struct fs_output {
+ struct fullscreen_shell *shell;
+ struct wl_list link;
+
+ struct weston_output *output;
+ struct wl_listener output_destroyed;
+
+ struct {
+ struct weston_surface *surface;
+ struct wl_listener surface_destroyed;
+ struct wl_resource *mode_feedback;
+
+ int presented_for_mode;
+ enum _wl_fullscreen_shell_present_method method;
+ int32_t framerate;
+ } pending;
+
+ struct weston_surface *surface;
+ struct wl_listener surface_destroyed;
+ struct weston_view *view;
+ struct weston_view *black_view;
+ struct weston_transform transform; /* matrix from x, y */
+
+ int presented_for_mode;
+ enum _wl_fullscreen_shell_present_method method;
+ uint32_t framerate;
+};
+
+struct pointer_focus_listener {
+ struct fullscreen_shell *shell;
+ struct wl_listener pointer_focus;
+ struct wl_listener seat_caps;
+ struct wl_listener seat_destroyed;
+};
+
+static void
+pointer_focus_changed(struct wl_listener *listener, void *data)
+{
+ struct weston_pointer *pointer = data;
+
+ if (pointer->focus && pointer->focus->surface->resource)
+ weston_surface_activate(pointer->focus->surface, pointer->seat);
+}
+
+static void
+seat_caps_changed(struct wl_listener *l, void *data)
+{
+ struct weston_seat *seat = data;
+ struct pointer_focus_listener *listener;
+ struct fs_output *fsout;
+
+ listener = container_of(l, struct pointer_focus_listener, seat_caps);
+
+ /* no pointer */
+ if (seat->pointer) {
+ if (!listener->pointer_focus.link.prev) {
+ wl_signal_add(&seat->pointer->focus_signal,
+ &listener->pointer_focus);
+ }
+ } else {
+ if (listener->pointer_focus.link.prev) {
+ wl_list_remove(&listener->pointer_focus.link);
+ }
+ }
+
+ if (seat->keyboard && seat->keyboard->focus != NULL) {
+ wl_list_for_each(fsout, &listener->shell->output_list, link) {
+ if (fsout->surface) {
+ weston_surface_activate(fsout->surface, seat);
+ return;
+ }
+ }
+ }
+}
+
+static void
+seat_destroyed(struct wl_listener *l, void *data)
+{
+ struct pointer_focus_listener *listener;
+
+ listener = container_of(l, struct pointer_focus_listener,
+ seat_destroyed);
+
+ free(listener);
+}
+
+static void
+seat_created(struct wl_listener *l, void *data)
+{
+ struct weston_seat *seat = data;
+ struct pointer_focus_listener *listener;
+
+ listener = malloc(sizeof *listener);
+ if (!listener)
+ return;
+ memset(listener, 0, sizeof *listener);
+
+ listener->shell = container_of(l, struct fullscreen_shell,
+ seat_created_listener);
+ listener->pointer_focus.notify = pointer_focus_changed;
+ listener->seat_caps.notify = seat_caps_changed;
+ listener->seat_destroyed.notify = seat_destroyed;
+
+ wl_signal_add(&seat->destroy_signal, &listener->seat_destroyed);
+ wl_signal_add(&seat->updated_caps_signal, &listener->seat_caps);
+
+ seat_caps_changed(&listener->seat_caps, seat);
+}
+
+static void
+black_surface_configure(struct weston_surface *es, int32_t sx, int32_t sy)
+{
+}
+
+static struct weston_view *
+create_black_surface(struct weston_compositor *ec, struct fs_output *fsout,
+ float x, float y, int w, int h)
+{
+ struct weston_surface *surface = NULL;
+ struct weston_view *view;
+
+ surface = weston_surface_create(ec);
+ if (surface == NULL) {
+ weston_log("no memory\n");
+ return NULL;
+ }
+ view = weston_view_create(surface);
+ if (!view) {
+ weston_surface_destroy(surface);
+ weston_log("no memory\n");
+ return NULL;
+ }
+
+ surface->configure = black_surface_configure;
+ surface->configure_private = fsout;
+ weston_surface_set_color(surface, 0.0f, 0.0f, 0.0f, 1.0f);
+ pixman_region32_fini(&surface->opaque);
+ pixman_region32_init_rect(&surface->opaque, 0, 0, w, h);
+ pixman_region32_fini(&surface->input);
+ pixman_region32_init_rect(&surface->input, 0, 0, w, h);
+
+ weston_surface_set_size(surface, w, h);
+ weston_view_set_position(view, x, y);
+
+ return view;
+}
+
+static void
+fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
+ enum _wl_fullscreen_shell_present_method method,
+ int32_t framerate, int presented_for_mode);
+static void
+fs_output_apply_pending(struct fs_output *fsout);
+static void
+fs_output_clear_pending(struct fs_output *fsout);
+
+static void
+fs_output_destroy(struct fs_output *fsout)
+{
+ fs_output_set_surface(fsout, NULL, 0, 0, 0);
+ fs_output_clear_pending(fsout);
+
+ wl_list_remove(&fsout->link);
+
+ if (fsout->output)
+ wl_list_remove(&fsout->output_destroyed.link);
+}
+
+static void
+output_destroyed(struct wl_listener *listener, void *data)
+{
+ struct fs_output *output = container_of(listener,
+ struct fs_output,
+ output_destroyed);
+ fs_output_destroy(output);
+}
+
+static void
+surface_destroyed(struct wl_listener *listener, void *data)
+{
+ struct fs_output *fsout = container_of(listener,
+ struct fs_output,
+ surface_destroyed);
+ fsout->surface = NULL;
+ fsout->view = NULL;
+}
+
+static void
+pending_surface_destroyed(struct wl_listener *listener, void *data)
+{
+ struct fs_output *fsout = container_of(listener,
+ struct fs_output,
+ pending.surface_destroyed);
+ fsout->pending.surface = NULL;
+}
+
+static struct fs_output *
+fs_output_create(struct fullscreen_shell *shell, struct weston_output *output)
+{
+ struct fs_output *fsout;
+
+ fsout = malloc(sizeof *fsout);
+ if (!fsout)
+ return NULL;
+ memset(fsout, 0, sizeof *fsout);
+
+ fsout->shell = shell;
+ wl_list_insert(&shell->output_list, &fsout->link);
+
+ fsout->output = output;
+ fsout->output_destroyed.notify = output_destroyed;
+ wl_signal_add(&output->destroy_signal, &fsout->output_destroyed);
+
+ fsout->surface_destroyed.notify = surface_destroyed;
+ fsout->pending.surface_destroyed.notify = pending_surface_destroyed;
+ fsout->black_view = create_black_surface(shell->compositor, fsout,
+ output->x, output->y,
+ output->width, output->height);
+ wl_list_insert(&shell->layer.view_list,
+ &fsout->black_view->layer_link);
+ wl_list_init(&fsout->transform.link);
+ return fsout;
+}
+
+static struct fs_output *
+fs_output_for_output(struct weston_output *output)
+{
+ struct wl_listener *listener;
+
+ if (!output)
+ return NULL;
+
+ listener = wl_signal_get(&output->destroy_signal, output_destroyed);
+
+ return container_of(listener, struct fs_output, output_destroyed);
+}
+
+static void
+restore_output_mode(struct weston_output *output)
+{
+ if (output->current_mode != output->original_mode ||
+ (int32_t)output->current_scale != output->original_scale)
+ weston_output_switch_mode(output,
+ output->original_mode,
+ output->original_scale,
+ WESTON_MODE_SWITCH_RESTORE_NATIVE);
+}
+
+/*
+ * Returns the bounding box of a surface and all its sub-surfaces,
+ * in the surface coordinates system. */
+static void
+surface_subsurfaces_boundingbox(struct weston_surface *surface, int32_t *x,
+ int32_t *y, int32_t *w, int32_t *h) {
+ pixman_region32_t region;
+ pixman_box32_t *box;
+ struct weston_subsurface *subsurface;
+
+ pixman_region32_init_rect(&region, 0, 0,
+ surface->width,
+ surface->height);
+
+ wl_list_for_each(subsurface, &surface->subsurface_list, parent_link) {
+ pixman_region32_union_rect(&region, &region,
+ subsurface->position.x,
+ subsurface->position.y,
+ subsurface->surface->width,
+ subsurface->surface->height);
+ }
+
+ box = pixman_region32_extents(&region);
+ if (x)
+ *x = box->x1;
+ if (y)
+ *y = box->y1;
+ if (w)
+ *w = box->x2 - box->x1;
+ if (h)
+ *h = box->y2 - box->y1;
+
+ pixman_region32_fini(&region);
+}
+
+static void
+fs_output_center_view(struct fs_output *fsout)
+{
+ int32_t surf_x, surf_y, surf_width, surf_height;
+ float x, y;
+ struct weston_output *output = fsout->output;
+
+ surface_subsurfaces_boundingbox(fsout->view->surface, &surf_x, &surf_y,
+ &surf_width, &surf_height);
+
+ x = output->x + (output->width - surf_width) / 2 - surf_x / 2;
+ y = output->y + (output->height - surf_height) / 2 - surf_y / 2;
+
+ weston_view_set_position(fsout->view, x, y);
+}
+
+static void
+fs_output_scale_view(struct fs_output *fsout, float width, float height)
+{
+ float x, y;
+ int32_t surf_x, surf_y, surf_width, surf_height;
+ struct weston_matrix *matrix;
+ struct weston_view *view = fsout->view;
+ struct weston_output *output = fsout->output;
+
+ surface_subsurfaces_boundingbox(view->surface, &surf_x, &surf_y,
+ &surf_width, &surf_height);
+
+ if (output->width == surf_width && output->height == surf_height) {
+ weston_view_set_position(view,
+ fsout->output->x - surf_x,
+ fsout->output->y - surf_y);
+ } else {
+ matrix = &fsout->transform.matrix;
+ weston_matrix_init(matrix);
+
+ weston_matrix_scale(matrix, width / surf_width,
+ height / surf_height, 1);
+ wl_list_remove(&fsout->transform.link);
+ wl_list_insert(&fsout->view->geometry.transformation_list,
+ &fsout->transform.link);
+
+ x = output->x + (output->width - width) / 2 - surf_x;
+ y = output->y + (output->height - height) / 2 - surf_y;
+
+ weston_view_set_position(view, x, y);
+ }
+}
+
+static void
+fs_output_configure(struct fs_output *fsout, struct weston_surface *surface);
+
+static void
+fs_output_configure_simple(struct fs_output *fsout,
+ struct weston_surface *configured_surface)
+{
+ struct weston_output *output = fsout->output;
+ float output_aspect, surface_aspect;
+ int32_t surf_x, surf_y, surf_width, surf_height;
+
+ if (fsout->pending.surface == configured_surface)
+ fs_output_apply_pending(fsout);
+
+ assert(fsout->view);
+
+ restore_output_mode(fsout->output);
+
+ wl_list_remove(&fsout->transform.link);
+ wl_list_init(&fsout->transform.link);
+
+ surface_subsurfaces_boundingbox(fsout->view->surface,
+ &surf_x, &surf_y,
+ &surf_width, &surf_height);
+
+ output_aspect = (float) output->width / (float) output->height;
+ surface_aspect = (float) surf_width / (float) surf_height;
+
+ switch (fsout->method) {
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
+ fs_output_center_view(fsout);
+ break;
+
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
+ if (output_aspect < surface_aspect)
+ fs_output_scale_view(fsout,
+ output->width,
+ output->width / surface_aspect);
+ else
+ fs_output_scale_view(fsout,
+ output->height * surface_aspect,
+ output->height);
+ break;
+
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
+ if (output_aspect < surface_aspect)
+ fs_output_scale_view(fsout,
+ output->height * surface_aspect,
+ output->height);
+ else
+ fs_output_scale_view(fsout,
+ output->width,
+ output->width / surface_aspect);
+ break;
+
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
+ fs_output_scale_view(fsout, output->width, output->height);
+ break;
+ default:
+ break;
+ }
+
+ weston_view_set_position(fsout->black_view,
+ fsout->output->x - surf_x,
+ fsout->output->y - surf_y);
+ weston_surface_set_size(fsout->black_view->surface,
+ fsout->output->width,
+ fsout->output->height);
+}
+
+static void
+fs_output_configure_for_mode(struct fs_output *fsout,
+ struct weston_surface *configured_surface)
+{
+ int32_t surf_x, surf_y, surf_width, surf_height;
+ struct weston_mode mode;
+ int ret;
+
+ if (fsout->pending.surface != configured_surface) {
+ /* Nothing to really reconfigure. We'll just recenter the
+ * view in case they played with subsurfaces */
+ fs_output_center_view(fsout);
+ return;
+ }
+
+ /* We have a pending surface */
+ surface_subsurfaces_boundingbox(fsout->pending.surface,
+ &surf_x, &surf_y,
+ &surf_width, &surf_height);
+
+ mode.flags = 0;
+ mode.width = surf_width * fsout->output->native_scale;
+ mode.height = surf_height * fsout->output->native_scale;
+ mode.refresh = fsout->pending.framerate;
+
+ ret = weston_output_switch_mode(fsout->output, &mode,
+ fsout->output->native_scale,
+ WESTON_MODE_SWITCH_SET_TEMPORARY);
+
+ if (ret != 0) {
+ /* The mode switch failed. Clear the pending and
+ * reconfigure as per normal */
+ if (fsout->pending.mode_feedback) {
+ _wl_fullscreen_shell_mode_feedback_send_mode_failed(
+ fsout->pending.mode_feedback);
+ wl_resource_destroy(fsout->pending.mode_feedback);
+ fsout->pending.mode_feedback = NULL;
+ }
+
+ fs_output_clear_pending(fsout);
+ return;
+ }
+
+ if (fsout->pending.mode_feedback) {
+ _wl_fullscreen_shell_mode_feedback_send_mode_successful(
+ fsout->pending.mode_feedback);
+ wl_resource_destroy(fsout->pending.mode_feedback);
+ fsout->pending.mode_feedback = NULL;
+ }
+
+ fs_output_apply_pending(fsout);
+
+ weston_view_set_position(fsout->view,
+ fsout->output->x - surf_x,
+ fsout->output->y - surf_y);
+}
+
+static void
+fs_output_configure(struct fs_output *fsout,
+ struct weston_surface *surface)
+{
+ if (fsout->pending.surface == surface) {
+ if (fsout->pending.presented_for_mode)
+ fs_output_configure_for_mode(fsout, surface);
+ else
+ fs_output_configure_simple(fsout, surface);
+ } else {
+ if (fsout->presented_for_mode)
+ fs_output_configure_for_mode(fsout, surface);
+ else
+ fs_output_configure_simple(fsout, surface);
+ }
+
+ weston_output_schedule_repaint(fsout->output);
+}
+
+static void
+configure_presented_surface(struct weston_surface *surface, int32_t sx,
+ int32_t sy)
+{
+ struct fullscreen_shell *shell = surface->configure_private;
+ struct fs_output *fsout;
+
+ if (surface->configure != configure_presented_surface)
+ return;
+
+ wl_list_for_each(fsout, &shell->output_list, link)
+ if (fsout->surface == surface ||
+ fsout->pending.surface == surface)
+ fs_output_configure(fsout, surface);
+}
+
+static void
+fs_output_apply_pending(struct fs_output *fsout)
+{
+ assert(fsout->pending.surface);
+
+ if (fsout->surface && fsout->surface != fsout->pending.surface) {
+ wl_list_remove(&fsout->surface_destroyed.link);
+
+ weston_view_destroy(fsout->view);
+ fsout->view = NULL;
+
+ if (wl_list_empty(&fsout->surface->views)) {
+ fsout->surface->configure = NULL;
+ fsout->surface->configure_private = NULL;
+ }
+
+ fsout->surface = NULL;
+ }
+
+ fsout->method = fsout->pending.method;
+ fsout->framerate = fsout->pending.framerate;
+ fsout->presented_for_mode = fsout->pending.presented_for_mode;
+
+ if (fsout->surface != fsout->pending.surface) {
+ fsout->surface = fsout->pending.surface;
+
+ fsout->view = weston_view_create(fsout->surface);
+ if (!fsout->view) {
+ weston_log("no memory\n");
+ return;
+ }
+
+ wl_signal_add(&fsout->surface->destroy_signal,
+ &fsout->surface_destroyed);
+ wl_list_insert(&fsout->shell->layer.view_list,
+ &fsout->view->layer_link);
+ }
+
+ fs_output_clear_pending(fsout);
+}
+
+static void
+fs_output_clear_pending(struct fs_output *fsout)
+{
+ if (!fsout->pending.surface)
+ return;
+
+ if (fsout->pending.mode_feedback) {
+ _wl_fullscreen_shell_mode_feedback_send_present_cancelled(
+ fsout->pending.mode_feedback);
+ wl_resource_destroy(fsout->pending.mode_feedback);
+ fsout->pending.mode_feedback = NULL;
+ }
+
+ wl_list_remove(&fsout->pending.surface_destroyed.link);
+ fsout->pending.surface = NULL;
+}
+
+static void
+fs_output_set_surface(struct fs_output *fsout, struct weston_surface *surface,
+ enum _wl_fullscreen_shell_present_method method,
+ int32_t framerate, int presented_for_mode)
+{
+ fs_output_clear_pending(fsout);
+
+ if (surface) {
+ if (!surface->configure) {
+ surface->configure = configure_presented_surface;
+ surface->configure_private = fsout->shell;
+ }
+
+ fsout->pending.surface = surface;
+ wl_signal_add(&fsout->pending.surface->destroy_signal,
+ &fsout->pending.surface_destroyed);
+
+ fsout->pending.method = method;
+ fsout->pending.framerate = framerate;
+ fsout->pending.presented_for_mode = presented_for_mode;
+ } else if (fsout->surface) {
+ /* we clear immediately */
+ wl_list_remove(&fsout->surface_destroyed.link);
+
+ weston_view_destroy(fsout->view);
+ fsout->view = NULL;
+
+ if (wl_list_empty(&fsout->surface->views)) {
+ fsout->surface->configure = NULL;
+ fsout->surface->configure_private = NULL;
+ }
+
+ fsout->surface = NULL;
+
+ weston_output_schedule_repaint(fsout->output);
+ }
+}
+
+static void
+fullscreen_shell_release(struct wl_client *client,
+ struct wl_resource *resource)
+{
+ wl_resource_destroy(resource);
+}
+
+static void
+fullscreen_shell_present_surface(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *surface_res,
+ uint32_t method,
+ struct wl_resource *output_res)
+{
+ struct fullscreen_shell *shell =
+ wl_resource_get_user_data(resource);
+ struct weston_output *output;
+ struct weston_surface *surface;
+ struct weston_seat *seat;
+ struct fs_output *fsout;
+
+ surface = surface_res ? wl_resource_get_user_data(surface_res) : NULL;
+
+ switch(method) {
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_DEFAULT:
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER:
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM:
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_ZOOM_CROP:
+ case _WL_FULLSCREEN_SHELL_PRESENT_METHOD_STRETCH:
+ break;
+ default:
+ wl_resource_post_error(resource,
+ _WL_FULLSCREEN_SHELL_ERROR_INVALID_METHOD,
+ "Invalid presentation method");
+ }
+
+ if (output_res) {
+ output = wl_resource_get_user_data(output_res);
+ fsout = fs_output_for_output(output);
+ fs_output_set_surface(fsout, surface, method, 0, 0);
+ } else {
+ wl_list_for_each(fsout, &shell->output_list, link)
+ fs_output_set_surface(fsout, surface, method, 0, 0);
+ }
+
+ if (surface) {
+ wl_list_for_each(seat, &shell->compositor->seat_list, link) {
+ if (seat->keyboard && seat->keyboard->focus == NULL)
+ weston_surface_activate(surface, seat);
+ }
+ }
+}
+
+static void
+mode_feedback_destroyed(struct wl_resource *resource)
+{
+ struct fs_output *fsout = wl_resource_get_user_data(resource);
+
+ fsout->pending.mode_feedback = NULL;
+}
+
+static void
+fullscreen_shell_present_surface_for_mode(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *surface_res,
+ struct wl_resource *output_res,
+ int32_t framerate,
+ uint32_t feedback_id)
+{
+ struct fullscreen_shell *shell =
+ wl_resource_get_user_data(resource);
+ struct weston_output *output;
+ struct weston_surface *surface;
+ struct weston_seat *seat;
+ struct fs_output *fsout;
+
+ output = wl_resource_get_user_data(output_res);
+ fsout = fs_output_for_output(output);
+
+ if (surface_res == NULL) {
+ fs_output_set_surface(fsout, NULL, 0, 0, 0);
+ return;
+ }
+
+ surface = wl_resource_get_user_data(surface_res);
+ fs_output_set_surface(fsout, surface, 0, framerate, 1);
+
+ fsout->pending.mode_feedback =
+ wl_resource_create(client,
+ &_wl_fullscreen_shell_mode_feedback_interface,
+ 1, feedback_id);
+ wl_resource_set_implementation(fsout->pending.mode_feedback, NULL,
+ fsout, mode_feedback_destroyed);
+
+ wl_list_for_each(seat, &shell->compositor->seat_list, link) {
+ if (seat->keyboard && seat->keyboard->focus == NULL)
+ weston_surface_activate(surface, seat);
+ }
+}
+
+struct _wl_fullscreen_shell_interface fullscreen_shell_implementation = {
+ fullscreen_shell_release,
+ fullscreen_shell_present_surface,
+ fullscreen_shell_present_surface_for_mode,
+};
+
+static void
+output_created(struct wl_listener *listener, void *data)
+{
+ struct fullscreen_shell *shell;
+
+ shell = container_of(listener, struct fullscreen_shell,
+ output_created_listener);
+
+ fs_output_create(shell, data);
+}
+
+static void
+client_destroyed(struct wl_listener *listener, void *data)
+{
+ struct fullscreen_shell *shell = container_of(listener,
+ struct fullscreen_shell,
+ client_destroyed);
+ shell->client = NULL;
+}
+
+static void
+bind_fullscreen_shell(struct wl_client *client, void *data, uint32_t version,
+ uint32_t id)
+{
+ struct fullscreen_shell *shell = data;
+ struct wl_resource *resource;
+
+ if (shell->client != NULL && shell->client != client)
+ return;
+ else if (shell->client == NULL) {
+ shell->client = client;
+ wl_client_add_destroy_listener(client, &shell->client_destroyed);
+ }
+
+ resource = wl_resource_create(client, &_wl_fullscreen_shell_interface,
+ 1, id);
+ wl_resource_set_implementation(resource,
+ &fullscreen_shell_implementation,
+ shell, NULL);
+
+ if (shell->compositor->capabilities & WESTON_CAP_CURSOR_PLANE)
+ _wl_fullscreen_shell_send_capability(resource,
+ _WL_FULLSCREEN_SHELL_CAPABILITY_CURSOR_PLANE);
+
+ if (shell->compositor->capabilities & WESTON_CAP_ARBITRARY_MODES)
+ _wl_fullscreen_shell_send_capability(resource,
+ _WL_FULLSCREEN_SHELL_CAPABILITY_ARBITRARY_MODES);
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *compositor,
+ int *argc, char *argv[])
+{
+ struct fullscreen_shell *shell;
+ struct weston_seat *seat;
+ struct weston_output *output;
+
+ shell = malloc(sizeof *shell);
+ if (shell == NULL)
+ return -1;
+
+ memset(shell, 0, sizeof *shell);
+ shell->compositor = compositor;
+
+ shell->client_destroyed.notify = client_destroyed;
+
+ weston_layer_init(&shell->layer, &compositor->cursor_layer.link);
+
+ wl_list_init(&shell->output_list);
+ shell->output_created_listener.notify = output_created;
+ wl_signal_add(&compositor->output_created_signal,
+ &shell->output_created_listener);
+ wl_list_for_each(output, &compositor->output_list, link)
+ fs_output_create(shell, output);
+
+ shell->seat_created_listener.notify = seat_created;
+ wl_signal_add(&compositor->seat_created_signal,
+ &shell->seat_created_listener);
+ wl_list_for_each(seat, &compositor->seat_list, link)
+ seat_created(NULL, seat);
+
+ wl_global_create(compositor->wl_display,
+ &_wl_fullscreen_shell_interface, 1, shell,
+ bind_fullscreen_shell);
+
+ return 0;
+}
diff --git a/man/weston.ini.man b/man/weston.ini.man
index ce3f9280..667f70a0 100644
--- a/man/weston.ini.man
+++ b/man/weston.ini.man
@@ -92,16 +92,29 @@ The
.B core
section is used to select the startup compositor modules.
.TP 7
-.BI "modules=" desktop-shell.so,xwayland.so
-specifies the modules to load (string). Available modules in the
+.BI "shell=" desktop-shell.so
+specifies a shell to load (string). This can be used to load your own
+implemented shell or one with Weston as default. Available shells
+in the
.IR "__weston_modules_dir__"
directory are:
.PP
.RS 10
.nf
.BR desktop-shell.so
-.BR tablet-shell.so
+.fi
+.RE
+.TP 7
+.TP 7
+.BI "modules=" xwayland.so,cms-colord.so
+specifies the modules to load (string). Available modules in the
+.IR "__weston_modules_dir__"
+directory are:
+.PP
+.RS 10
+.nf
.BR xwayland.so
+.BR cms-colord.so
.fi
.RE
.TP 7
diff --git a/man/weston.man b/man/weston.man
index f2d1b4c7..fd1c7a51 100644
--- a/man/weston.man
+++ b/man/weston.man
@@ -186,6 +186,10 @@ X windows to emulate the same number of outputs.
Make the default size of each X window
.IR W x H " pixels."
.TP
+.B \-\-scale\fR=\fIN\fR
+Give all outputs a scale factor of
+.I N.
+.TP
.B \-\-use\-pixman
Use the pixman renderer. By default weston will try to use EGL and
GLES2 for rendering. Passing this option will make weston use the
diff --git a/protocol/fullscreen-shell.xml b/protocol/fullscreen-shell.xml
new file mode 100644
index 00000000..3c2cf3c0
--- /dev/null
+++ b/protocol/fullscreen-shell.xml
@@ -0,0 +1,206 @@
+<protocol name="fullscreen_shell">
+ <interface name="_wl_fullscreen_shell" version="1">
+ <description summary="Displays a single surface per output">
+ Displays a single surface per output.
+
+ This interface provides a mechanism for a single client to display
+ simple full-screen surfaces. While there technically may be multiple
+ clients bound to this interface, only one of those clients should be
+ shown at a time.
+
+ To present a surface, the client uses either the present_surface or
+ present_surface_for_mode requests. Presenting a surface takes effect
+ on the next wl_surface.commit. See the individual requests for
+ details about scaling and mode switches.
+
+ The client can have at most one surface per output at any time.
+ Requesting a surface be presented on an output that already has a
+ surface replaces the previously presented surface. Presenting a null
+ surface removes its content and effectively disables the output.
+ Exactly what happens when an output is "disabled" is
+ compositor-specific. The same surface may be presented on multiple
+ outputs simultaneously.
+
+ Once a surface is presented on an output, it stays on that output
+ until either the client removes it or the compositor destroys the
+ output. This way, the client can update the output's contents by
+ simply attaching a new buffer.
+ </description>
+
+ <request name="release" type="destructor">
+ <description summary="release the wl_fullscreen_shell interface">
+ Release the binding from the wl_fullscreen_shell interface
+
+ This destroys the server-side object and frees this binding. If
+ the client binds to wl_fullscreen_shell multiple times, it may wish
+ to free some of those bindings.
+ </description>
+ </request>
+
+ <enum name="capability">
+ <description summary="capabilities advertised by the compositor">
+ Various capabilities that can be advertised by the compositor. They
+ are advertised one-at-a-time when the wl_fullscreen_shell interface is
+ bound. See the wl_fullscreen_shell.capability event for more details.
+
+ ARBITRARY_MODE:
+ This is a hint to the client that indicates that the compositor is
+ capable of setting practially any mode on its outputs. If this
+ capability is provided, wl_fullscreen_shell.present_surface_for_mode
+ will almost never fail and clients should feel free to set whatever
+ mode they like. If the compositor does not advertise this, it may
+ still suppot some modes that are not advertised through wl_global.mode
+ but it is less likely.
+
+ CURSOR_PLANE:
+ This is a hint to the client that indicates that the compositor can
+ handle a cursor surface from the client without actually compositing.
+ This may be because of a hardware cursor plane or some other mechanism.
+ If the compositor does not advertise this capability then setting
+ wl_pointer.cursor may degrade performance or be ignored entirely. If
+ CURSOR_PLANE is not advertised, it is recommended that the client draw
+ its own cursor and set wl_pointer.cursor(NULL).
+ </description>
+ <entry name="arbitrary_modes" value="1" summary="compositor is capable of almost any output mode"/>
+ <entry name="cursor_plane" value="2" summary="compositor has a seperate cursor plane"/>
+ </enum>
+
+ <event name="capability">
+ <description summary="advertises a capability of the compositor">
+ Advertises a single capability of the compositor.
+
+ When the wl_fullscreen_shell interface is bound, this event is emitted
+ once for each capability advertised. Valid capabilities are given by
+ the wl_fullscreen_shell.capability enum. If clients want to take
+ advantage of any of these capabilities, they sould use a
+ wl_display.sync request immediatly after binding to ensure that they
+ recieve all the capability events.
+ </description>
+ <arg name="capabilty" type="uint"/>
+ </event>
+
+ <enum name="present_method">
+ <description summary="different method to set the surface fullscreen">
+ Hints to indicate to the compositor how to deal with a conflict
+ between the dimensions of the surface and the dimensions of the
+ output. The compositor is free to ignore this parameter.
+ </description>
+ <entry name="default" value="0" summary="no preference, apply default policy"/>
+ <entry name="center" value="1" summary="center the surface on the output"/>
+ <entry name="zoom" value="2" summary="scale the surface, preserving aspect ratio, to the largest size that will fit on the output" />
+ <entry name="zoom_crop" value="3" summary="scale the surface, preserving aspect ratio, to fully fill the output cropping if needed" />
+ <entry name="stretch" value="4" summary="scale the surface to the size of the output ignoring aspect ratio" />
+ </enum>
+
+ <request name="present_surface">
+ <description summary="present surface for display">
+ Present a surface on the given output.
+
+ If the output is null, the compositor will present the surface on
+ whatever display (or displays) it thinks best. In particular, this
+ may replace any or all surfaces currently presented so it should
+ not be used in combination with placing surfaces on specific
+ outputs.
+
+ The method parameter is a hint to the compositor for how the surface
+ is to be presented. In particular, it tells the compostior how to
+ handle a size mismatch between the presented surface and the
+ output. The compositor is free to ignore this parameter.
+
+ The "zoom", "zoom_crop", and "stretch" methods imply a scaling
+ operation on the surface. This will override any kind of output
+ scaling, so the buffer_scale property of the surface is effectively
+ ignored.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+ <arg name="method" type="uint"/>
+ <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+ </request>
+
+ <request name="present_surface_for_mode">
+ <description summary="present surface for display at a particular mode">
+ Presents a surface on the given output for a particular mode.
+
+ If the current size of the output differs from that of the surface,
+ the compositor will attempt to change the size of the output to
+ match the surface. The result of the mode-switch operation will be
+ returned via the provided wl_fullscreen_shell_mode_feedback object.
+
+ If the current output mode matches the one requested or if the
+ compositor successfully switches the mode to match the surface,
+ then the mode_successful event will be sent and the output will
+ contain the contents of the given surface. If the compositor
+ cannot match the output size to the surface size, the mode_failed
+ will be sent and the output will contain the contents of the
+ previously presented surface (if any). If another surface is
+ presented on the given output before either of these has a chance
+ to happen, the present_cancelled event will be sent.
+
+ Due to race conditions and other issues unknown to the client, no
+ mode-switch operation is guaranteed to succeed. However, if the
+ mode is one advertised by wl_output.mode or if the compositor
+ advertises the ARBITRARY_MODES capability, then the client should
+ expect that the mode-switch operation will usually succeed.
+
+ If the size of the presented surface changes, the resulting output
+ is undefined. The compositor may attempt to change the output mode
+ to compensate. However, there is no guarantee that a suitable mode
+ will be found and the client has no way to be notified of success
+ or failure.
+
+ The framerate parameter specifies the desired framerate for the
+ output in mHz. The compositor is free to ignore this parameter. A
+ value of 0 indicates that the client has no preference.
+
+ If the value of wl_output.scale differs from wl_surface.buffer_scale,
+ then the compositor may choose a mode that matches either the buffer
+ size or the surface size. In either case, the surface will fill the
+ output.
+ </description>
+ <arg name="surface" type="object" interface="wl_surface"/>
+ <arg name="output" type="object" interface="wl_output"/>
+ <arg name="framerate" type="int"/>
+ <arg name="feedback" type="new_id" interface="_wl_fullscreen_shell_mode_feedback"/>
+ </request>
+
+ <enum name="error">
+ <description summary="wl_fullscreen_shell error values">
+ These errors can be emitted in response to wl_fullscreen_shell requests
+ </description>
+ <entry name="invalid_method" value="0" summary="present_method is not known"/>
+ </enum>
+ </interface>
+
+ <interface name="_wl_fullscreen_shell_mode_feedback" version="1">
+ <event name="mode_successful">
+ <description summary="mode switch succeeded">
+ This event indicates that the attempted mode switch operation was
+ successful. A surface of the size requested in the mode switch
+ will fill the output without scaling.
+
+ Upon receiving this event, the client should destroy the
+ wl_fullscreen_shell_mode_feedback object.
+ </description>
+ </event>
+ <event name="mode_failed">
+ <description summary="mode switch failed">
+ This event indicates that the attempted mode switch operation
+ failed. This may be because the requested output mode is not
+ possible or it may mean that the compositor does not want to allow it.
+
+ Upon receiving this event, the client should destroy the
+ wl_fullscreen_shell_mode_feedback object.
+ </description>
+ </event>
+ <event name="present_cancelled">
+ <description summary="mode switch cancelled">
+ This event indicates that the attempted mode switch operation was
+ cancelled. Most likely this is because the client requested a
+ second mode switch before the first one completed.
+
+ Upon receiving this event, the client should destroy the
+ wl_fullscreen_shell_mode_feedback object.
+ </description>
+ </event>
+ </interface>
+</protocol>
diff --git a/protocol/scaler.xml b/protocol/scaler.xml
index dfe44b87..e21ae5b0 100644
--- a/protocol/scaler.xml
+++ b/protocol/scaler.xml
@@ -2,7 +2,7 @@
<protocol name="scaler">
<copyright>
- Copyright © 2013 Collabora, Ltd.
+ Copyright © 2013-2014 Collabora, Ltd.
Permission to use, copy, modify, distribute, and sell this
software and its documentation for any purpose is hereby granted
@@ -26,7 +26,7 @@
THIS SOFTWARE.
</copyright>
- <interface name="wl_scaler" version="1">
+ <interface name="wl_scaler" version="2">
<description summary="surface cropping and scaling">
The global interface exposing surface cropping and scaling
capabilities is used to instantiate an interface extension for a
@@ -64,7 +64,7 @@
</request>
</interface>
- <interface name="wl_viewport" version="1">
+ <interface name="wl_viewport" version="2">
<description summary="crop and scale interface to a wl_surface">
An additional interface to a wl_surface object, which allows the
client to specify the cropping and scaling of the surface
@@ -76,20 +76,30 @@
dst_height). This state is double-buffered, and is applied on the
next wl_surface.commit.
- Before the first set request, the wl_surface still behaves as if
- there was no crop and scale state. That is, no scaling is applied,
- and the surface size is as defined in wl_surface.attach.
-
- The crop and scale state causes the surface size to become
- dst_width, dst_height. This overrides whatever the attached
- wl_buffer size is, unless the wl_buffer is NULL. If the wl_buffer is
- NULL, the surface has no content and therefore no size.
+ The two parts of crop and scale state are independent: the source
+ rectangle, and the destination size. Initially both are unset, that
+ is, no scaling is applied. The whole of the current wl_buffer is
+ used as the source, and the surface size is as defined in
+ wl_surface.attach.
+
+ If the destination size is set, it causes the surface size to become
+ dst_width, dst_height. The source (rectangle) is scaled to exactly
+ this size. This overrides whatever the attached wl_buffer size is,
+ unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
+ has no content and therefore no size. Otherwise, the size is always
+ at least 1x1 in surface coordinates.
+
+ If the source rectangle is set, it defines what area of the
+ wl_buffer is taken as the source. If the source rectangle is set and
+ the destination size is not set, the surface size becomes the source
+ rectangle size rounded up to the nearest integer. If the source size
+ is already exactly integers, this results in cropping without scaling.
The coordinate transformations from buffer pixel coordinates up to
the surface-local coordinates happen in the following order:
1. buffer_transform (wl_surface.set_buffer_transform)
2. buffer_scale (wl_surface.set_buffer_scale)
- 3. crop and scale (wl_viewport.set)
+ 3. crop and scale (wl_viewport.set*)
This means, that the source rectangle coordinates of crop and scale
are given in the coordinates after the buffer transform and scale,
i.e. in the coordinates that would be the surface-local coordinates
@@ -122,14 +132,14 @@
<enum name="error">
<entry name="bad_value" value="0"
- summary="negative values in width or height"/>
+ summary="negative or zero values in width or height"/>
</enum>
<request name="set">
<description summary="set the crop and scale state">
- Set the crop and scale state of the associated wl_surface. See
- wl_viewport for the description, and relation to the wl_buffer
- size.
+ Set both source rectangle and destination size of the associated
+ wl_surface. See wl_viewport for the description, and relation to
+ the wl_buffer size.
The bad_value protocol error is raised if src_width or
src_height is negative, or if dst_width or dst_height is not
@@ -152,5 +162,49 @@
<arg name="dst_height" type="int" summary="surface height"/>
</request>
+ <request name="set_source" since="2">
+ <description summary="set the source rectangle for cropping">
+ Set the source rectangle of the associated wl_surface. See
+ wl_viewport for the description, and relation to the wl_buffer
+ size.
+
+ If width is -1.0 and height is -1.0, the destination size is unset
+ instead. Any other pair of values for width and height that
+ contains zero or negative values raises the bad_value protocol
+ error.
+
+ The crop and scale state is double-buffered state, and will be
+ applied on the next wl_surface.commit.
+ </description>
+
+ <arg name="x" type="fixed" summary="source rectangle x"/>
+ <arg name="y" type="fixed" summary="source rectangle y"/>
+ <arg name="width" type="fixed" summary="source rectangle width"/>
+ <arg name="height" type="fixed" summary="source rectangle height"/>
+ </request>
+
+ <request name="set_destination" since="2">
+ <description summary="set the surface size for scaling">
+ Set the destination size of the associated wl_surface. See
+ wl_viewport for the description, and relation to the wl_buffer
+ size.
+
+ If width is -1 and height is -1, the destination size is unset
+ instead. Any other pair of values for width and height that
+ contains zero or negative values raises the bad_value protocol
+ error.
+
+ The crop and scale state is double-buffered state, and will be
+ applied on the next wl_surface.commit.
+
+ Arguments x and y do not exist here, use the x and y arguments to
+ wl_surface.attach. The x, y, width, and height define the
+ surface-local coordinate system irrespective of the attached
+ wl_buffer size.
+ </description>
+
+ <arg name="width" type="int" summary="surface width"/>
+ <arg name="height" type="int" summary="surface height"/>
+ </request>
</interface>
</protocol>
diff --git a/protocol/xdg-shell.xml b/protocol/xdg-shell.xml
index 4e5cff8d..79a28317 100644
--- a/protocol/xdg-shell.xml
+++ b/protocol/xdg-shell.xml
@@ -40,19 +40,22 @@
<enum name="version">
<description summary="latest protocol version">
- Use this enum to check the protocol version, and it will be updated
- automatically.
+ The 'current' member of this enum gives the version of the
+ protocol. Implementations can compare this to the version
+ they implement using static_assert to ensure the protocol and
+ implementation versions match.
</description>
- <entry name="current" value="1" summary="Always the latest version"/>
+ <entry name="current" value="3" summary="Always the latest version"/>
</enum>
<request name="use_unstable_version">
<description summary="enable use of this unstable version">
- Use this request in order to enable use of this interface.
-
- Understand and agree that one is using an unstable interface,
- that will likely change in the future, breaking the API.
+ Negotiate the unstable version of the interface. This
+ mechanism is in place to ensure client and server agree on the
+ unstable versions of the protocol that they speak or exit
+ cleanly if they don't agree. This request will go away once
+ the xdg-shell protocol is stable.
</description>
<arg name="version" type="int"/>
</request>
@@ -84,6 +87,28 @@
<arg name="y" type="int"/>
<arg name="flags" type="uint"/>
</request>
+
+ <event name="ping">
+ <description summary="check if the client is alive">
+ The ping event asks the client if it's still alive. Pass the
+ serial specified in the event back to the compositor by sending
+ a "pong" request back with the specified serial.
+
+ Compositors can use this to determine if the client is still
+ alive. It's unspecified what will happen if the client doesn't
+ respond to the ping request, or in what timeframe. Clients should
+ try to respond in a reasonable amount of time.
+ </description>
+ <arg name="serial" type="uint" summary="pass this to the callback"/>
+ </event>
+
+ <request name="pong">
+ <description summary="respond to a ping event">
+ A client must respond to a ping event with a pong request or
+ the client may be deemed unresponsive.
+ </description>
+ <arg name="serial" type="uint" summary="serial of the ping event"/>
+ </request>
</interface>
<interface name="xdg_surface" version="1">
@@ -124,6 +149,32 @@
<arg name="parent" type="object" interface="wl_surface" allow-null="true"/>
</request>
+ <request name="set_margin">
+ <description summary="set the visible frame boundaries">
+ This tells the compositor what the visible size of the window
+ should be, so it can use it to determine what borders to use for
+ constrainment and alignment.
+
+ CSD often has invisible areas for decoration purposes, like drop
+ shadows. These "shadow" drawings need to be subtracted out of the
+ normal boundaries of the window when computing where to place
+ windows (e.g. to set this window so it's centered on top of another,
+ or to put it to the left or right of the screen.)
+
+ This value should change as little as possible at runtime, to
+ prevent flicker.
+
+ This value is also ignored when the window is maximized or
+ fullscreen, and assumed to be 0.
+
+ If never called, this value is assumed to be 0.
+ </description>
+ <arg name="left_margin" type="int"/>
+ <arg name="right_margin" type="int"/>
+ <arg name="top_margin" type="int"/>
+ <arg name="bottom_margin" type="int"/>
+ </request>
+
<request name="set_title">
<description summary="set surface title">
Set a short title for the surface.
@@ -150,22 +201,6 @@
<arg name="app_id" type="string"/>
</request>
- <request name="pong">
- <description summary="respond to a ping event">
- A client must respond to a ping event with a pong request or
- the client may be deemed unresponsive.
- </description>
- <arg name="serial" type="uint" summary="serial of the ping event"/>
- </request>
-
- <event name="ping">
- <description summary="ping client">
- Ping a client to check if it is receiving events and sending
- requests. A client is expected to reply with a pong request.
- </description>
- <arg name="serial" type="uint"/>
- </event>
-
<request name="move">
<description summary="start an interactive move">
Start a pointer-driven move of the surface.
@@ -217,12 +252,6 @@
ignore it if it doesn't resize, pick a smaller size (to
satisfy aspect ratio or resize in steps of NxM pixels).
- The edges parameter provides a hint about how the surface
- was resized. The client may use this information to decide
- how to adjust its content to the new size (e.g. a scrolling
- area might adjust its content position to leave the viewable
- content unmoved). Valid edge values are from resize_edge enum.
-
The client is free to dismiss all but the last configure
event it received.
@@ -230,7 +259,6 @@
in surface local coordinates.
</description>
- <arg name="edges" type="uint"/>
<arg name="width" type="int"/>
<arg name="height" type="int"/>
</event>
@@ -250,128 +278,122 @@
<arg name="output" type="object" interface="wl_output" allow-null="true"/>
</request>
- <event name="request_set_fullscreen">
- <description summary="server requests that the client set fullscreen">
- Event sent from the compositor to the client requesting that the client
- goes to a fullscreen state. It's the client job to call set_fullscreen
- and really trigger the fullscreen state.
- </description>
- </event>
-
- <event name="request_unset_fullscreen">
- <description summary="server requests that the client unset fullscreen">
- Event sent from the compositor to the client requesting that the client
- leaves the fullscreen state. It's the client job to call
- unset_fullscreen and really leave the fullscreen state.
- </description>
- </event>
+ <enum name="state">
+ <description summary="types of state on the surface">
+ The different state values used on the surface. This is designed for
+ state values like maximized, fullscreen. It is paired with the
+ request_change_state event to ensure that both the client and the
+ compositor setting the state can be synchronized.
- <request name="set_fullscreen">
- <description summary="set the surface state as fullscreen">
- Set the surface as fullscreen.
+ States set in this way are double-buffered. They will get applied on
+ the next commit.
- After this request, the compositor should send a configure event
- informing the output size.
+ Desktop environments may extend this enum by taking up a range of
+ values and documenting the range they chose in this description.
+ They are not required to document the values for the range that they
+ chose. Ideally, any good extensions from a desktop environment should
+ make its way into standardization into this enum.
- This request informs the compositor that the next attached buffer
- committed will be in a fullscreen state. The buffer size should be the
- same size as the size informed in the configure event, if the client
- doesn't want to leave any empty area.
+ The current reserved ranges are:
- In other words: the next attached buffer after set_maximized is the new
- maximized buffer. And the surface will be positioned at the maximized
- position on commit.
-
- A simple way to synchronize and wait for the correct configure event is
- to use a wl_display.sync request right after the set_fullscreen
- request. When the sync callback returns, the last configure event
- received just before it will be the correct one, and should contain the
- right size for the surface to maximize.
-
- Setting one state won't unset another state. Use
- xdg_surface.unset_fullscreen for unsetting it.
+ 0x0000 - 0x0FFF: xdg-shell core values, documented below.
+ 0x1000 - 0x1FFF: GNOME
</description>
- </request>
+ <entry name="maximized" value="1" summary="the surface is maximized">
+ A non-zero value indicates the surface is maximized. Otherwise,
+ the surface is unmaximized.
+ </entry>
+ <entry name="fullscreen" value="2" summary="the surface is fullscreen">
+ A non-zero value indicates the surface is fullscreen. Otherwise,
+ the surface is not fullscreen.
+ </entry>
+ </enum>
- <request name="unset_fullscreen">
- <description summary="unset the surface state as fullscreen">
- Unset the surface fullscreen state.
+ <request name="request_change_state">
+ <description summary="client requests to change a surface's state">
+ This asks the compositor to change the state. If the compositor wants
+ to change the state, it will send a change_state event with the same
+ state_type, value, and serial, and the event flow continues as if it
+ it was initiated by the compositor.
- Same negotiation as set_fullscreen must be used.
+ If the compositor does not want to change the state, it will send a
+ change_state to the client with the old value of the state.
</description>
+ <arg name="state_type" type="uint" summary="the state to set"/>
+ <arg name="value" type="uint" summary="the value to change the state to"/>
+ <arg name="serial" type="uint" summary="an event serial">
+ This serial is so the client can know which change_state event corresponds
+ to which request_change_state request it sent out.
+ </arg>
</request>
- <event name="request_set_maximized">
- <description summary="server requests that the client set maximized">
- Event sent from the compositor to the client requesting that the client
- goes to a maximized state. It's the client job to call set_maximized
- and really trigger the maximized state.
+ <event name="change_state">
+ <description summary="compositor wants to change a surface's state">
+ This event tells the client to change a surface's state. The client
+ should respond with an ack_change_state request to the compositor to
+ guarantee that the compositor knows that the client has seen it.
</description>
- </event>
- <event name="request_unset_maximized">
- <description summary="server requests that the client unset maximized">
- Event sent from the compositor to the client requesting that the client
- leaves the maximized state. It's the client job to call unset_maximized
- and really leave the maximized state.
- </description>
+ <arg name="state_type" type="uint" summary="the state to set"/>
+ <arg name="value" type="uint" summary="the value to change the state to"/>
+ <arg name="serial" type="uint" summary="a serial for the compositor's own tracking"/>
</event>
- <request name="set_maximized">
- <description summary="set the surface state as maximized">
- Set the surface as maximized.
-
- After this request, the compositor will send a configure event
- informing the output size minus panel and other MW decorations.
-
- This request informs the compositor that the next attached buffer
- committed will be in a maximized state. The buffer size should be the
- same size as the size informed in the configure event, if the client
- doesn't want to leave any empty area.
+ <request name="ack_change_state">
+ <description summary="ack a change_state event">
+ When a change_state event is received, a client should then ack it
+ using the ack_change_state request to ensure that the compositor
+ knows the client has seen the event.
- In other words: the next attached buffer after set_maximized is the new
- maximized buffer. And the surface will be positioned at the maximized
- position on commit.
+ By this point, the state is confirmed, and the next attach should
+ contain the buffer drawn for the new state value.
- A simple way to synchronize and wait for the correct configure event is
- to use a wl_display.sync request right after the set_maximized request.
- When the sync callback returns, the last configure event received just
- before it will be the correct one, and should contain the right size
- for the surface to maximize.
-
- Setting one state won't unset another state. Use
- xdg_surface.unset_maximized for unsetting it.
+ The values here need to be the same as the values in the cooresponding
+ change_state event.
</description>
+ <arg name="state_type" type="uint" summary="the state to set"/>
+ <arg name="value" type="uint" summary="the value to change the state to"/>
+ <arg name="serial" type="uint" summary="a serial to pass to change_state"/>
</request>
- <request name="unset_maximized">
- <description summary="unset the surface state as maximized">
- Unset the surface maximized state.
-
- Same negotiation as set_maximized must be used.
+ <request name="set_minimized">
+ <description summary="minimize the surface">
+ Minimize the surface.
</description>
</request>
- <request name="set_minimized">
- <description summary="set the surface state as minimized">
- Set the surface minimized state.
-
- Setting one state won't unset another state.
+ <event name="activated">
+ <description summary="surface was activated">
+ The activated_set event is sent when this surface has been
+ activated, which means that the surface has user attention.
+ Window decorations should be updated accordingly. You should
+ not use this event for anything but the style of decorations
+ you display, use wl_keyboard.enter and wl_keyboard.leave for
+ determining keyboard focus.
</description>
- </request>
+ </event>
- <event name="focused_set">
- <description summary="surface was focused">
- The focused_set event is sent when this surface has been
- activated. Window decorations should be updated accordingly.
+ <event name="deactivated">
+ <description summary="surface was deactivated">
+ The deactivate event is sent when this surface has been
+ deactivated, which means that the surface lost user attention.
+ Window decorations should be updated accordingly. You should
+ not use this event for anything but the style of decorations
+ you display, use wl_keyboard.enter and wl_keyboard.leave for
+ determining keyboard focus.
</description>
</event>
- <event name="focused_unset">
- <description summary="surface was unfocused">
- The focused_unset event is sent when this surface has been
- deactivated, because another surface has been activated. Window
- decorations should be updated accordingly.
+ <event name="close">
+ <description summary="surface wants to be closed">
+ The close event is sent by the compositor when the user
+ wants the surface to be closed. This should be equivalent to
+ the user clicking the close button in client-side decorations,
+ if your application has any...
+
+ This is only a request that the user intends to close your
+ window. The client may choose to ignore this request, or show
+ a dialog to ask the user to save their data...
</description>
</event>
</interface>
@@ -409,22 +431,6 @@
</description>
</request>
- <request name="pong">
- <description summary="respond to a ping event">
- A client must respond to a ping event with a pong request or
- the client may be deemed unresponsive.
- </description>
- <arg name="serial" type="uint" summary="serial of the ping event"/>
- </request>
-
- <event name="ping">
- <description summary="ping client">
- Ping a client to check if it is receiving events and sending
- requests. A client is expected to reply with a pong request.
- </description>
- <arg name="serial" type="uint"/>
- </event>
-
<event name="popup_done">
<description summary="popup interaction is done">
The popup_done event is sent out when a popup grab is broken,
diff --git a/shared/cairo-util.h b/shared/cairo-util.h
index 7bcbc296..4493b0d9 100644
--- a/shared/cairo-util.h
+++ b/shared/cairo-util.h
@@ -165,6 +165,9 @@ void
frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
int32_t *width, int32_t *height);
+int
+frame_get_shadow_margin(struct frame *frame);
+
uint32_t
frame_status(struct frame *frame);
diff --git a/shared/frame.c b/shared/frame.c
index a039d157..35e6b65e 100644
--- a/shared/frame.c
+++ b/shared/frame.c
@@ -578,6 +578,14 @@ frame_opaque_rect(struct frame *frame, int32_t *x, int32_t *y,
*height = frame->height - frame->opaque_margin * 2;
}
+int
+frame_get_shadow_margin(struct frame *frame)
+{
+ frame_refresh_geometry(frame);
+
+ return frame->shadow_margin;
+}
+
uint32_t
frame_status(struct frame *frame)
{
diff --git a/shared/os-compatibility.h b/shared/os-compatibility.h
index c1edcfbd..172bb7ed 100644
--- a/shared/os-compatibility.h
+++ b/shared/os-compatibility.h
@@ -23,9 +23,9 @@
#ifndef OS_COMPATIBILITY_H
#define OS_COMPATIBILITY_H
-#include <sys/types.h>
+#include "config.h"
-#include "../config.h"
+#include <sys/types.h>
#ifdef HAVE_EXECINFO_H
#include <execinfo.h>
diff --git a/src/animation.c b/src/animation.c
index 33875d99..521e4f18 100644
--- a/src/animation.c
+++ b/src/animation.c
@@ -206,7 +206,7 @@ weston_view_animation_run(struct weston_view *view,
weston_matrix_init(&animation->transform.matrix);
wl_list_insert(&view->geometry.transformation_list,
&animation->transform.link);
- weston_spring_init(&animation->spring, 200.0, 0.0, 1.0);
+ weston_spring_init(&animation->spring, 200.0, start, stop);
animation->spring.friction = 700;
animation->animation.frame_counter = 0;
animation->animation.frame = weston_view_animation_frame;
@@ -290,17 +290,17 @@ weston_fade_run(struct weston_view *view,
{
struct weston_view_animation *fade;
- fade = weston_view_animation_run(view, 0, end,
+ fade = weston_view_animation_run(view, start, end,
fade_frame, reset_alpha,
done, data, NULL);
if (fade == NULL)
return NULL;
- weston_spring_init(&fade->spring, k, start, end);
+ fade->spring.k = 1000.0;
- fade->spring.friction = 1400;
- fade->spring.previous = -(end - start) * 0.03;
+ fade->spring.friction = 4000;
+ fade->spring.previous = start - (end - start) * 0.1;
view->alpha = start;
diff --git a/src/compositor-drm.c b/src/compositor-drm.c
index 154e15e4..3c15ec30 100644
--- a/src/compositor-drm.c
+++ b/src/compositor-drm.c
@@ -41,13 +41,13 @@
#include <drm_fourcc.h>
#include <gbm.h>
-#include <libbacklight.h>
#include <libudev.h>
+#include "libbacklight.h"
#include "compositor.h"
#include "gl-renderer.h"
#include "pixman-renderer.h"
-#include "udev-seat.h"
+#include "udev-input.h"
#include "launcher-util.h"
#include "vaapi-recorder.h"
@@ -147,6 +147,7 @@ struct drm_output {
drmModeCrtcPtr original_crtc;
struct drm_edid edid;
drmModePropertyPtr dpms_prop;
+ uint32_t format;
int vblank_pending;
int page_flip_pending;
@@ -420,8 +421,6 @@ static uint32_t
drm_output_check_scanout_format(struct drm_output *output,
struct weston_surface *es, struct gbm_bo *bo)
{
- struct drm_compositor *c =
- (struct drm_compositor *) output->base.compositor;
uint32_t format;
pixman_region32_t r;
@@ -442,7 +441,7 @@ drm_output_check_scanout_format(struct drm_output *output,
pixman_region32_fini(&r);
}
- if (c->format == format)
+ if (output->format == format)
return format;
return 0;
@@ -456,6 +455,7 @@ drm_output_prepare_scanout_view(struct weston_output *_output,
struct drm_compositor *c =
(struct drm_compositor *) output->base.compositor;
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;
@@ -464,7 +464,7 @@ drm_output_prepare_scanout_view(struct weston_output *_output,
buffer == NULL || c->gbm == NULL ||
buffer->width != output->base.current_mode->width ||
buffer->height != output->base.current_mode->height ||
- output->base.transform != ev->surface->buffer_viewport.transform ||
+ output->base.transform != viewport->buffer.transform ||
ev->transform.enabled)
return NULL;
@@ -507,7 +507,7 @@ drm_output_render_gl(struct drm_output *output, pixman_region32_t *damage)
return;
}
- output->next = drm_fb_get_from_bo(bo, c, c->format);
+ output->next = drm_fb_get_from_bo(bo, c, output->format);
if (!output->next) {
weston_log("failed to get drm_fb for bo\n");
gbm_surface_release_buffer(output->surface, bo);
@@ -809,6 +809,7 @@ drm_output_prepare_overlay_view(struct weston_output *output_base,
{
struct weston_compositor *ec = output_base->compositor;
struct drm_compositor *c =(struct drm_compositor *) ec;
+ struct weston_buffer_viewport *viewport = &ev->surface->buffer_viewport;
struct drm_sprite *s;
int found = 0;
struct gbm_bo *bo;
@@ -820,10 +821,10 @@ drm_output_prepare_overlay_view(struct weston_output *output_base,
if (c->gbm == NULL)
return NULL;
- if (ev->surface->buffer_viewport.transform != output_base->transform)
+ if (viewport->buffer.transform != output_base->transform)
return NULL;
- if (ev->surface->buffer_viewport.scale != output_base->current_scale)
+ if (viewport->buffer.scale != output_base->current_scale)
return NULL;
if (c->sprites_are_broken)
@@ -933,8 +934,8 @@ drm_output_prepare_overlay_view(struct weston_output *output_base,
tbox = weston_transformed_rect(wl_fixed_from_int(ev->surface->width),
wl_fixed_from_int(ev->surface->height),
- ev->surface->buffer_viewport.transform,
- ev->surface->buffer_viewport.scale,
+ viewport->buffer.transform,
+ viewport->buffer.scale,
tbox);
s->src_x = tbox.x1 << 8;
@@ -1528,12 +1529,13 @@ find_crtc_for_connector(struct drm_compositor *ec,
static int
drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
{
+ EGLint format = output->format;
int i, flags;
output->surface = gbm_surface_create(ec->gbm,
output->base.current_mode->width,
output->base.current_mode->height,
- ec->format,
+ format,
GBM_BO_USE_SCANOUT |
GBM_BO_USE_RENDERING);
if (!output->surface) {
@@ -1541,7 +1543,9 @@ drm_output_init_egl(struct drm_output *output, struct drm_compositor *ec)
return -1;
}
- if (gl_renderer->output_create(&output->base, output->surface) < 0) {
+ if (gl_renderer->output_create(&output->base, output->surface,
+ gl_renderer->opaque_attribs,
+ &format) < 0) {
weston_log("failed to create gl renderer output state\n");
gbm_surface_destroy(output->surface);
return -1;
@@ -1841,7 +1845,7 @@ setup_output_seat_constraint(struct drm_compositor *ec,
if (strcmp(s, "") != 0) {
struct udev_seat *seat;
- seat = udev_seat_get_named(&ec->base, s);
+ seat = udev_seat_get_named(&ec->input, s);
if (seat)
seat->base.output = output;
@@ -1853,6 +1857,35 @@ setup_output_seat_constraint(struct drm_compositor *ec,
}
static int
+get_gbm_format_from_section(struct weston_config_section *section,
+ uint32_t default_value,
+ uint32_t *format)
+{
+ char *s;
+ int ret = 0;
+
+ weston_config_section_get_string(section,
+ "gbm-format", &s, NULL);
+
+ if (s == NULL)
+ *format = default_value;
+ else if (strcmp(s, "xrgb8888") == 0)
+ *format = GBM_FORMAT_XRGB8888;
+ else if (strcmp(s, "rgb565") == 0)
+ *format = GBM_FORMAT_RGB565;
+ else if (strcmp(s, "xrgb2101010") == 0)
+ *format = GBM_FORMAT_XRGB2101010;
+ else {
+ weston_log("fatal: unrecognized pixel format: %s\n", s);
+ ret = -1;
+ }
+
+ free(s);
+
+ return ret;
+}
+
+static int
create_output_for_connector(struct drm_compositor *ec,
drmModeRes *resources,
drmModeConnector *connector,
@@ -1919,6 +1952,11 @@ create_output_for_connector(struct drm_compositor *ec,
transform = parse_transform(s, output->base.name);
free(s);
+ if (get_gbm_format_from_section(section,
+ ec->format,
+ &output->format) == -1)
+ output->format = ec->format;
+
weston_config_section_get_string(section, "seat", &s, "");
setup_output_seat_constraint(ec, &output->base, s);
free(s);
@@ -2399,7 +2437,7 @@ session_notify(struct wl_listener *listener, void *data)
compositor->state = ec->prev_state;
drm_compositor_set_modes(ec);
weston_compositor_damage_all(compositor);
- udev_input_enable(&ec->input, ec->udev);
+ udev_input_enable(&ec->input);
} else {
weston_log("deactivating session\n");
udev_input_disable(&ec->input);
@@ -2663,7 +2701,6 @@ drm_compositor_create(struct wl_display *display,
struct udev_device *drm_device;
struct wl_event_loop *loop;
const char *path;
- char *s;
uint32_t key;
weston_log("initializing drm backend\n");
@@ -2677,20 +2714,10 @@ drm_compositor_create(struct wl_display *display,
ec->sprites_are_broken = 1;
section = weston_config_get_section(config, "core", NULL, NULL);
- weston_config_section_get_string(section,
- "gbm-format", &s, "xrgb8888");
- if (strcmp(s, "xrgb8888") == 0)
- ec->format = GBM_FORMAT_XRGB8888;
- else if (strcmp(s, "rgb565") == 0)
- ec->format = GBM_FORMAT_RGB565;
- else if (strcmp(s, "xrgb2101010") == 0)
- ec->format = GBM_FORMAT_XRGB2101010;
- else {
- weston_log("fatal: unrecognized pixel format: %s\n", s);
- free(s);
+ if (get_gbm_format_from_section(section,
+ GBM_FORMAT_XRGB8888,
+ &ec->format) == -1)
goto err_base;
- }
- free(s);
ec->use_pixman = param->use_pixman;
@@ -2761,6 +2788,11 @@ drm_compositor_create(struct wl_display *display,
goto err_sprite;
}
+ /* A this point we have some idea of whether or not we have a working
+ * cursor plane. */
+ if (!ec->cursors_are_broken)
+ ec->base.capabilities |= WESTON_CAP_CURSOR_PLANE;
+
path = NULL;
if (udev_input_init(&ec->input,
diff --git a/src/compositor-fbdev.c b/src/compositor-fbdev.c
index 0d962693..e703e0ec 100644
--- a/src/compositor-fbdev.c
+++ b/src/compositor-fbdev.c
@@ -42,7 +42,7 @@
#include "compositor.h"
#include "launcher-util.h"
#include "pixman-renderer.h"
-#include "udev-seat.h"
+#include "udev-input.h"
#include "gl-renderer.h"
struct fbdev_compositor {
@@ -628,7 +628,9 @@ fbdev_output_create(struct fbdev_compositor *compositor,
} else {
setenv("HYBRIS_EGLPLATFORM", "wayland", 1);
if (gl_renderer->output_create(&output->base,
- (EGLNativeWindowType)NULL) < 0) {
+ (EGLNativeWindowType)NULL,
+ gl_renderer->opaque_attribs,
+ NULL) < 0) {
weston_log("gl_renderer_output_create failed.\n");
goto out_shadow_surface;
}
@@ -822,7 +824,7 @@ session_notify(struct wl_listener *listener, void *data)
weston_compositor_damage_all(&compositor->base);
- udev_input_enable(&compositor->input, compositor->udev);
+ udev_input_enable(&compositor->input);
} else {
weston_log("leaving VT\n");
udev_input_disable(&compositor->input);
diff --git a/src/compositor-headless.c b/src/compositor-headless.c
index 5a5c1e68..4ecb8d4d 100644
--- a/src/compositor-headless.c
+++ b/src/compositor-headless.c
@@ -131,6 +131,25 @@ headless_compositor_create_output(struct headless_compositor *c,
return 0;
}
+static int
+headless_input_create(struct headless_compositor *c)
+{
+ weston_seat_init(&c->fake_seat, &c->base, "default");
+
+ weston_seat_init_pointer(&c->fake_seat);
+
+ if (weston_seat_init_keyboard(&c->fake_seat, NULL) < 0)
+ return -1;
+
+ return 0;
+}
+
+static void
+headless_input_destroy(struct headless_compositor *c)
+{
+ weston_seat_release(&c->fake_seat);
+}
+
static void
headless_restore(struct weston_compositor *ec)
{
@@ -141,7 +160,7 @@ headless_destroy(struct weston_compositor *ec)
{
struct headless_compositor *c = (struct headless_compositor *) ec;
- weston_seat_release(&c->fake_seat);
+ headless_input_destroy(c);
weston_compositor_shutdown(ec);
free(ec);
@@ -162,19 +181,22 @@ headless_compositor_create(struct wl_display *display,
if (weston_compositor_init(&c->base, display, argc, argv, config) < 0)
goto err_free;
- weston_seat_init(&c->fake_seat, &c->base, "default");
+ if (headless_input_create(c) < 0)
+ goto err_compositor;
c->base.destroy = headless_destroy;
c->base.restore = headless_restore;
if (headless_compositor_create_output(c, width, height) < 0)
- goto err_compositor;
+ goto err_input;
if (noop_renderer_init(&c->base) < 0)
- goto err_compositor;
+ goto err_input;
return &c->base;
+err_input:
+ headless_input_destroy(c);
err_compositor:
weston_compositor_shutdown(&c->base);
err_free:
diff --git a/src/compositor-rdp.c b/src/compositor-rdp.c
index e8e4a8dc..aecc0a81 100644
--- a/src/compositor-rdp.c
+++ b/src/compositor-rdp.c
@@ -49,6 +49,7 @@
#define MAX_FREERDP_FDS 32
#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10)
+#define RDP_MODE_FREQ 60 * 1000
struct rdp_compositor_config {
int width;
@@ -58,8 +59,8 @@ struct rdp_compositor_config {
char *rdp_key;
char *server_cert;
char *server_key;
- char *extra_modes;
int env_socket;
+ int no_clients_resize;
};
struct rdp_output;
@@ -75,6 +76,7 @@ struct rdp_compositor {
char *server_key;
char *rdp_key;
int tls_enabled;
+ int no_clients_resize;
};
enum peer_item_flags {
@@ -121,8 +123,8 @@ rdp_compositor_config_init(struct rdp_compositor_config *config) {
config->rdp_key = NULL;
config->server_cert = NULL;
config->server_key = NULL;
- config->extra_modes = NULL;
config->env_socket = 0;
+ config->no_clients_resize = 0;
}
static void
@@ -320,11 +322,13 @@ rdp_output_repaint(struct weston_output *output_base, pixman_region32_t *damage)
pixman_renderer_output_set_buffer(output_base, output->shadow_surface);
ec->renderer->repaint_output(&output->base, 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);
+ 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);
+ }
}
}
@@ -352,16 +356,29 @@ finish_frame_handler(void *data)
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 *
-find_matching_mode(struct weston_output *output, struct weston_mode *target) {
+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))
+ if ((local->width == target->width) && (local->height == target->height))
return local;
}
- return 0;
+
+ return rdp_insert_new_mode(output, target->width, target->height, RDP_MODE_FREQ);
}
static int
@@ -372,13 +389,13 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {
pixman_image_t *new_shadow_buffer;
struct weston_mode *local_mode;
- local_mode = find_matching_mode(output, target_mode);
- if(!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)
+ if (local_mode == output->current_mode)
return 0;
output->current_mode->flags &= ~WL_OUTPUT_MODE_CURRENT;
@@ -398,7 +415,11 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {
wl_list_for_each(rdpPeer, &rdpOutput->peers, link) {
settings = rdpPeer->peer->settings;
- if(!settings->DesktopResize) {
+ 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 {
@@ -411,49 +432,12 @@ rdp_switch_mode(struct weston_output *output, struct weston_mode *target_mode) {
}
static int
-parse_extra_modes(const char *modes_str, struct rdp_output *output) {
- const char *startAt = modes_str;
- const char *nextPos;
- int w, h;
- struct weston_mode *mode;
-
- while(startAt && *startAt) {
- nextPos = strchr(startAt, 'x');
- if(!nextPos)
- return -1;
-
- w = strtoul(startAt, NULL, 0);
- startAt = nextPos + 1;
- if(!*startAt)
- return -1;
-
- h = strtoul(startAt, NULL, 0);
-
- if(!w || (w > 3000) || !h || (h > 3000))
- return -1;
- mode = malloc(sizeof *mode);
- if(!mode)
- return -1;
-
- mode->width = w;
- mode->height = h;
- mode->refresh = 5;
- mode->flags = 0;
- wl_list_insert(&output->base.mode_list, &mode->link);
-
- startAt = strchr(startAt, ',');
- if(startAt && *startAt == ',')
- startAt++;
- }
- return 0;
-}
-static int
-rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,
- const char *extraModes)
+rdp_compositor_create_output(struct rdp_compositor *c, int width, int height)
{
struct rdp_output *output;
struct wl_event_loop *loop;
- struct weston_mode *currentMode, *next;
+ struct weston_mode *currentMode;
+ struct weston_mode initMode;
output = zalloc(sizeof *output);
if (output == NULL)
@@ -462,19 +446,14 @@ rdp_compositor_create_output(struct rdp_compositor *c, int width, int height,
wl_list_init(&output->peers);
wl_list_init(&output->base.mode_list);
- currentMode = malloc(sizeof *currentMode);
- if(!currentMode)
+ 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;
- currentMode->flags = WL_OUTPUT_MODE_CURRENT | WL_OUTPUT_MODE_PREFERRED;
- currentMode->width = width;
- currentMode->height = height;
- currentMode->refresh = 5;
- wl_list_insert(&output->base.mode_list, &currentMode->link);
-
- if(parse_extra_modes(extraModes, output) < 0) {
- weston_log("invalid extra modes\n");
- goto out_free_output_and_modes;
- }
output->base.current_mode = output->base.native_mode = currentMode;
weston_output_init(&output->base, &c->base, 0, 0, width, height,
@@ -513,9 +492,6 @@ out_shadow_surface:
pixman_image_unref(output->shadow_surface);
out_output:
weston_output_destroy(&output->base);
-out_free_output_and_modes:
- wl_list_for_each_safe(currentMode, next, &output->base.mode_list, link)
- free(currentMode);
out_free_output:
free(output);
return -1;
@@ -599,7 +575,7 @@ static void
rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
{
int i;
- if(!context)
+ if (!context)
return;
wl_list_remove(&context->item.link);
@@ -608,7 +584,7 @@ rdp_peer_context_free(freerdp_peer* client, RdpPeerContext* context)
wl_event_source_remove(context->events[i]);
}
- if(context->item.flags & RDP_PEER_ACTIVATED) {
+ if (context->item.flags & RDP_PEER_ACTIVATED) {
weston_seat_release_keyboard(&context->item.seat);
weston_seat_release_pointer(&context->item.seat);
weston_seat_release(&context->item.seat);
@@ -700,18 +676,32 @@ xf_peer_post_connect(freerdp_peer* client)
if (output->base.width != (int)settings->DesktopWidth ||
output->base.height != (int)settings->DesktopHeight)
{
- struct weston_mode new_mode;
- struct weston_mode *target_mode;
- new_mode.width = (int)settings->DesktopWidth;
- new_mode.height = (int)settings->DesktopHeight;
- target_mode = find_matching_mode(&output->base, &new_mode);
- if (!target_mode) {
- weston_log("client mode not found\n");
- return FALSE;
+ if (c->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_switch_mode(&output->base, target_mode, 1, WESTON_MODE_SWITCH_SET_NATIVE);
+ output->base.width = new_mode.width;
+ output->base.height = new_mode.height;
}
- weston_output_switch_mode(&output->base, target_mode, 1, WESTON_MODE_SWITCH_SET_NATIVE);
- output->base.width = new_mode.width;
- output->base.height = new_mode.height;
}
weston_log("kbd_layout:%x kbd_type:%x kbd_subType:%x kbd_functionKeys:%x\n",
@@ -719,19 +709,19 @@ xf_peer_post_connect(freerdp_peer* client)
settings->KeyboardFunctionKey);
memset(&xkbRuleNames, 0, sizeof(xkbRuleNames));
- if(settings->KeyboardType <= 7)
+ if (settings->KeyboardType <= 7)
xkbRuleNames.model = rdp_keyboard_types[settings->KeyboardType];
for(i = 0; rdp_keyboards[i].xkbLayout; i++) {
- if(rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) {
+ if (rdp_keyboards[i].rdpLayoutCode == settings->KeyboardLayout) {
xkbRuleNames.layout = rdp_keyboards[i].xkbLayout;
break;
}
}
keymap = NULL;
- if(xkbRuleNames.layout) {
+ if (xkbRuleNames.layout) {
xkbContext = xkb_context_new(0);
- if(!xkbContext) {
+ if (!xkbContext) {
weston_log("unable to create a xkb_context\n");
return FALSE;
}
@@ -779,7 +769,7 @@ xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) {
if (flags & PTR_FLAGS_MOVE) {
output = peerContext->rdpCompositor->output;
- if(x < output->base.width && y < output->base.height) {
+ if (x < output->base.width && y < output->base.height) {
wl_x = wl_fixed_from_int((int)x);
wl_y = wl_fixed_from_int((int)y);
notify_motion_absolute(&peerContext->item.seat, weston_compositor_get_time(),
@@ -794,7 +784,7 @@ xf_mouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) {
else if (flags & PTR_FLAGS_BUTTON3)
button = BTN_MIDDLE;
- if(button) {
+ 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
);
@@ -824,7 +814,7 @@ xf_extendedMouseEvent(rdpInput *input, UINT16 flags, UINT16 x, UINT16 y) {
struct rdp_output *output;
output = peerContext->rdpCompositor->output;
- if(x < output->base.width && y < output->base.height) {
+ if (x < output->base.width && y < output->base.height) {
wl_x = wl_fixed_from_int((int)x);
wl_y = wl_fixed_from_int((int)y);
notify_motion_absolute(&peerContext->item.seat, weston_compositor_get_time(),
@@ -882,13 +872,13 @@ xf_input_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
notify = 1;
}
- if(notify) {
+ if (notify) {
full_code = code;
- if(flags & KBD_FLAGS_EXTENDED)
+ if (flags & KBD_FLAGS_EXTENDED)
full_code |= KBD_FLAGS_EXTENDED;
vk_code = GetVirtualKeyCodeFromVirtualScanCode(full_code, 4);
- if(vk_code > 0xff) {
+ if (vk_code > 0xff) {
weston_log("invalid vk_code %x", vk_code);
return;
}
@@ -912,7 +902,7 @@ xf_input_unicode_keyboard_event(rdpInput *input, UINT16 flags, UINT16 code)
static void
xf_suppress_output(rdpContext *context, BYTE allow, RECTANGLE_16 *area) {
RdpPeerContext *peerContext = (RdpPeerContext *)context;
- if(allow)
+ if (allow)
peerContext->item.flags |= RDP_PEER_OUTPUT_ENABLED;
else
peerContext->item.flags &= (~RDP_PEER_OUTPUT_ENABLED);
@@ -940,7 +930,7 @@ rdp_peer_init(freerdp_peer *client, struct rdp_compositor *c)
settings = client->settings;
settings->RdpKeyFile = c->rdp_key;
- if(c->tls_enabled) {
+ if (c->tls_enabled) {
settings->CertificateFile = c->server_cert;
settings->PrivateKeyFile = c->server_key;
} else {
@@ -1016,13 +1006,14 @@ rdp_compositor_create(struct wl_display *display,
c->base.destroy = rdp_destroy;
c->base.restore = rdp_restore;
c->rdp_key = config->rdp_key ? strdup(config->rdp_key) : NULL;
+ c->no_clients_resize = config->no_clients_resize;
/* activate TLS only if certificate/key are available */
- if(config->server_cert && config->server_key) {
+ if (config->server_cert && config->server_key) {
weston_log("TLS support activated\n");
c->server_cert = strdup(config->server_cert);
c->server_key = strdup(config->server_key);
- if(!c->server_cert || !c->server_key)
+ if (!c->server_cert || !c->server_key)
goto err_free_strings;
c->tls_enabled = 1;
}
@@ -1030,14 +1021,16 @@ rdp_compositor_create(struct wl_display *display,
if (pixman_renderer_init(&c->base) < 0)
goto err_compositor;
- if (rdp_compositor_create_output(c, config->width, config->height, config->extra_modes) < 0)
+ if (rdp_compositor_create_output(c, config->width, config->height) < 0)
goto err_compositor;
+ c->base.capabilities |= WESTON_CAP_ARBITRARY_MODES;
+
if(!config->env_socket) {
c->listener = freerdp_listener_new();
c->listener->PeerAccepted = rdp_incoming_peer;
c->listener->param4 = c;
- if(!c->listener->Open(c->listener, config->bind_address, config->port)) {
+ if (!c->listener->Open(c->listener, config->bind_address, config->port)) {
weston_log("unable to bind rdp socket\n");
goto err_listener;
}
@@ -1047,13 +1040,13 @@ rdp_compositor_create(struct wl_display *display,
} else {
/* get the socket from RDP_FD var */
fd_str = getenv("RDP_FD");
- if(!fd_str) {
+ if (!fd_str) {
weston_log("RDP_FD env variable not set");
goto err_output;
}
fd = strtoul(fd_str, NULL, 10);
- if(rdp_peer_init(freerdp_peer_new(fd), c))
+ if (rdp_peer_init(freerdp_peer_new(fd), c))
goto err_output;
}
@@ -1066,11 +1059,11 @@ err_output:
err_compositor:
weston_compositor_shutdown(&c->base);
err_free_strings:
- if(c->rdp_key)
+ if (c->rdp_key)
free(c->rdp_key);
- if(c->server_cert)
+ if (c->server_cert)
free(c->server_cert);
- if(c->server_key)
+ if (c->server_key)
free(c->server_key);
err_free:
free(c);
@@ -1093,9 +1086,9 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
{ WESTON_OPTION_BOOLEAN, "env-socket", 0, &config.env_socket },
{ WESTON_OPTION_INTEGER, "width", 0, &config.width },
{ WESTON_OPTION_INTEGER, "height", 0, &config.height },
- { WESTON_OPTION_STRING, "extra-modes", 0, &config.extra_modes },
{ WESTON_OPTION_STRING, "address", 0, &config.bind_address },
{ WESTON_OPTION_INTEGER, "port", 0, &config.port },
+ { WESTON_OPTION_BOOLEAN, "no-clients-resize", 0, &config.no_clients_resize },
{ WESTON_OPTION_STRING, "rdp4-key", 0, &config.rdp_key },
{ WESTON_OPTION_STRING, "rdp-tls-cert", 0, &config.server_cert },
{ WESTON_OPTION_STRING, "rdp-tls-key", 0, &config.server_key }
diff --git a/src/compositor-rpi.c b/src/compositor-rpi.c
index 399090dd..287451d1 100644
--- a/src/compositor-rpi.c
+++ b/src/compositor-rpi.c
@@ -29,10 +29,12 @@
#include <stdio.h>
#include <string.h>
#include <math.h>
+#include <sys/time.h>
#include <sys/types.h>
#include <fcntl.h>
#include <unistd.h>
+#include <linux/input.h>
#include <libudev.h>
#ifdef HAVE_BCM_HOST
@@ -43,9 +45,8 @@
#include "compositor.h"
#include "rpi-renderer.h"
-#include "evdev.h"
#include "launcher-util.h"
-#include "udev-seat.h"
+#include "udev-input.h"
#if 0
#define DBG(...) \
@@ -441,7 +442,7 @@ session_notify(struct wl_listener *listener, void *data)
weston_log("activating session\n");
compositor->base.state = compositor->prev_state;
weston_compositor_damage_all(&compositor->base);
- udev_input_enable(&compositor->input, compositor->udev);
+ udev_input_enable(&compositor->input);
} else {
weston_log("deactivating session\n");
udev_input_disable(&compositor->input);
@@ -527,13 +528,6 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
weston_log("Dispmanx planes are %s buffered.\n",
compositor->single_buffer ? "single" : "double");
- if (udev_input_init(&compositor->input,
- &compositor->base,
- compositor->udev, "seat0") != 0) {
- weston_log("Failed to initialize udev input.\n");
- goto out_launcher;
- }
-
for (key = KEY_F1; key < KEY_F9; key++)
weston_compositor_add_key_binding(&compositor->base, key,
MODIFIER_CTRL | MODIFIER_ALT,
@@ -549,19 +543,23 @@ rpi_compositor_create(struct wl_display *display, int *argc, char *argv[],
bcm_host_init();
if (rpi_renderer_create(&compositor->base, &param->renderer) < 0)
- goto out_udev_input;
+ goto out_launcher;
if (rpi_output_create(compositor, param->output_transform) < 0)
goto out_renderer;
+ if (udev_input_init(&compositor->input,
+ &compositor->base,
+ compositor->udev, "seat0") != 0) {
+ weston_log("Failed to initialize udev input.\n");
+ goto out_renderer;
+ }
+
return &compositor->base;
out_renderer:
compositor->base.renderer->destroy(&compositor->base);
-out_udev_input:
- udev_input_destroy(&compositor->input);
-
out_launcher:
weston_launcher_destroy(compositor->base.launcher);
diff --git a/src/compositor-wayland.c b/src/compositor-wayland.c
index 899c3293..f35db9c3 100644
--- a/src/compositor-wayland.c
+++ b/src/compositor-wayland.c
@@ -42,6 +42,7 @@
#include "../shared/image-loader.h"
#include "../shared/os-compatibility.h"
#include "../shared/cairo-util.h"
+#include "fullscreen-shell-client-protocol.h"
#define WINDOW_TITLE "Weston Compositor"
@@ -53,13 +54,17 @@ struct wayland_compositor {
struct wl_registry *registry;
struct wl_compositor *compositor;
struct wl_shell *shell;
+ struct _wl_fullscreen_shell *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;
@@ -75,6 +80,10 @@ struct wayland_output {
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;
@@ -103,6 +112,29 @@ struct wayland_output {
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;
@@ -135,6 +167,7 @@ struct wayland_input {
} cursor;
} parent;
+ enum weston_key_state_update keyboard_state_update;
uint32_t key_serial;
uint32_t enter_serial;
int focus;
@@ -211,13 +244,13 @@ wayland_output_get_shm_buffer(struct wayland_output *output)
fd = os_create_anonymous_file(height * stride);
if (fd < 0) {
- perror("os_create_anonymous_file");
+ 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) {
- perror("mmap");
+ weston_log("could not mmap %d memory for data: %m\n", height * stride);
close(fd);
return NULL;
}
@@ -289,10 +322,9 @@ draw_initial_frame(struct wayland_output *output)
sb->output = NULL;
wl_surface_attach(output->parent.surface, sb->buffer, 0, 0);
-
- /* We only need to damage some part, as its only transparant
- * pixels anyway. */
- wl_surface_damage(output->parent.surface, 0, 0, 1, 1);
+ wl_surface_damage(output->parent.surface, 0, 0,
+ output->base.current_mode->width,
+ output->base.current_mode->height);
}
static void
@@ -553,7 +585,8 @@ wayland_output_destroy(struct weston_output *output_base)
wl_egl_window_destroy(output->gl.egl_window);
wl_surface_destroy(output->parent.surface);
- wl_shell_surface_destroy(output->parent.shell_surface);
+ if (output->parent.shell_surface)
+ wl_shell_surface_destroy(output->parent.shell_surface);
if (output->frame)
frame_destroy(output->frame);
@@ -593,7 +626,9 @@ wayland_output_init_gl_renderer(struct wayland_output *output)
}
if (gl_renderer->output_create(&output->base,
- output->gl.egl_window) < 0)
+ output->gl.egl_window,
+ gl_renderer->alpha_attribs,
+ NULL) < 0)
goto cleanup_window;
return 0;
@@ -736,6 +771,9 @@ wayland_output_set_fullscreen(struct wayland_output *output,
enum wl_shell_surface_fullscreen_method method,
uint32_t framerate, struct wl_output *target)
{
+ struct wayland_compositor *c =
+ (struct wayland_compositor *)output->base.compositor;
+
if (output->frame) {
frame_destroy(output->frame);
output->frame = NULL;
@@ -743,8 +781,177 @@ wayland_output_set_fullscreen(struct wayland_output *output,
wayland_output_resize_surface(output);
- wl_shell_surface_set_fullscreen(output->parent.shell_surface,
- method, framerate, target);
+ if (output->parent.shell_surface) {
+ wl_shell_surface_set_fullscreen(output->parent.shell_surface,
+ method, framerate, target);
+ } else if (c->parent.fshell) {
+ _wl_fullscreen_shell_present_surface(c->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 _wl_fullscreen_shell_mode_feedback *fb)
+{
+ enum mode_status *value = data;
+
+ printf("Mode switch successful\n");
+
+ *value = MODE_STATUS_SUCCESS;
+}
+
+static void
+mode_feedback_failed(void *data, struct _wl_fullscreen_shell_mode_feedback *fb)
+{
+ enum mode_status *value = data;
+
+ printf("Mode switch failed\n");
+
+ *value = MODE_STATUS_FAIL;
+}
+
+static void
+mode_feedback_cancelled(void *data, struct _wl_fullscreen_shell_mode_feedback *fb)
+{
+ enum mode_status *value = data;
+
+ printf("Mode switch cancelled\n");
+
+ *value = MODE_STATUS_CANCEL;
+}
+
+struct _wl_fullscreen_shell_mode_feedback_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_compositor *c;
+ struct wl_surface *old_surface;
+ struct weston_mode *old_mode;
+ struct _wl_fullscreen_shell_mode_feedback *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;
+ }
+
+ c = (struct wayland_compositor *)output_base->compositor;
+
+ if (output->parent.shell_surface || !c->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(c->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 =
+ _wl_fullscreen_shell_present_surface_for_mode(c->parent.fshell,
+ output->parent.surface,
+ output->parent.output,
+ mode->refresh);
+ _wl_fullscreen_shell_mode_feedback_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(c->parent.wl_display);
+
+ _wl_fullscreen_shell_mode_feedback_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 (c->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 *
@@ -776,15 +983,18 @@ wayland_output_create(struct wayland_compositor *c, int x, int y,
wl_surface_set_user_data(output->parent.surface, output);
output->parent.draw_initial_frame = 1;
- output->parent.shell_surface =
- wl_shell_get_shell_surface(c->parent.shell,
- output->parent.surface);
- if (!output->parent.shell_surface)
- goto err_surface;
- wl_shell_surface_add_listener(output->parent.shell_surface,
- &shell_surface_listener, output);
- if (fullscreen) {
+ if (c->parent.shell) {
+ output->parent.shell_surface =
+ wl_shell_get_shell_surface(c->parent.shell,
+ output->parent.surface);
+ if (!output->parent.shell_surface)
+ goto err_surface;
+ wl_shell_surface_add_listener(output->parent.shell_surface,
+ &shell_surface_listener, output);
+ }
+
+ if (fullscreen && c->parent.shell) {
wl_shell_surface_set_fullscreen(output->parent.shell_surface,
0, 0, NULL);
wl_display_roundtrip(c->parent.wl_display);
@@ -825,7 +1035,7 @@ wayland_output_create(struct wayland_compositor *c, int x, int y,
output->base.assign_planes = NULL;
output->base.set_backlight = NULL;
output->base.set_dpms = NULL;
- output->base.switch_mode = NULL;
+ output->base.switch_mode = wayland_output_switch_mode;
wl_list_insert(c->base.output_list.prev, &output->base.link);
@@ -833,7 +1043,8 @@ wayland_output_create(struct wayland_compositor *c, int x, int y,
err_output:
weston_output_destroy(&output->base);
- wl_shell_surface_destroy(output->parent.shell_surface);
+ if (output->parent.shell_surface)
+ wl_shell_surface_destroy(output->parent.shell_surface);
err_surface:
wl_surface_destroy(output->parent.surface);
err_name:
@@ -921,6 +1132,71 @@ wayland_output_create_for_config(struct wayland_compositor *c,
return output;
}
+static struct wayland_output *
+wayland_output_create_for_parent_output(struct wayland_compositor *c,
+ 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->current_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");
+ return NULL;
+ }
+
+ if (!wl_list_empty(&c->base.output_list)) {
+ output = container_of(c->base.output_list.prev,
+ struct wayland_output, base.link);
+ x = output->base.x + output->base.current_mode->width;
+ } else {
+ x = 0;
+ }
+
+ output = wayland_output_create(c, 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 (c->parent.fshell) {
+ _wl_fullscreen_shell_present_surface(c->parent.fshell,
+ output->parent.surface,
+ _WL_FULLSCREEN_SHELL_PRESENT_METHOD_CENTER,
+ poutput->global);
+ _wl_fullscreen_shell_mode_feedback_destroy(
+ _wl_fullscreen_shell_present_surface_for_mode(c->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)
@@ -966,7 +1242,8 @@ input_set_cursor(struct wayland_input *input)
image = input->compositor->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,
@@ -1141,40 +1418,52 @@ input_handle_keymap(void *data, struct wl_keyboard *keyboard, uint32_t format,
struct xkb_keymap *keymap;
char *map_str;
- if (!data) {
- close(fd);
- return;
- }
+ if (!data)
+ goto error;
- if (format != WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1) {
- 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;
+ }
- map_str = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0);
- if (map_str == MAP_FAILED) {
- close(fd);
- return;
- }
+ keymap = xkb_map_new_from_string(input->compositor->base.xkb_context,
+ map_str,
+ XKB_KEYMAP_FORMAT_TEXT_V1,
+ 0);
+ munmap(map_str, size);
- keymap = xkb_map_new_from_string(input->compositor->base.xkb_context,
- map_str,
- XKB_KEYMAP_FORMAT_TEXT_V1,
- 0);
- munmap(map_str, size);
- close(fd);
+ if (!keymap) {
+ weston_log("failed to compile keymap\n");
+ goto error;
+ }
- if (!keymap) {
- weston_log("failed to compile keymap\n");
- return;
+ 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 (input->base.keyboard)
weston_seat_update_keymap(&input->base, keymap);
else
weston_seat_init_keyboard(&input->base, keymap);
- xkb_map_unref(keymap);
+ if (keymap)
+ xkb_map_unref(keymap);
+
+ return;
+
+error:
+ wl_keyboard_release(input->parent.keyboard);
+ close(fd);
}
static void
@@ -1249,7 +1538,7 @@ input_handle_key(void *data, struct wl_keyboard *keyboard,
notify_key(&input->base, time, key,
state ? WL_KEYBOARD_KEY_STATE_PRESSED :
WL_KEYBOARD_KEY_STATE_RELEASED,
- STATE_UPDATE_NONE);
+ input->keyboard_state_update);
}
static void
@@ -1339,6 +1628,130 @@ display_add_seat(struct wayland_compositor *c, uint32_t id)
}
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_compositor_register_output(struct wayland_compositor *c, uint32_t id)
+{
+ struct wayland_parent_output *output;
+
+ output = zalloc(sizeof *output);
+ if (!output)
+ return;
+
+ output->id = id;
+ output->global = wl_registry_bind(c->parent.registry, id,
+ &wl_output_interface, 1);
+ if (!output->global)
+ 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(&c->parent.output_list, &output->link);
+
+ if (c->sprawl_across_outputs) {
+ wl_display_roundtrip(c->parent.wl_display);
+ wayland_output_create_for_parent_output(c, 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)
{
@@ -1352,16 +1765,35 @@ registry_handle_global(void *data, struct wl_registry *registry, uint32_t name,
c->parent.shell =
wl_registry_bind(registry, name,
&wl_shell_interface, 1);
+ } else if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
+ c->parent.fshell =
+ wl_registry_bind(registry, name,
+ &_wl_fullscreen_shell_interface, 1);
} else if (strcmp(interface, "wl_seat") == 0) {
display_add_seat(c, name);
+ } else if (strcmp(interface, "wl_output") == 0) {
+ wayland_compositor_register_output(c, name);
} else if (strcmp(interface, "wl_shm") == 0) {
c->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_compositor *c = data;
+ struct wayland_parent_output *output;
+
+ wl_list_for_each(output, &c->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,
+ registry_handle_global_remove
};
static int
@@ -1426,6 +1858,10 @@ create_cursor(struct wayland_compositor *c, struct weston_config *config)
weston_config_section_get_int(s, "cursor-size", &size, 32);
c->cursor_theme = wl_cursor_theme_load(theme, size, c->parent.shm);
+ if (!c->cursor_theme) {
+ fprintf(stderr, "could not load cursor theme\n");
+ return;
+ }
free(theme);
@@ -1485,6 +1921,7 @@ wayland_compositor_create(struct wl_display *display, int use_pixman,
goto err_compositor;
}
+ wl_list_init(&c->parent.output_list);
wl_list_init(&c->input_list);
c->parent.registry = wl_display_get_registry(c->parent.wl_display);
wl_registry_add_listener(c->parent.registry, &registry_listener, c);
@@ -1534,10 +1971,6 @@ wayland_compositor_create(struct wl_display *display, int use_pixman,
wl_event_source_check(c->parent.wl_source);
- weston_compositor_add_key_binding(&c->base, KEY_F,
- MODIFIER_CTRL | MODIFIER_ALT,
- fullscreen_binding, c);
-
return c;
err_renderer:
c->base.renderer->destroy(&c->base);
@@ -1577,8 +2010,9 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
{
struct wayland_compositor *c;
struct wayland_output *output;
+ struct wayland_parent_output *poutput;
struct weston_config_section *section;
- int x, count, width, height, scale, use_pixman, fullscreen;
+ int x, count, width, height, scale, use_pixman, fullscreen, sprawl;
const char *section_name, *display_name;
char *name;
@@ -1590,6 +2024,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
{ WESTON_OPTION_BOOLEAN, "use-pixman", 0, &use_pixman },
{ WESTON_OPTION_INTEGER, "output-count", 0, &count },
{ WESTON_OPTION_BOOLEAN, "fullscreen", 0, &fullscreen },
+ { WESTON_OPTION_BOOLEAN, "sprawl", 0, &sprawl },
};
width = 0;
@@ -1599,6 +2034,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
use_pixman = 0;
count = 1;
fullscreen = 0;
+ sprawl = 0;
parse_options(wayland_options,
ARRAY_LENGTH(wayland_options), argc, argv);
@@ -1607,6 +2043,16 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
if (!c)
return NULL;
+ if (sprawl || c->parent.fshell) {
+ c->sprawl_across_outputs = 1;
+ wl_display_roundtrip(c->parent.wl_display);
+
+ wl_list_for_each(poutput, &c->parent.output_list, link)
+ wayland_output_create_for_parent_output(c, poutput);
+
+ return &c->base;
+ }
+
if (fullscreen) {
output = wayland_output_create(c, 0, 0, width, height,
NULL, 1, 0, 1);
@@ -1661,6 +2107,10 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
--count;
}
+ weston_compositor_add_key_binding(&c->base, KEY_F,
+ MODIFIER_CTRL | MODIFIER_ALT,
+ fullscreen_binding, c);
+
return &c->base;
err_outputs:
diff --git a/src/compositor-x11.c b/src/compositor-x11.c
index 6b5eb648..56b32287 100644
--- a/src/compositor-x11.c
+++ b/src/compositor-x11.c
@@ -56,6 +56,7 @@
static int option_width;
static int option_height;
+static int option_scale;
static int option_count;
struct x11_compositor {
@@ -602,8 +603,8 @@ x11_output_wait_for_map(struct x11_compositor *c, struct x11_output *output)
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->scale;
- output->mode.height = configure_notify->height / output->scale;
+ output->mode.width = configure_notify->width;
+ output->mode.height = configure_notify->height;
configured = 1;
break;
}
@@ -760,7 +761,7 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
xcb_screen_iterator_t iter;
struct wm_normal_hints normal_hints;
struct wl_event_loop *loop;
- int output_width, output_height;
+ 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];
@@ -875,8 +876,12 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
if (configured_name)
output->base.name = strdup(configured_name);
+ width_mm = width * c->screen->width_in_millimeters /
+ c->screen->width_in_pixels;
+ height_mm = height * c->screen->height_in_millimeters /
+ c->screen->height_in_pixels;
weston_output_init(&output->base, &c->base,
- x, y, width, height, transform, scale);
+ x, y, width_mm, height_mm, transform, scale);
if (c->use_pixman) {
if (x11_output_init_shm(c, output,
@@ -889,7 +894,9 @@ x11_compositor_create_output(struct x11_compositor *c, int x, int y,
}
} else {
ret = gl_renderer->output_create(&output->base,
- (EGLNativeWindowType) output->window);
+ (EGLNativeWindowType) output->window,
+ gl_renderer->opaque_attribs,
+ NULL);
if (ret < 0)
return NULL;
}
@@ -1478,7 +1485,7 @@ x11_compositor_create(struct wl_display *display,
struct weston_config_section *section;
xcb_screen_iterator_t s;
int i, x = 0, output_count = 0;
- int width, height, count, scale;
+ int width, height, scale, count;
const char *section_name;
char *name, *t, *mode;
uint32_t transform;
@@ -1534,6 +1541,7 @@ x11_compositor_create(struct wl_display *display,
width = option_width ? option_width : 1024;
height = option_height ? option_height : 640;
+ scale = option_scale ? option_scale : 1;
count = option_count ? option_count : 1;
section = NULL;
@@ -1563,6 +1571,9 @@ x11_compositor_create(struct wl_display *display,
height = option_height;
weston_config_section_get_int(section, "scale", &scale, 1);
+ if (option_scale)
+ scale = option_scale;
+
weston_config_section_get_string(section,
"transform", &t, "normal");
transform = parse_transform(t, name);
@@ -1586,7 +1597,7 @@ x11_compositor_create(struct wl_display *display,
for (i = output_count; i < count; i++) {
output = x11_compositor_create_output(c, x, 0, width, height,
fullscreen, no_input, NULL,
- WL_OUTPUT_TRANSFORM_NORMAL, 1);
+ WL_OUTPUT_TRANSFORM_NORMAL, scale);
if (output == NULL)
goto err_x11_input;
x = pixman_region32_extents(&output->base.region)->x2;
@@ -1623,6 +1634,7 @@ backend_init(struct wl_display *display, int *argc, char *argv[],
const struct weston_option x11_options[] = {
{ WESTON_OPTION_INTEGER, "width", 0, &option_width },
{ WESTON_OPTION_INTEGER, "height", 0, &option_height },
+ { WESTON_OPTION_INTEGER, "scale", 0, &option_scale },
{ WESTON_OPTION_BOOLEAN, "fullscreen", 'f', &fullscreen },
{ WESTON_OPTION_INTEGER, "output-count", 0, &option_count },
{ WESTON_OPTION_BOOLEAN, "no-input", 0, &no_input },
diff --git a/src/compositor.c b/src/compositor.c
index 40e4b119..fd2decb3 100644
--- a/src/compositor.c
+++ b/src/compositor.c
@@ -346,81 +346,6 @@ region_init_infinite(pixman_region32_t *region)
static struct weston_subsurface *
weston_surface_to_subsurface(struct weston_surface *surface);
-static void
-weston_view_output_move_handler(struct wl_listener *listener,
- void *data)
-{
- struct weston_view *ev;
- struct weston_output *output = data;
-
- ev = container_of(listener, struct weston_view,
- output_move_listener);
-
- /* the child window's view->geometry is a relative coordinate to
- * parent view, no need to move child_view. */
- if (ev->geometry.parent)
- return;
-
- weston_view_set_position(ev,
- ev->geometry.x + output->move_x,
- ev->geometry.y + output->move_y);
-}
-
-static void
-weston_view_output_destroy_handler(struct wl_listener *listener,
- void *data)
-{
- struct weston_view *ev;
- struct weston_compositor *ec;
- struct weston_output *output, *first_output;
- float x, y;
- int visible;
-
- ev = container_of(listener, struct weston_view,
- output_destroy_listener);
-
- ec = ev->surface->compositor;
-
- /* the child window's view->geometry is a relative coordinate to
- * parent view, no need to move child_view. */
- if (ev->geometry.parent)
- return;
-
- x = ev->geometry.x;
- y = ev->geometry.y;
-
- /* At this point the destroyed output is not in the list anymore.
- * If the view is still visible somewhere, we leave where it is,
- * otherwise, move it to the first output. */
- visible = 0;
- wl_list_for_each(output, &ec->output_list, link) {
- if (pixman_region32_contains_point(&output->region,
- x, y, NULL)) {
- visible = 1;
- break;
- }
- }
-
- if (!visible) {
- first_output = container_of(ec->output_list.next,
- struct weston_output, link);
-
- x = first_output->x + first_output->width / 4;
- y = first_output->y + first_output->height / 4;
- }
-
- weston_view_set_position(ev, x, y);
-
- if (ev->surface->output_destroyed)
- ev->surface->output_destroyed(ev->surface);
-
- wl_list_remove(&ev->output_move_listener.link);
- wl_list_remove(&ev->output_destroy_listener.link);
-
- wl_list_init(&ev->output_move_listener.link);
- wl_list_init(&ev->output_destroy_listener.link);
-}
-
WL_EXPORT struct weston_view *
weston_view_create(struct weston_surface *surface)
{
@@ -456,12 +381,6 @@ weston_view_create(struct weston_surface *surface)
view->output = NULL;
- view->output_move_listener.notify = weston_view_output_move_handler;
- wl_list_init(&view->output_move_listener.link);
- view->output_destroy_listener.notify =
- weston_view_output_destroy_handler;
- wl_list_init(&view->output_destroy_listener.link);
-
return view;
}
@@ -481,9 +400,10 @@ weston_surface_create(struct weston_compositor *compositor)
surface->compositor = compositor;
surface->ref_count = 1;
- surface->buffer_viewport.transform = WL_OUTPUT_TRANSFORM_NORMAL;
- surface->buffer_viewport.scale = 1;
- surface->buffer_viewport.viewport_set = 0;
+ 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;
surface->pending.buffer_viewport = surface->buffer_viewport;
surface->output = NULL;
surface->pending.newly_attached = 0;
@@ -720,33 +640,43 @@ static void
scaler_surface_to_buffer(struct weston_surface *surface,
float sx, float sy, float *bx, float *by)
{
- if (surface->buffer_viewport.viewport_set) {
- double a, b;
+ struct weston_buffer_viewport *vp = &surface->buffer_viewport;
+ double src_width, src_height;
+ double src_x, src_y;
- a = sx / surface->buffer_viewport.dst_width;
- b = a * wl_fixed_to_double(surface->buffer_viewport.src_width);
- *bx = b + wl_fixed_to_double(surface->buffer_viewport.src_x);
+ if (vp->buffer.src_width == wl_fixed_from_int(-1)) {
+ if (vp->surface.width == -1) {
+ *bx = sx;
+ *by = sy;
+ return;
+ }
- a = sy / surface->buffer_viewport.dst_height;
- b = a * wl_fixed_to_double(surface->buffer_viewport.src_height);
- *by = b + wl_fixed_to_double(surface->buffer_viewport.src_y);
+ src_x = 0.0;
+ src_y = 0.0;
+ src_width = surface->width_from_buffer;
+ src_height = surface->height_from_buffer;
} else {
- *bx = sx;
- *by = sy;
+ 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 scaler is set */
scaler_surface_to_buffer(surface, sx, sy, bx, by);
- weston_transformed_coord(surface->width,
- surface->height,
- surface->buffer_viewport.transform,
- surface->buffer_viewport.scale,
+ weston_transformed_coord(surface->width, surface->height,
+ vp->buffer.transform, vp->buffer.scale,
*bx, *by, bx, by);
}
@@ -767,6 +697,7 @@ 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 scaler is set */
@@ -778,10 +709,8 @@ weston_surface_to_buffer_rect(struct weston_surface *surface,
rect.x2 = floorf(xf);
rect.y2 = floorf(yf);
- return weston_transformed_rect(surface->width,
- surface->height,
- surface->buffer_viewport.transform,
- surface->buffer_viewport.scale,
+ return weston_transformed_rect(surface->width, surface->height,
+ vp->buffer.transform, vp->buffer.scale,
rect);
}
@@ -911,21 +840,6 @@ weston_view_assign_output(struct weston_view *ev)
}
pixman_region32_fini(&region);
- if (ev->output_mask != 0) {
- wl_list_remove(&ev->output_move_listener.link);
- wl_list_remove(&ev->output_destroy_listener.link);
- }
-
- if (mask != 0) {
- wl_signal_add(&new_output->move_signal,
- &ev->output_move_listener);
- wl_signal_add(&new_output->destroy_signal,
- &ev->output_destroy_listener);
- } else {
- wl_list_init(&ev->output_move_listener.link);
- wl_list_init(&ev->output_destroy_listener.link);
- }
-
ev->output = new_output;
ev->output_mask = mask;
@@ -1288,38 +1202,56 @@ weston_surface_set_size(struct weston_surface *surface,
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
weston_surface_set_size_from_buffer(struct weston_surface *surface)
{
+ struct weston_buffer_viewport *vp = &surface->buffer_viewport;
int32_t width, height;
if (!surface->buffer_ref.buffer) {
surface_set_size(surface, 0, 0);
+ surface->width_from_buffer = 0;
+ surface->height_from_buffer = 0;
return;
}
- if (surface->buffer_viewport.viewport_set) {
- surface->width = surface->buffer_viewport.dst_width;
- surface->height = surface->buffer_viewport.dst_height;
- return;
- }
-
- switch (surface->buffer_viewport.transform) {
+ switch (vp->buffer.transform) {
case WL_OUTPUT_TRANSFORM_90:
case WL_OUTPUT_TRANSFORM_270:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_270:
- width = surface->buffer_ref.buffer->height;
- height = surface->buffer_ref.buffer->width;
+ width = surface->buffer_ref.buffer->height / vp->buffer.scale;
+ height = surface->buffer_ref.buffer->width / vp->buffer.scale;
break;
default:
- width = surface->buffer_ref.buffer->width;
- height = surface->buffer_ref.buffer->height;
+ width = surface->buffer_ref.buffer->width / vp->buffer.scale;
+ height = surface->buffer_ref.buffer->height / vp->buffer.scale;
break;
}
- width = width / surface->buffer_viewport.scale;
- height = height / surface->buffer_viewport.scale;
+ surface->width_from_buffer = width;
+ surface->height_from_buffer = height;
+
+ if (vp->surface.width != -1) {
+ surface_set_size(surface,
+ vp->surface.width, vp->surface.height);
+ return;
+ }
+
+ if (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);
}
@@ -1379,10 +1311,6 @@ weston_view_unmap(struct weston_view *view)
wl_list_init(&view->layer_link);
wl_list_remove(&view->link);
wl_list_init(&view->link);
- wl_list_remove(&view->output_move_listener.link);
- wl_list_init(&view->output_move_listener.link);
- wl_list_remove(&view->output_destroy_listener.link);
- wl_list_init(&view->output_destroy_listener.link);
view->output_mask = 0;
weston_surface_assign_output(view->surface);
@@ -1412,6 +1340,17 @@ weston_surface_unmap(struct weston_surface *surface)
surface->output = NULL;
}
+static void
+weston_surface_reset_pending_buffer(struct weston_surface *surface)
+{
+ if (surface->pending.buffer)
+ wl_list_remove(&surface->pending.buffer_destroy_listener.link);
+ surface->pending.buffer = NULL;
+ surface->pending.sx = 0;
+ surface->pending.sy = 0;
+ surface->pending.newly_attached = 0;
+}
+
struct weston_frame_callback {
struct wl_resource *resource;
struct wl_list link;
@@ -1504,7 +1443,7 @@ weston_buffer_destroy_handler(struct wl_listener *listener, void *data)
free(buffer);
}
-struct weston_buffer *
+WL_EXPORT struct weston_buffer *
weston_buffer_from_resource(struct wl_resource *resource)
{
struct weston_buffer *buffer;
@@ -1578,6 +1517,8 @@ weston_surface_attach(struct weston_surface *surface,
}
surface->compositor->renderer->attach(surface, buffer);
+
+ weston_surface_set_size_from_buffer(surface);
}
WL_EXPORT void
@@ -2104,27 +2045,22 @@ weston_surface_commit(struct weston_surface *surface)
struct weston_view *view;
pixman_region32_t opaque;
+ /* XXX: wl_viewport.set without an attach should call configure */
+
/* wl_surface.set_buffer_transform */
/* wl_surface.set_buffer_scale */
/* wl_viewport.set */
surface->buffer_viewport = surface->pending.buffer_viewport;
/* wl_surface.attach */
- if (surface->pending.buffer || surface->pending.newly_attached) {
+ if (surface->pending.newly_attached)
weston_surface_attach(surface, surface->pending.buffer);
- weston_surface_set_size_from_buffer(surface);
- }
if (surface->configure && surface->pending.newly_attached)
surface->configure(surface,
surface->pending.sx, surface->pending.sy);
- if (surface->pending.buffer)
- wl_list_remove(&surface->pending.buffer_destroy_listener.link);
- surface->pending.buffer = NULL;
- surface->pending.sx = 0;
- surface->pending.sy = 0;
- surface->pending.newly_attached = 0;
+ weston_surface_reset_pending_buffer(surface);
/* wl_surface.damage */
pixman_region32_union(&surface->damage, &surface->damage,
@@ -2200,7 +2136,7 @@ surface_set_buffer_transform(struct wl_client *client,
{
struct weston_surface *surface = wl_resource_get_user_data(resource);
- surface->pending.buffer_viewport.transform = transform;
+ surface->pending.buffer_viewport.buffer.transform = transform;
}
static void
@@ -2210,7 +2146,7 @@ surface_set_buffer_scale(struct wl_client *client,
{
struct weston_surface *surface = wl_resource_get_user_data(resource);
- surface->pending.buffer_viewport.scale = scale;
+ surface->pending.buffer_viewport.buffer.scale = scale;
}
static const struct wl_surface_interface surface_interface = {
@@ -2248,6 +2184,8 @@ compositor_create_surface(struct wl_client *client,
}
wl_resource_set_implementation(surface->resource, &surface_interface,
surface, destroy_surface);
+
+ wl_signal_emit(&ec->create_surface_signal, surface);
}
static void
@@ -2336,10 +2274,8 @@ weston_subsurface_commit_from_cache(struct weston_subsurface *sub)
surface->buffer_viewport = sub->cached.buffer_viewport;
/* wl_surface.attach */
- if (sub->cached.buffer_ref.buffer || sub->cached.newly_attached) {
+ if (sub->cached.newly_attached)
weston_surface_attach(surface, sub->cached.buffer_ref.buffer);
- weston_surface_set_size_from_buffer(surface);
- }
weston_buffer_reference(&sub->cached.buffer_ref, NULL);
if (surface->configure && sub->cached.newly_attached)
@@ -2416,9 +2352,8 @@ weston_subsurface_commit_to_cache(struct weston_subsurface *sub)
}
sub->cached.sx += surface->pending.sx;
sub->cached.sy += surface->pending.sy;
- surface->pending.sx = 0;
- surface->pending.sy = 0;
- surface->pending.newly_attached = 0;
+
+ weston_surface_reset_pending_buffer(surface);
sub->cached.buffer_viewport = surface->pending.buffer_viewport;
@@ -3170,19 +3105,6 @@ weston_compositor_remove_output(struct weston_compositor *compositor,
}
}
-static void
-weston_compositor_verify_pointers(struct weston_compositor *ec)
-{
- struct weston_seat *seat;
-
- wl_list_for_each(seat, &ec->seat_list, link) {
- if (!seat->pointer)
- continue;
-
- weston_pointer_verify(seat->pointer);
- }
-}
-
WL_EXPORT void
weston_output_destroy(struct weston_output *output)
{
@@ -3191,8 +3113,7 @@ weston_output_destroy(struct weston_output *output)
weston_compositor_remove_output(output->compositor, output);
wl_list_remove(&output->link);
- weston_compositor_verify_pointers(output->compositor);
-
+ wl_signal_emit(&output->compositor->output_destroyed_signal, output);
wl_signal_emit(&output->destroy_signal, output);
free(output->name);
@@ -3356,10 +3277,10 @@ weston_output_move(struct weston_output *output, int x, int y)
output->dirty = 1;
/* Move views on this output. */
- wl_signal_emit(&output->move_signal, 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_resource_for_each(resource, &output->resource_list) {
wl_output_send_geometry(resource,
output->x,
output->y,
@@ -3369,6 +3290,10 @@ weston_output_move(struct weston_output *output, int x, int y)
output->make,
output->model,
output->transform);
+
+ if (wl_resource_get_version(resource) >= 2)
+ wl_output_send_done(resource);
+ }
}
WL_EXPORT void
@@ -3392,7 +3317,6 @@ weston_output_init(struct weston_output *output, struct weston_compositor *c,
wl_signal_init(&output->frame_signal);
wl_signal_init(&output->destroy_signal);
- wl_signal_init(&output->move_signal);
wl_list_init(&output->animation_list);
wl_list_init(&output->resource_list);
@@ -3463,7 +3387,9 @@ destroy_viewport(struct wl_resource *resource)
wl_resource_get_user_data(resource);
surface->viewport_resource = NULL;
- surface->pending.buffer_viewport.viewport_set = 0;
+ surface->pending.buffer_viewport.buffer.src_width =
+ wl_fixed_from_int(-1);
+ surface->pending.buffer_viewport.surface.width = -1;
}
static void
@@ -3506,19 +3432,84 @@ viewport_set(struct wl_client *client,
return;
}
- surface->pending.buffer_viewport.viewport_set = 1;
+ 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.surface.width = dst_width;
+ surface->pending.buffer_viewport.surface.height = dst_height;
+}
+
+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);
+
+ assert(surface->viewport_resource != NULL);
- surface->pending.buffer_viewport.src_x = src_x;
- surface->pending.buffer_viewport.src_y = src_y;
- surface->pending.buffer_viewport.src_width = src_width;
- surface->pending.buffer_viewport.src_height = src_height;
- surface->pending.buffer_viewport.dst_width = dst_width;
- surface->pending.buffer_viewport.dst_height = dst_height;
+ if (src_width == wl_fixed_from_int(-1) &&
+ src_height == wl_fixed_from_int(-1)) {
+ /* unset source size */
+ surface->pending.buffer_viewport.buffer.src_width =
+ wl_fixed_from_int(-1);
+ return;
+ }
+
+ if (src_width <= 0 || src_height <= 0) {
+ wl_resource_post_error(resource,
+ WL_VIEWPORT_ERROR_BAD_VALUE,
+ "source size must be positive (%fx%f)",
+ wl_fixed_to_double(src_width),
+ wl_fixed_to_double(src_height));
+ 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;
+}
+
+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);
+
+ assert(surface->viewport_resource != NULL);
+
+ if (dst_width == -1 && dst_height == -1) {
+ /* unset destination size */
+ surface->pending.buffer_viewport.surface.width = -1;
+ return;
+ }
+
+ if (dst_width <= 0 || dst_height <= 0) {
+ wl_resource_post_error(resource,
+ WL_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;
}
static const struct wl_viewport_interface viewport_interface = {
viewport_destroy,
- viewport_set
+ viewport_set,
+ viewport_set_source,
+ viewport_set_destination
};
static void
@@ -3534,7 +3525,9 @@ scaler_get_viewport(struct wl_client *client,
uint32_t id,
struct wl_resource *surface_resource)
{
- struct weston_surface *surface = wl_resource_get_user_data(surface_resource);
+ int version = wl_resource_get_version(scaler);
+ struct weston_surface *surface =
+ wl_resource_get_user_data(surface_resource);
struct wl_resource *resource;
if (surface->viewport_resource) {
@@ -3545,7 +3538,7 @@ scaler_get_viewport(struct wl_client *client,
}
resource = wl_resource_create(client, &wl_viewport_interface,
- 1, id);
+ version, id);
if (resource == NULL) {
wl_client_post_no_memory(client);
return;
@@ -3569,7 +3562,7 @@ bind_scaler(struct wl_client *client,
struct wl_resource *resource;
resource = wl_resource_create(client, &wl_scaler_interface,
- 1, id);
+ MIN(version, 2), id);
if (resource == NULL) {
wl_client_post_no_memory(client);
return;
@@ -3644,6 +3637,7 @@ weston_compositor_init(struct weston_compositor *ec,
ec->config = config;
ec->wl_display = display;
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);
@@ -3654,6 +3648,8 @@ weston_compositor_init(struct weston_compositor *ec,
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->session_signal);
ec->session_active = 1;
@@ -3667,7 +3663,7 @@ weston_compositor_init(struct weston_compositor *ec,
ec, bind_subcompositor))
return -1;
- if (!wl_global_create(ec->wl_display, &wl_scaler_interface, 1,
+ if (!wl_global_create(ec->wl_display, &wl_scaler_interface, 2,
ec, bind_scaler))
return -1;
@@ -3701,9 +3697,6 @@ weston_compositor_init(struct weston_compositor *ec,
if (weston_compositor_xkb_init(ec, &xkb_names) < 0)
return -1;
- ec->ping_handler = NULL;
-
- screenshooter_create(ec);
text_backend_init(ec);
wl_data_device_manager_init(ec->wl_display);
@@ -3983,9 +3976,8 @@ static const char xdg_wrong_message[] =
static const char xdg_wrong_mode_message[] =
"warning: XDG_RUNTIME_DIR \"%s\" is not configured\n"
- "correctly. Unix access mode must be 0700 but is %o,\n"
- "and XDG_RUNTIME_DIR must be owned by the user, but is\n"
- "owned by UID %d.\n";
+ "correctly. Unix access mode must be 0700 (current mode is %o),\n"
+ "and must be owned by the user (current owner is UID %d).\n";
static const char xdg_detail_message[] =
"Refer to your distribution on how to get it, or\n"
@@ -4069,6 +4061,7 @@ usage(int error_code)
" --fullscreen\t\tRun in fullscreen mode\n"
" --use-pixman\t\tUse the pixman (CPU) renderer\n"
" --output-count=COUNT\tCreate multiple outputs\n"
+ " --sprawl\t\tCreate one fullscreen output for every parent output\n"
" --display=DISPLAY\tWayland display to connect to\n\n");
#if defined(BUILD_RPI_COMPOSITOR) && defined(HAVE_BCM_HOST)
@@ -4088,10 +4081,10 @@ usage(int error_code)
"Options for rdp-backend.so:\n\n"
" --width=WIDTH\t\tWidth of desktop\n"
" --height=HEIGHT\tHeight of desktop\n"
- " --extra-modes=MODES\t\n"
" --env-socket=SOCKET\tUse that socket as peer connection\n"
" --address=ADDR\tThe address to bind\n"
" --port=PORT\tThe port to listen on\n"
+ " --no-clients-resize\tThe RDP peers will be forced to the size of the desktop\n"
" --rdp4-key=FILE\tThe file containing the key for RDP4 encryption\n"
" --rdp-tls-cert=FILE\tThe file containing the certificate for TLS encryption\n"
" --rdp-tls-key=FILE\tThe file containing the private key for TLS encryption\n"
@@ -4113,6 +4106,16 @@ catch_signals(void)
sigaction(SIGABRT, &action, NULL);
}
+static void
+handle_primary_client_destroyed(struct wl_listener *listener, void *data)
+{
+ struct wl_client *client = data;
+
+ weston_log("Primary client died. Closing...\n");
+
+ wl_display_terminate(wl_client_get_display(client));
+}
+
int main(int argc, char *argv[])
{
int ret = EXIT_SUCCESS;
@@ -4124,19 +4127,22 @@ int main(int argc, char *argv[])
*(*backend_init)(struct wl_display *display,
int *argc, char *argv[],
struct weston_config *config);
- int i;
+ int i, fd;
char *backend = NULL;
char *option_backend = NULL;
char *shell = NULL;
char *option_shell = NULL;
char *modules, *option_modules = NULL;
char *log = NULL;
+ char *server_socket = NULL, *end;
int32_t idle_time = 300;
int32_t help = 0;
char *socket_name = "wayland-0";
int32_t version = 0;
struct weston_config *config;
struct weston_config_section *section;
+ struct wl_client *primary_client;
+ struct wl_listener primary_client_destroyed;
const struct weston_option core_options[] = {
{ WESTON_OPTION_STRING, "backend", 'B', &option_backend },
@@ -4201,7 +4207,7 @@ int main(int argc, char *argv[])
NULL);
if (!backend) {
- if (getenv("WAYLAND_DISPLAY"))
+ if (getenv("WAYLAND_DISPLAY") || getenv("WAYLAND_SOCKET"))
backend = strdup("wayland-backend.so");
else if (getenv("DISPLAY"))
backend = strdup("x11-backend.so");
@@ -4259,10 +4265,33 @@ int main(int argc, char *argv[])
weston_compositor_log_capabilities(ec);
- if (wl_display_add_socket(display, socket_name)) {
- weston_log("fatal: failed to add socket: %m\n");
- ret = EXIT_FAILURE;
- goto out;
+ server_socket = getenv("WAYLAND_SERVER_SOCKET");
+ if (server_socket) {
+ weston_log("Running with single client\n");
+ fd = strtol(server_socket, &end, 0);
+ if (*end != '\0')
+ fd = -1;
+ } else {
+ fd = -1;
+ }
+
+ if (fd != -1) {
+ primary_client = wl_client_create(display, fd);
+ if (!primary_client) {
+ weston_log("fatal: failed to add client: %m\n");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
+ primary_client_destroyed.notify =
+ handle_primary_client_destroyed;
+ wl_client_add_destroy_listener(primary_client,
+ &primary_client_destroyed);
+ } else {
+ if (wl_display_add_socket(display, socket_name)) {
+ weston_log("fatal: failed to add socket: %m\n");
+ ret = EXIT_FAILURE;
+ goto out;
+ }
}
weston_compositor_wake(ec);
diff --git a/src/compositor.h b/src/compositor.h
index 22a485fc..af41b008 100644
--- a/src/compositor.h
+++ b/src/compositor.h
@@ -328,7 +328,10 @@ struct weston_pointer {
uint32_t grab_time;
wl_fixed_t x, y;
+ wl_fixed_t sx, sy;
uint32_t button_count;
+
+ struct wl_listener output_destroy_listener;
};
@@ -375,8 +378,6 @@ weston_pointer_move(struct weston_pointer *pointer,
void
weston_pointer_set_default_grab(struct weston_pointer *pointer,
const struct weston_pointer_grab_interface *interface);
-void
-weston_pointer_verify(struct weston_pointer *pointer);
struct weston_keyboard *
weston_keyboard_create(void);
@@ -494,6 +495,7 @@ struct weston_seat {
struct weston_output *output; /* constraint */
struct wl_signal destroy_signal;
+ struct wl_signal updated_caps_signal;
struct weston_compositor *compositor;
struct wl_list link;
@@ -556,6 +558,12 @@ enum weston_capability {
/* screencaptures need to be y-flipped */
WESTON_CAP_CAPTURE_YFLIP = 0x0002,
+
+ /* backend/renderer has a seperate cursor plane */
+ WESTON_CAP_CURSOR_PLANE = 0x0004,
+
+ /* backend supports setting arbitrary resolutions */
+ WESTON_CAP_ARBITRARY_MODES = 0x0008,
};
struct weston_compositor {
@@ -566,6 +574,7 @@ struct weston_compositor {
struct weston_config *config;
/* surface signals */
+ struct wl_signal create_surface_signal;
struct wl_signal activate_signal;
struct wl_signal transform_signal;
@@ -579,6 +588,8 @@ struct weston_compositor {
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_event_loop *input_loop;
struct wl_event_source *input_loop_source;
@@ -620,8 +631,6 @@ struct weston_compositor {
void (*restore)(struct weston_compositor *ec);
int (*authenticate)(struct weston_compositor *c, uint32_t id);
- void (*ping_handler)(struct weston_surface *surface, uint32_t serial);
-
struct weston_launcher *launcher;
uint32_t output_id_pool;
@@ -654,20 +663,27 @@ struct weston_buffer_reference {
};
struct weston_buffer_viewport {
- /* wl_surface.set_buffer_transform */
- uint32_t transform;
+ struct {
+ /* wl_surface.set_buffer_transform */
+ uint32_t transform;
- /* wl_surface.set_scaling_factor */
- int32_t scale;
+ /* wl_surface.set_scaling_factor */
+ int32_t scale;
- /* bool for whether wl_viewport.set has been
- * called yet (before this is called there is no
- * cropping or scaling on the surface) */
- int viewport_set; /* bool */
+ /*
+ * 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;
- wl_fixed_t src_x, src_y;
- wl_fixed_t src_width, src_height;
- int32_t dst_width, dst_height;
+ struct {
+ /*
+ * If width == -1, the size is inferred from the buffer.
+ */
+ int32_t width, height;
+ } surface;
};
struct weston_region {
@@ -818,9 +834,6 @@ struct weston_view {
* displayed on.
*/
uint32_t output_mask;
-
- struct wl_listener output_move_listener;
- struct wl_listener output_destroy_listener;
};
struct weston_surface {
@@ -859,6 +872,8 @@ struct weston_surface {
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;
int keep_buffer; /* bool for backends to prevent early release */
/* wl_viewport resource for this surface */
@@ -899,12 +914,6 @@ struct weston_surface {
void (*configure)(struct weston_surface *es, int32_t sx, int32_t sy);
void *configure_private;
- /* If non-NULL, this function will be called on surface->output::
- * destroy, after the output is removed from the compositor's
- * output list and the remaining outputs moved.
- */
- void (*output_destroyed)(struct weston_surface *surface);
-
/* 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.
@@ -1292,6 +1301,18 @@ tty_activate_vt(struct tty *tty, int vt);
void
screenshooter_create(struct weston_compositor *ec);
+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 clipboard *
clipboard_create(struct weston_seat *seat);
diff --git a/src/gl-renderer.c b/src/gl-renderer.c
index 0e5afbe3..63af75da 100644
--- a/src/gl-renderer.c
+++ b/src/gl-renderer.c
@@ -50,18 +50,29 @@ struct gl_shader {
#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;
- int dirty;
void *data;
};
struct gl_output_state {
EGLSurface egl_surface;
pixman_region32_t buffer_damage[BUFFER_DAMAGE_COUNT];
+ enum gl_border_status border_damage[BUFFER_DAMAGE_COUNT];
struct gl_border_image borders[4];
+ enum gl_border_status border_status;
};
enum buffer_type {
@@ -79,6 +90,12 @@ struct gl_surface_state {
int 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;
+
EGLImageKHR images[3];
GLenum target;
int num_images;
@@ -113,6 +130,10 @@ struct gl_renderer {
PFNEGLCREATEIMAGEKHRPROC create_image;
PFNEGLDESTROYIMAGEKHRPROC destroy_image;
+#ifdef EGL_EXT_swap_buffers_with_damage
+ PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC swap_buffers_with_damage;
+#endif
+
int has_unpack_subimage;
PFNEGLBINDWAYLANDDISPLAYWL bind_display;
@@ -124,6 +145,8 @@ struct gl_renderer {
int has_egl_buffer_age;
+ int has_configless_context;
+
struct gl_shader texture_shader_rgba;
struct gl_shader texture_shader_rgbx;
struct gl_shader texture_shader_egl_external;
@@ -536,7 +559,7 @@ draw_view(struct weston_view *ev, struct weston_output *output,
shader_uniforms(gs->shader, ev, output);
if (ev->transform.enabled || output->zoom.active ||
- output->current_scale != ev->surface->buffer_viewport.scale)
+ output->current_scale != ev->surface->buffer_viewport.buffer.scale)
filter = GL_LINEAR;
else
filter = GL_NEAREST;
@@ -597,9 +620,12 @@ repaint_views(struct weston_output *output, pixman_region32_t *damage)
}
static void
-draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
+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) {
@@ -627,7 +653,7 @@ draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
glBindTexture(GL_TEXTURE_2D, img->tex);
}
- if (img->dirty) {
+ 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);
@@ -636,7 +662,6 @@ draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
img->tex_width, img->height, 0,
GL_BGRA_EXT, GL_UNSIGNED_BYTE, img->data);
- img->dirty = 0;
}
GLfloat texcoord[] = {
@@ -664,8 +689,20 @@ draw_output_border_texture(struct gl_border_image *img, int32_t x, int32_t y,
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_border(struct weston_output *output)
+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);
@@ -674,6 +711,9 @@ draw_output_border(struct weston_output *output)
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];
@@ -696,23 +736,64 @@ draw_output_border(struct weston_output *output)
glUniform1f(shader->alpha_uniform, 1);
glActiveTexture(GL_TEXTURE0);
- draw_output_border_texture(top,
- 0, 0,
- full_width, top->height);
- draw_output_border_texture(left,
- 0, top->height,
- left->width, output->current_mode->height);
- draw_output_border_texture(right,
- full_width - right->width, top->height,
- right->width, output->current_mode->height);
- draw_output_border_texture(bottom,
- 0, full_height - bottom->height,
- full_width, bottom->height);
+ 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_buffer_damage(struct weston_output *output,
- pixman_region32_t *buffer_damage)
+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);
@@ -729,17 +810,31 @@ output_get_buffer_damage(struct weston_output *output,
}
}
- if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT)
+ if (buffer_age == 0 || buffer_age - 1 > BUFFER_DAMAGE_COUNT) {
pixman_region32_copy(buffer_damage, &output->region);
- else
+ *border_damage = BORDER_ALL_DIRTY;
+ } else {
for (i = 0; i < buffer_age - 1; i++)
- pixman_region32_union(buffer_damage, buffer_damage,
- &go->buffer_damage[i]);
+ *border_damage |= go->border_damage[i];
+
+ 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[i]);
+ }
+ }
}
static void
output_rotate_damage(struct weston_output *output,
- pixman_region32_t *output_damage)
+ 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);
@@ -748,10 +843,13 @@ output_rotate_damage(struct weston_output *output,
if (!gr->has_egl_buffer_age)
return;
- for (i = BUFFER_DAMAGE_COUNT - 1; i >= 1; i--)
+ for (i = BUFFER_DAMAGE_COUNT - 1; i >= 1; i--) {
+ go->border_damage[i] = go->border_damage[i - 1];
pixman_region32_copy(&go->buffer_damage[i],
&go->buffer_damage[i - 1]);
+ }
+ go->border_damage[0] = border_status;
pixman_region32_copy(&go->buffer_damage[0], output_damage);
}
@@ -764,7 +862,13 @@ gl_renderer_repaint_output(struct weston_output *output,
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;
/* Calculate the viewport */
glViewport(go->borders[GL_RENDERER_BORDER_LEFT].width,
@@ -792,28 +896,71 @@ gl_renderer_repaint_output(struct weston_output *output,
pixman_region32_init(&total_damage);
pixman_region32_init(&buffer_damage);
- output_get_buffer_damage(output, &buffer_damage);
- output_rotate_damage(output, output_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_border(output);
+ 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
@@ -823,6 +970,10 @@ gl_renderer_read_pixels(struct weston_output *output,
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:
@@ -853,8 +1004,6 @@ gl_renderer_flush_damage(struct weston_surface *surface)
struct weston_buffer *buffer = gs->buffer_ref.buffer;
struct weston_view *view;
int texture_used;
- GLenum format;
- int pixel_type;
#ifdef GL_EXT_unpack_subimage
pixman_box32_t *rectangles;
@@ -887,29 +1036,13 @@ gl_renderer_flush_damage(struct weston_surface *surface)
!gs->needs_full_upload)
goto done;
- switch (wl_shm_buffer_get_format(buffer->shm_buffer)) {
- case WL_SHM_FORMAT_XRGB8888:
- case WL_SHM_FORMAT_ARGB8888:
- format = GL_BGRA_EXT;
- pixel_type = GL_UNSIGNED_BYTE;
- break;
- case WL_SHM_FORMAT_RGB565:
- format = GL_RGB;
- pixel_type = GL_UNSIGNED_SHORT_5_6_5;
- break;
- default:
- weston_log("warning: unknown shm buffer format\n");
- format = GL_BGRA_EXT;
- pixel_type = GL_UNSIGNED_BYTE;
- }
-
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, format,
+ glTexImage2D(GL_TEXTURE_2D, 0, gs->gl_format,
gs->pitch, buffer->height, 0,
- format, pixel_type,
+ gs->gl_format, gs->gl_pixel_type,
wl_shm_buffer_get_data(buffer->shm_buffer));
wl_shm_buffer_end_access(buffer->shm_buffer);
@@ -924,9 +1057,9 @@ gl_renderer_flush_damage(struct weston_surface *surface)
glPixelStorei(GL_UNPACK_SKIP_PIXELS_EXT, 0);
glPixelStorei(GL_UNPACK_SKIP_ROWS_EXT, 0);
wl_shm_buffer_begin_access(buffer->shm_buffer);
- glTexSubImage2D(GL_TEXTURE_2D, 0,
- 0, 0, gs->pitch, buffer->height,
- format, pixel_type, data);
+ 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;
}
@@ -942,7 +1075,7 @@ gl_renderer_flush_damage(struct weston_surface *surface)
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,
- format, pixel_type, data);
+ gs->gl_format, gs->gl_pixel_type, data);
}
wl_shm_buffer_end_access(buffer->shm_buffer);
#endif
@@ -982,6 +1115,7 @@ gl_renderer_attach_shm(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);
+ GLenum gl_format, gl_pixel_type;
int pitch;
buffer->shm_buffer = shm_buffer;
@@ -992,19 +1126,25 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *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\n");
- gs->shader = &gr->texture_shader_rgba;
- pitch = wl_shm_buffer_get_stride(shm_buffer) / 4;
+ 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.
@@ -1012,10 +1152,14 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
* 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 = 1;
gs->y_inverted = 1;
@@ -1023,10 +1167,6 @@ gl_renderer_attach_shm(struct weston_surface *es, struct weston_buffer *buffer,
gs->surface = es;
ensure_textures(gs, 1);
- glBindTexture(GL_TEXTURE_2D, gs->textures[0]);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT,
- gs->pitch, buffer->height, 0,
- GL_BGRA_EXT, GL_UNSIGNED_BYTE, NULL);
}
}
@@ -1519,6 +1659,51 @@ log_egl_config_info(EGLDisplay egldpy, EGLConfig eglconfig)
weston_log_continue(" unknown\n");
}
+static int
+egl_choose_config(struct gl_renderer *gr, const EGLint *attribs,
+ const EGLint *visual_id,
+ EGLConfig *config_out)
+{
+ EGLint count = 0;
+ EGLint matched = 0;
+ EGLConfig *configs;
+ int i;
+
+ if (!eglGetConfigs(gr->egl_display, NULL, 0, &count) || count < 1)
+ return -1;
+
+ configs = calloc(count, sizeof *configs);
+ if (!configs)
+ return -1;
+
+ if (!eglChooseConfig(gr->egl_display, attribs, configs,
+ count, &matched))
+ goto out;
+
+ for (i = 0; i < matched; ++i) {
+ EGLint id;
+
+ if (visual_id) {
+ if (!eglGetConfigAttrib(gr->egl_display,
+ configs[i], EGL_NATIVE_VISUAL_ID,
+ &id))
+ continue;
+
+ if (id != 0 && id != *visual_id)
+ continue;
+ }
+
+ *config_out = configs[i];
+
+ free(configs);
+ return 0;
+ }
+
+out:
+ free(configs);
+ return -1;
+}
+
static void
gl_renderer_output_set_border(struct weston_output *output,
enum gl_renderer_border_side side,
@@ -1527,11 +1712,22 @@ gl_renderer_output_set_border(struct weston_output *output,
{
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->borders[side].dirty = 1;
+ go->border_status |= 1 << side;
}
static int
@@ -1539,19 +1735,37 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface);
static int
gl_renderer_output_create(struct weston_output *output,
- EGLNativeWindowType window)
+ EGLNativeWindowType window,
+ const EGLint *attribs,
+ const EGLint *visual_id)
{
struct weston_compositor *ec = output->compositor;
struct gl_renderer *gr = get_renderer(ec);
- struct gl_output_state *go = calloc(1, sizeof *go);
+ struct gl_output_state *go;
+ EGLConfig egl_config;
int i;
+ if (egl_choose_config(gr, attribs, visual_id, &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 = calloc(1, sizeof *go);
+
if (!go)
return -1;
go->egl_surface =
eglCreateWindowSurface(gr->egl_display,
- gr->egl_config,
+ egl_config,
window, NULL);
if (go->egl_surface == EGL_NO_SURFACE) {
@@ -1571,6 +1785,8 @@ gl_renderer_output_create(struct weston_output *output,
output->renderer_state = go;
+ log_egl_config_info(gr->egl_display, egl_config);
+
return 0;
}
@@ -1616,54 +1832,66 @@ gl_renderer_destroy(struct weston_compositor *ec)
wl_array_release(&gr->vertices);
wl_array_release(&gr->vtxcnt);
- weston_binding_destroy(gr->fragment_binding);
- weston_binding_destroy(gr->fan_binding);
+ if (gr->fragment_binding)
+ weston_binding_destroy(gr->fragment_binding);
+ if (gr->fan_binding)
+ weston_binding_destroy(gr->fan_binding);
free(gr);
}
static int
-egl_choose_config(struct gl_renderer *gr, const EGLint *attribs,
- const EGLint *visual_id)
+gl_renderer_setup_egl_extensions(struct weston_compositor *ec)
{
- EGLint count = 0;
- EGLint matched = 0;
- EGLConfig *configs;
- int i;
+ struct gl_renderer *gr = get_renderer(ec);
+ const char *extensions;
+ EGLBoolean ret;
- if (!eglGetConfigs(gr->egl_display, NULL, 0, &count) || count < 1)
- return -1;
+ 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");
- configs = calloc(count, sizeof *configs);
- if (!configs)
+ extensions =
+ (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
+ if (!extensions) {
+ weston_log("Retrieving EGL extension string failed.\n");
return -1;
+ }
- if (!eglChooseConfig(gr->egl_display, attribs, configs,
- count, &matched))
- goto out;
-
- for (i = 0; i < matched; ++i) {
- EGLint id;
-
- if (visual_id) {
- if (!eglGetConfigAttrib(gr->egl_display,
- configs[i], EGL_NATIVE_VISUAL_ID,
- &id))
- continue;
+ if (strstr(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 (id != 0 && id != *visual_id)
- continue;
- }
+ if (strstr(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");
- gr->egl_config = configs[i];
+#ifdef EGL_EXT_swap_buffers_with_damage
+ if (strstr(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
- free(configs);
- return 0;
- }
+#ifdef EGL_MESA_configless_context
+ if (strstr(extensions, "EGL_MESA_configless_context"))
+ gr->has_configless_context = 1;
+#endif
-out:
- free(configs);
- return -1;
+ return 0;
}
static const EGLint gl_renderer_opaque_attribs[] = {
@@ -1716,7 +1944,7 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
goto err_egl;
}
- if (egl_choose_config(gr, attribs, visual_id) < 0) {
+ if (egl_choose_config(gr, attribs, visual_id, &gr->egl_config) < 0) {
weston_log("failed to choose EGL config\n");
goto err_egl;
}
@@ -1725,6 +1953,9 @@ gl_renderer_create(struct weston_compositor *ec, EGLNativeDisplayType display,
ec->capabilities |= WESTON_CAP_ROTATION_ANY;
ec->capabilities |= WESTON_CAP_CAPTURE_YFLIP;
+ if (gl_renderer_setup_egl_extensions(ec) < 0)
+ goto err_egl;
+
wl_display_add_shm_format(ec->wl_display, WL_SHM_FORMAT_RGB565);
wl_signal_init(&gr->destroy_signal);
@@ -1817,6 +2048,7 @@ 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[] = {
@@ -1830,9 +2062,14 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
return -1;
}
- log_egl_config_info(gr->egl_display, gr->egl_config);
+ 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, gr->egl_config,
+ 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");
@@ -1852,14 +2089,6 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
gr->image_target_texture_2d =
(void *) eglGetProcAddress("glEGLImageTargetTexture2DOES");
- 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 *) glGetString(GL_EXTENSIONS);
if (!extensions) {
@@ -1885,27 +2114,6 @@ gl_renderer_setup(struct weston_compositor *ec, EGLSurface egl_surface)
if (strstr(extensions, "GL_OES_EGL_image_external"))
gr->has_egl_image_external = 1;
- extensions =
- (const char *) eglQueryString(gr->egl_display, EGL_EXTENSIONS);
- if (!extensions) {
- weston_log("Retrieving EGL extension string failed.\n");
- return -1;
- }
-
- if (strstr(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 (strstr(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");
-
glActiveTexture(GL_TEXTURE0);
if (compile_shaders(ec))
diff --git a/src/gl-renderer.h b/src/gl-renderer.h
index dcdf69d8..db42f6ca 100644
--- a/src/gl-renderer.h
+++ b/src/gl-renderer.h
@@ -58,7 +58,9 @@ struct gl_renderer_interface {
EGLDisplay (*display)(struct weston_compositor *ec);
int (*output_create)(struct weston_output *output,
- EGLNativeWindowType window);
+ EGLNativeWindowType window,
+ const EGLint *attribs,
+ const EGLint *visual_id);
void (*output_destroy)(struct weston_output *output);
diff --git a/src/input.c b/src/input.c
index 157066cc..9c514689 100644
--- a/src/input.c
+++ b/src/input.c
@@ -157,7 +157,7 @@ default_grab_pointer_focus(struct weston_pointer_grab *grab)
pointer->x, pointer->y,
&sx, &sy);
- if (pointer->focus != view)
+ if (pointer->focus != view || pointer->sx != sx || pointer->sy != sy)
weston_pointer_set_focus(pointer, view, sx, sy);
}
@@ -166,18 +166,19 @@ default_grab_pointer_motion(struct weston_pointer_grab *grab, uint32_t time,
wl_fixed_t x, wl_fixed_t y)
{
struct weston_pointer *pointer = grab->pointer;
- wl_fixed_t sx, sy;
struct wl_list *resource_list;
struct wl_resource *resource;
+ if (pointer->focus)
+ weston_view_from_global_fixed(pointer->focus, x, y,
+ &pointer->sx, &pointer->sy);
+
weston_pointer_move(pointer, x, y);
resource_list = &pointer->focus_resource_list;
wl_resource_for_each(resource, resource_list) {
- weston_view_from_global_fixed(pointer->focus,
- pointer->x, pointer->y,
- &sx, &sy);
- wl_pointer_send_motion(resource, time, sx, sy);
+ wl_pointer_send_motion(resource, time,
+ pointer->sx, pointer->sy);
}
}
@@ -438,6 +439,9 @@ 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)
{
@@ -465,6 +469,11 @@ weston_pointer_create(struct weston_seat *seat)
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);
+
return pointer;
}
@@ -478,6 +487,7 @@ weston_pointer_destroy(struct weston_pointer *pointer)
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);
}
@@ -593,6 +603,7 @@ seat_send_updated_caps(struct weston_seat *seat)
wl_resource_for_each(resource, &seat->base_resource_list) {
wl_seat_send_capabilities(resource, caps);
}
+ wl_signal_emit(&seat->updated_caps_signal, seat);
}
WL_EXPORT void
@@ -605,16 +616,17 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
struct wl_display *display = pointer->seat->compositor->wl_display;
uint32_t serial;
struct wl_list *focus_resource_list;
- int different_surface = 0;
+ int refocus = 0;
if ((!pointer->focus && view) ||
(pointer->focus && !view) ||
- (pointer->focus && pointer->focus->surface != view->surface))
- different_surface = 1;
+ (pointer->focus && pointer->focus->surface != view->surface) ||
+ pointer->sx != sx || pointer->sy != sy)
+ refocus = 1;
focus_resource_list = &pointer->focus_resource_list;
- if (!wl_list_empty(focus_resource_list) && different_surface) {
+ if (!wl_list_empty(focus_resource_list) && refocus) {
serial = wl_display_next_serial(display);
wl_resource_for_each(resource, focus_resource_list) {
wl_pointer_send_leave(resource, serial,
@@ -624,8 +636,7 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
move_resources(&pointer->resource_list, focus_resource_list);
}
- if (find_resource_for_view(&pointer->resource_list, view) &&
- different_surface) {
+ if (find_resource_for_view(&pointer->resource_list, view) && refocus) {
struct wl_client *surface_client =
wl_resource_get_client(view->surface->resource);
@@ -663,6 +674,9 @@ weston_pointer_set_focus(struct weston_pointer *pointer,
pointer->focus = view;
pointer->focus_view_listener.notify = pointer_focus_view_destroyed;
+ pointer->sx = sx;
+ pointer->sy = sy;
+
wl_signal_emit(&pointer->focus_signal, pointer);
}
@@ -871,14 +885,19 @@ weston_pointer_move(struct weston_pointer *pointer, wl_fixed_t x, wl_fixed_t y)
/** Verify if the pointer is in a valid position and move it if it isn't.
*/
-WL_EXPORT void
-weston_pointer_verify(struct weston_pointer *pointer)
+static void
+weston_pointer_handle_output_destroy(struct wl_listener *listener, void *data)
{
- struct weston_compositor *ec = pointer->seat->compositor;
+ 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);
@@ -986,13 +1005,8 @@ notify_button(struct weston_seat *seat, uint32_t time, int32_t button,
{
struct weston_compositor *compositor = seat->compositor;
struct weston_pointer *pointer = seat->pointer;
- struct weston_surface *focus =
- (struct weston_surface *) pointer->focus;
- uint32_t serial = wl_display_next_serial(compositor->wl_display);
if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- if (compositor->ping_handler && focus)
- compositor->ping_handler(focus, serial);
weston_compositor_idle_inhibit(compositor);
if (pointer->button_count == 0) {
pointer->grab_button = button;
@@ -1022,15 +1036,9 @@ notify_axis(struct weston_seat *seat, uint32_t time, uint32_t axis,
{
struct weston_compositor *compositor = seat->compositor;
struct weston_pointer *pointer = seat->pointer;
- struct weston_surface *focus =
- (struct weston_surface *) pointer->focus;
- uint32_t serial = wl_display_next_serial(compositor->wl_display);
struct wl_resource *resource;
struct wl_list *resource_list;
- if (compositor->ping_handler && focus)
- compositor->ping_handler(focus, serial);
-
weston_compositor_wake(compositor);
if (!value)
@@ -1246,15 +1254,10 @@ notify_key(struct weston_seat *seat, uint32_t time, uint32_t key,
{
struct weston_compositor *compositor = seat->compositor;
struct weston_keyboard *keyboard = seat->keyboard;
- struct weston_surface *focus = keyboard->focus;
struct weston_keyboard_grab *grab = keyboard->grab;
- uint32_t serial = wl_display_next_serial(compositor->wl_display);
uint32_t *k, *end;
if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- if (compositor->ping_handler && focus)
- compositor->ping_handler(focus, serial);
-
weston_compositor_idle_inhibit(compositor);
keyboard->grab_key = key;
keyboard->grab_time = time;
@@ -1468,6 +1471,9 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
return;
}
+ weston_compositor_run_touch_binding(ec, seat,
+ time, touch_type);
+
grab->interface->down(grab, time, touch_id, sx, sy);
if (touch->num_tp == 1) {
touch->grab_serial =
@@ -1504,8 +1510,6 @@ notify_touch(struct weston_seat *seat, uint32_t time, int touch_id,
weston_touch_set_focus(seat, NULL);
break;
}
-
- weston_compositor_run_touch_binding(ec, seat, time, touch_type);
}
static void
@@ -1529,6 +1533,7 @@ pointer_cursor_surface_configure(struct weston_surface *es,
weston_view_set_position(pointer->sprite, x, y);
empty_region(&es->pending.input);
+ empty_region(&es->input);
if (!weston_surface_is_mapped(es)) {
wl_list_insert(&es->compositor->cursor_layer.view_list,
@@ -2018,19 +2023,15 @@ weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
return -1;
}
- seat->keyboard = keyboard;
- seat->keyboard_device_count = 1;
- keyboard->seat = seat;
-
#ifdef ENABLE_XKBCOMMON
if (seat->compositor->use_xkbcommon) {
if (keymap != NULL) {
keyboard->xkb_info = weston_xkb_info_create(keymap);
if (keyboard->xkb_info == NULL)
- return -1;
+ goto err;
} else {
if (weston_compositor_build_global_keymap(seat->compositor) < 0)
- return -1;
+ goto err;
keyboard->xkb_info = seat->compositor->xkb_info;
keyboard->xkb_info->ref_count++;
}
@@ -2038,16 +2039,27 @@ weston_seat_init_keyboard(struct weston_seat *seat, struct xkb_keymap *keymap)
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");
- return -1;
+ goto err;
}
keyboard->xkb_state.leds = 0;
}
#endif
+ seat->keyboard = 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
@@ -2174,6 +2186,7 @@ weston_seat_init(struct weston_seat *seat, struct weston_compositor *ec,
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, 3,
seat, bind_seat);
@@ -2194,6 +2207,9 @@ 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)
weston_pointer_destroy(seat->pointer);
if (seat->keyboard)
diff --git a/src/libinput-device.c b/src/libinput-device.c
new file mode 100644
index 00000000..c8a64431
--- /dev/null
+++ b/src/libinput-device.c
@@ -0,0 +1,364 @@
+/*
+ * Copyright © 2010 Intel Corporation
+ * Copyright © 2013 Jonas Ådahl
+ *
+ * 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 <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"
+
+#define DEFAULT_AXIS_STEP_DISTANCE wl_fixed_from_int(10)
+
+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);
+
+ notify_key(device->seat,
+ libinput_event_keyboard_get_time(keyboard_event),
+ libinput_event_keyboard_get_key(keyboard_event),
+ libinput_event_keyboard_get_key_state(keyboard_event),
+ STATE_UPDATE_AUTOMATIC);
+}
+
+static void
+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);
+
+ notify_motion(device->seat,
+ libinput_event_pointer_get_time(pointer_event),
+ libinput_event_pointer_get_dx(pointer_event),
+ libinput_event_pointer_get_dy(pointer_event));
+}
+
+static void
+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;
+ wl_fixed_t x, y;
+ uint32_t width, height;
+
+ if (!output)
+ return;
+
+ 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);
+}
+
+static void
+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);
+
+ notify_button(device->seat,
+ libinput_event_pointer_get_time(pointer_event),
+ libinput_event_pointer_get_button(pointer_event),
+ libinput_event_pointer_get_button_state(pointer_event));
+}
+
+static void
+handle_pointer_axis(struct libinput_device *libinput_device,
+ struct libinput_event_pointer *pointer_event)
+{
+ struct evdev_device *device =
+ libinput_device_get_user_data(libinput_device);
+
+ notify_axis(device->seat,
+ libinput_event_pointer_get_time(pointer_event),
+ libinput_event_pointer_get_axis(pointer_event),
+ libinput_event_pointer_get_axis_value(pointer_event));
+}
+
+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);
+ wl_fixed_t x;
+ wl_fixed_t y;
+ uint32_t width, height;
+ uint32_t time;
+ int32_t slot;
+
+ 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);
+}
+
+int
+evdev_device_process_event(struct libinput_event *event)
+{
+ struct libinput_device *libinput_device =
+ libinput_event_get_device(event);
+ int handled = 1;
+
+ 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:
+ handle_pointer_motion(libinput_device,
+ libinput_event_get_pointer_event(event));
+ break;
+ case LIBINPUT_EVENT_POINTER_MOTION_ABSOLUTE:
+ handle_pointer_motion_absolute(
+ libinput_device,
+ libinput_event_get_pointer_event(event));
+ break;
+ case LIBINPUT_EVENT_POINTER_BUTTON:
+ handle_pointer_button(libinput_device,
+ libinput_event_get_pointer_event(event));
+ break;
+ case LIBINPUT_EVENT_POINTER_AXIS:
+ 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));
+ default:
+ handled = 0;
+ weston_log("unknown libinput event %d\n",
+ libinput_event_get_type(event));
+ }
+
+ 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) {
+ output = container_of(c->output_list.next,
+ struct weston_output, link);
+ evdev_device_set_output(device, output);
+ } else {
+ device->output = NULL;
+ }
+}
+
+void
+evdev_device_set_output(struct evdev_device *device,
+ struct weston_output *output)
+{
+ device->output = output;
+ device->output_destroy_listener.notify = notify_output_destroy;
+ wl_signal_add(&output->destroy_signal,
+ &device->output_destroy_listener);
+}
+
+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 evdev_device *device;
+ struct wl_array keys;
+ unsigned int i, set;
+ char evdev_keys[(KEY_CNT + 7) / 8];
+ char all_keys[(KEY_CNT + 7) / 8];
+ uint32_t *k;
+ int ret;
+
+ if (!seat->keyboard_device_count > 0)
+ return;
+
+ memset(all_keys, 0, sizeof all_keys);
+ wl_list_for_each(device, evdev_devices, link) {
+ memset(evdev_keys, 0, sizeof evdev_keys);
+ ret = libinput_device_get_keys(device->device,
+ evdev_keys,
+ sizeof evdev_keys);
+ if (ret < 0) {
+ weston_log("failed to get keys for device %s\n",
+ device->devnode);
+ continue;
+ }
+ for (i = 0; i < ARRAY_LENGTH(evdev_keys); i++)
+ all_keys[i] |= evdev_keys[i];
+ }
+
+ wl_array_init(&keys);
+ for (i = 0; i < KEY_CNT; i++) {
+ set = all_keys[i >> 3] & (1 << (i & 7));
+ if (set) {
+ k = wl_array_add(&keys, sizeof *k);
+ *k = i;
+ }
+ }
+
+ 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
new file mode 100644
index 00000000..07757436
--- /dev/null
+++ b/src/libinput-device.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright © 2011, 2012 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.
+ */
+
+#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);
+
+int
+dispatch_libinput(struct libinput *libinput);
+
+#endif /* _LIBINPUT_DEVICE_H_ */
diff --git a/src/libinput-seat.c b/src/libinput-seat.c
new file mode 100644
index 00000000..b6adc76b
--- /dev/null
+++ b/src/libinput-seat.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ * Copyright © 2013 Jonas Ådahl
+ *
+ * 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 <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"
+
+static const char default_seat[] = "seat0";
+static const char default_seat_name[] = "default";
+
+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 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 *seat_name;
+ const char *output_name;
+ struct libinput_seat *libinput_seat;
+ struct weston_seat *seat;
+ struct udev_seat *udev_seat;
+
+ c = input->compositor;
+ libinput_seat = libinput_device_get_seat(libinput_device);
+
+ seat_name = libinput_seat_get_logical_name(libinput_seat);
+ udev_seat = udev_seat_get_named(input, seat_name);
+ if (!udev_seat)
+ return;
+
+ seat = &udev_seat->base;
+ device = evdev_device_create(libinput_device, seat);
+ if (device == NULL)
+ return;
+
+ udev_seat = (struct udev_seat *) seat;
+ wl_list_insert(udev_seat->devices_list.prev, &device->link);
+
+ if (seat->output && seat->pointer)
+ weston_pointer_clamp(seat->pointer,
+ &seat->pointer->x,
+ &seat->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 (strcmp(output->name, device->output_name) == 0)
+ evdev_device_set_output(device, output);
+ } else if (device->output == NULL) {
+ 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
+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);
+ struct evdev_device *device;
+ 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 = libinput_device_get_user_data(libinput_device);
+ evdev_device_destroy(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;
+}
+
+int
+udev_input_init(struct udev_input *input, struct weston_compositor *c, struct udev *udev,
+ const char *seat_id)
+{
+ memset(input, 0, sizeof *input);
+
+ input->compositor = c;
+
+ input->libinput = libinput_udev_create_for_seat(&libinput_interface, input,
+ udev, seat_id);
+ if (!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_destroy(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);
+ break;
+ }
+}
+
+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)
+{
+ udev_seat_remove_devices(seat);
+ if (seat->base.keyboard)
+ notify_keyboard_focus_out(&seat->base);
+ 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
new file mode 100644
index 00000000..c448da03
--- /dev/null
+++ b/src/libinput-seat.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright © 2013 Intel Corporation
+ * Copyright © 2013 Jonas Ådahl
+ *
+ * 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 _LIBINPUT_SEAT_H_
+#define _LIBINPUT_SEAT_H_
+
+#include "config.h"
+
+#include <libudev.h>
+
+#include "compositor.h"
+
+struct udev_seat {
+ struct weston_seat base;
+ struct wl_list devices_list;
+ struct wl_listener output_create_listener;
+};
+
+struct udev_input {
+ struct libinput *libinput;
+ struct wl_event_source *libinput_source;
+ struct weston_compositor *compositor;
+ int suspended;
+};
+
+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);
+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/logind-util.c b/src/logind-util.c
index 40d811b4..6a1b4989 100644
--- a/src/logind-util.c
+++ b/src/logind-util.c
@@ -23,7 +23,6 @@
#include "config.h"
#include <errno.h>
-#include <dbus.h>
#include <fcntl.h>
#include <linux/vt.h>
#include <linux/kd.h>
diff --git a/src/noop-renderer.c b/src/noop-renderer.c
index ad750b5a..72332eb7 100644
--- a/src/noop-renderer.c
+++ b/src/noop-renderer.c
@@ -49,6 +49,39 @@ 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
diff --git a/src/pixman-renderer.c b/src/pixman-renderer.c
index 26f6f279..74ed58f4 100644
--- a/src/pixman-renderer.c
+++ b/src/pixman-renderer.c
@@ -139,6 +139,35 @@ region_global_to_output(struct weston_output *output, pixman_region32_t *region)
#define D2F(v) pixman_double_to_fixed((double)v)
static void
+transform_apply_viewport(pixman_transform_t *transform,
+ struct weston_surface *surface)
+{
+ 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)
+ 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);
+ }
+
+ pixman_transform_scale(transform, NULL,
+ D2F(src_width / surface->width),
+ D2F(src_height / surface->height));
+ pixman_transform_translate(transform, NULL, D2F(src_x), D2F(src_y));
+}
+
+static void
repaint_region(struct weston_view *ev, struct weston_output *output,
pixman_region32_t *region, pixman_region32_t *surf_region,
pixman_op_t pixman_op)
@@ -147,10 +176,13 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
(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_region32_t final_region;
float view_x, view_y;
pixman_transform_t transform;
pixman_fixed_t fw, fh;
+ pixman_image_t *mask_image;
+ pixman_color_t mask = { 0, };
/* The final region to be painted is the intersection of
* 'region' and 'surf_region'. However, 'region' is in the global
@@ -257,33 +289,12 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
pixman_double_to_fixed ((double)-ev->geometry.y));
}
- if (ev->surface->buffer_viewport.viewport_set) {
- double viewport_x, viewport_y, viewport_width, viewport_height;
- double ratio_x, ratio_y;
-
- viewport_x = wl_fixed_to_double(ev->surface->buffer_viewport.src_x);
- viewport_y = wl_fixed_to_double(ev->surface->buffer_viewport.src_y);
- viewport_width = wl_fixed_to_double(ev->surface->buffer_viewport.src_width);
- viewport_height = wl_fixed_to_double(ev->surface->buffer_viewport.src_height);
-
- ratio_x = viewport_width / ev->surface->buffer_viewport.dst_width;
- ratio_y = viewport_height / ev->surface->buffer_viewport.dst_height;
+ transform_apply_viewport(&transform, ev->surface);
- pixman_transform_scale(&transform, NULL,
- pixman_double_to_fixed(ratio_x),
- pixman_double_to_fixed(ratio_y));
- pixman_transform_translate(&transform, NULL, pixman_double_to_fixed(viewport_x),
- pixman_double_to_fixed(viewport_y));
- }
+ fw = pixman_int_to_fixed(ev->surface->width);
+ fh = pixman_int_to_fixed(ev->surface->height);
- pixman_transform_scale(&transform, NULL,
- pixman_double_to_fixed(ev->surface->buffer_viewport.scale),
- pixman_double_to_fixed(ev->surface->buffer_viewport.scale));
-
- fw = pixman_int_to_fixed(pixman_image_get_width(ps->image));
- fh = pixman_int_to_fixed(pixman_image_get_height(ps->image));
-
- switch (ev->surface->buffer_viewport.transform) {
+ switch (vp->buffer.transform) {
case WL_OUTPUT_TRANSFORM_FLIPPED:
case WL_OUTPUT_TRANSFORM_FLIPPED_90:
case WL_OUTPUT_TRANSFORM_FLIPPED_180:
@@ -295,7 +306,7 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
break;
}
- switch (ev->surface->buffer_viewport.transform) {
+ switch (vp->buffer.transform) {
default:
case WL_OUTPUT_TRANSFORM_NORMAL:
case WL_OUTPUT_TRANSFORM_FLIPPED:
@@ -317,9 +328,13 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
break;
}
+ pixman_transform_scale(&transform, NULL,
+ pixman_double_to_fixed(vp->buffer.scale),
+ pixman_double_to_fixed(vp->buffer.scale));
+
pixman_image_set_transform(ps->image, &transform);
- if (ev->transform.enabled || output->current_scale != ev->surface->buffer_viewport.scale)
+ if (ev->transform.enabled || output->current_scale != vp->buffer.scale)
pixman_image_set_filter(ps->image, PIXMAN_FILTER_BILINEAR, NULL, 0);
else
pixman_image_set_filter(ps->image, PIXMAN_FILTER_NEAREST, NULL, 0);
@@ -327,9 +342,16 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
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;
+ }
+
pixman_image_composite32(pixman_op,
ps->image, /* src */
- NULL /* mask */,
+ mask_image, /* mask */
po->shadow_image, /* dest */
0, 0, /* src_x, src_y */
0, 0, /* mask_x, mask_y */
@@ -337,6 +359,9 @@ repaint_region(struct weston_view *ev, struct weston_output *output,
pixman_image_get_width (po->shadow_image), /* width */
pixman_image_get_height (po->shadow_image) /* height */);
+ if (mask_image)
+ pixman_image_unref(mask_image);
+
if (ps->buffer_ref.buffer)
wl_shm_buffer_end_access(ps->buffer_ref.buffer->shm_buffer);
@@ -384,8 +409,9 @@ draw_view(struct weston_view *ev, struct weston_output *output,
}
/* TODO: Implement repaint_region_complex() using pixman_composite_trapezoids() */
- if (ev->transform.enabled &&
- ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE) {
+ if (ev->alpha != 1.0 ||
+ (ev->transform.enabled &&
+ ev->transform.matrix.type != WESTON_MATRIX_TRANSFORM_TRANSLATE)) {
repaint_region(ev, output, &repaint, NULL, PIXMAN_OP_OVER);
} else {
/* blended region is whole surface minus opaque region: */
diff --git a/src/screen-share.c b/src/screen-share.c
new file mode 100644
index 00000000..5de20bed
--- /dev/null
+++ b/src/screen-share.c
@@ -0,0 +1,1084 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2014 Jason Ekstrand
+ *
+ * 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 <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <linux/input.h>
+#include <errno.h>
+
+#include <wayland-client.h>
+
+#include "compositor.h"
+#include "../shared/os-compatibility.h"
+#include "fullscreen-shell-client-protocol.h"
+
+struct shared_output {
+ struct weston_output *output;
+ struct wl_listener output_destroyed;
+ struct wl_list seat_list;
+
+ struct {
+ struct wl_display *display;
+ struct wl_registry *registry;
+ struct wl_compositor *compositor;
+ struct wl_shm *shm;
+ uint32_t shm_formats;
+ struct _wl_fullscreen_shell *fshell;
+ struct wl_output *output;
+ struct wl_surface *surface;
+ struct wl_callback *frame_cb;
+ struct _wl_fullscreen_shell_mode_feedback *mode_feedback;
+ } parent;
+
+ struct wl_event_source *event_source;
+ struct wl_listener frame_listener;
+
+ struct {
+ int32_t width, height;
+
+ struct wl_list buffers;
+ struct wl_list free_buffers;
+ } shm;
+
+ int cache_dirty;
+ pixman_image_t *cache_image;
+ uint32_t *tmp_data;
+ size_t tmp_data_size;
+};
+
+struct ss_seat {
+ struct weston_seat base;
+ struct shared_output *output;
+ struct wl_list link;
+
+ struct {
+ struct wl_seat *seat;
+ struct wl_pointer *pointer;
+ struct wl_keyboard *keyboard;
+ } parent;
+
+ enum weston_key_state_update keyboard_state_update;
+ uint32_t key_serial;
+};
+
+struct ss_shm_buffer {
+ struct shared_output *output;
+ struct wl_list link;
+ struct wl_list free_link;
+
+ struct wl_buffer *buffer;
+ void *data;
+ size_t size;
+ pixman_region32_t damage;
+
+ pixman_image_t *pm_image;
+};
+
+static void
+ss_seat_handle_pointer_enter(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface,
+ wl_fixed_t x, wl_fixed_t y)
+{
+ struct ss_seat *seat = data;
+
+ /* No transformation of input position is required here because we are
+ * always receiving the input in the same coordinates as the output. */
+
+ notify_pointer_focus(&seat->base, NULL, 0, 0);
+}
+
+static void
+ss_seat_handle_pointer_leave(void *data, struct wl_pointer *pointer,
+ uint32_t serial, struct wl_surface *surface)
+{
+ struct ss_seat *seat = data;
+
+ notify_pointer_focus(&seat->base, NULL, 0, 0);
+}
+
+static void
+ss_seat_handle_motion(void *data, struct wl_pointer *pointer,
+ uint32_t time, wl_fixed_t x, wl_fixed_t y)
+{
+ struct ss_seat *seat = data;
+
+ /* No transformation of input position is required here because we are
+ * always receiving the input in the same coordinates as the output. */
+
+ notify_motion_absolute(&seat->base, time, x, y);
+}
+
+static void
+ss_seat_handle_button(void *data, struct wl_pointer *pointer,
+ uint32_t serial, uint32_t time, uint32_t button,
+ uint32_t state)
+{
+ struct ss_seat *seat = data;
+
+ notify_button(&seat->base, time, button, state);
+}
+
+static void
+ss_seat_handle_axis(void *data, struct wl_pointer *pointer,
+ uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+ struct ss_seat *seat = data;
+
+ notify_axis(&seat->base, time, axis, value);
+}
+
+static const struct wl_pointer_listener ss_seat_pointer_listener = {
+ ss_seat_handle_pointer_enter,
+ ss_seat_handle_pointer_leave,
+ ss_seat_handle_motion,
+ ss_seat_handle_button,
+ ss_seat_handle_axis,
+};
+
+static void
+ss_seat_handle_keymap(void *data, struct wl_keyboard *keyboard,
+ uint32_t format, int fd, uint32_t size)
+{
+ struct ss_seat *seat = data;
+ struct xkb_keymap *keymap;
+ char *map_str;
+
+ if (!data)
+ goto error;
+
+ 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_map_new_from_string(seat->base.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;
+ }
+
+ seat->keyboard_state_update = STATE_UPDATE_NONE;
+ } else if (format == WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP) {
+ weston_log("No keymap provided; falling back to default\n");
+ keymap = NULL;
+ seat->keyboard_state_update = STATE_UPDATE_AUTOMATIC;
+ } else {
+ weston_log("Invalid keymap\n");
+ goto error;
+ }
+
+ close(fd);
+
+ if (seat->base.keyboard)
+ weston_seat_update_keymap(&seat->base, keymap);
+ else
+ weston_seat_init_keyboard(&seat->base, keymap);
+
+ if (keymap)
+ xkb_map_unref(keymap);
+
+ return;
+
+error:
+ wl_keyboard_release(seat->parent.keyboard);
+ close(fd);
+}
+
+static void
+ss_seat_handle_keyboard_enter(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, struct wl_surface *surface,
+ struct wl_array *keys)
+{
+ struct ss_seat *seat = data;
+
+ /* XXX: If we get a modifier event immediately before the focus,
+ * we should try to keep the same serial. */
+ notify_keyboard_focus_in(&seat->base, keys,
+ STATE_UPDATE_AUTOMATIC);
+}
+
+static void
+ss_seat_handle_keyboard_leave(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, struct wl_surface *surface)
+{
+ struct ss_seat *seat = data;
+
+ notify_keyboard_focus_out(&seat->base);
+}
+
+static void
+ss_seat_handle_key(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial, uint32_t time,
+ uint32_t key, uint32_t state)
+{
+ struct ss_seat *seat = data;
+
+ seat->key_serial = serial;
+ notify_key(&seat->base, time, key,
+ state ? WL_KEYBOARD_KEY_STATE_PRESSED :
+ WL_KEYBOARD_KEY_STATE_RELEASED,
+ seat->keyboard_state_update);
+}
+
+static void
+ss_seat_handle_modifiers(void *data, struct wl_keyboard *keyboard,
+ uint32_t serial_in, uint32_t mods_depressed,
+ uint32_t mods_latched, uint32_t mods_locked,
+ uint32_t group)
+{
+ struct ss_seat *seat = data;
+ struct weston_compositor *c = seat->output->output->compositor;
+ 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 == seat->key_serial)
+ serial_out = wl_display_get_serial(c->wl_display);
+ else
+ serial_out = wl_display_next_serial(c->wl_display);
+
+ xkb_state_update_mask(seat->base.keyboard->xkb_state.state,
+ mods_depressed, mods_latched,
+ mods_locked, 0, 0, group);
+ notify_modifiers(&seat->base, serial_out);
+}
+
+static const struct wl_keyboard_listener ss_seat_keyboard_listener = {
+ ss_seat_handle_keymap,
+ ss_seat_handle_keyboard_enter,
+ ss_seat_handle_keyboard_leave,
+ ss_seat_handle_key,
+ ss_seat_handle_modifiers,
+};
+
+static void
+ss_seat_handle_capabilities(void *data, struct wl_seat *seat,
+ enum wl_seat_capability caps)
+{
+ struct ss_seat *ss_seat = data;
+
+ if ((caps & WL_SEAT_CAPABILITY_POINTER) && !ss_seat->parent.pointer) {
+ ss_seat->parent.pointer = wl_seat_get_pointer(seat);
+ wl_pointer_set_user_data(ss_seat->parent.pointer, ss_seat);
+ wl_pointer_add_listener(ss_seat->parent.pointer,
+ &ss_seat_pointer_listener, ss_seat);
+ weston_seat_init_pointer(&ss_seat->base);
+ } else if (!(caps & WL_SEAT_CAPABILITY_POINTER) && ss_seat->parent.pointer) {
+ wl_pointer_destroy(ss_seat->parent.pointer);
+ ss_seat->parent.pointer = NULL;
+ }
+
+ if ((caps & WL_SEAT_CAPABILITY_KEYBOARD) && !ss_seat->parent.keyboard) {
+ ss_seat->parent.keyboard = wl_seat_get_keyboard(seat);
+ wl_keyboard_set_user_data(ss_seat->parent.keyboard, ss_seat);
+ wl_keyboard_add_listener(ss_seat->parent.keyboard,
+ &ss_seat_keyboard_listener, ss_seat);
+ } else if (!(caps & WL_SEAT_CAPABILITY_KEYBOARD) && ss_seat->parent.keyboard) {
+ wl_keyboard_destroy(ss_seat->parent.keyboard);
+ ss_seat->parent.keyboard = NULL;
+ }
+}
+
+static const struct wl_seat_listener ss_seat_listener = {
+ ss_seat_handle_capabilities,
+};
+
+static struct ss_seat *
+ss_seat_create(struct shared_output *so, uint32_t id)
+{
+ struct ss_seat *seat;
+
+ seat = zalloc(sizeof *seat);
+ if (seat == NULL)
+ return NULL;
+
+ weston_seat_init(&seat->base, so->output->compositor, "default");
+ seat->output = so;
+ seat->parent.seat = wl_registry_bind(so->parent.registry, id,
+ &wl_seat_interface, 1);
+ wl_list_insert(so->seat_list.prev, &seat->link);
+
+ wl_seat_add_listener(seat->parent.seat, &ss_seat_listener, seat);
+ wl_seat_set_user_data(seat->parent.seat, seat);
+
+ return seat;
+}
+
+static void
+ss_seat_destroy(struct ss_seat *seat)
+{
+ if (seat->parent.pointer)
+ wl_pointer_release(seat->parent.pointer);
+ if (seat->parent.keyboard)
+ wl_keyboard_release(seat->parent.keyboard);
+ wl_seat_destroy(seat->parent.seat);
+
+ wl_list_remove(&seat->link);
+
+ weston_seat_release(&seat->base);
+
+ free(seat);
+}
+
+static void
+ss_shm_buffer_destroy(struct ss_shm_buffer *buffer)
+{
+ 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 ss_shm_buffer *sb = data;
+
+ if (sb->output) {
+ wl_list_insert(&sb->output->shm.free_buffers, &sb->free_link);
+ } else {
+ ss_shm_buffer_destroy(sb);
+ }
+}
+
+static const struct wl_buffer_listener buffer_listener = {
+ buffer_release
+};
+
+static struct ss_shm_buffer *
+shared_output_get_shm_buffer(struct shared_output *so)
+{
+ struct ss_shm_buffer *sb, *bnext;
+ struct wl_shm_pool *pool;
+ int width, height, stride;
+ int fd;
+ unsigned char *data;
+
+ width = so->output->width;
+ height = so->output->height;
+ stride = width * 4;
+
+ /* If the size of the output changed, we free the old buffers and
+ * make new ones. */
+ if (so->shm.width != width ||
+ so->shm.height != height) {
+
+ /* Destroy free buffers */
+ wl_list_for_each_safe(sb, bnext, &so->shm.free_buffers, link)
+ ss_shm_buffer_destroy(sb);
+
+ /* Orphan in-use buffers so they get destroyed */
+ wl_list_for_each(sb, &so->shm.buffers, link)
+ sb->output = NULL;
+
+ so->shm.width = width;
+ so->shm.height = height;
+ }
+
+ if (!wl_list_empty(&so->shm.free_buffers)) {
+ sb = container_of(so->shm.free_buffers.next,
+ struct ss_shm_buffer, free_link);
+ wl_list_remove(&sb->free_link);
+ wl_list_init(&sb->free_link);
+
+ return sb;
+ }
+
+ fd = os_create_anonymous_file(height * stride);
+ if (fd < 0) {
+ weston_log("os_create_anonymous_file: %m");
+ return NULL;
+ }
+
+ data = mmap(NULL, height * stride, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
+ if (data == MAP_FAILED) {
+ weston_log("mmap: %m");
+ close(fd);
+ return NULL;
+ }
+
+ sb = zalloc(sizeof *sb);
+
+ sb->output = so;
+ wl_list_init(&sb->free_link);
+ wl_list_insert(&so->shm.buffers, &sb->link);
+
+ pixman_region32_init_rect(&sb->damage, 0, 0, width, height);
+
+ sb->data = data;
+ sb->size = height * stride;
+
+ pool = wl_shm_create_pool(so->parent.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->pm_image =
+ pixman_image_create_bits(PIXMAN_a8r8g8b8, width, height,
+ (uint32_t *)data, stride);
+
+ return sb;
+}
+
+static void
+output_compute_transform(struct weston_output *output,
+ pixman_transform_t *transform)
+{
+ pixman_fixed_t fw, fh;
+
+ pixman_transform_init_identity(transform);
+
+ fw = pixman_int_to_fixed(output->width);
+ fh = pixman_int_to_fixed(output->height);
+
+ 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:
+ pixman_transform_scale(transform, NULL,
+ pixman_int_to_fixed (-1),
+ pixman_int_to_fixed (1));
+ pixman_transform_translate(transform, NULL, fw, 0);
+ }
+
+ 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:
+ pixman_transform_rotate(transform, NULL, 0, pixman_fixed_1);
+ pixman_transform_translate(transform, NULL, fh, 0);
+ break;
+ case WL_OUTPUT_TRANSFORM_180:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+ pixman_transform_rotate(transform, NULL, -pixman_fixed_1, 0);
+ pixman_transform_translate(transform, NULL, fw, fh);
+ break;
+ case WL_OUTPUT_TRANSFORM_270:
+ case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+ pixman_transform_rotate(transform, NULL, 0, -pixman_fixed_1);
+ pixman_transform_translate(transform, NULL, 0, fw);
+ break;
+ }
+
+ pixman_transform_scale(transform, NULL,
+ pixman_fixed_1 * output->current_scale,
+ pixman_fixed_1 * output->current_scale);
+}
+
+static void
+shared_output_destroy(struct shared_output *so);
+
+static int
+shared_output_ensure_tmp_data(struct shared_output *so,
+ pixman_region32_t *region)
+{
+ pixman_box32_t *ext;
+ size_t size;
+
+ if (!pixman_region32_not_empty(region))
+ return 0;
+
+ ext = pixman_region32_extents(region);
+
+ /* Damage is in output coordinates.
+ *
+ * We are multiplying by 4 because the temporary data needs to be able
+ * to store an 32 bit-per-pixel buffer.
+ */
+ size = 4 * (ext->x2 - ext->x1) * (ext->y2 - ext->y1)
+ * so->output->current_scale * so->output->current_scale;
+
+ if (so->tmp_data != NULL && size <= so->tmp_data_size)
+ return 0;
+
+ free(so->tmp_data);
+ so->tmp_data = malloc(size);
+ if (so->tmp_data == NULL) {
+ so->tmp_data_size = 0;
+ errno = ENOMEM;
+ return -1;
+ }
+
+ so->tmp_data_size = size;
+
+ return 0;
+}
+
+static void
+shared_output_update(struct shared_output *so);
+
+static void
+shared_output_frame_callback(void *data, struct wl_callback *cb, uint32_t time)
+{
+ struct shared_output *so = data;
+
+ if (cb != so->parent.frame_cb)
+ return;
+
+ wl_callback_destroy(cb);
+ so->parent.frame_cb = NULL;
+
+ shared_output_update(so);
+}
+
+static const struct wl_callback_listener shared_output_frame_listener = {
+ shared_output_frame_callback
+};
+
+static void
+shared_output_update(struct shared_output *so)
+{
+ struct ss_shm_buffer *sb;
+ pixman_box32_t *r;
+ int i, nrects;
+ pixman_transform_t transform;
+
+ /* Only update if we need to */
+ if (!so->cache_dirty || so->parent.frame_cb)
+ return;
+
+ sb = shared_output_get_shm_buffer(so);
+ if (sb == NULL) {
+ shared_output_destroy(so);
+ return;
+ }
+
+ output_compute_transform(so->output, &transform);
+ pixman_image_set_transform(so->cache_image, &transform);
+
+ pixman_image_set_clip_region32(sb->pm_image, &sb->damage);
+
+ if (so->output->current_scale == 1) {
+ pixman_image_set_filter(so->cache_image,
+ PIXMAN_FILTER_NEAREST, NULL, 0);
+ } else {
+ pixman_image_set_filter(so->cache_image,
+ PIXMAN_FILTER_BILINEAR, NULL, 0);
+ }
+
+ pixman_image_composite32(PIXMAN_OP_SRC,
+ so->cache_image, /* src */
+ NULL, /* mask */
+ sb->pm_image, /* dest */
+ 0, 0, /* src_x, src_y */
+ 0, 0, /* mask_x, mask_y */
+ 0, 0, /* dest_x, dest_y */
+ so->output->width, /* width */
+ so->output->height /* height */);
+
+ pixman_image_set_transform(sb->pm_image, NULL);
+ pixman_image_set_clip_region32(sb->pm_image, NULL);
+
+ r = pixman_region32_rectangles(&sb->damage, &nrects);
+ for (i = 0; i < nrects; ++i)
+ wl_surface_damage(so->parent.surface, r[i].x1, r[i].y1,
+ r[i].x2 - r[i].x1, r[i].y2 - r[i].y1);
+
+ wl_surface_attach(so->parent.surface, sb->buffer, 0, 0);
+
+ so->parent.frame_cb = wl_surface_frame(so->parent.surface);
+ wl_callback_add_listener(so->parent.frame_cb,
+ &shared_output_frame_listener, so);
+
+ wl_surface_commit(so->parent.surface);
+ wl_callback_destroy(wl_display_sync(so->parent.display));
+ wl_display_flush(so->parent.display);
+
+ /* Clear the buffer damage */
+ pixman_region32_fini(&sb->damage);
+ pixman_region32_init(&sb->damage);
+}
+
+static void
+shm_handle_format(void *data, struct wl_shm *wl_shm, uint32_t format)
+{
+ struct shared_output *so = data;
+
+ so->parent.shm_formats |= (1 << format);
+}
+
+struct wl_shm_listener shm_listener = {
+ shm_handle_format
+};
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+ uint32_t id, const char *interface, uint32_t version)
+{
+ struct shared_output *so = data;
+
+ if (strcmp(interface, "wl_compositor") == 0) {
+ so->parent.compositor =
+ wl_registry_bind(registry,
+ id, &wl_compositor_interface, 1);
+ } else if (strcmp(interface, "wl_output") == 0 && !so->parent.output) {
+ so->parent.output =
+ wl_registry_bind(registry,
+ id, &wl_output_interface, 1);
+ } else if (strcmp(interface, "wl_seat") == 0) {
+ ss_seat_create(so, id);
+ } else if (strcmp(interface, "wl_shm") == 0) {
+ so->parent.shm =
+ wl_registry_bind(registry,
+ id, &wl_shm_interface, 1);
+ wl_shm_add_listener(so->parent.shm, &shm_listener, so);
+ } else if (strcmp(interface, "_wl_fullscreen_shell") == 0) {
+ so->parent.fshell =
+ wl_registry_bind(registry,
+ id, &_wl_fullscreen_shell_interface, 1);
+ }
+}
+
+static void
+registry_handle_global_remove(void *data, struct wl_registry *registry,
+ uint32_t name)
+{
+}
+
+static const struct wl_registry_listener registry_listener = {
+ registry_handle_global,
+ registry_handle_global_remove
+};
+
+static int
+shared_output_handle_event(int fd, uint32_t mask, void *data)
+{
+ struct shared_output *so = data;
+ int count = 0;
+
+ if ((mask & WL_EVENT_HANGUP) || (mask & WL_EVENT_ERROR)) {
+ shared_output_destroy(so);
+ return 0;
+ }
+
+ if (mask & WL_EVENT_READABLE)
+ count = wl_display_dispatch(so->parent.display);
+ if (mask & WL_EVENT_WRITABLE)
+ wl_display_flush(so->parent.display);
+
+ if (mask == 0) {
+ count = wl_display_dispatch_pending(so->parent.display);
+ wl_display_flush(so->parent.display);
+ }
+
+ return count;
+}
+
+static void
+output_destroyed(struct wl_listener *l, void *data)
+{
+ struct shared_output *so;
+
+ so = container_of(l, struct shared_output, output_destroyed);
+
+ shared_output_destroy(so);
+}
+
+static void
+mode_feedback_ok(void *data, struct _wl_fullscreen_shell_mode_feedback *fb)
+{
+ struct shared_output *so = data;
+
+ _wl_fullscreen_shell_mode_feedback_destroy(so->parent.mode_feedback);
+}
+
+static void
+mode_feedback_failed(void *data, struct _wl_fullscreen_shell_mode_feedback *fb)
+{
+ struct shared_output *so = data;
+
+ _wl_fullscreen_shell_mode_feedback_destroy(so->parent.mode_feedback);
+
+ weston_log("Screen share failed: present_surface_for_mode failed\n");
+ shared_output_destroy(so);
+}
+
+struct _wl_fullscreen_shell_mode_feedback_listener mode_feedback_listener = {
+ mode_feedback_ok,
+ mode_feedback_failed,
+ mode_feedback_ok,
+};
+
+static void
+shared_output_repainted(struct wl_listener *listener, void *data)
+{
+ struct shared_output *so =
+ container_of(listener, struct shared_output, frame_listener);
+ pixman_region32_t damage;
+ struct ss_shm_buffer *sb;
+ int32_t x, y, width, height, stride;
+ int i, nrects, do_yflip;
+ pixman_box32_t *r;
+ uint32_t *cache_data;
+
+ /* Damage in output coordinates */
+ pixman_region32_init(&damage);
+ pixman_region32_intersect(&damage, &so->output->region,
+ &so->output->previous_damage);
+ pixman_region32_translate(&damage, -so->output->x, -so->output->y);
+
+ /* Apply damage to all buffers */
+ wl_list_for_each(sb, &so->shm.buffers, link)
+ pixman_region32_union(&sb->damage, &sb->damage, &damage);
+
+ /* Transform to buffer coordinates */
+ weston_transformed_region(so->output->width, so->output->height,
+ so->output->transform,
+ so->output->current_scale,
+ &damage, &damage);
+
+ width = so->output->current_mode->width;
+ height = so->output->current_mode->height;
+ stride = width;
+
+ if (!so->cache_image ||
+ pixman_image_get_width(so->cache_image) != width ||
+ pixman_image_get_height(so->cache_image) != height) {
+ if (so->cache_image)
+ pixman_image_unref(so->cache_image);
+
+ so->cache_image =
+ pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ width, height, NULL,
+ stride);
+ if (!so->cache_image) {
+ shared_output_destroy(so);
+ return;
+ }
+
+ pixman_region32_fini(&damage);
+ pixman_region32_init_rect(&damage, 0, 0, width, height);
+ }
+
+ if (shared_output_ensure_tmp_data(so, &damage) < 0) {
+ shared_output_destroy(so);
+ return;
+ }
+
+ do_yflip = !!(so->output->compositor->capabilities & WESTON_CAP_CAPTURE_YFLIP);
+
+ cache_data = pixman_image_get_data(so->cache_image);
+ r = pixman_region32_rectangles(&damage, &nrects);
+ for (i = 0; i < nrects; ++i) {
+ x = r[i].x1;
+ y = r[i].y1;
+ width = r[i].x2 - r[i].x1;
+ height = r[i].y2 - r[i].y1;
+
+ if (do_yflip) {
+ so->output->compositor->renderer->read_pixels(
+ so->output, PIXMAN_a8r8g8b8, so->tmp_data,
+ x, so->output->current_mode->height - r[i].y2,
+ width, height);
+
+ pixman_blt(so->tmp_data, cache_data, -width, stride,
+ 32, 32, 0, 1 - height, x, y, width, height);
+ } else {
+ so->output->compositor->renderer->read_pixels(
+ so->output, PIXMAN_a8r8g8b8, so->tmp_data,
+ x, y, width, height);
+
+ pixman_blt(so->tmp_data, cache_data, width, stride,
+ 32, 32, 0, 0, x, y, width, height);
+ }
+ }
+
+ pixman_region32_fini(&damage);
+
+ so->cache_dirty = 1;
+
+ shared_output_update(so);
+}
+
+static struct shared_output *
+shared_output_create(struct weston_output *output, int parent_fd)
+{
+ struct shared_output *so;
+ struct wl_event_loop *loop;
+ struct ss_seat *seat;
+ int epoll_fd;
+
+ so = zalloc(sizeof *so);
+ if (so == NULL)
+ goto err_close;
+
+ wl_list_init(&so->seat_list);
+
+ so->parent.display = wl_display_connect_to_fd(parent_fd);
+ if (!so->parent.display)
+ goto err_alloc;
+
+ so->parent.registry = wl_display_get_registry(so->parent.display);
+ if (!so->parent.registry)
+ goto err_display;
+ wl_registry_add_listener(so->parent.registry,
+ &registry_listener, so);
+ wl_display_roundtrip(so->parent.display);
+ if (so->parent.shm == NULL) {
+ weston_log("Screen share failed: No wl_shm found\n");
+ goto err_display;
+ }
+ if (so->parent.fshell == NULL) {
+ weston_log("Screen share failed: "
+ "Parent does not support wl_fullscreen_shell\n");
+ goto err_display;
+ }
+ if (so->parent.compositor == NULL) {
+ weston_log("Screen share failed: No wl_compositor found\n");
+ goto err_display;
+ }
+
+ /* Get SHM formats */
+ wl_display_roundtrip(so->parent.display);
+ if (!(so->parent.shm_formats & (1 << WL_SHM_FORMAT_XRGB8888))) {
+ weston_log("Screen share failed: "
+ "WL_SHM_FORMAT_XRGB8888 not available\n");
+ goto err_display;
+ }
+
+ so->parent.surface =
+ wl_compositor_create_surface(so->parent.compositor);
+ if (!so->parent.surface) {
+ weston_log("Screen share failed: %m");
+ goto err_display;
+ }
+
+ so->parent.mode_feedback =
+ _wl_fullscreen_shell_present_surface_for_mode(so->parent.fshell,
+ so->parent.surface,
+ so->parent.output,
+ output->current_mode->refresh);
+ if (!so->parent.mode_feedback) {
+ weston_log("Screen share failed: %m");
+ goto err_display;
+ }
+ _wl_fullscreen_shell_mode_feedback_add_listener(so->parent.mode_feedback,
+ &mode_feedback_listener,
+ so);
+
+ loop = wl_display_get_event_loop(output->compositor->wl_display);
+
+ epoll_fd = wl_display_get_fd(so->parent.display);
+ so->event_source =
+ wl_event_loop_add_fd(loop, epoll_fd, WL_EVENT_READABLE,
+ shared_output_handle_event, so);
+ if (!so->event_source) {
+ weston_log("Screen share failed: %m");
+ goto err_display;
+ }
+
+ /* Ok, everything's created. We should be good to go */
+ wl_list_init(&so->shm.buffers);
+ wl_list_init(&so->shm.free_buffers);
+
+ so->output = output;
+ so->output_destroyed.notify = output_destroyed;
+ wl_signal_add(&so->output->destroy_signal, &so->output_destroyed);
+
+ so->frame_listener.notify = shared_output_repainted;
+ wl_signal_add(&output->frame_signal, &so->frame_listener);
+ output->disable_planes++;
+ weston_output_damage(output);
+
+ return so;
+
+err_display:
+ wl_list_for_each(seat, &so->seat_list, link)
+ ss_seat_destroy(seat);
+ wl_display_disconnect(so->parent.display);
+err_alloc:
+ free(so);
+err_close:
+ close(parent_fd);
+ return NULL;
+}
+
+static void
+shared_output_destroy(struct shared_output *so)
+{
+ struct ss_shm_buffer *buffer, *bnext;
+
+ so->output->disable_planes--;
+
+ wl_list_for_each_safe(buffer, bnext, &so->shm.buffers, link)
+ ss_shm_buffer_destroy(buffer);
+ wl_list_for_each_safe(buffer, bnext, &so->shm.free_buffers, link)
+ ss_shm_buffer_destroy(buffer);
+
+ wl_display_disconnect(so->parent.display);
+ wl_event_source_remove(so->event_source);
+
+ wl_list_remove(&so->output_destroyed.link);
+ wl_list_remove(&so->frame_listener.link);
+
+ pixman_image_unref(so->cache_image);
+ free(so->tmp_data);
+
+ free(so);
+}
+
+static struct shared_output *
+weston_output_share(struct weston_output *output,
+ const char *path, char *const argv[])
+{
+ int sv[2];
+ char str[32];
+ pid_t pid;
+ sigset_t allsigs;
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
+ weston_log("weston_output_share: socketpair failed: %m\n");
+ return NULL;
+ }
+
+ pid = fork();
+
+ if (pid == -1) {
+ close(sv[0]);
+ close(sv[1]);
+ weston_log("weston_output_share: fork failed: %m\n");
+ return NULL;
+ }
+
+ if (pid == 0) {
+ /* We don't want anything circular */
+ unsetenv("WAYLAND_DISPLAY");
+ unsetenv("WAYLAND_SOCKET");
+
+ /* do not give our signal mask to the new process */
+ sigfillset(&allsigs);
+ sigprocmask(SIG_UNBLOCK, &allsigs, NULL);
+
+ /* Launch clients as the user. Do not launch clients with
+ * wrong euid. */
+ if (seteuid(getuid()) == -1) {
+ weston_log("weston_output_share: setuid failed: %m\n");
+ abort();
+ }
+
+ sv[1] = dup(sv[1]);
+ if (sv[1] == -1) {
+ weston_log("weston_output_share: dup failed: %m\n");
+ abort();
+ }
+
+ snprintf(str, sizeof str, "%d", sv[1]);
+ setenv("WAYLAND_SERVER_SOCKET", str, 1);
+
+ execv(path, argv);
+ weston_log("weston_output_share: exec failed: %m\n");
+ abort();
+ } else {
+ close(sv[1]);
+ return shared_output_create(output, sv[0]);
+ }
+
+ return NULL;
+}
+
+static struct weston_output *
+weston_output_find(struct weston_compositor *c, int32_t x, int32_t y)
+{
+ struct weston_output *output;
+
+ wl_list_for_each(output, &c->output_list, link) {
+ if (x >= output->x && y >= output->y &&
+ x < output->x + output->width &&
+ y < output->y + output->height)
+ return output;
+ }
+
+ return NULL;
+}
+
+static void
+share_output_binding(struct weston_seat *seat, uint32_t time, uint32_t key,
+ void *data)
+{
+ struct weston_output *output;
+ const char *path = BINDIR "/weston";
+
+ if (!seat->pointer) {
+ weston_log("Cannot pick output: Seat does not have pointer\n");
+ return;
+ }
+
+ output = weston_output_find(seat->compositor,
+ wl_fixed_to_int(seat->pointer->x),
+ wl_fixed_to_int(seat->pointer->y));
+ if (!output) {
+ weston_log("Cannot pick output: Pointer not on any output\n");
+ return;
+ }
+
+ char *const argv[] = {
+ "weston",
+ "--backend=rdp-backend.so",
+ "--shell=fullscreen-shell.so",
+ "--no-clients-resize",
+ NULL
+ };
+
+ weston_output_share(output, path, argv);
+}
+
+WL_EXPORT int
+module_init(struct weston_compositor *compositor,
+ int *argc, char *argv[])
+{
+ weston_compositor_add_key_binding(compositor, KEY_S,
+ MODIFIER_CTRL | MODIFIER_ALT,
+ share_output_binding, compositor);
+ return 0;
+}
diff --git a/src/screenshooter.c b/src/screenshooter.c
index 1d1c1b38..02146c89 100644
--- a/src/screenshooter.c
+++ b/src/screenshooter.c
@@ -46,7 +46,8 @@ struct screenshooter {
struct screenshooter_frame_listener {
struct wl_listener listener;
struct weston_buffer *buffer;
- struct wl_resource *resource;
+ weston_screenshooter_done_func_t done;
+ void *data;
};
static void
@@ -129,7 +130,7 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
pixels = malloc(stride * l->buffer->height);
if (pixels == NULL) {
- wl_resource_post_no_memory(l->resource);
+ l->done(l->data, WESTON_SCREENSHOOTER_NO_MEMORY);
free(l);
return;
}
@@ -167,51 +168,84 @@ screenshooter_frame_notify(struct wl_listener *listener, void *data)
wl_shm_buffer_end_access(l->buffer->shm_buffer);
- screenshooter_send_done(l->resource);
+ l->done(l->data, WESTON_SCREENSHOOTER_SUCCESS);
free(pixels);
free(l);
}
-static void
-screenshooter_shoot(struct wl_client *client,
- struct wl_resource *resource,
- struct wl_resource *output_resource,
- struct wl_resource *buffer_resource)
+WL_EXPORT int
+weston_screenshooter_shoot(struct weston_output *output,
+ struct weston_buffer *buffer,
+ weston_screenshooter_done_func_t done, void *data)
{
- struct weston_output *output =
- wl_resource_get_user_data(output_resource);
struct screenshooter_frame_listener *l;
- struct weston_buffer *buffer =
- weston_buffer_from_resource(buffer_resource);
- if (buffer == NULL) {
- wl_resource_post_no_memory(resource);
- return;
+ if (!wl_shm_buffer_get(buffer->resource)) {
+ done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
+ return -1;
}
- if (!wl_shm_buffer_get(buffer->resource))
- return;
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)
- return;
+ buffer->height < output->current_mode->height) {
+ done(data, WESTON_SCREENSHOOTER_BAD_BUFFER);
+ return -1;
+ }
l = malloc(sizeof *l);
if (l == NULL) {
- wl_resource_post_no_memory(resource);
- return;
+ done(data, WESTON_SCREENSHOOTER_NO_MEMORY);
+ return -1;
}
l->buffer = buffer;
- l->resource = resource;
-
+ 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;
+}
+
+static void
+screenshooter_done(void *data, enum weston_screenshooter_outcome outcome)
+{
+ struct wl_resource *resource = data;
+
+ switch (outcome) {
+ case WESTON_SCREENSHOOTER_SUCCESS:
+ screenshooter_send_done(resource);
+ break;
+ case WESTON_SCREENSHOOTER_NO_MEMORY:
+ wl_resource_post_no_memory(resource);
+ break;
+ default:
+ break;
+ }
+}
+
+static void
+screenshooter_shoot(struct wl_client *client,
+ struct wl_resource *resource,
+ struct wl_resource *output_resource,
+ struct wl_resource *buffer_resource)
+{
+ struct weston_output *output =
+ wl_resource_get_user_data(output_resource);
+ struct weston_buffer *buffer =
+ weston_buffer_from_resource(buffer_resource);
+
+ if (buffer == NULL) {
+ wl_resource_post_no_memory(resource);
+ return;
+ }
+
+ weston_screenshooter_shoot(output, buffer, screenshooter_done, resource);
}
struct screenshooter_interface screenshooter_implementation = {
@@ -551,7 +585,7 @@ screenshooter_destroy(struct wl_listener *listener, void *data)
free(shooter);
}
-void
+WL_EXPORT void
screenshooter_create(struct weston_compositor *ec)
{
struct screenshooter *shooter;
diff --git a/src/udev-input.h b/src/udev-input.h
new file mode 100644
index 00000000..e5f3d9de
--- /dev/null
+++ b/src/udev-input.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2014 Jonas Ådahl
+ *
+ * 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 _UDEV_INPUT_H_
+#define _UDEV_INPUT_H_
+
+#include "config.h"
+
+#ifdef BUILD_LIBINPUT_BACKEND
+#include "libinput-seat.h"
+#else
+#include "udev-seat.h"
+#endif
+
+#endif
diff --git a/src/udev-seat.c b/src/udev-seat.c
index f5c2fa88..7e4330a3 100644
--- a/src/udev-seat.c
+++ b/src/udev-seat.c
@@ -35,8 +35,6 @@
static const char default_seat[] = "seat0";
static const char default_seat_name[] = "default";
-static struct udev_seat *
-udev_seat_create(struct weston_compositor *c, const char *seat_name);
static void
udev_seat_destroy(struct udev_seat *seat);
@@ -67,7 +65,7 @@ device_added(struct udev_device *udev_device, struct udev_input *input)
if (!seat_name)
seat_name = default_seat_name;
- seat = udev_seat_get_named(c, seat_name);
+ seat = udev_seat_get_named(input, seat_name);
if (seat == NULL)
return -1;
@@ -239,13 +237,13 @@ out:
}
int
-udev_input_enable(struct udev_input *input, struct udev *udev)
+udev_input_enable(struct udev_input *input)
{
struct wl_event_loop *loop;
struct weston_compositor *c = input->compositor;
int fd;
- input->udev_monitor = udev_monitor_new_from_netlink(udev, "udev");
+ input->udev_monitor = udev_monitor_new_from_netlink(input->udev, "udev");
if (!input->udev_monitor) {
weston_log("udev: failed to create the udev monitor\n");
return -1;
@@ -270,7 +268,7 @@ udev_input_enable(struct udev_input *input, struct udev *udev)
return -1;
}
- if (udev_input_add_devices(input, udev) < 0)
+ if (udev_input_add_devices(input, input->udev) < 0)
return -1;
input->enabled = 1;
@@ -318,7 +316,9 @@ udev_input_init(struct udev_input *input, struct weston_compositor *c, struct ud
memset(input, 0, sizeof *input);
input->seat_id = strdup(seat_id);
input->compositor = c;
- if (udev_input_enable(input, udev) < 0)
+ input->udev = udev;
+ input->udev = udev_ref(udev);
+ if (udev_input_enable(input) < 0)
goto err;
return 0;
@@ -335,6 +335,7 @@ udev_input_destroy(struct udev_input *input)
udev_input_disable(input);
wl_list_for_each_safe(seat, next, &input->compositor->seat_list, base.link)
udev_seat_destroy(seat);
+ udev_unref(input->udev);
free(input->seat_id);
}
@@ -365,8 +366,9 @@ notify_output_create(struct wl_listener *listener, void *data)
}
static struct udev_seat *
-udev_seat_create(struct weston_compositor *c, const char *seat_name)
+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);
@@ -393,8 +395,9 @@ udev_seat_destroy(struct udev_seat *seat)
}
struct udev_seat *
-udev_seat_get_named(struct weston_compositor *c, const char *seat_name)
+udev_seat_get_named(struct udev_input *input, const char *seat_name)
{
+ struct weston_compositor *c = input->compositor;
struct udev_seat *seat;
wl_list_for_each(seat, &c->seat_list, base.link) {
@@ -402,7 +405,7 @@ udev_seat_get_named(struct weston_compositor *c, const char *seat_name)
return seat;
}
- seat = udev_seat_create(c, seat_name);
+ seat = udev_seat_create(input, seat_name);
if (!seat)
return NULL;
diff --git a/src/udev-seat.h b/src/udev-seat.h
index e0d491ab..e388f13e 100644
--- a/src/udev-seat.h
+++ b/src/udev-seat.h
@@ -36,6 +36,7 @@ struct udev_seat {
};
struct udev_input {
+ struct udev *udev;
struct udev_monitor *udev_monitor;
struct wl_event_source *udev_monitor_source;
char *seat_id;
@@ -43,7 +44,7 @@ struct udev_input {
int enabled;
};
-int udev_input_enable(struct udev_input *input, struct udev *udev);
+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,
@@ -51,6 +52,6 @@ int udev_input_init(struct udev_input *input,
const char *seat_id);
void udev_input_destroy(struct udev_input *input);
-struct udev_seat *udev_seat_get_named(struct weston_compositor *c,
+struct udev_seat *udev_seat_get_named(struct udev_input *input,
const char *seat_name);
#endif
diff --git a/src/vaapi-recorder.c b/src/vaapi-recorder.c
index 41314071..0095a42d 100644
--- a/src/vaapi-recorder.c
+++ b/src/vaapi-recorder.c
@@ -43,6 +43,8 @@
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
diff --git a/src/version.h.in b/src/version.h.in
index 79dba45c..7b2c5e39 100644
--- a/src/version.h.in
+++ b/src/version.h.in
@@ -28,7 +28,17 @@
#define WESTON_VERSION_MICRO @WESTON_VERSION_MICRO@
#define WESTON_VERSION "@WESTON_VERSION@"
-/* Can be used like #if WESTON_VERSION_AT_LEAST(1, 2, 0) */
+/* This macro may not do what you expect. Weston doesn't guarantee
+ * any 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 actualy version
+ * is 1.Y.0 and X !=Y). In particular, it fail 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) && \
diff --git a/tests/.gitignore b/tests/.gitignore
index dc4a71a8..67b722d1 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,14 +1,3 @@
-*.log
-*.test
-*.trs
-*.weston
-logs
-matrix-test
-setbacklight
-test-client
-test-text-client
-text-client-protocol.h
-text-protocol.c
-wayland-test-client-protocol.h
-wayland-test-protocol.c
-wayland-test-server-protocol.h
+wcap-decode
+wcap-snapshot
+
diff --git a/tests/README b/tests/README
new file mode 100644
index 00000000..0994a1bb
--- /dev/null
+++ b/tests/README
@@ -0,0 +1,99 @@
+WCAP Tools
+
+WCAP is the video capture format used by Weston (Weston CAPture).
+It's a simple, lossless format, that encodes the difference between
+frames as run-length encoded rectangles. It's a variable framerate
+format, that only records new frames along with a timestamp when
+something actually changes.
+
+Recording in Weston is started by pressing MOD+R and stopped by
+pressing MOD+R again. Currently this leaves a capture.wcap file in
+the cwd of the weston process. The file format is documented below
+and Weston comes with the wcap-decode tool to convert the wcap file
+into something more usable:
+
+ - Extract single or all frames as individual png files. This will
+ produce a lossless screenshot, which is useful if you're trying to
+ screenshot a brief glitch or something like that that's hard to
+ capture with the screenshot tool.
+
+ wcap-decode takes a number of options and a wcap file as its
+ arguments. Without anything else, it will show the screen size and
+ number of frames in the file. Pass --frame=<frame> to extract a
+ single frame or pass --all to extract all frames as png files:
+
+ [krh@minato weston]$ wcap-snapshot capture.wcap
+ wcap file: size 1024x640, 176 frames
+ [krh@minato weston]$ wcap-snapshot capture.wcap 20
+ wrote wcap-frame-20.png
+ wcap file: size 1024x640, 176 frames
+
+ - Decode and the wcap file and dump it as a YUV4MPEG2 stream on
+ stdout. This format is compatible with most video encoders and can
+ be piped directly into a command line encoder such as vpxenc (part
+ of libvpx, encodes to a webm file) or theora_encode (part of
+ libtheora, encodes to a ogg theora file).
+
+ Using vpxenc to encode a webm file would look something like this:
+
+ [krh@minato weston]$ wcap-decode --yuv4mpeg2 ../capture.wcap |
+ vpxenc --target-bitrate=1024 --best -t 4 -o foo.webm -
+
+ where we select target bitrate, pass -t 4 to let vpxenc use
+ multiple threads. To encode to Ogg Theora a command line like this
+ works:
+
+ [krh@minato weston]$ wcap-decode ../capture.wcap --yuv4mpeg2 |
+ theora_encode - -o cap.ogv
+
+
+WCAP File format
+
+The file format has a small header and then just consists of the
+indivial frames. The header is
+
+ uint32_t magic
+ uint32_t format
+ uint32_t width
+ uint32_t height
+
+all CPU endian 32 bit words. The magic number is
+
+ #define WCAP_HEADER_MAGIC 0x57434150
+
+and makes it easy to recognize a wcap file and verify that it's the
+right endian. There are four supported pixel formats:
+
+ #define WCAP_FORMAT_XRGB8888 0x34325258
+ #define WCAP_FORMAT_XBGR8888 0x34324258
+ #define WCAP_FORMAT_RGBX8888 0x34325852
+ #define WCAP_FORMAT_BGRX8888 0x34325842
+
+Each frame has a header:
+
+ uint32_t msecs
+ uint32_t nrects
+
+which specifies a timestamp in ms and the number of rectangles that
+changed since previous frame. The timestamps are typically just a raw
+system timestamp and the first frame doesn't start from 0ms.
+
+A frame consists of a list of rectangles, each of which represents the
+component-wise difference between the previous frame and the current
+using a run-length encoding. The initial frame is decoded against a
+previous frame of all 0x00000000 pixels. Each rectangle starts out
+with
+
+ int32_t x1
+ int32_t y1
+ int32_t x2
+ int32_t y2
+
+followed by (x2 - x1) * (y2 - y1) pixels, run-length encoded. The
+run-length encoding uses the 'X' channel in the pixel format to encode
+the length of the run. That is for WCAP_FORMAT_XRGB8888, for example,
+the length of the run is in the upper 8 bits. For X values 0-0xdf,
+the length is X + 1, for X above or equal to 0xe0, the run length is 1
+<< (X - 0xe0 + 7). That is, a pixel value of 0xe3000100, means that
+the next 1024 pixels differ by RGB(0x00, 0x01, 0x00) from the previous
+pixels.
diff --git a/tests/bad-buffer-test.c b/tests/bad-buffer-test.c
index 4f5f8109..6eae313e 100644
--- a/tests/bad-buffer-test.c
+++ b/tests/bad-buffer-test.c
@@ -21,6 +21,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <unistd.h>
#include <sys/types.h>
diff --git a/tests/buffer-count-test.c b/tests/buffer-count-test.c
index c7ddeb64..8b1dd5d1 100644
--- a/tests/buffer-count-test.c
+++ b/tests/buffer-count-test.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <string.h>
#include "weston-test-client-helper.h"
@@ -31,6 +33,8 @@
#include <wayland-egl.h>
#include <GLES2/gl2.h>
+#define fail(msg) { fprintf(stderr, "%s failed\n", msg); return -1; }
+
struct test_data {
struct client *client;
@@ -40,7 +44,7 @@ struct test_data {
EGLSurface egl_surface;
};
-static void
+static int
init_egl(struct test_data *test_data)
{
struct wl_egl_window *native_window;
@@ -67,21 +71,24 @@ init_egl(struct test_data *test_data)
test_data->egl_dpy = eglGetDisplay((EGLNativeDisplayType)
test_data->client->wl_display);
- assert(test_data->egl_dpy);
+ if (!test_data->egl_dpy)
+ fail("eglGetDisplay");
- ret = eglInitialize(test_data->egl_dpy, &major, &minor);
- assert(ret == EGL_TRUE);
- ret = eglBindAPI(EGL_OPENGL_ES_API);
- assert(ret == EGL_TRUE);
+ if (eglInitialize(test_data->egl_dpy, &major, &minor) != EGL_TRUE)
+ fail("eglInitialize");
+ if (eglBindAPI(EGL_OPENGL_ES_API) != EGL_TRUE)
+ fail("eglBindAPI");
ret = eglChooseConfig(test_data->egl_dpy, config_attribs,
&test_data->egl_conf, 1, &n);
- assert(ret && n == 1);
+ if (!(ret && n == 1))
+ fail("eglChooseConfig");
test_data->egl_ctx = eglCreateContext(test_data->egl_dpy,
test_data->egl_conf,
EGL_NO_CONTEXT, context_attribs);
- assert(test_data->egl_ctx);
+ if (!test_data->egl_ctx)
+ fail("eglCreateContext");
native_window =
wl_egl_window_create(surface->wl_surface,
@@ -95,7 +102,8 @@ init_egl(struct test_data *test_data)
ret = eglMakeCurrent(test_data->egl_dpy, test_data->egl_surface,
test_data->egl_surface, test_data->egl_ctx);
- assert(ret == EGL_TRUE);
+ if (ret != EGL_TRUE)
+ fail("eglMakeCurrent");
/* This test is specific to mesa 10.1 and later, which is the
* first release that doesn't accidentally triple-buffer. */
@@ -108,6 +116,7 @@ init_egl(struct test_data *test_data)
if (major < 10 || (major == 10 && minor < 1))
skip("mesa version too old (%s)\n", str);
+ return 0;
}
TEST(test_buffer_count)
@@ -117,7 +126,9 @@ TEST(test_buffer_count)
int i;
test_data.client = client_create(10, 10, 10, 10);
- init_egl(&test_data);
+ if (init_egl(&test_data) < 0)
+ skip("could not initialize egl, "
+ "possibly using the headless backend\n");
/* This is meant to represent a typical game loop which is
* expecting eglSwapBuffers to block and throttle the
diff --git a/tests/button-test.c b/tests/button-test.c
index dc02fd44..d5ad8134 100644
--- a/tests/button-test.c
+++ b/tests/button-test.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <linux/input.h>
#include "weston-test-client-helper.h"
diff --git a/tests/config-parser-test.c b/tests/config-parser-test.c
index 4b8fc7e7..4b255b7d 100644
--- a/tests/config-parser-test.c
+++ b/tests/config-parser-test.c
@@ -20,6 +20,8 @@
* OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
diff --git a/tests/main.c b/tests/main.c
new file mode 100644
index 00000000..29bb9c30
--- /dev/null
+++ b/tests/main.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright © 2012 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 <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+#include <assert.h>
+
+#include <cairo.h>
+
+#include "wcap-decode.h"
+
+static void
+write_png(struct wcap_decoder *decoder, const char *filename)
+{
+ cairo_surface_t *surface;
+
+ surface = cairo_image_surface_create_for_data((unsigned char *) decoder->frame,
+ CAIRO_FORMAT_ARGB32,
+ decoder->width,
+ decoder->height,
+ decoder->width * 4);
+ cairo_surface_write_to_png(surface, filename);
+ cairo_surface_destroy(surface);
+}
+
+static inline int
+rgb_to_yuv(uint32_t format, uint32_t p, int *u, int *v)
+{
+ int r, g, b, y;
+
+ switch (format) {
+ case WCAP_FORMAT_XRGB8888:
+ r = (p >> 16) & 0xff;
+ g = (p >> 8) & 0xff;
+ b = (p >> 0) & 0xff;
+ break;
+ case WCAP_FORMAT_XBGR8888:
+ r = (p >> 0) & 0xff;
+ g = (p >> 8) & 0xff;
+ b = (p >> 16) & 0xff;
+ break;
+ default:
+ assert(0);
+ }
+
+ y = (19595 * r + 38469 * g + 7472 * b) >> 16;
+ if (y > 255)
+ y = 255;
+
+ *u += 46727 * (r - y);
+ *v += 36962 * (b - y);
+
+ return y;
+}
+
+static inline
+int clamp_uv(int u)
+{
+ int clamp = (u >> 18) + 128;
+
+ if (clamp < 0)
+ return 0;
+ else if (clamp > 255)
+ return 255;
+ else
+ return clamp;
+}
+
+static void
+convert_to_yv12(struct wcap_decoder *decoder, unsigned char *out)
+{
+ unsigned char *y1, *y2, *u, *v;
+ uint32_t *p1, *p2, *end;
+ int i, u_accum, v_accum, stride0, stride1;
+ uint32_t format = decoder->format;
+
+ stride0 = decoder->width;
+ stride1 = decoder->width / 2;
+ for (i = 0; i < decoder->height; i += 2) {
+ y1 = out + stride0 * i;
+ y2 = y1 + stride0;
+ v = out + stride0 * decoder->height + stride1 * i / 2;
+ u = v + stride1 * decoder->height / 2;
+ p1 = decoder->frame + decoder->width * i;
+ p2 = p1 + decoder->width;
+ end = p1 + decoder->width;
+
+ while (p1 < end) {
+ u_accum = 0;
+ v_accum = 0;
+ y1[0] = rgb_to_yuv(format, p1[0], &u_accum, &v_accum);
+ y1[1] = rgb_to_yuv(format, p1[1], &u_accum, &v_accum);
+ y2[0] = rgb_to_yuv(format, p2[0], &u_accum, &v_accum);
+ y2[1] = rgb_to_yuv(format, p2[1], &u_accum, &v_accum);
+ u[0] = clamp_uv(u_accum);
+ v[0] = clamp_uv(v_accum);
+
+ y1 += 2;
+ p1 += 2;
+ y2 += 2;
+ p2 += 2;
+ u++;
+ v++;
+ }
+ }
+}
+
+static void
+convert_to_yuv444(struct wcap_decoder *decoder, unsigned char *out)
+{
+
+ unsigned char *yp, *up, *vp;
+ uint32_t *rp, *end;
+ int u, v;
+ int i, stride, psize;
+ uint32_t format = decoder->format;
+
+ stride = decoder->width;
+ psize = stride * decoder->height;
+ for (i = 0; i < decoder->height; i++) {
+ yp = out + stride * i;
+ up = yp + (psize * 2);
+ vp = yp + (psize * 1);
+ rp = decoder->frame + decoder->width * i;
+ end = rp + decoder->width;
+ while (rp < end) {
+ u = 0;
+ v = 0;
+ yp[0] = rgb_to_yuv(format, rp[0], &u, &v);
+ up[0] = clamp_uv(u/.3);
+ vp[0] = clamp_uv(v/.3);
+ up++;
+ vp++;
+ yp++;
+ rp++;
+ }
+ }
+}
+
+static void
+output_yuv_frame(struct wcap_decoder *decoder, int depth)
+{
+ static unsigned char *out;
+ int size;
+
+ if (depth == 444) {
+ size = decoder->width * decoder->height * 3;
+ } else {
+ size = decoder->width * decoder->height * 3 / 2;
+ }
+ if (out == NULL)
+ out = malloc(size);
+
+ if (depth == 444) {
+ convert_to_yuv444(decoder, out);
+ } else {
+ convert_to_yv12(decoder, out);
+ }
+
+ printf("FRAME\n");
+ fwrite(out, 1, size, stdout);
+}
+
+static void
+usage(int exit_code)
+{
+ fprintf(stderr, "usage: wcap-decode "
+ "[--help] [--yuv4mpeg2] [--frame=<frame>] [--all] \n"
+ "\t[--rate=<num:denom>] <wcap file>\n\n"
+ "\t--help\t\t\tthis help text\n"
+ "\t--yuv4mpeg2\t\tdump wcap file to stdout in yuv4mpeg2 format\n"
+ "\t--yuv4mpeg2-444\t\tdump wcap file to stdout in yuv4mpeg2 444 format\n"
+ "\t--frame=<frame>\t\twrite out the given frame number as png\n"
+ "\t--all\t\t\twrite all frames as pngs\n"
+ "\t--rate=<num:denom>\treplay frame rate for yuv4mpeg2,\n"
+ "\t\t\t\tspecified as an integer fraction\n\n");
+
+ exit(exit_code);
+}
+
+int main(int argc, char *argv[])
+{
+ struct wcap_decoder *decoder;
+ int i, j, output_frame = -1, yuv4mpeg2 = 0, all = 0, has_frame;
+ int num = 30, denom = 1;
+ char filename[200];
+ char *mode;
+ uint32_t msecs, frame_time;
+
+ for (i = 1, j = 1; i < argc; i++) {
+ if (strcmp(argv[i], "--yuv4mpeg2-444") == 0) {
+ yuv4mpeg2 = 444;
+ } else if (strcmp(argv[i], "--yuv4mpeg2") == 0) {
+ yuv4mpeg2 = 420;
+ } else if (strcmp(argv[i], "--help") == 0) {
+ usage(EXIT_SUCCESS);
+ } else if (strcmp(argv[i], "--all") == 0) {
+ all = 1;
+ } else if (sscanf(argv[i], "--frame=%d", &output_frame) == 1) {
+ ;
+ } else if (sscanf(argv[i], "--rate=%d", &num) == 1) {
+ ;
+ } else if (sscanf(argv[i], "--rate=%d:%d", &num, &denom) == 2) {
+ ;
+ } else if (strcmp(argv[i], "--") == 0) {
+ break;
+ } else if (argv[i][0] == '-') {
+ fprintf(stderr,
+ "unknown option or invalid argument: %s\n", argv[i]);
+ usage(EXIT_FAILURE);
+ } else {
+ argv[j++] = argv[i];
+ }
+ }
+ argc = j;
+
+ if (argc != 2)
+ usage(EXIT_FAILURE);
+ if (denom == 0) {
+ fprintf(stderr, "invalid rate, denom can not be 0\n");
+ exit(EXIT_FAILURE);
+ }
+
+ decoder = wcap_decoder_create(argv[1]);
+
+ if (yuv4mpeg2 && isatty(1)) {
+ fprintf(stderr, "Not dumping yuv4mpeg2 data to terminal. Pipe output to a file or a process.\n");
+ fprintf(stderr, "For example, to encode to webm, use something like\n\n");
+ fprintf(stderr, "\t$ wcap-decode --yuv4mpeg2 ../capture.wcap |\n"
+ "\t\tvpxenc --target-bitrate=1024 --best -t 4 -o foo.webm -\n\n");
+
+ exit(EXIT_FAILURE);
+ }
+
+ if (yuv4mpeg2) {
+ if (yuv4mpeg2 == 444) {
+ mode = "C444";
+ } else {
+ mode = "C420jpeg";
+ }
+ printf("YUV4MPEG2 %s W%d H%d F%d:%d Ip A0:0\n",
+ mode, decoder->width, decoder->height, num, denom);
+ fflush(stdout);
+ }
+
+ i = 0;
+ has_frame = wcap_decoder_get_frame(decoder);
+ msecs = decoder->msecs;
+ frame_time = 1000 * denom / num;
+ while (has_frame) {
+ if (all || i == output_frame) {
+ snprintf(filename, sizeof filename,
+ "wcap-frame-%d.png", i);
+ write_png(decoder, filename);
+ fprintf(stderr, "wrote %s\n", filename);
+ }
+ if (yuv4mpeg2)
+ output_yuv_frame(decoder, yuv4mpeg2);
+ i++;
+ msecs += frame_time;
+ while (decoder->msecs < msecs && has_frame)
+ has_frame = wcap_decoder_get_frame(decoder);
+ }
+
+ fprintf(stderr, "wcap file: size %dx%d, %d frames\n",
+ decoder->width, decoder->height, i);
+
+ wcap_decoder_destroy(decoder);
+
+ return EXIT_SUCCESS;
+}
diff --git a/tests/matrix-test.c b/tests/matrix-test.c
index 5b0513f3..7b414c9a 100644
--- a/tests/matrix-test.c
+++ b/tests/matrix-test.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
diff --git a/tests/setbacklight.c b/tests/setbacklight.c
index 92bd4bf3..c8eba436 100644
--- a/tests/setbacklight.c
+++ b/tests/setbacklight.c
@@ -28,6 +28,8 @@
* program.
*/
+#include "config.h"
+
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
diff --git a/tests/subsurface-test.c b/tests/subsurface-test.c
index 1c2641b6..0670e7f7 100644
--- a/tests/subsurface-test.c
+++ b/tests/subsurface-test.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <string.h>
#include "weston-test-client-helper.h"
diff --git a/tests/surface-global-test.c b/tests/surface-global-test.c
index b496635c..edc5d9f6 100644
--- a/tests/surface-global-test.c
+++ b/tests/surface-global-test.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <assert.h>
#include "../src/compositor.h"
diff --git a/tests/text-test.c b/tests/text-test.c
index 1f10b1bb..c838a5d2 100644
--- a/tests/text-test.c
+++ b/tests/text-test.c
@@ -20,6 +20,8 @@
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
+#include "config.h"
+
#include <string.h>
#include <stdio.h>
#include <linux/input.h>
diff --git a/tests/vertex-clip-test.c b/tests/vertex-clip-test.c
index 6d44aa2a..1a09437e 100644
--- a/tests/vertex-clip-test.c
+++ b/tests/vertex-clip-test.c
@@ -19,6 +19,9 @@
* 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 <stdio.h>
#include <stdlib.h>
diff --git a/tests/wcap-decode.c b/tests/wcap-decode.c
new file mode 100644
index 00000000..87d93379
--- /dev/null
+++ b/tests/wcap-decode.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright © 2012 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 <stdlib.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <sys/mman.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <string.h>
+#include <fcntl.h>
+
+#include <cairo.h>
+
+#include "wcap-decode.h"
+
+static void
+wcap_decoder_decode_rectangle(struct wcap_decoder *decoder,
+ struct wcap_rectangle *rect)
+{
+ uint32_t v, *p = decoder->p, *d;
+ int width = rect->x2 - rect->x1, height = rect->y2 - rect->y1;
+ int x, i, j, k, l, count = width * height;
+ unsigned char r, g, b, dr, dg, db;
+
+ d = decoder->frame + (rect->y2 - 1) * decoder->width;
+ x = rect->x1;
+ i = 0;
+ while (i < count) {
+ v = *p++;
+ l = v >> 24;
+ if (l < 0xe0) {
+ j = l + 1;
+ } else {
+ j = 1 << (l - 0xe0 + 7);
+ }
+
+ dr = (v >> 16);
+ dg = (v >> 8);
+ db = (v >> 0);
+ for (k = 0; k < j; k++) {
+ r = (d[x] >> 16) + dr;
+ g = (d[x] >> 8) + dg;
+ b = (d[x] >> 0) + db;
+ d[x] = 0xff000000 | (r << 16) | (g << 8) | b;
+ x++;
+ if (x == rect->x2) {
+ x = rect->x1;
+ d -= decoder->width;
+ }
+ }
+ i += j;
+ }
+
+ if (i != count)
+ printf("rle encoding longer than expected (%d expected %d)\n",
+ i, count);
+
+ decoder->p = p;
+}
+
+int
+wcap_decoder_get_frame(struct wcap_decoder *decoder)
+{
+ struct wcap_rectangle *rects;
+ struct wcap_frame_header *header;
+ uint32_t i;
+
+ if (decoder->p == decoder->end)
+ return 0;
+
+ header = decoder->p;
+ decoder->msecs = header->msecs;
+ decoder->count++;
+
+ rects = (void *) (header + 1);
+ decoder->p = (uint32_t *) (rects + header->nrects);
+ for (i = 0; i < header->nrects; i++)
+ wcap_decoder_decode_rectangle(decoder, &rects[i]);
+
+ return 1;
+}
+
+struct wcap_decoder *
+wcap_decoder_create(const char *filename)
+{
+ struct wcap_decoder *decoder;
+ struct wcap_header *header;
+ int frame_size;
+ struct stat buf;
+
+ decoder = malloc(sizeof *decoder);
+ if (decoder == NULL)
+ return NULL;
+
+ decoder->fd = open(filename, O_RDONLY);
+ if (decoder->fd == -1) {
+ free(decoder);
+ return NULL;
+ }
+
+ fstat(decoder->fd, &buf);
+ decoder->size = buf.st_size;
+ decoder->map = mmap(NULL, decoder->size,
+ PROT_READ, MAP_PRIVATE, decoder->fd, 0);
+
+ header = decoder->map;
+ decoder->format = header->format;
+ decoder->count = 0;
+ decoder->width = header->width;
+ decoder->height = header->height;
+ decoder->p = header + 1;
+ decoder->end = decoder->map + decoder->size;
+
+ frame_size = header->width * header->height * 4;
+ decoder->frame = malloc(frame_size);
+ memset(decoder->frame, 0, frame_size);
+
+ return decoder;
+}
+
+void
+wcap_decoder_destroy(struct wcap_decoder *decoder)
+{
+ munmap(decoder->map, decoder->size);
+ close(decoder->fd);
+ free(decoder->frame);
+ free(decoder);
+}
diff --git a/tests/wcap-decode.h b/tests/wcap-decode.h
new file mode 100644
index 00000000..d6304154
--- /dev/null
+++ b/tests/wcap-decode.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+#ifndef _WCAP_DECODE_
+#define _WCAP_DECODE_
+
+#define WCAP_HEADER_MAGIC 0x57434150
+
+#define WCAP_FORMAT_XRGB8888 0x34325258
+#define WCAP_FORMAT_XBGR8888 0x34324258
+#define WCAP_FORMAT_RGBX8888 0x34325852
+#define WCAP_FORMAT_BGRX8888 0x34325842
+
+struct wcap_header {
+ uint32_t magic;
+ uint32_t format;
+ uint32_t width, height;
+};
+
+struct wcap_frame_header {
+ uint32_t msecs;
+ uint32_t nrects;
+};
+
+struct wcap_rectangle {
+ int32_t x1, y1, x2, y2;
+};
+
+struct wcap_decoder {
+ int fd;
+ size_t size;
+ void *map, *p, *end;
+ uint32_t *frame;
+ uint32_t format;
+ uint32_t msecs;
+ uint32_t count;
+ int width, height;
+};
+
+int wcap_decoder_get_frame(struct wcap_decoder *decoder);
+struct wcap_decoder *wcap_decoder_create(const char *filename);
+void wcap_decoder_destroy(struct wcap_decoder *decoder);
+
+#endif
diff --git a/tests/weston-test-client-helper.c b/tests/weston-test-client-helper.c
index 399aa443..186b3956 100644
--- a/tests/weston-test-client-helper.c
+++ b/tests/weston-test-client-helper.c
@@ -505,9 +505,11 @@ skip(const char *fmt, ...)
vfprintf(stderr, fmt, argp);
va_end(argp);
- /* automake tests uses exit code 77, but we don't have a good
- * way to make weston exit with that from here. */
- exit(0);
+ /* automake tests uses exit code 77. weston-test-runner will see
+ * this and use it, and then weston-test's sigchld handler (in the
+ * weston process) will use that as an exit status, which is what
+ * automake will see in the end. */
+ exit(77);
}
static void
diff --git a/tests/weston-test-client-helper.h b/tests/weston-test-client-helper.h
index 6670ab37..4bfc3fac 100644
--- a/tests/weston-test-client-helper.h
+++ b/tests/weston-test-client-helper.h
@@ -23,6 +23,8 @@
#ifndef _WESTON_TEST_CLIENT_HELPER_H_
#define _WESTON_TEST_CLIENT_HELPER_H_
+#include "config.h"
+
#include <assert.h>
#include "weston-test-runner.h"
#include "wayland-test-client-protocol.h"
diff --git a/tests/weston-test-runner.c b/tests/weston-test-runner.c
index 4274b393..ef45bae7 100644
--- a/tests/weston-test-runner.c
+++ b/tests/weston-test-runner.c
@@ -32,6 +32,8 @@
#include <signal.h>
#include "weston-test-runner.h"
+#define SKIP 77
+
extern const struct weston_test __start_test_section, __stop_test_section;
static const struct weston_test *
@@ -67,6 +69,7 @@ static int
exec_and_report_test(const struct weston_test *t, void *test_data, int iteration)
{
int success = 0;
+ int skip = 0;
int hardfail = 0;
siginfo_t info;
@@ -91,6 +94,8 @@ exec_and_report_test(const struct weston_test *t, void *test_data, int iteration
fprintf(stderr, "exit status %d", info.si_status);
if (info.si_status == EXIT_SUCCESS)
success = 1;
+ else if (info.si_status == SKIP)
+ skip = 1;
break;
case CLD_KILLED:
case CLD_DUMPED:
@@ -106,7 +111,10 @@ exec_and_report_test(const struct weston_test *t, void *test_data, int iteration
if (success && !hardfail) {
fprintf(stderr, ", pass.\n");
return 1;
- } else {
+ } else if (skip) {
+ fprintf(stderr, ", skip.\n");
+ return SKIP;
+ } else {
fprintf(stderr, ", fail.\n");
return 0;
}
@@ -114,13 +122,16 @@ exec_and_report_test(const struct weston_test *t, void *test_data, int iteration
/* Returns number of tests and number of pass / fail in param args */
static int
-iterate_test(const struct weston_test *t, int *passed)
+iterate_test(const struct weston_test *t, int *passed, int *skipped)
{
- int i;
+ int ret, i;
void *current_test_data = (void *) t->table_data;
for (i = 0; i < t->n_elements; ++i, current_test_data += t->element_size)
{
- if (exec_and_report_test(t, current_test_data, i))
+ ret = exec_and_report_test(t, current_test_data, i);
+ if (ret == SKIP)
+ ++(*skipped);
+ else if (ret)
++(*passed);
}
@@ -132,6 +143,7 @@ int main(int argc, char *argv[])
const struct weston_test *t;
int total = 0;
int pass = 0;
+ int skip = 0;
if (argc == 2) {
const char *testname = argv[1];
@@ -149,19 +161,26 @@ int main(int argc, char *argv[])
exit(EXIT_FAILURE);
}
- int number_passed_in_test = 0;
- total += iterate_test(t, &number_passed_in_test);
+ int number_passed_in_test = 0, number_skipped_in_test = 0;
+ total += iterate_test(t, &number_passed_in_test, &number_skipped_in_test);
pass += number_passed_in_test;
+ skip += number_skipped_in_test;
} else {
for (t = &__start_test_section; t < &__stop_test_section; t++) {
- int number_passed_in_test = 0;
- total += iterate_test(t, &number_passed_in_test);
+ int number_passed_in_test = 0, number_skipped_in_test = 0;
+ total += iterate_test(t, &number_passed_in_test, &number_skipped_in_test);
pass += number_passed_in_test;
+ skip += number_skipped_in_test;
}
}
- fprintf(stderr, "%d tests, %d pass, %d fail\n",
- total, pass, total - pass);
+ fprintf(stderr, "%d tests, %d pass, %d skip, %d fail\n",
+ total, pass, skip, total - pass - skip);
+
+ if (skip == total)
+ return SKIP;
+ else if (pass + skip == total)
+ return EXIT_SUCCESS;
- return pass == total ? EXIT_SUCCESS : EXIT_FAILURE;
+ return EXIT_FAILURE;
}
diff --git a/tests/weston-test-runner.h b/tests/weston-test-runner.h
index 457cf31c..e1db0409 100644
--- a/tests/weston-test-runner.h
+++ b/tests/weston-test-runner.h
@@ -24,6 +24,8 @@
#ifndef _WESTON_TEST_RUNNER_H_
#define _WESTON_TEST_RUNNER_H_
+#include "config.h"
+
#include <stdlib.h>
#ifdef NDEBUG
diff --git a/tests/weston-test.c b/tests/weston-test.c
index 844059dc..35ccaa40 100644
--- a/tests/weston-test.c
+++ b/tests/weston-test.c
@@ -54,6 +54,12 @@ test_client_sigchld(struct weston_process *process, int status)
struct weston_test *test =
container_of(process, struct weston_test, process);
+ /* Chain up from weston-test-runner's exit code so that automake
+ * knows the exit status and can report e.g. skipped tests. */
+ if (WIFEXITED(status) && WEXITSTATUS(status) != 0)
+ exit(WEXITSTATUS(status));
+
+ /* In case the child aborted or segfaulted... */
assert(status == 0);
wl_display_terminate(test->compositor->wl_display);
diff --git a/tests/weston-tests-env b/tests/weston-tests-env
index b7322507..91800530 100755
--- a/tests/weston-tests-env
+++ b/tests/weston-tests-env
@@ -7,7 +7,7 @@ if test -z "$TESTNAME"; then
exit 1;
fi
-WESTON=$abs_builddir/../src/weston
+WESTON=$abs_builddir/weston
LOGDIR=$abs_builddir/logs
mkdir -p "$LOGDIR"
@@ -17,14 +17,12 @@ OUTLOG="$LOGDIR/$1-log.txt"
rm -f "$SERVERLOG"
-if test x$WAYLAND_DISPLAY != x; then
- BACKEND=$abs_builddir/../src/.libs/wayland-backend.so
-elif test x$DISPLAY != x; then
- BACKEND=$abs_builddir/../src/.libs/x11-backend.so
-else
- BACKEND=$abs_builddir/../src/.libs/wayland-backend.so
+if test -z "$BACKEND"; then
+ BACKEND=headless-backend.so
fi
+BACKEND=$abs_builddir/.libs/$BACKEND
+
case $TESTNAME in
*.la|*.so)
$WESTON --backend=$BACKEND \
diff --git a/weston.ini.in b/weston.ini.in
index 5181a9e5..2c391779 100644
--- a/weston.ini.in
+++ b/weston.ini.in
@@ -35,7 +35,7 @@ path=/usr/bin/google-chrome
[launcher]
icon=/usr/share/icons/gnome/24x24/apps/arts.png
-path=@abs_top_builddir@/clients/weston-flower
+path=@abs_top_builddir@/weston-flower
[screensaver]
# Uncomment path to disable screensaver
diff --git a/xwayland/dnd.c b/xwayland/dnd.c
index daeb08de..f0f2457d 100644
--- a/xwayland/dnd.c
+++ b/xwayland/dnd.c
@@ -37,7 +37,6 @@
#include "cairo-util.h"
#include "compositor.h"
-#include "xserver-server-protocol.h"
#include "hash.h"
static void
diff --git a/xwayland/launcher.c b/xwayland/launcher.c
index 8d8e060a..f0a87f5b 100644
--- a/xwayland/launcher.c
+++ b/xwayland/launcher.c
@@ -33,20 +33,38 @@
#include <signal.h>
#include "xwayland.h"
-#include "xserver-server-protocol.h"
static int
+handle_sigusr1(int signal_number, void *data)
+{
+ struct weston_xserver *wxs = data;
+
+ /* We'd be safer if we actually had the struct
+ * signalfd_siginfo from the signalfd data and could verify
+ * this came from Xwayland.*/
+ weston_wm_create(wxs, wxs->wm_fd);
+ wl_event_source_remove(wxs->sigusr1_source);
+
+ return 1;
+}
+
+static int
weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
{
struct weston_xserver *wxs = data;
- char display[8], s[8];
- int sv[2], client_fd;
+ char display[8], s[8], abstract_fd[8], unix_fd[8], wm_fd[8];
+ int sv[2], wm[2], fd;
char *xserver = NULL;
struct weston_config_section *section;
if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
- weston_log("socketpair failed\n");
+ weston_log("wl connection socketpair failed\n");
+ return 1;
+ }
+
+ if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, wm) < 0) {
+ weston_log("X wm connection socketpair failed\n");
return 1;
}
@@ -55,29 +73,52 @@ weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
case 0:
/* SOCK_CLOEXEC closes both ends, so we need to unset
* the flag on the client fd. */
- client_fd = dup(sv[1]);
- if (client_fd < 0)
- return 1;
-
- snprintf(s, sizeof s, "%d", client_fd);
+ fd = dup(sv[1]);
+ if (fd < 0)
+ goto fail;
+ snprintf(s, sizeof s, "%d", fd);
setenv("WAYLAND_SOCKET", s, 1);
snprintf(display, sizeof display, ":%d", wxs->display);
- section = weston_config_get_section(wxs->compositor->config, "xwayland", NULL, NULL);
- weston_config_section_get_string(section, "path", &xserver, XSERVER_PATH);
+ fd = dup(wxs->abstract_fd);
+ if (fd < 0)
+ goto fail;
+ snprintf(abstract_fd, sizeof abstract_fd, "%d", fd);
+ fd = dup(wxs->unix_fd);
+ if (fd < 0)
+ goto fail;
+ snprintf(unix_fd, sizeof unix_fd, "%d", fd);
+ fd = dup(wm[1]);
+ if (fd < 0)
+ goto fail;
+ snprintf(wm_fd, sizeof wm_fd, "%d", fd);
+
+ section = weston_config_get_section(wxs->compositor->config,
+ "xwayland", NULL, NULL);
+ weston_config_section_get_string(section, "path",
+ &xserver, XSERVER_PATH);
+
+ /* Ignore SIGUSR1 in the child, which will make the X
+ * server send SIGUSR1 to the parent (weston) when
+ * it's done with initialization. During
+ * initialization the X server will round trip and
+ * block on the wayland compositor, so avoid making
+ * blocking requests (like xcb_connect_to_fd) until
+ * it's done with that. */
+ signal(SIGUSR1, SIG_IGN);
if (execl(xserver,
xserver,
display,
- "-wayland",
"-rootless",
- "-retro",
- "-nolisten", "all",
+ "-listen", abstract_fd,
+ "-listen", unix_fd,
+ "-wm", wm_fd,
"-terminate",
NULL) < 0)
weston_log("exec failed: %m\n");
- free(xserver);
+ fail:
_exit(EXIT_FAILURE);
default:
@@ -86,6 +127,9 @@ weston_xserver_handle_event(int listen_fd, uint32_t mask, void *data)
close(sv[1]);
wxs->client = wl_client_create(wxs->wl_display, sv[0]);
+ close(wm[1]);
+ wxs->wm_fd = wm[0];
+
weston_watch_process(&wxs->process);
wl_event_source_remove(wxs->abstract_source);
@@ -153,32 +197,6 @@ weston_xserver_cleanup(struct weston_process *process, int status)
}
}
-static void
-bind_xserver(struct wl_client *client,
- void *data, uint32_t version, uint32_t id)
-{
- struct weston_xserver *wxs = data;
-
- /* If it's a different client than the xserver we launched,
- * don't start the wm. */
- if (client != wxs->client)
- return;
-
- wxs->resource =
- wl_resource_create(client, &xserver_interface,
- 1, id);
- wl_resource_set_implementation(wxs->resource, &xserver_implementation,
- wxs, NULL);
-
- wxs->wm = weston_wm_create(wxs);
- if (wxs->wm == NULL) {
- weston_log("failed to create wm\n");
- }
-
- xserver_send_listen_socket(wxs->resource, wxs->abstract_fd);
- xserver_send_listen_socket(wxs->resource, wxs->unix_fd);
-}
-
static int
bind_to_abstract_socket(int display)
{
@@ -251,7 +269,7 @@ create_lockfile(int display, char *lockfile, size_t lsize)
snprintf(lockfile, lsize, "/tmp/.X%d-lock", display);
fd = open(lockfile, O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0444);
if (fd < 0 && errno == EEXIST) {
- fd = open(lockfile, O_CLOEXEC, O_RDONLY);
+ fd = open(lockfile, O_CLOEXEC | O_RDONLY);
if (fd < 0 || read(fd, pid, 11) != 11) {
weston_log("can't read lock file %s: %s\n",
lockfile, strerror(errno));
@@ -380,8 +398,8 @@ module_init(struct weston_compositor *compositor,
WL_EVENT_READABLE,
weston_xserver_handle_event, wxs);
- wl_global_create(display, &xserver_interface, 1, wxs, bind_xserver);
-
+ wxs->sigusr1_source = wl_event_loop_add_signal(wxs->loop, SIGUSR1,
+ handle_sigusr1, wxs);
wxs->destroy_listener.notify = weston_xserver_destroy;
wl_signal_add(&compositor->destroy_signal, &wxs->destroy_listener);
diff --git a/xwayland/window-manager.c b/xwayland/window-manager.c
index 1bb9825d..699bade5 100644
--- a/xwayland/window-manager.c
+++ b/xwayland/window-manager.c
@@ -38,7 +38,6 @@
#include "cairo-util.h"
#include "compositor.h"
-#include "xserver-server-protocol.h"
#include "hash.h"
struct wm_size_hints {
@@ -122,6 +121,7 @@ struct weston_wm_window {
xcb_window_t frame_id;
struct frame *frame;
cairo_surface_t *cairo_surface;
+ uint32_t surface_id;
struct weston_surface *surface;
struct shell_surface *shsurf;
struct weston_view *view;
@@ -146,6 +146,7 @@ struct weston_wm_window {
int delete_window;
struct wm_size_hints size_hints;
struct motif_wm_hints motif_hints;
+ struct wl_list link;
};
static struct weston_wm_window *
@@ -154,6 +155,10 @@ get_wm_window(struct weston_surface *surface);
static void
weston_wm_window_schedule_repaint(struct weston_wm_window *window);
+static void
+xserver_map_shell_surface(struct weston_wm_window *window,
+ struct weston_surface *surface);
+
static int __attribute__ ((format (printf, 1, 2)))
wm_log(const char *fmt, ...)
{
@@ -661,6 +666,28 @@ weston_wm_kill_client(struct wl_listener *listener, void *data)
}
static void
+weston_wm_create_surface(struct wl_listener *listener, void *data)
+{
+ struct weston_surface *surface = data;
+ struct weston_wm *wm =
+ container_of(listener,
+ struct weston_wm, create_surface_listener);
+ struct weston_wm_window *window;
+
+ if (wl_resource_get_client(surface->resource) != wm->server->client)
+ return;
+
+ wl_list_for_each(window, &wm->unpaired_window_list, link)
+ if (window->surface_id ==
+ wl_resource_get_id(surface->resource)) {
+ xserver_map_shell_surface(window, surface);
+ window->surface_id = 0;
+ wl_list_remove(&window->link);
+ break;
+ }
+}
+
+static void
weston_wm_window_activate(struct wl_listener *listener, void *data)
{
struct weston_surface *surface = data;
@@ -1095,6 +1122,9 @@ weston_wm_window_destroy(struct weston_wm_window *window)
window->frame_id = XCB_WINDOW_NONE;
}
+ if (window->surface_id)
+ wl_list_remove(&window->link);
+
hash_table_remove(window->wm->window_hash, window->id);
free(window);
}
@@ -1283,6 +1313,51 @@ weston_wm_window_handle_state(struct weston_wm_window *window,
}
static void
+surface_destroy(struct wl_listener *listener, void *data)
+{
+ struct weston_wm_window *window =
+ container_of(listener,
+ struct weston_wm_window, surface_destroy_listener);
+
+ wm_log("surface for xid %d destroyed\n", window->id);
+
+ /* This should have been freed by the shell.
+ * Don't try to use it later. */
+ window->shsurf = NULL;
+ window->surface = NULL;
+ window->view = NULL;
+}
+
+static void
+weston_wm_window_handle_surface_id(struct weston_wm_window *window,
+ xcb_client_message_event_t *client_message)
+{
+ struct weston_wm *wm = window->wm;
+ struct wl_resource *resource;
+
+ if (window->surface_id != 0) {
+ wm_log("already have surface id for window %d\n", window->id);
+ return;
+ }
+
+ /* Xwayland will send the wayland requests to create the
+ * wl_surface before sending this client message. Even so, we
+ * can end up handling the X event before the wayland requests
+ * and thus when we try to look up the surface ID, the surface
+ * hasn't been created yet. In that case put the window on
+ * the unpaired window list and continue when the surface gets
+ * created. */
+ window->surface_id = client_message->data.data32[0];
+ resource = wl_client_get_object(wm->server->client,
+ window->surface_id);
+ if (resource)
+ xserver_map_shell_surface(window,
+ wl_resource_get_user_data(resource));
+ else
+ wl_list_insert(&wm->unpaired_window_list, &window->link);
+}
+
+static void
weston_wm_handle_client_message(struct weston_wm *wm,
xcb_generic_event_t *event)
{
@@ -1305,6 +1380,8 @@ weston_wm_handle_client_message(struct weston_wm *wm,
weston_wm_window_handle_moveresize(window, client_message);
else if (client_message->type == wm->atom.net_wm_state)
weston_wm_window_handle_state(window, client_message);
+ else if (client_message->type == wm->atom.wl_surface_id)
+ weston_wm_window_handle_surface_id(window, client_message);
}
enum cursor_type {
@@ -1777,7 +1854,8 @@ weston_wm_get_resources(struct weston_wm *wm)
{ "XdndStatus", F(atom.xdnd_status) },
{ "XdndFinished", F(atom.xdnd_finished) },
{ "XdndTypeList", F(atom.xdnd_type_list) },
- { "XdndActionCopy", F(atom.xdnd_action_copy) }
+ { "XdndActionCopy", F(atom.xdnd_action_copy) },
+ { "WL_SURFACE_ID", F(atom.wl_surface_id) }
};
#undef F
@@ -1899,13 +1977,12 @@ weston_wm_create_wm_window(struct weston_wm *wm)
}
struct weston_wm *
-weston_wm_create(struct weston_xserver *wxs)
+weston_wm_create(struct weston_xserver *wxs, int fd)
{
struct weston_wm *wm;
struct wl_event_loop *loop;
xcb_screen_iterator_t s;
uint32_t values[1];
- int sv[2];
xcb_atom_t supported[3];
wm = zalloc(sizeof *wm);
@@ -1919,22 +1996,11 @@ weston_wm_create(struct weston_xserver *wxs)
return NULL;
}
- if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) < 0) {
- weston_log("socketpair failed\n");
- hash_table_destroy(wm->window_hash);
- free(wm);
- return NULL;
- }
-
- xserver_send_client(wxs->resource, sv[1]);
- wl_client_flush(wl_resource_get_client(wxs->resource));
- close(sv[1]);
-
/* xcb_connect_to_fd takes ownership of the fd. */
- wm->conn = xcb_connect_to_fd(sv[0], NULL);
+ wm->conn = xcb_connect_to_fd(fd, NULL);
if (xcb_connection_has_error(wm->conn)) {
weston_log("xcb_connect_to_fd failed\n");
- close(sv[0]);
+ close(fd);
hash_table_destroy(wm->window_hash);
free(wm);
return NULL;
@@ -1945,7 +2011,7 @@ weston_wm_create(struct weston_xserver *wxs)
loop = wl_display_get_event_loop(wxs->wl_display);
wm->source =
- wl_event_loop_add_fd(loop, sv[0],
+ wl_event_loop_add_fd(loop, fd,
WL_EVENT_READABLE,
weston_wm_handle_event, wm);
wl_event_source_check(wm->source);
@@ -1965,8 +2031,6 @@ weston_wm_create(struct weston_xserver *wxs)
wm->theme = theme_create();
- weston_wm_create_wm_window(wm);
-
supported[0] = wm->atom.net_wm_moveresize;
supported[1] = wm->atom.net_wm_state;
supported[2] = wm->atom.net_wm_state_fullscreen;
@@ -1984,6 +2048,9 @@ weston_wm_create(struct weston_xserver *wxs)
xcb_flush(wm->conn);
+ wm->create_surface_listener.notify = weston_wm_create_surface;
+ wl_signal_add(&wxs->compositor->create_surface_signal,
+ &wm->create_surface_listener);
wm->activate_listener.notify = weston_wm_window_activate;
wl_signal_add(&wxs->compositor->activate_signal,
&wm->activate_listener);
@@ -1993,11 +2060,16 @@ weston_wm_create(struct weston_xserver *wxs)
wm->kill_listener.notify = weston_wm_kill_client;
wl_signal_add(&wxs->compositor->kill_signal,
&wm->kill_listener);
+ wl_list_init(&wm->unpaired_window_list);
weston_wm_create_cursors(wm);
weston_wm_window_set_cursor(wm, wm->screen->root, XWM_CURSOR_LEFT_PTR);
- weston_log("created wm\n");
+ /* Create wm window and take WM_S0 selection last, which
+ * signals to Xwayland that we're done with setup. */
+ weston_wm_create_wm_window(wm);
+
+ weston_log("created wm, root %d\n", wm->screen->root);
return wm;
}
@@ -2018,22 +2090,6 @@ weston_wm_destroy(struct weston_wm *wm)
free(wm);
}
-static void
-surface_destroy(struct wl_listener *listener, void *data)
-{
- struct weston_wm_window *window =
- container_of(listener,
- struct weston_wm_window, surface_destroy_listener);
-
- wm_log("surface for xid %d destroyed\n", window->id);
-
- /* This should have been freed by the shell.
- Don't try to use it later. */
- window->shsurf = NULL;
- window->surface = NULL;
- window->view = NULL;
-}
-
static struct weston_wm_window *
get_wm_window(struct weston_surface *surface)
{
@@ -2172,15 +2228,32 @@ legacy_fullscreen(struct weston_wm *wm,
return 0;
}
+
static void
-xserver_map_shell_surface(struct weston_wm *wm,
- struct weston_wm_window *window)
+xserver_map_shell_surface(struct weston_wm_window *window,
+ struct weston_surface *surface)
{
+ struct weston_wm *wm = window->wm;
struct weston_shell_interface *shell_interface =
&wm->server->compositor->shell_interface;
struct weston_output *output;
struct weston_wm_window *parent;
+ weston_wm_window_read_properties(window);
+
+ /* A weston_wm_window may have many different surfaces assigned
+ * throughout its life, so we must make sure to remove the listener
+ * from the old surface signal list. */
+ if (window->surface)
+ wl_list_remove(&window->surface_destroy_listener.link);
+
+ window->surface = surface;
+ window->surface_destroy_listener.notify = surface_destroy;
+ wl_signal_add(&window->surface->destroy_signal,
+ &window->surface_destroy_listener);
+
+ weston_wm_window_schedule_repaint(window);
+
if (!shell_interface->create_shell_surface)
return;
@@ -2224,45 +2297,3 @@ xserver_map_shell_surface(struct weston_wm *wm,
shell_interface->set_toplevel(window->shsurf);
}
}
-
-static void
-xserver_set_window_id(struct wl_client *client, struct wl_resource *resource,
- struct wl_resource *surface_resource, uint32_t id)
-{
- struct weston_xserver *wxs = wl_resource_get_user_data(resource);
- struct weston_wm *wm = wxs->wm;
- struct weston_surface *surface =
- wl_resource_get_user_data(surface_resource);
- struct weston_wm_window *window;
-
- if (client != wxs->client)
- return;
-
- window = hash_table_lookup(wm->window_hash, id);
- if (window == NULL) {
- weston_log("set_window_id for unknown window %d\n", id);
- return;
- }
-
- wm_log("set_window_id %d for surface %p\n", id, surface);
-
- weston_wm_window_read_properties(window);
-
- /* A weston_wm_window may have many different surfaces assigned
- * throughout its life, so we must make sure to remove the listener
- * from the old surface signal list. */
- if (window->surface)
- wl_list_remove(&window->surface_destroy_listener.link);
-
- window->surface = (struct weston_surface *) surface;
- window->surface_destroy_listener.notify = surface_destroy;
- wl_signal_add(&surface->destroy_signal,
- &window->surface_destroy_listener);
-
- weston_wm_window_schedule_repaint(window);
- xserver_map_shell_surface(wm, window);
-}
-
-const struct xserver_interface xserver_implementation = {
- xserver_set_window_id
-};
diff --git a/xwayland/xwayland.h b/xwayland/xwayland.h
index c684cc51..312c9b27 100644
--- a/xwayland/xwayland.h
+++ b/xwayland/xwayland.h
@@ -39,7 +39,9 @@ struct weston_xserver {
struct wl_event_source *abstract_source;
int unix_fd;
struct wl_event_source *unix_source;
+ int wm_fd;
int display;
+ struct wl_event_source *sigusr1_source;
struct weston_process process;
struct wl_resource *resource;
struct wl_client *client;
@@ -63,9 +65,11 @@ struct weston_wm {
xcb_render_pictforminfo_t format_rgb, format_rgba;
xcb_visualid_t visual_id;
xcb_colormap_t colormap;
+ struct wl_listener create_surface_listener;
struct wl_listener activate_listener;
struct wl_listener transform_listener;
struct wl_listener kill_listener;
+ struct wl_list unpaired_window_list;
xcb_window_t selection_window;
xcb_window_t selection_owner;
@@ -142,6 +146,7 @@ struct weston_wm {
xcb_atom_t xdnd_finished;
xcb_atom_t xdnd_type_list;
xcb_atom_t xdnd_action_copy;
+ xcb_atom_t wl_surface_id;
} atom;
};
@@ -158,10 +163,8 @@ int
weston_wm_handle_selection_event(struct weston_wm *wm,
xcb_generic_event_t *event);
-extern const struct xserver_interface xserver_implementation;
-
struct weston_wm *
-weston_wm_create(struct weston_xserver *wxs);
+weston_wm_create(struct weston_xserver *wxs, int fd);
void
weston_wm_destroy(struct weston_wm *wm);