Update to Wayland 1.19.0 am: b53eb39185 am: 204cce5a64 am: a51a73e0e3

Original change: https://android-review.googlesource.com/c/platform/external/wayland/+/1619581

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: I4c6f691615f5a0ee88d54da54339850515d7e214
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..d92e5e9
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,24 @@
+root = true
+
+[*]
+charset = utf-8
+end_of_line = lf
+trim_trailing_whitespace = true
+insert_final_newline = true
+indent_style = tab
+indent_size = 8
+max_line_length = 80
+
+[*.xml]
+indent_style = tab
+indent_size = 2
+tab_width = 8
+
+[*.py]
+indent_style = space
+indent_size = 4
+
+[*.yml]
+indent_style = space
+indent_size = 2
+max_line_length = off
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 2489665..b2e174f 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,18 +1,50 @@
-image: debian:stretch
+.templates_sha: &template_sha bd8010dd0123d3f0dda4ef691078566af2842613 # see https://docs.gitlab.com/ee/ci/yaml/#includefile
+
+
+include:
+  # Debian container builder template
+  - project: 'freedesktop/ci-templates'
+    ref: *template_sha
+    file: '/templates/debian.yml'
+
 
 stages:
+  - prep
   - build
 
-before_script:
-  - echo 'path-exclude=/usr/share/doc/*' > /etc/dpkg/dpkg.cfg.d/99-exclude-cruft
-  - echo 'path-exclude=/usr/share/man/*' >> /etc/dpkg/dpkg.cfg.d/99-exclude-cruft
-  - echo '#!/bin/sh' > /usr/sbin/policy-rc.d
-  - echo 'exit 101' >> /usr/sbin/policy-rc.d
-  - chmod +x /usr/sbin/policy-rc.d
-  - apt-get update
-  - apt-get -y --no-install-recommends install build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl
 
-build-native:
+variables:
+  DEBIAN_PACKAGES: 'build-essential automake autoconf libtool pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build'
+  DEBIAN_EXEC: 'pip3 install meson==0.52.1'
+  # these tags should be updated each time the list of packages is updated
+  # changing these will force rebuilding the associated image
+  # Note: these tags have no meaning and are not tied to a particular
+  # wayland version
+  DEBIAN_TAG: '2020-06-05.1'
+  FDO_UPSTREAM_REPO: wayland/wayland
+
+
+.debian.buster:
+  variables:
+    FDO_DISTRIBUTION_PACKAGES: $DEBIAN_PACKAGES
+    FDO_DISTRIBUTION_TAG: $DEBIAN_TAG
+    FDO_DISTRIBUTION_VERSION: 'buster'
+    FDO_DISTRIBUTION_EXEC: $DEBIAN_EXEC
+
+
+debian:buster@container-prep:
+  extends:
+    - .debian.buster
+    - .fdo.container-build@debian
+  stage: prep
+  variables:
+    GIT_STRATEGY: none
+
+
+build-native-autotools:
+  extends:
+    - .debian.buster
+    - .fdo.distribution-image@debian
   stage: build
   script:
   - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID"
@@ -34,3 +66,25 @@
     - build-*/wayland*/_build/sub/*.log
     - build-*/*.log
     - prefix-*
+
+
+build-native-meson:
+  extends:
+    - .debian.buster
+    - .fdo.distribution-image@debian
+  stage: build
+  script:
+  - export BUILD_ID="wayland-$CI_JOB_NAME_$CI_COMMIT_SHA-$CI_JOB_ID"
+  - export PREFIX="$(pwd)/prefix-$BUILD_ID"
+  - export BUILDDIR="$(pwd)/build-$BUILD_ID"
+  - mkdir "$BUILDDIR" "$PREFIX"
+  - cd "$BUILDDIR"
+  - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons ..
+  - ninja -k0 test
+  - ninja clean
+  artifacts:
+    name: wayland-meson-$CI_COMMIT_SHA-$CI_JOB_ID
+    when: always
+    paths:
+    - build-meson/meson-logs
+    - prefix-*
diff --git a/.gitlab/issue_templates/Bug.md b/.gitlab/issue_templates/Bug.md
new file mode 100644
index 0000000..b78a615
--- /dev/null
+++ b/.gitlab/issue_templates/Bug.md
@@ -0,0 +1,8 @@
+<!--
+This repository is for the Wayland protocol description and the libwayland IPC helper
+library only. Issues with Wayland during day-to-day usage are almost
+certainly a bug in your compositor and **not** a bug with in this
+repository.
+
+Please remove this comment before filing your bug.
+-->
diff --git a/Android.bp b/Android.bp
index dc17e11..d5e1acd 100644
--- a/Android.bp
+++ b/Android.bp
@@ -56,6 +56,7 @@
         "-Wno-cast-qual",
         "-Wno-pointer-arith",
         "-Wno-unused-parameter",
+        "-Wno-unused-variable",
     ],
 }
 
@@ -74,10 +75,6 @@
         "src/scanner.c",
         "src/wayland-util.c",
     ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
     static_libs: ["libexpat"],
 }
 
@@ -127,10 +124,6 @@
         "src/wayland-os.c",
         "src/wayland-util.c",
     ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
     static_libs: ["libffi"],
     local_include_dirs: ["src"],
     generated_headers: [
@@ -177,10 +170,6 @@
         "src/wayland-shm.c",
         "src/event-loop.c",
     ],
-    cflags: [
-        "-Wall",
-        "-Werror",
-    ],
     generated_sources: ["wayland_core_protocol_sources_static"],
     static_libs: ["libffi"],
     local_include_dirs: ["src"],
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index dcc9f56..1ea351f 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -232,7 +232,7 @@
 
 - Stable ABI or API additions must be justified by actual use cases, not only
 by speculation. They must also be documented, and it is strongly recommended to
-include tests excercising the additions in the test suite.
+include tests exercising the additions in the test suite.
 
 - The code fits the existing software architecture, e.g. no layering
 violations.
diff --git a/METADATA b/METADATA
index 0a2bfef..dc52692 100644
--- a/METADATA
+++ b/METADATA
@@ -16,7 +16,7 @@
     type: GIT
     value: "https://gitlab.freedesktop.org/wayland/wayland.git"
   }
-  version: "1.17.0"
-  last_upgrade_date { year: 2019 month: 9 day: 27 }
+  version: "1.19.0"
+  last_upgrade_date { year: 2021 month: 2 day: 9 }
   license_type: NOTICE
 }
diff --git a/Makefile.am b/Makefile.am
index f47d055..b9438b7 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -24,6 +24,7 @@
 
 bin_PROGRAMS = wayland-scanner
 wayland_scanner_SOURCES = src/scanner.c
+wayland_scanner_CPPFLAGS = $(AM_CPPFLAGS) -include config.h
 wayland_scanner_CFLAGS = $(EXPAT_CFLAGS) $(LIBXML_CFLAGS) $(AM_CFLAGS)
 wayland_scanner_LDADD = $(EXPAT_LIBS) $(LIBXML_LIBS) libwayland-util.la
 pkgconfig_DATA += src/wayland-scanner.pc
@@ -56,7 +57,8 @@
 	src/connection.c			\
 	src/wayland-os.c			\
 	src/wayland-os.h			\
-	src/wayland-private.h
+	src/wayland-private.h			\
+	src/wayland-server-private.h
 
 include_HEADERS =				\
 	src/wayland-util.h			\
@@ -71,7 +73,7 @@
 	protocol/wayland-client-protocol.h
 
 libwayland_server_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread
-libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la -lrt -lm
+libwayland_server_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la $(RT_LIBS) -lm
 libwayland_server_la_LDFLAGS = -version-info 1:0:1
 libwayland_server_la_SOURCES =			\
 	src/wayland-server.c			\
@@ -83,7 +85,7 @@
 	protocol/wayland-protocol.c
 
 libwayland_client_la_CFLAGS = $(FFI_CFLAGS) $(AM_CFLAGS) -pthread
-libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la -lrt -lm
+libwayland_client_la_LIBADD = $(FFI_LIBS) libwayland-private.la libwayland-util.la $(RT_LIBS) -lm
 libwayland_client_la_LDFLAGS = -version-info 3:0:3
 libwayland_client_la_SOURCES =			\
 	src/wayland-client.c
@@ -96,22 +98,22 @@
 
 protocol/%-protocol.c : $(top_srcdir)/protocol/%.xml
 if USE_HOST_SCANNER
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) code $< $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s code $< $@
 else
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) public-code $< $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s public-code $< $@
 endif
 
 protocol/%-server-protocol.h : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header $< $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s server-header $< $@
 
 protocol/%-client-protocol.h : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header $< $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s client-header $< $@
 
 protocol/%-server-protocol-core.h : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) server-header -c < $< > $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s server-header -c < $< > $@
 
 protocol/%-client-protocol-core.h : $(top_srcdir)/protocol/%.xml
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) client-header -c < $< > $@
+	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && $(wayland_scanner) -s client-header -c < $< > $@
 
 BUILT_SOURCES =					\
 	$(nodist_libwayland_server_la_SOURCES)	\
@@ -174,6 +176,7 @@
 	sanity-test				\
 	socket-test				\
 	queue-test				\
+	proxy-test				\
 	signal-test				\
 	newsignal-test				\
 	resources-test				\
@@ -227,12 +230,13 @@
 	libwayland-client.la			\
 	libwayland-server.la			\
 	libtest-helpers.la			\
-	-lrt -ldl $(FFI_LIBS)
+	$(RT_LIBS) $(DL_LIBS) $(FFI_LIBS)
 
 array_test_SOURCES = tests/array-test.c
 array_test_LDADD = libtest-runner.la
 client_test_SOURCES = tests/client-test.c
 client_test_LDADD = libtest-runner.la
+display_test_CFLAGS = -pthread
 display_test_SOURCES = tests/display-test.c
 display_test_LDADD = libtest-runner.la
 nodist_display_test_SOURCES =				\
@@ -257,6 +261,8 @@
 socket_test_LDADD = libtest-runner.la
 queue_test_SOURCES = tests/queue-test.c
 queue_test_LDADD = libtest-runner.la
+proxy_test_SOURCES = tests/proxy-test.c
+proxy_test_LDADD = libtest-runner.la
 signal_test_SOURCES = tests/signal-test.c
 signal_test_LDADD = libtest-runner.la
 # wayland-server.c is needed here to access wl_priv_* functions
@@ -282,6 +288,7 @@
 endif
 
 fixed_benchmark_SOURCES = tests/fixed-benchmark.c
+fixed_benchmark_LDADD = $(RT_LIBS)
 
 os_wrappers_test_SOURCES = tests/os-wrappers-test.c
 os_wrappers_test_LDADD = libtest-runner.la
@@ -291,6 +298,13 @@
 
 EXTRA_DIST += tests/scanner-test.sh			\
 	protocol/tests.xml				\
+	tests/data/bad-identifier-arg.xml		\
+	tests/data/bad-identifier-entry.xml		\
+	tests/data/bad-identifier-enum.xml		\
+	tests/data/bad-identifier-event.xml		\
+	tests/data/bad-identifier-interface.xml		\
+	tests/data/bad-identifier-protocol.xml		\
+	tests/data/bad-identifier-request.xml		\
 	tests/data/example.xml				\
 	tests/data/example-client.h			\
 	tests/data/example-server.h			\
@@ -302,7 +316,22 @@
 	tests/data/small-code-core.c			\
 	tests/data/small-client-core.h			\
 	tests/data/small-server-core.h			\
-	tests/data/small-private-code.c
+	tests/data/small-private-code.c			\
+	meson.build					\
+	meson_options.txt				\
+	cursor/meson.build				\
+	doc/meson.build					\
+	doc/doxygen/mainpage.dox			\
+	doc/doxygen/meson.build				\
+	doc/doxygen/gen-doxygen.py			\
+	doc/doxygen/xml/meson.build			\
+	doc/doxygen/xml/Client/meson.build		\
+	doc/doxygen/xml/Server/meson.build		\
+	doc/publican/meson.build			\
+	doc/publican/sources/meson.build		\
+	egl/meson.build					\
+	src/meson.build					\
+	tests/meson.build
 
 tests/scanner-test.sh: $(top_builddir)/wayland-scanner
 
diff --git a/README b/README
index 3ae9f0f..ad06dce 100644
--- a/README
+++ b/README
@@ -26,9 +26,8 @@
 
     $ git clone https://gitlab.freedesktop.org/wayland/wayland
     $ cd wayland
-    $ ./autogen.sh --prefix=PREFIX
-    $ make
-    $ make install
+    $ meson build/ --prefix=PREFIX
+    $ ninja -C build/ install
 
 where PREFIX is where you want to install the libraries.  See
 https://wayland.freedesktop.org for more complete build instructions
diff --git a/TODO b/TODO
deleted file mode 100644
index 88fa5cc..0000000
--- a/TODO
+++ /dev/null
@@ -1,146 +0,0 @@
-Core wayland protocol
-
- - Maybe try to make remote wayland actually happen, to see if there
-   is something in the protocol/architecture that makes it harder than
-   it should be.
-
-ICCCM
-
- - mime-type guidelines for data_source (ie, both dnd and selection):
-   recommended types for text or images, types that a clipboard
-   manager must support, mime-types must be listed in preferred order
-
- - we need a "no kb focus please" mechanism.  Or should this be
-   implicit in a specific surface type?
-
-EWMH
-
- - configure should provide dx_left, dx_right, dy_top, dy_bottom, or
-   dx, dy, width and height.
-
- - move to workspace, keep on top, on all workspaces, minimize etc
-   requests for implementing client side window menu? or just make a
-   "show window menu" request to let the compositor display and manage
-   a popup window?
-
- - window move and resize functionality for kb and touch.
-
- - Protocol for specifying title bar rectangle (for moving
-   unresponsive apps).  Rectangle for close button, so we can popup
-   force-close dialog if application doesn't respond to ping event
-   when user clicks there.  We could use the region mechanism here
-   too.
-
- - popup placement protocol logic.
-
- - subsurface mechanism.  we need this for cases where we would use an
-   X subwindow for gl or video other different visual type.
-
-EGL/gbm
-
- - Land Robert Braggs EGL extensions: frame age, swap with damage
-
- - Make it possible to share buffers from compositor to clients.
-   Tricky part here is how to indicate to EGL on the server side that
-   it should make an EGLImage available to a client.  We'll need a
-   "create a wl_buffer for this EGLImage for this client" kind of
-   entry point.
-
- - Protocol for arbitrating access to scanout buffers (physically
-   contiguous memory).  When a client goes fullscreen (or ideally as
-   the compositor starts the animation that will make it fullscreen)
-   we send a "give up your scanout buffer" to the current fullscreen
-   client (if any) and when the client acks that we send a "try to
-   allocate a scanout buffer now" event to the fullscreen-to-be
-   client.
-
-
-Misc
-
- - glyph cache
-
-    - Needs a mechanism to pass buffers to client.
-
-      buffer = drm.create_buffer(); /* buffer with stuff in it */
-
-      cache.upload(buffer, x, y, width, height, int hash)
-
-      drm.buffer: id, name, stride etc /* event to announce cache buffer */
-
-      cache.image: hash, buffer, x, y, stride /* event to announce
-					      * location in cache */
-
-      cache.reject: hash   /* no upload for you! */
-
-      cache.retire: buffer /* cache has stopped using buffer, please
-			    * reupload whatever you had in that buffer */
-
- - A "please suspend" event from the compositor, to indicate to an
-   application that it's no longer visible/active.  Or maybe discard
-   buffer, as in "wayland discarded your buffer, it's no longer
-   visible, you can stop updating it now.", reattach, as in "oh hey,
-   I'm about to show your buffer that I threw away, what was it
-   again?".  for wayland system compositor vt switcing, for example,
-   to be able to throw away the surfaces in the session we're
-   switching away from.  for minimized windows that we don't want live
-   thumb nails for. etc.
-
-
-Clients and ports
-
- - port gtk+
-
-    - draw window decorations in gtkwindow.c
-
-    - Details about pointer grabs. wayland doesn't have active grabs,
-      menus will behave subtly different.  Under X, clicking a menu
-      open grabs the pointer and clicking outside the window pops down
-      the menu and swallows the click.  without active grabs we can't
-      swallow the click.  I'm sure there much more...
-
-    - dnd, copy-paste
-
- - Investigate DirectFB on Wayland (or is that Wayland on DirectFB?)
-
-
-Ideas
-
- - A wayland settings protocol to tell clients about themes (icons,
-   cursors, widget themes), fonts details (family, hinting
-   preferences) etc.  Just send all settings at connect time, send
-   updates when a setting change.  Getting a little close to gconf
-   here, but could be pretty simple:
-
-     interface "settings":
-       event int_value(string name, int value)
-       event string_value(string name, string value)
-
-   but maybe it's better to just require that clients get that from
-   somewhere else (gconf/dbus).
-
-
-Crazy ideas
-
- - AF_WAYLAND - A new socket type.  Eliminate compositor context
-   switch by making kernel understand enough of wayland that it can
-   forward input events as wayland events and do page flipping in
-   response to surface_attach requests:
-
-    - ioctl(wayland_fd, "surface_attach to object 5 should do a kms page
-			 flip on ctrc 2");
-
-    - what about multiple crtcs? what about frame event for other
-      clients?
-
-    - forward these input devices to the client
-
-    - "scancode 124 pressed or released with scan codes 18,22 and 30
-       held down gives control back to userspace wayland.
-
-    - what about maintaining cursor position? what about pointer
-      acceleration?  maybe this only works in "client cursor mode",
-      where wayland hides the cursor and only sends relative events?
-      Solves the composited cursor problem.  How does X show its
-      cursor then?
-
-    - Probably not worth it.
diff --git a/config.h b/config.h
index 92e226c..96d00e1 100644
--- a/config.h
+++ b/config.h
@@ -14,5 +14,6 @@
  * limitations under the License.
  */
 
- // This is used by wayland-os.c
- #define HAVE_ACCEPT4
\ No newline at end of file
+// These are provided by bionic
+#define HAVE_ACCEPT4
+#define HAVE_STRNDUP
diff --git a/configure.ac b/configure.ac
index 8d56f2b..7f2f393 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1,8 +1,8 @@
 AC_PREREQ([2.64])
 
 m4_define([wayland_major_version],  [1])
-m4_define([wayland_minor_version], [17])
-m4_define([wayland_micro_version],  [0])
+m4_define([wayland_minor_version], [19])
+m4_define([wayland_micro_version], [0])
 m4_define([wayland_version],
           [wayland_major_version.wayland_minor_version.wayland_micro_version])
 
@@ -63,7 +63,13 @@
 AC_SUBST(GCC_CFLAGS)
 
 AC_CHECK_HEADERS([sys/prctl.h])
-AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl])
+AC_CHECK_FUNCS([accept4 mkostemp posix_fallocate prctl memfd_create strndup])
+
+# *BSD don't have libdl, but they have its functions in libc
+WESTON_SEARCH_LIBS([DL], [dl], [dlsym])
+
+# OpenBSD doesn't have librt, but it has its functions in libc
+WESTON_SEARCH_LIBS([RT], [rt], [clock_gettime])
 
 AC_ARG_ENABLE([libraries],
 	      [AC_HELP_STRING([--disable-libraries],
@@ -123,19 +129,6 @@
 AC_PATH_PROG(XSLTPROC, xsltproc)
 AM_CONDITIONAL([HAVE_XSLTPROC], [test "x$XSLTPROC" != "x"])
 
-AC_MSG_CHECKING([for docbook manpages stylesheet])
-MANPAGES_STYLESHEET=http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl
-AC_PATH_PROGS_FEATURE_CHECK([XSLTPROC_TMP], [xsltproc],
-			    AS_IF([`"$ac_path_XSLTPROC_TMP" --nonet "$MANPAGES_STYLESHEET" > /dev/null 2>&1`],
-				  [HAVE_MANPAGES_STYLESHEET=yes]))
-if test "x$HAVE_MANPAGES_STYLESHEET" = "xyes"; then
-	AM_CONDITIONAL([HAVE_MANPAGES_STYLESHEET], true)
-	AC_SUBST(MANPAGES_STYLESHEET)
-	AC_MSG_RESULT([yes])
-else
-	AM_CONDITIONAL([HAVE_MANPAGES_STYLESHEET], false)
-	AC_MSG_RESULT([no])
-fi
 
 AM_CONDITIONAL(BUILD_DOCS, [test x$enable_documentation = xyes])
 if test "x$enable_documentation" = "xyes"; then
@@ -171,6 +164,19 @@
 	                   [AC_MSG_RESULT([yes])],
 	                   [AC_MSG_RESULT([yes])])
 
+	AC_MSG_CHECKING([for docbook stylesheets])
+	DOCS_STYLESHEET=http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl
+	AC_PATH_PROGS_FEATURE_CHECK([XSLTPROC_TMP], [xsltproc],
+				    AS_IF([`"$ac_path_XSLTPROC_TMP" --nonet "$DOCS_STYLESHEET" > /dev/null 2>&1`],
+					  [HAVE_DOCS_STYLESHEET=yes]))
+	if test "x$HAVE_DOCS_STYLESHEET" != "xyes"; then
+		AC_MSG_RESULT([no])
+		AC_MSG_ERROR([Documentation build requested but docbook-xsl stylesheets are not found. Install the docbook-xsl package or disable the documentation using --disable-documentation])
+	fi
+
+	AC_MSG_RESULT([yes])
+	AC_SUBST(DOCS_STYLESHEET)
+
 	AC_CONFIG_FILES([
 	doc/doxygen/wayland.doxygen
 	])
@@ -184,7 +190,6 @@
 		 doc/Makefile
 		 doc/publican/Makefile
 		 doc/doxygen/Makefile
-		 doc/man/Makefile
 		 egl/wayland-egl.pc
 		 egl/wayland-egl-backend.pc
 		 src/wayland-server-uninstalled.pc
diff --git a/cursor/convert_font.c b/cursor/convert_font.c
index 45b6ac6..74e45fb 100644
--- a/cursor/convert_font.c
+++ b/cursor/convert_font.c
@@ -499,6 +499,11 @@
 	struct reconstructed_glyph *glyphs =
 		malloc(n * sizeof(*glyphs));
 
+	if (!glyphs) {
+		printf("reconstructed_glyph malloc failed\n");
+		abort();
+	}
+
 	for (i = 0; i < n; ++i) {
 		struct glyph *cursor, *mask;
 		find_cursor_and_mask(interesting_cursors[i].source_name,
diff --git a/cursor/meson.build b/cursor/meson.build
new file mode 100644
index 0000000..ae85ed9
--- /dev/null
+++ b/cursor/meson.build
@@ -0,0 +1,27 @@
+icondir = get_option('icon_directory')
+if icondir == ''
+	icondir = join_paths(get_option('prefix'), get_option('datadir'), 'icons')
+endif
+
+wayland_cursor = library(
+	'wayland-cursor',
+	sources: [
+		'wayland-cursor.c',
+		'os-compatibility.c',
+		'xcursor.c',
+	],
+	version: '0.0.0',
+	dependencies: [ wayland_client_dep ],
+	c_args: [ '-DICONDIR="@0@"'.format(icondir) ],
+	install: true,
+)
+
+install_headers('wayland-cursor.h')
+
+pkgconfig.generate(
+	name: 'Wayland Cursor',
+	description: 'Wayland cursor helper library',
+	version: meson.project_version(),
+	libraries: wayland_cursor,
+	filebase: 'wayland-cursor',
+)
diff --git a/cursor/os-compatibility.c b/cursor/os-compatibility.c
index e972d21..8d51e52 100644
--- a/cursor/os-compatibility.c
+++ b/cursor/os-compatibility.c
@@ -25,6 +25,8 @@
 
 #define _GNU_SOURCE
 
+#include "config.h"
+
 #include <sys/types.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -32,7 +34,10 @@
 #include <string.h>
 #include <stdlib.h>
 
-#include "config.h"
+#ifdef HAVE_MEMFD_CREATE
+#include <sys/mman.h>
+#endif
+
 #include "os-compatibility.h"
 
 #ifndef HAVE_MKOSTEMP
@@ -96,9 +101,16 @@
  *
  * If the C library implements posix_fallocate(), it is used to
  * guarantee that disk space is available for the file at the
- * given size. If disk space is insufficent, errno is set to ENOSPC.
+ * given size. If disk space is insufficient, errno is set to ENOSPC.
  * If posix_fallocate() is not supported, program may receive
  * SIGBUS on accessing mmap()'ed file contents instead.
+ *
+ * If the C library implements memfd_create(), it is used to create the
+ * file purely in memory, without any backing file name on the file
+ * system, and then sealing off the possibility of shrinking it.  This
+ * can then be checked before accessing mmap()'ed file contents, to
+ * make sure SIGBUS can't happen.  It also avoids requiring
+ * XDG_RUNTIME_DIR.
  */
 int
 os_create_anonymous_file(off_t size)
@@ -107,42 +119,65 @@
 	const char *path;
 	char *name;
 	int fd;
-	int ret;
 
-	path = getenv("XDG_RUNTIME_DIR");
-	if (!path) {
-		errno = ENOENT;
-		return -1;
-	}
-
-	name = malloc(strlen(path) + sizeof(template));
-	if (!name)
-		return -1;
-
-	strcpy(name, path);
-	strcat(name, template);
-
-	fd = create_tmpfile_cloexec(name);
-
-	free(name);
-
-	if (fd < 0)
-		return -1;
-
-#ifdef HAVE_POSIX_FALLOCATE
-	ret = posix_fallocate(fd, 0, size);
-	if (ret != 0) {
-		close(fd);
-		errno = ret;
-		return -1;
-	}
-#else
-	ret = ftruncate(fd, size);
-	if (ret < 0) {
-		close(fd);
-		return -1;
-	}
+#ifdef HAVE_MEMFD_CREATE
+	fd = memfd_create("wayland-cursor", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+	if (fd >= 0) {
+		/* We can add this seal before calling posix_fallocate(), as
+		 * the file is currently zero-sized anyway.
+		 *
+		 * There is also no need to check for the return value, we
+		 * couldn't do anything with it anyway.
+		 */
+		fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
+	} else
 #endif
+	{
+		path = getenv("XDG_RUNTIME_DIR");
+		if (!path) {
+			errno = ENOENT;
+			return -1;
+		}
+
+		name = malloc(strlen(path) + sizeof(template));
+		if (!name)
+			return -1;
+
+		strcpy(name, path);
+		strcat(name, template);
+
+		fd = create_tmpfile_cloexec(name);
+
+		free(name);
+
+		if (fd < 0)
+			return -1;
+	}
+
+	if (os_resize_anonymous_file(fd, size) < 0) {
+		close(fd);
+		return -1;
+	}
 
 	return fd;
 }
+
+int
+os_resize_anonymous_file(int fd, off_t size)
+{
+#ifdef HAVE_POSIX_FALLOCATE
+	/* 
+	 * Filesystems that do support fallocate will return EINVAL or
+	 * EOPNOTSUPP. In this case we need to fall back to ftruncate
+	 */
+	errno = posix_fallocate(fd, 0, size);
+	if (errno == 0)
+		return 0;
+	else if (errno != EINVAL && errno != EOPNOTSUPP)
+		return -1;
+#endif
+	if (ftruncate(fd, size) < 0)
+		return -1;
+
+	return 0;
+}
diff --git a/cursor/os-compatibility.h b/cursor/os-compatibility.h
index d0e69ac..fdfeb78 100644
--- a/cursor/os-compatibility.h
+++ b/cursor/os-compatibility.h
@@ -31,4 +31,7 @@
 int
 os_create_anonymous_file(off_t size);
 
+int
+os_resize_anonymous_file(int fd, off_t size);
+
 #endif /* OS_COMPATIBILITY_H */
diff --git a/cursor/wayland-cursor.c b/cursor/wayland-cursor.c
index d40c5c8..4e2dc50 100644
--- a/cursor/wayland-cursor.c
+++ b/cursor/wayland-cursor.c
@@ -83,15 +83,9 @@
 static int
 shm_pool_resize(struct shm_pool *pool, int size)
 {
-	if (ftruncate(pool->fd, size) < 0)
+	if (os_resize_anonymous_file(pool->fd, size) < 0)
 		return 0;
 
-#ifdef HAVE_POSIX_FALLOCATE
-	errno = posix_fallocate(pool->fd, 0, size);
-	if (errno != 0)
-		return 0;
-#endif
-
 	wl_shm_pool_resize(pool->pool, size);
 
 	munmap(pool->data, pool->size);
diff --git a/cursor/wayland-cursor.h b/cursor/wayland-cursor.h
index 40d3fc5..915a110 100644
--- a/cursor/wayland-cursor.h
+++ b/cursor/wayland-cursor.h
@@ -36,17 +36,36 @@
 struct wl_buffer;
 struct wl_shm;
 
+/** A still image part of a cursor
+ *
+ * Use `wl_cursor_image_get_buffer()` to get the corresponding `struct
+ * wl_buffer` to attach to your `struct wl_surface`. */
 struct wl_cursor_image {
-	uint32_t width;		/* actual width */
-	uint32_t height;	/* actual height */
-	uint32_t hotspot_x;	/* hot spot x (must be inside image) */
-	uint32_t hotspot_y;	/* hot spot y (must be inside image) */
-	uint32_t delay;		/* animation delay to next frame (ms) */
+	/** Actual width */
+	uint32_t width;
+
+	/** Actual height */
+	uint32_t height;
+
+	/** Hot spot x (must be inside image) */
+	uint32_t hotspot_x;
+
+	/** Hot spot y (must be inside image) */
+	uint32_t hotspot_y;
+
+	/** Animation delay to next frame (ms) */
+	uint32_t delay;
 };
 
+/** A cursor, as returned by `wl_cursor_theme_get_cursor()` */
 struct wl_cursor {
+	/** How many images there are in this cursor’s animation */
 	unsigned int image_count;
+
+	/** The array of still images composing this animation */
 	struct wl_cursor_image **images;
+
+	/** The name of this cursor */
 	char *name;
 };
 
diff --git a/cursor/xcursor.c b/cursor/xcursor.c
index 689c702..1f1360f 100644
--- a/cursor/xcursor.c
+++ b/cursor/xcursor.c
@@ -285,10 +285,11 @@
 
     if ((*file->read) (file, bytes, 4) != 4)
 	return XcursorFalse;
-    *u = ((bytes[0] << 0) |
-	  (bytes[1] << 8) |
-	  (bytes[2] << 16) |
-	  (bytes[3] << 24));
+
+    *u = ((XcursorUInt)(bytes[0]) << 0) |
+         ((XcursorUInt)(bytes[1]) << 8) |
+         ((XcursorUInt)(bytes[2]) << 16) |
+         ((XcursorUInt)(bytes[3]) << 24);
     return XcursorTrue;
 }
 
diff --git a/cursor/xcursor.h b/cursor/xcursor.h
index 62e2322..c1ca12c 100644
--- a/cursor/xcursor.h
+++ b/cursor/xcursor.h
@@ -26,8 +26,10 @@
 #ifndef XCURSOR_H
 #define XCURSOR_H
 
+#include <stdint.h>
+
 typedef int		XcursorBool;
-typedef unsigned int	XcursorUInt;
+typedef uint32_t	XcursorUInt;
 
 typedef XcursorUInt	XcursorDim;
 typedef XcursorUInt	XcursorPixel;
diff --git a/doc/Makefile.am b/doc/Makefile.am
index 1efd3e2..0b1c4f2 100644
--- a/doc/Makefile.am
+++ b/doc/Makefile.am
@@ -1 +1 @@
-SUBDIRS = doxygen publican man
+SUBDIRS = doxygen publican
diff --git a/doc/doxygen/.gitignore b/doc/doxygen/.gitignore
index a85e6c0..d68d6fc 100644
--- a/doc/doxygen/.gitignore
+++ b/doc/doxygen/.gitignore
@@ -1,4 +1,3 @@
 doxygen_sqlite3.db
 html/
 wayland.doxygen
-xml/
diff --git a/doc/doxygen/Makefile.am b/doc/doxygen/Makefile.am
index f8b0b3a..86fd8bf 100644
--- a/doc/doxygen/Makefile.am
+++ b/doc/doxygen/Makefile.am
@@ -3,8 +3,10 @@
 
 noinst_DATA = \
               xml/Client/index.xml \
+              xml/Cursor/index.xml \
               xml/Server/index.xml \
               html/Client/index.html \
+              html/Cursor/index.html \
               html/Server/index.html
 dist_noinst_DATA = wayland.doxygen.in
 
@@ -17,6 +19,10 @@
 	$(top_srcdir)/src/wayland-client.h	\
 	$(top_srcdir)/src/wayland-client-core.h
 
+scanned_src_files_Cursor = 				\
+	$(top_srcdir)/cursor/wayland-cursor.c	\
+	$(top_srcdir)/cursor/wayland-cursor.h
+
 scanned_src_files_Server = 				\
 	$(scanned_src_files_shared)			\
 	$(top_srcdir)/src/event-loop.c		\
@@ -42,6 +48,9 @@
 	$(top_builddir)/protocol/wayland-client-protocol.h \
 	$(extra_doxygen)
 
+extra_doxygen_Cursor = \
+	$(extra_doxygen)
+
 diagramsdir := $(srcdir)/dot
 diagramssrc := $(wildcard $(diagramsdir)/*.gv)
 diagrams := $(patsubst $(diagramsdir)/%,xml/%,$(diagramssrc:.gv=.png))
@@ -53,20 +62,21 @@
 dist_man3_MANS = $(shell test -d man && find man/man3 -name "wl_*.3" -printf "man/man3/%P\n")
 
 # Listing various directories that might need to be created.
-alldirs := xml xml/Client xml/Server man/man3 html/Client html/Server
+alldirsrel := xml xml/Client xml/Server xml/Cursor man/man3 html/Client html/Server html/Cursor
+alldirs := $(patsubst %,$(CURDIR)/%,$(alldirsrel))
 
 $(diagrams): $(diagramssrc)
 
 $(diagram_maps):  $(diagramssrc)
 
-xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | xml/%
+xml/%/index.xml: $(top_srcdir)/src/scanner.c $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | $(CURDIR)/xml/%
 	$(AM_V_GEN)(cat wayland.doxygen; \
           echo "GENERATE_XML=YES"; \
           echo "XML_OUTPUT=xml/$*"; \
           echo "INPUT= $(scanned_src_files_$*)"; \
           ) | $(DOXYGEN) -
 
-html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | html/%
+html/%/index.html: $(scanned_src_files_%) wayland.doxygen $(diagrams) $(diagram_maps) | $(CURDIR)/html/%
 	$(AM_V_GEN)(cat wayland.doxygen; \
           echo "PROJECT_NAME=\"Wayland $* API\""; \
           echo "GENERATE_HTML=YES"; \
@@ -74,7 +84,7 @@
           echo "INPUT= $(scanned_src_files_$*) $(extra_doxygen_$*)"; \
           ) | $(DOXYGEN) -
 
-man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayland.doxygen | man/man3
+man/man3/wl_display.3: $(top_srcdir)/src/scanner.c $(scanned_src_files_man) wayland.doxygen | $(CURDIR)/man/man3
 	$(AM_V_GEN)(cat wayland.doxygen; \
           echo "GENERATE_MAN=YES"; \
           echo "MAN_OUTPUT=man"; \
@@ -82,10 +92,10 @@
           echo "INPUT= $(scanned_src_files_man)"; \
           ) | $(DOXYGEN) -
 
-xml/%.png: $(diagramsdir)/%.gv | xml
+xml/%.png: $(diagramsdir)/%.gv | $(CURDIR)/xml
 	$(AM_V_GEN)$(DOT) -Tpng -o$@ $<
 
-xml/%.map: $(diagramsdir)/%.gv | xml
+xml/%.map: $(diagramsdir)/%.gv | $(CURDIR)/xml
 	$(AM_V_GEN)$(DOT) -Tcmapx_np -o$@ $<
 
 # general rule to create one of the listed directories.
diff --git a/doc/doxygen/gen-doxygen.py b/doc/doxygen/gen-doxygen.py
new file mode 100755
index 0000000..1bb07e5
--- /dev/null
+++ b/doc/doxygen/gen-doxygen.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python3
+
+import argparse
+import datetime
+import errno
+import os
+import subprocess
+import sys
+
+# Custom configuration for each documentation format
+doxygen_templates = {
+    'xml': [
+        'GENERATE_XML=YES\n',
+        'XML_OUTPUT={format}/{section}\n',
+        'INPUT= {files}\n',
+    ],
+    'html': [
+        'GENERATE_HTML=YES\n',
+        'HTML_OUTPUT={format}/{section}\n',
+        'PROJECT_NAME=\"Wayland {section} API\"\n',
+        'INPUT= {files}\n',
+    ],
+    'man': [
+        'GENERATE_MAN=YES\n',
+        'MAN_OUTPUT={format}\n',
+        'MAN_SUBDIR=.\n',
+        'JAVADOC_AUTOBRIEF=NO\n',
+        'INPUT= {files}\n',
+    ],
+}
+
+def load_doxygen_file(doxyfile):
+    with open(doxyfile, 'r') as f:
+        res = f.readlines()
+    return res
+
+def get_template(outformat):
+    for (k,v) in doxygen_templates.items():
+        if outformat.startswith(k):
+            return v
+
+def gen_doxygen_file(data, outformat, section, files):
+    for l in get_template(outformat):
+        data.append(l.format(format=outformat, section=section, files=' '.join(files)))
+    return data
+
+parser = argparse.ArgumentParser(description='Generate docs with Doxygen')
+parser.add_argument('doxygen_file',
+                    help='The doxygen file to use')
+parser.add_argument('files',
+                    help='The list of files to parse',
+                    metavar='FILES',
+                    nargs='+')
+parser.add_argument('--builddir',
+                    help='The build directory',
+                    metavar='DIR',
+                    default='.')
+parser.add_argument('--section',
+                    help='The section to build',
+                    metavar='NAME',
+                    default='Client')
+parser.add_argument('--output-format',
+                    help='The output format: xml, html, man',
+                    metavar='FORMAT',
+                    default='xml')
+parser.add_argument('--stamp',
+                    help='Stamp file to output',
+                    metavar='STAMP_FILE',
+                    nargs='?',
+                    type=argparse.FileType('w'))
+
+args = parser.parse_args()
+
+# Merge the doxyfile with our custom templates
+conf = load_doxygen_file(args.doxygen_file)
+conf = gen_doxygen_file(conf, args.output_format, args.section, args.files)
+
+# Doxygen is not clever enough to create the directories it
+# needs beforehand
+try:
+    os.makedirs(os.path.join(args.builddir, args.output_format))
+except OSError as e:
+    if e.errno != errno.EEXIST:
+        raise e
+
+# Run Doxygen with the generated doxyfile
+cmd = subprocess.Popen(['doxygen', '-'], stdin=subprocess.PIPE)
+cmd.stdin.write(''.join(conf).encode('utf-8'))
+cmd.stdin.close()
+if cmd.wait() != 0:
+    sys.exit(1)
+
+# This is a bit of a hack; Doxygen will generate way more files than we
+# want to install, but there's no way to know how many at configuration
+# time. Since we want to install only the wl_* man pages anyway, we can
+# delete the other files and let Meson install the whole man3 subdirectory
+if args.output_format.startswith('man'):
+    manpath = os.path.join(args.builddir, args.output_format)
+    for filename in os.listdir(manpath):
+        full_path = os.path.join(manpath, filename)
+        if not filename.startswith('wl_'):
+            os.remove(full_path)
+
+if args.stamp:
+   args.stamp.write(str(datetime.datetime.now()))
diff --git a/doc/doxygen/mainpage.dox b/doc/doxygen/mainpage.dox
index ca1da53..352f69b 100644
--- a/doc/doxygen/mainpage.dox
+++ b/doc/doxygen/mainpage.dox
@@ -6,6 +6,7 @@
  *
  * - <a href="../Server/index.html">Server-side API</a>
  * - <a href="../Client/index.html">Client-side API</a>
+ * - <a href="../Cursor/index.html">Cursor helper library API</a>
  *
  * Further documentation about the architecture and principles of Wayland is
  * available in the
diff --git a/doc/doxygen/meson.build b/doc/doxygen/meson.build
new file mode 100644
index 0000000..f2bee14
--- /dev/null
+++ b/doc/doxygen/meson.build
@@ -0,0 +1,115 @@
+# Here be dragons
+
+dot_gv = {
+	'wayland-architecture': files('dot/wayland-architecture.gv'),
+	'x-architecture': files('dot/x-architecture.gv'),
+}
+
+# This is a workaround for Meson's custom_target() directive, which
+# currently does not support outputs pointing to a sub-directory
+# XXX: try turning these into maps, so they can be indexed with picture name
+dot_png = []
+dot_map = []
+
+doxygen_conf = configuration_data()
+doxygen_conf.set('VERSION', meson.project_version())
+doxygen_conf.set('top_builddir', meson.build_root())
+wayland_doxygen = configure_file(
+	input: 'wayland.doxygen.in',
+	output: 'wayland.doxygen',
+	configuration: doxygen_conf,
+)
+
+shared_files = files([
+	'../../src/wayland-util.h',
+])
+
+client_files = files([
+	'../../src/wayland-client.c',
+	'../../src/wayland-client.h',
+	'../../src/wayland-client-core.h',
+])
+
+server_files = files([
+	'../../src/event-loop.c',
+	'../../src/wayland-server.c',
+	'../../src/wayland-server.h',
+	'../../src/wayland-server-core.h',
+	'../../src/wayland-shm.c',
+])
+
+cursor_files = files([
+	'../../cursor/wayland-cursor.c',
+	'../../cursor/wayland-cursor.h',
+])
+
+extra_client_files = [
+	'mainpage.dox',
+	wayland_client_protocol_h,
+]
+
+extra_server_files = [
+	'mainpage.dox',
+	wayland_server_protocol_h,
+]
+
+extra_cursor_files = [
+	'mainpage.dox',
+]
+
+gen_doxygen = find_program('gen-doxygen.py')
+
+subdir('xml')
+
+formats = {
+	'html': {
+		'Client': shared_files + client_files + extra_client_files,
+		'Server': shared_files + server_files + extra_server_files,
+		'Cursor': shared_files + cursor_files + extra_cursor_files,
+	},
+}
+
+foreach f_name, sections: formats
+	foreach s_name, s_files: sections
+		t_name = '@0@-@1@-doc'.format(f_name, s_name)
+
+		# We do not really need an output file, but Meson
+		# will complain if one is not set, so we use a
+		# dummy 'stamp' file
+		custom_target(
+			t_name,
+			command: [
+				gen_doxygen,
+				# XXX pass doxygen path as argument
+				'--builddir=@OUTDIR@',
+				'--section=@0@'.format(s_name),
+				'--output-format=@0@'.format(f_name),
+				'--stamp=doc/doxygen/@0@.stamp'.format(t_name),
+				wayland_doxygen,
+				'@INPUT@',
+			],
+			input: s_files,
+			output: '@0@.stamp'.format(t_name),
+			depends: [dot_png, dot_map],
+			build_by_default: true,
+		)
+	endforeach
+endforeach
+
+man_files = shared_files + server_files + client_files + cursor_files
+custom_target(
+	'man-pages-3',
+	command: [
+		gen_doxygen,
+		'--builddir=@OUTDIR@',
+		'--output-format=man3',
+		'--stamp=doc/doxygen/man3.stamp',
+		wayland_doxygen,
+		'@INPUT@',
+	],
+	input: man_files,
+	output: 'man3',
+	build_by_default: true,
+	install: true,
+	install_dir: join_paths(get_option('prefix'), get_option('mandir')),
+)
diff --git a/doc/doxygen/xml/Client/meson.build b/doc/doxygen/xml/Client/meson.build
new file mode 100644
index 0000000..849c30d
--- /dev/null
+++ b/doc/doxygen/xml/Client/meson.build
@@ -0,0 +1,18 @@
+tgt = custom_target(
+	'xml-Client-doc',
+	command: [
+		gen_doxygen,
+		# XXX pass doxygen path as argument
+		'--builddir=@OUTDIR@',
+		'--section=Client',
+		'--output-format=xml',
+		wayland_doxygen,
+		'@INPUT@',
+	],
+	input: [ shared_files, client_files ],
+	output: [ 'combine.xslt', 'index.xml' ],
+	depends: [dot_png, dot_map]
+)
+
+doxygen_Client_combine_xslt = tgt[0]
+doxygen_Client_index_xml = tgt[1]
diff --git a/doc/doxygen/xml/Server/meson.build b/doc/doxygen/xml/Server/meson.build
new file mode 100644
index 0000000..4792c1b
--- /dev/null
+++ b/doc/doxygen/xml/Server/meson.build
@@ -0,0 +1,18 @@
+tgt = custom_target(
+	'xml-Server-doc',
+	command: [
+		gen_doxygen,
+		# XXX pass doxygen path as argument
+		'--builddir=@OUTDIR@',
+		'--section=Server',
+		'--output-format=xml',
+		wayland_doxygen,
+		'@INPUT@',
+	],
+	input: [ shared_files, server_files ],
+	output: [ 'combine.xslt', 'index.xml' ],
+	depends: [dot_png, dot_map]
+)
+
+doxygen_Server_combine_xslt = tgt[0]
+doxygen_Server_index_xml = tgt[1]
diff --git a/doc/doxygen/xml/meson.build b/doc/doxygen/xml/meson.build
new file mode 100644
index 0000000..6d55c53
--- /dev/null
+++ b/doc/doxygen/xml/meson.build
@@ -0,0 +1,22 @@
+# dot_png: list of PNG targets
+# dot_map: list of MAP targets
+foreach name, infile: dot_gv
+	dot_png += custom_target(
+		name + '.png',
+		command: [ dot, '-Tpng', '-o@OUTPUT@', '@INPUT@' ],
+		input: infile,
+		output: name + '.png',
+		install: true,
+		install_dir: join_paths(publican_install_prefix, publican_html_dir, 'images')
+	)
+
+	dot_map += custom_target(
+		name + '.map',
+		command: [ dot, '-Tcmapx_np', '-o@OUTPUT@', '@INPUT@' ],
+		input: infile,
+		output: name + '.map',
+	)
+endforeach
+
+subdir('Client')
+subdir('Server')
diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am
deleted file mode 100644
index 41665eb..0000000
--- a/doc/man/Makefile.am
+++ /dev/null
@@ -1,51 +0,0 @@
-#
-# This generates man-pages out of the Docbook XML files. Simply add your files
-# to the $MANPAGES array. If aliases are created, please add them to the
-# MANPAGES_ALIASES array so they get installed correctly.
-#
-
-MANPAGES = \
-	wl_display_connect.3
-MANPAGES_ALIASES = \
-	wl_display_connect_to_fd.3
-
-XML_FILES = \
-	${patsubst %.1,%.xml,${patsubst %.3,%.xml,${patsubst %.5,%.xml,${patsubst %.7,%.xml,$(MANPAGES)}}}}
-CLEANFILES =
-EXTRA_DIST = $(XML_FILES)
-
-if HAVE_XSLTPROC
-if HAVE_MANPAGES_STYLESHEET
-
-CLEANFILES += $(MANPAGES) $(MANPAGES_ALIASES)
-EXTRA_DIST += $(MANPAGES) $(MANPAGES_ALIASES)
-dist_man_MANS = $(MANPAGES) $(MANPAGES_ALIASES)
-
-XSLTPROC_FLAGS = \
-	--stringparam man.authors.section.enabled 0 \
-	--stringparam man.copyright.section.enabled 0 \
-	--stringparam funcsynopsis.style ansi \
-	--stringparam man.output.quietly 1 \
-	--nonet
-
-XSLTPROC_PROCESS_MAN = \
-	$(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
-	$(XSLTPROC) -o $@ $(XSLTPROC_FLAGS) $(MANPAGES_STYLESHEET) $< && \
-	$(SED) -i -e 's/^\.so \(.*\)\.\(.\)$$/\.so man\2\/\1\.\2/' $(MANPAGES_ALIASES)
-
-%.1: %.xml
-	$(XSLTPROC_PROCESS_MAN)
-
-%.3: %.xml
-	$(XSLTPROC_PROCESS_MAN)
-
-%.5: %.xml
-	$(XSLTPROC_PROCESS_MAN)
-
-%.7: %.xml
-	$(XSLTPROC_PROCESS_MAN)
-
-wl_display_connect_to_fd.3: wl_display_connect.3
-
-endif # HAVE_MANPAGES_STYLESHEET
-endif # HAVE_XSLTPROC
diff --git a/doc/man/wl_display_connect.xml b/doc/man/wl_display_connect.xml
deleted file mode 100644
index dab4ddb..0000000
--- a/doc/man/wl_display_connect.xml
+++ /dev/null
@@ -1,112 +0,0 @@
-<?xml version='1.0'?> <!--*-nxml-*-->
-<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.2//EN"
-          "http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd">
-
-<!--
-  Written 2012 by David Herrmann <dh.herrmann@googlemail.com>
-  Dedicated to the Public Domain
--->
-
-<refentry id="wl_display_connect">
-  <refentryinfo>
-    <title>wl_display_connect</title>
-    <productname>wayland-client</productname>
-    <date>September 2012</date>
-    <authorgroup>
-      <author>
-        <contrib>Developer</contrib>
-        <firstname>David</firstname>
-        <surname>Herrmann</surname>
-        <email>dh.herrmann@googlemail.com</email>
-      </author>
-    </authorgroup>
-  </refentryinfo>
-
-  <refmeta>
-    <refentrytitle>wl_display_connect</refentrytitle>
-    <manvolnum>3</manvolnum>
-  </refmeta>
-
-  <refnamediv>
-    <refname>wl_display_connect</refname>
-    <refname>wl_display_connect_to_fd</refname>
-    <refpurpose>Connect to a Wayland socket</refpurpose>
-  </refnamediv>
-
-  <refsynopsisdiv>
-    <funcsynopsis>
-
-      <funcsynopsisinfo>#include &lt;wayland-client.h&gt;</funcsynopsisinfo>
-
-      <funcprototype>
-        <funcdef>struct wl_display *<function>wl_display_connect</function></funcdef>
-        <paramdef>const char *<parameter>name</parameter></paramdef>
-      </funcprototype>
-
-      <funcprototype>
-        <funcdef>struct wl_display *<function>wl_display_connect_to_fd</function></funcdef>
-        <paramdef>int <parameter>fd</parameter></paramdef>
-      </funcprototype>
-
-    </funcsynopsis>
-  </refsynopsisdiv>
-
-  <refsect1>
-    <title>Description</title>
-    <para><function>wl_display_connect</function> connects to a Wayland socket
-          that was previously opened by a Wayland server. The server socket must
-          be placed in <envar>XDG_RUNTIME_DIR</envar> when <envar>WAYLAND_DISPLAY</envar>
-	  (or <varname>name</varname>, see below) is a simple name, for this
-	  function to find it. The server socket is also allowed to exist at an
-	  arbitrary path; usage details follow. See below for compatibility issue
-	  details.</para>
-
-    <para>The <varname>name</varname> argument specifies the name of
-          the socket or <constant>NULL</constant> to use the default (which is
-          <constant>"wayland-0"</constant>). The environment variable
-          <envar>WAYLAND_DISPLAY</envar> replaces the default value.
-
-	  If <varname>name</varname> is an absolute path, then that path is used
-	  as the Wayland socket to which the connection is attempted. Note that
-	  in combination with the default-value behavior described above, this
-	  implies that setting <envar>WAYLAND_DISPLAY</envar> to an absolute
-	  path will implicitly cause <varname>name</varname> to take on that
-	  absolute path if <varname>name</varname> is <constant>NULL</constant>.
-
-          If <envar>WAYLAND_SOCKET</envar> is set, this function behaves like
-          <function>wl_display_connect_to_fd</function> with the file-descriptor
-          number taken from the environment variable.</para>
-
-    <para>Support for interpreting <envar>WAYLAND_DISPLAY</envar> as an
-          absolute path is a change in behavior compared to
-          <function>wl_display_connect</function>'s behavior in versions
-          1.14 and older of Wayland. It is no longer guaranteed in versions
-          1.15 and higher that the Wayland socket chosen is equivalent to
-          manually constructing a socket pathname by concatenating
-          <envar>XDG_RUNTIME_DIR</envar> and <envar>WAYLAND_DISPLAY</envar>.
-          Manual construction of the socket path must account for the
-          possibility that <envar>WAYLAND_DISPLAY</envar> contains an absolute
-          path.</para>
-
-    <para><function>wl_display_connect_to_fd</function> connects to a Wayland
-          socket with an explicit file-descriptor. The file-descriptor is passed
-          as argument <varname>fd</varname>.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>Return Value</title>
-    <para><function>wl_display_connect</function> and
-          <function>wl_display_connect_to_fd</function> return a new display
-          context object or NULL on failure. <varname>errno</varname> is set
-          correspondingly.</para>
-  </refsect1>
-
-  <refsect1>
-    <title>See Also</title>
-    <para>
-      <citerefentry><refentrytitle>wayland-client</refentrytitle><manvolnum>7</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>wl_display_disconnect</refentrytitle><manvolnum>3</manvolnum></citerefentry>,
-      <citerefentry><refentrytitle>wl_display_iterate</refentrytitle><manvolnum>3</manvolnum></citerefentry>
-    </para>
-  </refsect1>
-</refentry>
diff --git a/doc/meson.build b/doc/meson.build
new file mode 100644
index 0000000..f74b6b1
--- /dev/null
+++ b/doc/meson.build
@@ -0,0 +1,37 @@
+dot = find_program('dot')
+doxygen = find_program('doxygen')
+xsltproc = find_program('xsltproc')
+xmlto = find_program('xmlto')
+
+cmd = run_command(doxygen, '--version', check: true)
+message('doxygen: ' + cmd.stdout().strip())
+vers = cmd.stdout().strip()
+if vers.version_compare('< 1.6.0')
+	error('Doxygen 1.6 or later is required for building documentation, found @0@.'.format(vers))
+endif
+
+cmd = run_command(dot, '-V', check: true)
+message('dot: ' + cmd.stderr().strip())
+vers = cmd.stderr().split('version')[1].strip().split(' ')[0]
+if vers.version_compare('< 2.26.0')
+	error('Dot (Graphviz) 2.26 or later is required for building documentation, found @0@.'.format(vers))
+endif
+
+manpage_xsl = 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl'
+cmd = run_command(xsltproc, '--nonet', manpage_xsl)
+if cmd.returncode() != 0
+	error('The style sheet for man pages providing "@0@" was not found.'.format(manpage_xsl))
+endif
+
+publican_install_prefix = join_paths(
+	get_option('prefix'),
+	get_option('datadir'),
+	'doc',
+	meson.project_name(),
+	'Wayland', 'en-US'
+)
+
+publican_html_dir = 'html'
+
+subdir('doxygen')
+subdir('publican')
diff --git a/doc/publican/meson.build b/doc/publican/meson.build
new file mode 100644
index 0000000..60305f4
--- /dev/null
+++ b/doc/publican/meson.build
@@ -0,0 +1,31 @@
+merge_mapcoords_xsl = files('merge-mapcoords.xsl')
+
+subdir('sources')
+
+custom_target(
+	'Wayland-docbook-html',
+	command: [
+		xmlto,
+		'--skip-validation',
+		'--stringparam', 'chunk.section.depth=0',
+		'--stringparam', 'toc.section.depth=1',
+		'--stringparam', 'generate.consistent.ids=1',
+		'--stringparam', 'html.stylesheet=css/default.css',
+		'-o', '@OUTPUT@',
+		'html',
+		'@INPUT@'
+	],
+	input: publican_processed_main,
+	output: publican_html_dir,
+	depend_files: publican_copied_sources,
+	depends: [
+		publican_processed_targets,
+		ClientAPI_xml,
+		ServerAPI_xml,
+		ProtocolSpec_xml,
+		ProtocolInterfaces_xml
+	],
+	build_by_default: true,
+	install: true,
+	install_dir: publican_install_prefix
+)
diff --git a/doc/publican/protocol-to-docbook.xsl b/doc/publican/protocol-to-docbook.xsl
index 210e0db..79c938b 100644
--- a/doc/publican/protocol-to-docbook.xsl
+++ b/doc/publican/protocol-to-docbook.xsl
@@ -146,7 +146,7 @@
   </varlistentry>
 </xsl:template>
 
-<!-- enum and bitfield arguemnts -->
+<!-- enum and bitfield arguments -->
 <xsl:template match="arg[@enum]">
   <varlistentry>
     <term><xsl:value-of select="@name"/></term>
diff --git a/doc/publican/sources/Book_Info.xml b/doc/publican/sources/Book_Info.xml
index 0b7bf07..897673a 100644
--- a/doc/publican/sources/Book_Info.xml
+++ b/doc/publican/sources/Book_Info.xml
@@ -28,9 +28,9 @@
 	<imagedata fileref="images/wayland.png" format="PNG" />
       </imageobject>
       <textobject>
-        <phrase>
-          Wayland logo
-        </phrase>
+	<phrase>
+	  Wayland logo
+	</phrase>
       </textobject>
     </inlinemediaobject>
   </corpauthor>
diff --git a/doc/publican/sources/Compositors.xml b/doc/publican/sources/Compositors.xml
index eea627c..7a7bdaa 100644
--- a/doc/publican/sources/Compositors.xml
+++ b/doc/publican/sources/Compositors.xml
@@ -52,7 +52,7 @@
       run nested under the system compositor. Nesting is feasible because
       the protocol is asynchronous; roundtrips would be too expensive
       when nesting is involved. If no system compositor is present, a
-      session compositor can run directly on the hw.
+      session compositor can run directly on the hardware.
      </para>
      <para>
       X applications can continue working under a session compositor
@@ -61,8 +61,8 @@
     <para>
        Possible examples for session compositors include
       <itemizedlist>
-        <listitem>
-          <para>
+	<listitem>
+	  <para>
 	    gnome-shell
 	  </para>
 	</listitem>
diff --git a/doc/publican/sources/Foreword.xml b/doc/publican/sources/Foreword.xml
index e6875a3..46fda2b 100644
--- a/doc/publican/sources/Foreword.xml
+++ b/doc/publican/sources/Foreword.xml
@@ -22,7 +22,7 @@
   <literallayout>
 Yours,
 
-        the Wayland open-source community
-        November 2012
+	the Wayland open-source community
+	November 2012
   </literallayout>
 </preface>
diff --git a/doc/publican/sources/Introduction.xml b/doc/publican/sources/Introduction.xml
index 7516c33..276db2d 100644
--- a/doc/publican/sources/Introduction.xml
+++ b/doc/publican/sources/Introduction.xml
@@ -33,9 +33,9 @@
 	<imagedata fileref="images/x-architecture.png" format="PNG" />
       </imageobject>
       <textobject>
-        <phrase>
-          X architecture diagram
-        </phrase>
+	<phrase>
+	  X architecture diagram
+	</phrase>
       </textobject>
     </mediaobject>
     <para>
@@ -96,9 +96,9 @@
 	<imagedata fileref="images/wayland-architecture.png" format="PNG" />
       </imageobject>
       <textobject>
-        <phrase>
-          Wayland architecture diagram
-        </phrase>
+	<phrase>
+	  Wayland architecture diagram
+	</phrase>
       </textobject>
     </mediaobject>
     <para>
diff --git a/doc/publican/sources/Preface.xml b/doc/publican/sources/Preface.xml
index 61720a9..17c6ebf 100644
--- a/doc/publican/sources/Preface.xml
+++ b/doc/publican/sources/Preface.xml
@@ -15,6 +15,6 @@
   <literallayout>
 Best,
 
-        Kristian Høgsberg
+	Kristian Høgsberg
   </literallayout>
 </preface>
diff --git a/doc/publican/sources/Protocol.xml b/doc/publican/sources/Protocol.xml
index fedaaab..97e9ba2 100644
--- a/doc/publican/sources/Protocol.xml
+++ b/doc/publican/sources/Protocol.xml
@@ -167,10 +167,10 @@
 	  <term>new_id</term>
 	  <listitem>
 	    <para>
-	      The 32-bit object ID.  On requests, the client
-	      decides the ID.  The only events with <type>new_id</type> are
-	      advertisements of globals, and the server will use IDs below
-	      0x10000.
+	      The 32-bit object ID.  Generally, the interface used for the new
+	      object is inferred from the xml, but in the case where it's not
+	      specified, a new_id is preceded by a <code>string</code> specifying
+	      the interface name, and a <code>uint</code> specifying the version.
 	    </para>
 	  </listitem>
 	</varlistentry>
@@ -214,7 +214,7 @@
 	<listitem>
 	  <para>
 	    The object creation hierarchy must be a tree.  Otherwise,
-	    infering object versions from the parent object becomes a much
+	    inferring object versions from the parent object becomes a much
 	    more difficult to properly track.
 	  </para>
 	</listitem>
@@ -293,7 +293,7 @@
       creating the object (either client or server).  IDs allocated by the
       client are in the range [1, 0xfeffffff] while IDs allocated by the
       server are in the range [0xff000000, 0xffffffff].  The 0 ID is
-      reserved to represent a null or non-existant object.
+      reserved to represent a null or non-existent object.
 
       For efficiency purposes, the IDs are densely packed in the sense that
       the ID N will not be used until N-1 has been used.  Any ID allocation
@@ -401,10 +401,11 @@
       set the pointer image.
     </para>
     <para>
+      Setting the pointer image to NULL causes the cursor to be hidden.
+    </para>
+    <para>
       The compositor will revert the pointer image back to a default image
-      when no surface has the pointer focus for that device.  Clients can
-      revert the pointer image back to the default image by setting a NULL
-      image.
+      when no surface has the pointer focus for that device.
     </para>
     <para>
       What if the pointer moves from one window which has set a special
@@ -412,7 +413,10 @@
       the motion event?  The new surface will be stuck with the special
       pointer image.  We can't just revert the pointer image on leaving a
       surface, since if we immediately enter a surface that sets a different
-      image, the image will flicker.  Broken app, I suppose.
+      image, the image will flicker.  If a client does not set a pointer image
+      when the pointer enters a surface, the pointer stays with the image set
+      by the last surface that changed it, possibly even hidden.  Such a client
+      is likely just broken.
     </para>
   </section>
   <section id="sect-Protocol-Output">
diff --git a/doc/publican/sources/Server.xml b/doc/publican/sources/Server.xml
index f627d64..2333b1a 100644
--- a/doc/publican/sources/Server.xml
+++ b/doc/publican/sources/Server.xml
@@ -24,7 +24,7 @@
   </para>
   <para>
     Each open socket to a client is represented by a <link
-    linkend="Server-structwl__client">wl_client</link>.  The equvalent
+    linkend="Server-structwl__client">wl_client</link>.  The equivalent
     of the <link linkend="Client-classwl__proxy">wl_proxy</link> that
     libwayland-client uses to represent an object is <link
     linkend="Server-structwl__resource">wl_resource</link> for
diff --git a/doc/publican/sources/Xwayland.xml b/doc/publican/sources/Xwayland.xml
index a39866f..7915559 100644
--- a/doc/publican/sources/Xwayland.xml
+++ b/doc/publican/sources/Xwayland.xml
@@ -78,11 +78,11 @@
     <figure>
       <title>Xwayland architecture diagram</title>
       <mediaobjectco>
-        <imageobjectco>
-          <imageobject>
-            <imagedata fileref="images/xwayland-architecture.png" format="PNG" />
-          </imageobject>
-        </imageobjectco>
+	<imageobjectco>
+	  <imageobject>
+	    <imagedata fileref="images/xwayland-architecture.png" format="PNG" />
+	  </imageobject>
+	</imageobjectco>
       </mediaobjectco>
     </figure>
     <para>
@@ -145,25 +145,25 @@
       Xwayland. It is often nearly impossible to prove that synchronous or
       blocking X11 calls from XWM cannot cause a deadlock, and therefore it is
       strongly recommended to make all X11 communications asynchronous. All
-      Wayland communications are already asynchonous by design.
+      Wayland communications are already asynchronous by design.
     </para>
     <section id="sect-X11-Application-Support-xwm-window-identification">
       <title>Window identification</title>
       <para>
-        In Xwayland, an X11 window may have a corresponding wl_surface object
-        in Wayland. The wl_surface object is used for input and output: it is
-        referenced by input events and used to provide the X11 window content
-        to the Wayland compositor. The X11 window and the wl_surface live in
-        different protocol streams, and they need to be matched for XWM to do
-        its job.
+	In Xwayland, an X11 window may have a corresponding wl_surface object
+	in Wayland. The wl_surface object is used for input and output: it is
+	referenced by input events and used to provide the X11 window content
+	to the Wayland compositor. The X11 window and the wl_surface live in
+	different protocol streams, and they need to be matched for XWM to do
+	its job.
       </para>
       <para>
-        When Xwayland creates a wl_surface on Wayland, it will also send an X11
-        ClientMessage of type atom "WL_SURFACE_ID" to the X11 window carrying
-        the wl_surface Wayland object ID as the first 32-bit data element. This
-        is how XWM can associate a wl_surface with an X11 window. Note that
-        the request to create a wl_surface and the ID message may arrive in any
-        order in the Wayland compositor.
+	When Xwayland creates a wl_surface on Wayland, it will also send an X11
+	ClientMessage of type atom "WL_SURFACE_ID" to the X11 window carrying
+	the wl_surface Wayland object ID as the first 32-bit data element. This
+	is how XWM can associate a wl_surface with an X11 window. Note that
+	the request to create a wl_surface and the ID message may arrive in any
+	order in the Wayland compositor.
       </para>
     </section>
   </section>
diff --git a/doc/publican/sources/meson.build b/doc/publican/sources/meson.build
new file mode 100644
index 0000000..52f3a68
--- /dev/null
+++ b/doc/publican/sources/meson.build
@@ -0,0 +1,113 @@
+ProtocolSpec_xml = custom_target(
+	'ProtocolSpec.xml',
+	command: [ xsltproc, '-o', '@OUTPUT@', files('../protocol-to-docbook.xsl'), '@INPUT@' ],
+	input: wayland_protocol_xml,
+	output: 'ProtocolSpec.xml'
+)
+
+ProtocolInterfaces_xml = custom_target(
+	'ProtocolInterfaces.xml',
+	command: [ xsltproc, '-o', '@OUTPUT@', files('../protocol-interfaces-to-docbook.xsl'), '@INPUT@' ],
+	input: wayland_protocol_xml,
+	output: 'ProtocolInterfaces.xml'
+)
+
+ClientAPI_combined = custom_target(
+	'ClientAPI-combined',
+	command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ],
+	input: [ doxygen_Client_combine_xslt, doxygen_Client_index_xml ],
+	output: 'ClientAPI-combined.xml'
+)
+
+to_publican_xsl = files('../doxygen-to-publican.xsl')
+
+ClientAPI_xml = custom_target(
+	'ClientAPI.xml',
+	command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Client', to_publican_xsl, '@INPUT@' ],
+	input: ClientAPI_combined,
+	output: 'ClientAPI.xml'
+)
+
+ServerAPI_combined = custom_target(
+	'ServerAPI-combined',
+	command: [ xsltproc, '-o', '@OUTPUT@', '@INPUT@' ],
+	input: [ doxygen_Server_combine_xslt, doxygen_Server_index_xml ],
+	output: 'ServerAPI-combined.xml'
+)
+
+ServerAPI_xml = custom_target(
+	'ServerAPI.xml',
+	command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'which', 'Server', to_publican_xsl, '@INPUT@' ],
+	input: ServerAPI_combined,
+	output: 'ServerAPI.xml'
+)
+
+
+publican_sources = [
+	'Wayland.ent',
+	# 'Wayland.xml', # handled specially
+	'Book_Info.xml',
+	'Author_Group.xml',
+	'Foreword.xml',
+	'Preface.xml',
+	'Revision_History.xml',
+	'Protocol.xml',
+	'Xwayland.xml',
+	'Compositors.xml',
+	'Client.xml',
+	'Server.xml'
+]
+
+publican_processed_main = configure_file(
+	input: 'Wayland.xml',
+	output: 'Wayland.xml',
+	copy: true
+)
+
+publican_copied_sources = []
+foreach src: publican_sources
+	publican_copied_sources += configure_file(
+		input: src,
+		output: src,
+		copy: true
+	)
+endforeach
+
+publican_processed_sources = [
+	'Architecture.xml',
+	'Introduction.xml'
+]
+
+publican_processed_targets = []
+foreach src: publican_processed_sources
+	publican_processed_targets += custom_target(
+		src,
+		command: [ xsltproc, '-o', '@OUTPUT@', '--stringparam', 'basedir', '.', merge_mapcoords_xsl, '@INPUT@' ],
+		input: src,
+		output: src
+	)
+endforeach
+
+publican_css_sources = files([
+	'css/brand.css',
+	'css/common.css',
+	'css/default.css',
+	'css/epub.css',
+	'css/print.css'
+])
+
+install_data(
+	publican_css_sources,
+	install_dir: join_paths(publican_install_prefix, publican_html_dir, 'css')
+)
+
+publican_img_sources = files([
+	'images/icon.svg',
+	'images/wayland.png',
+	'images/xwayland-architecture.png'
+])
+
+install_data(
+	publican_img_sources,
+	install_dir: join_paths(publican_install_prefix, publican_html_dir, 'images')
+)
diff --git a/egl/meson.build b/egl/meson.build
new file mode 100644
index 0000000..dee9b1d
--- /dev/null
+++ b/egl/meson.build
@@ -0,0 +1,43 @@
+wayland_egl = library(
+	'wayland-egl',
+	sources: [
+		'wayland-egl.c',
+		wayland_client_protocol_h
+	],
+	include_directories: src_inc,
+	version: '1.0.0',
+	install: true
+)
+
+executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c')
+
+nm_path = find_program('nm').path()
+
+test(
+	'wayland-egl symbols check',
+	find_program('wayland-egl-symbols-check'),
+	env: [
+		'WAYLAND_EGL_LIB=@0@'.format(wayland_egl.full_path()),
+		'NM=@0@'.format(nm_path)
+	]
+)
+
+install_headers([
+	'wayland-egl.h',
+	'wayland-egl-core.h',
+	'wayland-egl-backend.h'
+])
+
+pkgconfig.generate(
+	name: 'wayland-egl',
+	description: 'Frontend wayland-egl library',
+	version: '18.1.0',
+	requires: 'wayland-client',
+	libraries: wayland_egl
+)
+
+pkgconfig.generate(
+	name: 'wayland-egl-backend',
+	description: 'Backend wayland-egl interface',
+	version: '3'
+)
diff --git a/egl/wayland-egl-abi-check.c b/egl/wayland-egl-abi-check.c
index faa6b57..ea877d0 100644
--- a/egl/wayland-egl-abi-check.c
+++ b/egl/wayland-egl-abi-check.c
@@ -112,7 +112,7 @@
     do {                                                                            \
         if (offsetof(struct wl_egl_window ## a_ver, a_member) !=                    \
             offsetof(struct wl_egl_window ## b_ver, b_member)) {                    \
-            printf("Backards incompatible change detected!\n   "                    \
+            printf("Backwards incompatible change detected!\n   "                    \
                    "offsetof(struct wl_egl_window" #a_ver "::" #a_member ") != "    \
                    "offsetof(struct wl_egl_window" #b_ver "::" #b_member ")\n");    \
             return 1;                                                               \
@@ -120,7 +120,7 @@
                                                                                     \
         if (MEMBER_SIZE(struct wl_egl_window ## a_ver, a_member) !=                 \
             MEMBER_SIZE(struct wl_egl_window ## b_ver, b_member)) {                 \
-            printf("Backards incompatible change detected!\n   "                    \
+            printf("Backwards incompatible change detected!\n   "                    \
                    "MEMBER_SIZE(struct wl_egl_window" #a_ver "::" #a_member ") != " \
                    "MEMBER_SIZE(struct wl_egl_window" #b_ver "::" #b_member ")\n"); \
             return 1;                                                               \
@@ -134,7 +134,7 @@
     do {                                                                            \
         if (sizeof(struct wl_egl_window ## a_ver) >                                 \
             sizeof(struct wl_egl_window ## b_ver)) {                                \
-            printf("Backards incompatible change detected!\n   "                    \
+            printf("Backwards incompatible change detected!\n   "                    \
                    "sizeof(struct wl_egl_window" #a_ver ") > "                      \
                    "sizeof(struct wl_egl_window" #b_ver ")\n");                     \
             return 1;                                                               \
@@ -145,7 +145,7 @@
     do {                                                                            \
         if (sizeof(struct wl_egl_window ## a_ver) !=                                \
             sizeof(struct wl_egl_window)) {                                         \
-            printf("Backards incompatible change detected!\n   "                    \
+            printf("Backwards incompatible change detected!\n   "                    \
                    "sizeof(struct wl_egl_window" #a_ver ") != "                     \
                    "sizeof(struct wl_egl_window)\n");                               \
             return 1;                                                               \
@@ -156,7 +156,7 @@
     do {                                                                            \
         if ((WL_EGL_WINDOW_VERSION ## a_ver) >=                                     \
             (WL_EGL_WINDOW_VERSION ## b_ver)) {                                     \
-            printf("Backards incompatible change detected!\n   "                    \
+            printf("Backwards incompatible change detected!\n   "                    \
                    "WL_EGL_WINDOW_VERSION" #a_ver " >= "                            \
                    "WL_EGL_WINDOW_VERSION" #b_ver "\n");                            \
             return 1;                                                               \
@@ -167,7 +167,7 @@
     do {                                                                            \
         if ((WL_EGL_WINDOW_VERSION ## a_ver) !=                                     \
             (WL_EGL_WINDOW_VERSION)) {                                              \
-            printf("Backards incompatible change detected!\n   "                    \
+            printf("Backwards incompatible change detected!\n   "                    \
                    "WL_EGL_WINDOW_VERSION" #a_ver " != "                            \
                    "WL_EGL_WINDOW_VERSION\n");                                      \
             return 1;                                                               \
diff --git a/m4/weston.m4 b/m4/weston.m4
new file mode 100644
index 0000000..636f9fb
--- /dev/null
+++ b/m4/weston.m4
@@ -0,0 +1,37 @@
+dnl
+dnl Copyright © 2016 Quentin “Sardem FF7” Glidic
+dnl
+dnl Permission is hereby granted, free of charge, to any person obtaining a
+dnl copy of this software and associated documentation files (the "Software"),
+dnl to deal in the Software without restriction, including without limitation
+dnl the rights to use, copy, modify, merge, publish, distribute, sublicense,
+dnl and/or sell copies of the Software, and to permit persons to whom the
+dnl Software is furnished to do so, subject to the following conditions:
+dnl
+dnl The above copyright notice and this permission notice (including the next
+dnl paragraph) shall be included in all copies or substantial portions of the
+dnl Software.
+dnl
+dnl THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+dnl IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+dnl FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+dnl THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+dnl LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+dnl FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+dnl DEALINGS IN THE SOFTWARE.
+dnl
+
+dnl WESTON_SEARCH_LIBS(PREFIX, search-libs, function, [action-if-found], [action-if-not-found], [other-libraries])
+dnl WESTON_SEARCH_LIBS is a wrapper around AC_SEARCH_LIBS with a little difference:
+dnl action-if-found is called even if no library is required
+AC_DEFUN([WESTON_SEARCH_LIBS], [
+	weston_save_LIBS=${LIBS}
+	AC_SEARCH_LIBS([$3], [$2], [$4], [$5], [$6])
+	AS_CASE([${ac_cv_search_][$3][}],
+		['none required'], [$4],
+		[no], [],
+		[$1][_LIBS=${ac_cv_search_][$3][}]
+	)
+	AC_SUBST([$1][_LIBS])
+	LIBS=${weston_save_LIBS}
+])
diff --git a/meson.build b/meson.build
new file mode 100644
index 0000000..11c35fa
--- /dev/null
+++ b/meson.build
@@ -0,0 +1,111 @@
+project(
+	'wayland', 'c', 'cpp',
+	version: '1.19.0',
+	license: 'MIT',
+	meson_version: '>= 0.52.1',
+	default_options: [
+		'warning_level=2',
+		'buildtype=debugoptimized'
+	]
+)
+
+config_h = configuration_data()
+config_h.set_quoted('PACKAGE', meson.project_name())
+config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
+
+compiler_flags = [
+	'-Wno-unused-parameter',
+	'-Wstrict-prototypes',
+	'-Wmissing-prototypes',
+	'-fvisibility=hidden',
+]
+
+cc = meson.get_compiler('c')
+add_project_arguments(
+	cc.get_supported_arguments(compiler_flags),
+	language: 'c'
+)
+
+foreach h: [ 'sys/prctl.h' ]
+	config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h))
+endforeach
+
+have_funcs = [
+	'accept4',
+	'mkostemp',
+	'posix_fallocate',
+	'prctl',
+	'memfd_create',
+	'strndup',
+]
+foreach f: have_funcs
+	config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f))
+endforeach
+
+if get_option('libraries')
+	ffi_dep = dependency('libffi')
+
+	decls = [
+		{ 'header': 'sys/signalfd.h', 'symbol': 'SFD_CLOEXEC' },
+		{ 'header': 'sys/timerfd.h', 'symbol': 'TFD_CLOEXEC' },
+		{ 'header': 'time.h', 'symbol': 'CLOCK_MONOTONIC' },
+	]
+
+	foreach d: decls
+		if not cc.has_header_symbol(d['header'], d['symbol'])
+			error('@0@ is needed to compile Wayland libraries'.format(d['symbol']))
+		endif
+	endforeach
+
+	rt_dep = []
+	if not cc.has_function('clock_gettime', prefix: '#include <time.h>')
+		rt_dep = cc.find_library('rt')
+		if not cc.has_function('clock_gettime', prefix: '#include <time.h>', dependencies: rt_dep)
+			error('clock_gettime not found')
+		endif
+	endif
+endif
+
+scanner_deps = [ dependency('expat') ]
+
+if get_option('dtd_validation')
+	scanner_deps += dependency('libxml-2.0')
+	config_h.set('HAVE_LIBXML', 1)
+endif
+
+configure_file(
+	output: 'config.h',
+	configuration: config_h,
+)
+
+pkgconfig = import('pkgconfig')
+
+wayland_protocol_xml = files('protocol/wayland.xml')
+
+root_inc = include_directories('.')
+protocol_inc = include_directories('protocol')
+src_inc = include_directories('src')
+
+subdir('src')
+
+if get_option('libraries')
+	subdir('cursor')
+	subdir('egl')
+	subdir('tests')
+	if get_option('documentation')
+		subdir('doc')
+	endif
+endif
+
+if get_option('scanner')
+	install_data([
+		'wayland-scanner.mk',
+		'protocol/wayland.xml',
+		'protocol/wayland.dtd',
+	])
+
+	install_data(
+		[ 'wayland-scanner.m4' ],
+		install_dir: join_paths(get_option('prefix'), get_option('datadir'), 'aclocal'),
+	)
+endif
diff --git a/meson_options.txt b/meson_options.txt
new file mode 100644
index 0000000..de588d1
--- /dev/null
+++ b/meson_options.txt
@@ -0,0 +1,20 @@
+option('libraries',
+  description: 'Compile Wayland libraries',
+  type: 'boolean',
+  value: 'true')
+option('scanner',
+  description: 'Compile wayland-scanner binary',
+  type: 'boolean',
+  value: 'true')
+option('documentation',
+  description: 'Build the documentation (requires Doxygen, dot, xmlto, xsltproc)',
+  type: 'boolean',
+  value: 'true')
+option('dtd_validation',
+  description: 'Validate the protocol DTD (requires libxml2)',
+  type: 'boolean',
+  value: 'true')
+option('icon_directory',
+  description: 'Location used to look for cursors (defaults to ${datadir}/icons if unset)',
+  type: 'string',
+  value: '')
diff --git a/patches/0001-client-Support-client-protocol-loggers.diff b/patches/0001-client-Support-client-protocol-loggers.diff
index 87dc19b..662f38b 100644
--- a/patches/0001-client-Support-client-protocol-loggers.diff
+++ b/patches/0001-client-Support-client-protocol-loggers.diff
@@ -24,10 +24,10 @@
 Signed-off-by: Lloyd Pique <lpique@google.com>
 
 diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
-index 03e781b..9b1df7f 100644
+index 0cd96e0..547ae04 100644
 --- a/src/wayland-client-core.h
 +++ b/src/wayland-client-core.h
-@@ -260,6 +260,32 @@ wl_display_read_events(struct wl_display *display);
+@@ -267,6 +267,32 @@ wl_display_read_events(struct wl_display *display);
  void
  wl_log_set_handler_client(wl_log_func_t handler);
  
@@ -61,10 +61,10 @@
  }
  #endif
 diff --git a/src/wayland-client.c b/src/wayland-client.c
-index b0805f1..eb1c299 100644
+index 21d4606..7f5a651 100644
 --- a/src/wayland-client.c
 +++ b/src/wayland-client.c
-@@ -106,12 +106,47 @@ struct wl_display {
+@@ -107,12 +107,47 @@ struct wl_display {
  	int reader_count;
  	uint32_t read_serial;
  	pthread_cond_t reader_cond;
@@ -112,17 +112,17 @@
  /**
   * This helper function wakes up all threads that are
   * waiting for display->reader_cond (i. e. when reading is done,
-@@ -743,8 +778,7 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
- 	if (closure == NULL)
- 		wl_abort("Error marshalling request: %s\n", strerror(errno));
+@@ -751,8 +786,7 @@ wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
+ 		goto err_unlock;
+ 	}
  
 -	if (debug_client)
 -		wl_closure_print(closure, &proxy->object, true);
 +	log_closure(closure, proxy, true);
  
- 	if (wl_closure_send(closure, proxy->display->connection))
- 		wl_abort("Error sending request: %s\n", strerror(errno));
-@@ -1046,6 +1080,7 @@ wl_display_connect_to_fd(int fd)
+ 	if (wl_closure_send(closure, proxy->display->connection)) {
+ 		wl_log("Error sending request: %s\n", strerror(errno));
+@@ -1056,6 +1090,7 @@ wl_display_connect_to_fd(int fd)
  	pthread_mutex_init(&display->mutex, NULL);
  	pthread_cond_init(&display->reader_cond, NULL);
  	display->reader_count = 0;
@@ -130,7 +130,7 @@
  
  	wl_map_insert_new(&display->objects, 0, NULL);
  
-@@ -1160,6 +1195,7 @@ wl_display_disconnect(struct wl_display *display)
+@@ -1177,6 +1212,7 @@ wl_display_disconnect(struct wl_display *display)
  	wl_map_release(&display->objects);
  	wl_event_queue_release(&display->default_queue);
  	wl_event_queue_release(&display->display_queue);
@@ -138,7 +138,7 @@
  	pthread_mutex_destroy(&display->mutex);
  	pthread_cond_destroy(&display->reader_cond);
  	close(display->fd);
-@@ -1417,16 +1453,12 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
+@@ -1439,16 +1475,12 @@ dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
  
  	pthread_mutex_unlock(&display->mutex);
  
@@ -157,7 +157,7 @@
  		wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
  				  &proxy->object, opcode, proxy->user_data);
  	}
-@@ -2194,3 +2226,60 @@ wl_log_set_handler_client(wl_log_func_t handler)
+@@ -2280,3 +2312,60 @@ wl_log_set_handler_client(wl_log_func_t handler)
  {
  	wl_log_handler = handler;
  }
diff --git a/patches/0003-client-server-Safe-casts-from-wl_object.diff b/patches/0003-client-server-Safe-casts-from-wl_object.diff
index 5dd4913..144daae 100644
--- a/patches/0003-client-server-Safe-casts-from-wl_object.diff
+++ b/patches/0003-client-server-Safe-casts-from-wl_object.diff
@@ -22,10 +22,10 @@
 Signed-off-by: Lloyd Pique <lpique@google.com>
 
 diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
-index 9b1df7f..919ca3b 100644
+index 547ae04..94c25e3 100644
 --- a/src/wayland-client-core.h
 +++ b/src/wayland-client-core.h
-@@ -197,6 +197,9 @@ wl_proxy_get_class(struct wl_proxy *proxy);
+@@ -204,6 +204,9 @@ wl_proxy_get_class(struct wl_proxy *proxy);
  void
  wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue);
  
@@ -36,10 +36,10 @@
  wl_display_connect(const char *name);
  
 diff --git a/src/wayland-client.c b/src/wayland-client.c
-index eb1c299..2e0aa33 100644
+index 7f5a651..74d4861 100644
 --- a/src/wayland-client.c
 +++ b/src/wayland-client.c
-@@ -2221,6 +2221,28 @@ wl_proxy_wrapper_destroy(void *proxy_wrapper)
+@@ -2307,6 +2307,28 @@ wl_proxy_wrapper_destroy(void *proxy_wrapper)
  	free(wrapper);
  }
  
@@ -69,10 +69,10 @@
  wl_log_set_handler_client(wl_log_func_t handler)
  {
 diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
-index 3e0272b..f824837 100644
+index 64d7169..e5f4e43 100644
 --- a/src/wayland-server-core.h
 +++ b/src/wayland-server-core.h
-@@ -581,6 +581,9 @@ struct wl_listener *
+@@ -587,6 +587,9 @@ struct wl_listener *
  wl_resource_get_destroy_listener(struct wl_resource *resource,
  				 wl_notify_func_t notify);
  
@@ -83,10 +83,10 @@
  	for (resource = 0, resource = wl_resource_from_link((list)->next);	\
  	     wl_resource_get_link(resource) != (list);				\
 diff --git a/src/wayland-server.c b/src/wayland-server.c
-index 19f6a76..7b91cf3 100644
+index d83bdec..ca0d98d 100644
 --- a/src/wayland-server.c
 +++ b/src/wayland-server.c
-@@ -855,6 +855,28 @@ wl_resource_get_class(struct wl_resource *resource)
+@@ -858,6 +858,28 @@ wl_resource_get_class(struct wl_resource *resource)
  	return resource->object.interface->name;
  }
  
diff --git a/protocol/generate-shm-formats.py b/protocol/generate-shm-formats.py
new file mode 100755
index 0000000..c56642e
--- /dev/null
+++ b/protocol/generate-shm-formats.py
@@ -0,0 +1,153 @@
+#!/usr/bin/env python3
+
+# This script synchronizes wayland.xml's wl_shm.format enum with drm_fourcc.h.
+# Invoke it to update wayland.xml, then manually check the changes applied.
+#
+# Requires Python 3, python-lxml, a C compiler and pkg-config.
+
+import os
+import subprocess
+import sys
+import tempfile
+# We need lxml instead of the standard library because we want
+# Element.sourceline
+from lxml import etree as ElementTree
+
+proto_dir = os.path.dirname(os.path.realpath(__file__))
+wayland_proto = proto_dir + "/wayland.xml"
+
+cc = os.getenv("CC", "cc")
+pkg_config = os.getenv("PKG_CONFIG", "pkg-config")
+
+# Find drm_fourcc.h
+version = subprocess.check_output([pkg_config, "libdrm",
+    "--modversion"]).decode().strip()
+cflags = subprocess.check_output([pkg_config, "libdrm",
+    "--cflags-only-I"]).decode().strip().split()
+libdrm_include = None
+for include_flag in cflags:
+    if not include_flag.startswith("-I"):
+        raise Exception("Expected one include dir for libdrm")
+    include_dir = include_flag[2:]
+    if include_dir.endswith("/libdrm"):
+        libdrm_include = include_dir
+        fourcc_include = libdrm_include + "/drm_fourcc.h"
+if libdrm_include == None:
+    raise Exception("Failed to find libdrm include dir")
+
+print("Using libdrm " + version, file=sys.stderr)
+
+def drm_format_to_wl(ident):
+    return ident.replace("DRM_FORMAT_", "").lower()
+
+# Collect DRM format constant names
+ident_list = []
+descriptions = {}
+prev_comment = None
+with open(fourcc_include) as input_file:
+    for l in input_file.readlines():
+        l = l.strip()
+
+        # Collect comments right before format definitions
+        if l.startswith("/*") and l.endswith("*/"):
+            prev_comment = l[2:-2]
+            continue
+        desc = prev_comment
+        prev_comment = None
+
+        # Recognize format definitions
+        parts = l.split()
+        if len(parts) < 3 or parts[0] != "#define":
+            continue
+        ident = parts[1]
+        if not ident.startswith("DRM_FORMAT_") or ident.startswith(
+                "DRM_FORMAT_MOD_"):
+            continue
+
+        ident_list.append(ident)
+
+        # Prefer in-line comments
+        if l.endswith("*/"):
+            desc = l[l.rfind("/*") + 2:-2]
+        if desc != None:
+            descriptions[drm_format_to_wl(ident)] = desc.strip()
+
+# Collect DRM format values
+idents = {}
+with tempfile.TemporaryDirectory() as work_dir:
+    c_file_name = work_dir + "/print-formats.c"
+    exe_file_name = work_dir + "/print-formats"
+
+    with open(c_file_name, "w+") as c_file:
+        c_file.write('#include <inttypes.h>\n')
+        c_file.write('#include <stdint.h>\n')
+        c_file.write('#include <stdio.h>\n')
+        c_file.write('#include <drm_fourcc.h>\n')
+        c_file.write('\n')
+        c_file.write('int main(void) {\n')
+        for ident in ident_list:
+            c_file.write('printf("0x%" PRIX64 "\\n", (uint64_t)' + ident + ');\n')
+        c_file.write('}\n')
+
+    subprocess.check_call([cc, "-Wall", "-Wextra", "-o", exe_file_name,
+        c_file_name] + cflags)
+    output = subprocess.check_output([exe_file_name]).decode().strip()
+    for i, val in enumerate(output.splitlines()):
+        idents[ident_list[i]] = val
+
+# We don't need those
+del idents["DRM_FORMAT_BIG_ENDIAN"]
+del idents["DRM_FORMAT_INVALID"]
+del idents["DRM_FORMAT_RESERVED"]
+
+# Convert from DRM constants to Wayland wl_shm.format entries
+formats = {}
+for ident, val in idents.items():
+    formats[drm_format_to_wl(ident)] = val.lower()
+# Special case for ARGB8888 and XRGB8888
+formats["argb8888"] = "0"
+formats["xrgb8888"] = "1"
+
+print("Loaded {} formats from drm_fourcc.h".format(len(formats)), file=sys.stderr)
+
+tree = ElementTree.parse("wayland.xml")
+root = tree.getroot()
+wl_shm_format = root.find("./interface[@name='wl_shm']/enum[@name='format']")
+if wl_shm_format == None:
+    raise Exception("wl_shm.format not found in wayland.xml")
+
+# Remove formats we already know about
+last_line = None
+for node in wl_shm_format:
+    if node.tag != "entry":
+        continue
+    fmt = node.attrib["name"]
+    val = node.attrib["value"]
+    if fmt not in formats:
+        raise Exception("Format present in wl_shm.formats but not in "
+            "drm_fourcc.h: " + fmt)
+    if val != formats[fmt]:
+        raise Exception("Format value in wl_shm.formats ({}) differs "
+            "from value in drm_fourcc.h ({}) for format {}"
+            .format(val, formats[fmt], fmt))
+    del formats[fmt]
+    last_line = node.sourceline
+if last_line == None:
+    raise Exception("Expected at least one existing wl_shm.format entry")
+
+print("Adding {} formats to wayland.xml...".format(len(formats)), file=sys.stderr)
+
+# Append new formats
+new_wayland_proto = wayland_proto + ".new"
+with open(new_wayland_proto, "w+") as output_file, \
+        open(wayland_proto) as input_file:
+    for i, l in enumerate(input_file.readlines()):
+        output_file.write(l)
+        if i + 1 == last_line:
+            for fmt, val in formats.items():
+                output_file.write('      <entry name="{}" value="{}"'
+                    .format(fmt, val))
+                if fmt in descriptions:
+                    output_file.write(' summary="{}"'.format(descriptions[fmt]))
+                output_file.write('/>\n')
+os.rename(new_wayland_proto, wayland_proto)
diff --git a/protocol/tests.xml b/protocol/tests.xml
index ea56ae4..22d80a1 100644
--- a/protocol/tests.xml
+++ b/protocol/tests.xml
@@ -43,8 +43,8 @@
     <!-- Version 2 additions -->
     <request name="conjoin" since="2">
       <description summary="register another fd passer with this one">
-        Tells this fd passer object about another one to send events
-        to for more complicated fd leak tests.
+	Tells this fd passer object about another one to send events
+	to for more complicated fd leak tests.
       </description>
       <arg name="passer" type="object" interface="fd_passer"/>
     </request>
diff --git a/protocol/wayland.xml b/protocol/wayland.xml
index b1c930d..471daf6 100644
--- a/protocol/wayland.xml
+++ b/protocol/wayland.xml
@@ -91,7 +91,7 @@
       <entry name="invalid_object" value="0"
 	     summary="server couldn't find object"/>
       <entry name="invalid_method" value="1"
-	     summary="method doesn't exist on the specified interface"/>
+	     summary="method doesn't exist on the specified interface or malformed request"/>
       <entry name="no_memory" value="2"
 	     summary="server is out of memory"/>
       <entry name="implementation" value="3"
@@ -101,10 +101,10 @@
     <event name="delete_id">
       <description summary="acknowledge object ID deletion">
 	This event is used internally by the object ID management
-	logic.  When a client deletes an object, the server will send
-	this event to acknowledge that it has seen the delete request.
-	When the client receives this event, it will know that it can
-	safely reuse the object ID.
+	logic. When a client deletes an object that it had created,
+	the server will send this event to acknowledge that it has
+	seen the delete request. When the client receives this event,
+	it will know that it can safely reuse the object ID.
       </description>
       <arg name="id" type="uint" summary="deleted object ID"/>
     </event>
@@ -293,10 +293,12 @@
 	formats are optional and may not be supported by the particular
 	renderer in use.
 
-	The drm format codes match the macros defined in drm_fourcc.h.
-	The formats actually supported by the compositor will be
-	reported by the format event.
+	The drm format codes match the macros defined in drm_fourcc.h, except
+	argb8888 and xrgb8888. The formats actually supported by the compositor
+	will be reported by the format event.
       </description>
+      <!-- Note to protocol writers: don't update this list manually, instead
+	   run the automated script that keeps it in sync with drm_fourcc.h. -->
       <entry name="argb8888" value="0" summary="32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian"/>
       <entry name="xrgb8888" value="1" summary="32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian"/>
       <entry name="c8" value="0x20203843" summary="8-bit color index format, [7:0] C"/>
@@ -355,6 +357,52 @@
       <entry name="yvu422" value="0x36315659" summary="3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes"/>
       <entry name="yuv444" value="0x34325559" summary="3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes"/>
       <entry name="yvu444" value="0x34325659" summary="3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes"/>
+      <entry name="r8" value="0x20203852" summary="[7:0] R"/>
+      <entry name="r16" value="0x20363152" summary="[15:0] R little endian"/>
+      <entry name="rg88" value="0x38384752" summary="[15:0] R:G 8:8 little endian"/>
+      <entry name="gr88" value="0x38385247" summary="[15:0] G:R 8:8 little endian"/>
+      <entry name="rg1616" value="0x32334752" summary="[31:0] R:G 16:16 little endian"/>
+      <entry name="gr1616" value="0x32335247" summary="[31:0] G:R 16:16 little endian"/>
+      <entry name="xrgb16161616f" value="0x48345258" summary="[63:0] x:R:G:B 16:16:16:16 little endian"/>
+      <entry name="xbgr16161616f" value="0x48344258" summary="[63:0] x:B:G:R 16:16:16:16 little endian"/>
+      <entry name="argb16161616f" value="0x48345241" summary="[63:0] A:R:G:B 16:16:16:16 little endian"/>
+      <entry name="abgr16161616f" value="0x48344241" summary="[63:0] A:B:G:R 16:16:16:16 little endian"/>
+      <entry name="xyuv8888" value="0x56555958" summary="[31:0] X:Y:Cb:Cr 8:8:8:8 little endian"/>
+      <entry name="vuy888" value="0x34325556" summary="[23:0] Cr:Cb:Y 8:8:8 little endian"/>
+      <entry name="vuy101010" value="0x30335556" summary="Y followed by U then V, 10:10:10. Non-linear modifier only"/>
+      <entry name="y210" value="0x30313259" summary="[63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 10:6:10:6:10:6:10:6 little endian per 2 Y pixels"/>
+      <entry name="y212" value="0x32313259" summary="[63:0] Cr0:0:Y1:0:Cb0:0:Y0:0 12:4:12:4:12:4:12:4 little endian per 2 Y pixels"/>
+      <entry name="y216" value="0x36313259" summary="[63:0] Cr0:Y1:Cb0:Y0 16:16:16:16 little endian per 2 Y pixels"/>
+      <entry name="y410" value="0x30313459" summary="[31:0] A:Cr:Y:Cb 2:10:10:10 little endian"/>
+      <entry name="y412" value="0x32313459" summary="[63:0] A:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian"/>
+      <entry name="y416" value="0x36313459" summary="[63:0] A:Cr:Y:Cb 16:16:16:16 little endian"/>
+      <entry name="xvyu2101010" value="0x30335658" summary="[31:0] X:Cr:Y:Cb 2:10:10:10 little endian"/>
+      <entry name="xvyu12_16161616" value="0x36335658" summary="[63:0] X:0:Cr:0:Y:0:Cb:0 12:4:12:4:12:4:12:4 little endian"/>
+      <entry name="xvyu16161616" value="0x38345658" summary="[63:0] X:Cr:Y:Cb 16:16:16:16 little endian"/>
+      <entry name="y0l0" value="0x304c3059" summary="[63:0]   A3:A2:Y3:0:Cr0:0:Y2:0:A1:A0:Y1:0:Cb0:0:Y0:0  1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian"/>
+      <entry name="x0l0" value="0x304c3058" summary="[63:0]   X3:X2:Y3:0:Cr0:0:Y2:0:X1:X0:Y1:0:Cb0:0:Y0:0  1:1:8:2:8:2:8:2:1:1:8:2:8:2:8:2 little endian"/>
+      <entry name="y0l2" value="0x324c3059" summary="[63:0]   A3:A2:Y3:Cr0:Y2:A1:A0:Y1:Cb0:Y0  1:1:10:10:10:1:1:10:10:10 little endian"/>
+      <entry name="x0l2" value="0x324c3058" summary="[63:0]   X3:X2:Y3:Cr0:Y2:X1:X0:Y1:Cb0:Y0  1:1:10:10:10:1:1:10:10:10 little endian"/>
+      <entry name="yuv420_8bit" value="0x38305559"/>
+      <entry name="yuv420_10bit" value="0x30315559"/>
+      <entry name="xrgb8888_a8" value="0x38415258"/>
+      <entry name="xbgr8888_a8" value="0x38414258"/>
+      <entry name="rgbx8888_a8" value="0x38415852"/>
+      <entry name="bgrx8888_a8" value="0x38415842"/>
+      <entry name="rgb888_a8" value="0x38413852"/>
+      <entry name="bgr888_a8" value="0x38413842"/>
+      <entry name="rgb565_a8" value="0x38413552"/>
+      <entry name="bgr565_a8" value="0x38413542"/>
+      <entry name="nv24" value="0x3432564e" summary="non-subsampled Cr:Cb plane"/>
+      <entry name="nv42" value="0x3234564e" summary="non-subsampled Cb:Cr plane"/>
+      <entry name="p210" value="0x30313250" summary="2x1 subsampled Cr:Cb plane, 10 bit per channel"/>
+      <entry name="p010" value="0x30313050" summary="2x2 subsampled Cr:Cb plane 10 bits per channel"/>
+      <entry name="p012" value="0x32313050" summary="2x2 subsampled Cr:Cb plane 12 bits per channel"/>
+      <entry name="p016" value="0x36313050" summary="2x2 subsampled Cr:Cb plane 16 bits per channel"/>
+      <entry name="axbxgxrx106106106106" value="0x30314241" summary="[63:0] A:x:B:x:G:x:R:x 10:6:10:6:10:6:10:6 little endian"/>
+      <entry name="nv15" value="0x3531564e" summary="2x2 subsampled Cr:Cb plane"/>
+      <entry name="q410" value="0x30313451"/>
+      <entry name="q401" value="0x31303451"/>
     </enum>
 
     <request name="create_pool">
@@ -509,6 +557,9 @@
 	this request after a NULL mime type has been set in
 	wl_data_offer.accept or no action was received through
 	wl_data_offer.action.
+
+	If wl_data_offer.finish request is received for a non drag and drop
+	operation, the invalid_finish protocol error is raised.
       </description>
     </request>
 
@@ -525,7 +576,7 @@
 
 	This request determines the final result of the drag-and-drop
 	operation. If the end result is that no action is accepted,
-	the drag source will receive wl_drag_source.cancelled.
+	the drag source will receive wl_data_source.cancelled.
 
 	The dnd_actions argument must contain only values expressed in the
 	wl_data_device_manager.dnd_actions enum, and the preferred_action
@@ -546,8 +597,10 @@
 	This request can only be made on drag-and-drop offers, a protocol error
 	will be raised otherwise.
       </description>
-      <arg name="dnd_actions" type="uint" summary="actions supported by the destination client"/>
-      <arg name="preferred_action" type="uint" summary="action preferred by the destination client"/>
+      <arg name="dnd_actions" type="uint" summary="actions supported by the destination client"
+	   enum="wl_data_device_manager.dnd_action"/>
+      <arg name="preferred_action" type="uint" summary="action preferred by the destination client"
+	   enum="wl_data_device_manager.dnd_action"/>
     </request>
 
     <event name="source_actions" since="3">
@@ -556,7 +609,8 @@
 	will be sent right after wl_data_device.enter, or anytime the source
 	side changes its offered actions through wl_data_source.set_actions.
       </description>
-      <arg name="source_actions" type="uint" summary="actions offered by the data source"/>
+      <arg name="source_actions" type="uint" summary="actions offered by the data source"
+	   enum="wl_data_device_manager.dnd_action"/>
     </event>
 
     <event name="action" since="3">
@@ -597,7 +651,8 @@
 	final wl_data_offer.set_actions and wl_data_offer.accept requests
 	must happen before the call to wl_data_offer.finish.
       </description>
-      <arg name="dnd_action" type="uint" summary="action selected by the compositor"/>
+      <arg name="dnd_action" type="uint" summary="action selected by the compositor"
+	   enum="wl_data_device_manager.dnd_action"/>
     </event>
   </interface>
 
@@ -694,7 +749,8 @@
 	wl_data_device.start_drag. Attempting to use the source other than
 	for drag-and-drop will raise a protocol error.
       </description>
-      <arg name="dnd_actions" type="uint" summary="actions supported by the data source"/>
+      <arg name="dnd_actions" type="uint" summary="actions supported by the data source"
+	   enum="wl_data_device_manager.dnd_action"/>
     </request>
 
     <event name="dnd_drop_performed" since="3">
@@ -750,7 +806,8 @@
 	Clients can trigger cursor surface changes from this point, so
 	they reflect the current action.
       </description>
-      <arg name="dnd_action" type="uint" summary="action selected by the compositor"/>
+      <arg name="dnd_action" type="uint" summary="action selected by the compositor"
+	   enum="wl_data_device_manager.dnd_action"/>
     </event>
   </interface>
 
@@ -776,7 +833,8 @@
 	for the eventual data transfer. If source is NULL, enter, leave
 	and motion events are sent only to the client that initiated the
 	drag and the client is expected to handle the data passing
-	internally.
+	internally. If source is destroyed, the drag-and-drop session will be
+	cancelled.
 
 	The origin surface is the surface where the drag originates and
 	the client must have an active implicit grab that matches the
@@ -1276,8 +1334,10 @@
 
   <interface name="wl_surface" version="4">
     <description summary="an onscreen surface">
-      A surface is a rectangular area that is displayed on the screen.
-      It has a location, size and pixel contents.
+      A surface is a rectangular area that may be displayed on zero
+      or more outputs, and shown any number of times at the compositor's
+      discretion. They can present wl_buffers, receive user input, and
+      define a local coordinate system.
 
       The size of a surface (and relative positions on it) is described
       in surface-local coordinates, which may differ from the buffer
@@ -1323,6 +1383,7 @@
       </description>
       <entry name="invalid_scale" value="0" summary="buffer scale value is invalid"/>
       <entry name="invalid_transform" value="1" summary="buffer transform value is invalid"/>
+      <entry name="invalid_size" value="2" summary="buffer size is invalid"/>
     </enum>
 
     <request name="destroy" type="destructor">
@@ -1337,8 +1398,9 @@
 
 	The new size of the surface is calculated based on the buffer
 	size transformed by the inverse buffer_transform and the
-	inverse buffer_scale. This means that the supplied buffer
-	must be an integer multiple of the buffer_scale.
+	inverse buffer_scale. This means that at commit time the supplied
+	buffer size must be an integer multiple of the buffer_scale. If
+	that's not the case, an invalid_size error is sent.
 
 	The x and y arguments specify the location of the new pending
 	buffer's upper left corner, relative to the current buffer's upper
@@ -1365,6 +1427,12 @@
 	will not receive a release event, and is not used by the
 	compositor.
 
+	If a pending wl_buffer has been committed to more than one wl_surface,
+	the delivery of wl_buffer.release events becomes undefined. A well
+	behaved client should not rely on wl_buffer.release events in this
+	case. Alternatively, a client could create multiple wl_buffer objects
+	from the same backing storage or use wp_linux_buffer_release.
+
 	Destroying the wl_buffer after wl_buffer.release does not change
 	the surface contents. However, if the client destroys the
 	wl_buffer before receiving the wl_buffer.release event, the surface
@@ -1545,6 +1613,12 @@
 	This is emitted whenever a surface's creation, movement, or resizing
 	results in it no longer having any part of it within the scanout region
 	of an output.
+
+	Clients should not use the number of outputs the surface is on for frame
+	throttling purposes. The surface might be hidden even if no leave event
+	has been sent, and the compositor might expect new surface content
+	updates even if no enter event has been sent. The frame event should be
+	used instead.
       </description>
       <arg name="output" type="object" interface="wl_output" summary="output left by the surface"/>
     </event>
@@ -1680,6 +1754,14 @@
       <entry name="touch" value="4" summary="the seat has touch devices"/>
     </enum>
 
+    <enum name="error">
+      <description summary="wl_seat error values">
+	These errors can be emitted in response to wl_seat requests.
+      </description>
+      <entry name="missing_capability" value="0"
+	     summary="get_pointer, get_keyboard or get_touch called on seat without the matching capability"/>
+    </enum>
+
     <event name="capabilities">
       <description summary="seat capabilities changed">
 	This is emitted whenever a seat gains or loses the pointer,
@@ -1718,7 +1800,8 @@
 	This request only takes effect if the seat has the pointer
 	capability, or has had the pointer capability in the past.
 	It is a protocol violation to issue this request on a seat that has
-	never had the pointer capability.
+	never had the pointer capability. The missing_capability error will
+	be sent in this case.
       </description>
       <arg name="id" type="new_id" interface="wl_pointer" summary="seat pointer"/>
     </request>
@@ -1731,7 +1814,8 @@
 	This request only takes effect if the seat has the keyboard
 	capability, or has had the keyboard capability in the past.
 	It is a protocol violation to issue this request on a seat that has
-	never had the keyboard capability.
+	never had the keyboard capability. The missing_capability error will
+	be sent in this case.
       </description>
       <arg name="id" type="new_id" interface="wl_keyboard" summary="seat keyboard"/>
     </request>
@@ -1744,7 +1828,8 @@
 	This request only takes effect if the seat has the touch
 	capability, or has had the touch capability in the past.
 	It is a protocol violation to issue this request on a seat that has
-	never had the touch capability.
+	never had the touch capability. The missing_capability error will
+	be sent in this case.
       </description>
       <arg name="id" type="new_id" interface="wl_touch" summary="seat touch interface"/>
     </request>
@@ -2128,6 +2213,9 @@
       <description summary="enter event">
 	Notification that this seat's keyboard focus is on a certain
 	surface.
+
+	The compositor must send the wl_keyboard.modifiers event after this
+	event.
       </description>
       <arg name="serial" type="uint" summary="serial number of the enter event"/>
       <arg name="surface" type="object" interface="wl_surface" summary="surface gaining keyboard focus"/>
@@ -2141,6 +2229,9 @@
 
 	The leave notification is sent before the enter notification
 	for the new focus.
+
+	After this event client must assume that all keys, including modifiers,
+	are lifted and also it must stop key repeating if there's some going on.
       </description>
       <arg name="serial" type="uint" summary="serial number of the leave event"/>
       <arg name="surface" type="object" interface="wl_surface" summary="surface that lost keyboard focus"/>
@@ -2159,6 +2250,12 @@
 	A key was pressed or released.
 	The time argument is a timestamp with millisecond
 	granularity, with an undefined base.
+
+	The key is a platform-specific key code that can be interpreted
+	by feeding it to the keyboard mapping (see the keymap event).
+
+	If this event produces a change in modifiers, then the resulting
+	wl_keyboard.modifiers event must be sent after this event.
       </description>
       <arg name="serial" type="uint" summary="serial number of the key event"/>
       <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
@@ -2454,6 +2551,10 @@
 	current.  In other words, the current mode is always the last
 	mode that was received with the current flag set.
 
+	Non-current modes are deprecated. A compositor can decide to only
+	advertise the current mode and never send other modes. Clients
+	should not rely on non-current modes.
+
 	The size of a mode is given in physical hardware units of
 	the output device. This is not necessarily the same as
 	the output size in the global compositor space. For instance,
@@ -2462,6 +2563,9 @@
 	willing to retrieve the output size in the global compositor
 	space should use xdg_output.logical_size instead.
 
+	The vertical refresh rate can be set to zero if it doesn't make
+	sense for this output (e.g. for virtual outputs).
+
 	Clients should not use the refresh rate to schedule frames. Instead,
 	they should use the wl_surface.frame event or the presentation-time
 	protocol.
@@ -2643,7 +2747,7 @@
       wl_surface state directly. A sub-surface is initially in the
       synchronized mode.
 
-      Sub-surfaces have also other kind of state, which is managed by
+      Sub-surfaces also have another kind of state, which is managed by
       wl_subsurface requests, as opposed to wl_surface requests. This
       state includes the sub-surface position relative to the parent
       surface (wl_subsurface.set_position), and the stacking order of
diff --git a/releasing.txt b/releasing.txt
new file mode 100644
index 0000000..1481f7c
--- /dev/null
+++ b/releasing.txt
@@ -0,0 +1,78 @@
+To make a release of Wayland, follow these steps.
+
+  0.  Verify the test suites and codebase checks pass.  All of the
+      tests should either pass or skip.
+
+      $ make check
+
+  1.  Update the first stanza of configure.ac to the intended version.
+
+      Then commit your changes:
+
+      $ export RELEASE_NUMBER="x.y.z"
+      $ export RELEASE_NAME="[alpha|beta|RC1|RC2|official|point]"
+      $ git status
+      $ git commit configure.ac -m "configure.ac: bump to version $RELEASE_NUMBER for the $RELEASE_NAME release"
+      $ git push
+
+  2.  Run the release.sh script to generate the tarballs, sign and
+      upload them, and generate a release announcement template.
+      This script can be obtained from X.org's modular package:
+
+        http://cgit.freedesktop.org/xorg/util/modular/tree/release.sh
+
+      The script supports a --dry-run option to test it without actually
+      doing a release.  If the script fails on the distcheck step due to
+      a testsuite error that can't be fixed for some reason, you can
+      skip testsuite by specifying the --dist argument.  Pass --help to
+      see other supported options.
+
+      $ release.sh .
+
+      For Wayland official and point releases, also publish the publican
+      documentation to wayland.freedesktop.org:
+
+      $ ./publish-doc
+
+  3.  Compose the release announcements.  The script will generate
+      *.x.y.z.announce files with a list of changes and tags.  Prepend
+      it with a human-readable listing of the most notable changes.
+      For x.y.0 releases, indicate the schedule for the x.y+1.0
+      release.
+
+  4.  PGP sign the release announcements and send them to
+      wayland-devel@lists.freedesktop.org
+
+  5.  Update releases.html in wayland-web with links to tarballs and
+      the release email URL.
+
+      The wl_register_release script in wayland-web will generate an HTML
+      snippet that can be pasted into releases.html (or e.g. in emacs
+      insert it via "C-u M-! scripts/wl_register_release x.y.z") and
+      customized.
+
+      Once satisfied:
+
+      $ git commit ./releases.html -m "releases: Add ${RELEASE_NUMBER} release"
+      $ git push
+      $ ./deploy
+
+For x.y.0 releases, also create the release series x.y branch.  The x.y
+branch is for bug fixes and conservative changes to the x.y.0 release,
+and is where we create x.y.z releases from.  Creating the x.y branch
+opens up master for new development and lets new development move on.
+We've done this both after the x.y.0 release (to focus development on
+bug fixing for the x.y.1 release for a little longer) or before the
+x.y.0 release (like we did with the 1.5.0 release, to unblock master
+development early).
+
+    $ git branch x.y [sha]
+    $ git push origin x.y
+
+The master branch's configure.ac version should always be (at least)
+x.y.90, with x.y being the most recent stable branch.  The stable
+branch's configure.ac version is just whatever was most recently
+released from that branch.
+
+For stable branches, we commit fixes to master first, then cherry-pick
+them back to the stable branch.
diff --git a/src/connection.c b/src/connection.c
index 7fba999..d0c7d9f 100644
--- a/src/connection.c
+++ b/src/connection.c
@@ -644,8 +644,12 @@
 		case 'h':
 			fd = args[i].h;
 			dup_fd = wl_os_dupfd_cloexec(fd, 0);
-			if (dup_fd < 0)
-				wl_abort("dup failed: %s\n", strerror(errno));
+			if (dup_fd < 0) {
+				wl_closure_destroy(closure);
+				wl_log("error marshalling arguments for %s: dup failed: %s\n",
+				       message->name, strerror(errno));
+				return NULL;
+			}
 			closure->args[i].h = dup_fd;
 			break;
 		default:
diff --git a/src/event-loop.c b/src/event-loop.c
index eb2dce6..339ff19 100644
--- a/src/event-loop.c
+++ b/src/event-loop.c
@@ -23,6 +23,7 @@
  * SOFTWARE.
  */
 
+#include <assert.h>
 #include <stddef.h>
 #include <stdio.h>
 #include <errno.h>
@@ -45,19 +46,11 @@
 
 /** \cond INTERNAL */
 
-struct wl_event_loop {
-	int epoll_fd;
-	struct wl_list check_list;
-	struct wl_list idle_list;
-	struct wl_list destroy_list;
+#define TIMER_REMOVED -2
 
-	struct wl_signal destroy_signal;
-};
-
-struct wl_event_source_interface {
-	int (*dispatch)(struct wl_event_source *source,
-			struct epoll_event *ep);
-};
+struct wl_event_loop;
+struct wl_event_source_interface;
+struct wl_event_source_timer;
 
 struct wl_event_source {
 	struct wl_event_source_interface *interface;
@@ -67,6 +60,30 @@
 	int fd;
 };
 
+struct wl_timer_heap {
+	struct wl_event_source base;
+	/* pointers to the user-visible event sources */
+	struct wl_event_source_timer **data;
+	int space, active, count;
+};
+
+struct wl_event_loop {
+	int epoll_fd;
+	struct wl_list check_list;
+	struct wl_list idle_list;
+	struct wl_list destroy_list;
+
+	struct wl_signal destroy_signal;
+
+	struct wl_timer_heap timers;
+};
+
+struct wl_event_source_interface {
+	int (*dispatch)(struct wl_event_source *source,
+			struct epoll_event *ep);
+};
+
+
 struct wl_event_source_fd {
 	struct wl_event_source base;
 	wl_event_loop_fd_func_t func;
@@ -215,31 +232,319 @@
 struct wl_event_source_timer {
 	struct wl_event_source base;
 	wl_event_loop_timer_func_t func;
+	struct wl_event_source_timer *next_due;
+	struct timespec deadline;
+	int heap_idx;
 };
 
-/** \endcond */
+static int
+noop_dispatch(struct wl_event_source *source,
+	      struct epoll_event *ep) {
+	return 0;
+}
+
+struct wl_event_source_interface timer_heap_source_interface = {
+	noop_dispatch,
+};
+
+static bool
+time_lt(struct timespec ta, struct timespec tb)
+{
+	if (ta.tv_sec != tb.tv_sec) {
+		return ta.tv_sec < tb.tv_sec;
+	}
+	return ta.tv_nsec < tb.tv_nsec;
+}
+
+static int
+set_timer(int timerfd, struct timespec deadline) {
+	struct itimerspec its;
+
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 0;
+	its.it_value = deadline;
+	return timerfd_settime(timerfd, TFD_TIMER_ABSTIME, &its, NULL);
+}
+
+static int
+clear_timer(int timerfd)
+{
+	struct itimerspec its;
+
+	its.it_interval.tv_sec = 0;
+	its.it_interval.tv_nsec = 0;
+	its.it_value.tv_sec = 0;
+	its.it_value.tv_nsec = 0;
+	return timerfd_settime(timerfd, 0, &its, NULL);
+}
+
+static void
+wl_timer_heap_init(struct wl_timer_heap *timers, struct wl_event_loop *loop)
+{
+	timers->base.fd = -1;
+	timers->base.data = NULL;
+	wl_list_init(&timers->base.link);
+	timers->base.interface = &timer_heap_source_interface;
+	timers->base.loop = loop;
+
+	loop->timers.data = NULL;
+	loop->timers.active = 0;
+	loop->timers.space = 0;
+	loop->timers.count = 0;
+}
+
+static void
+wl_timer_heap_release(struct wl_timer_heap *timers)
+{
+	if (timers->base.fd != -1) {
+		close(timers->base.fd);
+	}
+	free(timers->data);
+}
+
+static int
+wl_timer_heap_ensure_timerfd(struct wl_timer_heap *timers)
+{
+	struct epoll_event ep;
+	int timer_fd;
+
+	if (timers->base.fd != -1)
+		return 0;
+
+	memset(&ep, 0, sizeof ep);
+	ep.events = EPOLLIN;
+	ep.data.ptr = timers;
+
+	timer_fd = timerfd_create(CLOCK_MONOTONIC,
+				  TFD_CLOEXEC | TFD_NONBLOCK);
+	if (timer_fd < 0)
+		return -1;
+
+	if (epoll_ctl(timers->base.loop->epoll_fd,
+		      EPOLL_CTL_ADD, timer_fd, &ep) < 0) {
+		close(timer_fd);
+		return -1;
+	}
+
+	timers->base.fd = timer_fd;
+	return 0;
+}
+
+static int
+wl_timer_heap_reserve(struct wl_timer_heap *timers)
+{
+	struct wl_event_source_timer **n;
+	int new_space;
+
+	if (timers->count + 1 > timers->space) {
+		new_space = timers->space >= 8 ? timers->space * 2 : 8;
+		n = realloc(timers->data, (size_t)new_space * sizeof(*n));
+		if (!n) {
+			wl_log("Allocation failure when expanding timer list");
+			return -1;
+		}
+		timers->data = n;
+		timers->space = new_space;
+	}
+
+	timers->count++;
+	return 0;
+}
+
+static void
+wl_timer_heap_unreserve(struct wl_timer_heap *timers)
+{
+	struct wl_event_source_timer **n;
+
+	timers->count--;
+
+	if (timers->space >= 16 && timers->space >= 4 * timers->count) {
+		n = realloc(timers->data, (size_t)timers->space / 2 * sizeof(*n));
+		if (!n) {
+			wl_log("Reallocation failure when shrinking timer list");
+			return;
+		}
+		timers->data = n;
+		timers->space = timers->space / 2;
+	}
+}
+
+static int
+heap_set(struct wl_event_source_timer **data,
+	 struct wl_event_source_timer *a,
+	 int idx)
+{
+	int tmp;
+
+	tmp = a->heap_idx;
+	a->heap_idx = idx;
+	data[a->heap_idx] = a;
+
+	return tmp;
+}
+
+static void
+heap_sift_down(struct wl_event_source_timer **data,
+	       int num_active,
+	       struct wl_event_source_timer *source)
+{
+	struct wl_event_source_timer *child, *other_child;
+	int cursor_idx;
+	struct timespec key;
+
+	cursor_idx = source->heap_idx;
+	key = source->deadline;
+	while (1) {
+		int lchild_idx = cursor_idx * 2 + 1;
+
+		if (lchild_idx >= num_active) {
+			break;
+		}
+
+		child = data[lchild_idx];
+		if (lchild_idx + 1 < num_active) {
+			other_child = data[lchild_idx + 1];
+			if (time_lt(other_child->deadline, child->deadline))
+				child = other_child;
+		}
+
+		if (time_lt(child->deadline, key))
+			cursor_idx = heap_set(data, child, cursor_idx);
+		else
+			break;
+	}
+
+	heap_set(data, source, cursor_idx);
+}
+
+static void
+heap_sift_up(struct wl_event_source_timer **data,
+	     struct wl_event_source_timer *source)
+{
+	int cursor_idx;
+	struct timespec key;
+
+	cursor_idx = source->heap_idx;
+	key = source->deadline;
+	while (cursor_idx > 0) {
+		struct wl_event_source_timer *parent =
+			data[(cursor_idx - 1) / 2];
+
+		if (time_lt(key, parent->deadline))
+			cursor_idx = heap_set(data, parent, cursor_idx);
+		else
+			break;
+	}
+	heap_set(data, source, cursor_idx);
+}
+
+/* requires timer be armed */
+static void
+wl_timer_heap_disarm(struct wl_timer_heap *timers,
+		     struct wl_event_source_timer *source)
+{
+	struct wl_event_source_timer *last_end_evt;
+	int old_source_idx;
+
+	assert(source->heap_idx >= 0);
+
+	old_source_idx = source->heap_idx;
+	source->heap_idx = -1;
+	source->deadline.tv_sec = 0;
+	source->deadline.tv_nsec = 0;
+
+	last_end_evt = timers->data[timers->active - 1];
+	timers->data[timers->active - 1] = NULL;
+	timers->active--;
+
+	if (old_source_idx == timers->active)
+		return;
+
+	timers->data[old_source_idx] = last_end_evt;
+	last_end_evt->heap_idx = old_source_idx;
+
+	/* Move the displaced (active) element to its proper place.
+	 * Only one of sift-down and sift-up will have any effect */
+	heap_sift_down(timers->data, timers->active, last_end_evt);
+	heap_sift_up(timers->data, last_end_evt);
+}
+
+/* requires timer be disarmed */
+static void
+wl_timer_heap_arm(struct wl_timer_heap *timers,
+		  struct wl_event_source_timer *source,
+		  struct timespec deadline)
+{
+	assert(source->heap_idx == -1);
+
+	source->deadline = deadline;
+	timers->data[timers->active] = source;
+	source->heap_idx = timers->active;
+	timers->active++;
+	heap_sift_up(timers->data, source);
+}
+
+
+static int
+wl_timer_heap_dispatch(struct wl_timer_heap *timers)
+{
+	struct timespec now;
+	struct wl_event_source_timer *root;
+	struct wl_event_source_timer *list_cursor = NULL, *list_tail = NULL;
+
+	clock_gettime(CLOCK_MONOTONIC, &now);
+
+	while (timers->active > 0) {
+		root = timers->data[0];
+		if (time_lt(now, root->deadline))
+			break;
+
+		wl_timer_heap_disarm(timers, root);
+
+		if (list_cursor == NULL)
+			list_cursor = root;
+		else
+			list_tail->next_due = root;
+		list_tail = root;
+	}
+	if (list_tail)
+		list_tail->next_due = NULL;
+
+	if (timers->active > 0) {
+		if (set_timer(timers->base.fd, timers->data[0]->deadline) < 0)
+			return -1;
+	} else {
+		if (clear_timer(timers->base.fd) < 0)
+			return -1;
+	}
+
+	/* Execute precisely the functions for events before `now`, in order.
+	 * Because wl_event_loop_dispatch ignores return codes, do the same
+	 * here as well */
+	for (; list_cursor; list_cursor = list_cursor->next_due) {
+		if (list_cursor->base.fd != TIMER_REMOVED)
+			list_cursor->func(list_cursor->base.data);
+	}
+
+	return 0;
+}
 
 static int
 wl_event_source_timer_dispatch(struct wl_event_source *source,
 			       struct epoll_event *ep)
 {
-	struct wl_event_source_timer *timer_source =
-		(struct wl_event_source_timer *) source;
-	uint64_t expires;
-	int len;
+	struct wl_event_source_timer *timer;
 
-	len = read(source->fd, &expires, sizeof expires);
-	if (!(len == -1 && errno == EAGAIN) && len != sizeof expires)
-		/* Is there anything we can do here?  Will this ever happen? */
-		wl_log("timerfd read error: %m\n");
-
-	return timer_source->func(timer_source->base.data);
+	timer = wl_container_of(source, timer, base);
+	return timer->func(timer->base.data);
 }
 
 struct wl_event_source_interface timer_source_interface = {
 	wl_event_source_timer_dispatch,
 };
 
+/** \endcond */
+
 /** Create a timer event source
  *
  * \param loop The event loop that will process the new source.
@@ -260,16 +565,30 @@
 {
 	struct wl_event_source_timer *source;
 
+	if (wl_timer_heap_ensure_timerfd(&loop->timers) < 0)
+		return NULL;
+
 	source = malloc(sizeof *source);
 	if (source == NULL)
 		return NULL;
 
 	source->base.interface = &timer_source_interface;
-	source->base.fd = timerfd_create(CLOCK_MONOTONIC,
-					 TFD_CLOEXEC | TFD_NONBLOCK);
+	source->base.fd = -1;
 	source->func = func;
+	source->base.loop = loop;
+	source->base.data = data;
+	wl_list_init(&source->base.link);
+	source->next_due = NULL;
+	source->deadline.tv_sec = 0;
+	source->deadline.tv_nsec = 0;
+	source->heap_idx = -1;
 
-	return add_source(loop, &source->base, WL_EVENT_READABLE, data);
+	if (wl_timer_heap_reserve(&loop->timers) < 0) {
+		free(source);
+		return NULL;
+	}
+
+	return &source->base;
 }
 
 /** Arm or disarm a timer
@@ -291,14 +610,50 @@
 WL_EXPORT int
 wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
 {
-	struct itimerspec its;
+	struct wl_event_source_timer *tsource =
+		wl_container_of(source, tsource, base);
+	struct wl_timer_heap *timers = &tsource->base.loop->timers;
 
-	its.it_interval.tv_sec = 0;
-	its.it_interval.tv_nsec = 0;
-	its.it_value.tv_sec = ms_delay / 1000;
-	its.it_value.tv_nsec = (ms_delay % 1000) * 1000 * 1000;
-	if (timerfd_settime(source->fd, 0, &its, NULL) < 0)
-		return -1;
+	if (ms_delay > 0) {
+		struct timespec deadline;
+
+		clock_gettime(CLOCK_MONOTONIC, &deadline);
+
+		deadline.tv_nsec += (ms_delay % 1000) * 1000000L;
+		deadline.tv_sec += ms_delay / 1000;
+		if (deadline.tv_nsec >= 1000000000L) {
+			deadline.tv_nsec -= 1000000000L;
+			deadline.tv_sec += 1;
+		}
+
+		if (tsource->heap_idx == -1) {
+			wl_timer_heap_arm(timers, tsource, deadline);
+		} else if (time_lt(deadline, tsource->deadline)) {
+			tsource->deadline = deadline;
+			heap_sift_up(timers->data, tsource);
+		} else {
+			tsource->deadline = deadline;
+			heap_sift_down(timers->data, timers->active, tsource);
+		}
+
+		if (tsource->heap_idx == 0) {
+			/* Only update the timerfd if the new deadline is
+			 * the earliest */
+			if (set_timer(timers->base.fd, deadline) < 0)
+				return -1;
+		}
+	} else {
+		if (tsource->heap_idx == -1)
+			return 0;
+		wl_timer_heap_disarm(timers, tsource);
+
+		if (timers->active == 0) {
+			/* Only update the timerfd if this was the last
+			 * active timer */
+			if (clear_timer(timers->base.fd) < 0)
+				return -1;
+		}
+	}
 
 	return 0;
 }
@@ -325,7 +680,7 @@
 	len = read(source->fd, &signal_info, sizeof signal_info);
 	if (!(len == -1 && errno == EAGAIN) && len != sizeof signal_info)
 		/* Is there anything we can do here?  Will this ever happen? */
-		wl_log("signalfd read error: %m\n");
+		wl_log("signalfd read error: %s\n", strerror(errno));
 
 	return signal_source->func(signal_source->signal_number,
 				   signal_source->base.data);
@@ -483,6 +838,17 @@
 		source->fd = -1;
 	}
 
+	if (source->interface == &timer_source_interface &&
+	    source->fd != TIMER_REMOVED) {
+		/* Disarm the timer (and the loop's timerfd, if necessary),
+		 * before removing its space in the loop timer heap */
+		wl_event_source_timer_update(source, 0);
+		wl_timer_heap_unreserve(&loop->timers);
+		/* Set the fd field to to indicate that the timer should NOT
+		 * be dispatched in `wl_event_loop_dispatch` */
+		source->fd = TIMER_REMOVED;
+	}
+
 	wl_list_remove(&source->link);
 	wl_list_insert(&loop->destroy_list, &source->link);
 
@@ -534,6 +900,8 @@
 
 	wl_signal_init(&loop->destroy_signal);
 
+	wl_timer_heap_init(&loop->timers, loop);
+
 	return loop;
 }
 
@@ -556,6 +924,7 @@
 	wl_signal_emit(&loop->destroy_signal, loop);
 
 	wl_event_loop_process_destroy_list(loop);
+	wl_timer_heap_release(&loop->timers);
 	close(loop->epoll_fd);
 	free(loop);
 }
@@ -595,8 +964,8 @@
 	struct wl_event_source_idle *source;
 
 	while (!wl_list_empty(&loop->idle_list)) {
-		source = container_of(loop->idle_list.next,
-				      struct wl_event_source_idle, base.link);
+		source = wl_container_of(loop->idle_list.next,
+					 source, base.link);
 		source->func(source->base.data);
 		wl_event_source_remove(&source->base);
 	}
@@ -606,7 +975,7 @@
  *
  * \param loop The event loop whose sources to wait for.
  * \param timeout The polling timeout in milliseconds.
- * \return 0 for success, -1 for polling error.
+ * \return 0 for success, -1 for polling (or timer update) error.
  *
  * All the associated event sources are polled. This function blocks until
  * any event source delivers an event (idle sources excluded), or the timeout
@@ -628,6 +997,7 @@
 	struct epoll_event ep[32];
 	struct wl_event_source *source;
 	int i, count;
+	bool has_timers = false;
 
 	wl_event_loop_dispatch_idle(loop);
 
@@ -637,6 +1007,22 @@
 
 	for (i = 0; i < count; i++) {
 		source = ep[i].data.ptr;
+		if (source == &loop->timers.base)
+			has_timers = true;
+	}
+
+	if (has_timers) {
+		/* Dispatch timer sources before non-timer sources, so that
+		 * the non-timer sources can not cancel (by calling
+		 * `wl_event_source_timer_update`) the dispatching of the timers
+		 * (Note that timer sources also can't cancel pending non-timer
+		 * sources, since epoll_wait has already been called) */
+		if (wl_timer_heap_dispatch(&loop->timers) < 0)
+			return -1;
+	}
+
+	for (i = 0; i < count; i++) {
+		source = ep[i].data.ptr;
 		if (source->fd != -1)
 			source->interface->dispatch(source, &ep[i]);
 	}
diff --git a/src/meson.build b/src/meson.build
new file mode 100644
index 0000000..d91c503
--- /dev/null
+++ b/src/meson.build
@@ -0,0 +1,235 @@
+wayland_version = meson.project_version().split('.')
+wayland_version_h = configuration_data()
+wayland_version_h.set('WAYLAND_VERSION', meson.project_version())
+wayland_version_h.set('WAYLAND_VERSION_MAJOR', wayland_version[0].to_int())
+wayland_version_h.set('WAYLAND_VERSION_MINOR', wayland_version[1].to_int())
+wayland_version_h.set('WAYLAND_VERSION_MICRO', wayland_version[2].to_int())
+configure_file(
+	input: 'wayland-version.h.in',
+	output: 'wayland-version.h',
+	configuration: wayland_version_h,
+	install: get_option('libraries'),
+	install_dir: join_paths(get_option('prefix'), get_option('includedir'))
+)
+
+
+wayland_util = static_library(
+	'wayland-util',
+	sources: 'wayland-util.c'
+)
+
+wayland_util_dep = declare_dependency(
+	link_with: wayland_util,
+	include_directories: include_directories('.')
+)
+
+if get_option('scanner')
+	# wayland-scanner
+
+	configure_file(
+		input: '../protocol/wayland.dtd',
+		output: 'wayland.dtd.embed',
+		copy: true
+	)
+
+	wayland_scanner_sources = [ 'scanner.c', 'dtddata.S' ]
+	wayland_scanner_includes = [ root_inc, protocol_inc ]
+
+	wayland_scanner = executable(
+		'wayland-scanner',
+		wayland_scanner_sources,
+		c_args: [ '-include', 'config.h' ],
+		include_directories: wayland_scanner_includes,
+		dependencies: [ scanner_deps, wayland_util_dep, ],
+		install: true
+	)
+
+	pkgconfig.generate(
+		name: 'Wayland Scanner',
+		description: 'Wayland scanner',
+		version: meson.project_version(),
+		variables: [
+			'datarootdir=' + join_paths('${prefix}', get_option('datadir')),
+			'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name()),
+			'bindir=' + join_paths('${prefix}', get_option('bindir')),
+			'wayland_scanner=${bindir}/wayland-scanner'
+		],
+		filebase: 'wayland-scanner'
+	)
+endif
+
+if meson.is_cross_build() or not get_option('scanner')
+	scanner_dep = dependency('wayland-scanner', native: true, version: meson.project_version())
+	wayland_scanner_for_build = find_program(scanner_dep.get_pkgconfig_variable('wayland_scanner'))
+else
+	wayland_scanner_for_build = wayland_scanner
+endif
+
+if get_option('libraries')
+	# wayland libraries
+
+	mathlib_dep = cc.find_library('m', required: false)
+	threads_dep = dependency('threads', required: false)
+
+	wayland_private = static_library(
+		'wayland-private',
+		sources: [
+			'connection.c',
+			'wayland-os.c'
+		],
+		dependencies: [ ffi_dep, rt_dep ]
+	)
+
+	wayland_private_dep = declare_dependency(
+		link_with: wayland_private,
+		include_directories: include_directories('.')
+	)
+
+	generated_headers = [
+		{
+			'scanner_args': ['server-header'],
+			'output': 'wayland-server-protocol.h',
+			'install': true,
+		},
+		{
+			'scanner_args': ['server-header', '-c'],
+			'output': 'wayland-server-protocol-core.h',
+			'install': false,
+		},
+		{
+			'scanner_args': ['client-header'],
+			'output': 'wayland-client-protocol.h',
+			'install': true,
+		},
+		{
+			'scanner_args': ['client-header', '-c'],
+			'output': 'wayland-client-protocol-core.h',
+			'install': false,
+		},
+	]
+
+	foreach gen: generated_headers
+		scanner_args = gen['scanner_args']
+		output_file = gen['output']
+		install_file = gen['install']
+		install_dir = join_paths(get_option('prefix'), get_option('includedir'))
+		target_name = output_file.underscorify()
+
+		target = custom_target(
+			target_name,
+			command: [
+				wayland_scanner_for_build, '-s', scanner_args,
+				'@INPUT@', '@OUTPUT@'
+			],
+			input: wayland_protocol_xml,
+			output: output_file,
+			install: install_file,
+			install_dir: install_dir
+		)
+
+		set_variable(target_name, target)
+	endforeach
+
+	wayland_protocol_c = custom_target(
+		'protocol source',
+		command: [
+			wayland_scanner_for_build, '-s', 'public-code', '@INPUT@', '@OUTPUT@'
+		],
+		input: wayland_protocol_xml,
+		output: 'wayland-protocol.c'
+	)
+
+	wayland_server = library(
+		'wayland-server',
+		sources: [
+			wayland_server_protocol_core_h,
+			wayland_server_protocol_h,
+			wayland_protocol_c,
+			'wayland-server.c',
+			'wayland-shm.c',
+			'event-loop.c'
+		],
+		version: '0.1.0',
+		dependencies: [
+			ffi_dep,
+			wayland_private_dep,
+			wayland_util_dep,
+			mathlib_dep,
+			threads_dep,
+			rt_dep
+		],
+		include_directories: root_inc,
+		install: true
+	)
+
+	wayland_server_dep = declare_dependency(
+		link_with: wayland_server,
+		include_directories: [ root_inc, include_directories('.') ],
+		dependencies: [ ffi_dep, mathlib_dep, threads_dep ],
+		sources: [
+			wayland_server_protocol_core_h,
+			wayland_server_protocol_h
+		]
+	)
+
+	pkgconfig.generate(
+		wayland_server,
+		name: 'Wayland Server',
+		description: 'Server side implementation of the Wayland protocol',
+		version: meson.project_version(),
+		filebase: 'wayland-server',
+		variables: [
+			'datarootdir=' + join_paths('${prefix}', get_option('datadir')),
+			'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name())
+		]
+	)
+
+	wayland_client = library(
+		'wayland-client',
+		sources: [
+			wayland_client_protocol_core_h,
+			wayland_client_protocol_h,
+			wayland_protocol_c,
+			'wayland-client.c'
+		],
+		version: '0.3.0',
+		dependencies: [
+			ffi_dep,
+			wayland_private_dep,
+			wayland_util_dep,
+			mathlib_dep,
+			threads_dep
+		],
+		include_directories: root_inc,
+		install: true
+	)
+
+	pkgconfig.generate(
+		wayland_client,
+		name: 'Wayland Client',
+		description: 'Wayland client side library',
+		version: meson.project_version(),
+		filebase: 'wayland-client',
+		variables: [
+			'datarootdir=' + join_paths('${prefix}', get_option('datadir')),
+			'pkgdatadir=' + join_paths('${datarootdir}', meson.project_name())
+		]
+	)
+
+	wayland_client_dep = declare_dependency(
+		link_with: wayland_client,
+		include_directories: [ root_inc, include_directories('.') ],
+		sources: [
+			wayland_client_protocol_core_h,
+			wayland_client_protocol_h
+		]
+	)
+
+	install_headers([
+		'wayland-util.h',
+		'wayland-server.h',
+		'wayland-server-core.h',
+		'wayland-client.h',
+		'wayland-client-core.h',
+	])
+endif
diff --git a/src/scanner.c b/src/scanner.c
index a94be5d..36ac905 100644
--- a/src/scanner.c
+++ b/src/scanner.c
@@ -25,7 +25,6 @@
  * SOFTWARE.
  */
 
-#include "config.h"
 #include "wayland-version.h"
 
 #include <stdbool.h>
@@ -251,6 +250,11 @@
 	unsigned int character_data_length;
 };
 
+enum identifier_role {
+	STANDALONE_IDENT,
+	TRAILING_IDENT
+};
+
 static void *
 fail_on_null(void *p)
 {
@@ -627,6 +631,50 @@
 	return (int)ret;
 }
 
+/* Check that the provided string will produce valid "C" identifiers.
+ *
+ * If the string will form the prefix of an identifier in the
+ * generated C code, then it must match [_a-zA-Z][_0-9a-zA-Z]*.
+ *
+ * If the string will form the suffix of an identifier, then
+ * it must match [_0-9a-zA-Z]+.
+ *
+ * Unicode characters or escape sequences are not permitted,
+ * since not all C compilers support them.
+ *
+ * If the above conditions are not met, then fail()
+ */
+static void
+validate_identifier(struct location *loc,
+		const char *str,
+		enum identifier_role role)
+{
+	const char *scan;
+
+	if (!*str) {
+		fail(loc, "element name is empty");
+	}
+
+	for (scan = str; *scan; scan++) {
+		char c = *scan;
+
+		/* we do not use the locale-dependent `isalpha` */
+		bool is_alpha = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+		bool is_digit = c >= '0' && c <= '9';
+		bool leading_char = (scan == str) && role == STANDALONE_IDENT;
+
+		if (is_alpha || c == '_' || (!leading_char && is_digit))
+			continue;
+
+		if (role == TRAILING_IDENT)
+			fail(loc,
+			     "'%s' is not a valid trailing identifier part", str);
+		else
+			fail(loc,
+			     "'%s' is not a valid standalone identifier", str);
+	}
+}
+
 static int
 version_from_since(struct parse_context *ctx, const char *since)
 {
@@ -701,6 +749,7 @@
 		if (name == NULL)
 			fail(&ctx->loc, "no protocol name given");
 
+		validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
 		ctx->protocol->name = xstrdup(name);
 		ctx->protocol->uppercase_name = uppercase_dup(name);
 	} else if (strcmp(element_name, "copyright") == 0) {
@@ -712,6 +761,7 @@
 		if (version == 0)
 			fail(&ctx->loc, "no interface version given");
 
+		validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
 		interface = create_interface(ctx->loc, name, version);
 		ctx->interface = interface;
 		wl_list_insert(ctx->protocol->interface_list.prev,
@@ -721,6 +771,7 @@
 		if (name == NULL)
 			fail(&ctx->loc, "no request name given");
 
+		validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
 		message = create_message(ctx->loc, name);
 
 		if (strcmp(element_name, "request") == 0)
@@ -748,6 +799,7 @@
 		if (name == NULL)
 			fail(&ctx->loc, "no argument name given");
 
+		validate_identifier(&ctx->loc, name, STANDALONE_IDENT);
 		arg = create_arg(name);
 		if (!set_arg_type(arg, type))
 			fail(&ctx->loc, "unknown type (%s)", type);
@@ -757,8 +809,12 @@
 			ctx->message->new_id_count++;
 			/* fallthrough */
 		case OBJECT:
-			if (interface_name)
+			if (interface_name) {
+				validate_identifier(&ctx->loc,
+						    interface_name,
+						    STANDALONE_IDENT);
 				arg->interface_name = xstrdup(interface_name);
+			}
 			break;
 		default:
 			if (interface_name != NULL)
@@ -793,6 +849,7 @@
 		if (name == NULL)
 			fail(&ctx->loc, "no enum name given");
 
+		validate_identifier(&ctx->loc, name, TRAILING_IDENT);
 		enumeration = create_enumeration(name);
 
 		if (bitfield == NULL || strcmp(bitfield, "false") == 0)
@@ -812,6 +869,7 @@
 		if (name == NULL)
 			fail(&ctx->loc, "no entry name given");
 
+		validate_identifier(&ctx->loc, name, TRAILING_IDENT);
 		entry = create_entry(name, value);
 		version = version_from_since(ctx, since);
 
@@ -916,6 +974,17 @@
 
 }
 
+#ifndef HAVE_STRNDUP
+char *
+strndup(const char *s, size_t size)
+{
+	char *r = malloc(size + 1);
+	strncpy(r, s, size);
+	r[size] = '\0';
+	return r;
+}
+#endif
+
 static void
 end_element(void *data, const XML_Char *name)
 {
@@ -1567,6 +1636,8 @@
 	printf("\n");
 
 	wl_list_for_each(i, &protocol->interface_list, link) {
+		printf("#ifndef %s_INTERFACE\n", i->uppercase_name);
+		printf("#define %s_INTERFACE\n", i->uppercase_name);
 		printf("/**\n"
 		       " * @page page_iface_%s %s\n",
 		       i->name, i->name);
@@ -1587,6 +1658,7 @@
 		printf(" */\n");
 		printf("extern const struct wl_interface "
 		       "%s_interface;\n", i->name);
+		printf("#endif\n");
 	}
 
 	printf("\n");
@@ -1663,7 +1735,7 @@
 }
 
 static void
-emit_messages(struct wl_list *message_list,
+emit_messages(const char *name, struct wl_list *message_list,
 	      struct interface *interface, const char *suffix)
 {
 	struct message *m;
@@ -1716,7 +1788,7 @@
 				break;
 			}
 		}
-		printf("\", types + %d },\n", m->type_index);
+		printf("\", %s_types + %d },\n", name, m->type_index);
 	}
 
 	printf("};\n\n");
@@ -1773,7 +1845,7 @@
 	wl_array_release(&types);
 	printf("\n");
 
-	printf("static const struct wl_interface *types[] = {\n");
+	printf("static const struct wl_interface *%s_types[] = {\n", protocol->name);
 	emit_null_run(protocol);
 	wl_list_for_each(i, &protocol->interface_list, link) {
 		emit_types(protocol, &i->request_list);
@@ -1783,8 +1855,8 @@
 
 	wl_list_for_each_safe(i, next, &protocol->interface_list, link) {
 
-		emit_messages(&i->request_list, i, "requests");
-		emit_messages(&i->event_list, i, "events");
+		emit_messages(protocol->name, &i->request_list, i, "requests");
+		emit_messages(protocol->name, &i->event_list, i, "events");
 
 		printf("%s const struct wl_interface "
 		       "%s_interface = {\n"
@@ -1956,7 +2028,7 @@
 		buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
 		len = fread(buf, 1, XML_BUFFER_SIZE, input);
 		if (len < 0) {
-			fprintf(stderr, "fread: %m\n");
+			fprintf(stderr, "fread: %s\n", strerror(errno));
 			fclose(input);
 			exit(EXIT_FAILURE);
 		}
diff --git a/src/wayland-client-core.h b/src/wayland-client-core.h
index 919ca3b..94c25e3 100644
--- a/src/wayland-client-core.h
+++ b/src/wayland-client-core.h
@@ -191,6 +191,13 @@
 uint32_t
 wl_proxy_get_id(struct wl_proxy *proxy);
 
+void
+wl_proxy_set_tag(struct wl_proxy *proxy,
+		 const char * const *tag);
+
+const char * const *
+wl_proxy_get_tag(struct wl_proxy *proxy);
+
 const char *
 wl_proxy_get_class(struct wl_proxy *proxy);
 
diff --git a/src/wayland-client.c b/src/wayland-client.c
index 2e0aa33..74d4861 100644
--- a/src/wayland-client.c
+++ b/src/wayland-client.c
@@ -69,6 +69,7 @@
 	void *user_data;
 	wl_dispatcher_func_t dispatcher;
 	uint32_t version;
+	const char * const *tag;
 };
 
 struct wl_event_queue {
@@ -333,8 +334,8 @@
 	struct wl_closure *closure;
 
 	while (!wl_list_empty(&queue->event_list)) {
-		closure = container_of(queue->event_list.next,
-				       struct wl_closure, link);
+		closure = wl_container_of(queue->event_list.next,
+					  closure, link);
 		wl_list_remove(&closure->link);
 		destroy_queued_closure(closure);
 	}
@@ -774,14 +775,23 @@
 			goto err_unlock;
 	}
 
+	if (proxy->display->last_error) {
+		goto err_unlock;
+	}
+
 	closure = wl_closure_marshal(&proxy->object, opcode, args, message);
-	if (closure == NULL)
-		wl_abort("Error marshalling request: %s\n", strerror(errno));
+	if (closure == NULL) {
+		wl_log("Error marshalling request: %s\n", strerror(errno));
+		display_fatal_error(proxy->display, errno);
+		goto err_unlock;
+	}
 
 	log_closure(closure, proxy, true);
 
-	if (wl_closure_send(closure, proxy->display->connection))
-		wl_abort("Error sending request: %s\n", strerror(errno));
+	if (wl_closure_send(closure, proxy->display->connection)) {
+		wl_log("Error sending request: %s\n", strerror(errno));
+		display_fatal_error(proxy->display, errno);
+	}
 
 	wl_closure_destroy(closure);
 
@@ -1138,6 +1148,13 @@
  * its value will be replaced with the WAYLAND_DISPLAY environment
  * variable if it is set, otherwise display "wayland-0" will be used.
  *
+ * If WAYLAND_SOCKET is set, it's interpreted as a file descriptor number
+ * referring to an already opened socket. In this case, the socket is used
+ * as-is and \c name is ignored.
+ *
+ * If \c name is a relative path, then the socket is opened relative to
+ * the XDG_RUNTIME_DIR directory.
+ *
  * If \c name is an absolute path, then that path is used as-is for
  * the location of the socket at which the Wayland server is listening;
  * no qualification inside XDG_RUNTIME_DIR is attempted.
@@ -1399,6 +1416,12 @@
 		return size;
 	}
 
+	if (opcode >= proxy->object.interface->event_count) {
+		wl_log("interface '%s' has no event %u\n",
+		       proxy->object.interface->name, opcode);
+		return -1;
+	}
+
 	message = &proxy->object.interface->events[opcode];
 	closure = wl_connection_demarshal(display->connection, size,
 					  &display->objects, message);
@@ -1436,8 +1459,7 @@
 	int opcode;
 	bool proxy_destroyed;
 
-	closure = container_of(queue->event_list.next,
-			       struct wl_closure, link);
+	closure = wl_container_of(queue->event_list.next, closure, link);
 	wl_list_remove(&closure->link);
 	opcode = closure->opcode;
 
@@ -2092,6 +2114,70 @@
 	return proxy->object.id;
 }
 
+/** Set the tag of a proxy object
+ *
+ * A toolkit or application can set a unique tag on a proxy in order to
+ * identify whether an object is managed by itself or some external part.
+ *
+ * To create a tag, the recommended way is to define a statically allocated
+ * constant char array containing some descriptive string. The tag will be the
+ * pointer to the non-const pointer to the beginning of the array.
+ *
+ * For example, to define and set a tag on a surface managed by a certain
+ * subsystem:
+ *
+ * 	static const char *my_tag = "my tag";
+ *
+ * 	wl_proxy_set_tag((struct wl_proxy *) surface, &my_tag);
+ *
+ * Then, in a callback with wl_surface as an argument, in order to check
+ * whether it's a surface managed by the same subsystem.
+ *
+ * 	const char * const *tag;
+ *
+ * 	tag = wl_proxy_get_tag((struct wl_proxy *) surface);
+ * 	if (tag != &my_tag)
+ *		return;
+ *
+ *	...
+ *
+ * For debugging purposes, a tag should be suitable to be included in a debug
+ * log entry, e.g.
+ *
+ * 	const char * const *tag;
+ *
+ * 	tag = wl_proxy_get_tag((struct wl_proxy *) surface);
+ * 	printf("Got a surface with the tag %p (%s)\n",
+ * 	       tag, (tag && *tag) ? *tag : "");
+ *
+ * \param proxy The proxy object
+ * \param tag The tag
+ *
+ * \memberof wl_proxy
+ * \since 1.17.90
+ */
+WL_EXPORT void
+wl_proxy_set_tag(struct wl_proxy *proxy,
+		 const char * const *tag)
+{
+	proxy->tag = tag;
+}
+
+/** Get the tag of a proxy object
+ *
+ * See wl_proxy_set_tag for details.
+ *
+ * \param proxy The proxy object
+ *
+ * \memberof wl_proxy
+ * \since 1.17.90
+ */
+WL_EXPORT const char * const *
+wl_proxy_get_tag(struct wl_proxy *proxy)
+{
+	return proxy->tag;
+}
+
 /** Get the interface name (class) of a proxy object
  *
  * \param proxy The proxy object
diff --git a/src/wayland-private.h b/src/wayland-private.h
index 29516ec..9bf8cb7 100644
--- a/src/wayland-private.h
+++ b/src/wayland-private.h
@@ -31,21 +31,17 @@
 #include <stdarg.h>
 #include <stdlib.h>
 #include <stdint.h>
+#include <stdbool.h>
 
 #define WL_HIDE_DEPRECATED 1
 
 #include "wayland-util.h"
-#include "wayland-server-core.h"
 
 /* Invalid memory address */
 #define WL_ARRAY_POISON_PTR (void *) 4
 
 #define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
 
-#define container_of(ptr, type, member) ({				\
-	const __typeof__( ((type *)0)->member ) *__mptr = (ptr);	\
-	(type *)( (char *)__mptr - offsetof(type,member) );})
-
 #define WL_MAP_SERVER_SIDE 0
 #define WL_MAP_CLIENT_SIDE 1
 #define WL_SERVER_ID_START 0xff000000
@@ -236,26 +232,6 @@
 	return calloc(1, s);
 }
 
-struct wl_priv_signal {
-	struct wl_list listener_list;
-	struct wl_list emit_list;
-};
-
-void
-wl_priv_signal_init(struct wl_priv_signal *signal);
-
-void
-wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener);
-
-struct wl_listener *
-wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify);
-
-void
-wl_priv_signal_emit(struct wl_priv_signal *signal, void *data);
-
-void
-wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data);
-
 void
 wl_connection_close_fds_in(struct wl_connection *connection, int max);
 
diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h
index f824837..e5f4e43 100644
--- a/src/wayland-server-core.h
+++ b/src/wayland-server-core.h
@@ -247,6 +247,9 @@
 		 void *data, wl_global_bind_func_t bind);
 
 void
+wl_global_remove(struct wl_global *global);
+
+void
 wl_global_destroy(struct wl_global *global);
 
 /** A filter function for wl_global objects
@@ -258,8 +261,8 @@
  * A filter function enables the server to decide which globals to
  * advertise to each client.
  *
- * When a wl_global filter is set, the given callback funtion will be
- * called during wl_global advertisment and binding.
+ * When a wl_global filter is set, the given callback function will be
+ * called during wl_global advertisement and binding.
  *
  * This function should return true if the global object should be made
  * visible to the client or false otherwise.
@@ -279,6 +282,9 @@
 void *
 wl_global_get_user_data(const struct wl_global *global);
 
+void
+wl_global_set_user_data(struct wl_global *global, void *data);
+
 struct wl_client *
 wl_client_create(struct wl_display *display, int fd);
 
diff --git a/src/wayland-server-private.h b/src/wayland-server-private.h
new file mode 100644
index 0000000..23fa458
--- /dev/null
+++ b/src/wayland-server-private.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2013 Jason Ekstrand
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_SERVER_PRIVATE_H
+#define WAYLAND_SERVER_PRIVATE_H
+
+#include "wayland-server-core.h"
+
+struct wl_priv_signal {
+	struct wl_list listener_list;
+	struct wl_list emit_list;
+};
+
+void
+wl_priv_signal_init(struct wl_priv_signal *signal);
+
+void
+wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener);
+
+struct wl_listener *
+wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify);
+
+void
+wl_priv_signal_emit(struct wl_priv_signal *signal, void *data);
+
+void
+wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data);
+
+#endif
diff --git a/src/wayland-server.c b/src/wayland-server.c
index 7b91cf3..ca0d98d 100644
--- a/src/wayland-server.c
+++ b/src/wayland-server.c
@@ -25,6 +25,7 @@
 
 #define _GNU_SOURCE
 
+#include <stdbool.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <stddef.h>
@@ -45,6 +46,7 @@
 
 #include "wayland-util.h"
 #include "wayland-private.h"
+#include "wayland-server-private.h"
 #include "wayland-server.h"
 #include "wayland-os.h"
 
@@ -112,6 +114,7 @@
 	void *data;
 	wl_global_bind_func_t bind;
 	struct wl_list link;
+	bool removed;
 };
 
 struct wl_resource {
@@ -686,12 +689,12 @@
  * Before Wayland 1.2.0, the definition of struct wl_resource was public.
  * It was made opaque just before 1.2.0, and later new fields were added.
  * The new fields cannot be accessed if a program is using the deprecated
- * defition, as there would not be memory allocated for them.
+ * definition, as there would not be memory allocated for them.
  *
  * The creation pattern for the deprecated definition was wl_resource_init()
  * followed by wl_client_add_resource(). wl_resource_init() was an inline
  * function and no longer exists, but binaries might still carry it.
- * wl_client_add_resource() still exists for ABI compatiblity.
+ * wl_client_add_resource() still exists for ABI compatibility.
  */
 static bool
 resource_is_deprecated(struct wl_resource *resource)
@@ -910,7 +913,7 @@
 
 /* Check if a global filter is registered and use it if any.
  *
- * If no wl_global filter has been registered, this funtion will
+ * If no wl_global filter has been registered, this function will
  * return true, allowing the wl_global to be visible to the wl_client
  */
 static bool
@@ -939,6 +942,12 @@
 		wl_resource_post_error(resource,
 				       WL_DISPLAY_ERROR_INVALID_OBJECT,
 				       "invalid global %s (%d)", interface, name);
+	else if (strcmp(global->interface->name, interface) != 0)
+		wl_resource_post_error(resource,
+				       WL_DISPLAY_ERROR_INVALID_OBJECT,
+				       "invalid interface for global %u: "
+				       "have %s, wanted %s",
+				       name, interface, global->interface->name);
 	else if (version == 0)
 		wl_resource_post_error(resource,
 				       WL_DISPLAY_ERROR_INVALID_OBJECT,
@@ -1008,7 +1017,7 @@
 		       &registry_resource->link);
 
 	wl_list_for_each(global, &display->global_list, link)
-		if (wl_global_is_visible(client, global))
+		if (wl_global_is_visible(client, global) && !global->removed)
 			wl_resource_post_event(registry_resource,
 					       WL_REGISTRY_GLOBAL,
 					       global->name,
@@ -1164,13 +1173,13 @@
 /** Set a filter function for global objects
  *
  * \param display The Wayland display object.
- * \param filter  The global filter funtion.
+ * \param filter  The global filter function.
  * \param data User data to be associated with the global filter.
  * \return None.
  *
  * Set a filter for the wl_display to advertise or hide global objects
  * to clients.
- * The set filter will be used during wl_global advertisment to
+ * The set filter will be used during wl_global advertisement to
  * determine whether a global object should be advertised to a
  * given client, and during wl_global binding to determine whether
  * a given client should be allowed to bind to a global.
@@ -1224,6 +1233,7 @@
 	global->version = version;
 	global->data = data;
 	global->bind = bind;
+	global->removed = false;
 	wl_list_insert(display->global_list.prev, &global->link);
 
 	wl_list_for_each(resource, &display->registry_resource_list, link)
@@ -1236,15 +1246,50 @@
 	return global;
 }
 
+/** Remove the global
+ *
+ * \param global The Wayland global.
+ *
+ * Broadcast a global remove event to all clients without destroying the
+ * global. This function can only be called once per global.
+ *
+ * wl_global_destroy() removes the global and immediately destroys it. On
+ * the other end, this function only removes the global, allowing clients
+ * that have not yet received the global remove event to continue to bind to
+ * it.
+ *
+ * This can be used by compositors to mitigate clients being disconnected
+ * because a global has been added and removed too quickly. Compositors can call
+ * wl_global_remove(), then wait an implementation-defined amount of time, then
+ * call wl_global_destroy(). Note that the destruction of a global is still
+ * racy, since clients have no way to acknowledge that they received the remove
+ * event.
+ *
+ * \since 1.17.90
+ */
 WL_EXPORT void
-wl_global_destroy(struct wl_global *global)
+wl_global_remove(struct wl_global *global)
 {
 	struct wl_display *display = global->display;
 	struct wl_resource *resource;
 
+	if (global->removed)
+		wl_abort("wl_global_remove: called twice on the same "
+			 "global '%s@%"PRIu32"'", global->interface->name,
+			 global->name);
+
 	wl_list_for_each(resource, &display->registry_resource_list, link)
 		wl_resource_post_event(resource, WL_REGISTRY_GLOBAL_REMOVE,
 				       global->name);
+
+	global->removed = true;
+}
+
+WL_EXPORT void
+wl_global_destroy(struct wl_global *global)
+{
+	if (!global->removed)
+		wl_global_remove(global);
 	wl_list_remove(&global->link);
 	free(global);
 }
@@ -1261,6 +1306,19 @@
 	return global->data;
 }
 
+/** Set the global's user data
+ *
+ * \param global The global object
+ * \param data The user data pointer
+ *
+ * \since 1.17.90
+ */
+WL_EXPORT void
+wl_global_set_user_data(struct wl_global *global, void *data)
+{
+	global->data = data;
+}
+
 /** Get the current serial number
  *
  * \param display The display object
@@ -1384,7 +1442,7 @@
 	client_fd = wl_os_accept_cloexec(fd, (struct sockaddr *) &name,
 					 &length);
 	if (client_fd < 0)
-		wl_log("failed to accept: %m\n");
+		wl_log("failed to accept: %s\n", strerror(errno));
 	else
 		if (!wl_client_create(display, client_fd))
 			close(client_fd);
@@ -1400,7 +1458,7 @@
 	snprintf(socket->lock_addr, sizeof socket->lock_addr,
 		 "%s%s", socket->addr.sun_path, LOCK_SUFFIX);
 
-	socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC,
+	socket->fd_lock = open(socket->lock_addr, O_CREAT | O_CLOEXEC | O_RDWR,
 			       (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
 
 	if (socket->fd_lock < 0) {
@@ -1415,7 +1473,7 @@
 		goto err_fd;
 	}
 
-	if (stat(socket->addr.sun_path, &socket_stat) < 0 ) {
+	if (lstat(socket->addr.sun_path, &socket_stat) < 0 ) {
 		if (errno != ENOENT) {
 			wl_log("did not manage to stat file %s\n",
 				socket->addr.sun_path);
@@ -1445,28 +1503,32 @@
 wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
 {
 	int name_size;
-	const char *runtime_dir;
+	const char *runtime_dir = "";
+	const char *separator = "";
 
-	runtime_dir = getenv("XDG_RUNTIME_DIR");
-	if (!runtime_dir) {
-		wl_log("error: XDG_RUNTIME_DIR not set in the environment\n");
+	if (name[0] != '/') {
+		runtime_dir = getenv("XDG_RUNTIME_DIR");
+		if (!runtime_dir) {
+			wl_log("error: XDG_RUNTIME_DIR not set in the environment\n");
 
-		/* to prevent programs reporting
-		 * "failed to add socket: Success" */
-		errno = ENOENT;
-		return -1;
+			/* to prevent programs reporting
+			 * "failed to add socket: Success" */
+			errno = ENOENT;
+			return -1;
+		}
+		separator = "/";
 	}
 
 	s->addr.sun_family = AF_LOCAL;
 	name_size = snprintf(s->addr.sun_path, sizeof s->addr.sun_path,
-			     "%s/%s", runtime_dir, name) + 1;
+			     "%s%s%s", runtime_dir, separator, name) + 1;
 
 	s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name);
 
 	assert(name_size > 0);
 	if (name_size > (int)sizeof s->addr.sun_path) {
-		wl_log("error: socket path \"%s/%s\" plus null terminator"
-		       " exceeds 108 bytes\n", runtime_dir, name);
+		wl_log("error: socket path \"%s%s%s\" plus null terminator"
+		       " exceeds 108 bytes\n", runtime_dir, separator, name);
 		*s->addr.sun_path = 0;
 		/* to prevent programs reporting
 		 * "failed to add socket: Success" */
@@ -1489,12 +1551,12 @@
 
 	size = offsetof (struct sockaddr_un, sun_path) + strlen(s->addr.sun_path);
 	if (bind(s->fd, (struct sockaddr *) &s->addr, size) < 0) {
-		wl_log("bind() failed with error: %m\n");
+		wl_log("bind() failed with error: %s\n", strerror(errno));
 		return -1;
 	}
 
 	if (listen(s->fd, 128) < 0) {
-		wl_log("listen() failed with error: %m\n");
+		wl_log("listen() failed with error: %s\n", strerror(errno));
 		return -1;
 	}
 
@@ -1605,14 +1667,17 @@
  * variable for the socket name. If WAYLAND_DISPLAY is not set, then default
  * wayland-0 is used.
  *
- * The Unix socket will be created in the directory pointed to by environment
- * variable XDG_RUNTIME_DIR. If XDG_RUNTIME_DIR is not set, then this function
- * fails and returns -1.
+ * If the socket name is a relative path, the Unix socket will be created in
+ * the directory pointed to by environment variable XDG_RUNTIME_DIR. If
+ * XDG_RUNTIME_DIR is not set, then this function fails and returns -1.
  *
- * The length of socket path, i.e., the path set in XDG_RUNTIME_DIR and the
- * socket name, must not exceed the maximum length of a Unix socket path.
- * The function also fails if the user do not have write permission in the
- * XDG_RUNTIME_DIR path or if the socket name is already in use.
+ * If the socket name is an absolute path, then it is used as-is for the
+ * the Unix socket.
+ *
+ * The length of the computed socket path must not exceed the maximum length
+ * of a Unix socket path.
+ * The function also fails if the user does not have write permission in the
+ * directory or if the path is already in use.
  *
  * \memberof wl_display
  */
@@ -1921,7 +1986,9 @@
 WL_EXPORT struct wl_client *
 wl_client_from_link(struct wl_list *link)
 {
-	return container_of(link, struct wl_client, link);
+	struct wl_client *client;
+
+	return wl_container_of(link, client, link);
 }
 
 /** Add a listener for the client's resource creation signal
@@ -1997,7 +2064,7 @@
  * without corrupting the signal's list.
  *
  * Before passing a wl_priv_signal object to any other function it must be
- * initialized by useing wl_priv_signal_init().
+ * initialized by using wl_priv_signal_init().
  *
  * \memberof wl_priv_signal
  */
@@ -2027,7 +2094,7 @@
  *
  * Returns the listener added to the given \a signal and with the given
  * \a notify function, or NULL if there isn't any.
- * Calling this function from withing wl_priv_signal_emit() is safe and will
+ * Calling this function from within wl_priv_signal_emit() is safe and will
  * return the correct value.
  *
  * \memberof wl_priv_signal
diff --git a/src/wayland-shm.c b/src/wayland-shm.c
index 4191231..b85e5a7 100644
--- a/src/wayland-shm.c
+++ b/src/wayland-shm.c
@@ -30,6 +30,8 @@
 
 #define _GNU_SOURCE
 
+#include "config.h"
+
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
@@ -40,6 +42,8 @@
 #include <assert.h>
 #include <signal.h>
 #include <pthread.h>
+#include <errno.h>
+#include <fcntl.h>
 
 #include "wayland-util.h"
 #include "wayland-private.h"
@@ -59,6 +63,7 @@
 	char *data;
 	int32_t size;
 	int32_t new_size;
+	bool sigbus_is_impossible;
 };
 
 struct wl_shm_buffer {
@@ -258,6 +263,7 @@
 		uint32_t id, int fd, int32_t size)
 {
 	struct wl_shm_pool *pool;
+	int seals;
 
 	if (size <= 0) {
 		wl_resource_post_error(resource,
@@ -272,6 +278,15 @@
 		goto err_close;
 	}
 
+#ifdef HAVE_MEMFD_CREATE
+	seals = fcntl(fd, F_GET_SEALS);
+	if (seals == -1)
+		seals = 0;
+	pool->sigbus_is_impossible = (seals & F_SEAL_SHRINK) ? true : false;
+#else
+	pool->sigbus_is_impossible = false;
+#endif
+
 	pool->internal_refcount = 1;
 	pool->external_refcount = 0;
 	pool->size = size;
@@ -281,7 +296,8 @@
 	if (pool->data == MAP_FAILED) {
 		wl_resource_post_error(resource,
 				       WL_SHM_ERROR_INVALID_FD,
-				       "failed mmap fd %d: %m", fd);
+				       "failed mmap fd %d: %s", fd,
+				       strerror(errno));
 		goto err_free;
 	}
 	close(fd);
@@ -569,6 +585,9 @@
 	struct wl_shm_pool *pool = buffer->pool;
 	struct wl_shm_sigbus_data *sigbus_data;
 
+	if (pool->sigbus_is_impossible)
+		return;
+
 	pthread_once(&wl_shm_sigbus_once, init_sigbus_data_key);
 
 	sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key);
@@ -601,9 +620,13 @@
 WL_EXPORT void
 wl_shm_buffer_end_access(struct wl_shm_buffer *buffer)
 {
-	struct wl_shm_sigbus_data *sigbus_data =
-		pthread_getspecific(wl_shm_sigbus_data_key);
+	struct wl_shm_pool *pool = buffer->pool;
+	struct wl_shm_sigbus_data *sigbus_data;
 
+	if (pool->sigbus_is_impossible)
+		return;
+
+	sigbus_data = pthread_getspecific(wl_shm_sigbus_data_key);
 	assert(sigbus_data && sigbus_data->access_count >= 1);
 
 	if (--sigbus_data->access_count == 0) {
diff --git a/src/wayland-util.c b/src/wayland-util.c
index 3a471a8..d5973bf 100644
--- a/src/wayland-util.c
+++ b/src/wayland-util.c
@@ -131,7 +131,7 @@
 		array->alloc = alloc;
 	}
 
-	p = array->data + array->size;
+	p = (char *)array->data + array->size;
 	array->size += size;
 
 	return p;
diff --git a/src/wayland-util.h b/src/wayland-util.h
index 2115f5c..7997778 100644
--- a/src/wayland-util.h
+++ b/src/wayland-util.h
@@ -640,7 +640,7 @@
 
 	u.d = d + (3LL << (51 - 8));
 
-	return u.i;
+	return (wl_fixed_t)u.i;
 }
 
 /**
diff --git a/src/wayland-version.h b/src/wayland-version.h
index 65a614a..eb33462 100644
--- a/src/wayland-version.h
+++ b/src/wayland-version.h
@@ -27,8 +27,8 @@
 #define WAYLAND_VERSION_H
 
 #define WAYLAND_VERSION_MAJOR 1
-#define WAYLAND_VERSION_MINOR 17
+#define WAYLAND_VERSION_MINOR 19
 #define WAYLAND_VERSION_MICRO 0
-#define WAYLAND_VERSION "1.17.0"
+#define WAYLAND_VERSION "1.19.0"
 
 #endif
diff --git a/tests/array-test.c b/tests/array-test.c
index eda610b..78dfbb0 100644
--- a/tests/array-test.c
+++ b/tests/array-test.c
@@ -87,8 +87,7 @@
 
 	/* verify the data */
 	for (i = 0; i < iterations; ++i) {
-		const int index = datasize * i;
-		struct mydata* check = (struct mydata*)(array.data + index);
+		struct mydata* check = (struct mydata*)array.data + i;
 
 		assert(check->a == i * 3);
 		assert(check->b == 20000 - i);
@@ -121,9 +120,8 @@
 
 	/* check the copy */
 	for (i = 0; i < iterations; i++) {
-		const int index = sizeof(int) * i;
-		int *s = (int *)(source.data + index);
-		int *c = (int *)(copy.data + index);
+		int *s = (int *)source.data + i;
+		int *c = (int *)copy.data + i;
 
 		assert(*s == *c); /* verify the values are the same */
 		assert(s != c); /* ensure the addresses aren't the same */
diff --git a/tests/client-test.c b/tests/client-test.c
index 2e332f8..960cfa9 100644
--- a/tests/client-test.c
+++ b/tests/client-test.c
@@ -47,7 +47,7 @@
 client_destroy_notify(struct wl_listener *l, void *data)
 {
 	struct client_destroy_listener *listener =
-		container_of(l, struct client_destroy_listener, listener);
+		wl_container_of(l, listener, listener);
 
 	listener->done = 1;
 }
diff --git a/tests/connection-test.c b/tests/connection-test.c
index a06a3cc..c04845b 100644
--- a/tests/connection-test.c
+++ b/tests/connection-test.c
@@ -553,7 +553,7 @@
 	assert(errno == expected_error);
 }
 
-/* These tests are verifying that the demarshaling code will gracefuly handle
+/* These tests are verifying that the demarshaling code will gracefully handle
  * clients lying about string and array lengths and giving values near
  * UINT32_MAX. Before fixes f7fdface and f5b9e3b9 this test would crash on
  * 32bit systems.
diff --git a/tests/data/bad-identifier-arg.xml b/tests/data/bad-identifier-arg.xml
new file mode 100644
index 0000000..ac2a6b7
--- /dev/null
+++ b/tests/data/bad-identifier-arg.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="the_protocol">
+  <interface name="the_interface" version="1">
+    <description summary="the summary">
+    </description>
+    <request name="the_request">
+      <arg name="" type="uint"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/tests/data/bad-identifier-entry.xml b/tests/data/bad-identifier-entry.xml
new file mode 100644
index 0000000..6ea2fae
--- /dev/null
+++ b/tests/data/bad-identifier-entry.xml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="the_protocol">
+  <interface name="the_interface" version="1">
+    <description summary="the summary">
+    </description>
+    <enum name="4the_enum">
+      <entry name="60_seconds" value="1" summary="this is the first"/>
+      <entry name="invalid entry" value="2" summary="this is the first"/>
+    </enum>
+  </interface>
+</protocol>
diff --git a/tests/data/bad-identifier-enum.xml b/tests/data/bad-identifier-enum.xml
new file mode 100644
index 0000000..3225384
--- /dev/null
+++ b/tests/data/bad-identifier-enum.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="the_protocol">
+  <interface name="the_interface" version="1">
+    <description summary="the summary">
+    </description>
+    <enum name="the-enum">
+      <entry name="the_entry" value="0" summary="entry summary"/>
+    </enum>
+  </interface>
+</protocol>
diff --git a/tests/data/bad-identifier-event.xml b/tests/data/bad-identifier-event.xml
new file mode 100644
index 0000000..9708e3b
--- /dev/null
+++ b/tests/data/bad-identifier-event.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="the_protocol">
+  <interface name="the_interface" version="1">
+    <description summary="the summary">
+    </description>
+    <event name="theΔevent"/>
+  </interface>
+</protocol>
diff --git a/tests/data/bad-identifier-interface.xml b/tests/data/bad-identifier-interface.xml
new file mode 100644
index 0000000..17404c5
--- /dev/null
+++ b/tests/data/bad-identifier-interface.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="the_protocol">
+  <interface name="inter face" version="1">
+    <description summary="the summary">
+    </description>
+    <event name="the_event"/>
+  </interface>
+</protocol>
diff --git a/tests/data/bad-identifier-protocol.xml b/tests/data/bad-identifier-protocol.xml
new file mode 100644
index 0000000..7a17204
--- /dev/null
+++ b/tests/data/bad-identifier-protocol.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="1badprotocol">
+  <interface name="required_interface" version="13">
+    <description summary="required summary">
+    </description>
+    <event name="requied_event"/>
+  </interface>
+</protocol>
diff --git a/tests/data/bad-identifier-request.xml b/tests/data/bad-identifier-request.xml
new file mode 100644
index 0000000..a68c8aa
--- /dev/null
+++ b/tests/data/bad-identifier-request.xml
@@ -0,0 +1,10 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="the_protocol">
+  <interface name="the_interface" version="1">
+    <description summary="the summary">
+    </description>
+    <request name="req-west">
+      <arg name="the_arg" type="uint"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/tests/data/example-client.h b/tests/data/example-client.h
index c40e361..d421af9 100644
--- a/tests/data/example-client.h
+++ b/tests/data/example-client.h
@@ -88,6 +88,8 @@
 struct wl_surface;
 struct wl_touch;
 
+#ifndef WL_DISPLAY_INTERFACE
+#define WL_DISPLAY_INTERFACE
 /**
  * @page page_iface_wl_display wl_display
  * @section page_iface_wl_display_desc Description
@@ -104,6 +106,9 @@
  * is used for internal Wayland protocol features.
  */
 extern const struct wl_interface wl_display_interface;
+#endif
+#ifndef WL_REGISTRY_INTERFACE
+#define WL_REGISTRY_INTERFACE
 /**
  * @page page_iface_wl_registry wl_registry
  * @section page_iface_wl_registry_desc Description
@@ -156,6 +161,9 @@
  * the object.
  */
 extern const struct wl_interface wl_registry_interface;
+#endif
+#ifndef WL_CALLBACK_INTERFACE
+#define WL_CALLBACK_INTERFACE
 /**
  * @page page_iface_wl_callback wl_callback
  * @section page_iface_wl_callback_desc Description
@@ -172,6 +180,9 @@
  * the related request is done.
  */
 extern const struct wl_interface wl_callback_interface;
+#endif
+#ifndef WL_COMPOSITOR_INTERFACE
+#define WL_COMPOSITOR_INTERFACE
 /**
  * @page page_iface_wl_compositor wl_compositor
  * @section page_iface_wl_compositor_desc Description
@@ -190,6 +201,9 @@
  * surfaces into one displayable output.
  */
 extern const struct wl_interface wl_compositor_interface;
+#endif
+#ifndef WL_SHM_POOL_INTERFACE
+#define WL_SHM_POOL_INTERFACE
 /**
  * @page page_iface_wl_shm_pool wl_shm_pool
  * @section page_iface_wl_shm_pool_desc Description
@@ -216,6 +230,9 @@
  * a surface or for many small buffers.
  */
 extern const struct wl_interface wl_shm_pool_interface;
+#endif
+#ifndef WL_SHM_INTERFACE
+#define WL_SHM_INTERFACE
 /**
  * @page page_iface_wl_shm wl_shm
  * @section page_iface_wl_shm_desc Description
@@ -246,6 +263,9 @@
  * that can be used for buffers.
  */
 extern const struct wl_interface wl_shm_interface;
+#endif
+#ifndef WL_BUFFER_INTERFACE
+#define WL_BUFFER_INTERFACE
 /**
  * @page page_iface_wl_buffer wl_buffer
  * @section page_iface_wl_buffer_desc Description
@@ -268,6 +288,9 @@
  * updates the contents is defined by the buffer factory interface.
  */
 extern const struct wl_interface wl_buffer_interface;
+#endif
+#ifndef WL_DATA_OFFER_INTERFACE
+#define WL_DATA_OFFER_INTERFACE
 /**
  * @page page_iface_wl_data_offer wl_data_offer
  * @section page_iface_wl_data_offer_desc Description
@@ -292,6 +315,9 @@
  * data directly from the source client.
  */
 extern const struct wl_interface wl_data_offer_interface;
+#endif
+#ifndef WL_DATA_SOURCE_INTERFACE
+#define WL_DATA_SOURCE_INTERFACE
 /**
  * @page page_iface_wl_data_source wl_data_source
  * @section page_iface_wl_data_source_desc Description
@@ -312,6 +338,9 @@
  * to requests to transfer the data.
  */
 extern const struct wl_interface wl_data_source_interface;
+#endif
+#ifndef WL_DATA_DEVICE_INTERFACE
+#define WL_DATA_DEVICE_INTERFACE
 /**
  * @page page_iface_wl_data_device wl_data_device
  * @section page_iface_wl_data_device_desc Description
@@ -334,6 +363,9 @@
  * mechanisms such as copy-and-paste and drag-and-drop.
  */
 extern const struct wl_interface wl_data_device_interface;
+#endif
+#ifndef WL_DATA_DEVICE_MANAGER_INTERFACE
+#define WL_DATA_DEVICE_MANAGER_INTERFACE
 /**
  * @page page_iface_wl_data_device_manager wl_data_device_manager
  * @section page_iface_wl_data_device_manager_desc Description
@@ -366,6 +398,9 @@
  * wl_data_offer.accept and wl_data_offer.finish for details.
  */
 extern const struct wl_interface wl_data_device_manager_interface;
+#endif
+#ifndef WL_SHELL_INTERFACE
+#define WL_SHELL_INTERFACE
 /**
  * @page page_iface_wl_shell wl_shell
  * @section page_iface_wl_shell_desc Description
@@ -388,6 +423,9 @@
  * a basic surface.
  */
 extern const struct wl_interface wl_shell_interface;
+#endif
+#ifndef WL_SHELL_SURFACE_INTERFACE
+#define WL_SHELL_SURFACE_INTERFACE
 /**
  * @page page_iface_wl_shell_surface wl_shell_surface
  * @section page_iface_wl_shell_surface_desc Description
@@ -422,6 +460,9 @@
  * the wl_surface object.
  */
 extern const struct wl_interface wl_shell_surface_interface;
+#endif
+#ifndef WL_SURFACE_INTERFACE
+#define WL_SURFACE_INTERFACE
 /**
  * @page page_iface_wl_surface wl_surface
  * @section page_iface_wl_surface_desc Description
@@ -512,6 +553,9 @@
  * switching is not allowed).
  */
 extern const struct wl_interface wl_surface_interface;
+#endif
+#ifndef WL_SEAT_INTERFACE
+#define WL_SEAT_INTERFACE
 /**
  * @page page_iface_wl_seat wl_seat
  * @section page_iface_wl_seat_desc Description
@@ -532,6 +576,9 @@
  * maintains a keyboard focus and a pointer focus.
  */
 extern const struct wl_interface wl_seat_interface;
+#endif
+#ifndef WL_POINTER_INTERFACE
+#define WL_POINTER_INTERFACE
 /**
  * @page page_iface_wl_pointer wl_pointer
  * @section page_iface_wl_pointer_desc Description
@@ -560,6 +607,9 @@
  * and scrolling.
  */
 extern const struct wl_interface wl_pointer_interface;
+#endif
+#ifndef WL_KEYBOARD_INTERFACE
+#define WL_KEYBOARD_INTERFACE
 /**
  * @page page_iface_wl_keyboard wl_keyboard
  * @section page_iface_wl_keyboard_desc Description
@@ -576,6 +626,9 @@
  * associated with a seat.
  */
 extern const struct wl_interface wl_keyboard_interface;
+#endif
+#ifndef WL_TOUCH_INTERFACE
+#define WL_TOUCH_INTERFACE
 /**
  * @page page_iface_wl_touch wl_touch
  * @section page_iface_wl_touch_desc Description
@@ -604,6 +657,9 @@
  * contact point can be identified by the ID of the sequence.
  */
 extern const struct wl_interface wl_touch_interface;
+#endif
+#ifndef WL_OUTPUT_INTERFACE
+#define WL_OUTPUT_INTERFACE
 /**
  * @page page_iface_wl_output wl_output
  * @section page_iface_wl_output_desc Description
@@ -628,6 +684,9 @@
  * as global during start up, or when a monitor is hotplugged.
  */
 extern const struct wl_interface wl_output_interface;
+#endif
+#ifndef WL_REGION_INTERFACE
+#define WL_REGION_INTERFACE
 /**
  * @page page_iface_wl_region wl_region
  * @section page_iface_wl_region_desc Description
@@ -648,6 +707,9 @@
  * regions of a surface.
  */
 extern const struct wl_interface wl_region_interface;
+#endif
+#ifndef WL_SUBCOMPOSITOR_INTERFACE
+#define WL_SUBCOMPOSITOR_INTERFACE
 /**
  * @page page_iface_wl_subcompositor wl_subcompositor
  * @section page_iface_wl_subcompositor_desc Description
@@ -698,6 +760,9 @@
  * processing to dedicated overlay hardware when possible.
  */
 extern const struct wl_interface wl_subcompositor_interface;
+#endif
+#ifndef WL_SUBSURFACE_INTERFACE
+#define WL_SUBSURFACE_INTERFACE
 /**
  * @page page_iface_wl_subsurface wl_subsurface
  * @section page_iface_wl_subsurface_desc Description
@@ -808,6 +873,7 @@
  * unmapped.
  */
 extern const struct wl_interface wl_subsurface_interface;
+#endif
 
 #ifndef WL_DISPLAY_ERROR_ENUM
 #define WL_DISPLAY_ERROR_ENUM
diff --git a/tests/data/example-code.c b/tests/data/example-code.c
index bc03fe5..2055c88 100644
--- a/tests/data/example-code.c
+++ b/tests/data/example-code.c
@@ -48,7 +48,7 @@
 extern const struct wl_interface wl_surface_interface;
 extern const struct wl_interface wl_touch_interface;
 
-static const struct wl_interface *types[] = {
+static const struct wl_interface *wayland_types[] = {
 	NULL,
 	NULL,
 	NULL,
@@ -147,13 +147,13 @@
 };
 
 static const struct wl_message wl_display_requests[] = {
-	{ "sync", "n", types + 8 },
-	{ "get_registry", "n", types + 9 },
+	{ "sync", "n", wayland_types + 8 },
+	{ "get_registry", "n", wayland_types + 9 },
 };
 
 static const struct wl_message wl_display_events[] = {
-	{ "error", "ous", types + 0 },
-	{ "delete_id", "u", types + 0 },
+	{ "error", "ous", wayland_types + 0 },
+	{ "delete_id", "u", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_display_interface = {
@@ -163,12 +163,12 @@
 };
 
 static const struct wl_message wl_registry_requests[] = {
-	{ "bind", "usun", types + 0 },
+	{ "bind", "usun", wayland_types + 0 },
 };
 
 static const struct wl_message wl_registry_events[] = {
-	{ "global", "usu", types + 0 },
-	{ "global_remove", "u", types + 0 },
+	{ "global", "usu", wayland_types + 0 },
+	{ "global_remove", "u", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_registry_interface = {
@@ -178,7 +178,7 @@
 };
 
 static const struct wl_message wl_callback_events[] = {
-	{ "done", "u", types + 0 },
+	{ "done", "u", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_callback_interface = {
@@ -188,8 +188,8 @@
 };
 
 static const struct wl_message wl_compositor_requests[] = {
-	{ "create_surface", "n", types + 10 },
-	{ "create_region", "n", types + 11 },
+	{ "create_surface", "n", wayland_types + 10 },
+	{ "create_region", "n", wayland_types + 11 },
 };
 
 WL_EXPORT const struct wl_interface wl_compositor_interface = {
@@ -199,9 +199,9 @@
 };
 
 static const struct wl_message wl_shm_pool_requests[] = {
-	{ "create_buffer", "niiiiu", types + 12 },
-	{ "destroy", "", types + 0 },
-	{ "resize", "i", types + 0 },
+	{ "create_buffer", "niiiiu", wayland_types + 12 },
+	{ "destroy", "", wayland_types + 0 },
+	{ "resize", "i", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_shm_pool_interface = {
@@ -211,11 +211,11 @@
 };
 
 static const struct wl_message wl_shm_requests[] = {
-	{ "create_pool", "nhi", types + 18 },
+	{ "create_pool", "nhi", wayland_types + 18 },
 };
 
 static const struct wl_message wl_shm_events[] = {
-	{ "format", "u", types + 0 },
+	{ "format", "u", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_shm_interface = {
@@ -225,11 +225,11 @@
 };
 
 static const struct wl_message wl_buffer_requests[] = {
-	{ "destroy", "", types + 0 },
+	{ "destroy", "", wayland_types + 0 },
 };
 
 static const struct wl_message wl_buffer_events[] = {
-	{ "release", "", types + 0 },
+	{ "release", "", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_buffer_interface = {
@@ -239,17 +239,17 @@
 };
 
 static const struct wl_message wl_data_offer_requests[] = {
-	{ "accept", "u?s", types + 0 },
-	{ "receive", "sh", types + 0 },
-	{ "destroy", "", types + 0 },
-	{ "finish", "3", types + 0 },
-	{ "set_actions", "3uu", types + 0 },
+	{ "accept", "u?s", wayland_types + 0 },
+	{ "receive", "sh", wayland_types + 0 },
+	{ "destroy", "", wayland_types + 0 },
+	{ "finish", "3", wayland_types + 0 },
+	{ "set_actions", "3uu", wayland_types + 0 },
 };
 
 static const struct wl_message wl_data_offer_events[] = {
-	{ "offer", "s", types + 0 },
-	{ "source_actions", "3u", types + 0 },
-	{ "action", "3u", types + 0 },
+	{ "offer", "s", wayland_types + 0 },
+	{ "source_actions", "3u", wayland_types + 0 },
+	{ "action", "3u", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_data_offer_interface = {
@@ -259,18 +259,18 @@
 };
 
 static const struct wl_message wl_data_source_requests[] = {
-	{ "offer", "s", types + 0 },
-	{ "destroy", "", types + 0 },
-	{ "set_actions", "3u", types + 0 },
+	{ "offer", "s", wayland_types + 0 },
+	{ "destroy", "", wayland_types + 0 },
+	{ "set_actions", "3u", wayland_types + 0 },
 };
 
 static const struct wl_message wl_data_source_events[] = {
-	{ "target", "?s", types + 0 },
-	{ "send", "sh", types + 0 },
-	{ "cancelled", "", types + 0 },
-	{ "dnd_drop_performed", "3", types + 0 },
-	{ "dnd_finished", "3", types + 0 },
-	{ "action", "3u", types + 0 },
+	{ "target", "?s", wayland_types + 0 },
+	{ "send", "sh", wayland_types + 0 },
+	{ "cancelled", "", wayland_types + 0 },
+	{ "dnd_drop_performed", "3", wayland_types + 0 },
+	{ "dnd_finished", "3", wayland_types + 0 },
+	{ "action", "3u", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_data_source_interface = {
@@ -280,18 +280,18 @@
 };
 
 static const struct wl_message wl_data_device_requests[] = {
-	{ "start_drag", "?oo?ou", types + 21 },
-	{ "set_selection", "?ou", types + 25 },
-	{ "release", "2", types + 0 },
+	{ "start_drag", "?oo?ou", wayland_types + 21 },
+	{ "set_selection", "?ou", wayland_types + 25 },
+	{ "release", "2", wayland_types + 0 },
 };
 
 static const struct wl_message wl_data_device_events[] = {
-	{ "data_offer", "n", types + 27 },
-	{ "enter", "uoff?o", types + 28 },
-	{ "leave", "", types + 0 },
-	{ "motion", "uff", types + 0 },
-	{ "drop", "", types + 0 },
-	{ "selection", "?o", types + 33 },
+	{ "data_offer", "n", wayland_types + 27 },
+	{ "enter", "uoff?o", wayland_types + 28 },
+	{ "leave", "", wayland_types + 0 },
+	{ "motion", "uff", wayland_types + 0 },
+	{ "drop", "", wayland_types + 0 },
+	{ "selection", "?o", wayland_types + 33 },
 };
 
 WL_EXPORT const struct wl_interface wl_data_device_interface = {
@@ -301,8 +301,8 @@
 };
 
 static const struct wl_message wl_data_device_manager_requests[] = {
-	{ "create_data_source", "n", types + 34 },
-	{ "get_data_device", "no", types + 35 },
+	{ "create_data_source", "n", wayland_types + 34 },
+	{ "get_data_device", "no", wayland_types + 35 },
 };
 
 WL_EXPORT const struct wl_interface wl_data_device_manager_interface = {
@@ -312,7 +312,7 @@
 };
 
 static const struct wl_message wl_shell_requests[] = {
-	{ "get_shell_surface", "no", types + 37 },
+	{ "get_shell_surface", "no", wayland_types + 37 },
 };
 
 WL_EXPORT const struct wl_interface wl_shell_interface = {
@@ -322,22 +322,22 @@
 };
 
 static const struct wl_message wl_shell_surface_requests[] = {
-	{ "pong", "u", types + 0 },
-	{ "move", "ou", types + 39 },
-	{ "resize", "ouu", types + 41 },
-	{ "set_toplevel", "", types + 0 },
-	{ "set_transient", "oiiu", types + 44 },
-	{ "set_fullscreen", "uu?o", types + 48 },
-	{ "set_popup", "ouoiiu", types + 51 },
-	{ "set_maximized", "?o", types + 57 },
-	{ "set_title", "s", types + 0 },
-	{ "set_class", "s", types + 0 },
+	{ "pong", "u", wayland_types + 0 },
+	{ "move", "ou", wayland_types + 39 },
+	{ "resize", "ouu", wayland_types + 41 },
+	{ "set_toplevel", "", wayland_types + 0 },
+	{ "set_transient", "oiiu", wayland_types + 44 },
+	{ "set_fullscreen", "uu?o", wayland_types + 48 },
+	{ "set_popup", "ouoiiu", wayland_types + 51 },
+	{ "set_maximized", "?o", wayland_types + 57 },
+	{ "set_title", "s", wayland_types + 0 },
+	{ "set_class", "s", wayland_types + 0 },
 };
 
 static const struct wl_message wl_shell_surface_events[] = {
-	{ "ping", "u", types + 0 },
-	{ "configure", "uii", types + 0 },
-	{ "popup_done", "", types + 0 },
+	{ "ping", "u", wayland_types + 0 },
+	{ "configure", "uii", wayland_types + 0 },
+	{ "popup_done", "", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_shell_surface_interface = {
@@ -347,21 +347,21 @@
 };
 
 static const struct wl_message wl_surface_requests[] = {
-	{ "destroy", "", types + 0 },
-	{ "attach", "?oii", types + 58 },
-	{ "damage", "iiii", types + 0 },
-	{ "frame", "n", types + 61 },
-	{ "set_opaque_region", "?o", types + 62 },
-	{ "set_input_region", "?o", types + 63 },
-	{ "commit", "", types + 0 },
-	{ "set_buffer_transform", "2i", types + 0 },
-	{ "set_buffer_scale", "3i", types + 0 },
-	{ "damage_buffer", "4iiii", types + 0 },
+	{ "destroy", "", wayland_types + 0 },
+	{ "attach", "?oii", wayland_types + 58 },
+	{ "damage", "iiii", wayland_types + 0 },
+	{ "frame", "n", wayland_types + 61 },
+	{ "set_opaque_region", "?o", wayland_types + 62 },
+	{ "set_input_region", "?o", wayland_types + 63 },
+	{ "commit", "", wayland_types + 0 },
+	{ "set_buffer_transform", "2i", wayland_types + 0 },
+	{ "set_buffer_scale", "3i", wayland_types + 0 },
+	{ "damage_buffer", "4iiii", wayland_types + 0 },
 };
 
 static const struct wl_message wl_surface_events[] = {
-	{ "enter", "o", types + 64 },
-	{ "leave", "o", types + 65 },
+	{ "enter", "o", wayland_types + 64 },
+	{ "leave", "o", wayland_types + 65 },
 };
 
 WL_EXPORT const struct wl_interface wl_surface_interface = {
@@ -371,15 +371,15 @@
 };
 
 static const struct wl_message wl_seat_requests[] = {
-	{ "get_pointer", "n", types + 66 },
-	{ "get_keyboard", "n", types + 67 },
-	{ "get_touch", "n", types + 68 },
-	{ "release", "5", types + 0 },
+	{ "get_pointer", "n", wayland_types + 66 },
+	{ "get_keyboard", "n", wayland_types + 67 },
+	{ "get_touch", "n", wayland_types + 68 },
+	{ "release", "5", wayland_types + 0 },
 };
 
 static const struct wl_message wl_seat_events[] = {
-	{ "capabilities", "u", types + 0 },
-	{ "name", "2s", types + 0 },
+	{ "capabilities", "u", wayland_types + 0 },
+	{ "name", "2s", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_seat_interface = {
@@ -389,20 +389,20 @@
 };
 
 static const struct wl_message wl_pointer_requests[] = {
-	{ "set_cursor", "u?oii", types + 69 },
-	{ "release", "3", types + 0 },
+	{ "set_cursor", "u?oii", wayland_types + 69 },
+	{ "release", "3", wayland_types + 0 },
 };
 
 static const struct wl_message wl_pointer_events[] = {
-	{ "enter", "uoff", types + 73 },
-	{ "leave", "uo", types + 77 },
-	{ "motion", "uff", types + 0 },
-	{ "button", "uuuu", types + 0 },
-	{ "axis", "uuf", types + 0 },
-	{ "frame", "5", types + 0 },
-	{ "axis_source", "5u", types + 0 },
-	{ "axis_stop", "5uu", types + 0 },
-	{ "axis_discrete", "5ui", types + 0 },
+	{ "enter", "uoff", wayland_types + 73 },
+	{ "leave", "uo", wayland_types + 77 },
+	{ "motion", "uff", wayland_types + 0 },
+	{ "button", "uuuu", wayland_types + 0 },
+	{ "axis", "uuf", wayland_types + 0 },
+	{ "frame", "5", wayland_types + 0 },
+	{ "axis_source", "5u", wayland_types + 0 },
+	{ "axis_stop", "5uu", wayland_types + 0 },
+	{ "axis_discrete", "5ui", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_pointer_interface = {
@@ -412,16 +412,16 @@
 };
 
 static const struct wl_message wl_keyboard_requests[] = {
-	{ "release", "3", types + 0 },
+	{ "release", "3", wayland_types + 0 },
 };
 
 static const struct wl_message wl_keyboard_events[] = {
-	{ "keymap", "uhu", types + 0 },
-	{ "enter", "uoa", types + 79 },
-	{ "leave", "uo", types + 82 },
-	{ "key", "uuuu", types + 0 },
-	{ "modifiers", "uuuuu", types + 0 },
-	{ "repeat_info", "4ii", types + 0 },
+	{ "keymap", "uhu", wayland_types + 0 },
+	{ "enter", "uoa", wayland_types + 79 },
+	{ "leave", "uo", wayland_types + 82 },
+	{ "key", "uuuu", wayland_types + 0 },
+	{ "modifiers", "uuuuu", wayland_types + 0 },
+	{ "repeat_info", "4ii", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_keyboard_interface = {
@@ -431,17 +431,17 @@
 };
 
 static const struct wl_message wl_touch_requests[] = {
-	{ "release", "3", types + 0 },
+	{ "release", "3", wayland_types + 0 },
 };
 
 static const struct wl_message wl_touch_events[] = {
-	{ "down", "uuoiff", types + 84 },
-	{ "up", "uui", types + 0 },
-	{ "motion", "uiff", types + 0 },
-	{ "frame", "", types + 0 },
-	{ "cancel", "", types + 0 },
-	{ "shape", "6iff", types + 0 },
-	{ "orientation", "6if", types + 0 },
+	{ "down", "uuoiff", wayland_types + 84 },
+	{ "up", "uui", wayland_types + 0 },
+	{ "motion", "uiff", wayland_types + 0 },
+	{ "frame", "", wayland_types + 0 },
+	{ "cancel", "", wayland_types + 0 },
+	{ "shape", "6iff", wayland_types + 0 },
+	{ "orientation", "6if", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_touch_interface = {
@@ -451,14 +451,14 @@
 };
 
 static const struct wl_message wl_output_requests[] = {
-	{ "release", "3", types + 0 },
+	{ "release", "3", wayland_types + 0 },
 };
 
 static const struct wl_message wl_output_events[] = {
-	{ "geometry", "iiiiissi", types + 0 },
-	{ "mode", "uiii", types + 0 },
-	{ "done", "2", types + 0 },
-	{ "scale", "2i", types + 0 },
+	{ "geometry", "iiiiissi", wayland_types + 0 },
+	{ "mode", "uiii", wayland_types + 0 },
+	{ "done", "2", wayland_types + 0 },
+	{ "scale", "2i", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_output_interface = {
@@ -468,9 +468,9 @@
 };
 
 static const struct wl_message wl_region_requests[] = {
-	{ "destroy", "", types + 0 },
-	{ "add", "iiii", types + 0 },
-	{ "subtract", "iiii", types + 0 },
+	{ "destroy", "", wayland_types + 0 },
+	{ "add", "iiii", wayland_types + 0 },
+	{ "subtract", "iiii", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_region_interface = {
@@ -480,8 +480,8 @@
 };
 
 static const struct wl_message wl_subcompositor_requests[] = {
-	{ "destroy", "", types + 0 },
-	{ "get_subsurface", "noo", types + 90 },
+	{ "destroy", "", wayland_types + 0 },
+	{ "get_subsurface", "noo", wayland_types + 90 },
 };
 
 WL_EXPORT const struct wl_interface wl_subcompositor_interface = {
@@ -491,12 +491,12 @@
 };
 
 static const struct wl_message wl_subsurface_requests[] = {
-	{ "destroy", "", types + 0 },
-	{ "set_position", "ii", types + 0 },
-	{ "place_above", "o", types + 93 },
-	{ "place_below", "o", types + 94 },
-	{ "set_sync", "", types + 0 },
-	{ "set_desync", "", types + 0 },
+	{ "destroy", "", wayland_types + 0 },
+	{ "set_position", "ii", wayland_types + 0 },
+	{ "place_above", "o", wayland_types + 93 },
+	{ "place_below", "o", wayland_types + 94 },
+	{ "set_sync", "", wayland_types + 0 },
+	{ "set_desync", "", wayland_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface wl_subsurface_interface = {
diff --git a/tests/data/example-server.h b/tests/data/example-server.h
index adfc973..3311c5d 100644
--- a/tests/data/example-server.h
+++ b/tests/data/example-server.h
@@ -91,6 +91,8 @@
 struct wl_surface;
 struct wl_touch;
 
+#ifndef WL_DISPLAY_INTERFACE
+#define WL_DISPLAY_INTERFACE
 /**
  * @page page_iface_wl_display wl_display
  * @section page_iface_wl_display_desc Description
@@ -107,6 +109,9 @@
  * is used for internal Wayland protocol features.
  */
 extern const struct wl_interface wl_display_interface;
+#endif
+#ifndef WL_REGISTRY_INTERFACE
+#define WL_REGISTRY_INTERFACE
 /**
  * @page page_iface_wl_registry wl_registry
  * @section page_iface_wl_registry_desc Description
@@ -159,6 +164,9 @@
  * the object.
  */
 extern const struct wl_interface wl_registry_interface;
+#endif
+#ifndef WL_CALLBACK_INTERFACE
+#define WL_CALLBACK_INTERFACE
 /**
  * @page page_iface_wl_callback wl_callback
  * @section page_iface_wl_callback_desc Description
@@ -175,6 +183,9 @@
  * the related request is done.
  */
 extern const struct wl_interface wl_callback_interface;
+#endif
+#ifndef WL_COMPOSITOR_INTERFACE
+#define WL_COMPOSITOR_INTERFACE
 /**
  * @page page_iface_wl_compositor wl_compositor
  * @section page_iface_wl_compositor_desc Description
@@ -193,6 +204,9 @@
  * surfaces into one displayable output.
  */
 extern const struct wl_interface wl_compositor_interface;
+#endif
+#ifndef WL_SHM_POOL_INTERFACE
+#define WL_SHM_POOL_INTERFACE
 /**
  * @page page_iface_wl_shm_pool wl_shm_pool
  * @section page_iface_wl_shm_pool_desc Description
@@ -219,6 +233,9 @@
  * a surface or for many small buffers.
  */
 extern const struct wl_interface wl_shm_pool_interface;
+#endif
+#ifndef WL_SHM_INTERFACE
+#define WL_SHM_INTERFACE
 /**
  * @page page_iface_wl_shm wl_shm
  * @section page_iface_wl_shm_desc Description
@@ -249,6 +266,9 @@
  * that can be used for buffers.
  */
 extern const struct wl_interface wl_shm_interface;
+#endif
+#ifndef WL_BUFFER_INTERFACE
+#define WL_BUFFER_INTERFACE
 /**
  * @page page_iface_wl_buffer wl_buffer
  * @section page_iface_wl_buffer_desc Description
@@ -271,6 +291,9 @@
  * updates the contents is defined by the buffer factory interface.
  */
 extern const struct wl_interface wl_buffer_interface;
+#endif
+#ifndef WL_DATA_OFFER_INTERFACE
+#define WL_DATA_OFFER_INTERFACE
 /**
  * @page page_iface_wl_data_offer wl_data_offer
  * @section page_iface_wl_data_offer_desc Description
@@ -295,6 +318,9 @@
  * data directly from the source client.
  */
 extern const struct wl_interface wl_data_offer_interface;
+#endif
+#ifndef WL_DATA_SOURCE_INTERFACE
+#define WL_DATA_SOURCE_INTERFACE
 /**
  * @page page_iface_wl_data_source wl_data_source
  * @section page_iface_wl_data_source_desc Description
@@ -315,6 +341,9 @@
  * to requests to transfer the data.
  */
 extern const struct wl_interface wl_data_source_interface;
+#endif
+#ifndef WL_DATA_DEVICE_INTERFACE
+#define WL_DATA_DEVICE_INTERFACE
 /**
  * @page page_iface_wl_data_device wl_data_device
  * @section page_iface_wl_data_device_desc Description
@@ -337,6 +366,9 @@
  * mechanisms such as copy-and-paste and drag-and-drop.
  */
 extern const struct wl_interface wl_data_device_interface;
+#endif
+#ifndef WL_DATA_DEVICE_MANAGER_INTERFACE
+#define WL_DATA_DEVICE_MANAGER_INTERFACE
 /**
  * @page page_iface_wl_data_device_manager wl_data_device_manager
  * @section page_iface_wl_data_device_manager_desc Description
@@ -369,6 +401,9 @@
  * wl_data_offer.accept and wl_data_offer.finish for details.
  */
 extern const struct wl_interface wl_data_device_manager_interface;
+#endif
+#ifndef WL_SHELL_INTERFACE
+#define WL_SHELL_INTERFACE
 /**
  * @page page_iface_wl_shell wl_shell
  * @section page_iface_wl_shell_desc Description
@@ -391,6 +426,9 @@
  * a basic surface.
  */
 extern const struct wl_interface wl_shell_interface;
+#endif
+#ifndef WL_SHELL_SURFACE_INTERFACE
+#define WL_SHELL_SURFACE_INTERFACE
 /**
  * @page page_iface_wl_shell_surface wl_shell_surface
  * @section page_iface_wl_shell_surface_desc Description
@@ -425,6 +463,9 @@
  * the wl_surface object.
  */
 extern const struct wl_interface wl_shell_surface_interface;
+#endif
+#ifndef WL_SURFACE_INTERFACE
+#define WL_SURFACE_INTERFACE
 /**
  * @page page_iface_wl_surface wl_surface
  * @section page_iface_wl_surface_desc Description
@@ -515,6 +556,9 @@
  * switching is not allowed).
  */
 extern const struct wl_interface wl_surface_interface;
+#endif
+#ifndef WL_SEAT_INTERFACE
+#define WL_SEAT_INTERFACE
 /**
  * @page page_iface_wl_seat wl_seat
  * @section page_iface_wl_seat_desc Description
@@ -535,6 +579,9 @@
  * maintains a keyboard focus and a pointer focus.
  */
 extern const struct wl_interface wl_seat_interface;
+#endif
+#ifndef WL_POINTER_INTERFACE
+#define WL_POINTER_INTERFACE
 /**
  * @page page_iface_wl_pointer wl_pointer
  * @section page_iface_wl_pointer_desc Description
@@ -563,6 +610,9 @@
  * and scrolling.
  */
 extern const struct wl_interface wl_pointer_interface;
+#endif
+#ifndef WL_KEYBOARD_INTERFACE
+#define WL_KEYBOARD_INTERFACE
 /**
  * @page page_iface_wl_keyboard wl_keyboard
  * @section page_iface_wl_keyboard_desc Description
@@ -579,6 +629,9 @@
  * associated with a seat.
  */
 extern const struct wl_interface wl_keyboard_interface;
+#endif
+#ifndef WL_TOUCH_INTERFACE
+#define WL_TOUCH_INTERFACE
 /**
  * @page page_iface_wl_touch wl_touch
  * @section page_iface_wl_touch_desc Description
@@ -607,6 +660,9 @@
  * contact point can be identified by the ID of the sequence.
  */
 extern const struct wl_interface wl_touch_interface;
+#endif
+#ifndef WL_OUTPUT_INTERFACE
+#define WL_OUTPUT_INTERFACE
 /**
  * @page page_iface_wl_output wl_output
  * @section page_iface_wl_output_desc Description
@@ -631,6 +687,9 @@
  * as global during start up, or when a monitor is hotplugged.
  */
 extern const struct wl_interface wl_output_interface;
+#endif
+#ifndef WL_REGION_INTERFACE
+#define WL_REGION_INTERFACE
 /**
  * @page page_iface_wl_region wl_region
  * @section page_iface_wl_region_desc Description
@@ -651,6 +710,9 @@
  * regions of a surface.
  */
 extern const struct wl_interface wl_region_interface;
+#endif
+#ifndef WL_SUBCOMPOSITOR_INTERFACE
+#define WL_SUBCOMPOSITOR_INTERFACE
 /**
  * @page page_iface_wl_subcompositor wl_subcompositor
  * @section page_iface_wl_subcompositor_desc Description
@@ -701,6 +763,9 @@
  * processing to dedicated overlay hardware when possible.
  */
 extern const struct wl_interface wl_subcompositor_interface;
+#endif
+#ifndef WL_SUBSURFACE_INTERFACE
+#define WL_SUBSURFACE_INTERFACE
 /**
  * @page page_iface_wl_subsurface wl_subsurface
  * @section page_iface_wl_subsurface_desc Description
@@ -811,6 +876,7 @@
  * unmapped.
  */
 extern const struct wl_interface wl_subsurface_interface;
+#endif
 
 #ifndef WL_DISPLAY_ERROR_ENUM
 #define WL_DISPLAY_ERROR_ENUM
diff --git a/tests/data/small-client-core.h b/tests/data/small-client-core.h
index c85cca6..d424757 100644
--- a/tests/data/small-client-core.h
+++ b/tests/data/small-client-core.h
@@ -46,6 +46,8 @@
 struct intf_A;
 struct intf_not_here;
 
+#ifndef INTF_A_INTERFACE
+#define INTF_A_INTERFACE
 /**
  * @page page_iface_intf_A intf_A
  * @section page_iface_intf_A_desc Description
@@ -60,6 +62,7 @@
  * A useless example trying to tickle the scanner.
  */
 extern const struct wl_interface intf_A_interface;
+#endif
 
 #ifndef INTF_A_FOO_ENUM
 #define INTF_A_FOO_ENUM
diff --git a/tests/data/small-client.h b/tests/data/small-client.h
index 884346d..2a1f961 100644
--- a/tests/data/small-client.h
+++ b/tests/data/small-client.h
@@ -46,6 +46,8 @@
 struct intf_A;
 struct intf_not_here;
 
+#ifndef INTF_A_INTERFACE
+#define INTF_A_INTERFACE
 /**
  * @page page_iface_intf_A intf_A
  * @section page_iface_intf_A_desc Description
@@ -60,6 +62,7 @@
  * A useless example trying to tickle the scanner.
  */
 extern const struct wl_interface intf_A_interface;
+#endif
 
 #ifndef INTF_A_FOO_ENUM
 #define INTF_A_FOO_ENUM
diff --git a/tests/data/small-code-core.c b/tests/data/small-code-core.c
index 28a00ab..bd6d33d 100644
--- a/tests/data/small-code-core.c
+++ b/tests/data/small-code-core.c
@@ -32,7 +32,7 @@
 extern const struct wl_interface another_intf_interface;
 extern const struct wl_interface intf_not_here_interface;
 
-static const struct wl_interface *types[] = {
+static const struct wl_interface *small_test_types[] = {
 	NULL,
 	&intf_not_here_interface,
 	NULL,
@@ -44,13 +44,13 @@
 };
 
 static const struct wl_message intf_A_requests[] = {
-	{ "rq1", "sun", types + 0 },
-	{ "rq2", "nsiufho", types + 1 },
-	{ "destroy", "", types + 0 },
+	{ "rq1", "sun", small_test_types + 0 },
+	{ "rq2", "nsiufho", small_test_types + 1 },
+	{ "destroy", "", small_test_types + 0 },
 };
 
 static const struct wl_message intf_A_events[] = {
-	{ "hey", "", types + 0 },
+	{ "hey", "", small_test_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface intf_A_interface = {
diff --git a/tests/data/small-code.c b/tests/data/small-code.c
index 28a00ab..bd6d33d 100644
--- a/tests/data/small-code.c
+++ b/tests/data/small-code.c
@@ -32,7 +32,7 @@
 extern const struct wl_interface another_intf_interface;
 extern const struct wl_interface intf_not_here_interface;
 
-static const struct wl_interface *types[] = {
+static const struct wl_interface *small_test_types[] = {
 	NULL,
 	&intf_not_here_interface,
 	NULL,
@@ -44,13 +44,13 @@
 };
 
 static const struct wl_message intf_A_requests[] = {
-	{ "rq1", "sun", types + 0 },
-	{ "rq2", "nsiufho", types + 1 },
-	{ "destroy", "", types + 0 },
+	{ "rq1", "sun", small_test_types + 0 },
+	{ "rq2", "nsiufho", small_test_types + 1 },
+	{ "destroy", "", small_test_types + 0 },
 };
 
 static const struct wl_message intf_A_events[] = {
-	{ "hey", "", types + 0 },
+	{ "hey", "", small_test_types + 0 },
 };
 
 WL_EXPORT const struct wl_interface intf_A_interface = {
diff --git a/tests/data/small-private-code.c b/tests/data/small-private-code.c
index 5e0bc88..fe035ff 100644
--- a/tests/data/small-private-code.c
+++ b/tests/data/small-private-code.c
@@ -42,7 +42,7 @@
 extern const struct wl_interface another_intf_interface;
 extern const struct wl_interface intf_not_here_interface;
 
-static const struct wl_interface *types[] = {
+static const struct wl_interface *small_test_types[] = {
 	NULL,
 	&intf_not_here_interface,
 	NULL,
@@ -54,13 +54,13 @@
 };
 
 static const struct wl_message intf_A_requests[] = {
-	{ "rq1", "sun", types + 0 },
-	{ "rq2", "nsiufho", types + 1 },
-	{ "destroy", "", types + 0 },
+	{ "rq1", "sun", small_test_types + 0 },
+	{ "rq2", "nsiufho", small_test_types + 1 },
+	{ "destroy", "", small_test_types + 0 },
 };
 
 static const struct wl_message intf_A_events[] = {
-	{ "hey", "", types + 0 },
+	{ "hey", "", small_test_types + 0 },
 };
 
 WL_PRIVATE const struct wl_interface intf_A_interface = {
diff --git a/tests/data/small-server-core.h b/tests/data/small-server-core.h
index 6dd2d05..f0fd1f9 100644
--- a/tests/data/small-server-core.h
+++ b/tests/data/small-server-core.h
@@ -49,6 +49,8 @@
 struct intf_A;
 struct intf_not_here;
 
+#ifndef INTF_A_INTERFACE
+#define INTF_A_INTERFACE
 /**
  * @page page_iface_intf_A intf_A
  * @section page_iface_intf_A_desc Description
@@ -63,6 +65,7 @@
  * A useless example trying to tickle the scanner.
  */
 extern const struct wl_interface intf_A_interface;
+#endif
 
 #ifndef INTF_A_FOO_ENUM
 #define INTF_A_FOO_ENUM
diff --git a/tests/data/small-server.h b/tests/data/small-server.h
index 4763f5b..22b8113 100644
--- a/tests/data/small-server.h
+++ b/tests/data/small-server.h
@@ -49,6 +49,8 @@
 struct intf_A;
 struct intf_not_here;
 
+#ifndef INTF_A_INTERFACE
+#define INTF_A_INTERFACE
 /**
  * @page page_iface_intf_A intf_A
  * @section page_iface_intf_A_desc Description
@@ -63,6 +65,7 @@
  * A useless example trying to tickle the scanner.
  */
 extern const struct wl_interface intf_A_interface;
+#endif
 
 #ifndef INTF_A_FOO_ENUM
 #define INTF_A_FOO_ENUM
diff --git a/tests/data/small.xml b/tests/data/small.xml
index a6e62ad..832ed0e 100644
--- a/tests/data/small.xml
+++ b/tests/data/small.xml
@@ -50,9 +50,9 @@
     <event name="hey"/>
 
     <enum name="foo">
-        <entry name="first" value="0" summary="this is the first"/>
-        <entry name="second" value="1" summary="this is the second"/>
-        <entry name="third" value="2" since="2" summary="this is the third"/>
+	<entry name="first" value="0" summary="this is the first"/>
+	<entry name="second" value="1" summary="this is the second"/>
+	<entry name="third" value="2" since="2" summary="this is the third"/>
     </enum>
   </interface>
 </protocol>
diff --git a/tests/display-test.c b/tests/display-test.c
index 6d98cc7..3db7c95 100644
--- a/tests/display-test.c
+++ b/tests/display-test.c
@@ -60,7 +60,7 @@
 {
 	struct display_destroy_listener *listener;
 
-	listener = container_of(l, struct display_destroy_listener, listener);
+	listener = wl_container_of(l, listener, listener);
 	listener->done = 1;
 }
 
@@ -1355,3 +1355,277 @@
 
 	display_destroy(d);
 }
+
+
+static void
+registry_bind_interface_mismatch_handle_global(void *data,
+					       struct wl_registry *registry,
+					       uint32_t id, const char *intf,
+					       uint32_t ver)
+{
+	uint32_t *seat_id_ptr = data;
+
+	if (strcmp(intf, wl_seat_interface.name) == 0) {
+		*seat_id_ptr = id;
+	}
+}
+
+static const struct wl_registry_listener bind_interface_mismatch_registry_listener = {
+	registry_bind_interface_mismatch_handle_global,
+	NULL
+};
+
+static void
+registry_bind_interface_mismatch_client(void *data)
+{
+	struct client *c = client_connect();
+	struct wl_registry *registry;
+	uint32_t seat_id = 0;
+	void *ptr;
+	int ret;
+
+	registry = wl_display_get_registry(c->wl_display);
+	wl_registry_add_listener(registry,
+				 &bind_interface_mismatch_registry_listener,
+				 &seat_id);
+
+	ret = wl_display_roundtrip(c->wl_display);
+	assert(ret >= 0);
+	assert(seat_id != 0);
+
+	/* Bind with a different interface */
+	ptr = wl_registry_bind(registry, seat_id, &wl_output_interface, 1);
+	ret = wl_display_roundtrip(c->wl_display);
+	assert(ret < 0);
+	check_bind_error(c);
+
+	wl_proxy_destroy((struct wl_proxy *) ptr);
+	wl_registry_destroy(registry);
+
+	client_disconnect_nocheck(c);
+}
+
+TEST(registry_bind_interface_mismatch)
+{
+	struct display *d;
+	struct wl_global *seat_global;
+
+	d = display_create();
+
+	seat_global = wl_global_create(d->wl_display, &wl_seat_interface,
+				       1, NULL, NULL);
+
+	client_create_noarg(d, registry_bind_interface_mismatch_client);
+	display_run(d);
+
+	wl_global_destroy(seat_global);
+
+	display_destroy(d);
+}
+
+static void
+send_overflow_client(void *data)
+{
+	struct client *c = client_connect();
+	int i, err = 0;
+	int *pipes = data;
+	char tmp = '\0';
+	int sock, optval = 16384;
+
+	/* Limit the send buffer size for the display socket to guarantee
+	 * that the test will cause an overflow. */
+	sock = wl_display_get_fd(c->wl_display);
+	assert(setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &optval, sizeof(optval)) == 0);
+
+	/* Request to break out of 'display_run' in the main process */
+	assert(stop_display(c, 1) >= 0);
+
+	/* On Linux, the actual socket data + metadata space is twice `optval`;
+	 * since each noop request requires 8 bytes, the buffer should overflow
+	 * within <=4096 iterations. */
+	for (i = 0; i < 1000000; i++) {
+		noop_request(c);
+		err = wl_display_get_error(c->wl_display);
+		if (err)
+			break;
+	}
+
+	/* Do not close the pipe file descriptors afterwards, because the leak
+	 * check verifies that the initial/final FD counts are the same */
+	assert(write(pipes[1], &tmp, sizeof(tmp)) == (ssize_t)sizeof(tmp));
+
+	/* Expect an error */
+	fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err));
+	assert(err == EAGAIN);
+
+	client_disconnect_nocheck(c);
+}
+
+TEST(send_overflow_disconnection)
+{
+	struct display *d;
+	char tmp;
+	int rpipe[2];
+	ssize_t ret;
+
+	assert(pipe(rpipe) != -1);
+
+	d = display_create();
+
+	(void) client_create(d, send_overflow_client, &rpipe);
+
+	/* Close write end of the pipe, so that the later read() call gets
+	 * interrupted if the client dies */
+	close(rpipe[1]);
+
+	/* Run the display until the client sends a `stop_display`, then
+	 * send a resume message but don't actually look at new messages */
+	display_run(d);
+	display_post_resume_events(d);
+	wl_display_flush_clients(d->wl_display);
+
+	/* Wait until all noop requests have been sent (read returns 1), or
+	 * until client process aborts (read returns 0) */
+	do {
+		ret = read(rpipe[0], &tmp, sizeof(tmp));
+	} while (ret == -1 && errno == EINTR);
+	assert(ret != -1);
+	close(rpipe[0]);
+
+	/* For a clean shutdown */
+	display_run(d);
+
+	display_destroy(d);
+}
+
+static void
+registry_global_remove_before_handle_global(void *data,
+					    struct wl_registry *registry,
+					    uint32_t id, const char *intf,
+					    uint32_t ver)
+{
+	uint32_t *id_ptr = data;
+
+	if (strcmp(intf, wl_seat_interface.name) == 0) {
+		assert(*id_ptr == 0);
+		*id_ptr = id;
+	}
+}
+
+static void
+registry_global_remove_before_handle_global_remove(void *data,
+						   struct wl_registry *registry,
+						   uint32_t id)
+{
+	uint32_t *id_ptr = data;
+
+	if (*id_ptr == id) {
+		*id_ptr = 0;
+	}
+}
+
+/* This listener expects a uint32_t user data pointer, sets it to the wl_seat
+ * global ID when receiving a "global" event, and sets it to zero when receiving
+ * a "global_remove" event. */
+static const struct wl_registry_listener global_remove_before_registry_listener = {
+	registry_global_remove_before_handle_global,
+	registry_global_remove_before_handle_global_remove,
+};
+
+static void
+global_remove_before_client(void *data)
+{
+	struct client *c = client_connect();
+	struct wl_registry *registry;
+	uint32_t global_id = 0, saved_global_id;
+	struct wl_seat *seat;
+	int ret;
+
+	registry = wl_display_get_registry(c->wl_display);
+	wl_registry_add_listener(registry,
+				 &global_remove_before_registry_listener,
+				 &global_id);
+
+	ret = wl_display_roundtrip(c->wl_display);
+	assert(ret >= 0);
+	assert(global_id != 0);
+	saved_global_id = global_id;
+
+	/* Wait for the compositor to remove the global */
+	assert(stop_display(c, 1) >= 0);
+
+	/* Check binding still works after the global has been removed. Also
+	 * check we get the global_remove event. */
+	seat = wl_registry_bind(registry, saved_global_id, &wl_seat_interface, 1);
+	ret = wl_display_roundtrip(c->wl_display);
+	assert(ret >= 0);
+	assert(global_id == 0);
+
+	wl_seat_destroy(seat);
+	wl_registry_destroy(registry);
+
+	client_disconnect(c);
+}
+
+static void
+registry_global_remove_after_handle_global(void *data,
+					   struct wl_registry *registry,
+					   uint32_t id, const char *intf,
+					   uint32_t ver)
+{
+	/* Make sure the global isn't advertised anymore after being removed */
+	assert(strcmp(intf, wl_seat_interface.name) != 0);
+}
+
+static const struct wl_registry_listener global_remove_after_registry_listener = {
+	registry_global_remove_after_handle_global,
+	NULL,
+};
+
+static void
+global_remove_after_client(void *data)
+{
+	struct client *c = client_connect();
+	struct wl_registry *registry;
+	uint32_t global_id = 0;
+	int ret;
+
+	registry = wl_display_get_registry(c->wl_display);
+	wl_registry_add_listener(registry,
+				 &global_remove_after_registry_listener,
+				 &global_id);
+
+	ret = wl_display_roundtrip(c->wl_display);
+	assert(ret >= 0);
+
+	wl_registry_destroy(registry);
+
+	client_disconnect(c);
+}
+
+TEST(global_remove)
+{
+	struct display *d;
+	struct wl_global *global;
+
+	d = display_create();
+
+	global = wl_global_create(d->wl_display, &wl_seat_interface,
+				  1, d, bind_seat);
+
+	/* Create a client before removing the global */
+	client_create_noarg(d, global_remove_before_client);
+
+	display_run(d);
+
+	wl_global_remove(global);
+
+	/* Create another client after removing the global */
+	client_create_noarg(d, global_remove_after_client);
+
+	display_resume(d);
+
+	wl_global_destroy(global);
+
+	display_destroy(d);
+}
diff --git a/tests/event-loop-test.c b/tests/event-loop-test.c
index 33566b4..cbeaf8e 100644
--- a/tests/event-loop-test.c
+++ b/tests/event-loop-test.c
@@ -29,6 +29,7 @@
 #include <assert.h>
 #include <unistd.h>
 #include <signal.h>
+#include <string.h>
 #include <sys/time.h>
 
 #include "wayland-private.h"
@@ -229,18 +230,33 @@
 TEST(event_loop_timer)
 {
 	struct wl_event_loop *loop = wl_event_loop_create();
-	struct wl_event_source *source;
+	struct wl_event_source *source1, *source2;
 	int got_it = 0;
 
-	source = wl_event_loop_add_timer(loop, timer_callback, &got_it);
-	assert(source);
-	wl_event_source_timer_update(source, 10);
-	wl_event_loop_dispatch(loop, 0);
-	assert(!got_it);
-	wl_event_loop_dispatch(loop, 20);
-	assert(got_it == 1);
+	source1 = wl_event_loop_add_timer(loop, timer_callback, &got_it);
+	assert(source1);
+	wl_event_source_timer_update(source1, 20);
 
-	wl_event_source_remove(source);
+	source2 = wl_event_loop_add_timer(loop, timer_callback, &got_it);
+	assert(source2);
+	wl_event_source_timer_update(source2, 100);
+
+	/* Check that the timer marked for 20 msec from now fires within 30
+	 * msec, and that the timer marked for 100 msec is expected to fire
+	 * within an additional 90 msec. (Some extra wait time is provided to
+	 * account for reasonable code execution / thread preemption delays.) */
+
+	wl_event_loop_dispatch(loop, 0);
+	assert(got_it == 0);
+	wl_event_loop_dispatch(loop, 30);
+	assert(got_it == 1);
+	wl_event_loop_dispatch(loop, 0);
+	assert(got_it == 1);
+	wl_event_loop_dispatch(loop, 90);
+	assert(got_it == 2);
+
+	wl_event_source_remove(source1);
+	wl_event_source_remove(source2);
 	wl_event_loop_destroy(loop);
 }
 
@@ -330,6 +346,138 @@
 	wl_event_loop_destroy(loop);
 }
 
+struct timer_order_data {
+	struct wl_event_source *source;
+	int *last_number;
+	int number;
+};
+
+static int
+timer_order_callback(void *data)
+{
+	struct timer_order_data *tod = data;
+
+	/* Check that the timers have the correct sequence */
+	assert(tod->number == *tod->last_number + 2);
+	*tod->last_number = tod->number;
+	return 0;
+}
+
+TEST(event_loop_timer_order)
+{
+	struct wl_event_loop *loop = wl_event_loop_create();
+	struct timer_order_data order[20];
+	int i, j;
+	int last = -1;
+
+	/* Configure a set of timers so that only timers 1, 3, 5, ..., 19
+	 * (in that order) will be dispatched when the event loop is run */
+
+	for (i = 0; i < 20; i++) {
+		order[i].number = i;
+		order[i].last_number = &last;
+		order[i].source =
+			wl_event_loop_add_timer(loop, timer_order_callback,
+						&order[i]);
+		assert(order[i].source);
+		assert(wl_event_source_timer_update(order[i].source, 10) == 0);
+	}
+
+	for (i = 0; i < 20; i++) {
+		/* Permute the order in which timers are updated, so as to
+		 * more exhaustively test the underlying priority queue code */
+		j = ((i + 3) * 17) % 20;
+		assert(wl_event_source_timer_update(order[j].source, j) == 0);
+	}
+	for (i = 0; i < 20; i += 2) {
+		assert(wl_event_source_timer_update(order[i].source, 0) == 0);
+	}
+
+	/* Wait until all timers are due */
+	usleep(MSEC_TO_USEC(21));
+	wl_event_loop_dispatch(loop, 0);
+	assert(last == 19);
+
+	for (i = 0; i < 20; i++) {
+		wl_event_source_remove(order[i].source);
+	}
+	wl_event_loop_destroy(loop);
+}
+
+struct timer_cancel_context {
+	struct wl_event_source *timers[4];
+	struct timer_cancel_context *back_refs[4];
+	int order[4];
+	int called, first;
+};
+
+static int
+timer_cancel_callback(void *data) {
+	struct timer_cancel_context **context_ref = data;
+	struct timer_cancel_context *context = *context_ref;
+	int i = (int)(context_ref - context->back_refs);
+
+	context->called++;
+	context->order[i] = context->called;
+
+	if (context->called == 1) {
+		context->first = i;
+		/* Removing a timer always prevents its callback from
+		 * being called ... */
+		wl_event_source_remove(context->timers[(i + 1) % 4]);
+		/* ... but disarming or rescheduling a timer does not,
+		 * (in the case where the modified timers had already expired
+		 * as of when `wl_event_loop_dispatch` was called.) */
+		assert(wl_event_source_timer_update(context->timers[(i + 2) % 4],
+						    0) == 0);
+		assert(wl_event_source_timer_update(context->timers[(i + 3) % 4],
+						    2000000000) == 0);
+	}
+
+	return 0;
+}
+
+TEST(event_loop_timer_cancellation)
+{
+	struct wl_event_loop *loop = wl_event_loop_create();
+	struct timer_cancel_context context;
+	int i;
+
+	memset(&context, 0, sizeof(context));
+
+	/* Test that when multiple timers are dispatched in a single call
+	 * of `wl_event_loop_dispatch`, that having some timers run code
+	 * to modify the other timers only actually prevents the other timers
+	 * from running their callbacks when the those timers are removed, not
+	 * when they are disarmed or rescheduled. */
+
+	for (i = 0; i < 4; i++) {
+		context.back_refs[i] = &context;
+		context.timers[i] =
+			wl_event_loop_add_timer(loop, timer_cancel_callback,
+						&context.back_refs[i]);
+		assert(context.timers[i]);
+
+		assert(wl_event_source_timer_update(context.timers[i], 1) == 0);
+	}
+
+	usleep(MSEC_TO_USEC(2));
+	assert(wl_event_loop_dispatch(loop, 0) == 0);
+
+	/* Tracking which timer was first makes this test independent of the
+	 * actual timer dispatch order, which is not guaranteed by the docs */
+	assert(context.order[context.first] == 1);
+	assert(context.order[(context.first + 1) % 4] == 0);
+	assert(context.order[(context.first + 2) % 4] > 1);
+	assert(context.order[(context.first + 3) % 4] > 1);
+
+	wl_event_source_remove(context.timers[context.first]);
+	wl_event_source_remove(context.timers[(context.first + 2) % 4]);
+	wl_event_source_remove(context.timers[(context.first + 3) % 4]);
+
+	wl_event_loop_destroy(loop);
+}
+
 struct event_loop_destroy_listener {
 	struct wl_listener listener;
 	int done;
@@ -339,7 +487,7 @@
 event_loop_destroy_notify(struct wl_listener *l, void *data)
 {
 	struct event_loop_destroy_listener *listener =
-		container_of(l, struct event_loop_destroy_listener, listener);
+		wl_container_of(l, listener, listener);
 
 	listener->done = 1;
 }
diff --git a/tests/meson.build b/tests/meson.build
new file mode 100644
index 0000000..a32ac50
--- /dev/null
+++ b/tests/meson.build
@@ -0,0 +1,165 @@
+test_runner = static_library(
+	'test-runner',
+	sources: [
+		'test-runner.c',
+		'test-helpers.c',
+		'test-compositor.c'
+	],
+	include_directories: [ root_inc, src_inc ],
+	dependencies: [
+		cc.find_library('dl', required: false),
+		dependency('threads'),
+		ffi_dep,
+		wayland_util_dep,
+		wayland_private_dep,
+		wayland_client_dep,
+		wayland_server_dep
+	]
+)
+
+test_runner_dep = declare_dependency(
+	link_with: test_runner,
+	include_directories: [ src_inc ],
+	dependencies: [
+		dependency('threads'),
+		cc.find_library('dl', required: false)
+	]
+)
+
+tests_protocol_xml = files('../protocol/tests.xml')
+
+tests_server_protocol_h = custom_target(
+	'test server protocol header',
+	command: [ wayland_scanner_for_build, '-s', 'server-header', '@INPUT@', '@OUTPUT@' ],
+	input: tests_protocol_xml,
+	output: 'tests-server-protocol.h'
+)
+
+tests_client_protocol_c = custom_target(
+	'test client protocol header',
+	command: [ wayland_scanner_for_build, '-s', 'client-header', '@INPUT@', '@OUTPUT@' ],
+	input: tests_protocol_xml,
+	output: 'tests-client-protocol.h'
+)
+
+tests_protocol_c = custom_target(
+	'test protocol source',
+	command: [ wayland_scanner_for_build, '-s', 'public-code', '@INPUT@', '@OUTPUT@' ],
+	input: tests_protocol_xml,
+	output: 'tests-protocol.c'
+)
+
+benchmark(
+	'fixed-benchmark',
+	executable(
+		'fixed-benchmark',
+		'fixed-benchmark.c',
+		dependencies: [ test_runner_dep, rt_dep ]
+	)
+)
+
+executable(
+	'exec-fd-leak-checker',
+	'exec-fd-leak-checker.c',
+	dependencies: test_runner_dep
+)
+
+test(
+	'cpp-compile-test',
+	executable(
+		'cpp-compile-test',
+		'cpp-compile-test.cpp',
+		wayland_server_protocol_h,
+		include_directories: src_inc
+	)
+)
+
+sed_path = find_program('sed').path()
+
+if get_option('scanner')
+	test(
+		'scanner-test',
+		find_program('scanner-test.sh'),
+		env: [
+			'TEST_DATA_DIR=@0@/data'.format(meson.current_source_dir()),
+			'TEST_OUTPUT_DIR=@0@/output'.format(meson.current_build_dir()),
+			'SED=@0@'.format(sed_path),
+			'WAYLAND_SCANNER=@0@'.format(wayland_scanner.full_path()),
+		],
+	)
+endif
+
+tests = {
+	'array-test': [],
+	'client-test': [ wayland_server_protocol_h ],
+	'display-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+		tests_server_protocol_h,
+		tests_client_protocol_c,
+		tests_protocol_c,
+	],
+	'connection-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+	],
+	'event-loop-test': [ wayland_server_protocol_h ],
+	'fixed-test': [],
+	'interface-test': [ wayland_client_protocol_h ],
+	'list-test': [],
+	'map-test': [],
+	'sanity-test' : [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+	],
+	'socket-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+	],
+	'queue-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+	],
+	'signal-test': [ wayland_server_protocol_h ],
+	'newsignal-test': [
+		# wayland-server.c is needed here to access wl_priv_* functions
+		files('../src/wayland-server.c'),
+		wayland_server_protocol_h,
+	],
+	'resources-test': [ wayland_server_protocol_h ],
+	'message-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+	],
+	'compositor-introspection-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+	],
+	'protocol-logger-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+	],
+	'headers-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+		'headers-protocol-test.c',
+		wayland_client_protocol_core_h,
+		wayland_server_protocol_core_h,
+		'headers-protocol-core-test.c',
+	],
+	'os-wrappers-test': [],
+}
+
+foreach test_name, test_extra_sources: tests
+	test_sources = [ test_name + '.c' ] + test_extra_sources
+	test_deps = [test_runner_dep]
+	bin = executable(test_name, test_sources, dependencies: test_deps)
+	test(
+		test_name,
+		bin,
+		env: [
+			'TEST_SRC_DIR=@0@'.format(meson.current_source_dir()),
+			'TEST_BUILD_DIR=@0@'.format(meson.current_build_dir()),
+		],
+	)
+endforeach
diff --git a/tests/newsignal-test.c b/tests/newsignal-test.c
index 47c429b..051e10e 100644
--- a/tests/newsignal-test.c
+++ b/tests/newsignal-test.c
@@ -26,7 +26,7 @@
 #include <assert.h>
 
 #include "test-runner.h"
-#include "wayland-private.h"
+#include "wayland-server-private.h"
 
 static void
 signal_notify(struct wl_listener *listener, void *data)
@@ -223,7 +223,7 @@
 {
 	/* Readding a listener is supported, that is it doesn't trigger an
 	 * infinite loop or other weird things, but if in a listener you
-	 * readd another listener, that will not be fired in the current
+	 * re-add another listener, that will not be fired in the current
 	 * signal emission. */
 
 	test_set_timeout(4);
diff --git a/tests/proxy-test.c b/tests/proxy-test.c
new file mode 100644
index 0000000..c09468d
--- /dev/null
+++ b/tests/proxy-test.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2019 Red Hat, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+#include <string.h>
+
+#include "wayland-server.h"
+#include "wayland-client.h"
+#include "test-runner.h"
+
+static struct {
+	struct wl_display *display;
+	struct wl_event_loop *loop;
+	int sync_count;
+} server;
+
+static struct {
+	struct wl_display *display;
+	struct wl_callback *callback_a;
+	struct wl_callback *callback_b;
+	int callback_count;
+} client;
+
+static const char *tag_a = "tag";
+static const char *tag_b = "tag";
+
+static void
+callback_done(void *data, struct wl_callback *cb, uint32_t time)
+{
+	const char * const *expected_tag;
+	const char * const *tag;
+
+	if (cb == client.callback_a)
+		expected_tag = &tag_a;
+	else if (cb == client.callback_b)
+		expected_tag = &tag_b;
+	else
+		assert(!"unexpected callback");
+
+	tag = wl_proxy_get_tag((struct wl_proxy *) cb);
+
+	assert(tag == expected_tag);
+	assert(strcmp(*tag, "tag") == 0);
+
+	wl_callback_destroy(cb);
+
+	client.callback_count++;
+}
+
+static const struct wl_callback_listener callback_listener = {
+	callback_done,
+};
+
+static void
+logger_func(void *user_data,
+	    enum wl_protocol_logger_type type,
+	    const struct wl_protocol_logger_message *message)
+{
+	if (type != WL_PROTOCOL_LOGGER_REQUEST)
+		return;
+
+	assert(strcmp(wl_resource_get_class(message->resource),
+		      "wl_display") == 0);
+	assert(strcmp(message->message->name, "sync") == 0);
+
+	server.sync_count++;
+}
+
+TEST(proxy_tag)
+{
+	const char *socket;
+	struct wl_protocol_logger *logger;
+
+	assert(&tag_a != &tag_b);
+
+	server.display = wl_display_create();
+	assert(server.display);
+	server.loop = wl_display_get_event_loop(server.display);
+	assert(server.loop);
+	socket = wl_display_add_socket_auto(server.display);
+	assert(socket);
+	logger = wl_display_add_protocol_logger(server.display,
+						logger_func, NULL);
+	assert(logger);
+
+	client.display = wl_display_connect(socket);
+	assert(client.display);
+
+	client.callback_a = wl_display_sync(client.display);
+	wl_callback_add_listener(client.callback_a, &callback_listener, NULL);
+	wl_proxy_set_tag((struct wl_proxy *) client.callback_a,
+			 &tag_a);
+
+	client.callback_b = wl_display_sync(client.display);
+	wl_callback_add_listener(client.callback_b, &callback_listener, NULL);
+	wl_proxy_set_tag((struct wl_proxy *) client.callback_b,
+			 &tag_b);
+
+	wl_display_flush(client.display);
+
+	while (server.sync_count < 2) {
+		wl_event_loop_dispatch(server.loop, -1);
+		wl_display_flush_clients(server.display);
+	}
+
+	wl_display_dispatch(client.display);
+
+	assert(client.callback_count == 2);
+
+	wl_protocol_logger_destroy(logger);
+	wl_display_disconnect(client.display);
+	wl_event_loop_dispatch(server.loop, 100);
+
+	wl_display_destroy(server.display);
+}
diff --git a/tests/scanner-test.sh b/tests/scanner-test.sh
index ff25089..35ba047 100755
--- a/tests/scanner-test.sh
+++ b/tests/scanner-test.sh
@@ -36,6 +36,20 @@
 		fail "$2 -> $3"
 }
 
+verify_error() {
+	echo
+	echo "Checking that reading $1 gives an error on line $3"
+
+	[ -f "$TEST_DATA_DIR/$1" ] || hard_fail "$1 not present"
+
+	# Confirm failure error code
+	"$WAYLAND_SCANNER" server-header < "$TEST_DATA_DIR/$1" >/dev/null 2>"$TEST_OUTPUT_DIR/$2" && \
+		fail "$1 return code check"
+
+	# Verify that an error is produced at the correct line
+	grep -q "<stdin>:$3: error:" "$TEST_OUTPUT_DIR/$2" && echo "$1 PASS" || fail "$1 line number check"
+}
+
 generate_and_compare "code" "example.xml" "example-code.c"
 generate_and_compare "client-header" "example.xml" "example-client.h"
 generate_and_compare "server-header" "example.xml" "example-server.h"
@@ -52,4 +66,13 @@
 generate_and_compare "code" "small.xml" "small-code.c"
 generate_and_compare "public-code" "small.xml" "small-code.c"
 generate_and_compare "private-code" "small.xml" "small-private-code.c"
+
+verify_error "bad-identifier-arg.xml" "bad-identifier-arg.log" 7
+verify_error "bad-identifier-entry.xml" "bad-identifier-entry.log" 8
+verify_error "bad-identifier-enum.xml" "bad-identifier-enum.log" 6
+verify_error "bad-identifier-event.xml" "bad-identifier-event.log" 6
+verify_error "bad-identifier-interface.xml" "bad-identifier-interface.log" 3
+verify_error "bad-identifier-protocol.xml" "bad-identifier-protocol.log" 2
+verify_error "bad-identifier-request.xml" "bad-identifier-request.log" 6
+
 exit $RETCODE
diff --git a/tests/test-compositor.c b/tests/test-compositor.c
index 72f6351..468ee56 100644
--- a/tests/test-compositor.c
+++ b/tests/test-compositor.c
@@ -45,7 +45,8 @@
 
 static const struct wl_message tc_requests[] = {
 	/* this request serves as a barrier for synchronizing*/
-	{ "stop_display", "u", NULL }
+	{ "stop_display", "u", NULL },
+	{ "noop", "", NULL },
 };
 
 static const struct wl_message tc_events[] = {
@@ -54,7 +55,7 @@
 
 const struct wl_interface test_compositor_interface = {
 	"test", 1,
-	1, tc_requests,
+	2, tc_requests,
 	1, tc_events
 };
 
@@ -62,6 +63,8 @@
 	void (*stop_display)(struct wl_client *client,
 			     struct wl_resource *resource,
 			     uint32_t num);
+	void (*noop)(struct wl_client *client,
+			     struct wl_resource *resource);
 };
 
 struct test_compositor_listener {
@@ -70,7 +73,8 @@
 };
 
 enum {
-	STOP_DISPLAY = 0
+	STOP_DISPLAY = 0,
+	TEST_NOOP = 1
 };
 
 enum {
@@ -294,8 +298,16 @@
 		wl_display_terminate(d->wl_display);
 }
 
+static void
+handle_noop(struct wl_client *client, struct wl_resource *resource)
+{
+	(void)client;
+	(void)resource;
+}
+
 static const struct test_compositor_interface tc_implementation = {
-	handle_stop_display
+	handle_stop_display,
+	handle_noop,
 };
 
 static void
@@ -354,7 +366,7 @@
 }
 
 void
-display_resume(struct display *d)
+display_post_resume_events(struct display *d)
 {
 	struct wfr *wfr, *next;
 
@@ -368,7 +380,12 @@
 
 	assert(wl_list_empty(&d->waiting_for_resume));
 	d->wfr_num = 0;
+}
 
+void
+display_resume(struct display *d)
+{
+	display_post_resume_events(d);
 	wl_display_run(d->wl_display);
 }
 
@@ -509,3 +526,9 @@
 
 	return n;
 }
+
+void
+noop_request(struct client *c)
+{
+	wl_proxy_marshal((struct wl_proxy *) c->tc, TEST_NOOP);
+}
diff --git a/tests/test-compositor.h b/tests/test-compositor.h
index 876d0c0..180dad2 100644
--- a/tests/test-compositor.h
+++ b/tests/test-compositor.h
@@ -70,6 +70,7 @@
 struct client *client_connect(void);
 void client_disconnect(struct client *);
 int stop_display(struct client *, int);
+void noop_request(struct client *);
 
 /**
  * Usual workflow:
@@ -89,12 +90,21 @@
 void display_destroy(struct display *d);
 void display_run(struct display *d);
 
+/* This function posts the display_resumed event to all waiting clients,
+ * so that after flushing events the clients will stop waiting and continue.
+ *
+ * (Calling `display_run` after this function will resume the display loop.)
+ */
+void display_post_resume_events(struct display *d);
 /* After n clients called stop_display(..., n), the display
  * is stopped and can process the code after display_run().
- * This function rerun the display again and send display_resumed
- * event to waiting clients, so the clients will stop waiting and continue */
+ *
+ * This function posts the display_resumed event to the waiting
+ * clients, so that the clients will stop waiting and continue;
+ * it then reruns the display. */
 void display_resume(struct display *d);
 
+
 struct client_info *client_create_with_name(struct display *d,
 					    void (*client_main)(void *data),
 					    void *data,
diff --git a/tests/test-helpers.c b/tests/test-helpers.c
index b2189d8..20b6690 100644
--- a/tests/test-helpers.c
+++ b/tests/test-helpers.c
@@ -29,6 +29,7 @@
 #include <errno.h>
 #include <dirent.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <unistd.h>
 #include <time.h>
 #include <sys/time.h>
@@ -67,11 +68,19 @@
 void
 exec_fd_leak_check(int nr_expected_fds)
 {
-	const char *exe = "./exec-fd-leak-checker";
+	const char *exe = "exec-fd-leak-checker";
 	char number[16] = { 0 };
+	const char *test_build_dir = getenv("TEST_BUILD_DIR");
+	char exe_path[256] = { 0 };
+
+	if (test_build_dir == NULL || test_build_dir[0] == 0) {
+	        test_build_dir = ".";
+	}
+
+	snprintf(exe_path, sizeof exe_path - 1, "%s/%s", test_build_dir, exe);
 
 	snprintf(number, sizeof number - 1, "%d", nr_expected_fds);
-	execl(exe, exe, number, (char *)NULL);
+	execl(exe_path, exe, number, (char *)NULL);
 	assert(0 && "execing fd leak checker failed");
 }
 
diff --git a/tests/test-runner.c b/tests/test-runner.c
index 1487dc4..8f08445 100644
--- a/tests/test-runner.c
+++ b/tests/test-runner.c
@@ -338,7 +338,8 @@
 
 		if (waitid(P_PID, pid, &info, WEXITED)) {
 			stderr_set_color(RED);
-			fprintf(stderr, "waitid failed: %m\n");
+			fprintf(stderr, "waitid failed: %s\n",
+				strerror(errno));
 			stderr_reset_color();
 
 			abort();
diff --git a/wayland-scanner.m4 b/wayland-scanner.m4
index 4e4222a..2b222e8 100644
--- a/wayland-scanner.m4
+++ b/wayland-scanner.m4
@@ -1,7 +1,7 @@
 AC_DEFUN([WAYLAND_SCANNER_RULES], [
     PKG_PROG_PKG_CONFIG
 
-    PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner])
+    PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner >= 1.14.0])
 
     wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner`
     AC_SUBST([wayland_scanner])