diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index e6cabe7588e5c161a429165fec8dc831ed04c6de..43b6a5676fd063fe865336e2d9e6a94ce79fb6d4 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -28,7 +28,7 @@ stages:
 
 # Common variables
 variables:
-  COMMON_MESON_FLAGS: "-Dwerror=true -Dcairo:werror=false -Dgi-docgen:werror=false -Dgraphene:werror=false -Dlibepoxy:werror=false -Dlibsass:werror=false -Dpango:werror=false -Dsassc:werror=false -Dgdk-pixbuf:werror=false -Dglib:werror=false -Dlibcloudproviders:werror=false -Dlibpng:werror=false -Dlibtiff:werror=false -Dsysprof:werror=false -Dwayland-protocols:werror=false -Dharfbuzz:werror=false -Dfreetype2:werror=false -Dfontconfig:werror=false -Dfribidi:werror=false -Dlibffi:werror=false -Dlibjpeg-turbo:werror=false -Dmutest:werror=false -Dpcre2:werror=false -Dpixman:werror=false -Dproxy-libintl:werror=false"
+  COMMON_MESON_FLAGS: "-Dwerror=true -Dcairo:werror=false -Dgi-docgen:werror=false -Dgraphene:werror=false -Dlibepoxy:werror=false -Dlibsass:werror=false -Dpango:werror=false -Dsassc:werror=false -Dgdk-pixbuf:werror=false -Dglib:werror=false -Dlibcloudproviders:werror=false -Dlibpng:werror=false -Dlibtiff:werror=false -Dsysprof:werror=false -Dwayland:werror=false -Dwayland-protocols:werror=false -Dharfbuzz:werror=false -Dfreetype2:werror=false -Dfontconfig:werror=false -Dfribidi:werror=false -Dlibffi:werror=false -Dlibjpeg-turbo:werror=false -Dmutest:werror=false -Dpcre2:werror=false -Dpixman:werror=false -Dproxy-libintl:werror=false"
   BACKEND_FLAGS: "-Dx11-backend=true -Dwayland-backend=true -Dbroadway-backend=true"
   FEATURE_FLAGS: "-Dvulkan=enabled -Dcloudproviders=enabled -Dbuild-testsuite=true -Dintrospection=enabled"
   MESON_TEST_TIMEOUT_MULTIPLIER: 3
@@ -334,7 +334,7 @@ android:
     - git clone https://github.com/sp1ritCS/gtk-android-builder.git pixiewood
     - cp -f pixiewood/prepare/wraps/fontconfig/fontconfig.wrap subprojects/
     # Drop this as soon as Debian/the container has meson >= 1.7.0
-    - git clone --depth 1 https://github.com/mesonbuild/meson.git
+    - git clone --depth 1 https://github.com/mesonbuild/meson.git --branch 1.7.0
   script:
     - ./meson/meson.py setup
             --cross-file "${ANDROID_HOME}/toolchain.cross"
@@ -533,7 +533,9 @@ asan-build:
             -Dintrospection=disabled
             -Df16c=disabled
             _build
-    - ninja -C _build
+    - meson compile -C_build
+    # Work around https://gitlab.freedesktop.org/mesa/mesa/-/issues/12666
+    - rm -rf _build/subprojects/wayland/src/libwayland-server*
     - .gitlab-ci/run-tests.sh _build wayland gtk
 
 reference:
diff --git a/NEWS b/NEWS
index 5409765e28f63bf59c32ea461ab44ee45335950c..6e22689a47933223049cc91e603d889b51d13d02 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,103 @@
+Overview of Changes in 4.17.5, 23-02-2025
+=========================================
+
+* Numeric mode in GtkSpinButtons works again
+
+* Client-side dialogs can be made fully modal
+
+* Portals work better for unsandboxed apps, by registering
+
+* Editable labels have a context menu
+
+* GtkListBox size allocation has been improved
+
+* We require wayland 1.23 and wayland-protocols 1.41
+
+* We use the wp_color_manager_v1 protocol for color management under Wayland
+
+* Most screenshots in the documentation have a dark variant
+
+* GtkBuilder allows inline definition for GMenu-valued properties
+
+* Headerbars can use native window controls on macOS
+
+* Bugs fixed:
+  - #4353 Keyboard: Set shortcut does not work for key-codes > 247 (Matthias
+    Clasen)
+  - #5125 Demo / Menu: Popup at wrong position, hangs on Wayland (Matthias
+    Clasen)
+  - #5815 builder: integrate menus more properly (Matthias Clasen)
+  - #6010 gtk4-demo > Lists > Selections emits CRITICALS (Matthias Clasen)
+  - #6272 a11y: API for updating platform state for custom GtkAccessible
+    implementations is missing (Emmanuele Bassi)
+  - #6355 gtk_widget_compute_transform() not working correctly with GtkPopover
+    (Alessandro Astone)
+  - #6379 GtkListBox crashes if the placeholder is focused and then TAB is
+    pressed
+  - #7191 Have a way to block parent shortcuts in AdwDialog (Matthias Clasen)
+  - #7215 Changing the click behavior of Gtk.EditableLabel (Matthias Clasen)
+  - #7229 GSK/vulkan uses mipmaps without checking the formats/tiling
+    `VkImageFormatProperties.maxMipLevels` (Janne Grunau)
+  - #7249 Cursor hotspot and cursor image are not updated atomically on Wayland
+    (Carlos Garnacho)
+  - #7257 Unexpected spacing at the end of a textview when using child widgets.
+    (Sergey Bugaev)
+  - #7286 GtkApplicationWindow show-menubar documentation inconsistent
+  - #7307 GtkAppChooserWidget doesn't fit in a mobile screen (Automeris naranja)
+  - #7310 Inspector showing child widgets & controllers twice (Florian
+    "sp1rit"​)
+  - #7311 GtkSpinButton:numeric=True doesn't work (Matthias Clasen)
+  - #7312 Dead link in common questions
+  - #7321 mem leak in emoji chooser (Matthias Clasen)
+  - #7322 invalid array index use
+  - #7324 Missing support for F17, F18, F19 and F20 keys on MacOS (Elisa Pau)
+  - #7334 Gtk password inputs should expose the displayed text (e.g. black
+    circles) via AT-SPI; not the underlying value (Emmanuele Bassi)
+  - #7340 Job Failed #4757144: Meson error
+  - !7951 ListBox hacking
+  - !8071 macos: Native window controls
+  - !8073 gpu: Fix off-by-one error in gsk_vulkan_mipmap_levels
+  - !8155 application: Register host apps with portal
+  - !8177 Small Android fixes
+  - !8178 Fix typo in `FileLauncher.set_always_ask` docs
+  - !8179 gdk/wayland: Use forgotten include guards
+  - !8180 docs: fix some typos, mainly closing ticks
+  - !8184 android: Provide Gdk.FOCUS_CHANGE events
+  - !8187 demos: Fix gettext domain in metainfo
+  - !8195 gtk-demo: Tweak the fixed demo
+  - !8196 settings: Fix GdkDisplay values ignored at init
+  - !8197 popovermenubar: Do not steal the focus on hover
+  - !8198 gi: Add missing annotation to WaylandSurface.force_next_commit
+  - !8200 rendernode: Add fixed-size annotations
+  - !8201 fontdialogbutton: Gracefully handle unknown font
+  - !8205 Update getting_started.md - point to Gtk.Widget.present instead of
+    show
+  - !8206 docs: Fix 'Title overline too short' error
+  - !8207 Update getting_started for gdk_surface_create_similar_surface
+    depreaction
+  - !8208 a11y: Fix issues in text attribute run logic
+  - !8210 gdk: Small documentation improvements
+  - !8211 wayland: Use the wp_color_manager_v1 protocol
+  - !8217 macos: Disable animations if setting "Reduce Motion" is active
+  - !8219 application: Clean up dangling inhibitor surface
+  - !8221 gtk-demo: Improve colors of triangle in GLArea demo
+  - !8222 vulkan: Fix max amount of modifiers per format
+  - !8223 docs: Add dark variants to widget gallery
+  - !8224 docs: Fix gallery images for menus
+  - !8228 gsk: Don't color-convert empty surfaces
+  - !8229 gdk: Remove GDK_DEBUG=gl-no-fractional
+
+* Translation updates:
+  - Catalan (Jordi Mas)
+  - Chinese (Taiwan) (Chao-Hsiung Liao)
+  - French (Vincent Chatelain)
+  - Georgian (Ekaterine Papava)
+  - Nepali (Pawan Chitrakar)
+  - Persian (Danial Behzadi)
+  - Polish (Piotr DrÄ…g)
+  - Slovenian (Martin)
+
+
 Overview of Changes in 4.17.4, 01-02-2025
 =========================================
 
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 51f59a8c562fdb13d72350063fc9981654905b3e..8ac0045faefca5cf31d463242beeb41d95ec4bce 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -201,9 +201,9 @@
     <file>main.ui</file>
   </gresource>
   <gresource prefix="/menu">
-    <file>demo3widget.c</file>
-    <file>demo3widget.h</file>
-    <file>demo3widget.ui</file>
+    <file>imageview.c</file>
+    <file>imageview.h</file>
+    <file>imageview.ui</file>
   </gresource>
   <gresource prefix="/mask">
     <file>demo4widget.c</file>
@@ -273,6 +273,7 @@
     <file>filtermodel.c</file>
     <file>fishbowl.c</file>
     <file>fixed.c</file>
+    <file>fixed2.c</file>
     <file>flowbox.c</file>
     <file>frames.c</file>
     <file>font_features.c</file>
diff --git a/demos/gtk-demo/demo3widget.h b/demos/gtk-demo/demo3widget.h
deleted file mode 100644
index 5bf86bb85504931fcd6b1d09f14fbfd38fea7c77..0000000000000000000000000000000000000000
--- a/demos/gtk-demo/demo3widget.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#pragma once
-
-#include <gtk/gtk.h>
-
-#define DEMO3_TYPE_WIDGET (demo3_widget_get_type ())
-G_DECLARE_FINAL_TYPE (Demo3Widget, demo3_widget, DEMO3, WIDGET, GtkWidget)
-
-GtkWidget * demo3_widget_new (const char *resource);
diff --git a/demos/gtk-demo/fixed.c b/demos/gtk-demo/fixed.c
index 44c0c2a54de819d3d66c271da8a75fa0564ed911..2c33cf5380cbe466eabf5896891242c4dec342e3 100644
--- a/demos/gtk-demo/fixed.c
+++ b/demos/gtk-demo/fixed.c
@@ -1,8 +1,10 @@
-/* Fixed Layout
+/* Fixed Layout / Cube
  * #Keywords: GtkLayoutManager
  *
  * GtkFixed is a container that allows placing and transforming
  * widgets manually.
+ *
+ * This demo uses a GtkFixed to create a cube out of child widgets.
  */
 
 #include <gtk/gtk.h>
@@ -127,7 +129,7 @@ create_demo_window (GtkWidget *do_widget)
 
   window = gtk_window_new ();
   gtk_window_set_display (GTK_WINDOW (window),  gtk_widget_get_display (do_widget));
-  gtk_window_set_title (GTK_WINDOW (window), "Fixed Layout");
+  gtk_window_set_title (GTK_WINDOW (window), "Fixed Layout ‐ Cube");
   gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);
   g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);
 
diff --git a/demos/gtk-demo/fixed2.c b/demos/gtk-demo/fixed2.c
new file mode 100644
index 0000000000000000000000000000000000000000..6cfd0aaca64c89953ad979d3bf7bde80932f7624
--- /dev/null
+++ b/demos/gtk-demo/fixed2.c
@@ -0,0 +1,97 @@
+/* Fixed Layout / Transformations
+ * #Keywords: GtkLayoutManager
+ *
+ * GtkFixed is a container that allows placing and transforming
+ * widgets manually.
+ *
+ * This demo shows how to rotate and scale a child widget using
+ * a transform.
+ */
+
+#include <gtk/gtk.h>
+
+static GtkWidget *demo_window = NULL;
+static gint64 start_time = 0;
+
+static gboolean
+tick_cb (GtkWidget     *widget,
+         GdkFrameClock *frame_clock,
+         gpointer       user_data)
+{
+  GtkFixed *fixed = GTK_FIXED (widget);
+  GtkWidget *child = user_data;
+  gint64 now = g_get_monotonic_time ();
+  double duration;
+  double angle;
+  double width, height;
+  double child_width, child_height;
+  GskTransform *transform;
+  double scale;
+
+  duration = (now - start_time) / (double) G_TIME_SPAN_SECOND;
+
+  width = gtk_widget_get_width (widget);
+  height = gtk_widget_get_height (widget);
+
+  child_width = gtk_widget_get_width (child);
+  child_height = gtk_widget_get_height (child);
+
+  angle = duration * 90;
+  scale = 2 + sin (duration * M_PI);
+
+  transform = gsk_transform_translate (
+      gsk_transform_scale (
+          gsk_transform_rotate (
+              gsk_transform_translate (NULL,
+                  &GRAPHENE_POINT_INIT (width / 2, height / 2)),
+              angle),
+          scale, scale),
+      &GRAPHENE_POINT_INIT (- child_width / 2,  - child_height / 2));
+
+  gtk_fixed_set_child_transform (fixed, child, transform);
+
+  gsk_transform_unref (transform);
+
+  return G_SOURCE_CONTINUE;
+}
+
+static GtkWidget *
+create_demo_window (GtkWidget *do_widget)
+{
+  GtkWidget *window, *sw, *fixed, *child;
+
+  window = gtk_window_new ();
+  gtk_window_set_display (GTK_WINDOW (window),  gtk_widget_get_display (do_widget));
+  gtk_window_set_title (GTK_WINDOW (window), "Fixed Layout ‐ Transformations");
+  gtk_window_set_default_size (GTK_WINDOW (window), 400, 300);
+
+  sw = gtk_scrolled_window_new ();
+  gtk_window_set_child (GTK_WINDOW (window), sw);
+
+  fixed = gtk_fixed_new ();
+  gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), fixed);
+
+  child = gtk_label_new ("All fixed?");
+  gtk_fixed_put (GTK_FIXED (fixed), child, 0, 0);
+  gtk_widget_set_overflow (fixed, GTK_OVERFLOW_VISIBLE);
+
+  gtk_widget_add_tick_callback (fixed, tick_cb, child, NULL);
+
+  return window;
+}
+
+GtkWidget*
+do_fixed2 (GtkWidget *do_widget)
+{
+  if (demo_window == NULL)
+    demo_window = create_demo_window (do_widget);
+
+  start_time = g_get_monotonic_time ();
+
+  if (!gtk_widget_get_visible (demo_window))
+    gtk_widget_set_visible (demo_window, TRUE);
+  else
+    gtk_window_destroy (GTK_WINDOW (demo_window));
+
+  return demo_window;
+}
diff --git a/demos/gtk-demo/glarea-gl.fs.glsl b/demos/gtk-demo/glarea-gl.fs.glsl
index aaa73050728a05a187c0ae69ab46fb5143d913d2..ed6985e4bcfc57db476c92605f726a5ac8b9f4a7 100644
--- a/demos/gtk-demo/glarea-gl.fs.glsl
+++ b/demos/gtk-demo/glarea-gl.fs.glsl
@@ -1,9 +1,9 @@
 #version 330
 
+in vec4 color;
+
 out vec4 outputColor;
 
 void main() {
-  float lerpVal = gl_FragCoord.y / 500.0f;
-
-  outputColor = mix(vec4(1.0f, 0.85f, 0.35f, 1.0f), vec4(0.2f, 0.2f, 0.2f, 1.0f), lerpVal);
+  outputColor = color;
 }
diff --git a/demos/gtk-demo/glarea-gl.vs.glsl b/demos/gtk-demo/glarea-gl.vs.glsl
index 163f6efc57bb6057dab5429bf1f4fc63a3290a11..8073fe68e501c34872b3861bc3e8c0a712417e8a 100644
--- a/demos/gtk-demo/glarea-gl.vs.glsl
+++ b/demos/gtk-demo/glarea-gl.vs.glsl
@@ -1,8 +1,12 @@
 #version 330
 
-layout(location = 0) in vec4 position;
+in vec4 in_position;
+in vec4 in_color;
 uniform mat4 mvp;
 
+out vec4 color;
+
 void main() {
-  gl_Position = mvp * position;
+  color = in_color;
+  gl_Position = mvp * in_position;
 }
diff --git a/demos/gtk-demo/glarea-gles.fs.glsl b/demos/gtk-demo/glarea-gles.fs.glsl
index ac5e1950312ddd120b6edaad59ed16678301be57..14a8c2d8c8978fd2be7eadf8f17611d98e2fa3a7 100644
--- a/demos/gtk-demo/glarea-gles.fs.glsl
+++ b/demos/gtk-demo/glarea-gles.fs.glsl
@@ -1,7 +1,7 @@
 precision highp float;
 
-void main() {
-  float lerpVal = gl_FragCoord.y / 500.0;
+varying vec4 color;
 
-  gl_FragColor = mix(vec4(1.0, 0.85, 0.35, 1.0), vec4(0.2, 0.2, 0.2, 1.0), lerpVal);
+void main() {
+  gl_FragColor = color;
 }
diff --git a/demos/gtk-demo/glarea-gles.vs.glsl b/demos/gtk-demo/glarea-gles.vs.glsl
index 63064da4c765885f6027c037518703a5aeba7727..964994b9ddd4c3ef57abe860c2a3a90ad5015af1 100644
--- a/demos/gtk-demo/glarea-gles.vs.glsl
+++ b/demos/gtk-demo/glarea-gles.vs.glsl
@@ -1,7 +1,11 @@
-attribute vec4 position;
+attribute vec4 in_position;
+attribute vec4 in_color;
 
 uniform mat4 mvp;
 
+varying vec4 color;
+
 void main() {
-  gl_Position = mvp * position;
+  color = in_color;
+  gl_Position = mvp * in_position;
 }
diff --git a/demos/gtk-demo/glarea.c b/demos/gtk-demo/glarea.c
index 43942f5f7edc36a5d8d2266a35715c43e636d892..0bd95233aac9dc161209a8d97fbd2a15d005b76e 100644
--- a/demos/gtk-demo/glarea.c
+++ b/demos/gtk-demo/glarea.c
@@ -25,9 +25,10 @@ static float rotation_angles[N_AXIS] = { 0.0 };
 
 /* The object we are drawing */
 static const GLfloat vertex_data[] = {
-  0.f,   0.5f,   0.f, 1.f,
-  0.5f, -0.366f, 0.f, 1.f,
- -0.5f, -0.366f, 0.f, 1.f,
+  /* coord */               /* color */
+  0.f,   0.5f,   0.f, 1.f,  1.f, 0.f, 0.f, 1.f,
+  0.5f, -0.366f, 0.f, 1.f,  0.f, 1.f, 0.f, 1.f,
+ -0.5f, -0.366f, 0.f, 1.f,  0.f, 0.f, 1.f, 1.f
 };
 
 /* Initialize the GL buffers */
@@ -277,7 +278,9 @@ draw_triangle (void)
   /* Use the vertices in our buffer */
   glBindBuffer (GL_ARRAY_BUFFER, position_buffer);
   glEnableVertexAttribArray (0);
-  glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 0, 0);
+  glVertexAttribPointer (0, 4, GL_FLOAT, GL_FALSE, 32, 0);
+  glEnableVertexAttribArray (1);
+  glVertexAttribPointer (1, 4, GL_FLOAT, GL_FALSE, 32, (void *) 16);
 
   /* Draw the three vertices as a triangle */
   glDrawArrays (GL_TRIANGLES, 0, 3);
diff --git a/demos/gtk-demo/image_scaling.c b/demos/gtk-demo/image_scaling.c
index 7a541292b999200de7a5508cc42c65c261327a10..8de56b5a7297eeb6c08cdd66975bce0a4d0d8362 100644
--- a/demos/gtk-demo/image_scaling.c
+++ b/demos/gtk-demo/image_scaling.c
@@ -12,7 +12,8 @@
  */
 
 #include <gtk/gtk.h>
-#include "demo3widget.h"
+#include "imageview.h"
+
 
 static GtkWidget *window = NULL;
 static GCancellable *cancellable = NULL;
@@ -229,6 +230,7 @@ do_image_scaling (GtkWidget *do_widget)
       GtkWidget *box;
       GtkWidget *box2;
       GtkWidget *sw;
+      GtkWidget *vp;
       GtkWidget *widget;
       GtkWidget *scale;
       GtkWidget *dropdown;
@@ -263,8 +265,12 @@ do_image_scaling (GtkWidget *do_widget)
       gtk_widget_set_vexpand (sw, TRUE);
       gtk_box_append (GTK_BOX (box), sw);
 
-      widget = demo3_widget_new ("/transparent/portland-rose.jpg");
-      gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), widget);
+      widget = image_view_new ("/transparent/portland-rose.jpg");
+      vp = gtk_viewport_new (NULL, NULL);
+      gtk_viewport_set_scroll_to_focus (GTK_VIEWPORT (vp), FALSE);
+
+      gtk_viewport_set_child (GTK_VIEWPORT (vp), widget);
+      gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (sw), vp);
 
       box2 = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
       gtk_box_append (GTK_BOX (box), box2);
diff --git a/demos/gtk-demo/demo3widget.c b/demos/gtk-demo/imageview.c
similarity index 78%
rename from demos/gtk-demo/demo3widget.c
rename to demos/gtk-demo/imageview.c
index 28c5fc7105507e7747172a07f3c28a0836454dbb..9edbed69fa8c7696e1b015aad5bb50467e9a09b5 100644
--- a/demos/gtk-demo/demo3widget.c
+++ b/demos/gtk-demo/imageview.c
@@ -1,5 +1,6 @@
 #include <math.h>
-#include "demo3widget.h"
+#include "imageview.h"
+
 
 enum
 {
@@ -9,7 +10,7 @@ enum
   PROP_ANGLE,
 };
 
-struct _Demo3Widget
+struct _ImageView
 {
   GtkWidget parent_instance;
 
@@ -21,12 +22,12 @@ struct _Demo3Widget
   GtkWidget *menu;
 };
 
-struct _Demo3WidgetClass
+struct _ImageViewClass
 {
   GtkWidgetClass parent_class;
 };
 
-G_DEFINE_TYPE (Demo3Widget, demo3_widget, GTK_TYPE_WIDGET)
+G_DEFINE_TYPE (ImageView, image_view, GTK_TYPE_WIDGET)
 
 static gboolean
 query_tooltip (GtkWidget  *widget,
@@ -36,7 +37,7 @@ query_tooltip (GtkWidget  *widget,
                GtkTooltip *tooltip,
                gpointer    data)
 {
-  Demo3Widget *self = DEMO3_WIDGET (widget);
+  ImageView *self = IMAGE_VIEW (widget);
   GtkWidget *grid;
   GtkWidget *label;
   char *s, *s2;
@@ -105,7 +106,7 @@ query_tooltip (GtkWidget  *widget,
 }
 
 static void
-demo3_widget_init (Demo3Widget *self)
+image_view_init (ImageView *self)
 {
   self->scale = 1.f;
   self->angle = 0.f;
@@ -114,22 +115,22 @@ demo3_widget_init (Demo3Widget *self)
 }
 
 static void
-demo3_widget_dispose (GObject *object)
+image_view_dispose (GObject *object)
 {
-  Demo3Widget *self = DEMO3_WIDGET (object);
+  ImageView *self = IMAGE_VIEW (object);
 
   g_clear_object (&self->texture);
 
-  gtk_widget_dispose_template (GTK_WIDGET (self), DEMO3_TYPE_WIDGET);
+  gtk_widget_dispose_template (GTK_WIDGET (self), IMAGE_TYPE_VIEW);
 
-  G_OBJECT_CLASS (demo3_widget_parent_class)->dispose (object);
+  G_OBJECT_CLASS (image_view_parent_class)->dispose (object);
 }
 
 static void
-demo3_widget_snapshot (GtkWidget   *widget,
-                       GtkSnapshot *snapshot)
+image_view_snapshot (GtkWidget   *widget,
+                     GtkSnapshot *snapshot)
 {
-  Demo3Widget *self = DEMO3_WIDGET (widget);
+  ImageView *self = IMAGE_VIEW (widget);
   int x, y, width, height;
   double w, h, w2, h2;
 
@@ -165,15 +166,15 @@ demo3_widget_snapshot (GtkWidget   *widget,
 }
 
 static void
-demo3_widget_measure (GtkWidget      *widget,
-                      GtkOrientation  orientation,
-                      int             for_size,
-                      int            *minimum,
-                      int            *natural,
-                      int            *minimum_baseline,
-                      int            *natural_baseline)
+image_view_measure (GtkWidget      *widget,
+                    GtkOrientation  orientation,
+                    int             for_size,
+                    int            *minimum,
+                    int            *natural,
+                    int            *minimum_baseline,
+                    int            *natural_baseline)
 {
-  Demo3Widget *self = DEMO3_WIDGET (widget);
+  ImageView *self = IMAGE_VIEW (widget);
   int width, height;
   int size;
 
@@ -197,12 +198,12 @@ demo3_widget_measure (GtkWidget      *widget,
 }
 
 static void
-demo3_widget_size_allocate (GtkWidget *widget,
-                            int        width,
-                            int        height,
-                            int        baseline)
+image_view_size_allocate (GtkWidget *widget,
+                          int        width,
+                          int        height,
+                          int        baseline)
 {
-  Demo3Widget *self = DEMO3_WIDGET (widget);
+  ImageView *self = IMAGE_VIEW (widget);
 
   /* Since we are not using a layout manager (who would do this
    * for us), we need to allocate a size for our menu by calling
@@ -211,15 +212,15 @@ demo3_widget_size_allocate (GtkWidget *widget,
   gtk_popover_present (GTK_POPOVER (self->menu));
 }
 
-static void update_actions (Demo3Widget *self);
+static void update_actions (ImageView *self);
 
 static void
-demo3_widget_set_property (GObject      *object,
-                           guint         prop_id,
-                           const GValue *value,
-                           GParamSpec   *pspec)
+image_view_set_property (GObject      *object,
+                         guint         prop_id,
+                         const GValue *value,
+                         GParamSpec   *pspec)
 {
-  Demo3Widget *self = DEMO3_WIDGET (object);
+  ImageView *self = IMAGE_VIEW (object);
 
   switch (prop_id)
     {
@@ -259,12 +260,12 @@ demo3_widget_set_property (GObject      *object,
 }
 
 static void
-demo3_widget_get_property (GObject     *object,
-                           guint        prop_id,
-                           GValue      *value,
-                           GParamSpec  *pspec)
+image_view_get_property (GObject     *object,
+                         guint        prop_id,
+                         GValue      *value,
+                         GParamSpec  *pspec)
 {
-  Demo3Widget *self = DEMO3_WIDGET (object);
+  ImageView *self = IMAGE_VIEW (object);
 
   switch (prop_id)
     {
@@ -295,7 +296,7 @@ pressed_cb (GtkGestureClick *gesture,
             guint            n_press,
             double           x,
             double           y,
-            Demo3Widget     *self)
+            ImageView     *self)
 {
   /* We are placing our menu at the point where
    * the click happened, before popping it up.
@@ -306,7 +307,7 @@ pressed_cb (GtkGestureClick *gesture,
 }
 
 static void
-update_actions (Demo3Widget *self)
+update_actions (ImageView *self)
 {
   gtk_widget_action_set_enabled (GTK_WIDGET (self), "zoom.in", self->scale < 1024.);
   gtk_widget_action_set_enabled (GTK_WIDGET (self), "zoom.out", self->scale > 1./1024.);
@@ -318,7 +319,7 @@ zoom_cb (GtkWidget  *widget,
          const char *action_name,
          GVariant   *parameter)
 {
-  Demo3Widget *self = DEMO3_WIDGET (widget);
+  ImageView *self = IMAGE_VIEW (widget);
   float scale;
 
   if (g_str_equal (action_name, "zoom.in"))
@@ -338,7 +339,7 @@ rotate_cb (GtkWidget  *widget,
            const char *action_name,
            GVariant   *parameter)
 {
-  Demo3Widget *self = DEMO3_WIDGET (widget);
+  ImageView *self = IMAGE_VIEW (widget);
   int angle;
 
   g_variant_get (parameter, "i", &angle);
@@ -347,18 +348,18 @@ rotate_cb (GtkWidget  *widget,
 }
 
 static void
-demo3_widget_class_init (Demo3WidgetClass *class)
+image_view_class_init (ImageViewClass *class)
 {
   GObjectClass *object_class = G_OBJECT_CLASS (class);
   GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
 
-  object_class->dispose = demo3_widget_dispose;
-  object_class->set_property = demo3_widget_set_property;
-  object_class->get_property = demo3_widget_get_property;
+  object_class->dispose = image_view_dispose;
+  object_class->set_property = image_view_set_property;
+  object_class->get_property = image_view_get_property;
 
-  widget_class->snapshot = demo3_widget_snapshot;
-  widget_class->measure = demo3_widget_measure;
-  widget_class->size_allocate = demo3_widget_size_allocate;
+  widget_class->snapshot = image_view_snapshot;
+  widget_class->measure = image_view_measure;
+  widget_class->size_allocate = image_view_size_allocate;
 
   g_object_class_install_property (object_class, PROP_TEXTURE,
       g_param_spec_object ("texture", NULL, NULL,
@@ -386,28 +387,26 @@ demo3_widget_class_init (Demo3WidgetClass *class)
   gtk_widget_class_install_action (widget_class, "zoom.reset", NULL, zoom_cb);
   gtk_widget_class_install_action (widget_class, "rotate", "i", rotate_cb);
 
-  gtk_widget_class_set_template_from_resource (widget_class, "/menu/demo3widget.ui");
-  gtk_widget_class_bind_template_child (widget_class, Demo3Widget, menu);
+  gtk_widget_class_set_template_from_resource (widget_class, "/menu/imageview.ui");
+  gtk_widget_class_bind_template_child (widget_class, ImageView, menu);
   gtk_widget_class_bind_template_callback (widget_class, pressed_cb);
+  gtk_widget_class_bind_template_callback (widget_class, query_tooltip);
 
   gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_IMG);
 }
 
 GtkWidget *
-demo3_widget_new (const char *resource)
+image_view_new (const char *resource)
 {
-  Demo3Widget *self;
+  ImageView *self;
   GdkTexture *texture;
 
   texture = gdk_texture_new_from_resource (resource);
 
-  self = g_object_new (DEMO3_TYPE_WIDGET,
+  self = g_object_new (IMAGE_TYPE_VIEW,
                        "texture", texture,
-                       "has-tooltip", TRUE,
                        NULL);
 
-  g_signal_connect (self, "query-tooltip", G_CALLBACK (query_tooltip), NULL);
-
   g_object_unref (texture);
 
   return GTK_WIDGET (self);
diff --git a/demos/gtk-demo/imageview.h b/demos/gtk-demo/imageview.h
new file mode 100644
index 0000000000000000000000000000000000000000..d900f5fa14ae4431b75f435547f7c0e6ec6d5a02
--- /dev/null
+++ b/demos/gtk-demo/imageview.h
@@ -0,0 +1,8 @@
+#pragma once
+
+#include <gtk/gtk.h>
+
+#define IMAGE_TYPE_VIEW (image_view_get_type ())
+G_DECLARE_FINAL_TYPE (ImageView, image_view, IMAGE, VIEW, GtkWidget)
+
+GtkWidget * image_view_new (const char *resource);
diff --git a/demos/gtk-demo/demo3widget.ui b/demos/gtk-demo/imageview.ui
similarity index 82%
rename from demos/gtk-demo/demo3widget.ui
rename to demos/gtk-demo/imageview.ui
index b09c62001aebe3e08cb3acde3d1febec22fe834f..0db7327bc8d11deec42765b3883258fb824257bc 100644
--- a/demos/gtk-demo/demo3widget.ui
+++ b/demos/gtk-demo/imageview.ui
@@ -18,9 +18,11 @@
       <attribute name="target" type="i">90</attribute>
     </item>
   </menu>
-  <template class="Demo3Widget">
+  <template class="ImageView">
+    <signal name="query-tooltip" handler="query_tooltip"/>
+    <property name="has-tooltip">1</property>
     <accessibility>
-      <property name="label">Demo image</property>
+      <property name="label">Image view</property>
     </accessibility>
     <child>
       <object class="GtkPopoverMenu" id="menu">
@@ -29,6 +31,7 @@
         </accessibility>
         <property name="has-arrow">0</property>
         <property name="menu-model">model</property>
+        <property name="halign">start</property>
       </object>
     </child>
     <child>
diff --git a/demos/gtk-demo/listview_selections.c b/demos/gtk-demo/listview_selections.c
index 167ab713f96c68a28ce033e77bbfb7c757d994fd..8dd767942502f2e55663638d83c5a181c5f755fa 100644
--- a/demos/gtk-demo/listview_selections.c
+++ b/demos/gtk-demo/listview_selections.c
@@ -267,12 +267,6 @@ get_family_name (gpointer item)
   return g_strdup (pango_font_family_get_name (PANGO_FONT_FAMILY (item)));
 }
 
-static char *
-get_title (gpointer item)
-{
-  return g_strdup (STRING_HOLDER (item)->title);
-}
-
 static char *
 get_file_name (gpointer item)
 {
@@ -469,10 +463,9 @@ do_listview_selections (GtkWidget *do_widget)
       g_object_unref (minutes_model);
       g_object_unref (hours_model);
       flat = gtk_flatten_list_model_new (G_LIST_MODEL (store));
-      expression = gtk_cclosure_expression_new (G_TYPE_STRING, NULL,
-                                                0, NULL,
-                                                (GCallback)get_title,
-                                                NULL, NULL);
+      expression = gtk_property_expression_new (GTK_TYPE_STRING_OBJECT,
+                                                NULL,
+                                                "string");
       button = gtk_drop_down_new (G_LIST_MODEL (flat), expression);
       gtk_drop_down_set_enable_search (GTK_DROP_DOWN (button), TRUE);
       factory = gtk_signal_list_item_factory_new ();
diff --git a/demos/gtk-demo/main.ui b/demos/gtk-demo/main.ui
index 0da23622c90ab80a93e33cbbf1e2fd99e89c8463..cd085039f3e98519927a39a480cb5a0d51bb0f28 100644
--- a/demos/gtk-demo/main.ui
+++ b/demos/gtk-demo/main.ui
@@ -21,6 +21,7 @@
     <property name="default-height">600</property>
     <property name="titlebar">
       <object class="GtkHeaderBar" id="headerbar">
+        <property name="use-native-controls">1</property>
         <child type="start">
           <object class="GtkButton">
             <property name="valign">center</property>
diff --git a/demos/gtk-demo/meson.build b/demos/gtk-demo/meson.build
index bd32cb57f2a68b6b287f3516036dff9c1bfd1441..fa91194a9ada807f377ee7e9bdf1a1daec827c9a 100644
--- a/demos/gtk-demo/meson.build
+++ b/demos/gtk-demo/meson.build
@@ -18,8 +18,8 @@ demos = files([
   'css_shadows.c',
   'cursors.c',
   'dialog.c',
-  'drawingarea.c',
   'dnd.c',
+  'drawingarea.c',
   'editable_cells.c',
   'entry_completion.c',
   'entry_undo.c',
@@ -28,7 +28,10 @@ demos = files([
   'filtermodel.c',
   'fishbowl.c',
   'fixed.c',
+  'fixed2.c',
+  'flowbox.c',
   'fontrendering.c',
+  'font_features.c',
   'frames.c',
   'gears.c',
   'gestures.c',
@@ -46,8 +49,6 @@ demos = files([
   'links.c',
   'listbox.c',
   'listbox_controls.c',
-  'mask.c',
-  'flowbox.c',
   'list_store.c',
   'listview_applauncher.c',
   'listview_clocks.c',
@@ -61,6 +62,7 @@ demos = files([
   'listview_weather.c',
   'listview_words.c',
   'markup.c',
+  'mask.c',
   'overlay.c',
   'overlay_decorative.c',
   'paint.c',
@@ -74,8 +76,8 @@ demos = files([
   'path_fill.c',
   'path_maze.c',
   'path_spinner.c',
-  'path_walk.c',
   'path_text.c',
+  'path_walk.c',
   'peg_solitaire.c',
   'pickers.c',
   'printing.c',
@@ -105,40 +107,39 @@ demos = files([
   'transparent.c',
   'tree_store.c',
   'video_player.c',
-  'font_features.c',
 ])
 
 gtkdemo_deps = [ libgtk_dep, ]
 
 extra_demo_sources = files([
-  'main.c',
-  'fontify.c',
-  'gtkfishbowl.c',
-  'fontplane.c',
-  'gtkgears.c',
-  'gtkshadertoy.c',
-  'hsla.c',
-  'puzzlepiece.c',
   'bluroverlay.c',
-  'demoimage.c',
-  'demotaggedentry.c',
   'demochild.c',
+  'demoimage.c',
   'demolayout.c',
+  'demotaggedentry.c',
   'demowidget.c',
   'demo2layout.c',
-  'singular_value_decomposition.c',
-  'four_point_transform.c',
   'demo2widget.c',
-  'demo3widget.c',
   'demo4widget.c',
+  'fontify.c',
+  'fontplane.c',
+  'four_point_transform.c',
+  'graphwidget.c',
+  'gtkfishbowl.c',
+  'gtkshadertoy.c',
+  'gtkgears.c',
+  'hsla.c',
+  'imageview.c',
+  'language-names.c',
+  'main.c',
+  'nodewidget.c',
   'pixbufpaintable.c',
+  'puzzlepiece.c',
   'script-names.c',
   'settings-key.c',
-  'unicode-names.c',
+  'singular_value_decomposition.c',
   'suggestionentry.c',
-  'language-names.c',
-  'nodewidget.c',
-  'graphwidget.c',
+  'unicode-names.c',
 ])
 
 if os_unix
diff --git a/demos/gtk-demo/org.gtk.Demo4.appdata.xml.in b/demos/gtk-demo/org.gtk.Demo4.appdata.xml.in
index 94d71456706155a7afcafe7ce836bfde06d9c07b..6f1800977cbe548948f51370b4459d573aa1d71e 100644
--- a/demos/gtk-demo/org.gtk.Demo4.appdata.xml.in
+++ b/demos/gtk-demo/org.gtk.Demo4.appdata.xml.in
@@ -28,7 +28,7 @@
     <kudo>ModernToolkit</kudo>
   </kudos>
   <url type="homepage">https://www.gtk.org</url>
-  <translation type="gettext">gtk-4.0</translation>
+  <translation type="gettext">gtk40</translation>
   <update_contact>matthias.clasen_at_gmail.com</update_contact>
   <developer_name>Matthias Clasen and others</developer_name>
   <content_rating type="oars-1.1"/>
diff --git a/demos/gtk-demo/revealer.ui b/demos/gtk-demo/revealer.ui
index 092a9015d82549562ee717a3bb33a56eb6e3a633..02d4430edbd1afc0caa1543ab7fb525b486b1503 100644
--- a/demos/gtk-demo/revealer.ui
+++ b/demos/gtk-demo/revealer.ui
@@ -63,8 +63,8 @@
               <object class="GtkImage">
                 <property name="icon-name">face-cool-symbolic</property>
                 <property name="icon-size">large</property>
-              </property>
-            </child>
+              </object>
+            </property>
             <layout>
               <property name="column">2</property>
               <property name="row">3</property>
diff --git a/demos/node-editor/org.gtk.gtk4.NodeEditor.appdata.xml.in b/demos/node-editor/org.gtk.gtk4.NodeEditor.appdata.xml.in
index 16b7e92657f11fd0357fb9f718b0b84457ecdd76..7e35be163926e917cd9d7d71092e189e0f6b39c4 100644
--- a/demos/node-editor/org.gtk.gtk4.NodeEditor.appdata.xml.in
+++ b/demos/node-editor/org.gtk.gtk4.NodeEditor.appdata.xml.in
@@ -26,7 +26,7 @@
     <kudo>ModernToolkit</kudo>
   </kudos>
   <url type="homepage">https://www.gtk.org</url>
-  <translation type="gettext">gtk-4.0</translation>
+  <translation type="gettext">gtk40</translation>
   <update_contact>matthias.clasen_at_gmail.com</update_contact>
   <developer_name>Matthias Clasen and others</developer_name>
   <content_rating type="oars-1.1"/>
diff --git a/demos/print-editor/org.gtk.PrintEditor4.appdata.xml b/demos/print-editor/org.gtk.PrintEditor4.appdata.xml
index 66f5e43d3a1115274ed044a7323ded177736b7df..cc0bf67e0d3c7137babc86028a5f3a49c0e71ab5 100644
--- a/demos/print-editor/org.gtk.PrintEditor4.appdata.xml
+++ b/demos/print-editor/org.gtk.PrintEditor4.appdata.xml
@@ -22,7 +22,7 @@
     <kudo>ModernToolkit</kudo>
   </kudos>
   <url type="homepage">https://www.gtk.org</url>
-  <translation type="gettext">gtk-4.0</translation>
+  <translation type="gettext">gtk40</translation>
   <update_contact>matthias.clasen_at_gmail.com</update_contact>
   <developer_name>Matthias Clasen and others</developer_name>
   <content_rating type="oars-1.1"/>
diff --git a/demos/widget-factory/org.gtk.WidgetFactory4.appdata.xml.in b/demos/widget-factory/org.gtk.WidgetFactory4.appdata.xml.in
index b976069fb75cc1edd1f6216da80d5ddacc22279f..47463228d8f1d5ac55933bd8261224a901ab3f88 100644
--- a/demos/widget-factory/org.gtk.WidgetFactory4.appdata.xml.in
+++ b/demos/widget-factory/org.gtk.WidgetFactory4.appdata.xml.in
@@ -29,7 +29,7 @@
     <kudo>ModernToolkit</kudo>
   </kudos>
   <url type="homepage">https://www.gtk.org</url>
-  <translation type="gettext">gtk-4.0</translation>
+  <translation type="gettext">gtk40</translation>
   <update_contact>matthias.clasen_at_gmail.com</update_contact>
   <developer_name>Matthias Clasen and others</developer_name>
   <content_rating type="oars-1.1"/>
diff --git a/demos/widget-factory/widget-factory.c b/demos/widget-factory/widget-factory.c
index 362a4a59e2d319550ce0fd095876f4135c086133..6bc3f4c1cd40dd1e75b4bed9e20ab4cab469b82a 100644
--- a/demos/widget-factory/widget-factory.c
+++ b/demos/widget-factory/widget-factory.c
@@ -2247,6 +2247,7 @@ activate (GApplication *app)
                                    window);
 
   controller = gtk_shortcut_controller_new ();
+  gtk_event_controller_set_static_name (controller, "widget-factory-late-accels");
   gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_BUBBLE);
 
   for (i = 0; i < G_N_ELEMENTS (late_accels); i++)
diff --git a/docs/reference/gdk/keys.md b/docs/reference/gdk/keys.md
index 1bd4ff639e01210a831b77f697b67325fae7f173..bc5c3a68a62b2f6a0b25fde716e70929885be444 100644
--- a/docs/reference/gdk/keys.md
+++ b/docs/reference/gdk/keys.md
@@ -36,21 +36,18 @@ You can think of a [struct@Gdk.KeymapKey] as a representation of a symbol
 printed on a physical keyboard key. That is, it contains three pieces of
 information:
 
-1. first, it contains the hardware keycode; this is an identifying number
-   for a physical key
-1. second, it contains the “level” of the key. The level indicates which
-   symbol on the key will be used, in a vertical direction. So on a standard
-   US keyboard, the key with the number “1“ on it also has the exclamation
-   point (”!”) character on it. The level indicates whether to use the “1”
-   or the “!” symbol. The letter keys are considered to have a lowercase
-   letter at level 0, and an uppercase letter at level 1, though normally
-   only the uppercase letter is printed on the key
-1. third, the [struct@Gdk.KeymapKey] contains a group; groups are not used on
-   standard US keyboards, but are used in many other countries. On a
-   keyboard with groups, there can be 3 or 4 symbols printed on a single
-   key. The group indicates movement in a horizontal direction. Usually
-   groups are used for two different languages. In group 0, a key might
-   have two English characters, and in group 1 it might have two Hebrew
+1. The hardware keycode. This is an identifying number for a physical key
+1. The “level” of the key. The level indicates which symbol on the key will
+   be used, in a vertical direction. So on a standard US keyboard, the key with
+   the number “1“ on it also has the exclamation point (”!”) character on it.
+   The level indicates whether to use the “1" or the “!” symbol. The letter keys
+   are considered to have a lowercase letter at level 0, and an uppercase letter
+   at level 1, though normally only the uppercase letter is printed on the key
+1. A group. Groups are not used on standard US keyboards, but are used in many
+   other countries. On a keyboard with groups, there can be 3 or 4 symbols printed
+   on a single key. The group indicates movement in a horizontal direction.
+   Usually groups are used for two different languages. In group 0, a key
+   might have two English characters, and in group 1 it might have two Hebrew
    characters. The Hebrew characters will be printed on the key next to
    the English characters.
 
diff --git a/docs/reference/gdk/macos.md b/docs/reference/gdk/macos.md
index d629244a0a9bdb2dae80ed33f14a4cc0e357bcb7..c8097cfa0a88f727e092e200c890d297491b2ace 100644
--- a/docs/reference/gdk/macos.md
+++ b/docs/reference/gdk/macos.md
@@ -51,25 +51,8 @@ calls to different backends, and error out on unsupported windowing systems:
 
 The compile-time check is performed by using the `GDK_WINDOWING_*`
 pre-processor symbols; there is one defined for each windowing system
-backend built into GDK. For Wayland, the symbol is `GDK_WINDOWING_MACOS`.
+backend built into GDK. For macOS, the symbol is `GDK_WINDOWING_MACOS`.
 
 The run-time check is performed by looking at the type of the
 [class@Gdk.Display] object. For macOS, the display objects will be of type
 `GdkMacosDisplay`.
-
-## Menus
-
-By default a GTK app shows an app menu and an edit menu.
-To make menu actions work well with native windows, such as a file dialog,
-the most common edit commands are treated special:
-
-* `text.undo`
-* `text.redo`
-* `clipboard.cut`
-* `clipboard.copy`
-* `clipboard.paste`
-* `selection.select-all`
-
-Those actions map to their respective macOS counterparts.
-The actions are enabled in GTK if the action is available on the focused widget
-and is enabled.
diff --git a/docs/reference/gtk/building.md b/docs/reference/gtk/building.md
index 12b95b5be604e3ddf840b233bbb3387c7ec30299..8a1b176d8981de018da36ce574eb72dd5f0aa22a 100644
--- a/docs/reference/gtk/building.md
+++ b/docs/reference/gtk/building.md
@@ -34,12 +34,11 @@ You can get a list of all available options for the build by
 running `meson configure`.
 
 After Meson successfully configured the build directory, you then
-can run the build, using Ninja:
+can build and install GTK:
 
 ```
-cd builddir
-meson compile
-meson install
+meson compile -Cbuilddir
+meson install -Cbuilddir
 ```
 
 If you don't have permission to write to the directory you are
@@ -218,7 +217,7 @@ To see a summary of all supported options and their allowed values, run
 meson configure builddir
 ```
 
-### `x11-backend`, `win32-backend`, `broadway-backend`, `wayland-backend` and `macos-backend`
+### `x11-backend`, `win32-backend`, `broadway-backend`, `wayland-backend`, `macos-backend` and `android-backend`
 
 Enable specific backends for GDK.  If none of these options are given, the
 Wayland backend will be enabled by default, if the platform is Linux; the
diff --git a/docs/reference/gtk/compiling.md b/docs/reference/gtk/compiling.md
index f73207d446fcc025ae85acbfe8764ea57e3aa245..72e0da1343cc3802a7a46f889a72ac377aa2b525 100644
--- a/docs/reference/gtk/compiling.md
+++ b/docs/reference/gtk/compiling.md
@@ -26,11 +26,11 @@ Deprecated GTK functions are annotated to make the compiler
 emit warnings when they are used (e.g. with gcc, you need to use
 the -Wdeprecated-declarations option). If these warnings are
 problematic, they can be turned off by defining the preprocessor
-symbol %GDK_DISABLE_DEPRECATION_WARNINGS by using the commandline
+symbol `GDK_DISABLE_DEPRECATION_WARNINGS` by using the commandline
 option `-DGDK_DISABLE_DEPRECATION_WARNINGS`.
 
 GTK deprecation annotations are versioned; by defining the
-macros %GDK_VERSION_MIN_REQUIRED and %GDK_VERSION_MAX_ALLOWED,
+macros `GDK_VERSION_MIN_REQUIRED` and `GDK_VERSION_MAX_ALLOWED`,
 you can specify the range of GTK versions whose API you want
 to use. APIs that were deprecated before or introduced after
 this range will trigger compiler warnings.
@@ -48,9 +48,9 @@ $ cc `pkg-config --cflags gtk4` -DGDK_VERSION_MAX_ALLOWED=GDK_VERSION_4_2 hello.
 ```
 The older deprecation mechanism of hiding deprecated interfaces
 entirely from the compiler by using the preprocessor symbol
-GTK_DISABLE_DEPRECATED is still used for deprecated macros,
+`GTK_DISABLE_DEPRECATED` is still used for deprecated macros,
 enumeration values, etc. To detect uses of these in your code,
 use the commandline option `-DGTK_DISABLE_DEPRECATED`.
-There are similar symbols GDK_DISABLE_DEPRECATED,
-GDK_PIXBUF_DISABLE_DEPRECATED and G_DISABLE_DEPRECATED for GDK,
-GdkPixbuf and GLib.
+There are similar symbols `GDK_DISABLE_DEPRECATED`,
+`GDK_PIXBUF_DISABLE_DEPRECATED` and `G_DISABLE_DEPRECATED`
+for GDK, GdkPixbuf and GLib.
diff --git a/docs/reference/gtk/getting_started.md b/docs/reference/gtk/getting_started.md
index e58ba82b5ecc250a7002df4adff08dcb635de2db..d6b0ad5a7d3026e3c5fcdf1a6f3ebebe863387cd 100644
--- a/docs/reference/gtk/getting_started.md
+++ b/docs/reference/gtk/getting_started.md
@@ -75,12 +75,11 @@ functions, types and macros required by GTK applications.
 
 Even if GTK installs multiple header files, only the top-level `gtk/gtk.h`
 header can be directly included by third-party code. The compiler will abort
-with an error if any other header is directly included.
+with an error if any other GTK header is directly included.
 
 In a GTK application, the purpose of the `main()` function is to create a
-[class@Gtk.Application] object and run it. In this example a
-[class@Gtk.Application] pointer named `app` is declared and then initialized
-using `gtk_application_new()`.
+[class@Gtk.Application] object and run it. In this example a [class@Gtk.Application]
+pointer named `app` is declared and then initialized using `gtk_application_new()`.
 
 When creating a [class@Gtk.Application], you need to pick an application
 identifier (a name) and pass it to [ctor@Gtk.Application.new] as parameter. For
@@ -101,8 +100,8 @@ Within `g_application_run()` the activate signal is sent and we then proceed
 into the activate() function of the application. This is where we construct
 our GTK window, so that a window is shown when the application is launched.
 The call to [ctor@Gtk.ApplicationWindow.new] will create a new
-[class@Gtk.ApplicationWindow] and store it inside the `window` pointer. The
-window will have a frame, a title bar, and window controls depending on the
+[class@Gtk.ApplicationWindow] and store a pointer to it in the `window` variable.
+The window will have a frame, a title bar, and window controls depending on the
 platform.
 
 A window title is set using [`method@Gtk.Window.set_title`]. This function
@@ -115,7 +114,7 @@ warning if the check fails. More information about this convention can be
 found [in the GObject documentation](https://docs.gtk.org/gobject/concepts.html#conventions).
 
 Finally the window size is set using [`method@Gtk.Window.set_default_size`]
-and the window is then shown by GTK via [method@Gtk.Widget.show].
+and the window is then shown by GTK via [method@Gtk.Window.present].
 
 When you close the window, by (for example) pressing the X button, the
 `g_application_run()` call returns with a number which is saved inside an
@@ -409,10 +408,9 @@ resize_cb (GtkWidget *widget,
 
   if (gtk_native_get_surface (gtk_widget_get_native (widget)))
     {
-      surface = gdk_surface_create_similar_surface (gtk_native_get_surface (gtk_widget_get_native (widget)),
-                                                    CAIRO_CONTENT_COLOR,
-                                                    gtk_widget_get_width (widget),
-                                                    gtk_widget_get_height (widget));
+      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+                                            gtk_widget_get_width (widget),
+                                            gtk_widget_get_height (widget));
 
       /* Initialize the surface to white */
       clear_surface ();
diff --git a/docs/reference/gtk/gtk4-node-editor.rst b/docs/reference/gtk/gtk4-node-editor.rst
index aaba206e19cd86469814a146147b510dcfac54a1..59792010027acf62cb91f2db1e8ec03839ba1f54 100644
--- a/docs/reference/gtk/gtk4-node-editor.rst
+++ b/docs/reference/gtk/gtk4-node-editor.rst
@@ -4,9 +4,9 @@
 gtk4-node-editor
 =================
 
------------------
-Editor render nodes
------------------
+-------------------------------
+View and edit render node files
+-------------------------------
 
 :Version: GTK
 :Manual section: 1
diff --git a/docs/reference/gtk/gtk4.toml.in b/docs/reference/gtk/gtk4.toml.in
index f2c560e7b1a4c4618b1c132a2f3a4daf8e1bae31..01243f15ca635d7f89e39425af4a83e79ce96ab9 100644
--- a/docs/reference/gtk/gtk4.toml.in
+++ b/docs/reference/gtk/gtk4.toml.in
@@ -91,11 +91,16 @@ content_images = [
   "../images/favicon.svg",
   "../images/favicon-192x192.png",
   "images/aboutdialog.png",
+  "images/aboutdialog-dark.png",
   "images/action-bar.png",
+  "images/action-bar-dark.png",
   "images/appchooserbutton.png",
+  "images/appchooserbutton-dark.png",
   "images/appchooserdialog.png",
+  "images/appchooserdialog-dark.png",
   "images/arrows.png",
   "images/assistant.png",
+  "images/assistant-dark.png",
   "images/background.png",
   "images/bloatpad-gnome.png",
   "images/bloatpad-osx.png",
@@ -104,51 +109,75 @@ content_images = [
   "images/border2.png",
   "images/border3.png",
   "images/box.png",
+  "images/box-dark.png",
   "images/box-expand.png",
   "images/box-packing.png",
   "images/builder-shortcuts.png",
+  "images/builder-shortcuts-dark.png",
   "images/button.png",
+  "images/button-dark.png",
   "images/calendar.png",
+  "images/calendar-dark.png",
   "images/capture-bubble.png",
   "images/centerbox.png",
+  "images/centerbox-dark.png",
   "images/check-button.png",
+  "images/check-button-dark.png",
   "images/checks.png",
   "images/clocks-shortcuts.png",
+  "images/clocks-shortcuts-dark.png",
   "images/color-button.png",
+  "images/color-button-dark.png",
   "images/colorchooser.png",
+  "images/colorchooser-dark.png",
   "images/combo-box-entry.png",
+  "images/combo-box-entry-dark.png",
   "images/combo-box.png",
+  "images/combo-box-dark.png",
   "images/combo-box-text.png",
+  "images/combo-box-text-dark.png",
   "images/dialog.png",
+  "images/dialog-dark.png",
   "images/down-center.png",
   "images/down-end.png",
   "images/down-start.png",
   "images/drop-down.png",
+  "images/drop-down-dark.png",
   "images/drawing.png",
   "images/drawingarea.png",
+  "images/drawingarea-dark.png",
   "images/ease-in-out.png",
   "images/ease-in.png",
   "images/ease-out.png",
   "images/ease.png",
   "images/editable-label.png",
+  "images/editable-label-dark.png",
   "images/emojichooser.png",
+  "images/emojichooser-dark.png",
   "images/entry.png",
+  "images/entry-dark.png",
   "images/exampleapp.png",
   "images/expanders.png",
   "images/expander.png",
+  "images/expander-dark.png",
   "images/extensions.png",
   "images/figure-hierarchical-drawing.png",
   "images/figure-windowed-label.png",
   "images/file-button.png",
   "images/filechooser.png",
   "images/flow-box.png",
+  "images/flow-box-dark.png",
   "images/focus.png",
   "images/font-button.png",
+  "images/font-button-dark.png",
   "images/fontchooser.png",
+  "images/fontchooser-dark.png",
   "images/frame-gap.png",
   "images/frame.png",
+  "images/frame-dark.png",
   "images/frames.png",
   "images/gedit-shortcuts.png",
+  "images/gedit-shortcuts-dark.png",
   "images/getting-started-app10.png",
   "images/getting-started-app1.png",
   "images/getting-started-app2.png",
@@ -159,22 +188,29 @@ content_images = [
   "images/getting-started-app8.png",
   "images/getting-started-app9.png",
   "images/glarea.png",
+  "images/glarea-dark.png",
   "images/gradient1.png",
   "images/gradient2.png",
   "images/gradient3.png",
   "images/gradient4.png",
   "images/grid.png",
+  "images/grid-dark.png",
   "images/grid-packing.png",
   "images/gtk-logo.png",
   "images/gtk-logo.svg",
   "images/handles.png",
   "images/headerbar.png",
+  "images/headerbar-dark.png",
   "images/hello-world.png",
   "images/icon-view.png",
+  "images/icon-view-dark.png",
   "images/image.png",
+  "images/image-dark.png",
   "images/info-bar.png",
+  "images/info-bar-dark.png",
   "images/inspector.png",
   "images/label.png",
+  "images/label-dark.png",
   "images/layout-btlr.png",
   "images/layout-btrl.png",
   "images/layout-lrbt.png",
@@ -187,63 +223,104 @@ content_images = [
   "images/left-end.png",
   "images/left-start.png",
   "images/levelbar.png",
+  "images/levelbar-dark.png",
   "images/linear.png",
   "images/link-button.png",
+  "images/link-button-dark.png",
   "images/list-and-tree.png",
+  "images/list-and-tree-dark.png",
   "images/list-box.png",
-  "images/lockbutton-locked.png",
-  "images/lock-button.png",
+  "images/list-box-dark.png",
   "images/lockbutton.png",
+  "images/lockbutton-dark.png",
   "images/lockbutton-sorry.png",
+  "images/lockbutton-sorry-dark.png",
   "images/lockbutton-unlocked.png",
+  "images/lockbutton-unlocked-dark.png",
+  "images/macos-window-controls.png",
   "images/media-controls.png",
+  "images/media-controls-dark.png",
   "images/menu.png",
+  "images/menu-dark.png",
   "images/menubar.png",
+  "images/menubar-dark.png",
   "images/menu-button.png",
+  "images/menu-button-dark.png",
   "images/messagedialog.png",
+  "images/messagedialog-dark.png",
   "images/multiline-text.png",
+  "images/multiline-text-dark.png",
   "images/notebook.png",
+  "images/notebook-dark.png",
   "images/options.png",
   "images/overlay.png",
+  "images/overlay-dark.png",
   "images/pagesetupdialog.png",
+  "images/pagesetupdialog-dark.png",
   "images/panes.png",
+  "images/panes-dark.png",
   "images/password-entry.png",
+  "images/password-entry-dark.png",
   "images/picture.png",
+  "images/picture-dark.png",
   "images/popover.png",
+  "images/popover-dark.png",
   "images/printdialog.png",
+  "images/printdialog-dark.png",
   "images/progressbar.png",
+  "images/progressbar-dark.png",
   "images/radio-button.png",
+  "images/radio-button-dark.png",
   "images/right-center.png",
   "images/right-end.png",
   "images/right-start.png",
   "images/scales.png",
+  "images/scales-dark.png",
   "images/scrollbar.png",
+  "images/scrollbar-dark.png",
   "images/scrolledwindow.png",
+  "images/scrolledwindow-dark.png",
   "images/search-bar.png",
+  "images/search-bar-dark.png",
   "images/search-entry.png",
+  "images/search-entry-dark.png",
   "images/separator.png",
+  "images/separator-dark.png",
   "images/shortcuts-window.png",
+  "images/shortcuts-window-dark.png",
   "images/sidebar.png",
+  "images/sidebar-dark.png",
   "images/slices.png",
   "images/sliders.png",
   "images/spinbutton.png",
+  "images/spinbutton-dark.png",
   "images/spinner.png",
+  "images/spinner-dark.png",
   "images/stack.png",
+  "images/stack-dark.png",
   "images/stackswitcher.png",
+  "images/stackswitcher-dark.png",
   "images/statusbar.png",
+  "images/statusbar-dark.png",
   "images/switch.png",
+  "images/switch-dark.png",
   "images/toggle-button.png",
+  "images/toggle-button-dark.png",
   "images/toolbar.png",
   "images/tree-view-coordinates.png",
   "images/up-center.png",
   "images/up-end.png",
   "images/up-start.png",
   "images/video.png",
+  "images/video-dark.png",
   "images/volumebutton.png",
+  "images/volumebutton-dark.png",
   "images/widget-hvalign.png",
   "images/windowcontrols.png",
+  "images/windowcontrols-dark.png",
   "images/window-default.png",
   "images/window.png",
+  "images/window-dark.png",
   "images/rich-list.png",
   "images/data-table.png",
   "images/navigation-sidebar.png",
diff --git a/docs/reference/gtk/images/aboutdialog-dark.png b/docs/reference/gtk/images/aboutdialog-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..db60e3700f19fde8b206ddca2c9954ff696c0825
Binary files /dev/null and b/docs/reference/gtk/images/aboutdialog-dark.png differ
diff --git a/docs/reference/gtk/images/aboutdialog.png b/docs/reference/gtk/images/aboutdialog.png
index 91a4ebfc2fcba451a1c7fe6c1725f5c2fc91f6e1..de5307f4ce3c0663d52b1af8b1033dccd28b8b4c 100644
Binary files a/docs/reference/gtk/images/aboutdialog.png and b/docs/reference/gtk/images/aboutdialog.png differ
diff --git a/docs/reference/gtk/images/action-bar-dark.png b/docs/reference/gtk/images/action-bar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..542bdf47e3a04c1150d6e8af45c95c3ff7614d82
Binary files /dev/null and b/docs/reference/gtk/images/action-bar-dark.png differ
diff --git a/docs/reference/gtk/images/action-bar.png b/docs/reference/gtk/images/action-bar.png
index 9a2595fc8aa9f5eb2964d4854d324702afb3f0f1..41fa853db760b40c10a8726a40fd034561df6cfd 100644
Binary files a/docs/reference/gtk/images/action-bar.png and b/docs/reference/gtk/images/action-bar.png differ
diff --git a/docs/reference/gtk/images/appchooserbutton-dark.png b/docs/reference/gtk/images/appchooserbutton-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..48c4586af343134df7e4c3a9d89da55793b1dbec
Binary files /dev/null and b/docs/reference/gtk/images/appchooserbutton-dark.png differ
diff --git a/docs/reference/gtk/images/appchooserbutton.png b/docs/reference/gtk/images/appchooserbutton.png
index c74914e467a01f524f4e17e978dd8ad38b1c1f33..cbfd7e55c793e847441dfdb120b2f4bd35f53d5f 100644
Binary files a/docs/reference/gtk/images/appchooserbutton.png and b/docs/reference/gtk/images/appchooserbutton.png differ
diff --git a/docs/reference/gtk/images/appchooserdialog-dark.png b/docs/reference/gtk/images/appchooserdialog-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..0457b4ca8e650c0a9d50eb90af66749e9488e154
Binary files /dev/null and b/docs/reference/gtk/images/appchooserdialog-dark.png differ
diff --git a/docs/reference/gtk/images/appchooserdialog.png b/docs/reference/gtk/images/appchooserdialog.png
index afa9286273c33209de6ca931b9d79b4e021e8083..1d0e79ece403b8b3b908915b19e7d0a6f4efc903 100644
Binary files a/docs/reference/gtk/images/appchooserdialog.png and b/docs/reference/gtk/images/appchooserdialog.png differ
diff --git a/docs/reference/gtk/images/applications-graphics.png b/docs/reference/gtk/images/applications-graphics.png
new file mode 100644
index 0000000000000000000000000000000000000000..1495eea253c62a853a9c00f6dc239a41f9ebd2f3
Binary files /dev/null and b/docs/reference/gtk/images/applications-graphics.png differ
diff --git a/docs/reference/gtk/images/assistant-dark.png b/docs/reference/gtk/images/assistant-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..0f4b2a7c4b80ec727453a9b08b08de027466cb47
Binary files /dev/null and b/docs/reference/gtk/images/assistant-dark.png differ
diff --git a/docs/reference/gtk/images/assistant.png b/docs/reference/gtk/images/assistant.png
index 7a993677af631010147bcd07086b06ac1ac5693a..475550892c9574a43b8d4705338d41f2882e0de9 100644
Binary files a/docs/reference/gtk/images/assistant.png and b/docs/reference/gtk/images/assistant.png differ
diff --git a/docs/reference/gtk/images/box-dark.png b/docs/reference/gtk/images/box-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..d30b3a83024fb759c9c82aee15dddbf50009ce42
Binary files /dev/null and b/docs/reference/gtk/images/box-dark.png differ
diff --git a/docs/reference/gtk/images/box.png b/docs/reference/gtk/images/box.png
index 3713886bffe5ec2552e947dfea4b0f44ae46ae1c..d1c1e7d516af1d9f3fba30efd8c8fce617288793 100644
Binary files a/docs/reference/gtk/images/box.png and b/docs/reference/gtk/images/box.png differ
diff --git a/docs/reference/gtk/images/builder-shortcuts-dark.png b/docs/reference/gtk/images/builder-shortcuts-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..3524ed9e965dafac31fae2e77888b3c5bc51a09b
Binary files /dev/null and b/docs/reference/gtk/images/builder-shortcuts-dark.png differ
diff --git a/docs/reference/gtk/images/builder-shortcuts.png b/docs/reference/gtk/images/builder-shortcuts.png
index 639a1d3c372812ccf6823cfae08863919812c780..5ca0f57114ceb013b39633185843421a72cd6a9e 100644
Binary files a/docs/reference/gtk/images/builder-shortcuts.png and b/docs/reference/gtk/images/builder-shortcuts.png differ
diff --git a/docs/reference/gtk/images/builder-shortcuts.ui b/docs/reference/gtk/images/builder-shortcuts.ui
new file mode 100644
index 0000000000000000000000000000000000000000..008859908f425c3a9cf643708c32371659226fdb
--- /dev/null
+++ b/docs/reference/gtk/images/builder-shortcuts.ui
@@ -0,0 +1,472 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkShortcutsWindow" id="shortcuts-builder">
+    <property name="modal">1</property>
+    <child>
+      <object class="GtkShortcutsSection">
+        <property name="section-name">editor</property>
+        <property name="title" translatable="yes">Editor Shortcuts</property>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">General</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Global Search</property>
+                <property name="accelerator">&lt;ctrl&gt;period</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Preferences</property>
+                <property name="accelerator">&lt;ctrl&gt;comma</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Command Bar</property>
+                <property name="accelerator">&lt;ctrl&gt;Return</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Terminal</property>
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;t</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Keyboard Shortcuts</property>
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;question</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Panels</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Toggle left panel</property>
+                <property name="accelerator">F9</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Toggle right panel</property>
+                <property name="accelerator">&lt;shift&gt;F9</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Toggle bottom panel</property>
+                <property name="accelerator">&lt;ctrl&gt;F9</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Touchpad gestures</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-two-finger-swipe-right</property>
+                <property name="title" translatable="yes">Switch to the next document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-two-finger-swipe-left</property>
+                <property name="title" translatable="yes">Switch to the previous document</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Files</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;n</property>
+                <property name="title" translatable="yes">Create new document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;o</property>
+                <property name="title" translatable="yes">Open a document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;s</property>
+                <property name="title" translatable="yes">Save the document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;w</property>
+                <property name="title" translatable="yes">Close the document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;alt&gt;Page_Down</property>
+                <property name="title" translatable="yes">Switch to the next document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;alt&gt;Page_Up</property>
+                <property name="title" translatable="yes">Switch to the previous document</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Find and replace</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;f</property>
+                <property name="title" translatable="yes">Find</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;g</property>
+                <property name="title" translatable="yes">Find the next match</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;g</property>
+                <property name="title" translatable="yes">Find the previous match</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;k</property>
+                <property name="title" translatable="yes">Clear highlight</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Copy and Paste</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;c</property>
+                <property name="title" translatable="yes">Copy selected text to clipboard</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;x</property>
+                <property name="title" translatable="yes">Cut selected text to clipboard</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;v</property>
+                <property name="title" translatable="yes">Paste text from clipboard</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Undo and Redo</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;z</property>
+                <property name="title" translatable="yes">Undo previous command</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;z</property>
+                <property name="title" translatable="yes">Redo previous command</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Editing</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;a</property>
+                <property name="title" translatable="yes">Increment number at cursor</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;x</property>
+                <property name="title" translatable="yes">Decrement number at cursor</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;j</property>
+                <property name="title" translatable="yes">Join selected lines</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;space</property>
+                <property name="title" translatable="yes">Show completion window</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">Insert</property>
+                <property name="title" translatable="yes">Toggle overwrite</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;alt&gt;i</property>
+                <property name="title" translatable="yes">Reindent line</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Navigation</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;n</property>
+                <property name="title" translatable="yes">Move to next error in file</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;p</property>
+                <property name="title" translatable="yes">Move to previous error in file</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;shift&gt;&lt;alt&gt;Left</property>
+                <property name="title" translatable="yes">Move to previous edit location</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;shift&gt;&lt;alt&gt;Right</property>
+                <property name="title" translatable="yes">Move to next edit location</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;period</property>
+                <property name="title" translatable="yes">Jump to definition of symbol</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;&lt;shift&gt;Up</property>
+                <property name="title" translatable="yes">Move sectionport up within the file</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;&lt;shift&gt;Down</property>
+                <property name="title" translatable="yes">Move sectionport down within the file</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;&lt;shift&gt;End</property>
+                <property name="title" translatable="yes">Move sectionport to end of file</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;&lt;shift&gt;Home</property>
+                <property name="title" translatable="yes">Move sectionport to beginning of file</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;percent</property>
+                <property name="title" translatable="yes">Move to matching bracket</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Selections</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;a</property>
+                <property name="title" translatable="yes">Select all</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;backslash</property>
+                <property name="title" translatable="yes">Unselect all</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+    <child>
+      <object class="GtkShortcutsSection">
+        <property name="max-height">16</property>
+        <property name="section-name">terminal</property>
+        <property name="title" translatable="yes">Terminal Shortcuts</property>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">General</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Global Search</property>
+                <property name="accelerator">&lt;ctrl&gt;period</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Preferences</property>
+                <property name="accelerator">&lt;ctrl&gt;comma</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Command Bar</property>
+                <property name="accelerator">&lt;ctrl&gt;Return</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Terminal</property>
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;t</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="title" translatable="yes">Keyboard Shortcuts</property>
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;question</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Copy and Paste</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;c</property>
+                <property name="title" translatable="yes">Copy selected text to clipboard</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;shift&gt;v</property>
+                <property name="title" translatable="yes">Paste text from clipboard</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Switching</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;1...9</property>
+                <property name="title" translatable="yes">Switch to n-th tab</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">&apos;Special&apos; combinations</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">t+t</property>
+                <property name="title" translatable="yes">You want tea ?</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;shift&gt;&lt;ctrl&gt;</property>
+                <property name="title" translatable="yes">Shift Control</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&amp;&lt;ctrl&gt;</property>
+                <property name="title" translatable="yes">Control Control</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">Control_L&amp;Control_R</property>
+                <property name="title" translatable="yes">Left and right control</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">All gestures</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-pinch</property>
+                <property name="title" translatable="yes">A stock pinch gesture</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-stretch</property>
+                <property name="title" translatable="yes">A stock stretch gesture</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-rotate-clockwise</property>
+                <property name="title" translatable="yes">A stock rotation gesture</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-rotate-counterclockwise</property>
+                <property name="title" translatable="yes">A stock rotation gesture</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-two-finger-swipe-left</property>
+                <property name="title" translatable="yes">A stock swipe gesture</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-two-finger-swipe-right</property>
+                <property name="title" translatable="yes">A stock swipe gesture</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-swipe-left</property>
+                <property name="title" translatable="yes">A stock swipe gesture</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-swipe-right</property>
+                <property name="title" translatable="yes">A stock swipe gesture</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/docs/reference/gtk/images/button-dark.png b/docs/reference/gtk/images/button-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..6fa584e489cc212e999f8397627b395bdbad9189
Binary files /dev/null and b/docs/reference/gtk/images/button-dark.png differ
diff --git a/docs/reference/gtk/images/button.png b/docs/reference/gtk/images/button.png
index ce8f7998fb7589a3adaf5ba7ddafd4190bfdb96a..476ae3016f9491b3a7e6d64f1df66fcd9818cd8d 100644
Binary files a/docs/reference/gtk/images/button.png and b/docs/reference/gtk/images/button.png differ
diff --git a/docs/reference/gtk/images/calendar-dark.png b/docs/reference/gtk/images/calendar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..0c4d9949436935f4f21e66ad27a08f3b40eec2f3
Binary files /dev/null and b/docs/reference/gtk/images/calendar-dark.png differ
diff --git a/docs/reference/gtk/images/calendar.png b/docs/reference/gtk/images/calendar.png
index 93a29bfbf60543b2583f843d7fa87f98b5c60b94..df416b4652229ba4103f27fa986d45c5fc65cd30 100644
Binary files a/docs/reference/gtk/images/calendar.png and b/docs/reference/gtk/images/calendar.png differ
diff --git a/docs/reference/gtk/images/centerbox-dark.png b/docs/reference/gtk/images/centerbox-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..2d32cdd2c1a95e9a94a368b55b642df75566de64
Binary files /dev/null and b/docs/reference/gtk/images/centerbox-dark.png differ
diff --git a/docs/reference/gtk/images/centerbox.png b/docs/reference/gtk/images/centerbox.png
index e00e2dd635b5c6733922d8a0614fa50321268ef4..234ca0b23190c653f692fdce555f9a90f4cc6020 100644
Binary files a/docs/reference/gtk/images/centerbox.png and b/docs/reference/gtk/images/centerbox.png differ
diff --git a/docs/reference/gtk/images/check-button-dark.png b/docs/reference/gtk/images/check-button-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..19579c79d965a2e3419f18d12f126756114559ca
Binary files /dev/null and b/docs/reference/gtk/images/check-button-dark.png differ
diff --git a/docs/reference/gtk/images/check-button.png b/docs/reference/gtk/images/check-button.png
index f60a4881b11b6435ffdc610f65a60ea074c6c896..3ff76681a6aca3e9c27c305591bb31abc1bb8d2f 100644
Binary files a/docs/reference/gtk/images/check-button.png and b/docs/reference/gtk/images/check-button.png differ
diff --git a/docs/reference/gtk/images/clocks-shortcuts-dark.png b/docs/reference/gtk/images/clocks-shortcuts-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..4f90dd0ba4ff88fd50cc8270d1695937c5c7c216
Binary files /dev/null and b/docs/reference/gtk/images/clocks-shortcuts-dark.png differ
diff --git a/docs/reference/gtk/images/clocks-shortcuts.png b/docs/reference/gtk/images/clocks-shortcuts.png
index 9ab2d5a71f3b72bbcac5e6ea67978ce306741c1a..0a128d35219a8dd1c2b9505fc25bcebf012e8ad2 100644
Binary files a/docs/reference/gtk/images/clocks-shortcuts.png and b/docs/reference/gtk/images/clocks-shortcuts.png differ
diff --git a/docs/reference/gtk/images/clocks-shortcuts.ui b/docs/reference/gtk/images/clocks-shortcuts.ui
new file mode 100644
index 0000000000000000000000000000000000000000..c8066704a0a3c1dd324c218530a618a449c5af9c
--- /dev/null
+++ b/docs/reference/gtk/images/clocks-shortcuts.ui
@@ -0,0 +1,141 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkShortcutsWindow" id="shortcuts-clocks">
+    <property name="modal">1</property>
+    <child>
+      <object class="GtkShortcutsSection">
+        <property name="section-name">shortcuts</property>
+        <property name="max-height">10</property>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">General</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;Page_Down</property>
+                <property name="title" translatable="yes">Go to the next section</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;Page_Up</property>
+                <property name="title" translatable="yes">Go to the previous section</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;Q</property>
+                <property name="title" translatable="yes">Quit</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;Right</property>
+                <property name="direction">ltr</property>
+                <property name="title" translatable="yes">Forward</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;Left</property>
+                <property name="direction">ltr</property>
+                <property name="title" translatable="yes">Back</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;alt&gt;Left</property>
+                <property name="direction">rtl</property>
+                <property name="title" translatable="yes">Forward</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;Right</property>
+                <property name="direction">rtl</property>
+                <property name="title" translatable="yes">Back</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="view">world</property>
+            <property name="title" translatable="yes">World Clocks</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;N</property>
+                <property name="title" translatable="yes">Add a world clock</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;S</property>
+                <property name="title" translatable="yes">Select world clocks</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="view">alarm</property>
+            <property name="title" translatable="yes">Alarm</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;N</property>
+                <property name="title" translatable="yes">Add an alarm</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;S</property>
+                <property name="title" translatable="yes">Select alarms</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="view">stopwatch</property>
+            <property name="title" translatable="yes">Stopwatch</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">Return space</property>
+                <property name="title" translatable="yes">Start / Stop / Continue</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">L</property>
+                <property name="title" translatable="yes">Lap</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">Delete</property>
+                <property name="title" translatable="yes">Reset</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="view">timer</property>
+            <property name="title" translatable="yes">Timer</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">Return space</property>
+                <property name="title" translatable="yes">Start / Stop / Pause</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">Delete</property>
+                <property name="title" translatable="yes">Reset</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/docs/reference/gtk/images/color-button-dark.png b/docs/reference/gtk/images/color-button-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..9ca02b88c8b4fb53b42fedb50ff2e89515386334
Binary files /dev/null and b/docs/reference/gtk/images/color-button-dark.png differ
diff --git a/docs/reference/gtk/images/color-button.png b/docs/reference/gtk/images/color-button.png
index a71f03e9ba935b60281ce625cd6b0d0a5828c6c0..80ba2b19095cec71e08a8549be12d528d6d9edc1 100644
Binary files a/docs/reference/gtk/images/color-button.png and b/docs/reference/gtk/images/color-button.png differ
diff --git a/docs/reference/gtk/images/colorchooser-dark.png b/docs/reference/gtk/images/colorchooser-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..e67d07847bffc6b64293b7e0786b52e4033b9a72
Binary files /dev/null and b/docs/reference/gtk/images/colorchooser-dark.png differ
diff --git a/docs/reference/gtk/images/colorchooser.png b/docs/reference/gtk/images/colorchooser.png
index beba6249b27a854bb33d769ca5ba39a460219eea..b0d3403c545a5abeabbca0ac622feb88aa96c4c2 100644
Binary files a/docs/reference/gtk/images/colorchooser.png and b/docs/reference/gtk/images/colorchooser.png differ
diff --git a/docs/reference/gtk/images/combo-box-dark.png b/docs/reference/gtk/images/combo-box-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..9cc57489cbb2719f88e03c808a8dfca4285a578c
Binary files /dev/null and b/docs/reference/gtk/images/combo-box-dark.png differ
diff --git a/docs/reference/gtk/images/combo-box-entry-dark.png b/docs/reference/gtk/images/combo-box-entry-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..87d8edc5989ed789e13ca86c81ace4da635bfcb4
Binary files /dev/null and b/docs/reference/gtk/images/combo-box-entry-dark.png differ
diff --git a/docs/reference/gtk/images/combo-box-entry.png b/docs/reference/gtk/images/combo-box-entry.png
index d21c0879c9fe276333017335245e5709fdb8e104..c9e735169febcefcb29533bb13b6d386f73b31a7 100644
Binary files a/docs/reference/gtk/images/combo-box-entry.png and b/docs/reference/gtk/images/combo-box-entry.png differ
diff --git a/docs/reference/gtk/images/combo-box-text-dark.png b/docs/reference/gtk/images/combo-box-text-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..3e6670971ef7d0db78f21b6c360050af0c96a0d5
Binary files /dev/null and b/docs/reference/gtk/images/combo-box-text-dark.png differ
diff --git a/docs/reference/gtk/images/combo-box-text.png b/docs/reference/gtk/images/combo-box-text.png
index 959374debfbe6926ff2d61dacf0ed4b52f9e5018..ff9b5fa971a703df2eb9a7172359763e7744bb33 100644
Binary files a/docs/reference/gtk/images/combo-box-text.png and b/docs/reference/gtk/images/combo-box-text.png differ
diff --git a/docs/reference/gtk/images/combo-box.png b/docs/reference/gtk/images/combo-box.png
index 59feb96f88d41d18245cf0c4de34287145e8987f..ff0da831445bb27dd56c56a223df49724c2d5367 100644
Binary files a/docs/reference/gtk/images/combo-box.png and b/docs/reference/gtk/images/combo-box.png differ
diff --git a/docs/reference/gtk/images/dialog-dark.png b/docs/reference/gtk/images/dialog-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9b9376c327e29691e889580354a50ea965f346c
Binary files /dev/null and b/docs/reference/gtk/images/dialog-dark.png differ
diff --git a/docs/reference/gtk/images/dialog.png b/docs/reference/gtk/images/dialog.png
index ae6fa233b37d676fff60d45e14522bc399365ce2..457398252e4f3204c302937cf14079f1ef937db6 100644
Binary files a/docs/reference/gtk/images/dialog.png and b/docs/reference/gtk/images/dialog.png differ
diff --git a/docs/reference/gtk/images/drawingarea-dark.png b/docs/reference/gtk/images/drawingarea-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..897133e7f5de93762be0550bafd5344245f006d6
Binary files /dev/null and b/docs/reference/gtk/images/drawingarea-dark.png differ
diff --git a/docs/reference/gtk/images/drawingarea.png b/docs/reference/gtk/images/drawingarea.png
index 40392fe803469df5373e7bf795028b82b328137b..5908d1e91374e06612b9cd6a0af1a64b38f0ec5e 100644
Binary files a/docs/reference/gtk/images/drawingarea.png and b/docs/reference/gtk/images/drawingarea.png differ
diff --git a/docs/reference/gtk/images/drop-down-dark.png b/docs/reference/gtk/images/drop-down-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..856e4486fb3689ec63b3dfb6a47f03d051a79809
Binary files /dev/null and b/docs/reference/gtk/images/drop-down-dark.png differ
diff --git a/docs/reference/gtk/images/drop-down.png b/docs/reference/gtk/images/drop-down.png
index c230b27815a624760d8ef52d234ea70a5087e2be..48bc03be2b4c4d8793beebb71614243b7223e06e 100644
Binary files a/docs/reference/gtk/images/drop-down.png and b/docs/reference/gtk/images/drop-down.png differ
diff --git a/docs/reference/gtk/images/editable-label-dark.png b/docs/reference/gtk/images/editable-label-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..e209b215602a587b55ba6672f4ecc5a988f961b6
Binary files /dev/null and b/docs/reference/gtk/images/editable-label-dark.png differ
diff --git a/docs/reference/gtk/images/editable-label.png b/docs/reference/gtk/images/editable-label.png
index bedeb02b762af245b2de48b9f2707b9de59b5c89..6768e6e76148ce7612c5a0d14adeaafe1e85454d 100644
Binary files a/docs/reference/gtk/images/editable-label.png and b/docs/reference/gtk/images/editable-label.png differ
diff --git a/docs/reference/gtk/images/emojichooser-dark.png b/docs/reference/gtk/images/emojichooser-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..bbdb0d83ce1b876200e7e3c9459677a62c366144
Binary files /dev/null and b/docs/reference/gtk/images/emojichooser-dark.png differ
diff --git a/docs/reference/gtk/images/emojichooser.png b/docs/reference/gtk/images/emojichooser.png
index e5ad579bea2db1399a8b1fbbeb997b1b09f269e3..bc16b117e05ba0f668ebf516d25c6700e8dfbb90 100644
Binary files a/docs/reference/gtk/images/emojichooser.png and b/docs/reference/gtk/images/emojichooser.png differ
diff --git a/docs/reference/gtk/images/entry-dark.png b/docs/reference/gtk/images/entry-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..d043da35677c0f843f08d62c41e78a89b0b10ab1
Binary files /dev/null and b/docs/reference/gtk/images/entry-dark.png differ
diff --git a/docs/reference/gtk/images/entry.png b/docs/reference/gtk/images/entry.png
index b23b053044cb6dfe0ce0cc5202eea0e61cd7672c..9694567c1622af371cb123e7e3b2bd94403126eb 100644
Binary files a/docs/reference/gtk/images/entry.png and b/docs/reference/gtk/images/entry.png differ
diff --git a/docs/reference/gtk/images/expander-dark.png b/docs/reference/gtk/images/expander-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..64316ee56e73048718552cdca2ea310a3bff5343
Binary files /dev/null and b/docs/reference/gtk/images/expander-dark.png differ
diff --git a/docs/reference/gtk/images/expander.png b/docs/reference/gtk/images/expander.png
index c60dce6e1e21345c1dbd0287314e27173295cff8..58958a63963797e9cd2079c8331a25b609be8c0b 100644
Binary files a/docs/reference/gtk/images/expander.png and b/docs/reference/gtk/images/expander.png differ
diff --git a/docs/reference/gtk/images/flow-box-dark.png b/docs/reference/gtk/images/flow-box-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..ac0f633353ac26b02e476b36919f76e4a9af0c1b
Binary files /dev/null and b/docs/reference/gtk/images/flow-box-dark.png differ
diff --git a/docs/reference/gtk/images/flow-box.png b/docs/reference/gtk/images/flow-box.png
index fac59ffc22846a734ce5323ace45e74b376a4e6d..70590536bfa3c6fbe1b66cae80a7d4c4935331f1 100644
Binary files a/docs/reference/gtk/images/flow-box.png and b/docs/reference/gtk/images/flow-box.png differ
diff --git a/docs/reference/gtk/images/font-button-dark.png b/docs/reference/gtk/images/font-button-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..0596f9dc9e8020ae6b6e6041455c404480774ca2
Binary files /dev/null and b/docs/reference/gtk/images/font-button-dark.png differ
diff --git a/docs/reference/gtk/images/font-button.png b/docs/reference/gtk/images/font-button.png
index a60e093f6917aac1fc24e25ea3268ddf59664e23..d4ff0794eec06ff8559f2ec3c6f1d80569d3cb35 100644
Binary files a/docs/reference/gtk/images/font-button.png and b/docs/reference/gtk/images/font-button.png differ
diff --git a/docs/reference/gtk/images/fontchooser-dark.png b/docs/reference/gtk/images/fontchooser-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..1eac148b6cd57b9dd61b308887bec8e417a3c632
Binary files /dev/null and b/docs/reference/gtk/images/fontchooser-dark.png differ
diff --git a/docs/reference/gtk/images/fontchooser.png b/docs/reference/gtk/images/fontchooser.png
index 71ee87bf9ee766f7f6479e2af759b5e3908cccec..8ac904f021d0e00ba95c8316fc34359f226b4eee 100644
Binary files a/docs/reference/gtk/images/fontchooser.png and b/docs/reference/gtk/images/fontchooser.png differ
diff --git a/docs/reference/gtk/images/frame-dark.png b/docs/reference/gtk/images/frame-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..881ecf30b67f07af472543e3d2cc36fbb678ac6e
Binary files /dev/null and b/docs/reference/gtk/images/frame-dark.png differ
diff --git a/docs/reference/gtk/images/frame.png b/docs/reference/gtk/images/frame.png
index 4c886890fccf8b4d852657f724c3999039148ffd..c3a99e1eb5d957d92e85366923e270712535f781 100644
Binary files a/docs/reference/gtk/images/frame.png and b/docs/reference/gtk/images/frame.png differ
diff --git a/docs/reference/gtk/images/gedit-shortcuts-dark.png b/docs/reference/gtk/images/gedit-shortcuts-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..7c033b9b7b6d72ba840519da09850842df72561a
Binary files /dev/null and b/docs/reference/gtk/images/gedit-shortcuts-dark.png differ
diff --git a/docs/reference/gtk/images/gedit-shortcuts.png b/docs/reference/gtk/images/gedit-shortcuts.png
index 5d566ff8baf287ccaf054b1192465d396bb84888..7bcc294cfaae969311bc1f8650b6311b67aa1826 100644
Binary files a/docs/reference/gtk/images/gedit-shortcuts.png and b/docs/reference/gtk/images/gedit-shortcuts.png differ
diff --git a/docs/reference/gtk/images/gedit-shortcuts.ui b/docs/reference/gtk/images/gedit-shortcuts.ui
new file mode 100644
index 0000000000000000000000000000000000000000..b745c3c11b7a9c7b257d3bb5818718626bba5c10
--- /dev/null
+++ b/docs/reference/gtk/images/gedit-shortcuts.ui
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkShortcutsWindow" id="shortcuts-gedit">
+    <property name="modal">1</property>
+    <child>
+      <object class="GtkShortcutsSection">
+        <property name="section-name">shortcuts</property>
+        <property name="max-height">12</property>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Touchpad gestures</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-two-finger-swipe-right</property>
+                <property name="title" translatable="yes">Switch to the next document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="shortcut-type">gesture-two-finger-swipe-left</property>
+                <property name="title" translatable="yes">Switch to the previous document</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Documents</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;N</property>
+                <property name="title" translatable="yes">Create new document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;O</property>
+                <property name="title" translatable="yes">Open a document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;S</property>
+                <property name="title" translatable="yes">Save the document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;W</property>
+                <property name="title" translatable="yes">Close the document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;Alt&gt;Page_Down</property>
+                <property name="title" translatable="yes">Switch to the next document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;Alt&gt;Page_Up</property>
+                <property name="title" translatable="yes">Switch to the previous document</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Find and Replace</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;F</property>
+                <property name="title" translatable="yes">Find</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;G</property>
+                <property name="title" translatable="yes">Find the next match</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;Shift&gt;G</property>
+                <property name="title" translatable="yes">Find the previous match</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;H</property>
+                <property name="title" translatable="yes">Find and Replace</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;&lt;Shift&gt;K</property>
+                <property name="title" translatable="yes">Clear highlight</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;I</property>
+                <property name="title" translatable="yes">Go to line</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Tools</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;shift&gt;F7</property>
+                <property name="title" translatable="yes">Check spelling</property>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child>
+          <object class="GtkShortcutsGroup">
+            <property name="title" translatable="yes">Miscellaneous</property>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">F11</property>
+                <property name="title" translatable="yes">Fullscreen on / off</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">&lt;ctrl&gt;P</property>
+                <property name="title" translatable="yes">Print the document</property>
+              </object>
+            </child>
+            <child>
+              <object class="GtkShortcutsShortcut">
+                <property name="accelerator">Insert</property>
+                <property name="title" translatable="yes">Toggle insert / overwrite</property>
+              </object>
+            </child>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/docs/reference/gtk/images/glarea-dark.png b/docs/reference/gtk/images/glarea-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..e506fee378efe4ab1d91a037171afd3401b3135e
Binary files /dev/null and b/docs/reference/gtk/images/glarea-dark.png differ
diff --git a/docs/reference/gtk/images/glarea.png b/docs/reference/gtk/images/glarea.png
index 750dde8fdf7ae9cc1ddfd4673b910ea72b6342ed..8d52448cfb697aa0a1eb7a8bef4d20915624cf5e 100644
Binary files a/docs/reference/gtk/images/glarea.png and b/docs/reference/gtk/images/glarea.png differ
diff --git a/docs/reference/gtk/images/grid-dark.png b/docs/reference/gtk/images/grid-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..4edb625e0cadd186c9e958e596f121db9c9d9dd9
Binary files /dev/null and b/docs/reference/gtk/images/grid-dark.png differ
diff --git a/docs/reference/gtk/images/grid.png b/docs/reference/gtk/images/grid.png
index ae3722d1d361a27476fcd50e6fdf7f6c47bc63d3..536a108a049301bac0c804b57fe93664bccdd3c6 100644
Binary files a/docs/reference/gtk/images/grid.png and b/docs/reference/gtk/images/grid.png differ
diff --git a/docs/reference/gtk/images/headerbar-dark.png b/docs/reference/gtk/images/headerbar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..fb9082acc69a62bb6dbc2546450cfd1ea39d4a9a
Binary files /dev/null and b/docs/reference/gtk/images/headerbar-dark.png differ
diff --git a/docs/reference/gtk/images/headerbar.png b/docs/reference/gtk/images/headerbar.png
index 803487567443e1e654cc0577fde9b5c9fec6390d..9111c37a923155cfca874ac536fac4d18dab7632 100644
Binary files a/docs/reference/gtk/images/headerbar.png and b/docs/reference/gtk/images/headerbar.png differ
diff --git a/docs/reference/gtk/images/icon-view-dark.png b/docs/reference/gtk/images/icon-view-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..8132f133b84afbbe3bc4574774969a7fd7653b6b
Binary files /dev/null and b/docs/reference/gtk/images/icon-view-dark.png differ
diff --git a/docs/reference/gtk/images/icon-view.png b/docs/reference/gtk/images/icon-view.png
index 677918234f846c1322dec22c02666a07d75d1a41..83fe7a28bb03455538f4b59f6a21d8384343081c 100644
Binary files a/docs/reference/gtk/images/icon-view.png and b/docs/reference/gtk/images/icon-view.png differ
diff --git a/docs/reference/gtk/images/image-dark.png b/docs/reference/gtk/images/image-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..078a865a197903b8844bb74a0ebff82ea8e5216d
Binary files /dev/null and b/docs/reference/gtk/images/image-dark.png differ
diff --git a/docs/reference/gtk/images/image.png b/docs/reference/gtk/images/image.png
index e3fc27c4a551cac442d4056f3caa61f7b84e0c6b..3c69ca832936dd0fbbe6a337b60390b2c9e0d9b9 100644
Binary files a/docs/reference/gtk/images/image.png and b/docs/reference/gtk/images/image.png differ
diff --git a/docs/reference/gtk/images/info-bar-dark.png b/docs/reference/gtk/images/info-bar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..d1f6c17395579fb594c2c1e340218d1747f80252
Binary files /dev/null and b/docs/reference/gtk/images/info-bar-dark.png differ
diff --git a/docs/reference/gtk/images/info-bar.png b/docs/reference/gtk/images/info-bar.png
index 95665a5e8ffe972ef13cb3cef6d38bed30a236a1..bf670fccbd23050bef4a72fa41a7499164cbdfe8 100644
Binary files a/docs/reference/gtk/images/info-bar.png and b/docs/reference/gtk/images/info-bar.png differ
diff --git a/docs/reference/gtk/images/label-dark.png b/docs/reference/gtk/images/label-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..5f041b41516c5f46bcd96d61cb5cae884bf4c91e
Binary files /dev/null and b/docs/reference/gtk/images/label-dark.png differ
diff --git a/docs/reference/gtk/images/label.png b/docs/reference/gtk/images/label.png
index ecc10f13cb86d8217538469fcb2e07629584af3f..29fcfcb4924bf0bffc925f4379c5cf635d31acf3 100644
Binary files a/docs/reference/gtk/images/label.png and b/docs/reference/gtk/images/label.png differ
diff --git a/docs/reference/gtk/images/levelbar-dark.png b/docs/reference/gtk/images/levelbar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..b9b4cd66141ef22eb6d9f992bc394d461cf18c63
Binary files /dev/null and b/docs/reference/gtk/images/levelbar-dark.png differ
diff --git a/docs/reference/gtk/images/levelbar.png b/docs/reference/gtk/images/levelbar.png
index 3aa8b22d294db700b6e34288d09e569ab7f98051..88511d90223a51d9cd49d7d49ff6945fd9501fd1 100644
Binary files a/docs/reference/gtk/images/levelbar.png and b/docs/reference/gtk/images/levelbar.png differ
diff --git a/docs/reference/gtk/images/link-button-dark.png b/docs/reference/gtk/images/link-button-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..b5c7d2469c97062ee2addf526d7e33840725f25e
Binary files /dev/null and b/docs/reference/gtk/images/link-button-dark.png differ
diff --git a/docs/reference/gtk/images/link-button.png b/docs/reference/gtk/images/link-button.png
index 6f860356efd39cc2f63883296c270a29e39970b9..e1cb6bc6446bc1c5ce10b2392c07e9892d422347 100644
Binary files a/docs/reference/gtk/images/link-button.png and b/docs/reference/gtk/images/link-button.png differ
diff --git a/docs/reference/gtk/images/list-and-tree-dark.png b/docs/reference/gtk/images/list-and-tree-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..a16c4df3ee3fee6727cbf8f3a3afb14be21ad123
Binary files /dev/null and b/docs/reference/gtk/images/list-and-tree-dark.png differ
diff --git a/docs/reference/gtk/images/list-and-tree.png b/docs/reference/gtk/images/list-and-tree.png
index af0a7a2e62dc9531f8b6e38a8b0c6204db56b5dd..f043c77a64148d86732f1b53dbdaa52ce04d2cb3 100644
Binary files a/docs/reference/gtk/images/list-and-tree.png and b/docs/reference/gtk/images/list-and-tree.png differ
diff --git a/docs/reference/gtk/images/list-box-dark.png b/docs/reference/gtk/images/list-box-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..a56e1c27b557d85125fe04667cbce39b4d241d28
Binary files /dev/null and b/docs/reference/gtk/images/list-box-dark.png differ
diff --git a/docs/reference/gtk/images/list-box.png b/docs/reference/gtk/images/list-box.png
index b299b2fd31f166caecb6b2623eb4cb395a4efbd8..6c56514367df1b110593d6c2584483b825d61fd2 100644
Binary files a/docs/reference/gtk/images/list-box.png and b/docs/reference/gtk/images/list-box.png differ
diff --git a/docs/reference/gtk/images/lock-button.png b/docs/reference/gtk/images/lock-button.png
deleted file mode 100644
index 4282613bf3d202d3e07992dcd8d7e7acdfc3fab5..0000000000000000000000000000000000000000
Binary files a/docs/reference/gtk/images/lock-button.png and /dev/null differ
diff --git a/docs/reference/gtk/images/lockbutton-dark.png b/docs/reference/gtk/images/lockbutton-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..09f06189deb15a4f220e8e8159633bc6c6516098
Binary files /dev/null and b/docs/reference/gtk/images/lockbutton-dark.png differ
diff --git a/docs/reference/gtk/images/lockbutton-locked.png b/docs/reference/gtk/images/lockbutton-locked.png
deleted file mode 100644
index dec1e7cd016f29058375f18a1930dbedc4280207..0000000000000000000000000000000000000000
Binary files a/docs/reference/gtk/images/lockbutton-locked.png and /dev/null differ
diff --git a/docs/reference/gtk/images/lockbutton-sorry-dark.png b/docs/reference/gtk/images/lockbutton-sorry-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..77fa466e3933af4c78935c23df69d44f43d72d1e
Binary files /dev/null and b/docs/reference/gtk/images/lockbutton-sorry-dark.png differ
diff --git a/docs/reference/gtk/images/lockbutton-sorry.png b/docs/reference/gtk/images/lockbutton-sorry.png
index ef9374a0badbbb1da6c4ab069a49885c22630723..40b3c29accae34fd578b58caf88854f1b8d597c2 100644
Binary files a/docs/reference/gtk/images/lockbutton-sorry.png and b/docs/reference/gtk/images/lockbutton-sorry.png differ
diff --git a/docs/reference/gtk/images/lockbutton-unlocked-dark.png b/docs/reference/gtk/images/lockbutton-unlocked-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..1b82afbc9e6bc4f5c8e15587d16725111746fd3e
Binary files /dev/null and b/docs/reference/gtk/images/lockbutton-unlocked-dark.png differ
diff --git a/docs/reference/gtk/images/lockbutton-unlocked.png b/docs/reference/gtk/images/lockbutton-unlocked.png
index a1d5f719b6000034d9dc22cec5d5605734e47085..dd00f6160e18f5c419cfd4d59a1551f54274fc42 100644
Binary files a/docs/reference/gtk/images/lockbutton-unlocked.png and b/docs/reference/gtk/images/lockbutton-unlocked.png differ
diff --git a/docs/reference/gtk/images/lockbutton.png b/docs/reference/gtk/images/lockbutton.png
index 7cc008f06ea8c43f6f1a94329ec9bc60068c611a..921b3ad29726d89b1e598eb955ab7805f1c92ef1 100644
Binary files a/docs/reference/gtk/images/lockbutton.png and b/docs/reference/gtk/images/lockbutton.png differ
diff --git a/docs/reference/gtk/images/lockbutton.ui b/docs/reference/gtk/images/lockbutton.ui
new file mode 100644
index 0000000000000000000000000000000000000000..669297005b4cb4fd0d68adb4ec59c0a6ec41ec57
--- /dev/null
+++ b/docs/reference/gtk/images/lockbutton.ui
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkWindow" id="window">
+    <property name="decorated">0</property>
+    <property name="resizable">0</property>
+    <property name="default-width">280</property>
+    <property name="default-height">120</property>
+    <style>
+       <class name="nobackground"/>
+    </style>
+    <child>
+      <object class="GtkBox">
+        <style>
+          <class name="shadow"/>
+          <class name="background"/>
+          <class name="frame"/>
+        </style>
+        <child>
+          <object class="GtkLockButton" id="lockbutton">
+            <property name="hexpand">1</property>
+            <property name="vexpand">1</property>
+            <property name="halign">center</property>
+            <property name="valign">center</property>
+          </object>
+        </child>
+      </object>
+    </child>
+  </object>
+</interface>
diff --git a/docs/reference/gtk/images/macos-window-controls.png b/docs/reference/gtk/images/macos-window-controls.png
new file mode 100644
index 0000000000000000000000000000000000000000..4e3c6e1ff64c4906a2d5b081b44067d2ad99f2e4
Binary files /dev/null and b/docs/reference/gtk/images/macos-window-controls.png differ
diff --git a/docs/reference/gtk/images/media-controls-dark.png b/docs/reference/gtk/images/media-controls-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..5130018756a14b5177d9bf0bbfaeb3276b92a34f
Binary files /dev/null and b/docs/reference/gtk/images/media-controls-dark.png differ
diff --git a/docs/reference/gtk/images/media-controls.png b/docs/reference/gtk/images/media-controls.png
index 9d894a14f02f339c48a77d8abc03ba1eb9ab19dc..27bf198b5000ff5d5b796100bcaf4ea4386498ef 100644
Binary files a/docs/reference/gtk/images/media-controls.png and b/docs/reference/gtk/images/media-controls.png differ
diff --git a/docs/reference/gtk/images/menu-button-dark.png b/docs/reference/gtk/images/menu-button-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..6e8dbd2e4d8049a8491ef106481e730b6dd7a795
Binary files /dev/null and b/docs/reference/gtk/images/menu-button-dark.png differ
diff --git a/docs/reference/gtk/images/menu-button.png b/docs/reference/gtk/images/menu-button.png
index ca9a7d362b50c4e2b06cb336cc6c615cd89169e7..de06b0a908286b263ca286308e403aeb09a45d3e 100644
Binary files a/docs/reference/gtk/images/menu-button.png and b/docs/reference/gtk/images/menu-button.png differ
diff --git a/docs/reference/gtk/images/menu-dark.png b/docs/reference/gtk/images/menu-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..d8407f4ea416747bcb8dd5f6548ccb87fa0c7c61
Binary files /dev/null and b/docs/reference/gtk/images/menu-dark.png differ
diff --git a/docs/reference/gtk/images/menu.png b/docs/reference/gtk/images/menu.png
index aff2fce102103d582d04863cb29d48eb1f432d57..12056f7f7585b3debce95b2b33f611323c7d557c 100644
Binary files a/docs/reference/gtk/images/menu.png and b/docs/reference/gtk/images/menu.png differ
diff --git a/docs/reference/gtk/images/menubar-dark.png b/docs/reference/gtk/images/menubar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..acdbe67b9a892f6022d3a118523475238747138d
Binary files /dev/null and b/docs/reference/gtk/images/menubar-dark.png differ
diff --git a/docs/reference/gtk/images/menubar.png b/docs/reference/gtk/images/menubar.png
index 1c30bd7108cd2e186ba65aa2c272e26288eafb89..f0c6874756789068ac61f29ebd9fb2eb7f1bde36 100644
Binary files a/docs/reference/gtk/images/menubar.png and b/docs/reference/gtk/images/menubar.png differ
diff --git a/docs/reference/gtk/images/meson.build b/docs/reference/gtk/images/meson.build
index fbd719192f8267ae3fc02d22cb0020183c8a79bb..7694ff350356fcf106982ebea833988d16aa8b5c 100644
--- a/docs/reference/gtk/images/meson.build
+++ b/docs/reference/gtk/images/meson.build
@@ -7,10 +7,12 @@ ui_files = [
   'appchooserdialog.ui',
   'assistant.ui',
   'box.ui',
+  'builder-shortcuts.ui',
   'button.ui',
   'calendar.ui',
   'centerbox.ui',
   'check-button.ui',
+  'clocks-shortcuts.ui',
   'colorchooser.ui',
   'color-button.ui',
   'combo-box.ui',
@@ -27,6 +29,7 @@ ui_files = [
   'fontchooser.ui',
   'font-button.ui',
   'frame.ui',
+  'gedit-shortcuts.ui',
   'glarea.ui',
   'grid.ui',
   'headerbar.ui',
@@ -50,7 +53,7 @@ ui_files = [
   'panes.ui',
   'password-entry.ui',
   'picture.ui',
-  'popover.ui',
+  #'popover.ui',
   'printdialog.ui',
   'progressbar.ui',
   'radio-button.ui',
@@ -88,5 +91,15 @@ if get_option('screenshots')
                                            '--force',
                                            '--css', '@INPUT1@',
                                            '@INPUT0@', '@OUTPUT@' ])
+
+    dark_png_file = ui_file.replace('.ui', '-dark.png')
+    gtk_images += custom_target('@0@ from @1@'.format(dark_png_file, ui_file),
+                                input: [ui_file, 'style.css'],
+                                output: dark_png_file,
+                                env: [ 'GTK_THEME=Default-dark' ],
+                                command: [ gtk_builder_tool, 'screenshot',
+                                           '--force',
+                                           '--css', '@INPUT1@',
+                                           '@INPUT0@', '@OUTPUT@' ])
   endforeach
 endif
diff --git a/docs/reference/gtk/images/messagedialog-dark.png b/docs/reference/gtk/images/messagedialog-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..34b681372a1acd7c426c8babc980e5d49079468f
Binary files /dev/null and b/docs/reference/gtk/images/messagedialog-dark.png differ
diff --git a/docs/reference/gtk/images/messagedialog.png b/docs/reference/gtk/images/messagedialog.png
index b6d6a16856baa196da4ec8e848c226de07f6125a..bbc9e84ee6cda6b3323cb9a25bc5cdfa2712d77b 100644
Binary files a/docs/reference/gtk/images/messagedialog.png and b/docs/reference/gtk/images/messagedialog.png differ
diff --git a/docs/reference/gtk/images/multiline-text-dark.png b/docs/reference/gtk/images/multiline-text-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..d170ffc244084b26a4df68a4a3eb489c2c12b164
Binary files /dev/null and b/docs/reference/gtk/images/multiline-text-dark.png differ
diff --git a/docs/reference/gtk/images/multiline-text.png b/docs/reference/gtk/images/multiline-text.png
index 3ba454bbfe684ffa6249e5364ae54a0e6e297860..0415d7fd9e01bcadd16bef34680ddfd87507f93e 100644
Binary files a/docs/reference/gtk/images/multiline-text.png and b/docs/reference/gtk/images/multiline-text.png differ
diff --git a/docs/reference/gtk/images/notebook-dark.png b/docs/reference/gtk/images/notebook-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..b44932429698d9c5d1744d029d4dc50b497ff546
Binary files /dev/null and b/docs/reference/gtk/images/notebook-dark.png differ
diff --git a/docs/reference/gtk/images/notebook.png b/docs/reference/gtk/images/notebook.png
index 18d898ee3fa5be5b0ff0b9037fa8ad279757ff25..457c0b104be34893b88e3235d3769a2a8a15810f 100644
Binary files a/docs/reference/gtk/images/notebook.png and b/docs/reference/gtk/images/notebook.png differ
diff --git a/docs/reference/gtk/images/overlay-dark.png b/docs/reference/gtk/images/overlay-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..76691302fe0e3559b72ff5d4379f62c51f2d12d2
Binary files /dev/null and b/docs/reference/gtk/images/overlay-dark.png differ
diff --git a/docs/reference/gtk/images/overlay.png b/docs/reference/gtk/images/overlay.png
index 730db88a462ef943da5eb407982f2fa2baa7ef26..25d5de57f158b348c6210a5ba79b4314d4baf137 100644
Binary files a/docs/reference/gtk/images/overlay.png and b/docs/reference/gtk/images/overlay.png differ
diff --git a/docs/reference/gtk/images/pagesetupdialog-dark.png b/docs/reference/gtk/images/pagesetupdialog-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..765af489bcc03cdc49c9a5be74163553712a6dec
Binary files /dev/null and b/docs/reference/gtk/images/pagesetupdialog-dark.png differ
diff --git a/docs/reference/gtk/images/pagesetupdialog.png b/docs/reference/gtk/images/pagesetupdialog.png
index ef1ae452f2054440fe734243a31830ec6d8743bf..6ef51c9916e4ee4e4065d511aad1848b85b72fb2 100644
Binary files a/docs/reference/gtk/images/pagesetupdialog.png and b/docs/reference/gtk/images/pagesetupdialog.png differ
diff --git a/docs/reference/gtk/images/panes-dark.png b/docs/reference/gtk/images/panes-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..c32e251e4a22209edaaaf2222bfda816c1440acb
Binary files /dev/null and b/docs/reference/gtk/images/panes-dark.png differ
diff --git a/docs/reference/gtk/images/panes.png b/docs/reference/gtk/images/panes.png
index e648f617038fca314024926df0ce000a91f44083..f11f78d08a20c307081e6ad306c48fba535eb51c 100644
Binary files a/docs/reference/gtk/images/panes.png and b/docs/reference/gtk/images/panes.png differ
diff --git a/docs/reference/gtk/images/password-entry-dark.png b/docs/reference/gtk/images/password-entry-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..417568cb6c0fc5a2101b646f1310ca93afea0f49
Binary files /dev/null and b/docs/reference/gtk/images/password-entry-dark.png differ
diff --git a/docs/reference/gtk/images/password-entry.png b/docs/reference/gtk/images/password-entry.png
index 151f7d1447cb2fa7e18bd30ba5e3485ace1ab8de..aa4e9e28a46dbba0b33133c2e4ec6b5221e0f815 100644
Binary files a/docs/reference/gtk/images/password-entry.png and b/docs/reference/gtk/images/password-entry.png differ
diff --git a/docs/reference/gtk/images/picture-dark.png b/docs/reference/gtk/images/picture-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..12d4d38487334f3eaa16cfc2e5393efea3e0d68a
Binary files /dev/null and b/docs/reference/gtk/images/picture-dark.png differ
diff --git a/docs/reference/gtk/images/picture.png b/docs/reference/gtk/images/picture.png
index 36670d0e570393531cbc69ae315a0a3e4dfcbd26..a529609bc13af9b09f99febb69f97e6704211973 100644
Binary files a/docs/reference/gtk/images/picture.png and b/docs/reference/gtk/images/picture.png differ
diff --git a/docs/reference/gtk/images/popover-dark.png b/docs/reference/gtk/images/popover-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..f14892753eb7f37b346c8d9561922d5d3a937aa9
Binary files /dev/null and b/docs/reference/gtk/images/popover-dark.png differ
diff --git a/docs/reference/gtk/images/popover.png b/docs/reference/gtk/images/popover.png
index df9314b1bb867cc1adda0d7b1ae4ad7017c2a6cd..6d4295d2408f92db598ef483f987c03d8c398e35 100644
Binary files a/docs/reference/gtk/images/popover.png and b/docs/reference/gtk/images/popover.png differ
diff --git a/docs/reference/gtk/images/printdialog-dark.png b/docs/reference/gtk/images/printdialog-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..573896843cef2cd8b685fe1bde23b6a851b7b83d
Binary files /dev/null and b/docs/reference/gtk/images/printdialog-dark.png differ
diff --git a/docs/reference/gtk/images/printdialog.png b/docs/reference/gtk/images/printdialog.png
index 323778c72cd30099af4089abebc3fb1a47a33d22..b07b1099fe2f1d79a8a2d1df7635358f7072c4ed 100644
Binary files a/docs/reference/gtk/images/printdialog.png and b/docs/reference/gtk/images/printdialog.png differ
diff --git a/docs/reference/gtk/images/progressbar-dark.png b/docs/reference/gtk/images/progressbar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..0956afa8fcfe6d49b39e8ad0467cbf09c8bc9473
Binary files /dev/null and b/docs/reference/gtk/images/progressbar-dark.png differ
diff --git a/docs/reference/gtk/images/progressbar.png b/docs/reference/gtk/images/progressbar.png
index c44840d464f675aa5becb4672174d75e324f137f..14f0ec650323742889ae462fcfeeeed3bb4f6db4 100644
Binary files a/docs/reference/gtk/images/progressbar.png and b/docs/reference/gtk/images/progressbar.png differ
diff --git a/docs/reference/gtk/images/radio-button-dark.png b/docs/reference/gtk/images/radio-button-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..41e13c94f0ce1d2fa0ef654f68e303bf19794ccf
Binary files /dev/null and b/docs/reference/gtk/images/radio-button-dark.png differ
diff --git a/docs/reference/gtk/images/radio-button.png b/docs/reference/gtk/images/radio-button.png
index 9c205c6ec549da599f129dcd68b23337c8e7a7a7..614dc7352ef401c7c736f5046c4a7fdf5816e894 100644
Binary files a/docs/reference/gtk/images/radio-button.png and b/docs/reference/gtk/images/radio-button.png differ
diff --git a/docs/reference/gtk/images/scales-dark.png b/docs/reference/gtk/images/scales-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..526be433a94d1f68e080104a0bac420faa3c08a2
Binary files /dev/null and b/docs/reference/gtk/images/scales-dark.png differ
diff --git a/docs/reference/gtk/images/scales.png b/docs/reference/gtk/images/scales.png
index c4c191bcd7853575cc55715ab0e2897158dfac0c..7a2519aee6187489407abd2524e77a6b3e1af333 100644
Binary files a/docs/reference/gtk/images/scales.png and b/docs/reference/gtk/images/scales.png differ
diff --git a/docs/reference/gtk/images/scrollbar-dark.png b/docs/reference/gtk/images/scrollbar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..52fc823a576e7fbf33a43bc22f22cbf6606ceee4
Binary files /dev/null and b/docs/reference/gtk/images/scrollbar-dark.png differ
diff --git a/docs/reference/gtk/images/scrollbar.png b/docs/reference/gtk/images/scrollbar.png
index c475be552a0686581abd28ac1b868dfa8451196a..80e505283a3dca997da7923c65b317f12bffebdc 100644
Binary files a/docs/reference/gtk/images/scrollbar.png and b/docs/reference/gtk/images/scrollbar.png differ
diff --git a/docs/reference/gtk/images/scrolledwindow-dark.png b/docs/reference/gtk/images/scrolledwindow-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..d6a19b5ad5bfdbf9f62cc282edab7fd8fb2091e2
Binary files /dev/null and b/docs/reference/gtk/images/scrolledwindow-dark.png differ
diff --git a/docs/reference/gtk/images/scrolledwindow.png b/docs/reference/gtk/images/scrolledwindow.png
index a09e504f4427da9e5a89d80b57c625688ee968de..d5d124b55a89322455b0eb47f4775b71d0663b5d 100644
Binary files a/docs/reference/gtk/images/scrolledwindow.png and b/docs/reference/gtk/images/scrolledwindow.png differ
diff --git a/docs/reference/gtk/images/search-bar-dark.png b/docs/reference/gtk/images/search-bar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..c34403975705e369d5ca0507aff7202c2ee1026f
Binary files /dev/null and b/docs/reference/gtk/images/search-bar-dark.png differ
diff --git a/docs/reference/gtk/images/search-bar.png b/docs/reference/gtk/images/search-bar.png
index 60845837c1da15a6a1b1dbaa30ea1cbc1c5812af..6e8447c07493a8ce5b2f1dba3f46fed6b5a300bf 100644
Binary files a/docs/reference/gtk/images/search-bar.png and b/docs/reference/gtk/images/search-bar.png differ
diff --git a/docs/reference/gtk/images/search-entry-dark.png b/docs/reference/gtk/images/search-entry-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..9dc91d58cf379a68f130dd296cea77dcaaf4e461
Binary files /dev/null and b/docs/reference/gtk/images/search-entry-dark.png differ
diff --git a/docs/reference/gtk/images/search-entry.png b/docs/reference/gtk/images/search-entry.png
index 1462a01ef7c4a484310302f1b22d1eb14de72ca1..abe0c58b738dca76a45378386b8a103c6c409d79 100644
Binary files a/docs/reference/gtk/images/search-entry.png and b/docs/reference/gtk/images/search-entry.png differ
diff --git a/docs/reference/gtk/images/separator-dark.png b/docs/reference/gtk/images/separator-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..4cc5507efc8df57655468ccd3b1a15713ae6e825
Binary files /dev/null and b/docs/reference/gtk/images/separator-dark.png differ
diff --git a/docs/reference/gtk/images/separator.png b/docs/reference/gtk/images/separator.png
index fed07a41de25714962707be3a7b0368f0dec1d61..254bd21fa4d393faeefca4634883e31a657fe6a4 100644
Binary files a/docs/reference/gtk/images/separator.png and b/docs/reference/gtk/images/separator.png differ
diff --git a/docs/reference/gtk/images/shortcuts-window-dark.png b/docs/reference/gtk/images/shortcuts-window-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..db43362ce8ea5cabb01e5d40658f6e5f8022d870
Binary files /dev/null and b/docs/reference/gtk/images/shortcuts-window-dark.png differ
diff --git a/docs/reference/gtk/images/shortcuts-window.png b/docs/reference/gtk/images/shortcuts-window.png
index 86978b6efbe11a440453e37ecfe8cbc6014a7c04..3382c1647560f802f315f79d14db6044895b2848 100644
Binary files a/docs/reference/gtk/images/shortcuts-window.png and b/docs/reference/gtk/images/shortcuts-window.png differ
diff --git a/docs/reference/gtk/images/sidebar-dark.png b/docs/reference/gtk/images/sidebar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..0edfb2733ee3080da794239854873e91f7aee291
Binary files /dev/null and b/docs/reference/gtk/images/sidebar-dark.png differ
diff --git a/docs/reference/gtk/images/sidebar.png b/docs/reference/gtk/images/sidebar.png
index f36f6df772e3d36a9e8313565633fe9beef9e04e..0c7c171e14283769c11020112f90e3ae289767b7 100644
Binary files a/docs/reference/gtk/images/sidebar.png and b/docs/reference/gtk/images/sidebar.png differ
diff --git a/docs/reference/gtk/images/spinbutton-dark.png b/docs/reference/gtk/images/spinbutton-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..49d46e866471135efd3c9ff5a2aad00de71018f6
Binary files /dev/null and b/docs/reference/gtk/images/spinbutton-dark.png differ
diff --git a/docs/reference/gtk/images/spinbutton.png b/docs/reference/gtk/images/spinbutton.png
index fa4375fd82ae7f7654946b80c7f49c2ddd42a3e6..a33871c0d1694a58734b00ed22759aa5b8d14f22 100644
Binary files a/docs/reference/gtk/images/spinbutton.png and b/docs/reference/gtk/images/spinbutton.png differ
diff --git a/docs/reference/gtk/images/spinner-dark.png b/docs/reference/gtk/images/spinner-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..7b031e3cbc6d1188194559413a10bb27c5d95321
Binary files /dev/null and b/docs/reference/gtk/images/spinner-dark.png differ
diff --git a/docs/reference/gtk/images/spinner.png b/docs/reference/gtk/images/spinner.png
index 9351841c791debca28ec470fb969289683fca222..12f807f714842d8b42d56de9a727492fddedfab3 100644
Binary files a/docs/reference/gtk/images/spinner.png and b/docs/reference/gtk/images/spinner.png differ
diff --git a/docs/reference/gtk/images/stack-dark.png b/docs/reference/gtk/images/stack-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..70f12ed6f01660fd2e3a713161202b2f4213b994
Binary files /dev/null and b/docs/reference/gtk/images/stack-dark.png differ
diff --git a/docs/reference/gtk/images/stack.png b/docs/reference/gtk/images/stack.png
index 48c445b35db8450d13e054bc7b94742afb37a941..5e12d1a412d035c1c9b8aa674d6c571946cb9d6b 100644
Binary files a/docs/reference/gtk/images/stack.png and b/docs/reference/gtk/images/stack.png differ
diff --git a/docs/reference/gtk/images/stackswitcher-dark.png b/docs/reference/gtk/images/stackswitcher-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..94b97d4e6203cbe110cb161e6be09c6335b68033
Binary files /dev/null and b/docs/reference/gtk/images/stackswitcher-dark.png differ
diff --git a/docs/reference/gtk/images/stackswitcher.png b/docs/reference/gtk/images/stackswitcher.png
index ee51c3626b44ea424fa3ae8b2600a57fee406e33..5cc2c39b69319eaa4ca31e6d2fa8e106c60c9f9c 100644
Binary files a/docs/reference/gtk/images/stackswitcher.png and b/docs/reference/gtk/images/stackswitcher.png differ
diff --git a/docs/reference/gtk/images/statusbar-dark.png b/docs/reference/gtk/images/statusbar-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..e1c4c46532e256d1b71d436d3b35160533f37256
Binary files /dev/null and b/docs/reference/gtk/images/statusbar-dark.png differ
diff --git a/docs/reference/gtk/images/statusbar.png b/docs/reference/gtk/images/statusbar.png
index 1d41a1a86e86afa8fc6695c4ab5c23216cccc949..66ef88dc8ee72daf15c5a72f907601d60a06a5dd 100644
Binary files a/docs/reference/gtk/images/statusbar.png and b/docs/reference/gtk/images/statusbar.png differ
diff --git a/docs/reference/gtk/images/switch-dark.png b/docs/reference/gtk/images/switch-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..3d16f182d431b65a049fb2acde0e8f6e7f213042
Binary files /dev/null and b/docs/reference/gtk/images/switch-dark.png differ
diff --git a/docs/reference/gtk/images/switch-state-dark.png b/docs/reference/gtk/images/switch-state-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..acf545d279d15ff64facaf0f1813d487d1239827
Binary files /dev/null and b/docs/reference/gtk/images/switch-state-dark.png differ
diff --git a/docs/reference/gtk/images/switch-state.png b/docs/reference/gtk/images/switch-state.png
index 97a965b4ef22121d6d635f963116c3f26a76e267..e5484b4cadbc633305ec84f99268a7ae7bb1475b 100644
Binary files a/docs/reference/gtk/images/switch-state.png and b/docs/reference/gtk/images/switch-state.png differ
diff --git a/docs/reference/gtk/images/switch.png b/docs/reference/gtk/images/switch.png
index 73b95ab0758fe6c39ea19990f74e78aed7a0453e..6b2880b89c4978bcd931097ca9f34768776134ca 100644
Binary files a/docs/reference/gtk/images/switch.png and b/docs/reference/gtk/images/switch.png differ
diff --git a/docs/reference/gtk/images/toggle-button-dark.png b/docs/reference/gtk/images/toggle-button-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..3d25427dbc3dc86944c6ad7e7a98fb881b0d3c3d
Binary files /dev/null and b/docs/reference/gtk/images/toggle-button-dark.png differ
diff --git a/docs/reference/gtk/images/toggle-button.png b/docs/reference/gtk/images/toggle-button.png
index 01cdda398c83dbf7e5eaecb611312acb91b55760..ae2f1563d86c6c207919d51a8974eae65c0daf6c 100644
Binary files a/docs/reference/gtk/images/toggle-button.png and b/docs/reference/gtk/images/toggle-button.png differ
diff --git a/docs/reference/gtk/images/video-dark.png b/docs/reference/gtk/images/video-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..39f6372e7b1a807dee46f6006165c34edb965e36
Binary files /dev/null and b/docs/reference/gtk/images/video-dark.png differ
diff --git a/docs/reference/gtk/images/video.png b/docs/reference/gtk/images/video.png
index 2ce75a38e788b28d10a9f0b27f667f071aa0d58e..f3fa19ff7dd0de5cd5c23a9391e2bf3c37c62172 100644
Binary files a/docs/reference/gtk/images/video.png and b/docs/reference/gtk/images/video.png differ
diff --git a/docs/reference/gtk/images/volumebutton-dark.png b/docs/reference/gtk/images/volumebutton-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..d8bdfe6d6c509c173e2e5631057e5c317b6c3cd4
Binary files /dev/null and b/docs/reference/gtk/images/volumebutton-dark.png differ
diff --git a/docs/reference/gtk/images/volumebutton.png b/docs/reference/gtk/images/volumebutton.png
index 0b8031f4f197dd1e7905eddc25fb9efc3409244c..e824a3c7f93ac6444136954fab96655aa2dc8bdd 100644
Binary files a/docs/reference/gtk/images/volumebutton.png and b/docs/reference/gtk/images/volumebutton.png differ
diff --git a/docs/reference/gtk/images/window-dark.png b/docs/reference/gtk/images/window-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..c5e7d17b53264a6bc724fa6cfc9160d060fd2e4c
Binary files /dev/null and b/docs/reference/gtk/images/window-dark.png differ
diff --git a/docs/reference/gtk/images/window.png b/docs/reference/gtk/images/window.png
index b76054275308c5a18efb323e53b3fb42bf0cb8e7..82e1ab78dca14d21833b8a9f7f34e4b55d21265a 100644
Binary files a/docs/reference/gtk/images/window.png and b/docs/reference/gtk/images/window.png differ
diff --git a/docs/reference/gtk/images/windowcontrols-dark.png b/docs/reference/gtk/images/windowcontrols-dark.png
new file mode 100644
index 0000000000000000000000000000000000000000..4a75567b8a0bfa1778bea6e9fe07a9e8f95d15a6
Binary files /dev/null and b/docs/reference/gtk/images/windowcontrols-dark.png differ
diff --git a/docs/reference/gtk/images/windowcontrols.png b/docs/reference/gtk/images/windowcontrols.png
index 5407cfece75d6529d9f6da8bc0b1b167801e4d85..c24b111dfa83aae2dc33bbd2449771a93fb791be 100644
Binary files a/docs/reference/gtk/images/windowcontrols.png and b/docs/reference/gtk/images/windowcontrols.png differ
diff --git a/docs/reference/gtk/initialization.md b/docs/reference/gtk/initialization.md
index e9e467d7b2012ce821856ef025aa87d7a6b00756..0af7212ed116206eb6c2a2b625a96123a59a2a42 100644
--- a/docs/reference/gtk/initialization.md
+++ b/docs/reference/gtk/initialization.md
@@ -17,8 +17,8 @@ more widgets.
 
 When widgets receive an event, they frequently emit one or more “signals”.
 Signals notify your program that "something interesting happened" by invoking
-functions you’ve connected to the signal with `g_signal_connect()`. Functions
-connected to a signal are often called “callbacks”.
+functions you’ve connected to the signal with [func@GObject.signal_connect].
+Functions connected to a signal are often called “callbacks”.
 
 When your callbacks are invoked, you would typically take some action - for
 example, when an Open button is clicked you might display a [class@Gtk.FileChooserDialog].
@@ -64,5 +64,5 @@ as spinning the main loop.
 
 ### See also
 
-- the GLib manual, especially `GMainLoop`
-- signal-related functions, such as `g_signal_connect()` in GObject
+- the GLib manual, especially [struct@GLib.MainContext]
+- signal-related functions, such as [func@GObject.signal_connect] in GObject
diff --git a/docs/reference/gtk/input-handling.md b/docs/reference/gtk/input-handling.md
index 442143a381ece5826e7941950a921960287e8742..c8f492054a90dbe34f60e53ccd6bea6d8b73e024 100644
--- a/docs/reference/gtk/input-handling.md
+++ b/docs/reference/gtk/input-handling.md
@@ -73,16 +73,16 @@ In the first phase (the “capture” phase) the event is delivered to
 each widget from the top-most (the top-level `GtkWindow` or grab widget)
 down to the target widget.
 [Event controllers](event-controllers-and-gestures) that are attached
-with %GTK_PHASE_CAPTURE get a chance to react to the event.
+with `GTK_PHASE_CAPTURE` get a chance to react to the event.
 
 After the “capture” phase, the widget that was intended to be the
 destination of the event will run event controllers attached to
-it with %GTK_PHASE_TARGET. This is known as the “target” phase,
+it with `GTK_PHASE_TARGET`. This is known as the “target” phase,
 and only happens on that widget.
 
 In the last phase (the “bubble” phase), the event is delivered
 to each widget from the target to the top-most, and event
-controllers attached with %GTK_PHASE_BUBBLE are run.
+controllers attached with `GTK_PHASE_BUBBLE` are run.
 
 Events are not delivered to a widget which is insensitive or unmapped.
 
@@ -97,7 +97,7 @@ below to learn more about gestures and sequences.
 
 Every `GtkWindow` maintains a single focus location (in the :focus-widget
 property). The focus widget is the target widget for key events sent to
-the window. Only widgets which have :focusable set to %TRUE can become
+the window. Only widgets which have :focusable set to true can become
 the focus. Typically these are input controls such as entries or text
 fields, but e.g. buttons can take the focus too.
 
@@ -208,7 +208,7 @@ Alternatively, or at a later point in time, the widget may choose
 to deny the touch sequences, thus letting those go through again
 in event propagation. When this happens in the capture phase, and
 if there are no other claiming gestures in the widget,
-a %GDK_TOUCH_BEGIN/%GDK_BUTTON_PRESS event will be emulated and
+a `GDK_TOUCH_BEGIN`/`GDK_BUTTON_PRESS` event will be emulated and
 propagated downwards, in order to preserve consistency.
 
 Grouped gestures always share the same state for a given touch
diff --git a/docs/reference/gtk/meson.build b/docs/reference/gtk/meson.build
index 46b2e220cfffe4e464d24c530ee38a31e1b49c52..7b5e18b0fc91df2f2be306442386550a00adf183 100644
--- a/docs/reference/gtk/meson.build
+++ b/docs/reference/gtk/meson.build
@@ -104,6 +104,7 @@ endif
 
 rst2x_flags = [
   '--syntax-highlight=none',
+  '--halt=warning',
 ]
 
 if get_option('man-pages')
diff --git a/docs/reference/gtk/migrating-3to4.md b/docs/reference/gtk/migrating-3to4.md
index eee5a740d258335bb263a5e35416af5410b6d93b..f10509150aa44b4717180d1fbcc97a2d32e119fd 100644
--- a/docs/reference/gtk/migrating-3to4.md
+++ b/docs/reference/gtk/migrating-3to4.md
@@ -995,7 +995,7 @@ since these windows no longer exist:
 
 ### Widgets are now visible by default
 
-The default value of [property@Gtk.Widget:visible] in GTK 4 is %TRUE, so you no
+The default value of [property@Gtk.Widget:visible] in GTK 4 is true, so you no
 longer need to explicitly show all your widgets. On the flip side, you
 need to hide widgets that are not meant to be visible from the start.
 The only widgets that still need to be explicitly shown are toplevel
@@ -1140,7 +1140,7 @@ The way search entries are connected to global events has changed;
 
 ### Adapt to GtkScale changes
 
-The default value of `GtkScale:draw-value` has been changed to %FALSE.
+The default value of `GtkScale:draw-value` has been changed to false.
 If you want your scales to draw values, you will have to set this
 property explicitly now.
 
@@ -1201,11 +1201,11 @@ instead, as appropriate.
 
 To allow signal handlers to access the deleted text before it
 has been deleted, the [signal@Gtk.EntryBuffer::deleted-text] signal
-has changed from %G_SIGNAL_RUN_FIRST to %G_SIGNAL_RUN_LAST. The default
+has changed from `G_SIGNAL_RUN_FIRST` to `G_SIGNAL_RUN_LAST`. The default
 handler removes the text from the [class@Gtk.EntryBuffer].
 
 To adapt existing code, use `g_signal_connect_after()` or
-%G_CONNECT_AFTER when using `g_signal_connect_data()` or
+`G_CONNECT_AFTER` when using `g_signal_connect_data()` or
 `g_signal_connect_object()`.
 
 ### GtkMenu, GtkMenuBar and GtkMenuItem are gone
@@ -1302,7 +1302,7 @@ has been removed; GFile can be used to access non-local as well as local
 resources.
 
 The `GTK_FILE_CHOOSER_ACTION_CREATE_FOLDER` action has been removed. Use
-%GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER, instead. If a new folder is needed,
+`GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER`, instead. If a new folder is needed,
 the user can create one.
 
 The "confirm-overwrite" signal, and the "do-overwrite-confirmation"
@@ -1327,7 +1327,7 @@ the event-driven programming model of GTK.
 
 You can replace calls to `gtk_dialog_run()` by specifying that the
 `GtkDialog` must be modal using [method@Gtk.Window.set_modal] or the
-%GTK_DIALOG_MODAL flag, and connecting to the [signal@Gtk.Dialog::response]
+`GTK_DIALOG_MODAL` flag, and connecting to the [signal@Gtk.Dialog::response]
 signal.
 
 ### Stop using GtkBuildable API
diff --git a/docs/reference/gtk/osx.md b/docs/reference/gtk/osx.md
index a3a385f409ac1417297509e7cc89e6669269930f..c5b3c5e83dc4ef99c583dd3ece41de23b2d542dc 100644
--- a/docs/reference/gtk/osx.md
+++ b/docs/reference/gtk/osx.md
@@ -10,6 +10,51 @@ or environment variables.
 For up-to-date information on building, installation, and bundling, see the
 [GTK website](https://www.gtk.org/docs/installations/macos).
 
+## Menus
+
+By default a GTK app shows an app menu and an edit menu.
+To make menu actions work well with native windows, such as a file dialog,
+the most common edit commands are treated special:
+
+* `text.undo`
+* `text.redo`
+* `clipboard.cut`
+* `clipboard.copy`
+* `clipboard.paste`
+* `selection.select-all`
+
+Those actions map to their respective macOS counterparts.
+The actions are enabled in GTK if the action is available on the focused widget
+and is enabled.
+
+To extend the macOS system menu, add application and window actions to the
+application with [`Application.set_accels_for_action()`](method.Application.set_accels_for_action.html).
+The menubar can be configured via [`Application.set_menubar()`](method.Application.set_menubar.html).
+Those actions can then be activated from the menu.
+
+## Native window controls
+
+By default, GTK applications use common window decorators (close/minimize/maximize) on all platforms.
+They show as grey rounded buttons on the top-right corner of the window.
+
+Since GTK 4.18, [`GtkHeaderBar`](class.HeaderBar.html) has the option to use native window controls.
+The controls are positioned in their normal place: the top-left corner.
+This feature can be enabled by setting the property [`use-native-controls`](property.HeaderBar.use-native-controls.html) to `TRUE` on a `GtkHeaderBar`.
+The property [`decoration-layout`](property.HeaderBar.decoration-layout.html) can be used to
+enable/disable buttons. 
+
+![The GTK demo application with macOS native window controls](macos-window-controls.png)
+
+Native window controls are an opt-in feature. If you want a more macOS native experience for your app,
+it's up to you to make sure all windows have native controls. You'll need to pay special attention in case of split header bars, since only the leftmost header bar should support the native window controls.
+
+Window decorators only work for normal, toplevel windows.
+
+::: important
+    Native window controls are drawn on top of the window, and are not controlled by GTK.
+    It's up to you, the application developer, to make sure the header bar that "contain" the
+    native window controls, and occupy the space below the window controls.
+
 ## Content types
 
 While GTK uses MIME types, macOS uses Unified Type descriptors.
diff --git a/docs/reference/gtk/question_index.md b/docs/reference/gtk/question_index.md
index 7ace7c8d0d9de4e17e933a946dc9e77cbea1f9e0..ba270155ebd7ed3a153d00857b8e533ce8abc4a2 100644
--- a/docs/reference/gtk/question_index.md
+++ b/docs/reference/gtk/question_index.md
@@ -257,7 +257,7 @@ the question you have, this list is a good place to start.
 
 *  How do I use GTK with other non-C languages?
 
-    See the list of [language bindings](https://www.gtk.org/language-bindings.php)
+    See the list of [language bindings](https://www.gtk.org/docs/language-bindings/)
     on the GTK [website](https://www.gtk.org).
 
 *  How do I load an image or animation from a file?
diff --git a/docs/reference/gtk/running.md b/docs/reference/gtk/running.md
index c358ca6ddbc4ca32531fe9255f4f6be986dd712c..075c7879adb243c16aa3401b7e03200fada76e46 100644
--- a/docs/reference/gtk/running.md
+++ b/docs/reference/gtk/running.md
@@ -229,9 +229,6 @@ A number of options affect behavior instead of logging:
 : Force graphics offload for all textures, even when slower. This allows
   to debug offloading in the absence of dmabufs.
 
-`gl-no-fractional`
-: Disable fractional scaling for OpenGL.
-
 `gl-debug`
 : Insert debugging information in OpenGL
 
@@ -504,13 +501,6 @@ The value can be -1 to disable GC entirely, 0 to force GC to happen
 before every frame, or a positive number to do GC in a timeout every
 n seconds. The default timeout is 15 seconds.
 
-### `GSK_MAX_TEXTURE_SIZE`
-
-Limit texture size to the minimum of this value and the OpenGL limit for
-texture sizes in the "gl" renderer. This can be used to debug issues with
-texture slicing on systems where the OpenGL texture size limit would
-otherwise make texture slicing difficult to test.
-
 ### `GTK_CSD`
 
 The default value of this environment variable is `1`. If changed
diff --git a/docs/reference/gtk/section-accessibility.md b/docs/reference/gtk/section-accessibility.md
index e15c3601f195a624d0781b0b323c1a2a4d325ccd..c4e61ed50d30a6f70d8a4739a21708c2d8e6f883 100644
--- a/docs/reference/gtk/section-accessibility.md
+++ b/docs/reference/gtk/section-accessibility.md
@@ -90,10 +90,8 @@ Attributes provide specific information about an accessible UI
 control, and describe it for the assistive technology applications. GTK
 divides the accessible attributes into three categories:
 
- - *properties*, described by the values of the `GtkAccessibleProperty`
-   enumeration
- - *relations*, described by the values of the `GtkAccessibleRelation`
-   enumeration
+ - *properties*, described by the values of the `GtkAccessibleProperty` enumeration
+ - *relations*, described by the values of the `GtkAccessibleRelation` enumeration
  - *states*, described by the values of the `GtkAccessibleState` enumeration
 
 Each attribute accepts a value of a specific type.
@@ -101,14 +99,14 @@ Each attribute accepts a value of a specific type.
 Unlike roles, attributes may change over time, or in response to user action;
 for instance:
 
- - a toggle button will change its %GTK_ACCESSIBLE_STATE_CHECKED state every
+ - a toggle button will change its `GTK_ACCESSIBLE_STATE_CHECKED` state every
    time it is toggled, either by the user or programmatically
  - setting the mnemonic widget on a `GtkLabel` will update the
-   %GTK_ACCESSIBLE_RELATION_LABELLED_BY relation on the widget with a
+   `GTK_ACCESSIBLE_RELATION_LABELLED_BY` relation on the widget with a
    reference to the label
  - changing the `GtkAdjustment` instance on a `GtkScrollbar` will change the
-   %GTK_ACCESSIBLE_PROPERTY_VALUE_MAX, %GTK_ACCESSIBLE_PROPERTY_VALUE_MIN,
-   and %GTK_ACCESSIBLE_PROPERTY_VALUE_NOW properties with the upper, lower,
+   `GTK_ACCESSIBLE_PROPERTY_VALUE_MAX`, `GTK_ACCESSIBLE_PROPERTY_VALUE_MIN`,
+   and `GTK_ACCESSIBLE_PROPERTY_VALUE_NOW` properties with the upper, lower,
    and value properties of the `GtkAdjustment`
 
 See the [WAI-ARIA](https://www.w3.org/WAI/PF/aria/appendices#quickref) list
@@ -120,15 +118,15 @@ Each state name is part of the `GtkAccessibleState` enumeration.
 
 | State name | ARIA attribute | Value type | Notes |
 |------------|----------------|------------|-------|
-| %GTK_ACCESSIBLE_STATE_BUSY | “aria-busy” | boolean |
-| %GTK_ACCESSIBLE_STATE_CHECKED | “aria-checked” | `GtkAccessibleTristate` | Indicates the current state of a [class@Gtk.CheckButton] |
-| %GTK_ACCESSIBLE_STATE_DISABLED | “aria-disabled” | boolean | Corresponds to the [property@Gtk.Widget:sensitive] property on [class@Gtk.Widget] |
-| %GTK_ACCESSIBLE_STATE_EXPANDED | “aria-expanded” | boolean or undefined | Corresponds to the  [property@Gtk.Expander:expanded] property on [class@Gtk.Expander] |
-| %GTK_ACCESSIBLE_STATE_HIDDEN | “aria-hidden” | boolean | Corresponds to the [property@Gtk.Widget:visible] property on [class@Gtk.Widget] |
-| %GTK_ACCESSIBLE_STATE_INVALID | “aria-invalid” | `GtkAccessibleInvalidState` | Set when a widget is showing an error |
-| %GTK_ACCESSIBLE_STATE_PRESSED | “aria-pressed” | `GtkAccessibleTristate` | Indicates the current state of a [class@Gtk.ToggleButton] |
-| %GTK_ACCESSIBLE_STATE_SELECTED | “aria-selected” | boolean or undefined | Set when a widget is selected |
-| %GTK_ACCESSIBLE_STATE_VISITED | N/A | boolean or undefined | Set when a link-like widget is visited |
+| `GTK_ACCESSIBLE_STATE_BUSY` | “aria-busy” | boolean |
+| `GTK_ACCESSIBLE_STATE_CHECKED` | “aria-checked” | `GtkAccessibleTristate` | Indicates the current state of a [class@Gtk.CheckButton] |
+| `GTK_ACCESSIBLE_STATE_DISABLED` | “aria-disabled” | boolean | Corresponds to the [property@Gtk.Widget:sensitive] property on [class@Gtk.Widget] |
+| `GTK_ACCESSIBLE_STATE_EXPANDED` | “aria-expanded” | boolean or undefined | Corresponds to the  [property@Gtk.Expander:expanded] property on [class@Gtk.Expander] |
+| `GTK_ACCESSIBLE_STATE_HIDDEN` | “aria-hidden” | boolean | Corresponds to the [property@Gtk.Widget:visible] property on [class@Gtk.Widget] |
+| `GTK_ACCESSIBLE_STATE_INVALID` | “aria-invalid” | `GtkAccessibleInvalidState` | Set when a widget is showing an error |
+| `GTK_ACCESSIBLE_STATE_PRESSED` | “aria-pressed” | `GtkAccessibleTristate` | Indicates the current state of a [class@Gtk.ToggleButton] |
+| `GTK_ACCESSIBLE_STATE_SELECTED` | “aria-selected” | boolean or undefined | Set when a widget is selected |
+| `GTK_ACCESSIBLE_STATE_VISITED` | N/A | boolean or undefined | Set when a link-like widget is visited |
 
 #### List of accessible properties
 
@@ -136,26 +134,26 @@ Each property name is part of the `GtkAccessibleProperty` enumeration.
 
 | State name | ARIA attribute | Value type |
 |------------|----------------|------------|
-| %GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE | “aria-autocomplete” | `GtkAccessibleAutocomplete` |
-| %GTK_ACCESSIBLE_PROPERTY_DESCRIPTION | “aria-description” | translatable string |
-| %GTK_ACCESSIBLE_PROPERTY_HAS_POPUP | “aria-haspopup” | boolean |
-| %GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS | “aria-keyshortcuts” | string |
-| %GTK_ACCESSIBLE_PROPERTY_LABEL | “aria-label” | translatable string |
-| %GTK_ACCESSIBLE_PROPERTY_LEVEL | “aria-level” | integer |
-| %GTK_ACCESSIBLE_PROPERTY_MODAL | “aria-modal” | boolean |
-| %GTK_ACCESSIBLE_PROPERTY_MULTI_LINE | “aria-multiline” | boolean |
-| %GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE | “aria-multiselectable” | boolean |
-| %GTK_ACCESSIBLE_PROPERTY_ORIENTATION | “aria-orientation” | `GtkOrientation` |
-| %GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER | “aria-placeholder” | translatable string |
-| %GTK_ACCESSIBLE_PROPERTY_READ_ONLY | “aria-readonly” | boolean |
-| %GTK_ACCESSIBLE_PROPERTY_REQUIRED | “aria-required” | boolean |
-| %GTK_ACCESSIBLE_PROPERTY_ROLE_DESCRIPTION | “aria-roledescription” | translatable string |
-| %GTK_ACCESSIBLE_PROPERTY_SORT | “aria-sort” | `GtkAccessibleSort` |
-| %GTK_ACCESSIBLE_PROPERTY_VALUE_MAX | “aria-valuemax” | double |
-| %GTK_ACCESSIBLE_PROPERTY_VALUE_MIN | “aria-valuemin” | double |
-| %GTK_ACCESSIBLE_PROPERTY_VALUE_NOW | “aria-valuenow” | double |
-| %GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT | “aria-valuetext” | translatable string |
-| %GTK_ACCESSIBLE_PROPERTY_HELP_TEXT | N/A | translatable string |
+| `GTK_ACCESSIBLE_PROPERTY_AUTOCOMPLETE` | “aria-autocomplete” | `GtkAccessibleAutocomplete` |
+| `GTK_ACCESSIBLE_PROPERTY_DESCRIPTION` | “aria-description” | translatable string |
+| `GTK_ACCESSIBLE_PROPERTY_HAS_POPUP` | “aria-haspopup” | boolean |
+| `GTK_ACCESSIBLE_PROPERTY_KEY_SHORTCUTS` | “aria-keyshortcuts” | string |
+| `GTK_ACCESSIBLE_PROPERTY_LABEL` | “aria-label” | translatable string |
+| `GTK_ACCESSIBLE_PROPERTY_LEVEL` | “aria-level” | integer |
+| `GTK_ACCESSIBLE_PROPERTY_MODAL` | “aria-modal” | boolean |
+| `GTK_ACCESSIBLE_PROPERTY_MULTI_LINE` | “aria-multiline” | boolean |
+| `GTK_ACCESSIBLE_PROPERTY_MULTI_SELECTABLE` | “aria-multiselectable” | boolean |
+| `GTK_ACCESSIBLE_PROPERTY_ORIENTATION` | “aria-orientation” | `GtkOrientation` |
+| `GTK_ACCESSIBLE_PROPERTY_PLACEHOLDER` | “aria-placeholder” | translatable string |
+| `GTK_ACCESSIBLE_PROPERTY_READ_ONLY` | “aria-readonly” | boolean |
+| `GTK_ACCESSIBLE_PROPERTY_REQUIRED` | “aria-required” | boolean |
+| `GTK_ACCESSIBLE_PROPERTY_ROLE_DESCRIPTION` | “aria-roledescription” | translatable string |
+| `GTK_ACCESSIBLE_PROPERTY_SORT` | “aria-sort” | `GtkAccessibleSort` |
+| `GTK_ACCESSIBLE_PROPERTY_VALUE_MAX` | “aria-valuemax” | double |
+| `GTK_ACCESSIBLE_PROPERTY_VALUE_MIN` | “aria-valuemin” | double |
+| `GTK_ACCESSIBLE_PROPERTY_VALUE_NOW` | “aria-valuenow” | double |
+| `GTK_ACCESSIBLE_PROPERTY_VALUE_TEXT` | “aria-valuetext” | translatable string |
+| `GTK_ACCESSIBLE_PROPERTY_HELP_TEXT` | N/A | translatable string |
 
 #### List of accessible relations
 
@@ -163,28 +161,28 @@ Each relation name is part of the `GtkAccessibleRelation` enumeration.
 
 | State name | ARIA attribute | Value type |
 |------------|----------------|------------|
-| %GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT | “aria-activedescendant” | `GtkAccessible` |
-| %GTK_ACCESSIBLE_RELATION_COL_COUNT | “aria-colcount” | integer |
-| %GTK_ACCESSIBLE_RELATION_COL_INDEX | “aria-colindex” | integer |
-| %GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT | “aria-colindextext” | translatable string |
-| %GTK_ACCESSIBLE_RELATION_COL_SPAN | “aria-colspan” | integer |
-| %GTK_ACCESSIBLE_RELATION_CONTROLS | “aria-controls” | a list of `GtkAccessible` |
-| %GTK_ACCESSIBLE_RELATION_DESCRIBED_BY | “aria-describedby” | a list of `GtkAccessible` |
-| %GTK_ACCESSIBLE_RELATION_DETAILS | “aria-details” | a list of `GtkAccessible` |
-| %GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE | “aria-errormessage” | a list of `GtkAccessible` |
-| %GTK_ACCESSIBLE_RELATION_FLOW_TO | “aria-flowto” | a list of `GtkAccessible` |
-| %GTK_ACCESSIBLE_RELATION_LABELLED_BY | “aria-labelledby” | a list of `GtkAccessible` |
-| %GTK_ACCESSIBLE_RELATION_OWNS | “aria-owns” | a list of `GtkAccessible` |
-| %GTK_ACCESSIBLE_RELATION_POS_IN_SET | “aria-posinset” | integer |
-| %GTK_ACCESSIBLE_RELATION_ROW_COUNT | “aria-rowcount” | integer |
-| %GTK_ACCESSIBLE_RELATION_ROW_INDEX | “aria-rowindex” | integer |
-| %GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT | “aria-rowindextext” | translatable string |
-| %GTK_ACCESSIBLE_RELATION_ROW_SPAN | “aria-rowspan” | integer |
-| %GTK_ACCESSIBLE_RELATION_SET_SIZE | “aria-setsize” | integer |
+| `GTK_ACCESSIBLE_RELATION_ACTIVE_DESCENDANT` | “aria-activedescendant” | `GtkAccessible` |
+| `GTK_ACCESSIBLE_RELATION_COL_COUNT` | “aria-colcount” | integer |
+| `GTK_ACCESSIBLE_RELATION_COL_INDEX` | “aria-colindex” | integer |
+| `GTK_ACCESSIBLE_RELATION_COL_INDEX_TEXT` | “aria-colindextext” | translatable string |
+| `GTK_ACCESSIBLE_RELATION_COL_SPAN` | “aria-colspan” | integer |
+| `GTK_ACCESSIBLE_RELATION_CONTROLS` | “aria-controls” | a list of `GtkAccessible` |
+| `GTK_ACCESSIBLE_RELATION_DESCRIBED_BY` | “aria-describedby” | a list of `GtkAccessible` |
+| `GTK_ACCESSIBLE_RELATION_DETAILS` | “aria-details” | a list of `GtkAccessible` |
+| `GTK_ACCESSIBLE_RELATION_ERROR_MESSAGE` | “aria-errormessage” | a list of `GtkAccessible` |
+| `GTK_ACCESSIBLE_RELATION_FLOW_TO` | “aria-flowto” | a list of `GtkAccessible` |
+| `GTK_ACCESSIBLE_RELATION_LABELLED_BY` | “aria-labelledby” | a list of `GtkAccessible` |
+| `GTK_ACCESSIBLE_RELATION_OWNS` | “aria-owns” | a list of `GtkAccessible` |
+| `GTK_ACCESSIBLE_RELATION_POS_IN_SET` | “aria-posinset” | integer |
+| `GTK_ACCESSIBLE_RELATION_ROW_COUNT` | “aria-rowcount” | integer |
+| `GTK_ACCESSIBLE_RELATION_ROW_INDEX` | “aria-rowindex” | integer |
+| `GTK_ACCESSIBLE_RELATION_ROW_INDEX_TEXT` | “aria-rowindextext” | translatable string |
+| `GTK_ACCESSIBLE_RELATION_ROW_SPAN` | “aria-rowspan” | integer |
+| `GTK_ACCESSIBLE_RELATION_SET_SIZE` | “aria-setsize” | integer |
 
 *Note*: When using gtk_accessible_update_relation() with a relation that
 requires a list of `GtkAccessible` instances, you should pass every
-accessible object separately, followed by %NULL. 
+accessible object separately, followed by `NULL`. 
 
 ## Application development rules
 
@@ -269,15 +267,15 @@ gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_BUTTON);
 is a promise that the widget being created will provide the same keyboard
 interactions expected for a button. An accessible role of a button will not
 turn automatically any widget into a `GtkButton`; but if your widget behaves
-like a button, using the %GTK_ACCESSIBLE_ROLE_BUTTON will allow any
+like a button, using the `GTK_ACCESSIBLE_ROLE_BUTTON` will allow any
 assistive technology to handle it like they would a `GtkButton`.
 
 For widgets that act as containers of other widgets, you should use
-%GTK_ACCESSIBLE_ROLE_GROUP if the grouping of the children is semantic
+`GTK_ACCESSIBLE_ROLE_GROUP` if the grouping of the children is semantic
 in nature; for instance, the children of a [class@Gtk.HeaderBar] are
 grouped together on the header of a window. For generic containers that
 only impose a layout on their children, you should use
-%GTK_ACCESSIBLE_ROLE_GENERIC instead.
+`GTK_ACCESSIBLE_ROLE_GENERIC` instead.
 
 ### Attributes can both hide and enhance
 
@@ -322,13 +320,13 @@ widgets.
 
 The accessibility API is mainly used to express semantics useful for
 assistive technologies, but it can also be used to hide elements. The
-canonical way to do so is to use the %GTK_ACCESSIBLE_ROLE_PRESENTATION,
+canonical way to do so is to use the `GTK_ACCESSIBLE_ROLE_PRESENTATION`,
 which declares that a UI element is purely meant for presentation purposes,
 and as such it has no meaningful impact on the accessibility of the
 interface.
 
 A "presentation" role should not be confused with the
-%GTK_ACCESSIBLE_STATE_HIDDEN state; the "hidden" state is transient, and is
+`GTK_ACCESSIBLE_STATE_HIDDEN` state; the "hidden" state is transient, and is
 typically controlled by showing and hiding a widget using the `GtkWidget`
 API.
 
@@ -345,7 +343,7 @@ recommended you use `GtkButton` for anything that looks and behaves like a
 button, it is possible to apply a button behavior to UI elements like images
 by using a `GtkGestureClick` gesture. When doing so, you should:
 
-  - Give your widget the role %GTK_ACCESSIBLE_ROLE_BUTTON
+  - Give your widget the role `GTK_ACCESSIBLE_ROLE_BUTTON`
   - Install an action with no parameters, which will activate the widget
 
 ### Custom entries
@@ -362,12 +360,12 @@ as the core, and just make a custom tab widget to control the active
 stack page. When doing so, the following extra steps will ensure that
 your tabs are accessible in the same way as `GtkStackSwitcher` or `GtkNotebook`:
 
-- Give your tab container the role %GTK_ACCESSIBLE_ROLE_TAB_LIST
-- Give your tab widgets the role %GTK_ACCESSIBLE_ROLE_TAB
-- Set up the %GTK_ACCESSIBLE_RELATION_CONTROLS relation between each
+- Give your tab container the role `GTK_ACCESSIBLE_ROLE_TAB_LIST`
+- Give your tab widgets the role `GTK_ACCESSIBLE_ROLE_TAB`
+- Set up the `GTK_ACCESSIBLE_RELATION_CONTROLS` relation between each
   tab and the `GtkStackPage` object for its page
-- Set the %GTK_ACCESSIBLE_PROPERTY_SELECTED property on each tab, with
-  the active tab getting the value %TRUE, all others %FALSE
+- Set the `GTK_ACCESSIBLE_PROPERTY_SELECTED` property on each tab, with
+  the active tab getting the value true, all others false
 
 To allow changing the active tab via accessible technologies, you can
 export actions. Since the accessibility interfaces only support actions
@@ -379,8 +377,8 @@ or add a `activate-tab` action on each tab.
 
 A value control (ie a widget that controls a one-dimensional quantity
 that can be represented by a `GtkAdjustment`) can be represented to
-accessible technologies by setting the %GTK_ACCESSIBLE_PROPERTY_VALUE_MIN,
-%GTK_ACCESSIBLE_PROPERTY_VALUE_MAX, and %GTK_ACCESSIBLE_PROPERTY_VALUE_NOW
+accessible technologies by setting the `GTK_ACCESSIBLE_PROPERTY_VALUE_MIN`,
+`GTK_ACCESSIBLE_PROPERTY_VALUE_MAX` and `GTK_ACCESSIBLE_PROPERTY_VALUE_NOW`
 properties.
 
 To allow changing the value via accessible technologies, you can export
diff --git a/docs/reference/gtk/section-text-widget.md b/docs/reference/gtk/section-text-widget.md
index a3c8e2a3ecc770abaa0d2e2b38109c5fbea0840f..49b6eb8e310b2742293d6396369b3d7f9875207f 100644
--- a/docs/reference/gtk/section-text-widget.md
+++ b/docs/reference/gtk/section-text-widget.md
@@ -74,7 +74,7 @@ multiple bytes in UTF-8, and the two-character sequence "\r\n" is also
 considered a line separator.
 
 Text buffers support undo and redo if gtk_text_buffer_set_enable_undo()
-has been set to %TRUE. Use gtk_text_buffer_undo() or gtk_text_buffer_redo()
+has been set to true. Use gtk_text_buffer_undo() or gtk_text_buffer_redo()
 to perform the necessary action. Note that these operations are ignored if
 the buffer is not editable. Developers may want some operations to not be
 undoable. To do this, wrap your changes in
diff --git a/docs/reference/gtk/visual_index.md b/docs/reference/gtk/visual_index.md
index d117e97c4706246092d980f601f755244369222b..6adb78c988ccaf6bc55c5bcae9d77f9849026410 100644
--- a/docs/reference/gtk/visual_index.md
+++ b/docs/reference/gtk/visual_index.md
@@ -4,88 +4,88 @@ Title: Widget Gallery
 
 ## Display widgets
 
-[![label](label.png)](class.Label.html)
-[![spinner](spinner.png)](class.Spinner.html)
-[![statusbar](statusbar.png)](class.Statusbar.html)
-[![levelbar](levelbar.png)](class.LevelBar.html)
-[![progressbar](progressbar.png)](class.ProgressBar.html)
-[![infobar](info-bar.png)](class.InfoBar.html)
-[![scrollbar](scrollbar.png)](class.Scrollbar.html)
-[![image](image.png)](class.Image.html)
-[![picture](picture.png)](class.Picture.html)
-[![separator](separator.png)](class.Separator.html)
-[![textview](multiline-text.png)](class.TextView.html)
-[![scale](scales.png)](class.Scale.html)
-[![glarea](glarea.png)](class.GLArea.html)
-[![drawingarea](drawingarea.png)](class.DrawingArea.html)
-[![video](video.png)](class.Video.html)
-[![mediacontrols](media-controls.png)](class.MediaControls.html)
-[![windowcontrols](windowcontrols.png)](class.WindowControls.html)
-[![menubar](menubar.png)](class.PopoverMenuBar.html)
-[![calendar](calendar.png)](class.Calendar.html)
-[![emojichooser](emojichooser.png)](class.EmojiChooser.html)
-[![menu](menu.png)](class.PopoverMenu.html)
+<a href="class.Label.html"><picture><source srcset="label-dark.png" media="(prefers-color-scheme: dark)"><img src="label.png"></picture></a>
+<a href="class.Spinner.html"><picture><source srcset="spinner-dark.png" media="(prefers-color-scheme: dark)"><img src="spinner.png"></picture></a>
+<a href="class.Statusbar.html"><picture><source srcset="statusbar-dark.png" media="(prefers-color-scheme: dark)"><img src="statusbar.png"></picture></a>
+<a href="class.LevelBar.html"><picture><source srcset="levelbar-dark.png" media="(prefers-color-scheme: dark)"><img src="levelbar.png"></picture></a>
+<a href="class.ProgressBar.html"><picture><source srcset="progressbar-dark.png" media="(prefers-color-scheme: dark)"><img src="progressbar.png"></picture></a>
+<a href="class.InfoBar.html"><picture><source srcset="info-bar-dark.png" media="(prefers-color-scheme: dark)"><img src="info-bar.png"></picture></a>
+<a href="class.Scrollbar.html"><picture><source srcset="scrollbar-dark.png" media="(prefers-color-scheme: dark)"><img src="scrollbar.png"></picture></a>
+<a href="class.Image.html"><picture><source srcset="image-dark.png" media="(prefers-color-scheme: dark)"><img src="image.png"></picture></a>
+<a href="class.Picture.html"><picture><source srcset="picture-dark.png" media="(prefers-color-scheme: dark)"><img src="picture.png"></picture></a>
+<a href="class.Separator.html"><picture><source srcset="separator-dark.png" media="(prefers-color-scheme: dark)"><img src="separator.png"></picture></a>
+<a href="class.TextView.html"><picture><source srcset="multiline-text-dark.png" media="(prefers-color-scheme: dark)"><img src="multiline-text.png"></picture></a>
+<a href="class.Scale.html"><picture><source srcset="scales-dark.png" media="(prefers-color-scheme: dark)"><img src="scales.png"></picture></a>
+<a href="class.GLArea.html"><picture><source srcset="glarea-dark.png" media="(prefers-color-scheme: dark)"><img src="glarea.png"></picture></a>
+<a href="class.DrawingArea.html"><picture><source srcset="drawingarea-dark.png" media="(prefers-color-scheme: dark)"><img src="drawingarea.png"></picture></a>
+<a href="class.Video.html"><picture><source srcset="video-dark.png" media="(prefers-color-scheme: dark)"><img src="video.png"></picture></a>
+<a href="class.MediaControls.html"><picture><source srcset="media-controls-dark.png" media="(prefers-color-scheme: dark)"><img src="media-controls.png"></picture></a>
+<a href="class.WindowControls.html"><picture><source srcset="windowcontrols-dark.png" media="(prefers-color-scheme: dark)"><img src="windowcontrols.png"></picture></a>
+<a href="class.PopoverMenuBar.html"><picture><source srcset="menubar-dark.png" media="(prefers-color-scheme: dark)"><img src="menubar.png"></picture></a>
+<a href="class.Calendar.html"><picture><source srcset="calendar-dark.png" media="(prefers-color-scheme: dark)"><img src="calendar.png"></picture></a>
+<a href="class.EmojiChooser.html"><picture><source srcset="emojichooser-dark.png" media="(prefers-color-scheme: dark)"><img src="emojichooser.png"></picture></a>
+<a href="class.PopoverMenu.html"><picture><source srcset="menu-dark.png" media="(prefers-color-scheme: dark)"><img src="menu.png"></picture></a>
 
 ## Buttons
 
-[![button](button.png)](class.Button.html)
-[![togglebutton](toggle-button.png)](class.ToggleButton.html)
-[![linkbutton](link-button.png)](class.LinkButton.html)
-[![checkbutton](check-button.png)](class.CheckButton.html)
-[![checkbutton](radio-button.png)](class.CheckButton.html)
-[![menubutton](menu-button.png)](class.MenuButton.html)
-[![lockbutton](lockbutton.png)](class.LockButton.html)
-[![volumebutton](volumebutton.png)](class.VolumeButton.html)
-[![switch](switch.png)](class.Switch.html)
-[![combobox](combo-box.png)](class.ComboBox.html)
-[![comboboxtext](combo-box-text.png)](class.ComboBoxText.html)
-[![dropdown](drop-down.png)](class.DropDown.html)
-[![colorbutton](color-button.png)](class.ColorButton.html)
-[![fontbutton](font-button.png)](class.FontButton.html)
-[![appchooserbutton](appchooserbutton.png)](class.AppChooserButton.html)
+<a href="class.Button.html"><picture><source srcset="button-dark.png" media="(prefers-color-scheme: dark)"><img src="button.png"></picture></a>
+<a href="class.ToggleButton.html"><picture><source srcset="toggle-button-dark.png" media="(prefers-color-scheme: dark)"><img src="toggle-button.png"></picture></a>
+<a href="class.LinkButton.html"><picture><source srcset="link-button-dark.png" media="(prefers-color-scheme: dark)"><img src="link-button.png"></picture></a>
+<a href="class.CheckButton.html"><picture><source srcset="check-button-dark.png" media="(prefers-color-scheme: dark)"><img src="check-button.png"></picture></a>
+<a href="class.CheckButton.html"><picture><source srcset="radio-button-dark.png" media="(prefers-color-scheme: dark)"><img src="radio-button.png"></picture></a>
+<a href="class.MenuButton.html"><picture><source srcset="menu-button-dark.png" media="(prefers-color-scheme: dark)"><img src="menu-button.png"></picture></a>
+<a href="class.LockButton.html"><picture><source srcset="lockbutton-dark.png" media="(prefers-color-scheme: dark)"><img src="lockbutton.png"></picture></a>
+<a href="class.VolumeButton.html"><picture><source srcset="volumebutton-dark.png" media="(prefers-color-scheme: dark)"><img src="volumebutton.png"></picture></a>
+<a href="class.Switch.html"><picture><source srcset="switch-dark.png" media="(prefers-color-scheme: dark)"><img src="switch.png"></picture></a>
+<a href="class.ComboBox.html"><picture><source srcset="combo-box-dark.png" media="(prefers-color-scheme: dark)"><img src="combo-box.png"></picture></a>
+<a href="class.ComboBoxText.html"><picture><source srcset="combo-box-text-dark.png" media="(prefers-color-scheme: dark)"><img src="combo-box-text.png"></picture></a>
+<a href="class.DropDown.html"><picture><source srcset="drop-down-dark.png" media="(prefers-color-scheme: dark)"><img src="drop-down.png"></picture></a>
+<a href="class.ColorDialogButton.html"><picture><source srcset="color-button-dark.png" media="(prefers-color-scheme: dark)"><img src="color-button.png"></picture></a>
+<a href="class.FontDialogButton.html"><picture><source srcset="font-button-dark.png" media="(prefers-color-scheme: dark)"><img src="font-button.png"></picture></a>
+<a href="class.AppChooserButton.html"><picture><source srcset="appchooserbutton-dark.png" media="(prefers-color-scheme: dark)"><img src="appchooserbutton.png"></picture></a>
 
 ## Entries
 
-[![entry](entry.png)](class.Entry.html)
-[![searchentry](search-entry.png)](class.SearchEntry.html)
-[![passwordentry](password-entry.png)](class.PasswordEntry.html)
-[![spinbutton](spinbutton.png)](class.SpinButton.html)
-[![editablelabel](editable-label.png)](class.EditableLabel.html)
+<a href="class.Entry.html"><picture><source srcset="entry-dark.png" media="(prefers-color-scheme: dark)"><img src="entry.png"></picture></a>
+<a href="class.SearchEntry.html"><picture><source srcset="search-entry-dark.png" media="(prefers-color-scheme: dark)"><img src="search-entry.png"></picture></a>
+<a href="class.PasswordEntry.html"><picture><source srcset="password-entry-dark.png" media="(prefers-color-scheme: dark)"><img src="password-entry.png"></picture></a>
+<a href="class.SpinButton.html"><picture><source srcset="spinbutton-dark.png" media="(prefers-color-scheme: dark)"><img src="spinbutton.png"></picture></a>
+<a href="class.EditableLabel.html"><picture><source srcset="editable-label-dark.png" media="(prefers-color-scheme: dark)"><img src="editable-label.png"></picture></a>
 
 ## Containers
 
-[![box](box.png)](class.Box.html)
-[![grid](grid.png)](class.Grid.html)
-[![centerbox](centerbox.png)](class.CenterBox.html)
-[![scrolledwindow](scrolledwindow.png)](class.ScrolledWindow.html)
-[![panes](panes.png)](class.Paned.html)
-[![frame](frame.png)](class.Frame.html)
-[![expander](expander.png)](class.Expander.html)
-[![searchbar](search-bar.png)](class.SearchBar.html)
-[![actionbar](action-bar.png)](class.ActionBar.html)
-[![headerbar](headerbar.png)](class.HeaderBar.html)
-[![notebook](notebook.png)](class.Notebook.html)
-[![listbox](list-box.png)](class.ListBox.html)
-[![flowbox](flow-box.png)](class.FlowBox.html)
-[![treeview](list-and-tree.png)](class.TreeView.html)
-[![iconview](icon-view.png)](class.IconView.html)
-[![overlay](overlay.png)](class.Overlay.html)
-[![stack](stack.png)](class.Stack.html)
-[![stackswitcher](stackswitcher.png)](class.StackSwitcher.html)
-[![stacksidebar](sidebar.png)](class.StackSidebar.html)
-[![popover](popover.png)](class.Popover.html)
+<a href="class.Box.html"><picture><source srcset="box-dark.png" media="(prefers-color-scheme: dark)"><img src="box.png"></picture></a>
+<a href="class.Grid.html"><picture><source srcset="grid-dark.png" media="(prefers-color-scheme: dark)"><img src="grid.png"></picture></a>
+<a href="class.CenterBox.html"><picture><source srcset="centerbox-dark.png" media="(prefers-color-scheme: dark)"><img src="centerbox.png"></picture></a>
+<a href="class.ScrolledWindow.html"><picture><source srcset="scrolledwindow-dark.png" media="(prefers-color-scheme: dark)"><img src="scrolledwindow.png"></picture></a>
+<a href="class.Paned.html"><picture><source srcset="panes-dark.png" media="(prefers-color-scheme: dark)"><img src="panes.png"></picture></a>
+<a href="class.Frame.html"><picture><source srcset="frame-dark.png" media="(prefers-color-scheme: dark)"><img src="frame.png"></picture></a>
+<a href="class.Expander.html"><picture><source srcset="expander-dark.png" media="(prefers-color-scheme: dark)"><img src="expander.png"></picture></a>
+<a href="class.SearchBar.html"><picture><source srcset="search-bar-dark.png" media="(prefers-color-scheme: dark)"><img src="search-bar.png"></picture></a>
+<a href="class.ActionBar.html"><picture><source srcset="action-bar-dark.png" media="(prefers-color-scheme: dark)"><img src="action-bar.png"></picture></a>
+<a href="class.HeaderBar.html"><picture><source srcset="headerbar-dark.png" media="(prefers-color-scheme: dark)"><img src="headerbar.png"></picture></a>
+<a href="class.Notebook.html"><picture><source srcset="notebook-dark.png" media="(prefers-color-scheme: dark)"><img src="notebook.png"></picture></a>
+<a href="class.ListBox.html"><picture><source srcset="list-box-dark.png" media="(prefers-color-scheme: dark)"><img src="list-box.png"></picture></a>
+<a href="class.FlowBox.html"><picture><source srcset="flow-box-dark.png" media="(prefers-color-scheme: dark)"><img src="flow-box.png"></picture></a>
+<a href="class.TreeView.html"><picture><source srcset="list-and-tree-dark.png" media="(prefers-color-scheme: dark)"><img src="list-and-tree.png"></picture></a>
+<a href="class.IconView.html"><picture><source srcset="icon-view-dark.png" media="(prefers-color-scheme: dark)"><img src="icon-view.png"></picture></a>
+<a href="class.Overlay.html"><picture><source srcset="overlay-dark.png" media="(prefers-color-scheme: dark)"><img src="overlay.png"></picture></a>
+<a href="class.Stack.html"><picture><source srcset="stack-dark.png" media="(prefers-color-scheme: dark)"><img src="stack.png"></picture></a>
+<a href="class.StackSwitcher.html"><picture><source srcset="stackswitcher-dark.png" media="(prefers-color-scheme: dark)"><img src="stackswitcher.png"></picture></a>
+<a href="class.StackSidebar.html"><picture><source srcset="sidebar-dark.png" media="(prefers-color-scheme: dark)"><img src="sidebar.png"></picture></a>
+<a href="class.Popover.html"><picture><source srcset="popover-dark.png" media="(prefers-color-scheme: dark)"><img src="popover.png"></picture></a>
 
 ## Windows
 
-[![window](window.png)](class.Window.html)
-[![dialog](dialog.png)](class.Dialog.html)
-[![messagedialog](messagedialog.png)](class.MessageDialog.html)
-[![aboutdialog](aboutdialog.png)](class.AboutDialog.html)
-[![assistant](assistant.png)](class.Assistant.html)
-[![colorchooser](colorchooser.png)](class.ColorChooserDialog.html)
-[![filechooser](filechooser.png)](class.FileChooserDialog.html)
-[![fontchooser](fontchooser.png)](class.FontChooserDialog.html)
-[![appchooserdialog](appchooserdialog.png)](class.AppChooserDialog.html)
-[![pagesetupdialog](pagesetupdialog.png)](class.PageSetupUnixDialog.html)
-[![printdialog](printdialog.png)](class.PrintUnixDialog.html)
-[![shortcutswindow](shortcuts-window.png)](class.ShortcutsWindow.html)
+<a href="class.Window.html"><picture><source srcset="window-dark.png" media="(prefers-color-scheme: dark)"><img src="window.png"></picture></a>
+<a href="class.Dialog.html"><picture><source srcset="dialog-dark.png" media="(prefers-color-scheme: dark)"><img src="dialog.png"></picture></a>
+<a href="class.MessageDialog.html"><picture><source srcset="messagedialog-dark.png" media="(prefers-color-scheme: dark)"><img src="messagedialog.png"></picture></a>
+<a href="class.AboutDialog.html"><picture><source srcset="aboutdialog-dark.png" media="(prefers-color-scheme: dark)"><img src="aboutdialog.png"></picture></a>
+<a href="class.Assistant.html"><picture><source srcset="assistant-dark.png" media="(prefers-color-scheme: dark)"><img src="assistant.png"></picture></a>
+<a href="class.ColorChooserDialog.html"><picture><source srcset="colorchooser-dark.png" media="(prefers-color-scheme: dark)"><img src="colorchooser.png"></picture></a>
+<a href="class.FileChooserDialog.html"><picture><source srcset="filechooser-dark.png" media="(prefers-color-scheme: dark)"><img src="filechooser.png"></picture></a>
+<a href="class.FontChooserDialog.html"><picture><source srcset="fontchooser-dark.png" media="(prefers-color-scheme: dark)"><img src="fontchooser.png"></picture></a>
+<a href="class.AppChooserDialog.html"><picture><source srcset="appchooserdialog-dark.png" media="(prefers-color-scheme: dark)"><img src="appchooserdialog.png"></picture></a>
+<a href="class.PageSetupUnixDialog.html"><picture><source srcset="pagesetupdialog-dark.png" media="(prefers-color-scheme: dark)"><img src="pagesetupdialog.png"></picture></a>
+<a href="class.PrintUnixDialog.html"><picture><source srcset="printdialog-dark.png" media="(prefers-color-scheme: dark)"><img src="printdialog.png"></picture></a>
+<a href="class.ShortcutsWindow.html"><picture><source srcset="shortcuts-window-dark.png" media="(prefers-color-scheme: dark)"><img src="shortcuts-window.png"></picture></a>
diff --git a/gdk/android/gdkandroiddevice-private.h b/gdk/android/gdkandroiddevice-private.h
index efb8187a95de243d842eebc5b2ac7db500e72f54..035b5552dbfa54e070cd04ee50394539559706c5 100644
--- a/gdk/android/gdkandroiddevice-private.h
+++ b/gdk/android/gdkandroiddevice-private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -41,5 +41,6 @@ struct _GdkAndroidDevice
 };
 
 void gdk_android_device_maybe_update_surface (GdkAndroidDevice *self, GdkAndroidSurface *new_surface, GdkModifierType new_mods, guint32 timestamp, gfloat x, gfloat y);
+void gdk_android_device_keyboard_maybe_update_surface_focus (GdkAndroidDevice *self, GdkAndroidSurface *new_surface);
 
 G_END_DECLS
diff --git a/gdk/android/gdkandroiddevice.c b/gdk/android/gdkandroiddevice.c
index 63e21caf46e711b1d6cfa6a1868e49d6bb58f8ee..cd9623aab6f1a36479db050d1d4d35abaab6a2cd 100644
--- a/gdk/android/gdkandroiddevice.c
+++ b/gdk/android/gdkandroiddevice.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -208,3 +208,23 @@ gdk_android_device_maybe_update_surface (GdkAndroidDevice  *self,
                                          GDK_CROSSING_NORMAL, GDK_NOTIFY_UNKNOWN);
   gdk_android_seat_consume_event (display, ev);
 }
+
+void
+gdk_android_device_keyboard_maybe_update_surface_focus (GdkAndroidDevice  *self,
+                                                        GdkAndroidSurface *new_surface)
+{
+  g_return_if_fail (((GdkDevice *)self)->source == GDK_SOURCE_KEYBOARD);
+  if (self->last == new_surface)
+    return;
+  GdkDisplay *display = gdk_device_get_display ((GdkDevice *) self);
+  if (self->last)
+    {
+      GdkEvent *ev = gdk_focus_event_new ((GdkSurface *)self->last, (GdkDevice *)self, FALSE);
+      gdk_android_seat_consume_event (display, ev);
+      g_object_remove_weak_pointer ((GObject *) self->last, (gpointer *) &self->last);
+    }
+  self->last = new_surface;
+  g_object_add_weak_pointer ((GObject *) self->last, (gpointer *) &self->last);
+  GdkEvent *ev = gdk_focus_event_new ((GdkSurface *)self->last, (GdkDevice *)self, TRUE);
+  gdk_android_seat_consume_event (display, ev);
+}
diff --git a/gdk/android/gdkandroiddisplay.c b/gdk/android/gdkandroiddisplay.c
index 984eda4330337c36baa00da058963aaf069d2377..6bf55b8d056c540c9c50b004abd1203ad48d8b8d 100644
--- a/gdk/android/gdkandroiddisplay.c
+++ b/gdk/android/gdkandroiddisplay.c
@@ -173,6 +173,11 @@ gdk_android_display_get_setting (GdkDisplay *display,
       g_value_set_boolean (value, self->night_mode == GDK_ANDROID_DISPLAY_NIGHT_YES);
       return TRUE;
     }
+  else if (g_strcmp0 (name, "gtk-decoration-layout") == 0)
+    {
+      g_value_set_string (value, ":");
+      return TRUE;
+    }
   else
     {
       return FALSE;
diff --git a/gdk/android/gdkandroidevents.c b/gdk/android/gdkandroidevents.c
index 38f21e7ff1890261a7ff29fdcfb5cd19fffba921..dfdd96fbdecb7e778c641b1ef5e23651ade90510 100644
--- a/gdk/android/gdkandroidevents.c
+++ b/gdk/android/gdkandroidevents.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -141,6 +141,10 @@ gdk_android_events_handle_motion_event (GdkAndroidSurface *surface,
   gfloat x = AMotionEvent_getX (event, 0) / surface->cfg.scale;
   gfloat y = AMotionEvent_getY (event, 0) / surface->cfg.scale;
 
+  // Update keyboard focus
+  GdkDevice *keyboard = gdk_seat_get_keyboard ((GdkSeat *) display->seat);
+  gdk_android_device_keyboard_maybe_update_surface_focus ((GdkAndroidDevice *) keyboard, surface);
+
   if (GDK_ANDROID_EVENTS_COMPARE_MASK (src, AINPUT_SOURCE_TOUCHSCREEN))
     {
       if (masked_action == AMOTION_EVENT_ACTION_POINTER_DOWN ||
@@ -340,6 +344,7 @@ gdk_android_events_handle_key_event (GdkAndroidSurface *surface,
   GdkEventType event_type = (action == AKEY_STATE_UP || action == AKEY_STATE_VIRTUAL) ? GDK_KEY_PRESS : GDK_KEY_RELEASE;
 
   GdkDevice *dev = gdk_seat_get_keyboard ((GdkSeat *) display->seat);
+  gdk_android_device_keyboard_maybe_update_surface_focus ((GdkAndroidDevice *) dev, surface);
 
   GdkModifierType mods = gdk_android_events_meta_to_gdk (AKeyEvent_getMetaState (event));
   mods |= gdk_android_events_buttons_to_gdkmods (((GdkAndroidDevice *) display->seat->logical_pointer)->button_state);
diff --git a/gdk/android/gdkandroidinit-private.h b/gdk/android/gdkandroidinit-private.h
index e61f9f973e8d5f5b4c277e53275182053661b3f9..a7781798636ee88b9c7eb87ac972cefc110f6c6b 100644
--- a/gdk/android/gdkandroidinit-private.h
+++ b/gdk/android/gdkandroidinit-private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024/25 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/gdk/android/gdkandroidinit.c b/gdk/android/gdkandroidinit.c
index 0a1ace5fe8fd6c8ec560dd42a982617dcb864b19..87ea9fbb92fa4be050a74749a75ed14d19918d1b 100644
--- a/gdk/android/gdkandroidinit.c
+++ b/gdk/android/gdkandroidinit.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024/25 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/gdk/android/gdkandroidtoplevel-private.h b/gdk/android/gdkandroidtoplevel-private.h
index a03917df489a296afb981d04a9d42e9ae2f9988d..ef5c33186f412eb4eb08682f6cef4dd91129352a 100644
--- a/gdk/android/gdkandroidtoplevel-private.h
+++ b/gdk/android/gdkandroidtoplevel-private.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024/25 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/gdk/android/gdkandroidtoplevel.c b/gdk/android/gdkandroidtoplevel.c
index 6096f9a9689dffa51aba29903ec1acd74eede824..60bcbd3f4c54f0a56b66098c21844e85e8c6d382 100644
--- a/gdk/android/gdkandroidtoplevel.c
+++ b/gdk/android/gdkandroidtoplevel.c
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024/25 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -677,11 +677,11 @@ gdk_android_toplevel_get_activity (GdkAndroidToplevel *self)
  * gdk_android_toplevel_launch_activity: (skip)
  * @self: (transfer none): the toplevel
  * @intent: [Intent](https://developer.android.com/reference/android/content/Intent) to launch
- * @error: return location for a [struct@GLib.Error] or %NULL
+ * @error: return location for a [struct@GLib.Error]
  *
  * Launch a new activity defined by @intent with @self as parent.
  *
- * Returns: %TRUE if successful, %FALSE otherwise
+ * Returns: true if successful, false otherwise
  *
  * Since: 4.18
  */
@@ -777,7 +777,7 @@ gdk_android_toplevel_launch_activity_for_result_async (GdkAndroidToplevel *self,
  * Get the result code (and data) returned from an activity launched via
  * [method@Gdk.AndroidToplevel.launch_activity_for_result_async].
  *
- * Returns: %TRUE if successful, %FALSE otherwise
+ * Returns: true if successful, false otherwise
  */
 gboolean
 gdk_android_toplevel_launch_activity_for_result_finish (GdkAndroidToplevel *self,
diff --git a/gdk/android/gdkandroidtoplevel.h b/gdk/android/gdkandroidtoplevel.h
index 262e63a0810b5ddd1cb988ab8af04f35621495c2..776288fde1bc8d78d789781942edcbed2ad092dc 100644
--- a/gdk/android/gdkandroidtoplevel.h
+++ b/gdk/android/gdkandroidtoplevel.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024/25 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/gdk/android/glue/glue.c b/gdk/android/glue/glue.c
index f723f84079218e9963cdd653d85ce412d883c9e8..449d4465ca40b207d21b4614fb57cac0ff735673 100644
--- a/gdk/android/glue/glue.c
+++ b/gdk/android/glue/glue.c
@@ -188,9 +188,7 @@ JNIEXPORT void JNICALL Java_org_gtk_android_GlueLibraryContext_runApplication(JN
   if (gtk_thread_s)
     return;
 
-  LOGD("Entered OnLoad");
-
-  g_log_set_always_fatal(G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_ERROR);
+  LOGD("Reached GTK Android entrypoint");
 
   g_set_print_handler(android_print_handler);
   g_set_printerr_handler(android_printerr_handler);
diff --git a/gdk/android/glue/java/org/gtk/android/ToplevelActivity.java b/gdk/android/glue/java/org/gtk/android/ToplevelActivity.java
index fbf62070250b64ba3736146a8ed543280502cac0..28161831ab46de747599e715d7a56ee2f4deb896 100644
--- a/gdk/android/glue/java/org/gtk/android/ToplevelActivity.java
+++ b/gdk/android/glue/java/org/gtk/android/ToplevelActivity.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2024/25 Florian "sp1rit" <sp1rit@disroot.org>
+ * Copyright (c) 2024-2025 Florian "sp1rit" <sp1rit@disroot.org>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
diff --git a/gdk/gdk-keysyms-update.py b/gdk/gdk-keysyms-update.py
new file mode 100755
index 0000000000000000000000000000000000000000..9f096218721f9a24005e52d02add87a081f5f526
--- /dev/null
+++ b/gdk/gdk-keysyms-update.py
@@ -0,0 +1,136 @@
+#!/usr/bin/env python3
+
+# Author  : Simos Xenitellis <simos at gnome dot org>.
+# Author  : Bastien Nocera <hadess@hadess.net>
+# Author  : Alberto Ruiz <aruiz@gnome.org>
+# Version : 1.2
+#
+# Notes   : It downloads keysymdef.h from the Internet,
+# Notes   : and creates an updated clutter-keysyms.h
+
+import os
+import sys
+import re
+from typing import TextIO, Iterable
+
+import requests  # type: ignore[import-untyped]
+
+KEYSYMDEF_URL = "https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/raw/master/include/X11/keysymdef.h"
+XF86KEYSYM_URL = "https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/raw/master/include/X11/XF86keysym.h"
+
+LICENSE_HEADER = f"""/* GDK - The GIMP Drawing Kit
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ * Copyright (C) 2005, 2006, 2007, 2009 GNOME Foundation
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*
+ * File auto-generated from script at:
+ * https://gitlab.gnome.org/GNOME/gtk/-/raw/main/gdk/gdk-keysyms-update.py?ref_type=heads&inline=false
+ *
+ * using the input files:
+ *  {KEYSYMDEF_URL}
+ * and
+ *  {XF86KEYSYM_URL}
+ */
+
+#pragma once
+"""
+
+GDK_KEYSYMS_H = "gdkkeysyms.h"
+
+
+def get_and_filter_header(
+    url: str,
+    prefix: str,
+    output_file: TextIO,
+    filter_out: Iterable[str] | None = None,
+    replaces: dict[str, str] | None = None,
+):
+    """
+    Fetches and processes a header file containing macro definitions, filtering
+    and transforming entries based on the specified prefix, exclusions, and
+    replacements.
+
+    Args:
+        url: The URL to fetch the file content from.
+        prefix: The prefix to filter the macro definitions in the file.
+        output_file: The file object where the filtered and transformed
+                     definitions will be written.
+        filter_out: An iterable producing macro names to exclude from
+                    processing. Defaults to None.
+        replaces: A dictionary mapping macro names to their replacements.
+                  Defaults to None.
+    """
+    for line in requests.get(url, timeout=5).text.splitlines():
+        if not line.startswith("#define " + prefix):
+            continue
+
+        keysymelements = line.split()
+        if len(keysymelements) < 3:
+            sys.exit(
+                f"Internal error, no properly defined keysym entry: {line}",
+            )
+
+        if keysymelements[2].startswith("_EVDEVK("):
+            value = int(keysymelements[2][8:-1], 0)
+            value += 0x10081000  # _EVDEVK macro does this
+            keysymelements[2] = hex(value)
+        elif not keysymelements[2].startswith("0x"):
+            sys.exit(
+                f'Internal error, was expecting "0x*", found: {keysymelements[2]}',
+            )
+
+        if filter_out and keysymelements[1] in filter_out:
+            continue
+
+        if replaces and keysymelements[1] in replaces.keys():
+            keysymelements[1] = replaces[keysymelements[1]]
+
+        binding = re.sub(f"^{prefix}", "GDK_KEY_", keysymelements[1])
+        print(
+            f"#define {binding} 0x{int(keysymelements[2], 0):03x}",
+            file=output_file,
+        )
+
+
+if __name__ == "__main__":
+    if os.path.exists(GDK_KEYSYMS_H):
+        sys.exit(
+            f"""There is already a {GDK_KEYSYMS_H} file in this directory. We are not overwriting it.
+Please move it somewhere else in order to run this script.
+Exiting...""",
+        )
+
+    with open(GDK_KEYSYMS_H, "x", encoding="utf8") as output_file:
+        print(LICENSE_HEADER, file=output_file)
+
+        get_and_filter_header(KEYSYMDEF_URL, "XK_", output_file)
+
+        # Work-around https://bugs.freedesktop.org/show_bug.cgi?id=11193
+        # XF86XK_Clear could end up a dupe of XK_Clear
+        # XF86XK_Select could end up a dupe of XK_Select
+        # Ignore XF86XK_Qu, XF86XK_Calculater is misspelled, and a dupe
+        get_and_filter_header(
+            XF86KEYSYM_URL,
+            "XF86XK_",
+            output_file,
+            ("XF86XK_Q", "XF86XK_Calculater", "XF86XK_Break"),
+            {
+                "XF86XK_XF86BackForward": "XF86XK_AudioForward",
+                "XF86XK_Clear": "XF86XK_WindowClear",
+                "XF86XK_Select": "XF86XK_SelectButton",
+            },
+        )
diff --git a/gdk/gdk.c b/gdk/gdk.c
index 3726a7e43f795cc93a096bc82f30aeaaca875b37..8e6512d89f5d9a61f6f3a8399bb47a13388abd98 100644
--- a/gdk/gdk.c
+++ b/gdk/gdk.c
@@ -139,7 +139,6 @@ static const GdkDebugKey gdk_debug_keys[] = {
   { "portals",         GDK_DEBUG_PORTALS, "Force use of portals" },
   { "no-portals",      GDK_DEBUG_NO_PORTALS, "Disable use of portals" },
   { "force-offload",   GDK_DEBUG_FORCE_OFFLOAD, "Force graphics offload for all textures" },
-  { "gl-no-fractional", GDK_DEBUG_GL_NO_FRACTIONAL, "Disable fractional scaling for OpenGL" },
   { "gl-debug",        GDK_DEBUG_GL_DEBUG, "Insert debugging information in OpenGL" },
   { "gl-prefer-gl",    GDK_DEBUG_GL_PREFER_GL, "Prefer GL over GLES API" },
   { "default-settings",GDK_DEBUG_DEFAULT_SETTINGS, "Force default values for xsettings" },
@@ -281,7 +280,7 @@ gdk_parse_debug_var (const char        *variable,
                 }
             }
           if (i == nkeys)
-            fprintf (stderr, "Unrecognized value \"%.*s\". Try %s=help\n", (int) (q - p), p, variable);
+            gdk_help_message ("Unrecognized value \"%.*s\". Try %s=help", (int) (q - p), p, variable);
          }
 
       p = q;
@@ -296,14 +295,13 @@ gdk_parse_debug_var (const char        *variable,
         max_width = MAX (max_width, strlen (keys[i].key));
       max_width += 4;
 
-      fprintf (stderr, "%s\n", docs);
-      fprintf (stderr, "Supported %s values:\n", variable);
-      for (i = 0; i < nkeys; i++) {
-        fprintf (stderr, "  %s%*s%s\n", keys[i].key, (int)(max_width - strlen (keys[i].key)), " ", keys[i].help);
-      }
-      fprintf (stderr, "  %s%*s%s\n", "all", max_width - 3, " ", "Enable all values. Other given values are subtracted");
-      fprintf (stderr, "  %s%*s%s\n", "help", max_width - 4, " ", "Print this help");
-      fprintf (stderr, "\nMultiple values can be given, separated by : or space.\n");
+      gdk_help_message ("%s", docs);
+      gdk_help_message ("Supported %s values:", variable);
+      for (i = 0; i < nkeys; i++)
+        gdk_help_message ("  %s%*s%s", keys[i].key, (int)(max_width - strlen (keys[i].key)), " ", keys[i].help);
+      gdk_help_message ("  %s%*s%s", "all", max_width - 3, " ", "Enable all values. Other given values are subtracted");
+      gdk_help_message ("  %s%*s%s", "help", max_width - 4, " ", "Print this help");
+      gdk_help_message ("\nMultiple values can be given, separated by : or space.");
     }
 
   if (invert)
diff --git a/gdk/gdkapplaunchcontext.c b/gdk/gdkapplaunchcontext.c
index 5c2e62b50133805ef872cc07d6928a063cbd96ce..43d93fe0d78108a78a2edd5b6ba4310ab211fd7e 100644
--- a/gdk/gdkapplaunchcontext.c
+++ b/gdk/gdkapplaunchcontext.c
@@ -28,7 +28,7 @@
 /**
  * GdkAppLaunchContext:
  *
- * `GdkAppLaunchContext` handles launching an application in a graphical context.
+ * Handles launching an application in a graphical context.
  *
  * It is an implementation of `GAppLaunchContext` that provides startup
  * notification and allows to launch applications on a specific workspace.
diff --git a/gdk/gdkcairocontext.c b/gdk/gdkcairocontext.c
index 6533a9d39ef4d50d11880762514072a16a004469..9335371a5e32f3f181a98da96851f1f7dffff77d 100644
--- a/gdk/gdkcairocontext.c
+++ b/gdk/gdkcairocontext.c
@@ -29,8 +29,7 @@
 /**
  * GdkCairoContext:
  *
- * `GdkCairoContext` is an object representing the platform-specific
- * draw context.
+ * Represents the platform-specific draw context.
  *
  * `GdkCairoContext`s are created for a surface using
  * [method@Gdk.Surface.create_cairo_context], and the context
diff --git a/gdk/gdkcairoprivate.h b/gdk/gdkcairoprivate.h
index 53fbb98289980a44e8188b691cf32e309ee8dada..84e12a8d267ec63c37d3f83dc360061d35882a80 100644
--- a/gdk/gdkcairoprivate.h
+++ b/gdk/gdkcairoprivate.h
@@ -149,19 +149,27 @@ gdk_cairo_surface_convert_color_state (cairo_surface_t *surface,
                                        GdkColorState   *target)
 {
   cairo_surface_t *image_surface;
+  int status, width, height;
 
   if (gdk_color_state_equal (source, target))
     return;
 
   image_surface = cairo_surface_map_to_image (surface, NULL);
 
-  gdk_memory_convert_color_state (cairo_image_surface_get_data (image_surface),
-                                  cairo_image_surface_get_stride (image_surface),
-                                  gdk_cairo_format_to_memory_format (cairo_image_surface_get_format (image_surface)),
-                                  source,
-                                  target,
-                                  cairo_image_surface_get_width (image_surface),
-                                  cairo_image_surface_get_height (image_surface));
+  status = cairo_surface_status (image_surface);
+  width = cairo_image_surface_get_width (image_surface);
+  height = cairo_image_surface_get_height (image_surface);
+
+  if (status == CAIRO_STATUS_SUCCESS && width > 0 && height > 0)
+    {
+      gdk_memory_convert_color_state (cairo_image_surface_get_data (image_surface),
+                                      cairo_image_surface_get_stride (image_surface),
+                                      gdk_cairo_format_to_memory_format (cairo_image_surface_get_format (image_surface)),
+                                      source,
+                                      target,
+                                      width,
+                                      height);
+    }
 
   cairo_surface_mark_dirty (image_surface);
   cairo_surface_unmap_image (surface, image_surface);
diff --git a/gdk/gdkcicpparams.c b/gdk/gdkcicpparams.c
index eb90c5887dab8784f00f3a4b1125989bace36f05..d3e8d87eeaa794f1be764f6a601fe06c3e1d47d0 100644
--- a/gdk/gdkcicpparams.c
+++ b/gdk/gdkcicpparams.c
@@ -25,8 +25,9 @@
 /**
  * GdkCicpParams:
  *
- * The `GdkCicpParams` struct contains the parameters that define
- * a colorstate according to the ITU-T H.273
+ * Contains the parameters that define a colorstate with cicp parameters.
+ *
+ * Cicp parameters are specified in the ITU-T H.273
  * [specification](https://www.itu.int/rec/T-REC-H.273/en).
  *
  * See the documentation of individual properties for supported values.
diff --git a/gdk/gdkclipboard.c b/gdk/gdkclipboard.c
index 15de331d8ffee0b88d2444dc6b842fc0c1c7d54d..f771589f6e1f5542b7e67240b548e1116aab0b18 100644
--- a/gdk/gdkclipboard.c
+++ b/gdk/gdkclipboard.c
@@ -36,8 +36,7 @@
 /**
  * GdkClipboard:
  *
- * The `GdkClipboard` object represents data shared between applications or
- * inside an application.
+ * Represents data shared between applications or inside an application.
  *
  * To get a `GdkClipboard` object, use [method@Gdk.Display.get_clipboard] or
  * [method@Gdk.Display.get_primary_clipboard]. You can find out about the data
diff --git a/gdk/gdkcolorstate.c b/gdk/gdkcolorstate.c
index 5ca8ca7e4a32425337e588ffde594fa6a8bcca93..7dbd8a8e95ffe1e6898716fd3e3fa62fcfc4f892 100644
--- a/gdk/gdkcolorstate.c
+++ b/gdk/gdkcolorstate.c
@@ -29,8 +29,7 @@
 /**
  * GdkColorState:
  *
- * A `GdkColorState` object provides the information to interpret
- * colors and pixels in a variety of ways.
+ * Provides information to interpret colors and pixels in a variety of ways.
  *
  * They are also known as
  * [*color spaces*](https://en.wikipedia.org/wiki/Color_space).
diff --git a/gdk/gdkcontentdeserializer.c b/gdk/gdkcontentdeserializer.c
index 2e3293683d14f09d6493d570cf0de08e18daf06c..e367c938c4d2d2cf6d58d11a8557dd4360f507bb 100644
--- a/gdk/gdkcontentdeserializer.c
+++ b/gdk/gdkcontentdeserializer.c
@@ -35,8 +35,7 @@
 /**
  * GdkContentDeserializer:
  *
- * A `GdkContentDeserializer` is used to deserialize content received via
- * inter-application data transfers.
+ * Deserializes content received via inter-application data transfers.
  *
  * The `GdkContentDeserializer` transforms serialized content that is
  * identified by a mime type into an object identified by a GType.
@@ -542,9 +541,9 @@ deserialize_not_found (GdkContentDeserializer *deserializer)
  * @callback: (scope async) (closure user_data): callback to call when the operation is done
  * @user_data: data to pass to the callback function
  *
- * Read content from the given input stream and deserialize it, asynchronously.
+ * Reads content from the given input stream and deserialize it, asynchronously.
  *
- * The default I/O priority is %G_PRIORITY_DEFAULT (i.e. 0), and lower numbers
+ * The default I/O priority is `G_PRIORITY_DEFAULT` (i.e. 0), and lower numbers
  * indicate a higher priority.
  */
 void
diff --git a/gdk/gdkcontentformats.c b/gdk/gdkcontentformats.c
index c0e8832d2e49c2839a4c35bb9b80eb7f10196b86..a4a81d80af4402bc36e7f360435da727f378834d 100644
--- a/gdk/gdkcontentformats.c
+++ b/gdk/gdkcontentformats.c
@@ -18,8 +18,7 @@
 /**
  * GdkContentFormats:
  *
- * The `GdkContentFormats` structure is used to advertise and negotiate the
- * format of content.
+ * Used to advertise and negotiate the format of content.
  *
  * You will encounter `GdkContentFormats` when interacting with objects
  * controlling operations that pass data between different widgets, window
@@ -55,7 +54,7 @@
 /**
  * GdkContentFormatsBuilder:
  *
- * Auxiliary object to create a `GdkContentFormats`.
+ * Creates `GdkContentFormats` objects.
  */
 
 #include "config.h"
diff --git a/gdk/gdkcontentprovider.c b/gdk/gdkcontentprovider.c
index 99e45426ee8e87b4d46eec830d774b8c5bc507e6..80eb350ff70b69cf3fdbcb08cacd53b67dd66574 100644
--- a/gdk/gdkcontentprovider.c
+++ b/gdk/gdkcontentprovider.c
@@ -28,8 +28,8 @@
 /**
  * GdkContentProvider:
  *
- * A `GdkContentProvider` is used to provide content for the clipboard or
- * for drag-and-drop operations in a number of formats.
+ * Provides content for the clipboard or for drag-and-drop operations
+ * in a number of formats.
  *
  * To create a `GdkContentProvider`, use [ctor@Gdk.ContentProvider.new_for_value]
  * or [ctor@Gdk.ContentProvider.new_for_bytes].
diff --git a/gdk/gdkcontentserializer.c b/gdk/gdkcontentserializer.c
index 1295eb423023553958ef311593283fc402f97ac2..72e648c355c5e5513cb446b07fcdde4cc036dec5 100644
--- a/gdk/gdkcontentserializer.c
+++ b/gdk/gdkcontentserializer.c
@@ -39,8 +39,7 @@
 /**
  * GdkContentSerializer:
  *
- * A `GdkContentSerializer` is used to serialize content for
- * inter-application data transfers.
+ * Serializes content for inter-application data transfers.
  *
  * The `GdkContentSerializer` transforms an object that is identified
  * by a GType into a serialized form (i.e. a byte stream) that is
diff --git a/gdk/gdkcursor.c b/gdk/gdkcursor.c
index 4762a26209dacc6fb8ebda53124beac0917eb03e..6fc0e47e743c25e770402d884c4b03b3b8bfb4b2 100644
--- a/gdk/gdkcursor.c
+++ b/gdk/gdkcursor.c
@@ -38,7 +38,7 @@
 /**
  * GdkCursor:
  *
- * `GdkCursor` is used to create and destroy cursors.
+ * Used to create and destroy cursors.
  *
  * Cursors are immutable objects, so once you created them, there is no way
  * to modify them later. You should create a new cursor when you want to change
diff --git a/gdk/gdkdebugprivate.h b/gdk/gdkdebugprivate.h
index 4372ec7203f4ed4a0d69e6885f2c2bfd49635075..68e64e1c266d14031fa5afedeb2c3a270de46557 100644
--- a/gdk/gdkdebugprivate.h
+++ b/gdk/gdkdebugprivate.h
@@ -44,13 +44,12 @@ typedef enum {
   GDK_DEBUG_HDR             = 1 << 14,
   GDK_DEBUG_PORTALS         = 1 << 15,
   GDK_DEBUG_NO_PORTALS      = 1 << 16,
-  GDK_DEBUG_GL_NO_FRACTIONAL= 1 << 17,
-  GDK_DEBUG_FORCE_OFFLOAD   = 1 << 18,
-  GDK_DEBUG_GL_PREFER_GL    = 1 << 19,
-  GDK_DEBUG_GL_DEBUG        = 1 << 20,
-  GDK_DEBUG_DEFAULT_SETTINGS= 1 << 21,
-  GDK_DEBUG_HIGH_DEPTH      = 1 << 22,
-  GDK_DEBUG_NO_VSYNC        = 1 << 23,
+  GDK_DEBUG_FORCE_OFFLOAD   = 1 << 17,
+  GDK_DEBUG_GL_PREFER_GL    = 1 << 18,
+  GDK_DEBUG_GL_DEBUG        = 1 << 19,
+  GDK_DEBUG_DEFAULT_SETTINGS= 1 << 20,
+  GDK_DEBUG_HIGH_DEPTH      = 1 << 21,
+  GDK_DEBUG_NO_VSYNC        = 1 << 22,
 } GdkDebugFlags;
 
 typedef enum {
@@ -83,17 +82,34 @@ static inline void
 gdk_debug_message (const char *format, ...)
 {
   va_list args;
-  char *s;
 
   va_start (args, format);
-  s = g_strdup_vprintf (format, args);
+#ifdef GLIB_USING_SYSTEM_PRINTF
+  vfprintf (stderr, format, args);
+#else
+  g_vfprintf (stderr, format, args);
+#endif
   va_end (args);
+
+  fprintf (stderr, "\n");
+}
+
+static inline void
+gdk_help_message (const char *format, ...) G_GNUC_PRINTF(1, 2);
+static inline void
+gdk_help_message (const char *format, ...)
+{
+  va_list args;
+
+  va_start (args, format);
 #ifdef GLIB_USING_SYSTEM_PRINTF
-  fprintf (stderr, "%s\n", s);
+  vfprintf (stderr, format, args);
 #else
-  g_fprintf (stderr, "%s\n", s);
+  g_vfprintf (stderr, format, args);
 #endif
-  g_free (s);
+  va_end (args);
+
+  fprintf (stderr, "\n");
 }
 
 #define GDK_DISPLAY_DEBUG_CHECK(display,type) \
diff --git a/gdk/gdkdevice.c b/gdk/gdkdevice.c
index 3122ada2a8428882c4d1e4f76d225b26bb3dcb0e..1e87b4e52ddb964e833eca54792f34f90a08d228 100644
--- a/gdk/gdkdevice.c
+++ b/gdk/gdkdevice.c
@@ -28,8 +28,7 @@
 /**
  * GdkDevice:
  *
- * The `GdkDevice` object represents an input device, such
- * as a keyboard, a mouse, or a touchpad.
+ * Represents an input device, such as a keyboard, mouse or touchpad.
  *
  * See the [class@Gdk.Seat] documentation for more information
  * about the various kinds of devices, and their relationships.
diff --git a/gdk/gdkdevice.h b/gdk/gdkdevice.h
index f86763aac8da8f9fb87174975bb1ae9412963ec6..d2ef66d7849d4de94acd2d6f0ce8c0c4d7ca8db6 100644
--- a/gdk/gdkdevice.h
+++ b/gdk/gdkdevice.h
@@ -66,7 +66,7 @@ typedef enum
  * @flags: Flags indicating what axes are present, see [flags@Gdk.AxisFlags]
  * @axes: (array fixed-size=12): axis values, indexed by [enum@Gdk.AxisUse]
  *
- * A `GdkTimeCoord` stores a single event in a motion history.
+ * Stores a single event in a motion history.
  *
  * To check whether an axis is present, check whether the corresponding
  * flag from the [flags@Gdk.AxisFlags] enumeration is set in the @flags
diff --git a/gdk/gdkdevicepad.c b/gdk/gdkdevicepad.c
index ed0bcb9ab404aec6c523cba07ddf87bfba848b1a..c29ec661c7917ca77c532f3aebec8b9e3c169a87 100644
--- a/gdk/gdkdevicepad.c
+++ b/gdk/gdkdevicepad.c
@@ -20,8 +20,7 @@
 /**
  * GdkDevicePad:
  *
- * `GdkDevicePad` is an interface implemented by devices of type
- * %GDK_SOURCE_TABLET_PAD
+ * An interface for tablet pad devices.
  *
  * It allows querying the features provided by the pad device.
  *
diff --git a/gdk/gdkdisplay.c b/gdk/gdkdisplay.c
index b9fd777ad33f5a7074508304ffdb2d3762336f9c..7504826640c0dd736a0271e6a7d94642bb1c8cd9 100644
--- a/gdk/gdkdisplay.c
+++ b/gdk/gdkdisplay.c
@@ -56,7 +56,7 @@
 /**
  * GdkDisplay:
  *
- * `GdkDisplay` objects are the GDK representation of a workstation.
+ * A representation of a workstation.
  *
  * Their purpose are two-fold:
  *
diff --git a/gdk/gdkdisplaymanager.c b/gdk/gdkdisplaymanager.c
index 3999a71789a1721f4a38671263c120e334d2aed4..991eea397278e998588f97de1392ca0677724520 100644
--- a/gdk/gdkdisplaymanager.c
+++ b/gdk/gdkdisplaymanager.c
@@ -60,8 +60,9 @@
 /**
  * GdkDisplayManager:
  *
- * A singleton object that offers notification when displays appear or
- * disappear.
+ * Offers notification when displays appear or disappear.
+ *
+ * `GdkDisplayManager` is a singleton object.
  *
  * You can use [func@Gdk.DisplayManager.get] to obtain the `GdkDisplayManager`
  * singleton, but that should be rarely necessary. Typically, initializing
diff --git a/gdk/gdkdmabufformats.c b/gdk/gdkdmabufformats.c
index 5b7b19ef48976dc40303b7a952c63d48594c08ad..96622194cf59b22bd81b60dead2605ace33f0cae 100644
--- a/gdk/gdkdmabufformats.c
+++ b/gdk/gdkdmabufformats.c
@@ -25,8 +25,7 @@
 /**
  * GdkDmabufFormats:
  *
- * The `GdkDmabufFormats` struct provides information about
- * supported DMA buffer formats.
+ * Provides information about supported DMA buffer formats.
  *
  * You can query whether a given format is supported with
  * [method@Gdk.DmabufFormats.contains] and you can iterate
diff --git a/gdk/gdkdmabuftexturebuilder.c b/gdk/gdkdmabuftexturebuilder.c
index d0bd18ae7744c221d542d5e4c7f7d2a6962a3673..a1432cd0b8a92397923f2bb6bed456c6e87c7d18 100644
--- a/gdk/gdkdmabuftexturebuilder.c
+++ b/gdk/gdkdmabuftexturebuilder.c
@@ -56,8 +56,7 @@ struct _GdkDmabufTextureBuilderClass
 /**
  * GdkDmabufTextureBuilder:
  *
- * `GdkDmabufTextureBuilder` is a builder used to construct [class@Gdk.Texture]
- * objects from DMA buffers.
+ * Constructs [class@Gdk.Texture] objects from DMA buffers.
  *
  * DMA buffers are commonly called **_dma-bufs_**.
  *
diff --git a/gdk/gdkdrag.c b/gdk/gdkdrag.c
index 67d50ee7f0d92f930371ade675eab67e6fb64aeb..0e1091d03637f9fe490b4f26760cb6c9533ebae8 100644
--- a/gdk/gdkdrag.c
+++ b/gdk/gdkdrag.c
@@ -25,7 +25,7 @@
 /**
  * GdkDrag:
  *
- * The `GdkDrag` object represents the source of an ongoing DND operation.
+ * Represents the source of an ongoing DND operation.
  *
  * A `GdkDrag` is created when a drag is started, and stays alive for duration of
  * the DND operation. After a drag has been started with [func@Gdk.Drag.begin],
diff --git a/gdk/gdkdragsurface.c b/gdk/gdkdragsurface.c
index e9c097ed2e3c5d53439f5144dad10f3421e08d3e..51091df6d48754b046921ebc866a858a6656ae98 100644
--- a/gdk/gdkdragsurface.c
+++ b/gdk/gdkdragsurface.c
@@ -26,7 +26,7 @@
 /**
  * GdkDragSurface:
  *
- * A `GdkDragSurface` is an interface for surfaces used during DND.
+ * A surface that is used during DND.
  */
 
 /**
diff --git a/gdk/gdkdragsurfacesize.c b/gdk/gdkdragsurfacesize.c
index 509e02c3343b7e66d5eccac12b2724c987e29a65..c3fc7565acbfebb4dadff3b02ba329a2c1cb0c14 100644
--- a/gdk/gdkdragsurfacesize.c
+++ b/gdk/gdkdragsurfacesize.c
@@ -23,8 +23,7 @@
 /**
  * GdkDragSurfaceSize:
  *
- * The `GdkDragSurfaceSize` struct contains information that is useful
- * to compute the size of a drag surface.
+ * Contains information that is useful to compute the size of a drag surface.
  *
  * Since: 4.12
  */
diff --git a/gdk/gdkdrop.c b/gdk/gdkdrop.c
index 39bdafb7b7f8997f79a56d29ee5ce76ed399c36e..7f19d7863861f6fe55b843759913d905ef2f390b 100644
--- a/gdk/gdkdrop.c
+++ b/gdk/gdkdrop.c
@@ -20,7 +20,7 @@
 /**
  * GdkDrop:
  *
- * The `GdkDrop` object represents the target of an ongoing DND operation.
+ * Represents the target of an ongoing DND operation.
  *
  * Possible drop sites get informed about the status of the ongoing drag
  * operation with events of type %GDK_DRAG_ENTER, %GDK_DRAG_LEAVE,
diff --git a/gdk/gdkenums.h b/gdk/gdkenums.h
index 69f99935cdef819c140ff03105e35a2d8ab01aef..13ea7460fcf507cd17a20ecdc5949f846fb7ec58 100644
--- a/gdk/gdkenums.h
+++ b/gdk/gdkenums.h
@@ -319,7 +319,7 @@ typedef enum
  *   more formats get added, so do not rely on its concrete integer.
  * @GDK_MEMORY_R32G32B32_FLOAT: 3 float values; for red, green, blue.
  *
- * `GdkMemoryFormat` describes formats that image data can have in memory.
+ * Describes formats that image data can have in memory.
  *
  * It describes formats by listing the contents of the memory passed to it.
  * So `GDK_MEMORY_A8R8G8B8` will be 1 byte (8 bits) of alpha, followed by a
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index 2d7540a2e7d7e73b76fbbdcea3de2d3b43507ed4..ec4c8ab36946d84d9d7e2cdc8cfbfb492060a7ef 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -41,19 +41,19 @@
 /**
  * GdkEvent: (ref-func gdk_event_ref) (unref-func gdk_event_unref)
  *
- * `GdkEvent`s are immutable data structures, created by GDK to
- * represent windowing system events.
+ * Represents windowing system events.
  *
  * In GTK applications the events are handled automatically by toplevel
  * widgets and passed on to the event controllers of appropriate widgets,
  * so using `GdkEvent` and its related API is rarely needed.
+ *
+ * `GdkEvent` structs are immutable.
  */
 
 /**
  * GdkEventSequence:
  *
- * `GdkEventSequence` is an opaque type representing a sequence
- * of related touch events.
+ * An opaque type representing a sequence of related events.
  */
 
 static void
diff --git a/gdk/gdkframeclock.c b/gdk/gdkframeclock.c
index 27bd5453f2692f97958a57adbbc6a6862f5b86a7..79d1dc8ed8dc46186bd377768d18fa61c82aec6c 100644
--- a/gdk/gdkframeclock.c
+++ b/gdk/gdkframeclock.c
@@ -29,8 +29,7 @@
 /**
  * GdkFrameClock:
  *
- * A `GdkFrameClock` tells the application when to update and repaint
- * a surface.
+ * Tells the application when to update and repaint a surface.
  *
  * This may be synced to the vertical refresh rate of the monitor, for example.
  * Even when the frame clock uses a simple timer rather than a hardware-based
diff --git a/gdk/gdkframetimings.c b/gdk/gdkframetimings.c
index e15890fff5a22bff5b01fa54361e467f965abec6..debf9244c9d77771619c0b63f19754cfb32087ff 100644
--- a/gdk/gdkframetimings.c
+++ b/gdk/gdkframetimings.c
@@ -24,8 +24,7 @@
 /**
  * GdkFrameTimings:
  *
- * A `GdkFrameTimings` object holds timing information for a single frame
- * of the application’s displays.
+ * Holds timing information for a single frame of the application’s displays.
  *
  * To retrieve `GdkFrameTimings` objects, use [method@Gdk.FrameClock.get_timings]
  * or [method@Gdk.FrameClock.get_current_timings]. The information in
diff --git a/gdk/gdkgl.c b/gdk/gdkgl.c
index 55d69bf6e0134bb9c654df4ae5d235189031dc86..4148729235e73dc2832a32655776e7e293d054b3 100644
--- a/gdk/gdkgl.c
+++ b/gdk/gdkgl.c
@@ -42,7 +42,7 @@
  * @width: The width of the region to draw
  * @height: The height of the region to draw
  *
- * The main way to not draw GL content in GTK.
+ * Draws GL content onto a cairo context.
  *
  * It takes a render buffer ID (@source_type == GL_RENDERBUFFER) or a texture
  * id (@source_type == GL_TEXTURE) and draws it onto @cr with an OVER operation,
@@ -68,15 +68,15 @@
  *   image surface.
  */
 void
-gdk_cairo_draw_from_gl (cairo_t              *cr,
-                        GdkSurface            *surface,
-                        int                   source,
-                        int                   source_type,
-                        int                   buffer_scale,
-                        int                   x,
-                        int                   y,
-                        int                   width,
-                        int                   height)
+gdk_cairo_draw_from_gl (cairo_t    *cr,
+                        GdkSurface *surface,
+                        int         source,
+                        int         source_type,
+                        int         buffer_scale,
+                        int         x,
+                        int         y,
+                        int         width,
+                        int         height)
 {
   GdkGLContext *paint_context;
   cairo_surface_t *image;
diff --git a/gdk/gdkglcontext.c b/gdk/gdkglcontext.c
index 7c774915a66676a920b5c6fad54bc0ac988a68af..41ec2d12f3319eeb659a3b99b4e8b94147f704da 100644
--- a/gdk/gdkglcontext.c
+++ b/gdk/gdkglcontext.c
@@ -21,8 +21,7 @@
 /**
  * GdkGLContext:
  *
- * `GdkGLContext` is an object representing a platform-specific
- * OpenGL draw context.
+ * Represents a platform-specific OpenGL draw context.
  *
  * `GdkGLContext`s are created for a surface using
  * [method@Gdk.Surface.create_gl_context], and the context will match
@@ -587,23 +586,6 @@ gdk_gl_context_real_make_current (GdkGLContext *context,
 #endif
 }
 
-double
-gdk_gl_context_get_scale (GdkGLContext *self)
-{
-  GdkDisplay *display;
-  GdkSurface *surface;
-  double scale;
-
-  surface = gdk_draw_context_get_surface (GDK_DRAW_CONTEXT (self));
-  scale = gdk_surface_get_scale (surface);
-
-  display = gdk_gl_context_get_display (self);
-  if (gdk_display_get_debug_flags (display) & GDK_DEBUG_GL_NO_FRACTIONAL)
-    scale = ceil (scale);
-
-  return scale;
-}
-
 static void
 gdk_gl_context_real_begin_frame (GdkDrawContext  *draw_context,
                                  GdkMemoryDepth   depth,
@@ -621,7 +603,7 @@ gdk_gl_context_real_begin_frame (GdkDrawContext  *draw_context,
   int i;
 
   color_state = gdk_surface_get_color_state (surface);
-  scale = gdk_gl_context_get_scale (context);
+  scale = gdk_surface_get_scale (surface);
 
   depth = gdk_memory_depth_merge (depth, gdk_color_state_get_depth (color_state));
 
@@ -698,7 +680,7 @@ gdk_gl_context_real_end_frame (GdkDrawContext *draw_context,
       EGLint *heap_rects = NULL;
       int i, j, n_rects = cairo_region_num_rectangles (painted);
       int surface_height = gdk_surface_get_height (surface);
-      double scale = gdk_gl_context_get_scale (context);
+      double scale = gdk_surface_get_scale (surface);
       EGLint *rects;
 
       if (n_rects < G_N_ELEMENTS (stack_rects) / 4)
diff --git a/gdk/gdkglcontextprivate.h b/gdk/gdkglcontextprivate.h
index 2e6f42c80093b85f5a05f032d706dab06e3a3a88..71ab1b7e1b2f43d167361d936170e6df36f3ecfc 100644
--- a/gdk/gdkglcontextprivate.h
+++ b/gdk/gdkglcontextprivate.h
@@ -181,8 +181,6 @@ gboolean                gdk_gl_context_use_es_bgra              (GdkGLContext
 
 gboolean                gdk_gl_context_has_vertex_arrays        (GdkGLContext    *self) G_GNUC_PURE;
 
-double                  gdk_gl_context_get_scale                (GdkGLContext    *self);
-
 void                    gdk_gl_context_download                 (GdkGLContext    *self,
                                                                  GLuint           tex_id,
                                                                  GdkMemoryFormat  tex_format,
diff --git a/gdk/gdkgltexture.c b/gdk/gdkgltexture.c
index 7a60fd08487a6cb9941372f467cf4005d5d346ee..5230c27fea85f099adf907f3acf8b06688df40ad 100644
--- a/gdk/gdkgltexture.c
+++ b/gdk/gdkgltexture.c
@@ -31,7 +31,7 @@
 /**
  * GdkGLTexture:
  *
- * A GdkTexture representing a GL texture object.
+ * A `GdkTexture` representing a GL texture object.
  */
 
 struct _GdkGLTexture {
diff --git a/gdk/gdkgltexturebuilder.c b/gdk/gdkgltexturebuilder.c
index 0c8fafefc61bf9d2543fd12135a01da85479f223..96330b71894462f6562a4ada53d0157d6f010f9d 100644
--- a/gdk/gdkgltexturebuilder.c
+++ b/gdk/gdkgltexturebuilder.c
@@ -53,8 +53,7 @@ struct _GdkGLTextureBuilderClass
 /**
  * GdkGLTextureBuilder:
  *
- * `GdkGLTextureBuilder` is a builder used to construct [class@Gdk.Texture] objects from
- * GL textures.
+ * Constructs [class@Gdk.Texture] objects from GL textures.
  *
  * The operation is quite simple: Create a texture builder, set all the necessary
  * properties - keep in mind that the properties [property@Gdk.GLTextureBuilder:context],
diff --git a/gdk/gdkkeys.c b/gdk/gdkkeys.c
index 2374761049fa4b0ce1557089f54e499d57f202c0..8f95293d8cd82b99d3e45fe416dd36facbe211cc 100644
--- a/gdk/gdkkeys.c
+++ b/gdk/gdkkeys.c
@@ -249,9 +249,9 @@ gdk_keyval_to_lower (guint keyval)
  * gdk_keyval_is_upper:
  * @keyval: a key value.
  *
- * Returns %TRUE if the given key value is in upper case.
+ * Returns true if the given key value is in upper case.
  *
- * Returns: %TRUE if @keyval is in upper case, or if @keyval is not subject to
+ * Returns: true if @keyval is in upper case, or if @keyval is not subject to
  *  case conversion.
  */
 gboolean
@@ -271,9 +271,9 @@ gdk_keyval_is_upper (guint keyval)
  * gdk_keyval_is_lower:
  * @keyval: a key value.
  *
- * Returns %TRUE if the given key value is in lower case.
+ * Returns true if the given key value is in lower case.
  *
- * Returns: %TRUE if @keyval is in lower case, or if @keyval is not
+ * Returns: true if @keyval is in lower case, or if @keyval is not
  *   subject to case conversion.
  */
 gboolean
@@ -296,10 +296,10 @@ gdk_keyval_is_lower (guint keyval)
  * Returns the direction of effective layout of the keymap.
  *
  * The direction of a layout is the direction of the majority of its
- * symbols. See pango_unichar_direction().
+ * symbols. See [function@Pango.unichar_direction].
  *
- * Returns: %PANGO_DIRECTION_LTR or %PANGO_DIRECTION_RTL
- *   if it can determine the direction. %PANGO_DIRECTION_NEUTRAL
+ * Returns: `PANGO_DIRECTION_LTR` or `PANGO_DIRECTION_RTL`
+ *   if it can determine the direction, and `PANGO_DIRECTION_NEUTRAL`
  *   otherwise.
  */
 PangoDirection
@@ -317,7 +317,7 @@ gdk_keymap_get_direction (GdkKeymap *keymap)
  * Determines if keyboard layouts for both right-to-left and left-to-right
  * languages are in use.
  *
- * Returns: %TRUE if there are layouts in both directions, %FALSE otherwise
+ * Returns: true if there are layouts in both directions, false otherwise
  */
 gboolean
 gdk_keymap_have_bidi_layouts (GdkKeymap *keymap)
@@ -333,7 +333,7 @@ gdk_keymap_have_bidi_layouts (GdkKeymap *keymap)
  *
  * Returns whether the Caps Lock modifier is locked.
  *
- * Returns: %TRUE if Caps Lock is on
+ * Returns: true if Caps Lock is on
  */
 gboolean
 gdk_keymap_get_caps_lock_state (GdkKeymap *keymap)
@@ -349,7 +349,7 @@ gdk_keymap_get_caps_lock_state (GdkKeymap *keymap)
  *
  * Returns whether the Num Lock modifier is locked.
  *
- * Returns: %TRUE if Num Lock is on
+ * Returns: true if Num Lock is on
  */
 gboolean
 gdk_keymap_get_num_lock_state (GdkKeymap *keymap)
@@ -365,7 +365,7 @@ gdk_keymap_get_num_lock_state (GdkKeymap *keymap)
  *
  * Returns whether the Scroll Lock modifier is locked.
  *
- * Returns: %TRUE if Scroll Lock is on
+ * Returns: true if Scroll Lock is on
  */
 gboolean
 gdk_keymap_get_scroll_lock_state (GdkKeymap *keymap)
@@ -420,10 +420,10 @@ gdk_keymap_get_active_layout_index (GdkKeymap *keymap)
  * gdk_keymap_get_layout_names:
  * @keymap: a `GdkKeymap`
  *
- * Returns the layouts as a %NULL-terminated array of strings.
+ * Returns the layouts as a `NULL`-terminated array of strings.
  *
  * Returns: (transfer full) (nullable) (array zero-terminated=1):
- *   %NULL-terminated array of strings of layouts,
+ *   `NULL`-terminated array of strings of layouts,
  */
 gchar **
 gdk_keymap_get_layout_names (GdkKeymap *keymap)
@@ -439,14 +439,16 @@ gdk_keymap_get_layout_names (GdkKeymap *keymap)
 /*< private >
  * gdk_keymap_get_entries_for_keyval:
  * @keymap: a `GdkKeymap`
- * @keyval: a keyval, such as %GDK_KEY_a, %GDK_KEY_Up, %GDK_KEY_Return, etc.
+ * @keyval: a keyval, such as `GDK_KEY_a`, `GDK_KEY_Up`, `GDK_KEY_Return`, etc.
  * @keys: (out) (array length=n_keys) (transfer full): return location
  *   for an array of `GdkKeymapKey`
  * @n_keys: return location for number of elements in returned array
  *
  * Obtains a list of keycode/group/level combinations that will
- * generate @keyval. Groups and levels are two kinds of keyboard mode;
- * in general, the level determines whether the top or bottom symbol
+ * generate @keyval.
+ *
+ * Groups and levels are two kinds of keyboard mode; in general,
+ * the level determines whether the top or bottom symbol
  * on a key is used, and the group determines whether the left or
  * right symbol is used. On US keyboards, the shift key changes the
  * keyboard level, and there are no groups. A group switch key might
@@ -456,7 +458,7 @@ gdk_keymap_get_layout_names (GdkKeymap *keymap)
  * The returned array should be freed
  * with g_free().
  *
- * Returns: %TRUE if keys were found and returned
+ * Returns: true if keys were found and returned
  **/
 gboolean
 gdk_keymap_get_entries_for_keyval (GdkKeymap     *keymap,
@@ -529,13 +531,14 @@ gdk_keymap_get_cached_entries_for_keyval (GdkKeymap     *keymap,
  * @n_entries: length of @keys and @keyvals
  *
  * Returns the keyvals bound to @hardware_keycode.
+ *
  * The Nth `GdkKeymapKey` in @keys is bound to the Nth
  * keyval in @keyvals. Free the returned arrays with g_free().
  * When a keycode is pressed by the user, the keyval from
  * this list of entries is selected by considering the effective
  * keyboard group and level. See gdk_keymap_translate_keyboard_state().
  *
- * Returns: %TRUE if there were any entries
+ * Returns: true if there were any entries
  **/
 gboolean
 gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
@@ -557,6 +560,7 @@ gdk_keymap_get_entries_for_keycode (GdkKeymap     *keymap,
  * @key: a `GdkKeymapKey` with keycode, group, and level initialized
  *
  * Looks up the keyval mapped to a keycode/group/level triplet.
+ *
  * If no keyval is bound to @key, returns 0. For normal user input,
  * you want to use gdk_keymap_translate_keyboard_state() instead of
  * this function, since the effective group/level may not be
@@ -587,9 +591,10 @@ gdk_keymap_lookup_key (GdkKeymap          *keymap,
  *   that were used to determine the group or level
  *
  * Translates the contents of a `GdkEventKey` into a keyval, effective
- * group, and level. Modifiers that affected the translation and
- * are thus unavailable for application use are returned in
- * @consumed_modifiers.
+ * group, and level.
+ *
+ * Modifiers that affected the translation and are thus unavailable for
+ * application use are returned in @consumed_modifiers.
  * See [Groups][key-group-explanation] for an explanation of
  * groups and levels. The @effective_group is the group that was
  * actually used for the translation; some keys such as Enter are not
@@ -637,7 +642,7 @@ gdk_keymap_lookup_key (GdkKeymap          *keymap,
  * you store accelerators, you should always store them with consumed
  * modifiers removed. Store `<Control>plus`, not `<Control><Shift>plus`,
  *
- * Returns: %TRUE if there was a keyval bound to the keycode/state/group
+ * Returns: true if there was a keyval bound to the keycode/state/group
  **/
 gboolean
 gdk_keymap_translate_keyboard_state (GdkKeymap       *keymap,
@@ -758,7 +763,7 @@ gdk_keyval_name (guint keyval)
  * `gdk/gdkkeysyms.h` header file
  * but without the leading “GDK_KEY_”.
  *
- * Returns: the corresponding key value, or %GDK_KEY_VoidSymbol
+ * Returns: the corresponding key value, or `GDK_KEY_VoidSymbol`
  *   if the key name is not a valid key
  */
 guint
diff --git a/gdk/gdkkeysyms-update.pl b/gdk/gdkkeysyms-update.pl
deleted file mode 100755
index 3843d4d399e3b421d5d1acfbf809f57a3c8872a8..0000000000000000000000000000000000000000
--- a/gdk/gdkkeysyms-update.pl
+++ /dev/null
@@ -1,169 +0,0 @@
-#!/usr/bin/env perl
-
-# Updates https://gitlab.gnome.org/GNOME/gtk/tree/main/gdk/gdkkeysyms.h from upstream (X.org 7.x),
-# from https://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
-#
-# Author  : Simos Xenitellis <simos at gnome dot org>.
-# Author  : Bastien Nocera <hadess@hadess.net>
-# Version : 1.2
-#
-# Input   : https://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
-# Input   : https://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h
-# Output  : https://gitlab.gnome.org/GNOME/gtk/tree/main/gdk/gdkkeysyms.h
-#
-# Notes   : It downloads keysymdef.h from the Internet, if not found locally,
-# Notes   : and creates an updated gdkkeysyms.h
-# Notes   : This version updates the source of gdkkeysyms.h from CVS to the GIT server.
-
-use strict;
-
-# Used for reading the keysymdef symbols.
-my @keysymelements;
-
-if ( ! -f "keysymdef.h" )
-{
-	print "Trying to download keysymdef.h from\n";
-	print "http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\n";
-	die "Unable to download keysymdef.h from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\n"
-		unless system("wget -c -O keysymdef.h \"http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\"") == 0;
-	print " done.\n\n";
-}
-else
-{
-	print "We are using existing keysymdef.h found in this directory.\n";
-	print "It is assumed that you took care and it is a recent version\n";
-	print "as found at http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h\n\n";
-}
-
-if ( ! -f "XF86keysym.h" )
-{
-	print "Trying to download XF86keysym.h from\n";
-	print "http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\n";
-	die "Unable to download keysymdef.h from http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\n"
-		unless system("wget -c -O XF86keysym.h \"http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\"") == 0;
-	print " done.\n\n";
-}
-else
-{
-	print "We are using existing XF86keysym.h found in this directory.\n";
-	print "It is assumed that you took care and it is a recent version\n";
-	print "as found at http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h\n\n";
-}
-
-# Source: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
-die "Could not open file keysymdef.h: $!\n" unless open(IN_KEYSYMDEF, "<:utf8", "keysymdef.h");
-
-# Output: gtk/gdk/gdkkeysyms.h
-die "Could not open file gdkkeysyms.h: $!\n" unless open(OUT_GDKKEYSYMS, ">:utf8", "gdkkeysyms.h");
-
-my $LICENSE_HEADER= <<EOF;
-/* GDK - The GIMP Drawing Kit
- * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
- * Copyright (C) 2005, 2006, 2007, 2009 GNOME Foundation
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-EOF
-
-print OUT_GDKKEYSYMS $LICENSE_HEADER;
-
-print OUT_GDKKEYSYMS<<EOF;
-
-/*
- * File auto-generated from script https://gitlab.gnome.org/GNOME/gtk/tree/main/gdk/gdkkeysyms-update.pl
- * using the input file
- * http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
- * and
- * http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2007.  See the AUTHORS
- * file for a list of people on the GTK+ Team.  See the ChangeLog
- * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
- */
-
-#pragma once
-
-
-EOF
-
-while (<IN_KEYSYMDEF>)
-{
-	next if ( ! /^#define / );
-
-	@keysymelements = split(/\s+/);
-	die "Internal error, no \@keysymelements: $_\n" unless @keysymelements;
-
-	$_ = $keysymelements[1];
-	die "Internal error, was expecting \"XC_*\", found: $_\n" if ( ! /^XK_/ );
-
-	$_ = $keysymelements[2];
-	die "Internal error, was expecting \"0x*\", found: $_\n" if ( ! /^0x/ );
-
-	my $element = $keysymelements[1];
-	my $binding = $element;
-	$binding =~ s/^XK_/GDK_KEY_/g;
-
-	printf OUT_GDKKEYSYMS "#define %s 0x%03x\n", $binding, hex($keysymelements[2]);
-}
-
-close IN_KEYSYMDEF;
-
-# Source: http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h
-die "Could not open file XF86keysym.h: $!\n" unless open(IN_XF86KEYSYM, "<:utf8", "XF86keysym.h");
-
-while (<IN_XF86KEYSYM>)
-{
-	next if ( ! /^#define / );
-
-	@keysymelements = split(/\s+/);
-	die "Internal error, no \@keysymelements: $_\n" unless @keysymelements;
-
-	$_ = $keysymelements[1];
-	die "Internal error, was expecting \"XF86XK_*\", found: $_\n" if ( ! /^XF86XK_/ );
-
-	# XF86XK_Clear could end up a dupe of XK_Clear
-	# XF86XK_Select could end up a dupe of XK_Select
-	if ($_ eq "XF86XK_Clear") {
-		$keysymelements[1] = "XF86XK_WindowClear";
-	}
-	if ($_ eq "XF86XK_Select") {
-		$keysymelements[1] = "XF86XK_SelectButton";
-	}
-
-	# Ignore XF86XK_Q
-	next if ( $_ eq "XF86XK_Q");
-	# XF86XK_Calculater is misspelled, and a dupe
-	next if ( $_ eq "XF86XK_Calculater");
-
-	$_ = $keysymelements[2];
-	die "Internal error, was expecting \"0x*\", found: $_\n" if ( ! /^0x/ );
-
-	my $element = $keysymelements[1];
-	my $binding = $element;
-	$binding =~ s/^XF86XK_/GDK_KEY_/g;
-
-	printf OUT_GDKKEYSYMS "#define %s 0x%03x\n", $binding, hex($keysymelements[2]);
-}
-
-close IN_XF86KEYSYM;
-
-
-print OUT_GDKKEYSYMS<<EOF;
-EOF
-
-printf "We just finished converting keysymdef.h to gdkkeysyms.h\nThank you\n";
diff --git a/gdk/gdkkeysyms.h b/gdk/gdkkeysyms.h
index b4c6b6e35a85b4b76b495ea7212d7ad8816a8e37..c3041879e58d8195c559524d4af64edb0fd7aa4f 100644
--- a/gdk/gdkkeysyms.h
+++ b/gdk/gdkkeysyms.h
@@ -16,25 +16,18 @@
  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
  */
 
-
 /*
- * File auto-generated from script https://gitlab.gnome.org/GNOME/gtk/tree/main/gdk/gdkkeysyms-update.pl
- * using the input file
- * http://cgit.freedesktop.org/xorg/proto/x11proto/plain/keysymdef.h
+ * File auto-generated from script at:
+ * https://gitlab.gnome.org/GNOME/gtk/-/raw/main/gdk/gdk-keysyms-update.py?ref_type=heads&inline=false
+ *
+ * using the input files:
+ *  https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/raw/master/include/X11/keysymdef.h
  * and
- * http://cgit.freedesktop.org/xorg/proto/x11proto/plain/XF86keysym.h
- */
-
-/*
- * Modified by the GTK+ Team and others 1997-2007.  See the AUTHORS
- * file for a list of people on the GTK+ Team.  See the ChangeLog
- * files for a list of changes.  These files are distributed with
- * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
+ *  https://gitlab.freedesktop.org/xorg/proto/xorgproto/-/raw/master/include/X11/XF86keysym.h
  */
 
 #pragma once
 
-
 #define GDK_KEY_VoidSymbol 0xffffff
 #define GDK_KEY_BackSpace 0xff08
 #define GDK_KEY_Tab 0xff09
@@ -2151,6 +2144,7 @@
 #define GDK_KEY_KbdLightOnOff 0x1008ff04
 #define GDK_KEY_KbdBrightnessUp 0x1008ff05
 #define GDK_KEY_KbdBrightnessDown 0x1008ff06
+#define GDK_KEY_MonBrightnessCycle 0x1008ff07
 #define GDK_KEY_Standby 0x1008ff10
 #define GDK_KEY_AudioLowerVolume 0x1008ff11
 #define GDK_KEY_AudioMute 0x1008ff12
@@ -2306,6 +2300,8 @@
 #define GDK_KEY_WWAN 0x1008ffb4
 #define GDK_KEY_RFKill 0x1008ffb5
 #define GDK_KEY_AudioPreset 0x1008ffb6
+#define GDK_KEY_RotationLockToggle 0x1008ffb7
+#define GDK_KEY_FullScreen 0x1008ffb8
 #define GDK_KEY_Switch_VT_1 0x1008fe01
 #define GDK_KEY_Switch_VT_2 0x1008fe02
 #define GDK_KEY_Switch_VT_3 0x1008fe03
@@ -2324,3 +2320,161 @@
 #define GDK_KEY_Prev_VMode 0x1008fe23
 #define GDK_KEY_LogWindowTree 0x1008fe24
 #define GDK_KEY_LogGrabInfo 0x1008fe25
+#define GDK_KEY_BrightnessAuto 0x100810f4
+#define GDK_KEY_DisplayOff 0x100810f5
+#define GDK_KEY_Info 0x10081166
+#define GDK_KEY_AspectRatio 0x10081177
+#define GDK_KEY_DVD 0x10081185
+#define GDK_KEY_Audio 0x10081188
+#define GDK_KEY_ChannelUp 0x10081192
+#define GDK_KEY_ChannelDown 0x10081193
+#define GDK_KEY_VideoPhone 0x100811a0
+#define GDK_KEY_ZoomReset 0x100811a4
+#define GDK_KEY_Editor 0x100811a6
+#define GDK_KEY_GraphicsEditor 0x100811a8
+#define GDK_KEY_Presentation 0x100811a9
+#define GDK_KEY_Database 0x100811aa
+#define GDK_KEY_Voicemail 0x100811ac
+#define GDK_KEY_Addressbook 0x100811ad
+#define GDK_KEY_DisplayToggle 0x100811af
+#define GDK_KEY_SpellCheck 0x100811b0
+#define GDK_KEY_ContextMenu 0x100811b6
+#define GDK_KEY_MediaRepeat 0x100811b7
+#define GDK_KEY_10ChannelsUp 0x100811b8
+#define GDK_KEY_10ChannelsDown 0x100811b9
+#define GDK_KEY_Images 0x100811ba
+#define GDK_KEY_NotificationCenter 0x100811bc
+#define GDK_KEY_PickupPhone 0x100811bd
+#define GDK_KEY_HangupPhone 0x100811be
+#define GDK_KEY_Fn 0x100811d0
+#define GDK_KEY_Fn_Esc 0x100811d1
+#define GDK_KEY_FnRightShift 0x100811e5
+#define GDK_KEY_Numeric0 0x10081200
+#define GDK_KEY_Numeric1 0x10081201
+#define GDK_KEY_Numeric2 0x10081202
+#define GDK_KEY_Numeric3 0x10081203
+#define GDK_KEY_Numeric4 0x10081204
+#define GDK_KEY_Numeric5 0x10081205
+#define GDK_KEY_Numeric6 0x10081206
+#define GDK_KEY_Numeric7 0x10081207
+#define GDK_KEY_Numeric8 0x10081208
+#define GDK_KEY_Numeric9 0x10081209
+#define GDK_KEY_NumericStar 0x1008120a
+#define GDK_KEY_NumericPound 0x1008120b
+#define GDK_KEY_NumericA 0x1008120c
+#define GDK_KEY_NumericB 0x1008120d
+#define GDK_KEY_NumericC 0x1008120e
+#define GDK_KEY_NumericD 0x1008120f
+#define GDK_KEY_CameraFocus 0x10081210
+#define GDK_KEY_WPSButton 0x10081211
+#define GDK_KEY_CameraZoomIn 0x10081215
+#define GDK_KEY_CameraZoomOut 0x10081216
+#define GDK_KEY_CameraUp 0x10081217
+#define GDK_KEY_CameraDown 0x10081218
+#define GDK_KEY_CameraLeft 0x10081219
+#define GDK_KEY_CameraRight 0x1008121a
+#define GDK_KEY_AttendantOn 0x1008121b
+#define GDK_KEY_AttendantOff 0x1008121c
+#define GDK_KEY_AttendantToggle 0x1008121d
+#define GDK_KEY_LightsToggle 0x1008121e
+#define GDK_KEY_ALSToggle 0x10081230
+#define GDK_KEY_RefreshRateToggle 0x10081232
+#define GDK_KEY_Buttonconfig 0x10081240
+#define GDK_KEY_Taskmanager 0x10081241
+#define GDK_KEY_Journal 0x10081242
+#define GDK_KEY_ControlPanel 0x10081243
+#define GDK_KEY_AppSelect 0x10081244
+#define GDK_KEY_Screensaver 0x10081245
+#define GDK_KEY_VoiceCommand 0x10081246
+#define GDK_KEY_Assistant 0x10081247
+#define GDK_KEY_EmojiPicker 0x10081249
+#define GDK_KEY_Dictate 0x1008124a
+#define GDK_KEY_CameraAccessEnable 0x1008124b
+#define GDK_KEY_CameraAccessDisable 0x1008124c
+#define GDK_KEY_CameraAccessToggle 0x1008124d
+#define GDK_KEY_Accessibility 0x1008124e
+#define GDK_KEY_DoNotDisturb 0x1008124f
+#define GDK_KEY_BrightnessMin 0x10081250
+#define GDK_KEY_BrightnessMax 0x10081251
+#define GDK_KEY_KbdInputAssistPrev 0x10081260
+#define GDK_KEY_KbdInputAssistNext 0x10081261
+#define GDK_KEY_KbdInputAssistPrevgroup 0x10081262
+#define GDK_KEY_KbdInputAssistNextgroup 0x10081263
+#define GDK_KEY_KbdInputAssistAccept 0x10081264
+#define GDK_KEY_KbdInputAssistCancel 0x10081265
+#define GDK_KEY_RightUp 0x10081266
+#define GDK_KEY_RightDown 0x10081267
+#define GDK_KEY_LeftUp 0x10081268
+#define GDK_KEY_LeftDown 0x10081269
+#define GDK_KEY_RootMenu 0x1008126a
+#define GDK_KEY_MediaTopMenu 0x1008126b
+#define GDK_KEY_Numeric11 0x1008126c
+#define GDK_KEY_Numeric12 0x1008126d
+#define GDK_KEY_AudioDesc 0x1008126e
+#define GDK_KEY_3DMode 0x1008126f
+#define GDK_KEY_NextFavorite 0x10081270
+#define GDK_KEY_StopRecord 0x10081271
+#define GDK_KEY_PauseRecord 0x10081272
+#define GDK_KEY_VOD 0x10081273
+#define GDK_KEY_Unmute 0x10081274
+#define GDK_KEY_FastReverse 0x10081275
+#define GDK_KEY_SlowReverse 0x10081276
+#define GDK_KEY_Data 0x10081277
+#define GDK_KEY_OnScreenKeyboard 0x10081278
+#define GDK_KEY_PrivacyScreenToggle 0x10081279
+#define GDK_KEY_SelectiveScreenshot 0x1008127a
+#define GDK_KEY_NextElement 0x1008127b
+#define GDK_KEY_PreviousElement 0x1008127c
+#define GDK_KEY_AutopilotEngageToggle 0x1008127d
+#define GDK_KEY_MarkWaypoint 0x1008127e
+#define GDK_KEY_Sos 0x1008127f
+#define GDK_KEY_NavChart 0x10081280
+#define GDK_KEY_FishingChart 0x10081281
+#define GDK_KEY_SingleRangeRadar 0x10081282
+#define GDK_KEY_DualRangeRadar 0x10081283
+#define GDK_KEY_RadarOverlay 0x10081284
+#define GDK_KEY_TraditionalSonar 0x10081285
+#define GDK_KEY_ClearvuSonar 0x10081286
+#define GDK_KEY_SidevuSonar 0x10081287
+#define GDK_KEY_NavInfo 0x10081288
+#define GDK_KEY_Macro1 0x10081290
+#define GDK_KEY_Macro2 0x10081291
+#define GDK_KEY_Macro3 0x10081292
+#define GDK_KEY_Macro4 0x10081293
+#define GDK_KEY_Macro5 0x10081294
+#define GDK_KEY_Macro6 0x10081295
+#define GDK_KEY_Macro7 0x10081296
+#define GDK_KEY_Macro8 0x10081297
+#define GDK_KEY_Macro9 0x10081298
+#define GDK_KEY_Macro10 0x10081299
+#define GDK_KEY_Macro11 0x1008129a
+#define GDK_KEY_Macro12 0x1008129b
+#define GDK_KEY_Macro13 0x1008129c
+#define GDK_KEY_Macro14 0x1008129d
+#define GDK_KEY_Macro15 0x1008129e
+#define GDK_KEY_Macro16 0x1008129f
+#define GDK_KEY_Macro17 0x100812a0
+#define GDK_KEY_Macro18 0x100812a1
+#define GDK_KEY_Macro19 0x100812a2
+#define GDK_KEY_Macro20 0x100812a3
+#define GDK_KEY_Macro21 0x100812a4
+#define GDK_KEY_Macro22 0x100812a5
+#define GDK_KEY_Macro23 0x100812a6
+#define GDK_KEY_Macro24 0x100812a7
+#define GDK_KEY_Macro25 0x100812a8
+#define GDK_KEY_Macro26 0x100812a9
+#define GDK_KEY_Macro27 0x100812aa
+#define GDK_KEY_Macro28 0x100812ab
+#define GDK_KEY_Macro29 0x100812ac
+#define GDK_KEY_Macro30 0x100812ad
+#define GDK_KEY_MacroRecordStart 0x100812b0
+#define GDK_KEY_MacroRecordStop 0x100812b1
+#define GDK_KEY_MacroPresetCycle 0x100812b2
+#define GDK_KEY_MacroPreset1 0x100812b3
+#define GDK_KEY_MacroPreset2 0x100812b4
+#define GDK_KEY_MacroPreset3 0x100812b5
+#define GDK_KEY_KbdLcdMenu1 0x100812b8
+#define GDK_KEY_KbdLcdMenu2 0x100812b9
+#define GDK_KEY_KbdLcdMenu3 0x100812ba
+#define GDK_KEY_KbdLcdMenu4 0x100812bb
+#define GDK_KEY_KbdLcdMenu5 0x100812bc
diff --git a/gdk/gdkkeyuni.c b/gdk/gdkkeyuni.c
index 5736aed2255d2c904b98af69afd695c2498ccb78..b3b6aa6ff14225f9b54ef304d8f75dd2b3f5e8f9 100644
--- a/gdk/gdkkeyuni.c
+++ b/gdk/gdkkeyuni.c
@@ -875,12 +875,12 @@ static const struct {
  * gdk_keyval_to_unicode:
  * @keyval: a GDK key symbol
  *
- * Convert from a GDK key symbol to the corresponding Unicode
+ * Converts from a GDK key symbol to the corresponding Unicode
  * character.
  *
  * Note that the conversion does not take the current locale
  * into consideration, which might be expected for particular
- * keyvals, such as %GDK_KEY_KP_Decimal.
+ * keyvals, such as `GDK_KEY_KP_Decimal`.
  *
  * Returns: the corresponding unicode character, or 0 if there
  *   is no corresponding character.
@@ -1699,10 +1699,10 @@ static const struct {
  * gdk_unicode_to_keyval:
  * @wc: a Unicode character
  *
- * Convert from a Unicode character to a key symbol.
+ * Converts from a Unicode character to a key symbol.
  *
- * Returns: the corresponding GDK key symbol, if one exists.
- *   or, if there is no corresponding symbol, wc | 0x01000000
+ * Returns: the corresponding GDK key symbol, if one exists,
+ *   or, if there is no corresponding symbol, `wc | 0x01000000`
  */
 guint
 gdk_unicode_to_keyval (guint32 wc)
@@ -1728,7 +1728,7 @@ gdk_unicode_to_keyval (guint32 wc)
       return gdk_unicode_to_keysym_tab[mid].keysym;
     }
   }
-  
+
   /*
    * No matching keysym value found, return Unicode value plus 0x01000000
    * (a convention introduced in the UTF-8 work on xterm).
diff --git a/gdk/gdkmemorytexturebuilder.c b/gdk/gdkmemorytexturebuilder.c
index 424b767180cf50147a0a0241da4a972996decd3f..576b906a70ab0ba655a5f90349e49bbd8b89f21a 100644
--- a/gdk/gdkmemorytexturebuilder.c
+++ b/gdk/gdkmemorytexturebuilder.c
@@ -50,8 +50,8 @@ struct _GdkMemoryTextureBuilderClass
 /**
  * GdkMemoryTextureBuilder:
  *
- * `GdkMemoryTextureBuilder` is a builder used to construct [class@Gdk.Texture] objects
- * from system memory provided via [struct@GLib.Bytes].
+ * Constructs [class@Gdk.Texture] objects from system memory provided
+ * via [struct@GLib.Bytes].
  *
  * The operation is quite simple: Create a texture builder, set all the necessary
  * properties - keep in mind that the properties [property@Gdk.MemoryTextureBuilder:bytes],
diff --git a/gdk/gdkmonitor.c b/gdk/gdkmonitor.c
index 5acddfcada6da678281ed17fb16358d00d4240f8..793aa92da2aa2967ca8127ccff579047dd91fac9 100644
--- a/gdk/gdkmonitor.c
+++ b/gdk/gdkmonitor.c
@@ -31,8 +31,7 @@
 /**
  * GdkMonitor:
  *
- * `GdkMonitor` objects represent the individual outputs that are
- * associated with a `GdkDisplay`.
+ * Represents the individual outputs that are associated with a `GdkDisplay`.
  *
  * `GdkDisplay` keeps a `GListModel` to enumerate and monitor
  * monitors with [method@Gdk.Display.get_monitors]. You can use
diff --git a/gdk/gdkpaintable.c b/gdk/gdkpaintable.c
index 8a3149b4539345b6fd63b06667e978423540567c..ebdb4db07774e557a3362fdef1b4dfc2a7af7007 100644
--- a/gdk/gdkpaintable.c
+++ b/gdk/gdkpaintable.c
@@ -38,8 +38,7 @@ GdkPaintable *  gtk_snapshot_free_to_paintable          (GdkSnapshot
 /**
  * GdkPaintable:
  *
- * `GdkPaintable` is a simple interface used by GTK to represent content that
- * can be painted.
+ * An interface for content that can be painted.
  *
  * The content of a `GdkPaintable` can be painted anywhere at any size
  * without requiring any sort of layout. The interface is inspired by
diff --git a/gdk/gdkpopup.c b/gdk/gdkpopup.c
index 7df023f9c160fc1dc60561b6bd338c63aae2fa03..e07d0e18c51673b8de3e9736f30f8356ad22877b 100644
--- a/gdk/gdkpopup.c
+++ b/gdk/gdkpopup.c
@@ -26,7 +26,7 @@
 /**
  * GdkPopup:
  *
- * A `GdkPopup` is a surface that is attached to another surface.
+ * A surface that is attached to another surface.
  *
  * The `GdkPopup` is positioned relative to its parent surface.
  *
diff --git a/gdk/gdkpopuplayout.c b/gdk/gdkpopuplayout.c
index a5a098d3120312b717fe3a8c51d0230cc7f51f9b..39a2de6fea661aa4ec81686b893487ecaf108110 100644
--- a/gdk/gdkpopuplayout.c
+++ b/gdk/gdkpopuplayout.c
@@ -26,8 +26,8 @@
 /**
  * GdkPopupLayout:
  *
- * The `GdkPopupLayout` struct contains information that is
- * necessary position a [iface@Gdk.Popup] relative to its parent.
+ * Contains information that is necessary position a [iface@Gdk.Popup]
+ * relative to its parent.
  *
  * The positioning requires a negotiation with the windowing system,
  * since it depends on external constraints, such as the position of
diff --git a/gdk/gdkrectangle.c b/gdk/gdkrectangle.c
index 32f7e86e201f710d75feaa1a2553f6e2938fe385..5c820ac616a03b1d588861acc3bef863a61db8e6 100644
--- a/gdk/gdkrectangle.c
+++ b/gdk/gdkrectangle.c
@@ -35,7 +35,7 @@
  * @width: the width of the rectangle
  * @height: the height of the rectangle
  *
- * A `GdkRectangle` data type for representing rectangles.
+ * Represents a rectangle.
  *
  * `GdkRectangle` is identical to `cairo_rectangle_t`. Together with Cairo’s
  * `cairo_region_t` data type, these are the central types for representing
diff --git a/gdk/gdkrgba.c b/gdk/gdkrgba.c
index ecaab93644b21eadf95138efc4974e6285fbb216..923016a98afec9c53189b43363d4b019bca56cf2 100644
--- a/gdk/gdkrgba.c
+++ b/gdk/gdkrgba.c
@@ -43,8 +43,7 @@ G_DEFINE_BOXED_TYPE (GdkRGBA, gdk_rgba,
  * @alpha: The opacity of the color from 0.0 for completely translucent to
  *   1.0 for opaque
  *
- * A `GdkRGBA` is used to represent a color, in a way that is compatible
- * with cairo’s notion of color.
+ * Represents a color, in a way that is compatible with cairo’s notion of color.
  *
  * `GdkRGBA` is a convenient way to pass colors around. It’s based on
  * cairo’s way to deal with colors and mirrors its behavior. All values
diff --git a/gdk/gdkseat.c b/gdk/gdkseat.c
index d9d0589564b4e4ef8bedac3562b49779c360dfab..cad4d72a5b631dae5626efb319be2a97ed978d25 100644
--- a/gdk/gdkseat.c
+++ b/gdk/gdkseat.c
@@ -30,8 +30,7 @@
 /**
  * GdkSeat:
  *
- * The `GdkSeat` object represents a collection of input devices
- * that belong to a user.
+ * Represents a collection of input devices that belong to a user.
  */
 
 typedef struct _GdkSeatPrivate GdkSeatPrivate;
diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c
index 13f1d4554a92756948c85ca1dd760295e47c03de..1ea60a9fa1d73cc1f875246923d8f156e426baa3 100644
--- a/gdk/gdksurface.c
+++ b/gdk/gdksurface.c
@@ -56,7 +56,7 @@
 /**
  * GdkSurface:
  *
- * A `GdkSurface` is a rectangular region on the screen.
+ * Represents a rectangular region on the screen.
  *
  * It’s a low-level object, used to implement high-level objects
  * such as [GtkWindow](../gtk4/class.Window.html).
diff --git a/gdk/gdktexture.c b/gdk/gdktexture.c
index 876d09553e75ba988d2ce4b63793ddee1cd7e445..9bd36e2f5131e545ec496492b99248bfcefb0514 100644
--- a/gdk/gdktexture.c
+++ b/gdk/gdktexture.c
@@ -19,7 +19,7 @@
 /**
  * GdkTexture:
  *
- * `GdkTexture` is the basic element used to refer to pixel data.
+ * Refers to pixel data in various forms.
  *
  * It is primarily meant for pixel data that will not change over
  * multiple frames, and will be used for a long time.
diff --git a/gdk/gdktexturedownloader.c b/gdk/gdktexturedownloader.c
index aec4e21ba439158b50c3452c49455b261aceeba0..0334fcc96467fe39c0eb9030c0b60172a4c29e28 100644
--- a/gdk/gdktexturedownloader.c
+++ b/gdk/gdktexturedownloader.c
@@ -18,8 +18,7 @@
 /**
  * GdkTextureDownloader:
  *
- * The `GdkTextureDownloader` is used to download the contents of a
- * [class@Gdk.Texture].
+ * Used to download the contents of a [class@Gdk.Texture].
  *
  * It is intended to be created as a short-term object for a single download,
  * but can be used for multiple downloads of different textures or with different
diff --git a/gdk/gdktoplevel.c b/gdk/gdktoplevel.c
index 3e47560a766b8d40b249b17d9f6e9c8a425b7153..62260a6c2008df5c5560b43c4e5bec9537c1c1d5 100644
--- a/gdk/gdktoplevel.c
+++ b/gdk/gdktoplevel.c
@@ -32,7 +32,7 @@
 /**
  * GdkToplevel:
  *
- * A `GdkToplevel` is a freestanding toplevel surface.
+ * A freestanding toplevel surface.
  *
  * The `GdkToplevel` interface provides useful APIs for interacting with
  * the windowing system, such as controlling maximization and size of the
diff --git a/gdk/gdktoplevellayout.c b/gdk/gdktoplevellayout.c
index 64f648c476e5f2ec9fdcba974acd8a38fdba9c13..f992937b7c2f603ca5bcb2e56f5b43073b5b9bc6 100644
--- a/gdk/gdktoplevellayout.c
+++ b/gdk/gdktoplevellayout.c
@@ -25,8 +25,8 @@
 /**
  * GdkToplevelLayout:
  *
- * The `GdkToplevelLayout` struct contains information that
- * is necessary to present a sovereign window on screen.
+ * Contains information that is necessary to present a sovereign
+ * window on screen.
  *
  * The `GdkToplevelLayout` struct is necessary for using
  * [method@Gdk.Toplevel.present].
diff --git a/gdk/gdktoplevelsize.c b/gdk/gdktoplevelsize.c
index 4672323723d8f2bf321e8dea4fad8cc4f3d5ff91..7d118159c71f232031f1e24d373dfdedf23cf4b1 100644
--- a/gdk/gdktoplevelsize.c
+++ b/gdk/gdktoplevelsize.c
@@ -23,8 +23,7 @@
 /**
  * GdkToplevelSize:
  *
- * The `GdkToplevelSize` struct contains information that is useful
- * to compute the size of a toplevel.
+ * Contains information that is useful to compute the size of a toplevel.
  */
 
 G_DEFINE_POINTER_TYPE (GdkToplevelSize, gdk_toplevel_size)
diff --git a/gdk/gdktypes.h b/gdk/gdktypes.h
index 1d05dafb35c45a92cd7ce241cd8b16d3ec95cb0d..9fdb4d1b5b7175e05f0bcb7aa9a8f71281a18d7a 100644
--- a/gdk/gdktypes.h
+++ b/gdk/gdktypes.h
@@ -157,7 +157,7 @@ typedef struct _GdkKeymapKey GdkKeymapKey;
  *   letter at level 0, and an uppercase letter at level 1, though only the
  *   uppercase letter is printed.
  *
- * A `GdkKeymapKey` is a hardware key that can be mapped to a keyval.
+ * Represents a hardware key that can be mapped to a keyval.
  */
 struct _GdkKeymapKey
 {
diff --git a/gdk/gdkvulkancontext.c b/gdk/gdkvulkancontext.c
index 3b69ed195e9ad370a185c33a61306b91b4896c04..c2b8fb2842d19a416ae07860dc31ef814e4b29b7 100644
--- a/gdk/gdkvulkancontext.c
+++ b/gdk/gdkvulkancontext.c
@@ -48,8 +48,7 @@ const GdkDebugKey gdk_vulkan_feature_keys[] = {
 /**
  * GdkVulkanContext:
  *
- * `GdkVulkanContext` is an object representing the platform-specific
- * Vulkan draw context.
+ * Represents the platform-specific Vulkan draw context.
  *
  * `GdkVulkanContext`s are created for a surface using
  * [method@Gdk.Surface.create_vulkan_context], and the context will match
@@ -1945,11 +1944,11 @@ gdk_vulkan_init_dmabuf (GdkDisplay *display)
       if (vk_format == VK_FORMAT_UNDEFINED)
         continue;
 
-      modifier_props.drmFormatModifierCount = sizeof (modifier_list);
+      modifier_props.drmFormatModifierCount = G_N_ELEMENTS (modifier_list);
       vkGetPhysicalDeviceFormatProperties2 (display->vk_physical_device,
                                             vk_format,
                                             &props);
-      g_warn_if_fail (modifier_props.drmFormatModifierCount < sizeof (modifier_list));
+      g_warn_if_fail (modifier_props.drmFormatModifierCount < G_N_ELEMENTS (modifier_list));
       for (j = 0; j < modifier_props.drmFormatModifierCount; j++)
         {
           gboolean advertise = modifier_list[j].drmFormatModifier != DRM_FORMAT_MOD_LINEAR;
diff --git a/gdk/macos/GdkMacosWindow.c b/gdk/macos/GdkMacosWindow.c
index e0f72ae0ebc6ad4e3efd3b651a15ab1cd07f9a1e..c2d6f8f664e07cf5134a550c4413a318a1e1dcc0 100644
--- a/gdk/macos/GdkMacosWindow.c
+++ b/gdk/macos/GdkMacosWindow.c
@@ -734,6 +734,9 @@ static Class _contentViewClass = nil;
 {
   inFullscreenTransition = NO;
   initialPositionKnown = NO;
+
+  [self updateToolbarAppearence];
+
   [self checkSendEnterNotify];
 }
 
@@ -746,6 +749,9 @@ static Class _contentViewClass = nil;
 {
   inFullscreenTransition = NO;
   initialPositionKnown = NO;
+
+  [self updateToolbarAppearence];
+
   [self checkSendEnterNotify];
 }
 
@@ -776,20 +782,57 @@ static Class _contentViewClass = nil;
   if (decorated)
     {
       style_mask &= ~NSWindowStyleMaskFullSizeContentView;
-      [self setTitleVisibility:NSWindowTitleVisible];
     }
   else
     {
       style_mask |= NSWindowStyleMaskFullSizeContentView;
-      [self setTitleVisibility:NSWindowTitleHidden];
     }
 
-  [self setTitlebarAppearsTransparent:!decorated];
-  [[self standardWindowButton:NSWindowCloseButton] setHidden:!decorated];
-  [[self standardWindowButton:NSWindowMiniaturizeButton] setHidden:!decorated];
-  [[self standardWindowButton:NSWindowZoomButton] setHidden:!decorated];
-
   [self setStyleMask:style_mask];
+
+  [self updateToolbarAppearence];
+}
+
+-(void)setShowStandardWindowButtons:(BOOL)show
+{
+  _showStandardWindowButtons = show;
+  [self updateToolbarAppearence];
+}
+
+/* updateToolbarAppearence:
+ * Update the toolbar appearence based on the following criteria:
+ *
+ * 1. The window is used Client Side Decorations (style mask is set)
+ * 2. The window has native window buttons enabled
+ * 3. The window is in fullscreen mode
+ */
+-(void)updateToolbarAppearence
+{
+  NSWindowStyleMask style_mask = [self styleMask];
+  BOOL is_fullscreen = (style_mask & NSWindowStyleMaskFullScreen) != 0;
+  BOOL is_csd = !is_fullscreen && (style_mask & NSWindowStyleMaskFullSizeContentView) != 0;
+  BOOL hidden = is_csd && !_showStandardWindowButtons;
+
+  /* By assigning a toolbar, the window controls are moved a bit more inwards,
+   * In line with how toolbars look in macOS apps.
+   * I haven't found a better way. Unfortunately we have to be careful not to
+   * update the toolbar during a fullscreen transition.
+   */
+  if (is_csd && _showStandardWindowButtons && [self toolbar] == nil)
+    {
+      NSToolbar *toolbar = [[NSToolbar alloc] init];
+      [self setToolbar:toolbar];
+      [toolbar release];
+    }
+  else if (!is_csd && [self toolbar] != nil)
+    [self setToolbar:nil];
+
+  [self setTitleVisibility:is_csd ? NSWindowTitleHidden : NSWindowTitleVisible];
+  [self setTitlebarAppearsTransparent:is_csd];
+
+  [[self standardWindowButton:NSWindowCloseButton] setHidden:hidden];
+  [[self standardWindowButton:NSWindowMiniaturizeButton] setHidden:hidden];
+  [[self standardWindowButton:NSWindowZoomButton] setHidden:hidden];
 }
 
 -(GdkMacosSurface *)gdkSurface
diff --git a/gdk/macos/GdkMacosWindow.h b/gdk/macos/GdkMacosWindow.h
index a52a184f814990772c62662d1a27f85289c3cb5a..9bd3d8328f308ed68b108d0ce1d28d34e9c948c9 100644
--- a/gdk/macos/GdkMacosWindow.h
+++ b/gdk/macos/GdkMacosWindow.h
@@ -30,7 +30,7 @@
 #include "gdkmacossurface.h"
 #include "edgesnapping.h"
 
-#define GDK_IS_MACOS_WINDOW(obj) ([obj isKindOfClass:[GdkMacosWindow class]])
+#define GDK_IS_MACOS_WINDOW(obj) (obj != nil && [obj isKindOfClass:[GdkMacosWindow class]])
 
 @interface GdkMacosWindow : NSWindow <NSDraggingSource, NSDraggingDestination> {
   GdkMacosSurface *gdk_surface;
@@ -52,6 +52,8 @@
   BOOL             inFullscreenTransition;
 }
 
+@property (nonatomic) BOOL showStandardWindowButtons;
+
 +(void)setContentViewClass:(Class)newViewClass;
 
 -(void)beginManualMove;
diff --git a/gdk/macos/gdkmacos.h b/gdk/macos/gdkmacos.h
index bee9aa981241e5a101c05c5dced6ade01e4207e6..1fcd58d35680b39f90b939ffbd5d043715c554f6 100644
--- a/gdk/macos/gdkmacos.h
+++ b/gdk/macos/gdkmacos.h
@@ -19,6 +19,8 @@
 
 #pragma once
 
+#define __GDKMACOS_H_INSIDE__
+
 #include <gdk/gdk.h>
 
 #include "gdkmacosdevice.h"
@@ -28,3 +30,4 @@
 #include "gdkmacosmonitor.h"
 #include "gdkmacossurface.h"
 
+#undef __GDKMACOS_H_INSIDE__
diff --git a/gdk/macos/gdkmacosdisplay-settings.c b/gdk/macos/gdkmacosdisplay-settings.c
index 53d6df0672a7c298587116457088c3932d00bcd3..c9ca6bf2f4eeec19ee12c51e71ee7c9e724bde9f 100644
--- a/gdk/macos/gdkmacosdisplay-settings.c
+++ b/gdk/macos/gdkmacosdisplay-settings.c
@@ -60,7 +60,7 @@ _gdk_macos_settings_load (GdkMacosSettings *settings)
 
   settings->shell_shows_desktop = TRUE;
   settings->shell_shows_menubar = TRUE;
-  settings->enable_animations = TRUE;
+  settings->enable_animations = [[NSWorkspace sharedWorkspace] accessibilityDisplayShouldReduceMotion] == NO;
   settings->xft_dpi = 72 * 1024;
 
   ival = [defaults integerForKey:@"NSTextInsertionPointBlinkPeriod"];
diff --git a/gdk/macos/gdkmacosdisplay-translate.c b/gdk/macos/gdkmacosdisplay-translate.c
index 10a02c83cf209fd4a6eaa9b1484c3b4dfe464671..e6e2ad42ea17ec2d8bafea121822bbdf4c2424a4 100644
--- a/gdk/macos/gdkmacosdisplay-translate.c
+++ b/gdk/macos/gdkmacosdisplay-translate.c
@@ -166,6 +166,17 @@ _gdk_macos_display_get_current_keyboard_modifiers (GdkMacosDisplay *self)
   return get_keyboard_modifiers_from_ns_flags ([NSEvent modifierFlags]);
 }
 
+static gboolean
+over_native_window_buttons (GdkMacosWindow *window, int x, int y)
+{
+  NSPoint pos = NSMakePoint(x, y);
+
+  return [window showStandardWindowButtons] &&
+         (NSPointInRect(pos, [[window standardWindowButton:NSWindowCloseButton] frame]) ||
+          NSPointInRect(pos, [[window standardWindowButton:NSWindowMiniaturizeButton] frame]) ||
+          NSPointInRect(pos, [[window standardWindowButton:NSWindowZoomButton] frame]));
+}
+
 static GdkEvent *
 fill_button_event (GdkMacosDisplay *display,
                    GdkMacosSurface *surface,
@@ -218,6 +229,17 @@ fill_button_event (GdkMacosDisplay *display,
        (input_region && !cairo_region_contains_point (input_region, x, y))))
     return NULL;
 
+  /* Ignore button press events that happen on a native window button.
+   * For those events we do not receive a button release event which leaves
+   * our app in a "grabbed" state.
+   */
+  if (type == GDK_BUTTON_PRESS &&
+      over_native_window_buttons ((GdkMacosWindow *) _gdk_macos_surface_get_native (surface), x, y))
+    {
+      GDK_DEBUG (EVENTS, "Ignoring button press over native controls (%d, %d)", x, y);
+      return NULL;
+    }
+
   if (([nsevent subtype] == NSEventSubtypeTabletPoint) &&
       _gdk_macos_seat_get_tablet (GDK_MACOS_SEAT (seat), &pointer, &tool))
     axes = _gdk_macos_seat_get_tablet_axes_from_nsevent (GDK_MACOS_SEAT (seat), nsevent);
diff --git a/gdk/macos/gdkmacoskeymap.c b/gdk/macos/gdkmacoskeymap.c
index a286c093bb01b33c889dc24acc1101a12e6200a7..b6e1e1c935f5b716f31e58981abdc3fb76fd19ff 100644
--- a/gdk/macos/gdkmacoskeymap.c
+++ b/gdk/macos/gdkmacoskeymap.c
@@ -115,7 +115,11 @@ const static struct {
   { 105, GDK_KEY_F13 },
   { 107, GDK_KEY_F14 },
   { 113, GDK_KEY_F15 },
-  { 106, GDK_KEY_F16 }
+  { 106, GDK_KEY_F16 },
+  {  64, GDK_KEY_F17 },
+  {  79, GDK_KEY_F18 },
+  {  80, GDK_KEY_F19 },
+  {  90, GDK_KEY_F20 }
 };
 
 const static struct {
diff --git a/gdk/wayland/gdkdevice-wayland-private.h b/gdk/wayland/gdkdevice-wayland-private.h
index 9075a094301a5ead5059c03fac2aabf8950dd944..23ba34ff738c8ce5878c78df58f84e1d1a26fa3f 100644
--- a/gdk/wayland/gdkdevice-wayland-private.h
+++ b/gdk/wayland/gdkdevice-wayland-private.h
@@ -65,12 +65,16 @@ struct _GdkWaylandPointerData {
   struct wl_surface *pointer_surface;
   struct wp_viewport *pointer_surface_viewport;
   guint cursor_is_default: 1;
+  guint has_cursor_surface : 1;
   GdkCursor *cursor;
   guint cursor_timeout_id;
   guint cursor_image_index;
   guint cursor_image_delay;
   guint touchpad_event_sequence;
 
+  int32_t cursor_hotspot_x;
+  int32_t cursor_hotspot_y;
+
   GdkFractionalScale preferred_scale;
   struct wp_fractional_scale_v1 *fractional_scale;
 
diff --git a/gdk/wayland/gdkdevice-wayland.c b/gdk/wayland/gdkdevice-wayland.c
index 973c55d95245f098e2ee62bdc155a6a129055dbc..7dcad01ff42b2f1b554b2c022cddc24556d54bbb 100644
--- a/gdk/wayland/gdkdevice-wayland.c
+++ b/gdk/wayland/gdkdevice-wayland.c
@@ -285,30 +285,14 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device)
       return G_SOURCE_REMOVE;
     }
 
-  if (tablet)
-    {
-      if (!tablet->current_tool)
-        {
-          pointer->cursor_timeout_id = 0;
-          return G_SOURCE_REMOVE;
-        }
-
-      zwp_tablet_tool_v2_set_cursor (tablet->current_tool->wp_tablet_tool,
-                                     pointer->enter_serial,
-                                     pointer->pointer_surface,
-                                     x, y);
-    }
-  else if (seat->wl_pointer)
+  if (pointer->has_cursor_surface)
     {
-      wl_pointer_set_cursor (seat->wl_pointer,
-                             pointer->enter_serial,
-                             pointer->pointer_surface,
-                             x, y);
-    }
-  else
-    {
-      pointer->cursor_timeout_id = 0;
-      return G_SOURCE_REMOVE;
+      /* We already have the surface attached to the cursor, change the
+       * offset to adapt to the new buffer.
+       */
+      wl_surface_offset (pointer->pointer_surface,
+                         pointer->cursor_hotspot_x - x,
+                         pointer->cursor_hotspot_y - y);
     }
 
   if (buffer)
@@ -332,6 +316,40 @@ gdk_wayland_device_update_surface_cursor (GdkDevice *device)
       wl_surface_commit (pointer->pointer_surface);
     }
 
+  if (!pointer->has_cursor_surface)
+    {
+      if (tablet)
+        {
+          if (!tablet->current_tool)
+            {
+              pointer->cursor_timeout_id = 0;
+              return G_SOURCE_REMOVE;
+            }
+
+          zwp_tablet_tool_v2_set_cursor (tablet->current_tool->wp_tablet_tool,
+                                         pointer->enter_serial,
+                                         pointer->pointer_surface,
+                                         x, y);
+        }
+      else if (seat->wl_pointer)
+        {
+          wl_pointer_set_cursor (seat->wl_pointer,
+                                 pointer->enter_serial,
+                                 pointer->pointer_surface,
+                                 x, y);
+        }
+      else
+        {
+          pointer->cursor_timeout_id = 0;
+          return G_SOURCE_REMOVE;
+        }
+
+      pointer->has_cursor_surface = TRUE;
+    }
+
+  pointer->cursor_hotspot_x = x;
+  pointer->cursor_hotspot_y = y;
+
   next_image_index =
     _gdk_wayland_cursor_get_next_image_index (GDK_WAYLAND_DISPLAY (seat->display),
                                               pointer->cursor,
diff --git a/gdk/wayland/gdkdisplay-wayland.c b/gdk/wayland/gdkdisplay-wayland.c
index bdc74677231c4b3ef4bbba18f7c8f0a2c306cffe..adb32c32768738180570cd4c7a56ff2a36d99805 100644
--- a/gdk/wayland/gdkdisplay-wayland.c
+++ b/gdk/wayland/gdkdisplay-wayland.c
@@ -24,14 +24,17 @@
 #include <errno.h>
 #include <unistd.h>
 #include <fcntl.h>
+
+#ifdef HAVE_SYS_SYSMACROS_H
 #include <sys/sysmacros.h>
+#endif
 
 #ifdef HAVE_LINUX_MEMFD_H
 #include <linux/memfd.h>
+#include <sys/syscall.h>
 #endif
 
 #include <sys/mman.h>
-#include <sys/syscall.h>
 
 #include <glib.h>
 #include <gio/gio.h>
@@ -62,7 +65,7 @@
 #include <wayland/server-decoration-client-protocol.h>
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
 #include "presentation-time-client-protocol.h"
-#include "xx-color-management-v4-client-protocol.h"
+#include "color-management-v1-client-protocol.h"
 
 #include "wm-button-layout-translation.h"
 
@@ -536,7 +539,7 @@ gdk_registry_handle_global (void               *data,
                           &wp_presentation_interface,
                           MIN (version, 1));
     }
-  else if (strcmp (interface, xx_color_manager_v4_interface.name) == 0 &&
+  else if (strcmp (interface, wp_color_manager_v1_interface.name) == 0 &&
            gdk_has_feature (GDK_FEATURE_COLOR_MANAGEMENT))
     {
       display_wayland->color = gdk_wayland_color_new (display_wayland, registry, id, version);
diff --git a/gdk/wayland/gdkdmabuf-wayland.c b/gdk/wayland/gdkdmabuf-wayland.c
index 15d2666259c5fa7d834abad714911c78ed1a84e1..570bad71ca15d9a63e3e670fffc8f82cd14300df 100644
--- a/gdk/wayland/gdkdmabuf-wayland.c
+++ b/gdk/wayland/gdkdmabuf-wayland.c
@@ -9,7 +9,10 @@
 
 #include <fcntl.h>
 #include <sys/mman.h>
+
+#ifdef HAVE_SYS_SYSMACROS_H
 #include <sys/sysmacros.h>
+#endif
 
 #include "linux-dmabuf-unstable-v1-client-protocol.h"
 
@@ -52,19 +55,24 @@ update_dmabuf_formats (DmabufFormatsInfo *info)
 
   GDK_DISPLAY_DEBUG (info->display, MISC,
                      "dmabuf format table (%" G_GSIZE_FORMAT " entries)", info->n_dmabuf_formats);
+
+#ifdef HAVE_SYS_SYSMACROS_H
   GDK_DISPLAY_DEBUG (info->display, MISC,
                      "dmabuf main device: %u %u",
                      major (formats->main_device),
                      minor (formats->main_device));
+#endif
 
   for (gsize i = 0; i < formats->tranches->len; i++)
     {
       DmabufTranche *tranche = g_ptr_array_index (formats->tranches, i);
 
+#ifdef HAVE_SYS_SYSMACROS_H
       GDK_DISPLAY_DEBUG (info->display, MISC,
                          "dmabuf tranche target device: %u %u",
                          major (tranche->target_device),
                          minor (tranche->target_device));
+#endif
 
       GDK_DISPLAY_DEBUG (info->display, MISC,
                          "dmabuf%s tranche (%" G_GSIZE_FORMAT " entries):",
diff --git a/gdk/wayland/gdkseat-wayland.c b/gdk/wayland/gdkseat-wayland.c
index 9ca0c2b141ad04dcfe4019c23244d2f10e9415c7..21e8cf56fd5aad56d6368cdfa8567fbc95c9651d 100644
--- a/gdk/wayland/gdkseat-wayland.c
+++ b/gdk/wayland/gdkseat-wayland.c
@@ -748,6 +748,8 @@ pointer_handle_leave (void              *data,
   if (seat->cursor)
     gdk_wayland_seat_stop_cursor_animation (seat, &seat->pointer_info);
 
+  seat->pointer_info.has_cursor_surface = FALSE;
+
   if (wl_seat_get_version (seat->wl_seat) < WL_POINTER_HAS_FRAME)
     gdk_wayland_seat_flush_frame_event (seat);
 }
@@ -2845,6 +2847,7 @@ tablet_tool_handle_proximity_out (void                      *data,
 
   g_object_unref (tablet->pointer_info.focus);
   tablet->pointer_info.focus = NULL;
+  tablet->pointer_info.has_cursor_surface = FALSE;
 
   tablet->pointer_info.button_modifiers &=
     ~(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK |
diff --git a/gdk/wayland/gdksurface-wayland.c b/gdk/wayland/gdksurface-wayland.c
index 65d74c527bc2ad8853adcae7a371546bcf5681e4..5b3927bfdcbd272c1adacc13fe772696c85f199f 100644
--- a/gdk/wayland/gdksurface-wayland.c
+++ b/gdk/wayland/gdksurface-wayland.c
@@ -201,26 +201,13 @@ get_egl_window_size (GdkSurface *surface,
   GdkDisplay *display = gdk_surface_get_display (surface);
   GdkWaylandSurface *impl = GDK_WAYLAND_SURFACE (surface);
 
-  if (GDK_DISPLAY_DEBUG_CHECK (display, GL_NO_FRACTIONAL))
-    {
-      *width = surface->width * gdk_fractional_scale_to_int (&impl->scale);
-      *height = surface->height * gdk_fractional_scale_to_int (&impl->scale);
-
-      GDK_DISPLAY_DEBUG (display, OPENGL, "Using integer scale %d for EGL window (%d %d => %d %d)",
-                         gdk_fractional_scale_to_int (&impl->scale),
-                         surface->width, surface->height,
-                         *width, *height);
-    }
-  else
-    {
-      *width = gdk_fractional_scale_scale (&impl->scale, surface->width),
-      *height = gdk_fractional_scale_scale (&impl->scale, surface->height);
+  *width = gdk_fractional_scale_scale (&impl->scale, surface->width),
+  *height = gdk_fractional_scale_scale (&impl->scale, surface->height);
 
-      GDK_DISPLAY_DEBUG (display, OPENGL, "Using fractional scale %g for EGL window (%d %d => %d %d)",
-                         gdk_fractional_scale_to_double (&impl->scale),
-                         surface->width, surface->height,
-                         *width, *height);
-    }
+  GDK_DISPLAY_DEBUG (display, OPENGL, "Using fractional scale %g for EGL window (%d %d => %d %d)",
+                     gdk_fractional_scale_to_double (&impl->scale),
+                     surface->width, surface->height,
+                     *width, *height);
 }
 
 void
@@ -449,6 +436,14 @@ gdk_wayland_surface_commit (GdkSurface *surface)
   wl_surface_commit (impl->display_server.wl_surface);
 }
 
+/**
+ * gdk_wayland_surface_force_next_commit:
+ * @surface: (type GdkWaylandSurface): a `GdkSurface`
+ *
+ * Forces next commit.
+ *
+ * Since: 4.18
+ */
 void
 gdk_wayland_surface_force_next_commit (GdkSurface *surface)
 {
diff --git a/gdk/wayland/gdkwaylandcolor.c b/gdk/wayland/gdkwaylandcolor.c
index 5984dfe7316741540cf91ce8a9351ef3985d6d2a..bfab264c400d292e196a3ce106c57dae964ea574 100644
--- a/gdk/wayland/gdkwaylandcolor.c
+++ b/gdk/wayland/gdkwaylandcolor.c
@@ -1,61 +1,61 @@
 
 #include "gdkwaylandcolor-private.h"
 #include "gdksurface-wayland-private.h"
-#include <gdk/wayland/xx-color-management-v4-client-protocol.h>
+#include <gdk/wayland/color-management-v1-client-protocol.h>
 
 typedef struct _ImageDescription ImageDescription;
 
 static const uint primaries_map[] = {
-  [XX_COLOR_MANAGER_V4_PRIMARIES_SRGB] = 1,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M] = 4,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_PAL] = 5,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_NTSC] = 6,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM] = 8,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_BT2020] = 9,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ] = 10,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3] = 11,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3] = 12,
-  [XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB] = 0,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_SRGB] = 1,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_PAL_M] = 4,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_PAL] = 5,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_NTSC] = 6,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM] = 8,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_BT2020] = 9,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_CIE1931_XYZ] = 10,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3] = 11,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3] = 12,
+  [WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB] = 0,
 };
 
 static uint
-wl_to_cicp_primaries (enum xx_color_manager_v4_primaries cp)
+wl_to_cicp_primaries (enum wp_color_manager_v1_primaries cp)
 {
   return primaries_map[cp];
 }
 
-static enum xx_color_manager_v4_primaries
+static enum wp_color_manager_v1_primaries
 cicp_to_wl_primaries (uint cp)
 {
   for (guint i = 0; i < G_N_ELEMENTS (primaries_map); i++)
     if (primaries_map[i] == cp)
-       return (enum xx_color_manager_v4_primaries)i;
+       return (enum wp_color_manager_v1_primaries)i;
 
   return 0;
 }
 
 static const uint primaries_primaries[][8] = {
-  [XX_COLOR_MANAGER_V4_PRIMARIES_SRGB] =         { 6400, 3300, 3000, 6000, 1500,  600, 3127, 3290 },
-  [XX_COLOR_MANAGER_V4_PRIMARIES_PAL_M] =        { 6700, 3300, 2100, 7100, 1400,  800, 3100, 3160 },
-  [XX_COLOR_MANAGER_V4_PRIMARIES_PAL] =          { 6400, 3300, 2900, 6000, 1500,  600, 3127, 3290 },
-  [XX_COLOR_MANAGER_V4_PRIMARIES_NTSC] =         { 6300, 3400, 3100, 5950, 1550,  700, 3127, 3290 },
-  [XX_COLOR_MANAGER_V4_PRIMARIES_GENERIC_FILM] = { 2430, 6920, 1450,  490, 6810, 3190, 3100, 3160 },
-  [XX_COLOR_MANAGER_V4_PRIMARIES_BT2020] =       { 7080, 2920, 1700, 7970, 1310,  460, 3127, 3290 },
-  [XX_COLOR_MANAGER_V4_PRIMARIES_CIE1931_XYZ] =  {10000,    0,    0,10000,    0,    0, 3333, 3333 }, 
-  [XX_COLOR_MANAGER_V4_PRIMARIES_DCI_P3] =       { 6800, 3200, 2650, 6900, 1500,  600, 3140, 3510 },
-  [XX_COLOR_MANAGER_V4_PRIMARIES_DISPLAY_P3] =   { 6800, 3200, 2650, 6900, 1500,  600, 3127, 3290 },
-  [XX_COLOR_MANAGER_V4_PRIMARIES_ADOBE_RGB] =    { 6400, 3300, 2100, 7100, 1500,  600, 3127, 3290 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_SRGB] =         { 640000, 330000, 300000, 600000, 150000,  60000, 312700, 329000 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_PAL_M] =        { 670000, 330000, 210000, 710000, 140000,  80000, 310000, 316000 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_PAL] =          { 640000, 330000, 290000, 600000, 150000,  60000, 312700, 329000 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_NTSC] =         { 630000, 340000, 310000, 595000, 155000,  70000, 312700, 329000 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_GENERIC_FILM] = { 243000, 692000, 145000,  49000, 681000, 319000, 310000, 316000 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_BT2020] =       { 708000, 292000, 170000, 797000, 131000,  46000, 312700, 329000 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_CIE1931_XYZ] =  {1000000,      0,      0,1000000,      0,      0, 333300, 333300 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_DCI_P3] =       { 680000, 320000, 265000, 690000, 150000,  60000, 314000, 351000 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_DISPLAY_P3] =   { 680000, 320000, 265000, 690000, 150000,  60000, 312700, 329000 },
+  [WP_COLOR_MANAGER_V1_PRIMARIES_ADOBE_RGB] =    { 640000, 330000, 210000, 710000, 150000,  60000, 312700, 329000 },
 };
 
 static const uint *
-wl_primaries_to_primaries (enum xx_color_manager_v4_primaries primaries)
+wl_primaries_to_primaries (enum wp_color_manager_v1_primaries primaries)
 {
   return primaries_primaries[primaries];
 }
 
 static gboolean
 primaries_to_wl_primaries (const uint primaries[8],
-                           enum xx_color_manager_v4_primaries *out_primaries)
+                           enum wp_color_manager_v1_primaries *out_primaries)
 {
   guint i, j;
 
@@ -76,34 +76,33 @@ primaries_to_wl_primaries (const uint primaries[8],
 }
 
 static const uint transfer_map[] = {
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_BT709] = 1,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA22] = 4,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_GAMMA28] = 5,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST240] = 7,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR] = 8,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LOG_100] = 9,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LOG_316] = 10,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_XVYCC] = 11,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_BT1361] = 12,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB] = 13,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_EXT_SRGB] = 13,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ] = 16,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST428] = 17,
-  [XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_HLG] = 18,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_BT1886] = 1,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA22] = 4,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_GAMMA28] = 5,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST240] = 7,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR] = 8,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_100] = 9,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_LOG_316] = 10,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_XVYCC] = 11,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB] = 13,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_SRGB] = 13,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ] = 16,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST428] = 17,
+  [WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_HLG] = 18,
 };
 
 static uint
-wl_to_cicp_transfer (enum xx_color_manager_v4_transfer_function tf)
+wl_to_cicp_transfer (enum wp_color_manager_v1_transfer_function tf)
 {
   return transfer_map[tf];
 }
 
-static enum xx_color_manager_v4_transfer_function
+static enum wp_color_manager_v1_transfer_function
 cicp_to_wl_transfer (uint tf)
 {
   for (guint i = 0; i < G_N_ELEMENTS (transfer_map); i++)
     if (transfer_map[i] == tf)
-       return (enum xx_color_manager_v4_transfer_function)i;
+       return (enum wp_color_manager_v1_transfer_function)i;
 
   return 0;
 }
@@ -112,7 +111,7 @@ struct _GdkWaylandColor
 {
   GdkWaylandDisplay *display;
 
-  struct xx_color_manager_v4 *color_manager;
+  struct wp_color_manager_v1 *color_manager;
   struct {
     unsigned int intents;
     unsigned int features;
@@ -120,7 +119,7 @@ struct _GdkWaylandColor
     unsigned int primaries;
   } color_manager_supported;
 
-  GHashTable *cs_to_desc; /* GdkColorState => xx_image_description_v4 or NULL */
+  GHashTable *cs_to_desc; /* GdkColorState => wp_image_description_v1 or NULL */
   GHashTable *id_to_cs; /* uint32 identifier => GdkColorState */
 };
 
@@ -163,8 +162,8 @@ color_state_equal (gconstpointer a,
 }
 
 static void
-xx_color_manager_v4_supported_intent (void                       *data,
-                                      struct xx_color_manager_v4 *xx_color_manager_v4,
+wp_color_manager_v1_supported_intent (void                       *data,
+                                      struct wp_color_manager_v1 *wp_color_manager_v1,
                                       uint32_t                    render_intent)
 {
   GdkWaylandColor *color = data;
@@ -173,8 +172,8 @@ xx_color_manager_v4_supported_intent (void                       *data,
 }
 
 static void
-xx_color_manager_v4_supported_feature (void                       *data,
-                                       struct xx_color_manager_v4 *xx_color_manager_v4,
+wp_color_manager_v1_supported_feature (void                       *data,
+                                       struct wp_color_manager_v1 *wp_color_manager_v1,
                                        uint32_t                    feature)
 {
   GdkWaylandColor *color = data;
@@ -183,8 +182,8 @@ xx_color_manager_v4_supported_feature (void                       *data,
 }
 
 static void
-xx_color_manager_v4_supported_tf_named (void                       *data,
-                                        struct xx_color_manager_v4 *xx_color_manager_v4,
+wp_color_manager_v1_supported_tf_named (void                       *data,
+                                        struct wp_color_manager_v1 *wp_color_manager_v1,
                                         uint32_t                    tf)
 {
   GdkWaylandColor *color = data;
@@ -193,8 +192,8 @@ xx_color_manager_v4_supported_tf_named (void                       *data,
 }
 
 static void
-xx_color_manager_v4_supported_primaries_named (void                       *data,
-                                               struct xx_color_manager_v4 *xx_color_manager_v4,
+wp_color_manager_v1_supported_primaries_named (void                       *data,
+                                               struct wp_color_manager_v1 *wp_color_manager_v1,
                                                uint32_t                    primaries)
 {
   GdkWaylandColor *color = data;
@@ -202,11 +201,18 @@ xx_color_manager_v4_supported_primaries_named (void                       *data,
   color->color_manager_supported.primaries |= (1 << primaries);
 }
 
-static struct xx_color_manager_v4_listener color_manager_listener = {
-  xx_color_manager_v4_supported_intent,
-  xx_color_manager_v4_supported_feature,
-  xx_color_manager_v4_supported_tf_named,
-  xx_color_manager_v4_supported_primaries_named,
+static void
+wp_color_manager_v1_done (void                       *data,
+                          struct wp_color_manager_v1 *wp_color_manager_v1)
+{
+}
+
+static struct wp_color_manager_v1_listener color_manager_listener = {
+  wp_color_manager_v1_supported_intent,
+  wp_color_manager_v1_supported_feature,
+  wp_color_manager_v1_supported_tf_named,
+  wp_color_manager_v1_supported_primaries_named,
+  wp_color_manager_v1_done,
 };
 
 GdkWaylandColor *
@@ -223,7 +229,7 @@ gdk_wayland_color_new (GdkWaylandDisplay  *display,
   color->cs_to_desc = g_hash_table_new_full (color_state_hash,
                                              color_state_equal,
                                              (GDestroyNotify) gdk_color_state_unref,
-                                             (GDestroyNotify) xx_image_description_v4_destroy);
+                                             (GDestroyNotify) wp_image_description_v1_destroy);
   color->id_to_cs = g_hash_table_new_full (g_direct_hash,
                                            g_direct_equal,
                                            NULL,
@@ -231,10 +237,10 @@ gdk_wayland_color_new (GdkWaylandDisplay  *display,
 
   color->color_manager = wl_registry_bind (registry,
                                            id,
-                                           &xx_color_manager_v4_interface,
-                                           MIN (version, 2));
+                                           &wp_color_manager_v1_interface,
+                                           MIN (version, 1));
 
-  xx_color_manager_v4_add_listener (color->color_manager,
+  wp_color_manager_v1_add_listener (color->color_manager,
                                     &color_manager_listener,
                                     color);
 
@@ -244,7 +250,7 @@ gdk_wayland_color_new (GdkWaylandDisplay  *display,
 void
 gdk_wayland_color_free (GdkWaylandColor *color)
 {
-  g_clear_pointer (&color->color_manager, xx_color_manager_v4_destroy);
+  g_clear_pointer (&color->color_manager, wp_color_manager_v1_destroy);
 
   g_hash_table_unref (color->cs_to_desc);
   g_hash_table_unref (color->id_to_cs);
@@ -278,14 +284,14 @@ cs_image_listener_data_free (CsImageDescListenerData *csi)
 
 static void
 cs_image_desc_failed (void                           *data,
-                      struct xx_image_description_v4 *desc,
+                      struct wp_image_description_v1 *desc,
                       uint32_t                        cause,
                       const char                     *msg)
 {
   CsImageDescListenerData *csi = data;
 
   g_warning ("Failed to get one of the standard image descriptions: %s", msg);
-  xx_image_description_v4_destroy (desc);
+  wp_image_description_v1_destroy (desc);
 
   g_hash_table_insert (csi->color->cs_to_desc,
                        gdk_color_state_ref (csi->color_state),
@@ -296,7 +302,7 @@ cs_image_desc_failed (void                           *data,
 
 static void
 cs_image_desc_ready (void                           *data,
-                     struct xx_image_description_v4 *desc,
+                     struct wp_image_description_v1 *desc,
                      uint32_t                        identity)
 {
   CsImageDescListenerData *csi = data;
@@ -311,7 +317,7 @@ cs_image_desc_ready (void                           *data,
   cs_image_listener_data_free (csi);
 }
 
-static struct xx_image_description_v4_listener cs_image_desc_listener = {
+static struct wp_image_description_v1_listener cs_image_desc_listener = {
   cs_image_desc_failed,
   cs_image_desc_ready,
 };
@@ -322,8 +328,8 @@ create_image_desc (GdkWaylandColor *color,
                    gboolean         sync)
 {
   CsImageDescListenerData data;
-  struct xx_image_description_creator_params_v4 *creator;
-  struct xx_image_description_v4 *desc;
+  struct wp_image_description_creator_params_v1 *creator;
+  struct wp_image_description_v1 *desc;
   const GdkCicp *cicp;
   GdkCicp norm;
   uint32_t primaries, tf;
@@ -342,7 +348,7 @@ create_image_desc (GdkWaylandColor *color,
   tf = cicp_to_wl_transfer (norm.transfer_function);
 
   if (((color->color_manager_supported.primaries & (1 << primaries)) == 0 &&
-       (color->color_manager_supported.features & (1 << XX_COLOR_MANAGER_V4_FEATURE_SET_PRIMARIES)) == 0) ||
+       (color->color_manager_supported.features & (1 << WP_COLOR_MANAGER_V1_FEATURE_SET_PRIMARIES)) == 0) ||
       (color->color_manager_supported.transfers & (1 << tf)) == 0)
     {
       GDK_DEBUG (MISC, "Unsupported color state %s: Primaries or transfer function unsupported",
@@ -356,24 +362,24 @@ create_image_desc (GdkWaylandColor *color,
   data.sync = sync;
   data.done = FALSE;
 
-  creator = xx_color_manager_v4_new_parametric_creator (color->color_manager);
+  creator = wp_color_manager_v1_create_parametric_creator (color->color_manager);
 
   if (color->color_manager_supported.primaries & (1 << primaries))
     {
-      xx_image_description_creator_params_v4_set_primaries_named (creator, primaries);
+      wp_image_description_creator_params_v1_set_primaries_named (creator, primaries);
     }
   else
     {
       const uint *p = wl_primaries_to_primaries (primaries);
-      xx_image_description_creator_params_v4_set_primaries (creator,
+      wp_image_description_creator_params_v1_set_primaries (creator,
                                                             p[0], p[1],
                                                             p[2], p[3],
                                                             p[4], p[5],
                                                             p[6], p[7]);
     }
-  xx_image_description_creator_params_v4_set_tf_named (creator, tf);
+  wp_image_description_creator_params_v1_set_tf_named (creator, tf);
 
-  desc = xx_image_description_creator_params_v4_create (creator);
+  desc = wp_image_description_creator_params_v1_create (creator);
 
   if (sync)
     {
@@ -381,7 +387,7 @@ create_image_desc (GdkWaylandColor *color,
       
       event_queue = wl_display_create_queue (color->display->wl_display);
       wl_proxy_set_queue ((struct wl_proxy *) desc, event_queue);
-      xx_image_description_v4_add_listener (desc, &cs_image_desc_listener, &data);
+      wp_image_description_v1_add_listener (desc, &cs_image_desc_listener, &data);
       while (!data.done)
         gdk_wayland_display_dispatch_queue (GDK_DISPLAY (color->display), event_queue);
 
@@ -389,7 +395,7 @@ create_image_desc (GdkWaylandColor *color,
     }
   else
     {
-      xx_image_description_v4_add_listener (desc, &cs_image_desc_listener, g_memdup2 (&data, sizeof data));
+      wp_image_description_v1_add_listener (desc, &cs_image_desc_listener, g_memdup2 (&data, sizeof data));
     }
 }
 
@@ -440,37 +446,37 @@ gdk_wayland_color_prepare (GdkWaylandColor *color)
     }
 
   if (color->color_manager &&
-      !(color->color_manager_supported.intents & (1 << XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL)))
+      !(color->color_manager_supported.intents & (1 << WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL)))
     {
       GDK_DEBUG (MISC, "Not using color management: Missing perceptual render intent");
-      g_clear_pointer (&color->color_manager, xx_color_manager_v4_destroy);
+      g_clear_pointer (&color->color_manager, wp_color_manager_v1_destroy);
     }
 
   if (color->color_manager &&
-      (!(color->color_manager_supported.features & (1 << XX_COLOR_MANAGER_V4_FEATURE_PARAMETRIC)) ||
-       !(color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_SRGB)) ||
-       !((color->color_manager_supported.primaries & (1 << XX_COLOR_MANAGER_V4_PRIMARIES_SRGB)) ||
-         (color->color_manager_supported.features & (1 << XX_COLOR_MANAGER_V4_FEATURE_SET_PRIMARIES)))))
+      (!(color->color_manager_supported.features & (1 << WP_COLOR_MANAGER_V1_FEATURE_PARAMETRIC)) ||
+       !(color->color_manager_supported.transfers & (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_SRGB)) ||
+       !((color->color_manager_supported.primaries & (1 << WP_COLOR_MANAGER_V1_PRIMARIES_SRGB)) ||
+         (color->color_manager_supported.features & (1 << WP_COLOR_MANAGER_V1_FEATURE_SET_PRIMARIES)))))
 
     {
       GDK_DEBUG (MISC, "Not using color management: Can't create srgb image description");
-      g_clear_pointer (&color->color_manager, xx_color_manager_v4_destroy);
+      g_clear_pointer (&color->color_manager, wp_color_manager_v1_destroy);
     }
 
   if (color->color_manager)
     {
       create_image_desc (color, GDK_COLOR_STATE_SRGB, FALSE);
 
-      if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR))
+      if (color->color_manager_supported.transfers & (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR))
         create_image_desc (color, GDK_COLOR_STATE_SRGB_LINEAR, FALSE);
 
-      if ((color->color_manager_supported.primaries & (1 << XX_COLOR_MANAGER_V4_PRIMARIES_BT2020) ||
-          (color->color_manager_supported.features & (1 << XX_COLOR_MANAGER_V4_FEATURE_SET_PRIMARIES))))
+      if ((color->color_manager_supported.primaries & (1 << WP_COLOR_MANAGER_V1_PRIMARIES_BT2020) ||
+          (color->color_manager_supported.features & (1 << WP_COLOR_MANAGER_V1_FEATURE_SET_PRIMARIES))))
         {
-          if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_ST2084_PQ))
+          if (color->color_manager_supported.transfers & (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_ST2084_PQ))
             create_image_desc (color, GDK_COLOR_STATE_REC2100_PQ, FALSE);
 
-          if (color->color_manager_supported.transfers & (1 << XX_COLOR_MANAGER_V4_TRANSFER_FUNCTION_LINEAR))
+          if (color->color_manager_supported.transfers & (1 << WP_COLOR_MANAGER_V1_TRANSFER_FUNCTION_EXT_LINEAR))
             create_image_desc (color, GDK_COLOR_STATE_REC2100_LINEAR, FALSE);
         }
     }
@@ -481,8 +487,8 @@ gdk_wayland_color_prepare (GdkWaylandColor *color)
 struct _GdkWaylandColorSurface
 {
   GdkWaylandColor *color;
-  struct xx_color_management_surface_v4 *surface;
-  struct xx_color_management_feedback_surface_v4 *feedback;
+  struct wp_color_management_surface_v1 *surface;
+  struct wp_color_management_surface_feedback_v1 *feedback;
   ImageDescription *current_desc;
   GdkColorStateChanged callback;
   gpointer data;
@@ -492,8 +498,8 @@ struct _ImageDescription
 {
   GdkWaylandColorSurface *surface;
 
-  struct xx_image_description_v4 *image_desc;
-  struct xx_image_description_info_v4 *info;
+  struct wp_image_description_v1 *image_desc;
+  struct wp_image_description_info_v1 *info;
 
   uint32_t identity;
 
@@ -546,8 +552,8 @@ gdk_wayland_color_surface_clear_image_desc (GdkWaylandColorSurface *self)
   if (desc == NULL)
     return;
 
-  g_clear_pointer (&desc->image_desc, xx_image_description_v4_destroy);
-  g_clear_pointer (&desc->info, xx_image_description_info_v4_destroy);
+  g_clear_pointer (&desc->image_desc, wp_image_description_v1_destroy);
+  g_clear_pointer (&desc->info, wp_image_description_info_v1_destroy);
   g_free (desc);
 
   self->current_desc = NULL;
@@ -555,7 +561,7 @@ gdk_wayland_color_surface_clear_image_desc (GdkWaylandColorSurface *self)
 
 static void
 image_desc_info_done (void *data,
-                      struct xx_image_description_info_v4 *info)
+                      struct wp_image_description_info_v1 *info)
 {
   ImageDescription *desc = data;
   GdkWaylandColorSurface *self = desc->surface;
@@ -573,7 +579,7 @@ image_desc_info_done (void *data,
   else
     {
       cs = GDK_COLOR_STATE_SRGB;
-      g_clear_pointer (&desc->image_desc, xx_image_description_v4_destroy);
+      g_clear_pointer (&desc->image_desc, wp_image_description_v1_destroy);
     }
 
   if (self->callback)
@@ -586,7 +592,7 @@ image_desc_info_done (void *data,
 
 static void
 image_desc_info_icc_file (void *data,
-                          struct xx_image_description_info_v4 *info,
+                          struct wp_image_description_info_v1 *info,
                           int32_t icc,
                           uint32_t icc_size)
 {
@@ -599,7 +605,7 @@ image_desc_info_icc_file (void *data,
 
 static void
 image_desc_info_primaries (void *data,
-                           struct xx_image_description_info_v4 *info,
+                           struct wp_image_description_info_v1 *info,
                            int32_t r_x, int32_t r_y,
                            int32_t g_x, int32_t g_y,
                            int32_t b_x, int32_t b_y,
@@ -619,7 +625,7 @@ image_desc_info_primaries (void *data,
 
 static void
 image_desc_info_primaries_named (void *data,
-                                 struct xx_image_description_info_v4 *info,
+                                 struct wp_image_description_info_v1 *info,
                                  uint32_t primaries)
 {
   ImageDescription *desc = data;
@@ -637,7 +643,7 @@ image_desc_info_primaries_named (void *data,
 
 static void
 image_desc_info_tf_power (void *data,
-                          struct xx_image_description_info_v4 *info,
+                          struct wp_image_description_info_v1 *info,
                           uint32_t tf_power)
 {
   ImageDescription *desc = data;
@@ -648,7 +654,7 @@ image_desc_info_tf_power (void *data,
 
 static void
 image_desc_info_tf_named (void *data,
-                          struct xx_image_description_info_v4 *info,
+                          struct wp_image_description_info_v1 *info,
                           uint32_t tf)
 {
   ImageDescription *desc = data;
@@ -659,7 +665,7 @@ image_desc_info_tf_named (void *data,
 
 static void
 image_desc_info_luminances (void *data,
-                            struct xx_image_description_info_v4 *info,
+                            struct wp_image_description_info_v1 *info,
                             uint32_t min_lum,
                             uint32_t max_lum,
                             uint32_t ref_lum)
@@ -674,7 +680,7 @@ image_desc_info_luminances (void *data,
 
 static void
 image_desc_info_target_primaries (void *data,
-                                  struct xx_image_description_info_v4 *info,
+                                  struct wp_image_description_info_v1 *info,
                                   int32_t r_x, int32_t r_y,
                                   int32_t g_x, int32_t g_y,
                                   int32_t b_x, int32_t b_y,
@@ -691,7 +697,7 @@ image_desc_info_target_primaries (void *data,
 
 static void
 image_desc_info_target_luminance (void *data,
-                                  struct xx_image_description_info_v4 *info,
+                                  struct wp_image_description_info_v1 *info,
                                   uint32_t min_lum,
                                   uint32_t max_lum)
 {
@@ -704,7 +710,7 @@ image_desc_info_target_luminance (void *data,
 
 static void
 image_desc_info_target_max_cll (void *data,
-                                struct xx_image_description_info_v4 *info,
+                                struct wp_image_description_info_v1 *info,
                                 uint32_t max_cll)
 {
   ImageDescription *desc = data;
@@ -715,7 +721,7 @@ image_desc_info_target_max_cll (void *data,
 
 static void
 image_desc_info_target_max_fall (void *data,
-                                 struct xx_image_description_info_v4 *info,
+                                 struct wp_image_description_info_v1 *info,
                                  uint32_t max_fall)
 {
   ImageDescription *desc = data;
@@ -724,7 +730,7 @@ image_desc_info_target_max_fall (void *data,
   desc->has_target_max_fall = 1;
 }
 
-static struct xx_image_description_info_v4_listener info_listener = {
+static struct wp_image_description_info_v1_listener info_listener = {
   image_desc_info_done,
   image_desc_info_icc_file,
   image_desc_info_primaries,
@@ -740,7 +746,7 @@ static struct xx_image_description_info_v4_listener info_listener = {
 
 static void
 image_desc_failed (void                           *data,
-                   struct xx_image_description_v4 *image_desc,
+                   struct wp_image_description_v1 *image_desc,
                    uint32_t                        cause,
                    const char                     *msg)
 {
@@ -756,7 +762,7 @@ image_desc_failed (void                           *data,
 
 static void
 image_desc_ready (void                           *data,
-                  struct xx_image_description_v4 *image_desc,
+                  struct wp_image_description_v1 *image_desc,
                   uint32_t                        identity)
 {
   ImageDescription *desc = data;
@@ -774,20 +780,21 @@ image_desc_ready (void                           *data,
       return;
     }
 
-  desc->info = xx_image_description_v4_get_information (image_desc);
+  desc->info = wp_image_description_v1_get_information (image_desc);
   desc->identity = identity;
 
-  xx_image_description_info_v4_add_listener (desc->info, &info_listener, desc);
+  wp_image_description_info_v1_add_listener (desc->info, &info_listener, desc);
 }
 
-static const struct xx_image_description_v4_listener image_desc_listener = {
+static const struct wp_image_description_v1_listener image_desc_listener = {
   image_desc_failed,
   image_desc_ready
 };
 
 static void
 preferred_changed (void *data,
-                   struct xx_color_management_feedback_surface_v4 *feedback)
+                   struct wp_color_management_surface_feedback_v1 *feedback,
+                   uint32_t identity)
 {
   GdkWaylandColorSurface *self = data;
   ImageDescription *desc;
@@ -803,20 +810,20 @@ preferred_changed (void *data,
   desc->surface = self;
   self->current_desc = desc;
 
-  desc->image_desc = xx_color_management_feedback_surface_v4_get_preferred (self->feedback);
+  desc->image_desc = wp_color_management_surface_feedback_v1_get_preferred_parametric (self->feedback);
 
-  xx_image_description_v4_add_listener (desc->image_desc, &image_desc_listener, desc);
+  wp_image_description_v1_add_listener (desc->image_desc, &image_desc_listener, desc);
 }
 
-static const struct xx_color_management_feedback_surface_v4_listener color_listener = {
+static const struct wp_color_management_surface_feedback_v1_listener color_listener = {
   preferred_changed,
 };
 
 GdkWaylandColorSurface *
-gdk_wayland_color_surface_new (GdkWaylandColor          *color,
-                               struct wl_surface        *wl_surface,
-                               GdkColorStateChanged      callback,
-                               gpointer                  data)
+gdk_wayland_color_surface_new (GdkWaylandColor      *color,
+                               struct wl_surface    *wl_surface,
+                               GdkColorStateChanged  callback,
+                               gpointer              data)
 {
   GdkWaylandColorSurface *self;
 
@@ -824,14 +831,14 @@ gdk_wayland_color_surface_new (GdkWaylandColor          *color,
 
   self->color = color;
 
-  self->surface = xx_color_manager_v4_get_surface (color->color_manager, wl_surface);
-  self->feedback = xx_color_manager_v4_get_feedback_surface (color->color_manager, wl_surface);
+  self->surface = wp_color_manager_v1_get_surface (color->color_manager, wl_surface);
+  self->feedback = wp_color_manager_v1_get_surface_feedback (color->color_manager, wl_surface);
 
   self->callback = callback;
   self->data = data;
 
-  xx_color_management_feedback_surface_v4_add_listener (self->feedback, &color_listener, self);
-  preferred_changed (self, self->feedback);
+  wp_color_management_surface_feedback_v1_add_listener (self->feedback, &color_listener, self);
+  preferred_changed (self, self->feedback, 0);
 
   return self;
 }
@@ -841,13 +848,13 @@ gdk_wayland_color_surface_free (GdkWaylandColorSurface *self)
 {
   gdk_wayland_color_surface_clear_image_desc (self);
 
-  xx_color_management_surface_v4_destroy (self->surface);
-  xx_color_management_feedback_surface_v4_destroy (self->feedback);
+  wp_color_management_surface_v1_destroy (self->surface);
+  wp_color_management_surface_feedback_v1_destroy (self->feedback);
 
   g_free (self);
 }
 
-static struct xx_image_description_v4 *
+static struct wp_image_description_v1 *
 gdk_wayland_color_get_image_description (GdkWaylandColor *color,
                                          GdkColorState   *cs)
 {
@@ -870,16 +877,16 @@ void
 gdk_wayland_color_surface_set_color_state (GdkWaylandColorSurface *self,
                                            GdkColorState          *cs)
 {
-  struct xx_image_description_v4 *desc;
+  struct wp_image_description_v1 *desc;
 
   desc = gdk_wayland_color_get_image_description (self->color, cs);
 
   if (desc)
-    xx_color_management_surface_v4_set_image_description (self->surface,
+    wp_color_management_surface_v1_set_image_description (self->surface,
                                                           desc,
-                                                          XX_COLOR_MANAGER_V4_RENDER_INTENT_PERCEPTUAL);
+                                                          WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL);
   else
-    xx_color_management_surface_v4_unset_image_description (self->surface);
+    wp_color_management_surface_v1_unset_image_description (self->surface);
 }
 
 gboolean
diff --git a/gdk/wayland/gdkwaylandsurface.h b/gdk/wayland/gdkwaylandsurface.h
index 371370caed960ed543056ae974b783cb42842b6e..0bd07e0c9f56b17da3548f3d1fed7451d4cf819b 100644
--- a/gdk/wayland/gdkwaylandsurface.h
+++ b/gdk/wayland/gdkwaylandsurface.h
@@ -43,7 +43,7 @@ GType                    gdk_wayland_surface_get_type             (void);
 GDK_AVAILABLE_IN_ALL
 struct wl_surface       *gdk_wayland_surface_get_wl_surface       (GdkSurface *surface);
 
-GDK_AVAILABLE_IN_ALL
+GDK_AVAILABLE_IN_4_18
 void                     gdk_wayland_surface_force_next_commit    (GdkSurface *surface);
 
 G_END_DECLS
diff --git a/gdk/wayland/meson.build b/gdk/wayland/meson.build
index 498302984ecd1591282796a81e6ff154a3b4251d..2b4b16d71c3d12a9200672d2c8ab03eba4d9d519 100644
--- a/gdk/wayland/meson.build
+++ b/gdk/wayland/meson.build
@@ -147,13 +147,13 @@ proto_sources = [
     'version': 1,
   },
   {
-    'name': 'xx-color-management',
-    'stability': 'private',
-    'version': 4,
+    'name': 'color-management',
+    'stability': 'staging',
+    'version': 1,
   },
   {
     'name': 'xdg-system-bell',
-    'stability': 'private',
+    'stability': 'staging',
     'version': 1,
   },
 ]
@@ -200,4 +200,8 @@ libgdk_wayland = static_library('gdk-wayland',
 )
 
 # Used to generate pkg-config Requires
-wayland_public_deps = [wlclientdep]
+wayland_public_deps = []
+
+if wlclientdep.type_name() != 'internal'
+  wayland_public_deps += [wlclientdep]
+endif
diff --git a/gsk/gpu/gskglrenderer.c b/gsk/gpu/gskglrenderer.c
index 1cdce228ce7444a694e40fc48881cbeeb8b343d5..67bfa13766338ae9dcde898054a7be537af06bd4 100644
--- a/gsk/gpu/gskglrenderer.c
+++ b/gsk/gpu/gskglrenderer.c
@@ -120,7 +120,7 @@ gsk_gl_renderer_get_backbuffer (GskGpuRenderer *renderer)
 
   context = gsk_gpu_renderer_get_context (renderer);
   surface = gdk_draw_context_get_surface (context);
-  scale = gsk_gpu_renderer_get_scale (renderer);
+  scale = gdk_surface_get_scale (surface);
 
   if (self->backbuffer == NULL ||
       !!(gsk_gpu_image_get_flags (self->backbuffer) & GSK_GPU_IMAGE_SRGB) != gdk_surface_get_gl_is_srgb (surface) ||
@@ -139,14 +139,6 @@ gsk_gl_renderer_get_backbuffer (GskGpuRenderer *renderer)
   return self->backbuffer;
 }
 
-static double
-gsk_gl_renderer_get_scale (GskGpuRenderer *self)
-{
-  GdkDrawContext *context = gsk_gpu_renderer_get_context (self);
-
-  return gdk_gl_context_get_scale (GDK_GL_CONTEXT (context));
-}
-
 static void
 gsk_gl_renderer_unrealize (GskRenderer *renderer)
 {
@@ -173,7 +165,6 @@ gsk_gl_renderer_class_init (GskGLRendererClass *klass)
   gpu_renderer_class->save_current = gsk_gl_renderer_save_current;
   gpu_renderer_class->restore_current = gsk_gl_renderer_restore_current;
   gpu_renderer_class->get_backbuffer = gsk_gl_renderer_get_backbuffer;
-  gpu_renderer_class->get_scale = gsk_gl_renderer_get_scale;
 
   renderer_class->unrealize = gsk_gl_renderer_unrealize;
 }
@@ -196,6 +187,13 @@ gsk_gl_renderer_new (void)
   return g_object_new (GSK_TYPE_GL_RENDERER, NULL);
 }
 
+/**
+ * GskNglRenderer:
+ *
+ * A GL based renderer.
+ *
+ * See [class@Gsk.Renderer].
+ */
 typedef struct {
   GskRenderer parent_instance;
 } GskNglRenderer;
diff --git a/gsk/gpu/gskgpudevice.c b/gsk/gpu/gskgpudevice.c
index e08c51a3549445db29a7aeecf476971b943d697f..6c71fdd96c2385ed617fb9190217c2baf59fc160 100644
--- a/gsk/gpu/gskgpudevice.c
+++ b/gsk/gpu/gskgpudevice.c
@@ -223,7 +223,7 @@ gsk_gpu_device_get_cache (GskGpuDevice *self)
  *
  * Returns the max image size supported by this device.
  *
- * This maps to GL_MAX_TEXTURE_SIZE on GL, but Vulkan is more flexible with
+ * This maps to `GL_MAX_TEXTURE_SIZE` on GL, but Vulkan is more flexible with
  * per-format size limits, so this is an estimate and code should still handle
  * failures of image creation at smaller sizes. (Besides handling them anyway
  * in case of OOM.)
@@ -242,10 +242,12 @@ gsk_gpu_device_get_max_image_size (GskGpuDevice *self)
  * gsk_gpu_device_get_tile_size:
  * @self: a device
  *
- * The suggested size for tiling images. This value will be small enough so that
- * image creation never fails due to size constraints. It should also not be too
- * large to allow efficient caching of tiles and evictions of unused tiles
- * (think of an image editor showing only a section of a large image).
+ * The suggested size for tiling images.
+ *
+ * This value will be small enough so that image creation never fails
+ * due to size constraints. It should also not be too large to allow
+ * efficient caching of tiles and evictions of unused tiles (think of
+ * an image editor showing only a section of a large image).
  *
  * Returns: The suggested size of tiles when tiling images.
  **/
@@ -262,7 +264,8 @@ gsk_gpu_device_get_tile_size (GskGpuDevice *self)
  * @self: a device
  *
  * The required size for allocating arrays of globals.
- * This value will be at least sizeof (GskGpuGlobalsInstance) but due to constraints
+ *
+ * This value will be at least `sizeof (GskGpuGlobalsInstance)` but due to constraints
  * of how buffers are mapped, it might be larger to allow a single buffer to hold
  * all the globals instances.
  *
@@ -285,14 +288,15 @@ gsk_gpu_device_get_globals_aligned_size (GskGpuDevice *self)
  * @width: width of the image
  * @height: height of the image
  *
- * Creates an image suitable for offscreen rendering. Note that the format
- * is a hint and the device may choose a different format if the desired
- * format is not be renderable on the device.
- * 
- * If width/height is too large or the device is out of memory, NULL may
- * be returned.
+ * Creates an image suitable for offscreen rendering.
+ *
+ * Note that the format is a hint and the device may choose a different
+ * format if the desired format is not be renderable on the device.
+ *
+ * If width/height is too large or the device is out of memory,
+ * `NULL` may be returned.
  *
- * Returns: (nullable): The created image or NULL on error.
+ * Returns: (nullable): The created image or `NULL` on error.
  **/
 GskGpuImage *
 gsk_gpu_device_create_offscreen_image (GskGpuDevice    *self,
diff --git a/gsk/gpu/gskgpurenderer.c b/gsk/gpu/gskgpurenderer.c
index f904211d2c592455db26a108a8e1a8d9e5aa29fc..f86ca1237cad00105b869b67dbe4a95241aec06b 100644
--- a/gsk/gpu/gskgpurenderer.c
+++ b/gsk/gpu/gskgpurenderer.c
@@ -188,7 +188,7 @@ get_render_region (GskGpuRenderer *self)
   cairo_region_t *scaled_damage;
   double scale;
 
-  scale = gsk_gpu_renderer_get_scale (self);
+  scale = gdk_surface_get_scale (gdk_draw_context_get_surface (priv->context));
 
   damage = gdk_draw_context_get_frame_region (priv->context);
   scaled_damage = cairo_region_create ();
@@ -447,7 +447,7 @@ gsk_gpu_renderer_render (GskRenderer          *renderer,
 
   depth = gsk_render_node_get_preferred_depth (root);
   frame = gsk_gpu_renderer_get_frame (self);
-  scale = gsk_gpu_renderer_get_scale (self);
+  scale = gdk_surface_get_scale (gdk_draw_context_get_surface (priv->context));
 
   if (gsk_render_node_get_opaque_rect (root, &opaque_tmp))
     opaque = &opaque_tmp;
@@ -477,17 +477,6 @@ gsk_gpu_renderer_render (GskRenderer          *renderer,
   gsk_gpu_device_queue_gc (priv->device);
 }
 
-static double
-gsk_gpu_renderer_real_get_scale (GskGpuRenderer *self)
-{
-  GskGpuRendererPrivate *priv = gsk_gpu_renderer_get_instance_private (self);
-  GdkSurface *surface;
-
-  surface = gdk_draw_context_get_surface (priv->context);
-
-  return gdk_surface_get_scale (surface);
-}
-
 static void
 gsk_gpu_renderer_class_init (GskGpuRendererClass *klass)
 {
@@ -508,7 +497,6 @@ gsk_gpu_renderer_class_init (GskGpuRendererClass *klass)
       "certain optimizations in the \'ngl\' and \'vulkan\' renderers.\n",
       gsk_gpu_optimization_keys,
       G_N_ELEMENTS (gsk_gpu_optimization_keys));
-  klass->get_scale = gsk_gpu_renderer_real_get_scale;
 }
 
 static void
@@ -534,9 +522,3 @@ gsk_gpu_renderer_get_device (GskGpuRenderer *self)
 
   return priv->device;
 }
-
-double
-gsk_gpu_renderer_get_scale (GskGpuRenderer *self)
-{
-  return GSK_GPU_RENDERER_GET_CLASS (self)->get_scale (self);
-}
diff --git a/gsk/gpu/gskgpurendererprivate.h b/gsk/gpu/gskgpurendererprivate.h
index 12652bb8270a9856bf3b01846934f9bc825d8f84..a0c5e24830b6af06cdb57a248973e83756840bc7 100644
--- a/gsk/gpu/gskgpurendererprivate.h
+++ b/gsk/gpu/gskgpurendererprivate.h
@@ -38,13 +38,10 @@ struct _GskGpuRendererClass
   void                  (* restore_current)                             (GskGpuRenderer         *self,
                                                                          gpointer                current);
   GskGpuImage *         (* get_backbuffer)                              (GskGpuRenderer         *self);
-
-  double                (* get_scale)                                   (GskGpuRenderer         *self);
 };
 
 GdkDrawContext *        gsk_gpu_renderer_get_context                    (GskGpuRenderer         *self);
 GskGpuDevice *          gsk_gpu_renderer_get_device                     (GskGpuRenderer         *self);
-double                  gsk_gpu_renderer_get_scale                      (GskGpuRenderer         *self);
 
 G_END_DECLS
 
diff --git a/gsk/gpu/gskvulkanimage.c b/gsk/gpu/gskvulkanimage.c
index f5ffb1a1c669476783cf2f4e9d75e8bdc2f6dfc3..f720f4494f163ab0e44ac321ab76e9f294f433d2 100644
--- a/gsk/gpu/gskvulkanimage.c
+++ b/gsk/gpu/gskvulkanimage.c
@@ -159,6 +159,8 @@ gsk_vulkan_device_supports_format (GskVulkanDevice   *device,
     *out_flags |= GSK_GPU_IMAGE_FILTERABLE;
   if (features & VK_FORMAT_FEATURE_COLOR_ATTACHMENT_BLEND_BIT)
     *out_flags |= GSK_GPU_IMAGE_RENDERABLE;
+  if (image_properties.imageFormatProperties.maxMipLevels >= gsk_vulkan_mipmap_levels (width, height))
+    *out_flags |= GSK_GPU_IMAGE_CAN_MIPMAP;
 
   return TRUE;
 }
@@ -204,7 +206,7 @@ gsk_vulkan_device_check_format (GskVulkanDevice          *device,
                                 VkImageTiling            *out_tiling,
                                 GskGpuImageFlags         *out_flags)
 {
-#define CHECK_FLAGS (GSK_GPU_IMAGE_NO_BLIT | GSK_GPU_IMAGE_FILTERABLE | GSK_GPU_IMAGE_RENDERABLE)
+#define CHECK_FLAGS (GSK_GPU_IMAGE_NO_BLIT | GSK_GPU_IMAGE_FILTERABLE | GSK_GPU_IMAGE_RENDERABLE | GSK_GPU_IMAGE_CAN_MIPMAP)
   GskGpuImageFlags flags;
 
   if (vk_format == VK_FORMAT_UNDEFINED)
diff --git a/gsk/gpu/gskvulkanimageprivate.h b/gsk/gpu/gskvulkanimageprivate.h
index ad3d80cd13b04b33a6bf2a91338001c0798ca8af..9ca32080cc9f934ffb623542d1d5ce78a95961eb 100644
--- a/gsk/gpu/gskvulkanimageprivate.h
+++ b/gsk/gpu/gskvulkanimageprivate.h
@@ -81,7 +81,7 @@ static inline guint
 gsk_vulkan_mipmap_levels (gsize width,
                           gsize height)
 {
-  return g_bit_nth_msf (MAX (MAX (width, height) - 1, 1), -1) + 1;
+  return g_bit_nth_msf (MAX (width, height), -1) + 1;
 }
 
 G_END_DECLS
diff --git a/gsk/gskenums.h b/gsk/gskenums.h
index ba9dd011b234a4a5aaba0e1f0e5acb7c5ba02694..3370eda1b2693fb2e7ce7cbaeb5199d3c9aa07f5 100644
--- a/gsk/gskenums.h
+++ b/gsk/gskenums.h
@@ -224,7 +224,7 @@ typedef enum {
  *   the total number of intersections is odd, the point will be
  *   filled.
  *
- * `GskFillRule` is used to select how paths are filled.
+ * Specifies how paths are filled.
  *
  * Whether or not a point is included in the fill is determined by taking
  * a ray from that point to infinity and looking at intersections with the
@@ -323,7 +323,7 @@ typedef enum {
  *   the start point, control point and end point of the curve. A weight for the
  *   curve will be passed, too.
  *
- * Path operations are used to describe the segments of a `GskPath`.
+ * Describes the segments of a `GskPath`.
  *
  * More values may be added in the future.
  *
@@ -349,8 +349,7 @@ typedef enum {
  * @GSK_PATH_FROM_END: The tangent against path direction of the outgoing
  *   side of the path
  *
- * The values of the `GskPathDirection` enum are used to pick one
- * of the four tangents at a given point on the path.
+ * Used to pick one of the four tangents at a given point on the path.
  *
  * Note that the directions for @GSK_PATH_FROM_START/@GSK_PATH_TO_END and
  * @GSK_PATH_TO_START/@GSK_PATH_FROM_END will coincide for smooth points.
@@ -436,11 +435,12 @@ typedef enum
  * @GSK_GL_UNIFORM_TYPE_VEC3: A GLSL vec3 / graphene_vec3_t uniform
  * @GSK_GL_UNIFORM_TYPE_VEC4: A GLSL vec4 / graphene_vec4_t uniform
  *
- * This defines the types of the uniforms that `GskGLShaders`
- * declare.
+ * Defines the types of the uniforms that `GskGLShaders` declare.
  *
  * It defines both what the type is called in the GLSL shader
  * code, and what the corresponding C type is on the Gtk side.
+ *
+ * Deprecated: 4.16
  */
 typedef enum
 {
diff --git a/gsk/gskglshader.c b/gsk/gskglshader.c
index 453f11dfd85393c6f77b8b303e87db4dbb6639ff..f9ad6cfff3340e72c0b06a81f5e8f1707bd96c46 100644
--- a/gsk/gskglshader.c
+++ b/gsk/gskglshader.c
@@ -133,14 +133,12 @@
  * }
  * ```
  *
- * # Deprecation
- *
- * This feature was deprecated in GTK 4.16 after the new rendering infrastructure
- * introduced in 4.14 did not support it.
- * The lack of Vulkan integration would have made it a very hard feature to support.
- *
- * If you want to use OpenGL directly, you should look at [GtkGLArea](../gtk4/class.GLArea.html)
- * which uses a different approach and is still well supported.
+ * Deprecated: 4.16: This feature was deprecated in GTK 4.16 after the new
+ * rendering infrastructure introduced in 4.14 did not support it. The lack
+ * of Vulkan integration would have made it a very hard feature to support.
+ * If you want to use OpenGL directly, you should look at
+ * [GtkGLArea](../gtk4/class.GLArea.html), which uses a different approach
+ * and is still well-supported.
  */
 
 #include "config.h"
diff --git a/gsk/gskglshader.h b/gsk/gskglshader.h
index 0cb9fbf6437cee54ac4807603fbecbed5a0182b6..0a0d969cfdf1835f110c5fe35511e4d7e7fa11a0 100644
--- a/gsk/gskglshader.h
+++ b/gsk/gskglshader.h
@@ -36,7 +36,9 @@ G_BEGIN_DECLS
 /**
  * GskShaderArgsBuilder:
  *
- * An object to build the uniforms data for a `GskGLShader`.
+ * Builds the uniforms data for a `GskGLShader`.
+ *
+ * Deprecated: 4.16
  */
 typedef struct _GskGLShader GskGLShader GDK_DEPRECATED_TYPE_IN_4_16_FOR(GtkGLArea);
 typedef struct _GskShaderArgsBuilder GskShaderArgsBuilder GDK_DEPRECATED_TYPE_IN_4_16_FOR(GtkGLArea);
diff --git a/gsk/gskpath.h b/gsk/gskpath.h
index 246440264e288a5c2aecfbebadba22b8f1b0c7b6..cfd632a93b9a3b205acd4df1b350d331efbc3753 100644
--- a/gsk/gskpath.h
+++ b/gsk/gskpath.h
@@ -61,8 +61,7 @@ typedef enum
  * @weight: The weight for conic curves, or unused if not a conic curve
  * @user_data: The user data provided with the function
  *
- * Prototype of the callback to iterate through the operations of
- * a path.
+ * Type of the callback to iterate through the operations of a path.
  *
  * For each operation, the callback is given the @op itself, the points
  * that the operation is applied to in @pts, and a @weight for conic
diff --git a/gsk/gskpathbuilder.c b/gsk/gskpathbuilder.c
index 597fe4bd13f4a78357d7f5c129e8d5f68117f52a..f5667fc27dea2ead43c6176aba5b8ed92f14fc6f 100644
--- a/gsk/gskpathbuilder.c
+++ b/gsk/gskpathbuilder.c
@@ -31,7 +31,7 @@
 /**
  * GskPathBuilder:
  *
- * An auxiliary object for constructing `GskPath` objects.
+ * Constructs `GskPath` objects.
  *
  * A path is constructed like this:
  *
diff --git a/gsk/gskpathmeasure.c b/gsk/gskpathmeasure.c
index d20ac35d0d707ae90b184a350edaef7b7fc47ffc..d9307a98548c60763e8cc552290398e11930221d 100644
--- a/gsk/gskpathmeasure.c
+++ b/gsk/gskpathmeasure.c
@@ -29,8 +29,7 @@
 /**
  * GskPathMeasure:
  *
- * An object that allows measurements on paths such as determining
- * the length of the path.
+ * Performs measurements on paths such as determining the length of the path.
  *
  * Many measuring operations require sampling the path length
  * at intermediate points. Therefore, a `GskPathMeasure` has
diff --git a/gsk/gskrenderer.c b/gsk/gskrenderer.c
index 1cd3cae7aae7fd2941ba2a62e62ed434c428dcdd..3468243206b14d05e69d415a46279f26bd0e2392 100644
--- a/gsk/gskrenderer.c
+++ b/gsk/gskrenderer.c
@@ -528,25 +528,25 @@ get_renderer_for_name (const char *renderer_name)
 #endif
   else if (g_ascii_strcasecmp (renderer_name, "help") == 0)
     {
-      fprintf (stderr, "Supported arguments for GSK_RENDERER environment variable:\n");
+      gdk_help_message ("Supported arguments for GSK_RENDERER environment variable:\n"
 #ifdef GDK_WINDOWING_BROADWAY
-      fprintf (stderr, "  broadway - Use the Broadway specific renderer\n");
+                        "  broadway - Use the Broadway specific renderer\n"
 #else
-      fprintf (stderr, "  broadway - Disabled during GTK build\n");
+                        "  broadway - Disabled during GTK build\n"
 #endif
-      fprintf (stderr, "     cairo - Use the Cairo fallback renderer\n");
-      fprintf (stderr, "    opengl - Use the OpenGL renderer\n");
-      fprintf (stderr, "       ngl - Use the OpenGL renderer\n");
-      fprintf (stderr, "        gl - Use the OpenGL renderer\n");
+                        "     cairo - Use the Cairo fallback renderer\n"
+                        "    opengl - Use the OpenGL renderer\n"
+                        "       ngl - Use the OpenGL renderer\n"
+                        "        gl - Use the OpenGL renderer\n"
 #ifdef GDK_RENDERING_VULKAN
-      fprintf (stderr, "    vulkan - Use the Vulkan renderer\n");
+                        "    vulkan - Use the Vulkan renderer\n"
 #else
-      fprintf (stderr, "    vulkan - Disabled during GTK build\n");
+                        "    vulkan - Disabled during GTK build\n"
 #endif
-      fprintf (stderr, "      help - Print this help\n\n");
-      fprintf (stderr, "The old OpenGL renderer has been removed in GTK 4.18, so using\n");
-      fprintf (stderr, "GSK_RENDERER=gl will cause a warning and use the new OpenGL renderer.\n\n");
-      fprintf (stderr, "Other arguments will cause a warning and be ignored.\n");
+                        "      help - Print this help\n\n"
+                        "The old OpenGL renderer has been removed in GTK 4.18, so using\n"
+                        "GSK_RENDERER=gl will cause a warning and use the new OpenGL renderer.\n\n"
+                        "Other arguments will cause a warning and be ignored.");
     }
   else
     {
diff --git a/gsk/gskrendernode.h b/gsk/gskrendernode.h
index 950e7e05e763b7936f9fd6672f050e33fe236413..88b2678a1f4100b33b9c0ce94fa79692085ee844 100644
--- a/gsk/gskrendernode.h
+++ b/gsk/gskrendernode.h
@@ -614,7 +614,7 @@ gpointer                gsk_subsurface_node_get_subsurface      (const GskRender
  * GSK_VALUE_HOLDS_RENDER_NODE:
  * @value: a `GValue`
  *
- * Evaluates to %TRUE if @value was initialized with %GSK_TYPE_RENDER_NODE.
+ * Evaluates to true if @value was initialized with `GSK_TYPE_RENDER_NODE`.
  */
 #define GSK_VALUE_HOLDS_RENDER_NODE(value)       (G_VALUE_HOLDS ((value), GSK_TYPE_RENDER_NODE))
 
diff --git a/gsk/gskrendernodeimpl.c b/gsk/gskrendernodeimpl.c
index 1369f12c42ee45fc24e6e51c192c65a711c90edf..3f059f5eb403d12c9ae11e2e7a41c5d708a03547 100644
--- a/gsk/gskrendernodeimpl.c
+++ b/gsk/gskrendernodeimpl.c
@@ -2541,8 +2541,8 @@ gsk_border_node_get_widths (const GskRenderNode *node)
  *
  * Retrieves the colors of the border.
  *
- * Returns: (transfer none): an array of 4 `GdkRGBA` structs
- *     for the top, right, bottom and left color of the border
+ * Returns: (transfer none) (array fixed-size=4): an array of 4 `GdkRGBA`
+ *   structs for the top, right, bottom and left color of the border
  */
 const GdkRGBA *
 gsk_border_node_get_colors (const GskRenderNode *node)
@@ -2663,8 +2663,8 @@ gsk_border_node_new2 (const GskRoundedRect *outline,
  *
  * Retrieves the colors of the border.
  *
- * Returns: (transfer none): an array of 4 `GdkColor` structs
- *     for the top, right, bottom and left color of the border
+ * Returns: (transfer none) (array fixed-size=4): an array of 4 `GdkColor`
+ *   structs for the top, right, bottom and left color of the border
  */
 const GdkColor *
 gsk_border_node_get_colors2 (const GskRenderNode *node)
@@ -2922,7 +2922,7 @@ gsk_texture_node_new (GdkTexture            *texture,
 /**
  * GskTextureScaleNode:
  *
- * A render node for a `GdkTexture`.
+ * A render node for a `GdkTexture`, with control over scaling.
  *
  * Since: 4.10
  */
diff --git a/gsk/gskstroke.c b/gsk/gskstroke.c
index 11d9d8f3bdde8092c404d0cb5038c230dbea31b2..4c76fd947c512507f10f578ad17b4380d338fae4 100644
--- a/gsk/gskstroke.c
+++ b/gsk/gskstroke.c
@@ -24,7 +24,7 @@
 /**
  * GskStroke:
  *
- * Collects the parameters that influence the operation of stroking a path.
+ * Collects the parameters that are needed when stroking a path.
  *
  * Since: 4.14
  */
diff --git a/gsk/gsktransform.c b/gsk/gsktransform.c
index 1a66747501cff8763c43cf4121becde600eb363b..b47cc9d72e2336f61964f917838824e2c403ce1e 100644
--- a/gsk/gsktransform.c
+++ b/gsk/gsktransform.c
@@ -21,7 +21,7 @@
 /**
  * GskTransform: (ref-func gsk_transform_ref) (unref-func gsk_transform_unref)
  *
- * An object to describe transform matrices.
+ * Describes a 3D transform.
  *
  * Unlike `graphene_matrix_t`, `GskTransform` retains the steps in how
  * a transform was constructed, and allows inspecting them. It is modeled
diff --git a/gtk/a11y/gtkatspicontext.c b/gtk/a11y/gtkatspicontext.c
index e3e76eac4bd490569a5ca6809ed6d5d9aaaf14f8..2fdb5eec5c99246f166d0b4eb0162bf5fde2ddec 100644
--- a/gtk/a11y/gtkatspicontext.c
+++ b/gtk/a11y/gtkatspicontext.c
@@ -1224,32 +1224,31 @@ gtk_at_spi_context_platform_change (GtkATContext                *ctx,
 {
   GtkAtSpiContext *self = GTK_AT_SPI_CONTEXT (ctx);
   GtkAccessible *accessible = gtk_at_context_get_accessible (ctx);
-  GtkWidget *widget;
 
-  if (!GTK_IS_WIDGET (accessible))
-    return;
-
-  widget = GTK_WIDGET (accessible);
-  if (!gtk_widget_get_realized (widget))
+  /* Do not emit state changes for unrealized widgets; this may happen during
+   * construction, but since the widget is not realized, there's nothing to be
+   * perceived
+   */
+  if (GTK_IS_WIDGET (accessible) && !gtk_widget_get_realized (GTK_WIDGET (accessible)))
     return;
 
   if (changed_platform & GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSABLE)
     {
-      gboolean state = gtk_accessible_get_platform_state (GTK_ACCESSIBLE (widget),
+      gboolean state = gtk_accessible_get_platform_state (accessible,
                                                           GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE);
       emit_state_changed (self, "focusable", state);
     }
 
   if (changed_platform & GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSED)
     {
-      gboolean state = gtk_accessible_get_platform_state (GTK_ACCESSIBLE (widget),
+      gboolean state = gtk_accessible_get_platform_state (accessible,
                                                           GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED);
       emit_state_changed (self, "focused", state);
     }
 
   if (changed_platform & GTK_ACCESSIBLE_PLATFORM_CHANGE_ACTIVE)
     {
-      gboolean state = gtk_accessible_get_platform_state (GTK_ACCESSIBLE (widget),
+      gboolean state = gtk_accessible_get_platform_state (accessible,
                                                           GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE);
       emit_state_changed (self, "active", state);
 
diff --git a/gtk/a11y/gtkatspitext.c b/gtk/a11y/gtkatspitext.c
index d90fd605e7c445938f0f20c6adca81eb58af6078..65b71e3a914b62cfd8e7e622c5882a298e06374f 100644
--- a/gtk/a11y/gtkatspitext.c
+++ b/gtk/a11y/gtkatspitext.c
@@ -225,9 +225,8 @@ accessible_text_handle_method (GDBusConnection       *connection,
       GVariantBuilder builder = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE ("a{ss}"));
       gboolean include_defaults = FALSE;
       int offset;
-      gsize n_ranges = 0;
-      GtkAccessibleTextRange *ranges = NULL;
-      int start, end;
+      gsize n_attributes = 0;
+      int start = 0, end = 0;
       char **attr_names = NULL;
       char **attr_values = NULL;
       gboolean res;
@@ -237,10 +236,11 @@ accessible_text_handle_method (GDBusConnection       *connection,
       res = gtk_accessible_text_get_attributes_run (accessible_text,
                                                     offset,
                                                     include_defaults,
-                                                    &n_ranges,
-                                                    &ranges,
+                                                    &n_attributes,
                                                     &attr_names,
-                                                    &attr_values);
+                                                    &attr_values,
+                                                    &start,
+                                                    &end);
       if (!res)
         {
           /* No attributes */
@@ -251,17 +251,8 @@ accessible_text_handle_method (GDBusConnection       *connection,
       for (unsigned i = 0; attr_names[i] != NULL; i++)
         g_variant_builder_add (&builder, "{ss}", attr_names[i], attr_values[i]);
 
-      start = 0;
-      end = G_MAXINT;
-      for (unsigned i = 0; i < n_ranges; i++)
-        {
-          start = MAX (start, ranges[i].start);
-          end = MIN (end, start + ranges[i].length);
-        }
-
       g_dbus_method_invocation_return_value (invocation, g_variant_new ("(a{ss}ii)", &builder, start, end));
 
-      g_clear_pointer (&ranges, g_free);
       g_strfreev (attr_names);
       g_strfreev (attr_values);
     }
@@ -456,16 +447,7 @@ accessible_text_get_property (GDBusConnection  *connection,
 
   if (g_strcmp0 (property_name, "CharacterCount") == 0)
     {
-      GBytes *contents;
-      const char *str;
-      gsize len;
-
-      contents = gtk_accessible_text_get_contents (accessible_text, 0, G_MAXUINT);
-      str = g_bytes_get_data (contents, NULL);
-      len = g_utf8_strlen (str, -1);
-      g_bytes_unref (contents);
-
-      return g_variant_new_int32 ((int) len);
+      return g_variant_new_int32 ((int) gtk_accessible_text_get_character_count (accessible_text));
     }
   else if (g_strcmp0 (property_name, "CaretOffset") == 0)
     {
diff --git a/gtk/css/gtkcsslocation.h b/gtk/css/gtkcsslocation.h
index 0371823236a7585d8879a0855d3f592645f5253b..471906425beb7a4a95af4fad7d58b6bacdf7d60a 100644
--- a/gtk/css/gtkcsslocation.h
+++ b/gtk/css/gtkcsslocation.h
@@ -30,7 +30,7 @@ typedef struct _GtkCssLocation GtkCssLocation;
 /**
  * GtkCssLocation:
  *
- * A description of a location inside a CSS stream.
+ * Points at a location inside a CSS stream.
  */
 struct _GtkCssLocation
 {
diff --git a/gtk/css/gtkcsssection.c b/gtk/css/gtkcsssection.c
index ceb8cff40b0f0f07e4b6136b35899281b714dfca..f61ad61cd964cb765c0d506214883944b634d552 100644
--- a/gtk/css/gtkcsssection.c
+++ b/gtk/css/gtkcsssection.c
@@ -144,7 +144,7 @@ gtk_css_section_unref (GtkCssSection *section)
  * Gets the parent section for the given `section`.
  *
  * The parent section is the section that contains this `section`. A special
- * case are sections of  type `GTK_CSS_SECTION_DOCUMEN`T. Their parent will
+ * case are sections of  type `GTK_CSS_SECTION_DOCUMENT`. Their parent will
  * either be `NULL` if they are the original CSS document that was loaded by
  * [method@Gtk.CssProvider.load_from_file] or a section of type
  * `GTK_CSS_SECTION_IMPORT` if it was loaded with an `@import` rule from
diff --git a/gtk/deprecated/gtkappchooserbutton.c b/gtk/deprecated/gtkappchooserbutton.c
index 00c995c1aa8ff3ca88f6e05e358b815803d9bd02..a3d8e76b636ed122b9b0db9deae37a97dc887ddc 100644
--- a/gtk/deprecated/gtkappchooserbutton.c
+++ b/gtk/deprecated/gtkappchooserbutton.c
@@ -23,7 +23,10 @@
  *
  * The `GtkAppChooserButton` lets the user select an application.
  *
- * ![An example GtkAppChooserButton](appchooserbutton.png)
+ * <picture>
+ *   <source srcset="appchooserbutton-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkAppChooserButton" src="appchooserbutton.png">
+ * </picture>
  *
  * Initially, a `GtkAppChooserButton` selects the first application
  * in its list, which will either be the most-recently used application
diff --git a/gtk/deprecated/gtkappchooserdialog.c b/gtk/deprecated/gtkappchooserdialog.c
index 71a74461da4561e26a5e927ad5bf785056b378be..05403250053477e938a80f99e23772035bc4a33e 100644
--- a/gtk/deprecated/gtkappchooserdialog.c
+++ b/gtk/deprecated/gtkappchooserdialog.c
@@ -27,7 +27,10 @@
  *
  * `GtkAppChooserDialog` shows a `GtkAppChooserWidget` inside a `GtkDialog`.
  *
- * ![An example GtkAppChooserDialog](appchooserdialog.png)
+ * <picture>
+ *   <source srcset="appchooserdialog-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkAppChooserDialog" src="appchooserdialog.png">
+ * </picture>
  *
  * Note that `GtkAppChooserDialog` does not have any interesting methods
  * of its own. Instead, you should get the embedded `GtkAppChooserWidget`
diff --git a/gtk/deprecated/gtkassistant.c b/gtk/deprecated/gtkassistant.c
index 485a0d3e19ea69a7dbce762532935b00929716a2..3381f79dda5470265a2ddf8c18dd38698d984300 100644
--- a/gtk/deprecated/gtkassistant.c
+++ b/gtk/deprecated/gtkassistant.c
@@ -26,7 +26,10 @@
  *
  * `GtkAssistant` is used to represent a complex as a series of steps.
  *
- * ![An example GtkAssistant](assistant.png)
+ * <picture>
+ *   <source srcset="assistant-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkAssistant" src="assistant.png">
+ * </picture>
  *
  * Each step consists of one or more pages. `GtkAssistant` guides the user
  * through the pages, and controls the page flow to collect the data needed
@@ -67,7 +70,7 @@
 /**
  * GtkAssistantPage:
  *
- * `GtkAssistantPage` is an auxiliary object used by `GtkAssistant.
+ * `GtkAssistantPage` is an auxiliary object used by `GtkAssistant`.
  *
  * Deprecated: 4.10: This object will be removed in GTK 5
  */
diff --git a/gtk/deprecated/gtkassistant.h b/gtk/deprecated/gtkassistant.h
index 2d86181d86b51b29da6738cd9cf1aa66f2ccdd52..bdf0b45f4377b54ace5198f2666bde325239b112 100644
--- a/gtk/deprecated/gtkassistant.h
+++ b/gtk/deprecated/gtkassistant.h
@@ -53,7 +53,7 @@ G_BEGIN_DECLS
  *  appropriate. No buttons will be shown, and the application must
  *  add its own buttons through gtk_assistant_add_action_widget().
  *
- * Determines the page role inside a `GtkAssistant`.
+ * Determines the role of a page inside a `GtkAssistant`.
  *
  * The role is used to handle buttons sensitivity and visibility.
  *
@@ -63,6 +63,8 @@ G_BEGIN_DECLS
  *
  * The Cancel button will only be shown if the page isn’t “committed”.
  * See gtk_assistant_commit() for details.
+ *
+ * Deprecated: 4.10: `GtkAssistant` will be removed in GTK 5
  */
 typedef enum
 {
diff --git a/gtk/deprecated/gtkcolorbutton.c b/gtk/deprecated/gtkcolorbutton.c
index eceb1266f69c550c88c9579988587500cac8a8b0..4fd77085019e09f435d3d9cbd9433226fdf04dba 100644
--- a/gtk/deprecated/gtkcolorbutton.c
+++ b/gtk/deprecated/gtkcolorbutton.c
@@ -54,7 +54,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * The `GtkColorButton` allows to open a color chooser dialog to change
  * the color.
  *
- * ![An example GtkColorButton](color-button.png)
+ * <picture>
+ *   <source srcset="color-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkColorButton" src="color-button.png">
+ * </picture>
  *
  * It is suitable widget for selecting a color in a preference dialog.
  *
diff --git a/gtk/deprecated/gtkcombobox.c b/gtk/deprecated/gtkcombobox.c
index e6bdc59a25996c968b754c0e230f6c4a2ece5eba..d76f123057bf620db2ab7d4271321e32431844fc 100644
--- a/gtk/deprecated/gtkcombobox.c
+++ b/gtk/deprecated/gtkcombobox.c
@@ -50,7 +50,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * A `GtkComboBox` is a widget that allows the user to choose from a list of
  * valid choices.
  *
- * ![An example GtkComboBox](combo-box.png)
+ * <picture>
+ *   <source srcset="combo-box-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkComboBox" src="combo-box.png">
+ * </picture>
  *
  * The `GtkComboBox` displays the selected choice; when activated, the
  * `GtkComboBox` displays a popup which allows the user to make a new choice.
@@ -106,7 +109,7 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * ## Accessibility
  *
- * `GtkComboBox` uses the %GTK_ACCESSIBLE_ROLE_COMBO_BOX role.
+ * `GtkComboBox` uses the [enum@Gtk.AccessibleRole.combo_box] role.
  *
  * Deprecated: 4.10: Use [class@Gtk.DropDown] instead
  */
diff --git a/gtk/deprecated/gtkcomboboxtext.c b/gtk/deprecated/gtkcomboboxtext.c
index 1ddaa6c75e70e8318aa438fb5dcff1c27c8aa4de..9e8676283a203b6091f30e3c61c2f989af730c3b 100644
--- a/gtk/deprecated/gtkcomboboxtext.c
+++ b/gtk/deprecated/gtkcomboboxtext.c
@@ -36,7 +36,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * A `GtkComboBoxText` is a simple variant of `GtkComboBox` for text-only
  * use cases.
  *
- * ![An example GtkComboBoxText](combo-box-text.png)
+ * <picture>
+ *   <source srcset="combo-box-text-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkComboBoxText" src="combo-box-text.png">
+ * </picture>
  *
  * `GtkComboBoxText` hides the model-view complexity of `GtkComboBox`.
  *
diff --git a/gtk/deprecated/gtkdialog.c b/gtk/deprecated/gtkdialog.c
index 8dd104db023ed035e7397f822aaca9e5b83afed0..f47e753d624b71526e8f00762acba4b3b52943ea 100644
--- a/gtk/deprecated/gtkdialog.c
+++ b/gtk/deprecated/gtkdialog.c
@@ -51,7 +51,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * Dialogs are a convenient way to prompt the user for a small amount
  * of input.
  *
- * ![An example GtkDialog](dialog.png)
+ * <picture>
+ *   <source srcset="dialog-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkDialog" src="dialog.png">
+ * </picture>
  *
  * Typical uses are to display a message, ask a question, or anything else
  * that does not require extensive effort on the user’s part.
diff --git a/gtk/deprecated/gtkfontbutton.c b/gtk/deprecated/gtkfontbutton.c
index d324dec6b9354143759f747d3d4a4fb9cedcbf32..0216497b3c41dcb2c90d0c7483b34f2fb28d579d 100644
--- a/gtk/deprecated/gtkfontbutton.c
+++ b/gtk/deprecated/gtkfontbutton.c
@@ -53,7 +53,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * The `GtkFontButton` allows to open a font chooser dialog to change
  * the font.
  *
- * ![An example GtkFontButton](font-button.png)
+ * <picture>
+ *   <source srcset="font-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkFontButton" src="font-button.png">
+ * </picture>
  *
  * It is suitable widget for selecting a font in a preference dialog.
  *
diff --git a/gtk/deprecated/gtkiconview.c b/gtk/deprecated/gtkiconview.c
index e5d5f71cd5d0f04b9da886cfde841c8675368607..cd2a7442f7a226431db65423b509f70324fa0bff 100644
--- a/gtk/deprecated/gtkiconview.c
+++ b/gtk/deprecated/gtkiconview.c
@@ -56,6 +56,11 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * `GtkIconView` is a widget which displays data in a grid of icons.
  *
+ * <picture>
+ *   <source srcset="icon-view-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkIconView" src="icon-view.png">
+ * </picture>
+ *
  * `GtkIconView` provides an alternative view on a `GtkTreeModel`.
  * It displays the model as a grid of icons with labels. Like
  * [class@Gtk.TreeView], it allows to select one or multiple items
diff --git a/gtk/deprecated/gtkinfobar.c b/gtk/deprecated/gtkinfobar.c
index 5f62f191afbcc3643c414a4108e6930c571e00d7..54fefe4879f78fecd602f71eec0f09f4ad2e6874 100644
--- a/gtk/deprecated/gtkinfobar.c
+++ b/gtk/deprecated/gtkinfobar.c
@@ -56,7 +56,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * `GtkInfoBar` can be used to show messages to the user without a dialog.
  *
- * ![An example GtkInfoBar](info-bar.png)
+ * <picture>
+ *   <source srcset="info-bar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkInfoBar" src="info-bar.png">
+ * </picture>
  *
  * It is often temporarily shown at the top or bottom of a document.
  * In contrast to [class@Gtk.Dialog], which has an action area at the
diff --git a/gtk/deprecated/gtklockbutton.c b/gtk/deprecated/gtklockbutton.c
index 977adc7369d63fcd8c483b96ac93a5397e509b25..394488f7ae0fe49862d348d9c4aff17c0843bc61 100644
--- a/gtk/deprecated/gtklockbutton.c
+++ b/gtk/deprecated/gtklockbutton.c
@@ -36,7 +36,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * `GtkLockButton` is a widget to obtain and revoke authorizations
  * needed to operate the controls.
  *
- * ![An example GtkLockButton](lock-button.png)
+ * <picture>
+ *   <source srcset="lockbutton-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkLockButton" src="lockbutton.png">
+ * </picture>
  *
  * It is typically used in preference dialogs or control panels.
  *
@@ -48,19 +51,28 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * If the user is not currently allowed to perform the action, but can
  * obtain the permission, the widget looks like this:
  *
- * ![](lockbutton-locked.png)
+ * <picture>
+ *   <source srcset="lockbutton-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An locked GtkLockButton" src="lockbutton.png">
+ * </picture>
  *
  * and the user can click the button to request the permission. Depending
  * on the platform, this may pop up an authentication dialog or ask the user
  * to authenticate in some other way. Once the user has obtained the permission,
  * the widget changes to this:
  *
- * ![](lockbutton-unlocked.png)
+ * <picture>
+ *   <source srcset="lockbutton-unlocked-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An unlocked GtkLockButton" src="lockbutton-unlocked.png">
+ * </picture>
  *
  * and the permission can be dropped again by clicking the button. If the user
  * is not able to obtain the permission at all, the widget looks like this:
  *
- * ![](lockbutton-sorry.png)
+ * <picture>
+ *   <source srcset="lockbutton-sorry-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An unobtainable GtkLockButton" src="lockbutton-sorry.png">
+ * </picture>
  *
  * If the user has the permission and cannot drop it, the button is hidden.
  *
diff --git a/gtk/deprecated/gtkshortcutswindow.c b/gtk/deprecated/gtkshortcutswindow.c
index f2d9e762d9bc0cf7f7fd5dfb6d069144d37af84d..d171cfd58143d25d133b8108beba5f707fe671a1 100644
--- a/gtk/deprecated/gtkshortcutswindow.c
+++ b/gtk/deprecated/gtkshortcutswindow.c
@@ -69,7 +69,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * # A simple example:
  *
- * ![](gedit-shortcuts.png)
+ * <picture>
+ *   <source srcset="gedit-shortcuts-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="A simple example" src="gedit-shortcuts.png">
+ * </picture>
  *
  * This example has as single section. As you can see, the shortcut groups
  * are arranged in columns, and spread across several pages if there are too
@@ -79,7 +82,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * # An example with multiple views:
  *
- * ![](clocks-shortcuts.png)
+ * <picture>
+ *   <source srcset="clocks-shortcuts-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example with multiple views" src="clocks-shortcuts.png">
+ * </picture>
  *
  * This example shows a `GtkShortcutsWindow` that has been configured to show only
  * the shortcuts relevant to the “Stopwatch” view.
@@ -88,7 +94,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * # An example with multiple sections:
  *
- * ![](builder-shortcuts.png)
+ * <picture>
+ *   <source srcset="builder-shortcuts-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example with multiple sections" src="builder-shortcuts.png">
+ * </picture>
  *
  * This example shows a `GtkShortcutsWindow` with two sections, “Editor Shortcuts”
  * and “Terminal Shortcuts”.
diff --git a/gtk/deprecated/gtkstatusbar.c b/gtk/deprecated/gtkstatusbar.c
index 6f9a40b6e5a296d69883485dc15be1cf50110186..fb98f350ba3ef6e5b1756f4b23d6204a2ab5703a 100644
--- a/gtk/deprecated/gtkstatusbar.c
+++ b/gtk/deprecated/gtkstatusbar.c
@@ -44,7 +44,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * A `GtkStatusbar` widget is usually placed along the bottom of an application's
  * main [class@Gtk.Window].
  *
- * ![An example GtkStatusbar](statusbar.png)
+ * picture>
+ *   <source srcset="statusbar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkStatusbar" src="statusbar.png">
+ * </picture>
  *
  * A `GtkStatusBar` may provide a regular commentary of the application's
  * status (as is usually the case in a web browser, for example), or may be
diff --git a/gtk/deprecated/gtktreeview.c b/gtk/deprecated/gtktreeview.c
index f26aced4c44a5aa6ae4c07d472052055d9e5941d..d3612f2acfb6b65d0bf9a01a1959b9995d4d5ae7 100644
--- a/gtk/deprecated/gtktreeview.c
+++ b/gtk/deprecated/gtktreeview.c
@@ -76,6 +76,11 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * A widget for displaying both trees and lists
  *
+ * <picture>
+ *   <source srcset="list-and-tree-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkTreeView" src="list-and-tree.png">
+ * </picture>
+ *
  * Widget that displays any object that implements the [iface@Gtk.TreeModel] interface.
  *
  * Please refer to the [tree widget conceptual overview](section-tree-widget.html)
diff --git a/gtk/deprecated/gtkvolumebutton.c b/gtk/deprecated/gtkvolumebutton.c
index ab6655b9bcd6f60fd640dd74fadff41b444b223b..59c686561935658d883ae0f0776692e74fc2ad28 100644
--- a/gtk/deprecated/gtkvolumebutton.c
+++ b/gtk/deprecated/gtkvolumebutton.c
@@ -43,7 +43,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  * `GtkVolumeButton` is a `GtkScaleButton` subclass tailored for
  * volume control.
  *
- * ![An example GtkVolumeButton](volumebutton.png)
+ * <picture>
+ *   <source srcset="volumebutton-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkVolumeButton" src="volumebutton.png">
+ * </picture>
  *
  * Deprecated: 4.10: This widget will be removed in GTK 5
  */
diff --git a/gtk/gtkaboutdialog.c b/gtk/gtkaboutdialog.c
index 7bcd3c2f3c2c19e089b6a499da86be1422df723d..8e0ed2d71ef7bae4f8331238bd6ae382074c7145 100644
--- a/gtk/gtkaboutdialog.c
+++ b/gtk/gtkaboutdialog.c
@@ -58,7 +58,7 @@
 /**
  * GtkAboutDialog:
  *
- * A simple way to display information about a program.
+ * Displays information about a program.
  *
  * The shown information includes the programs' logo, name, copyright,
  * website and license. It is also possible to give credits to the authors,
@@ -67,7 +67,10 @@
  * An about dialog is typically opened when the user selects the `About`
  * option from the `Help` menu. All parts of the dialog are optional.
  *
- * ![An example GtkAboutDialog](aboutdialog.png)
+ * <picture>
+ *   <source srcset="aboutdialot-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkAboutDialog" src="aboutdialog.png">
+ * </picture>
  *
  * About dialogs often contain links and email addresses. `GtkAboutDialog`
  * displays these as clickable links. By default, it calls [method@Gtk.FileLauncher.launch]
diff --git a/gtk/gtkaccelgroup.c b/gtk/gtkaccelgroup.c
index 112ec9a996c7b5467f3dca3b8abeb8cfa25eaf00..352aa0e1a2ea34ac39e557f8034052fbb4c3a965 100644
--- a/gtk/gtkaccelgroup.c
+++ b/gtk/gtkaccelgroup.c
@@ -41,11 +41,11 @@
  * Determines whether a given keyval and modifier mask constitute
  * a valid keyboard accelerator.
  *
- * For example, the %GDK_KEY_a keyval plus %GDK_CONTROL_MASK mark is valid,
+ * For example, the `GDK_KEY_a` keyval plus `GDK_CONTROL_MASK` mask is valid,
  * and matches the “Ctrl+a” accelerator. But, you can't, for instance, use
- * the %GDK_KEY_Control_L keyval as an accelerator.
+ * the `GDK_KEY_Control_L` keyval as an accelerator.
  *
- * Returns: %TRUE if the accelerator is valid
+ * Returns: true if the accelerator is valid
  */
 gboolean
 gtk_accelerator_valid (guint           keyval,
@@ -250,7 +250,7 @@ is_keycode (const char *string)
  * If the parse fails, @accelerator_key, @accelerator_mods and
  * @accelerator_codes will be set to 0 (zero).
  *
- * Returns: %TRUE if parsing succeeded
+ * Returns: true if parsing succeeded
  */
 gboolean
 gtk_accelerator_parse_with_keycode (const char      *accelerator,
@@ -518,13 +518,13 @@ gtk_accelerator_parse (const char      *accelerator,
 
 /**
  * gtk_accelerator_name_with_keycode:
- * @display: (nullable): a `GdkDisplay` or %NULL to use the default display
+ * @display: (nullable): a `GdkDisplay`
  * @accelerator_key: accelerator keyval
  * @keycode: accelerator keycode
  * @accelerator_mods: accelerator modifier mask
  *
  * Converts an accelerator keyval and modifier mask
- * into a string parseable by gtk_accelerator_parse_with_keycode().
+ * into a string that can be parsed by [func@Gtk.accelerator_parse_with_keycode].
  *
  * This is similar to [func@Gtk.accelerator_name] but handling keycodes.
  * This is only useful for system-level components, applications
@@ -559,9 +559,9 @@ gtk_accelerator_name_with_keycode (GdkDisplay      *display,
  * @accelerator_mods: accelerator modifier mask
  *
  * Converts an accelerator keyval and modifier mask into a string
- * parseable by gtk_accelerator_parse().
+ * that can be parsed by [func@Gtk.accelerator_parse].
  *
- * For example, if you pass in %GDK_KEY_q and %GDK_CONTROL_MASK,
+ * For example, if you pass in `GDK_KEY_q` and `GDK_CONTROL_MASK`,
  * this function returns `<Control>q`.
  *
  * If you need to display accelerators in the user interface,
@@ -634,7 +634,7 @@ gtk_accelerator_name (guint           accelerator_key,
 
 /**
  * gtk_accelerator_get_label_with_keycode:
- * @display: (nullable): a `GdkDisplay` or %NULL to use the default display
+ * @display: (nullable): a `GdkDisplay`
  * @accelerator_key: accelerator keyval
  * @keycode: accelerator keycode
  * @accelerator_mods: accelerator modifier mask
@@ -990,7 +990,7 @@ gtk_accelerator_print_label (GString        *gstring,
  *
  * The modifier mask determines which modifiers are considered significant
  * for keyboard accelerators. This includes all keyboard modifiers except
- * for %GDK_LOCK_MASK.
+ * for `GDK_LOCK_MASK`.
  *
  * Returns: the modifier mask for accelerators
  */
diff --git a/gtk/gtkaccessible.c b/gtk/gtkaccessible.c
index efaf5d17c2e90ef0be373575ba0652382f3a7d31..a390db15a08bec57810debaa7ed7f7421ac7e202 100644
--- a/gtk/gtkaccessible.c
+++ b/gtk/gtkaccessible.c
@@ -26,7 +26,7 @@
  * Every accessible implementation has:
  *
  *  - a “role”, represented by a value of the [enum@Gtk.AccessibleRole] enumeration
- *  - an “attribute”, represented by a set of [enum@Gtk.AccessibleState],
+ *  - “attributes”, represented by a set of [enum@Gtk.AccessibleState],
  *    [enum@Gtk.AccessibleProperty] and [enum@Gtk.AccessibleRelation] values
  *
  * The role cannot be changed after instantiating a `GtkAccessible`
@@ -42,8 +42,10 @@
  * by reimplementing the [vfunc@Gtk.Accessible.get_accessible_parent],
  * [vfunc@Gtk.Accessible.get_first_accessible_child] and
  * [vfunc@Gtk.Accessible.get_next_accessible_sibling] virtual functions.
+ *
  * Note that you can not create a top-level accessible object as of now,
  * which means that you must always have a parent accessible object.
+ *
  * Also note that when an accessible object does not correspond to a widget,
  * and it has children, whose implementation you don't control,
  * it is necessary to ensure the correct shape of the a11y tree
@@ -1103,12 +1105,15 @@ gtk_accessible_role_is_abstract (GtkAccessibleRole role)
  * AT backends should use [method@Gtk.Accessible.get_platform_state]
  * to obtain the actual state.
  */
-void
+static void
 gtk_accessible_platform_changed (GtkAccessible               *self,
                                  GtkAccessiblePlatformChange  change)
 {
   GtkATContext *context;
 
+  if (change == 0)
+    return;
+
   if (GTK_IS_WIDGET (self) &&
       gtk_widget_get_root (GTK_WIDGET (self)) == NULL)
     return;
@@ -1160,6 +1165,48 @@ gtk_accessible_get_platform_state (GtkAccessible              *self,
   return GTK_ACCESSIBLE_GET_IFACE (self)->get_platform_state (self, state);
 }
 
+/**
+ * gtk_accessible_update_platform_state:
+ * @self: an accessible object
+ * @state: the platform state to update
+ *
+ * Informs ATs that the platform state has changed.
+ *
+ * This function should be used by `GtkAccessible` implementations that
+ * have a platform state but are not widgets. Widgets handle platform
+ * states automatically.
+ *
+ * Since: 4.18
+ */
+void
+gtk_accessible_update_platform_state (GtkAccessible              *self,
+                                      GtkAccessiblePlatformState  state)
+{
+  GtkAccessiblePlatformChange change = 0;
+
+  g_return_if_fail (GTK_IS_ACCESSIBLE (self));
+
+  switch (state)
+    {
+    case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE:
+      change |= GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSABLE;
+      break;
+
+    case GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED:
+      change |= GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSED;
+      break;
+
+    case GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE:
+      change |= GTK_ACCESSIBLE_PLATFORM_CHANGE_ACTIVE;
+      break;
+
+    default:
+      g_assert_not_reached ();
+    }
+
+  gtk_accessible_platform_changed (self, change);
+}
+
 /*< private >
  * gtk_accessible_bounds_changed:
  * @self: an accessible object
diff --git a/gtk/gtkaccessible.h b/gtk/gtkaccessible.h
index 9826e95f113dbe504b51f2dac1329a5e7e006604..5bafbf3b6631212bdd94428bf182c93ab97888d6 100644
--- a/gtk/gtkaccessible.h
+++ b/gtk/gtkaccessible.h
@@ -157,7 +157,7 @@ struct _GtkAccessibleInterface
 /**
  * GtkAccessibleList:
  *
- * A boxed type which wraps a list of references to GtkAccessible objects.
+ * Wraps a list of references to [iface@Gtk.Accessible] objects.
  *
  * Since: 4.14
  */
@@ -265,4 +265,8 @@ void gtk_accessible_announce (GtkAccessible                     *self,
                               const char                        *message,
                               GtkAccessibleAnnouncementPriority  priority);
 
+GDK_AVAILABLE_IN_4_18
+void gtk_accessible_update_platform_state (GtkAccessible              *self,
+                                           GtkAccessiblePlatformState  state);
+
 G_END_DECLS
diff --git a/gtk/gtkaccessibleprivate.h b/gtk/gtkaccessibleprivate.h
index b26cd02086136b01637a6d1ccdbe708b8183c2e9..18621f325a4aa26e4bf61b44046b596dc8f784fb 100644
--- a/gtk/gtkaccessibleprivate.h
+++ b/gtk/gtkaccessibleprivate.h
@@ -99,7 +99,4 @@ void            gtk_accessible_update_children  (GtkAccessible           *self,
 
 void            gtk_accessible_bounds_changed   (GtkAccessible *self);
 
-void            gtk_accessible_platform_changed (GtkAccessible                *self,
-                                                 GtkAccessiblePlatformChange   change);
-
 G_END_DECLS
diff --git a/gtk/gtkaccessiblerange.c b/gtk/gtkaccessiblerange.c
index ad7302b95d64aa383c4210c5c7d3c483fea32cc4..c4f4799302df770b726584c4a93d193fd53a77eb 100644
--- a/gtk/gtkaccessiblerange.c
+++ b/gtk/gtkaccessiblerange.c
@@ -7,11 +7,15 @@
 /**
  * GtkAccessibleRange:
  *
- * This interface describes ranged controls, e.g. controls which have a single
- * value within an allowed range and that can optionally be changed by the user.
+ * An interface for accessible objects containing a numeric value.
  *
- * This interface is expected to be implemented by controls using the following
- * roles:
+ * `GtkAccessibleRange` describes ranged controls for Assistive Technologies.
+ *
+ * Ranged controls have a single value within an allowed range that can
+ * optionally be changed by the user.
+ *
+ * This interface is expected to be implemented by controls using the
+ * following roles:
  *
  * - `GTK_ACCESSIBLE_ROLE_METER`
  * - `GTK_ACCESSIBLE_ROLE_PROGRESS_BAR`
diff --git a/gtk/gtkaccessibletext.c b/gtk/gtkaccessibletext.c
index 13129514606d3e44b8289ca7d764da851668d73e..7e3855de2c2af0cc879d1815e5bc6fbb4ebf49bb 100644
--- a/gtk/gtkaccessibletext.c
+++ b/gtk/gtkaccessibletext.c
@@ -184,6 +184,33 @@ gtk_accessible_text_get_contents_at (GtkAccessibleText            *self,
   return nul_terminate_contents (bytes);
 }
 
+/*< private >
+ * gtk_accessible_text_get_character_count:
+ * @self: the accessible object
+ *
+ * Returns the amount of characters that the text contains.
+ *
+ * Returns: the length of the text, in characters
+ *
+ * Since: 4.18
+ */
+unsigned int
+gtk_accessible_text_get_character_count (GtkAccessibleText *self)
+{
+  GBytes *contents;
+  const char *str;
+  gsize len;
+
+  g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), 0);
+
+  contents = gtk_accessible_text_get_contents (self, 0, G_MAXUINT);
+  str = g_bytes_get_data (contents, NULL);
+  len = g_utf8_strlen (str, -1);
+  g_bytes_unref (contents);
+
+  return len;
+}
+
 /*< private >
  * gtk_accessible_text_get_caret_position:
  * @self: the accessible object
@@ -318,13 +345,13 @@ gtk_accessible_text_get_default_attributes (GtkAccessibleText   *self,
  * @offset: the offset, in characters
  * @include_defaults: whether to include the default attributes in the
  *   returned array
- * @n_ranges: (out): the number of attributes
- * @ranges: (out) (array length=n_attributes) (optional): the ranges of the attributes
- *   inside the accessible object
+ * @n_attributes: (out): the number of attributes
  * @attribute_names: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
  *   the names of the attributes inside the accessible object
  * @attribute_values: (out) (array zero-terminated=1) (element-type utf8) (optional) (transfer full):
  *   the values of the attributes inside the accessible object
+ * @start (out): the start index of the attribute run (portion of text where attributes are the same)
+ * @end (out): the end index of the attribute run (portion of text where attributes are the same)
  *
  * Retrieves the text attributes inside the accessible object.
  *
@@ -334,25 +361,26 @@ gtk_accessible_text_get_default_attributes (GtkAccessibleText   *self,
  * - a name, typically in the form of a reverse DNS identifier
  * - a value
  *
- * If this function returns true, `n_ranges` will be set to a value
- * greater than or equal to one, @ranges will be set to a newly
- * allocated array of [struct#Gtk.AccessibleTextRange] which should
- * be freed with g_free(), @attribute_names and @attribute_values
- * will be set to string arrays that should be freed with g_strfreev().
+ * If this function returns true, `n_attributes` will be set to a value
+ * greater than or equal to one, @attribute_names and @attribute_values
+ * will be set to string arrays that should be freed with g_strfreev()
+ * and @start and @end will be set to the start and end (character) index
+ * of the run.
  *
  * Returns: true if the accessible object has at least an attribute,
  *   and false otherwise
  *
- * Since: 4.14
+ * Since: 4.18
  */
 gboolean
 gtk_accessible_text_get_attributes_run (GtkAccessibleText        *self,
                                         unsigned int              offset,
                                         gboolean                  include_defaults,
-                                        gsize                    *n_ranges,
-                                        GtkAccessibleTextRange  **ranges,
+                                        gsize                    *n_attributes,
                                         char                   ***attribute_names,
-                                        char                   ***attribute_values)
+                                        char                   ***attribute_values,
+                                        int                      *start,
+                                        int                      *end)
 {
   GHashTable *attrs;
   GHashTableIter attr_iter;
@@ -361,6 +389,7 @@ gtk_accessible_text_get_attributes_run (GtkAccessibleText        *self,
   gboolean res;
   GStrvBuilder *names_builder;
   GStrvBuilder *values_builder;
+  GtkAccessibleTextRange *ranges = NULL;
 
   g_return_val_if_fail (GTK_IS_ACCESSIBLE_TEXT (self), FALSE);
 
@@ -381,12 +410,14 @@ gtk_accessible_text_get_attributes_run (GtkAccessibleText        *self,
 
       g_free (attr_names);
       g_free (attr_values);
+      attr_names = NULL;
+      attr_values = NULL;
     }
 
   res = gtk_accessible_text_get_attributes (self,
                                             offset,
-                                            n_ranges,
-                                            ranges,
+                                            n_attributes,
+                                            &ranges,
                                             &attr_names,
                                             &attr_values);
 
@@ -399,24 +430,34 @@ gtk_accessible_text_get_attributes_run (GtkAccessibleText        *self,
       return FALSE;
     }
 
+  *start = 0;
+  *end = G_MAXINT;
+
   /* The text attributes override the default ones */
-  for (unsigned i = 0; i < *n_ranges; i++)
+  for (unsigned i = 0; i < *n_attributes; i++)
     {
       g_hash_table_insert (attrs,
                            g_steal_pointer (&attr_names[i]),
                            g_steal_pointer (&attr_values[i]));
+      *start = MAX (*start, ranges[i].start);
+      *end = MIN (*end, *start + ranges[i].length);
     }
 
+  if (*end == G_MAXINT)
+    *end = gtk_accessible_text_get_character_count (self);
+
   g_free (attr_names);
   g_free (attr_values);
 
   names_builder = g_strv_builder_new ();
   values_builder = g_strv_builder_new ();
   g_hash_table_iter_init (&attr_iter, attrs);
+  *n_attributes = 0;
   while (g_hash_table_iter_next (&attr_iter, &key, &value))
     {
       g_strv_builder_add (names_builder, key);
       g_strv_builder_add (values_builder, value);
+      (*n_attributes)++;
     }
 
   *attribute_names = g_strv_builder_end (names_builder);
@@ -425,8 +466,9 @@ gtk_accessible_text_get_attributes_run (GtkAccessibleText        *self,
   g_strv_builder_unref (names_builder);
   g_strv_builder_unref (values_builder);
   g_hash_table_unref (attrs);
+  g_clear_pointer (&ranges, g_free);
 
-  return TRUE;
+  return *n_attributes > 0;
 }
 
 /*< private >
diff --git a/gtk/gtkaccessibletextprivate.h b/gtk/gtkaccessibletextprivate.h
index 2efe55221e4c130cecee16022f9cd683dd0744f1..807ed3619c5c4a61436de7ca9aafb3113ebd5950 100644
--- a/gtk/gtkaccessibletextprivate.h
+++ b/gtk/gtkaccessibletextprivate.h
@@ -22,6 +22,9 @@ gtk_accessible_text_get_contents_at (GtkAccessibleText            *self,
                                      unsigned int                 *start,
                                      unsigned int                 *end);
 
+unsigned int
+gtk_accessible_text_get_character_count (GtkAccessibleText *self);
+
 unsigned int
 gtk_accessible_text_get_caret_position (GtkAccessibleText *self);
 
@@ -47,10 +50,11 @@ gboolean
 gtk_accessible_text_get_attributes_run (GtkAccessibleText        *self,
                                         unsigned int              offset,
                                         gboolean                  include_defaults,
-                                        gsize                    *n_ranges,
-                                        GtkAccessibleTextRange  **ranges,
+                                        gsize                    *n_attributes,
                                         char                   ***attribute_names,
-                                        char                   ***attribute_values);
+                                        char                   ***attribute_values,
+                                        int                      *start,
+                                        int                      *end);
 
 gboolean
 gtk_accessible_text_get_extents (GtkAccessibleText *self,
diff --git a/gtk/gtkactionable.c b/gtk/gtkactionable.c
index 5919ec9faf087002e003a1833be956f466e31fdc..648398708c4b1b3af79884607223248beeac1820 100644
--- a/gtk/gtkactionable.c
+++ b/gtk/gtkactionable.c
@@ -26,8 +26,7 @@
 /**
  * GtkActionable:
  *
- * The `GtkActionable` interface provides a convenient way of associating
- * widgets with actions.
+ * Provides a way to associate widgets with actions.
  *
  * It primarily consists of two properties: [property@Gtk.Actionable:action-name]
  * and [property@Gtk.Actionable:action-target]. There are also some convenience
diff --git a/gtk/gtkactionbar.c b/gtk/gtkactionbar.c
index 053c0fb0478c8ce4540c5534a9d54435b5b7b89f..e6ded7dd7b777b402975c2dfc67f9adefc4a0fbc 100644
--- a/gtk/gtkactionbar.c
+++ b/gtk/gtkactionbar.c
@@ -34,9 +34,12 @@
 /**
  * GtkActionBar:
  *
- * Designed to present contextual actions.
+ * Presents contextual actions.
  *
- * ![An example GtkActionBar](action-bar.png)
+ * <picture>
+ *   <source srcset="action-bar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkActionBar" src="action-bar.png">
+ * </picture>
  *
  * `GtkActionBar` is expected to be displayed below the content and expand
  * horizontally to fill the area.
@@ -68,7 +71,7 @@
  *
  * A `GtkActionBar`'s CSS node is called `actionbar`. It contains a `revealer`
  * subnode, which contains a `box` subnode, which contains two `box` subnodes at
- * the start and end of the action bar, with `start` and `end style classes
+ * the start and end of the action bar, with `start` and `end` style classes
  * respectively, as well as a center node that represents the center child.
  *
  * Each of the boxes contains children packed for that side.
diff --git a/gtk/gtkapplication-quartz-menu.c b/gtk/gtkapplication-quartz-menu.c
index d1dc3876dd3fa352e08ac849d851d24de6caabe3..b4f116c711743eefa45c81cb2159cb5093827ff1 100644
--- a/gtk/gtkapplication-quartz-menu.c
+++ b/gtk/gtkapplication-quartz-menu.c
@@ -22,7 +22,6 @@
 
 #include "gtkapplicationprivate.h"
 #include "gtkicontheme.h"
-#include "gtkquartz.h"
 #include "gtkprivate.h"
 #include "gtkwidgetprivate.h"
 
@@ -78,63 +77,6 @@ tracker_item_changed (GObject    *object,
     }
 }
 
-#if 0
-static void
-icon_loaded (GObject      *object,
-             GAsyncResult *result,
-             gpointer      user_data)
-{
-  GtkIconPaintable *icon = GTK_ICON_PAINTABLE (object);
-  GNSMenuItem *item = user_data;
-  GError *error = NULL;
-  GdkPixbuf *pixbuf;
-  int scale = 1;
-
-  /* we need a run-time check for the backingScaleFactor selector because we
-   * may be compiling on a 10.7 framework, but targeting a 10.6 one
-   */
-  if ([[NSScreen mainScreen] respondsToSelector:@selector(backingScaleFactor)])
-    scale = roundf ([[NSScreen mainScreen] backingScaleFactor]);
-
-  pixbuf = gtk_icon_load_symbolic_finish (icon, result, NULL, &error);
-
-  if (pixbuf != NULL)
-    {
-      cairo_t *cr;
-      cairo_surface_t *surface;
-      NSImage *image;
-
-      surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-                                            gdk_pixbuf_get_width (pixbuf),
-                                            gdk_pixbuf_get_height (pixbuf));
-
-      cr = cairo_create (surface);
-      cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-      gdk_cairo_set_source_pixbuf (cr, pixbuf, 0, 0);
-      cairo_paint (cr);
-      cairo_destroy (cr);
-      g_object_unref (pixbuf);
-
-      cairo_surface_set_device_scale (surface, scale, scale);
-      image = _gtk_quartz_create_image_from_surface (surface);
-      cairo_surface_destroy (surface);
-
-      if (image != NULL)
-        [item setImage:image];
-      else
-        [item setImage:nil];
-    }
-  else
-    {
-      /* on failure to load, clear the old icon */
-      if (!g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-        [item setImage:nil];
-
-      g_error_free (error);
-    }
-}
-#endif
-
 @implementation GNSMenuItem
 
 - (id)initWithTrackerItem:(GtkMenuTrackerItem *)aTrackerItem
diff --git a/gtk/gtkapplication-wayland.c b/gtk/gtkapplication-wayland.c
index f002c3fc6650f02b6c2d400212372ff63ff66a5b..6630bfa7d8330f83448c69a6c73fdd76c7b4b131 100644
--- a/gtk/gtkapplication-wayland.c
+++ b/gtk/gtkapplication-wayland.c
@@ -113,6 +113,30 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
 G_GNUC_END_IGNORE_DEPRECATIONS
 }
 
+static void
+gtk_application_impl_wayland_window_removed (GtkApplicationImpl *impl,
+                                             GtkWindow          *window)
+{
+  GtkApplicationImplWayland *wayland = (GtkApplicationImplWayland *) impl;
+  GSList *iter;
+
+  for (iter = wayland->inhibitors; iter; iter = iter->next)
+    {
+      GtkApplicationWaylandInhibitor *inhibitor = iter->data;
+
+      if (inhibitor->surface && inhibitor->surface == gtk_native_get_surface (GTK_NATIVE (window)))
+        {
+          inhibitor->surface = NULL;
+
+          if (!inhibitor->dbus_cookie)
+            {
+              gtk_application_wayland_inhibitor_free (inhibitor);
+              wayland->inhibitors = g_slist_delete_link (wayland->inhibitors, iter);
+            }
+        }
+    }
+}
+
 static guint
 gtk_application_impl_wayland_inhibit (GtkApplicationImpl         *impl,
                                       GtkWindow                  *window,
@@ -132,7 +156,7 @@ gtk_application_impl_wayland_inhibit (GtkApplicationImpl         *impl,
   inhibitor->flags = flags;
   wayland->inhibitors = g_slist_prepend (wayland->inhibitors, inhibitor);
 
-  if (flags & GTK_APPLICATION_INHIBIT_IDLE)
+  if (flags & GTK_APPLICATION_INHIBIT_IDLE && impl->application == gtk_window_get_application (window))
     {
       surface = gtk_native_get_surface (GTK_NATIVE (window));
       if (GDK_IS_WAYLAND_TOPLEVEL (surface))
@@ -195,6 +219,8 @@ gtk_application_impl_wayland_class_init (GtkApplicationImplWaylandClass *class)
     gtk_application_impl_wayland_handle_window_realize;
   impl_class->before_emit =
     gtk_application_impl_wayland_before_emit;
+  impl_class->window_removed =
+    gtk_application_impl_wayland_window_removed;
   impl_class->inhibit =
     gtk_application_impl_wayland_inhibit;
   impl_class->uninhibit =
diff --git a/gtk/gtkapplication.c b/gtk/gtkapplication.c
index fe308d377ac2117ee01f76f4487735f46f5094ec..2b7094b757a64ddc0afb18be7d208aaaa39785ae 100644
--- a/gtk/gtkapplication.c
+++ b/gtk/gtkapplication.c
@@ -278,6 +278,41 @@ gtk_application_set_window_icon (GtkApplication *application)
   gtk_window_set_default_icon_name (appid);
 }
 
+#if defined(GDK_WINDOWING_WAYLAND) || defined(GDK_WINDOWING_X11)
+static void
+gtk_application_identify_to_portal (GtkApplication *application)
+{
+  GVariantBuilder builder;
+  GApplication *g_application = G_APPLICATION (application);
+  GDBusConnection *session_bus;
+  const char *application_id;
+
+  session_bus = g_application_get_dbus_connection (g_application);
+  if (!session_bus)
+    return;
+
+  application_id = g_application_get_application_id (g_application);
+  if (!application_id)
+    return;
+
+  g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+
+  /* Intentionally ignore errors */
+  g_dbus_connection_call (session_bus,
+                          PORTAL_BUS_NAME,
+                          PORTAL_OBJECT_PATH,
+                          "org.freedesktop.host.portal.Registry",
+                          "Register",
+                          g_variant_new ("(sa{sv})",
+                                         application_id,
+                                         &builder),
+                          NULL,
+                          G_DBUS_CALL_FLAGS_NO_AUTO_START,
+                          -1,
+                          NULL, NULL, NULL);
+}
+#endif
+
 static void
 gtk_application_startup (GApplication *g_application)
 {
@@ -292,6 +327,11 @@ gtk_application_startup (GApplication *g_application)
 
   gtk_action_muxer_insert (priv->muxer, "app", G_ACTION_GROUP (application));
 
+#if defined(GDK_WINDOWING_WAYLAND) || defined(GDK_WINDOWING_X11)
+  if (!gdk_running_in_sandbox ())
+    gtk_application_identify_to_portal (application);
+#endif
+
   before2 = GDK_PROFILER_CURRENT_TIME;
   gtk_init ();
   gdk_profiler_end_mark (before2, "gtk_init", NULL);
@@ -980,7 +1020,7 @@ gtk_application_get_menubar (GtkApplication *application)
  * If a window is given, the session manager may point the user to
  * this window to find out more about why the action is inhibited.
  *
- * The cookie tha tis returned by this function  should be used as an
+ * The cookie that is returned by this function  should be used as an
  * argument to [method@Gtk.Application.uninhibit] in order to remove
  * the request.
  *
diff --git a/gtk/gtkapplicationwindow.c b/gtk/gtkapplicationwindow.c
index 8b0382f2b1af2b08618d8cf0f8901bcb615689d5..06606f9fed64e86e1994937681857243b031ec6e 100644
--- a/gtk/gtkapplicationwindow.c
+++ b/gtk/gtkapplicationwindow.c
@@ -57,13 +57,12 @@
  * For instance, on OS X, both menus will be displayed remotely;
  * on Windows neither will be.
  *
- * If the desktop environment does not display the menubar, then
- * `GtkApplicationWindow` will automatically show a menubar for it.
- * This behaviour can be overridden with the
- * [property@Gtk.ApplicationWindow:show-menubar] property. If the
- * desktop environment does not display the application menu, then
- * it will automatically be included in the menubar or in the windows
- * client-side decorations.
+ * If the desktop environment does not display the menubar, it can be shown in
+ * the `GtkApplicationWindow` by setting the
+ * [property@Gtk.ApplicationWindow:show-menubar] property to true. If the
+ * desktop environment does not display the application menu, then it will
+ * automatically be included in the menubar or in the window’s client-side
+ * decorations.
  *
  * See [class@Gtk.PopoverMenu] for information about the XML language
  * used by `GtkBuilder` for menu models.
diff --git a/gtk/gtkaspectframe.c b/gtk/gtkaspectframe.c
index 4215d8eecaeeb0c7c035dfc88867c510ae47a010..ecae842f8f0bf0661aef9418362a8b00c56d06c3 100644
--- a/gtk/gtkaspectframe.c
+++ b/gtk/gtkaspectframe.c
@@ -30,7 +30,7 @@
 /**
  * GtkAspectFrame:
  *
- * `GtkAspectFrame` preserves the aspect ratio of its child.
+ * Preserves the aspect ratio of its child.
  *
  * The frame can respect the aspect ratio of the child widget,
  * or use its own aspect ratio.
@@ -41,9 +41,9 @@
  *
  * # Accessibility
  *
- * Until GTK 4.10, `GtkAspectFrame` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
+ * Until GTK 4.10, `GtkAspectFrame` used the [enum@Gtk.AccessibleRole.group] role.
  *
- * Starting from GTK 4.12, `GtkAspectFrame` uses the `GTK_ACCESSIBLE_ROLE_GENERIC` role.
+ * Starting from GTK 4.12, `GtkAspectFrame` uses the [enum@Gtk.AccessibleRole.generic] role.
 
  */
 
diff --git a/gtk/gtkatcontext.c b/gtk/gtkatcontext.c
index 88357931652e7497eaa447683e8416a0eb79fb21..9770c8ef0ed7015d9a0da18f46901fd8b8f65051 100644
--- a/gtk/gtkatcontext.c
+++ b/gtk/gtkatcontext.c
@@ -21,8 +21,7 @@
 /**
  * GtkATContext:
  *
- * `GtkATContext` is an abstract class provided by GTK to communicate to
- * platform-specific assistive technologies API.
+ * Communicates with platform-specific assistive technologies API.
  *
  * Each platform supported by GTK implements a `GtkATContext` subclass, and
  * is responsible for updating the accessible state in response to state
diff --git a/gtk/gtkbinlayout.c b/gtk/gtkbinlayout.c
index a8e1e8cf01db6847d06106217c7e8d8c6f1235ca..4a496ce6cbca5fe4d7533cb6d3349d98d0f0d84f 100644
--- a/gtk/gtkbinlayout.c
+++ b/gtk/gtkbinlayout.c
@@ -18,8 +18,7 @@
 /**
  * GtkBinLayout:
  *
- * `GtkBinLayout` is a `GtkLayoutManager` subclass useful for create "bins" of
- * widgets.
+ * A layout manager for widgets with a single child.
  *
  * `GtkBinLayout` will stack each child of a widget on top of each other,
  * using the [property@Gtk.Widget:hexpand], [property@Gtk.Widget:vexpand],
diff --git a/gtk/gtkbitset.c b/gtk/gtkbitset.c
index c7451947197ab80e7f9464a32384e66a69d731e0..f967038b342db09cf073ad055042cdd505477459 100644
--- a/gtk/gtkbitset.c
+++ b/gtk/gtkbitset.c
@@ -26,9 +26,9 @@
 /**
  * GtkBitset: (ref-func gtk_bitset_ref) (unref-func gtk_bitset_unref)
  *
- * A `GtkBitset` represents a set of unsigned integers.
+ * A set of unsigned integers.
  *
- * Another name for this data structure is "bitmap".
+ * Another name for this data structure is “bitmap”.
  *
  * The current implementation is based on [roaring bitmaps](https://roaringbitmap.org/).
  *
diff --git a/gtk/gtkbitset.h b/gtk/gtkbitset.h
index cca01a37370aeccb4c406d75af9be2f4d24693cd..f140c06707a120a8639cfe687bd9612f25592370 100644
--- a/gtk/gtkbitset.h
+++ b/gtk/gtkbitset.h
@@ -133,8 +133,9 @@ void                    gtk_bitset_splice                       (GtkBitset
 /**
  * GtkBitsetIter:
  *
- * An opaque, stack-allocated struct for iterating
- * over the elements of a `GtkBitset`.
+ * Iterates over the elements of a [struct@Gtk.Bitset].
+ *
+ * `GtkBitSetIter is an opaque, stack-allocated struct.
  *
  * Before a `GtkBitsetIter` can be used, it needs to be initialized with
  * [func@Gtk.BitsetIter.init_first], [func@Gtk.BitsetIter.init_last]
diff --git a/gtk/gtkbookmarklist.c b/gtk/gtkbookmarklist.c
index c76d3a0cf3f7903adc86a62e9ddfbfaaa949daff..570ec352e0a72f97b224fecf4cd1c7d1fd8c79ad 100644
--- a/gtk/gtkbookmarklist.c
+++ b/gtk/gtkbookmarklist.c
@@ -27,7 +27,7 @@
 /**
  * GtkBookmarkList:
  *
- * `GtkBookmarkList` is a list model that wraps `GBookmarkFile`.
+ * A list model that wraps `GBookmarkFile`.
  *
  * It presents a `GListModel` and fills it asynchronously with the
  * `GFileInfo`s returned from that function.
diff --git a/gtk/gtkborder.h b/gtk/gtkborder.h
index 58180de4d9143dc3b2c5d44d4e22061a4a2eb5d0..58ee28f5c8130a0ada0cceb63241d9f088818fce 100644
--- a/gtk/gtkborder.h
+++ b/gtk/gtkborder.h
@@ -44,9 +44,9 @@ typedef struct _GtkBorder GtkBorder;
  * @top: The width of the top border
  * @bottom: The width of the bottom border
  *
- * A struct that specifies a border around a rectangular area.
+ * Specifies a border around a rectangular area.
  *
- * Each side can have different width.
+ * Each side can have a different width.
  */
 struct _GtkBorder
 {
diff --git a/gtk/gtkbox.c b/gtk/gtkbox.c
index 92d3f8fa60d6a2832871962b20dcb7e077b21924..8429055e6bcb81cea4779bc92c119909f36b1045 100644
--- a/gtk/gtkbox.c
+++ b/gtk/gtkbox.c
@@ -27,7 +27,10 @@
  *
  * Arranges child widgets into a single row or column.
  *
- * ![An example GtkBox](box.png)
+ * <picture>
+ *   <source srcset="box-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkBox" src="box.png">
+ * </picture>
  *
  * Whether it is a row or column depends on the value of its
  * [property@Gtk.Orientable:orientation] property. Within the other
diff --git a/gtk/gtkboxlayout.c b/gtk/gtkboxlayout.c
index 6b74b0d9ad1bae9d88d3d93cca0857632d6a3e49..77b579c59a3c19080d0203fc3c6cd99cc4f45d79 100644
--- a/gtk/gtkboxlayout.c
+++ b/gtk/gtkboxlayout.c
@@ -31,8 +31,7 @@
 /**
  * GtkBoxLayout:
  *
- * `GtkBoxLayout` is a layout manager that arranges children in a single
- * row or column.
+ * Arranges children in a single row or column.
  *
  * Whether it is a row or column depends on the value of its
  * [property@Gtk.Orientable:orientation] property. Within the other dimension
diff --git a/gtk/gtkbuildable.c b/gtk/gtkbuildable.c
index 492bf8dfd6146aea42a35ad66eabf1a602abd5e3..55be717dfd2438297530671f547a7b1afbb13b47 100644
--- a/gtk/gtkbuildable.c
+++ b/gtk/gtkbuildable.c
@@ -19,16 +19,15 @@
 /**
  * GtkBuildable:
  *
- * `GtkBuildable` allows objects to extend and customize their deserialization
- * from ui files.
+ * Allows objects to extend and customize deserialization from ui files.
  *
- * The interface includes methods for setting names and properties of objects,
- * parsing custom tags and constructing child objects.
+ * The `GtkBuildable` interface includes methods for setting names and
+ * properties of objects, parsing custom tags and constructing child objects.
  *
- * The `GtkBuildable` interface is implemented by all widgets and
- * many of the non-widget objects that are provided by GTK. The
- * main user of this interface is [class@Gtk.Builder]. There should be
- * very little need for applications to call any of these functions directly.
+ * It is implemented by all widgets and many of the non-widget objects that are
+ * provided by GTK. The main user of this interface is [class@Gtk.Builder].
+ * There should be very little need for applications to call any of these
+ * functions directly.
  *
  * An object only needs to implement this interface if it needs to extend the
  * `GtkBuilder` XML format or run any extra routines at deserialization time.
diff --git a/gtk/gtkbuildable.h b/gtk/gtkbuildable.h
index 6eda22c8ddcebb1185cbd1496efb2c43fb3747c6..b537402b4f8b44361f640c13a90593f477eb45aa 100644
--- a/gtk/gtkbuildable.h
+++ b/gtk/gtkbuildable.h
@@ -40,7 +40,9 @@ typedef struct _GtkBuildableParser GtkBuildableParser;
 /**
  * GtkBuildableParseContext:
  *
- * An opaque context struct for `GtkBuildableParser`.
+ * Provides context for parsing GtkBuilder UI files.
+ *
+ * `GtkBuildableParseContext` is an opaque struct.
  */
 
 /**
@@ -131,8 +133,7 @@ struct _GtkBuildableParser
  *  Implement this if the buildable has internal children that may
  *  need to be accessed from a UI definition.
  *
- * The `GtkBuildableIface` interface contains methods that are
- * necessary to allow `GtkBuilder` to construct an object from
+ * Contains methods to let `GtkBuilder` construct an object from
  * a `GtkBuilder` UI definition.
  */
 struct _GtkBuildableIface
diff --git a/gtk/gtkbuilder-menus.c b/gtk/gtkbuilder-menus.c
index 7855885173d92143941325dd9cd1b26df6bb0e77..b36380c4fe6558e3d6278cd4b1cfbc0ffb8a5d8d 100644
--- a/gtk/gtkbuilder-menus.c
+++ b/gtk/gtkbuilder-menus.c
@@ -37,6 +37,7 @@ typedef struct
 {
   ParserData *parser_data;
   struct frame frame;
+  char *id;
 
   /* attributes */
   char         *attribute;
@@ -366,33 +367,47 @@ _gtk_builder_menu_start (ParserData   *parser_data,
                          GError      **error)
 {
   GtkBuilderMenuState *state;
-  char *id;
+  const char *id = NULL;
+  char *internal_id = NULL;
 
   state = g_new0 (GtkBuilderMenuState, 1);
   state->parser_data = parser_data;
   gtk_buildable_parse_context_push (&parser_data->ctx, &gtk_builder_menu_subparser, state);
 
-  if (COLLECT (STRING, "id", &id))
+  if (COLLECT (STRING | OPTIONAL, "id", &id))
     {
       GMenu *menu;
 
+      if (id == NULL)
+        {
+          internal_id = g_strdup_printf ("___object_%d___", ++parser_data->object_counter);
+          id = internal_id;
+        }
+
       menu = g_menu_new ();
       _gtk_builder_add_object (state->parser_data->builder, id, G_OBJECT (menu));
       gtk_builder_menu_push_frame (state, menu, NULL);
       g_object_unref (menu);
+      state->id = g_strdup (id);
     }
+
+  g_free (internal_id);
 }
 
-void
+char *
 _gtk_builder_menu_end (ParserData *parser_data)
 {
   GtkBuilderMenuState *state;
+  char *id;
 
   state = gtk_buildable_parse_context_pop (&parser_data->ctx);
+  id = state->id;
   gtk_builder_menu_pop_frame (state);
 
   g_assert (state->frame.prev == NULL);
   g_assert (state->frame.item == NULL);
   g_assert (state->frame.menu == NULL);
   g_free (state);
+
+  return id;
 }
diff --git a/gtk/gtkbuilder.c b/gtk/gtkbuilder.c
index e13b94c70a05676c0d5a47533af38fdb750556d3..5e0d49ca8c8291a589f66ebff5f08b2bfa04d982 100644
--- a/gtk/gtkbuilder.c
+++ b/gtk/gtkbuilder.c
@@ -21,8 +21,7 @@
 /**
  * GtkBuilder:
  *
- * A `GtkBuilder` reads XML descriptions of a user interface and
- * instantiates the described objects.
+ * Reads XML descriptions of a user interface and instantiates the described objects.
  *
  * To create a `GtkBuilder` from a user interface description, call
  * [ctor@Gtk.Builder.new_from_file], [ctor@Gtk.Builder.new_from_resource]
@@ -356,6 +355,14 @@
  * elements and attributes to the XML. Typically, any extension will be
  * documented in each type that implements the interface.
  *
+ * ## Menus
+ *
+ * In addition to objects with properties that are created with `<object>` and
+ * `<property>` elements, `GtkBuilder` also allows to parse XML menu definitions
+ * as used by [class@Gio.Menu] when exporting menu models over D-Bus, and as
+ * described in the [class@Gtk.PopoverMenu] documentation. Menus can be defined
+ * as toplevel elements, or as property values for properties of type `GMenuModel`.
+ *
  * ## Templates
  *
  * When describing a [class@Gtk.Widget], you can use the `<template>` tag to
diff --git a/gtk/gtkbuilderlistitemfactory.c b/gtk/gtkbuilderlistitemfactory.c
index 007972dfb986c3b1485d0c2d8a160393e5a74429..ede9116287b188f7ddb77363345a765dc36ae8b8 100644
--- a/gtk/gtkbuilderlistitemfactory.c
+++ b/gtk/gtkbuilderlistitemfactory.c
@@ -29,8 +29,8 @@
 /**
  * GtkBuilderListItemFactory:
  *
- * `GtkBuilderListItemFactory` is a `GtkListItemFactory` that creates
- * widgets by instantiating `GtkBuilder` UI templates.
+ * A `GtkListItemFactory` that creates widgets by instantiating `GtkBuilder`
+ * UI templates.
  *
  * The templates must extend the class that the parent widget expects.
  * For example, a factory provided to [property@Gtk.ListView:factory] must have
diff --git a/gtk/gtkbuilderparser.c b/gtk/gtkbuilderparser.c
index b37f930cbe03581ecbd294abf3315dd2eb85799b..4c163207800ee7b847293158dd537de5e980d6dc 100644
--- a/gtk/gtkbuilderparser.c
+++ b/gtk/gtkbuilderparser.c
@@ -2073,7 +2073,16 @@ end_element (GtkBuildableParseContext  *context,
     }
   else if (strcmp (element_name, "menu") == 0)
     {
-      _gtk_builder_menu_end (data);
+      PropertyInfo *prop_info;
+      char *id;
+
+      id = _gtk_builder_menu_end (data);
+
+      prop_info = state_peek_info (data, PropertyInfo);
+      if (prop_info && prop_info->tag_type == TAG_PROPERTY)
+        g_string_assign (prop_info->text, id);
+
+      g_free (id);
     }
   else if (strcmp (element_name, "placeholder") == 0)
     {
diff --git a/gtk/gtkbuilderprivate.h b/gtk/gtkbuilderprivate.h
index ae89328638ae6342375ea6f62b84c58a90758622..8af564fcebb5e88a6a305b321b5506979f88744f 100644
--- a/gtk/gtkbuilderprivate.h
+++ b/gtk/gtkbuilderprivate.h
@@ -262,7 +262,7 @@ void      _gtk_builder_menu_start (ParserData   *parser_data,
                                    const char **attribute_names,
                                    const char **attribute_values,
                                    GError      **error);
-void      _gtk_builder_menu_end   (ParserData  *parser_data);
+char *    _gtk_builder_menu_end   (ParserData  *parser_data);
 
 GType     gtk_builder_get_template_type (GtkBuilder *builder,
                                          gboolean *out_allow_parents);
diff --git a/gtk/gtkbuilderscope.c b/gtk/gtkbuilderscope.c
index e24cd62618ec82f693eeeedcff65b326d94787d5..0fb578e23e32937836bbaa523cc101a17b8df9f5 100644
--- a/gtk/gtkbuilderscope.c
+++ b/gtk/gtkbuilderscope.c
@@ -27,8 +27,7 @@
 /**
  * GtkBuilderScope:
  *
- * `GtkBuilderScope` is an interface to provide language binding support
- * to `GtkBuilder`.
+ * Provides language binding support to `GtkBuilder`.
  *
  * The goal of `GtkBuilderScope` is to look up programming-language-specific
  * values for strings that are given in a `GtkBuilder` UI file.
diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c
index ecfefaaa21b7ffb14fb412270c6f8abecdbf2599..f78f2ee7212e7859118412dee89da9ce37cc34ed 100644
--- a/gtk/gtkbutton.c
+++ b/gtk/gtkbutton.c
@@ -25,10 +25,12 @@
 /**
  * GtkButton:
  *
- * The `GtkButton` widget is generally used to trigger a callback function that is
- * called when the button is pressed.
+ * Calls a callback function when the button is clicked.
  *
- * ![An example GtkButton](button.png)
+ * <picture>
+ *   <source srcset="button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkButton" src="button.png">
+ * </picture>
  *
  * The `GtkButton` widget can hold any valid child widget. That is, it can hold
  * almost any other standard `GtkWidget`. The most commonly used child is the
@@ -60,7 +62,7 @@
  *
  * # Accessibility
  *
- * `GtkButton` uses the %GTK_ACCESSIBLE_ROLE_BUTTON role.
+ * `GtkButton` uses the [enum@Gtk.AccessibleRole.button] role.
  */
 
 #include "config.h"
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index 85c8bd9df053e99e1b5914c3a7d5a6965f675502..55b272abcf5eb0ed68d276fc7274e6c4d7098a44 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -28,10 +28,12 @@
 /**
  * GtkCalendar:
  *
- * `GtkCalendar` is a widget that displays a Gregorian calendar, one month
- * at a time.
+ * Displays a Gregorian calendar, one month at a time.
  *
- * ![An example GtkCalendar](calendar.png)
+ * <picture>
+ *   <source srcset="calendar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkCalendar" src="calendar.png">
+ * </picture>
  *
  * A `GtkCalendar` can be created with [ctor@Gtk.Calendar.new].
  *
diff --git a/gtk/gtkcenterbox.c b/gtk/gtkcenterbox.c
index b9881ed6788ffd41b17404a0a938028f79c40672..ef8a198623cf0038fc268ca7bb243176c421ba10 100644
--- a/gtk/gtkcenterbox.c
+++ b/gtk/gtkcenterbox.c
@@ -24,7 +24,10 @@
  * Arranges three children in a row, keeping the middle child
  * centered as well as possible.
  *
- * ![An example GtkCenterBox](centerbox.png)
+ * <picture>
+ *   <source srcset="centerbox-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkCenterBox" src="centerbox.png">
+ * </picture>
  *
  * To add children to `GtkCenterBox`, use [method@Gtk.CenterBox.set_start_widget],
  * [method@Gtk.CenterBox.set_center_widget] and
diff --git a/gtk/gtkcenterlayout.c b/gtk/gtkcenterlayout.c
index fe744b1e752fa2add8bf5ffaa21c4fd66b9b2c5b..0a10415a055096766bea9511b059baae56afe640 100644
--- a/gtk/gtkcenterlayout.c
+++ b/gtk/gtkcenterlayout.c
@@ -28,7 +28,7 @@
 /**
  * GtkCenterLayout:
  *
- * `GtkCenterLayout` is a layout manager that manages up to three children.
+ * Manages up to three children.
  *
  * The start widget is allocated at the start of the layout (left in
  * left-to-right locales and right in right-to-left ones), and the end
diff --git a/gtk/gtkcheckbutton.c b/gtk/gtkcheckbutton.c
index 9309a85e42d666feb1e7ae7bdd3937b59f2f72d9..a35de37baeb34c1bc42652ab00b99a60799e3c0f 100644
--- a/gtk/gtkcheckbutton.c
+++ b/gtk/gtkcheckbutton.c
@@ -40,9 +40,12 @@
 /**
  * GtkCheckButton:
  *
- * A `GtkCheckButton` places a label next to an indicator.
+ * Places a label next to an indicator.
  *
- * ![Example GtkCheckButtons](check-button.png)
+ * <picture>
+ *   <source srcset="check-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="Example GtkCheckButtons" src="check-button.png">
+ * </picture>
  *
  * A `GtkCheckButton` is created by calling either [ctor@Gtk.CheckButton.new]
  * or [ctor@Gtk.CheckButton.new_with_label].
@@ -71,7 +74,10 @@
  * Grouped check buttons use a different indicator, and are commonly referred
  * to as *radio buttons*.
  *
- * ![Example GtkCheckButtons](radio-button.png)
+ * <picture>
+ *   <source srcset="radio-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="Example GtkRadioButtons" src="radio-button.png">
+ * </picture>
  *
  * To add a `GtkCheckButton` to a group, use [method@Gtk.CheckButton.set_group].
  *
@@ -102,7 +108,7 @@
  *
  * # Accessibility
  *
- * `GtkCheckButton` uses the %GTK_ACCESSIBLE_ROLE_CHECKBOX role.
+ * `GtkCheckButton` uses the [enum@Gtk.AccessibleRole.checkbox] role.
  */
 
 typedef struct {
diff --git a/gtk/gtkcolorchooserdialog.c b/gtk/gtkcolorchooserdialog.c
index 82bfd8d3da352b5c1e6a343c9c22a755d1f4dccf..28e76f0bad3d66014cb3768aa8570d580414203e 100644
--- a/gtk/gtkcolorchooserdialog.c
+++ b/gtk/gtkcolorchooserdialog.c
@@ -35,7 +35,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * A dialog for choosing a color.
  *
- * ![An example GtkColorChooserDialog](colorchooser.png)
+ * <picture>
+ *   <source srcset="colorchooser-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkColorChooserDialog" src="colorchooser.png">
+ * </picture>
  *
  * `GtkColorChooserDialog` implements the [iface@Gtk.ColorChooser] interface
  * and does not provide much API of its own.
diff --git a/gtk/gtkcolordialog.c b/gtk/gtkcolordialog.c
index 9f737a810276b103fd4b0fdfa0b90f14c39b99a6..180896fa7222547f8fba3fcc863c08983e29e0e8 100644
--- a/gtk/gtkcolordialog.c
+++ b/gtk/gtkcolordialog.c
@@ -30,9 +30,11 @@
 /**
  * GtkColorDialog:
  *
- * Collects the arguments that are needed to present a color chooser
- * dialog to the user, such as a title for the dialog and whether it
- * should be modal.
+ * Asynchronous API to present a color chooser dialog.
+ *
+ * `GtkColorDialog` collects the arguments that are needed to present
+ * the dialog to the user, such as a title for the dialog and whether
+ * it should be modal.
  *
  * The dialog is shown with the [method@Gtk.ColorDialog.choose_rgba]
  * function.
diff --git a/gtk/gtkcolordialogbutton.c b/gtk/gtkcolordialogbutton.c
index 98fdc57e17230ff1af0c026b0b655d77620c7533..789b2b33a9b49a703f46d045c190206dc512a860 100644
--- a/gtk/gtkcolordialogbutton.c
+++ b/gtk/gtkcolordialogbutton.c
@@ -53,10 +53,12 @@ static void     update_button_sensitivity
 /**
  * GtkColorDialogButton:
  *
- * The `GtkColorDialogButton` is a wrapped around a [class@Gtk.ColorDialog]
- * and allows to open a color chooser dialog to change the color.
+ * Opens a color chooser dialog to select a color.
  *
- * ![An example GtkColorDialogButton](color-button.png)
+ * <picture>
+ *   <source srcset="color-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkColorDialogButton" src="color-button.png">
+ * </picture>
  *
  * It is suitable widget for selecting a color in a preference dialog.
  *
diff --git a/gtk/gtkcolumnview.c b/gtk/gtkcolumnview.c
index 277cd7102a378808a07e2e1a12dba7962e39750a..6e219dd6c42b7990014d68457b831dc5cca2d50f 100644
--- a/gtk/gtkcolumnview.c
+++ b/gtk/gtkcolumnview.c
@@ -43,8 +43,7 @@
 /**
  * GtkColumnView:
  *
- * `GtkColumnView` presents a large dynamic list of items using multiple columns
- * with headers.
+ * Presents a large dynamic list of items using multiple columns with headers.
  *
  * `GtkColumnView` uses the factories of its columns to generate a cell widget for
  * each column, for each visible item and displays them together as the row for
@@ -104,10 +103,10 @@
  *
  * # Accessibility
  *
- * `GtkColumnView` uses the %GTK_ACCESSIBLE_ROLE_TREE_GRID role, header title
- * widgets are using the %GTK_ACCESSIBLE_ROLE_COLUMN_HEADER role. The row widgets
- * are using the %GTK_ACCESSIBLE_ROLE_ROW role, and individual cells are using
- * the %GTK_ACCESSIBLE_ROLE_GRID_CELL role
+ * `GtkColumnView` uses the [enum@Gtk.AccessibleRole.tree_grid] role, header title
+ * widgets are using the [enum@Gtk.AccessibleRole.column_header] role. The row widgets
+ * are using the [enum@Gtk.AccessibleRole.row] role, and individual cells are using
+ * the [enum@Gtk.AccessibleRole.grid_cell] role
  */
 
 /* We create a subclass of GtkListView for the sole purpose of overriding
diff --git a/gtk/gtkcolumnviewcell.c b/gtk/gtkcolumnviewcell.c
index 3929c9926fc9b2b35294fe701ebbd93771820564..4cca9beff6d90eeb8de05e747f0bff8b78d28589 100644
--- a/gtk/gtkcolumnviewcell.c
+++ b/gtk/gtkcolumnviewcell.c
@@ -26,12 +26,12 @@
 /**
  * GtkColumnViewCell:
  *
- * `GtkColumnViewCell` is used by [class@Gtk.ColumnViewColumn] to represent items
- * in a cell in [class@Gtk.ColumnView].
+ * Represents items in a cell in [class@Gtk.ColumnView].
  *
- * The `GtkColumnViewCell`s are managed by the columnview widget (with its factory)
- * and cannot be created by applications, but they need to be populated
- * by application code. This is done by calling [method@Gtk.ColumnViewCell.set_child].
+ * The `GtkColumnViewCell`s are managed by the [class@Gtk.ColumnView]
+ * widget (with its factory) and cannot be created by applications, but
+ * they need to be populated by application code. This is done by calling
+ * [method@Gtk.ColumnViewCell.set_child].
  *
  * `GtkColumnViewCell`s exist in 2 stages:
  *
diff --git a/gtk/gtkcolumnviewrow.c b/gtk/gtkcolumnviewrow.c
index 707f1a2902050e09d5aff1e2eb0b813747eefde6..b7b080e702b73faa56a9ef09d8b634d98cc3b0e6 100644
--- a/gtk/gtkcolumnviewrow.c
+++ b/gtk/gtkcolumnviewrow.c
@@ -26,8 +26,7 @@
 /**
  * GtkColumnViewRow:
  *
- * `GtkColumnViewRow` is used by [class@Gtk.ColumnView] to allow configuring
- * how rows are displayed.
+ * Configures how rows are displayed in a [class@Gtk.ColumnView].
  *
  * It is not used to set the widgets displayed in the individual cells. For that
  * see [method@GtkColumnViewColumn.set_factory] and [class@GtkColumnViewCell].
diff --git a/gtk/gtkcolumnviewsorter.c b/gtk/gtkcolumnviewsorter.c
index 8bdb078ffe60ffb731770f76420ac6720234b31a..dcf6f7b7f320044e3d0a8f00ae8b276d1f7a9bb2 100644
--- a/gtk/gtkcolumnviewsorter.c
+++ b/gtk/gtkcolumnviewsorter.c
@@ -48,8 +48,7 @@ free_sorter (gpointer data)
 /**
  * GtkColumnViewSorter:
  *
- * `GtkColumnViewSorter` is a sorter implementation that
- * is geared towards the needs of `GtkColumnView`.
+ * Sorts [class@Gtk.ColumnView] columns.
  *
  * The sorter returned by [method@Gtk.ColumnView.get_sorter] is
  * a `GtkColumnViewSorter`.
diff --git a/gtk/gtkconstraint.c b/gtk/gtkconstraint.c
index 7e31b8d35b007df8a54618fe07acf6eae12c35f6..15d66d5d5de7281f659ca51ba0d464c9609083de 100644
--- a/gtk/gtkconstraint.c
+++ b/gtk/gtkconstraint.c
@@ -20,7 +20,7 @@
 /**
  * GtkConstraint:
  *
- * `GtkConstraint` describes a constraint between attributes of two widgets,
+ * Describes a constraint between attributes of two widgets,
  *  expressed as a linear equation.
  *
  * The typical equation for a constraint is:
diff --git a/gtk/gtkconstraint.h b/gtk/gtkconstraint.h
index 6ffd081bfaf8c4067d24cc40ddcf73e9a629a6a8..cc469c20f3cba582522d49af2f521f6bad324f2b 100644
--- a/gtk/gtkconstraint.h
+++ b/gtk/gtkconstraint.h
@@ -31,8 +31,8 @@ typedef struct _GtkConstraintTarget GtkConstraintTarget;
 /**
  * GtkConstraintTarget:
  *
- * The `GtkConstraintTarget` interface is implemented by objects that
- * can be used as source or target in `GtkConstraint`s.
+ * Makes it possible to use an object as source or target in a
+ * [class@Gtk.Constraint].
  *
  * Besides `GtkWidget`, it is also implemented by `GtkConstraintGuide`.
  */
diff --git a/gtk/gtkconstraintguide.c b/gtk/gtkconstraintguide.c
index 72319954a32061242674dcae9ab3e041bacd220a..9a8996de75d8107f785b31a64b600ddd9db067b7 100644
--- a/gtk/gtkconstraintguide.c
+++ b/gtk/gtkconstraintguide.c
@@ -20,8 +20,7 @@
 /**
  * GtkConstraintGuide:
  *
- * A `GtkConstraintGuide` is an invisible layout element in a
- * `GtkConstraintLayout`.
+ * An invisible layout element in a `GtkConstraintLayout`.
  *
  * The `GtkConstraintLayout` treats guides like widgets. They
  * can be used as the source or target of a `GtkConstraint`.
diff --git a/gtk/gtkconstraintlayout.c b/gtk/gtkconstraintlayout.c
index a185d1b46b5cf99b30a5b77687ece009d0721ae2..f1f15ebef882205b0f1bbf6868a83a7a83f18751 100644
--- a/gtk/gtkconstraintlayout.c
+++ b/gtk/gtkconstraintlayout.c
@@ -20,7 +20,7 @@
 /**
  * GtkConstraintLayout:
  *
- * A layout manager using constraints to describe relations between widgets.
+ * Uses constraints to describe relations between widgets.
  *
  * `GtkConstraintLayout` is a layout manager that uses relations between
  * widget attributes, expressed via [class@Gtk.Constraint] instances, to
diff --git a/gtk/gtkcssprovider.c b/gtk/gtkcssprovider.c
index 9bab293f36199b76a9462e5733c03f28eb0b8e4c..5d086b2fc58eb6ac2910e2ede53628e86bd6df6e 100644
--- a/gtk/gtkcssprovider.c
+++ b/gtk/gtkcssprovider.c
@@ -58,8 +58,7 @@ G_STATIC_ASSERT (GTK_DEBUG_CSS == GTK_CSS_PARSER_DEBUG_CSS);
 /**
  * GtkCssProvider:
  *
- * `GtkCssProvider` is an object implementing the `GtkStyleProvider` interface
- * for CSS.
+ * A style provider for CSS.
  *
  * It is able to parse CSS-like input in order to style widgets.
  *
diff --git a/gtk/gtkcustomlayout.c b/gtk/gtkcustomlayout.c
index aa64882e2ee55fda26d23b005b8eb9d34406b2ba..93b18267b74f8dd5969ece7dfc3cf244738812a7 100644
--- a/gtk/gtkcustomlayout.c
+++ b/gtk/gtkcustomlayout.c
@@ -1,11 +1,11 @@
 /**
  * GtkCustomLayout:
  *
- * `GtkCustomLayout` uses closures for size negotiation.
+ * Uses closures for size negotiation.
  *
- * A `GtkCustomLayout `uses closures matching to the old `GtkWidget`
+ * A `GtkCustomLayout` uses closures matching to the old `GtkWidget`
  * virtual functions for size negotiation, as a convenience API to
- * ease the porting towards the corresponding `GtkLayoutManager
+ * ease the porting towards the corresponding `GtkLayoutManager`
  * virtual functions.
  */
 
diff --git a/gtk/gtkcustomsorter.c b/gtk/gtkcustomsorter.c
index 309711ed7e242bb031939030e9dc869a4e1fe212..c7dc2c4f9f5db07adc1bea77c0069f967636b5e9 100644
--- a/gtk/gtkcustomsorter.c
+++ b/gtk/gtkcustomsorter.c
@@ -26,8 +26,7 @@
 /**
  * GtkCustomSorter:
  *
- * `GtkCustomSorter` is a `GtkSorter` implementation that sorts via a callback
- * function.
+ * Sorts items via a callback function.
  */
 struct _GtkCustomSorter
 {
diff --git a/gtk/gtkdirectorylist.c b/gtk/gtkdirectorylist.c
index f7f6cb4b6b292c39b900f2937ba0a323a6cfd6cb..b7c69a94006dbc0f40947dfd61ba7ec6608dd33a 100644
--- a/gtk/gtkdirectorylist.c
+++ b/gtk/gtkdirectorylist.c
@@ -26,7 +26,7 @@
 /**
  * GtkDirectoryList:
  *
- * `GtkDirectoryList` is a list model that wraps g_file_enumerate_children_async().
+ * A list model that wraps [method@Gio.File.enumerate_children_async].
  *
  * It presents a `GListModel` and fills it asynchronously with the `GFileInfo`s
  * returned from that function.
diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c
index 7827ee0ae7ae781411997687eb2e6c98c1610744..cd1f1bf65f3222ac86e1f6c9c523eabb5817856d 100644
--- a/gtk/gtkdragicon.c
+++ b/gtk/gtkdragicon.c
@@ -41,7 +41,7 @@
 /**
  * GtkDragIcon:
  *
- * `GtkDragIcon` is a `GtkRoot` implementation for drag icons.
+ * A `GtkRoot` implementation for drag icons.
  *
  * A drag icon moves with the pointer during a Drag-and-Drop operation
  * and is destroyed when the drag ends.
diff --git a/gtk/gtkdragsource.c b/gtk/gtkdragsource.c
index f152edd55fe5a7b11accd7ac16ba1439fb55f4c9..f1d445c266db257ea1e85851c37472bb97362f41 100644
--- a/gtk/gtkdragsource.c
+++ b/gtk/gtkdragsource.c
@@ -44,7 +44,7 @@
 /**
  * GtkDragSource:
  *
- * `GtkDragSource` is an event controller to initiate Drag-And-Drop operations.
+ * An event controller to initiate Drag-And-Drop operations.
  *
  * `GtkDragSource` can be set up with the necessary
  * ingredients for a DND operation ahead of time. This includes
diff --git a/gtk/gtkdrawingarea.c b/gtk/gtkdrawingarea.c
index c5cad6e5290191e7e74fc13fca25b4498d4f498e..3d1b3ba38a2c3079fc8fc6553de524a056a1ec2c 100644
--- a/gtk/gtkdrawingarea.c
+++ b/gtk/gtkdrawingarea.c
@@ -60,9 +60,12 @@ static guint signals[LAST_SIGNAL] = { 0, };
 /**
  * GtkDrawingArea:
  *
- * `GtkDrawingArea` is a widget that allows drawing with cairo.
+ * Allows drawing with cairo.
  *
- * ![An example GtkDrawingArea](drawingarea.png)
+ * <picture>
+ *   <source srcset="drawingarea-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkDrawingArea" src="drawingarea.png">
+ * </picture>
  *
  * It’s essentially a blank widget; you can draw on it. After
  * creating a drawing area, the application may want to connect to:
diff --git a/gtk/gtkdropcontrollermotion.c b/gtk/gtkdropcontrollermotion.c
index 5cdafac8c3b6d5c1ab4991bbb50b0a816fbb94ef..ca8d357b20ccca5fd75d3c6eb5a8b2489fc370a6 100644
--- a/gtk/gtkdropcontrollermotion.c
+++ b/gtk/gtkdropcontrollermotion.c
@@ -20,8 +20,7 @@
 /**
  * GtkDropControllerMotion:
  *
- * `GtkDropControllerMotion` is an event controller tracking
- * the pointer during Drag-and-Drop operations.
+ * An event controller tracking the pointer during Drag-and-Drop operations.
  *
  * It is modeled after [class@Gtk.EventControllerMotion] so if you
  * have used that, this should feel really familiar.
diff --git a/gtk/gtkdropdown.c b/gtk/gtkdropdown.c
index 0c9afb53efd3613ae2d49b10aacb4972bfa6f6b8..8d5b85b8feb303cc333ee07a53ba1048a7dce3a6 100644
--- a/gtk/gtkdropdown.c
+++ b/gtk/gtkdropdown.c
@@ -49,10 +49,12 @@
 /**
  * GtkDropDown:
  *
- * `GtkDropDown` is a widget that allows the user to choose an item
- * from a list of options.
+ * Allows the user to choose an item from a list of options.
  *
- * ![An example GtkDropDown](drop-down.png)
+ * <picture>
+ *   <source srcset="drop-down-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkDropDown" src="drop-down.png">
+ * </picture>
  *
  * The `GtkDropDown` displays the [selected][property@Gtk.DropDown:selected]
  * choice.
@@ -104,7 +106,7 @@
  *
  * ## Accessibility
  *
- * `GtkDropDown` uses the %GTK_ACCESSIBLE_ROLE_COMBO_BOX role.
+ * `GtkDropDown` uses the [enum@Gtk.AccessibleRole.combo_box] role.
  */
 
 struct _GtkDropDown
diff --git a/gtk/gtkdroptarget.c b/gtk/gtkdroptarget.c
index d1bbc401f95d6192e0705d3a2561fae57b79d166..d6a0dcd4ada4a79cb4877ca73fb7cef26411f3a2 100644
--- a/gtk/gtkdroptarget.c
+++ b/gtk/gtkdroptarget.c
@@ -38,7 +38,7 @@
 /**
  * GtkDropTarget:
  *
- * `GtkDropTarget` is an event controller to receive Drag-and-Drop operations.
+ * An event controller to receive Drag-and-Drop operations.
  *
  * The most basic way to use a `GtkDropTarget` to receive drops on a
  * widget is to create it via [ctor@Gtk.DropTarget.new], passing in the
diff --git a/gtk/gtkdroptargetasync.c b/gtk/gtkdroptargetasync.c
index dcd87482ca9099c48fa818dd80776e8cb0ca1556..ea341c6e9fa6c2d68382ad22096c38316735342b 100644
--- a/gtk/gtkdroptargetasync.c
+++ b/gtk/gtkdroptargetasync.c
@@ -38,8 +38,7 @@
 /**
  * GtkDropTargetAsync:
  *
- * `GtkDropTargetAsync` is an event controller to receive Drag-and-Drop
- * operations, asynchronously.
+ * An event controller to receive Drag-and-Drop operations, asynchronously.
  *
  * It is the more complete but also more complex method of handling drop
  * operations compared to [class@Gtk.DropTarget], and you should only use
diff --git a/gtk/gtkeditable.c b/gtk/gtkeditable.c
index 84136471fa694d1f17d95a4e6125173d005b031c..c2c247b813a8b7efa93568a5ef43e6cf6a02153d 100644
--- a/gtk/gtkeditable.c
+++ b/gtk/gtkeditable.c
@@ -25,7 +25,7 @@
 /**
  * GtkEditable:
  *
- * `GtkEditable` is an interface for text editing widgets.
+ * Interface for single-line text editing widgets.
  *
  * Typical examples of editable widgets are [class@Gtk.Entry] and
  * [class@Gtk.SpinButton]. It contains functions for generically manipulating
diff --git a/gtk/gtkeditablelabel.c b/gtk/gtkeditablelabel.c
index 4f1c0f5582354d0468b7bfcc90d8b5d2cd436f70..b6668e79e9e18e76024a6e564accae45f5590121 100644
--- a/gtk/gtkeditablelabel.c
+++ b/gtk/gtkeditablelabel.c
@@ -29,16 +29,21 @@
 #include "gtkprivate.h"
 #include "gtkshortcut.h"
 #include "gtkshortcuttrigger.h"
+#include "gtkpopovermenu.h"
 #include "gtkwidgetprivate.h"
 #include "gtkeventcontrollerfocus.h"
 
+#include <glib/gi18n-lib.h>
+
 /**
  * GtkEditableLabel:
  *
- * A `GtkEditableLabel` is a label that allows users to
- * edit the text by switching to an “edit mode”.
+ * Allows users to edit the displayed text by switching to an “edit mode”.
  *
- * ![An example GtkEditableLabel](editable-label.png)
+ * <picture>
+ *   <source srcset="editable-label-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkEditableLabel" src="editable-label.png">
+ * </picture>
  *
  * `GtkEditableLabel` does not have API of its own, but it
  * implements the [iface@Gtk.Editable] interface.
@@ -86,6 +91,7 @@ struct _GtkEditableLabel
   GtkWidget *stack;
   GtkWidget *label;
   GtkWidget *entry;
+  GtkWidget *popup_menu;
 
   guint stop_editing_soon_id;
 };
@@ -140,9 +146,86 @@ stop_editing (GtkWidget  *widget,
 }
 
 static void
-clicked_cb (GtkWidget *self)
+clipboard_copy (GtkWidget  *widget,
+                const char *name,
+                GVariant   *parameter)
+{
+  GtkEditableLabel *self = GTK_EDITABLE_LABEL (widget);
+  GdkClipboard *clipboard;
+  const char *text;
+
+  clipboard = gtk_widget_get_clipboard (widget);
+  text = gtk_label_get_label (GTK_LABEL (self->label));
+
+  gdk_clipboard_set_text (clipboard, text);
+}
+
+static GMenuModel *
+create_menu (void)
+{
+  GMenu *menu;
+
+  menu = g_menu_new ();
+
+  g_menu_append (menu, _("_Edit"), "editing.start");
+  g_menu_append (menu, _("_Copy"), "clipboard.copy");
+
+  return G_MENU_MODEL (menu);
+}
+
+static void
+do_popup (GtkEditableLabel *self,
+          double            x,
+          double            y)
+{
+  if (x != -1 && y != -1)
+    {
+      GdkRectangle rect = { x, y, 1, 1 };
+      gtk_popover_set_pointing_to (GTK_POPOVER (self->popup_menu), &rect);
+    }
+  else
+    {
+      gtk_popover_set_pointing_to (GTK_POPOVER (self->popup_menu), NULL);
+    }
+
+  gtk_popover_popup (GTK_POPOVER (self->popup_menu));
+}
+
+static void
+clicked_cb (GtkGestureClick  *gesture,
+            int               n_press,
+            double            x,
+            double            y,
+            GtkEditableLabel *self)
 {
-  gtk_widget_activate_action (self, "editing.start", NULL);
+  guint button;
+  GdkEventSequence *sequence;
+  GdkEvent *event;
+
+  button = gtk_gesture_single_get_current_button (GTK_GESTURE_SINGLE (gesture));
+  sequence = gtk_gesture_single_get_current_sequence (GTK_GESTURE_SINGLE (gesture));
+  event = gtk_gesture_get_last_event (GTK_GESTURE (gesture), sequence);
+
+  if (button == GDK_BUTTON_PRIMARY)
+    {
+      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+      gtk_widget_activate_action (GTK_WIDGET (self), "editing.start", NULL);
+    }
+  else if (gdk_event_triggers_context_menu (event))
+    {
+      gtk_gesture_set_state (GTK_GESTURE (gesture), GTK_EVENT_SEQUENCE_CLAIMED);
+      do_popup (self, x, y);
+    }
+}
+
+static void
+popup_menu (GtkWidget  *widget,
+            const char *action_name,
+            GVariant   *parameters)
+{
+  GtkEditableLabel *self = GTK_EDITABLE_LABEL (widget);
+
+  do_popup (self, -1, -1);
 }
 
 static void
@@ -226,6 +309,9 @@ static void
 gtk_editable_label_focus_out (GtkEventController *controller,
                               GtkEditableLabel   *self)
 {
+  if (!gtk_editable_label_get_editing (self))
+    return;
+
   if (self->stop_editing_soon_id == 0)
     self->stop_editing_soon_id = g_timeout_add (100, stop_editing_soon, controller);
 }
@@ -237,6 +323,7 @@ gtk_editable_label_init (GtkEditableLabel *self)
   GtkDropTarget *target;
   GtkDragSource *source;
   GtkEventController *controller;
+  GMenuModel *model;
 
   gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
 
@@ -245,13 +332,28 @@ gtk_editable_label_init (GtkEditableLabel *self)
   gtk_label_set_xalign (GTK_LABEL (self->label), 0.0);
   self->entry = gtk_text_new ();
 
+  model = create_menu ();
+  self->popup_menu = gtk_popover_menu_new_from_model (model);
+  gtk_widget_set_parent (self->popup_menu, GTK_WIDGET (self));
+  gtk_popover_set_position (GTK_POPOVER (self->popup_menu), GTK_POS_BOTTOM);
+
+  gtk_popover_set_has_arrow (GTK_POPOVER (self->popup_menu), FALSE);
+  gtk_widget_set_halign (self->popup_menu, GTK_ALIGN_START);
+
+  gtk_accessible_update_property (GTK_ACCESSIBLE (self->popup_menu),
+                                  GTK_ACCESSIBLE_PROPERTY_LABEL, _("Context menu"),
+                                  -1);
+
+  g_object_unref (model);
+
   gtk_stack_add_named (GTK_STACK (self->stack), self->label, "label");
   gtk_stack_add_named (GTK_STACK (self->stack), self->entry, "entry");
 
   gtk_widget_set_parent (self->stack, GTK_WIDGET (self));
 
   gesture = gtk_gesture_click_new ();
-  g_signal_connect_swapped (gesture, "released", G_CALLBACK (clicked_cb), self);
+  gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (gesture), 0);
+  g_signal_connect (gesture, "pressed", G_CALLBACK (clicked_cb), self);
   gtk_widget_add_controller (self->label, GTK_EVENT_CONTROLLER (gesture));
 
   g_signal_connect_swapped (self->entry, "activate", G_CALLBACK (activate_cb), self);
@@ -375,6 +477,7 @@ gtk_editable_label_dispose (GObject *object)
 
   gtk_editable_finish_delegate (GTK_EDITABLE (self));
 
+  g_clear_pointer (&self->popup_menu, gtk_widget_unparent);
   g_clear_pointer (&self->stack, gtk_widget_unparent);
 
   self->entry = NULL;
@@ -424,7 +527,7 @@ gtk_editable_label_class_init (GtkEditableLabelClass *class)
    * on the widget and the <kbd>Enter</kbd> key.
    *
    * This action is disabled when `GtkEditableLabel:editing`
-   * is %FALSE.
+   * is %TRUE.
    */
   gtk_widget_class_install_action (widget_class, "editing.start", NULL, start_editing);
 
@@ -459,6 +562,18 @@ gtk_editable_label_class_init (GtkEditableLabelClass *class)
                                        "editing.stop",
                                        "b", FALSE);
 
+  gtk_widget_class_install_action (widget_class, "clipboard.copy", NULL, clipboard_copy);
+  gtk_widget_class_install_action (widget_class, "menu.popup", NULL, popup_menu);
+
+  gtk_widget_class_add_binding_action (widget_class,
+                                       GDK_KEY_F10, GDK_SHIFT_MASK,
+                                       "menu.popup",
+                                       NULL);
+  gtk_widget_class_add_binding_action (widget_class,
+                                       GDK_KEY_Menu, 0,
+                                       "menu.popup",
+                                       NULL);
+
   gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
   gtk_widget_class_set_css_name (widget_class, "editablelabel");
 }
diff --git a/gtk/gtkemojichooser.c b/gtk/gtkemojichooser.c
index a0d624c8067df07f7a772f6895fb43a612a8678e..5daed8adc17096d61edee9e6ab5ca0ba5b4599d1 100644
--- a/gtk/gtkemojichooser.c
+++ b/gtk/gtkemojichooser.c
@@ -40,10 +40,12 @@
 /**
  * GtkEmojiChooser:
  *
- * The `GtkEmojiChooser` is used by text widgets such as `GtkEntry` or
- * `GtkTextView` to let users insert Emoji characters.
+ * Used by text widgets to let users insert Emoji characters.
  *
- * ![An example GtkEmojiChooser](emojichooser.png)
+ * <picture>
+ *   <source srcset="emojichooser-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkEmojiChooser" src="emojichooser.png">
+ * </picture>
  *
  * `GtkEmojiChooser` emits the [signal@Gtk.EmojiChooser::emoji-picked]
  * signal when an Emoji is selected.
@@ -917,6 +919,8 @@ filter_func (GtkFlowBoxChild *child,
   g_strfreev (term_tokens);
   g_strfreev (name_tokens);
   g_strfreev (name_tokens_en);
+  g_free (keywords_en);
+  g_free (keywords);
 
 out:
   if (res)
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 0659dcd6e9bb977f047f591caf7818cbc5afec88..8c0e7fd00be1102cbb2058b695e0816d8bd27d7c 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -65,9 +65,12 @@
 /**
  * GtkEntry:
  *
- * `GtkEntry` is a single line text entry widget.
+ * A single-line text entry widget.
  *
- * ![An example GtkEntry](entry.png)
+ * <picture>
+ *   <source srcset="entry-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkEntry" src="entry.png">
+ * </picture>
  *
  * A fairly large set of key bindings are supported by default. If the
  * entered text is longer than the allocation of the widget, the widget
@@ -151,7 +154,7 @@
  *
  * # Accessibility
  *
- * `GtkEntry` uses the %GTK_ACCESSIBLE_ROLE_TEXT_BOX role.
+ * `GtkEntry` uses the [enum@Gtk.AccessibleRole.text_box] role.
  */
 
 #define MAX_ICONS 2
@@ -2831,7 +2834,7 @@ gtk_entry_get_icon_storage_type (GtkEntry             *entry,
  * The position’s coordinates are relative to the @entry’s
  * top left corner. If @x, @y doesn’t lie inside an icon,
  * -1 is returned. This function is intended for use in a
- *  [signal@Gtk.Widget::query-tooltip] signal handler.
+ * [signal@Gtk.Widget::query-tooltip] signal handler.
  *
  * Returns: the index of the icon at the given position, or -1
  */
diff --git a/gtk/gtkentrybuffer.c b/gtk/gtkentrybuffer.c
index 8558444da964c0e631a104b8c9c7245430f420fa..e83898a70bc16bdb97548a2e54cfe1d5aff26759 100644
--- a/gtk/gtkentrybuffer.c
+++ b/gtk/gtkentrybuffer.c
@@ -29,7 +29,7 @@
 /**
  * GtkEntryBuffer:
  *
- * A `GtkEntryBuffer` hold the text displayed in a `GtkText` widget.
+ * Holds the text that is displayed in a single-line text entry widget.
  *
  * A single `GtkEntryBuffer` object can be shared by multiple widgets
  * which will then share the same text content, but not the cursor
diff --git a/gtk/gtkenums.h b/gtk/gtkenums.h
index 147dc4ec9bcb138d91c75d10cae4a08c5492d82c..2aaf4cbe44d90b96ad80d4c1abc9d262de4c5e36 100644
--- a/gtk/gtkenums.h
+++ b/gtk/gtkenums.h
@@ -99,7 +99,7 @@ typedef enum
  * @GTK_ARROW_RIGHT: Represents a right pointing arrow.
  * @GTK_ARROW_NONE: No arrow.
  *
- * Used to indicate the direction in which an arrow should point.
+ * Indicates the direction in which an arrow should point.
  */
 typedef enum
 {
@@ -1043,9 +1043,10 @@ typedef enum
  * GtkPropagationLimit:
  * @GTK_LIMIT_NONE: Events are handled regardless of what their
  *   target is.
- * @GTK_LIMIT_SAME_NATIVE: Events are only handled if their target
- *   is in the same [iface@Native] as the event controllers widget. Note
- *   that some event types have two targets (origin and destination).
+ * @GTK_LIMIT_SAME_NATIVE: Events are only handled if their target is in
+ *   the same [iface@Native] (or widget with [property@Gtk.Widget:limit-events]
+ *   set) as the event controllers widget.
+ *   Note that some event types have two targets (origin and destination).
  *
  * Describes limits of a [class@EventController] for handling events
  * targeting other widgets.
diff --git a/gtk/gtkeventcontroller.c b/gtk/gtkeventcontroller.c
index feb0a1c78d5aafe52face60e23f7c8b750c1ebe9..f0c41e9c368318986de1d3da241d694c9e8fc86d 100644
--- a/gtk/gtkeventcontroller.c
+++ b/gtk/gtkeventcontroller.c
@@ -21,7 +21,7 @@
 /**
  * GtkEventController:
  *
- * `GtkEventController` is the base class for event controllers.
+ * The base class for event controllers.
  *
  * These are ancillary objects associated to widgets, which react
  * to `GdkEvents`, and possibly trigger actions as a consequence.
@@ -251,20 +251,38 @@ gtk_event_controller_init (GtkEventController *controller)
   priv->limit = GTK_LIMIT_SAME_NATIVE;
 }
 
+static inline gboolean
+is_event_limit (GtkWidget *widget)
+{
+  return GTK_IS_NATIVE (widget) ||
+         gtk_widget_get_limit_events (widget);
+}
+
+/* Variant of gtk_widget_get_native() that respects GtkWidget:limit-events
+ */
+static GtkWidget *
+get_event_limit (GtkWidget *widget)
+{
+  while (widget && !is_event_limit (widget))
+    widget = _gtk_widget_get_parent (widget);
+
+  return widget;
+}
+
 static gboolean
 same_native (GtkWidget *widget,
              GtkWidget *target)
 {
-  GtkNative *native;
-  GtkNative *native2;
+  GtkWidget *limit1;
+  GtkWidget *limit2;
 
   if (!widget || !target)
     return TRUE;
 
-  native = gtk_widget_get_native (widget);
-  native2 = gtk_widget_get_native (target);
+  limit1 = get_event_limit (widget);
+  limit2 = get_event_limit (target);
 
-  return native == native2;
+  return limit1 == limit2;
 }
 
 static gboolean
diff --git a/gtk/gtkeventcontrollerfocus.c b/gtk/gtkeventcontrollerfocus.c
index 512895fe5452c5b171f3db073dd5ce8a5a6b3b86..cabb279c7130cf35ea4bdd1d2d3b3480fc47ec83 100644
--- a/gtk/gtkeventcontrollerfocus.c
+++ b/gtk/gtkeventcontrollerfocus.c
@@ -20,8 +20,7 @@
 /**
  * GtkEventControllerFocus:
  *
- * `GtkEventControllerFocus` is an event controller to keep track of
- * keyboard focus.
+ * Tracks keyboard focus.
  *
  * The event controller offers [signal@Gtk.EventControllerFocus::enter]
  * and [signal@Gtk.EventControllerFocus::leave] signals, as well as
diff --git a/gtk/gtkeventcontrollerkey.c b/gtk/gtkeventcontrollerkey.c
index 4f9097e8e28e9c123916fb6c34f707f4d76cd3f0..795f0e02a696ad90f5515064bd375506c87b41d8 100644
--- a/gtk/gtkeventcontrollerkey.c
+++ b/gtk/gtkeventcontrollerkey.c
@@ -20,8 +20,7 @@
 /**
  * GtkEventControllerKey:
  *
- * `GtkEventControllerKey` is an event controller that provides access
- * to key events.
+ * Provides access to key events.
  */
 
 #include "config.h"
diff --git a/gtk/gtkeventcontrollerlegacy.c b/gtk/gtkeventcontrollerlegacy.c
index 8df55ce0bc488510373d5aa33f4449cbb122c8d0..9eaa961dcc484d51a10a9dbbdc1953946ec06d22 100644
--- a/gtk/gtkeventcontrollerlegacy.c
+++ b/gtk/gtkeventcontrollerlegacy.c
@@ -20,8 +20,7 @@
 /**
  * GtkEventControllerLegacy:
  *
- * `GtkEventControllerLegacy` is an event controller that provides raw
- * access to the event stream.
+ * Provides raw access to the event stream.
  *
  * It should only be used as a last resort if none of the other event
  * controllers or gestures do the job.
diff --git a/gtk/gtkeventcontrollermotion.c b/gtk/gtkeventcontrollermotion.c
index 12ab2738cf9cbb3864ffee4f2f4b873e01c9fde6..b0c4d55ddddd12775dbb8a2049604dfa897fb91b 100644
--- a/gtk/gtkeventcontrollermotion.c
+++ b/gtk/gtkeventcontrollermotion.c
@@ -20,8 +20,7 @@
 /**
  * GtkEventControllerMotion:
  *
- * `GtkEventControllerMotion` is an event controller tracking the pointer
- * position.
+ * Tracks the pointer position.
  *
  * The event controller offers [signal@Gtk.EventControllerMotion::enter]
  * and [signal@Gtk.EventControllerMotion::leave] signals, as well as
diff --git a/gtk/gtkeventcontrollerscroll.c b/gtk/gtkeventcontrollerscroll.c
index 7d6adce483a83526be755b130c869ec146e05391..8f68f54145ccfbe176d5a19b568d82a5b99aa563 100644
--- a/gtk/gtkeventcontrollerscroll.c
+++ b/gtk/gtkeventcontrollerscroll.c
@@ -20,8 +20,7 @@
 /**
  * GtkEventControllerScroll:
  *
- * `GtkEventControllerScroll` is an event controller that handles scroll
- * events.
+ * Handles scroll events.
  *
  * It is capable of handling both discrete and continuous scroll
  * events from mice or touchpads, abstracting them both with the
diff --git a/gtk/gtkexpander.c b/gtk/gtkexpander.c
index 45557a2df5697fdd56caf0758fd66339c00995a3..a487218443f671e37f9b81163207d2a7da1a5dca 100644
--- a/gtk/gtkexpander.c
+++ b/gtk/gtkexpander.c
@@ -22,10 +22,12 @@
 /**
  * GtkExpander:
  *
- * `GtkExpander` allows the user to reveal its child by clicking
- * on an expander triangle.
+ * Allows the user to reveal or conceal a child widget.
  *
- * ![An example GtkExpander](expander.png)
+ * <picture>
+ *   <source srcset="expander-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkExpander" src="expander.png">
+ * </picture>
  *
  * This is similar to the triangles used in a `GtkTreeView`.
  *
@@ -113,7 +115,7 @@
  *
  * # Accessibility
  *
- * `GtkExpander` uses the %GTK_ACCESSIBLE_ROLE_BUTTON role.
+ * `GtkExpander` uses the [enum@Gtk.AccessibleRole.button] role.
  */
 
 #include "config.h"
diff --git a/gtk/gtkexpression.c b/gtk/gtkexpression.c
index 9839e262a569136ed36a22061ffcf3156a79c3e3..e79a39f1179a5548c88d64b95403be3ba955b562 100644
--- a/gtk/gtkexpression.c
+++ b/gtk/gtkexpression.c
@@ -28,7 +28,7 @@
 /**
  * GtkExpression: (ref-func gtk_expression_ref) (unref-func gtk_expression_unref) (set-value-func gtk_value_set_expression) (get-value-func gtk_value_get_expression)
  *
- * `GtkExpression` provides a way to describe references to values.
+ * Provides a way to describe references to values.
  *
  * An important aspect of expressions is that the value can be obtained
  * from a source that is several steps away. For example, an expression
diff --git a/gtk/gtkexpression.h b/gtk/gtkexpression.h
index aa1d9d2479adcbb0e83966387547bfecf4eed7cb..de737e3aacf9ff4667f1d19ea076e7a706bde266 100644
--- a/gtk/gtkexpression.h
+++ b/gtk/gtkexpression.h
@@ -162,7 +162,7 @@ GtkExpression *         gtk_cclosure_expression_new             (GType
  * GTK_VALUE_HOLDS_EXPRESSION:
  * @value: a `GValue`
  *
- * Evaluates to %TRUE if @value was initialized with %GTK_TYPE_EXPRESSION.
+ * Evaluates to true if @value was initialized with `GTK_TYPE_EXPRESSION`
  */
 #define GTK_VALUE_HOLDS_EXPRESSION(value)       (G_VALUE_HOLDS ((value), GTK_TYPE_EXPRESSION))
 
diff --git a/gtk/gtkfiledialog.c b/gtk/gtkfiledialog.c
index 848b2f9f5d6e5d3728178aa569e3287a1a167ae5..f87516ec457f922bad1e6ea2210c52d03dacf2c8 100644
--- a/gtk/gtkfiledialog.c
+++ b/gtk/gtkfiledialog.c
@@ -32,9 +32,11 @@
 /**
  * GtkFileDialog:
  *
- * Collects the arguments that are needed to present a file chooser
- * dialog to the user, such as a title for the dialog and whether it
- * should be modal.
+ * Asynchronous API to present a file chooser dialog.
+ *
+ * `GtkFileDialog` collects the arguments that are needed to present
+ * the dialog to the user, such as a title for the dialog and whether
+ * it should be modal.
  *
  * The dialog is shown with [method@Gtk.FileDialog.open],
  * [method@Gtk.FileDialog.save], etc.
diff --git a/gtk/gtkfilelauncher.c b/gtk/gtkfilelauncher.c
index 5bc1bc34bcad84f0e7fe499ebd41cda8c4a6eb5f..4c3bf873c05fe14122826fb11785d6e7a61d68cf 100644
--- a/gtk/gtkfilelauncher.c
+++ b/gtk/gtkfilelauncher.c
@@ -44,7 +44,9 @@
 /**
  * GtkFileLauncher:
  *
- * Collects the arguments that are needed to open a file with an application.
+ * Asynchronous API to open a file with an application.
+ *
+ * `GtkFileLauncher` collects the arguments that are needed to open the file.
  *
  * Depending on system configuration, user preferences and available APIs, this
  * may or may not show an app chooser dialog or launch the default application
@@ -287,7 +289,7 @@ gtk_file_launcher_get_always_ask (GtkFileLauncher *self)
  * @self: a file launcher
  * @always_ask: whether to always ask
  *
- * Sets whether to awlays ask the user which app to use.
+ * Sets whether to always ask the user which app to use.
  *
  * If false, the file might be opened with a default app
  * or the previous choice.
diff --git a/gtk/gtkfilterlistmodel.c b/gtk/gtkfilterlistmodel.c
index c7a78bf0510a73de37fbdbcb973e17055fe00974..b0a5a206ccef58622259885f5ae673817b8b3a49 100644
--- a/gtk/gtkfilterlistmodel.c
+++ b/gtk/gtkfilterlistmodel.c
@@ -28,10 +28,9 @@
 /**
  * GtkFilterListModel:
  *
- * `GtkFilterListModel` is a list model that filters the elements of
- * the underlying model according to a `GtkFilter`.
+ * A list model that filters the elements of another model.
  *
- * It hides some elements from the other model according to
+ * It hides some elements from the underlying model according to
  * criteria given by a `GtkFilter`.
  *
  * The model can be set up to do incremental filtering, so that
diff --git a/gtk/gtkfixed.c b/gtk/gtkfixed.c
index 1ad36aa78dc10c7746dfd35ec4888b549215415a..8a689936e15a24de67ba94d420d542585449cf66 100644
--- a/gtk/gtkfixed.c
+++ b/gtk/gtkfixed.c
@@ -25,7 +25,7 @@
 /**
  * GtkFixed:
  *
- * `GtkFixed` places its child widgets at fixed positions and with fixed sizes.
+ * Places its child widgets at fixed positions and with fixed sizes.
  *
  * `GtkFixed` performs no automatic layout management.
  *
diff --git a/gtk/gtkfixedlayout.c b/gtk/gtkfixedlayout.c
index 3371043e48b6053f858d3839855f40bef46dcfc0..995575d6d376f8c7e1ad36f185604825c5ca85e0 100644
--- a/gtk/gtkfixedlayout.c
+++ b/gtk/gtkfixedlayout.c
@@ -21,8 +21,7 @@
 /**
  * GtkFixedLayout:
  *
- * `GtkFixedLayout` is a layout manager which can place child widgets
- * at fixed positions.
+ * Places child widgets at fixed positions.
  *
  * Most applications should never use this layout manager; fixed positioning
  * and sizing requires constant recalculations on where children need to be
diff --git a/gtk/gtkflattenlistmodel.c b/gtk/gtkflattenlistmodel.c
index 3f8d16928b65705a01d32104fe5d06b17dd780cf..bad21a287abad161d4c012b14c76f6b9cab21fa9 100644
--- a/gtk/gtkflattenlistmodel.c
+++ b/gtk/gtkflattenlistmodel.c
@@ -27,7 +27,7 @@
 /**
  * GtkFlattenListModel:
  *
- * `GtkFlattenListModel` is a list model that concatenates other list models.
+ * A list model that concatenates other list models.
  *
  * `GtkFlattenListModel` takes a list model containing list models, and flattens
  * it into a single model. Each list model becomes a section in the single model.
diff --git a/gtk/gtkflowbox.c b/gtk/gtkflowbox.c
index 096f483e53f4677c06a342911441c8b7b3479fd7..a0c03a01b9a925d2a2c11d8d3feb249850e2a339 100644
--- a/gtk/gtkflowbox.c
+++ b/gtk/gtkflowbox.c
@@ -26,7 +26,12 @@
 /**
  * GtkFlowBox:
  *
- * A `GtkFlowBox` puts child widgets in reflowing grid.
+ * Puts child widgets in a reflowing grid.
+ *
+ * <picture>
+ *   <source srcset="flow-box-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkFlowBox" src="flow-box.png">
+ * </picture>
  *
  * For instance, with the horizontal orientation, the widgets will be
  * arranged from left to right, starting a new row under the previous
@@ -79,14 +84,17 @@
  *
  * # Accessibility
  *
- * `GtkFlowBox` uses the %GTK_ACCESSIBLE_ROLE_GRID role, and `GtkFlowBoxChild`
- * uses the %GTK_ACCESSIBLE_ROLE_GRID_CELL role.
+ * `GtkFlowBox` uses the [enum@Gtk.AccessibleRole.grid] role, and `GtkFlowBoxChild`
+ * uses the [enum@Gtk.AccessibleRole.grid_cell] role.
  */
 
 /**
  * GtkFlowBoxChild:
  *
- * `GtkFlowBoxChild` is the kind of widget that can be added to a `GtkFlowBox`.
+ * The kind of widget that can be added to a `GtkFlowBox`.
+ *
+ * [class@Gtk.FlowBox] will automatically wrap its children in a `GtkFlowBoxChild`
+ * when necessary.
  */
 
 #include <config.h>
diff --git a/gtk/gtkfontchooserdialog.c b/gtk/gtkfontchooserdialog.c
index 4c747a39370e8e733cb1b146eeccc8dcfe363c82..299a522355f0db2ed2c5effcc9810c7b833a2402 100644
--- a/gtk/gtkfontchooserdialog.c
+++ b/gtk/gtkfontchooserdialog.c
@@ -62,7 +62,10 @@ struct _GtkFontChooserDialogClass
  *
  * The `GtkFontChooserDialog` widget is a dialog for selecting a font.
  *
- * ![An example GtkFontChooserDialog](fontchooser.png)
+ * <picture>
+ *   <source srcset="fontchooser-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkFontChooserDialog" src="fontchooser.png">
+ * </picture>
  *
  * `GtkFontChooserDialog` implements the [iface@Gtk.FontChooser] interface
  * and does not provide much API of its own.
diff --git a/gtk/gtkfontdialog.c b/gtk/gtkfontdialog.c
index e18703396224ef24c175078cb887536cdc238890..ece536dda60faf180c31f4d923fc159485f9d679 100644
--- a/gtk/gtkfontdialog.c
+++ b/gtk/gtkfontdialog.c
@@ -31,8 +31,11 @@
 /**
  * GtkFontDialog:
  *
- * Collects the arguments that are needed to present a font chooser dialog
- * to the user, such as a title for the dialog and whether it should be modal.
+ * Asynchronous API to present a font chooser dialog.
+ *
+ * `GtkFontDialog` collects the arguments that are needed to present
+ * the dialog to the user, such as a title for the dialog and whether
+ * it should be modal.
  *
  * The dialog is shown with the [method@Gtk.FontDialog.choose_font]
  * function or its variants.
diff --git a/gtk/gtkfontdialogbutton.c b/gtk/gtkfontdialogbutton.c
index 0eee4b38807d266e92dabe8bf30be0e65c26017a..0ea5c28d9d2af65dc81497ed466622ce1eb03180 100644
--- a/gtk/gtkfontdialogbutton.c
+++ b/gtk/gtkfontdialogbutton.c
@@ -40,10 +40,12 @@ static void     update_button_sensitivity
 /**
  * GtkFontDialogButton:
  *
- * The `GtkFontDialogButton` is wrapped around a [class@Gtk.FontDialog]
- * and allows to open a font chooser dialog to change the font.
+ * Opens a font chooser dialog to select a font.
  *
- * ![An example GtkFontDialogButton](font-button.png)
+ * <picture>
+ *   <source srcset="font-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkFontDialogButton" src="font-button.png">
+ * </picture>
  *
  * It is suitable widget for selecting a font in a preference dialog.
  *
@@ -621,6 +623,9 @@ update_font_data (GtkFontDialogButton *self)
         }
     }
 
+  if (self->font_family == NULL)
+    return;
+
   for (unsigned i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (self->font_family)); i++)
     {
       PangoFontFace *face = g_list_model_get_item (G_LIST_MODEL (self->font_family), i);
diff --git a/gtk/gtkframe.c b/gtk/gtkframe.c
index 37849ae6a6ad927bf906d2fedb5822639f20534f..e8a84ce9433f262e73b952cf4c3e71710510dc1e 100644
--- a/gtk/gtkframe.c
+++ b/gtk/gtkframe.c
@@ -36,10 +36,12 @@
 /**
  * GtkFrame:
  *
- * `GtkFrame` is a widget that surrounds its child with a decorative
- * frame and an optional label.
+ * Surrounds its child with a decorative frame and an optional label.
  *
- * ![An example GtkFrame](frame.png)
+ * <picture>
+ *   <source srcset="frame-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkFrame" src="frame.png">
+ * </picture>
  *
  * If present, the label is drawn inside the top edge of the frame.
  * The horizontal position of the label can be controlled with
@@ -81,7 +83,7 @@
  *
  * # Accessibility
  *
- * `GtkFrame` uses the `GTK_ACCESSIBLE_ROLE_GROUP` role.
+ * `GtkFrame` uses the [enum@Gtk.AccessibleRole.group] role.
  */
 
 typedef struct
diff --git a/gtk/gtkgesture.c b/gtk/gtkgesture.c
index 6a2869cf006e105a41ce58cf9b0b96e34a3f02bb..d8065f7af202360c707efd36133b149e4f2bb8bd 100644
--- a/gtk/gtkgesture.c
+++ b/gtk/gtkgesture.c
@@ -21,7 +21,7 @@
 /**
  * GtkGesture:
  *
- * `GtkGesture` is the base class for gesture recognition.
+ * The base class for gesture recognition.
  *
  * Although `GtkGesture` is quite generalized to serve as a base for
  * multi-touch gestures, it is suitable to implement single-touch and
diff --git a/gtk/gtkgestureclick.c b/gtk/gtkgestureclick.c
index 795e8ec02c08c16c05f00a0748f0fc14c88ec44e..2825efe09363aa901d0abcfaf62e5774dd810935 100644
--- a/gtk/gtkgestureclick.c
+++ b/gtk/gtkgestureclick.c
@@ -20,7 +20,7 @@
 /**
  * GtkGestureClick:
  *
- * `GtkGestureClick` is a `GtkGesture` implementation for clicks.
+ * Recognizes click gestures.
  *
  * It is able to recognize multiple clicks on a nearby zone, which
  * can be listened for through the [signal@Gtk.GestureClick::pressed]
diff --git a/gtk/gtkgesturedrag.c b/gtk/gtkgesturedrag.c
index a05892a840954b31c8113bc5deb8c0e2e32e396b..91d6d33c8b1fa9e4e41e28dda79197b20d9f71c4 100644
--- a/gtk/gtkgesturedrag.c
+++ b/gtk/gtkgesturedrag.c
@@ -20,7 +20,7 @@
 /**
  * GtkGestureDrag:
  *
- * `GtkGestureDrag` is a `GtkGesture` implementation for drags.
+ * Recognizes drag gestures.
  *
  * The drag operation itself can be tracked throughout the
  * [signal@Gtk.GestureDrag::drag-begin],
diff --git a/gtk/gtkgesturelongpress.c b/gtk/gtkgesturelongpress.c
index f5597abac182a5c275382fca32a7cc237e406231..a9a0a3230555d6ca7467ff802cf07ecfe3c89a5b 100644
--- a/gtk/gtkgesturelongpress.c
+++ b/gtk/gtkgesturelongpress.c
@@ -21,7 +21,7 @@
 /**
  * GtkGestureLongPress:
  *
- * `GtkGestureLongPress` is a `GtkGesture` for long presses.
+ * Recognizes long press gestures.
  *
  * This gesture is also known as “Press and Hold”.
  *
diff --git a/gtk/gtkgesturepan.c b/gtk/gtkgesturepan.c
index ae38b73c874c8e328c1b54eb90d58ac1a2ee2cd0..09e4f2fb274de181c440016baf1187e8dcd062ea 100644
--- a/gtk/gtkgesturepan.c
+++ b/gtk/gtkgesturepan.c
@@ -20,7 +20,7 @@
 /**
  * GtkGesturePan:
  *
- * `GtkGesturePan` is a `GtkGesture` for pan gestures.
+ * Recognizes pan gestures.
  *
  * These are drags that are locked to happen along one axis. The axis
  * that a `GtkGesturePan` handles is defined at construct time, and
diff --git a/gtk/gtkgesturerotate.c b/gtk/gtkgesturerotate.c
index 37130eb06faed083306a68606701d0ee2566bb1d..17cc827fd8fcf8916b473450caa7ae5a9a491fb1 100644
--- a/gtk/gtkgesturerotate.c
+++ b/gtk/gtkgesturerotate.c
@@ -21,7 +21,7 @@
 /**
  * GtkGestureRotate:
  *
- * `GtkGestureRotate` is a `GtkGesture` for 2-finger rotations.
+ * Recognizes 2-finger rotation gestures.
  *
  * Whenever the angle between both handled sequences changes, the
  * [signal@Gtk.GestureRotate::angle-changed] signal is emitted.
diff --git a/gtk/gtkgesturesingle.c b/gtk/gtkgesturesingle.c
index 72bb82affb1a5f8bb80d19fdca1abdea7c1254ba..a718938f883d701257746ec49ebd59bc5e1af730 100644
--- a/gtk/gtkgesturesingle.c
+++ b/gtk/gtkgesturesingle.c
@@ -21,8 +21,7 @@
 /**
  * GtkGestureSingle:
  *
- * `GtkGestureSingle` is a `GtkGestures` subclass optimized for singe-touch
- * and mouse gestures.
+ * A `GtkGesture` subclass optimized for singe-touch and mouse gestures.
  *
  * Under interaction, these gestures stick to the first interacting sequence,
  * which is accessible through [method@Gtk.GestureSingle.get_current_sequence]
diff --git a/gtk/gtkgesturestylus.c b/gtk/gtkgesturestylus.c
index 5d34decd1e98c0e22e2243118832d68c1b381451..821578539fd2b21c6d9e51b2b250573826ad6c09 100644
--- a/gtk/gtkgesturestylus.c
+++ b/gtk/gtkgesturestylus.c
@@ -20,7 +20,7 @@
 /**
  * GtkGestureStylus:
  *
- * `GtkGestureStylus` is a `GtkGesture` specific to stylus input.
+ * Recognizes tablet stylus input.
  *
  * The provided signals just relay the basic information of the
  * stylus events.
diff --git a/gtk/gtkgestureswipe.c b/gtk/gtkgestureswipe.c
index 5ec737049551d333a01e051173ae5cf548b56ceb..72e5e70a1e2d8543347a1a4b2dbfcdc1d62dd6ad 100644
--- a/gtk/gtkgestureswipe.c
+++ b/gtk/gtkgestureswipe.c
@@ -21,7 +21,7 @@
 /**
  * GtkGestureSwipe:
  *
- * `GtkGestureSwipe` is a `GtkGesture` for swipe gestures.
+ * Recognizes swipe gestures.
  *
  * After a press/move/.../move/release sequence happens, the
  * [signal@Gtk.GestureSwipe::swipe] signal will be emitted,
diff --git a/gtk/gtkgesturezoom.c b/gtk/gtkgesturezoom.c
index ea90ae16c2fa86c5e036c43a7a290159bd744a3f..892e95d0ff8698a51b96127d6135f699110a2e92 100644
--- a/gtk/gtkgesturezoom.c
+++ b/gtk/gtkgesturezoom.c
@@ -21,7 +21,7 @@
 /**
  * GtkGestureZoom:
  *
- * `GtkGestureZoom` is a `GtkGesture` for 2-finger pinch/zoom gestures.
+ * Recognizes 2-finger pinch/zoom gestures.
  *
  * Whenever the distance between both tracked sequences changes, the
  * [signal@Gtk.GestureZoom::scale-changed] signal is emitted to report
diff --git a/gtk/gtkglarea.c b/gtk/gtkglarea.c
index 4a69febf4d9cbae74df0f8c391aafa52cfb6a440..a5f475327a3ccbd84519c62891cd46268c890d8c 100644
--- a/gtk/gtkglarea.c
+++ b/gtk/gtkglarea.c
@@ -46,9 +46,12 @@
 /**
  * GtkGLArea:
  *
- * `GtkGLArea` is a widget that allows drawing with OpenGL.
+ * Allows drawing with OpenGL.
  *
- * ![An example GtkGLArea](glarea.png)
+ * <picture>
+ *   <source srcset="glarea-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkGLArea" src="glarea.png">
+ * </picture>
  *
  * `GtkGLArea` sets up its own [class@Gdk.GLContext], and creates a custom
  * GL framebuffer that the widget will do GL rendering onto. It also ensures
diff --git a/gtk/gtkgraphicsoffload.c b/gtk/gtkgraphicsoffload.c
index 8b20086e40a598fe4fb1079fdfc464fe83d2298e..0dc2104e37ee8ab59bcd124d209770d12905034e 100644
--- a/gtk/gtkgraphicsoffload.c
+++ b/gtk/gtkgraphicsoffload.c
@@ -34,8 +34,7 @@
 /**
  * GtkGraphicsOffload:
  *
- * A widget that allows to bypass gsk rendering for its child by passing the content
- * directly to the compositor.
+ * Bypasses gsk rendering by passing the content of its child directly to the compositor.
  *
  * Graphics offload is an optimization to reduce overhead and battery use that is
  * most useful for video content. It only works on some platforms and in certain
diff --git a/gtk/gtkgrid.c b/gtk/gtkgrid.c
index 4b157cd7e1beadcecf800cc77481c55a8870693b..e018c6ba6c2662ec58c9012b96f553cd2cb2a68d 100644
--- a/gtk/gtkgrid.c
+++ b/gtk/gtkgrid.c
@@ -35,10 +35,12 @@
 /**
  * GtkGrid:
  *
- * `GtkGrid` is a container which arranges its child widgets in
- * rows and columns.
+ * Arranges its child widgets in rows and columns.
  *
- * ![An example GtkGrid](grid.png)
+ * <picture>
+ *   <source srcset="grid-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkGrid" src="grid.png">
+ * </picture>
  *
  * It supports arbitrary positions and horizontal/vertical spans.
  *
@@ -116,9 +118,9 @@
  *
  * # Accessibility
  *
- * Until GTK 4.10, `GtkGrid` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
+ * Until GTK 4.10, `GtkGrid` used the [enum@Gtk.AccessibleRole.group] role.
  *
- * Starting from GTK 4.12, `GtkGrid` uses the `GTK_ACCESSIBLE_ROLE_GENERIC` role.
+ * Starting from GTK 4.12, `GtkGrid` uses the [enum@Gtk.AccessibleRole.generic] role.
  */
 
 typedef struct
diff --git a/gtk/gtkgridlayout.c b/gtk/gtkgridlayout.c
index 1d0fa3821348d5daec2e6b70c343cba84050c390..41e8448d859ee3ab709a790fe02123f5eff8a83b 100644
--- a/gtk/gtkgridlayout.c
+++ b/gtk/gtkgridlayout.c
@@ -20,8 +20,7 @@
 /**
  * GtkGridLayout:
  *
- * `GtkGridLayout` is a layout manager which arranges child widgets in
- * rows and columns.
+ * Arranges child widgets in rows and columns.
  *
  * Children have an "attach point" defined by the horizontal and vertical
  * index of the cell they occupy; children can span multiple rows or columns.
diff --git a/gtk/gtkgridview.c b/gtk/gtkgridview.c
index e87f3ffa51799707e68ae95cc67e44993cc33f17..16882b3cfde0249a0a6b51b583ce11a643baae5c 100644
--- a/gtk/gtkgridview.c
+++ b/gtk/gtkgridview.c
@@ -44,7 +44,7 @@
 /**
  * GtkGridView:
  *
- * `GtkGridView` presents a large dynamic grid of items.
+ * Presents a large dynamic grid of items.
  *
  * `GtkGridView` uses its factory to generate one child widget for each
  * visible item and shows them in a grid. The orientation of the grid view
@@ -84,8 +84,8 @@
  *
  * # Accessibility
  *
- * `GtkGridView` uses the %GTK_ACCESSIBLE_ROLE_GRID role, and the items
- * use the %GTK_ACCESSIBLE_ROLE_GRID_CELL role.
+ * `GtkGridView` uses the [enum@Gtk.AccessibleRole.grid] role, and the items
+ * use the [enum@Gtk.AccessibleRole.grid_cell] role.
  */
 
 struct _GtkGridView
diff --git a/gtk/gtkheaderbar.c b/gtk/gtkheaderbar.c
index 9af3f1d0c0d7bec3e748fd5e8b44127616507e9c..f7a678f08de3851f1e84345748a957a304956325 100644
--- a/gtk/gtkheaderbar.c
+++ b/gtk/gtkheaderbar.c
@@ -38,9 +38,12 @@
 /**
  * GtkHeaderBar:
  *
- * A widget for creating custom title bars for windows.
+ * Creates a custom titlebar for a window.
  *
- * ![An example GtkHeaderBar](headerbar.png)
+ * <picture>
+ *   <source srcset="headerbar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkHeaderBar" src="headerbar.png">
+ * </picture>
  *
  * `GtkHeaderBar` is similar to a horizontal `GtkCenterBox`. It allows
  * children to be placed at the start or the end. In addition, it allows
@@ -131,6 +134,7 @@ struct _GtkHeaderBar
   char *decoration_layout;
 
   guint show_title_buttons : 1;
+  guint use_native_controls : 1;
   guint track_default_decoration : 1;
 };
 
@@ -146,6 +150,7 @@ enum {
   PROP_TITLE_WIDGET,
   PROP_SHOW_TITLE_BUTTONS,
   PROP_DECORATION_LAYOUT,
+  PROP_USE_NATIVE_CONTROLS,
   LAST_PROP
 };
 
@@ -166,6 +171,9 @@ create_window_controls (GtkHeaderBar *bar)
   g_object_bind_property (bar, "decoration-layout",
                           controls, "decoration-layout",
                           G_BINDING_SYNC_CREATE);
+  g_object_bind_property (bar, "use-native-controls",
+                          controls, "use-native-controls",
+                          G_BINDING_SYNC_CREATE);
   g_object_bind_property (controls, "empty",
                           controls, "visible",
                           G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
@@ -176,6 +184,9 @@ create_window_controls (GtkHeaderBar *bar)
   g_object_bind_property (bar, "decoration-layout",
                           controls, "decoration-layout",
                           G_BINDING_SYNC_CREATE);
+  g_object_bind_property (bar, "use-native-controls",
+                          controls, "use-native-controls",
+                          G_BINDING_SYNC_CREATE);
   g_object_bind_property (controls, "empty",
                           controls, "visible",
                           G_BINDING_SYNC_CREATE | G_BINDING_INVERT_BOOLEAN);
@@ -419,6 +430,10 @@ gtk_header_bar_get_property (GObject    *object,
       g_value_set_string (value, gtk_header_bar_get_decoration_layout (bar));
       break;
 
+    case PROP_USE_NATIVE_CONTROLS:
+      g_value_set_boolean (value, gtk_header_bar_get_use_native_controls (bar));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -447,6 +462,10 @@ gtk_header_bar_set_property (GObject      *object,
       gtk_header_bar_set_decoration_layout (bar, g_value_get_string (value));
       break;
 
+    case PROP_USE_NATIVE_CONTROLS:
+      gtk_header_bar_set_use_native_controls (bar, g_value_get_boolean (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -601,6 +620,25 @@ gtk_header_bar_class_init (GtkHeaderBarClass *class)
                            NULL,
                            GTK_PARAM_READWRITE);
 
+  /**
+   * GtkHeaderBar:use-native-controls:
+   *
+   * Whether to show platform native close/minimize/maximize buttons.
+   *
+   * For macOS, the [property@Gtk.HeaderBar:decoration-layout] property
+   * can be used to enable/disable controls.
+   *
+   * On Linux, this option has no effect.
+   *
+   * See also [Using GTK on Apple macOS](osx.html?native-window-controls).
+   *
+   * Since: 4.18
+   */
+  header_bar_props[PROP_USE_NATIVE_CONTROLS] =
+      g_param_spec_boolean ("use-native-controls", NULL, NULL,
+                            FALSE,
+                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
   g_object_class_install_properties (object_class, LAST_PROP, header_bar_props);
 
   gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
@@ -614,6 +652,7 @@ gtk_header_bar_init (GtkHeaderBar *bar)
   bar->title_widget = NULL;
   bar->decoration_layout = NULL;
   bar->show_title_buttons = TRUE;
+  bar->use_native_controls = FALSE;
 
   bar->handle = gtk_window_handle_new ();
   gtk_widget_set_parent (bar->handle, GTK_WIDGET (bar));
@@ -821,3 +860,50 @@ gtk_header_bar_get_decoration_layout (GtkHeaderBar *bar)
 
   return bar->decoration_layout;
 }
+
+/**
+ * gtk_header_bar_get_use_native_controls:
+ * @bar: a header bar
+ *
+ * Returns whether this header bar shows platform
+ * native window controls.
+ *
+ * Returns: true if native window controls are shown
+ *
+ * Since: 4.18
+ */
+gboolean
+gtk_header_bar_get_use_native_controls (GtkHeaderBar *bar)
+{
+  return bar->use_native_controls;
+}
+
+/**
+ * gtk_header_bar_set_use_native_controls:
+ * @bar: a header bar
+ * @setting: true to show native window controls
+ *
+ * Sets whether this header bar shows native window controls.
+ *
+ * This option shows the "stoplight" buttons on macOS.
+ * For Linux, this option has no effect.
+ *
+ * See also [Using GTK on Apple macOS](osx.html?native-window-controls).
+ *
+ * Since: 4.18
+ */
+void
+gtk_header_bar_set_use_native_controls (GtkHeaderBar *bar,
+                                         gboolean      setting)
+{
+  g_return_if_fail (GTK_IS_HEADER_BAR (bar));
+
+  setting = setting != FALSE;
+
+  if (bar->use_native_controls == setting)
+    return;
+
+  bar->use_native_controls = setting;
+
+  g_object_notify_by_pspec (G_OBJECT (bar), header_bar_props[PROP_USE_NATIVE_CONTROLS]);
+}
diff --git a/gtk/gtkheaderbar.h b/gtk/gtkheaderbar.h
index 8033f0ae306d7c0abe691bad52df89e05d929dd3..5331e194de616ce920e781959174e9dcb31d2879 100644
--- a/gtk/gtkheaderbar.h
+++ b/gtk/gtkheaderbar.h
@@ -66,6 +66,13 @@ void         gtk_header_bar_set_decoration_layout (GtkHeaderBar *bar,
 GDK_AVAILABLE_IN_ALL
 const char *gtk_header_bar_get_decoration_layout (GtkHeaderBar *bar);
 
+GDK_AVAILABLE_IN_4_18
+gboolean     gtk_header_bar_get_use_native_controls (GtkHeaderBar *bar);
+
+GDK_AVAILABLE_IN_4_18
+void         gtk_header_bar_set_use_native_controls (GtkHeaderBar *bar,
+                                                     gboolean      setting);
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkHeaderBar, g_object_unref)
 
 G_END_DECLS
diff --git a/gtk/gtkicontheme.c b/gtk/gtkicontheme.c
index 8e13eba147d681cd60d17a2eea51750a88b0e01e..5ae6321990bc86747022b82ce3c16ae3d9ebd9c1 100644
--- a/gtk/gtkicontheme.c
+++ b/gtk/gtkicontheme.c
@@ -66,7 +66,7 @@
 /**
  * GtkIconTheme:
  *
- * `GtkIconTheme` provides a facility for loading themed icons.
+ * Loads themed icons.
  *
  * The main reason for using a name rather than simply providing a filename
  * is to allow different icons to be used depending on what “icon theme” is
diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c
index b60f6da6d6cd72a8d8d055bec2fb08d65e43b21b..4306d2e339757deccd75ec0d97afcc28476fec11 100644
--- a/gtk/gtkimage.c
+++ b/gtk/gtkimage.c
@@ -40,9 +40,12 @@
 /**
  * GtkImage:
  *
- * The `GtkImage` widget displays an image.
+ * Displays an image.
  *
- * ![An example GtkImage](image.png)
+ * picture>
+ *   <source srcset="image-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkImage" src="image.png">
+ * </picture>
  *
  * Various kinds of object can be displayed as an image; most typically,
  * you would load a `GdkTexture` from a file, using the convenience function
@@ -78,7 +81,7 @@
  *
  * ## Accessibility
  *
- * `GtkImage` uses the `GTK_ACCESSIBLE_ROLE_IMG` role.
+ * `GtkImage` uses the [enum@Gtk.AccessibleRole.img] role.
  */
 
 typedef struct _GtkImageClass GtkImageClass;
diff --git a/gtk/gtkimcontext.c b/gtk/gtkimcontext.c
index 087d7912f2698ae8550a72ea5a0660478063c4ae..0194689f006abc1f0fd4e0542e4c5b7c5f8d769d 100644
--- a/gtk/gtkimcontext.c
+++ b/gtk/gtkimcontext.c
@@ -27,7 +27,7 @@
 /**
  * GtkIMContext:
  *
- * `GtkIMContext` defines the interface for GTK input methods.
+ * The interface for GTK input methods.
  *
  * `GtkIMContext` is used by GTK text input widgets like `GtkText`
  * to map from key events to Unicode character strings.
diff --git a/gtk/gtkimcontextsimple.c b/gtk/gtkimcontextsimple.c
index 6501ed35b0172961e17478455ee2c25e8bd18a16..27496f55996c8d9c52456459df2e18f6744e4075 100644
--- a/gtk/gtkimcontextsimple.c
+++ b/gtk/gtkimcontextsimple.c
@@ -39,7 +39,7 @@
 /**
  * GtkIMContextSimple:
  *
- * `GtkIMContextSimple` is an input method supporting table-based input methods.
+ * Supports compose sequences, dead keys and numeric Unicode input.
  *
  * ## Compose sequences
  *
diff --git a/gtk/gtkimmulticontext.c b/gtk/gtkimmulticontext.c
index 91ccf0c0e855e024f38125f3df14ea3a5fe326f7..c4e32aa69b89b9d5d77bceb64e779e93a095611b 100644
--- a/gtk/gtkimmulticontext.c
+++ b/gtk/gtkimmulticontext.c
@@ -31,8 +31,7 @@
 /**
  * GtkIMMulticontext:
  *
- * `GtkIMMulticontext` is an input method context supporting multiple,
- * switchable input methods.
+ * Supports switching between multiple input methods.
  *
  * Text widgets such as `GtkText` or `GtkTextView` use a `GtkIMMultiContext`
  * to implement their `im-module` property for switching between different
diff --git a/gtk/gtkinscription.c b/gtk/gtkinscription.c
index 188b3dca33d9ba7b728e4313c835e5de92b6b962..f90640fd70831408c48fbcbf10496efa72f78e1f 100644
--- a/gtk/gtkinscription.c
+++ b/gtk/gtkinscription.c
@@ -35,7 +35,7 @@
 /**
  * GtkInscription:
  *
- * `GtkInscription` is a widget to show text in a predefined area.
+ * Shows text in a predefined area.
  *
  * You likely want to use `GtkLabel` instead as this widget is intended only
  * for a small subset of use cases. The main scenario envisaged is inside lists
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 3b1350bff2bc6ab25c09cc6e8d394771a5fea0f0..919d9d2c8e044cc9092b9490cc1f36fb1bac12bd 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -70,7 +70,10 @@
  *
  * Most labels are used to label another widget (such as an [class@Entry]).
  *
- * ![An example GtkLabel](label.png)
+ * <picture>
+ *   <source srcset="label-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkLabel" src="label.png">
+ * </picture>
  *
  * ## Shortcuts and Gestures
  *
diff --git a/gtk/gtklayoutchild.c b/gtk/gtklayoutchild.c
index f75f78e6991ac642b200459da5ab9d36a66e5395..0ff59256b509175c3146bca4a084eae3646712c9 100644
--- a/gtk/gtklayoutchild.c
+++ b/gtk/gtklayoutchild.c
@@ -8,8 +8,7 @@
 /**
  * GtkLayoutChild:
  *
- * `GtkLayoutChild` is the base class for objects that are meant to hold
- * layout properties.
+ * The base class for objects that are meant to hold layout properties.
  *
  * If a `GtkLayoutManager` has per-child properties, like their packing type,
  * or the horizontal and vertical span, or the icon name, then the layout
diff --git a/gtk/gtklayoutmanager.c b/gtk/gtklayoutmanager.c
index 47ced92b075cdafe3aeb4251460c1ef48d23b999..90f8b51fe4d1a2f1ed1013edba390a8338e35cbe 100644
--- a/gtk/gtklayoutmanager.c
+++ b/gtk/gtklayoutmanager.c
@@ -20,8 +20,7 @@
 /**
  * GtkLayoutManager:
  *
- * Layout managers are delegate classes that handle the preferred size
- * and the allocation of a widget.
+ * Handles the preferred size and allocation for children of a widget.
  *
  * You typically subclass `GtkLayoutManager` if you want to implement a
  * layout policy for the children of a widget, or if you want to determine
diff --git a/gtk/gtklevelbar.c b/gtk/gtklevelbar.c
index 06a1a9f2585a2b8cff4d5fce8f079eae9403f7d3..f95d82b1bead33debe212e802fa464d6d99b5b1b 100644
--- a/gtk/gtklevelbar.c
+++ b/gtk/gtklevelbar.c
@@ -21,12 +21,15 @@
 /**
  * GtkLevelBar:
  *
- * `GtkLevelBar` is a widget that can be used as a level indicator.
+ * Shows a level indicator.
  *
  * Typical use cases are displaying the strength of a password, or
  * showing the charge level of a battery.
  *
- * ![An example GtkLevelBar](levelbar.png)
+ * <picture>
+ *   <source srcset="levelbar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkLevelBar" src="levelbar.png">
+ * </picture>
  *
  * Use [method@Gtk.LevelBar.set_value] to set the current value, and
  * [method@Gtk.LevelBar.add_offset_value] to set the value offsets at which
@@ -117,7 +120,7 @@
  *
  * # Accessibility
  *
- * `GtkLevelBar` uses the %GTK_ACCESSIBLE_ROLE_METER role.
+ * `GtkLevelBar` uses the [enum@Gtk.AccessibleRole.meter] role.
  */
 #include "config.h"
 
diff --git a/gtk/gtklinkbutton.c b/gtk/gtklinkbutton.c
index d0b35368eb8f4636230d60bcddd8e48fd5f6cce8..c115652a2a687bb09e510fac8d738c79f325f2d1 100644
--- a/gtk/gtklinkbutton.c
+++ b/gtk/gtklinkbutton.c
@@ -24,9 +24,12 @@
 /**
  * GtkLinkButton:
  *
- * A `GtkLinkButton` is a button with a hyperlink.
+ * A button with a hyperlink.
  *
- * ![An example GtkLinkButton](link-button.png)
+ * <picture>
+ *   <source srcset="link-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkLinkButton" src="link-button.png">
+ * </picture>
  *
  * It is useful to show quick links to resources.
  *
@@ -62,7 +65,7 @@
  *
  * # Accessibility
  *
- * `GtkLinkButton` uses the %GTK_ACCESSIBLE_ROLE_LINK role.
+ * `GtkLinkButton` uses the [enum@Gtk.AccessibleRole.link] role.
  */
 
 #include "config.h"
diff --git a/gtk/gtklistbase.h b/gtk/gtklistbase.h
index 369f72fefba1dc7d58b20ca976bc06c43e8a0476..cae71fe046a53795761e481b53a4b9fa5fcfae73 100644
--- a/gtk/gtklistbase.h
+++ b/gtk/gtklistbase.h
@@ -38,7 +38,7 @@ G_BEGIN_DECLS
 /**
  * GtkListBase:
  *
- * `GtkListBase` is the abstract base class for GTK's list widgets.
+ * The abstract base class for GTK's list widgets.
  *
  * # Shortcuts and Gestures
  *
diff --git a/gtk/gtklistbox.c b/gtk/gtklistbox.c
index 61316875613f6ad04fcf683742a32bb42c259ca1..2783bdf6f32c290f66baa7e59b0c4c0dcdbff25b 100644
--- a/gtk/gtklistbox.c
+++ b/gtk/gtklistbox.c
@@ -31,6 +31,7 @@
 #include "gtkscrollable.h"
 #include "gtktypebuiltins.h"
 #include "gtkwidgetprivate.h"
+#include "gtksizerequest.h"
 
 #include <float.h>
 #include <math.h>
@@ -39,7 +40,12 @@
 /**
  * GtkListBox:
  *
- * `GtkListBox` is a vertical list.
+ * Shows a vertical list.
+ *
+ * <picture>
+ *   <source srcset="list-box-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkListBox" src="list-box.png">
+ * </picture>
  *
  * A `GtkListBox` only contains `GtkListBoxRow` children. These rows can
  * by dynamically sorted and filtered, and headers can be added dynamically
@@ -99,14 +105,17 @@
  *
  * # Accessibility
  *
- * `GtkListBox` uses the %GTK_ACCESSIBLE_ROLE_LIST role and `GtkListBoxRow` uses
- * the %GTK_ACCESSIBLE_ROLE_LIST_ITEM role.
+ * `GtkListBox` uses the [enum@Gtk.AccessibleRole.list] role and `GtkListBoxRow` uses
+ * the [enum@Gtk.AccessibleRole.list_item] role.
  */
 
 /**
  * GtkListBoxRow:
  *
- * `GtkListBoxRow` is the kind of widget that can be added to a `GtkListBox`.
+ * The kind of widget that can be added to a `GtkListBox`.
+ *
+ * [class@Gtk.ListBox] will automatically wrap its children in a `GtkListboxRow`
+ * when necessary.
  */
 
 typedef struct _GtkListBoxClass   GtkListBoxClass;
@@ -2087,7 +2096,7 @@ gtk_list_box_focus (GtkWidget        *widget,
                 i = NULL;
             }
 
-          while (!g_sequence_iter_is_end (i))
+          while (i != NULL && !g_sequence_iter_is_end (i))
             {
               if (gtk_widget_get_sensitive (g_sequence_get (i)))
                 {
@@ -2548,119 +2557,265 @@ gtk_list_box_compute_expand (GtkWidget *widget,
 
   *hexpand_p = hexpand;
   *vexpand_p = vexpand;
-
-  /* We don't expand vertically beyond the minimum size */
-  if (*vexpand_p)
-    *vexpand_p = FALSE;
 }
 
 static GtkSizeRequestMode
 gtk_list_box_get_request_mode (GtkWidget *widget)
 {
-  return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+  GtkListBox *box = GTK_LIST_BOX (widget);
+  GSequenceIter *iter;
+  GtkListBoxRow *row;
+
+  if (box->placeholder && gtk_widget_get_child_visible (box->placeholder))
+    return gtk_widget_get_request_mode (box->placeholder);
+
+  /* Return constant-size, unless any of the children do hfw (or wfh) */
+
+  for (iter = g_sequence_get_begin_iter (box->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      row = g_sequence_get (iter);
+      if (!row_is_visible (row))
+        continue;
+
+      if (ROW_PRIV (row)->header != NULL &&
+          gtk_widget_get_request_mode (ROW_PRIV (row)->header) != GTK_SIZE_REQUEST_CONSTANT_SIZE)
+        return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+      if (gtk_widget_get_request_mode (GTK_WIDGET (row)) != GTK_SIZE_REQUEST_CONSTANT_SIZE)
+        return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
+    }
+
+  return GTK_SIZE_REQUEST_CONSTANT_SIZE;
 }
 
 static void
-gtk_list_box_measure (GtkWidget     *widget,
-                      GtkOrientation  orientation,
-                      int             for_size,
-                      int            *minimum,
-                      int            *natural,
-                      int            *minimum_baseline,
-                      int            *natural_baseline)
+gtk_list_box_measure_height_for_width (GtkListBox       *box,
+                                       int               for_width,
+                                       int              *minimum,
+                                       int              *natural,
+                                       GtkRequestedSize *sizes)
 {
-  GtkListBox *box = GTK_LIST_BOX (widget);
   GSequenceIter *iter;
+  GtkListBoxRow *row;
+  int i = 0;
 
-  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+  if (box->placeholder && gtk_widget_get_child_visible (box->placeholder))
     {
-      *minimum = 0;
-      *natural = 0;
+      gtk_widget_measure (box->placeholder, GTK_ORIENTATION_VERTICAL,
+                          for_width, minimum, natural, NULL, NULL);
+      return;
+    }
 
-      if (box->placeholder && gtk_widget_get_child_visible (box->placeholder))
-        gtk_widget_measure (box->placeholder, GTK_ORIENTATION_HORIZONTAL, -1,
-                            minimum, natural,
-                            NULL, NULL);
+  *minimum = 0;
+  *natural = 0;
+
+  for (iter = g_sequence_get_begin_iter (box->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      int row_min = 0, row_nat = 0;
 
-      for (iter = g_sequence_get_begin_iter (box->children);
-           !g_sequence_iter_is_end (iter);
-           iter = g_sequence_iter_next (iter))
+      row = g_sequence_get (iter);
+      if (!row_is_visible (row))
+        continue;
+
+      if (ROW_PRIV (row)->header != NULL)
         {
-          GtkListBoxRow *row;
-          int row_min;
-          int row_nat;
+          gtk_widget_measure (ROW_PRIV (row)->header, GTK_ORIENTATION_VERTICAL,
+                              for_width, &row_min, &row_nat, NULL, NULL);
+          *minimum += row_min;
+          *natural += row_nat;
 
-          row = g_sequence_get (iter);
+          if (sizes)
+            {
+              sizes[i].minimum_size = row_min;
+              sizes[i].natural_size = row_nat;
+              i++;
+            }
+        }
+      gtk_widget_measure (GTK_WIDGET (row), GTK_ORIENTATION_VERTICAL,
+                          for_width, &row_min, &row_nat, NULL, NULL);
+      *minimum += row_min;
+      *natural += row_nat;
 
-          /* We *do* take visible but filtered rows into account here so that
-           * the list width doesn't change during filtering
-           */
-          if (!gtk_widget_get_visible (GTK_WIDGET (row)))
-            continue;
+      if (sizes)
+        {
+          sizes[i].minimum_size = row_min;
+          sizes[i].natural_size = row_nat;
+          i++;
+        }
+    }
+}
 
-          gtk_widget_measure (GTK_WIDGET (row), orientation, -1,
-                              &row_min, &row_nat,
-                              NULL, NULL);
+static void
+gtk_list_box_measure_width_for_height (GtkListBox *box,
+                                       int         for_height,
+                                       int        *minimum,
+                                       int        *natural)
+{
+  GSequenceIter *iter;
+  GtkListBoxRow *row;
+  int i = 0;
+  GtkRequestedSize *sizes = NULL;
+  int min, max, min_height, nat_height;
+  int n_vexpand_children = 0;
+  int extra_height;
+
+  if (box->placeholder && gtk_widget_get_child_visible (box->placeholder))
+    {
+      gtk_widget_measure (box->placeholder, GTK_ORIENTATION_HORIZONTAL,
+                          for_height, minimum, natural, NULL, NULL);
+      return;
+    }
+
+  *minimum = 0;
+  *natural = 0;
+
+  /* Measure width for natural height */
+  for (iter = g_sequence_get_begin_iter (box->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      int row_min, row_nat;
 
+      row = g_sequence_get (iter);
+
+      /* We *do* take visible but filtered rows into account here so that
+       * the list width doesn't change during filtering
+       */
+      if (!gtk_widget_get_visible (GTK_WIDGET (row)))
+        continue;
+
+      gtk_widget_measure (GTK_WIDGET (row), GTK_ORIENTATION_HORIZONTAL,
+                          -1, &row_min, &row_nat, NULL, NULL);
+
+      *minimum = MAX (*minimum, row_min);
+      *natural = MAX (*natural, row_nat);
+
+      if (for_height >= 0 && gtk_widget_compute_expand (GTK_WIDGET (row), GTK_ORIENTATION_VERTICAL))
+        n_vexpand_children++;
+
+      i++;
+
+      if (ROW_PRIV (row)->header != NULL)
+        {
+          gtk_widget_measure (ROW_PRIV (row)->header, GTK_ORIENTATION_HORIZONTAL,
+                              -1, &row_min, &row_nat, NULL, NULL);
           *minimum = MAX (*minimum, row_min);
           *natural = MAX (*natural, row_nat);
 
-          if (ROW_PRIV (row)->header != NULL)
-            {
-              gtk_widget_measure (ROW_PRIV (row)->header, orientation, -1,
-                                  &row_min, &row_nat,
-                                  NULL, NULL);
-              *minimum = MAX (*minimum, row_min);
-              *natural = MAX (*natural, row_nat);
-            }
+          if (for_height >= 0 && gtk_widget_compute_expand (ROW_PRIV (row)->header, GTK_ORIENTATION_VERTICAL))
+            n_vexpand_children++;
+
+          i++;
         }
     }
-  else
+
+  if (for_height < 0)
+    return;
+
+  /* Binary search for the smallest width that lets us fit
+   * into the suggested height.  */
+  min = *minimum;
+  max = G_MAXINT;
+
+  while (min < max)
     {
-      if (for_size < 0)
-        {
-          int f;
-          gtk_list_box_measure (widget, GTK_ORIENTATION_HORIZONTAL, -1,
-                                &f, &for_size, NULL, NULL);
-        }
+      int test;
+
+      /* We're most likely to be measured for a height that matches
+       * our min or nat width, so start by checking around those
+       * sizes.  */
+      if (min == *minimum + 1 && max == *natural)
+        test = max - 1;
+      else if (max != G_MAXINT)
+        test = (min + max) / 2;
+      else if (min == *minimum)
+        test = min;
+      else if (min == *minimum + 1 && *natural >= min)
+        test = *natural;
+      else
+        test = min * 2;
 
-      *minimum = 0;
+      gtk_list_box_measure_height_for_width (box, test,
+                                             &min_height, &nat_height,
+                                             NULL);
+      if (min_height > for_height)
+        min = test + 1;
+      else
+        max = test;
+    }
 
-      if (box->placeholder && gtk_widget_get_child_visible (box->placeholder))
-        gtk_widget_measure (box->placeholder, orientation, for_size,
-                            minimum, NULL,
-                            NULL, NULL);
+  *minimum = min;
 
-      for (iter = g_sequence_get_begin_iter (box->children);
-           !g_sequence_iter_is_end (iter);
-           iter = g_sequence_iter_next (iter))
-        {
-          GtkListBoxRow *row;
-          int row_min = 0;
+  /* Now find the natural width */
+  sizes = g_new (GtkRequestedSize, i);
+  gtk_list_box_measure_height_for_width (box, -1,
+                                         &min_height, &nat_height,
+                                         sizes);
+  extra_height = gtk_distribute_natural_allocation (for_height - min_height,
+                                                    i, sizes);
+  *natural = 0;
+  i = 0;
 
-          row = g_sequence_get (iter);
-          if (!row_is_visible (row))
-            continue;
+  for (iter = g_sequence_get_begin_iter (box->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      int row_height, row_min, row_nat;
 
-          if (ROW_PRIV (row)->header != NULL)
-            {
-              gtk_widget_measure (ROW_PRIV (row)->header, orientation, for_size,
-                                  &row_min, NULL,
-                                  NULL, NULL);
-              *minimum += row_min;
-            }
-          gtk_widget_measure (GTK_WIDGET (row), orientation, for_size,
-                              &row_min, NULL,
+      row = g_sequence_get (iter);
+
+      if (!gtk_widget_get_visible (GTK_WIDGET (row)))
+        continue;
+
+      row_height = sizes[i].minimum_size;
+      if (gtk_widget_compute_expand (GTK_WIDGET (row), GTK_ORIENTATION_VERTICAL))
+        row_height += extra_height / n_vexpand_children;
+
+      gtk_widget_measure (GTK_WIDGET (row), GTK_ORIENTATION_HORIZONTAL,
+                          row_height, &row_min, &row_nat,
+                          NULL, NULL);
+
+      *natural = MAX (*natural, row_nat);
+      i++;
+
+      if (ROW_PRIV (row)->header != NULL)
+        {
+          row_height = sizes[i].minimum_size;
+          if (gtk_widget_compute_expand (ROW_PRIV (row)->header, GTK_ORIENTATION_VERTICAL))
+            row_height += extra_height / n_vexpand_children;
+
+          gtk_widget_measure (ROW_PRIV (row)->header, GTK_ORIENTATION_HORIZONTAL,
+                              row_height, &row_min, &row_nat,
                               NULL, NULL);
-          *minimum += row_min;
-        }
 
-      /* We always allocate the minimum height, since handling expanding rows
-       * is way too costly, and unlikely to be used, as lists are generally put
-       * inside a scrolling window anyway.
-       */
-      *natural = *minimum;
+          *natural = MAX (*natural, row_nat);
+          i++;
+        }
     }
+
+  g_free (sizes);
+}
+
+static void
+gtk_list_box_measure (GtkWidget     *widget,
+                      GtkOrientation orientation,
+                      int            for_size,
+                      int           *minimum,
+                      int           *natural,
+                      int           *minimum_baseline,
+                      int           *natural_baseline)
+{
+  GtkListBox *box = GTK_LIST_BOX (widget);
+
+  if (orientation == GTK_ORIENTATION_HORIZONTAL)
+    gtk_list_box_measure_width_for_height (box, for_size,
+                                           minimum, natural);
+  else
+    gtk_list_box_measure_height_for_width (box, for_size,
+                                           minimum, natural, NULL);
 }
 
 static void
@@ -2674,7 +2829,13 @@ gtk_list_box_size_allocate (GtkWidget *widget,
   GtkAllocation header_allocation;
   GtkListBoxRow *row;
   GSequenceIter *iter;
-  int child_min;
+  int child_min, child_nat;
+  int total_min = 0, total_nat = 0;
+  gboolean allocate_min = FALSE, allocate_nat = FALSE;
+  GtkRequestedSize *sizes = NULL;
+  int i = 0;
+  int n_vexpand_children = 0;
+  int extra_height = height;
 
 
   child_allocation.x = 0;
@@ -2698,6 +2859,88 @@ gtk_list_box_size_allocate (GtkWidget *widget,
       child_allocation.y += child_min;
     }
 
+  for (iter = g_sequence_get_begin_iter (box->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      row = g_sequence_get (iter);
+      if (!row_is_visible (row))
+        continue;
+
+      if (ROW_PRIV (row)->header != NULL)
+        {
+          gtk_widget_measure (ROW_PRIV (row)->header, GTK_ORIENTATION_VERTICAL,
+                              width, &child_min, &child_nat, NULL, NULL);
+          total_min += child_min;
+          total_nat += child_nat;
+          i++;
+
+          if (gtk_widget_compute_expand (ROW_PRIV (row)->header, GTK_ORIENTATION_VERTICAL))
+            n_vexpand_children++;
+        }
+
+      gtk_widget_measure (GTK_WIDGET (row), GTK_ORIENTATION_VERTICAL,
+                          width, &child_min, &child_nat, NULL, NULL);
+      total_min += child_min;
+      total_nat += child_nat;
+      i++;
+
+      if (gtk_widget_compute_expand (GTK_WIDGET (row), GTK_ORIENTATION_VERTICAL))
+        n_vexpand_children++;
+    }
+
+  /* We're most likely to be allocated either our minimum or natural
+   * height, even more so when we're placed inside a GtkScrolledWindow &
+   * GtkViewport. Detect these cases and skip the logic for distributing
+   * sizes.
+   */
+  if (height == total_min)
+    {
+      allocate_min = TRUE;
+      extra_height = 0;
+      goto do_allocate;
+    }
+  else if (height >= total_nat)
+    {
+      allocate_nat = TRUE;
+      extra_height = height - total_nat;
+      goto do_allocate;
+    }
+
+  extra_height = height - total_min;
+  sizes = g_new (GtkRequestedSize, i);
+  i = 0;
+
+  for (iter = g_sequence_get_begin_iter (box->children);
+       !g_sequence_iter_is_end (iter);
+       iter = g_sequence_iter_next (iter))
+    {
+      row = g_sequence_get (iter);
+      if (!row_is_visible (row))
+        continue;
+
+      if (ROW_PRIV (row)->header != NULL)
+        {
+          gtk_widget_measure (ROW_PRIV (row)->header,
+                              GTK_ORIENTATION_VERTICAL, width,
+                              &sizes[i].minimum_size,
+                              &sizes[i].natural_size,
+                              NULL, NULL);
+          i++;
+        }
+
+      gtk_widget_measure (GTK_WIDGET (row),
+                          GTK_ORIENTATION_VERTICAL, width,
+                          &sizes[i].minimum_size,
+                          &sizes[i].natural_size,
+                          NULL, NULL);
+      i++;
+    }
+
+  extra_height = gtk_distribute_natural_allocation (extra_height, i, sizes);
+
+do_allocate:
+  i = 0;
   for (iter = g_sequence_get_begin_iter (box->children);
        !g_sequence_iter_is_end (iter);
        iter = g_sequence_iter_next (iter))
@@ -2712,28 +2955,51 @@ gtk_list_box_size_allocate (GtkWidget *widget,
 
       if (ROW_PRIV (row)->header != NULL)
         {
-          gtk_widget_measure (ROW_PRIV (row)->header, GTK_ORIENTATION_VERTICAL,
-                              width,
-                              &child_min, NULL, NULL, NULL);
-          header_allocation.height = child_min;
+          if (allocate_min || allocate_nat)
+            gtk_widget_measure (ROW_PRIV (row)->header,
+                                GTK_ORIENTATION_VERTICAL, width,
+                                &child_min, &child_nat,
+                                NULL, NULL);
+          if (allocate_min)
+            header_allocation.height = child_min;
+          else if (allocate_nat)
+            header_allocation.height = child_nat;
+          else
+            header_allocation.height = sizes[i].minimum_size;
+
+          if (gtk_widget_compute_expand (ROW_PRIV (row)->header, GTK_ORIENTATION_VERTICAL))
+            header_allocation.height += extra_height / n_vexpand_children;
           header_allocation.y = child_allocation.y;
           gtk_widget_size_allocate (ROW_PRIV (row)->header,
                                     &header_allocation,
                                     -1);
-          child_allocation.y += child_min;
+          child_allocation.y += header_allocation.height;
+          i++;
         }
 
-      ROW_PRIV (row)->y = child_allocation.y;
+      if (allocate_min || allocate_nat)
+        gtk_widget_measure (GTK_WIDGET (row),
+                            GTK_ORIENTATION_VERTICAL, width,
+                            &child_min, &child_nat,
+                            NULL, NULL);
+      if (allocate_min)
+        child_allocation.height = child_min;
+      else if (allocate_nat)
+        child_allocation.height = child_nat;
+      else
+        child_allocation.height = sizes[i].minimum_size;
 
-      gtk_widget_measure (GTK_WIDGET (row), GTK_ORIENTATION_VERTICAL,
-                          child_allocation.width,
-                          &child_min, NULL, NULL, NULL);
-      child_allocation.height = child_min;
+      if (gtk_widget_compute_expand (GTK_WIDGET (row), GTK_ORIENTATION_VERTICAL))
+        child_allocation.height += extra_height / n_vexpand_children;
 
+      ROW_PRIV (row)->y = child_allocation.y;
       ROW_PRIV (row)->height = child_allocation.height;
       gtk_widget_size_allocate (GTK_WIDGET (row), &child_allocation, -1);
-      child_allocation.y += child_min;
+      child_allocation.y += child_allocation.height;
+      i++;
     }
+
+  g_free (sizes);
 }
 
 /**
diff --git a/gtk/gtklistheader.c b/gtk/gtklistheader.c
index 0729e0bb9d14f4c5143942d66766b7bd5f5a3b5b..cb5f518ff086c109dc48c0634533afb9f806e1d9 100644
--- a/gtk/gtklistheader.c
+++ b/gtk/gtklistheader.c
@@ -24,8 +24,7 @@
 /**
  * GtkListHeader:
  *
- * `GtkListHeader` is used by list widgets to represent the headers they
- * display.
+ * Used by list widgets to represent the headers they display.
  *
  * `GtkListHeader` objects are managed just like [class@Gtk.ListItem]
  * objects via their factory, but provide a different set of properties suitable
diff --git a/gtk/gtklistitem.c b/gtk/gtklistitem.c
index 998162745e7b0169330ea1f8350ee4c60eb00bfe..c27cdd9805925b58f400a5ad9be44e739b30802a 100644
--- a/gtk/gtklistitem.c
+++ b/gtk/gtklistitem.c
@@ -27,8 +27,7 @@
 /**
  * GtkListItem:
  *
- * `GtkListItem` is used by list widgets to represent items in a
- * [iface@Gio.ListModel].
+ * Used by list widgets to represent items in a [iface@Gio.ListModel].
  *
  * `GtkListItem` objects are managed by the list widget (with its factory)
  * and cannot be created by applications, but they need to be populated
diff --git a/gtk/gtklistitemfactory.c b/gtk/gtklistitemfactory.c
index 4d6d75d5a7fbb043f01856ead22d05f623f53185..5e815e189c333edc003ae01fdfa7b6f37e470940 100644
--- a/gtk/gtklistitemfactory.c
+++ b/gtk/gtklistitemfactory.c
@@ -26,7 +26,7 @@
 /**
  * GtkListItemFactory:
  *
- * A `GtkListItemFactory` creates widgets for the items taken from a `GListModel`.
+ * Creates widgets for the items taken from a `GListModel`.
  *
  * This is one of the core concepts of handling list widgets such
  * as [class@Gtk.ListView] or [class@Gtk.GridView].
diff --git a/gtk/gtklistlistmodel.c b/gtk/gtklistlistmodel.c
index a35493b03b7833529fa291bff6fbc5b063762900..be7de75922862e6b987040bcf7556f4d7b8d910e 100644
--- a/gtk/gtklistlistmodel.c
+++ b/gtk/gtklistlistmodel.c
@@ -21,8 +21,7 @@
 /*
  * GtkListListModel:
  *
- * `GtkListListModel` is a `GListModel` implementation that takes a list API
- * and provides it as a `GListModel`.
+ * A list model that takes a list API and provides it as a `GListModel`.
  */
 
 #include "config.h"
diff --git a/gtk/gtklistview.c b/gtk/gtklistview.c
index a90b31bb46d5de4279f10eaf060bfc35c4f4a1d5..f0af449b796879d6ae4287ac585a47af2a11f4f5 100644
--- a/gtk/gtklistview.c
+++ b/gtk/gtklistview.c
@@ -42,7 +42,7 @@
 /**
  * GtkListView:
  *
- * `GtkListView` presents a large dynamic list of items.
+ * Presents a large dynamic list of items.
  *
  * `GtkListView` uses its factory to generate one row widget for each visible
  * item and shows them in a linear display, either vertically or horizontally.
@@ -144,8 +144,8 @@
  *
  * # Accessibility
  *
- * `GtkListView` uses the %GTK_ACCESSIBLE_ROLE_LIST role, and the list
- * items use the %GTK_ACCESSIBLE_ROLE_LIST_ITEM role.
+ * `GtkListView` uses the [enum@Gtk.AccessibleRole.list] role, and the list
+ * items use the [enum@Gtk.AccessibleRole.list_item] role.
  */
 
 enum
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index cad8ca8b16825c3afb0bf92a7da91ae3c1513b01..cdbd17516281163a9d8da239b15e8ea2e4ed44bd 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -247,12 +247,11 @@ static gboolean do_setlocale = TRUE;
 /**
  * gtk_disable_setlocale:
  *
- * Prevents [func@Gtk.init] and [func@Gtk.init_check] from automatically calling
- * `setlocale (LC_ALL, "")`.
+ * Prevents [func@Gtk.init] and [func@Gtk.init_check] from calling `setlocale()`.
  *
  * You would want to use this function if you wanted to set the locale for
- * your program to something other than the user’s locale, or if
- * you wanted to set different values for different locale categories.
+ * your program to something other than the user’s locale, or if you wanted
+ * to set different values for different locale categories.
  *
  * Most programs should not need to call this function.
  **/
@@ -604,16 +603,18 @@ do_post_parse_initialization (void)
 /**
  * gtk_init_check:
  *
- * This function does the same work as gtk_init() with only a single
- * change: It does not terminate the program if the windowing system
- * can’t be initialized. Instead it returns %FALSE on failure.
+ * Initializes GTK.
+ *
+ * This function does the same work as [func@Gtk.init] with only a
+ * single change: It does not terminate the program if the windowing
+ * system can’t be initialized. Instead it returns false on failure.
  *
  * This way the application can fall back to some other means of
  * communication with the user - for example a curses or command line
  * interface.
  *
- * Returns: %TRUE if the windowing system has been successfully
- *   initialized, %FALSE otherwise
+ * Returns: true if the windowing system has been successfully
+ *   initialized, false otherwise
  */
 gboolean
 gtk_init_check (void)
@@ -649,16 +650,18 @@ gtk_init_check (void)
 /**
  * gtk_init:
  *
- * Call this function before using any other GTK functions in your GUI
- * applications.
+ * Initializes GTK.
+ *
+ * This function must be called before using any other GTK functions
+ * in your GUI applications.
  *
  * It will initialize everything needed to operate the toolkit. In particular,
  * it will open the default display (see [func@Gdk.Display.get_default]).
  *
- * If you are using `GtkApplication`, you usually don't have to call this
- * function; the `GApplication::startup` handler does it for you. Though,
- * if you are using GApplication methods that will be invoked before `startup`,
- * such as `local_command_line`, you may need to initialize stuff explicitly.
+ * If you are using [class@Gtk.Application], you usually don't have to call this
+ * function; the [vfunc@Gio.Application.startup] handler does it for you. Though,
+ * if you are using `GApplication` methods that will be invoked before `startup`,
+ * such as `local_command_line`, you may need to initialize GTK explicitly.
  *
  * This function will terminate your program if it was unable to initialize
  * the windowing system for some reason. If you want your program to fall back
@@ -745,7 +748,7 @@ gtk_init_check_abi_check (int num_checks, size_t sizeof_GtkWindow, size_t sizeof
 /**
  * gtk_is_initialized:
  *
- * Use this function to check if GTK has been initialized.
+ * Returns whether GTK has been initialized.
  *
  * See [func@Gtk.init].
  *
@@ -761,17 +764,17 @@ gtk_is_initialized (void)
 /**
  * gtk_get_locale_direction:
  *
- * Get the direction of the current locale. This is the expected
- * reading direction for text and UI.
+ * Gets the direction of the current locale.
+ *
+ * This is the expected reading direction for text and UI.
  *
  * This function depends on the current locale being set with
- * setlocale() and will default to setting the %GTK_TEXT_DIR_LTR
- * direction otherwise. %GTK_TEXT_DIR_NONE will never be returned.
+ * `setlocale()` and will default to setting the `GTK_TEXT_DIR_LTR`
+ * direction otherwise. `GTK_TEXT_DIR_NONE` will never be returned.
  *
- * GTK sets the default text direction according to the locale
- * during gtk_init(), and you should normally use
- * gtk_widget_get_direction() or gtk_widget_get_default_direction()
- * to obtain the current direction.
+ * GTK sets the default text direction according to the locale during
+ * [func@Gtk.init], and you should normally use [method@Gtk.Widget.get_direction]
+ * or [func@Gtk.Widget.get_default_direction] to obtain the current direction.
  *
  * This function is only needed rare cases when the locale is
  * changed after GTK has already been initialized. In this case,
@@ -1267,6 +1270,8 @@ update_pointer_focus_state (GtkWindow *toplevel,
   GtkWidget *old_target = NULL;
   GdkEventSequence *sequence;
   GdkDevice *device;
+  GtkWidget *event_widget;
+  graphene_point_t p;
   double x, y;
   double nx, ny;
 
@@ -1277,12 +1282,18 @@ update_pointer_focus_state (GtkWindow *toplevel,
     return old_target;
 
   gdk_event_get_position (event, &x, &y);
+  p = GRAPHENE_POINT_INIT (x, y);
+
+  event_widget  = gtk_get_event_widget (event);
+  if (!gtk_widget_compute_point (event_widget, GTK_WIDGET (toplevel), &p, &p))
+    return old_target;
+
   gtk_native_get_surface_transform (GTK_NATIVE (toplevel), &nx, &ny);
-  x -= nx;
-  y -= ny;
+  p.x -= nx;
+  p.y -= ny;
 
   gtk_window_update_pointer_focus (toplevel, device, sequence,
-                                   new_target, x, y);
+                                   new_target, p.x, p.y);
 
   return old_target;
 }
diff --git a/gtk/gtkmaplistmodel.c b/gtk/gtkmaplistmodel.c
index 3166bccf1def440a15e18fd68be12c04ce19b494..a7466b0d48293dbdb52498bd3ebe8084e5fbb9c0 100644
--- a/gtk/gtkmaplistmodel.c
+++ b/gtk/gtkmaplistmodel.c
@@ -28,7 +28,7 @@
 /**
  * GtkMapListModel:
  *
- * A `GtkMapListModel` maps the items in a list model to different items.
+ * A list model that maps the items in another model to different items.
  *
  * `GtkMapListModel` uses a [callback@Gtk.MapListModelMapFunc].
  *
diff --git a/gtk/gtkmediacontrols.c b/gtk/gtkmediacontrols.c
index 4278c53e1115479e9ec2185fe816cb15fa29922b..960c75cdd0cb1fc1463b23f81b62a7d787c896e4 100644
--- a/gtk/gtkmediacontrols.c
+++ b/gtk/gtkmediacontrols.c
@@ -31,9 +31,12 @@
 /**
  * GtkMediaControls:
  *
- * `GtkMediaControls` is a widget to show controls for a video.
+ * Shows controls for video playback.
  *
- * ![An example GtkMediaControls](media-controls.png)
+ * <picture>
+ *   <source srcset="media-controls-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkMediaControls" src="media-controls.png">
+ * </picture>
  *
  * Usually, `GtkMediaControls` is used as part of [class@Gtk.Video].
  */
diff --git a/gtk/gtkmediafile.c b/gtk/gtkmediafile.c
index 8a70e703ab4d023fbc9a1a946c50e65d6919fa8a..cd3863758e18dd2bd98b13ce535d7b0bb964c138 100644
--- a/gtk/gtkmediafile.c
+++ b/gtk/gtkmediafile.c
@@ -30,7 +30,7 @@
 /**
  * GtkMediaFile:
  *
- * `GtkMediaFile` implements `GtkMediaStream` for files.
+ * Implements the `GtkMediaStream` interface for files.
  *
  * This provides a simple way to play back video files with GTK.
  *
@@ -420,7 +420,7 @@ gtk_media_file_clear (GtkMediaFile *self)
  * @self: a `GtkMediaFile`
  * @filename: (type filename) (nullable): name of file to play
  *
- * Sets the `GtkMediaFile to play the given file.
+ * Sets the `GtkMediaFile` to play the given file.
  *
  * This is a utility function that converts the given @filename
  * to a `GFile` and calls [method@Gtk.MediaFile.set_file].
@@ -449,7 +449,7 @@ gtk_media_file_set_filename (GtkMediaFile *self,
  * @self: a `GtkMediaFile`
  * @resource_path: (nullable): path to resource to play
  *
- * Sets the `GtkMediaFile to play the given resource.
+ * Sets the `GtkMediaFile` to play the given resource.
  *
  * This is a utility function that converts the given @resource_path
  * to a `GFile` and calls [method@Gtk.MediaFile.set_file].
diff --git a/gtk/gtkmediastream.c b/gtk/gtkmediastream.c
index 75538eaa320e3862e2fc0b148f058721d5667017..2ea9a2fed0cd97fbee006aea11bb1e284924bb57 100644
--- a/gtk/gtkmediastream.c
+++ b/gtk/gtkmediastream.c
@@ -25,7 +25,7 @@
 /**
  * GtkMediaStream:
  *
- * `GtkMediaStream` is the integration point for media playback inside GTK.
+ * The integration point for media playback inside GTK.
  *
  * GTK provides an implementation of the `GtkMediaStream` interface that
  * is called [class@Gtk.MediaFile].
diff --git a/gtk/gtkmenubutton.c b/gtk/gtkmenubutton.c
index 6543a24b299ac7ea6841a49af5005df52ceabbb3..afb6913915de3215763c3aedc60a29e61d49a391 100644
--- a/gtk/gtkmenubutton.c
+++ b/gtk/gtkmenubutton.c
@@ -21,9 +21,12 @@
 /**
  * GtkMenuButton:
  *
- * The `GtkMenuButton` widget is used to display a popup when clicked.
+ * Displays a popup when clicked.
  *
- * ![An example GtkMenuButton](menu-button.png)
+ * <picture>
+ *   <source srcset="menu-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkMenuButton" src="menu-button.png">
+ * </picture>
  *
  * This popup can be provided either as a `GtkPopover` or as an abstract
  * `GMenuModel`.
@@ -82,7 +85,7 @@
  *
  * # Accessibility
  *
- * `GtkMenuButton` uses the %GTK_ACCESSIBLE_ROLE_BUTTON role.
+ * `GtkMenuButton` uses the [enum@Gtk.AccessibleRole.button] role.
  */
 
 #include "config.h"
diff --git a/gtk/gtkmessagedialog.c b/gtk/gtkmessagedialog.c
index 7ac60fd7a9c8f553a5be09301779e9f330e1e6d3..c4e9f1a7e3422d299587dd77634632763af319d4 100644
--- a/gtk/gtkmessagedialog.c
+++ b/gtk/gtkmessagedialog.c
@@ -44,7 +44,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
  *
  * `GtkMessageDialog` presents a dialog with some message text.
  *
- * ![An example GtkMessageDialog](messagedialog.png)
+ * <picture>
+ *   <source srcset="messagedialog-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkMessageDialog" src="messagedialog.png">
+ * </picture>
  *
  * It’s simply a convenience widget; you could construct the equivalent of
  * `GtkMessageDialog` from `GtkDialog` without too much effort, but
diff --git a/gtk/gtkmountoperation.c b/gtk/gtkmountoperation.c
index 4429467860c48c715ac557aa79976f1b7f613304..866c8c395bea3f85975a9a0510b0f1557c01d349 100644
--- a/gtk/gtkmountoperation.c
+++ b/gtk/gtkmountoperation.c
@@ -60,16 +60,16 @@
 /**
  * GtkMountOperation:
  *
- * `GtkMountOperation` is an implementation of `GMountOperation`.
- *
- * The functions and objects described here make working with GTK and
- * GIO more convenient.
+ * Asks the user for passwords and other information required to
+ * mount a volume.
  *
  * `GtkMountOperation` is needed when mounting volumes:
  * It is an implementation of `GMountOperation` that can be used with
  * GIO functions for mounting volumes such as
- * g_file_mount_enclosing_volume(), g_file_mount_mountable(),
- * g_volume_mount(), g_mount_unmount_with_operation() and others.
+ * [method@Gio.File.mount_enclosing_volume],
+ * [method@Gio.File.mount_mountable],
+ * [method@Gio.Volume.mount],
+ * [method@Gio.Mount.unmount_with_operation] and others.
  *
  * When necessary, `GtkMountOperation` shows dialogs to let the user
  * enter passwords, ask questions or show processes blocking unmount.
diff --git a/gtk/gtkmultiselection.c b/gtk/gtkmultiselection.c
index c5bc5dae399e3b62216b485ae9d128b5725904d8..346388e0e3edb30ea7ad5b771e45fd1599206f3c 100644
--- a/gtk/gtkmultiselection.c
+++ b/gtk/gtkmultiselection.c
@@ -28,8 +28,7 @@
 /**
  * GtkMultiSelection:
  *
- * `GtkMultiSelection` is a `GtkSelectionModel` that allows selecting multiple
- * elements.
+ * A selection model that allows selecting multiple elements.
  */
 
 struct _GtkMultiSelection
diff --git a/gtk/gtkmultisorter.c b/gtk/gtkmultisorter.c
index fd7a95b041c6c55a2d7742ec13770667d15440dc..7b66e6b2193673579c35d9df6786cd0e9cd4e271 100644
--- a/gtk/gtkmultisorter.c
+++ b/gtk/gtkmultisorter.c
@@ -35,8 +35,7 @@
 /**
  * GtkMultiSorter:
  *
- * `GtkMultiSorter` combines multiple sorters by trying them
- * in turn.
+ * Combines multiple sorters by trying them in turn.
  *
  * If the first sorter compares two items as equal,
  * the second is tried next, and so on.
diff --git a/gtk/gtknative.c b/gtk/gtknative.c
index c35c331be8fe9a1b19c72226fe31d8d7295aabc4..0dcf1af3680740f59f7297ea42970c011b804795 100644
--- a/gtk/gtknative.c
+++ b/gtk/gtknative.c
@@ -44,8 +44,7 @@ static GQuark quark_gtk_native_private;
 /**
  * GtkNative:
  *
- * `GtkNative` is the interface implemented by all widgets that have
- * their own `GdkSurface`.
+ * An interface for widgets that have their own [class@Gdk.Surface].
  *
  * The obvious example of a `GtkNative` is `GtkWindow`.
  *
diff --git a/gtk/gtknativedialog.c b/gtk/gtknativedialog.c
index 2def629fcae5c58cd57b7afe07ca5aff3ec46015..4ef66b74e6e97877fa35e75adf8dcf43ec5d2494 100644
--- a/gtk/gtknativedialog.c
+++ b/gtk/gtknativedialog.c
@@ -32,10 +32,10 @@
 /**
  * GtkNativeDialog:
  *
- * Native dialogs are platform dialogs that don't use `GtkDialog`.
+ * Base class for platform dialogs that don't use `GtkDialog`.
  *
- * They are used in order to integrate better with a platform, by
- * looking the same as other native applications and supporting
+ * Native dialogs are used in order to integrate better with a platform,
+ * by looking the same as other native applications and supporting
  * platform specific features.
  *
  * The [class@Gtk.Dialog] functions cannot be used on such objects,
diff --git a/gtk/gtknoselection.c b/gtk/gtknoselection.c
index 05fafa8ec78848121113b6e03cd0e46ccd44b0f3..7bec8238cba73b8843bac70f28aa6e59719b1883 100644
--- a/gtk/gtknoselection.c
+++ b/gtk/gtknoselection.c
@@ -28,8 +28,7 @@
 /**
  * GtkNoSelection:
  *
- * `GtkNoSelection` is a `GtkSelectionModel` that does not allow selecting
- * anything.
+ * A selection model that does not allow selecting anything.
  *
  * This model is meant to be used as a simple wrapper around a `GListModel`
  * when a `GtkSelectionModel` is required.
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 2b505a1279676e5b223b8641ff9b8db1fd6d368a..8f43c3ecc1f0ed53b41f40c6a387257fb0ba1eac 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -61,10 +61,12 @@
 /**
  * GtkNotebook:
  *
- * `GtkNotebook` is a container whose children are pages switched
- * between using tabs.
+ * Switches between children using tabs.
  *
- * ![An example GtkNotebook](notebook.png)
+ * <picture>
+ *   <source srcset="notebook-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkNotebook" src="notebook.png">
+ * </picture>
  *
  * There are many configuration options for `GtkNotebook`. Among
  * other things, you can choose on which edge the tabs appear
@@ -174,16 +176,16 @@
  *
  * `GtkNotebook` uses the following roles:
  *
- *  - %GTK_ACCESSIBLE_ROLE_GROUP for the notebook widget
- *  - %GTK_ACCESSIBLE_ROLE_TAB_LIST for the list of tabs
- *  - %GTK_ACCESSIBLE_ROLE_TAB role for each tab
- *  - %GTK_ACCESSIBLE_ROLE_TAB_PANEL for each page
+ *  - [enum@Gtk.AccessibleRole.group] for the notebook widget
+ *  - [enum@Gtk.AccessibleRole.tab_list] for the list of tabs
+ *  - [enum@Gtk.AccessibleRole.tab] role for each tab
+ *  - [enum@Gtk.AccessibleRole.tab_panel] for each page
  */
 
 /**
  * GtkNotebookPage:
  *
- * `GtkNotebookPage` is an auxiliary object used by `GtkNotebook`.
+ * An auxiliary object used by `GtkNotebook`.
  */
 
 #define SCROLL_DELAY_FACTOR   5
diff --git a/gtk/gtknumericsorter.c b/gtk/gtknumericsorter.c
index 2be43051c40b367040e59f3d429eb82931b87308..d5a6ccdc5a57f670765f1502b5444c82e3a72957 100644
--- a/gtk/gtknumericsorter.c
+++ b/gtk/gtknumericsorter.c
@@ -29,7 +29,7 @@
 /**
  * GtkNumericSorter:
  *
- * `GtkNumericSorter` is a `GtkSorter` that compares numbers.
+ * Sorts items numerically.
  *
  * To obtain the numbers to compare, this sorter evaluates a
  * [class@Gtk.Expression].
diff --git a/gtk/gtkorientable.c b/gtk/gtkorientable.c
index b816873f76849f97cea47c2d10e887e1ca812973..39fc44bedaf4a810e77308d586a5310cdf2e204d 100644
--- a/gtk/gtkorientable.c
+++ b/gtk/gtkorientable.c
@@ -31,8 +31,7 @@
 /**
  * GtkOrientable:
  *
- * The `GtkOrientable` interface is implemented by all widgets that can be
- * oriented horizontally or vertically.
+ * An interface for widgets that can be oriented horizontally or vertically.
  *
  * `GtkOrientable` is more flexible in that it allows the orientation to be
  * changed at runtime, allowing the widgets to “flip”.
diff --git a/gtk/gtkoverlay.c b/gtk/gtkoverlay.c
index ef4516c1c93d878a9061a55c1ec4cb2eda2d15c0..ec497f055fdbd6218c25c7936087f4e8fdc28777 100644
--- a/gtk/gtkoverlay.c
+++ b/gtk/gtkoverlay.c
@@ -34,10 +34,12 @@
 /**
  * GtkOverlay
  *
- * `GtkOverlay` is a container which contains a single main child, on top
- * of which it can place “overlay” widgets.
+ * Places “overlay” widgets on top of a single main child.
  *
- * ![An example GtkOverlay](overlay.png)
+ * <picture>
+ *   <source srcset="overlay-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkOverlay" src="overlay.png">
+ * </picture>
  *
  * The position of each overlay widget is determined by its
  * [property@Gtk.Widget:halign] and [property@Gtk.Widget:valign]
diff --git a/gtk/gtkoverlaylayout.c b/gtk/gtkoverlaylayout.c
index 8d8b28ac242dcf002476b73167e6fef1346da1a6..9f32a50e2dd606902947770feff846d25962a1bf 100644
--- a/gtk/gtkoverlaylayout.c
+++ b/gtk/gtkoverlaylayout.c
@@ -33,7 +33,7 @@
 /**
  * GtkOverlayLayout:
  *
- * `GtkOverlayLayout` is the layout manager used by [class@Gtk.Overlay].
+ * The layout manager used by [class@Gtk.Overlay].
  *
  * It places widgets as overlays on top of the main child.
  *
diff --git a/gtk/gtkpadcontroller.c b/gtk/gtkpadcontroller.c
index 171375eaaccf53bed7041a2ee0fc1c2fb86d6d32..03e281d4645de95214ffb95ea00a6e8c4ac1b9b3 100644
--- a/gtk/gtkpadcontroller.c
+++ b/gtk/gtkpadcontroller.c
@@ -20,8 +20,7 @@
 /**
  * GtkPadController:
  *
- * `GtkPadController` is an event controller for the pads found in drawing
- * tablets.
+ * Handles input from the pads found in drawing tablets.
  *
  * Pads are the collection of buttons and tactile sensors often found around
  * the stylus-sensitive area.
diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c
index 6137a41f09cbeb1411b6aab64710ca47b4fbf7f7..3e399d65d4a10a46120045966b9036b603b10ee4 100644
--- a/gtk/gtkpaned.c
+++ b/gtk/gtkpaned.c
@@ -45,9 +45,12 @@
 /**
  * GtkPaned:
  *
- * A widget with two panes, arranged either horizontally or vertically.
+ * Arranges its children in two panes, horizontally or vertically.
  *
- * ![An example GtkPaned](panes.png)
+ * <picture>
+ *   <source srcset="panes-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkPaned" src="panes.png">
+ * </picture>
  *
  * The division between the two panes is adjustable by the user
  * by dragging a handle.
diff --git a/gtk/gtkpasswordentry.c b/gtk/gtkpasswordentry.c
index 5f61579550865b8d3bd84d82d7d7cd4e8eab1970..c9378d04a078f017242177294eba63007cd96259 100644
--- a/gtk/gtkpasswordentry.c
+++ b/gtk/gtkpasswordentry.c
@@ -40,9 +40,12 @@
 /**
  * GtkPasswordEntry:
  *
- * `GtkPasswordEntry` is an entry that has been tailored for entering secrets.
+ * A single-line text entry widget for entering passwords and other secrets.
  *
- * ![An example GtkPasswordEntry](password-entry.png)
+ * <picture>
+ *   <source srcset="password-entry-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkPasswordEntry" src="password-entry.png">
+ * </picture>
  *
  * It does not show its contents in clear text, does not allow to copy it
  * to the clipboard, and it shows a warning when Caps Lock is engaged. If
@@ -71,7 +74,7 @@
  *
  * # Accessibility
  *
- * `GtkPasswordEntry` uses the %GTK_ACCESSIBLE_ROLE_TEXT_BOX role.
+ * `GtkPasswordEntry` uses the [enum@Gtk.AccessibleRole.text_box] role.
  */
 
 struct _GtkPasswordEntry
diff --git a/gtk/gtkpicture.c b/gtk/gtkpicture.c
index 34942151f2596e001c916deb36e5d6e3b345bf65..350e72006378ed426b48ba90477485e8e5fc62bf 100644
--- a/gtk/gtkpicture.c
+++ b/gtk/gtkpicture.c
@@ -33,9 +33,12 @@
 /**
  * GtkPicture:
  *
- * The `GtkPicture` widget displays a `GdkPaintable`.
+ * Displays a `GdkPaintable`.
  *
- * ![An example GtkPicture](picture.png)
+ * picture>
+ *   <source srcset="picture-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkPicture" src="picture.png">
+ * </picture>
  *
  * Many convenience functions are provided to make pictures simple to use.
  * For example, if you want to load an image from a file, and then display
@@ -78,7 +81,7 @@
  *
  * ## Accessibility
  *
- * `GtkPicture` uses the `GTK_ACCESSIBLE_ROLE_IMG` role.
+ * `GtkPicture` uses the [enum@Gtk.AccessibleRole.img] role.
  */
 
 enum
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index d8dcfc90436c6a94bf479b6fef5be473f33602e0..f71be4864bbb17594dc9416178ff5e1b9a829f6c 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -21,9 +21,12 @@
 /**
  * GtkPopover:
  *
- * `GtkPopover` is a bubble-like context popup.
+ * Presents a bubble-like popup.
  *
- * ![An example GtkPopover](popover.png)
+ * <picture>
+ *   <source srcset="popover-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkPopover" src="popover.png">
+ * </picture>
  *
  * It is primarily meant to provide context-dependent information
  * or options. Popovers are attached to a parent widget. By default,
@@ -726,7 +729,26 @@ gtk_popover_native_layout (GtkNative *native,
 
   if (gtk_widget_needs_allocate (widget))
     {
-      gtk_widget_allocate (widget, width, height, -1, NULL);
+      /* We know the popup's position in the toplevel's coordinate space,
+       * so convert it to be relative to the parent widget to define the
+       * popover's transform.
+       */
+      GskTransform *transform = NULL;
+      double native_x, native_y;
+      GtkWidget *parent = gtk_widget_get_parent (widget);
+      GtkWidget *root = GTK_WIDGET (gtk_widget_get_root (parent));
+      graphene_point_t parent_coords;
+      if (gtk_widget_compute_point (parent, root, &GRAPHENE_POINT_INIT (0, 0), &parent_coords))
+        {
+          transform = gsk_transform_translate (transform,
+                                               &GRAPHENE_POINT_INIT (
+                                                 priv->final_rect.x - parent_coords.x,
+                                                 priv->final_rect.y - parent_coords.y));
+        }
+      gtk_native_get_surface_transform (native, &native_x, &native_y);
+      transform = gsk_transform_translate (transform,
+                                           &GRAPHENE_POINT_INIT (-native_x, -native_y));
+      gtk_widget_allocate (widget, width, height, -1, transform);
 
       /* This fake motion event is needed for getting up to date pointer focus
        * and coordinates when the pointer didn't move but the layout changed
diff --git a/gtk/gtkpopovermenu.c b/gtk/gtkpopovermenu.c
index afd639fd69751bfef7788c65a08e1347346dcd4c..2601422dcb5671db779108f8338b346a00d684a6 100644
--- a/gtk/gtkpopovermenu.c
+++ b/gtk/gtkpopovermenu.c
@@ -41,10 +41,12 @@
 /**
  * GtkPopoverMenu:
  *
- * `GtkPopoverMenu` is a subclass of `GtkPopover` that implements menu
- * behavior.
+ * A subclass of `GtkPopover` that implements menu behavior.
  *
- * ![An example GtkPopoverMenu](menu.png)
+ * <picture>
+ *   <source srcset="menu-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkPopoverMenu" src="menu.png">
+ * </picture>
  *
  * `GtkPopoverMenu` treats its children like menus and allows switching
  * between them. It can open submenus as traditional, nested submenus,
@@ -152,11 +154,10 @@
  *
  * # Accessibility
  *
- * `GtkPopoverMenu` uses the %GTK_ACCESSIBLE_ROLE_MENU role, and its
- * items use the %GTK_ACCESSIBLE_ROLE_MENU_ITEM,
- * %GTK_ACCESSIBLE_ROLE_MENU_ITEM_CHECKBOX or
- * %GTK_ACCESSIBLE_ROLE_MENU_ITEM_RADIO roles, depending on the
- * action they are connected to.
+ * `GtkPopoverMenu` uses the [enum@Gtk.AccessibleRole.menu] role, and its
+ * items use the [enum@Gtk.AccessibleRole.menu_item],
+ * [enum@Gtk.AccessibleRole.checkbox] or [enum@Gtk.AccessibleRole.menu_item_radio]
+ * roles, depending on the action they are connected to.
  */
 
 typedef struct _GtkPopoverMenuClass GtkPopoverMenuClass;
diff --git a/gtk/gtkpopovermenubar.c b/gtk/gtkpopovermenubar.c
index d913499bcd3d19e7e6764d3b2eb5006f61277c67..662ee6ecbe6d0c35957a36b7e13dc112e4712de9 100644
--- a/gtk/gtkpopovermenubar.c
+++ b/gtk/gtkpopovermenubar.c
@@ -21,10 +21,12 @@
 /**
  * GtkPopoverMenuBar:
  *
- * `GtkPopoverMenuBar` presents a horizontal bar of items that pop
- * up popover menus when clicked.
+ * Presents a horizontal bar of items that pop up menus when clicked.
  *
- * ![An example GtkPopoverMenuBar](menubar.png)
+ * <picture>
+ *   <source srcset="menubar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkPopoverMenuBar" src="menubar.png">
+ * </picture>
  *
  * The only way to create instances of `GtkPopoverMenuBar` is
  * from a `GMenuModel`.
@@ -47,9 +49,9 @@
  *
  * # Accessibility
  *
- * `GtkPopoverMenuBar` uses the %GTK_ACCESSIBLE_ROLE_MENU_BAR role,
- * the menu items use the %GTK_ACCESSIBLE_ROLE_MENU_ITEM role and
- * the menus use the %GTK_ACCESSIBLE_ROLE_MENU role.
+ * `GtkPopoverMenuBar` uses the [enum@Gtk.AccessibleRole.menu_bar] role,
+ * the menu items use the [enum@Gtk.AccessibleRole.menu_item] role and
+ * the menus use the [enum@Gtk.AccessibleRole.menu] role.
  */
 
 
@@ -160,9 +162,11 @@ set_active_item (GtkPopoverMenuBar     *bar,
 
   if (bar->active_item)
     {
+      GtkStateFlags state = gtk_widget_get_state_flags (GTK_WIDGET (bar));
+
       if (popup || (was_popup && changed))
         open_submenu (bar->active_item);
-      else if (changed)
+      else if (changed && (state & GTK_STATE_FLAG_FOCUS_WITHIN))
         gtk_widget_grab_focus (GTK_WIDGET (bar->active_item));
     }
 }
diff --git a/gtk/gtkprintdialog.c b/gtk/gtkprintdialog.c
index 3d10c38fc3eab281ffe7eb2965bc31a8e0fed456..561609e9a813baf4a327f2c702ea0e6cbc3bc96b 100644
--- a/gtk/gtkprintdialog.c
+++ b/gtk/gtkprintdialog.c
@@ -50,8 +50,7 @@
 /**
  * GtkPrintSetup:
  *
- * A `GtkPrintSetup` is an auxiliary object for printing that allows decoupling
- * the setup from the printing.
+ * An auxiliary object for printing that allows decoupling the setup from the printing.
  *
  * A print setup is obtained by calling [method@Gtk.PrintDialog.setup],
  * and can later be passed to print functions such as [method@Gtk.PrintDialog.print].
@@ -217,11 +216,14 @@ gtk_print_setup_set_printer (GtkPrintSetup *setup,
 /**
  * GtkPrintDialog:
  *
- * A `GtkPrintDialog` object collects the arguments that
- * are needed to present a print dialog to the user, such
- * as a title for the dialog and whether it should be modal.
+ * Asynchronous API to present a print dialog to the user.
+ *
+ * `GtkPrintDialog` collects the arguments that are needed to present
+ *  the dialog, such as a title for the dialog and whether it should
+ *  be modal.
  *
  * The dialog is shown with the [method@Gtk.PrintDialog.setup] function.
+ *
  * The actual printing can be done with [method@Gtk.PrintDialog.print] or
  * [method@Gtk.PrintDialog.print_file]. These APIs follows the GIO async pattern,
  * and the results can be obtained by calling the corresponding finish methods.
diff --git a/gtk/gtkprivate.c b/gtk/gtkprivate.c
index 519d91f4a11bf1edfd5979e27b46ac9df75779af..85799235c87d89f3d39c12884d8fba20ae6352fb 100644
--- a/gtk/gtkprivate.c
+++ b/gtk/gtkprivate.c
@@ -33,7 +33,7 @@
 #include "gtkresources.h"
 
 
-#if !defined G_OS_WIN32 && !(defined GDK_WINDOWING_MACOS && defined QUARTZ_RELOCATION)
+#if !defined (G_OS_WIN32) && !(defined (GDK_WINDOWING_MACOS) && defined (QUARTZ_RELOCATION))
 
 const char *
 _gtk_get_datadir (void)
diff --git a/gtk/gtkprivate.h b/gtk/gtkprivate.h
index c1b63fddeddf07974d0f19c7ee4d283962906cbe..3b83f027f9bffb38a19a27d36cdf4d90e55617a9 100644
--- a/gtk/gtkprivate.h
+++ b/gtk/gtkprivate.h
@@ -162,8 +162,6 @@ void gtk_synthesize_crossing_events (GtkRoot         *toplevel,
 
 void _gtk_load_dll_with_libgtk3_manifest (const wchar_t *dllname);
 
-wchar_t * g_wcsdup (const wchar_t *wcs);
-
 #endif /* G_OS_WIN32 */
 
 G_END_DECLS
diff --git a/gtk/gtkprogressbar.c b/gtk/gtkprogressbar.c
index 6bfb456cf7ea06809694c4d8c50f8afb28cd4c58..a0a8c0e3664445cba04f8ea9b952c0ab3f882ae0 100644
--- a/gtk/gtkprogressbar.c
+++ b/gtk/gtkprogressbar.c
@@ -43,13 +43,15 @@
 /**
  * GtkProgressBar:
  *
- * `GtkProgressBar` is typically used to display the progress of a long
- * running operation.
+ * Displays the progress of a long-running operation.
  *
- * It provides a visual clue that processing is underway. `GtkProgressBar`
- * can be used in two different modes: percentage mode and activity mode.
+ * `GtkProgressBar` provides a visual clue that processing is underway.
+ * It can be used in two different modes: percentage mode and activity mode.
  *
- * ![An example GtkProgressBar](progressbar.png)
+ * <picture>
+ *   <source srcset="progressbar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkProgressBar" src="progressbar.png">
+ * </picture>
  *
  * When an application can determine how much work needs to take place
  * (e.g. read a fixed number of bytes from a file) and can monitor its
@@ -88,7 +90,7 @@
  *
  * # Accessibility
  *
- * `GtkProgressBar` uses the %GTK_ACCESSIBLE_ROLE_PROGRESS_BAR role.
+ * `GtkProgressBar` uses the [enum@Gtk.AccessibleRole.progress_bar] role.
  */
 
 typedef struct _GtkProgressBarClass         GtkProgressBarClass;
diff --git a/gtk/gtkpropertylookuplistmodel.c b/gtk/gtkpropertylookuplistmodel.c
index bf8f12b2517a0d7949100ff961e94c5f680c6879..48dbc032e3ca3d1de328cf13f05d45a9e77633c3 100644
--- a/gtk/gtkpropertylookuplistmodel.c
+++ b/gtk/gtkpropertylookuplistmodel.c
@@ -21,12 +21,13 @@
 /*
  * GtkPropertyLookupListModel:
  *
- * `GtkPropertyLookupListModel` is a `GListModel` implementation that takes an
- * object and a property and then recursively looks up the next element using
- * the property on the previous object.
+ * A list model that recursively looks up a property.
  *
- * For example, one could use this list model with the GtkWidget:parent property
- * to get a list of a widgets and all its ancestors.
+ * `GtkPropertyLookupListModel` takes an object and a property and looks
+ * up the next element using the property on the previous object.
+ *
+ * For example, one could use this list model with the [property@Gtk.Widget:parent]
+ * property to get a list of a widget and all its ancestors.
  **/
 
 #include "config.h"
diff --git a/gtk/gtkquartz.c b/gtk/gtkquartz.c
index f6916fc849d59ac001f8b865beee63a8a55ad021..3fe8dd5eedd9faf666f9d66a01b214501945a5cf 100644
--- a/gtk/gtkquartz.c
+++ b/gtk/gtkquartz.c
@@ -18,111 +18,10 @@
 
 #include "config.h"
 
-#include "gtkquartz.h"
+#include "gtkprivate.h"
 
 #include <gdk/macos/gdkmacos.h>
 
-static gboolean
-_cairo_surface_extents (cairo_surface_t *surface,
-                        GdkRectangle    *extents)
-{
-  double x1, x2, y1, y2;
-  cairo_t *cr;
-
-  g_return_val_if_fail (surface != NULL, FALSE);
-  g_return_val_if_fail (extents != NULL, FALSE);
-
-  cr = cairo_create (surface);
-  cairo_clip_extents (cr, &x1, &y1, &x2, &y2);
-
-  x1 = floor (x1);
-  y1 = floor (y1);
-  x2 = ceil (x2);
-  y2 = ceil (y2);
-  x2 -= x1;
-  y2 -= y1;
-
-  if (x1 < G_MININT || x1 > G_MAXINT ||
-      y1 < G_MININT || y1 > G_MAXINT ||
-      x2 > G_MAXINT || y2 > G_MAXINT)
-    {
-      extents->x = extents->y = extents->width = extents->height = 0;
-      return FALSE;
-    }
-
-  extents->x = x1;
-  extents->y = y1;
-  extents->width = x2;
-  extents->height = y2;
-
-  return TRUE;
-}
-
-static void
-_data_provider_release_cairo_surface (void       *info,
-                                      const void *data,
-                                      size_t      size)
-{
-  cairo_surface_destroy ((cairo_surface_t *)info);
-}
-
-/* Returns a new NSImage or %NULL in case of an error.
- * The device scale factor will be transferred to the NSImage (hidpi)
- */
-NSImage *
-_gtk_quartz_create_image_from_surface (cairo_surface_t *surface)
-{
-  CGColorSpaceRef colorspace;
-  CGDataProviderRef data_provider;
-  CGImageRef image;
-  void *data;
-  NSImage *nsimage;
-  double sx, sy;
-  cairo_t *cr;
-  cairo_surface_t *img_surface;
-  cairo_rectangle_int_t extents;
-  int width, height, rowstride;
-
-  if (!_cairo_surface_extents (surface, &extents))
-    return NULL;
-
-  cairo_surface_get_device_scale (surface, &sx, &sy);
-  width = extents.width * sx;
-  height = extents.height * sy;
-
-  img_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
-  cr = cairo_create (img_surface);
-  cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
-  cairo_scale (cr, sx, sy);
-  cairo_set_source_surface (cr, surface, -extents.x, -extents.y);
-  cairo_paint (cr);
-  cairo_destroy (cr);
-
-  cairo_surface_flush (img_surface);
-  rowstride = cairo_image_surface_get_stride (img_surface);
-  data = cairo_image_surface_get_data (img_surface);
-
-  colorspace = CGColorSpaceCreateDeviceRGB ();
-  /* Note: the release callback will only be called after NSImage below dies */
-  data_provider = CGDataProviderCreateWithData (surface, data, height * rowstride,
-                                                _data_provider_release_cairo_surface);
-
-  image = CGImageCreate (width, height, 8,
-                         32, rowstride,
-                         colorspace,
-                         /* XXX: kCGBitmapByteOrderDefault gives wrong colors..?? */
-                         kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst,
-                         data_provider, NULL, FALSE,
-                         kCGRenderingIntentDefault);
-  CGDataProviderRelease (data_provider);
-  CGColorSpaceRelease (colorspace);
-
-  nsimage = [[NSImage alloc] initWithCGImage:image size:NSMakeSize (extents.width, extents.height)];
-  CGImageRelease (image);
-
-  return nsimage;
-}
-
 #ifdef QUARTZ_RELOCATION
 
 /* Bundle-based functions for various directories. These almost work
diff --git a/gtk/gtkquartz.h b/gtk/gtkquartz.h
deleted file mode 100644
index 45b2c67054fc36163f24dc7376ea7c5d4f6ad215..0000000000000000000000000000000000000000
--- a/gtk/gtkquartz.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/* gtkquartz.h: Utility functions used by the Quartz port
- *
- * Copyright (C) 2006 Imendio AB
- *
- * This library is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 2 of the License, or (at your option) any later version.
- *
- * This library is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public
- * License along with this library. If not, see <http://www.gnu.org/licenses/>.
- */
-
-#pragma once
-
-#import <Cocoa/Cocoa.h>
-
-#include <cairo.h>
-#include <glib.h>
-
-G_BEGIN_DECLS
-
-NSImage    *_gtk_quartz_create_image_from_surface (cairo_surface_t *surface);
-const char *_gtk_get_datadir                      (void);
-const char *_gtk_get_libdir                       (void);
-const char *_gtk_get_localedir                    (void);
-const char *_gtk_get_sysconfdir                   (void);
-const char *_gtk_get_data_prefix                  (void);
-
-G_END_DECLS
-
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index 156079fc9e427051cba3af3e852470bacb312445..6ece2f2e40b9492a7af5793da4226c04d96b9638 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -53,8 +53,7 @@
 /**
  * GtkRange:
  *
- * `GtkRange` is the common base class for widgets which visualize an
- * adjustment.
+ * Base class for widgets which visualize an adjustment.
  *
  * Widgets that are derived from `GtkRange` include
  * [class@Gtk.Scale] and [class@Gtk.Scrollbar].
diff --git a/gtk/gtkrecentmanager.c b/gtk/gtkrecentmanager.c
index af42e229b70e680b370b38ce6b7f0104df9028b4..f6f783da9e46c58b3f7bd06277bd7f6c311304ed 100644
--- a/gtk/gtkrecentmanager.c
+++ b/gtk/gtkrecentmanager.c
@@ -20,7 +20,7 @@
 /**
  * GtkRecentManager:
  *
- * `GtkRecentManager` manages and looks up recently used files.
+ * Manages and looks up recently used files.
  *
  * Each recently used file is identified by its URI, and has meta-data
  * associated to it, like the names and command lines of the applications
@@ -124,7 +124,7 @@ typedef struct
 /**
  * GtkRecentInfo:
  *
- * `GtkRecentInfo` contains the metadata associated with an item in the
+ * Contains the metadata associated with an item in the
  * recently used files list.
  */
 struct _GtkRecentInfo
diff --git a/gtk/gtkrevealer.c b/gtk/gtkrevealer.c
index d2aad41c09277beecefb66298296d1ced00be792..ef6b11966864a351405facb0ee2e1f5fc644d5d5 100644
--- a/gtk/gtkrevealer.c
+++ b/gtk/gtkrevealer.c
@@ -35,7 +35,7 @@
 /**
  * GtkRevealer:
  *
- * A `GtkRevealer` animates the transition of its child from invisible to visible.
+ * Animates the transition of its child from invisible to visible.
  *
  * The style of transition can be controlled with
  * [method@Gtk.Revealer.set_transition_type].
@@ -52,7 +52,7 @@
  *
  * # Accessibility
  *
- * `GtkRevealer` uses the %GTK_ACCESSIBLE_ROLE_GROUP role.
+ * `GtkRevealer` uses the [enum@Gtk.AccessibleRole.group] role.
  *
  * The child of `GtkRevealer`, if set, is always available in the accessibility
  * tree, regardless of the state of the revealer widget.
diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c
index fe1da061b11f43db24e061a8b28c685a77e2092e..31cfaa9fe024e4c92a7cf7a909b240f172a481be 100644
--- a/gtk/gtkroot.c
+++ b/gtk/gtkroot.c
@@ -32,11 +32,11 @@
 /**
  * GtkRoot:
  *
- * `GtkRoot` is the interface implemented by all widgets that can act as a toplevel
- * widget.
+ * An interface for widgets that can act as the root of a widget hierarchy.
  *
- * The root widget takes care of providing the connection to the windowing system
- * and manages layout, drawing and event delivery for its widget hierarchy.
+ * The root widget takes care of providing the connection to the windowing
+ * system and manages layout, drawing and event delivery for its widget
+ * hierarchy.
  *
  * The obvious example of a `GtkRoot` is `GtkWindow`.
  *
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c
index 73bc1b04b0c4d19f2c1b4b3e6941057f8ebd8c30..7053e4b861a12122362ed876963bc91e01700198 100644
--- a/gtk/gtkscale.c
+++ b/gtk/gtkscale.c
@@ -46,9 +46,12 @@
 /**
  * GtkScale:
  *
- * A `GtkScale` is a slider control used to select a numeric value.
+ * Allows to select a numeric value with a slider control.
  *
- * ![An example GtkScale](scales.png)
+ * <picture>
+ *   <source srcset="scales-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkScale" src="scales.png">
+ * </picture>
  *
  * To use it, you’ll probably want to investigate the methods on its base
  * class, [class@Gtk.Range], in addition to the methods for `GtkScale` itself.
@@ -134,7 +137,7 @@
  *
  * # Accessibility
  *
- * `GtkScale` uses the %GTK_ACCESSIBLE_ROLE_SLIDER role.
+ * `GtkScale` uses the [enum@Gtk.AccessibleRole.slider] role.
  */
 
 
diff --git a/gtk/gtkscalebutton.c b/gtk/gtkscalebutton.c
index d536c20aba0a550a1ce256c3efb216b3208255ad..02232e7ee3daa016db20e031e276d40a210b774a 100644
--- a/gtk/gtkscalebutton.c
+++ b/gtk/gtkscalebutton.c
@@ -63,7 +63,7 @@
 /**
  * GtkScaleButton:
  *
- * `GtkScaleButton` provides a button which pops up a scale widget.
+ * Provides a button which pops up a scale widget.
  *
  * This kind of widget is commonly used for volume controls in multimedia
  * applications, and GTK provides a [class@Gtk.VolumeButton] subclass that
diff --git a/gtk/gtkscrollable.c b/gtk/gtkscrollable.c
index 02435cb7eecb742f9e3c0c9d5cb67d6fabd91580..a0862bf3ebec6fc17ba6b677c256f373343590ae 100644
--- a/gtk/gtkscrollable.c
+++ b/gtk/gtkscrollable.c
@@ -18,7 +18,7 @@
 /**
  * GtkScrollable:
  *
- * `GtkScrollable` is an interface for widgets with native scrolling ability.
+ * An interface for widgets with native scrolling ability.
  *
  * To implement this interface you should override the
  * [property@Gtk.Scrollable:hadjustment] and
diff --git a/gtk/gtkscrollbar.c b/gtk/gtkscrollbar.c
index 40bc72348d23e277afba1a210f15f05e90fcb333..6ef2676746ba03d0b2528b7e7a58cdf14cebf29c 100644
--- a/gtk/gtkscrollbar.c
+++ b/gtk/gtkscrollbar.c
@@ -39,9 +39,12 @@
 /**
  * GtkScrollbar:
  *
- * The `GtkScrollbar` widget is a horizontal or vertical scrollbar.
+ * Shows a horizontal or vertical scrollbar.
  *
- * ![An example GtkScrollbar](scrollbar.png)
+ * <picture>
+ *   <source srcset="scrollbar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkScrollbar" src="scrollbar.png">
+ * </picture>
  *
  * Its position and movement are controlled by the adjustment that is passed to
  * or created by [ctor@Gtk.Scrollbar.new]. See [class@Gtk.Adjustment] for more
@@ -80,7 +83,7 @@
  *
  * # Accessibility
  *
- * `GtkScrollbar` uses the %GTK_ACCESSIBLE_ROLE_SCROLLBAR role.
+ * `GtkScrollbar` uses the [enum@Gtk.AccessibleRole.scrollbar] role.
  */
 
 typedef struct _GtkScrollbarClass   GtkScrollbarClass;
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index d218959e54d7e66496dadfdd7176045f6da95a5f..f1b5b5112e0455d650fda8aed2c0ecf634ea94e7 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -60,7 +60,12 @@
 /**
  * GtkScrolledWindow:
  *
- * `GtkScrolledWindow` is a container that makes its child scrollable.
+ * Makes its child scrollable.
+ *
+ * <picture>
+ *   <source srcset="scrolledwindow-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkScrolledWindow" src="scrolledwindow.png">
+ * </picture>
  *
  * It does so using either internally added scrollbars or externally
  * associated adjustments, and optionally draws a frame around the child.
@@ -131,9 +136,10 @@
  *
  * # Accessibility
  *
- * Until GTK 4.10, `GtkScrolledWindow` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
+ * Until GTK 4.10, `GtkScrolledWindow` used the [enum@Gtk.AccessibleRole.group] role.
  *
- * Starting from GTK 4.12, `GtkScrolledWindow` uses the `GTK_ACCESSIBLE_ROLE_GENERIC` role.
+ * Starting from GTK 4.12, `GtkScrolledWindow` uses the [enum@Gtk.AccessibleRole.generic]
+ * role.
  */
 
 /* scrolled window policy and size requisition handling:
diff --git a/gtk/gtkscrollinfo.c b/gtk/gtkscrollinfo.c
index 513eccacc981ff27b29516980e12c3485be77c9a..c81040daecfc53282c12e92adcd0f867f090cb68 100644
--- a/gtk/gtkscrollinfo.c
+++ b/gtk/gtkscrollinfo.c
@@ -18,11 +18,10 @@
 /**
  * GtkScrollInfo:
  *
- * The `GtkScrollInfo` can be used to provide more accurate data on how a scroll
- * operation should be performed.
+ * Provides detailed information on how a scroll operation should be performed.
  *
- * Scrolling functions usually allow passing a %NULL scroll info which will cause
- * the default values to be used and just scroll the element into view.
+ * Scrolling functions usually allow passing a `NULL` scroll info which will
+ * cause the default values to be used and just scroll the element into view.
  *
  * Since: 4.12
  */
diff --git a/gtk/gtksearchbar.c b/gtk/gtksearchbar.c
index 02f76c0a0136db9b7eeb3600c233dcf98785e1cd..556b0c42b572eacb848bbb4aaa798a5cbd09e53f 100644
--- a/gtk/gtksearchbar.c
+++ b/gtk/gtksearchbar.c
@@ -45,9 +45,12 @@
 /**
  * GtkSearchBar:
  *
- * `GtkSearchBar` is a container made to have a search entry.
+ * Reveals a search entry when search is started.
  *
- * ![An example GtkSearchBar](search-bar.png)
+ * <picture>
+ *   <source srcset="search-bar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkSearchBar" src="search-bar.png">
+ * </picture>
  *
  * It can also contain additional widgets, such as drop-down menus,
  * or buttons.  The search bar would appear when a search is started
@@ -94,7 +97,7 @@
  *
  * # Accessibility
  *
- * `GtkSearchBar` uses the %GTK_ACCESSIBLE_ROLE_SEARCH role.
+ * `GtkSearchBar` uses the [enum@Gtk.AccessibleRole.search] role.
  */
 
 typedef struct _GtkSearchBarClass   GtkSearchBarClass;
diff --git a/gtk/gtksearchentry.c b/gtk/gtksearchentry.c
index 8a6bc7605717ca4a803a5760d90ba9caa4d6872e..6a4ebb3d306048534bfe058847d2b13b98ce5b78 100644
--- a/gtk/gtksearchentry.c
+++ b/gtk/gtksearchentry.c
@@ -47,13 +47,15 @@
 /**
  * GtkSearchEntry:
  *
- * `GtkSearchEntry` is an entry widget that has been tailored for use
- * as a search entry.
+ * A single-line text entry widget for use as a search entry.
  *
  * The main API for interacting with a `GtkSearchEntry` as entry
  * is the `GtkEditable` interface.
  *
- * ![An example GtkSearchEntry](search-entry.png)
+ * <picture>
+ *   <source srcset="search-entry-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkSearchEntry" src="search-entry.png">
+ * </picture>
  *
  * It will show an inactive symbolic “find” icon when the search
  * entry is empty, and a symbolic “clear” icon when there is text.
@@ -99,7 +101,7 @@
  *
  * ## Accessibility
  *
- * `GtkSearchEntry` uses the %GTK_ACCESSIBLE_ROLE_SEARCH_BOX role.
+ * `GtkSearchEntry` uses the [enum@Gtk.AccessibleRole.search_box] role.
  */
 
 enum {
diff --git a/gtk/gtksectionmodel.c b/gtk/gtksectionmodel.c
index 8883c51e35f6cbbf999aea4c81f9f7e5c3a0647b..69884e92aa9372d0cd5b7bb62304c8de11b242ef 100644
--- a/gtk/gtksectionmodel.c
+++ b/gtk/gtksectionmodel.c
@@ -26,7 +26,7 @@
 /**
  * GtkSectionModel:
  *
- * `GtkSectionModel` is an interface that adds support for sections to list models.
+ * An interface that adds support for sections to list models.
  *
  * A `GtkSectionModel` groups successive items into so-called sections. List widgets
  * like `GtkListView` and `GtkGridView` then allow displaying section headers for
diff --git a/gtk/gtkselectionfiltermodel.c b/gtk/gtkselectionfiltermodel.c
index fb3c0b0c43113a09a956ba320ef3f8d2beed6001..79c090d50bb0bd2e9e874579fb58dfc901fcf6ac 100644
--- a/gtk/gtkselectionfiltermodel.c
+++ b/gtk/gtkselectionfiltermodel.c
@@ -27,8 +27,7 @@
 /**
  * GtkSelectionFilterModel:
  *
- * `GtkSelectionFilterModel` is a list model that presents the selection from
- * a `GtkSelectionModel`.
+ * A list model that presents the selection from a `GtkSelectionModel`.
  */
 
 enum {
diff --git a/gtk/gtkselectionmodel.c b/gtk/gtkselectionmodel.c
index 07c01bfb2d4fdbf7b6ead63665dc911c522212ee..569d2b2b31fdd6ae4842b1985548c22edf186390 100644
--- a/gtk/gtkselectionmodel.c
+++ b/gtk/gtkselectionmodel.c
@@ -27,7 +27,7 @@
 /**
  * GtkSelectionModel:
  *
- * `GtkSelectionModel` is an interface that add support for selection to list models.
+ * An interface that adds support for selection to list models.
  *
  * This support is then used by widgets using list models to add the ability
  * to select and unselect various items.
diff --git a/gtk/gtkseparator.c b/gtk/gtkseparator.c
index c485abd88d996cba3d8cb16e262862e35d41aa72..2c553e1e7e38d9433f4a8b259d7caf901e4952af 100644
--- a/gtk/gtkseparator.c
+++ b/gtk/gtkseparator.c
@@ -34,9 +34,12 @@
 /**
  * GtkSeparator:
  *
- * `GtkSeparator` is a horizontal or vertical separator widget.
+ * Draws a horizontal or vertical line to separate other widgets.
  *
- * ![An example GtkSeparator](separator.png)
+ * <picture>
+ *   <source srcset="separator-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkSeparator" src="separator.png">
+ * </picture>
  *
  * A `GtkSeparator` can be used to group the widgets within a window.
  * It displays a line with a shadow to make it appear sunken into the
@@ -49,7 +52,7 @@
  *
  * # Accessibility
  *
- * `GtkSeparator` uses the %GTK_ACCESSIBLE_ROLE_SEPARATOR role.
+ * `GtkSeparator` uses the [enum@Gtk.AccessibleRole.separator] role.
  */
 
 typedef struct _GtkSeparatorClass GtkSeparatorClass;
diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
index 146c086ba662c3810b61f40af302561b386d9232..15cc3aa0dfb25a3759c6016b5ffca8f547470fe8 100644
--- a/gtk/gtksettings.c
+++ b/gtk/gtksettings.c
@@ -64,8 +64,7 @@
 /**
  * GtkSettings:
  *
- * `GtkSettings` provides a mechanism to share global settings between
- * applications.
+ * Provides a mechanism to share global settings between applications.
  *
  * On the X window system, this sharing is realized by an
  * [XSettings](http://www.freedesktop.org/wiki/Specifications/xsettings-spec)
@@ -1870,7 +1869,7 @@ settings_update_xsettings (GtkSettings *settings)
 {
   int i;
 
-  for (i = 0; pspecs[i]; i++)
+  for (i = 1; i < NUM_PROPERTIES; i++)
     settings_update_xsetting (settings, pspecs[i], FALSE);
 }
 
diff --git a/gtk/gtkshortcut.c b/gtk/gtkshortcut.c
index 97a84dce1b79bc296fc66960fc6cd5e41f2ce6bc..8eaa41d9a1b41c215ec30dcc89a280fd63466ce6 100644
--- a/gtk/gtkshortcut.c
+++ b/gtk/gtkshortcut.c
@@ -28,7 +28,7 @@
 /**
  * GtkShortcut:
  *
- * A `GtkShortcut` describes a keyboard shortcut.
+ * Describes a keyboard shortcut.
  *
  * It contains a description of how to trigger the shortcut via a
  * [class@Gtk.ShortcutTrigger] and a way to activate the shortcut
diff --git a/gtk/gtkshortcutaction.c b/gtk/gtkshortcutaction.c
index fea9698ff47c6dc0e35cc1f418f4f5a3b9e2060c..9681b3b1dafb10367fe30cfbd22436c3a56a65ad 100644
--- a/gtk/gtkshortcutaction.c
+++ b/gtk/gtkshortcutaction.c
@@ -20,8 +20,7 @@
 /**
 * GtkShortcutAction:
 *
-* `GtkShortcutAction` encodes an action that can be triggered by a
-* keyboard shortcut.
+* Encodes an action that can be triggered by a keyboard shortcut.
 *
 * `GtkShortcutActions` contain functions that allow easy presentation
 * to end users as well as being printed for debugging.
diff --git a/gtk/gtkshortcutaction.h b/gtk/gtkshortcutaction.h
index 92de06d2792358fc93fa246d8fcff6656a6c8429..937020b76310bf3e7e315710a77ff8b6ded26817 100644
--- a/gtk/gtkshortcutaction.h
+++ b/gtk/gtkshortcutaction.h
@@ -35,9 +35,9 @@ G_BEGIN_DECLS
  * @args: (nullable): The arguments passed to the activation
  * @user_data: (nullable): The user data provided when activating the action
  *
- * Prototype for shortcuts based on user callbacks.
+ * Type for shortcuts based on user callbacks.
  *
- * Returns: %TRUE if the action was successful.
+ * Returns: true if the action was successful
  */
 typedef gboolean (* GtkShortcutFunc) (GtkWidget *widget,
                                       GVariant  *args,
@@ -49,7 +49,7 @@ typedef gboolean (* GtkShortcutFunc) (GtkWidget *widget,
  *   action that can be activated. If this flag is not set,
  *   a future activation may select a different action.
  *
- * List of flags that can be passed to action activation.
+ * Flags that can be passed to action activation.
  *
  * More flags may be added in the future.
  **/
@@ -79,7 +79,7 @@ gboolean                gtk_shortcut_action_activate            (GtkShortcutActi
 /**
  * GtkNothingAction:
  *
- * A `GtkShortcutAction` that does nothing.
+ * Does nothing.
  */
 GDK_AVAILABLE_IN_ALL
 GDK_DECLARE_INTERNAL_TYPE (GtkNothingAction, gtk_nothing_action, GTK, NOTHING_ACTION, GtkShortcutAction)
@@ -92,7 +92,7 @@ GtkShortcutAction *     gtk_nothing_action_get                  (void);
 /**
  * GtkCallbackAction:
  *
- * A `GtkShortcutAction` that invokes a callback.
+ * Invokes a callback.
  */
 GDK_AVAILABLE_IN_ALL
 GDK_DECLARE_INTERNAL_TYPE (GtkCallbackAction, gtk_callback_action, GTK, CALLBACK_ACTION, GtkShortcutAction)
@@ -107,7 +107,9 @@ GtkShortcutAction *     gtk_callback_action_new                 (GtkShortcutFunc
 /**
  * GtkMnemonicAction:
  *
- * A `GtkShortcutAction` that calls gtk_widget_mnemonic_activate().
+ * Activates a widget with a mnemonic.
+ *
+ * This means that [method@Gtk.Widget.mnemonic_activate] is called.
  */
 GDK_AVAILABLE_IN_ALL
 GDK_DECLARE_INTERNAL_TYPE (GtkMnemonicAction, gtk_mnemonic_action, GTK, MNEMONIC_ACTION, GtkShortcutAction)
@@ -120,7 +122,9 @@ GtkShortcutAction *     gtk_mnemonic_action_get                 (void);
 /**
  * GtkActivateAction:
  *
- * A `GtkShortcutAction` that calls gtk_widget_activate().
+ * Activates a widget.
+ *
+ * Widgets are activated by calling [method@Gtk.Widget.activate].
  */
 GDK_AVAILABLE_IN_ALL
 GDK_DECLARE_INTERNAL_TYPE (GtkActivateAction, gtk_activate_action, GTK, ACTIVATE_ACTION, GtkShortcutAction)
@@ -133,10 +137,10 @@ GtkShortcutAction *     gtk_activate_action_get                 (void);
 /**
  * GtkSignalAction:
  *
- * A `GtkShortcut`Action that emits a signal.
+ * Emits a signal on a widget.
  *
  * Signals that are used in this way are referred to as keybinding signals,
- * and they are expected to be defined with the %G_SIGNAL_ACTION flag.
+ * and they are expected to be defined with the `G_SIGNAL_ACTION` flag.
  */
 GDK_AVAILABLE_IN_ALL
 GDK_DECLARE_INTERNAL_TYPE (GtkSignalAction, gtk_signal_action, GTK, SIGNAL_ACTION, GtkShortcutAction)
@@ -151,7 +155,11 @@ const char *            gtk_signal_action_get_signal_name       (GtkSignalAction
 /**
  * GtkNamedAction:
  *
- * A `GtkShortcutAction` that activates an action by name.
+ * Activates a named action.
+ *
+ * See [method@Gtk.WidgetClass.install_action] and
+ * [method@Gtk.Widget.insert_action_group] for ways
+ * to associate named actions with widgets.
  */
 GDK_AVAILABLE_IN_ALL
 GDK_DECLARE_INTERNAL_TYPE (GtkNamedAction, gtk_named_action, GTK, NAMED_ACTION, GtkShortcutAction)
diff --git a/gtk/gtkshortcutcontroller.c b/gtk/gtkshortcutcontroller.c
index eb78f0444ddcd7b23b9755b2bfb2885aac9c85e3..640e27b85fd17ac660ec2ca3eb27042622bae653 100644
--- a/gtk/gtkshortcutcontroller.c
+++ b/gtk/gtkshortcutcontroller.c
@@ -21,7 +21,7 @@
 /**
  * GtkShortcutController:
  *
- * `GtkShortcutController` is an event controller that manages shortcuts.
+ * Manages keyboard shortcuts and their activation.
  *
  * Most common shortcuts are using this controller implicitly, e.g. by
  * adding a mnemonic underline to a [class@Gtk.Label], or by installing a key
diff --git a/gtk/gtkshortcutmanager.c b/gtk/gtkshortcutmanager.c
index 0a7940246a57759fe6e7c6de43482c58df6520a0..edcb07d7f09331cdea24f65f678f5d8e3378340c 100644
--- a/gtk/gtkshortcutmanager.c
+++ b/gtk/gtkshortcutmanager.c
@@ -26,8 +26,7 @@
 /**
  * GtkShortcutManager:
  *
- * The `GtkShortcutManager` interface is used to implement
- * shortcut scopes.
+ * An interface that is used to implement shortcut scopes.
  *
  * This is important for [iface@Gtk.Native] widgets that have their
  * own surface, since the event controllers that are used to implement
@@ -37,7 +36,7 @@
  * [class@Gtk.Window] and [class@Gtk.Popover].
  *
  * Every widget that implements `GtkShortcutManager` will be used as a
- * %GTK_SHORTCUT_SCOPE_MANAGED.
+ * `GTK_SHORTCUT_SCOPE_MANAGED`.
  */
 
 G_DEFINE_INTERFACE (GtkShortcutManager, gtk_shortcut_manager, G_TYPE_OBJECT)
diff --git a/gtk/gtkshortcuttrigger.c b/gtk/gtkshortcuttrigger.c
index 956f12890636cc3c5491ef43acf2378500f75153..9fac64a70709f95ee8d9014ebf8a3321c7a4b71b 100644
--- a/gtk/gtkshortcuttrigger.c
+++ b/gtk/gtkshortcuttrigger.c
@@ -22,7 +22,7 @@
 /**
  * GtkShortcutTrigger:
  *
- * `GtkShortcutTrigger` tracks how a `GtkShortcut` should be activated.
+ * Tracks how a `GtkShortcut` can be activated.
  *
  * To find out if a `GtkShortcutTrigger` triggers, you can call
  * [method@Gtk.ShortcutTrigger.trigger] on a `GdkEvent`.
diff --git a/gtk/gtkshortcuttrigger.h b/gtk/gtkshortcuttrigger.h
index ebbb230a9f7a086b5f8988eefff59341b6540fb7..1fff511fe663871fd47c2d371f76373dd7394dab 100644
--- a/gtk/gtkshortcuttrigger.h
+++ b/gtk/gtkshortcuttrigger.h
@@ -81,7 +81,7 @@ GtkShortcutTrigger *    gtk_never_trigger_get                   (void);
 /**
  * GtkKeyvalTrigger:
  *
- * A `GtkShortcutTrigger` that triggers when a specific keyval and modifiers are pressed.
+ * Triggers when a specific keyval and modifiers are pressed.
  */
 
 GDK_AVAILABLE_IN_ALL
@@ -100,7 +100,7 @@ guint                   gtk_keyval_trigger_get_keyval           (GtkKeyvalTrigge
 /**
  * GtkMnemonicTrigger:
  *
- * A `GtkShortcutTrigger` that triggers when a specific mnemonic is pressed.
+ * Triggers when a specific mnemonic is pressed.
  *
  * Mnemonics require a *mnemonic modifier* (typically <kbd>Alt</kbd>) to be
  * pressed together with the mnemonic key.
@@ -118,9 +118,9 @@ guint                   gtk_mnemonic_trigger_get_keyval         (GtkMnemonicTrig
 /**
  * GtkAlternativeTrigger:
  *
- * A `GtkShortcutTrigger` that combines two triggers.
+ * Combines two shortcut triggers.
  *
- * The `GtkAlternativeTrigger` triggers when either of two trigger.
+ * The `GtkAlternativeTrigger` triggers when either of the two trigger.
  *
  * This can be cascaded to combine more than two triggers.
  */
diff --git a/gtk/gtksignallistitemfactory.c b/gtk/gtksignallistitemfactory.c
index 269f3fe85c85ec118baea7f795665a2b91ed889a..cae44441a08cc0139de7d88c6a29b20e6cc25089 100644
--- a/gtk/gtksignallistitemfactory.c
+++ b/gtk/gtksignallistitemfactory.c
@@ -28,8 +28,7 @@
 /**
  * GtkSignalListItemFactory:
  *
- * `GtkSignalListItemFactory` is a `GtkListItemFactory` that emits signals
- * to manage listitems.
+ * A `GtkListItemFactory` that emits signals to manage listitems.
  *
  * Signals are emitted for every listitem in the same order:
  *
@@ -56,9 +55,9 @@
  *  make sure to properly clean up the listitem in step 3 so that no information
  *  from the previous use leaks into the next use.
  *
- * 5. [signal@Gtk.SignalListItemFactory::teardown] is emitted to allow undoing
- * the effects of [signal@Gtk.SignalListItemFactory::setup]. After this signal
- * was emitted on a listitem, the listitem will be destroyed and not be used again.
+ *  5. [signal@Gtk.SignalListItemFactory::teardown] is emitted to allow undoing
+ *  the effects of [signal@Gtk.SignalListItemFactory::setup]. After this signal
+ *  was emitted on a listitem, the listitem will be destroyed and not be used again.
  *
  * Note that during the signal emissions, changing properties on the
  * listitems passed will not trigger notify signals as the listitem's
diff --git a/gtk/gtksingleselection.c b/gtk/gtksingleselection.c
index b47e77fd9fd78c4b903e8661dfed814a4b156587..59a5a51525dfd2ad65a6e23324fa2e90248a5b16 100644
--- a/gtk/gtksingleselection.c
+++ b/gtk/gtksingleselection.c
@@ -28,8 +28,7 @@
 /**
  * GtkSingleSelection:
  *
- * `GtkSingleSelection` is a `GtkSelectionModel` that allows selecting a single
- * item.
+ * A selection model that allows selecting a single item.
  *
  * Note that the selection is *persistent* -- if the selected item is removed
  * and re-added in the same [signal@Gio.ListModel::items-changed] emission, it
diff --git a/gtk/gtksizegroup.c b/gtk/gtksizegroup.c
index cb69ab22b1983cfb26ef8126c60d63a7c8f98dc7..cbae1e3b090e621171a12fd468c9bc909ce041b3 100644
--- a/gtk/gtksizegroup.c
+++ b/gtk/gtksizegroup.c
@@ -31,7 +31,7 @@
 /**
  * GtkSizeGroup
  *
- * `GtkSizeGroup` groups widgets together so they all request the same size.
+ * Groups widgets together so they all request the same size.
  *
  * This is typically useful when you want a column of widgets to have
  * the same size, but you can’t use a [class@Gtk.Grid] or [class@Gtk.Box].
diff --git a/gtk/gtksizerequest.h b/gtk/gtksizerequest.h
index 108b61a85a6b3c02c84c28e37b44c06c55689816..35f75e860fddc159c50b0613228ad4766264dc3e 100644
--- a/gtk/gtksizerequest.h
+++ b/gtk/gtksizerequest.h
@@ -33,9 +33,10 @@ typedef struct _GtkRequestedSize         GtkRequestedSize;
  * @minimum_size: The minimum size needed for allocation in a given orientation
  * @natural_size: The natural size for allocation in a given orientation
  *
- * Represents a request of a screen object in a given orientation. These
- * are primarily used in container implementations when allocating a natural
- * size for children calling. See [func@distribute_natural_allocation].
+ * Represents a request of a screen object in a given orientation.
+ *
+ * These are primarily used in container implementations when allocating
+ * a natural size for children. See [func@distribute_natural_allocation].
  */
 struct _GtkRequestedSize
 {
diff --git a/gtk/gtkslicelistmodel.c b/gtk/gtkslicelistmodel.c
index 7cc25b439a2643d59029f19f72afedb859df21d3..96e122f5b5c5089d7e644c46a39de84f604f2d84 100644
--- a/gtk/gtkslicelistmodel.c
+++ b/gtk/gtkslicelistmodel.c
@@ -27,7 +27,7 @@
 /**
  * GtkSliceListModel:
  *
- * `GtkSliceListModel` is a list model that presents a slice of another model.
+ * A list model that presents a slice of another model.
  *
  * This is useful when implementing paging by setting the size to the number
  * of elements per page and updating the offset whenever a different page is
diff --git a/gtk/gtksnapshot.c b/gtk/gtksnapshot.c
index 1d90a9ea0d36a2f698f1d7909efc694324ce8adf..fdea93dc3356762d670a60aefecf8a6d4374ccac 100644
--- a/gtk/gtksnapshot.c
+++ b/gtk/gtksnapshot.c
@@ -44,7 +44,7 @@
 /**
  * GtkSnapshot:
  *
- * `GtkSnapshot` assists in creating [class@Gsk.RenderNode]s for widgets.
+ * Assists in creating [class@Gsk.RenderNode]s for widgets.
  *
  * It functions in a similar way to a cairo context, and maintains a stack
  * of render nodes and their associated transformations.
diff --git a/gtk/gtksorter.c b/gtk/gtksorter.c
index 6d35dbb5f84eefba631e4c8d13817f8144366404..957c1b010a270381f16a7ab2e6e087134a9f1ba6 100644
--- a/gtk/gtksorter.c
+++ b/gtk/gtksorter.c
@@ -28,7 +28,7 @@
 /**
  * GtkSorter:
  *
- * `GtkSorter` is an object to describe sorting criteria.
+ * Describes sorting criteria for a [class@Gtk.SortListModel].
  *
  * Its primary user is [class@Gtk.SortListModel]
  *
diff --git a/gtk/gtksortlistmodel.c b/gtk/gtksortlistmodel.c
index eb1df98ed9c0b61ca2726d6a368c1ef0b3baea02..adebe950428f1830df14967d8a2385906ce36e1a 100644
--- a/gtk/gtksortlistmodel.c
+++ b/gtk/gtksortlistmodel.c
@@ -56,12 +56,14 @@
 /**
  * GtkSortListModel:
  *
- * A `GListModel` that sorts the elements of an underlying model
- * according to a `GtkSorter`.
+ * A list model that sorts the elements of another model.
+ *
+ * The elements are sorted according to a `GtkSorter`.
  *
  * The model is a stable sort. If two items compare equal according
  * to the sorter, the one that appears first in the original model will
  * also appear first after sorting.
+ *
  * Note that if you change the sorter, the previous order will have no
  * influence on the new order. If you want that, consider using a
  * `GtkMultiSorter` and appending the previous sorter to it.
diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c
index 2a5396f221b6c7d20b2433388d1c118a6e88c520..c6f76b10c59198c8bf2eed7502aed7e9284c9f93 100644
--- a/gtk/gtkspinbutton.c
+++ b/gtk/gtkspinbutton.c
@@ -69,10 +69,12 @@
 /**
  * GtkSpinButton:
  *
- * A `GtkSpinButton` is an ideal way to allow the user to set the
- * value of some attribute.
+ * Allows to enter or change numeric values.
  *
- * ![An example GtkSpinButton](spinbutton.png)
+ * <picture>
+ *   <source srcset="spinbutton-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkSpinButton" src="spinbutton.png">
+ * </picture>
  *
  * Rather than having to directly type a number into a `GtkEntry`,
  * `GtkSpinButton` allows the user to click on one of two arrows
@@ -186,7 +188,7 @@
  *
  * # Accessibility
  *
- * `GtkSpinButton` uses the %GTK_ACCESSIBLE_ROLE_SPIN_BUTTON role.
+ * `GtkSpinButton` uses the [enum@Gtk.AccessibleRole.spin_button] role.
  */
 
 typedef struct _GtkSpinButton      GtkSpinButton;
@@ -306,7 +308,8 @@ static void gtk_spin_button_snap           (GtkSpinButton      *spin_button,
 static void gtk_spin_button_insert_text    (GtkEditable        *editable,
                                             const char         *new_text,
                                             int                 new_text_length,
-                                            int                *position);
+                                            int                *position,
+                                            gpointer            data);
 static void gtk_spin_button_real_spin      (GtkSpinButton      *spin_button,
                                             double              step);
 static void gtk_spin_button_real_change_value (GtkSpinButton   *spin,
@@ -662,7 +665,6 @@ static void
 gtk_spin_button_editable_init (GtkEditableInterface *iface)
 {
   iface->get_delegate = gtk_spin_button_get_delegate;
-  iface->insert_text = gtk_spin_button_insert_text;
 }
 
 static gboolean
@@ -1087,6 +1089,7 @@ gtk_spin_button_init (GtkSpinButton *spin_button)
   gtk_widget_set_vexpand (spin_button->entry, TRUE);
   g_signal_connect (spin_button->entry, "activate", G_CALLBACK (gtk_spin_button_activate), spin_button);
   g_signal_connect (spin_button->entry, "changed", G_CALLBACK (gtk_spin_button_changed), spin_button);
+  g_signal_connect (spin_button->entry, "insert-text", G_CALLBACK (gtk_spin_button_insert_text), spin_button);
   gtk_widget_set_parent (spin_button->entry, GTK_WIDGET (spin_button));
 
   spin_button->down_button = g_object_new (GTK_TYPE_BUTTON,
@@ -1579,11 +1582,14 @@ gtk_spin_button_activate (GtkText *entry,
 
 static void
 gtk_spin_button_insert_text (GtkEditable *editable,
-                             const char *new_text,
+                             const char  *new_text,
                              int          new_text_length,
-                             int         *position)
+                             int         *position,
+                             gpointer     data)
 {
-  GtkSpinButton *spin = GTK_SPIN_BUTTON (editable);
+  GtkSpinButton *spin = GTK_SPIN_BUTTON (data);
+
+  g_signal_stop_emission_by_name (editable, "insert-text");
 
   if (spin->numeric)
     {
@@ -1674,8 +1680,12 @@ gtk_spin_button_insert_text (GtkEditable *editable,
         }
     }
 
+  g_signal_handlers_block_by_func (editable, gtk_spin_button_insert_text, data);
+
   gtk_editable_insert_text (GTK_EDITABLE (spin->entry),
                             new_text, new_text_length, position);
+
+  g_signal_handlers_unblock_by_func (editable, gtk_spin_button_insert_text, data);
 }
 
 static void
diff --git a/gtk/gtkspinner.c b/gtk/gtkspinner.c
index 63b58b1e3ae67722ca794acb4bc04b2833eba722..f0efe63e9a4bc636040645ee812b3905aadf9aa4 100644
--- a/gtk/gtkspinner.c
+++ b/gtk/gtkspinner.c
@@ -42,12 +42,15 @@
 /**
  * GtkSpinner:
  *
- * A `GtkSpinner` widget displays an icon-size spinning animation.
+ * Displays an icon-size spinning animation.
  *
  * It is often used as an alternative to a [class@Gtk.ProgressBar]
  * for displaying indefinite activity, instead of actual progress.
  *
- * ![An example GtkSpinner](spinner.png)
+ * <picture>
+ *   <source srcset="spinner-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkSpinner" src="spinner.png">
+ * </picture>
  *
  * To start the animation, use [method@Gtk.Spinner.start], to stop it
  * use [method@Gtk.Spinner.stop].
diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c
index 496f9a299c0dd84910a59f0e4010a7ccd86e42fc..2bd88aebcfcb400d8b71c94b7b03c33f4cd205a1 100644
--- a/gtk/gtkstack.c
+++ b/gtk/gtkstack.c
@@ -39,8 +39,12 @@
 /**
  * GtkStack:
  *
- * `GtkStack` is a container which only shows one of its children
- * at a time.
+ * Shows one of its children at a time.
+ *
+ * <picture>
+ *   <source srcset="stack-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkStack" src="stack.png">
+ * </picture>
  *
  * In contrast to `GtkNotebook`, `GtkStack` does not provide a means
  * for users to change the visible child. Instead, a separate widget
@@ -84,7 +88,7 @@
  *
  * # Accessibility
  *
- * `GtkStack` uses the %GTK_ACCESSIBLE_ROLE_TAB_PANEL for the stack
+ * `GtkStack` uses the [enum@Gtk.AccessibleRole.tab_panel] role for the stack
  * pages, which are the accessible parent objects of the child widgets.
  */
 
@@ -122,7 +126,7 @@
 /**
  * GtkStackPage:
  *
- * `GtkStackPage` is an auxiliary class used by `GtkStack`.
+ * An auxiliary class used by `GtkStack`.
  */
 
 /* TODO:
diff --git a/gtk/gtkstacksidebar.c b/gtk/gtkstacksidebar.c
index 71eb0fbaab274d752bb903893f5b63b433137797..6ab7303c8150b1e85921f668de97fa23908a61bb 100644
--- a/gtk/gtkstacksidebar.c
+++ b/gtk/gtkstacksidebar.c
@@ -38,7 +38,12 @@
 /**
  * GtkStackSidebar:
  *
- * A `GtkStackSidebar` uses a sidebar to switch between `GtkStack` pages.
+ * Uses a sidebar to switch between `GtkStack` pages.
+ *
+ * <picture>
+ *   <source srcset="sidebar-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkStackSidebar" src="sidebar.png">
+ * </picture>
  *
  * In order to use a `GtkStackSidebar`, you simply use a `GtkStack` to
  * organize your UI flow, and add the sidebar to your sidebar area. You
diff --git a/gtk/gtkstackswitcher.c b/gtk/gtkstackswitcher.c
index ecc10ac439cedf9e2b6dcc9361bb8ac104d89d2d..8cfce8a15a2da41e289d3f3997107b92cd32dd48 100644
--- a/gtk/gtkstackswitcher.c
+++ b/gtk/gtkstackswitcher.c
@@ -35,10 +35,12 @@
 /**
  * GtkStackSwitcher:
  *
- * The `GtkStackSwitcher` shows a row of buttons to switch between `GtkStack`
- * pages.
+ * Shows a row of buttons to switch between `GtkStack` pages.
  *
- * ![An example GtkStackSwitcher](stackswitcher.png)
+ * <picture>
+ *   <source srcset="stackswitcher-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkStackSwitcher" src="stackswitcher.png">
+ * </picture>
  *
  * It acts as a controller for the associated `GtkStack`.
  *
@@ -60,8 +62,8 @@
  *
  * # Accessibility
  *
- * `GtkStackSwitcher` uses the %GTK_ACCESSIBLE_ROLE_TAB_LIST role
- * and uses the %GTK_ACCESSIBLE_ROLE_TAB for its buttons.
+ * `GtkStackSwitcher` uses the [enum@Gtk.AccessibleRole.tab_list] role
+ * and uses the [enum@Gtk.AccessibleRole.tab] role for its buttons.
  *
  * # Orientable
  *
diff --git a/gtk/gtkstringlist.c b/gtk/gtkstringlist.c
index e210695593ccd67c6bde6516c57093df8aefa37d..d164f01bace5327d00ef0cfc196cf5bb76bb1305 100644
--- a/gtk/gtkstringlist.c
+++ b/gtk/gtkstringlist.c
@@ -28,7 +28,7 @@
 /**
  * GtkStringList:
  *
- * `GtkStringList` is a list model that wraps an array of strings.
+ * A list model that wraps an array of strings.
  *
  * The objects in the model are of type [class@Gtk.StringObject] and have
  * a "string" property that can be used inside expressions.
@@ -62,7 +62,7 @@
 /**
  * GtkStringObject:
  *
- * `GtkStringObject` is the type of items in a `GtkStringList`.
+ * The type of items in a `GtkStringList`.
  *
  * A `GtkStringObject` is a wrapper around a `const char*`; it has
  * a [property@Gtk.StringObject:string] property that can be used
diff --git a/gtk/gtkstringsorter.c b/gtk/gtkstringsorter.c
index a96a7528b80216fc6f6aa7de45dfc62817484b23..06e5b916b14c70b76d6a81cfe12c277fe6c9ea68 100644
--- a/gtk/gtkstringsorter.c
+++ b/gtk/gtkstringsorter.c
@@ -27,14 +27,14 @@
 /**
  * GtkStringSorter:
  *
- * `GtkStringSorter` is a `GtkSorter` that compares strings.
+ * Sorts items by comparing strings.
+ *
+ * To obtain the strings to compare, this sorter evaluates a
+ * [class@Gtk.Expression].
  *
  * It does the comparison in a linguistically correct way using the
  * current locale by normalizing Unicode strings and possibly case-folding
  * them before performing the comparison.
- *
- * To obtain the strings to compare, this sorter evaluates a
- * [class@Gtk.Expression].
  */
 
 struct _GtkStringSorter
diff --git a/gtk/gtkstyleprovider.c b/gtk/gtkstyleprovider.c
index a8098a3d60a786aef709fd67ea1a645f6541979e..197c83ecd6f98301b38e01604e3b0aa586d426c9 100644
--- a/gtk/gtkstyleprovider.c
+++ b/gtk/gtkstyleprovider.c
@@ -25,8 +25,7 @@
 /**
  * GtkStyleProvider:
  *
- * `GtkStyleProvider` is an interface for style information used by
- * `GtkStyleContext`.
+ * An interface for style information used by [class@Gtk.StyleContext].
  *
  * See [method@Gtk.StyleContext.add_provider] and
  * [func@Gtk.StyleContext.add_provider_for_display] for
diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c
index dbae9f7130f96089e83bf673696b00551dfcb4ef..99e74f014cb6912d42be36ee088b4bc22035683c 100644
--- a/gtk/gtkswitch.c
+++ b/gtk/gtkswitch.c
@@ -26,9 +26,12 @@
 /**
  * GtkSwitch:
  *
- * `GtkSwitch` is a "light switch" that has two states: on or off.
+ * Shows a "light switch" that has two states: on or off.
  *
- * ![An example GtkSwitch](switch.png)
+ * <picture>
+ *   <source srcset="switch-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkSwitch" src="switch.png">
+ * </picture>
  *
  * The user can control which state should be active by clicking the
  * empty area, or by dragging the slider.
@@ -39,7 +42,10 @@
  * trough color indicates the present underlying state (represented by the
  * [property@Gtk.Switch:state] property).
  *
- * ![GtkSwitch with delayed state change](switch-state.png)
+ * <picture>
+ *   <source srcset="switch-state-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="GtkSwitch with delayed state change" src="switch-state.png">
+ * </picture>
  *
  * See [signal@Gtk.Switch::state-set] for details.
  *
@@ -62,7 +68,7 @@
  *
  * # Accessibility
  *
- * `GtkSwitch` uses the %GTK_ACCESSIBLE_ROLE_SWITCH role.
+ * `GtkSwitch` uses the [enum@Gtk.AccessibleRole.switch] role.
  */
 
 #include "config.h"
diff --git a/gtk/gtksymbolicpaintable.c b/gtk/gtksymbolicpaintable.c
index 0509eb5d9c9ccd7ede320d25dd66ec9ecfaa4de0..7da4b0670d208c9bdc4b049133a067db81c7a593 100644
--- a/gtk/gtksymbolicpaintable.c
+++ b/gtk/gtksymbolicpaintable.c
@@ -26,8 +26,7 @@
 /**
  * GtkSymbolicPaintable:
  *
- * `GtkSymbolicPaintable` is an interface that support symbolic colors in
- * paintables.
+ * An interface that supports symbolic colors in paintables.
  *
  * `GdkPaintable`s implementing the interface will have the
  * [vfunc@Gtk.SymbolicPaintable.snapshot_symbolic] function called and
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index 0b3a7f40d9c687f46cc328f0a8e48e23811b539b..749f187fca6d8076ef9013e0fc67701eb156aeb3 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -7585,14 +7585,11 @@ gtk_text_accessible_text_get_contents (GtkAccessibleText *self,
                                        unsigned int       start,
                                        unsigned int       end)
 {
-  const char *text;
-  int len;
+  char *text = gtk_text_get_display_text (GTK_TEXT (self), 0, -1);
+  int len = g_utf8_strlen (text, -1);
   char *string;
   gsize size;
 
-  text = gtk_editable_get_text (GTK_EDITABLE (self));
-  len = g_utf8_strlen (text, -1);
-
   start = CLAMP (start, 0, len);
   end = CLAMP (end, 0, len);
 
@@ -7610,6 +7607,8 @@ gtk_text_accessible_text_get_contents (GtkAccessibleText *self,
       string = g_strndup (p, q - p);
     }
 
+  g_free (text);
+
   return g_bytes_new_take (string, size);
 }
 
diff --git a/gtk/gtktextchild.h b/gtk/gtktextchild.h
index 1f4cf2edcf65002d424290040e2bfb42542f4824..e4754fc99797df612d1327c850deb6fbd3498c6c 100644
--- a/gtk/gtktextchild.h
+++ b/gtk/gtktextchild.h
@@ -38,8 +38,7 @@ G_BEGIN_DECLS
 /**
  * GtkTextChildAnchor:
  *
- * A `GtkTextChildAnchor` is a spot in a `GtkTextBuffer` where child widgets can
- * be “anchored”.
+ * Marks a spot in a `GtkTextBuffer` where child widgets can be “anchored”.
  *
  * The anchor can have multiple widgets anchored, to allow for multiple views.
  */
diff --git a/gtk/gtktextiter.c b/gtk/gtktextiter.c
index 16907e5feb0bfe629da8edfaa41d111ef51ac47c..90ed01fd0bb80a36f494f8252aeb7114bc86173a 100644
--- a/gtk/gtktextiter.c
+++ b/gtk/gtktextiter.c
@@ -35,7 +35,7 @@
 /**
  * GtkTextIter:
  *
- * An iterator for the contents of a `GtkTextBuffer`.
+ * Iterates over the contents of a `GtkTextBuffer`.
  *
  * You may wish to begin by reading the
  * [text widget conceptual overview](section-text-widget.html),
diff --git a/gtk/gtktextiter.h b/gtk/gtktextiter.h
index 9445746cf24cac05b7fcf1716ac7989ed092acd5..08eeef344cde5250e2394c74134af093d40c33de 100644
--- a/gtk/gtktextiter.h
+++ b/gtk/gtktextiter.h
@@ -44,9 +44,9 @@ G_BEGIN_DECLS
  *
  * Flags affecting how a search is done.
  *
- * If neither %GTK_TEXT_SEARCH_VISIBLE_ONLY nor %GTK_TEXT_SEARCH_TEXT_ONLY are
- * enabled, the match must be exact; the special 0xFFFC character will match
- * embedded paintables or child widgets.
+ * If neither `GTK_TEXT_SEARCH_VISIBLE_ONLY` nor `GTK_TEXT_SEARCH_TEXT_ONLY`
+ * are enabled, the match must be exact; the special 0xFFFC character will
+ * match embedded paintables or child widgets.
  */
 typedef enum {
   GTK_TEXT_SEARCH_VISIBLE_ONLY     = 1 << 0,
diff --git a/gtk/gtktextmark.c b/gtk/gtktextmark.c
index 665079e62ff1c1124ee439c67ded6006413522ef..fd3556b1e83c86b452d70adf41aa28a08e004d18 100644
--- a/gtk/gtktextmark.c
+++ b/gtk/gtktextmark.c
@@ -55,7 +55,7 @@
 /**
  * GtkTextMark:
  *
- * A `GtkTextMark` is a position in a `GtkTextbuffer` that is preserved
+ * Marks a position in a `GtkTextbuffer` that is preserved
  * across modifications.
  *
  * You may wish to begin by reading the
diff --git a/gtk/gtktexttag.c b/gtk/gtktexttag.c
index f7796d42e767a74ebac6cda15becbf4d99bd021d..838d407ccccebafc925ec0dfc0897a29ce330099 100644
--- a/gtk/gtktexttag.c
+++ b/gtk/gtktexttag.c
@@ -50,7 +50,7 @@
 /**
  * GtkTextTag:
  *
- * A tag that can be applied to text contained in a `GtkTextBuffer`.
+ * Can be applied to text contained in a `GtkTextBuffer`.
  *
  * You may wish to begin by reading the
  * [text widget conceptual overview](section-text-widget.html),
diff --git a/gtk/gtktexttagtable.c b/gtk/gtktexttagtable.c
index ad7dc95d83cbb398dd7182198101f506db979769..ee62f2ffa2c71cb16bb8aa6e4cea2978e7b7c656 100644
--- a/gtk/gtktexttagtable.c
+++ b/gtk/gtktexttagtable.c
@@ -39,7 +39,7 @@
 /**
  * GtkTextTagTable:
  *
- * The collection of tags in a `GtkTextBuffer`
+ * Collects the tags in a `GtkTextBuffer`.
  *
  * You may wish to begin by reading the
  * [text widget conceptual overview](section-text-widget.html),
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index ff7ad7622e86c87a64f6ae9447191c80942b2902..dd984e6845d17c180b14d0e0e80d72bb5fbe083b 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -66,9 +66,12 @@
 /**
  * GtkTextView:
  *
- * A widget that displays the contents of a [class@Gtk.TextBuffer].
+ * Displays the contents of a [class@Gtk.TextBuffer].
  *
- * ![An example GtkTextView](multiline-text.png)
+ * <picture>
+ *   <source srcset="multiline-text-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkTextView" src="multiline-text.png">
+ * </picture>
  *
  * You may wish to begin by reading the [conceptual overview](section-text-widget.html),
  * which gives an overview of all the objects and data types related to the
@@ -136,7 +139,7 @@
  *
  * ## Accessibility
  *
- * `GtkTextView` uses the %GTK_ACCESSIBLE_ROLE_TEXT_BOX role.
+ * `GtkTextView` uses the [enum@Gtk.AccessibleRole.text_box] role.
  */
 
 /* How scrolling, validation, exposes, etc. work.
@@ -4538,7 +4541,11 @@ gtk_text_view_measure (GtkWidget      *widget,
   if (orientation == GTK_ORIENTATION_HORIZONTAL)
     extra = borders.left + priv->left_margin + priv->right_margin + borders.right;
   else
-    extra = borders.top + priv->height + borders.bottom;
+    {
+      min = MAX (min, priv->height);
+      nat = MAX (nat, priv->height);
+      extra = borders.top + borders.bottom;
+    }
 
   *minimum = min + extra;
   *natural = nat + extra;
diff --git a/gtk/gtktogglebutton.c b/gtk/gtktogglebutton.c
index 86674043d2815ac24d93a723a4a894169d551a49..78ad2b29442342869eabac15ebb8ef0f5662520b 100644
--- a/gtk/gtktogglebutton.c
+++ b/gtk/gtktogglebutton.c
@@ -37,8 +37,12 @@
 /**
  * GtkToggleButton:
  *
- * A `GtkToggleButton` is a button which remains “pressed-in” when
- * clicked.
+ * Shows a button which remains “pressed-in” when clicked.
+ *
+ * <picture>
+ *   <source srcset="toggle-button-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="Example GtkToggleButtons" src="toggle-button.png">
+ * </picture>
  *
  * Clicking again will cause the toggle button to return to its normal state.
  *
@@ -66,7 +70,7 @@
  *
  * ## Accessibility
  *
- * `GtkToggleButton` uses the %GTK_ACCESSIBLE_ROLE_TOGGLE_BUTTON role.
+ * `GtkToggleButton` uses the [enum@Gtk.AccessibleRole.toggle_button] role.
  *
  * ## Creating two `GtkToggleButton` widgets.
  *
diff --git a/gtk/gtktooltip.c b/gtk/gtktooltip.c
index a7aa163673151805337755e3988c1bef9d4cc35a..b8ee0334e12b3b5cc9991fe583c1c1e32f984aed 100644
--- a/gtk/gtktooltip.c
+++ b/gtk/gtktooltip.c
@@ -38,7 +38,7 @@
 /**
  * GtkTooltip:
  *
- * `GtkTooltip` is an object representing a widget tooltip.
+ * Represents a widget tooltip.
  *
  * Basic tooltips can be realized simply by using
  * [method@Gtk.Widget.set_tooltip_text] or
diff --git a/gtk/gtktreeexpander.c b/gtk/gtktreeexpander.c
index 91b8b6f9e7f87564dc0fabf507bcf6e63699297d..f9fd967e8e9ed564983e860765349e31da068111 100644
--- a/gtk/gtktreeexpander.c
+++ b/gtk/gtktreeexpander.c
@@ -34,7 +34,7 @@
 /**
  * GtkTreeExpander:
  *
- * `GtkTreeExpander` is a widget that provides an expander for a list.
+ * Provides an expander for a tree-like list.
  *
  * It is typically placed as a bottommost child into a `GtkListView`
  * to allow users to expand and collapse children in a list with a
@@ -106,9 +106,9 @@
  *
  * ## Accessibility
  *
- * Until GTK 4.10, `GtkTreeExpander` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
+ * Until GTK 4.10, `GtkTreeExpander` used the [enum@Gtk.AccessibleRole.group] role.
  *
- * Since GTK 4.12, `GtkTreeExpander` uses the `GTK_ACCESSIBLE_ROLE_BUTTON` role.
+ * Since GTK 4.12, `GtkTreeExpander` uses the [enum@Gtk.AccessibleRole.button] role.
  * Toggling it will change the `GTK_ACCESSIBLE_STATE_EXPANDED` state.
  */
 
diff --git a/gtk/gtktreelistmodel.c b/gtk/gtktreelistmodel.c
index 7a4a7f015a86c710c5799be49a0907546f450e3f..1a43f1272043cf4f85ecd0d6319e90ea8c96f735 100644
--- a/gtk/gtktreelistmodel.c
+++ b/gtk/gtktreelistmodel.c
@@ -27,7 +27,7 @@
 /**
  * GtkTreeListModel:
  *
- * `GtkTreeListModel` is a list model that can create child models on demand.
+ * A list model that can create child models on demand.
  */
 
 enum {
@@ -931,7 +931,7 @@ gtk_tree_list_model_get_child_row (GtkTreeListModel *self,
 /**
  * GtkTreeListRow:
  *
- * `GtkTreeListRow` is used by `GtkTreeListModel` to represent items.
+ * The type of item used by `GtkTreeListModel`.
  *
  * It allows navigating the model as a tree and modify the state of rows.
  *
diff --git a/gtk/gtktreelistrowsorter.c b/gtk/gtktreelistrowsorter.c
index cf6ec3f91b8a358feb25fc67953dd8384d97ccab..986b7542f055015b7495cf469ba7a535641952a1 100644
--- a/gtk/gtktreelistrowsorter.c
+++ b/gtk/gtktreelistrowsorter.c
@@ -29,8 +29,7 @@
 /**
  * GtkTreeListRowSorter:
  *
- * `GtkTreeListRowSorter` is a special-purpose sorter that will apply a given
- * sorter to the levels in a tree.
+ * Applies a gives sorter to the levels in a tree.
  *
  * Here is an example for setting up a column view with a tree model and
  * a `GtkTreeListSorter`:
diff --git a/gtk/gtkurilauncher.c b/gtk/gtkurilauncher.c
index 70961bf569fed5899bfe48581d9da9bc69d51294..7a37420ffcc4545ff372a8880aa66c692aa437ee 100644
--- a/gtk/gtkurilauncher.c
+++ b/gtk/gtkurilauncher.c
@@ -30,7 +30,9 @@
 /**
  * GtkUriLauncher:
  *
- * Collects the arguments that are needed to open a uri with an application.
+ * Asynchronous API to open a uri with an application.
+ *
+ * `GtkUriLauncher` collects the arguments that are needed to open the uri.
  *
  * Depending on system configuration, user preferences and available APIs, this
  * may or may not show an app chooser dialog or launch the default application
diff --git a/gtk/gtkversion.h.in b/gtk/gtkversion.h.in
index 992863dd7af55ae906e53e6d6279bc4ee261cedd..c75f4273e2e94afcb08356335634b8fb959825a3 100644
--- a/gtk/gtkversion.h.in
+++ b/gtk/gtkversion.h.in
@@ -84,10 +84,10 @@ G_BEGIN_DECLS
  * @minor: minor version (e.g. 2 for version 1.2.5)
  * @micro: micro version (e.g. 5 for version 1.2.5)
  *
- * Returns %TRUE if the version of the GTK header files
+ * Returns true if the version of the GTK header files
  * is the same as or newer than the passed-in version.
  *
- * Returns: %TRUE if GTK headers are new enough
+ * Returns: true if GTK headers are new enough
  */
 #define GTK_CHECK_VERSION(major,minor,micro)                          \
     (GTK_MAJOR_VERSION > (major) ||                                   \
diff --git a/gtk/gtkvideo.c b/gtk/gtkvideo.c
index c83edcdf04de186f5ed6d7fc89eeaf3daba84828..345c58267539fb3e24ab422459c6099830aba9f3 100644
--- a/gtk/gtkvideo.c
+++ b/gtk/gtkvideo.c
@@ -39,9 +39,12 @@
 /**
  * GtkVideo:
  *
- * `GtkVideo` is a widget to show a `GtkMediaStream` with media controls.
+ * Shows a `GtkMediaStream` with media controls.
  *
- * ![An example GtkVideo](video.png)
+ * <picture>
+ *   <source srcset="video-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkVideo" src="video.png">
+ * </picture>
  *
  * The controls are available separately as [class@Gtk.MediaControls].
  * If you just want to display a video without controls, you can treat it
diff --git a/gtk/gtkviewport.c b/gtk/gtkviewport.c
index 4968ddebaf141d94eae42d5993b5074cabbe4538..5af65d0a50763aea6ef56660cfb0555a409e424a 100644
--- a/gtk/gtkviewport.c
+++ b/gtk/gtkviewport.c
@@ -42,8 +42,8 @@
 /**
  * GtkViewport:
  *
- * `GtkViewport` implements scrollability for widgets that lack their
- * own scrolling capabilities.
+ * Implements scrollability for widgets that don't support scrolling
+ * on their own.
  *
  * Use `GtkViewport` to scroll child widgets such as `GtkGrid`,
  * `GtkBox`, and so on.
@@ -57,9 +57,9 @@
  *
  * # Accessibility
  *
- * Until GTK 4.10, `GtkViewport` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
+ * Until GTK 4.10, `GtkViewport` used the [enum@Gtk.AccessibleRole.group] role.
  *
- * Starting from GTK 4.12, `GtkViewport` uses the `GTK_ACCESSIBLE_ROLE_GENERIC` role.
+ * Starting from GTK 4.12, `GtkViewport` uses the [enum@Gtk.AccessibleRole.generic] role.
  */
 
 typedef struct _GtkViewportPrivate       GtkViewportPrivate;
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 4321e9f4451df63f13ee8386e8bb50fa396fd0b2..39bd836300500289bebf9c2584a4cb926ccc4360 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -551,6 +551,7 @@ enum {
   PROP_CSS_NAME,
   PROP_CSS_CLASSES,
   PROP_LAYOUT_MANAGER,
+  PROP_LIMIT_EVENTS,
   NUM_PROPERTIES,
 
   /* GtkAccessible */
@@ -1039,6 +1040,9 @@ gtk_widget_set_property (GObject      *object,
     case PROP_ACCESSIBLE_ROLE:
       gtk_widget_set_accessible_role (widget, g_value_get_enum (value));
       break;
+    case PROP_LIMIT_EVENTS:
+      gtk_widget_set_limit_events (widget, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1172,6 +1176,9 @@ gtk_widget_get_property (GObject    *object,
     case PROP_ACCESSIBLE_ROLE:
       g_value_set_enum (value, gtk_widget_get_accessible_role (widget));
       break;
+    case PROP_LIMIT_EVENTS:
+      g_value_set_boolean (value, gtk_widget_get_limit_events (widget));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1647,6 +1654,23 @@ gtk_widget_class_init (GtkWidgetClass *klass)
                          GTK_TYPE_LAYOUT_MANAGER,
                          GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * GtkWidget:limit-events:
+   *
+   * Makes this widget act like a modal dialog, with respect to
+   * event delivery.
+   *
+   * Global event controllers will not handle events with targets
+   * inside the widget, unless they are set up to ignore propagation
+   * limits. See [method@Gtk.EventController.set_propagation_limit].
+   *
+   * Since: 4.18
+   */
+  widget_props[PROP_LIMIT_EVENTS] =
+      g_param_spec_boolean ("limit-events", NULL, NULL,
+                            FALSE,
+                            GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
+
   g_object_class_install_properties (gobject_class, NUM_PROPERTIES, widget_props);
 
   g_object_class_override_property (gobject_class, PROP_ACCESSIBLE_ROLE, "accessible-role");
@@ -5356,7 +5380,8 @@ gtk_widget_set_focusable (GtkWidget *widget,
 
   gtk_widget_queue_resize (widget);
 
-  gtk_accessible_platform_changed (GTK_ACCESSIBLE (widget), GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSABLE);
+  gtk_accessible_update_platform_state (GTK_ACCESSIBLE (widget),
+                                        GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSABLE);
 
   g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_FOCUSABLE]);
 }
@@ -10492,13 +10517,6 @@ gtk_widget_compute_transform (GtkWidget         *widget,
   for (iter = widget; iter != ancestor; iter = iter->priv->parent)
     {
       GtkWidgetPrivate *priv = gtk_widget_get_instance_private (iter);
-
-      if (GTK_IS_NATIVE (iter))
-        {
-          graphene_matrix_init_identity (out_transform);
-          return FALSE;
-        }
-
       gsk_transform_to_matrix (priv->transform, &tmp);
       graphene_matrix_multiply (&transform, &tmp, &transform);
     }
@@ -10515,13 +10533,6 @@ gtk_widget_compute_transform (GtkWidget         *widget,
     {
       GtkWidgetPrivate *priv = gtk_widget_get_instance_private (iter);
       gsk_transform_to_matrix (priv->transform, &tmp);
-
-      if (GTK_IS_NATIVE (iter))
-        {
-          graphene_matrix_init_identity (out_transform);
-          return FALSE;
-        }
-
       graphene_matrix_multiply (&inverse, &tmp, &inverse);
     }
   if (!graphene_matrix_inverse (&inverse, &inverse))
@@ -10820,7 +10831,8 @@ gtk_widget_set_has_focus (GtkWidget *widget,
 
   priv->has_focus = has_focus;
 
-  gtk_accessible_platform_changed (GTK_ACCESSIBLE (widget), GTK_ACCESSIBLE_PLATFORM_CHANGE_FOCUSED);
+  gtk_accessible_update_platform_state (GTK_ACCESSIBLE (widget),
+                                        GTK_ACCESSIBLE_PLATFORM_STATE_FOCUSED);
 
   g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_HAS_FOCUS]);
 }
@@ -13390,3 +13402,46 @@ gtk_widget_set_active_state (GtkWidget *widget,
         gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_ACTIVE);
     }
 }
+
+/**
+ * gtk_widget_set_limit_events:
+ * @widget: a `GtkWidget`
+ * @limit_events: whether to limit events
+ *
+ * Sets whether the widget acts like a modal dialog,
+ * with respect to event delivery.
+ *
+ * Since: 4.18
+ */
+void
+gtk_widget_set_limit_events (GtkWidget *widget,
+                             gboolean   limit_events)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  if (priv->limit_events == limit_events)
+    return;
+
+  priv->limit_events = limit_events;
+  g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_LIMIT_EVENTS]);
+}
+
+/**
+ * gtk_widget_get_limit_events:
+ * @widget: a `GtkWidget`
+ *
+ * Gets the value of the [property@Gtk.Widget:limit-events] property.
+ *
+ * Since: 4.18
+ */
+gboolean
+gtk_widget_get_limit_events (GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  return priv->limit_events;
+}
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 02c85a2cc3b6aaf9c49540b8e456ab0dffefac22..69a76c8c5cabc09ae1c46f664a3fb6eec494cf3b 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -984,6 +984,14 @@ void                    gtk_widget_class_set_accessible_role    (GtkWidgetClass
 GDK_AVAILABLE_IN_ALL
 GtkAccessibleRole       gtk_widget_class_get_accessible_role    (GtkWidgetClass    *widget_class);
 
+GDK_AVAILABLE_IN_4_18
+void                    gtk_widget_set_limit_events             (GtkWidget         *widget,
+                                                                 gboolean           limit_events);
+GDK_AVAILABLE_IN_4_18
+gboolean                gtk_widget_get_limit_events             (GtkWidget         *widget);
+
+
+
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkWidget, g_object_unref)
 G_DEFINE_AUTOPTR_CLEANUP_FUNC(GtkRequisition, gtk_requisition_free)
 
diff --git a/gtk/gtkwidgetpaintable.c b/gtk/gtkwidgetpaintable.c
index 87f7bdbcafe45f179929dc9990ccc501aca4f4b2..ff81c25db14d15c59ce205b8b44f0c8c284bd369 100644
--- a/gtk/gtkwidgetpaintable.c
+++ b/gtk/gtkwidgetpaintable.c
@@ -29,8 +29,7 @@
 /**
  * GtkWidgetPaintable:
  *
- * `GtkWidgetPaintable` is a `GdkPaintable` that displays the contents
- * of a widget.
+ * A `GdkPaintable` that displays the contents of a widget.
  *
  * `GtkWidgetPaintable` will also take care of the widget not being in a
  * state where it can be drawn (like when it isn't shown) and just draw
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index f7e84191e995052b53c623ed453a965e48796010..483e050dae8330361ab96027e36d1d5d5026c4bd 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -81,6 +81,7 @@ struct _GtkWidgetPrivate
   guint has_grab              : 1;
   guint child_visible         : 1;
   guint can_target            : 1;
+  guint limit_events          : 1;
 
   /* Queue-resize related flags */
   guint resize_needed         : 1; /* queue_resize() has been called but no get_preferred_size() yet */
diff --git a/gtk/gtkwin32.c b/gtk/gtkwin32.c
index 264be44f5eea50f326d52f6cb75af9d75e6ccc70..1e6e2b937bd4ec58a176e24fbd0dcd334cc70edb 100644
--- a/gtk/gtkwin32.c
+++ b/gtk/gtkwin32.c
@@ -44,6 +44,23 @@ this_module (void)
  */
 #define EMPIRIC_MANIFEST_RESOURCE_INDEX 2
 
+static wchar_t *
+g_wcsdup (const wchar_t *wcs)
+{
+  wchar_t *new_wcs = NULL;
+  gsize length;
+
+  if G_LIKELY (wcs)
+    {
+      length = wcslen (wcs) + 1;
+      new_wcs = g_new (wchar_t, length);
+      wcscpy (new_wcs, wcs);
+      new_wcs[length - 1] = L'\0';
+    }
+
+  return new_wcs;
+}
+
 static BOOL CALLBACK
 find_first_manifest (HMODULE  module_handle,
                      LPCWSTR  resource_type,
@@ -64,15 +81,15 @@ find_first_manifest (HMODULE  module_handle,
 }
 
 /*
- * Grabs the first manifest it finds in libgtk3 (which is expected to be the
+ * Grabs the first manifest it finds in libgtk (which is expected to be the
  * common-controls-6.0.0.0 manifest we embedded to enable visual styles),
  * uses it to create a process-default activation context, activates that
  * context, loads up the library passed in @dllname, then deactivates and
  * releases the context.
  *
  * In practice this is used to force system DLLs (like comdlg32) to be
- * loaded as if the application had the same manifest as libgtk3
- * (otherwise libgtk3 manifest only affests libgtk3 itself).
+ * loaded as if the application had the same manifest as libgtk
+ * (otherwise libgtk3 manifest only affests libgtk itself).
  * This way application does not need to have a manifest or to link
  * against comctl32.
  *
@@ -217,20 +234,3 @@ _gtk_get_data_prefix (void)
 
   return gtk_data_prefix;
 }
-
-wchar_t *
-g_wcsdup (const wchar_t *wcs)
-{
-  wchar_t *new_wcs = NULL;
-  gsize length;
-
-  if G_LIKELY (wcs)
-    {
-      length = wcslen (wcs) + 1;
-      new_wcs = g_new (wchar_t, length);
-      wcscpy (new_wcs, wcs);
-      new_wcs[length - 1] = L'\0';
-    }
-
-  return new_wcs;
-}
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 2f446d46d0c334c599a8ab0ecbde7e677a34ee9b..2eb2007ffa63baa14047dbe3ec0ed0383fe8e78c 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -114,7 +114,10 @@
  *
  * A toplevel window which can contain other widgets.
  *
- * ![An example GtkWindow](window.png)
+ * <picture>
+ *   <source srcset="window-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkWindow" src="window.png">
+ * </picture>
  *
  * Windows normally have decorations that are under the control
  * of the windowing system and allow the user to manipulate the window
@@ -1763,6 +1766,8 @@ gtk_window_init (GtkWindow *window)
 
   target = gtk_drop_target_async_new (gdk_content_formats_new ((const char*[1]) { "application/x-rootwindow-drop" }, 1),
                                       GDK_ACTION_MOVE);
+  gtk_event_controller_set_static_name (GTK_EVENT_CONTROLLER (target),
+                                        "gtk-window-rootwindow-drop");
   g_signal_connect (target, "drop", G_CALLBACK (gtk_window_accept_rootwindow_drop), NULL);
   gtk_widget_add_controller (GTK_WIDGET (window), GTK_EVENT_CONTROLLER (target));
 
@@ -1772,8 +1777,8 @@ gtk_window_init (GtkWindow *window)
                       G_CALLBACK (device_removed_cb), window);
 
   controller = gtk_event_controller_motion_new ();
-  gtk_event_controller_set_propagation_phase (controller,
-                                              GTK_PHASE_CAPTURE);
+  gtk_event_controller_set_static_name (controller, "gtk-window-resize-cursor");
+  gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
   g_signal_connect_swapped (controller, "motion",
                             G_CALLBACK (gtk_window_capture_motion), window);
   g_signal_connect_swapped (controller, "leave",
@@ -1781,7 +1786,9 @@ gtk_window_init (GtkWindow *window)
   gtk_widget_add_controller (widget, controller);
 
   controller = gtk_event_controller_key_new ();
+  gtk_event_controller_set_static_name (controller, "gtk-window-visible-focus");
   gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
+  gtk_event_controller_set_propagation_limit (controller, GTK_LIMIT_NONE);
   g_signal_connect_swapped (controller, "key-pressed",
                             G_CALLBACK (gtk_window_key_pressed), window);
   g_signal_connect_swapped (controller, "key-released",
@@ -1815,6 +1822,7 @@ gtk_window_constructed (GObject *object)
   G_OBJECT_CLASS (gtk_window_parent_class)->constructed (object);
 
   priv->click_gesture = gtk_gesture_click_new ();
+  gtk_event_controller_set_static_name (GTK_EVENT_CONTROLLER (priv->click_gesture), "gtk-window-resize");
   gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (priv->click_gesture), 0);
   gtk_event_controller_set_propagation_phase (GTK_EVENT_CONTROLLER (priv->click_gesture),
                                               GTK_PHASE_BUBBLE);
@@ -6035,7 +6043,8 @@ _gtk_window_set_is_active (GtkWindow *window,
       g_object_unref (focus);
     }
 
-  gtk_accessible_platform_changed (GTK_ACCESSIBLE (window), GTK_ACCESSIBLE_PLATFORM_CHANGE_ACTIVE);
+  gtk_accessible_update_platform_state (GTK_ACCESSIBLE (window),
+                                        GTK_ACCESSIBLE_PLATFORM_STATE_ACTIVE);
 
   g_object_notify_by_pspec (G_OBJECT (window), window_props[PROP_IS_ACTIVE]);
 }
diff --git a/gtk/gtkwindowbuttonsquartz.c b/gtk/gtkwindowbuttonsquartz.c
new file mode 100644
index 0000000000000000000000000000000000000000..235d995003472cf88570be38cd79e3bc55642b72
--- /dev/null
+++ b/gtk/gtkwindowbuttonsquartz.c
@@ -0,0 +1,362 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (c) 2024 Arjan Molenaar <amolenaar@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#include "config.h"
+
+#import <AppKit/AppKit.h>
+#include <math.h>
+#include <gdk/macos/GdkMacosWindow.h>
+#include "gtkprivate.h"
+#include "gtknative.h"
+#include "gtkwindowbuttonsquartzprivate.h"
+
+@interface NSWindow()
+/* Expose the private titlebarHeight property, so we can set
+ * the titlebar height to match the height of a GTK header bar.
+ */
+@property CGFloat titlebarHeight;
+
+@end
+
+enum
+{
+  PROP_0,
+  PROP_DECORATION_LAYOUT,
+  NUM_PROPERTIES
+};
+
+static GParamSpec *props[NUM_PROPERTIES] = { NULL, };
+
+/**
+ * GtkWindowButtonsQuartz:
+ *
+ * This class provides macOS native window buttons for close/minimize/maximize.
+ *
+ * The buttons can be set by adding "native" to the `decoration-layout` of
+ * GtkWindowControls or GtkHeader.
+ *
+ * ## Accessibility
+ *
+ * `GtkWindowButtonsQuartz` uses the `GTK_ACCESSIBLE_ROLE_IMG` role.
+ */
+
+typedef struct _GtkWindowButtonsQuartzClass GtkWindowButtonsQuartzClass;
+
+struct _GtkWindowButtonsQuartz
+{
+  GtkWidget parent_instance;
+
+  gboolean close;
+  gboolean minimize;
+  gboolean maximize;
+
+  char *decoration_layout;
+};
+
+struct _GtkWindowButtonsQuartzClass
+{
+  GtkWidgetClass parent_class;
+};
+
+G_DEFINE_TYPE (GtkWindowButtonsQuartz, gtk_window_buttons_quartz, GTK_TYPE_WIDGET)
+
+static void
+set_window_controls_height (GdkMacosWindow *window,
+                            int             height)
+{
+  g_return_if_fail (GDK_IS_MACOS_WINDOW (window));
+
+  if ([window respondsToSelector:@selector(setTitlebarHeight:)])
+    [window setTitlebarHeight:height];
+  [[window contentView] setNeedsLayout:YES];
+}
+
+static void
+window_controls_bounds (NSWindow *window, NSRect *out_bounds)
+{
+  NSRect bounds = NSZeroRect;
+  NSButton* button;
+
+  button = [window standardWindowButton:NSWindowCloseButton];
+  bounds = NSUnionRect(bounds, [button frame]);
+
+  button = [window standardWindowButton:NSWindowZoomButton];
+  bounds = NSUnionRect(bounds, [button frame]);
+
+  *out_bounds = bounds;
+}
+
+static GdkMacosWindow*
+native_window (GtkWidget *widget)
+{
+  GtkNative *native = GTK_NATIVE (gtk_widget_get_root (widget));
+
+  if (native != NULL)
+    {
+      GdkSurface *surface = gtk_native_get_surface (native);
+
+      if (GDK_IS_MACOS_SURFACE (surface))
+        return (GdkMacosWindow*) gdk_macos_surface_get_native_window (GDK_MACOS_SURFACE (surface));
+    }
+  return NULL;
+}
+
+static void
+enable_window_controls (GtkWindowButtonsQuartz *self,
+                        gboolean                enabled)
+{
+  gboolean is_sovereign_window;
+  gboolean resizable;
+  gboolean deletable;
+  GtkRoot *root;
+  GtkWindow *window;
+  GdkMacosWindow *nswindow;
+
+  root = gtk_widget_get_root (GTK_WIDGET (self));
+  if (!root || !GTK_IS_WINDOW (root))
+    return;
+
+  nswindow = native_window (GTK_WIDGET (self));
+  if (!GDK_IS_MACOS_WINDOW (nswindow))
+    return;
+  
+  window = GTK_WINDOW (root);
+  is_sovereign_window = !gtk_window_get_modal (window) &&
+                         gtk_window_get_transient_for (window) == NULL;
+  resizable = gtk_window_get_resizable (window);
+  deletable = gtk_window_get_deletable (window);
+
+  [[nswindow standardWindowButton:NSWindowCloseButton] setEnabled:enabled && self->close && deletable];
+  [[nswindow standardWindowButton:NSWindowMiniaturizeButton] setEnabled:enabled && self->minimize && is_sovereign_window];
+  [[nswindow standardWindowButton:NSWindowZoomButton] setEnabled:enabled && self->maximize && resizable && is_sovereign_window];
+}
+
+static void
+update_window_controls_from_decoration_layout (GtkWindowButtonsQuartz *self)
+{
+  char **tokens;
+
+  if (self->decoration_layout)
+    tokens = g_strsplit_set (self->decoration_layout, ",:", -1);
+  else
+    {
+      char *layout_desc;
+      g_object_get (gtk_widget_get_settings (GTK_WIDGET (self)),
+                    "gtk-decoration-layout", &layout_desc,
+                    NULL);
+      tokens = g_strsplit_set (layout_desc, ",:", -1);
+
+      g_free (layout_desc);
+    }
+
+  self->close = g_strv_contains ((const char * const *) tokens, "close");
+  self->minimize = g_strv_contains ((const char * const *) tokens, "minimize");
+  self->maximize = g_strv_contains ((const char * const *) tokens, "maximize");
+
+  g_strfreev (tokens);
+
+  enable_window_controls (self, TRUE);
+}
+
+static void
+gtk_window_buttons_quartz_finalize (GObject *object)
+{
+  GtkWindowButtonsQuartz *self = GTK_WINDOW_BUTTONS_QUARTZ (object);
+
+  g_clear_pointer (&self->decoration_layout, g_free);
+
+  G_OBJECT_CLASS (gtk_window_buttons_quartz_parent_class)->finalize (object);
+}
+
+static void
+gtk_window_buttons_quartz_get_property (GObject     *object,
+                                        guint        prop_id,
+                                        GValue      *value,
+                                        GParamSpec  *pspec)
+{
+  GtkWindowButtonsQuartz *self = GTK_WINDOW_BUTTONS_QUARTZ (object);
+
+  switch (prop_id)
+    {
+    case PROP_DECORATION_LAYOUT:
+      g_value_set_string (value, self->decoration_layout);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_window_buttons_quartz_set_property (GObject      *object,
+                                        guint         prop_id,
+                                        const GValue *value,
+                                        GParamSpec   *pspec)
+{
+  GtkWindowButtonsQuartz *self = GTK_WINDOW_BUTTONS_QUARTZ (object);
+
+  switch (prop_id)
+    {
+    case PROP_DECORATION_LAYOUT:
+      g_free (self->decoration_layout);
+      self->decoration_layout = g_strdup (g_value_get_string (value));
+
+      update_window_controls_from_decoration_layout (self);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+    }
+}
+
+static void
+gtk_window_buttons_quartz_realize (GtkWidget *widget)
+{
+  GtkWindowButtonsQuartz *self = GTK_WINDOW_BUTTONS_QUARTZ (widget);
+  GdkMacosWindow *window;
+  NSRect bounds;
+
+  GTK_WIDGET_CLASS (gtk_window_buttons_quartz_parent_class)->realize (widget);
+
+  window = native_window (widget);
+
+  if (!GDK_IS_MACOS_WINDOW (window))
+    {
+      g_critical ("Cannot show GtkWindowButtonsQuartz on a non-macos window");
+      return;
+    }
+
+  [window setShowStandardWindowButtons:YES];
+  
+  enable_window_controls (self, TRUE);
+
+  window_controls_bounds (window, &bounds);
+  gtk_widget_set_size_request (widget, bounds.origin.x + bounds.size.width, bounds.size.height);
+}
+
+static void
+gtk_window_buttons_quartz_unrealize (GtkWidget *widget)
+{
+  GdkMacosWindow *window = native_window (widget);
+
+  if (GDK_IS_MACOS_WINDOW (window))
+    [window setShowStandardWindowButtons:NO];
+
+  GTK_WIDGET_CLASS (gtk_window_buttons_quartz_parent_class)->unrealize (widget);
+}
+
+static void
+gtk_window_buttons_quartz_measure (GtkWidget      *widget,
+                                   GtkOrientation  orientation,
+                                   int             for_size,
+                                   int            *minimum,
+                                   int            *natural,
+                                   int            *minimum_baseline,
+                                   int            *natural_baseline)
+{
+  GdkMacosWindow *window = native_window (widget);
+
+  if (GDK_IS_MACOS_WINDOW (window))
+    {
+      NSRect bounds;
+
+      window_controls_bounds (window, &bounds);
+
+      if (orientation == GTK_ORIENTATION_VERTICAL)
+        *minimum = *natural = ceil(bounds.size.height);
+      else if (orientation == GTK_ORIENTATION_HORIZONTAL)
+        *minimum = *natural = ceil(bounds.origin.x + bounds.size.width);
+    }
+}
+
+static void
+gtk_window_buttons_quartz_size_allocate (GtkWidget *widget,
+                                         int        width,
+                                         int        height,
+                                         int        baseline)
+{
+  GdkMacosWindow *window = native_window (widget);
+  graphene_rect_t bounds = { 0 };
+
+  GTK_WIDGET_CLASS (gtk_window_buttons_quartz_parent_class)->size_allocate (widget, width, height, baseline);
+
+  if (!gtk_widget_compute_bounds (widget, (GtkWidget *) gtk_widget_get_root (widget), &bounds))
+    g_warning ("Could not calculate widget bounds");
+
+  set_window_controls_height (window, bounds.origin.y * 2 + height);
+}
+
+static void
+gtk_window_buttons_quartz_state_flags_changed (GtkWidget* widget,
+                                               GtkStateFlags previous_state_flags)
+{
+  GtkWindowButtonsQuartz *self = GTK_WINDOW_BUTTONS_QUARTZ (widget);
+
+  if (gtk_widget_get_state_flags (widget) & GTK_STATE_FLAG_INSENSITIVE)
+    enable_window_controls (self, FALSE);
+  else
+    enable_window_controls (self, TRUE);
+
+  GTK_WIDGET_CLASS (gtk_window_buttons_quartz_parent_class)->state_flags_changed (widget, previous_state_flags);
+}
+
+static void
+gtk_window_buttons_quartz_class_init (GtkWindowButtonsQuartzClass *class)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  gobject_class->finalize = gtk_window_buttons_quartz_finalize;
+  gobject_class->get_property = gtk_window_buttons_quartz_get_property;
+  gobject_class->set_property = gtk_window_buttons_quartz_set_property;
+
+  widget_class->measure = gtk_window_buttons_quartz_measure;
+  widget_class->size_allocate = gtk_window_buttons_quartz_size_allocate;
+  widget_class->realize = gtk_window_buttons_quartz_realize;
+  widget_class->unrealize = gtk_window_buttons_quartz_unrealize;
+  widget_class->state_flags_changed = gtk_window_buttons_quartz_state_flags_changed;
+
+  /**
+   * GtkWindowButtonsQuartz:decoration-layout:
+   *
+   * The decoration layout for window buttons.
+   *
+   * If this property is not set, the
+   * [property@Gtk.Settings:gtk-decoration-layout] setting is used.
+   */
+  props[PROP_DECORATION_LAYOUT] =
+      g_param_spec_string ("decoration-layout", NULL, NULL,
+                           NULL,
+                           GTK_PARAM_READWRITE);
+
+  g_object_class_install_properties (gobject_class, NUM_PROPERTIES, props);
+
+  gtk_widget_class_set_css_name (widget_class, I_("windowbuttonsquartz"));
+
+  gtk_widget_class_set_accessible_role (widget_class, GTK_ACCESSIBLE_ROLE_IMG);
+}
+
+static void
+gtk_window_buttons_quartz_init (GtkWindowButtonsQuartz *self)
+{
+  self->close = TRUE;
+  self->minimize = TRUE;
+  self->maximize = TRUE;
+  self->decoration_layout = NULL;
+}
diff --git a/gtk/gtkwindowbuttonsquartzprivate.h b/gtk/gtkwindowbuttonsquartzprivate.h
new file mode 100644
index 0000000000000000000000000000000000000000..7f4915e9c352460b01e262147fdf8d4522dcf8f5
--- /dev/null
+++ b/gtk/gtkwindowbuttonsquartzprivate.h
@@ -0,0 +1,38 @@
+/* GTK - The GIMP Toolkit
+ * Copyright (c) 2024 Arjan Molenaar <amolenaar@gnome.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * SPDX-License-Identifier: LGPL-2.1-or-later
+ */
+
+#pragma once
+
+
+#include <gtk/gtkwidget.h>
+
+
+G_BEGIN_DECLS
+
+#define GTK_TYPE_WINDOW_BUTTONS_QUARTZ                  (gtk_window_buttons_quartz_get_type ())
+#define GTK_WINDOW_BUTTONS_QUARTZ(obj)                  (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_WINDOW_BUTTONS_QUARTZ, GtkWindowButtonsQuartz))
+#define GTK_IS_WINDOW_BUTTONS_QUARTZ(obj)               (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_WINDOW_BUTTONS_QUARTZ))
+
+typedef struct _GtkWindowButtonsQuartz              GtkWindowButtonsQuartz;
+
+GDK_AVAILABLE_IN_ALL
+GType      gtk_window_buttons_quartz_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
diff --git a/gtk/gtkwindowcontrols.c b/gtk/gtkwindowcontrols.c
index 73ec4919f8d678b4155f7e58466840e8a88b979a..6e6cc241b7e24c9c2bdd0fbc8a54b8d450deb8b7 100644
--- a/gtk/gtkwindowcontrols.c
+++ b/gtk/gtkwindowcontrols.c
@@ -32,15 +32,22 @@
 #include "gtktypebuiltins.h"
 #include "gtkwindowprivate.h"
 
+#ifdef GDK_WINDOWING_MACOS
+#include "gtkwindowbuttonsquartzprivate.h"
+#endif
+
 /**
  * GtkWindowControls:
  *
- * A widget that shows window frame controls.
+ * Shows window frame controls.
  *
  * Typical window frame controls are minimize, maximize and close buttons,
  * and the window icon.
  *
- * ![An example GtkWindowControls](windowcontrols.png)
+ * <picture>
+ *   <source srcset="windowcontrols-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkWindowControls" src="windowcontrols.png">
+ * </picture>
  *
  * `GtkWindowControls` only displays start or end side of the controls (see
  * [property@Gtk.WindowControls:side]), so it's intended to be always used
@@ -93,6 +100,7 @@ struct _GtkWindowControls {
   GtkPackType side;
   char *decoration_layout;
 
+  gboolean use_native_controls;
   gboolean empty;
 };
 
@@ -100,6 +108,7 @@ enum {
   PROP_0,
   PROP_SIDE,
   PROP_DECORATION_LAYOUT,
+  PROP_USE_NATIVE_CONTROLS,
   PROP_EMPTY,
   LAST_PROP
 };
@@ -129,20 +138,33 @@ get_layout (GtkWindowControls *self)
                   "gtk-decoration-layout", &layout_desc,
                   NULL);
 
+  if (layout_desc == NULL || layout_desc[0] == '\0')
+    {
+      g_free (layout_desc);
+      return NULL;
+    }
+
   tokens = g_strsplit (layout_desc, ":", 2);
 
-  switch (self->side)
+  if (tokens[1] == NULL)
     {
-    case GTK_PACK_START:
       layout_half = g_strdup (tokens[0]);
-      break;
+    }
+  else
+    {
+      switch (self->side)
+        {
+        case GTK_PACK_START:
+          layout_half = g_strdup (tokens[0]);
+          break;
 
-    case GTK_PACK_END:
-      layout_half = g_strdup (tokens[1]);
-      break;
+        case GTK_PACK_END:
+          layout_half = g_strdup (tokens[1]);
+          break;
 
-    default:
-      g_assert_not_reached ();
+        default:
+          g_assert_not_reached ();
+        }
     }
 
   g_free (layout_desc);
@@ -247,6 +269,36 @@ update_window_buttons (GtkWindowControls *self)
       return;
     }
 
+#ifdef GDK_WINDOWING_MACOS
+  if (self->use_native_controls)
+    {
+      if (GTK_IS_WINDOW_BUTTONS_QUARTZ (gtk_widget_get_first_child (widget)))
+        return;
+
+      clear_controls (self);
+
+      if (self->side == GTK_PACK_START)
+        {
+          GtkWidget *controls = g_object_new (GTK_TYPE_WINDOW_BUTTONS_QUARTZ, NULL);
+          g_object_bind_property (self, "decoration-layout",
+                                  controls, "decoration-layout",
+                                  G_BINDING_SYNC_CREATE);
+          gtk_widget_set_parent (controls, GTK_WIDGET (self));
+
+          gtk_widget_add_css_class (GTK_WIDGET (self), "native");
+          empty = FALSE;
+        }
+
+      set_empty (self, empty);
+
+      return;
+    }
+  else
+    {
+      gtk_widget_remove_css_class (GTK_WIDGET (self), "native");
+    }
+#endif
+
   clear_controls (self);
 
   window = GTK_WINDOW (root);
@@ -458,6 +510,10 @@ gtk_window_controls_get_property (GObject    *object,
       g_value_set_string (value, gtk_window_controls_get_decoration_layout (self));
       break;
 
+    case PROP_USE_NATIVE_CONTROLS:
+      g_value_set_boolean (value, gtk_window_controls_get_use_native_controls (self));
+      break;
+
     case PROP_EMPTY:
       g_value_set_boolean (value, gtk_window_controls_get_empty (self));
       break;
@@ -486,6 +542,10 @@ gtk_window_controls_set_property (GObject      *object,
       gtk_window_controls_set_decoration_layout (self, g_value_get_string (value));
       break;
 
+    case PROP_USE_NATIVE_CONTROLS:
+      gtk_window_controls_set_use_native_controls (self, g_value_get_boolean (value));
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -532,6 +592,26 @@ gtk_window_controls_class_init (GtkWindowControlsClass *klass)
                            NULL,
                            GTK_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY);
 
+
+  /**
+   * GtkWindowControls:use-native-controls:
+   *
+   * Whether to show platform native close/minimize/maximize buttons.
+   *
+   * For macOS, the [property@Gtk.HeaderBar:decoration-layout] property
+   * controls the use of native window controls.
+   *
+   * On other platforms, this option has no effect.
+   *
+   * See also [Using GTK on Apple macOS](osx.html?native-window-controls).
+   *
+   * Since: 4.18
+   */
+  props[PROP_USE_NATIVE_CONTROLS] =
+      g_param_spec_boolean ("use-native-controls", NULL, NULL,
+                            FALSE,
+                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
   /**
    * GtkWindowControls:empty:
    *
@@ -554,6 +634,7 @@ gtk_window_controls_init (GtkWindowControls *self)
 {
   self->decoration_layout = NULL;
   self->side = GTK_PACK_START;
+  self->use_native_controls = FALSE;
   self->empty = TRUE;
 
   gtk_widget_add_css_class (GTK_WIDGET (self), "empty");
@@ -680,14 +761,64 @@ gtk_window_controls_set_decoration_layout (GtkWindowControls *self,
 {
   g_return_if_fail (GTK_IS_WINDOW_CONTROLS (self));
 
-  g_free (self->decoration_layout);
-  self->decoration_layout = g_strdup (layout);
+  g_set_str (&self->decoration_layout, layout);
 
   update_window_buttons (self);
 
   g_object_notify_by_pspec (G_OBJECT (self), props[PROP_DECORATION_LAYOUT]);
 }
 
+
+/**
+ * gtk_window_controls_get_use_native_controls:
+ * @self: a window controls widget
+ *
+ * Returns whether platform native window controls are shown.
+ *
+ * Returns: true if native window controls are shown
+ *
+ * Since: 4.18
+ */
+gboolean
+gtk_window_controls_get_use_native_controls (GtkWindowControls *self)
+{
+  g_return_val_if_fail (GTK_IS_WINDOW_CONTROLS (self), FALSE);
+
+  return self->use_native_controls;
+}
+
+/**
+ * gtk_window_controls_set_use_native_controls:
+ * @self: a window_controls widget
+ * @setting: true to show native window controls
+ *
+ * Sets whether platform native window controls are used.
+ *
+ * This option shows the "stoplight" buttons on macOS.
+ * For Linux, this option has no effect.
+ *
+ * See also [Using GTK on Apple macOS](osx.html?native-window-controls).
+ *
+ * Since: 4.18
+ */
+void
+gtk_window_controls_set_use_native_controls (GtkWindowControls *self,
+                                             gboolean           setting)
+{
+  g_return_if_fail (GTK_IS_WINDOW_CONTROLS (self));
+
+  setting = setting != FALSE;
+
+  if (self->use_native_controls == setting)
+    return;
+
+  self->use_native_controls = setting;
+
+  update_window_buttons (self);
+
+  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_USE_NATIVE_CONTROLS]);
+}
+
 /**
  * gtk_window_controls_get_empty:
  * @self: a window controls widget
diff --git a/gtk/gtkwindowcontrols.h b/gtk/gtkwindowcontrols.h
index d76edfaeb9097108ae4227697fc9b31bdbdd04aa..7a08cb61e72890dd9f118e4f81c315e0c9831585 100644
--- a/gtk/gtkwindowcontrols.h
+++ b/gtk/gtkwindowcontrols.h
@@ -48,6 +48,13 @@ GDK_AVAILABLE_IN_ALL
 void         gtk_window_controls_set_decoration_layout (GtkWindowControls *self,
                                                         const char        *layout);
 
+GDK_AVAILABLE_IN_4_18
+gboolean     gtk_window_controls_get_use_native_controls (GtkWindowControls *self);
+
+GDK_AVAILABLE_IN_4_18
+void         gtk_window_controls_set_use_native_controls (GtkWindowControls *self,
+                                                          gboolean           setting);
+
 GDK_AVAILABLE_IN_ALL
 gboolean     gtk_window_controls_get_empty             (GtkWindowControls *self);
 
diff --git a/gtk/gtkwindowgroup.c b/gtk/gtkwindowgroup.c
index 7bd30739c9d6a8de7f04f1e6544dd78dedca2dc0..a18e53d62b9685679c78c9fb68f2d8e72306a6df 100644
--- a/gtk/gtkwindowgroup.c
+++ b/gtk/gtkwindowgroup.c
@@ -33,7 +33,7 @@
 /**
  * GtkWindowGroup:
  *
- * `GtkWindowGroup` makes group of windows behave like separate applications.
+ * Creates groups of windows that behave like separate applications.
  *
  * It achieves this by limiting the effect of GTK grabs and modality
  * to windows in the same group.
diff --git a/gtk/gtkwindowhandle.c b/gtk/gtkwindowhandle.c
index a829e6fd22a9f57e318ed8e8d8892799d88712f2..e77f6307a2668c9c9134189e66cc36615e160079 100644
--- a/gtk/gtkwindowhandle.c
+++ b/gtk/gtkwindowhandle.c
@@ -40,10 +40,11 @@
 /**
  * GtkWindowHandle:
  *
- * `GtkWindowHandle` is a titlebar area widget.
+ * Implements titlebar functionality for a window.
  *
- * When added into a window, it can be dragged to move the window, and handles
- * right click, double click and middle click as expected of a titlebar.
+ * When added into a window, it can be dragged to move the window,
+ * and it implements the right click, double click and middle click
+ * behaviors that are expected of a titlebar.
  *
  * # CSS nodes
  *
@@ -51,9 +52,10 @@
  *
  * # Accessibility
  *
- * Until GTK 4.10, `GtkWindowHandle` used the `GTK_ACCESSIBLE_ROLE_GROUP` role.
+ * Until GTK 4.10, `GtkWindowHandle` used the [enum@Gtk.AccessibleRole.group] role.
  *
- * Starting from GTK 4.12, `GtkWindowHandle` uses the `GTK_ACCESSIBLE_ROLE_GENERIC` role.
+ * Starting from GTK 4.12, `GtkWindowHandle` uses the [enum@Gtk.AccessibleRole.generic]
+ * role.
  */
 
 struct _GtkWindowHandle {
diff --git a/gtk/inspector/general.c b/gtk/inspector/general.c
index 6f1daa13c3ff6541300ab9eb9bcbba528583104b..8674ce4fc24e6c245dd6dc6a4006553c0755ce62 100644
--- a/gtk/inspector/general.c
+++ b/gtk/inspector/general.c
@@ -1081,7 +1081,6 @@ static const char *env_list[] = {
   "GSK_CACHE_TIMEOUT",
   "GSK_DEBUG",
   "GSK_GPU_DISABLE",
-  "GSK_MAX_TEXTURE_SIZE",
   "GSK_RENDERER",
   "GSK_SUBSET_FONTS",
   "GTK_A11Y",
diff --git a/gtk/inspector/object-tree.c b/gtk/inspector/object-tree.c
index 36a87998ca5ef88aa7a3339926cba5260364eed4..d8c3b2afb8e672d5f10f829be9835b7ecbe2c9e8 100644
--- a/gtk/inspector/object-tree.c
+++ b/gtk/inspector/object-tree.c
@@ -144,24 +144,15 @@ object_tree_native_get_children (GObject *object)
 {
   GtkNative *native = GTK_NATIVE (object);
   GListStore *list;
-  GListModel *sublist;
-
-  list = g_list_store_new (G_TYPE_LIST_MODEL);
 
-  sublist = G_LIST_MODEL (g_list_store_new (G_TYPE_OBJECT));
+  list = g_list_store_new (G_TYPE_OBJECT);
 
   if (gtk_native_get_surface (native))
-    g_list_store_append (G_LIST_STORE (sublist), gtk_native_get_surface (native));
+    g_list_store_append (list, gtk_native_get_surface (native));
   if (gtk_native_get_renderer (native))
-    g_list_store_append (G_LIST_STORE (sublist), gtk_native_get_renderer (native));
-  g_list_store_append (list, sublist);
-  g_object_unref (sublist);
+    g_list_store_append (list, gtk_native_get_renderer (native));
 
-  sublist = object_tree_widget_get_children (object);
-  g_list_store_append (list, sublist);
-  g_object_unref (sublist);
-
-  return G_LIST_MODEL (gtk_flatten_list_model_new (G_LIST_MODEL (list)));
+  return G_LIST_MODEL (list);
 }
 
 static GListModel *
@@ -505,9 +496,9 @@ object_tree_event_controller_get_parent (GObject *object)
 }
 
 /* Note:
- * This tree must be sorted with the most specific types first.
- * We iterate over it top to bottom and return the first match
- * using g_type_is_a ()
+ * This tree should be sorted with the most specific types first.
+ * We iterate over it top to bottom and append the children to the
+ * list if g_type_is_a () matches.
  */
 static const ObjectTreeClassFuncs object_tree_class_funcs[] = {
   {
diff --git a/gtk/meson.build b/gtk/meson.build
index 063c25b57e51ce8284e27ec06bd754e16db0bdb6..f9d484d860c7066016d2b2a38895a7a5a72e2934 100644
--- a/gtk/meson.build
+++ b/gtk/meson.build
@@ -689,6 +689,7 @@ if macos_enabled
     'gtkfilechoosernativequartz.c',
     'gtkimcontextquartz.c',
     'gtkquartz.c',
+    'gtkwindowbuttonsquartz.c',
   ])
 
   gtk_cargs += ['-xobjective-c']  # FIXME? maybe add_languages() instead?
diff --git a/gtk/print/gtkpagesetup.c b/gtk/print/gtkpagesetup.c
index 1b9416aa9dfb761663b01eeab9466a87e5caa4d2..779ef9e9e40b91f91c54a94c7d289140e293814d 100644
--- a/gtk/print/gtkpagesetup.c
+++ b/gtk/print/gtkpagesetup.c
@@ -29,7 +29,7 @@
 /**
  * GtkPageSetup:
  *
- * A `GtkPageSetup` object stores the page size, orientation and margins.
+ * Stores page size, orientation and margins for printing.
  *
  * The idea is that you can get one of these from the page setup dialog
  * and then pass it to the `GtkPrintOperation` when printing.
diff --git a/gtk/print/gtkpagesetupunixdialog.c b/gtk/print/gtkpagesetupunixdialog.c
index 5879427d3a8af641944fc6966c7d94b9685c1598..b8800c06a7edde9d756a58413b034f4ff7e7fab9 100644
--- a/gtk/print/gtkpagesetupunixdialog.c
+++ b/gtk/print/gtkpagesetupunixdialog.c
@@ -34,10 +34,13 @@
 /**
  * GtkPageSetupUnixDialog:
  *
- * `GtkPageSetupUnixDialog` implements a page setup dialog for platforms
- * which don’t provide a native page setup dialog, like Unix.
+ * Presents a page setup dialog for platforms which don’t provide
+ * a native page setup dialog, like Unix.
  *
- * ![An example GtkPageSetupUnixDialog](pagesetupdialog.png)
+ * <picture>
+ *   <source srcset="pagesetupdialog-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkPageSetupUnixDialog" src="pagesetupdialog.png">
+ * </picture>
  *
  * It can be used very much like any other GTK dialog, at the
  * cost of the portability offered by the high-level printing
diff --git a/gtk/print/gtkprintcontext.c b/gtk/print/gtkprintcontext.c
index 1141062d3128fa61636d1d6075352f1c645f38e9..a04b7366a02399aa4bc7ee5f561a55c4ec86454e 100644
--- a/gtk/print/gtkprintcontext.c
+++ b/gtk/print/gtkprintcontext.c
@@ -23,7 +23,7 @@
 /**
  * GtkPrintContext:
  *
- * A `GtkPrintContext` encapsulates context information that is required when
+ * Encapsulates context information that is required when
  * drawing pages for printing.
  *
  * This includes the cairo context and important parameters like page size
diff --git a/gtk/print/gtkprinter.c b/gtk/print/gtkprinter.c
index 8e85c575ee85c38b6aa65ec1dad6dfedc364c3da..ea48ac7b44caa901091e41f7baa02768ffb9ce25 100644
--- a/gtk/print/gtkprinter.c
+++ b/gtk/print/gtkprinter.c
@@ -34,7 +34,7 @@
 /**
  * GtkPrinter:
  *
- * A `GtkPrinter` object represents a printer.
+ * Represents a printer.
  *
  * You only need to deal directly with printers if you use the
  * non-portable [class@Gtk.PrintUnixDialog] API.
@@ -1297,12 +1297,12 @@ list_printers_init (PrinterList     *printer_list,
  * @func: a function to call for each printer
  * @data: user data to pass to @func
  * @destroy: function to call if @data is no longer needed
- * @wait: if %TRUE, wait in a recursive mainloop until
+ * @wait: if true, wait in a recursive mainloop until
  *    all printers are enumerated; otherwise return early
  *
- * Calls a function for all `GtkPrinter`s.
+ * Calls a function for all printers that are known to GTK.
  *
- * If @func returns %TRUE, the enumeration is stopped.
+ * If @func returns true, the enumeration is stopped.
  */
 void
 gtk_enumerate_printers (GtkPrinterFunc func,
diff --git a/gtk/print/gtkprintjob.c b/gtk/print/gtkprintjob.c
index b70e9ce9f49e670bcb1172ba112cdc558dbd731f..3e0b360bbe9b71b2d3037398a825f8154391553f 100644
--- a/gtk/print/gtkprintjob.c
+++ b/gtk/print/gtkprintjob.c
@@ -18,7 +18,7 @@
 /**
  * GtkPrintJob:
  *
- * A `GtkPrintJob` object represents a job that is sent to a printer.
+ * Represents a job that is sent to a printer.
  *
  * You only need to deal directly with print jobs if you use the
  * non-portable [class@Gtk.PrintUnixDialog] API.
diff --git a/gtk/print/gtkprintoperation-unix.c b/gtk/print/gtkprintoperation-unix.c
index 5cdd102ff6070ef036751936a4953bd97db3338a..c4cf52eadfc7898ac5ad73bd694db77f9c7cdf43 100644
--- a/gtk/print/gtkprintoperation-unix.c
+++ b/gtk/print/gtkprintoperation-unix.c
@@ -980,13 +980,14 @@ get_page_setup_dialog (GtkWindow        *parent,
  * @page_setup: (nullable): an existing `GtkPageSetup`
  * @settings: a `GtkPrintSettings`
  *
- * Runs a page setup dialog, letting the user modify the values from
- * @page_setup. If the user cancels the dialog, the returned `GtkPageSetup`
- * is identical to the passed in @page_setup, otherwise it contains the
- * modifications done in the dialog.
+ * Runs a page setup dialog, letting the user modify the values from @page_setup.
+ *
+ * If the user cancels the dialog, the returned `GtkPageSetup` is identical
+ * to the passed in @page_setup, otherwise it contains the modifications
+ * done in the dialog.
  *
  * Note that this function may use a recursive mainloop to show the page
- * setup dialog. See gtk_print_run_page_setup_dialog_async() if this is
+ * setup dialog. See [func@Gtk.print_run_page_setup_dialog_async] if this is
  * a problem.
  *
  * Returns: (transfer full): a new `GtkPageSetup`
@@ -1036,9 +1037,9 @@ gtk_print_run_page_setup_dialog (GtkWindow        *parent,
  *
  * Runs a page setup dialog, letting the user modify the values from @page_setup.
  *
- * In contrast to gtk_print_run_page_setup_dialog(), this function  returns after
- * showing the page setup dialog on platforms that support this, and calls @done_cb
- * from a signal handler for the ::response signal of the dialog.
+ * In contrast to [func@Gtk.print_run_page_setup_dialog], this function  returns
+ * after showing the page setup dialog on platforms that support this, and calls
+ * @done_cb from a signal handler for the ::response signal of the dialog.
  */
 void
 gtk_print_run_page_setup_dialog_async (GtkWindow            *parent,
diff --git a/gtk/print/gtkprintoperation.c b/gtk/print/gtkprintoperation.c
index ba6d4a928ad4f7696e595ded4e7d67bea1bdbd39..35df92eaa6f2f38c515508c42d1c3953cfb7b04c 100644
--- a/gtk/print/gtkprintoperation.c
+++ b/gtk/print/gtkprintoperation.c
@@ -38,7 +38,7 @@
 /**
  * GtkPrintOperation:
  *
- * `GtkPrintOperation` is the high-level, portable printing API.
+ * High-level, portable printing API.
  *
  * It looks a bit different than other GTK dialogs such as the
  * `GtkFileChooser`, since some platforms don’t expose enough
diff --git a/gtk/print/gtkprintoperationpreview.c b/gtk/print/gtkprintoperationpreview.c
index 8e782bd4986e5ca8110544255c2480ae4f642eb7..31a07c59db666d78c0da10f04137f0b6085b10b6 100644
--- a/gtk/print/gtkprintoperationpreview.c
+++ b/gtk/print/gtkprintoperationpreview.c
@@ -28,8 +28,7 @@
 /**
  * GtkPrintOperationPreview:
  *
- * `GtkPrintOperationPreview` is the interface that is used to
- * implement print preview.
+ * The interface that is used to implement print preview.
  *
  * A `GtkPrintOperationPreview` object is passed to the
  * [signal@Gtk.PrintOperation::preview] signal by
diff --git a/gtk/print/gtkprintsettings.c b/gtk/print/gtkprintsettings.c
index fe95a150b69dd148ccefa7770f2d18068687eafd..ad22a234522834296177a970a659c196c0aa5dbb 100644
--- a/gtk/print/gtkprintsettings.c
+++ b/gtk/print/gtkprintsettings.c
@@ -32,8 +32,7 @@
 /**
  * GtkPrintSettings:
  *
- * A `GtkPrintSettings` object represents the settings of a print dialog in
- * a system-independent way.
+ * Collects the settings of a print dialog in a system-independent way.
  *
  * The main use for this object is that once you’ve printed you can get a
  * settings object that represents the settings the user chose, and the next
diff --git a/gtk/print/gtkprintunixdialog.c b/gtk/print/gtkprintunixdialog.c
index a6c9cdb3a7b95f6a60e505730a57a8816c2d0e2a..89866e067ffe1172d22e6855a47fd123367f5e26 100644
--- a/gtk/print/gtkprintunixdialog.c
+++ b/gtk/print/gtkprintunixdialog.c
@@ -45,10 +45,13 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
 /**
  * GtkPrintUnixDialog:
  *
- * `GtkPrintUnixDialog` implements a print dialog for platforms
- * which don’t provide a native print dialog, like Unix.
+ * A print dialog for platforms which don’t provide a native
+ * print dialog, like Unix.
  *
- * ![An example GtkPrintUnixDialog](printdialog.png)
+ * <picture>
+ *   <source srcset="printdialog-dark.png" media="(prefers-color-scheme: dark)">
+ *   <img alt="An example GtkPrintUnixDialog" src="printdialog.png">
+ * </picture>
  *
  * It can be used very much like any other GTK dialog, at the cost of
  * the portability offered by the high-level printing API with
diff --git a/gtk/ui/gtkappchooserwidget.ui b/gtk/ui/gtkappchooserwidget.ui
index 22cad8eb99d28ea81801a89400d67a4017df6f36..3e1235e56685117b93e0961225f0a03bcda33d8d 100644
--- a/gtk/ui/gtkappchooserwidget.ui
+++ b/gtk/ui/gtkappchooserwidget.ui
@@ -22,8 +22,8 @@
       <object class="GtkOverlay" id="overlay">
         <property name="child">
           <object class="GtkScrolledWindow" id="scrolled_window">
-            <property name="width-request">400</property>
-            <property name="height-request">300</property>
+            <property name="max-content-width">400</property>
+            <property name="max-content-height">300</property>
             <property name="hscrollbar-policy">2</property>
             <property name="has-frame">1</property>
             <property name="child">
diff --git a/meson.build b/meson.build
index 3399fd96be50b61442ce1be10567fbf4382c4a68..32c547fdae054b07a86d4315a51f17e6bf84f671 100644
--- a/meson.build
+++ b/meson.build
@@ -1,5 +1,5 @@
 project('gtk', 'c',
-        version: '4.17.4',
+        version: '4.17.5',
         default_options: [
           'buildtype=debugoptimized',
           'warning_level=1',
@@ -24,8 +24,8 @@ harfbuzz_req       = '>= 8.4.0'
 fribidi_req        = '>= 1.0.6'
 cairo_req          = '>= 1.18.2'
 gdk_pixbuf_req     = '>= 2.30.0'
-wayland_proto_req  = '>= 1.36'
-wayland_req        = '>= 1.21.0'
+wayland_proto_req  = '>= 1.41'
+wayland_req        = '>= 1.23.0'
 graphene_req       = '>= 1.10.0'
 epoxy_req          = '>= 1.4'
 cloudproviders_req = '>= 0.3.1'
@@ -538,8 +538,9 @@ endif
 wayland_pkgs = []
 if wayland_enabled
   wlclientdep    = dependency('wayland-client', version:  wayland_req,
-                              default_options: ['documentation=false'])
-  wlprotocolsdep = dependency('wayland-protocols', version: wayland_proto_req)
+                              default_options: ['documentation=false', 'tests=false'])
+  wlprotocolsdep = dependency('wayland-protocols', version: wayland_proto_req,
+                              default_options: ['tests=false'])
   wlegldep       = dependency('wayland-egl')
 
   wayland_pkgs = [
diff --git a/po/POTFILES.in b/po/POTFILES.in
index e8e7b0a0441bf8eb7b920c73cbb551be9a1cb54b..20a3b1b9463f6fd4983ad4a5e7cd07871b8fc329 100644
--- a/po/POTFILES.in
+++ b/po/POTFILES.in
@@ -1,5 +1,6 @@
 # Files from the Gtk distribution which have already been
 # marked to allow runtime translation of messages
+gdk/android/gdkandroidclipboard.c
 gdk/broadway/gdkbroadway-server.c
 gdk/gdkapplaunchcontext.c
 gdk/gdk.c
diff --git a/po/ca.po b/po/ca.po
index 7b3f7713a725f2f42f3c7ca35c0d337a403a2afc..37e9336994fb8d18de58b9d2a014874530f06588 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -11,7 +11,7 @@
 # Gil Forcada <gilforcada@guifi.net>, 2012, 2013, 2014.
 # Jordi Serratosa <jordis@softcatala.cat>, 2012.
 # Josep Sànchez <papapep@gmx.com>, 2013.
-# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2015-2024
+# Jordi Mas i Hernàndez <jmas@softcatala.org>, 2015-2025
 #
 # Recull de termes
 #
@@ -35,7 +35,7 @@ msgstr ""
 "Project-Id-Version: gtk+ 2.8.2\n"
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
 "POT-Creation-Date: 2024-09-17 05:42+0000\n"
-"PO-Revision-Date: 2024-09-17 12:26+0200\n"
+"PO-Revision-Date: 2025-02-23 12:26+0200\n"
 "Last-Translator: Jordi Mas i Hernàndez <jmas@softcatala.org>\n"
 "Language-Team: Catalan <tradgnome@softcatala.org>\n"
 "Language: ca\n"
@@ -109,7 +109,7 @@ msgstr "S'ha desactivat el suport OpenGL mitjançant GDK_DISABLE"
 
 #: gdk/gdkdisplay.c:1683
 msgid "No EGL configuration available"
-msgstr "No hi ha cap implementació EGL disponible"
+msgstr "No hi ha cap configuració EGL disponible"
 
 #: gdk/gdkdisplay.c:1691
 msgid "Failed to get EGL configurations"
@@ -554,7 +554,7 @@ msgstr "Hiberna"
 #: gdk/keynamesprivate.h:6929
 msgctxt "keyboard label"
 msgid "WLAN"
-msgstr "Wi-Fi"
+msgstr "WLAN"
 
 #: gdk/keynamesprivate.h:6930
 msgctxt "keyboard label"
@@ -3950,7 +3950,7 @@ msgstr "Desa el CSS personalitzat"
 
 #: gtk/inspector/css-editor.ui:51
 msgid "Show deprecations"
-msgstr "Mostra les precedències"
+msgstr "Mostra obsolets"
 
 #: gtk/inspector/css-node-tree.ui:28 tools/gtk-builder-tool-preview.c:178
 #: tools/gtk-builder-tool-screenshot.c:359
@@ -8130,6 +8130,7 @@ msgstr ""
 "Ordres:\n"
 "  benchmark    Prova de rendiment de la renderització d'un node\n"
 "  compare      Compara nodes o imatges\n"
+"  extract      Extreu els URL de dades\n"
 "  info         Proporciona informació sobre el node\n"
 "  show         Mostra el node\n"
 "  render       Fes una captura de pantalla del node\n"
diff --git a/po/fa.po b/po/fa.po
index 3b263ac1987897397be2e3e27a6b7083031b172f..d2a6b99e4c03250e0f45233427bedb8f38a752b8 100644
--- a/po/fa.po
+++ b/po/fa.po
@@ -12,8 +12,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gtk+ 2.6\n"
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
-"POT-Creation-Date: 2024-09-17 05:42+0000\n"
-"PO-Revision-Date: 2024-09-17 14:02+0330\n"
+"POT-Creation-Date: 2025-02-22 01:17+0000\n"
+"PO-Revision-Date: 2025-02-23 19:35+0330\n"
 "Last-Translator: Danial Behzadi <dani.behzi@ubuntu.com>\n"
 "Language-Team: Persian <>\n"
 "Language: fa\n"
@@ -23,41 +23,53 @@ msgstr ""
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
 "X-Poedit-Bookmarks: 133,-1,-1,-1,-1,-1,-1,-1,-1,-1\n"
 "X-Poedit-SourceCharset: UTF-8\n"
-"X-Generator: Poedit 3.4.4\n"
+"X-Generator: Poedit 3.5\n"
+
+#: gdk/android/gdkandroidclipboard.c:174
+msgid "No compatible formats to transfer contents of content provider."
+msgstr "هیچ قالب سازگاری برای انتقال محتویات فراهمگر محتوا وجود ندارد."
+
+#: gdk/android/gdkandroidclipboard.c:623 gdk/macos/gdkmacospasteboard.c:161
+#: gdk/wayland/gdkclipboard-wayland.c:244 gdk/wayland/gdkdrop-wayland.c:205
+#: gdk/wayland/gdkprimary-wayland.c:343 gdk/win32/gdkdrop-win32.c:1014
+#: gdk/win32/gdkdrop-win32.c:1063 gdk/x11/gdkclipboard-x11.c:801
+#: gdk/x11/gdkdrop-x11.c:237
+msgid "No compatible transfer format found"
+msgstr "هیچ قالب انتقال سازگاری پیدا نشد"
 
 #: gdk/broadway/gdkbroadway-server.c:135
 #, c-format
 msgid "Broadway display type not supported: %s"
 msgstr "نوع نمایشگر broadway پشتیبانی نمی‌شود: %s"
 
-#: gdk/gdkclipboard.c:232
+#: gdk/gdkclipboard.c:231
 msgid "This clipboard cannot store data."
 msgstr "این تخته‌گیره نمی‌تواند داده ذخیره کند."
 
-#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:781 gdk/gdkclipboard.c:1072
+#: gdk/gdkclipboard.c:286 gdk/gdkclipboard.c:780 gdk/gdkclipboard.c:1071
 msgid "Cannot read from empty clipboard."
 msgstr "نمی‌توان از تخته‌گیرهٔ خالی خواند."
 
-#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1122 gdk/gdkdrag.c:606
+#: gdk/gdkclipboard.c:317 gdk/gdkclipboard.c:1121 gdk/gdkdrag.c:606
 msgid "No compatible formats to transfer clipboard contents."
 msgstr "هیچ قالب سازگاری برای انتقال محتویات تخته‌گیره وجود ندارد."
 
-#: gdk/gdkcolorstate.c:668
+#: gdk/gdkcolorstate.c:921
 #, c-format
 msgid "cicp: Narrow range or YUV not supported"
 msgstr "cicp: دامنه باریک بوده یا YUV پشتیبانی نمی‌شود"
 
-#: gdk/gdkcolorstate.c:678
+#: gdk/gdkcolorstate.c:931
 #, c-format
 msgid "cicp: Unspecified parameters not supported"
 msgstr "cicp: پارامترهای مشخص نشده یا پشتیبانی نشده"
 
-#: gdk/gdkcolorstate.c:724
+#: gdk/gdkcolorstate.c:977
 #, c-format
 msgid "cicp: Transfer function %u not supported"
 msgstr "cicp: تابع جابه‌جایی %Iu پشتیبانی نمی‌شود"
 
-#: gdk/gdkcolorstate.c:754
+#: gdk/gdkcolorstate.c:1007
 #, c-format
 msgid "cicp: Color primaries %u not supported"
 msgstr "cicp: اولیه‌های رنگی %Iu پشتیبانی نمی‌شود"
@@ -73,58 +85,58 @@ msgstr "نمی‌توان محتوا را به شکل «%s» فراهم کرد"
 msgid "Cannot provide contents as %s"
 msgstr "نمی‌توان محتوا را به شکل %s فراهم کرد"
 
-#: gdk/gdkdisplay.c:176 gdk/gdkglcontext.c:472
+#: gdk/gdkdisplay.c:176 gdk/gdkglcontext.c:466
 msgid "The current backend does not support OpenGL"
 msgstr "پسانه در حال حاضر از OpenGL پشتیبانی نمی‌کند"
 
-#: gdk/gdkdisplay.c:1315 gdk/gdkvulkancontext.c:1668
+#: gdk/gdkdisplay.c:1364 gdk/gdkvulkancontext.c:1726
 msgid "Vulkan support disabled via GDK_DISABLE"
 msgstr "پشتیبانی از ولکان به دست GDK_DISABLE از کار افتاده"
 
-#: gdk/gdkdisplay.c:1369
+#: gdk/gdkdisplay.c:1418
 msgid "OpenGL support disabled via GDK_DISABLE"
 msgstr "پشتیبانی از GL به دست GDK_DISABLE از کار افتاده"
 
-#: gdk/gdkdisplay.c:1683
+#: gdk/gdkdisplay.c:1732
 msgid "No EGL configuration available"
 msgstr "هیچ پیکربندی‌ای برای EGL موجود نیست"
 
-#: gdk/gdkdisplay.c:1691
+#: gdk/gdkdisplay.c:1740
 msgid "Failed to get EGL configurations"
 msgstr "شکست در گرفتن پیکربندی EGL"
 
-#: gdk/gdkdisplay.c:1721
+#: gdk/gdkdisplay.c:1770
 msgid "No EGL configuration with required features found"
 msgstr "هیچ پیکربندی‌ای با ویژگی‌های موردنیاز برای EGL موجود نیست"
 
-#: gdk/gdkdisplay.c:1728
+#: gdk/gdkdisplay.c:1777
 msgid "No perfect EGL configuration found"
 msgstr "هیچ پیکربندی بی‌نظیری برایEGL موجود نیست"
 
-#: gdk/gdkdisplay.c:1770
+#: gdk/gdkdisplay.c:1819
 #, c-format
 msgid "EGL implementation is missing extension %s"
 msgid_plural "EGL implementation is missing %2$d extensions: %1$s"
 msgstr[0] "پیاده‌سازی EGL افزونهٔ %s را کم دارد"
 msgstr[1] "پیاده‌سازی EGL ‏%2$Id افزونه کم دارد: %1$s"
 
-#: gdk/gdkdisplay.c:1819
+#: gdk/gdkdisplay.c:1868
 msgid "libEGL not available in this sandbox"
 msgstr "libEGL در این قرنطینه موجود نیست"
 
-#: gdk/gdkdisplay.c:1820
+#: gdk/gdkdisplay.c:1869
 msgid "libEGL not available"
 msgstr "libEGL موجود نیست"
 
-#: gdk/gdkdisplay.c:1830
+#: gdk/gdkdisplay.c:1879
 msgid "Failed to create EGL display"
 msgstr "شکست در ایجاد نمایشگر EGL"
 
-#: gdk/gdkdisplay.c:1839
+#: gdk/gdkdisplay.c:1888
 msgid "Could not initialize EGL display"
 msgstr "نتوانست نمایشگر EGL را راه‌اندازی کند"
 
-#: gdk/gdkdisplay.c:1849
+#: gdk/gdkdisplay.c:1898
 #, c-format
 msgid "EGL version %d.%d is too old. GTK requires %d.%d"
 msgstr "EGL نگارش %Id. %Id بیش از حد قدیمی است. GTK به %Id.%Id نیاز دارد"
@@ -137,25 +149,25 @@ msgstr "کشیدن و رها کردن از دیگر برنامه‌ها پشتی
 msgid "No compatible formats to transfer contents."
 msgstr "هیچ قالب سازگاری برای انتقال محتویات وجود ندارد."
 
-#: gdk/gdkglcontext.c:432 gdk/x11/gdkglcontext-glx.c:651
+#: gdk/gdkglcontext.c:426 gdk/x11/gdkglcontext-glx.c:653
 msgid "No GL API allowed."
 msgstr "هیچ رابط برنامه‌نویسی GLای مجاز نیست."
 
-#: gdk/gdkglcontext.c:455 gdk/win32/gdkglcontext-win32-wgl.c:723
-#: gdk/win32/gdkglcontext-win32-wgl.c:866 gdk/win32/gdkglcontext-win32-wgl.c:910
-#: gdk/x11/gdkglcontext-glx.c:697
+#: gdk/gdkglcontext.c:449 gdk/win32/gdkglcontext-win32-wgl.c:746
+#: gdk/win32/gdkglcontext-win32-wgl.c:889 gdk/win32/gdkglcontext-win32-wgl.c:933
+#: gdk/x11/gdkglcontext-glx.c:699
 msgid "Unable to create a GL context"
 msgstr "امکان ساخت زمینه مناسب برای GL نبود"
 
-#: gdk/gdkglcontext.c:1340
+#: gdk/gdkglcontext.c:1327
 msgid "OpenGL ES API disabled via GDK_DISABLE"
 msgstr "میانای برنامه نویسی OpenGL ES به دست GDK_DISABLE از کار افتاد"
 
-#: gdk/gdkglcontext.c:1352
+#: gdk/gdkglcontext.c:1339
 msgid "OpenGL API disabled via GDK_DISABLE"
 msgstr "میانای برنامه نویسی OpenGL به دست GDK_DISABLE از کار افتاد"
 
-#: gdk/gdkglcontext.c:1363
+#: gdk/gdkglcontext.c:1350
 #, c-format
 msgid "Application does not support %s API"
 msgstr "برنامه از API مربوط به %s پشتبانی نمی‌کند"
@@ -163,12 +175,12 @@ msgstr "برنامه از API مربوط به %s پشتبانی نمی‌کند"
 #. translators: This is about OpenGL backend names, like
 #. * "Trying to use X11 GLX, but EGL is already in use"
 #.
-#: gdk/gdkglcontext.c:2175
+#: gdk/gdkglcontext.c:2127
 #, c-format
 msgid "Trying to use %s, but %s is already in use"
 msgstr "تلاش شد از %s استفاده شود، ولی %s از پیش در حال استفاده است"
 
-#: gdk/gdkglcontext.c:2186
+#: gdk/gdkglcontext.c:2138
 #, c-format
 msgid "Trying to use %s, but it is disabled via GDK_DISABLE"
 msgstr "تلاش شد از %s استفاده شود، ولی به دست GDK_DISABLE از کار افتاده"
@@ -253,12 +265,12 @@ msgctxt "keyboard label"
 msgid "Down"
 msgstr "پایین"
 
-#: gdk/keynamesprivate.h:6874 gtk/gtkshortcutlabel.c:217
+#: gdk/keynamesprivate.h:6874 gtk/deprecated/gtkshortcutlabel.c:219
 msgctxt "keyboard label"
 msgid "Page_Up"
 msgstr "صفحه‌_بالا"
 
-#: gdk/keynamesprivate.h:6875 gtk/gtkshortcutlabel.c:220
+#: gdk/keynamesprivate.h:6875 gtk/deprecated/gtkshortcutlabel.c:222
 msgctxt "keyboard label"
 msgid "Page_Down"
 msgstr "صفحه‌_پایین"
@@ -554,37 +566,37 @@ msgctxt "keyboard label"
 msgid "Suspend"
 msgstr "تعلیق"
 
-#: gdk/loaders/gdkjpeg.c:65
+#: gdk/loaders/gdkjpeg.c:71
 #, c-format
 msgid "Error interpreting JPEG image file (%s)"
 msgstr "خطا در تفسیر پروندهٔ JPEG ‏(%s)"
 
-#: gdk/loaders/gdkjpeg.c:179
+#: gdk/loaders/gdkjpeg.c:185
 #, c-format
 msgid "Unsupported JPEG colorspace (%d)"
 msgstr "فضای رنگ JPEG پشتیبانی نشده (%Id)"
 
-#: gdk/loaders/gdkjpeg.c:188 gdk/loaders/gdkpng.c:436 gdk/loaders/gdktiff.c:472
+#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:468 gdk/loaders/gdktiff.c:472
 #, c-format
 msgid "Not enough memory for image size %ux%u"
 msgstr "حافظهٔ ناکافی برای اندازهٔ تصویر %Iu×%Iu"
 
-#: gdk/loaders/gdkpng.c:120
+#: gdk/loaders/gdkpng.c:119
 #, c-format
 msgid "Error reading png (%s)"
 msgstr "خطای خواندن png) %s)"
 
-#: gdk/loaders/gdkpng.c:357
+#: gdk/loaders/gdkpng.c:389
 #, c-format
 msgid "Unsupported depth %u in png image"
 msgstr "عمق پشتیبانی‌نشدهٔ %Iu در تصویر png"
 
-#: gdk/loaders/gdkpng.c:407
+#: gdk/loaders/gdkpng.c:439
 #, c-format
 msgid "Unsupported color type %u in png image"
 msgstr "گونهٔ رنگ پشتیبانی نشدهٔ %Iu در تصویر png"
 
-#: gdk/loaders/gdkpng.c:421
+#: gdk/loaders/gdkpng.c:453
 #, c-format
 msgid "Image stride too large for image size %ux%u"
 msgstr "گام تصویر بیش از حد بزرگ برای اندازهٔ تصویر %Iu×%Iu"
@@ -602,368 +614,356 @@ msgstr "نتوانست دادهٔ TIFF را بار کند"
 msgid "Reading data failed at row %d"
 msgstr "خواندن داده‌ها در ردیف %Id شکست خورد"
 
-#: gdk/macos/gdkmacospasteboard.c:211 gdk/wayland/gdkclipboard-wayland.c:238
-#: gdk/wayland/gdkdrop-wayland.c:205 gdk/wayland/gdkprimary-wayland.c:337
-#: gdk/win32/gdkdrop-win32.c:1018 gdk/win32/gdkdrop-win32.c:1067
-#: gdk/x11/gdkclipboard-x11.c:799 gdk/x11/gdkdrop-x11.c:235
-msgid "No compatible transfer format found"
-msgstr "هیچ قالب انتقال سازگاری پیدا نشد"
-
-#: gdk/macos/gdkmacospasteboard.c:297
+#: gdk/macos/gdkmacospasteboard.c:255
 #, c-format
 msgid "Failed to decode contents with mime-type of '%s'"
 msgstr "شکست در رمزگشایی محتوا با mime از گونهٔ %s"
 
-#: gdk/win32/gdkclipdrop-win32.c:719
+#: gdk/win32/gdkclipdrop-win32.c:684
 #, c-format
 msgid "Cannot claim clipboard ownership. OpenClipboard() timed out."
 msgstr "نتوانست مدّعی مالکیت تخته‌گیره شود. زمان ‪OpenClipboard()‬ تمام شد."
 
-#: gdk/win32/gdkclipdrop-win32.c:729
+#: gdk/win32/gdkclipdrop-win32.c:694
 #, c-format
 msgid "Cannot claim clipboard ownership. Another process claimed it before us."
 msgstr "نتوانست مدّعی مالکیت تخته‌گیره شود. فرایند دیگری پیش از ما مدّعیش شد."
 
-#: gdk/win32/gdkclipdrop-win32.c:743
+#: gdk/win32/gdkclipdrop-win32.c:708
 #, c-format
 msgid "Cannot claim clipboard ownership. OpenClipboard() failed: 0x%lx."
 msgstr "نتوانست مدّعی مالکیت تخته‌گیره شود. ‪OpenClipboard()‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:755
+#: gdk/win32/gdkclipdrop-win32.c:718
 #, c-format
 msgid "Cannot claim clipboard ownership. EmptyClipboard() failed: 0x%lx."
 msgstr "نتوانست مدّعی مالکیت تخته‌گیره شود. ‪EmptyClipboard()‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:798
+#: gdk/win32/gdkclipdrop-win32.c:760
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() timed out."
 msgstr "نتوانست دادهٔ تخته‌گیره را تنظیم کند. زمان ‪OpenClipboard()‬ تمام شد."
 
-#: gdk/win32/gdkclipdrop-win32.c:808 gdk/win32/gdkclipdrop-win32.c:839
+#: gdk/win32/gdkclipdrop-win32.c:770 gdk/win32/gdkclipdrop-win32.c:801
 #, c-format
 msgid "Cannot set clipboard data. Another process claimed clipboard ownership."
 msgstr "نتوانست دادهٔ تخته‌گیره را تنظیم کند. فرایند دیگری پیش از ما مدّعیش شد."
 
-#: gdk/win32/gdkclipdrop-win32.c:822
+#: gdk/win32/gdkclipdrop-win32.c:784
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr "نتوانست دادهٔ تخته‌گیره را تنظیم کند. ‪OpenClipboard()‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:874
+#: gdk/win32/gdkclipdrop-win32.c:836
 #, c-format
 msgid "Cannot get clipboard data. GlobalLock(0x%p) failed: 0x%lx."
 msgstr "نتوانست دادهٔ تخته‌گیره را بگیرد. ‪GlobalLock(0x%p)‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:885
+#: gdk/win32/gdkclipdrop-win32.c:847
 #, c-format
 msgid "Cannot get clipboard data. GlobalSize(0x%p) failed: 0x%lx."
 msgstr "نتوانست دادهٔ تخته‌گیره را بگیرد. ‪GlobalSize(0x%p)‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:898
+#: gdk/win32/gdkclipdrop-win32.c:860
 #, c-format
 msgid "Cannot get clipboard data. Failed to allocate %s bytes to store the data."
 msgstr "نتوانست دادهٔ تخته‌گیره را بگیرد. تخصیص %s بایت برای ذخیرهٔ داده شکست خورد."
 
-#: gdk/win32/gdkclipdrop-win32.c:930
+#: gdk/win32/gdkclipdrop-win32.c:893
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() timed out."
 msgstr "نتوانست دادهٔ تخته‌گیره را بگیرد. زمان ‪OpenClipboard()‬ تمام شد."
 
-#: gdk/win32/gdkclipdrop-win32.c:940
+#: gdk/win32/gdkclipdrop-win32.c:903
 #, c-format
 msgid "Cannot get clipboard data. Clipboard ownership changed."
 msgstr "نتوانست دادهٔ تخته‌گیره را تنظیم کند. مالکیت تخته‌گیره تغییر کرد."
 
-#: gdk/win32/gdkclipdrop-win32.c:950
+#: gdk/win32/gdkclipdrop-win32.c:913
 #, c-format
 msgid "Cannot get clipboard data. Clipboard data changed before we could get it."
 msgstr ""
 "نتوانست دادهٔ تخته‌گیره را بگیرد. داده‌ّای تخته‌گیره پیش از این که بتوانیم بگیریمشان "
 "عوض شدند."
 
-#: gdk/win32/gdkclipdrop-win32.c:967
+#: gdk/win32/gdkclipdrop-win32.c:928
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr "نتوانست دادهٔ تخته‌گیره را بگیرد. ‪OpenClipboard()‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:992
+#: gdk/win32/gdkclipdrop-win32.c:953
 #, c-format
 msgid "Cannot get clipboard data. No compatible transfer format found."
 msgstr "نتوانست دادهٔ تخته‌گیره را بگیرد. هیچ قالب انتقال سازگاری پیدا نشد."
 
-#: gdk/win32/gdkclipdrop-win32.c:1002
+#: gdk/win32/gdkclipdrop-win32.c:963
 #, c-format
 msgid "Cannot get clipboard data. GetClipboardData() failed: 0x%lx."
 msgstr "نتوانست دادهٔ تخته‌گیره را بگیرد. ‪GetClipboardData()‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkdrop-win32.c:949
+#: gdk/win32/gdkdrop-win32.c:945
 #, c-format
 msgid "Cannot get DnD data. GlobalLock(0x%p) failed: 0x%lx."
 msgstr "نتوانست دادهٔ ک‌ور را بگیرد. ‪GlobalLock(0x%p)‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkdrop-win32.c:958
+#: gdk/win32/gdkdrop-win32.c:954
 #, c-format
 msgid "Cannot get DnD data. GlobalSize(0x%p) failed: 0x%lx."
 msgstr "نتوانست دادهٔ ک‌ور را بگیرد. ‪GlobalSize(0x%p)‬ شکست خورد: 0x%lx."
 
-#: gdk/win32/gdkdrop-win32.c:969
+#: gdk/win32/gdkdrop-win32.c:965
 #, c-format
 msgid "Cannot get DnD data. Failed to allocate %s bytes to store the data."
 msgstr "نتوانست دادهٔ ک‌ور را بگیرد.. تخصیص %s بایت برای ذخیرهٔ داده شکست خورد."
 
-#: gdk/win32/gdkdrop-win32.c:1039
+#: gdk/win32/gdkdrop-win32.c:1035
 #, c-format
 msgid "GDK surface 0x%p is not registered as a drop target"
 msgstr "سطح GTK 0x%p به عنوان یک مقصد رها کردن ثبت نشده"
 
-#: gdk/win32/gdkdrop-win32.c:1047
+#: gdk/win32/gdkdrop-win32.c:1043
 #, c-format
 msgid "Target context record 0x%p has no data object"
 msgstr "رکورد زمینهٔ مقصد  0x%p هیچ شی داده‌ای ندارد"
 
-#: gdk/win32/gdkdrop-win32.c:1087
+#: gdk/win32/gdkdrop-win32.c:1083
 #, c-format
 msgid "IDataObject_GetData (0x%x) failed, returning 0x%lx"
 msgstr "IDataObject_GetData (0x%x) شکست خورد. 0x%lx را برگرداند"
 
-#: gdk/win32/gdkdrop-win32.c:1121
+#: gdk/win32/gdkdrop-win32.c:1122
 #, c-format
 msgid "Failed to transmute DnD data W32 format 0x%x to %p (%s)"
 msgstr "شکست در تغییر شکل قالب W32 دادهٔ ک‌ور 0x%x به %p (%s)"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:645
+#: gdk/win32/gdkglcontext-win32-wgl.c:668
 msgid "No GL implementation is available"
 msgstr "هیچ پیاده سازی GLای پیدا نشد"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:732
+#: gdk/win32/gdkglcontext-win32-wgl.c:755
 #, c-format
 msgid "WGL version %d.%d is too low, need at least %d.%d"
 msgstr "WGL نگارش %Id. %Id بیش از حد قدیمی است. کمینه به %Id.%Id نیاز است"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:750
+#: gdk/win32/gdkglcontext-win32-wgl.c:773
 #, c-format
 msgid "GL implementation cannot share GL contexts"
 msgstr "پیاده‌سازی GL نمی‌تواند بافتارهای GL را هم‌رساند"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:1030
+#: gdk/win32/gdkglcontext-win32-wgl.c:1053
 msgid "No available configurations for the given pixel format"
 msgstr "هیچ پیکربندی برای قالب نقطه‌ای ارائه شده موجود نیست"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:63
+#: gdk/win32/gdkhdataoutputstream-win32.c:64
 msgid "writing a closed stream"
 msgstr "در حال نوشتن روی جریان بسته‌شده"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:85
+#: gdk/win32/gdkhdataoutputstream-win32.c:86
 msgid "g_try_realloc () failed"
 msgstr "g_try_realloc () شکست خورد"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:93
-#: gdk/win32/gdkhdataoutputstream-win32.c:231
+#: gdk/win32/gdkhdataoutputstream-win32.c:94
+#: gdk/win32/gdkhdataoutputstream-win32.c:233
 msgid "GlobalReAlloc() failed: "
 msgstr "GlobalReAlloc() شکست خورد: "
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:105
+#: gdk/win32/gdkhdataoutputstream-win32.c:106
 msgid "Ran out of buffer space (buffer size is fixed)"
 msgstr "فضای میانگیر تمام شد (اندازهٔ میانگیر ثابت است)"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:203
+#: gdk/win32/gdkhdataoutputstream-win32.c:204
 msgid "Can’t transmute a single handle"
 msgstr "نمی‌نوان یک تک گیره را تغییر شکل داد"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:215
+#: gdk/win32/gdkhdataoutputstream-win32.c:217
 #, c-format
 msgid "Failed to transmute %zu bytes of data from %s to %u"
 msgstr "شکست در تغییر شکل %zu بایت داده از %s به %u"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:250
+#: gdk/win32/gdkhdataoutputstream-win32.c:252
 msgid "GlobalLock() failed: "
 msgstr "GlobalLock() شکست خورد: "
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:364
+#: gdk/win32/gdkhdataoutputstream-win32.c:367
 msgid "GlobalAlloc() failed: "
 msgstr "GlobalAlloc() شکست خورد: "
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:297
+#: gdk/x11/gdkapplaunchcontext-x11.c:299
 #, c-format
 msgid "Starting “%s”"
 msgstr "در حال آغاز %s"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:310
+#: gdk/x11/gdkapplaunchcontext-x11.c:312
 #, c-format
 msgid "Opening “%s”"
 msgstr "درحال گشودن «%s»."
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:315
+#: gdk/x11/gdkapplaunchcontext-x11.c:317
 #, c-format
 msgid "Opening %d Item"
 msgid_plural "Opening %d Items"
 msgstr[0] "گشودن %Id مورد"
 msgstr[1] "گشودن %Id مورد"
 
-#: gdk/x11/gdkclipboard-x11.c:473
+#: gdk/x11/gdkclipboard-x11.c:475
 msgid "Clipboard manager could not store selection."
 msgstr "مدیر تخته‌گیره نتوانست گزینش را ذخیره کند."
 
-#: gdk/x11/gdkclipboard-x11.c:649
+#: gdk/x11/gdkclipboard-x11.c:651
 msgid "Cannot store clipboard. No clipboard manager is active."
 msgstr "نتوانست تخته‌گیره را ذخیره کند. هیچ مدیر تخته‌گیره‌ای فعّال نیست."
 
-#: gdk/x11/gdkglcontext-glx.c:817
+#: gdk/x11/gdkglcontext-glx.c:819
 msgid "No GLX configurations available"
 msgstr "هیچ پیکربندی‌ای برای GLX موجود نیست"
 
-#: gdk/x11/gdkglcontext-glx.c:904
+#: gdk/x11/gdkglcontext-glx.c:906
 msgid "No GLX configuration with required features found"
 msgstr "هیچ پیکربندی‌ای با ویژگی‌های موردنیاز برای GLX موجود نیست"
 
-#: gdk/x11/gdkglcontext-glx.c:978
+#: gdk/x11/gdkglcontext-glx.c:982
 msgid "GLX is not supported"
 msgstr "GLX پشتیبانی نمی‌شود"
 
-#: gdk/x11/gdkselectioninputstream-x11.c:465
+#: gdk/x11/gdkselectioninputstream-x11.c:467
 #, c-format
 msgid "Format %s not supported"
 msgstr "قالب «%s» پشتیبانی نمی‌شود"
 
-#: gdk/x11/gdktextlistconverter-x11.c:65 gdk/x11/gdktextlistconverter-x11.c:105
+#: gdk/x11/gdktextlistconverter-x11.c:67 gdk/x11/gdktextlistconverter-x11.c:107
 msgid "Not enough space in destination"
 msgstr "حافظهٔ ناکافی در مقصد"
 
-#: gdk/x11/gdktextlistconverter-x11.c:91 gdk/x11/gdktextlistconverter-x11.c:195
+#: gdk/x11/gdktextlistconverter-x11.c:93 gdk/x11/gdktextlistconverter-x11.c:197
 msgid "Need complete input to do conversion"
 msgstr "برای تبدیل نیاز به ورودی کامل است"
 
-#: gdk/x11/gdktextlistconverter-x11.c:216 gdk/x11/gdktextlistconverter-x11.c:250
+#: gdk/x11/gdktextlistconverter-x11.c:218 gdk/x11/gdktextlistconverter-x11.c:252
 msgid "Invalid byte sequence in conversion input"
 msgstr "دنبالهٔ بایتی نامعتبر در ورودی تبدیل"
 
-#: gdk/x11/gdktextlistconverter-x11.c:242
+#: gdk/x11/gdktextlistconverter-x11.c:244
 msgid "Invalid formats in compound text conversion."
 msgstr "قالب نامعتبر در تبدیل متن ترکیبی."
 
-#: gdk/x11/gdktextlistconverter-x11.c:259
+#: gdk/x11/gdktextlistconverter-x11.c:261
 #, c-format
 msgid "Unsupported encoding “%s”"
 msgstr "رمزنگاری پشتیبانی‌نشدهٔ %s"
 
-#: gsk/gl/gskglrenderer.c:215
-#, c-format
-msgid "This GLES %d.%d implementation does not support half-float vertex data"
-msgstr "این پشتیبانی EGL %Id.%Id از داده‌های رأس نیم‌شناور پیشتیبانی نمی‌کند"
-
-#: gsk/gpu/gskgldevice.c:252
+#: gsk/gpu/gskgldevice.c:253
 #, c-format
 msgid "OpenGL ES 3.0 is not supported by this renderer."
 msgstr "نگارش ۳٫۰ OpenGL ES از سوی این پرداختگر پشتیبانی نمی‌شود."
 
-#: gsk/gpu/gsknglrenderer.c:68
+#: gsk/gpu/gskglrenderer.c:66
 msgid "OpenGL 3.3 required"
 msgstr "نیازمند OpenGL 3.3"
 
-#: gtk/a11y/gtkatspiaction.c:239
+#: gtk/a11y/gtkatspiaction.c:285
 msgctxt "accessibility"
 msgid "Click"
 msgstr "کلیک"
 
-#: gtk/a11y/gtkatspiaction.c:240
+#: gtk/a11y/gtkatspiaction.c:286
 msgctxt "accessibility"
 msgid "Clicks the button"
 msgstr "زدن دکمه"
 
-#: gtk/a11y/gtkatspiaction.c:290
+#: gtk/a11y/gtkatspiaction.c:336
 msgctxt "accessibility"
 msgid "Toggle"
 msgstr "تغییر وضعیت"
 
-#: gtk/a11y/gtkatspiaction.c:291
+#: gtk/a11y/gtkatspiaction.c:337
 msgctxt "accessibility"
 msgid "Toggles the switch"
 msgstr "تغییر وضعیت کلید"
 
-#: gtk/a11y/gtkatspiaction.c:371
+#: gtk/a11y/gtkatspiaction.c:418
 msgctxt "accessibility"
 msgid "Select"
 msgstr "گزینش"
 
-#: gtk/a11y/gtkatspiaction.c:372
+#: gtk/a11y/gtkatspiaction.c:419
 msgctxt "accessibility"
 msgid "Selects the color"
 msgstr "گزینش رنگ"
 
-#: gtk/a11y/gtkatspiaction.c:379 gtk/a11y/gtkatspiaction.c:439
-#: gtk/a11y/gtkatspiaction.c:495 gtk/a11y/gtkatspiaction.c:603
-#: gtk/a11y/gtkatspiaction.c:690
+#: gtk/a11y/gtkatspiaction.c:426 gtk/a11y/gtkatspiaction.c:487
+#: gtk/a11y/gtkatspiaction.c:543 gtk/a11y/gtkatspiaction.c:651
+#: gtk/a11y/gtkatspiaction.c:738
 msgctxt "accessibility"
 msgid "Activate"
 msgstr "فعّال سازی"
 
-#: gtk/a11y/gtkatspiaction.c:380
+#: gtk/a11y/gtkatspiaction.c:427
 msgctxt "accessibility"
 msgid "Activates the color"
 msgstr "فعّال سازی رنگ"
 
-#: gtk/a11y/gtkatspiaction.c:387
+#: gtk/a11y/gtkatspiaction.c:434
 msgctxt "accessibility"
 msgid "Customize"
 msgstr "سفارشی سازی"
 
-#: gtk/a11y/gtkatspiaction.c:388
+#: gtk/a11y/gtkatspiaction.c:435
 msgctxt "accessibility"
 msgid "Customizes the color"
 msgstr "سفارشی سازی رنگ"
 
-#: gtk/a11y/gtkatspiaction.c:440
+#: gtk/a11y/gtkatspiaction.c:488
 msgctxt "accessibility"
 msgid "Activates the expander"
 msgstr "فعّال سازی گسترنده"
 
-#: gtk/a11y/gtkatspiaction.c:496 gtk/a11y/gtkatspiaction.c:604
-#: gtk/a11y/gtkatspiaction.c:691
+#: gtk/a11y/gtkatspiaction.c:544 gtk/a11y/gtkatspiaction.c:652
+#: gtk/a11y/gtkatspiaction.c:739
 msgctxt "accessibility"
 msgid "Activates the entry"
 msgstr "فعّال سازی ورودی"
 
-#: gtk/a11y/gtkatspiaction.c:503
+#: gtk/a11y/gtkatspiaction.c:551
 msgctxt "accessibility"
 msgid "Activate primary icon"
 msgstr "فعّال سازی نقشک نخستین"
 
-#: gtk/a11y/gtkatspiaction.c:504
+#: gtk/a11y/gtkatspiaction.c:552
 msgctxt "accessibility"
 msgid "Activates the primary icon of the entry"
 msgstr "فعّال سازی نقشک نخستین ورودی"
 
-#: gtk/a11y/gtkatspiaction.c:511
+#: gtk/a11y/gtkatspiaction.c:559
 msgctxt "accessibility"
 msgid "Activate secondary icon"
 msgstr "فعّال سازی نقشک ثانویه"
 
-#: gtk/a11y/gtkatspiaction.c:512
+#: gtk/a11y/gtkatspiaction.c:560
 msgctxt "accessibility"
 msgid "Activates the secondary icon of the entry"
 msgstr "فعّال سازی نقشک ثانویهٔ ورودی"
 
-#: gtk/a11y/gtkatspiaction.c:611
+#: gtk/a11y/gtkatspiaction.c:659
 msgctxt "accessibility"
 msgid "Peek"
 msgstr "نگاه"
 
-#: gtk/a11y/gtkatspiaction.c:612
+#: gtk/a11y/gtkatspiaction.c:660
 msgctxt "accessibility"
 msgid "Shows the contents of the password entry"
 msgstr "نمایش محتوای ورودی گذرواژه"
 
-#: gtk/a11y/gtkatspiaction.c:698
+#: gtk/a11y/gtkatspiaction.c:746
 msgctxt "accessibility"
 msgid "Clear"
 msgstr "پاک سازی"
 
-#: gtk/a11y/gtkatspiaction.c:699
+#: gtk/a11y/gtkatspiaction.c:747
 msgctxt "accessibility"
 msgid "Clears the contents of the entry"
 msgstr "پاک سازی محتوای ورودی"
 
-#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:869
+#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:906
 msgctxt "accessibility"
 msgid "application"
 msgstr "برنامه"
@@ -983,37 +983,37 @@ msgstr "دادهٔ بدریخت: URL"
 msgid "Could not unescape string"
 msgstr "نمی‌توان رشته را ناگریز کرد"
 
-#: gtk/deprecated/gtkappchooserbutton.c:323
+#: gtk/deprecated/gtkappchooserbutton.c:326
 msgid "Other app…"
 msgstr "کارهٔ دیگر…"
 
-#: gtk/deprecated/gtkappchooserdialog.c:215 gtk/deprecated/gtkappchooserdialog.c:266
+#: gtk/deprecated/gtkappchooserdialog.c:218 gtk/deprecated/gtkappchooserdialog.c:269
 msgid "Select Application"
 msgstr "گزینش برنامه"
 
 #. Translators: %s is a filename
-#: gtk/deprecated/gtkappchooserdialog.c:222
+#: gtk/deprecated/gtkappchooserdialog.c:225
 #, c-format
 msgid "Opening “%s”."
 msgstr "درحال گشودن «%s»."
 
-#: gtk/deprecated/gtkappchooserdialog.c:223
+#: gtk/deprecated/gtkappchooserdialog.c:226
 #, c-format
 msgid "No applications found for “%s”"
 msgstr "هیچ برنامه‌ای برای «%s» پیدا نشد"
 
 #. Translators: %s is a file type description
-#: gtk/deprecated/gtkappchooserdialog.c:228
+#: gtk/deprecated/gtkappchooserdialog.c:231
 #, c-format
 msgid "Opening “%s” files."
 msgstr "در حال گشودن پرونده‌های «%s»."
 
-#: gtk/deprecated/gtkappchooserdialog.c:230
+#: gtk/deprecated/gtkappchooserdialog.c:233
 #, c-format
 msgid "No applications found for “%s” files"
 msgstr "هیچ برنامه‌ای برای پرونده‌های «%s» پیدا نشد"
 
-#: gtk/deprecated/gtkappchooserdialog.c:432
+#: gtk/deprecated/gtkappchooserdialog.c:435
 msgid "Failed to start GNOME Software"
 msgstr "شکست در اجرای نرم‌افزارهای گنوم"
 
@@ -1071,52 +1071,52 @@ msgctxt "progress bar label"
 msgid "%d %%"
 msgstr "%Id ٪"
 
-#: gtk/deprecated/gtkcolorbutton.c:183 gtk/deprecated/gtkcolorbutton.c:314
+#: gtk/deprecated/gtkcolorbutton.c:186 gtk/deprecated/gtkcolorbutton.c:317
 #: gtk/gtkcolordialog.c:409
 msgid "Pick a Color"
 msgstr "یک رنگ بردارید"
 
-#: gtk/deprecated/gtkcolorbutton.c:505 gtk/gtkcolorchooserwidget.c:321
-#: gtk/gtkcolordialogbutton.c:335
+#: gtk/deprecated/gtkcolorbutton.c:508 gtk/gtkcolorchooserwidget.c:321
+#: gtk/gtkcolordialogbutton.c:337
 #, c-format
 msgid "Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"
 msgstr "قرمز ٪%Id، سبز ٪%Id، آبی ٪%Id، آلفا ٪%Id"
 
-#: gtk/deprecated/gtkcolorbutton.c:511 gtk/gtkcolorchooserwidget.c:327
-#: gtk/gtkcolordialogbutton.c:341
+#: gtk/deprecated/gtkcolorbutton.c:514 gtk/gtkcolorchooserwidget.c:327
+#: gtk/gtkcolordialogbutton.c:343
 #, c-format
 msgid "Red %d%%, Green %d%%, Blue %d%%"
 msgstr "قرمز ٪%Id، سبز ٪%Id، آبی ٪%Id"
 
-#: gtk/deprecated/gtkfontbutton.c:396
+#: gtk/deprecated/gtkfontbutton.c:399
 msgid "Sans 12"
 msgstr "Sans 12"
 
-#: gtk/deprecated/gtkfontbutton.c:507 gtk/deprecated/gtkfontbutton.c:624
-#: gtk/gtkfontdialog.c:594
+#: gtk/deprecated/gtkfontbutton.c:510 gtk/deprecated/gtkfontbutton.c:627
+#: gtk/gtkfontdialog.c:590
 msgid "Pick a Font"
 msgstr "یک قلم بردارید"
 
-#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3847
-#: gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:285
+#: gtk/deprecated/gtkfontbutton.c:603 gtk/gtkfilechooserwidget.c:3818
+#: gtk/gtkfontdialogbutton.c:128 gtk/inspector/visual.ui:284
 msgid "Font"
 msgstr "قلم"
 
 # farmaan
-#: gtk/deprecated/gtkfontbutton.c:1155 gtk/gtkfontdialogbutton.c:652
+#: gtk/deprecated/gtkfontbutton.c:1158 gtk/gtkfontdialogbutton.c:657
 msgctxt "font"
 msgid "None"
 msgstr "هیچ‌کدام"
 
-#: gtk/deprecated/gtklockbutton.c:294 gtk/ui/gtklockbutton.ui:20
+#: gtk/deprecated/gtklockbutton.c:306 gtk/ui/gtklockbutton.ui:20
 msgid "Lock"
 msgstr "قفل"
 
-#: gtk/deprecated/gtklockbutton.c:308 gtk/ui/gtklockbutton.ui:26
+#: gtk/deprecated/gtklockbutton.c:320 gtk/ui/gtklockbutton.ui:26
 msgid "Unlock"
 msgstr "قفل‌گشایی"
 
-#: gtk/deprecated/gtklockbutton.c:322
+#: gtk/deprecated/gtklockbutton.c:334
 msgid ""
 "Dialog is unlocked.\n"
 "Click to prevent further changes"
@@ -1124,7 +1124,7 @@ msgstr ""
 "محاوره باز شده است.\n"
 "جهت جلوگیری از تغییرات آتی کلیک کنید"
 
-#: gtk/deprecated/gtklockbutton.c:336
+#: gtk/deprecated/gtklockbutton.c:348
 msgid ""
 "Dialog is locked.\n"
 "Click to make changes"
@@ -1132,7 +1132,7 @@ msgstr ""
 "محاوره قفل شده است.\n"
 "جهت ایجاد تغییرات کلیک کنید"
 
-#: gtk/deprecated/gtklockbutton.c:350
+#: gtk/deprecated/gtklockbutton.c:362
 msgid ""
 "System policy prevents changes.\n"
 "Contact your system administrator"
@@ -1140,15 +1140,15 @@ msgstr ""
 "سیاست‌های سیستم از تغییرات جلوگیری می‌کند.\n"
 "با مدیر سیستم خود تماس بگیرید"
 
-#: gtk/deprecated/gtkshow.c:217
+#: gtk/deprecated/gtkshow.c:291
 msgid "Could not show link"
 msgstr "نتوانست پیوند را نشان دهد"
 
-#: gtk/deprecated/gtkvolumebutton.c:236
+#: gtk/deprecated/gtkvolumebutton.c:239
 msgid "Muted"
 msgstr "بی‌صدا"
 
-#: gtk/deprecated/gtkvolumebutton.c:240
+#: gtk/deprecated/gtkvolumebutton.c:243
 msgid "Full Volume"
 msgstr "نهایت صدا"
 
@@ -1157,117 +1157,117 @@ msgstr "نهایت صدا"
 #. * Translate the "%d" to "%Id" if you want to use localised digits,
 #. * or otherwise translate the "%d" to "%d".
 #.
-#: gtk/deprecated/gtkvolumebutton.c:253
+#: gtk/deprecated/gtkvolumebutton.c:256
 #, c-format
 msgctxt "volume percentage"
 msgid "%d %%"
 msgstr "%Id ٪"
 
-#: gtk/gtkaboutdialog.c:125 gtk/ui/gtkaboutdialog.ui:173
+#: gtk/gtkaboutdialog.c:127 gtk/ui/gtkaboutdialog.ui:173
 msgid "License"
 msgstr "پروانه"
 
-#: gtk/gtkaboutdialog.c:126
+#: gtk/gtkaboutdialog.c:128
 msgid "Custom License"
 msgstr "پروانهٔ سفارشی"
 
-#: gtk/gtkaboutdialog.c:127
+#: gtk/gtkaboutdialog.c:129
 msgid "GNU General Public License, version 2 or later"
 msgstr "نگارش ۲ یا بالاتر پروانهٔ جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:128
+#: gtk/gtkaboutdialog.c:130
 msgid "GNU General Public License, version 3 or later"
 msgstr "نگارش ۳ یا بالاتر پروانهٔ جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:129
+#: gtk/gtkaboutdialog.c:131
 msgid "GNU Lesser General Public License, version 2.1 or later"
 msgstr "نگارش ۲٫۱ یا بالاتر پروانهٔ کم‌تر جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:130
+#: gtk/gtkaboutdialog.c:132
 msgid "GNU Lesser General Public License, version 3 or later"
 msgstr "نگارش ۳ یا بالاتر پروانهٔ کم‌تر جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:131
+#: gtk/gtkaboutdialog.c:133
 msgid "BSD 2-Clause License"
 msgstr "پروانهٔ دو بندی BSD"
 
-#: gtk/gtkaboutdialog.c:132
+#: gtk/gtkaboutdialog.c:134
 msgid "The MIT License (MIT)"
 msgstr "پروانهٔ MIT"
 
-#: gtk/gtkaboutdialog.c:133
+#: gtk/gtkaboutdialog.c:135
 msgid "Artistic License 2.0"
 msgstr "پروانهٔ Artistic 2.0"
 
-#: gtk/gtkaboutdialog.c:134
+#: gtk/gtkaboutdialog.c:136
 msgid "GNU General Public License, version 2 only"
 msgstr "فقط نگارش ۲ پروانهٔ جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:135
+#: gtk/gtkaboutdialog.c:137
 msgid "GNU General Public License, version 3 only"
 msgstr "فقط نگارش ۳ پروانهٔ جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:136
+#: gtk/gtkaboutdialog.c:138
 msgid "GNU Lesser General Public License, version 2.1 only"
 msgstr "فقط نگارش ۲٫۱ پروانهٔ کم‌تر جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:137
+#: gtk/gtkaboutdialog.c:139
 msgid "GNU Lesser General Public License, version 3 only"
 msgstr "فقط نگارش ۳ پروانهٔ کم‌تر جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:138
+#: gtk/gtkaboutdialog.c:140
 msgid "GNU Affero General Public License, version 3 or later"
 msgstr "نگارش ۳ یا بالاتر پروانهٔ Affero جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:139
+#: gtk/gtkaboutdialog.c:141
 msgid "GNU Affero General Public License, version 3 only"
 msgstr "فقط نگارش ۳ پروانهٔ Affero جامع همگانی گنو"
 
-#: gtk/gtkaboutdialog.c:140
+#: gtk/gtkaboutdialog.c:142
 msgid "BSD 3-Clause License"
 msgstr "پروانهٔ سه‌بندی BSD"
 
-#: gtk/gtkaboutdialog.c:141
+#: gtk/gtkaboutdialog.c:143
 msgid "Apache License, Version 2.0"
 msgstr "نگارش ۲٫۰ پروانهٔ آپاچی"
 
-#: gtk/gtkaboutdialog.c:142
+#: gtk/gtkaboutdialog.c:144
 msgid "Mozilla Public License 2.0"
 msgstr "پروانهٔ عمومی موزیلا ۲٫۰"
 
-#: gtk/gtkaboutdialog.c:143
+#: gtk/gtkaboutdialog.c:145
 msgid "BSD Zero-Clause License"
 msgstr "پروانهٔ بی‌بند BSD"
 
-#: gtk/gtkaboutdialog.c:1028
+#: gtk/gtkaboutdialog.c:1029
 msgid "Website"
 msgstr "پایگاه وب"
 
-#: gtk/gtkaboutdialog.c:1064 gtk/ui/gtkapplication-quartz.ui:6
+#: gtk/gtkaboutdialog.c:1071 gtk/ui/gtkapplication-quartz.ui:6
 #, c-format
 msgid "About %s"
 msgstr "دربارهٔ %s"
 
-#: gtk/gtkaboutdialog.c:2158
+#: gtk/gtkaboutdialog.c:2165
 msgid "Created by"
 msgstr "ایجاد شده به دست"
 
-#: gtk/gtkaboutdialog.c:2161
+#: gtk/gtkaboutdialog.c:2168
 msgid "Documented by"
 msgstr "مستند شده به دست"
 
-#: gtk/gtkaboutdialog.c:2171
+#: gtk/gtkaboutdialog.c:2178
 msgid "Translated by"
 msgstr "بازگردانی به دست"
 
-#: gtk/gtkaboutdialog.c:2176
+#: gtk/gtkaboutdialog.c:2183
 msgid "Design by"
 msgstr "طرّاحی به دست"
 
 #. Translators: this is the license preamble; the string at the end
 #. * contains the name of the license as link text.
 #.
-#: gtk/gtkaboutdialog.c:2341
+#: gtk/gtkaboutdialog.c:2348
 #, c-format
 msgid ""
 "This program comes with absolutely no warranty.\n"
@@ -1281,7 +1281,8 @@ msgstr ""
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:839 gtk/gtkshortcutlabel.c:101 gtk/gtkshortcutlabel.c:137
+#: gtk/gtkaccelgroup.c:839 gtk/deprecated/gtkshortcutlabel.c:103
+#: gtk/deprecated/gtkshortcutlabel.c:139
 msgctxt "keyboard label"
 msgid "Shift"
 msgstr "تبدیل"
@@ -1291,7 +1292,8 @@ msgstr "تبدیل"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:858 gtk/gtkshortcutlabel.c:104 gtk/gtkshortcutlabel.c:139
+#: gtk/gtkaccelgroup.c:858 gtk/deprecated/gtkshortcutlabel.c:106
+#: gtk/deprecated/gtkshortcutlabel.c:141
 msgctxt "keyboard label"
 msgid "Ctrl"
 msgstr "مهار"
@@ -1301,7 +1303,8 @@ msgstr "مهار"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:877 gtk/gtkshortcutlabel.c:107 gtk/gtkshortcutlabel.c:141
+#: gtk/gtkaccelgroup.c:877 gtk/deprecated/gtkshortcutlabel.c:109
+#: gtk/deprecated/gtkshortcutlabel.c:143
 msgctxt "keyboard label"
 msgid "Alt"
 msgstr "دگرساز"
@@ -1311,7 +1314,8 @@ msgstr "دگرساز"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:895 gtk/gtkshortcutlabel.c:113 gtk/gtkshortcutlabel.c:143
+#: gtk/gtkaccelgroup.c:895 gtk/deprecated/gtkshortcutlabel.c:115
+#: gtk/deprecated/gtkshortcutlabel.c:145
 msgctxt "keyboard label"
 msgid "Super"
 msgstr "سوپر"
@@ -1321,7 +1325,8 @@ msgstr "سوپر"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:909 gtk/gtkshortcutlabel.c:116 gtk/gtkshortcutlabel.c:145
+#: gtk/gtkaccelgroup.c:909 gtk/deprecated/gtkshortcutlabel.c:118
+#: gtk/deprecated/gtkshortcutlabel.c:147
 msgctxt "keyboard label"
 msgid "Hyper"
 msgstr "فوق"
@@ -1331,7 +1336,8 @@ msgstr "فوق"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:924 gtk/gtkshortcutlabel.c:110 gtk/gtkshortcutlabel.c:148
+#: gtk/gtkaccelgroup.c:924 gtk/deprecated/gtkshortcutlabel.c:112
+#: gtk/deprecated/gtkshortcutlabel.c:150
 msgctxt "keyboard label"
 msgid "Meta"
 msgstr "فرا"
@@ -1350,433 +1356,433 @@ msgctxt "keyboard label"
 msgid "Space"
 msgstr "فاصله"
 
-#: gtk/gtkaccelgroup.c:954 gtk/gtkshortcutlabel.c:176
+#: gtk/gtkaccelgroup.c:954 gtk/deprecated/gtkshortcutlabel.c:178
 msgctxt "keyboard label"
 msgid "Backslash"
 msgstr "ممیز وارونه"
 
-#: gtk/gtkaccessible.c:790
+#: gtk/gtkaccessible.c:827
 msgctxt "accessibility"
 msgid "alert"
 msgstr "هشدار"
 
-#: gtk/gtkaccessible.c:791
+#: gtk/gtkaccessible.c:828
 msgctxt "accessibility"
 msgid "alert dialog"
 msgstr "گفت‌وگوی هشدار"
 
-#: gtk/gtkaccessible.c:792
+#: gtk/gtkaccessible.c:829
 msgctxt "accessibility"
 msgid "banner"
 msgstr "بیرق"
 
-#: gtk/gtkaccessible.c:793
+#: gtk/gtkaccessible.c:830
 msgctxt "accessibility"
 msgid "button"
 msgstr "دکمه"
 
-#: gtk/gtkaccessible.c:794
+#: gtk/gtkaccessible.c:831
 msgctxt "accessibility"
 msgid "caption"
 msgstr "عنوان"
 
-#: gtk/gtkaccessible.c:795
+#: gtk/gtkaccessible.c:832
 msgctxt "accessibility"
 msgid "cell"
 msgstr "سلول"
 
-#: gtk/gtkaccessible.c:796
+#: gtk/gtkaccessible.c:833
 msgctxt "accessibility"
 msgid "checkbox"
 msgstr "جعبهٔ تیکی"
 
-#: gtk/gtkaccessible.c:797
+#: gtk/gtkaccessible.c:834
 msgctxt "accessibility"
 msgid "column header"
 msgstr "سرایند ستون"
 
-#: gtk/gtkaccessible.c:798
+#: gtk/gtkaccessible.c:835
 msgctxt "accessibility"
 msgid "combo box"
 msgstr "جعبهٔ بازشونده"
 
-#: gtk/gtkaccessible.c:799
+#: gtk/gtkaccessible.c:836
 msgctxt "accessibility"
 msgid "command"
 msgstr "فرمان"
 
-#: gtk/gtkaccessible.c:800
+#: gtk/gtkaccessible.c:837
 msgctxt "accessibility"
 msgid "composite"
 msgstr "مرکب"
 
-#: gtk/gtkaccessible.c:801
+#: gtk/gtkaccessible.c:838
 msgctxt "accessibility"
 msgid "dialog"
 msgstr "گفت‌وگو"
 
-#: gtk/gtkaccessible.c:802
+#: gtk/gtkaccessible.c:839
 msgctxt "accessibility"
 msgid "document"
 msgstr "سند"
 
-#: gtk/gtkaccessible.c:803
+#: gtk/gtkaccessible.c:840
 msgctxt "accessibility"
 msgid "feed"
 msgstr "خوراک"
 
-#: gtk/gtkaccessible.c:804
+#: gtk/gtkaccessible.c:841
 msgctxt "accessibility"
 msgid "form"
 msgstr "از"
 
-#: gtk/gtkaccessible.c:805
+#: gtk/gtkaccessible.c:842
 msgctxt "accessibility"
 msgid "generic"
 msgstr "عمومی"
 
-#: gtk/gtkaccessible.c:806
+#: gtk/gtkaccessible.c:843
 msgctxt "accessibility"
 msgid "grid"
 msgstr "شبکه"
 
-#: gtk/gtkaccessible.c:807
+#: gtk/gtkaccessible.c:844
 msgctxt "accessibility"
 msgid "grid cell"
 msgstr "سلول شبکه"
 
-#: gtk/gtkaccessible.c:808
+#: gtk/gtkaccessible.c:845
 msgctxt "accessibility"
 msgid "group"
 msgstr "گروه"
 
-#: gtk/gtkaccessible.c:809
+#: gtk/gtkaccessible.c:846
 msgctxt "accessibility"
 msgid "heading"
 msgstr "سرایند"
 
-#: gtk/gtkaccessible.c:810
+#: gtk/gtkaccessible.c:847
 msgctxt "accessibility"
 msgid "image"
 msgstr "تصویر"
 
-#: gtk/gtkaccessible.c:811
+#: gtk/gtkaccessible.c:848
 msgctxt "accessibility"
 msgid "input"
 msgstr "ورودی"
 
-#: gtk/gtkaccessible.c:812
+#: gtk/gtkaccessible.c:849
 msgctxt "accessibility"
 msgid "label"
 msgstr "برچسب"
 
-#: gtk/gtkaccessible.c:813
+#: gtk/gtkaccessible.c:850
 msgctxt "accessibility"
 msgid "landmark"
 msgstr "نشانه"
 
-#: gtk/gtkaccessible.c:814
+#: gtk/gtkaccessible.c:851
 msgctxt "accessibility"
 msgid "legend"
 msgstr "راهنما"
 
-#: gtk/gtkaccessible.c:815
+#: gtk/gtkaccessible.c:852
 msgctxt "accessibility"
 msgid "link"
 msgstr "پیوند"
 
-#: gtk/gtkaccessible.c:816
+#: gtk/gtkaccessible.c:853
 msgctxt "accessibility"
 msgid "list"
 msgstr "فهرست"
 
-#: gtk/gtkaccessible.c:817
+#: gtk/gtkaccessible.c:854
 msgctxt "accessibility"
 msgid "list box"
 msgstr "جعبهٔ فهرست"
 
-#: gtk/gtkaccessible.c:818
+#: gtk/gtkaccessible.c:855
 msgctxt "accessibility"
 msgid "list item"
 msgstr "مورد فرست"
 
-#: gtk/gtkaccessible.c:819
+#: gtk/gtkaccessible.c:856
 msgctxt "accessibility"
 msgid "log"
 msgstr "گزارش"
 
-#: gtk/gtkaccessible.c:820
+#: gtk/gtkaccessible.c:857
 msgctxt "accessibility"
 msgid "main"
 msgstr "اصلی"
 
-#: gtk/gtkaccessible.c:821
+#: gtk/gtkaccessible.c:858
 msgctxt "accessibility"
 msgid "marquee"
 msgstr "چادر"
 
-#: gtk/gtkaccessible.c:822
+#: gtk/gtkaccessible.c:859
 msgctxt "accessibility"
 msgid "math"
 msgstr "ریاضی"
 
-#: gtk/gtkaccessible.c:823
+#: gtk/gtkaccessible.c:860
 msgctxt "accessibility"
 msgid "meter"
 msgstr "متر"
 
-#: gtk/gtkaccessible.c:824
+#: gtk/gtkaccessible.c:861
 msgctxt "accessibility"
 msgid "menu"
 msgstr "فهرست"
 
-#: gtk/gtkaccessible.c:825
+#: gtk/gtkaccessible.c:862
 msgctxt "accessibility"
 msgid "menu bar"
 msgstr "نوار فهرست"
 
-#: gtk/gtkaccessible.c:826
+#: gtk/gtkaccessible.c:863
 msgctxt "accessibility"
 msgid "menu item"
 msgstr "مورد فرست"
 
-#: gtk/gtkaccessible.c:827
+#: gtk/gtkaccessible.c:864
 msgctxt "accessibility"
 msgid "menu item checkbox"
 msgstr "مورد فهرست جعبه تیکی"
 
-#: gtk/gtkaccessible.c:828
+#: gtk/gtkaccessible.c:865
 msgctxt "accessibility"
 msgid "menu item radio"
 msgstr "مورد فهرست رادیویی"
 
-#: gtk/gtkaccessible.c:829
+#: gtk/gtkaccessible.c:866
 msgctxt "accessibility"
 msgid "navigation"
 msgstr "ناوبری"
 
-#: gtk/gtkaccessible.c:830
+#: gtk/gtkaccessible.c:867
 msgctxt "accessibility"
 msgid "none"
 msgstr "هیچ"
 
-#: gtk/gtkaccessible.c:831
+#: gtk/gtkaccessible.c:868
 msgctxt "accessibility"
 msgid "note"
 msgstr "یاداشت"
 
-#: gtk/gtkaccessible.c:832
+#: gtk/gtkaccessible.c:869
 msgctxt "accessibility"
 msgid "option"
 msgstr "گزینه"
 
-#: gtk/gtkaccessible.c:833
+#: gtk/gtkaccessible.c:870
 msgctxt "accessibility"
 msgid "presentation"
 msgstr "ارائه"
 
-#: gtk/gtkaccessible.c:834
+#: gtk/gtkaccessible.c:871
 msgctxt "accessibility"
 msgid "progress bar"
 msgstr "نوار پیشرفت"
 
-#: gtk/gtkaccessible.c:835
+#: gtk/gtkaccessible.c:872
 msgctxt "accessibility"
 msgid "radio"
 msgstr "رادیویی"
 
-#: gtk/gtkaccessible.c:836
+#: gtk/gtkaccessible.c:873
 msgctxt "accessibility"
 msgid "radio group"
 msgstr "گروه رادیویی"
 
-#: gtk/gtkaccessible.c:837
+#: gtk/gtkaccessible.c:874
 msgctxt "accessibility"
 msgid "range"
 msgstr "دامنه"
 
-#: gtk/gtkaccessible.c:838
+#: gtk/gtkaccessible.c:875
 msgctxt "accessibility"
 msgid "region"
 msgstr "ناحیه"
 
-#: gtk/gtkaccessible.c:839
+#: gtk/gtkaccessible.c:876
 msgctxt "accessibility"
 msgid "row"
 msgstr "ردیف"
 
-#: gtk/gtkaccessible.c:840
+#: gtk/gtkaccessible.c:877
 msgctxt "accessibility"
 msgid "row group"
 msgstr "گروه ردیف"
 
-#: gtk/gtkaccessible.c:841
+#: gtk/gtkaccessible.c:878
 msgctxt "accessibility"
 msgid "row header"
 msgstr "سرایند ردیف"
 
-#: gtk/gtkaccessible.c:842
+#: gtk/gtkaccessible.c:879
 msgctxt "accessibility"
 msgid "scroll bar"
 msgstr "نوار لغزش"
 
-#: gtk/gtkaccessible.c:843
+#: gtk/gtkaccessible.c:880
 msgctxt "accessibility"
 msgid "search"
 msgstr "جست‌وجو"
 
-#: gtk/gtkaccessible.c:844
+#: gtk/gtkaccessible.c:881
 msgctxt "accessibility"
 msgid "search box"
 msgstr "جعبهٔ جست‌وجو"
 
-#: gtk/gtkaccessible.c:845
+#: gtk/gtkaccessible.c:882
 msgctxt "accessibility"
 msgid "section"
 msgstr "بخش"
 
-#: gtk/gtkaccessible.c:846
+#: gtk/gtkaccessible.c:883
 msgctxt "accessibility"
 msgid "section head"
 msgstr "سر بخش"
 
-#: gtk/gtkaccessible.c:847
+#: gtk/gtkaccessible.c:884
 msgctxt "accessibility"
 msgid "select"
 msgstr "گزینش"
 
-#: gtk/gtkaccessible.c:848
+#: gtk/gtkaccessible.c:885
 msgctxt "accessibility"
 msgid "separator"
 msgstr "جداساز"
 
-#: gtk/gtkaccessible.c:849
+#: gtk/gtkaccessible.c:886
 msgctxt "accessibility"
 msgid "slider"
 msgstr "سرنده"
 
-#: gtk/gtkaccessible.c:850
+#: gtk/gtkaccessible.c:887
 msgctxt "accessibility"
 msgid "spin button"
 msgstr "دکمهٔ مقداری"
 
-#: gtk/gtkaccessible.c:851
+#: gtk/gtkaccessible.c:888
 msgctxt "accessibility"
 msgid "status"
 msgstr "وضعیت"
 
-#: gtk/gtkaccessible.c:852
+#: gtk/gtkaccessible.c:889
 msgctxt "accessibility"
 msgid "structure"
 msgstr "ساختار"
 
-#: gtk/gtkaccessible.c:853
+#: gtk/gtkaccessible.c:890
 msgctxt "accessibility"
 msgid "switch"
 msgstr "کلید"
 
-#: gtk/gtkaccessible.c:854
+#: gtk/gtkaccessible.c:891
 msgctxt "accessibility"
 msgid "tab"
 msgstr "زبانه"
 
-#: gtk/gtkaccessible.c:855
+#: gtk/gtkaccessible.c:892
 msgctxt "accessibility"
 msgid "table"
 msgstr "جدول"
 
-#: gtk/gtkaccessible.c:856
+#: gtk/gtkaccessible.c:893
 msgctxt "accessibility"
 msgid "tab list"
 msgstr "فهرست زبانه"
 
-#: gtk/gtkaccessible.c:857
+#: gtk/gtkaccessible.c:894
 msgctxt "accessibility"
 msgid "tab panel"
 msgstr "تابلوی زبانه"
 
-#: gtk/gtkaccessible.c:858
+#: gtk/gtkaccessible.c:895
 msgctxt "accessibility"
 msgid "text box"
 msgstr "جعبهٔ متنی"
 
-#: gtk/gtkaccessible.c:859
+#: gtk/gtkaccessible.c:896
 msgctxt "accessibility"
 msgid "time"
 msgstr "زمان"
 
-#: gtk/gtkaccessible.c:860
+#: gtk/gtkaccessible.c:897
 msgctxt "accessibility"
 msgid "timer"
 msgstr "زمان‌سنج"
 
-#: gtk/gtkaccessible.c:861
+#: gtk/gtkaccessible.c:898
 msgctxt "accessibility"
 msgid "tool bar"
 msgstr "نوار ابزار"
 
-#: gtk/gtkaccessible.c:862
+#: gtk/gtkaccessible.c:899
 msgctxt "accessibility"
 msgid "tool tip"
 msgstr "راهنمای ابزار"
 
-#: gtk/gtkaccessible.c:863
+#: gtk/gtkaccessible.c:900
 msgctxt "accessibility"
 msgid "tree"
 msgstr "درخت"
 
-#: gtk/gtkaccessible.c:864
+#: gtk/gtkaccessible.c:901
 msgctxt "accessibility"
 msgid "tree grid"
 msgstr "شبکهٔ درختی"
 
-#: gtk/gtkaccessible.c:865
+#: gtk/gtkaccessible.c:902
 msgctxt "accessibility"
 msgid "tree item"
 msgstr "مورد درخت"
 
-#: gtk/gtkaccessible.c:866
+#: gtk/gtkaccessible.c:903
 msgctxt "accessibility"
 msgid "widget"
 msgstr "ابزارک"
 
-#: gtk/gtkaccessible.c:867
+#: gtk/gtkaccessible.c:904
 msgctxt "accessibility"
 msgid "window"
 msgstr "پنجره"
 
-#: gtk/gtkaccessible.c:868
+#: gtk/gtkaccessible.c:905
 msgctxt "accessibility"
 msgid "toggle button"
 msgstr "دکمهٔ تغییر وضعیت"
 
-#: gtk/gtkaccessible.c:870
+#: gtk/gtkaccessible.c:907
 msgctxt "accessibility"
 msgid "paragraph"
 msgstr "بند"
 
-#: gtk/gtkaccessible.c:871
+#: gtk/gtkaccessible.c:908
 msgctxt "accessibility"
 msgid "block quote"
 msgstr "نقل‌قول مستقیم"
 
-#: gtk/gtkaccessible.c:872
+#: gtk/gtkaccessible.c:909
 msgctxt "accessibility"
 msgid "article"
 msgstr "حرف تعریف"
 
-#: gtk/gtkaccessible.c:873
+#: gtk/gtkaccessible.c:910
 msgctxt "accessibility"
 msgid "comment"
 msgstr "نظر"
 
-#: gtk/gtkaccessible.c:874
+#: gtk/gtkaccessible.c:911
 msgctxt "accessibility"
 msgid "terminal"
 msgstr "پایانه"
 
-#: gtk/gtkalertdialog.c:667 gtk/print/gtkcustompaperunixdialog.c:322
-#: gtk/gtkmessagedialog.c:166 gtk/ui/gtkassistant.ui:40
+#: gtk/gtkalertdialog.c:666 gtk/print/gtkcustompaperunixdialog.c:322
+#: gtk/gtkmessagedialog.c:169 gtk/ui/gtkassistant.ui:40
 msgid "_Close"
 msgstr "_بستن"
 
@@ -1784,11 +1790,11 @@ msgstr "_بستن"
 #. * suspend or screen locking, and the caller hasn't specified
 #. * a reason.
 #.
-#: gtk/gtkapplication-dbus.c:721 gtk/gtkapplication-dbus.c:763
+#: gtk/gtkapplication-dbus.c:728 gtk/gtkapplication-dbus.c:770
 msgid "Reason not specified"
 msgstr "دلیل مشخّص نشده"
 
-#: gtk/gtkapplicationwindow.c:236
+#: gtk/gtkapplicationwindow.c:234
 msgid "Menu bar"
 msgstr "نوار فهرست"
 
@@ -1802,17 +1808,17 @@ msgstr "‏«%s» در فهرست نشانک‌ها موجود نیست"
 msgid "%s already exists in the bookmarks list"
 msgstr "‏«%s» از قبل در فهرست نشانک‌ها موجود است"
 
-#: gtk/gtkbuilder-menus.c:224
+#: gtk/gtkbuilder-menus.c:225
 #, c-format
 msgid "Element <%s> not allowed inside <%s>"
 msgstr "عنصر <%s> درون <%s> مجاز نیست"
 
-#: gtk/gtkbuilder-menus.c:230
+#: gtk/gtkbuilder-menus.c:231
 #, c-format
 msgid "Element <%s> not allowed at toplevel"
 msgstr "عنصر <%s> به عنوان سطح بالا (toplevel) مجاز نیست"
 
-#: gtk/gtkbuilder-menus.c:319
+#: gtk/gtkbuilder-menus.c:320
 #, c-format
 msgid "Text may not appear inside <%s>"
 msgstr "متن ممکن است درون «%s» نمایان نشود"
@@ -1821,7 +1827,7 @@ msgstr "متن ممکن است درون «%s» نمایان نشود"
 #. * first day of the week to calendar:week_start:1 if you want Monday
 #. * to be the first day of the week, and so on.
 #.
-#: gtk/gtkcalendar.c:670
+#: gtk/gtkcalendar.c:672
 msgid "calendar:week_start:0"
 msgstr "calendar:week_start:6"
 
@@ -1835,7 +1841,7 @@ msgstr "calendar:week_start:6"
 #. * text direction of RTL and specify "calendar:YM", then the year
 #. * will appear to the right of the month.
 #.
-#: gtk/gtkcalendar.c:821
+#: gtk/gtkcalendar.c:823
 msgid "calendar:MY"
 msgstr "calendar:YM"
 
@@ -1849,7 +1855,7 @@ msgstr "calendar:YM"
 #. * digits. That needs support from your system and locale definition
 #. * too.
 #.
-#: gtk/gtkcalendar.c:1002
+#: gtk/gtkcalendar.c:1004
 #, c-format
 msgctxt "calendar:day:digits"
 msgid "%d"
@@ -1861,7 +1867,7 @@ msgstr "%Id"
 #. *
 #. * "%Y" is appropriate for most locales.
 #.
-#: gtk/gtkcalendar.c:1106
+#: gtk/gtkcalendar.c:1108
 msgctxt "calendar year format"
 msgid "%Y"
 msgstr "%Y"
@@ -1874,7 +1880,7 @@ msgstr "%Y"
 #. * Note that translating this doesn't guarantee that you get localized
 #. * digits. That needs support from your system and locale definition
 #. * too.
-#: gtk/gtkcalendar.c:1152
+#: gtk/gtkcalendar.c:1154
 #, c-format
 msgctxt "calendar:week:digits"
 msgid "%d"
@@ -2143,15 +2149,15 @@ msgid "Margins from Printer…"
 msgstr "حاشیه‌ها از چاپگر…"
 
 #. And show the custom paper dialog
-#: gtk/print/gtkcustompaperunixdialog.c:377 gtk/print/gtkprintunixdialog.c:2975
+#: gtk/print/gtkcustompaperunixdialog.c:377 gtk/print/gtkprintunixdialog.c:2952
 msgid "Manage Custom Sizes"
 msgstr "مدیریت اندازه‌های سفارشی"
 
-#: gtk/print/gtkcustompaperunixdialog.c:440 gtk/print/gtkpagesetupunixdialog.c:720
+#: gtk/print/gtkcustompaperunixdialog.c:440 gtk/print/gtkpagesetupunixdialog.c:723
 msgid "inch"
 msgstr "اینچ"
 
-#: gtk/print/gtkcustompaperunixdialog.c:442 gtk/print/gtkpagesetupunixdialog.c:718
+#: gtk/print/gtkcustompaperunixdialog.c:442 gtk/print/gtkpagesetupunixdialog.c:721
 msgid "mm"
 msgstr "میلی‌متر"
 
@@ -2192,11 +2198,29 @@ msgstr "_راست:"
 msgid "Paper Margins"
 msgstr "حاشیه‌های کاغذ"
 
-#: gtk/gtkentry.c:3685
+#: gtk/gtkeditablelabel.c:170 gtk/ui/gtkapplication-quartz.ui:50
+msgid "_Edit"
+msgstr "_ویرایش"
+
+#: gtk/gtkeditablelabel.c:171 gtk/gtklabel.c:5898 gtk/gtktext.c:6322
+#: gtk/gtktextview.c:9326
+msgid "_Copy"
+msgstr "_رونوشت"
+
+#: gtk/gtkeditablelabel.c:344 gtk/gtklabel.c:5958 gtk/gtktext.c:2877
+#: gtk/gtktextview.c:9404
+msgid "Context menu"
+msgstr "فهرست بافتاری"
+
+#: gtk/gtkentry.c:3687
 msgid "Insert Emoji"
 msgstr "درج ایموجی"
 
-#: gtk/gtkfilechooserdialog.c:557
+#: gtk/gtkfilechooserdialog.c:481
+msgid "Search"
+msgstr "جست‌وجو"
+
+#: gtk/gtkfilechooserdialog.c:562
 msgid "_Name"
 msgstr "_نام"
 
@@ -2256,27 +2280,32 @@ msgstr "یک پوشه با همان نام در حال حاضر وجود دار
 msgid "A file with that name already exists"
 msgstr "یک پرونده با همان نام در حال حاضر وجود دارد"
 
-#: gtk/gtkfilechoosernative.c:520 gtk/gtkfilechoosernative.c:600
-#: gtk/gtkfilechooserwidget.c:1213 gtk/gtkfilechooserwidget.c:5017
-#: gtk/gtkfiledialog.c:840 gtk/gtkmessagedialog.c:170 gtk/gtkmessagedialog.c:179
-#: gtk/gtkmountoperation.c:608 gtk/print/gtkpagesetupunixdialog.c:282
-#: gtk/print/gtkprintbackend.c:638 gtk/print/gtkprintunixdialog.c:682
-#: gtk/print/gtkprintunixdialog.c:839 gtk/gtkwindow.c:6211
+#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:4988
+#: gtk/gtkfiledialog.c:913 gtk/gtkmessagedialog.c:173 gtk/gtkmessagedialog.c:182
+#: gtk/gtkmountoperation.c:608 gtk/print/gtkpagesetupunixdialog.c:285
+#: gtk/print/gtkprintbackend.c:638 gtk/print/gtkprintunixdialog.c:683
+#: gtk/print/gtkprintunixdialog.c:840 gtk/gtkwindow.c:6330
 #: gtk/ui/gtkappchooserdialog.ui:48 gtk/ui/gtkassistant.ui:52
-#: gtk/ui/gtkcolorchooserdialog.ui:36 gtk/ui/gtkfontchooserdialog.ui:27
+#: gtk/ui/gtkcolorchooserdialog.ui:36 gtk/ui/gtkfontchooserdialog.ui:29
 msgid "_Cancel"
 msgstr "_انصراف"
 
-#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594
-#: gtk/gtkfiledialog.c:812 gtk/gtkplacessidebar.c:3149 gtk/gtkplacessidebar.c:3234
-#: gtk/gtkplacesview.c:1645
+#: gtk/gtkfilechoosernative.c:522 gtk/gtkfilechoosernative.c:588
+#: gtk/gtkfiledialog.c:885 gtk/gtkplacessidebar.c:3149 gtk/gtkplacessidebar.c:3234
+#: gtk/gtkplacesview.c:1646
 msgid "_Open"
 msgstr "_گشودن"
 
-#: gtk/gtkfilechoosernative.c:594 gtk/gtkfiledialog.c:817
+#: gtk/gtkfilechoosernative.c:588 gtk/gtkfiledialog.c:890
 msgid "_Save"
 msgstr "_ذخیره"
 
+#: gtk/gtkfilechoosernativeportal.c:499
+#, c-format
+msgid "The session bus is not available"
+msgstr "گذرگاه سامانه موجود نیست"
+
 #: gtk/gtkfilechoosernativequartz.c:348 gtk/ui/gtkfilechooserwidget.ui:299
 msgid "Select which types of files are shown"
 msgstr "انتخاب این که کدام نوع پرونده‌ها نمایش داده شوند"
@@ -2290,321 +2319,329 @@ msgstr "انتخاب این که کدام نوع پرونده‌ها نمایش
 msgid "%1$s on %2$s"
 msgstr "%1$s روی %2$s"
 
-#: gtk/gtkfilechooserwidget.c:364
+#: gtk/gtkfilechooserwidget.c:365
 msgid "Type name of new folder"
 msgstr "نام پوشهٔ جدید را وارد کنید"
 
-#: gtk/gtkfilechooserwidget.c:751
+#: gtk/gtkfilechooserwidget.c:752
 msgid "The folder could not be created"
 msgstr "نمی‌توان پوشه را ایجاد کرد"
 
-#: gtk/gtkfilechooserwidget.c:764
+#: gtk/gtkfilechooserwidget.c:765
 msgid "You need to choose a valid filename."
 msgstr "شما باید یک نام معتبر انتخاب کنید."
 
-#: gtk/gtkfilechooserwidget.c:767
+#: gtk/gtkfilechooserwidget.c:768
 #, c-format
 msgid "Cannot create a file under %s as it is not a folder"
 msgstr "از آنجایی که %s یک پوشه نیست، نمی‌توان یک پرونده در آن ساخت"
 
-#: gtk/gtkfilechooserwidget.c:777
+#: gtk/gtkfilechooserwidget.c:778
 msgid "Cannot create file as the filename is too long"
 msgstr "باتوجه به اینکه نام پرونده بسیار بزرگ است، نمی‌توان پرونده را ساخت"
 
-#: gtk/gtkfilechooserwidget.c:778
+#: gtk/gtkfilechooserwidget.c:779
 msgid "Try using a shorter name."
 msgstr "سعی کنید نامی کوتاه‌تر انتخاب کنید."
 
-#: gtk/gtkfilechooserwidget.c:788
+#: gtk/gtkfilechooserwidget.c:789
 msgid "You may only select folders"
 msgstr "شما می‌توانید از پوشه‌ها انتخاب کنید"
 
-#: gtk/gtkfilechooserwidget.c:789
+#: gtk/gtkfilechooserwidget.c:790
 msgid "The item that you selected is not a folder try using a different item."
 msgstr "موردی که شما انتخاب کرده‌اید، پوشه نیست، سعی کنید مورد دیگری استفاده کنید."
 
-#: gtk/gtkfilechooserwidget.c:797
+#: gtk/gtkfilechooserwidget.c:798
 msgid "Invalid file name"
 msgstr "نام پروندهٔ نامعتبر"
 
-#: gtk/gtkfilechooserwidget.c:806
+#: gtk/gtkfilechooserwidget.c:807
 msgid "The folder contents could not be displayed"
 msgstr "نمی‌توان محتویات پوشه را نمایش داد"
 
-#: gtk/gtkfilechooserwidget.c:814
+#: gtk/gtkfilechooserwidget.c:815
 msgid "The file could not be deleted"
 msgstr "نمی‌توان پوشه را حذف کرد"
 
-#: gtk/gtkfilechooserwidget.c:822
+#: gtk/gtkfilechooserwidget.c:823
 msgid "The file could not be moved to the Trash"
 msgstr "پرونده را نمی‌توان به زباله‌دان منتقل کرد"
 
-#: gtk/gtkfilechooserwidget.c:1211
+#: gtk/gtkfilechooserwidget.c:1212
 #, c-format
 msgid "Are you sure you want to permanently delete “%s”?"
 msgstr "آیا مطمئنید که می‌خواهید برای همیشه «%s» را پاک کنید؟"
 
-#: gtk/gtkfilechooserwidget.c:1212
+#: gtk/gtkfilechooserwidget.c:1213
 msgid "If you delete an item, it will be permanently lost."
 msgstr "اگر موردی را پاک کنید، برای همیشه از دست خواهد رفت."
 
-#: gtk/gtkfilechooserwidget.c:1213 gtk/gtkfilechooserwidget.c:1815
-#: gtk/gtklabel.c:5883 gtk/gtktext.c:6334 gtk/gtktextview.c:9237
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:1816
+#: gtk/gtklabel.c:5900 gtk/gtktext.c:6330 gtk/gtktextview.c:9334
 msgid "_Delete"
 msgstr "_حذف"
 
-#: gtk/gtkfilechooserwidget.c:1330
+#: gtk/gtkfilechooserwidget.c:1331
 msgid "The file could not be renamed"
 msgstr "نمی‌توان نام پرونده را تغییر داد"
 
-#: gtk/gtkfilechooserwidget.c:1506
+#: gtk/gtkfilechooserwidget.c:1507
 msgid "Could not select file"
 msgstr "انتخاب پرونده ممکن نیست"
 
-#: gtk/gtkfilechooserwidget.c:1726 gtk/ui/gtkfilechooserwidget.ui:66
+#: gtk/gtkfilechooserwidget.c:1727 gtk/ui/gtkfilechooserwidget.ui:66
 msgid "Grid View"
 msgstr "نمای شبکه‌ای"
 
-#: gtk/gtkfilechooserwidget.c:1732
+#: gtk/gtkfilechooserwidget.c:1733
 msgid "List View"
 msgstr "نمای سیاهه‌ای"
 
-#: gtk/gtkfilechooserwidget.c:1795
+#: gtk/gtkfilechooserwidget.c:1796
 msgid "_Visit File"
 msgstr "_مشاهده پرونده"
 
-#: gtk/gtkfilechooserwidget.c:1799
+#: gtk/gtkfilechooserwidget.c:1800
 msgid "_Open With File Manager"
 msgstr "_گشودن با مدیر پرونده‌ها"
 
-#: gtk/gtkfilechooserwidget.c:1803
+#: gtk/gtkfilechooserwidget.c:1804
 msgid "_Copy Location"
 msgstr "_رونوشت از مکان"
 
-#: gtk/gtkfilechooserwidget.c:1807
+#: gtk/gtkfilechooserwidget.c:1808
 msgid "_Add to Bookmarks"
 msgstr "_افزودن به نشانک‌ها"
 
-#: gtk/gtkfilechooserwidget.c:1811 gtk/gtkplacessidebar.c:2312
-#: gtk/gtkplacessidebar.c:3270 gtk/ui/gtkfilechooserwidget.ui:421
+#: gtk/gtkfilechooserwidget.c:1812 gtk/gtkplacessidebar.c:2312
+#: gtk/gtkplacessidebar.c:3270 gtk/ui/gtkfilechooserwidget.ui:417
 msgid "_Rename"
 msgstr "_تغییر نام"
 
-#: gtk/gtkfilechooserwidget.c:1819
+#: gtk/gtkfilechooserwidget.c:1820
 msgid "_Move to Trash"
 msgstr "_انتقال به زباله‌دان"
 
-#: gtk/gtkfilechooserwidget.c:1828
+#: gtk/gtkfilechooserwidget.c:1829
 msgid "Show _Hidden Files"
 msgstr "نمایش پرونده‌های _مخفی"
 
-#: gtk/gtkfilechooserwidget.c:1832
+#: gtk/gtkfilechooserwidget.c:1833
 msgid "Sort _Folders Before Files"
 msgstr "مرتب کردن _شاخه‌ها پیش از پرونده‌ها"
 
-#: gtk/gtkfilechooserwidget.c:1955 gtk/gtkfilechooserwidget.c:1985
-#: gtk/gtkfilechooserwidget.c:3890
+#: gtk/gtkfilechooserwidget.c:1956 gtk/gtkfilechooserwidget.c:1986
+#: gtk/gtkfilechooserwidget.c:3861
 msgid "Unknown"
 msgstr "نامعلوم"
 
-#: gtk/gtkfilechooserwidget.c:2040 gtk/gtkplacessidebar.c:1025
+#: gtk/gtkfilechooserwidget.c:2041 gtk/gtkplacessidebar.c:1025
 msgid "Home"
 msgstr "خانه"
 
 #. this is the header for the location column in the print dialog
-#: gtk/gtkfilechooserwidget.c:2195 gtk/gtkfilechooserwidget.c:7439
+#: gtk/gtkfilechooserwidget.c:2196 gtk/gtkfilechooserwidget.c:7420
 #: gtk/inspector/css-node-tree.ui:76 gtk/print/ui/gtkprintunixdialog.ui:111
 msgid "Location"
 msgstr "مکان"
 
 #. Label
-#: gtk/gtkfilechooserwidget.c:2302
+#: gtk/gtkfilechooserwidget.c:2303
 msgid "_Name:"
 msgstr "_نام:"
 
-#: gtk/gtkfilechooserwidget.c:2859 gtk/gtkfilechooserwidget.c:2873
+#: gtk/gtkfilechooserwidget.c:2860 gtk/gtkfilechooserwidget.c:2874
 #, c-format
 msgid "Searching in %s"
 msgstr "در حال جست‌وجو در %s"
 
-#: gtk/gtkfilechooserwidget.c:2879
+#: gtk/gtkfilechooserwidget.c:2880
 msgid "Searching"
 msgstr "درحال جست‌وجو"
 
-#: gtk/gtkfilechooserwidget.c:2885
+#: gtk/gtkfilechooserwidget.c:2886
 msgid "Enter location or URL"
 msgstr "وارد کردن مکان یا URL"
 
-#: gtk/gtkfilechooserwidget.c:3444 gtk/gtkfilechooserwidget.c:5804
-#: gtk/gtkfilechooserwidget.c:7461
+#: gtk/gtkfilechooserwidget.c:3445 gtk/gtkfilechooserwidget.c:5775
+#: gtk/gtkfilechooserwidget.c:7442
 msgid "Modified"
 msgstr "تغییریافته"
 
-#: gtk/gtkfilechooserwidget.c:3629
+#: gtk/gtkfilechooserwidget.c:3630
 #, c-format
 msgid "Could not read the contents of %s"
 msgstr "محتوای %s قابل خواندن نبود"
 
-#: gtk/gtkfilechooserwidget.c:3633
+#: gtk/gtkfilechooserwidget.c:3634
 msgid "Could not read the contents of the folder"
 msgstr "محتوای پوشه قابل خواندن نبود"
 
 #. Translators: see g_date_time_format() for details on the format
-#: gtk/gtkfilechooserwidget.c:3784 gtk/gtkfilechooserwidget.c:3828
+#: gtk/gtkfilechooserwidget.c:3757 gtk/gtkfilechooserwidget.c:3800
 msgid "%H:%M"
 msgstr "%OH:%OM"
 
-#: gtk/gtkfilechooserwidget.c:3786 gtk/gtkfilechooserwidget.c:3830
+#: gtk/gtkfilechooserwidget.c:3759 gtk/gtkfilechooserwidget.c:3802
 msgid "%l:%M %p"
 msgstr "%OI:%OM %p"
 
-#: gtk/gtkfilechooserwidget.c:3790
+#: gtk/gtkfilechooserwidget.c:3763
 msgid "Yesterday"
 msgstr "دیروز"
 
-#: gtk/gtkfilechooserwidget.c:3799
+#: gtk/gtkfilechooserwidget.c:3772
 #, no-c-format
 msgid "%-e %b"
 msgstr "%O-e %b"
 
-#: gtk/gtkfilechooserwidget.c:3803
+#: gtk/gtkfilechooserwidget.c:3776
 msgid "%-e %b %Y"
 msgstr "%O-e %b %OY"
 
-#: gtk/gtkfilechooserwidget.c:3845 gtk/gtkfilechooserwidget.c:3853
+#: gtk/gtkfilechooserwidget.c:3816 gtk/gtkfilechooserwidget.c:3824
 msgid "Program"
 msgstr "برنامه"
 
-#: gtk/gtkfilechooserwidget.c:3846
+#: gtk/gtkfilechooserwidget.c:3817
 msgid "Audio"
 msgstr "صدا"
 
-#: gtk/gtkfilechooserwidget.c:3848 gtk/gtkfilefilter.c:1013
+#: gtk/gtkfilechooserwidget.c:3819 gtk/gtkfilefilter.c:1069
 msgid "Image"
 msgstr "تصویر"
 
-#: gtk/gtkfilechooserwidget.c:3849
+#: gtk/gtkfilechooserwidget.c:3820
 msgid "Archive"
 msgstr "بایگانی"
 
-#: gtk/gtkfilechooserwidget.c:3850
+#: gtk/gtkfilechooserwidget.c:3821
 msgid "Markup"
 msgstr "نشانه‌گذاری"
 
-#: gtk/gtkfilechooserwidget.c:3851 gtk/gtkfilechooserwidget.c:3852
+#: gtk/gtkfilechooserwidget.c:3822 gtk/gtkfilechooserwidget.c:3823
 msgid "Text"
 msgstr "متن"
 
-#: gtk/gtkfilechooserwidget.c:3854
+#: gtk/gtkfilechooserwidget.c:3825
 msgid "Video"
 msgstr "ویدیو"
 
-#: gtk/gtkfilechooserwidget.c:3855
+#: gtk/gtkfilechooserwidget.c:3826
 msgid "Contacts"
 msgstr "آشنایان"
 
-#: gtk/gtkfilechooserwidget.c:3856
+#: gtk/gtkfilechooserwidget.c:3827
 msgid "Calendar"
 msgstr "تقویم"
 
-#: gtk/gtkfilechooserwidget.c:3857
+#: gtk/gtkfilechooserwidget.c:3828
 msgid "Document"
 msgstr "سند"
 
-#: gtk/gtkfilechooserwidget.c:3858
+#: gtk/gtkfilechooserwidget.c:3829
 msgid "Presentation"
 msgstr "ارائه‌"
 
-#: gtk/gtkfilechooserwidget.c:3859
+#: gtk/gtkfilechooserwidget.c:3830
 msgid "Spreadsheet"
 msgstr "صفحهٔ گسترده"
 
-#: gtk/gtkfilechooserwidget.c:5009 gtk/print/gtkprintunixdialog.c:673
+#: gtk/gtkfilechooserwidget.c:4980 gtk/print/gtkprintunixdialog.c:674
 #, c-format
 msgid "A file named “%s” already exists.  Do you want to replace it?"
 msgstr "پرونده‌ای با نام «%s» از قبل وجود دارد.  می‌خواهید آن را جایگزین کنید؟"
 
-#: gtk/gtkfilechooserwidget.c:5011 gtk/print/gtkprintunixdialog.c:677
+#: gtk/gtkfilechooserwidget.c:4982 gtk/print/gtkprintunixdialog.c:678
 #, c-format
 msgid "The file already exists in “%s”.  Replacing it will overwrite its contents."
 msgstr ""
 "پرونده از قبل در «%s» وجود دارد.  با جایگزینی آن تمام محتوایش بازنویسی می‌شود."
 
-#: gtk/gtkfilechooserwidget.c:5017 gtk/print/gtkprintunixdialog.c:685
+#: gtk/gtkfilechooserwidget.c:4988 gtk/print/gtkprintunixdialog.c:686
 msgid "_Replace"
 msgstr "_جایگزینی"
 
-#: gtk/gtkfilechooserwidget.c:5172
+#: gtk/gtkfilechooserwidget.c:5143
 msgid "You do not have access to the specified folder."
 msgstr "شما دسترسی به پوشه مشخص شده را ندارید."
 
-#: gtk/gtkfilechooserwidget.c:5751
+#: gtk/gtkfilechooserwidget.c:5722
 msgid "Could not send the search request"
 msgstr "نمی‌توان درخواست جست‌وجو را ارسال کرد"
 
-#: gtk/gtkfilechooserwidget.c:6032
+#: gtk/gtkfilechooserwidget.c:6003
 msgid "Accessed"
 msgstr "در دسترس"
 
-#: gtk/gtkfilechooserwidget.c:7417
+#: gtk/gtkfilechooserwidget.c:7398
 msgid "_Size"
 msgstr "ا_ندازه"
 
-#: gtk/gtkfilechooserwidget.c:7421
+#: gtk/gtkfilechooserwidget.c:7402
 msgid "T_ype"
 msgstr "_گونه"
 
-#: gtk/gtkfilechooserwidget.c:7425
+#: gtk/gtkfilechooserwidget.c:7406
 msgid "_Time"
 msgstr "_زمان"
 
-#: gtk/gtkfilechooserwidget.c:7431 gtk/gtkplacessidebar.c:2306
+#: gtk/gtkfilechooserwidget.c:7412 gtk/gtkplacessidebar.c:2306
 #: gtk/inspector/a11y.ui:43 gtk/inspector/actions.ui:18
 #: gtk/inspector/css-node-tree.ui:22 gtk/inspector/prop-list.ui:24
-#: gtk/ui/gtkfilechooserwidget.ui:396 gtk/print/ui/gtkprintunixdialog.ui:80
+#: gtk/ui/gtkfilechooserwidget.ui:394 gtk/print/ui/gtkprintunixdialog.ui:80
 msgid "Name"
 msgstr "نام"
 
-#: gtk/gtkfilechooserwidget.c:7448 gtk/inspector/resource-list.ui:82
-#: gtk/ui/gtkfontchooserwidget.ui:218 gtk/ui/gtkfontchooserwidget.ui:387
+#: gtk/gtkfilechooserwidget.c:7429 gtk/inspector/resource-list.ui:82
+#: gtk/ui/gtkfontchooserwidget.ui:216 gtk/ui/gtkfontchooserwidget.ui:382
 msgid "Size"
 msgstr "اندازه"
 
-#: gtk/gtkfilechooserwidget.c:7454 gtk/inspector/misc-info.ui:57
+#: gtk/gtkfilechooserwidget.c:7435 gtk/inspector/misc-info.ui:57
 #: gtk/inspector/prop-list.ui:35 gtk/inspector/statistics.ui:36
 msgid "Type"
 msgstr "نوع"
 
-#: gtk/gtkfiledialog.c:813
+#: gtk/gtkfiledialog.c:886
 msgid "Pick Files"
 msgstr "گزینش پرونده‌ها"
 
-#: gtk/gtkfiledialog.c:813
+#: gtk/gtkfiledialog.c:886
 msgid "Pick a File"
 msgstr "پرونده‌ای را بردارید"
 
-#: gtk/gtkfiledialog.c:818
+#: gtk/gtkfiledialog.c:891
 msgid "Save a File"
 msgstr "پرونده‌ای را ذخیره کنید"
 
-#: gtk/gtkfiledialog.c:822 gtk/ui/gtkappchooserdialog.ui:53
-#: gtk/ui/gtkcolorchooserdialog.ui:41 gtk/ui/gtkfontchooserdialog.ui:32
+#: gtk/gtkfiledialog.c:895 gtk/ui/gtkappchooserdialog.ui:53
+#: gtk/ui/gtkcolorchooserdialog.ui:41 gtk/ui/gtkfontchooserdialog.ui:34
 msgid "_Select"
 msgstr "_گزینش"
 
-#: gtk/gtkfiledialog.c:823
+#: gtk/gtkfiledialog.c:896
 msgid "Select Folders"
 msgstr "گزینش شاخه‌ها"
 
-#: gtk/gtkfiledialog.c:823
+#: gtk/gtkfiledialog.c:896
 msgid "Select a Folder"
 msgstr "شاخه‌ای را برگزنید"
 
-#: gtk/gtkfilefilter.c:1026
+#: gtk/gtkfiledialog.c:1397 gtk/gtkfiledialog.c:1514 gtk/gtkfiledialog.c:1623
+msgid "Encoding"
+msgstr "کدگذاری"
+
+#: gtk/gtkfiledialog.c:1634
+msgid "Line Ending"
+msgstr "پایان‌دهی خط"
+
+#: gtk/gtkfilefilter.c:1082
 msgid "Unspecified"
 msgstr "نامشخّص"
 
-#: gtk/gtkfontchooserdialog.c:192 gtk/gtkfontchooserdialog.c:195
+#: gtk/gtkfontchooserdialog.c:195 gtk/gtkfontchooserdialog.c:198
 msgid "Change Font Features"
 msgstr "تغییر ویژگی‌های قلم"
 
@@ -2643,84 +2680,80 @@ msgctxt "Font feature value"
 msgid "Enable"
 msgstr "به کار انداختن"
 
-#: gtk/gtkfontchooserwidget.c:2403
+#: gtk/gtkfontchooserwidget.c:2406
 msgid "Default"
 msgstr "پیش‌گزیده"
 
-#: gtk/gtkfontchooserwidget.c:2465
+#: gtk/gtkfontchooserwidget.c:2469
 msgid "Ligatures"
 msgstr "جایگزین‌ها"
 
-#: gtk/gtkfontchooserwidget.c:2466
+#: gtk/gtkfontchooserwidget.c:2470
 msgid "Letter Case"
 msgstr "حالت حرف"
 
-#: gtk/gtkfontchooserwidget.c:2467
+#: gtk/gtkfontchooserwidget.c:2471
 msgid "Number Case"
 msgstr "حالت عدد"
 
-#: gtk/gtkfontchooserwidget.c:2468
+#: gtk/gtkfontchooserwidget.c:2472
 msgid "Number Spacing"
 msgstr "فاصله‌گذاری عدد"
 
-#: gtk/gtkfontchooserwidget.c:2469
+#: gtk/gtkfontchooserwidget.c:2473
+msgid "Numeric Extras"
+msgstr "اضافات رقمی"
+
+#: gtk/gtkfontchooserwidget.c:2474
 msgid "Fractions"
 msgstr "کسرها"
 
-#: gtk/gtkfontchooserwidget.c:2470
+#: gtk/gtkfontchooserwidget.c:2475
 msgid "Style Variations"
 msgstr "دگرگونه‌های سبک"
 
-#: gtk/gtkfontchooserwidget.c:2472
+#: gtk/gtkfontchooserwidget.c:2477
 msgid "Character Variations"
 msgstr "دگرگونه‌های نویسه"
 
-#: gtk/gtkglarea.c:316
+#: gtk/gtkglarea.c:319
 msgid "OpenGL context creation failed"
 msgstr "ساخت زمینه OpenGL شکست خورد"
 
-#: gtk/deprecated/gtkinfobar.c:498 gtk/gtkwindowcontrols.c:357
-#: gtk/gtkwindowhandle.c:250
+#: gtk/deprecated/gtkinfobar.c:501 gtk/gtkwindowcontrols.c:373
+#: gtk/gtkwindowhandle.c:253
 msgid "Close"
 msgstr "بستن"
 
-#: gtk/deprecated/gtkinfobar.c:499
+#: gtk/deprecated/gtkinfobar.c:502
 msgid "Close the infobar"
 msgstr "بستن نوار اطّلاعات"
 
-#: gtk/gtklabel.c:5880 gtk/gtktext.c:6322 gtk/gtktextview.c:9225
+#: gtk/gtklabel.c:5897 gtk/gtktext.c:6318 gtk/gtktextview.c:9322
 msgid "Cu_t"
 msgstr "_برش"
 
-#: gtk/gtklabel.c:5881 gtk/gtktext.c:6326 gtk/gtktextview.c:9229
-msgid "_Copy"
-msgstr "_رونوشت"
-
-#: gtk/gtklabel.c:5882 gtk/gtktext.c:6330 gtk/gtktextview.c:9233
+#: gtk/gtklabel.c:5899 gtk/gtktext.c:6326 gtk/gtktextview.c:9330
 msgid "_Paste"
 msgstr "_چسباندن"
 
-#: gtk/gtklabel.c:5888 gtk/gtktext.c:6343 gtk/gtktextview.c:9258
+#: gtk/gtklabel.c:5905 gtk/gtktext.c:6339 gtk/gtktextview.c:9355
 msgid "Select _All"
 msgstr "انتخاب _همه"
 
-#: gtk/gtklabel.c:5893
+#: gtk/gtklabel.c:5910
 msgid "_Open Link"
 msgstr "_گشودن پیوند"
 
-#: gtk/gtklabel.c:5897
+#: gtk/gtklabel.c:5914
 msgid "Copy _Link Address"
 msgstr "_رونوشت از نشانی پیوند"
 
-#: gtk/gtklabel.c:5941 gtk/gtktext.c:2851 gtk/gtktextview.c:9307
-msgid "Context menu"
-msgstr "فهرست بافتاری"
-
-#: gtk/gtklinkbutton.c:273
+#: gtk/gtklinkbutton.c:276
 msgid "_Copy URL"
 msgstr "_رونوشت از نشانی"
 
-#: gtk/gtklinkbutton.c:602
+#: gtk/gtklinkbutton.c:605
 msgid "Invalid URI"
 msgstr "نشانی نامعتبر"
 
@@ -2730,7 +2763,7 @@ msgstr "نشانی نامعتبر"
 #. * the separator that your locale uses or use "%Id" instead
 #. * of "%d" if your locale uses localized digits.
 #.
-#: gtk/gtkmediacontrols.c:100
+#: gtk/gtkmediacontrols.c:103
 #, c-format
 msgctxt "long time format"
 msgid "%d:%02d:%02d"
@@ -2742,7 +2775,7 @@ msgstr "%Id:%I02d:%I02d"
 #. * change ":" to the separator that your locale uses or use
 #. * "%Id" instead of "%d" if your locale uses localized digits.
 #.
-#: gtk/gtkmediacontrols.c:108
+#: gtk/gtkmediacontrols.c:111
 #, c-format
 msgctxt "long time format"
 msgid "-%d:%02d:%02d"
@@ -2754,7 +2787,7 @@ msgstr "-%Id:%I02d:%I02d"
 #. * ":" to the separator that your locale uses or use "%Id"
 #. * instead of "%d" if your locale uses localized digits.
 #.
-#: gtk/gtkmediacontrols.c:119
+#: gtk/gtkmediacontrols.c:122
 #, c-format
 msgctxt "short time format"
 msgid "-%d:%02d"
@@ -2766,32 +2799,32 @@ msgstr "-%Id:%I02d"
 #. * separator that your locale uses or use "%Id" instead of
 #. * "%d" if your locale uses localized digits.
 #.
-#: gtk/gtkmediacontrols.c:128
+#: gtk/gtkmediacontrols.c:131
 #, c-format
 msgctxt "short time format"
 msgid "%d:%02d"
 msgstr "%Id:%I02d"
 
-#: gtk/gtkmediacontrols.c:412
+#: gtk/gtkmediacontrols.c:415
 msgctxt "media controls tooltip"
 msgid "Stop"
 msgstr "توقّف"
 
-#: gtk/gtkmediacontrols.c:417 gtk/ui/gtkmediacontrols.ui:28
+#: gtk/gtkmediacontrols.c:420 gtk/ui/gtkmediacontrols.ui:28
 msgctxt "media controls tooltip"
 msgid "Play"
 msgstr "پخش"
 
-#: gtk/gtkmessagedialog.c:162 gtk/gtkmessagedialog.c:180
-#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6212
+#: gtk/gtkmessagedialog.c:165 gtk/gtkmessagedialog.c:183
+#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6331
 msgid "_OK"
 msgstr "_تأیید"
 
-#: gtk/gtkmessagedialog.c:174
+#: gtk/gtkmessagedialog.c:177
 msgid "_No"
 msgstr "_خیر"
 
-#: gtk/gtkmessagedialog.c:175
+#: gtk/gtkmessagedialog.c:178
 msgid "_Yes"
 msgstr "_بله"
 
@@ -2876,27 +2909,27 @@ msgid "Cannot kill process with PID %d. Operation is not implemented."
 msgstr "نمی‌توان فرایند با شناسهٔ %Id را کشت. عملیان پیاده سازی نشده."
 
 #. translators: this string is a name for the 'less' command
-#: gtk/gtkmountoperation-x11.c:986
+#: gtk/gtkmountoperation-x11.c:988
 msgid "Terminal Pager"
 msgstr "پی‌جوی پایانه"
 
-#: gtk/gtkmountoperation-x11.c:987
+#: gtk/gtkmountoperation-x11.c:989
 msgid "Top Command"
 msgstr "فرمان تاپ (top)"
 
-#: gtk/gtkmountoperation-x11.c:988
+#: gtk/gtkmountoperation-x11.c:990
 msgid "Bourne Again Shell"
 msgstr "پوستهٔ بورن اِگِین"
 
-#: gtk/gtkmountoperation-x11.c:989
+#: gtk/gtkmountoperation-x11.c:991
 msgid "Bourne Shell"
 msgstr "پوستهٔ بورن"
 
-#: gtk/gtkmountoperation-x11.c:990
+#: gtk/gtkmountoperation-x11.c:992
 msgid "Z Shell"
 msgstr "پوستهٔ زی"
 
-#: gtk/gtkmountoperation-x11.c:1090
+#: gtk/gtkmountoperation-x11.c:1092
 #, c-format
 msgid "Cannot end process with PID %d: %s"
 msgstr "نمی‌توان فرایند با شناسهٔ %Id را به پایان برد: %s"
@@ -2905,15 +2938,15 @@ msgstr "نمی‌توان فرایند با شناسهٔ %Id را به پایا
 msgid "GTK could not find a media module. Check your installation."
 msgstr "GTK نتوانست پیمانه‌ٔ رسانه‌ای بیابد. نصبتان را بررسی کنید."
 
-#: gtk/gtknotebook.c:3304
+#: gtk/gtknotebook.c:3306
 msgid "Previous tab"
 msgstr "زبانهٔ پیشین"
 
-#: gtk/gtknotebook.c:3308
+#: gtk/gtknotebook.c:3310
 msgid "Next tab"
 msgstr "_زبانهٔ بعدی"
 
-#: gtk/gtknotebook.c:4424 gtk/gtknotebook.c:6634
+#: gtk/gtknotebook.c:4426 gtk/gtknotebook.c:6636
 #, c-format
 msgid "Page %u"
 msgstr "صفحهٔ %Iu"
@@ -2923,23 +2956,23 @@ msgstr "صفحهٔ %Iu"
 msgid "Not a valid page setup file"
 msgstr "پروندهٔ برپایی صفحهٔ نامعتبر"
 
-#: gtk/print/gtkpagesetupunixdialog.c:198 gtk/print/gtkprintunixdialog.c:768
+#: gtk/print/gtkpagesetupunixdialog.c:201 gtk/print/gtkprintunixdialog.c:769
 msgid "Manage Custom Sizes…"
 msgstr "مدیریت اندازه‌های سفارشی…"
 
-#: gtk/print/gtkpagesetupunixdialog.c:283 gtk/ui/gtkassistant.ui:98
+#: gtk/print/gtkpagesetupunixdialog.c:286 gtk/ui/gtkassistant.ui:98
 msgid "_Apply"
 msgstr "_اعمال"
 
-#: gtk/print/gtkpagesetupunixdialog.c:318 gtk/print/gtkpagesetupunixdialog.c:570
+#: gtk/print/gtkpagesetupunixdialog.c:321 gtk/print/gtkpagesetupunixdialog.c:573
 msgid "Any Printer"
 msgstr "هر چاپگری"
 
-#: gtk/print/gtkpagesetupunixdialog.c:319
+#: gtk/print/gtkpagesetupunixdialog.c:322
 msgid "For portable documents"
 msgstr "برای سند‌های قابل حمل"
 
-#: gtk/print/gtkpagesetupunixdialog.c:738
+#: gtk/print/gtkpagesetupunixdialog.c:741
 #, c-format
 msgid ""
 "Margins:\n"
@@ -2954,24 +2987,24 @@ msgstr ""
 "بالا:%s %s\n"
 "پایین:%s %s"
 
-#: gtk/print/gtkpagesetupunixdialog.c:784 gtk/print/ui/gtkpagesetupunixdialog.ui:5
-#: gtk/print/ui/gtkprintunixdialog.ui:782
+#: gtk/print/gtkpagesetupunixdialog.c:787 gtk/print/ui/gtkpagesetupunixdialog.ui:5
+#: gtk/print/ui/gtkprintunixdialog.ui:783
 msgid "Page Setup"
 msgstr "برپایی صفحه"
 
-#: gtk/gtkpasswordentry.c:168
+#: gtk/gtkpasswordentry.c:171
 msgid "Hide Text"
 msgstr "نهفتن متن"
 
-#: gtk/gtkpasswordentry.c:173 gtk/gtkpasswordentry.c:624
+#: gtk/gtkpasswordentry.c:176 gtk/gtkpasswordentry.c:623
 msgid "Show Text"
 msgstr "نمایش متن"
 
-#: gtk/gtkpasswordentry.c:215
+#: gtk/gtkpasswordentry.c:218
 msgid "Caps Lock is on"
 msgstr "قفل تبدیل روشن است"
 
-#: gtk/gtkpasswordentry.c:700
+#: gtk/gtkpasswordentry.c:699
 msgid "_Show Text"
 msgstr "_نمایش متن"
 
@@ -3098,11 +3131,11 @@ msgstr "نتوانست %s را بیرون دهد"
 msgid "Unable to poll “%s” for media changes"
 msgstr "نتوانست %s را برای تغییرات رسانه‌ای بررسی کند"
 
-#: gtk/gtkplacessidebar.c:3155 gtk/gtkplacessidebar.c:3242 gtk/gtkplacesview.c:1649
+#: gtk/gtkplacessidebar.c:3155 gtk/gtkplacessidebar.c:3242 gtk/gtkplacesview.c:1650
 msgid "Open in New _Tab"
 msgstr "گشودن در _زبانهٔ جدید"
 
-#: gtk/gtkplacessidebar.c:3161 gtk/gtkplacessidebar.c:3251 gtk/gtkplacesview.c:1654
+#: gtk/gtkplacessidebar.c:3161 gtk/gtkplacessidebar.c:3251 gtk/gtkplacesview.c:1655
 msgid "Open in New _Window"
 msgstr "گشودن در _پنجرهٔ جدید"
 
@@ -3114,11 +3147,11 @@ msgstr "_افزودن نشانک"
 msgid "_Remove"
 msgstr "_برداشتن"
 
-#: gtk/gtkplacessidebar.c:3282 gtk/gtkplacesview.c:1679
+#: gtk/gtkplacessidebar.c:3282 gtk/gtkplacesview.c:1680
 msgid "_Mount"
 msgstr "_سوار کردن"
 
-#: gtk/gtkplacessidebar.c:3291 gtk/gtkplacesview.c:1668
+#: gtk/gtkplacessidebar.c:3291 gtk/gtkplacesview.c:1669
 msgid "_Unmount"
 msgstr "_پیاده کردن"
 
@@ -3170,94 +3203,98 @@ msgstr "_توقف افزارهٔ چنددیسکه"
 msgid "_Lock Device"
 msgstr "_قفل افزاره"
 
-#: gtk/gtkplacessidebar.c:3827 gtk/gtkplacesview.c:1089
+#: gtk/gtkplacessidebar.c:3828 gtk/gtkplacesview.c:1090
 msgid "Computer"
 msgstr "رایانه"
 
-#: gtk/gtkplacesview.c:875
+#: gtk/gtkplacesview.c:593
+msgid "Remove server"
+msgstr "برداشتن %کارساز"
+
+#: gtk/gtkplacesview.c:876
 msgid "Searching for network locations"
 msgstr "جست‌وجو برای مکان‌های شبکه"
 
-#: gtk/gtkplacesview.c:882
+#: gtk/gtkplacesview.c:883
 msgid "No network locations found"
 msgstr "هیچ مکان شبکه‌ای پیدا نشد"
 
 #. if it wasn't cancelled show a dialog
-#: gtk/gtkplacesview.c:1196 gtk/gtkplacesview.c:1293
+#: gtk/gtkplacesview.c:1197 gtk/gtkplacesview.c:1294
 msgid "Unable to access location"
 msgstr "نتوانست به موقعیت دسترسی یابد"
 
 #. Restore from Cancel to Connect
-#: gtk/gtkplacesview.c:1214 gtk/ui/gtkplacesview.ui:250
+#: gtk/gtkplacesview.c:1215 gtk/ui/gtkplacesview.ui:237
 msgid "Con_nect"
 msgstr "اتّ_صال"
 
 #. if it wasn't cancelled show a dialog
-#: gtk/gtkplacesview.c:1353
+#: gtk/gtkplacesview.c:1354
 msgid "Unable to unmount volume"
 msgstr "نتوانست حجم را پیاده کند"
 
 #. Allow to cancel the operation
-#: gtk/gtkplacesview.c:1445
+#: gtk/gtkplacesview.c:1446
 msgid "Cance_l"
 msgstr "_لغو"
 
-#: gtk/gtkplacesview.c:1592
+#: gtk/gtkplacesview.c:1593
 msgid "AppleTalk"
 msgstr "اپل‌تاک"
 
-#: gtk/gtkplacesview.c:1598
+#: gtk/gtkplacesview.c:1599
 msgid "File Transfer Protocol"
 msgstr "قرارداد انتقال پرونده"
 
 #. Translators: do not translate ftp:// and ftps://
-#: gtk/gtkplacesview.c:1600
+#: gtk/gtkplacesview.c:1601
 msgid "ftp:// or ftps://"
 msgstr "ftp:// یا ftps://"
 
-#: gtk/gtkplacesview.c:1606
+#: gtk/gtkplacesview.c:1607
 msgid "Network File System"
 msgstr "سامانهٔ پروندهٔ شبکه"
 
-#: gtk/gtkplacesview.c:1612
+#: gtk/gtkplacesview.c:1613
 msgid "Samba"
 msgstr "سامبا"
 
-#: gtk/gtkplacesview.c:1618
+#: gtk/gtkplacesview.c:1619
 msgid "SSH File Transfer Protocol"
 msgstr "قرارداد انتقال پروندهٔ SSH"
 
 #. Translators: do not translate sftp:// and ssh://
-#: gtk/gtkplacesview.c:1620
+#: gtk/gtkplacesview.c:1621
 msgid "sftp:// or ssh://"
 msgstr "sftp:// یا ssh://"
 
-#: gtk/gtkplacesview.c:1626
+#: gtk/gtkplacesview.c:1627
 msgid "WebDAV"
 msgstr "وب‌دو"
 
 #. Translators: do not translate dav:// and davs://
-#: gtk/gtkplacesview.c:1628
+#: gtk/gtkplacesview.c:1629
 msgid "dav:// or davs://"
 msgstr "dav:// یا davs://"
 
-#: gtk/gtkplacesview.c:1663
+#: gtk/gtkplacesview.c:1664
 msgid "_Disconnect"
 msgstr "_قطع ارتباط"
 
-#: gtk/gtkplacesview.c:1674
+#: gtk/gtkplacesview.c:1675
 msgid "_Connect"
 msgstr "اتّ_صال"
 
-#: gtk/gtkplacesview.c:1894
+#: gtk/gtkplacesview.c:1895
 msgid "Unable to get remote server location"
 msgstr "نتوانست موقعیت کارساز دوردست را بگیرد"
 
-#: gtk/gtkplacesview.c:2038 gtk/gtkplacesview.c:2047
+#: gtk/gtkplacesview.c:2039 gtk/gtkplacesview.c:2048
 msgid "Networks"
 msgstr "شبکه"
 
-#: gtk/gtkplacesview.c:2038 gtk/gtkplacesview.c:2047
+#: gtk/gtkplacesview.c:2039 gtk/gtkplacesview.c:2048
 msgid "On This Computer"
 msgstr "روی این رایانه"
 
@@ -3289,11 +3326,11 @@ msgstr "تأیید هویت"
 msgid "_Remember password"
 msgstr "_به‌خاطرسپاری گذرواژه"
 
-#: gtk/print/gtkprinteroptionwidget.c:703
+#: gtk/print/gtkprinteroptionwidget.c:576
 msgid "Select a filename"
 msgstr "نام پرونده‌ای برگزینید"
 
-#: gtk/print/gtkprinteroptionwidget.c:947
+#: gtk/print/gtkprinteroptionwidget.c:820
 msgid "Not available"
 msgstr "در دسترس نیست"
 
@@ -3301,160 +3338,160 @@ msgstr "در دسترس نیست"
 #. * jobs. %s gets replaced by the application name, %d gets replaced
 #. * by the job number.
 #.
-#: gtk/print/gtkprintoperation.c:252
+#: gtk/print/gtkprintoperation.c:255
 #, c-format
 msgid "%s job #%d"
 msgstr "%s کار شماره %Id"
 
-#: gtk/print/gtkprintoperation.c:1699
+#: gtk/print/gtkprintoperation.c:1702
 msgctxt "print operation status"
 msgid "Initial state"
 msgstr "وضعیت نخستین"
 
-#: gtk/print/gtkprintoperation.c:1700
+#: gtk/print/gtkprintoperation.c:1703
 msgctxt "print operation status"
 msgid "Preparing to print"
 msgstr "در حال آماده سازی برای چاپ"
 
-#: gtk/print/gtkprintoperation.c:1701
+#: gtk/print/gtkprintoperation.c:1704
 msgctxt "print operation status"
 msgid "Generating data"
 msgstr "درحال تولید داده"
 
-#: gtk/print/gtkprintoperation.c:1702
+#: gtk/print/gtkprintoperation.c:1705
 msgctxt "print operation status"
 msgid "Sending data"
 msgstr "در حال فرستادن داده"
 
-#: gtk/print/gtkprintoperation.c:1703
+#: gtk/print/gtkprintoperation.c:1706
 msgctxt "print operation status"
 msgid "Waiting"
 msgstr "منتظر"
 
-#: gtk/print/gtkprintoperation.c:1704
+#: gtk/print/gtkprintoperation.c:1707
 msgctxt "print operation status"
 msgid "Blocking on issue"
 msgstr "در حال مسدود کردن بدلیل یک مشکل"
 
-#: gtk/print/gtkprintoperation.c:1705
+#: gtk/print/gtkprintoperation.c:1708
 msgctxt "print operation status"
 msgid "Printing"
 msgstr "در حال چاپ"
 
-#: gtk/print/gtkprintoperation.c:1706
+#: gtk/print/gtkprintoperation.c:1709
 msgctxt "print operation status"
 msgid "Finished"
 msgstr "پایان یافت"
 
-#: gtk/print/gtkprintoperation.c:1707
+#: gtk/print/gtkprintoperation.c:1710
 msgctxt "print operation status"
 msgid "Finished with error"
 msgstr "با خطا پایان یافت"
 
-#: gtk/print/gtkprintoperation.c:2250
+#: gtk/print/gtkprintoperation.c:2254
 #, c-format
 msgid "Preparing %d"
 msgstr "آماده سازی %Id"
 
-#: gtk/print/gtkprintoperation.c:2252 gtk/print/gtkprintoperation.c:2871
+#: gtk/print/gtkprintoperation.c:2256 gtk/print/gtkprintoperation.c:2875
 #, c-format
 msgid "Preparing"
 msgstr "در حال آماده سازی"
 
-#: gtk/print/gtkprintoperation.c:2255
+#: gtk/print/gtkprintoperation.c:2259
 #, c-format
 msgid "Printing %d"
 msgstr "چاپ کردن %Id"
 
-#: gtk/print/gtkprintoperation.c:2904
+#: gtk/print/gtkprintoperation.c:2908
 #, c-format
 msgid "Error creating print preview"
 msgstr "خطا در ایجاد پیش‌نمایش چاپ"
 
-#: gtk/print/gtkprintoperation.c:2907
+#: gtk/print/gtkprintoperation.c:2911
 #, c-format
 msgid "The most probable reason is that a temporary file could not be created."
 msgstr "محتمل‌ترین دلیل این‌است که نمی‌توان یک پروندهٔ موقت ایجاد کرد."
 
 #. window
-#: gtk/print/gtkprintoperation-portal.c:264 gtk/print/gtkprintoperation-portal.c:594
-#: gtk/print/gtkprintoperation-portal.c:663 gtk/print/gtkprintunixdialog.c:3015
+#: gtk/print/gtkprintoperation-portal.c:273 gtk/print/gtkprintoperation-portal.c:603
+#: gtk/print/gtkprintoperation-portal.c:672 gtk/print/gtkprintunixdialog.c:2992
 msgid "Print"
 msgstr "چاپ"
 
-#: gtk/print/gtkprintoperation-unix.c:481 gtk/print/gtkprintoperation-win32.c:1505
+#: gtk/print/gtkprintoperation-unix.c:490 gtk/print/gtkprintoperation-win32.c:1498
 msgid "Application"
 msgstr "برنامه"
 
-#: gtk/print/gtkprintoperation-win32.c:636
+#: gtk/print/gtkprintoperation-win32.c:626
 msgid "Printer offline"
 msgstr "چاپگر برون‌خط"
 
-#: gtk/print/gtkprintoperation-win32.c:638
+#: gtk/print/gtkprintoperation-win32.c:628
 msgid "Out of paper"
 msgstr "بدون کاغذ"
 
 #. Translators: this is a printer status.
-#: gtk/print/gtkprintoperation-win32.c:640
+#: gtk/print/gtkprintoperation-win32.c:630
 #: modules/printbackends/gtkprintbackendcpdb.c:1533
 #: modules/printbackends/gtkprintbackendcups.c:2639
 msgid "Paused"
 msgstr "مکث شده"
 
-#: gtk/print/gtkprintoperation-win32.c:642
+#: gtk/print/gtkprintoperation-win32.c:632
 msgid "Need user intervention"
 msgstr "نیاز به مداخله کاربر هست"
 
-#: gtk/print/gtkprintoperation-win32.c:749
+#: gtk/print/gtkprintoperation-win32.c:739
 msgid "Custom size"
 msgstr "اندازهٔ سفارشی"
 
-#: gtk/print/gtkprintoperation-win32.c:1597
+#: gtk/print/gtkprintoperation-win32.c:1590
 msgid "No printer found"
 msgstr "چاپگری پیدا نشد"
 
-#: gtk/print/gtkprintoperation-win32.c:1624
+#: gtk/print/gtkprintoperation-win32.c:1617
 msgid "Invalid argument to CreateDC"
 msgstr "نشان‌وند نامعتبر به CreateDC"
 
-#: gtk/print/gtkprintoperation-win32.c:1660 gtk/print/gtkprintoperation-win32.c:1906
+#: gtk/print/gtkprintoperation-win32.c:1653 gtk/print/gtkprintoperation-win32.c:1899
 msgid "Error from StartDoc"
 msgstr "خطا از StartDoc"
 
-#: gtk/print/gtkprintoperation-win32.c:1761 gtk/print/gtkprintoperation-win32.c:1784
-#: gtk/print/gtkprintoperation-win32.c:1832
+#: gtk/print/gtkprintoperation-win32.c:1754 gtk/print/gtkprintoperation-win32.c:1777
+#: gtk/print/gtkprintoperation-win32.c:1825
 msgid "Not enough free memory"
 msgstr "حافظهٔ آزاد کافی نیست"
 
-#: gtk/print/gtkprintoperation-win32.c:1837
+#: gtk/print/gtkprintoperation-win32.c:1830
 msgid "Invalid argument to PrintDlgEx"
 msgstr "نشان‌وند نامعتبر برای PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1842
+#: gtk/print/gtkprintoperation-win32.c:1835
 msgid "Invalid pointer to PrintDlgEx"
 msgstr "اشاره‌گر نامعتبر برای PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1847
+#: gtk/print/gtkprintoperation-win32.c:1840
 msgid "Invalid handle to PrintDlgEx"
 msgstr "تصدی نامعتبر به PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1852
+#: gtk/print/gtkprintoperation-win32.c:1845
 msgid "Unspecified error"
 msgstr "خطای نامشخص"
 
-#: gtk/print/gtkprintunixdialog.c:838
+#: gtk/print/gtkprintunixdialog.c:839
 msgid "Pre_view"
 msgstr "_پیش‌نمایش"
 
-#: gtk/print/gtkprintunixdialog.c:840
+#: gtk/print/gtkprintunixdialog.c:841
 msgid "_Print"
 msgstr "_چاپ"
 
-#: gtk/print/gtkprintunixdialog.c:966
+#: gtk/print/gtkprintunixdialog.c:957
 msgid "Getting printer information failed"
 msgstr "گرفتن اطلاعات چاپگر شکست خورد"
 
-#: gtk/print/gtkprintunixdialog.c:1890
+#: gtk/print/gtkprintunixdialog.c:1881
 msgid "Getting printer information…"
 msgstr "در حال گرفتن اطلاعاتِ چاپگر…"
 
@@ -3464,67 +3501,71 @@ msgstr "در حال گرفتن اطلاعاتِ چاپگر…"
 #. Translators: These strings name the possible arrangements of
 #. * multiple pages on a sheet when printing
 #.
-#: gtk/print/gtkprintunixdialog.c:2760
-#: modules/printbackends/gtkprintbackendcups.c:5677
+#: gtk/print/gtkprintunixdialog.c:2737
+#: modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, top to bottom"
 msgstr "از چپ به راست، از بالا به پایین"
 
-#: gtk/print/gtkprintunixdialog.c:2760
-#: modules/printbackends/gtkprintbackendcups.c:5677
+#: gtk/print/gtkprintunixdialog.c:2737
+#: modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, bottom to top"
 msgstr "از چپ به راست، از پایین به ابتدا"
 
-#: gtk/print/gtkprintunixdialog.c:2761
-#: modules/printbackends/gtkprintbackendcups.c:5678
+#: gtk/print/gtkprintunixdialog.c:2738
+#: modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, top to bottom"
 msgstr "از راست به چپ، از بالا به پایین"
 
-#: gtk/print/gtkprintunixdialog.c:2761
-#: modules/printbackends/gtkprintbackendcups.c:5678
+#: gtk/print/gtkprintunixdialog.c:2738
+#: modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, bottom to top"
 msgstr "از راست به چپ، از پایین به بالا"
 
-#: gtk/print/gtkprintunixdialog.c:2762
-#: modules/printbackends/gtkprintbackendcups.c:5679
+#: gtk/print/gtkprintunixdialog.c:2739
+#: modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, left to right"
 msgstr "از بالا به پایین، از چپ به راست"
 
-#: gtk/print/gtkprintunixdialog.c:2762
-#: modules/printbackends/gtkprintbackendcups.c:5679
+#: gtk/print/gtkprintunixdialog.c:2739
+#: modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, right to left"
 msgstr "از بالا به پایین، از راست به چپ"
 
-#: gtk/print/gtkprintunixdialog.c:2763
-#: modules/printbackends/gtkprintbackendcups.c:5680
+#: gtk/print/gtkprintunixdialog.c:2740
+#: modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, left to right"
 msgstr "از انتها به ابتدا، از چپ به راست"
 
-#: gtk/print/gtkprintunixdialog.c:2763
-#: modules/printbackends/gtkprintbackendcups.c:5680
+#: gtk/print/gtkprintunixdialog.c:2740
+#: modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, right to left"
 msgstr "از پایین به بالا، از راست به چپ"
 
-#: gtk/print/gtkprintunixdialog.c:2767 gtk/print/gtkprintunixdialog.c:2780
+#: gtk/print/gtkprintunixdialog.c:2744 gtk/print/gtkprintunixdialog.c:2757
 msgid "Page Ordering"
 msgstr "ترتیب صفحه‌ها"
 
-#: gtk/print/gtkprintunixdialog.c:2796
+#: gtk/print/gtkprintunixdialog.c:2773
 msgid "Left to right"
 msgstr "چپ به راست"
 
-#: gtk/print/gtkprintunixdialog.c:2797
+#: gtk/print/gtkprintunixdialog.c:2774
 msgid "Right to left"
 msgstr "راست به چپ"
 
-#: gtk/print/gtkprintunixdialog.c:2809
+#: gtk/print/gtkprintunixdialog.c:2786
 msgid "Top to bottom"
 msgstr "از بالا به پایین"
 
-#: gtk/print/gtkprintunixdialog.c:2810
+#: gtk/print/gtkprintunixdialog.c:2787
 msgid "Bottom to top"
 msgstr "از پایین به بالا"
 
-#: gtk/gtkprogressbar.c:627
+#: gtk/gtkprintdialog.c:1755
+msgid "Failed to create the read file descriptor"
+msgstr "شکست در ایجاد شرح دهندهٔ پروندهٔ خواندن"
+
+#: gtk/gtkprogressbar.c:629
 #, c-format
 msgctxt "progress bar label"
 msgid "%.0f %%"
@@ -3547,7 +3588,7 @@ msgstr "نمی‌توان مورد با نشانی «%s» را به %s منتق
 msgid "No registered application with name “%s” for item with URI “%s” found"
 msgstr "هیچ برنامهٔ ثبت شده‌ای با نام «%s» برای موردی با آدرس «%s» یافت نشد"
 
-#: gtk/gtksearchentry.c:836
+#: gtk/gtksearchentry.c:838
 msgid "Clear Entry"
 msgstr "پاک‌سازی ورودی"
 
@@ -3556,7 +3597,7 @@ msgstr "پاک‌سازی ورودی"
 #. * this string very short, ideally just a single character, since it will
 #. * be rendered as part of the key.
 #.
-#: gtk/gtkshortcutlabel.c:79
+#: gtk/deprecated/gtkshortcutlabel.c:81
 msgctxt "keyboard side marker"
 msgid "L"
 msgstr "Ú†"
@@ -3566,96 +3607,256 @@ msgstr "Ú†"
 #. * this string very short, ideally just a single character, since it will
 #. * be rendered as part of the key.
 #.
-#: gtk/gtkshortcutlabel.c:92
+#: gtk/deprecated/gtkshortcutlabel.c:94
 msgctxt "keyboard side marker"
 msgid "R"
 msgstr "ر"
 
-#: gtk/gtkshortcutssection.c:435
+#: gtk/deprecated/gtkshortcutssection.c:449
 msgid "_Show All"
 msgstr "_نمایش همه"
 
-#: gtk/gtkshortcutsshortcut.c:143
+#: gtk/deprecated/gtkshortcutsshortcut.c:147
 msgid "Two finger pinch"
 msgstr "کاهش دو انگشتی"
 
-#: gtk/gtkshortcutsshortcut.c:147
+#: gtk/deprecated/gtkshortcutsshortcut.c:151
 msgid "Two finger stretch"
 msgstr "گسترش دو انگشتی"
 
-#: gtk/gtkshortcutsshortcut.c:151
+#: gtk/deprecated/gtkshortcutsshortcut.c:155
 msgid "Rotate clockwise"
 msgstr "چرخش ساعتگرد"
 
-#: gtk/gtkshortcutsshortcut.c:155
+#: gtk/deprecated/gtkshortcutsshortcut.c:159
 msgid "Rotate counterclockwise"
 msgstr "چرخش پادساعتگرد"
 
-#: gtk/gtkshortcutsshortcut.c:159
+#: gtk/deprecated/gtkshortcutsshortcut.c:163
 msgid "Two finger swipe left"
 msgstr "کشیدن دو انگشتی به چپ"
 
-#: gtk/gtkshortcutsshortcut.c:163
+#: gtk/deprecated/gtkshortcutsshortcut.c:167
 msgid "Two finger swipe right"
 msgstr "کشیدن دو انگشتی به راست"
 
-#: gtk/gtkshortcutsshortcut.c:167
+#: gtk/deprecated/gtkshortcutsshortcut.c:171
 msgid "Swipe left"
 msgstr "کشیدن به جپ"
 
-#: gtk/gtkshortcutsshortcut.c:171
+#: gtk/deprecated/gtkshortcutsshortcut.c:175
 msgid "Swipe right"
 msgstr "کشیدن به راست"
 
 #. Translators: This is placeholder text for the search entry in the shortcuts window
-#: gtk/gtkshortcutswindow.c:894 gtk/gtkshortcutswindow.c:961
-#: gtk/gtkshortcutswindow.c:967
+#: gtk/deprecated/gtkshortcutswindow.c:912 gtk/deprecated/gtkshortcutswindow.c:979
+#: gtk/deprecated/gtkshortcutswindow.c:985
 msgid "Search Shortcuts"
 msgstr "جست‌وجوی میان‌برها"
 
 #. Translators: This is the window title for the shortcuts window in normal mode
-#: gtk/gtkshortcutswindow.c:926 gtk/inspector/window.ui:498
+#: gtk/deprecated/gtkshortcutswindow.c:944 gtk/inspector/window.ui:496
 msgid "Shortcuts"
 msgstr "میان‌برها"
 
 #. Translators: This is the window title for the shortcuts window in search mode
-#: gtk/gtkshortcutswindow.c:931
+#: gtk/deprecated/gtkshortcutswindow.c:949
 msgid "Search Results"
 msgstr "نتایج جست‌وجو"
 
-#: gtk/gtkshortcutswindow.c:1029 gtk/ui/gtkemojichooser.ui:350
-#: gtk/ui/gtkfilechooserwidget.ui:250
+#: gtk/deprecated/gtkshortcutswindow.c:1047 gtk/ui/gtkemojichooser.ui:352
+#: gtk/ui/gtkfilechooserwidget.ui:253
 msgid "No Results Found"
 msgstr "هیچ نتیجه‌ای پیدا نشد"
 
-#: gtk/gtkshortcutswindow.c:1040 gtk/ui/gtkemojichooser.ui:363
-#: gtk/ui/gtkfilechooserwidget.ui:263 gtk/ui/gtkplacesview.ui:218
+#: gtk/deprecated/gtkshortcutswindow.c:1058 gtk/ui/gtkemojichooser.ui:362
+#: gtk/ui/gtkfilechooserwidget.ui:263 gtk/ui/gtkplacesview.ui:207
 msgid "Try a different search"
 msgstr "جست‌وجو دیگری را امتحان کنید"
 
-#: gtk/gtkstacksidebar.c:154
+#: gtk/gtkstacksidebar.c:160
 msgctxt "accessibility"
 msgid "Sidebar"
 msgstr "نوار کناری"
 
-#: gtk/gtktext.c:6348 gtk/gtktextview.c:9263
+#: gtk/gtktext.c:6344
+msgid "Change di_rection"
+msgstr "دگرگونی _جهت"
+
+#: gtk/gtktext.c:6349 gtk/gtktextview.c:9360
 msgid "Insert _Emoji"
 msgstr "درج _ایموجی"
 
-#: gtk/gtktextview.c:9245
+#: gtk/gtktextencoding.c:31
+msgctxt "Encoding name"
+msgid "Automatically Detected"
+msgstr "تشخیص داده به صورت خودکار"
+
+#: gtk/gtktextencoding.c:32
+msgctxt "Encoding name"
+msgid "ASCII"
+msgstr "اَسکی"
+
+#: gtk/gtktextencoding.c:34 gtk/gtktextencoding.c:47 gtk/gtktextencoding.c:74
+#: gtk/gtktextencoding.c:95
+msgctxt "Encoding name"
+msgid "Western"
+msgstr "غربی"
+
+#: gtk/gtktextencoding.c:35 gtk/gtktextencoding.c:75 gtk/gtktextencoding.c:93
+msgctxt "Encoding name"
+msgid "Central European"
+msgstr "اروپای مرکزی"
+
+#: gtk/gtktextencoding.c:36
+msgctxt "Encoding name"
+msgid "South European"
+msgstr "اروپای جنوبی"
+
+#: gtk/gtktextencoding.c:37 gtk/gtktextencoding.c:45 gtk/gtktextencoding.c:100
+msgctxt "Encoding name"
+msgid "Baltic"
+msgstr "بالتی"
+
+#: gtk/gtktextencoding.c:38 gtk/gtktextencoding.c:76 gtk/gtktextencoding.c:83
+#: gtk/gtktextencoding.c:85 gtk/gtktextencoding.c:94
+msgctxt "Encoding name"
+msgid "Cyrillic"
+msgstr "سیریلیک"
+
+#: gtk/gtktextencoding.c:39 gtk/gtktextencoding.c:79 gtk/gtktextencoding.c:99
+msgctxt "Encoding name"
+msgid "Arabic"
+msgstr "عربی"
+
+#: gtk/gtktextencoding.c:40 gtk/gtktextencoding.c:96
+msgctxt "Encoding name"
+msgid "Greek"
+msgstr "یونانی"
+
+#: gtk/gtktextencoding.c:41
+msgctxt "Encoding name"
+msgid "Hebrew Visual"
+msgstr "عبری دیداری"
+
+#: gtk/gtktextencoding.c:42 gtk/gtktextencoding.c:77 gtk/gtktextencoding.c:97
+msgctxt "Encoding name"
+msgid "Turkish"
+msgstr "ترکی"
+
+#: gtk/gtktextencoding.c:43
+msgctxt "Encoding name"
+msgid "Nordic"
+msgstr "اسکاندیناویایی"
+
+#: gtk/gtktextencoding.c:44 gtk/gtktextencoding.c:89
+msgctxt "Encoding name"
+msgid "Thai"
+msgstr "تایلندی"
+
+#: gtk/gtktextencoding.c:46
+msgctxt "Encoding name"
+msgid "Celtic"
+msgstr "سلتی"
+
+#: gtk/gtktextencoding.c:48
+msgctxt "Encoding name"
+msgid "Romanian"
+msgstr "رومانیایی"
+
+#: gtk/gtktextencoding.c:50 gtk/gtktextencoding.c:51 gtk/gtktextencoding.c:52
+#: gtk/gtktextencoding.c:53 gtk/gtktextencoding.c:54 gtk/gtktextencoding.c:55
+#: gtk/gtktextencoding.c:56 gtk/gtktextencoding.c:57
+msgctxt "Encoding name"
+msgid "Unicode"
+msgstr "یونی‌کد"
+
+#: gtk/gtktextencoding.c:59
+msgctxt "Encoding name"
+msgid "Armenian"
+msgstr "ارمنی"
+
+#: gtk/gtktextencoding.c:60 gtk/gtktextencoding.c:61 gtk/gtktextencoding.c:67
+msgctxt "Encoding name"
+msgid "Chinese Traditional"
+msgstr "چینی سنتی"
+
+#: gtk/gtktextencoding.c:62
+msgctxt "Encoding name"
+msgid "Cyrillic/Russian"
+msgstr "سیریلیک/روسی"
+
+#: gtk/gtktextencoding.c:63 gtk/gtktextencoding.c:64 gtk/gtktextencoding.c:65
+#: gtk/gtktextencoding.c:81 gtk/gtktextencoding.c:87
+msgctxt "Encoding name"
+msgid "Japanese"
+msgstr "ژاپنی"
+
+#: gtk/gtktextencoding.c:66 gtk/gtktextencoding.c:82 gtk/gtktextencoding.c:84
+#: gtk/gtktextencoding.c:90
+msgctxt "Encoding name"
+msgid "Korean"
+msgstr "کره‌ای"
+
+#: gtk/gtktextencoding.c:69 gtk/gtktextencoding.c:70 gtk/gtktextencoding.c:71
+msgctxt "Encoding name"
+msgid "Chinese Simplified"
+msgstr "چینی ساده‌شده"
+
+#: gtk/gtktextencoding.c:72
+msgctxt "Encoding name"
+msgid "Georgian"
+msgstr "گرجی"
+
+#: gtk/gtktextencoding.c:78 gtk/gtktextencoding.c:98
+msgctxt "Encoding name"
+msgid "Hebrew"
+msgstr "عبری"
+
+#: gtk/gtktextencoding.c:86
+msgctxt "Encoding name"
+msgid "Cyrillic/Ukrainian"
+msgstr "سیریلیک/اوکراینی"
+
+#: gtk/gtktextencoding.c:88 gtk/gtktextencoding.c:91 gtk/gtktextencoding.c:101
+msgctxt "Encoding name"
+msgid "Vietnamese"
+msgstr "ویتنامی"
+
+#: gtk/gtktextencoding.c:163
+msgctxt "Line ending name"
+msgid "Unchanged"
+msgstr "بدون تغییر"
+
+#: gtk/gtktextencoding.c:164
+msgctxt "Line ending name"
+msgid "Unix/Linux"
+msgstr "یونیکس/لینوکس"
+
+#: gtk/gtktextencoding.c:165
+msgctxt "Line ending name"
+msgid "Windows"
+msgstr "پنجره‌ها"
+
+#: gtk/gtktextencoding.c:166
+msgctxt "Line ending name"
+msgid "Mac OS Classic"
+msgstr "سامانه عامل کلاسیک مک"
+
+#: gtk/gtktextview.c:9342
 msgid "_Undo"
 msgstr "بر_گردان"
 
-#: gtk/gtktextview.c:9249
+#: gtk/gtktextview.c:9346
 msgid "_Redo"
 msgstr "_انجام دوباره"
 
-#: gtk/gtkwindow.c:6200
+#: gtk/gtkwindow.c:6319
 #, c-format
 msgid "Do you want to use GTK Inspector?"
 msgstr "می‌خواهید از بازرس +GTK استفاده کنید؟"
 
-#: gtk/gtkwindow.c:6202
+#: gtk/gtkwindow.c:6321
 #, c-format
 msgid ""
 "GTK Inspector is an interactive debugger that lets you explore and modify the "
@@ -3665,31 +3866,31 @@ msgstr ""
 "بازرس +GTK یک بازرس تعاملی است که به شما اجازه پیمایش و تغییر هسته برنامه‌های +GTK "
 "را می‌دهد. استفاده از آن ممکن است باعث شود که برنامه‌ها قفل کنند یا از هم بپاشند."
 
-#: gtk/gtkwindow.c:6207
+#: gtk/gtkwindow.c:6326
 msgid "Don’t show this message again"
 msgstr "این پیام را دوباره نشان نده"
 
-#: gtk/gtkwindowcontrols.c:309 gtk/gtkwindowhandle.c:234
+#: gtk/gtkwindowcontrols.c:325 gtk/gtkwindowhandle.c:237
 msgid "Minimize"
 msgstr "حداقل کردن"
 
-#: gtk/gtkwindowcontrols.c:311
+#: gtk/gtkwindowcontrols.c:327
 msgid "Minimize the window"
 msgstr "کمینه کردن پنجره"
 
-#: gtk/gtkwindowcontrols.c:335 gtk/gtkwindowhandle.c:240
+#: gtk/gtkwindowcontrols.c:351 gtk/gtkwindowhandle.c:243
 msgid "Maximize"
 msgstr "حداکثر کردن"
 
-#: gtk/gtkwindowcontrols.c:337
+#: gtk/gtkwindowcontrols.c:353
 msgid "Maximize the window"
 msgstr "بیشینه کردن پنجره"
 
-#: gtk/gtkwindowcontrols.c:359
+#: gtk/gtkwindowcontrols.c:375
 msgid "Close the window"
 msgstr "بستن پنجره"
 
-#: gtk/gtkwindowhandle.c:227
+#: gtk/gtkwindowhandle.c:230
 msgid "Restore"
 msgstr "بازآوری"
 
@@ -3749,17 +3950,17 @@ msgstr "نمایش"
 msgid "Hover to load"
 msgstr "شناوری برای بار شدن"
 
-#: gtk/inspector/clipboard.c:278
+#: gtk/inspector/clipboard.c:286
 msgctxt "clipboard"
 msgid "empty"
 msgstr "خالی"
 
-#: gtk/inspector/clipboard.c:283 gtk/inspector/clipboard.c:325
+#: gtk/inspector/clipboard.c:291 gtk/inspector/clipboard.c:344
 msgctxt "clipboard"
 msgid "local"
 msgstr "محلّی"
 
-#: gtk/inspector/clipboard.c:285 gtk/inspector/clipboard.c:327
+#: gtk/inspector/clipboard.c:293 gtk/inspector/clipboard.c:346
 msgctxt "clipboard"
 msgid "remote"
 msgstr "دوردست"
@@ -3768,7 +3969,7 @@ msgstr "دوردست"
 msgid "Drag and hold here"
 msgstr "کشیدن و نگه داشتن در این‌جا"
 
-#: gtk/inspector/clipboard.ui:71 gtk/inspector/window.ui:574
+#: gtk/inspector/clipboard.ui:71 gtk/inspector/window.ui:572
 msgid "Clipboard"
 msgstr "تخته‌گیره"
 
@@ -3847,139 +4048,151 @@ msgstr "سبک کلاس‌ها"
 msgid "CSS Property"
 msgstr "مشخصه CSS"
 
+#: gtk/inspector/general.c:446
+msgid "IM Context is hardcoded by GTK_IM_MODULE"
+msgstr "بافتار IM به دست GTK_IM_MODULE به صورت سخت رمز شده است"
+
 # farmaan
-#: gtk/inspector/general.c:372
-msgctxt "GL version"
+#: gtk/inspector/general.c:577
+msgctxt "GL renderer"
 msgid "None"
 msgstr "هیچ‌کدام"
 
-#: gtk/inspector/general.c:464
+#: gtk/inspector/general.c:674
 msgctxt "GL version"
 msgid "Unknown"
 msgstr "ناشناخته"
 
-#: gtk/inspector/general.c:526
-msgctxt "Vulkan device"
-msgid "Disabled"
-msgstr "از کار افتاده"
-
-#: gtk/inspector/general.c:527 gtk/inspector/general.c:528
-msgctxt "Vulkan version"
-msgid "Disabled"
-msgstr "از کار افتاده"
-
 # farmaan
-#: gtk/inspector/general.c:579
+#: gtk/inspector/general.c:928 gtk/inspector/general.c:967
 msgctxt "Vulkan device"
 msgid "None"
 msgstr "هیچ‌کدام"
 
-# farmaan
-#: gtk/inspector/general.c:580 gtk/inspector/general.c:581
-msgctxt "Vulkan version"
-msgid "None"
-msgstr "هیچ‌کدام"
-
-#: gtk/inspector/general.c:934
-msgid "IM Context is hardcoded by GTK_IM_MODULE"
-msgstr "بافتار IM به دست GTK_IM_MODULE به صورت سخت رمز شده است"
+#: gtk/inspector/general.ui:13
+msgid "Copy to clipboard as gitlab markdown"
+msgstr "رونوشت در تخته‌گیره به شکل مارک‌دون گیت‌لب"
 
-#: gtk/inspector/general.ui:31
+#: gtk/inspector/general.ui:45
 msgid "GTK Version"
 msgstr "نگارش GTK"
 
-#: gtk/inspector/general.ui:57
+#: gtk/inspector/general.ui:71
 msgid "GDK Backend"
 msgstr "پسانه GDK"
 
-#: gtk/inspector/general.ui:83
+#: gtk/inspector/general.ui:97
 msgid "GSK Renderer"
 msgstr "پرداختگر GSK"
 
-#: gtk/inspector/general.ui:109
+#: gtk/inspector/general.ui:123
 msgid "Pango Fontmap"
 msgstr "نگاشت قلم پنگو"
 
-#: gtk/inspector/general.ui:135
+#: gtk/inspector/general.ui:149
 msgid "Media Backend"
 msgstr "پسانهٔ رسانه"
 
-#: gtk/inspector/general.ui:161
+#: gtk/inspector/general.ui:175
 msgid "Input Method"
 msgstr "روش ورودی"
 
-#: gtk/inspector/general.ui:198
+#: gtk/inspector/general.ui:212
 msgid "Application ID"
 msgstr "شناسهٔ برنامه"
 
-#: gtk/inspector/general.ui:224
+#: gtk/inspector/general.ui:238
 msgid "Resource Path"
 msgstr "مسیر منبع"
 
-#: gtk/inspector/general.ui:261 gtk/ui/gtkplacesview.ui:67
+#: gtk/inspector/general.ui:275 gtk/ui/gtkplacesview.ui:63
 msgid "Prefix"
 msgstr "پیشوند"
 
-#: gtk/inspector/general.ui:460
+#: gtk/inspector/general.ui:302
+msgid "Environment"
+msgstr "محیط"
+
+#: gtk/inspector/general.ui:405
 msgid "Display"
 msgstr "نمایشگر"
 
-#: gtk/inspector/general.ui:487
+#: gtk/inspector/general.ui:432
 msgid "RGBA Visual"
 msgstr "RGBA بصری"
 
-#: gtk/inspector/general.ui:513
+#: gtk/inspector/general.ui:458
 msgid "Composited"
 msgstr "مرکب"
 
-#: gtk/inspector/general.ui:538
+#: gtk/inspector/general.ui:483
 msgid "Protocols"
 msgstr "شیوه‌نامه‌ها"
 
-#: gtk/inspector/general.ui:594
+#: gtk/inspector/general.ui:539
+msgid "GL Renderer"
+msgstr "پرداختگر GL"
+
+#: gtk/inspector/general.ui:568
+msgid "GL Vendor"
+msgstr "تولیدکننده GL"
+
+#: gtk/inspector/general.ui:597
 msgid "GL Version"
 msgstr "نسخهٔ GL"
 
-#: gtk/inspector/general.ui:621
-msgid "GL Backend Version"
-msgstr "نگارش پسانهٔ GL"
-
-#: gtk/inspector/general.ui:671
+#: gtk/inspector/general.ui:624
 msgid "GL Backend Vendor"
 msgstr "سازندهٔ پسانهٔ GL"
 
-#: gtk/inspector/general.ui:698
-msgid "GL_VENDOR"
-msgstr "GL_VENDOR"
+#: gtk/inspector/general.ui:651
+msgid "GL Backend Version"
+msgstr "نگارش پسانهٔ GL"
+
+#: gtk/inspector/general.ui:701
+msgid "GL Full Version"
+msgstr "نگارش کمل GL"
 
-#: gtk/inspector/general.ui:727
-msgid "GL_RENDERER"
-msgstr "GL_RENDERER"
+#: gtk/inspector/general.ui:730
+msgid "GLSL Version"
+msgstr "نگارش GLSL"
 
-#: gtk/inspector/general.ui:756
-msgid "GL_VERSION"
-msgstr "GL_VERSION"
+#: gtk/inspector/general.ui:759
+msgid "GL Extensions"
+msgstr "افزونه‌های GL"
 
-#: gtk/inspector/general.ui:785
-msgid "GL_SHADING_LANGUAGE_VERSION"
-msgstr "GL_SHADING_LANGUAGE_VERSION"
+#: gtk/inspector/general.ui:847
+msgid "EGL Extensions"
+msgstr "افزونه‌های EGL"
 
-#: gtk/inspector/general.ui:813 gtk/inspector/general.ui:929
-msgid "Extensions"
-msgstr "افزونه‌ها"
+#: gtk/inspector/general.ui:934
+msgid "GL Features"
+msgstr "ویژگی‌های GL"
 
-#: gtk/inspector/general.ui:849
+#: gtk/inspector/general.ui:970
 msgid "Vulkan Device"
 msgstr "افزارهٔ ولکان"
 
-#: gtk/inspector/general.ui:876
-msgid "Vulkan API version"
+#: gtk/inspector/general.ui:997
+msgid "Vulkan API Version"
 msgstr "نگارش API ولکان"
 
-#: gtk/inspector/general.ui:903
-msgid "Vulkan driver version"
+#: gtk/inspector/general.ui:1024
+msgid "Vulkan Driver Version"
 msgstr "نگارش راه‌انداز ولکان"
 
+#: gtk/inspector/general.ui:1073
+msgid "Vulkan Layers"
+msgstr "لایه‌های ولکان"
+
+#: gtk/inspector/general.ui:1142
+msgid "Vulkan Extensions"
+msgstr "افزونه‌های ولکان"
+
+#: gtk/inspector/general.ui:1229
+msgid "Vulkan Features"
+msgstr "ویژگی‌های ولکان"
+
 #: gtk/inspector/menu.c:264
 msgid "Unnamed section"
 msgstr "قسمت بدون نام"
@@ -4042,7 +4255,7 @@ msgstr "سطح"
 
 #: gtk/inspector/misc-info.ui:365 gtk/inspector/misc-info.ui:400
 #: gtk/inspector/misc-info.ui:435 gtk/inspector/prop-editor.c:1153
-#: gtk/inspector/prop-editor.c:1536 gtk/inspector/window.ui:396
+#: gtk/inspector/prop-editor.c:1536 gtk/inspector/window.ui:394
 msgid "Properties"
 msgstr "ویژگی‌ها"
 
@@ -4066,7 +4279,7 @@ msgstr "تعداد قاب"
 msgid "Frame Rate"
 msgstr "آهنگ قاب"
 
-#: gtk/inspector/misc-info.ui:527 gtk/inspector/visual.ui:315
+#: gtk/inspector/misc-info.ui:527 gtk/inspector/visual.ui:314
 msgid "Scale"
 msgstr "مقیاس"
 
@@ -4195,7 +4408,7 @@ msgstr "منبع:"
 msgid "Defined At"
 msgstr "تعریف شده در"
 
-#: gtk/inspector/recorder.c:2021
+#: gtk/inspector/recorder.c:2036
 #, c-format
 msgid "Saving RenderNode failed"
 msgstr "ذخیرهٔ RenderNode شکست خورد"
@@ -4248,7 +4461,7 @@ msgstr "نام:"
 msgid "Type:"
 msgstr "نوع:"
 
-#: gtk/inspector/resource-list.ui:164 tools/gtk-image-tool-info.c:54
+#: gtk/inspector/resource-list.ui:164 tools/gtk-image-tool-info.c:56
 msgid "Size:"
 msgstr "اندازه:"
 
@@ -4362,90 +4575,91 @@ msgstr "تم شمایل‌ها"
 msgid "Text Direction"
 msgstr "جهت متن"
 
+#. translators: these strings must be separated by newlines
 #: gtk/inspector/visual.ui:184
-msgid "Left-to-Right"
-msgstr "چپ به راست"
-
-#: gtk/inspector/visual.ui:185
-msgid "Right-to-Left"
-msgstr "راست به چپ"
+msgid ""
+"Left-to-Right\n"
+"Right-to-Left"
+msgstr ""
+"چپ به راست\n"
+"راست به چپ"
 
-#: gtk/inspector/visual.ui:202
+#: gtk/inspector/visual.ui:201
 msgid "Animations"
 msgstr "پویانمایی‌ها"
 
-#: gtk/inspector/visual.ui:227
+#: gtk/inspector/visual.ui:226
 msgid "Slowdown"
 msgstr "کاهش سرعت"
 
-#: gtk/inspector/visual.ui:362
+#: gtk/inspector/visual.ui:361
 msgid "Rendering"
 msgstr "پرداخت کردن"
 
-#: gtk/inspector/visual.ui:377
-msgctxt "Font rendering"
-msgid "Automatic"
-msgstr "خودکار"
-
-#: gtk/inspector/visual.ui:378
+#. translators: these strings must be separated by newlines
+#: gtk/inspector/visual.ui:376
 msgctxt "Font rendering"
-msgid "Manual"
-msgstr "دستی"
+msgid ""
+"Automatic\n"
+"Manual"
+msgstr ""
+"خودکار\n"
+"دستی"
 
-#: gtk/inspector/visual.ui:405
+#: gtk/inspector/visual.ui:403
 msgid "Show Framerate"
 msgstr "نمایش آهنگ قاب"
 
-#: gtk/inspector/visual.ui:430
+#: gtk/inspector/visual.ui:428
 msgid "Show Graphic Updates"
 msgstr "نمایش بروزرسانی‌های گرافیکی"
 
-#: gtk/inspector/visual.ui:450
+#: gtk/inspector/visual.ui:448
 msgid ""
 "Tints all the places where the current renderer uses Cairo instead of the GPU."
 msgstr "تیره کردن تمام جاهایی که پرداختگر کنونی به جای GPU از کایرو استفاده می‌کند."
 
-#: gtk/inspector/visual.ui:456
+#: gtk/inspector/visual.ui:454
 msgid "Show Cairo Rendering"
 msgstr "نمایش پرداخت کایرو"
 
-#: gtk/inspector/visual.ui:481
+#: gtk/inspector/visual.ui:479
 msgid "Show Baselines"
 msgstr "نمایش مبناها"
 
-#: gtk/inspector/visual.ui:509
+#: gtk/inspector/visual.ui:507
 msgid "Show Layout Borders"
 msgstr "نمایش حاشیه‌های چیدمان"
 
-#: gtk/inspector/visual.ui:566
+#: gtk/inspector/visual.ui:564
 msgid "CSS Padding"
 msgstr "فاصله‌دهی CSS"
 
-#: gtk/inspector/visual.ui:576
+#: gtk/inspector/visual.ui:574
 msgid "CSS Border"
 msgstr "لبهٔ CSS"
 
-#: gtk/inspector/visual.ui:586
+#: gtk/inspector/visual.ui:584
 msgid "CSS Margin"
 msgstr "حاشیهٔ CSS"
 
-#: gtk/inspector/visual.ui:596
+#: gtk/inspector/visual.ui:594
 msgid "Widget Margin"
 msgstr "حاشیهٔ ابزارک"
 
-#: gtk/inspector/visual.ui:631
+#: gtk/inspector/visual.ui:629
 msgid "Show Focus"
 msgstr "نمایش تمرکز"
 
-#: gtk/inspector/visual.ui:656
+#: gtk/inspector/visual.ui:654
 msgid "Show Accessibility warnings"
 msgstr "شنمایش هشدارهای دسترسی‌پذیری"
 
-#: gtk/inspector/visual.ui:681
+#: gtk/inspector/visual.ui:679
 msgid "Show Graphics Offload"
 msgstr "نمایش تخلیهٔ گرافیکی"
 
-#: gtk/inspector/visual.ui:713
+#: gtk/inspector/visual.ui:711
 msgid "Inspect Inspector"
 msgstr "بازرسی بازرس"
 
@@ -4497,79 +4711,79 @@ msgstr "هم‌نیای پیشین"
 msgid "List Position"
 msgstr "جایگاه فهرست"
 
-#: gtk/inspector/window.ui:356
+#: gtk/inspector/window.ui:354
 msgid "Next sibling"
 msgstr "هم‌نیای بعدی"
 
-#: gtk/inspector/window.ui:386
+#: gtk/inspector/window.ui:384
 msgid "Miscellaneous"
 msgstr "گوناگون"
 
-#: gtk/inspector/window.ui:407 gtk/print/ui/gtkprintunixdialog.ui:451
+#: gtk/inspector/window.ui:405 gtk/print/ui/gtkprintunixdialog.ui:451
 msgid "Layout"
 msgstr "صفحه‌بندی"
 
-#: gtk/inspector/window.ui:418
+#: gtk/inspector/window.ui:416
 msgid "CSS Nodes"
 msgstr "گره‌های CSS"
 
-#: gtk/inspector/window.ui:429
+#: gtk/inspector/window.ui:427
 msgid "Size Groups"
 msgstr "گروه‌های اندازه‌ها"
 
-#: gtk/inspector/window.ui:438 gtk/inspector/window.ui:447
+#: gtk/inspector/window.ui:436 gtk/inspector/window.ui:445
 msgid "Data"
 msgstr "داده"
 
-#: gtk/inspector/window.ui:457
+#: gtk/inspector/window.ui:455
 msgid "Actions"
 msgstr "کنش‌ها"
 
-#: gtk/inspector/window.ui:468
+#: gtk/inspector/window.ui:466
 msgid "Menu"
 msgstr "فهرست"
 
-#: gtk/inspector/window.ui:477
+#: gtk/inspector/window.ui:475
 msgid "Controllers"
 msgstr "واپایشگرها"
 
-#: gtk/inspector/window.ui:487
+#: gtk/inspector/window.ui:485
 msgid "Magnifier"
 msgstr "ذره‌بین"
 
-#: gtk/inspector/window.ui:508
+#: gtk/inspector/window.ui:506
 msgid "Accessibility"
 msgstr "دسترسی‌پذیری"
 
-#: gtk/inspector/window.ui:532
+#: gtk/inspector/window.ui:530
 msgid "Global"
 msgstr "عمومی"
 
-#: gtk/inspector/window.ui:545
+#: gtk/inspector/window.ui:543
 msgid "Information"
 msgstr "اطّلاعات"
 
-#: gtk/inspector/window.ui:554
+#: gtk/inspector/window.ui:552
 msgid "Settings"
 msgstr "تنظیمات"
 
-#: gtk/inspector/window.ui:563
+#: gtk/inspector/window.ui:561
 msgid "Resources"
 msgstr "منابع"
 
-#: gtk/inspector/window.ui:584
+#: gtk/inspector/window.ui:582
 msgid "Statistics"
 msgstr "آمارها"
 
-#: gtk/inspector/window.ui:595
+#: gtk/inspector/window.ui:593
 msgid "Logging"
 msgstr "گزارش‌گیری"
 
-#: gtk/inspector/window.ui:610
+#: gtk/inspector/window.ui:608
 msgid "CSS"
 msgstr "CSS"
 
-#: gtk/inspector/window.ui:619
+#: gtk/inspector/window.ui:617
 msgid "Recorder"
 msgstr "ضبط‌کننده"
 
@@ -6091,7 +6305,7 @@ msgstr "درباره"
 msgid "Credits"
 msgstr "دست‌اندرکاران"
 
-#: gtk/ui/gtkaboutdialog.ui:219
+#: gtk/ui/gtkaboutdialog.ui:221
 msgid "System"
 msgstr "سامانه"
 
@@ -6135,6 +6349,34 @@ msgstr "نمایش همه"
 msgid "Quit %s"
 msgstr "خروج از %s"
 
+#: gtk/ui/gtkapplication-quartz.ui:53
+msgid "Undo"
+msgstr "برگردان"
+
+#: gtk/ui/gtkapplication-quartz.ui:57
+msgid "Redo"
+msgstr "انجام دوباره"
+
+#: gtk/ui/gtkapplication-quartz.ui:63
+msgid "Cut"
+msgstr "برش"
+
+#: gtk/ui/gtkapplication-quartz.ui:67
+msgid "Copy"
+msgstr "رونوشت"
+
+#: gtk/ui/gtkapplication-quartz.ui:71
+msgid "Paste"
+msgstr "چسباندن"
+
+#: gtk/ui/gtkapplication-quartz.ui:75
+msgid "Delete"
+msgstr "حذف"
+
+#: gtk/ui/gtkapplication-quartz.ui:79
+msgid "Select All"
+msgstr "گزینش همه"
+
 #: gtk/ui/gtkassistant.ui:64
 msgid "_Finish"
 msgstr "_پایان"
@@ -6254,7 +6496,7 @@ msgstr "اخیر"
 msgid "Create Folder"
 msgstr "ایجاد پوشه"
 
-#: gtk/ui/gtkfilechooserwidget.ui:202
+#: gtk/ui/gtkfilechooserwidget.ui:205
 msgid "Remote location — only searching the current folder"
 msgstr "مکان دوردست — تنها با جست‌وجو در پوشه فعلی"
 
@@ -6262,7 +6504,7 @@ msgstr "مکان دوردست — تنها با جست‌وجو در پوشه ف
 msgid "Folder Name"
 msgstr "نام پوشه"
 
-#: gtk/ui/gtkfilechooserwidget.ui:360
+#: gtk/ui/gtkfilechooserwidget.ui:358
 msgid "_Create"
 msgstr "_ایجاد"
 
@@ -6290,21 +6532,21 @@ msgstr "تک‌عرض"
 msgid "Language"
 msgstr "زبان"
 
-#: gtk/ui/gtkfontchooserwidget.ui:199 gtk/ui/gtkfontchooserwidget.ui:201
-#: gtk/ui/gtkfontchooserwidget.ui:354 gtk/ui/gtkfontchooserwidget.ui:358
+#: gtk/ui/gtkfontchooserwidget.ui:197 gtk/ui/gtkfontchooserwidget.ui:199
+#: gtk/ui/gtkfontchooserwidget.ui:349 gtk/ui/gtkfontchooserwidget.ui:353
 msgid "Preview Font"
 msgstr "پیش‌نمایش قلم"
 
-#: gtk/ui/gtkfontchooserwidget.ui:297
+#: gtk/ui/gtkfontchooserwidget.ui:295
 msgid "No Fonts Found"
 msgstr "هیچ قلمی پیدا نشد"
 
-#: gtk/ui/gtkmediacontrols.ui:47
+#: gtk/ui/gtkmediacontrols.ui:45
 msgctxt "media controls"
 msgid "Position"
 msgstr "جایگاه"
 
-#: gtk/ui/gtkmediacontrols.ui:65
+#: gtk/ui/gtkmediacontrols.ui:61
 msgctxt "media controls"
 msgid "Volume"
 msgstr "حجم صدا"
@@ -6341,35 +6583,39 @@ msgstr "منظره‌ای معکوس"
 msgid "Server Addresses"
 msgstr "آدرس کارساز"
 
-#: gtk/ui/gtkplacesview.ui:28
+#: gtk/ui/gtkplacesview.ui:26
 msgid "Server addresses are made up of a protocol prefix and an address. Examples:"
 msgstr "آدرس کارسازها از یک پیشوند پروتکل و یک آدرس تشکیل شده‌اند. مثال‌ها:"
 
-#: gtk/ui/gtkplacesview.ui:54
+#: gtk/ui/gtkplacesview.ui:52
 msgid "Available Protocols"
 msgstr "پروتکل‌های موجود"
 
 #. Translators: Server as any successfully connected network address
-#: gtk/ui/gtkplacesview.ui:106
+#: gtk/ui/gtkplacesview.ui:100
 msgid "No recent servers found"
 msgstr "هیچ کارسازی که اخیرا استفاده شده باشد پیدا نشد"
 
-#: gtk/ui/gtkplacesview.ui:129
+#: gtk/ui/gtkplacesview.ui:123
 msgid "Recent Servers"
 msgstr "کارسازهای اخیر"
 
-#: gtk/ui/gtkplacesview.ui:209
+#: gtk/ui/gtkplacesview.ui:201
 msgid "No results found"
 msgstr "هیچ نتیجه‌ای پیدا نشد"
 
-#: gtk/ui/gtkplacesview.ui:240
+#: gtk/ui/gtkplacesview.ui:229
 msgid "Connect to _Server"
 msgstr "اتصال به _کارساز"
 
-#: gtk/ui/gtkplacesview.ui:265
+#: gtk/ui/gtkplacesview.ui:252
 msgid "Enter server address…"
 msgstr "وارد کردن نشانی کارساز…"
 
+#: gtk/ui/gtkplacesview.ui:265
+msgid "Show recent servers"
+msgstr "نمایش کارسازهای اخیر"
+
 #. this is the header for the printer status column in the print dialog
 #: gtk/print/ui/gtkprintunixdialog.ui:142
 msgid "Status"
@@ -6475,35 +6721,35 @@ msgstr "_سینی خروجی:"
 msgid "Or_ientation:"
 msgstr "_جهت:"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:805
+#: gtk/print/ui/gtkprintunixdialog.ui:806
 msgid "Job Details"
 msgstr "جزییات کار"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:820
+#: gtk/print/ui/gtkprintunixdialog.ui:821
 msgid "Pri_ority:"
 msgstr "او_لویت:"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:841
+#: gtk/print/ui/gtkprintunixdialog.ui:842
 msgid "_Billing info:"
 msgstr "ا_طلاعات صورتحساب:"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:874
+#: gtk/print/ui/gtkprintunixdialog.ui:875
 msgid "Print Document"
 msgstr "چاپ سند"
 
 #. this is one of the choices for the print at option in the print dialog
-#: gtk/print/ui/gtkprintunixdialog.ui:887
+#: gtk/print/ui/gtkprintunixdialog.ui:888
 msgid "_Now"
 msgstr "_اکنون"
 
 #. this is one of the choices for the print at option in the print dialog. It also serves as the label for an entry that allows the user to enter a time.
-#: gtk/print/ui/gtkprintunixdialog.ui:901
+#: gtk/print/ui/gtkprintunixdialog.ui:902
 msgid "A_t:"
 msgstr "_در:"
 
 #. Ability to parse the am/pm format depends on actual locale. You can remove the am/pm values below for your locale if they are not supported.
-#: gtk/print/ui/gtkprintunixdialog.ui:903 gtk/print/ui/gtkprintunixdialog.ui:905
-#: gtk/print/ui/gtkprintunixdialog.ui:921 gtk/print/ui/gtkprintunixdialog.ui:923
+#: gtk/print/ui/gtkprintunixdialog.ui:904 gtk/print/ui/gtkprintunixdialog.ui:906
+#: gtk/print/ui/gtkprintunixdialog.ui:922 gtk/print/ui/gtkprintunixdialog.ui:924
 msgid ""
 "Specify the time of print,\n"
 " e.g. 15∶30, 2∶35 pm, 14∶15∶20, 11∶46∶30 am, 4 pm"
@@ -6512,75 +6758,75 @@ msgstr ""
 "مثلا ۱۵:۳۰، ۲:۳۵ ب.ظ، ۱۴:۱۵:۲۰، ۱۱:۴۶ ق.ظ، ۴ ب.ظ"
 
 #. this is one of the choices for the print at option in the print dialog. It means that the print job will not be printed until it explicitly gets 'released'.
-#: gtk/print/ui/gtkprintunixdialog.ui:935
+#: gtk/print/ui/gtkprintunixdialog.ui:936
 msgid "On _hold"
 msgstr "_در حال انتظار"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:937 gtk/print/ui/gtkprintunixdialog.ui:938
+#: gtk/print/ui/gtkprintunixdialog.ui:938 gtk/print/ui/gtkprintunixdialog.ui:939
 msgid "Hold the job until it is explicitly released"
 msgstr "متوقف کردن کار تا زمانی که به صراحت منتشر شود"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:965
+#: gtk/print/ui/gtkprintunixdialog.ui:966
 msgid "Add Cover Page"
 msgstr "اضافه‌کردن صفحهٔ جلد"
 
 #. this is the label used for the option in the print dialog that controls the front cover page.
-#: gtk/print/ui/gtkprintunixdialog.ui:980
+#: gtk/print/ui/gtkprintunixdialog.ui:981
 msgid "Be_fore:"
 msgstr "_پیش از:"
 
 #. this is the label used for the option in the print dialog that controls the back cover page.
-#: gtk/print/ui/gtkprintunixdialog.ui:1001
+#: gtk/print/ui/gtkprintunixdialog.ui:1002
 msgid "_After:"
 msgstr "_پس از:"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:1030
+#: gtk/print/ui/gtkprintunixdialog.ui:1031
 msgid "Job"
 msgstr "کار"
 
 #. This will appear as a tab label in the print dialog.
-#: gtk/print/ui/gtkprintunixdialog.ui:1060
+#: gtk/print/ui/gtkprintunixdialog.ui:1061
 msgid "Image Quality"
 msgstr "کیفیت تصویر"
 
 #. This will appear as a tab label in the print dialog.
-#: gtk/print/ui/gtkprintunixdialog.ui:1089
+#: gtk/print/ui/gtkprintunixdialog.ui:1090
 msgid "Color"
 msgstr "رنگ"
 
 #. This will appear as a tab label in the print dialog. It's a typographical term, as in "Binding and finishing"
-#: gtk/print/ui/gtkprintunixdialog.ui:1118
+#: gtk/print/ui/gtkprintunixdialog.ui:1119
 msgid "Finishing"
 msgstr "در حال پایان بردن"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:1147
+#: gtk/print/ui/gtkprintunixdialog.ui:1148
 msgid "Advanced"
 msgstr "پیشرفته"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:1163
+#: gtk/print/ui/gtkprintunixdialog.ui:1164
 msgid "Some of the settings in the dialog conflict"
 msgstr "بعضی از تنظیمات در محاوره ناسازگارند"
 
 #: modules/printbackends/gtkprintbackendcpdb.c:542
-#: modules/printbackends/gtkprintbackendcups.c:5668
+#: modules/printbackends/gtkprintbackendcups.c:5670
 msgctxt "Print job priority"
 msgid "Urgent"
 msgstr "فوری"
 
 #: modules/printbackends/gtkprintbackendcpdb.c:543
-#: modules/printbackends/gtkprintbackendcups.c:5669
+#: modules/printbackends/gtkprintbackendcups.c:5671
 msgctxt "Print job priority"
 msgid "High"
 msgstr "زیاد"
 
 #: modules/printbackends/gtkprintbackendcpdb.c:544
-#: modules/printbackends/gtkprintbackendcups.c:5670
+#: modules/printbackends/gtkprintbackendcups.c:5672
 msgctxt "Print job priority"
 msgid "Medium"
 msgstr "متوسّط"
 
 #: modules/printbackends/gtkprintbackendcpdb.c:545
-#: modules/printbackends/gtkprintbackendcups.c:5671
+#: modules/printbackends/gtkprintbackendcups.c:5673
 msgctxt "Print job priority"
 msgid "Low"
 msgstr "Ú©Ù…"
@@ -6589,7 +6835,7 @@ msgstr "Ú©Ù…"
 #. * dialog that controls the front cover page.
 #.
 #: modules/printbackends/gtkprintbackendcpdb.c:567
-#: modules/printbackends/gtkprintbackendcups.c:5814
+#: modules/printbackends/gtkprintbackendcups.c:5816
 msgctxt "printer option"
 msgid "Before"
 msgstr "پیش از"
@@ -6598,7 +6844,7 @@ msgstr "پیش از"
 #. * dialog that controls the back cover page.
 #.
 #: modules/printbackends/gtkprintbackendcpdb.c:574
-#: modules/printbackends/gtkprintbackendcups.c:5829
+#: modules/printbackends/gtkprintbackendcups.c:5831
 msgctxt "printer option"
 msgid "After"
 msgstr "پس از"
@@ -6774,229 +7020,229 @@ msgstr "چاپگر «%s» مشکلی دارد."
 msgid "; "
 msgstr "Ø› "
 
-#: modules/printbackends/gtkprintbackendcups.c:4609
-#: modules/printbackends/gtkprintbackendcups.c:4676
+#: modules/printbackends/gtkprintbackendcups.c:4611
+#: modules/printbackends/gtkprintbackendcups.c:4678
 msgctxt "printing option"
 msgid "Two Sided"
 msgstr "دو رو"
 
-#: modules/printbackends/gtkprintbackendcups.c:4610
+#: modules/printbackends/gtkprintbackendcups.c:4612
 msgctxt "printing option"
 msgid "Paper Type"
 msgstr "نوع کاغذ"
 
-#: modules/printbackends/gtkprintbackendcups.c:4611
+#: modules/printbackends/gtkprintbackendcups.c:4613
 msgctxt "printing option"
 msgid "Paper Source"
 msgstr "منبع کاغذ"
 
-#: modules/printbackends/gtkprintbackendcups.c:4612
-#: modules/printbackends/gtkprintbackendcups.c:4677
+#: modules/printbackends/gtkprintbackendcups.c:4614
+#: modules/printbackends/gtkprintbackendcups.c:4679
 msgctxt "printing option"
 msgid "Output Tray"
 msgstr "خروجی کاغذ"
 
-#: modules/printbackends/gtkprintbackendcups.c:4613
+#: modules/printbackends/gtkprintbackendcups.c:4615
 msgctxt "printing option"
 msgid "Resolution"
 msgstr "تفکیک‌پذیری"
 
-#: modules/printbackends/gtkprintbackendcups.c:4614
+#: modules/printbackends/gtkprintbackendcups.c:4616
 msgctxt "printing option"
 msgid "GhostScript pre-filtering"
 msgstr "پیش‌پالایش GhostScript"
 
-#: modules/printbackends/gtkprintbackendcups.c:4623
+#: modules/printbackends/gtkprintbackendcups.c:4625
 msgctxt "printing option value"
 msgid "One Sided"
 msgstr "یک رو"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4625
+#: modules/printbackends/gtkprintbackendcups.c:4627
 msgctxt "printing option value"
 msgid "Long Edge (Standard)"
 msgstr "لبه بلند (استاندارد)"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4627
+#: modules/printbackends/gtkprintbackendcups.c:4629
 msgctxt "printing option value"
 msgid "Short Edge (Flip)"
 msgstr "لبه کوتاه (برگشته)"
 
 #. Translators: this is an option of "Paper Source"
-#: modules/printbackends/gtkprintbackendcups.c:4629
 #: modules/printbackends/gtkprintbackendcups.c:4631
-#: modules/printbackends/gtkprintbackendcups.c:4639
+#: modules/printbackends/gtkprintbackendcups.c:4633
+#: modules/printbackends/gtkprintbackendcups.c:4641
 msgctxt "printing option value"
 msgid "Auto Select"
 msgstr "گزینش خودکار"
 
 #. Translators: this is an option of "Paper Source"
 #. Translators: this is an option of "Resolution"
-#: modules/printbackends/gtkprintbackendcups.c:4633
 #: modules/printbackends/gtkprintbackendcups.c:4635
 #: modules/printbackends/gtkprintbackendcups.c:4637
-#: modules/printbackends/gtkprintbackendcups.c:4641
+#: modules/printbackends/gtkprintbackendcups.c:4639
+#: modules/printbackends/gtkprintbackendcups.c:4643
 msgctxt "printing option value"
 msgid "Printer Default"
 msgstr "پیش‌فرض چاپگر"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4643
+#: modules/printbackends/gtkprintbackendcups.c:4645
 msgctxt "printing option value"
 msgid "Embed GhostScript fonts only"
 msgstr "تنها قلم‌های GhostScript نهفته شوند"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4645
+#: modules/printbackends/gtkprintbackendcups.c:4647
 msgctxt "printing option value"
 msgid "Convert to PS level 1"
 msgstr "تبدیل به سطح ۱ از PS"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4647
+#: modules/printbackends/gtkprintbackendcups.c:4649
 msgctxt "printing option value"
 msgid "Convert to PS level 2"
 msgstr "تبدیل به سطح ۲ از PS"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4649
+#: modules/printbackends/gtkprintbackendcups.c:4651
 msgctxt "printing option value"
 msgid "No pre-filtering"
 msgstr "بدون پیش‌پالایش"
 
 #. Translators: "Miscellaneous" is the label for a button, that opens
 #. up an extra panel of settings in a print dialog.
-#: modules/printbackends/gtkprintbackendcups.c:4658
+#: modules/printbackends/gtkprintbackendcups.c:4660
 msgctxt "printing option group"
 msgid "Miscellaneous"
 msgstr "متفرّقه"
 
-#: modules/printbackends/gtkprintbackendcups.c:4685
+#: modules/printbackends/gtkprintbackendcups.c:4687
 msgctxt "sides"
 msgid "One Sided"
 msgstr "یک رو"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4687
+#: modules/printbackends/gtkprintbackendcups.c:4689
 msgctxt "sides"
 msgid "Long Edge (Standard)"
 msgstr "لبه بلند (استاندارد)"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4689
+#: modules/printbackends/gtkprintbackendcups.c:4691
 msgctxt "sides"
 msgid "Short Edge (Flip)"
 msgstr "لبه کوتاه (برگشته)"
 
 #. Translators: Top output bin
-#: modules/printbackends/gtkprintbackendcups.c:4692
+#: modules/printbackends/gtkprintbackendcups.c:4694
 msgctxt "output-bin"
 msgid "Top Bin"
 msgstr "محفظه بالایی"
 
 #. Translators: Middle output bin
-#: modules/printbackends/gtkprintbackendcups.c:4694
+#: modules/printbackends/gtkprintbackendcups.c:4696
 msgctxt "output-bin"
 msgid "Middle Bin"
 msgstr "محفظه وسط"
 
 #. Translators: Bottom output bin
-#: modules/printbackends/gtkprintbackendcups.c:4696
+#: modules/printbackends/gtkprintbackendcups.c:4698
 msgctxt "output-bin"
 msgid "Bottom Bin"
 msgstr "محفظه پایین"
 
 #. Translators: Side output bin
-#: modules/printbackends/gtkprintbackendcups.c:4698
+#: modules/printbackends/gtkprintbackendcups.c:4700
 msgctxt "output-bin"
 msgid "Side Bin"
 msgstr "محفظه کنار"
 
 #. Translators: Left output bin
-#: modules/printbackends/gtkprintbackendcups.c:4700
+#: modules/printbackends/gtkprintbackendcups.c:4702
 msgctxt "output-bin"
 msgid "Left Bin"
 msgstr "محفظه چپ"
 
 #. Translators: Right output bin
-#: modules/printbackends/gtkprintbackendcups.c:4702
+#: modules/printbackends/gtkprintbackendcups.c:4704
 msgctxt "output-bin"
 msgid "Right Bin"
 msgstr "محفظه راست"
 
 #. Translators: Center output bin
-#: modules/printbackends/gtkprintbackendcups.c:4704
+#: modules/printbackends/gtkprintbackendcups.c:4706
 msgctxt "output-bin"
 msgid "Center Bin"
 msgstr "محفظه مرکزی"
 
 #. Translators: Rear output bin
-#: modules/printbackends/gtkprintbackendcups.c:4706
+#: modules/printbackends/gtkprintbackendcups.c:4708
 msgctxt "output-bin"
 msgid "Rear Bin"
 msgstr "محفظه عقب"
 
 #. Translators: Output bin where one sided output is oriented in the face-up position
-#: modules/printbackends/gtkprintbackendcups.c:4708
+#: modules/printbackends/gtkprintbackendcups.c:4710
 msgctxt "output-bin"
 msgid "Face Up Bin"
 msgstr "محفظه رو به بالا"
 
 #. Translators: Output bin where one sided output is oriented in the face-down position
-#: modules/printbackends/gtkprintbackendcups.c:4710
+#: modules/printbackends/gtkprintbackendcups.c:4712
 msgctxt "output-bin"
 msgid "Face Down Bin"
 msgstr "محفطه رو به پایین"
 
 #. Translators: Large capacity output bin
-#: modules/printbackends/gtkprintbackendcups.c:4712
+#: modules/printbackends/gtkprintbackendcups.c:4714
 msgctxt "output-bin"
 msgid "Large Capacity Bin"
 msgstr "محفظه با گنجایش بالا"
 
 #. Translators: Output stacker number %d
-#: modules/printbackends/gtkprintbackendcups.c:4734
+#: modules/printbackends/gtkprintbackendcups.c:4736
 #, c-format
 msgctxt "output-bin"
 msgid "Stacker %d"
 msgstr "پشته‌ساز %Id"
 
 #. Translators: Output mailbox number %d
-#: modules/printbackends/gtkprintbackendcups.c:4738
+#: modules/printbackends/gtkprintbackendcups.c:4740
 #, c-format
 msgctxt "output-bin"
 msgid "Mailbox %d"
 msgstr "صندوق پستی %Id"
 
 #. Translators: Private mailbox
-#: modules/printbackends/gtkprintbackendcups.c:4742
+#: modules/printbackends/gtkprintbackendcups.c:4744
 msgctxt "output-bin"
 msgid "My Mailbox"
 msgstr "صندوق پستی من"
 
 #. Translators: Output tray number %d
-#: modules/printbackends/gtkprintbackendcups.c:4746
+#: modules/printbackends/gtkprintbackendcups.c:4748
 #, c-format
 msgctxt "output-bin"
 msgid "Tray %d"
 msgstr "سینی %Id"
 
-#: modules/printbackends/gtkprintbackendcups.c:5223
+#: modules/printbackends/gtkprintbackendcups.c:5225
 msgid "Printer Default"
 msgstr "پیش‌فرض چاپگر"
 
 #. Translators, this string is used to label the job priority option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5702
+#: modules/printbackends/gtkprintbackendcups.c:5704
 msgid "Job Priority"
 msgstr "اولویت کار"
 
 #. Translators, this string is used to label the billing info entry
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5713
+#: modules/printbackends/gtkprintbackendcups.c:5715
 msgid "Billing Info"
 msgstr "اطلاعات صورتحساب"
 
@@ -7004,37 +7250,37 @@ msgstr "اطلاعات صورتحساب"
 #. Translators, these strings are names for various 'standard' cover
 #. * pages that the printing system may support.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5737
+#: modules/printbackends/gtkprintbackendcups.c:5739
 msgctxt "cover page"
 msgid "None"
 msgstr "هیچ‌کدام"
 
-#: modules/printbackends/gtkprintbackendcups.c:5738
+#: modules/printbackends/gtkprintbackendcups.c:5740
 msgctxt "cover page"
 msgid "Classified"
 msgstr "طبقه‌بندی شده"
 
-#: modules/printbackends/gtkprintbackendcups.c:5739
+#: modules/printbackends/gtkprintbackendcups.c:5741
 msgctxt "cover page"
 msgid "Confidential"
 msgstr "محرمانه"
 
-#: modules/printbackends/gtkprintbackendcups.c:5740
+#: modules/printbackends/gtkprintbackendcups.c:5742
 msgctxt "cover page"
 msgid "Secret"
 msgstr "سری"
 
-#: modules/printbackends/gtkprintbackendcups.c:5741
+#: modules/printbackends/gtkprintbackendcups.c:5743
 msgctxt "cover page"
 msgid "Standard"
 msgstr "استاندارد"
 
-#: modules/printbackends/gtkprintbackendcups.c:5742
+#: modules/printbackends/gtkprintbackendcups.c:5744
 msgctxt "cover page"
 msgid "Top Secret"
 msgstr "فوق سری"
 
-#: modules/printbackends/gtkprintbackendcups.c:5743
+#: modules/printbackends/gtkprintbackendcups.c:5745
 msgctxt "cover page"
 msgid "Unclassified"
 msgstr "طبقه‌بندی نشده"
@@ -7042,7 +7288,7 @@ msgstr "طبقه‌بندی نشده"
 #. Translators, this string is used to label the pages-per-sheet option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5755
+#: modules/printbackends/gtkprintbackendcups.c:5757
 msgctxt "printer option"
 msgid "Pages per Sheet"
 msgstr "تعداد صفحه‌ها در برگه"
@@ -7050,7 +7296,7 @@ msgstr "تعداد صفحه‌ها در برگه"
 #. Translators, this string is used to label the option in the print
 #. * dialog that controls in what order multiple pages are arranged
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5772
+#: modules/printbackends/gtkprintbackendcups.c:5774
 msgctxt "printer option"
 msgid "Page Ordering"
 msgstr "ترتیب صفحه‌ها"
@@ -7059,7 +7305,7 @@ msgstr "ترتیب صفحه‌ها"
 #. * a print job is printed. Possible values are 'now', a specified time,
 #. * or 'on hold'
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5849
+#: modules/printbackends/gtkprintbackendcups.c:5851
 msgctxt "printer option"
 msgid "Print at"
 msgstr "زمان چاپ"
@@ -7067,7 +7313,7 @@ msgstr "زمان چاپ"
 #. Translators: this is the name of the option that allows the user
 #. * to specify a time when a print job will be printed.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5860
+#: modules/printbackends/gtkprintbackendcups.c:5862
 msgctxt "printer option"
 msgid "Print at time"
 msgstr "چاپ در زمان مشخص"
@@ -7077,52 +7323,52 @@ msgstr "چاپ در زمان مشخص"
 #. * the width and height in points. E.g: "Custom
 #. * 230.4x142.9"
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5907
+#: modules/printbackends/gtkprintbackendcups.c:5909
 #, c-format
 msgid "Custom %s×%s"
 msgstr "سفارشی %s×%s"
 
 #. TRANSLATORS: this is the ICC color profile to use for this job
-#: modules/printbackends/gtkprintbackendcups.c:6018
+#: modules/printbackends/gtkprintbackendcups.c:6020
 msgctxt "printer option"
 msgid "Printer Profile"
 msgstr "نمایهٔ چاپگر"
 
 #. TRANSLATORS: this is when color profile information is unavailable
-#: modules/printbackends/gtkprintbackendcups.c:6025
+#: modules/printbackends/gtkprintbackendcups.c:6027
 msgctxt "printer option value"
 msgid "Unavailable"
 msgstr "خارج از دسترس"
 
-#: modules/printbackends/gtkprintbackendfile.c:238
+#: modules/printbackends/gtkprintbackendfile.c:263
 msgid "output"
 msgstr "خروجی"
 
-#: modules/printbackends/gtkprintbackendfile.c:510
+#: modules/printbackends/gtkprintbackendfile.c:543
 msgid "Print to File"
 msgstr "چاپ در پرونده"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PDF"
 msgstr "PDF"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PostScript"
 msgstr "پست‌اسکریپت"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "SVG"
 msgstr "SVG"
 
-#: modules/printbackends/gtkprintbackendfile.c:649
+#: modules/printbackends/gtkprintbackendfile.c:688
 msgid "Pages per _sheet:"
 msgstr "تعداد صفحات در _برگه:"
 
-#: modules/printbackends/gtkprintbackendfile.c:709
+#: modules/printbackends/gtkprintbackendfile.c:758
 msgid "File"
 msgstr "پرونده"
 
-#: modules/printbackends/gtkprintbackendfile.c:719
+#: modules/printbackends/gtkprintbackendfile.c:768
 msgid "_Output format"
 msgstr "_قالب خروجی"
 
@@ -7203,8 +7449,8 @@ msgstr ""
 
 #: tools/gtk-builder-tool-enumerate.c:56 tools/gtk-builder-tool-preview.c:179
 #: tools/gtk-builder-tool-preview.c:180 tools/gtk-builder-tool-screenshot.c:360
-#: tools/gtk-builder-tool-simplify.c:2623 tools/gtk-builder-tool-validate.c:261
-#: tools/gtk-image-tool-compare.c:43 tools/gtk-image-tool-info.c:68
+#: tools/gtk-builder-tool-simplify.c:2709 tools/gtk-builder-tool-validate.c:267
+#: tools/gtk-image-tool-compare.c:43 tools/gtk-image-tool-info.c:79
 #: tools/gtk-path-tool-render.c:121 tools/gtk-rendernode-tool-compare.c:67
 #: tools/gtk-rendernode-tool-extract.c:294 tools/gtk-rendernode-tool-info.c:226
 #: tools/gtk-rendernode-tool-show.c:116
@@ -7239,7 +7485,7 @@ msgid "Use style from CSS file"
 msgstr "استفادهٔ سبک از پروندهٔ CSS"
 
 #: tools/gtk-builder-tool-preview.c:187 tools/gtk-builder-tool-screenshot.c:370
-#: tools/gtk-builder-tool-validate.c:268 tools/gtk-rendernode-tool-benchmark.c:108
+#: tools/gtk-builder-tool-validate.c:274 tools/gtk-rendernode-tool-benchmark.c:108
 #: tools/gtk-rendernode-tool-render.c:262 tools/gtk-rendernode-tool-show.c:123
 #, c-format
 msgid "Could not initialize windowing system\n"
@@ -7250,7 +7496,7 @@ msgid "Preview the file."
 msgstr "پیش‌نمایش پرونده."
 
 #: tools/gtk-builder-tool-preview.c:208 tools/gtk-builder-tool-screenshot.c:391
-#: tools/gtk-builder-tool-simplify.c:2646 tools/gtk-builder-tool-validate.c:287
+#: tools/gtk-builder-tool-simplify.c:2733 tools/gtk-builder-tool-validate.c:293
 #, c-format
 msgid "No .ui file specified\n"
 msgstr "هیچ پروندهٔ ‪.ui‬ ای مشخّص نشده\n"
@@ -7322,77 +7568,82 @@ msgstr "پرداخت یک پروندهٔ ‪.ui‬ در یک تصویر."
 msgid "Can only render a single .ui file to a single output file\n"
 msgstr "تنها می‌تواند یک تک‌پروندهٔ ‪.ui‬ را در یک پروندهٔ خروحی پرداخت کند\n"
 
-#: tools/gtk-builder-tool-simplify.c:444
+#: tools/gtk-builder-tool-simplify.c:447
 #, c-format
 msgid "%s:%d: Couldn’t parse value for property '%s': %s\n"
 msgstr ""
 "%s:%Id: نمی‌توان مقدار ویژگی «%s» را تجزیه کرد: %s\n"
 "\n"
 
-#: tools/gtk-builder-tool-simplify.c:658
+#: tools/gtk-builder-tool-simplify.c:666
 #, c-format
 msgid "Property %s not found"
 msgstr "مشخّصهٔ %s پیدا نشد"
 
-#: tools/gtk-builder-tool-simplify.c:661
+#: tools/gtk-builder-tool-simplify.c:669
 #, c-format
 msgid "Packing property %s not found"
 msgstr "مشخّصهٔ جاسازی %s پیدا نشد"
 
-#: tools/gtk-builder-tool-simplify.c:664
+#: tools/gtk-builder-tool-simplify.c:672
 #, c-format
 msgid "Cell property %s not found"
 msgstr "مشخّصهٔ سلّول %s پیدا نشد"
 
-#: tools/gtk-builder-tool-simplify.c:667
+#: tools/gtk-builder-tool-simplify.c:675
 #, c-format
 msgid "Layout property %s not found"
 msgstr "مشخّصهٔ چینش %s پیدا نشد"
 
-#: tools/gtk-builder-tool-simplify.c:1400
+#: tools/gtk-builder-tool-simplify.c:1408
 #, c-format
 msgid "%s only accepts three children"
 msgstr "%s تنها سه فرزند می‌پذیرد"
 
-#: tools/gtk-builder-tool-simplify.c:1773
+#: tools/gtk-builder-tool-simplify.c:1796
 #, c-format
 msgid "%s only accepts one center child"
 msgstr "%s تنها یک فرزند وسط می‌پذیرد"
 
-#: tools/gtk-builder-tool-simplify.c:2549
+#: tools/gtk-builder-tool-simplify.c:2606
+#, c-format
+msgid "Unable to create temporary file: %s\n"
+msgstr "ناتوان در ایجاد پروندهٔ موفّتی: %s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2620
 #, c-format
 msgid "Can’t load “%s”: %s\n"
 msgstr "نمی‌توان «%s» را بار کرد: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2560 tools/gtk-builder-tool-simplify.c:2566
-#: tools/gtk-builder-tool-simplify.c:2572
+#: tools/gtk-builder-tool-simplify.c:2632 tools/gtk-builder-tool-simplify.c:2642
+#: tools/gtk-builder-tool-simplify.c:2651
 #, c-format
 msgid "Can’t parse “%s”: %s\n"
 msgstr "نمی‌توان «%s» را تجزیه کرد: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2598
+#: tools/gtk-builder-tool-simplify.c:2677
 #, c-format
 msgid "Failed to read “%s”: %s\n"
 msgstr "نمی‌توان «%s» را خواند: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2604
+#: tools/gtk-builder-tool-simplify.c:2684
 #, c-format
 msgid "Failed to write “%s”: “%s”\n"
 msgstr "شکست در نوشتن «%s»  %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2621
+#: tools/gtk-builder-tool-simplify.c:2707
 msgid "Replace the file"
 msgstr "جایگزینی پرونده"
 
-#: tools/gtk-builder-tool-simplify.c:2622
+#: tools/gtk-builder-tool-simplify.c:2708
 msgid "Convert from GTK 3 to GTK 4"
 msgstr "تبدیل از GTK 3 به GTK 4"
 
-#: tools/gtk-builder-tool-simplify.c:2633
+#: tools/gtk-builder-tool-simplify.c:2719
 msgid "Simplify the file."
 msgstr "ساده سازی پرونده."
 
-#: tools/gtk-builder-tool-simplify.c:2652
+#: tools/gtk-builder-tool-simplify.c:2739
 #, c-format
 msgid "Can only simplify a single .ui file without --replace\n"
 msgstr "تنها می‌تواند یک تک‌پروندهٔ ‪.ui‬ را بدون ‪--replace‬ ساده سازی کند\n"
@@ -7406,12 +7657,12 @@ msgstr "شکست در یافتن گونهٔ والد الگوی %s\n"
 msgid "Deprecated types:\n"
 msgstr "گونه‌های منقضی:\n"
 
-#: tools/gtk-builder-tool-validate.c:167
+#: tools/gtk-builder-tool-validate.c:170
 #, c-format
 msgid "Failed to create an instance of the template type %s\n"
 msgstr "شکست در ایجاد نمونه‌ای از گونهٔ %s\n"
 
-#: tools/gtk-builder-tool-validate.c:276
+#: tools/gtk-builder-tool-validate.c:282
 msgid "Validate the file."
 msgstr "اعتبارسنجی پرونده."
 
@@ -7454,7 +7705,7 @@ msgid "Compare two images"
 msgstr "مقایسهٔ دو تصویر"
 
 #: tools/gtk-image-tool-compare.c:70 tools/gtk-image-tool-convert.c:113
-#: tools/gtk-image-tool-info.c:90 tools/gtk-image-tool-relabel.c:109
+#: tools/gtk-image-tool-info.c:101 tools/gtk-image-tool-relabel.c:109
 #: tools/gtk-image-tool-show.c:141
 #, c-format
 msgid "No image file specified\n"
@@ -7557,19 +7808,24 @@ msgstr "نمی‌توان هم ‪--color-state‬ و هم ‪‬--cicp‬ را
 msgid "Not a supported cicp tuple: %s\n"
 msgstr "دوتایی پشتیبانی شدهٔ cicp نیست: %s\n"
 
-#: tools/gtk-image-tool-info.c:55
+#: tools/gtk-image-tool-info.c:57
 msgid "Format:"
 msgstr "قالب:"
 
-#: tools/gtk-image-tool-info.c:56
+#: tools/gtk-image-tool-info.c:63 tools/gtk-image-tool-info.c:65
+#: tools/gtk-image-tool-info.c:67
 msgid "Color state:"
 msgstr "وضعیت رنگ:"
 
-#: tools/gtk-image-tool-info.c:77
+#: tools/gtk-image-tool-info.c:67
+msgid "unknown"
+msgstr "ناشناخته"
+
+#: tools/gtk-image-tool-info.c:88
 msgid "Provide information about the image."
 msgstr "فراهم کردن اطّلاعاتی دربارهٔ تصویر."
 
-#: tools/gtk-image-tool-info.c:96
+#: tools/gtk-image-tool-info.c:107
 #, c-format
 msgid "Can only accept a single image file\n"
 msgstr "تنها می‌تواند یک تک‌پروندهٔ تصویر را بپذیرد\n"
@@ -7595,7 +7851,7 @@ msgstr "نیفزودن نوار عنوان"
 msgid "Show one or more images."
 msgstr "نمایش یک تصویر یا بیش‌تر."
 
-#: tools/gtk-image-tool-utils.c:234
+#: tools/gtk-image-tool-utils.c:255
 #, c-format
 msgid "cicp must be 4 numbers, separated by /\n"
 msgstr "cicp باید ۴ شماره باشد که با / جدا شده‌اند\n"
@@ -8146,105 +8402,105 @@ msgstr "خطا در %s: %s\n"
 msgid "Failed to load node file: %s\n"
 msgstr "شکست در بار کردن پروندهٔ گره: %s\n"
 
-#: tools/updateiconcache.c:1391
+#: tools/updateiconcache.c:1402
 #, c-format
 msgid "Failed to write header\n"
 msgstr "نوشتن سرآیند خراب شد\n"
 
-#: tools/updateiconcache.c:1397
+#: tools/updateiconcache.c:1408
 #, c-format
 msgid "Failed to write hash table\n"
 msgstr "نوشتن جدول درهم خراب شد \n"
 
-#: tools/updateiconcache.c:1403
+#: tools/updateiconcache.c:1414
 #, c-format
 msgid "Failed to write folder index\n"
 msgstr "نوشتن نمایهٔ پوشه خراب شد\n"
 
-#: tools/updateiconcache.c:1411
+#: tools/updateiconcache.c:1422
 #, c-format
 msgid "Failed to rewrite header\n"
 msgstr "بازنویسی سرآیند خراب شد\n"
 
-#: tools/updateiconcache.c:1505
+#: tools/updateiconcache.c:1516
 #, c-format
 msgid "Failed to open file %s : %s\n"
 msgstr "گشودن پروندهٔ%s : %s خراب شد\n"
 
-#: tools/updateiconcache.c:1513 tools/updateiconcache.c:1543
+#: tools/updateiconcache.c:1524 tools/updateiconcache.c:1554
 #, c-format
 msgid "Failed to write cache file: %s\n"
 msgstr "نوشتن پروندهٔ حافظه‌نهان «‎%s» خراب شد\n"
 
-#: tools/updateiconcache.c:1553
+#: tools/updateiconcache.c:1564
 #, c-format
 msgid "The generated cache was invalid.\n"
 msgstr "حافظه‌نهان تولید شده نامعتبر بود\n"
 
-#: tools/updateiconcache.c:1567
+#: tools/updateiconcache.c:1578
 #, c-format
 msgid "Could not rename %s to %s: %s, removing %s then.\n"
 msgstr "تغییر نما %s به %s ممکن نبود:  %s، پس %s پاک می‌شود.\n"
 
-#: tools/updateiconcache.c:1581
+#: tools/updateiconcache.c:1592
 #, c-format
 msgid "Could not rename %s to %s: %s\n"
 msgstr "تغییر نام «%s» به %s ممکن نبود: %s \n"
 
-#: tools/updateiconcache.c:1591
+#: tools/updateiconcache.c:1602
 #, c-format
 msgid "Could not rename %s back to %s: %s.\n"
 msgstr "برگشت تغییر نام پوشهٔ %s به %s ممکن نبود: %s \n"
 
-#: tools/updateiconcache.c:1614
+#: tools/updateiconcache.c:1625
 #, c-format
 msgid "Cache file created successfully.\n"
 msgstr "پروندهٔ حافظه‌نهان با موفقیت ایجاد شد.\n"
 
-#: tools/updateiconcache.c:1653
+#: tools/updateiconcache.c:1664
 msgid "Overwrite an existing cache, even if up to date"
 msgstr "جای‌نوشتن یک حافظه‌نهان موجود، حتی اگر به‌روز باشد"
 
-#: tools/updateiconcache.c:1654
+#: tools/updateiconcache.c:1665
 msgid "Don’t check for the existence of index.theme"
 msgstr "وجود index.theme بررسی نشود"
 
-#: tools/updateiconcache.c:1655
+#: tools/updateiconcache.c:1666
 msgid "Don’t include image data in the cache"
 msgstr "انباره شامل داده‌های تصویر نشود"
 
-#: tools/updateiconcache.c:1656
+#: tools/updateiconcache.c:1667
 msgid "Include image data in the cache"
 msgstr "حافظه‌نهان، داده‌های تصویر را شامل شود"
 
-#: tools/updateiconcache.c:1657
+#: tools/updateiconcache.c:1668
 msgid "Output a C header file"
 msgstr "خروج یک سر‌آیند C"
 
-#: tools/updateiconcache.c:1658
+#: tools/updateiconcache.c:1669
 msgid "Turn off verbose output"
 msgstr "خروجی مفصل را خاموش کن"
 
-#: tools/updateiconcache.c:1659
+#: tools/updateiconcache.c:1670
 msgid "Validate existing icon cache"
 msgstr "حافظه‌نهان نشان موجود اعتبارسنجی شود"
 
-#: tools/updateiconcache.c:1724
+#: tools/updateiconcache.c:1736
 #, c-format
 msgid "File not found: %s\n"
 msgstr "پرونده پیدا نشد: %s\n"
 
-#: tools/updateiconcache.c:1730
+#: tools/updateiconcache.c:1742
 #, c-format
 msgid "Not a valid icon cache: %s\n"
 msgstr "این یک حافظه نهان شمایل معتبر نیست: %s\n"
 
-#: tools/updateiconcache.c:1743
+#: tools/updateiconcache.c:1755
 #, c-format
 msgid "No theme index file.\n"
 msgstr "پروندهٔ نمایهٔ چهره‌ای نیست.\n"
 
-#: tools/updateiconcache.c:1747
+#: tools/updateiconcache.c:1759
 #, c-format
 msgid ""
 "No theme index file in “%s”.\n"
@@ -8254,6 +8510,47 @@ msgstr ""
 "اگر به‌راستی می‌خواهید این‌جا انبارهٔ نقشکی ایجاد کنید، از ‪--ignore-theme-index‬ "
 "استفاده کنید.\n"
 
+#, c-format
+#~ msgid "This GLES %d.%d implementation does not support half-float vertex data"
+#~ msgstr "این پشتیبانی EGL %Id.%Id از داده‌های رأس نیم‌شناور پیشتیبانی نمی‌کند"
+
+# farmaan
+#~ msgctxt "GL version"
+#~ msgid "None"
+#~ msgstr "هیچ‌کدام"
+
+#~ msgctxt "Vulkan device"
+#~ msgid "Disabled"
+#~ msgstr "از کار افتاده"
+
+#~ msgctxt "Vulkan version"
+#~ msgid "Disabled"
+#~ msgstr "از کار افتاده"
+
+# farmaan
+#~ msgctxt "Vulkan version"
+#~ msgid "None"
+#~ msgstr "هیچ‌کدام"
+
+#~ msgid "GL_VENDOR"
+#~ msgstr "GL_VENDOR"
+
+#~ msgid "GL_RENDERER"
+#~ msgstr "GL_RENDERER"
+
+#~ msgid "GL_VERSION"
+#~ msgstr "GL_VERSION"
+
+#~ msgid "GL_SHADING_LANGUAGE_VERSION"
+#~ msgstr "GL_SHADING_LANGUAGE_VERSION"
+
+#~ msgid "Right-to-Left"
+#~ msgstr "راست به چپ"
+
+#~ msgctxt "Font rendering"
+#~ msgid "Manual"
+#~ msgstr "دستی"
+
 #~ msgid "Antialiasing"
 #~ msgstr "خوش‌نماسازی"
 
@@ -8495,14 +8792,6 @@ msgstr ""
 #~ msgid "The EGL implementation does not support any allowed APIs"
 #~ msgstr "پشتیبانی EGL از هیچ API مجازی پیشتیبانی نمی‌کند"
 
-#~ msgctxt "Script"
-#~ msgid "Arabic"
-#~ msgstr "عربی"
-
-#~ msgctxt "Script"
-#~ msgid "Armenian"
-#~ msgstr "ارمنی"
-
 #~ msgctxt "Script"
 #~ msgid "Bengali"
 #~ msgstr "بنگالی"
@@ -8519,10 +8808,6 @@ msgstr ""
 #~ msgid "Coptic"
 #~ msgstr "قبطی"
 
-#~ msgctxt "Script"
-#~ msgid "Cyrillic"
-#~ msgstr "سریلیک"
-
 #~ msgctxt "Script"
 #~ msgid "Deseret"
 #~ msgstr "ده‌سه‌رت"
@@ -8535,18 +8820,10 @@ msgstr ""
 #~ msgid "Ethiopic"
 #~ msgstr "اتیوپیایی"
 
-#~ msgctxt "Script"
-#~ msgid "Georgian"
-#~ msgstr "گرجی"
-
 #~ msgctxt "Script"
 #~ msgid "Gothic"
 #~ msgstr "گوتی"
 
-#~ msgctxt "Script"
-#~ msgid "Greek"
-#~ msgstr "یونانی"
-
 #~ msgctxt "Script"
 #~ msgid "Gujarati"
 #~ msgstr "گجراتی"
@@ -8563,10 +8840,6 @@ msgstr ""
 #~ msgid "Hangul"
 #~ msgstr "هانگول"
 
-#~ msgctxt "Script"
-#~ msgid "Hebrew"
-#~ msgstr "عبری"
-
 #~ msgctxt "Script"
 #~ msgid "Hiragana"
 #~ msgstr "هیراگانا"
@@ -8639,10 +8912,6 @@ msgstr ""
 #~ msgid "Thaana"
 #~ msgstr "تانا"
 
-#~ msgctxt "Script"
-#~ msgid "Thai"
-#~ msgstr "تایلندی"
-
 #~ msgctxt "Script"
 #~ msgid "Tibetan"
 #~ msgstr "تبّتی"
@@ -8819,10 +9088,6 @@ msgstr ""
 #~ msgid "Inscriptional Parthian"
 #~ msgstr "پارتی کتیبه‌ای"
 
-#~ msgctxt "Script"
-#~ msgid "Javanese"
-#~ msgstr "جاوه‌ای"
-
 #~ msgctxt "Script"
 #~ msgid "Kaithi"
 #~ msgstr "کای‌تی"
@@ -9903,10 +10168,6 @@ msgstr ""
 #~ msgid "_Disconnect"
 #~ msgstr "_قطع ارتباط"
 
-#~ msgctxt "Stock label"
-#~ msgid "_Edit"
-#~ msgstr "_ویرایش"
-
 #~ msgctxt "Stock label"
 #~ msgid "_Index"
 #~ msgstr "_نمایه"
@@ -9978,15 +10239,6 @@ msgstr ""
 #~ msgid "Select all"
 #~ msgstr "انتخاب همه"
 
-#~ msgid "Cut"
-#~ msgstr "برش"
-
-#~ msgid "Copy"
-#~ msgstr "رونوشت"
-
-#~ msgid "Paste"
-#~ msgstr "چسباندن"
-
 #~ msgctxt "input method menu"
 #~ msgid "Simple"
 #~ msgstr "ساده"
@@ -10187,9 +10439,6 @@ msgstr ""
 #~ msgid "bidirectional, inverted"
 #~ msgstr "دوجهته، معکوس"
 
-#~ msgid "Binding:"
-#~ msgstr "مقیدسازی:"
-
 #~ msgid "Selector"
 #~ msgstr "انتخابگر"
 
@@ -10239,12 +10488,6 @@ msgstr ""
 #~ msgid "CSS Selector"
 #~ msgstr "انتخابگر CSS"
 
-#~ msgid "Gestures"
-#~ msgstr "حرکات"
-
-#~ msgid "Visual"
-#~ msgstr "نمایشی"
-
 #~ msgid "smb://"
 #~ msgstr "smb://"
 
@@ -10291,10 +10534,6 @@ msgstr ""
 #~ msgid "Tigrigna-Ethiopian (EZ+)"
 #~ msgstr "تیگرینیایی-اریتره‌ای (EZ+‎)"
 
-#~ msgctxt "input method menu"
-#~ msgid "Vietnamese (VIQR)"
-#~ msgstr "ویتنامی (VIQR)"
-
 #~ msgctxt "input method menu"
 #~ msgid "X Input Method"
 #~ msgstr "شیوه‌ی ورودی X"
@@ -10311,9 +10550,6 @@ msgstr ""
 #~ msgid "paused"
 #~ msgstr "مکث‌کرده"
 
-#~ msgid "unknown"
-#~ msgstr "ناشناخته"
-
 #~ msgid "test-output.%s"
 #~ msgstr "آزمایش خروجی.%s"
 
@@ -10822,9 +11058,6 @@ msgstr ""
 #~ msgid "This build of gdk-pixbuf does not support saving the image format: %s"
 #~ msgstr "این ساخت gdk-pixbuf از ذخیره‌ی این قالب تصویری پشتیبانی نمی‌کند: %s"
 
-#~ msgid "Failed to open temporary file"
-#~ msgstr "باز کردن پرونده‌ی موقت شکست خورد"
-
 #~ msgid "Failed to open '%s' for writing: %s"
 #~ msgstr "نمی‌توان «%s» را برای نوشتن باز کرد: %s"
 
diff --git a/po/fr.po b/po/fr.po
index 5a4c16f403af3cff85f0e492181c06ca13c89c0d..138c03a667a61b8c18c4fffb96c486b59a87bd40 100644
--- a/po/fr.po
+++ b/po/fr.po
@@ -17,22 +17,23 @@
 # Charles Monzat <charles.monzat@numericable.fr>, 2016-2018
 # Baylard Gérard <geodebay@gmail.com>, 2020.
 # Guillaume Bernard <associations@guillaume-bernard.fr>, 2021-2024.
-# Vincent Chatelain <vinchatl_gnome@proton.me>, 2024.
+# Vincent Chatelain <vincent_chatelain@proton.me>, 2024.
+# Irénée Thirion <irenee.thirion@e.email>, 2024.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: gtk master\n"
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
-"POT-Creation-Date: 2024-03-16 23:08+0000\n"
-"PO-Revision-Date: 2024-03-19 14:05+0100\n"
-"Last-Translator: Guillaume Bernard <associations@guillaume-bernard.fr>\n"
+"POT-Creation-Date: 2025-01-13 00:43+0000\n"
+"PO-Revision-Date: 2024-10-23 22:47+0200\n"
+"Last-Translator: Vincent Chatelain <vincent_chatelain@proton.me>\n"
 "Language-Team: GNOME French Team <gnomefr@traduc.org>\n"
 "Language: fr\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2; plural=(n > 1);\n"
-"X-Generator: Poedit 3.4.2\n"
+"X-Generator: Poedit 3.4.4\n"
 
 #: gdk/broadway/gdkbroadway-server.c:135
 #, c-format
@@ -43,14 +44,34 @@ msgstr "Type d’affichage Broadway non pris en charge : %s"
 msgid "This clipboard cannot store data."
 msgstr "Ce presse-papiers ne peut pas stocker de données."
 
-#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:786 gdk/gdkclipboard.c:1086
+#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:781 gdk/gdkclipboard.c:1072
 msgid "Cannot read from empty clipboard."
 msgstr "Impossible de lire depuis un presse-papiers vide."
 
-#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1136 gdk/gdkdrag.c:618
+#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1122 gdk/gdkdrag.c:606
 msgid "No compatible formats to transfer clipboard contents."
 msgstr "Aucun format compatible pour transférer le contenu du presse-papiers."
 
+#: gdk/gdkcolorstate.c:668
+#, c-format
+msgid "cicp: Narrow range or YUV not supported"
+msgstr "cicp : palette réduite ou YUV non prise en charge"
+
+#: gdk/gdkcolorstate.c:678
+#, c-format
+msgid "cicp: Unspecified parameters not supported"
+msgstr "cicp : paramètres non indiqués non pris en charge"
+
+#: gdk/gdkcolorstate.c:724
+#, c-format
+msgid "cicp: Transfer function %u not supported"
+msgstr "cicp : function de transfert %u non prise en charge"
+
+#: gdk/gdkcolorstate.c:754
+#, c-format
+msgid "cicp: Color primaries %u not supported"
+msgstr "cicp : couleurs primaires %u non prises en charge"
+
 #: gdk/gdkcontentprovider.c:106 gdk/gdkcontentproviderimpl.c:313
 #: gdk/gdkcontentproviderimpl.c:532
 #, c-format
@@ -62,59 +83,59 @@ msgstr "Impossible de fournir le contenu comme « %s »"
 msgid "Cannot provide contents as %s"
 msgstr "Impossible de fournir le contenu comme %s"
 
-#: gdk/gdkdisplay.c:176 gdk/gdkglcontext.c:463
+#: gdk/gdkdisplay.c:176 gdk/gdkglcontext.c:470
 msgid "The current backend does not support OpenGL"
 msgstr "Le moteur actuel ne gère pas OpenGL"
 
-#: gdk/gdkdisplay.c:1315 gdk/gdkvulkancontext.c:1600
-msgid "Vulkan support disabled via GDK_DEBUG"
-msgstr "Prise en charge de Vulkan désactivée via GDK_DEBUG"
+#: gdk/gdkdisplay.c:1317 gdk/gdkvulkancontext.c:1754
+msgid "Vulkan support disabled via GDK_DISABLE"
+msgstr "Prise en charge de Vulkan désactivée via GDK_DISABLE"
 
-#: gdk/gdkdisplay.c:1369
-msgid "GL support disabled via GDK_DEBUG"
-msgstr "Prise en charge de GL désactivée via GDK_DEBUG"
+#: gdk/gdkdisplay.c:1371
+msgid "OpenGL support disabled via GDK_DISABLE"
+msgstr "Prise en charge de OpenGL désactivée via GDK_DISABLE"
 
-#: gdk/gdkdisplay.c:1674
+#: gdk/gdkdisplay.c:1685
 msgid "No EGL configuration available"
 msgstr "Aucune configuration EGL disponible"
 
-#: gdk/gdkdisplay.c:1682
+#: gdk/gdkdisplay.c:1693
 msgid "Failed to get EGL configurations"
 msgstr "Impossible d’obtenir les configurations EGL"
 
-#: gdk/gdkdisplay.c:1712
+#: gdk/gdkdisplay.c:1723
 msgid "No EGL configuration with required features found"
 msgstr ""
 "Aucune configuration EGL avec les fonctionnalités requises n’a été trouvée"
 
-#: gdk/gdkdisplay.c:1719
+#: gdk/gdkdisplay.c:1730
 msgid "No perfect EGL configuration found"
 msgstr "Aucune configuration EGL idéale trouvée"
 
-#: gdk/gdkdisplay.c:1761
+#: gdk/gdkdisplay.c:1772
 #, c-format
 msgid "EGL implementation is missing extension %s"
 msgid_plural "EGL implementation is missing %2$d extensions: %1$s"
 msgstr[0] "L’extension %s manque dans l’implémentation EGL"
 msgstr[1] "%2$d extensions manquent dans l’implémentation EGL : %1$s"
 
-#: gdk/gdkdisplay.c:1810
+#: gdk/gdkdisplay.c:1821
 msgid "libEGL not available in this sandbox"
 msgstr "libEGL n’est pas disponible dans ce bac à sable"
 
-#: gdk/gdkdisplay.c:1811
+#: gdk/gdkdisplay.c:1822
 msgid "libEGL not available"
 msgstr "libEGL non disponible"
 
-#: gdk/gdkdisplay.c:1821
+#: gdk/gdkdisplay.c:1832
 msgid "Failed to create EGL display"
 msgstr "Impossible de créer l’affichage EGL"
 
-#: gdk/gdkdisplay.c:1830
+#: gdk/gdkdisplay.c:1841
 msgid "Could not initialize EGL display"
 msgstr "Impossible d’initialiser l’affichage EGL"
 
-#: gdk/gdkdisplay.c:1840
+#: gdk/gdkdisplay.c:1851
 #, c-format
 msgid "EGL version %d.%d is too old. GTK requires %d.%d"
 msgstr "La version %d.%d d’EGL est trop ancienne. GTK requiert %d.%d"
@@ -128,448 +149,454 @@ msgstr ""
 msgid "No compatible formats to transfer contents."
 msgstr "Aucun format compatible pour le transfert du contenu."
 
-#: gdk/gdkglcontext.c:423 gdk/x11/gdkglcontext-glx.c:645
+#: gdk/gdkglcontext.c:430 gdk/x11/gdkglcontext-glx.c:651
 msgid "No GL API allowed."
 msgstr "Aucune API GL autorisée."
 
-#: gdk/gdkglcontext.c:446 gdk/win32/gdkglcontext-win32-wgl.c:395
-#: gdk/win32/gdkglcontext-win32-wgl.c:538
-#: gdk/win32/gdkglcontext-win32-wgl.c:582 gdk/x11/gdkglcontext-glx.c:691
+#: gdk/gdkglcontext.c:453 gdk/win32/gdkglcontext-win32-wgl.c:762
+#: gdk/win32/gdkglcontext-win32-wgl.c:905
+#: gdk/win32/gdkglcontext-win32-wgl.c:949 gdk/x11/gdkglcontext-glx.c:697
 msgid "Unable to create a GL context"
 msgstr "Impossible de créer un contexte GL"
 
-#: gdk/gdkglcontext.c:1309
-msgid "OpenGL ES disabled via GDK_DEBUG"
-msgstr "OpenGL ES désactivé via GTK_DEBUG"
+#: gdk/gdkglcontext.c:1338
+msgid "OpenGL ES API disabled via GDK_DISABLE"
+msgstr "API OpenGL ES désactivée via GTK_DISABLE"
 
-#: gdk/gdkglcontext.c:1321
-msgid "OpenGL disabled via GDK_DEBUG"
-msgstr "OpenGL désactivé via GTK_DEBUG"
+#: gdk/gdkglcontext.c:1350
+msgid "OpenGL API disabled via GDK_DISABLE"
+msgstr "API OpenGL désactivée via GTK_DISABLE"
 
-#: gdk/gdkglcontext.c:1332
+#: gdk/gdkglcontext.c:1361
 #, c-format
 msgid "Application does not support %s API"
 msgstr "L’application ne prend pas en charge l’API %s"
 
 #. translators: This is about OpenGL backend names, like
 #. * "Trying to use X11 GLX, but EGL is already in use"
-#: gdk/gdkglcontext.c:2117
+#.
+#: gdk/gdkglcontext.c:2171
 #, c-format
 msgid "Trying to use %s, but %s is already in use"
 msgstr "Tentative d’utilisation de %s, mais %s est déjà utilisé"
 
-#: gdk/gdktexture.c:580
+#: gdk/gdkglcontext.c:2182
+#, c-format
+msgid "Trying to use %s, but it is disabled via GDK_DISABLE"
+msgstr "Tentative d’utilisation de %s, mais il est désactivé via GDK_DISABLE"
+
+#: gdk/gdktexture.c:672
 msgid "Unknown image format."
 msgstr "Format d’image inconnu."
 
 #.
-#. * Translators, the strings in the “keyboard label” context are
+#. * Translators, the strings in the 'keyboard label' context are
 #. * display names for keyboard keys. Some of them have prefixes like
-#. * XF86 or ISO_ — these should be removed in the translation. Similarly,
-#. * underscores should be replaced by spaces. The prefix “KP_” stands
-#. * for “key pad” and you may want to include that in your translation.
+#. * XF86 or ISO_ - these should be removed in the translation. Similarly,
+#. * underscores should be replaced by spaces. The prefix 'KP_' stands
+#. * for 'key pad' and you may want to include that in your translation.
 #. * Here are some examples of English translations:
 #. * XF86AudioMute - Audio mute
 #. * Scroll_lock   - Scroll lock
 #. * KP_Space      - Space (keypad)
 #.
-#: gdk/keynamesprivate.h:6843
+#: gdk/keynamesprivate.h:6861
 msgctxt "keyboard label"
 msgid "BackSpace"
 msgstr "Retour arrière"
 
-#: gdk/keynamesprivate.h:6844
+#: gdk/keynamesprivate.h:6862
 msgctxt "keyboard label"
 msgid "Tab"
 msgstr "Tabulation"
 
-#: gdk/keynamesprivate.h:6845
+#: gdk/keynamesprivate.h:6863
 msgctxt "keyboard label"
 msgid "Return"
 msgstr "Retour"
 
-#: gdk/keynamesprivate.h:6846
+#: gdk/keynamesprivate.h:6864
 msgctxt "keyboard label"
 msgid "Pause"
 msgstr "Pause"
 
-#: gdk/keynamesprivate.h:6847
+#: gdk/keynamesprivate.h:6865
 msgctxt "keyboard label"
 msgid "Scroll_Lock"
 msgstr "Arrêt défil."
 
-#: gdk/keynamesprivate.h:6848
+#: gdk/keynamesprivate.h:6866
 msgctxt "keyboard label"
 msgid "Sys_Req"
 msgstr "Syst"
 
-#: gdk/keynamesprivate.h:6849
+#: gdk/keynamesprivate.h:6867
 msgctxt "keyboard label"
 msgid "Escape"
 msgstr "Échap."
 
-#: gdk/keynamesprivate.h:6850
+#: gdk/keynamesprivate.h:6868
 msgctxt "keyboard label"
 msgid "Multi_key"
 msgstr "Touche multi"
 
-#: gdk/keynamesprivate.h:6851
+#: gdk/keynamesprivate.h:6869
 msgctxt "keyboard label"
 msgid "Home"
 msgstr "Origine"
 
-#: gdk/keynamesprivate.h:6852
+#: gdk/keynamesprivate.h:6870
 msgctxt "keyboard label"
 msgid "Left"
 msgstr "Gauche"
 
-#: gdk/keynamesprivate.h:6853
+#: gdk/keynamesprivate.h:6871
 msgctxt "keyboard label"
 msgid "Up"
 msgstr "Haut"
 
-#: gdk/keynamesprivate.h:6854
+#: gdk/keynamesprivate.h:6872
 msgctxt "keyboard label"
 msgid "Right"
 msgstr "Droite"
 
-#: gdk/keynamesprivate.h:6855
+#: gdk/keynamesprivate.h:6873
 msgctxt "keyboard label"
 msgid "Down"
 msgstr "Bas"
 
-#: gdk/keynamesprivate.h:6856 gtk/gtkshortcutlabel.c:217
+#: gdk/keynamesprivate.h:6874 gtk/gtkshortcutlabel.c:217
 msgctxt "keyboard label"
 msgid "Page_Up"
 msgstr "Page haut"
 
-#: gdk/keynamesprivate.h:6857 gtk/gtkshortcutlabel.c:220
+#: gdk/keynamesprivate.h:6875 gtk/gtkshortcutlabel.c:220
 msgctxt "keyboard label"
 msgid "Page_Down"
 msgstr "Page bas"
 
-#: gdk/keynamesprivate.h:6858
+#: gdk/keynamesprivate.h:6876
 msgctxt "keyboard label"
 msgid "End"
 msgstr "Fin"
 
-#: gdk/keynamesprivate.h:6859
+#: gdk/keynamesprivate.h:6877
 msgctxt "keyboard label"
 msgid "Begin"
 msgstr "Début"
 
-#: gdk/keynamesprivate.h:6860
+#: gdk/keynamesprivate.h:6878
 msgctxt "keyboard label"
 msgid "Print"
 msgstr "Impr"
 
-#: gdk/keynamesprivate.h:6861
+#: gdk/keynamesprivate.h:6879
 msgctxt "keyboard label"
 msgid "Insert"
 msgstr "Inser"
 
-#: gdk/keynamesprivate.h:6862
+#: gdk/keynamesprivate.h:6880
 msgctxt "keyboard label"
 msgid "Num_Lock"
 msgstr "Verr. num."
 
-#. Translators: KP_ means “key pad” here
-#: gdk/keynamesprivate.h:6864
+#. Translators: KP_ means 'key pad' here
+#: gdk/keynamesprivate.h:6882
 msgctxt "keyboard label"
 msgid "KP_Space"
 msgstr "Espace (pavé num.)"
 
-#: gdk/keynamesprivate.h:6865
+#: gdk/keynamesprivate.h:6883
 msgctxt "keyboard label"
 msgid "KP_Tab"
 msgstr "Tabulation (pavé num.)"
 
-#: gdk/keynamesprivate.h:6866
+#: gdk/keynamesprivate.h:6884
 msgctxt "keyboard label"
 msgid "KP_Enter"
 msgstr "Entrée (pavé num.)"
 
-#: gdk/keynamesprivate.h:6867
+#: gdk/keynamesprivate.h:6885
 msgctxt "keyboard label"
 msgid "KP_Home"
 msgstr "Origine (pavé num.)"
 
-#: gdk/keynamesprivate.h:6868
+#: gdk/keynamesprivate.h:6886
 msgctxt "keyboard label"
 msgid "KP_Left"
 msgstr "Gauche (pavé num.)"
 
-#: gdk/keynamesprivate.h:6869
+#: gdk/keynamesprivate.h:6887
 msgctxt "keyboard label"
 msgid "KP_Up"
 msgstr "Haut (pavé num.)"
 
-#: gdk/keynamesprivate.h:6870
+#: gdk/keynamesprivate.h:6888
 msgctxt "keyboard label"
 msgid "KP_Right"
 msgstr "Droite (pavé num.)"
 
-#: gdk/keynamesprivate.h:6871
+#: gdk/keynamesprivate.h:6889
 msgctxt "keyboard label"
 msgid "KP_Down"
 msgstr "Bas (pavé num.)"
 
-#: gdk/keynamesprivate.h:6872
+#: gdk/keynamesprivate.h:6890
 msgctxt "keyboard label"
 msgid "KP_Page_Up"
 msgstr "Page haut (pavé num.)"
 
-#: gdk/keynamesprivate.h:6873
+#: gdk/keynamesprivate.h:6891
 msgctxt "keyboard label"
 msgid "KP_Prior"
 msgstr "Précédent (pavé num.)"
 
-#: gdk/keynamesprivate.h:6874
+#: gdk/keynamesprivate.h:6892
 msgctxt "keyboard label"
 msgid "KP_Page_Down"
 msgstr "Page bas (pavé num.)"
 
-#: gdk/keynamesprivate.h:6875
+#: gdk/keynamesprivate.h:6893
 msgctxt "keyboard label"
 msgid "KP_Next"
 msgstr "Suivant (pavé num.)"
 
-#: gdk/keynamesprivate.h:6876
+#: gdk/keynamesprivate.h:6894
 msgctxt "keyboard label"
 msgid "KP_End"
 msgstr "Fin (pavé num.)"
 
-#: gdk/keynamesprivate.h:6877
+#: gdk/keynamesprivate.h:6895
 msgctxt "keyboard label"
 msgid "KP_Begin"
 msgstr "Début (pavé num.)"
 
-#: gdk/keynamesprivate.h:6878
+#: gdk/keynamesprivate.h:6896
 msgctxt "keyboard label"
 msgid "KP_Insert"
 msgstr "Inser (pavé num.)"
 
-#: gdk/keynamesprivate.h:6879
+#: gdk/keynamesprivate.h:6897
 msgctxt "keyboard label"
 msgid "KP_Delete"
 msgstr "Suppr (pavé num.)"
 
-#: gdk/keynamesprivate.h:6880
+#: gdk/keynamesprivate.h:6898
 msgctxt "keyboard label"
 msgid "Delete"
 msgstr "Suppr"
 
-#: gdk/keynamesprivate.h:6881
+#: gdk/keynamesprivate.h:6899
 msgctxt "keyboard label"
 msgid "MonBrightnessUp"
 msgstr "Luminosité écran plus forte"
 
-#: gdk/keynamesprivate.h:6882
+#: gdk/keynamesprivate.h:6900
 msgctxt "keyboard label"
 msgid "MonBrightnessDown"
 msgstr "Luminosité écran plus faible"
 
-#: gdk/keynamesprivate.h:6883
+#: gdk/keynamesprivate.h:6901
 msgctxt "keyboard label"
 msgid "KbdBrightnessUp"
 msgstr "Luminosité clavier plus forte"
 
-#: gdk/keynamesprivate.h:6884
+#: gdk/keynamesprivate.h:6902
 msgctxt "keyboard label"
 msgid "KbdBrightnessDown"
 msgstr "Luminosité clavier plus faible"
 
-#: gdk/keynamesprivate.h:6885
+#: gdk/keynamesprivate.h:6903
 msgctxt "keyboard label"
 msgid "AudioMute"
 msgstr "Sourdine volume"
 
-#: gdk/keynamesprivate.h:6886
+#: gdk/keynamesprivate.h:6904
 msgctxt "keyboard label"
 msgid "AudioMicMute"
 msgstr "Sourdine volume micro"
 
-#: gdk/keynamesprivate.h:6887
+#: gdk/keynamesprivate.h:6905
 msgctxt "keyboard label"
 msgid "AudioLowerVolume"
 msgstr "Volume plus faible"
 
-#: gdk/keynamesprivate.h:6888
+#: gdk/keynamesprivate.h:6906
 msgctxt "keyboard label"
 msgid "AudioRaiseVolume"
 msgstr "Volume plus fort"
 
-#: gdk/keynamesprivate.h:6889
+#: gdk/keynamesprivate.h:6907
 msgctxt "keyboard label"
 msgid "AudioPlay"
 msgstr "Démarrage lecture"
 
-#: gdk/keynamesprivate.h:6890
+#: gdk/keynamesprivate.h:6908
 msgctxt "keyboard label"
 msgid "AudioStop"
 msgstr "Arrêt lecture"
 
-#: gdk/keynamesprivate.h:6891
+#: gdk/keynamesprivate.h:6909
 msgctxt "keyboard label"
 msgid "AudioNext"
 msgstr "Morceau suivant"
 
-#: gdk/keynamesprivate.h:6892
+#: gdk/keynamesprivate.h:6910
 msgctxt "keyboard label"
 msgid "AudioPrev"
 msgstr "Morceau précédent"
 
-#: gdk/keynamesprivate.h:6893
+#: gdk/keynamesprivate.h:6911
 msgctxt "keyboard label"
 msgid "AudioRecord"
 msgstr "Enregistrement"
 
-#: gdk/keynamesprivate.h:6894
+#: gdk/keynamesprivate.h:6912
 msgctxt "keyboard label"
 msgid "AudioPause"
 msgstr "Pause"
 
-#: gdk/keynamesprivate.h:6895
+#: gdk/keynamesprivate.h:6913
 msgctxt "keyboard label"
 msgid "AudioRewind"
 msgstr "Lecture en arrière"
 
-#: gdk/keynamesprivate.h:6896
+#: gdk/keynamesprivate.h:6914
 msgctxt "keyboard label"
 msgid "AudioMedia"
 msgstr "Média audio"
 
-#: gdk/keynamesprivate.h:6897
+#: gdk/keynamesprivate.h:6915
 msgctxt "keyboard label"
 msgid "Eject"
 msgstr "Éjection"
 
-#: gdk/keynamesprivate.h:6898
+#: gdk/keynamesprivate.h:6916
 msgctxt "keyboard label"
 msgid "Explorer"
 msgstr "Navigateur"
 
-#: gdk/keynamesprivate.h:6899
+#: gdk/keynamesprivate.h:6917
 msgctxt "keyboard label"
 msgid "Calculator"
 msgstr "Calculatrice"
 
-#: gdk/keynamesprivate.h:6900
+#: gdk/keynamesprivate.h:6918
 msgctxt "keyboard label"
 msgid "Mail"
 msgstr "Courriel"
 
-#: gdk/keynamesprivate.h:6901
+#: gdk/keynamesprivate.h:6919
 msgctxt "keyboard label"
 msgid "WWW"
 msgstr "Web"
 
-#: gdk/keynamesprivate.h:6902
+#: gdk/keynamesprivate.h:6920
 msgctxt "keyboard label"
 msgid "Search"
 msgstr "Recherche"
 
-#: gdk/keynamesprivate.h:6903
+#: gdk/keynamesprivate.h:6921
 msgctxt "keyboard label"
 msgid "Tools"
 msgstr "Outils"
 
-#: gdk/keynamesprivate.h:6904
+#: gdk/keynamesprivate.h:6922
 msgctxt "keyboard label"
 msgid "ScreenSaver"
 msgstr "Économiseur écran"
 
-#: gdk/keynamesprivate.h:6905
+#: gdk/keynamesprivate.h:6923
 msgctxt "keyboard label"
 msgid "Battery"
 msgstr "Batterie"
 
-#: gdk/keynamesprivate.h:6906
+#: gdk/keynamesprivate.h:6924
 msgctxt "keyboard label"
 msgid "Launch1"
 msgstr "Lancement1"
 
-#: gdk/keynamesprivate.h:6907
+#: gdk/keynamesprivate.h:6925
 msgctxt "keyboard label"
 msgid "Forward"
 msgstr "En avant"
 
-#: gdk/keynamesprivate.h:6908
+#: gdk/keynamesprivate.h:6926
 msgctxt "keyboard label"
 msgid "Back"
 msgstr "En arrière"
 
-#: gdk/keynamesprivate.h:6909
+#: gdk/keynamesprivate.h:6927
 msgctxt "keyboard label"
 msgid "Sleep"
 msgstr "Mise en veille"
 
-#: gdk/keynamesprivate.h:6910
+#: gdk/keynamesprivate.h:6928
 msgctxt "keyboard label"
 msgid "Hibernate"
 msgstr "Hibernation"
 
-#: gdk/keynamesprivate.h:6911
+#: gdk/keynamesprivate.h:6929
 msgctxt "keyboard label"
 msgid "WLAN"
 msgstr "Réseau sans fil"
 
-#: gdk/keynamesprivate.h:6912
+#: gdk/keynamesprivate.h:6930
 msgctxt "keyboard label"
 msgid "WebCam"
 msgstr "Webcam"
 
-#: gdk/keynamesprivate.h:6913
+#: gdk/keynamesprivate.h:6931
 msgctxt "keyboard label"
 msgid "Display"
 msgstr "Écran"
 
-#: gdk/keynamesprivate.h:6914
+#: gdk/keynamesprivate.h:6932
 msgctxt "keyboard label"
 msgid "TouchpadToggle"
 msgstr "Bascule pavé tactile"
 
-#: gdk/keynamesprivate.h:6915
+#: gdk/keynamesprivate.h:6933
 msgctxt "keyboard label"
 msgid "WakeUp"
 msgstr "Réveil"
 
-#: gdk/keynamesprivate.h:6916
+#: gdk/keynamesprivate.h:6934
 msgctxt "keyboard label"
 msgid "Suspend"
 msgstr "Suspension"
 
-#: gdk/loaders/gdkjpeg.c:63
+#: gdk/loaders/gdkjpeg.c:71
 #, c-format
 msgid "Error interpreting JPEG image file (%s)"
 msgstr "Erreur d’interprétation du fichier d’image JPEG (%s)"
 
-#: gdk/loaders/gdkjpeg.c:194
+#: gdk/loaders/gdkjpeg.c:185
 #, c-format
 msgid "Unsupported JPEG colorspace (%d)"
 msgstr "Espace de couleur JPEG non pris en charge (%d)"
 
-#: gdk/loaders/gdkjpeg.c:203 gdk/loaders/gdkpng.c:286 gdk/loaders/gdktiff.c:472
+#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:436 gdk/loaders/gdktiff.c:472
 #, c-format
 msgid "Not enough memory for image size %ux%u"
 msgstr "Mémoire insuffisante pour une taille d’image de %ux%u"
 
-#: gdk/loaders/gdkpng.c:118
+#: gdk/loaders/gdkpng.c:120
 #, c-format
 msgid "Error reading png (%s)"
 msgstr "Erreur lors de la lecture du png (%s)"
 
-#: gdk/loaders/gdkpng.c:212
+#: gdk/loaders/gdkpng.c:357
 #, c-format
 msgid "Unsupported depth %u in png image"
 msgstr "Profondeur d’image %u du png non prise en charge"
 
-#: gdk/loaders/gdkpng.c:262
+#: gdk/loaders/gdkpng.c:407
 #, c-format
 msgid "Unsupported color type %u in png image"
 msgstr "Type de couleur %u du png non pris en charge"
 
-#: gdk/loaders/gdkpng.c:272
+#: gdk/loaders/gdkpng.c:421
 #, c-format
 msgid "Image stride too large for image size %ux%u"
 msgstr "Foulée d’image trop grande pour une taille d’image de %ux%u"
@@ -587,9 +614,9 @@ msgstr "Impossible de lire les données TIFF"
 msgid "Reading data failed at row %d"
 msgstr "La lecture des données a échoué à la ligne %d"
 
-#: gdk/macos/gdkmacospasteboard.c:211 gdk/wayland/gdkclipboard-wayland.c:238
-#: gdk/wayland/gdkdrop-wayland.c:205 gdk/wayland/gdkprimary-wayland.c:337
-#: gdk/win32/gdkdrop-win32.c:1018 gdk/win32/gdkdrop-win32.c:1063
+#: gdk/macos/gdkmacospasteboard.c:211 gdk/wayland/gdkclipboard-wayland.c:244
+#: gdk/wayland/gdkdrop-wayland.c:205 gdk/wayland/gdkprimary-wayland.c:343
+#: gdk/win32/gdkdrop-win32.c:1018 gdk/win32/gdkdrop-win32.c:1067
 #: gdk/x11/gdkclipboard-x11.c:799 gdk/x11/gdkdrop-x11.c:235
 msgid "No compatible transfer format found"
 msgstr "Aucun format de transfert compatible n’a été trouvé"
@@ -733,43 +760,43 @@ msgstr ""
 "Impossible d’obtenir les données glisser-déposer. Échec d’allocation de %s "
 "octets pour stocker les données."
 
-#: gdk/win32/gdkdrop-win32.c:1037
+#: gdk/win32/gdkdrop-win32.c:1039
 #, c-format
 msgid "GDK surface 0x%p is not registered as a drop target"
 msgstr "Surface GDK 0x%p n’est pas inscrite comme cible de déposer"
 
-#: gdk/win32/gdkdrop-win32.c:1044
+#: gdk/win32/gdkdrop-win32.c:1047
 #, c-format
 msgid "Target context record 0x%p has no data object"
 msgstr "L’enregistrement de contexte cible 0x%p n’a pas d’objet de données"
 
-#: gdk/win32/gdkdrop-win32.c:1082
+#: gdk/win32/gdkdrop-win32.c:1087
 #, c-format
 msgid "IDataObject_GetData (0x%x) failed, returning 0x%lx"
 msgstr "IDataObject_GetData (0x%x) a échoué, renvoi de 0x%lx"
 
-#: gdk/win32/gdkdrop-win32.c:1114
+#: gdk/win32/gdkdrop-win32.c:1121
 #, c-format
 msgid "Failed to transmute DnD data W32 format 0x%x to %p (%s)"
 msgstr ""
 "Impossible de transmuter le format W32 de données glisser-déposer 0x%x vers "
 "%p (%s)"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:329
+#: gdk/win32/gdkglcontext-win32-wgl.c:681
 msgid "No GL implementation is available"
 msgstr "Aucune implémentation GL disponible"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:404
+#: gdk/win32/gdkglcontext-win32-wgl.c:771
 #, c-format
 msgid "WGL version %d.%d is too low, need at least %d.%d"
 msgstr "La version %d.%d d’EGL est trop basse, elle doit être au moins à %d.%d"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:422
+#: gdk/win32/gdkglcontext-win32-wgl.c:789
 #, c-format
 msgid "GL implementation cannot share GL contexts"
 msgstr "L’implémentation GL ne peut pas partager les contextes GL"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:702
+#: gdk/win32/gdkglcontext-win32-wgl.c:1069
 msgid "No available configurations for the given pixel format"
 msgstr "Pas de configuration disponible pour le format de pixel donné"
 
@@ -792,7 +819,7 @@ msgstr "Espace tampon plein (taille de tampon fixe)"
 
 #: gdk/win32/gdkhdataoutputstream-win32.c:203
 msgid "Can’t transmute a single handle"
-msgstr "Impossible de transmuter un descripteur unique"
+msgstr "Impossible de transmuter un seul descripteur"
 
 #: gdk/win32/gdkhdataoutputstream-win32.c:215
 #, c-format
@@ -834,16 +861,16 @@ msgstr ""
 "Impossible de stocker le presse-papiers. Aucun gestionnaire de presse-"
 "papiers n’est actif."
 
-#: gdk/x11/gdkglcontext-glx.c:810
+#: gdk/x11/gdkglcontext-glx.c:817
 msgid "No GLX configurations available"
 msgstr "Aucune configuration GLX disponible"
 
-#: gdk/x11/gdkglcontext-glx.c:883
+#: gdk/x11/gdkglcontext-glx.c:904
 msgid "No GLX configuration with required features found"
 msgstr ""
 "Aucune configuration GLX avec les fonctionnalités requises n’a été trouvée"
 
-#: gdk/x11/gdkglcontext-glx.c:957
+#: gdk/x11/gdkglcontext-glx.c:978
 msgid "GLX is not supported"
 msgstr "GLX n’est pas pris en charge"
 
@@ -874,19 +901,19 @@ msgstr "Formats non valides dans la conversion de texte composé."
 msgid "Unsupported encoding “%s”"
 msgstr "Codage « %s » non pris en charge"
 
-#: gsk/gl/gskglrenderer.c:204
+#: gsk/gl/gskglrenderer.c:215
 #, c-format
 msgid "This GLES %d.%d implementation does not support half-float vertex data"
 msgstr ""
 "Cette implémentation de GLES %d.%d ne prend pas en charge les valeurs demi-"
 "flottantes pour les coordonnées des sommets."
 
-#: gsk/gpu/gskgldevice.c:246
+#: gsk/gpu/gskgldevice.c:252
 #, c-format
 msgid "OpenGL ES 3.0 is not supported by this renderer."
 msgstr "OpenGL ES 3.0 n’est pas pris en charge par ce moteur de rendu."
 
-#: gsk/gpu/gsknglrenderer.c:62
+#: gsk/gpu/gsknglrenderer.c:69
 msgid "OpenGL 3.3 required"
 msgstr "OpenGL 3.3 nécessaire"
 
@@ -993,7 +1020,7 @@ msgctxt "accessibility"
 msgid "Clears the contents of the entry"
 msgstr "Efface le contenu de la zone de saisie"
 
-#: gtk/a11y/gtkatspiroot.c:256 gtk/gtkaccessible.c:869
+#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:869
 msgctxt "accessibility"
 msgid "application"
 msgstr "application"
@@ -1103,17 +1130,17 @@ msgid "%d %%"
 msgstr "%d %%"
 
 #: gtk/deprecated/gtkcolorbutton.c:183 gtk/deprecated/gtkcolorbutton.c:314
-#: gtk/gtkcolordialog.c:411
+#: gtk/gtkcolordialog.c:409
 msgid "Pick a Color"
 msgstr "Choisissez une couleur"
 
-#: gtk/deprecated/gtkcolorbutton.c:505 gtk/gtkcolorchooserwidget.c:313
+#: gtk/deprecated/gtkcolorbutton.c:505 gtk/gtkcolorchooserwidget.c:321
 #: gtk/gtkcolordialogbutton.c:335
 #, c-format
 msgid "Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"
 msgstr "Rouge %d%%, Vert %d%%, Bleu %d%%, Alpha %d%%"
 
-#: gtk/deprecated/gtkcolorbutton.c:511 gtk/gtkcolorchooserwidget.c:319
+#: gtk/deprecated/gtkcolorbutton.c:511 gtk/gtkcolorchooserwidget.c:327
 #: gtk/gtkcolordialogbutton.c:341
 #, c-format
 msgid "Red %d%%, Green %d%%, Blue %d%%"
@@ -1124,12 +1151,12 @@ msgid "Sans 12"
 msgstr "Sans 12"
 
 #: gtk/deprecated/gtkfontbutton.c:507 gtk/deprecated/gtkfontbutton.c:624
-#: gtk/gtkfontdialog.c:596
+#: gtk/gtkfontdialog.c:594
 msgid "Pick a Font"
 msgstr "Choisissez une police"
 
-#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3815
-#: gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:169
+#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3848
+#: gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:285
 msgid "Font"
 msgstr "Police"
 
@@ -1170,7 +1197,7 @@ msgstr ""
 "La politique système empêche les modifications.\n"
 "Contactez votre administrateur système"
 
-#: gtk/deprecated/gtkshow.c:183
+#: gtk/deprecated/gtkshow.c:217
 msgid "Could not show link"
 msgstr "Impossible d’afficher le lien"
 
@@ -1193,111 +1220,111 @@ msgctxt "volume percentage"
 msgid "%d %%"
 msgstr "%d %%"
 
-#: gtk/gtkaboutdialog.c:119 gtk/ui/gtkaboutdialog.ui:173
+#: gtk/gtkaboutdialog.c:125 gtk/ui/gtkaboutdialog.ui:173
 msgid "License"
 msgstr "Licence"
 
-#: gtk/gtkaboutdialog.c:120
+#: gtk/gtkaboutdialog.c:126
 msgid "Custom License"
 msgstr "Licence personnalisée"
 
-#: gtk/gtkaboutdialog.c:121
+#: gtk/gtkaboutdialog.c:127
 msgid "GNU General Public License, version 2 or later"
 msgstr "Licence publique générale GNU, version 2 ou ultérieure"
 
-#: gtk/gtkaboutdialog.c:122
+#: gtk/gtkaboutdialog.c:128
 msgid "GNU General Public License, version 3 or later"
 msgstr "Licence publique générale GNU, version 3 ou ultérieure"
 
-#: gtk/gtkaboutdialog.c:123
+#: gtk/gtkaboutdialog.c:129
 msgid "GNU Lesser General Public License, version 2.1 or later"
 msgstr "Licence publique générale limitée GNU, version 2.1 ou ultérieure"
 
-#: gtk/gtkaboutdialog.c:124
+#: gtk/gtkaboutdialog.c:130
 msgid "GNU Lesser General Public License, version 3 or later"
 msgstr "Licence publique générale limitée GNU, version 3 ou ultérieure"
 
-#: gtk/gtkaboutdialog.c:125
+#: gtk/gtkaboutdialog.c:131
 msgid "BSD 2-Clause License"
 msgstr "Licence BSD à 2 clauses"
 
-#: gtk/gtkaboutdialog.c:126
+#: gtk/gtkaboutdialog.c:132
 msgid "The MIT License (MIT)"
 msgstr "Licence MIT"
 
-#: gtk/gtkaboutdialog.c:127
+#: gtk/gtkaboutdialog.c:133
 msgid "Artistic License 2.0"
 msgstr "Licence artistique 2.0"
 
-#: gtk/gtkaboutdialog.c:128
+#: gtk/gtkaboutdialog.c:134
 msgid "GNU General Public License, version 2 only"
 msgstr "Licence publique générale GNU, version 2 uniquement"
 
-#: gtk/gtkaboutdialog.c:129
+#: gtk/gtkaboutdialog.c:135
 msgid "GNU General Public License, version 3 only"
 msgstr "Licence publique générale GNU, version 3 uniquement"
 
-#: gtk/gtkaboutdialog.c:130
+#: gtk/gtkaboutdialog.c:136
 msgid "GNU Lesser General Public License, version 2.1 only"
 msgstr "Licence publique générale limitée GNU, version 2.1 uniquement"
 
-#: gtk/gtkaboutdialog.c:131
+#: gtk/gtkaboutdialog.c:137
 msgid "GNU Lesser General Public License, version 3 only"
 msgstr "Licence publique générale limitée GNU, version 3 uniquement"
 
-#: gtk/gtkaboutdialog.c:132
+#: gtk/gtkaboutdialog.c:138
 msgid "GNU Affero General Public License, version 3 or later"
 msgstr "Licence publique générale GNU Affero, version 3 ou ultérieure"
 
-#: gtk/gtkaboutdialog.c:133
+#: gtk/gtkaboutdialog.c:139
 msgid "GNU Affero General Public License, version 3 only"
 msgstr "Licence publique générale GNU Affero, version 3 uniquement"
 
-#: gtk/gtkaboutdialog.c:134
+#: gtk/gtkaboutdialog.c:140
 msgid "BSD 3-Clause License"
 msgstr "Licence BSD 3 clauses"
 
-#: gtk/gtkaboutdialog.c:135
+#: gtk/gtkaboutdialog.c:141
 msgid "Apache License, Version 2.0"
 msgstr "Licence Apache, version 2.0"
 
-#: gtk/gtkaboutdialog.c:136
+#: gtk/gtkaboutdialog.c:142
 msgid "Mozilla Public License 2.0"
 msgstr "Licence publique Mozilla 2.0"
 
-#: gtk/gtkaboutdialog.c:137
+#: gtk/gtkaboutdialog.c:143
 msgid "BSD Zero-Clause License"
 msgstr "Licence BSD à zéro clause"
 
-#: gtk/gtkaboutdialog.c:964
+#: gtk/gtkaboutdialog.c:1028
 msgid "Website"
 msgstr "Site Web"
 
-#: gtk/gtkaboutdialog.c:1000 gtk/ui/gtkapplication-quartz.ui:6
+#: gtk/gtkaboutdialog.c:1070 gtk/ui/gtkapplication-quartz.ui:6
 #, c-format
 msgid "About %s"
 msgstr "À propos de %s"
 
-#: gtk/gtkaboutdialog.c:2090
+#: gtk/gtkaboutdialog.c:2164
 msgid "Created by"
 msgstr "Créé par"
 
-#: gtk/gtkaboutdialog.c:2093
+#: gtk/gtkaboutdialog.c:2167
 msgid "Documented by"
 msgstr "Documenté par"
 
-#: gtk/gtkaboutdialog.c:2103
+#: gtk/gtkaboutdialog.c:2177
 msgid "Translated by"
 msgstr "Traduit par"
 
-#: gtk/gtkaboutdialog.c:2108
+#: gtk/gtkaboutdialog.c:2182
 msgid "Design by"
 msgstr "Conception par"
 
 #. Translators: this is the license preamble; the string at the end
 #. * contains the name of the license as link text.
 #.
-#: gtk/gtkaboutdialog.c:2273
+#: gtk/gtkaboutdialog.c:2347
 #, c-format
 msgid ""
 "This program comes with absolutely no warranty.\n"
@@ -1311,7 +1338,7 @@ msgstr ""
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:837 gtk/gtkshortcutlabel.c:101
+#: gtk/gtkaccelgroup.c:839 gtk/gtkshortcutlabel.c:101
 #: gtk/gtkshortcutlabel.c:137
 msgctxt "keyboard label"
 msgid "Shift"
@@ -1322,7 +1349,7 @@ msgstr "Maj"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:856 gtk/gtkshortcutlabel.c:104
+#: gtk/gtkaccelgroup.c:858 gtk/gtkshortcutlabel.c:104
 #: gtk/gtkshortcutlabel.c:139
 msgctxt "keyboard label"
 msgid "Ctrl"
@@ -1333,7 +1360,7 @@ msgstr "Ctrl"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:875 gtk/gtkshortcutlabel.c:107
+#: gtk/gtkaccelgroup.c:877 gtk/gtkshortcutlabel.c:107
 #: gtk/gtkshortcutlabel.c:141
 msgctxt "keyboard label"
 msgid "Alt"
@@ -1344,7 +1371,7 @@ msgstr "Alt"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:893 gtk/gtkshortcutlabel.c:113
+#: gtk/gtkaccelgroup.c:895 gtk/gtkshortcutlabel.c:113
 #: gtk/gtkshortcutlabel.c:143
 msgctxt "keyboard label"
 msgid "Super"
@@ -1355,7 +1382,7 @@ msgstr "Super"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:907 gtk/gtkshortcutlabel.c:116
+#: gtk/gtkaccelgroup.c:909 gtk/gtkshortcutlabel.c:116
 #: gtk/gtkshortcutlabel.c:145
 msgctxt "keyboard label"
 msgid "Hyper"
@@ -1366,7 +1393,7 @@ msgstr "Hyper"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:922 gtk/gtkshortcutlabel.c:110
+#: gtk/gtkaccelgroup.c:924 gtk/gtkshortcutlabel.c:110
 #: gtk/gtkshortcutlabel.c:148
 msgctxt "keyboard label"
 msgid "Meta"
@@ -1376,17 +1403,17 @@ msgstr "Méta"
 #. * be used in accelerators such as "Ctrl+Shift+KP 1" in menus,
 #. * and therefore the translation needs to be very short.
 #.
-#: gtk/gtkaccelgroup.c:942
+#: gtk/gtkaccelgroup.c:944
 msgctxt "keyboard label"
 msgid "KP"
 msgstr "PNum"
 
-#: gtk/gtkaccelgroup.c:949
+#: gtk/gtkaccelgroup.c:951
 msgctxt "keyboard label"
 msgid "Space"
 msgstr "Espace"
 
-#: gtk/gtkaccelgroup.c:952 gtk/gtkshortcutlabel.c:176
+#: gtk/gtkaccelgroup.c:954 gtk/gtkshortcutlabel.c:176
 msgctxt "keyboard label"
 msgid "Backslash"
 msgstr "Barre oblique inverse"
@@ -1689,7 +1716,7 @@ msgstr "séparateur"
 #: gtk/gtkaccessible.c:849
 msgctxt "accessibility"
 msgid "slider"
-msgstr "glissière"
+msgstr "curseur"
 
 #: gtk/gtkaccessible.c:850
 msgctxt "accessibility"
@@ -1811,7 +1838,7 @@ msgctxt "accessibility"
 msgid "terminal"
 msgstr "console"
 
-#: gtk/gtkalertdialog.c:668 gtk/print/gtkcustompaperunixdialog.c:322
+#: gtk/gtkalertdialog.c:667 gtk/print/gtkcustompaperunixdialog.c:322
 #: gtk/gtkmessagedialog.c:166 gtk/ui/gtkassistant.ui:40
 msgid "_Close"
 msgstr "_Fermer"
@@ -1820,10 +1847,14 @@ msgstr "_Fermer"
 #. * suspend or screen locking, and the caller hasn't specified
 #. * a reason.
 #.
-#: gtk/gtkapplication-dbus.c:721 gtk/gtkapplication-dbus.c:763
+#: gtk/gtkapplication-dbus.c:724 gtk/gtkapplication-dbus.c:766
 msgid "Reason not specified"
 msgstr "Raison non indiquée"
 
+#: gtk/gtkapplicationwindow.c:236
+msgid "Menu bar"
+msgstr "Barre de menus"
+
 #: gtk/gtkbookmarksmanager.c:53
 #, c-format
 msgid "%s does not exist in the bookmarks list"
@@ -1853,7 +1884,7 @@ msgstr "Il se peut que le texte n’apparaisse pas à l’intérieur de <%s>"
 #. * first day of the week to calendar:week_start:1 if you want Monday
 #. * to be the first day of the week, and so on.
 #.
-#: gtk/gtkcalendar.c:659
+#: gtk/gtkcalendar.c:670
 msgid "calendar:week_start:0"
 msgstr "calendar:week_start:1"
 
@@ -1867,21 +1898,10 @@ msgstr "calendar:week_start:1"
 #. * text direction of RTL and specify "calendar:YM", then the year
 #. * will appear to the right of the month.
 #.
-#: gtk/gtkcalendar.c:810
+#: gtk/gtkcalendar.c:821
 msgid "calendar:MY"
 msgstr "calendar:MY"
 
-#. Translators: This dictates how the year is displayed in
-#. * gtkcalendar widget.  See strftime() manual for the format.
-#. * Use only ASCII in the translation.
-#. *
-#. * "%Y" is appropriate for most locales.
-#.
-#: gtk/gtkcalendar.c:995
-msgctxt "calendar year format"
-msgid "%Y"
-msgstr "%Y"
-
 #. Translators: this defines whether the day numbers should use
 #. * localized digits or the ones used in English (0123...).
 #. *
@@ -1892,12 +1912,23 @@ msgstr "%Y"
 #. * digits. That needs support from your system and locale definition
 #. * too.
 #.
-#: gtk/gtkcalendar.c:1032
+#: gtk/gtkcalendar.c:1002
 #, c-format
 msgctxt "calendar:day:digits"
 msgid "%d"
 msgstr "%d"
 
+#. Translators: This dictates how the year is displayed in
+#. * gtkcalendar widget.  See strftime() manual for the format.
+#. * Use only ASCII in the translation.
+#. *
+#. * "%Y" is appropriate for most locales.
+#.
+#: gtk/gtkcalendar.c:1106
+msgctxt "calendar year format"
+msgid "%Y"
+msgstr "%Y"
+
 #. Translators: this defines whether the week numbers should use
 #. * localized digits or the ones used in English (0123...).
 #. *
@@ -1906,252 +1937,252 @@ msgstr "%d"
 #. * Note that translating this doesn't guarantee that you get localized
 #. * digits. That needs support from your system and locale definition
 #. * too.
-#: gtk/gtkcalendar.c:1097
+#: gtk/gtkcalendar.c:1152
 #, c-format
 msgctxt "calendar:week:digits"
 msgid "%d"
 msgstr "%d"
 
-#: gtk/gtkcolorchooserwidget.c:376 gtk/gtkcoloreditor.c:171
+#: gtk/gtkcolorchooserwidget.c:384 gtk/gtkcoloreditor.c:171
 #, c-format
 msgid "Color: %s"
 msgstr "Couleur : %s"
 
-#: gtk/gtkcolorchooserwidget.c:441
+#: gtk/gtkcolorchooserwidget.c:449
 msgctxt "Color name"
 msgid "Very Light Blue"
 msgstr "Bleu très clair"
 
-#: gtk/gtkcolorchooserwidget.c:442
+#: gtk/gtkcolorchooserwidget.c:450
 msgctxt "Color name"
 msgid "Light Blue"
 msgstr "Bleu clair"
 
-#: gtk/gtkcolorchooserwidget.c:443
+#: gtk/gtkcolorchooserwidget.c:451
 msgctxt "Color name"
 msgid "Blue"
 msgstr "Bleu"
 
-#: gtk/gtkcolorchooserwidget.c:444
+#: gtk/gtkcolorchooserwidget.c:452
 msgctxt "Color name"
 msgid "Dark Blue"
 msgstr "Bleu foncé"
 
-#: gtk/gtkcolorchooserwidget.c:445
+#: gtk/gtkcolorchooserwidget.c:453
 msgctxt "Color name"
 msgid "Very Dark Blue"
 msgstr "Bleu très foncé"
 
-#: gtk/gtkcolorchooserwidget.c:446
+#: gtk/gtkcolorchooserwidget.c:454
 msgctxt "Color name"
 msgid "Very Light Green"
 msgstr "Vert très clair"
 
-#: gtk/gtkcolorchooserwidget.c:447
+#: gtk/gtkcolorchooserwidget.c:455
 msgctxt "Color name"
 msgid "Light Green"
 msgstr "Vert clair"
 
-#: gtk/gtkcolorchooserwidget.c:448
+#: gtk/gtkcolorchooserwidget.c:456
 msgctxt "Color name"
 msgid "Green"
 msgstr "Vert"
 
-#: gtk/gtkcolorchooserwidget.c:449
+#: gtk/gtkcolorchooserwidget.c:457
 msgctxt "Color name"
 msgid "Dark Green"
 msgstr "Vert foncé"
 
-#: gtk/gtkcolorchooserwidget.c:450
+#: gtk/gtkcolorchooserwidget.c:458
 msgctxt "Color name"
 msgid "Very Dark Green"
 msgstr "Vert très foncé"
 
-#: gtk/gtkcolorchooserwidget.c:451
+#: gtk/gtkcolorchooserwidget.c:459
 msgctxt "Color name"
 msgid "Very Light Yellow"
 msgstr "Jaune très clair"
 
-#: gtk/gtkcolorchooserwidget.c:452
+#: gtk/gtkcolorchooserwidget.c:460
 msgctxt "Color name"
 msgid "Light Yellow"
 msgstr "Jaune clair"
 
-#: gtk/gtkcolorchooserwidget.c:453
+#: gtk/gtkcolorchooserwidget.c:461
 msgctxt "Color name"
 msgid "Yellow"
 msgstr "Jaune"
 
-#: gtk/gtkcolorchooserwidget.c:454
+#: gtk/gtkcolorchooserwidget.c:462
 msgctxt "Color name"
 msgid "Dark Yellow"
 msgstr "Jaune foncé"
 
-#: gtk/gtkcolorchooserwidget.c:455
+#: gtk/gtkcolorchooserwidget.c:463
 msgctxt "Color name"
 msgid "Very Dark Yellow"
 msgstr "Jaune très foncé"
 
-#: gtk/gtkcolorchooserwidget.c:456
+#: gtk/gtkcolorchooserwidget.c:464
 msgctxt "Color name"
 msgid "Very Light Orange"
 msgstr "Orange très clair"
 
-#: gtk/gtkcolorchooserwidget.c:457
+#: gtk/gtkcolorchooserwidget.c:465
 msgctxt "Color name"
 msgid "Light Orange"
 msgstr "Orange clair"
 
-#: gtk/gtkcolorchooserwidget.c:458
+#: gtk/gtkcolorchooserwidget.c:466
 msgctxt "Color name"
 msgid "Orange"
 msgstr "Orange"
 
-#: gtk/gtkcolorchooserwidget.c:459
+#: gtk/gtkcolorchooserwidget.c:467
 msgctxt "Color name"
 msgid "Dark Orange"
 msgstr "Orange foncé"
 
-#: gtk/gtkcolorchooserwidget.c:460
+#: gtk/gtkcolorchooserwidget.c:468
 msgctxt "Color name"
 msgid "Very Dark Orange"
 msgstr "Orange très foncé"
 
-#: gtk/gtkcolorchooserwidget.c:461
+#: gtk/gtkcolorchooserwidget.c:469
 msgctxt "Color name"
 msgid "Very Light Red"
 msgstr "Rouge très clair"
 
-#: gtk/gtkcolorchooserwidget.c:462
+#: gtk/gtkcolorchooserwidget.c:470
 msgctxt "Color name"
 msgid "Light Red"
 msgstr "Rouge clair"
 
-#: gtk/gtkcolorchooserwidget.c:463
+#: gtk/gtkcolorchooserwidget.c:471
 msgctxt "Color name"
 msgid "Red"
 msgstr "Rouge"
 
-#: gtk/gtkcolorchooserwidget.c:464
+#: gtk/gtkcolorchooserwidget.c:472
 msgctxt "Color name"
 msgid "Dark Red"
 msgstr "Rouge foncé"
 
-#: gtk/gtkcolorchooserwidget.c:465
+#: gtk/gtkcolorchooserwidget.c:473
 msgctxt "Color name"
 msgid "Very Dark Red"
 msgstr "Rouge très foncé"
 
-#: gtk/gtkcolorchooserwidget.c:466
+#: gtk/gtkcolorchooserwidget.c:474
 msgctxt "Color name"
 msgid "Very Light Purple"
 msgstr "Violet très clair"
 
-#: gtk/gtkcolorchooserwidget.c:467
+#: gtk/gtkcolorchooserwidget.c:475
 msgctxt "Color name"
 msgid "Light Purple"
 msgstr "Violet clair"
 
-#: gtk/gtkcolorchooserwidget.c:468
+#: gtk/gtkcolorchooserwidget.c:476
 msgctxt "Color name"
 msgid "Purple"
 msgstr "Violet"
 
-#: gtk/gtkcolorchooserwidget.c:469
+#: gtk/gtkcolorchooserwidget.c:477
 msgctxt "Color name"
 msgid "Dark Purple"
 msgstr "Violet foncé"
 
-#: gtk/gtkcolorchooserwidget.c:470
+#: gtk/gtkcolorchooserwidget.c:478
 msgctxt "Color name"
 msgid "Very Dark Purple"
 msgstr "Violet très foncé"
 
-#: gtk/gtkcolorchooserwidget.c:471
+#: gtk/gtkcolorchooserwidget.c:479
 msgctxt "Color name"
 msgid "Very Light Brown"
 msgstr "Brun très clair"
 
-#: gtk/gtkcolorchooserwidget.c:472
+#: gtk/gtkcolorchooserwidget.c:480
 msgctxt "Color name"
 msgid "Light Brown"
 msgstr "Brun clair"
 
-#: gtk/gtkcolorchooserwidget.c:473
+#: gtk/gtkcolorchooserwidget.c:481
 msgctxt "Color name"
 msgid "Brown"
 msgstr "Brun"
 
-#: gtk/gtkcolorchooserwidget.c:474
+#: gtk/gtkcolorchooserwidget.c:482
 msgctxt "Color name"
 msgid "Dark Brown"
 msgstr "Brun foncé"
 
-#: gtk/gtkcolorchooserwidget.c:475
+#: gtk/gtkcolorchooserwidget.c:483
 msgctxt "Color name"
 msgid "Very Dark Brown"
 msgstr "Brun très foncé"
 
-#: gtk/gtkcolorchooserwidget.c:476
+#: gtk/gtkcolorchooserwidget.c:484
 msgctxt "Color name"
 msgid "White"
 msgstr "Blanc"
 
-#: gtk/gtkcolorchooserwidget.c:477
+#: gtk/gtkcolorchooserwidget.c:485
 msgctxt "Color name"
 msgid "Light Gray 1"
 msgstr "Gris clair 1"
 
-#: gtk/gtkcolorchooserwidget.c:478
+#: gtk/gtkcolorchooserwidget.c:486
 msgctxt "Color name"
 msgid "Light Gray 2"
 msgstr "Gris clair 2"
 
-#: gtk/gtkcolorchooserwidget.c:479
+#: gtk/gtkcolorchooserwidget.c:487
 msgctxt "Color name"
 msgid "Light Gray 3"
 msgstr "Gris clair 3"
 
-#: gtk/gtkcolorchooserwidget.c:480
+#: gtk/gtkcolorchooserwidget.c:488
 msgctxt "Color name"
 msgid "Light Gray 4"
 msgstr "Gris clair 4"
 
-#: gtk/gtkcolorchooserwidget.c:481
+#: gtk/gtkcolorchooserwidget.c:489
 msgctxt "Color name"
 msgid "Dark Gray 1"
 msgstr "Gris foncé 1"
 
-#: gtk/gtkcolorchooserwidget.c:482
+#: gtk/gtkcolorchooserwidget.c:490
 msgctxt "Color name"
 msgid "Dark Gray 2"
 msgstr "Gris foncé 2"
 
-#: gtk/gtkcolorchooserwidget.c:483
+#: gtk/gtkcolorchooserwidget.c:491
 msgctxt "Color name"
 msgid "Dark Gray 3"
 msgstr "Gris foncé 3"
 
-#: gtk/gtkcolorchooserwidget.c:484
+#: gtk/gtkcolorchooserwidget.c:492
 msgctxt "Color name"
 msgid "Dark Gray 4"
 msgstr "Gris foncé 4"
 
-#: gtk/gtkcolorchooserwidget.c:485
+#: gtk/gtkcolorchooserwidget.c:493
 msgctxt "Color name"
 msgid "Black"
 msgstr "Noir"
 
 #. translators: label for the custom section in the color chooser
-#: gtk/gtkcolorchooserwidget.c:557
+#: gtk/gtkcolorchooserwidget.c:565
 msgid "Custom"
 msgstr "Personnalisée"
 
-#: gtk/gtkcolorchooserwidget.c:571
+#: gtk/gtkcolorchooserwidget.c:579
 msgid "Add Color"
 msgstr "Ajouter la couleur"
 
-#: gtk/gtkcolorchooserwidget.c:593
+#: gtk/gtkcolorchooserwidget.c:601
 #, c-format
 msgid "Custom color %d: %s"
 msgstr "Couleur personnalisée %d : %s"
@@ -2175,7 +2206,7 @@ msgid "Margins from Printer…"
 msgstr "Marges de l’imprimante…"
 
 #. And show the custom paper dialog
-#: gtk/print/gtkcustompaperunixdialog.c:377 gtk/print/gtkprintunixdialog.c:2968
+#: gtk/print/gtkcustompaperunixdialog.c:377 gtk/print/gtkprintunixdialog.c:2976
 msgid "Manage Custom Sizes"
 msgstr "Gérer les tailles personnalisées"
 
@@ -2291,28 +2322,28 @@ msgid "A file with that name already exists"
 msgstr "Un fichier avec ce nom existe déjà"
 
 #: gtk/gtkfilechoosernative.c:520 gtk/gtkfilechoosernative.c:600
-#: gtk/gtkfilechooserwidget.c:1188 gtk/gtkfilechooserwidget.c:4973
-#: gtk/gtkfiledialog.c:843 gtk/gtkmessagedialog.c:170
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:5018
+#: gtk/gtkfiledialog.c:840 gtk/gtkmessagedialog.c:170
 #: gtk/gtkmessagedialog.c:179 gtk/gtkmountoperation.c:608
 #: gtk/print/gtkpagesetupunixdialog.c:282 gtk/print/gtkprintbackend.c:638
 #: gtk/print/gtkprintunixdialog.c:682 gtk/print/gtkprintunixdialog.c:839
-#: gtk/gtkwindow.c:6256 gtk/ui/gtkappchooserdialog.ui:48
+#: gtk/gtkwindow.c:6211 gtk/ui/gtkappchooserdialog.ui:48
 #: gtk/ui/gtkassistant.ui:52 gtk/ui/gtkcolorchooserdialog.ui:36
-#: gtk/ui/gtkfontchooserdialog.ui:27
+#: gtk/ui/gtkfontchooserdialog.ui:29
 msgid "_Cancel"
 msgstr "A_nnuler"
 
 #: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594
-#: gtk/gtkfiledialog.c:815 gtk/gtkplacessidebar.c:3149
+#: gtk/gtkfiledialog.c:812 gtk/gtkplacessidebar.c:3149
 #: gtk/gtkplacessidebar.c:3234 gtk/gtkplacesview.c:1645
 msgid "_Open"
 msgstr "_Ouvrir"
 
-#: gtk/gtkfilechoosernative.c:594 gtk/gtkfiledialog.c:820
+#: gtk/gtkfilechoosernative.c:594 gtk/gtkfiledialog.c:817
 msgid "_Save"
 msgstr "_Enregistrer"
 
-#: gtk/gtkfilechoosernativequartz.c:344 gtk/ui/gtkfilechooserwidget.ui:288
+#: gtk/gtkfilechoosernativequartz.c:348 gtk/ui/gtkfilechooserwidget.ui:299
 msgid "Select which types of files are shown"
 msgstr "Sélectionne les types de fichiers à afficher"
 
@@ -2325,314 +2356,315 @@ msgstr "Sélectionne les types de fichiers à afficher"
 msgid "%1$s on %2$s"
 msgstr "%1$s sur %2$s"
 
-#: gtk/gtkfilechooserwidget.c:343
+#: gtk/gtkfilechooserwidget.c:365
 msgid "Type name of new folder"
 msgstr "Saisissez le nom du nouveau dossier"
 
-#: gtk/gtkfilechooserwidget.c:730
+#: gtk/gtkfilechooserwidget.c:752
 msgid "The folder could not be created"
 msgstr "Le dossier ne peut pas être créé"
 
-#: gtk/gtkfilechooserwidget.c:743
+#: gtk/gtkfilechooserwidget.c:765
 msgid "You need to choose a valid filename."
 msgstr "Vous devez choisir un nom de fichier valide."
 
-#: gtk/gtkfilechooserwidget.c:746
+#: gtk/gtkfilechooserwidget.c:768
 #, c-format
 msgid "Cannot create a file under %s as it is not a folder"
 msgstr "Impossible de créer un fichier dans %s car ce n’est pas un dossier"
 
-#: gtk/gtkfilechooserwidget.c:756
+#: gtk/gtkfilechooserwidget.c:778
 msgid "Cannot create file as the filename is too long"
 msgstr "Impossible de créer le fichier car le nom de fichier est trop long"
 
-#: gtk/gtkfilechooserwidget.c:757
+#: gtk/gtkfilechooserwidget.c:779
 msgid "Try using a shorter name."
 msgstr "Essayez avec un nom plus court."
 
-#: gtk/gtkfilechooserwidget.c:767
+#: gtk/gtkfilechooserwidget.c:789
 msgid "You may only select folders"
 msgstr "Seuls les dossiers peuvent être sélectionnés"
 
-#: gtk/gtkfilechooserwidget.c:768
+#: gtk/gtkfilechooserwidget.c:790
 msgid "The item that you selected is not a folder try using a different item."
 msgstr ""
 "L’élément que vous avez choisi n’est pas un dossier ; essayez d’utiliser un "
 "autre élément."
 
-#: gtk/gtkfilechooserwidget.c:776
+#: gtk/gtkfilechooserwidget.c:798
 msgid "Invalid file name"
 msgstr "Nom de fichier non valide"
 
-#: gtk/gtkfilechooserwidget.c:785
+#: gtk/gtkfilechooserwidget.c:807
 msgid "The folder contents could not be displayed"
 msgstr "Le contenu du dossier ne peut pas être affiché"
 
-#: gtk/gtkfilechooserwidget.c:793
+#: gtk/gtkfilechooserwidget.c:815
 msgid "The file could not be deleted"
 msgstr "Le fichier n’a pas pu être supprimé"
 
-#: gtk/gtkfilechooserwidget.c:801
+#: gtk/gtkfilechooserwidget.c:823
 msgid "The file could not be moved to the Trash"
 msgstr "Le fichier n’a pas pu être mis à la corbeille"
 
-#: gtk/gtkfilechooserwidget.c:1186
+#: gtk/gtkfilechooserwidget.c:1212
 #, c-format
 msgid "Are you sure you want to permanently delete “%s”?"
 msgstr "Voulez-vous réellement supprimer « %s » de manière permanente ?"
 
-#: gtk/gtkfilechooserwidget.c:1187
+#: gtk/gtkfilechooserwidget.c:1213
 msgid "If you delete an item, it will be permanently lost."
 msgstr "Si vous supprimez un élément, il sera définitivement perdu."
 
-#: gtk/gtkfilechooserwidget.c:1188 gtk/gtkfilechooserwidget.c:1786
-#: gtk/gtklabel.c:5712 gtk/gtktext.c:6194 gtk/gtktextview.c:9099
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:1816
+#: gtk/gtklabel.c:5882 gtk/gtktext.c:6335 gtk/gtktextview.c:9237
 msgid "_Delete"
 msgstr "_Supprimer"
 
-#: gtk/gtkfilechooserwidget.c:1301
+#: gtk/gtkfilechooserwidget.c:1331
 msgid "The file could not be renamed"
 msgstr "Le fichier n’a pas pu être renommé"
 
-#: gtk/gtkfilechooserwidget.c:1477
+#: gtk/gtkfilechooserwidget.c:1507
 msgid "Could not select file"
 msgstr "Impossible de sélectionner le fichier"
 
-#: gtk/gtkfilechooserwidget.c:1697 gtk/ui/gtkfilechooserwidget.ui:66
+#: gtk/gtkfilechooserwidget.c:1727 gtk/ui/gtkfilechooserwidget.ui:66
 msgid "Grid View"
 msgstr "Vue en grille"
 
-#: gtk/gtkfilechooserwidget.c:1703
+#: gtk/gtkfilechooserwidget.c:1733
 msgid "List View"
 msgstr "Vue en liste"
 
-#: gtk/gtkfilechooserwidget.c:1766
+#: gtk/gtkfilechooserwidget.c:1796
 msgid "_Visit File"
 msgstr "C_onsulter ce fichier"
 
-#: gtk/gtkfilechooserwidget.c:1770
+#: gtk/gtkfilechooserwidget.c:1800
 msgid "_Open With File Manager"
 msgstr "_Ouvrir avec le gestionnaire de fichiers"
 
-#: gtk/gtkfilechooserwidget.c:1774
+#: gtk/gtkfilechooserwidget.c:1804
 msgid "_Copy Location"
 msgstr "_Copier l’emplacement"
 
-#: gtk/gtkfilechooserwidget.c:1778
+#: gtk/gtkfilechooserwidget.c:1808
 msgid "_Add to Bookmarks"
 msgstr "A_jouter aux signets"
 
-#: gtk/gtkfilechooserwidget.c:1782 gtk/gtkplacessidebar.c:2312
-#: gtk/gtkplacessidebar.c:3270 gtk/ui/gtkfilechooserwidget.ui:410
+#: gtk/gtkfilechooserwidget.c:1812 gtk/gtkplacessidebar.c:2312
+#: gtk/gtkplacessidebar.c:3270 gtk/ui/gtkfilechooserwidget.ui:421
 msgid "_Rename"
 msgstr "_Renommer"
 
-#: gtk/gtkfilechooserwidget.c:1790
+#: gtk/gtkfilechooserwidget.c:1820
 msgid "_Move to Trash"
 msgstr "_Mettre à la corbeille"
 
-#: gtk/gtkfilechooserwidget.c:1799
+#: gtk/gtkfilechooserwidget.c:1829
 msgid "Show _Hidden Files"
 msgstr "Afficher les fichiers _cachés"
 
-#: gtk/gtkfilechooserwidget.c:1803
+#: gtk/gtkfilechooserwidget.c:1833
 msgid "Sort _Folders Before Files"
 msgstr "Trier les dossiers avant les _fichiers"
 
-#: gtk/gtkfilechooserwidget.c:1926 gtk/gtkfilechooserwidget.c:1956
-#: gtk/gtkfilechooserwidget.c:3858
+#: gtk/gtkfilechooserwidget.c:1956 gtk/gtkfilechooserwidget.c:1986
+#: gtk/gtkfilechooserwidget.c:3891
 msgid "Unknown"
 msgstr "Inconnu"
 
-#: gtk/gtkfilechooserwidget.c:2011 gtk/gtkplacessidebar.c:1025
+#: gtk/gtkfilechooserwidget.c:2041 gtk/gtkplacessidebar.c:1025
 msgid "Home"
 msgstr "Dossier personnel"
 
 #. this is the header for the location column in the print dialog
-#: gtk/gtkfilechooserwidget.c:2166 gtk/gtkfilechooserwidget.c:7383
+#: gtk/gtkfilechooserwidget.c:2196 gtk/gtkfilechooserwidget.c:7446
 #: gtk/inspector/css-node-tree.ui:76 gtk/print/ui/gtkprintunixdialog.ui:111
 msgid "Location"
 msgstr "Emplacement"
 
 #. Label
-#: gtk/gtkfilechooserwidget.c:2273
+#: gtk/gtkfilechooserwidget.c:2303
 msgid "_Name:"
 msgstr "_Nom :"
 
-#: gtk/gtkfilechooserwidget.c:2828 gtk/gtkfilechooserwidget.c:2842
+#: gtk/gtkfilechooserwidget.c:2860 gtk/gtkfilechooserwidget.c:2874
 #, c-format
 msgid "Searching in %s"
 msgstr "Recherche dans %s"
 
-#: gtk/gtkfilechooserwidget.c:2848
+#: gtk/gtkfilechooserwidget.c:2880
 msgid "Searching"
 msgstr "Recherche"
 
-#: gtk/gtkfilechooserwidget.c:2854
+#: gtk/gtkfilechooserwidget.c:2886
 msgid "Enter location or URL"
 msgstr "Saisir un emplacement ou un URL"
 
-#: gtk/gtkfilechooserwidget.c:3413 gtk/gtkfilechooserwidget.c:5758
-#: gtk/gtkfilechooserwidget.c:7405
+#: gtk/gtkfilechooserwidget.c:3445 gtk/gtkfilechooserwidget.c:5805
+#: gtk/gtkfilechooserwidget.c:7468
 msgid "Modified"
 msgstr "Modifié"
 
-#: gtk/gtkfilechooserwidget.c:3598
+#: gtk/gtkfilechooserwidget.c:3630
 #, c-format
 msgid "Could not read the contents of %s"
 msgstr "Impossible de lire le contenu de %s"
 
-#: gtk/gtkfilechooserwidget.c:3602
+#: gtk/gtkfilechooserwidget.c:3634
 msgid "Could not read the contents of the folder"
 msgstr "Impossible de lire le contenu du dossier"
 
 #. Translators: see g_date_time_format() for details on the format
-#: gtk/gtkfilechooserwidget.c:3753 gtk/gtkfilechooserwidget.c:3796
+#: gtk/gtkfilechooserwidget.c:3785 gtk/gtkfilechooserwidget.c:3829
 msgid "%H:%M"
 msgstr "%H:%M"
 
-#: gtk/gtkfilechooserwidget.c:3755 gtk/gtkfilechooserwidget.c:3798
+#: gtk/gtkfilechooserwidget.c:3787 gtk/gtkfilechooserwidget.c:3831
 msgid "%l:%M %p"
 msgstr "%l:%M %p"
 
-#: gtk/gtkfilechooserwidget.c:3759
+#: gtk/gtkfilechooserwidget.c:3791
 msgid "Yesterday"
 msgstr "Hier"
 
-#: gtk/gtkfilechooserwidget.c:3767
+#: gtk/gtkfilechooserwidget.c:3800
+#, no-c-format
 msgid "%-e %b"
 msgstr "%-e %b"
 
-#: gtk/gtkfilechooserwidget.c:3771
+#: gtk/gtkfilechooserwidget.c:3804
 msgid "%-e %b %Y"
 msgstr "%-e %b %Y"
 
-#: gtk/gtkfilechooserwidget.c:3813 gtk/gtkfilechooserwidget.c:3821
+#: gtk/gtkfilechooserwidget.c:3846 gtk/gtkfilechooserwidget.c:3854
 msgid "Program"
 msgstr "Programme"
 
-#: gtk/gtkfilechooserwidget.c:3814
+#: gtk/gtkfilechooserwidget.c:3847
 msgid "Audio"
 msgstr "Audio"
 
-#: gtk/gtkfilechooserwidget.c:3816 gtk/gtkfilefilter.c:1013
+#: gtk/gtkfilechooserwidget.c:3849 gtk/gtkfilefilter.c:1013
 msgid "Image"
 msgstr "Image"
 
-#: gtk/gtkfilechooserwidget.c:3817
+#: gtk/gtkfilechooserwidget.c:3850
 msgid "Archive"
 msgstr "Archive"
 
-#: gtk/gtkfilechooserwidget.c:3818
+#: gtk/gtkfilechooserwidget.c:3851
 msgid "Markup"
 msgstr "Balisage"
 
-#: gtk/gtkfilechooserwidget.c:3819 gtk/gtkfilechooserwidget.c:3820
+#: gtk/gtkfilechooserwidget.c:3852 gtk/gtkfilechooserwidget.c:3853
 msgid "Text"
 msgstr "Texte"
 
-#: gtk/gtkfilechooserwidget.c:3822
+#: gtk/gtkfilechooserwidget.c:3855
 msgid "Video"
 msgstr "Vidéo"
 
-#: gtk/gtkfilechooserwidget.c:3823
+#: gtk/gtkfilechooserwidget.c:3856
 msgid "Contacts"
 msgstr "Contacts"
 
-#: gtk/gtkfilechooserwidget.c:3824
+#: gtk/gtkfilechooserwidget.c:3857
 msgid "Calendar"
 msgstr "Agenda"
 
-#: gtk/gtkfilechooserwidget.c:3825
+#: gtk/gtkfilechooserwidget.c:3858
 msgid "Document"
 msgstr "Document"
 
-#: gtk/gtkfilechooserwidget.c:3826
+#: gtk/gtkfilechooserwidget.c:3859
 msgid "Presentation"
 msgstr "Présentation"
 
-#: gtk/gtkfilechooserwidget.c:3827
+#: gtk/gtkfilechooserwidget.c:3860
 msgid "Spreadsheet"
 msgstr "Feuille de calcul"
 
-#: gtk/gtkfilechooserwidget.c:4965 gtk/print/gtkprintunixdialog.c:673
+#: gtk/gtkfilechooserwidget.c:5010 gtk/print/gtkprintunixdialog.c:673
 #, c-format
 msgid "A file named “%s” already exists.  Do you want to replace it?"
 msgstr "Un fichier nommé « %s » existe déjà. Voulez-vous le remplacer ?"
 
-#: gtk/gtkfilechooserwidget.c:4967 gtk/print/gtkprintunixdialog.c:677
+#: gtk/gtkfilechooserwidget.c:5012 gtk/print/gtkprintunixdialog.c:677
 #, c-format
 msgid ""
 "The file already exists in “%s”.  Replacing it will overwrite its contents."
 msgstr "Le fichier existe déjà dans « %s ». Le remplacer écrasera son contenu."
 
-#: gtk/gtkfilechooserwidget.c:4973 gtk/print/gtkprintunixdialog.c:685
+#: gtk/gtkfilechooserwidget.c:5018 gtk/print/gtkprintunixdialog.c:685
 msgid "_Replace"
 msgstr "_Remplacer"
 
-#: gtk/gtkfilechooserwidget.c:5128
+#: gtk/gtkfilechooserwidget.c:5173
 msgid "You do not have access to the specified folder."
 msgstr "Vous n’avez pas accès à ce dossier."
 
-#: gtk/gtkfilechooserwidget.c:5705
+#: gtk/gtkfilechooserwidget.c:5752
 msgid "Could not send the search request"
 msgstr "Impossible d’envoyer la requête de recherche"
 
-#: gtk/gtkfilechooserwidget.c:5986
+#: gtk/gtkfilechooserwidget.c:6033
 msgid "Accessed"
 msgstr "Accédé"
 
-#: gtk/gtkfilechooserwidget.c:7361
+#: gtk/gtkfilechooserwidget.c:7424
 msgid "_Size"
 msgstr "_Taille"
 
-#: gtk/gtkfilechooserwidget.c:7365
+#: gtk/gtkfilechooserwidget.c:7428
 msgid "T_ype"
 msgstr "T_ype"
 
-#: gtk/gtkfilechooserwidget.c:7369
+#: gtk/gtkfilechooserwidget.c:7432
 msgid "_Time"
 msgstr "D_ate"
 
-#: gtk/gtkfilechooserwidget.c:7375 gtk/gtkplacessidebar.c:2306
+#: gtk/gtkfilechooserwidget.c:7438 gtk/gtkplacessidebar.c:2306
 #: gtk/inspector/a11y.ui:43 gtk/inspector/actions.ui:18
 #: gtk/inspector/css-node-tree.ui:22 gtk/inspector/prop-list.ui:24
-#: gtk/ui/gtkfilechooserwidget.ui:385 gtk/print/ui/gtkprintunixdialog.ui:80
+#: gtk/ui/gtkfilechooserwidget.ui:396 gtk/print/ui/gtkprintunixdialog.ui:80
 msgid "Name"
 msgstr "Nom"
 
-#: gtk/gtkfilechooserwidget.c:7392 gtk/inspector/resource-list.ui:82
-#: gtk/ui/gtkfontchooserwidget.ui:217 gtk/ui/gtkfontchooserwidget.ui:386
+#: gtk/gtkfilechooserwidget.c:7455 gtk/inspector/resource-list.ui:82
+#: gtk/ui/gtkfontchooserwidget.ui:216 gtk/ui/gtkfontchooserwidget.ui:385
 msgid "Size"
 msgstr "Taille"
 
-#: gtk/gtkfilechooserwidget.c:7398 gtk/inspector/misc-info.ui:57
+#: gtk/gtkfilechooserwidget.c:7461 gtk/inspector/misc-info.ui:57
 #: gtk/inspector/prop-list.ui:35 gtk/inspector/statistics.ui:36
 msgid "Type"
 msgstr "Type"
 
-#: gtk/gtkfiledialog.c:816
+#: gtk/gtkfiledialog.c:813
 msgid "Pick Files"
 msgstr "Choisir des fichiers"
 
-#: gtk/gtkfiledialog.c:816
+#: gtk/gtkfiledialog.c:813
 msgid "Pick a File"
 msgstr "Choisir un fichier"
 
-#: gtk/gtkfiledialog.c:821
+#: gtk/gtkfiledialog.c:818
 msgid "Save a File"
 msgstr "Enregistrer un fichier"
 
-#: gtk/gtkfiledialog.c:825 gtk/ui/gtkappchooserdialog.ui:53
-#: gtk/ui/gtkcolorchooserdialog.ui:41 gtk/ui/gtkfontchooserdialog.ui:32
+#: gtk/gtkfiledialog.c:822 gtk/ui/gtkappchooserdialog.ui:53
+#: gtk/ui/gtkcolorchooserdialog.ui:41 gtk/ui/gtkfontchooserdialog.ui:34
 msgid "_Select"
 msgstr "_Sélectionner"
 
-#: gtk/gtkfiledialog.c:826
+#: gtk/gtkfiledialog.c:823
 msgid "Select Folders"
 msgstr "Choisir des dossiers"
 
-#: gtk/gtkfiledialog.c:826
+#: gtk/gtkfiledialog.c:823
 msgid "Select a Folder"
 msgstr "Choisir un dossier"
 
@@ -2644,74 +2676,74 @@ msgstr "Non précisé"
 msgid "Change Font Features"
 msgstr "Modifier les fonctionnalités de police"
 
-#: gtk/gtkfontchooserwidget.c:1547
+#: gtk/gtkfontchooserwidget.c:1491
 msgctxt "Font variation axis"
 msgid "Width"
 msgstr "Largeur"
 
-#: gtk/gtkfontchooserwidget.c:1548
+#: gtk/gtkfontchooserwidget.c:1492
 msgctxt "Font variation axis"
 msgid "Weight"
 msgstr "Poids"
 
-#: gtk/gtkfontchooserwidget.c:1549
+#: gtk/gtkfontchooserwidget.c:1493
 msgctxt "Font variation axis"
 msgid "Italic"
 msgstr "Italique"
 
-#: gtk/gtkfontchooserwidget.c:1550
+#: gtk/gtkfontchooserwidget.c:1494
 msgctxt "Font variation axis"
 msgid "Slant"
 msgstr "Inclinaison"
 
-#: gtk/gtkfontchooserwidget.c:1551
+#: gtk/gtkfontchooserwidget.c:1495
 msgctxt "Font variation axis"
 msgid "Optical Size"
 msgstr "Taille optique"
 
-#: gtk/gtkfontchooserwidget.c:2109
+#: gtk/gtkfontchooserwidget.c:2053
 msgctxt "Font feature value"
 msgid "Default"
 msgstr "Par défaut"
 
-#: gtk/gtkfontchooserwidget.c:2126
+#: gtk/gtkfontchooserwidget.c:2070
 msgctxt "Font feature value"
 msgid "Enable"
 msgstr "Activer"
 
-#: gtk/gtkfontchooserwidget.c:2459
+#: gtk/gtkfontchooserwidget.c:2404
 msgid "Default"
 msgstr "Par défaut"
 
-#: gtk/gtkfontchooserwidget.c:2521
+#: gtk/gtkfontchooserwidget.c:2466
 msgid "Ligatures"
 msgstr "Ligatures"
 
-#: gtk/gtkfontchooserwidget.c:2522
+#: gtk/gtkfontchooserwidget.c:2467
 msgid "Letter Case"
 msgstr "Casse des lettres"
 
-#: gtk/gtkfontchooserwidget.c:2523
+#: gtk/gtkfontchooserwidget.c:2468
 msgid "Number Case"
 msgstr "Casse des nombres"
 
-#: gtk/gtkfontchooserwidget.c:2524
+#: gtk/gtkfontchooserwidget.c:2469
 msgid "Number Spacing"
 msgstr "Espacement des nombres"
 
-#: gtk/gtkfontchooserwidget.c:2525
+#: gtk/gtkfontchooserwidget.c:2470
 msgid "Fractions"
 msgstr "Fractions"
 
-#: gtk/gtkfontchooserwidget.c:2526
+#: gtk/gtkfontchooserwidget.c:2471
 msgid "Style Variations"
 msgstr "Variations de style"
 
-#: gtk/gtkfontchooserwidget.c:2528
+#: gtk/gtkfontchooserwidget.c:2473
 msgid "Character Variations"
 msgstr "Variations de caractères"
 
-#: gtk/gtkglarea.c:309
+#: gtk/gtkglarea.c:316
 msgid "OpenGL context creation failed"
 msgstr "La création de contexte OpenGL a échoué"
 
@@ -2724,39 +2756,39 @@ msgstr "Fermer"
 msgid "Close the infobar"
 msgstr "Fermer la barre d’information"
 
-#: gtk/gtklabel.c:5709 gtk/gtktext.c:6182 gtk/gtktextview.c:9087
+#: gtk/gtklabel.c:5879 gtk/gtktext.c:6323 gtk/gtktextview.c:9225
 msgid "Cu_t"
 msgstr "Co_uper"
 
-#: gtk/gtklabel.c:5710 gtk/gtktext.c:6186 gtk/gtktextview.c:9091
+#: gtk/gtklabel.c:5880 gtk/gtktext.c:6327 gtk/gtktextview.c:9229
 msgid "_Copy"
 msgstr "_Copier"
 
-#: gtk/gtklabel.c:5711 gtk/gtktext.c:6190 gtk/gtktextview.c:9095
+#: gtk/gtklabel.c:5881 gtk/gtktext.c:6331 gtk/gtktextview.c:9233
 msgid "_Paste"
 msgstr "C_oller"
 
-#: gtk/gtklabel.c:5717 gtk/gtktext.c:6203 gtk/gtktextview.c:9120
+#: gtk/gtklabel.c:5887 gtk/gtktext.c:6344 gtk/gtktextview.c:9258
 msgid "Select _All"
 msgstr "_Tout sélectionner"
 
-#: gtk/gtklabel.c:5722
+#: gtk/gtklabel.c:5892
 msgid "_Open Link"
 msgstr "_Ouvrir le lien"
 
-#: gtk/gtklabel.c:5726
+#: gtk/gtklabel.c:5896
 msgid "Copy _Link Address"
 msgstr "Copier l’_adresse du lien"
 
-#: gtk/gtklabel.c:5770 gtk/gtktext.c:2723 gtk/gtktextview.c:9169
+#: gtk/gtklabel.c:5940 gtk/gtktext.c:2851 gtk/gtktextview.c:9307
 msgid "Context menu"
 msgstr "Menu contextuel"
 
-#: gtk/gtklinkbutton.c:260
+#: gtk/gtklinkbutton.c:273
 msgid "_Copy URL"
 msgstr "_Copier l’URL"
 
-#: gtk/gtklinkbutton.c:567
+#: gtk/gtklinkbutton.c:602
 msgid "Invalid URI"
 msgstr "URI non valide"
 
@@ -2819,7 +2851,7 @@ msgid "Play"
 msgstr "Lecture"
 
 #: gtk/gtkmessagedialog.c:162 gtk/gtkmessagedialog.c:180
-#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6257
+#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6212
 msgid "_OK"
 msgstr "_Valider"
 
@@ -2943,15 +2975,15 @@ msgstr "Impossible de terminer le processus ayant le PID %d : %s"
 msgid "GTK could not find a media module. Check your installation."
 msgstr "GTK n’a pas trouvé de module média. Vérifiez votre installation."
 
-#: gtk/gtknotebook.c:3211
+#: gtk/gtknotebook.c:3304
 msgid "Previous tab"
 msgstr "Onglet précédent"
 
-#: gtk/gtknotebook.c:3215
+#: gtk/gtknotebook.c:3308
 msgid "Next tab"
 msgstr "Onglet suivant"
 
-#: gtk/gtknotebook.c:4331 gtk/gtknotebook.c:6541
+#: gtk/gtknotebook.c:4424 gtk/gtknotebook.c:6634
 #, c-format
 msgid "Page %u"
 msgstr "Page %u"
@@ -3334,11 +3366,11 @@ msgstr "Authentification"
 msgid "_Remember password"
 msgstr "_Se souvenir du mot de passe"
 
-#: gtk/print/gtkprinteroptionwidget.c:702
+#: gtk/print/gtkprinteroptionwidget.c:703
 msgid "Select a filename"
 msgstr "Sélectionner un nom de fichier"
 
-#: gtk/print/gtkprinteroptionwidget.c:919
+#: gtk/print/gtkprinteroptionwidget.c:947
 msgid "Not available"
 msgstr "Pas disponible"
 
@@ -3346,91 +3378,91 @@ msgstr "Pas disponible"
 #. * jobs. %s gets replaced by the application name, %d gets replaced
 #. * by the job number.
 #.
-#: gtk/print/gtkprintoperation.c:252
+#: gtk/print/gtkprintoperation.c:255
 #, c-format
 msgid "%s job #%d"
 msgstr "%s, tâche n°%d"
 
-#: gtk/print/gtkprintoperation.c:1699
+#: gtk/print/gtkprintoperation.c:1702
 msgctxt "print operation status"
 msgid "Initial state"
 msgstr "État initial"
 
-#: gtk/print/gtkprintoperation.c:1700
+#: gtk/print/gtkprintoperation.c:1703
 msgctxt "print operation status"
 msgid "Preparing to print"
 msgstr "Préparation de l’impression"
 
-#: gtk/print/gtkprintoperation.c:1701
+#: gtk/print/gtkprintoperation.c:1704
 msgctxt "print operation status"
 msgid "Generating data"
 msgstr "Production des données"
 
-#: gtk/print/gtkprintoperation.c:1702
+#: gtk/print/gtkprintoperation.c:1705
 msgctxt "print operation status"
 msgid "Sending data"
 msgstr "Envoi des données"
 
-#: gtk/print/gtkprintoperation.c:1703
+#: gtk/print/gtkprintoperation.c:1706
 msgctxt "print operation status"
 msgid "Waiting"
 msgstr "En attente"
 
-#: gtk/print/gtkprintoperation.c:1704
+#: gtk/print/gtkprintoperation.c:1707
 msgctxt "print operation status"
 msgid "Blocking on issue"
 msgstr "Interruption à cause d’un problème"
 
-#: gtk/print/gtkprintoperation.c:1705
+#: gtk/print/gtkprintoperation.c:1708
 msgctxt "print operation status"
 msgid "Printing"
 msgstr "Impression"
 
-#: gtk/print/gtkprintoperation.c:1706
+#: gtk/print/gtkprintoperation.c:1709
 msgctxt "print operation status"
 msgid "Finished"
 msgstr "Terminé"
 
-#: gtk/print/gtkprintoperation.c:1707
+#: gtk/print/gtkprintoperation.c:1710
 msgctxt "print operation status"
 msgid "Finished with error"
 msgstr "Terminé avec une erreur"
 
-#: gtk/print/gtkprintoperation.c:2250
+#: gtk/print/gtkprintoperation.c:2254
 #, c-format
 msgid "Preparing %d"
 msgstr "Préparation de %d"
 
-#: gtk/print/gtkprintoperation.c:2252 gtk/print/gtkprintoperation.c:2871
+#: gtk/print/gtkprintoperation.c:2256 gtk/print/gtkprintoperation.c:2875
 #, c-format
 msgid "Preparing"
 msgstr "Préparation"
 
-#: gtk/print/gtkprintoperation.c:2255
+#: gtk/print/gtkprintoperation.c:2259
 #, c-format
 msgid "Printing %d"
 msgstr "Impression de %d"
 
-#: gtk/print/gtkprintoperation.c:2904
+#: gtk/print/gtkprintoperation.c:2908
 #, c-format
 msgid "Error creating print preview"
 msgstr "Erreur lors de la création de l’aperçu"
 
-#: gtk/print/gtkprintoperation.c:2907
+#: gtk/print/gtkprintoperation.c:2911
 #, c-format
 msgid "The most probable reason is that a temporary file could not be created."
 msgstr ""
 "La raison la plus probable est qu’un fichier temporaire n’a pas pu être créé."
 
 #. window
-#: gtk/print/gtkprintoperation-portal.c:264
-#: gtk/print/gtkprintoperation-portal.c:594
-#: gtk/print/gtkprintoperation-portal.c:663 gtk/print/gtkprintunixdialog.c:3008
+#: gtk/print/gtkprintoperation-portal.c:273
+#: gtk/print/gtkprintoperation-portal.c:603
+#: gtk/print/gtkprintoperation-portal.c:672 gtk/print/gtkprintunixdialog.c:3016
 msgid "Print"
 msgstr "Imprimer"
 
-#: gtk/print/gtkprintoperation-unix.c:481
-#: gtk/print/gtkprintoperation-win32.c:1505
+#: gtk/print/gtkprintoperation-unix.c:490
+#: gtk/print/gtkprintoperation-win32.c:1508
 msgid "Application"
 msgstr "Application"
 
@@ -3444,7 +3476,7 @@ msgstr "Absence de papier"
 
 #. Translators: this is a printer status.
 #: gtk/print/gtkprintoperation-win32.c:640
-#: modules/printbackends/gtkprintbackendcpdb.c:1528
+#: modules/printbackends/gtkprintbackendcpdb.c:1533
 #: modules/printbackends/gtkprintbackendcups.c:2639
 msgid "Paused"
 msgstr "En pause"
@@ -3457,38 +3489,38 @@ msgstr "Nécessite l’intervention de l’utilisateur"
 msgid "Custom size"
 msgstr "Taille personnalisée"
 
-#: gtk/print/gtkprintoperation-win32.c:1597
+#: gtk/print/gtkprintoperation-win32.c:1600
 msgid "No printer found"
 msgstr "Aucune imprimante trouvée"
 
-#: gtk/print/gtkprintoperation-win32.c:1624
+#: gtk/print/gtkprintoperation-win32.c:1627
 msgid "Invalid argument to CreateDC"
 msgstr "Paramètre non valide pour CreateDC"
 
-#: gtk/print/gtkprintoperation-win32.c:1660
-#: gtk/print/gtkprintoperation-win32.c:1906
+#: gtk/print/gtkprintoperation-win32.c:1663
+#: gtk/print/gtkprintoperation-win32.c:1909
 msgid "Error from StartDoc"
 msgstr "Erreur de StartDoc"
 
-#: gtk/print/gtkprintoperation-win32.c:1761
-#: gtk/print/gtkprintoperation-win32.c:1784
-#: gtk/print/gtkprintoperation-win32.c:1832
+#: gtk/print/gtkprintoperation-win32.c:1764
+#: gtk/print/gtkprintoperation-win32.c:1787
+#: gtk/print/gtkprintoperation-win32.c:1835
 msgid "Not enough free memory"
 msgstr "Mémoire insuffisante"
 
-#: gtk/print/gtkprintoperation-win32.c:1837
+#: gtk/print/gtkprintoperation-win32.c:1840
 msgid "Invalid argument to PrintDlgEx"
 msgstr "Paramètre non valide pour PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1842
+#: gtk/print/gtkprintoperation-win32.c:1845
 msgid "Invalid pointer to PrintDlgEx"
 msgstr "Pointeur non valide pour PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1847
+#: gtk/print/gtkprintoperation-win32.c:1850
 msgid "Invalid handle to PrintDlgEx"
 msgstr "Identificateur non valide pour PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1852
+#: gtk/print/gtkprintoperation-win32.c:1855
 msgid "Unspecified error"
 msgstr "Erreur non précisée"
 
@@ -3500,11 +3532,11 @@ msgstr "_Aperçu"
 msgid "_Print"
 msgstr "_Imprimer"
 
-#: gtk/print/gtkprintunixdialog.c:961
+#: gtk/print/gtkprintunixdialog.c:967
 msgid "Getting printer information failed"
 msgstr "Impossible d’obtenir des informations sur l’imprimante"
 
-#: gtk/print/gtkprintunixdialog.c:1885
+#: gtk/print/gtkprintunixdialog.c:1891
 msgid "Getting printer information…"
 msgstr "Récupération des informations sur l’imprimante…"
 
@@ -3515,92 +3547,92 @@ msgstr "Récupération des informations sur l’imprimante…"
 #. Translators: These strings name the possible arrangements of
 #. * multiple pages on a sheet when printing
 #.
-#: gtk/print/gtkprintunixdialog.c:2753
-#: modules/printbackends/gtkprintbackendcups.c:5672
+#: gtk/print/gtkprintunixdialog.c:2761
+#: modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, top to bottom"
 msgstr "De gauche à droite, du haut vers le bas"
 
-#: gtk/print/gtkprintunixdialog.c:2753
-#: modules/printbackends/gtkprintbackendcups.c:5672
+#: gtk/print/gtkprintunixdialog.c:2761
+#: modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, bottom to top"
 msgstr "De gauche à droite, du bas vers le haut"
 
-#: gtk/print/gtkprintunixdialog.c:2754
-#: modules/printbackends/gtkprintbackendcups.c:5673
+#: gtk/print/gtkprintunixdialog.c:2762
+#: modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, top to bottom"
 msgstr "De droite à gauche, du haut vers le bas"
 
-#: gtk/print/gtkprintunixdialog.c:2754
-#: modules/printbackends/gtkprintbackendcups.c:5673
+#: gtk/print/gtkprintunixdialog.c:2762
+#: modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, bottom to top"
 msgstr "De droite à gauche, du bas vers le haut"
 
-#: gtk/print/gtkprintunixdialog.c:2755
-#: modules/printbackends/gtkprintbackendcups.c:5674
+#: gtk/print/gtkprintunixdialog.c:2763
+#: modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, left to right"
 msgstr "Du haut vers le bas, de gauche à droite"
 
-#: gtk/print/gtkprintunixdialog.c:2755
-#: modules/printbackends/gtkprintbackendcups.c:5674
+#: gtk/print/gtkprintunixdialog.c:2763
+#: modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, right to left"
 msgstr "Du haut vers le bas, de droite à gauche"
 
-#: gtk/print/gtkprintunixdialog.c:2756
-#: modules/printbackends/gtkprintbackendcups.c:5675
+#: gtk/print/gtkprintunixdialog.c:2764
+#: modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, left to right"
 msgstr "Du bas vers le haut, de gauche à droite"
 
-#: gtk/print/gtkprintunixdialog.c:2756
-#: modules/printbackends/gtkprintbackendcups.c:5675
+#: gtk/print/gtkprintunixdialog.c:2764
+#: modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, right to left"
 msgstr "Du bas vers le haut, de droite à gauche"
 
-#: gtk/print/gtkprintunixdialog.c:2760 gtk/print/gtkprintunixdialog.c:2773
+#: gtk/print/gtkprintunixdialog.c:2768 gtk/print/gtkprintunixdialog.c:2781
 msgid "Page Ordering"
 msgstr "Ordre des pages"
 
-#: gtk/print/gtkprintunixdialog.c:2789
+#: gtk/print/gtkprintunixdialog.c:2797
 msgid "Left to right"
 msgstr "De gauche à droite"
 
-#: gtk/print/gtkprintunixdialog.c:2790
+#: gtk/print/gtkprintunixdialog.c:2798
 msgid "Right to left"
 msgstr "De droite à gauche"
 
-#: gtk/print/gtkprintunixdialog.c:2802
+#: gtk/print/gtkprintunixdialog.c:2810
 msgid "Top to bottom"
 msgstr "De haut en bas"
 
-#: gtk/print/gtkprintunixdialog.c:2803
+#: gtk/print/gtkprintunixdialog.c:2811
 msgid "Bottom to top"
 msgstr "De bas en haut"
 
-#: gtk/gtkprogressbar.c:609
+#: gtk/gtkprogressbar.c:627
 #, c-format
 msgctxt "progress bar label"
 msgid "%.0f %%"
 msgstr "%.0f %%"
 
-#: gtk/gtkrecentmanager.c:1023 gtk/gtkrecentmanager.c:1036
-#: gtk/gtkrecentmanager.c:1174 gtk/gtkrecentmanager.c:1184
-#: gtk/gtkrecentmanager.c:1234 gtk/gtkrecentmanager.c:1243
+#: gtk/gtkrecentmanager.c:1030 gtk/gtkrecentmanager.c:1043
+#: gtk/gtkrecentmanager.c:1181 gtk/gtkrecentmanager.c:1191
+#: gtk/gtkrecentmanager.c:1241 gtk/gtkrecentmanager.c:1250
 #, c-format
 msgid "Unable to find an item with URI “%s”"
 msgstr "Impossible de trouver un élément dont l’URI est « %s »"
 
-#: gtk/gtkrecentmanager.c:1258
+#: gtk/gtkrecentmanager.c:1265
 #, c-format
 msgid "Unable to move the item with URI “%s” to “%s”"
 msgstr "Impossible de déplacer l’élément dont l’URI est « %s » vers « %s »"
 
-#: gtk/gtkrecentmanager.c:2323
+#: gtk/gtkrecentmanager.c:2330
 #, c-format
 msgid "No registered application with name “%s” for item with URI “%s” found"
 msgstr ""
 "Impossible de trouver une application enregistrée sous le nom « %s » pour "
 "l’élément dont l’URI est « %s »"
 
-#: gtk/gtksearchentry.c:814
+#: gtk/gtksearchentry.c:836
 msgid "Clear Entry"
 msgstr "Efface la saisie"
 
@@ -3624,7 +3656,7 @@ msgctxt "keyboard side marker"
 msgid "R"
 msgstr "D"
 
-#: gtk/gtkshortcutssection.c:414
+#: gtk/gtkshortcutssection.c:435
 msgid "_Show All"
 msgstr "_Tout afficher"
 
@@ -3661,54 +3693,54 @@ msgid "Swipe right"
 msgstr "Glissement vers la droite"
 
 #. Translators: This is placeholder text for the search entry in the shortcuts window
-#: gtk/gtkshortcutswindow.c:879 gtk/gtkshortcutswindow.c:946
-#: gtk/gtkshortcutswindow.c:952
+#: gtk/gtkshortcutswindow.c:894 gtk/gtkshortcutswindow.c:961
+#: gtk/gtkshortcutswindow.c:967
 msgid "Search Shortcuts"
 msgstr "Raccourcis de recherche"
 
 #. Translators: This is the window title for the shortcuts window in normal mode
-#: gtk/gtkshortcutswindow.c:911 gtk/inspector/window.ui:498
+#: gtk/gtkshortcutswindow.c:926 gtk/inspector/window.ui:498
 msgid "Shortcuts"
 msgstr "Raccourcis"
 
 #. Translators: This is the window title for the shortcuts window in search mode
-#: gtk/gtkshortcutswindow.c:916
+#: gtk/gtkshortcutswindow.c:931
 msgid "Search Results"
 msgstr "Résultats de recherche"
 
-#: gtk/gtkshortcutswindow.c:1014 gtk/ui/gtkemojichooser.ui:349
-#: gtk/ui/gtkfilechooserwidget.ui:239
+#: gtk/gtkshortcutswindow.c:1029 gtk/ui/gtkemojichooser.ui:352
+#: gtk/ui/gtkfilechooserwidget.ui:250
 msgid "No Results Found"
 msgstr "Aucun résultat trouvé"
 
-#: gtk/gtkshortcutswindow.c:1025 gtk/ui/gtkemojichooser.ui:362
-#: gtk/ui/gtkfilechooserwidget.ui:252 gtk/ui/gtkplacesview.ui:218
+#: gtk/gtkshortcutswindow.c:1040 gtk/ui/gtkemojichooser.ui:365
+#: gtk/ui/gtkfilechooserwidget.ui:263 gtk/ui/gtkplacesview.ui:218
 msgid "Try a different search"
 msgstr "Essayez une autre recherche"
 
-#: gtk/gtkstacksidebar.c:154
+#: gtk/gtkstacksidebar.c:155
 msgctxt "accessibility"
 msgid "Sidebar"
 msgstr "Panneau latéral"
 
-#: gtk/gtktext.c:6208 gtk/gtktextview.c:9125
+#: gtk/gtktext.c:6349 gtk/gtktextview.c:9263
 msgid "Insert _Emoji"
 msgstr "Insérer un _émoji"
 
-#: gtk/gtktextview.c:9107
+#: gtk/gtktextview.c:9245
 msgid "_Undo"
 msgstr "Ann_uler"
 
-#: gtk/gtktextview.c:9111
+#: gtk/gtktextview.c:9249
 msgid "_Redo"
 msgstr "_Rétablir"
 
-#: gtk/gtkwindow.c:6245
+#: gtk/gtkwindow.c:6200
 #, c-format
 msgid "Do you want to use GTK Inspector?"
 msgstr "Voulez-vous utiliser l’Inspecteur GTK ?"
 
-#: gtk/gtkwindow.c:6247
+#: gtk/gtkwindow.c:6202
 #, c-format
 msgid ""
 "GTK Inspector is an interactive debugger that lets you explore and modify "
@@ -3719,7 +3751,7 @@ msgstr ""
 "modifier les éléments internes de toute application GTK. Son utilisation "
 "peut causer une interruption ou un plantage de l’application."
 
-#: gtk/gtkwindow.c:6252
+#: gtk/gtkwindow.c:6207
 msgid "Don’t show this message again"
 msgstr "Ne plus afficher ce message"
 
@@ -3803,17 +3835,17 @@ msgstr "Afficher"
 msgid "Hover to load"
 msgstr "Charger au survol"
 
-#: gtk/inspector/clipboard.c:278
+#: gtk/inspector/clipboard.c:286
 msgctxt "clipboard"
 msgid "empty"
 msgstr "vide"
 
-#: gtk/inspector/clipboard.c:283 gtk/inspector/clipboard.c:325
+#: gtk/inspector/clipboard.c:291 gtk/inspector/clipboard.c:344
 msgctxt "clipboard"
 msgid "local"
 msgstr "local"
 
-#: gtk/inspector/clipboard.c:285 gtk/inspector/clipboard.c:327
+#: gtk/inspector/clipboard.c:293 gtk/inspector/clipboard.c:346
 msgctxt "clipboard"
 msgid "remote"
 msgstr "distant"
@@ -3855,11 +3887,11 @@ msgctxt "propagation limit"
 msgid "Native"
 msgstr "Natif"
 
-#: gtk/inspector/css-editor.c:128
+#: gtk/inspector/css-editor.c:135
 msgid "You can type here any CSS rule recognized by GTK."
 msgstr "Vous pouvez saisir ici toute règle CSS reconnue par GTK."
 
-#: gtk/inspector/css-editor.c:129
+#: gtk/inspector/css-editor.c:136
 msgid ""
 "You can temporarily disable this custom CSS by clicking on the “Pause” "
 "button above."
@@ -3867,25 +3899,29 @@ msgstr ""
 "Vous pouvez désactiver temporairement ce CSS personnalisé en cliquant sur le "
 "bouton « Pause » ci-dessus."
 
-#: gtk/inspector/css-editor.c:130
+#: gtk/inspector/css-editor.c:137
 msgid "Changes are applied instantly and globally, for the whole application."
 msgstr ""
 "Les changements sont appliqués instantanément et globalement, pour toute "
 "l’application."
 
-#: gtk/inspector/css-editor.c:206
+#: gtk/inspector/css-editor.c:236
 #, c-format
 msgid "Saving CSS failed"
 msgstr "L’enregistrement du CSS a échoué"
 
-#: gtk/inspector/css-editor.ui:30
+#: gtk/inspector/css-editor.ui:37
 msgid "Disable this custom CSS"
 msgstr "Désactive ce CSS personnalisé"
 
-#: gtk/inspector/css-editor.ui:37
+#: gtk/inspector/css-editor.ui:44
 msgid "Save the current CSS"
 msgstr "Enregistre le CSS actuel"
 
+#: gtk/inspector/css-editor.ui:51
+msgid "Show deprecations"
+msgstr "Affiche les dépréciations"
+
 #: gtk/inspector/css-node-tree.ui:28 tools/gtk-builder-tool-preview.c:178
 #: tools/gtk-builder-tool-screenshot.c:359
 msgid "ID"
@@ -3899,37 +3935,37 @@ msgstr "Classes de style"
 msgid "CSS Property"
 msgstr "Propriété CSS"
 
-#: gtk/inspector/general.c:370
+#: gtk/inspector/general.c:372
 msgctxt "GL version"
 msgid "None"
 msgstr "Aucune"
 
-#: gtk/inspector/general.c:461
+#: gtk/inspector/general.c:464
 msgctxt "GL version"
 msgid "Unknown"
 msgstr "Inconnu"
 
-#: gtk/inspector/general.c:523
+#: gtk/inspector/general.c:526
 msgctxt "Vulkan device"
 msgid "Disabled"
 msgstr "Désactivé"
 
-#: gtk/inspector/general.c:524 gtk/inspector/general.c:525
+#: gtk/inspector/general.c:527 gtk/inspector/general.c:528
 msgctxt "Vulkan version"
 msgid "Disabled"
 msgstr "Désactivé"
 
-#: gtk/inspector/general.c:576
+#: gtk/inspector/general.c:579
 msgctxt "Vulkan device"
 msgid "None"
 msgstr "Aucun"
 
-#: gtk/inspector/general.c:577 gtk/inspector/general.c:578
+#: gtk/inspector/general.c:580 gtk/inspector/general.c:581
 msgctxt "Vulkan version"
 msgid "None"
 msgstr "Aucune"
 
-#: gtk/inspector/general.c:923
+#: gtk/inspector/general.c:934
 msgid "IM Context is hardcoded by GTK_IM_MODULE"
 msgstr "Le contexte de méthode de saisie est fixé par GTK_IM_MODULE"
 
@@ -4115,23 +4151,27 @@ msgstr "Nombre d’images"
 msgid "Frame Rate"
 msgstr "Fréquence d’image"
 
-#: gtk/inspector/misc-info.ui:527
+#: gtk/inspector/misc-info.ui:527 gtk/inspector/visual.ui:315
 msgid "Scale"
 msgstr "Échelle"
 
 #: gtk/inspector/misc-info.ui:552
+msgid "Color state"
+msgstr "État colorimétrique"
+
+#: gtk/inspector/misc-info.ui:577
 msgid "Mapped"
 msgstr "Mappé"
 
-#: gtk/inspector/misc-info.ui:578
+#: gtk/inspector/misc-info.ui:603
 msgid "Realized"
 msgstr "Réalisé"
 
-#: gtk/inspector/misc-info.ui:604
+#: gtk/inspector/misc-info.ui:629
 msgid "Is Toplevel"
 msgstr "De premier niveau"
 
-#: gtk/inspector/misc-info.ui:630
+#: gtk/inspector/misc-info.ui:655
 msgid "Child Visible"
 msgstr "Enfant visible"
 
@@ -4239,7 +4279,7 @@ msgstr "Source :"
 msgid "Defined At"
 msgstr "Défini à"
 
-#: gtk/inspector/recorder.c:1941
+#: gtk/inspector/recorder.c:2021
 #, c-format
 msgid "Saving RenderNode failed"
 msgstr "L’enregistrement de RenderNode a échoué"
@@ -4292,7 +4332,7 @@ msgstr "Nom :"
 msgid "Type:"
 msgstr "Type :"
 
-#: gtk/inspector/resource-list.ui:164
+#: gtk/inspector/resource-list.ui:164 tools/gtk-image-tool-info.c:54
 msgid "Size:"
 msgstr "Taille :"
 
@@ -4377,7 +4417,7 @@ msgstr "Hiérarchie"
 msgid "Implements"
 msgstr "Implémente"
 
-#: gtk/inspector/visual.c:672 gtk/inspector/visual.c:691
+#: gtk/inspector/visual.c:690 gtk/inspector/visual.c:708
 msgid "Theme is hardcoded by GTK_THEME"
 msgstr "Le thème est figé par GTK_THEME"
 
@@ -4401,39 +4441,49 @@ msgstr "Taille de curseur"
 msgid "Icon Theme"
 msgstr "Thème d’icônes"
 
-#: gtk/inspector/visual.ui:199
-msgid "Font Scale"
-msgstr "Mise à l’échelle des polices"
-
-#: gtk/inspector/visual.ui:244
+#: gtk/inspector/visual.ui:169
 msgid "Text Direction"
 msgstr "Direction du texte"
 
-#: gtk/inspector/visual.ui:259
+#: gtk/inspector/visual.ui:184
 msgid "Left-to-Right"
 msgstr "De gauche à droite"
 
-#: gtk/inspector/visual.ui:260
+#: gtk/inspector/visual.ui:185
 msgid "Right-to-Left"
 msgstr "De droite à gauche"
 
-#: gtk/inspector/visual.ui:277
+#: gtk/inspector/visual.ui:202
 msgid "Animations"
 msgstr "Animations"
 
-#: gtk/inspector/visual.ui:302
+#: gtk/inspector/visual.ui:227
 msgid "Slowdown"
 msgstr "Ralenti"
 
-#: gtk/inspector/visual.ui:356
+#: gtk/inspector/visual.ui:362
+msgid "Rendering"
+msgstr "Rendu"
+
+#: gtk/inspector/visual.ui:377
+msgctxt "Font rendering"
+msgid "Automatic"
+msgstr "Automatique"
+
+#: gtk/inspector/visual.ui:378
+msgctxt "Font rendering"
+msgid "Manual"
+msgstr "Manuel"
+
+#: gtk/inspector/visual.ui:405
 msgid "Show Framerate"
 msgstr "Afficher la fréquence d’image"
 
-#: gtk/inspector/visual.ui:381
+#: gtk/inspector/visual.ui:430
 msgid "Show Graphic Updates"
 msgstr "Afficher les mises à jour graphiques"
 
-#: gtk/inspector/visual.ui:401
+#: gtk/inspector/visual.ui:450
 msgid ""
 "Tints all the places where the current renderer uses Cairo instead of the "
 "GPU."
@@ -4441,47 +4491,47 @@ msgstr ""
 "Colore tous les endroits où le moteur de rendu actuel utilise Cairo au lieu "
 "du GPU."
 
-#: gtk/inspector/visual.ui:407
+#: gtk/inspector/visual.ui:456
 msgid "Show Cairo Rendering"
 msgstr "Afficher le rendu de Cairo"
 
-#: gtk/inspector/visual.ui:432
+#: gtk/inspector/visual.ui:481
 msgid "Show Baselines"
 msgstr "Afficher les lignes de base"
 
-#: gtk/inspector/visual.ui:460
+#: gtk/inspector/visual.ui:509
 msgid "Show Layout Borders"
 msgstr "Afficher les bords de l’agencement"
 
-#: gtk/inspector/visual.ui:517
+#: gtk/inspector/visual.ui:566
 msgid "CSS Padding"
 msgstr "Remplissage CSS"
 
-#: gtk/inspector/visual.ui:527
+#: gtk/inspector/visual.ui:576
 msgid "CSS Border"
 msgstr "Bordure CSS"
 
-#: gtk/inspector/visual.ui:537
+#: gtk/inspector/visual.ui:586
 msgid "CSS Margin"
 msgstr "Marge CSS"
 
-#: gtk/inspector/visual.ui:547
+#: gtk/inspector/visual.ui:596
 msgid "Widget Margin"
 msgstr "Marge du composant graphique"
 
-#: gtk/inspector/visual.ui:582
+#: gtk/inspector/visual.ui:631
 msgid "Show Focus"
 msgstr "Montrer le focus"
 
-#: gtk/inspector/visual.ui:607
+#: gtk/inspector/visual.ui:656
 msgid "Show Accessibility warnings"
 msgstr "Afficher les avertissements d’accessibilité"
 
-#: gtk/inspector/visual.ui:632
+#: gtk/inspector/visual.ui:681
 msgid "Show Graphics Offload"
 msgstr "Afficher le déchargement graphique"
 
-#: gtk/inspector/visual.ui:664
+#: gtk/inspector/visual.ui:713
 msgid "Inspect Inspector"
 msgstr "Inspecter l’inspecteur"
 
@@ -6128,7 +6178,7 @@ msgstr "À propos"
 msgid "Credits"
 msgstr "Crédits"
 
-#: gtk/ui/gtkaboutdialog.ui:219
+#: gtk/ui/gtkaboutdialog.ui:221
 msgid "System"
 msgstr "Système"
 
@@ -6236,52 +6286,52 @@ msgstr "(Aucun)"
 msgid "Search…"
 msgstr "Recherche…"
 
-#: gtk/ui/gtkemojichooser.ui:69 gtk/ui/gtkemojichooser.ui:239
+#: gtk/ui/gtkemojichooser.ui:70 gtk/ui/gtkemojichooser.ui:240
 msgctxt "emoji category"
 msgid "Smileys & People"
 msgstr "Émoticônes et personnes"
 
-#: gtk/ui/gtkemojichooser.ui:94 gtk/ui/gtkemojichooser.ui:248
+#: gtk/ui/gtkemojichooser.ui:95 gtk/ui/gtkemojichooser.ui:249
 msgctxt "emoji category"
 msgid "Body & Clothing"
 msgstr "Corps et vêtements"
 
-#: gtk/ui/gtkemojichooser.ui:119 gtk/ui/gtkemojichooser.ui:257
+#: gtk/ui/gtkemojichooser.ui:120 gtk/ui/gtkemojichooser.ui:258
 msgctxt "emoji category"
 msgid "Animals & Nature"
 msgstr "Animaux et nature"
 
-#: gtk/ui/gtkemojichooser.ui:133 gtk/ui/gtkemojichooser.ui:266
+#: gtk/ui/gtkemojichooser.ui:134 gtk/ui/gtkemojichooser.ui:267
 msgctxt "emoji category"
 msgid "Food & Drink"
 msgstr "Nourriture et boissons"
 
-#: gtk/ui/gtkemojichooser.ui:147 gtk/ui/gtkemojichooser.ui:275
+#: gtk/ui/gtkemojichooser.ui:148 gtk/ui/gtkemojichooser.ui:276
 msgctxt "emoji category"
 msgid "Travel & Places"
 msgstr "Voyages et lieux"
 
-#: gtk/ui/gtkemojichooser.ui:161 gtk/ui/gtkemojichooser.ui:284
+#: gtk/ui/gtkemojichooser.ui:162 gtk/ui/gtkemojichooser.ui:285
 msgctxt "emoji category"
 msgid "Activities"
 msgstr "Activités"
 
-#: gtk/ui/gtkemojichooser.ui:175 gtk/ui/gtkemojichooser.ui:293
+#: gtk/ui/gtkemojichooser.ui:176 gtk/ui/gtkemojichooser.ui:294
 msgctxt "emoji category"
 msgid "Objects"
 msgstr "Objets"
 
-#: gtk/ui/gtkemojichooser.ui:189 gtk/ui/gtkemojichooser.ui:302
+#: gtk/ui/gtkemojichooser.ui:190 gtk/ui/gtkemojichooser.ui:303
 msgctxt "emoji category"
 msgid "Symbols"
 msgstr "Symboles"
 
-#: gtk/ui/gtkemojichooser.ui:203 gtk/ui/gtkemojichooser.ui:311
+#: gtk/ui/gtkemojichooser.ui:204 gtk/ui/gtkemojichooser.ui:312
 msgctxt "emoji category"
 msgid "Flags"
 msgstr "Drapeaux"
 
-#: gtk/ui/gtkemojichooser.ui:230
+#: gtk/ui/gtkemojichooser.ui:231
 msgctxt "emoji category"
 msgid "Recent"
 msgstr "Récents"
@@ -6290,15 +6340,15 @@ msgstr "Récents"
 msgid "Create Folder"
 msgstr "Créer un dossier"
 
-#: gtk/ui/gtkfilechooserwidget.ui:191
+#: gtk/ui/gtkfilechooserwidget.ui:202
 msgid "Remote location — only searching the current folder"
 msgstr "Emplacement distant — recherche du dossier en cours uniquement"
 
-#: gtk/ui/gtkfilechooserwidget.ui:323
+#: gtk/ui/gtkfilechooserwidget.ui:334
 msgid "Folder Name"
 msgstr "Nom du dossier"
 
-#: gtk/ui/gtkfilechooserwidget.ui:349
+#: gtk/ui/gtkfilechooserwidget.ui:360
 msgid "_Create"
 msgstr "_Créer"
 
@@ -6306,32 +6356,32 @@ msgstr "_Créer"
 msgid "Select Font"
 msgstr "Choisir une police"
 
-#: gtk/ui/gtkfontchooserwidget.ui:64
+#: gtk/ui/gtkfontchooserwidget.ui:66
 msgid "Search font name"
 msgstr "Rechercher un nom de police"
 
-#: gtk/ui/gtkfontchooserwidget.ui:77
+#: gtk/ui/gtkfontchooserwidget.ui:79
 msgid "Filters"
 msgstr "Filtres"
 
-#: gtk/ui/gtkfontchooserwidget.ui:89
+#: gtk/ui/gtkfontchooserwidget.ui:91
 msgid "Filter by"
 msgstr "Filtrer par"
 
-#: gtk/ui/gtkfontchooserwidget.ui:99
+#: gtk/ui/gtkfontchooserwidget.ui:101
 msgid "Monospace"
 msgstr "Chasse fixe"
 
-#: gtk/ui/gtkfontchooserwidget.ui:105
+#: gtk/ui/gtkfontchooserwidget.ui:106
 msgid "Language"
 msgstr "Langue"
 
-#: gtk/ui/gtkfontchooserwidget.ui:198 gtk/ui/gtkfontchooserwidget.ui:200
-#: gtk/ui/gtkfontchooserwidget.ui:353 gtk/ui/gtkfontchooserwidget.ui:357
+#: gtk/ui/gtkfontchooserwidget.ui:197 gtk/ui/gtkfontchooserwidget.ui:199
+#: gtk/ui/gtkfontchooserwidget.ui:352 gtk/ui/gtkfontchooserwidget.ui:356
 msgid "Preview Font"
 msgstr "Prévisualiser la police"
 
-#: gtk/ui/gtkfontchooserwidget.ui:296
+#: gtk/ui/gtkfontchooserwidget.ui:295
 msgid "No Fonts Found"
 msgstr "Aucune police trouvée"
 
@@ -6609,34 +6659,35 @@ msgstr "Avancé"
 msgid "Some of the settings in the dialog conflict"
 msgstr "Certains paramètres dans la boîte de dialogue sont en conflit"
 
-#. Translators: These strings name the possible values of the
-#. * job priority option in the print dialog
-#.
-#: modules/printbackends/gtkprintbackendcpdb.c:541
-#: modules/printbackends/gtkprintbackendcups.c:5667
+#: modules/printbackends/gtkprintbackendcpdb.c:542
+#: modules/printbackends/gtkprintbackendcups.c:5670
+msgctxt "Print job priority"
 msgid "Urgent"
-msgstr "Urgent"
+msgstr "Urgente"
 
-#: modules/printbackends/gtkprintbackendcpdb.c:541
-#: modules/printbackends/gtkprintbackendcups.c:5667
+#: modules/printbackends/gtkprintbackendcpdb.c:543
+#: modules/printbackends/gtkprintbackendcups.c:5671
+msgctxt "Print job priority"
 msgid "High"
 msgstr "Haute"
 
-#: modules/printbackends/gtkprintbackendcpdb.c:541
-#: modules/printbackends/gtkprintbackendcups.c:5667
+#: modules/printbackends/gtkprintbackendcpdb.c:544
+#: modules/printbackends/gtkprintbackendcups.c:5672
+msgctxt "Print job priority"
 msgid "Medium"
 msgstr "Moyenne"
 
-#: modules/printbackends/gtkprintbackendcpdb.c:541
-#: modules/printbackends/gtkprintbackendcups.c:5667
+#: modules/printbackends/gtkprintbackendcpdb.c:545
+#: modules/printbackends/gtkprintbackendcups.c:5673
+msgctxt "Print job priority"
 msgid "Low"
 msgstr "Basse"
 
 #. Translators, this is the label used for the option in the print
 #. * dialog that controls the front cover page.
 #.
-#: modules/printbackends/gtkprintbackendcpdb.c:562
-#: modules/printbackends/gtkprintbackendcups.c:5809
+#: modules/printbackends/gtkprintbackendcpdb.c:567
+#: modules/printbackends/gtkprintbackendcups.c:5816
 msgctxt "printer option"
 msgid "Before"
 msgstr "Avant"
@@ -6644,33 +6695,33 @@ msgstr "Avant"
 #. Translators, this is the label used for the option in the print
 #. * dialog that controls the back cover page.
 #.
-#: modules/printbackends/gtkprintbackendcpdb.c:569
-#: modules/printbackends/gtkprintbackendcups.c:5824
+#: modules/printbackends/gtkprintbackendcpdb.c:574
+#: modules/printbackends/gtkprintbackendcups.c:5831
 msgctxt "printer option"
 msgid "After"
 msgstr "Après"
 
-#: modules/printbackends/gtkprintbackendcpdb.c:592
+#: modules/printbackends/gtkprintbackendcpdb.c:597
 msgid "Print at"
 msgstr "Imprimer à"
 
-#: modules/printbackends/gtkprintbackendcpdb.c:602
+#: modules/printbackends/gtkprintbackendcpdb.c:607
 msgid "Print at time"
 msgstr "Imprimer à l’heure"
 
-#: modules/printbackends/gtkprintbackendcpdb.c:665
+#: modules/printbackends/gtkprintbackendcpdb.c:670
 msgctxt "print option"
 msgid "Borderless"
 msgstr "Sans bordure"
 
 #. Translators: this is a printer status.
-#: modules/printbackends/gtkprintbackendcpdb.c:1525
+#: modules/printbackends/gtkprintbackendcpdb.c:1530
 #: modules/printbackends/gtkprintbackendcups.c:2636
 msgid "Paused; Rejecting Jobs"
 msgstr "En pause ; les tâches sont rejetées"
 
 #. Translators: this is a printer status.
-#: modules/printbackends/gtkprintbackendcpdb.c:1531
+#: modules/printbackends/gtkprintbackendcpdb.c:1536
 #: modules/printbackends/gtkprintbackendcups.c:2642
 msgid "Rejecting Jobs"
 msgstr "Tâches non acceptées"
@@ -6830,266 +6881,266 @@ msgstr "Il y a un problème avec l’imprimante « %s »."
 msgid "; "
 msgstr " ; "
 
-#: modules/printbackends/gtkprintbackendcups.c:4609
-#: modules/printbackends/gtkprintbackendcups.c:4676
+#: modules/printbackends/gtkprintbackendcups.c:4611
+#: modules/printbackends/gtkprintbackendcups.c:4678
 msgctxt "printing option"
 msgid "Two Sided"
 msgstr "Recto verso"
 
-#: modules/printbackends/gtkprintbackendcups.c:4610
+#: modules/printbackends/gtkprintbackendcups.c:4612
 msgctxt "printing option"
 msgid "Paper Type"
 msgstr "Type de papier"
 
-#: modules/printbackends/gtkprintbackendcups.c:4611
+#: modules/printbackends/gtkprintbackendcups.c:4613
 msgctxt "printing option"
 msgid "Paper Source"
 msgstr "Source du papier"
 
-#: modules/printbackends/gtkprintbackendcups.c:4612
-#: modules/printbackends/gtkprintbackendcups.c:4677
+#: modules/printbackends/gtkprintbackendcups.c:4614
+#: modules/printbackends/gtkprintbackendcups.c:4679
 msgctxt "printing option"
 msgid "Output Tray"
 msgstr "Bac de sortie"
 
-#: modules/printbackends/gtkprintbackendcups.c:4613
+#: modules/printbackends/gtkprintbackendcups.c:4615
 msgctxt "printing option"
 msgid "Resolution"
 msgstr "Résolution"
 
-#: modules/printbackends/gtkprintbackendcups.c:4614
+#: modules/printbackends/gtkprintbackendcups.c:4616
 msgctxt "printing option"
 msgid "GhostScript pre-filtering"
 msgstr "Pré-filtrage GhostScript"
 
-#: modules/printbackends/gtkprintbackendcups.c:4623
+#: modules/printbackends/gtkprintbackendcups.c:4625
 msgctxt "printing option value"
 msgid "One Sided"
 msgstr "Recto"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4625
+#: modules/printbackends/gtkprintbackendcups.c:4627
 msgctxt "printing option value"
 msgid "Long Edge (Standard)"
 msgstr "Bord long (standard)"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4627
+#: modules/printbackends/gtkprintbackendcups.c:4629
 msgctxt "printing option value"
 msgid "Short Edge (Flip)"
 msgstr "Bord court (retourné)"
 
 #. Translators: this is an option of "Paper Source"
-#: modules/printbackends/gtkprintbackendcups.c:4629
 #: modules/printbackends/gtkprintbackendcups.c:4631
-#: modules/printbackends/gtkprintbackendcups.c:4639
+#: modules/printbackends/gtkprintbackendcups.c:4633
+#: modules/printbackends/gtkprintbackendcups.c:4641
 msgctxt "printing option value"
 msgid "Auto Select"
 msgstr "Sélection automatique"
 
 #. Translators: this is an option of "Paper Source"
 #. Translators: this is an option of "Resolution"
-#: modules/printbackends/gtkprintbackendcups.c:4633
 #: modules/printbackends/gtkprintbackendcups.c:4635
 #: modules/printbackends/gtkprintbackendcups.c:4637
-#: modules/printbackends/gtkprintbackendcups.c:4641
+#: modules/printbackends/gtkprintbackendcups.c:4639
+#: modules/printbackends/gtkprintbackendcups.c:4643
 msgctxt "printing option value"
 msgid "Printer Default"
 msgstr "Selon l’imprimante"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4643
+#: modules/printbackends/gtkprintbackendcups.c:4645
 msgctxt "printing option value"
 msgid "Embed GhostScript fonts only"
 msgstr "Inclure uniquement les polices GhostScript"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4645
+#: modules/printbackends/gtkprintbackendcups.c:4647
 msgctxt "printing option value"
 msgid "Convert to PS level 1"
 msgstr "Convertir en PS niveau 1"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4647
+#: modules/printbackends/gtkprintbackendcups.c:4649
 msgctxt "printing option value"
 msgid "Convert to PS level 2"
 msgstr "Convertir en PS niveau 2"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4649
+#: modules/printbackends/gtkprintbackendcups.c:4651
 msgctxt "printing option value"
 msgid "No pre-filtering"
 msgstr "Pas de pré-filtrage"
 
 #. Translators: "Miscellaneous" is the label for a button, that opens
 #. up an extra panel of settings in a print dialog.
-#: modules/printbackends/gtkprintbackendcups.c:4658
+#: modules/printbackends/gtkprintbackendcups.c:4660
 msgctxt "printing option group"
 msgid "Miscellaneous"
 msgstr "Divers"
 
-#: modules/printbackends/gtkprintbackendcups.c:4685
+#: modules/printbackends/gtkprintbackendcups.c:4687
 msgctxt "sides"
 msgid "One Sided"
 msgstr "Recto"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4687
+#: modules/printbackends/gtkprintbackendcups.c:4689
 msgctxt "sides"
 msgid "Long Edge (Standard)"
 msgstr "Bord long (standard)"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4689
+#: modules/printbackends/gtkprintbackendcups.c:4691
 msgctxt "sides"
 msgid "Short Edge (Flip)"
 msgstr "Bord court (retourné)"
 
 #. Translators: Top output bin
-#: modules/printbackends/gtkprintbackendcups.c:4692
+#: modules/printbackends/gtkprintbackendcups.c:4694
 msgctxt "output-bin"
 msgid "Top Bin"
 msgstr "Bac supérieur"
 
 #. Translators: Middle output bin
-#: modules/printbackends/gtkprintbackendcups.c:4694
+#: modules/printbackends/gtkprintbackendcups.c:4696
 msgctxt "output-bin"
 msgid "Middle Bin"
 msgstr "Bac intermédiaire"
 
 #. Translators: Bottom output bin
-#: modules/printbackends/gtkprintbackendcups.c:4696
+#: modules/printbackends/gtkprintbackendcups.c:4698
 msgctxt "output-bin"
 msgid "Bottom Bin"
 msgstr "Bac inférieur"
 
 #. Translators: Side output bin
-#: modules/printbackends/gtkprintbackendcups.c:4698
+#: modules/printbackends/gtkprintbackendcups.c:4700
 msgctxt "output-bin"
 msgid "Side Bin"
 msgstr "Bac latéral"
 
 #. Translators: Left output bin
-#: modules/printbackends/gtkprintbackendcups.c:4700
+#: modules/printbackends/gtkprintbackendcups.c:4702
 msgctxt "output-bin"
 msgid "Left Bin"
 msgstr "Bac de gauche"
 
 #. Translators: Right output bin
-#: modules/printbackends/gtkprintbackendcups.c:4702
+#: modules/printbackends/gtkprintbackendcups.c:4704
 msgctxt "output-bin"
 msgid "Right Bin"
 msgstr "Bac de droite"
 
 #. Translators: Center output bin
-#: modules/printbackends/gtkprintbackendcups.c:4704
+#: modules/printbackends/gtkprintbackendcups.c:4706
 msgctxt "output-bin"
 msgid "Center Bin"
 msgstr "Bac central"
 
 #. Translators: Rear output bin
-#: modules/printbackends/gtkprintbackendcups.c:4706
+#: modules/printbackends/gtkprintbackendcups.c:4708
 msgctxt "output-bin"
 msgid "Rear Bin"
 msgstr "Bac arrière"
 
 #. Translators: Output bin where one sided output is oriented in the face-up position
-#: modules/printbackends/gtkprintbackendcups.c:4708
+#: modules/printbackends/gtkprintbackendcups.c:4710
 msgctxt "output-bin"
 msgid "Face Up Bin"
 msgstr "Bac à face vers le haut"
 
 #. Translators: Output bin where one sided output is oriented in the face-down position
-#: modules/printbackends/gtkprintbackendcups.c:4710
+#: modules/printbackends/gtkprintbackendcups.c:4712
 msgctxt "output-bin"
 msgid "Face Down Bin"
 msgstr "Bac à face vers le bas"
 
 #. Translators: Large capacity output bin
-#: modules/printbackends/gtkprintbackendcups.c:4712
+#: modules/printbackends/gtkprintbackendcups.c:4714
 msgctxt "output-bin"
 msgid "Large Capacity Bin"
 msgstr "Bac de grande capacité"
 
 #. Translators: Output stacker number %d
-#: modules/printbackends/gtkprintbackendcups.c:4734
+#: modules/printbackends/gtkprintbackendcups.c:4736
 #, c-format
 msgctxt "output-bin"
 msgid "Stacker %d"
 msgstr "Empileur %d"
 
 #. Translators: Output mailbox number %d
-#: modules/printbackends/gtkprintbackendcups.c:4738
+#: modules/printbackends/gtkprintbackendcups.c:4740
 #, c-format
 msgctxt "output-bin"
 msgid "Mailbox %d"
 msgstr "Boîte de messagerie %d"
 
 #. Translators: Private mailbox
-#: modules/printbackends/gtkprintbackendcups.c:4742
+#: modules/printbackends/gtkprintbackendcups.c:4744
 msgctxt "output-bin"
 msgid "My Mailbox"
 msgstr "Ma boîte de messagerie"
 
 #. Translators: Output tray number %d
-#: modules/printbackends/gtkprintbackendcups.c:4746
+#: modules/printbackends/gtkprintbackendcups.c:4748
 #, c-format
 msgctxt "output-bin"
 msgid "Tray %d"
 msgstr "Plateau %d"
 
-#: modules/printbackends/gtkprintbackendcups.c:5223
+#: modules/printbackends/gtkprintbackendcups.c:5225
 msgid "Printer Default"
 msgstr "Selon l’imprimante"
 
 #. Translators, this string is used to label the job priority option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5697
+#: modules/printbackends/gtkprintbackendcups.c:5704
 msgid "Job Priority"
 msgstr "Priorité de la tâche"
 
 #. Translators, this string is used to label the billing info entry
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5708
+#: modules/printbackends/gtkprintbackendcups.c:5715
 msgid "Billing Info"
 msgstr "Informations de facturation"
 
 #. Translators, these strings are names for various 'standard' cover
 #. * pages that the printing system may support.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5732
+#: modules/printbackends/gtkprintbackendcups.c:5739
 msgctxt "cover page"
 msgid "None"
 msgstr "Aucune"
 
-#: modules/printbackends/gtkprintbackendcups.c:5733
+#: modules/printbackends/gtkprintbackendcups.c:5740
 msgctxt "cover page"
 msgid "Classified"
 msgstr "Classifié"
 
-#: modules/printbackends/gtkprintbackendcups.c:5734
+#: modules/printbackends/gtkprintbackendcups.c:5741
 msgctxt "cover page"
 msgid "Confidential"
 msgstr "Confidentiel"
 
-#: modules/printbackends/gtkprintbackendcups.c:5735
+#: modules/printbackends/gtkprintbackendcups.c:5742
 msgctxt "cover page"
 msgid "Secret"
 msgstr "Secret"
 
-#: modules/printbackends/gtkprintbackendcups.c:5736
+#: modules/printbackends/gtkprintbackendcups.c:5743
 msgctxt "cover page"
 msgid "Standard"
 msgstr "Standard"
 
-#: modules/printbackends/gtkprintbackendcups.c:5737
+#: modules/printbackends/gtkprintbackendcups.c:5744
 msgctxt "cover page"
 msgid "Top Secret"
 msgstr "Top secret"
 
-#: modules/printbackends/gtkprintbackendcups.c:5738
+#: modules/printbackends/gtkprintbackendcups.c:5745
 msgctxt "cover page"
 msgid "Unclassified"
 msgstr "Non classifié"
@@ -7097,7 +7148,7 @@ msgstr "Non classifié"
 #. Translators, this string is used to label the pages-per-sheet option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5750
+#: modules/printbackends/gtkprintbackendcups.c:5757
 msgctxt "printer option"
 msgid "Pages per Sheet"
 msgstr "Pages par feuille"
@@ -7105,7 +7156,7 @@ msgstr "Pages par feuille"
 #. Translators, this string is used to label the option in the print
 #. * dialog that controls in what order multiple pages are arranged
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5767
+#: modules/printbackends/gtkprintbackendcups.c:5774
 msgctxt "printer option"
 msgid "Page Ordering"
 msgstr "Ordre des pages"
@@ -7114,7 +7165,7 @@ msgstr "Ordre des pages"
 #. * a print job is printed. Possible values are 'now', a specified time,
 #. * or 'on hold'
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5844
+#: modules/printbackends/gtkprintbackendcups.c:5851
 msgctxt "printer option"
 msgid "Print at"
 msgstr "Imprimer à"
@@ -7122,7 +7173,7 @@ msgstr "Imprimer à"
 #. Translators: this is the name of the option that allows the user
 #. * to specify a time when a print job will be printed.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5855
+#: modules/printbackends/gtkprintbackendcups.c:5862
 msgctxt "printer option"
 msgid "Print at time"
 msgstr "Imprimer à l’heure"
@@ -7132,52 +7183,52 @@ msgstr "Imprimer à l’heure"
 #. * the width and height in points. E.g: "Custom
 #. * 230.4x142.9"
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5902
+#: modules/printbackends/gtkprintbackendcups.c:5909
 #, c-format
 msgid "Custom %s×%s"
 msgstr "Personnalisé %s×%s"
 
 #. TRANSLATORS: this is the ICC color profile to use for this job
-#: modules/printbackends/gtkprintbackendcups.c:6013
+#: modules/printbackends/gtkprintbackendcups.c:6020
 msgctxt "printer option"
 msgid "Printer Profile"
 msgstr "Profil d’imprimante"
 
 #. TRANSLATORS: this is when color profile information is unavailable
-#: modules/printbackends/gtkprintbackendcups.c:6020
+#: modules/printbackends/gtkprintbackendcups.c:6027
 msgctxt "printer option value"
 msgid "Unavailable"
 msgstr "Non disponible"
 
-#: modules/printbackends/gtkprintbackendfile.c:238
+#: modules/printbackends/gtkprintbackendfile.c:263
 msgid "output"
 msgstr "sortie"
 
-#: modules/printbackends/gtkprintbackendfile.c:510
+#: modules/printbackends/gtkprintbackendfile.c:543
 msgid "Print to File"
 msgstr "Imprimer dans un fichier"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PDF"
 msgstr "PDF"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PostScript"
 msgstr "PostScript"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "SVG"
 msgstr "SVG"
 
-#: modules/printbackends/gtkprintbackendfile.c:649
+#: modules/printbackends/gtkprintbackendfile.c:688
 msgid "Pages per _sheet:"
 msgstr "Pages par _feuille :"
 
-#: modules/printbackends/gtkprintbackendfile.c:709
+#: modules/printbackends/gtkprintbackendfile.c:758
 msgid "File"
 msgstr "Fichier"
 
-#: modules/printbackends/gtkprintbackendfile.c:719
+#: modules/printbackends/gtkprintbackendfile.c:768
 msgid "_Output format"
 msgstr "Format de _sortie"
 
@@ -7205,22 +7256,22 @@ msgstr "Produit le contenu dans ce répertoire à la place du répertoire couran
 msgid "Generate debug output"
 msgstr "Générer la sortie de débogage"
 
-#: tools/encodesymbolic.c:92
+#: tools/encodesymbolic.c:95
 #, c-format
 msgid "Invalid size %s\n"
 msgstr "Taille %s non valide\n"
 
-#: tools/encodesymbolic.c:104 tools/encodesymbolic.c:113
+#: tools/encodesymbolic.c:107 tools/encodesymbolic.c:116
 #, c-format
 msgid "Can’t load file: %s\n"
 msgstr "Impossible de charge le fichier : %s\n"
 
-#: tools/encodesymbolic.c:141 tools/encodesymbolic.c:147
+#: tools/encodesymbolic.c:144 tools/encodesymbolic.c:162
 #, c-format
 msgid "Can’t save file %s: %s\n"
 msgstr "Impossible d’enregistrer le fichier « %s » : %s\n"
 
-#: tools/encodesymbolic.c:153
+#: tools/encodesymbolic.c:168
 #, c-format
 msgid "Can’t close stream"
 msgstr "Impossible de fermer le flux"
@@ -7258,9 +7309,11 @@ msgstr ""
 
 #: tools/gtk-builder-tool-enumerate.c:56 tools/gtk-builder-tool-preview.c:179
 #: tools/gtk-builder-tool-preview.c:180 tools/gtk-builder-tool-screenshot.c:360
-#: tools/gtk-builder-tool-simplify.c:2529 tools/gtk-builder-tool-validate.c:261
+#: tools/gtk-builder-tool-simplify.c:2623 tools/gtk-builder-tool-validate.c:261
+#: tools/gtk-image-tool-compare.c:43 tools/gtk-image-tool-info.c:68
 #: tools/gtk-path-tool-render.c:121 tools/gtk-rendernode-tool-compare.c:67
-#: tools/gtk-rendernode-tool-info.c:214 tools/gtk-rendernode-tool-show.c:106
+#: tools/gtk-rendernode-tool-extract.c:294 tools/gtk-rendernode-tool-info.c:226
+#: tools/gtk-rendernode-tool-show.c:116
 msgid "FILE"
 msgstr "FICHIER"
 
@@ -7293,8 +7346,8 @@ msgstr "Utiliser le style d’un fichier CSS"
 
 #: tools/gtk-builder-tool-preview.c:187 tools/gtk-builder-tool-screenshot.c:370
 #: tools/gtk-builder-tool-validate.c:268
-#: tools/gtk-rendernode-tool-benchmark.c:106
-#: tools/gtk-rendernode-tool-render.c:203 tools/gtk-rendernode-tool-show.c:113
+#: tools/gtk-rendernode-tool-benchmark.c:108
+#: tools/gtk-rendernode-tool-render.c:262 tools/gtk-rendernode-tool-show.c:123
 #, c-format
 msgid "Could not initialize windowing system\n"
 msgstr "Impossible d’initialiser le système de fenêtrage\n"
@@ -7304,7 +7357,7 @@ msgid "Preview the file."
 msgstr "Aperçu du fichier."
 
 #: tools/gtk-builder-tool-preview.c:208 tools/gtk-builder-tool-screenshot.c:391
-#: tools/gtk-builder-tool-simplify.c:2552 tools/gtk-builder-tool-validate.c:287
+#: tools/gtk-builder-tool-simplify.c:2646 tools/gtk-builder-tool-validate.c:287
 #, c-format
 msgid "No .ui file specified\n"
 msgstr "Aucun fichier .ui indiqué\n"
@@ -7339,13 +7392,13 @@ msgstr ""
 "Utilisez --force pour l’écraser.\n"
 
 #: tools/gtk-builder-tool-screenshot.c:332
-#: tools/gtk-rendernode-tool-render.c:171
+#: tools/gtk-rendernode-tool-render.c:230
 #, c-format
 msgid "Output written to %s.\n"
 msgstr "Sortie écrite dans %s.\n"
 
 #: tools/gtk-builder-tool-screenshot.c:336
-#: tools/gtk-rendernode-tool-render.c:175
+#: tools/gtk-rendernode-tool-render.c:234
 #, c-format
 msgid "Failed to save %s: %s\n"
 msgstr "Impossible d’enregistrer %s : %s\n"
@@ -7362,9 +7415,10 @@ msgstr "Enregistrer comme fichier nœud au lieu de png"
 msgid "Overwrite existing file"
 msgstr "Écraser un fichier existant"
 
-#: tools/gtk-builder-tool-screenshot.c:363
-#: tools/gtk-rendernode-tool-benchmark.c:97
-#: tools/gtk-rendernode-tool-render.c:196
+#: tools/gtk-builder-tool-screenshot.c:363 tools/gtk-image-tool-compare.c:46
+#: tools/gtk-image-tool-convert.c:89 tools/gtk-image-tool-relabel.c:86
+#: tools/gtk-image-tool-show.c:119 tools/gtk-rendernode-tool-benchmark.c:99
+#: tools/gtk-rendernode-tool-render.c:255
 msgid "FILE…"
 msgstr "FICHIER…"
 
@@ -7376,8 +7430,8 @@ msgstr "Réaliser le rendu du fichier .ui vers une image."
 #, c-format
 msgid "Can only render a single .ui file to a single output file\n"
 msgstr ""
-"Ne peut effectuer le rendu que d’un unique fichier .ui vers un seul fichier "
-"de sortie\n"
+"Ne peut effectuer le rendu que d’un seul fichier .ui vers un seul fichier de "
+"sortie\n"
 
 #: tools/gtk-builder-tool-simplify.c:444
 #, c-format
@@ -7404,49 +7458,54 @@ msgstr "Propriété de cellule %s introuvable"
 msgid "Layout property %s not found"
 msgstr "Propriété d’agencement %s introuvable"
 
-#: tools/gtk-builder-tool-simplify.c:1397
+#: tools/gtk-builder-tool-simplify.c:1400
 #, c-format
 msgid "%s only accepts three children"
 msgstr "%s accepte seulement trois enfants"
 
-#: tools/gtk-builder-tool-simplify.c:2455
+#: tools/gtk-builder-tool-simplify.c:1773
+#, c-format
+msgid "%s only accepts one center child"
+msgstr "%s accepte seulement un enfant central"
+
+#: tools/gtk-builder-tool-simplify.c:2549
 #, c-format
 msgid "Can’t load “%s”: %s\n"
 msgstr "Impossible de charger « %s » : %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2466
-#: tools/gtk-builder-tool-simplify.c:2472
-#: tools/gtk-builder-tool-simplify.c:2478
+#: tools/gtk-builder-tool-simplify.c:2560
+#: tools/gtk-builder-tool-simplify.c:2566
+#: tools/gtk-builder-tool-simplify.c:2572
 #, c-format
 msgid "Can’t parse “%s”: %s\n"
 msgstr "Impossible d’analyser « %s » : %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2504
+#: tools/gtk-builder-tool-simplify.c:2598
 #, c-format
 msgid "Failed to read “%s”: %s\n"
 msgstr "Impossible de lire « %s » : %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2510
+#: tools/gtk-builder-tool-simplify.c:2604
 #, c-format
 msgid "Failed to write “%s”: “%s”\n"
 msgstr "Impossible d’écrire dans « %s » : « %s »\n"
 
-#: tools/gtk-builder-tool-simplify.c:2527
+#: tools/gtk-builder-tool-simplify.c:2621
 msgid "Replace the file"
 msgstr "Remplacer le fichier"
 
-#: tools/gtk-builder-tool-simplify.c:2528
+#: tools/gtk-builder-tool-simplify.c:2622
 msgid "Convert from GTK 3 to GTK 4"
 msgstr "Convertir de GTK 3 vers GTK 4"
 
-#: tools/gtk-builder-tool-simplify.c:2539
+#: tools/gtk-builder-tool-simplify.c:2633
 msgid "Simplify the file."
 msgstr "Simplifier le fichier."
 
-#: tools/gtk-builder-tool-simplify.c:2558
+#: tools/gtk-builder-tool-simplify.c:2652
 #, c-format
 msgid "Can only simplify a single .ui file without --replace\n"
-msgstr "Un seul fichier .ui peut être simplifié sans --replace\n"
+msgstr "Ne peut simplifier qu’un seul fichier .ui sans --replace\n"
 
 #: tools/gtk-builder-tool-validate.c:45
 #, c-format
@@ -7466,6 +7525,188 @@ msgstr "La création d’une instance de modèle du type %s a échoué\n"
 msgid "Validate the file."
 msgstr "Valider le fichier."
 
+#: tools/gtk-image-tool.c:36
+#, c-format
+msgid ""
+"Usage:\n"
+"  gtk4-image-tool [COMMAND] [OPTION…] FILE…\n"
+"\n"
+"Perform various tasks on images.\n"
+"\n"
+"Commands:\n"
+"  compare      Show differences between two images\n"
+"  convert      Convert the image to a different format or color state\n"
+"  info         Show general information about the image\n"
+"  relabel      Change the color state of the image without conversion\n"
+"  show         Show the image\n"
+"\n"
+msgstr ""
+"Utilisation :\n"
+"  gtk4-image-tool [COMMANDE] [OPTION…] FICHIER…\n"
+"\n"
+"Effectuer diverses opérations sur les images.\n"
+"\n"
+"Commandes :\n"
+"  compare      Afficher les différences entre deux images\n"
+"  convert      Convertir l’image dans un format ou un état colorimétrique différent\n"
+"  info         Afficher des informations générales sur l’image\n"
+"  relabel      Modifie l’état colorimétrique de l’image sans conversion\n"
+"  show         Afficher l’image\n"
+"\n"
+
+#: tools/gtk-image-tool-compare.c:43 tools/gtk-rendernode-tool-compare.c:67
+msgid "Output file"
+msgstr "Fichier de sortie"
+
+#: tools/gtk-image-tool-compare.c:57
+msgid "Compare two images"
+msgstr "Comparer deux images"
+
+#: tools/gtk-image-tool-compare.c:70 tools/gtk-image-tool-convert.c:113
+#: tools/gtk-image-tool-info.c:90 tools/gtk-image-tool-relabel.c:109
+#: tools/gtk-image-tool-show.c:141
+#, c-format
+msgid "No image file specified\n"
+msgstr "Aucun fichier image indiqué\n"
+
+#: tools/gtk-image-tool-compare.c:76
+#, c-format
+msgid "Can only accept two image files\n"
+msgstr "N’accepte que deux fichiers image\n"
+
+#: tools/gtk-image-tool-compare.c:85 tools/gtk-rendernode-tool-compare.c:111
+#, c-format
+msgid "Failed to load %s: %s\n"
+msgstr "Impossible de charger %s : %s\n"
+
+#: tools/gtk-image-tool-compare.c:96 tools/gtk-rendernode-tool-compare.c:122
+#, c-format
+msgid "Could not save diff image to %s\n"
+msgstr "Impossible d’enregistrer l’image de différences dans %s\n"
+
+#: tools/gtk-image-tool-compare.c:106 tools/gtk-rendernode-tool-compare.c:132
+#, c-format
+msgid "Differences witten to %s.\n"
+msgstr "Différences écrites dans %s.\n"
+
+#: tools/gtk-image-tool-compare.c:108 tools/gtk-rendernode-tool-compare.c:134
+#, c-format
+msgid "The images are different.\n"
+msgstr "Les images sont différentes.\n"
+
+#: tools/gtk-image-tool-compare.c:111 tools/gtk-rendernode-tool-compare.c:137
+#, c-format
+msgid "No differences.\n"
+msgstr "Aucune différence.\n"
+
+#: tools/gtk-image-tool-convert.c:86
+msgid "Format to use"
+msgstr "Format à utiliser"
+
+#: tools/gtk-image-tool-convert.c:86
+msgid "FORMAT"
+msgstr "FORMAT"
+
+#: tools/gtk-image-tool-convert.c:87 tools/gtk-image-tool-relabel.c:84
+msgid "Color state to use"
+msgstr "État colorimétrique à utiliser"
+
+#: tools/gtk-image-tool-convert.c:87 tools/gtk-image-tool-relabel.c:84
+msgid "COLORSTATE"
+msgstr "ÉTATCOLORIMÉTRIQUE"
+
+#: tools/gtk-image-tool-convert.c:88 tools/gtk-image-tool-relabel.c:85
+msgid "Color state to use, as cicp tuple"
+msgstr "État colorimétrique à utiliser, en tant que tuple cicp"
+
+#: tools/gtk-image-tool-convert.c:88 tools/gtk-image-tool-relabel.c:85
+msgid "CICP"
+msgstr "CICP"
+
+#: tools/gtk-image-tool-convert.c:100
+msgid "Convert the image to a different format or color state."
+msgstr "Convertir l’image vers un format ou un état colorimétrique différent."
+
+#: tools/gtk-image-tool-convert.c:119 tools/gtk-image-tool-relabel.c:115
+#, c-format
+msgid "Can only accept a single image file and output file\n"
+msgstr "N’accepte qu’un seul fichier image et fichier de sortie\n"
+
+#: tools/gtk-image-tool-convert.c:133
+#, c-format
+msgid ""
+"Not a memory format: %s\n"
+"Possible values:\n"
+"  %s\n"
+msgstr ""
+"Pas un format mémoire : %s\n"
+"Valeurs possibles :\n"
+"  %s\n"
+
+#: tools/gtk-image-tool-convert.c:150
+#, c-format
+msgid ""
+"Not a color state: %s\n"
+"Possible values:\n"
+"  %s\n"
+msgstr ""
+"Pas un état colorimétrique : %s\n"
+"Valeurs possibles :\n"
+"  %s\n"
+
+#: tools/gtk-image-tool-convert.c:160 tools/gtk-image-tool-relabel.c:140
+#, c-format
+msgid "Can't specify both --color-state and --cicp\n"
+msgstr "Impossible d’indiquer à la fois --color-state et --cicp\n"
+
+#: tools/gtk-image-tool-convert.c:168 tools/gtk-image-tool-relabel.c:148
+#, c-format
+msgid "Not a supported cicp tuple: %s\n"
+msgstr "Tuple cicp non pris en charge :%s\n"
+
+#: tools/gtk-image-tool-info.c:55
+msgid "Format:"
+msgstr "Format :"
+
+#: tools/gtk-image-tool-info.c:56
+msgid "Color state:"
+msgstr "État colorimétrique :"
+
+#: tools/gtk-image-tool-info.c:77
+msgid "Provide information about the image."
+msgstr "Fournir des informations sur l’image."
+
+#: tools/gtk-image-tool-info.c:96
+#, c-format
+msgid "Can only accept a single image file\n"
+msgstr "N’accepte qu’un seul fichier image\n"
+
+#: tools/gtk-image-tool-relabel.c:96
+msgid "Change the color state of the image without conversion."
+msgstr "Modifier l’état colorimétrique de l’image sans conversion."
+
+#: tools/gtk-image-tool-relabel.c:130
+#, c-format
+msgid ""
+"Not a color state: %s\n"
+"Possible values: %s\n"
+msgstr ""
+"Pas un état colorimétrique : %s\n"
+"Possible values : %s\n"
+
+#: tools/gtk-image-tool-show.c:117 tools/gtk-rendernode-tool-show.c:115
+msgid "Don't add a titlebar"
+msgstr "Ne pas ajouter de barre de titre"
+
+#: tools/gtk-image-tool-show.c:128
+msgid "Show one or more images."
+msgstr "Afficher une ou plusieurs images."
+
+#: tools/gtk-image-tool-utils.c:234
+#, c-format
+msgid "cicp must be 4 numbers, separated by /\n"
+msgstr "cicp doit être 4 nombres, séparés par /\n"
+
 #: tools/gtk-launch.c:40
 msgid "Show program version"
 msgstr "Afficher la version du programme"
@@ -7542,7 +7783,7 @@ msgid ""
 "\n"
 msgstr ""
 "Utilisation :\n"
-"  gtk4-path-tool [COMMANDE][OPTION…] CHEMIN\n"
+"  gtk4-path-tool [COMMANDE] [OPTION…] CHEMIN\n"
 "\n"
 "Effectue diverses opérations sur les chemins.\n"
 "\n"
@@ -7552,7 +7793,7 @@ msgstr ""
 "  restrict     Limite le chemin à un segment\n"
 "  show         Affiche le chemin dans une fenêtre d’affichage\n"
 "  render       Effectuer de rendu du chemin vers une image\n"
-"  info         Affiche des informations à propos du chemin\n"
+"  info         Affiche des informations sur le chemin\n"
 
 #: tools/gtk-path-tool-decompose.c:84
 msgid "Allow quadratic Bézier curves"
@@ -7588,7 +7829,7 @@ msgstr "Cela n’a pas fonctionné."
 
 #: tools/gtk-path-tool-info.c:100
 msgid "Print information about a path."
-msgstr "Affiche des informations à propose d’un chemin."
+msgstr "Affiche des informations sur un chemin."
 
 #: tools/gtk-path-tool-info.c:121
 msgid "Path is empty."
@@ -7839,6 +8080,7 @@ msgid ""
 "Commands:\n"
 "  benchmark    Benchmark rendering of a node\n"
 "  compare      Compare nodes or images\n"
+"  extract      Extract data urls\n"
 "  info         Provide information about the node\n"
 "  show         Show the node\n"
 "  render       Take a screenshot of the node\n"
@@ -7852,58 +8094,55 @@ msgstr ""
 "Commandes :\n"
 "  benchmark    Évalue le rendu d’un nœud\n"
 "  compare      Comparer des nœuds ou des images\n"
+"  extract      Extraire les urls des données\n"
 "  info         Obtenir les informations du nœud\n"
 "  show         Afficher le nœud\n"
 "  render       Prendre une capture d’écran du nœud\n"
 "\n"
 
-#: tools/gtk-rendernode-tool-benchmark.c:94
+#: tools/gtk-rendernode-tool-benchmark.c:96
 msgid "Add renderer to benchmark"
 msgstr "Ajouter un moteur de rendu à évaluer"
 
-#: tools/gtk-rendernode-tool-benchmark.c:94
+#: tools/gtk-rendernode-tool-benchmark.c:96
 #: tools/gtk-rendernode-tool-compare.c:65
-#: tools/gtk-rendernode-tool-render.c:195
+#: tools/gtk-rendernode-tool-render.c:254
 msgid "RENDERER"
 msgstr "MOTEUR_DE_RENDU"
 
-#: tools/gtk-rendernode-tool-benchmark.c:95
+#: tools/gtk-rendernode-tool-benchmark.c:97
 msgid "Number of runs with each renderer"
 msgstr "Nombre d’exécutions avec chaque moteur de rendu"
 
-#: tools/gtk-rendernode-tool-benchmark.c:95
+#: tools/gtk-rendernode-tool-benchmark.c:97
 msgid "RUNS"
 msgstr "EXÉCUTIONS"
 
-#: tools/gtk-rendernode-tool-benchmark.c:96
+#: tools/gtk-rendernode-tool-benchmark.c:98
 msgid "Don’t download result/wait for GPU to finish"
 msgstr "Ne pas récupérer les résultats ou attendre que le GPU termine"
 
-#: tools/gtk-rendernode-tool-benchmark.c:114
+#: tools/gtk-rendernode-tool-benchmark.c:116
 msgid "Benchmark rendering of a .node file."
 msgstr "Évaluer le rendu d’un fichier .node"
 
-#: tools/gtk-rendernode-tool-benchmark.c:127
-#: tools/gtk-rendernode-tool-info.c:236 tools/gtk-rendernode-tool-render.c:224
-#: tools/gtk-rendernode-tool-show.c:134
+#: tools/gtk-rendernode-tool-benchmark.c:129
+#: tools/gtk-rendernode-tool-extract.c:316 tools/gtk-rendernode-tool-info.c:248
+#: tools/gtk-rendernode-tool-render.c:283 tools/gtk-rendernode-tool-show.c:144
 #, c-format
 msgid "No .node file specified\n"
 msgstr "Aucun fichier .node indiqué\n"
 
-#: tools/gtk-rendernode-tool-benchmark.c:133
+#: tools/gtk-rendernode-tool-benchmark.c:135
 #, c-format
 msgid "Can only benchmark a single .node file\n"
-msgstr "N’évalue qu’un unique fichier .node\n"
+msgstr "N’évalue qu’un seul fichier .node\n"
 
 #: tools/gtk-rendernode-tool-compare.c:65
-#: tools/gtk-rendernode-tool-render.c:195
+#: tools/gtk-rendernode-tool-render.c:254
 msgid "Renderer to use"
 msgstr "Moteur de rendu à utiliser"
 
-#: tools/gtk-rendernode-tool-compare.c:67
-msgid "Output file"
-msgstr "Fichier de sortie"
-
 #: tools/gtk-rendernode-tool-compare.c:70
 msgid "FILE1 FILE2"
 msgstr "FICHIER1 FICHIER2"
@@ -7918,66 +8157,63 @@ msgid "Must specify two files\n"
 msgstr "Doit indiquer deux fichiers\n"
 
 #: tools/gtk-rendernode-tool-compare.c:102
-#: tools/gtk-rendernode-tool-render.c:150
+#: tools/gtk-rendernode-tool-render.c:209
 #, c-format
 msgid "Failed to create renderer: %s\n"
 msgstr "Échec de création du moteur de rendu : %s\n"
 
-#: tools/gtk-rendernode-tool-compare.c:111
+#: tools/gtk-rendernode-tool-extract.c:73
+#: tools/gtk-rendernode-tool-extract.c:149
 #, c-format
-msgid "Failed to load %s: %s\n"
-msgstr "Impossible de charger %s : %s\n"
+msgid "Failed to write %s\n"
+msgstr "Impossible d’écrire %s\n"
 
-#: tools/gtk-rendernode-tool-compare.c:122
-#, c-format
-msgid "Could not save diff image to %s\n"
-msgstr "Impossible d’enregistrer l’image de différences dans %s\n"
+#: tools/gtk-rendernode-tool-extract.c:292
+msgid "Directory to use"
+msgstr "Répertoire à utiliser"
 
-#: tools/gtk-rendernode-tool-compare.c:132
-#, c-format
-msgid "Differences witten to %s.\n"
-msgstr "Différences écrites dans %s.\n"
+#: tools/gtk-rendernode-tool-extract.c:292
+msgid "DIRECTORY"
+msgstr "RÉPERTOIRE"
 
-#: tools/gtk-rendernode-tool-compare.c:134
-#, c-format
-msgid "The images are different.\n"
-msgstr "Les images sont différentes.\n"
+#: tools/gtk-rendernode-tool-extract.c:293
+msgid "Be verbose"
+msgstr "Soyez explicite"
 
-#: tools/gtk-rendernode-tool-compare.c:137
-#, c-format
-msgid "No differences.\n"
-msgstr "Aucune différence.\n"
+#: tools/gtk-rendernode-tool-extract.c:303
+msgid "Extract data urls from the render node."
+msgstr "Extraire des urls de données à partir du nœud de rendu."
 
-#: tools/gtk-rendernode-tool-info.c:191
+#: tools/gtk-rendernode-tool-extract.c:322 tools/gtk-rendernode-tool-info.c:254
 #, c-format
-msgid "Number of nodes: %u\n"
-msgstr "Nombre de nœuds : %u\n"
+msgid "Can only accept a single .node file\n"
+msgstr "N’accepte qu’un seul fichier .node\n"
 
-#: tools/gtk-rendernode-tool-info.c:198
-#, c-format
-msgid "Depth: %u\n"
-msgstr "Profondeur : %u\n"
+#: tools/gtk-rendernode-tool-info.c:193
+msgid "Number of nodes:"
+msgstr "Nombre de nœuds :"
 
-#: tools/gtk-rendernode-tool-info.c:201
-#, c-format
-msgid "Bounds: %g x %g\n"
-msgstr "Limites : %g × %g\n"
+#: tools/gtk-rendernode-tool-info.c:200
+msgid "Depth:"
+msgstr "Profondeur :"
 
-#: tools/gtk-rendernode-tool-info.c:202
-#, c-format
-msgid "Origin: %g %g\n"
-msgstr "Origine : %g %g\n"
+#: tools/gtk-rendernode-tool-info.c:203
+msgid "Bounds:"
+msgstr "Limites :"
+
+#: tools/gtk-rendernode-tool-info.c:204
+msgid "Origin:"
+msgstr "Origine :"
 
-#: tools/gtk-rendernode-tool-info.c:223
+#: tools/gtk-rendernode-tool-info.c:208 tools/gtk-rendernode-tool-info.c:214
+msgid "Opaque part:"
+msgstr "Partie opaque :"
+
+#: tools/gtk-rendernode-tool-info.c:235
 msgid "Provide information about the render node."
 msgstr "Fournir des informations sur le nœud de rendu."
 
-#: tools/gtk-rendernode-tool-info.c:242
-#, c-format
-msgid "Can only accept a single .node file\n"
-msgstr "N’accepte qu’un unique fichier .node\n"
-
-#: tools/gtk-rendernode-tool-render.c:123
+#: tools/gtk-rendernode-tool-render.c:170
 #, c-format
 msgid ""
 "File %s exists.\n"
@@ -7986,34 +8222,31 @@ msgstr ""
 "Le fichier %s existe.\n"
 "Si vous souhaitez l’écraser, indiquez le nom du fichier.\n"
 
-#: tools/gtk-rendernode-tool-render.c:137
+#: tools/gtk-rendernode-tool-render.c:184
+#: tools/gtk-rendernode-tool-render.c:196
 #, c-format
 msgid "Failed to generate SVG: %s\n"
 msgstr "Échec de génération du SVG : %s\n"
 
-#: tools/gtk-rendernode-tool-render.c:211
+#: tools/gtk-rendernode-tool-render.c:270
 msgid "Render a .node file to an image."
 msgstr "Réaliser le rendu du fichier .node vers une image."
 
-#: tools/gtk-rendernode-tool-render.c:230
+#: tools/gtk-rendernode-tool-render.c:289
 #, c-format
 msgid "Can only render a single .node file to a single output file\n"
 msgstr ""
-"Ne peut effectuer le rendu que d’un unique fichier .node vers un seul "
-"fichier de sortie\n"
-
-#: tools/gtk-rendernode-tool-show.c:105
-msgid "Don't add a titlebar"
-msgstr "Ne pas ajouter de barre de titre"
+"Ne peut effectuer le rendu que d’un seul fichier .node vers un seul fichier "
+"de sortie\n"
 
-#: tools/gtk-rendernode-tool-show.c:121
+#: tools/gtk-rendernode-tool-show.c:131
 msgid "Show the render node."
 msgstr "Afficher le nœud de rendu."
 
-#: tools/gtk-rendernode-tool-show.c:140
+#: tools/gtk-rendernode-tool-show.c:150
 #, c-format
 msgid "Can only preview a single .node file\n"
-msgstr "Ne peut afficher l’aperçu que d’un unique fichier .node\n"
+msgstr "Ne peut afficher l’aperçu que d’un seul fichier .node\n"
 
 #: tools/gtk-rendernode-tool-utils.c:54
 #, c-format
@@ -8108,22 +8341,22 @@ msgstr "Désactiver la sortie détaillée"
 msgid "Validate existing icon cache"
 msgstr "Valider le cache d’icônes existant"
 
-#: tools/updateiconcache.c:1724
+#: tools/updateiconcache.c:1725
 #, c-format
 msgid "File not found: %s\n"
 msgstr "Fichier introuvable : %s\n"
 
-#: tools/updateiconcache.c:1730
+#: tools/updateiconcache.c:1731
 #, c-format
 msgid "Not a valid icon cache: %s\n"
 msgstr "Cache d’icônes non valide : %s\n"
 
-#: tools/updateiconcache.c:1743
+#: tools/updateiconcache.c:1744
 #, c-format
 msgid "No theme index file.\n"
 msgstr "Aucun fichier d’index de thème.\n"
 
-#: tools/updateiconcache.c:1747
+#: tools/updateiconcache.c:1748
 #, c-format
 msgid ""
 "No theme index file in “%s”.\n"
@@ -8133,6 +8366,13 @@ msgstr ""
 "Si vous souhaitez vraiment créer un cache d’icônes ici, utilisez --ignore-"
 "theme-index.\n"
 
+#~ msgid "Font Scale"
+#~ msgstr "Mise à l’échelle des polices"
+
+#, c-format
+#~ msgid "Bounds: %g x %g\n"
+#~ msgstr "Limites : %g × %g\n"
+
 #~ msgid "Backend does not support window scaling"
 #~ msgstr "Le moteur ne gère pas la mise à l’échelle des fenêtres"
 
diff --git a/po/ka.po b/po/ka.po
index ccbf0737a3890ba21117cf8a55f9330e3a4c2ffe..891741dcd5fbfab00a27d3d42d27fa4b6cbef499 100644
--- a/po/ka.po
+++ b/po/ka.po
@@ -11,8 +11,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gtk\n"
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
-"POT-Creation-Date: 2025-01-14 05:07+0000\n"
-"PO-Revision-Date: 2025-01-16 00:28+0100\n"
+"POT-Creation-Date: 2025-02-10 19:32+0000\n"
+"PO-Revision-Date: 2025-02-12 04:50+0100\n"
 "Last-Translator: Ekaterine Papava <papava.e@gtu.ge>\n"
 "Language-Team: Georgian <http://mail.gnome.org/mailman/listinfo/gnome-ge-"
 "list>\n"
@@ -23,6 +23,20 @@ msgstr ""
 "Plural-Forms: nplurals=1; plural=0;\n"
 "X-Generator: Poedit 3.5\n"
 
+#: gdk/android/gdkandroidclipboard.c:174
+msgid "No compatible formats to transfer contents of content provider."
+msgstr ""
+"შემცველობის მომწოდებლის შემცველობის გადასაცემად თავსებადი ფორმატები "
+"აღმოჩენილი არაა."
+
+#: gdk/android/gdkandroidclipboard.c:623 gdk/macos/gdkmacospasteboard.c:161
+#: gdk/wayland/gdkclipboard-wayland.c:244 gdk/wayland/gdkdrop-wayland.c:205
+#: gdk/wayland/gdkprimary-wayland.c:343 gdk/win32/gdkdrop-win32.c:1014
+#: gdk/win32/gdkdrop-win32.c:1063 gdk/x11/gdkclipboard-x11.c:801
+#: gdk/x11/gdkdrop-x11.c:237
+msgid "No compatible transfer format found"
+msgstr "გადატანის თავსებადი ფორმატი ნაპოვნი არაა"
+
 #: gdk/broadway/gdkbroadway-server.c:135
 #, c-format
 msgid "Broadway display type not supported: %s"
@@ -75,7 +89,7 @@ msgstr "შემცველობის %s-ად გამოტანა შ
 msgid "The current backend does not support OpenGL"
 msgstr "მიმდინარე უკანაბოლოს OpenGL-ის მხარდაჭერა არ გააჩნია"
 
-#: gdk/gdkdisplay.c:1364 gdk/gdkvulkancontext.c:1723
+#: gdk/gdkdisplay.c:1364 gdk/gdkvulkancontext.c:1727
 msgid "Vulkan support disabled via GDK_DISABLE"
 msgstr "Vulkan-ის მხარდაჭერა გამორთულია GDK_DISABLE-ით"
 
@@ -134,13 +148,13 @@ msgstr "სხვა აპლიკაციებიდან DnD მხარ
 msgid "No compatible formats to transfer contents."
 msgstr "შემცველობის გადატანის თავსებადი ფორმატების გარეშე."
 
-#: gdk/gdkglcontext.c:427 gdk/x11/gdkglcontext-glx.c:651
+#: gdk/gdkglcontext.c:427 gdk/x11/gdkglcontext-glx.c:653
 msgid "No GL API allowed."
 msgstr "GL API არ არის დაშვებული."
 
 #: gdk/gdkglcontext.c:450 gdk/win32/gdkglcontext-win32-wgl.c:746
 #: gdk/win32/gdkglcontext-win32-wgl.c:889
-#: gdk/win32/gdkglcontext-win32-wgl.c:933 gdk/x11/gdkglcontext-glx.c:697
+#: gdk/win32/gdkglcontext-win32-wgl.c:933 gdk/x11/gdkglcontext-glx.c:699
 msgid "Unable to create a GL context"
 msgstr "GL-ის კონტექსტის შექმნა შეუძლებელია"
 
@@ -250,12 +264,12 @@ msgctxt "keyboard label"
 msgid "Down"
 msgstr "ქვემოთ"
 
-#: gdk/keynamesprivate.h:6874 gtk/deprecated/gtkshortcutlabel.c:217
+#: gdk/keynamesprivate.h:6874 gtk/deprecated/gtkshortcutlabel.c:219
 msgctxt "keyboard label"
 msgid "Page_Up"
 msgstr "Page_Up"
 
-#: gdk/keynamesprivate.h:6875 gtk/deprecated/gtkshortcutlabel.c:220
+#: gdk/keynamesprivate.h:6875 gtk/deprecated/gtkshortcutlabel.c:222
 msgctxt "keyboard label"
 msgid "Page_Down"
 msgstr "Page_Down"
@@ -561,27 +575,27 @@ msgstr "JPEG გამოსახულების ფაილის კი
 msgid "Unsupported JPEG colorspace (%d)"
 msgstr "მხარდაუჭერელი JPEG ფერთა სივრცე (%d)"
 
-#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:436 gdk/loaders/gdktiff.c:472
+#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:468 gdk/loaders/gdktiff.c:472
 #, c-format
 msgid "Not enough memory for image size %ux%u"
 msgstr "არასაკმარისი მეხსიერება გამოსახულების ჩასატვირთად %ux%u"
 
-#: gdk/loaders/gdkpng.c:120
+#: gdk/loaders/gdkpng.c:119
 #, c-format
 msgid "Error reading png (%s)"
 msgstr "PNG-ის წაკითხვის შეცდომა (%s)"
 
-#: gdk/loaders/gdkpng.c:357
+#: gdk/loaders/gdkpng.c:389
 #, c-format
 msgid "Unsupported depth %u in png image"
 msgstr "PNG გამოსახულების მხარდაუჭერელი ფერთა სიღრმე %u"
 
-#: gdk/loaders/gdkpng.c:407
+#: gdk/loaders/gdkpng.c:439
 #, c-format
 msgid "Unsupported color type %u in png image"
 msgstr "PNG გამოსახულების ფერების მხარდაუჭერელი ტიპი %u"
 
-#: gdk/loaders/gdkpng.c:421
+#: gdk/loaders/gdkpng.c:453
 #, c-format
 msgid "Image stride too large for image size %ux%u"
 msgstr "გამოსახულებს ბიჯი მეტისმეტად დიდია გამოსახულების ზომისთვის %ux%u"
@@ -599,13 +613,6 @@ msgstr "TIFF-ის მონაცემების ჩატვირთვ
 msgid "Reading data failed at row %d"
 msgstr "მონაცემების კითხვის შეცდომა %d-ე ხაზზე"
 
-#: gdk/macos/gdkmacospasteboard.c:161 gdk/wayland/gdkclipboard-wayland.c:244
-#: gdk/wayland/gdkdrop-wayland.c:205 gdk/wayland/gdkprimary-wayland.c:343
-#: gdk/win32/gdkdrop-win32.c:1014 gdk/win32/gdkdrop-win32.c:1063
-#: gdk/x11/gdkclipboard-x11.c:799 gdk/x11/gdkdrop-x11.c:235
-msgid "No compatible transfer format found"
-msgstr "გადატანის თავსებადი ფორმატი ნაპოვნი არაა"
-
 #: gdk/macos/gdkmacospasteboard.c:255
 #, c-format
 msgid "Failed to decode contents with mime-type of '%s'"
@@ -814,66 +821,66 @@ msgstr "GlobalLock()-ის შეცდომა: "
 msgid "GlobalAlloc() failed: "
 msgstr "GlobalAlloc()-ის შეცდომა: "
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:297
+#: gdk/x11/gdkapplaunchcontext-x11.c:299
 #, c-format
 msgid "Starting “%s”"
 msgstr "\"%s\"-ის გაშვება"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:310
+#: gdk/x11/gdkapplaunchcontext-x11.c:312
 #, c-format
 msgid "Opening “%s”"
 msgstr "იხსნება “%s”"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:315
+#: gdk/x11/gdkapplaunchcontext-x11.c:317
 #, c-format
 msgid "Opening %d Item"
 msgid_plural "Opening %d Items"
 msgstr[0] "იხსნება %d საგანი"
 
-#: gdk/x11/gdkclipboard-x11.c:473
+#: gdk/x11/gdkclipboard-x11.c:475
 msgid "Clipboard manager could not store selection."
 msgstr "გაცვლის ბაფერის მმართველის შეცდომა მონიშნულის დამახსოვრებისას."
 
-#: gdk/x11/gdkclipboard-x11.c:649
+#: gdk/x11/gdkclipboard-x11.c:651
 msgid "Cannot store clipboard. No clipboard manager is active."
 msgstr ""
 "გაცვლის ბაფერის დამახსოვრება შეუძლებელია. ბაფერის მმართველი აქტიური არაა."
 
-#: gdk/x11/gdkglcontext-glx.c:817
+#: gdk/x11/gdkglcontext-glx.c:819
 msgid "No GLX configurations available"
 msgstr "GLX-ის კონფიგურაციები მიუწვდომელია"
 
-#: gdk/x11/gdkglcontext-glx.c:904
+#: gdk/x11/gdkglcontext-glx.c:906
 msgid "No GLX configuration with required features found"
 msgstr "მოთხოვნილი ფუნქციების მქონე GLX-ის კონფიგურაცია ნაპოვნი არაა"
 
-#: gdk/x11/gdkglcontext-glx.c:978
+#: gdk/x11/gdkglcontext-glx.c:982
 msgid "GLX is not supported"
 msgstr "GLX მხარდაჭერილი არაა"
 
-#: gdk/x11/gdkselectioninputstream-x11.c:465
+#: gdk/x11/gdkselectioninputstream-x11.c:467
 #, c-format
 msgid "Format %s not supported"
 msgstr "ფორმატი მხარდაუჭერელია: %s"
 
-#: gdk/x11/gdktextlistconverter-x11.c:65 gdk/x11/gdktextlistconverter-x11.c:105
+#: gdk/x11/gdktextlistconverter-x11.c:67 gdk/x11/gdktextlistconverter-x11.c:107
 msgid "Not enough space in destination"
 msgstr "დანიშნულების წერტილში საკმარისი ადგილი არაა"
 
-#: gdk/x11/gdktextlistconverter-x11.c:91 gdk/x11/gdktextlistconverter-x11.c:195
+#: gdk/x11/gdktextlistconverter-x11.c:93 gdk/x11/gdktextlistconverter-x11.c:197
 msgid "Need complete input to do conversion"
 msgstr "გადაყვანისთვის შეყვანა დასრულებული უნდა იყოს"
 
-#: gdk/x11/gdktextlistconverter-x11.c:216
-#: gdk/x11/gdktextlistconverter-x11.c:250
+#: gdk/x11/gdktextlistconverter-x11.c:218
+#: gdk/x11/gdktextlistconverter-x11.c:252
 msgid "Invalid byte sequence in conversion input"
 msgstr "შეტანილ ტექსტში ბაიტების მიმდევრობა მცდარია"
 
-#: gdk/x11/gdktextlistconverter-x11.c:242
+#: gdk/x11/gdktextlistconverter-x11.c:244
 msgid "Invalid formats in compound text conversion."
 msgstr "არასწორი ფორმატები შედგენილი ტექსტის გადაყვანისას."
 
-#: gdk/x11/gdktextlistconverter-x11.c:259
+#: gdk/x11/gdktextlistconverter-x11.c:261
 #, c-format
 msgid "Unsupported encoding “%s”"
 msgstr "კოდირება \"%s\" მხარდაუჭერელია"
@@ -883,114 +890,114 @@ msgstr "კოდირება \"%s\" მხარდაუჭერელი
 msgid "OpenGL ES 3.0 is not supported by this renderer."
 msgstr "OpenGL ES 3.0 ამ რენდერერის მიერ მხარდაჭერილი არაა."
 
-#: gsk/gpu/gsknglrenderer.c:66
+#: gsk/gpu/gskglrenderer.c:66
 msgid "OpenGL 3.3 required"
 msgstr "აუცილებელია OpenGL 3.3"
 
-#: gtk/a11y/gtkatspiaction.c:239
+#: gtk/a11y/gtkatspiaction.c:285
 msgctxt "accessibility"
 msgid "Click"
 msgstr "დააწკაპუნეთ"
 
-#: gtk/a11y/gtkatspiaction.c:240
+#: gtk/a11y/gtkatspiaction.c:286
 msgctxt "accessibility"
 msgid "Clicks the button"
 msgstr "დააწექით ღილაკს"
 
-#: gtk/a11y/gtkatspiaction.c:290
+#: gtk/a11y/gtkatspiaction.c:336
 msgctxt "accessibility"
 msgid "Toggle"
 msgstr "გადართვა"
 
-#: gtk/a11y/gtkatspiaction.c:291
+#: gtk/a11y/gtkatspiaction.c:337
 msgctxt "accessibility"
 msgid "Toggles the switch"
 msgstr "მდგომარეობის გადართვა"
 
-#: gtk/a11y/gtkatspiaction.c:371
+#: gtk/a11y/gtkatspiaction.c:418
 msgctxt "accessibility"
 msgid "Select"
 msgstr "მონიშვნა"
 
-#: gtk/a11y/gtkatspiaction.c:372
+#: gtk/a11y/gtkatspiaction.c:419
 msgctxt "accessibility"
 msgid "Selects the color"
 msgstr "ფერის არჩევა"
 
-#: gtk/a11y/gtkatspiaction.c:379 gtk/a11y/gtkatspiaction.c:439
-#: gtk/a11y/gtkatspiaction.c:495 gtk/a11y/gtkatspiaction.c:603
-#: gtk/a11y/gtkatspiaction.c:690
+#: gtk/a11y/gtkatspiaction.c:426 gtk/a11y/gtkatspiaction.c:487
+#: gtk/a11y/gtkatspiaction.c:543 gtk/a11y/gtkatspiaction.c:651
+#: gtk/a11y/gtkatspiaction.c:738
 msgctxt "accessibility"
 msgid "Activate"
 msgstr "აქტივაცია"
 
-#: gtk/a11y/gtkatspiaction.c:380
+#: gtk/a11y/gtkatspiaction.c:427
 msgctxt "accessibility"
 msgid "Activates the color"
 msgstr "ფერის აქტივაცია"
 
-#: gtk/a11y/gtkatspiaction.c:387
+#: gtk/a11y/gtkatspiaction.c:434
 msgctxt "accessibility"
 msgid "Customize"
 msgstr "მორგება"
 
-#: gtk/a11y/gtkatspiaction.c:388
+#: gtk/a11y/gtkatspiaction.c:435
 msgctxt "accessibility"
 msgid "Customizes the color"
 msgstr "ფერის მორგება"
 
-#: gtk/a11y/gtkatspiaction.c:440
+#: gtk/a11y/gtkatspiaction.c:488
 msgctxt "accessibility"
 msgid "Activates the expander"
 msgstr "გაააქტიურებს გამფართოებელს"
 
-#: gtk/a11y/gtkatspiaction.c:496 gtk/a11y/gtkatspiaction.c:604
-#: gtk/a11y/gtkatspiaction.c:691
+#: gtk/a11y/gtkatspiaction.c:544 gtk/a11y/gtkatspiaction.c:652
+#: gtk/a11y/gtkatspiaction.c:739
 msgctxt "accessibility"
 msgid "Activates the entry"
 msgstr "ელემენტის აქტივაცია"
 
-#: gtk/a11y/gtkatspiaction.c:503
+#: gtk/a11y/gtkatspiaction.c:551
 msgctxt "accessibility"
 msgid "Activate primary icon"
 msgstr "ძირითადი ხატულას აქტივაცია"
 
-#: gtk/a11y/gtkatspiaction.c:504
+#: gtk/a11y/gtkatspiaction.c:552
 msgctxt "accessibility"
 msgid "Activates the primary icon of the entry"
 msgstr "ჩანაწერის ძირითადი ხატულას აქტივაცია"
 
-#: gtk/a11y/gtkatspiaction.c:511
+#: gtk/a11y/gtkatspiaction.c:559
 msgctxt "accessibility"
 msgid "Activate secondary icon"
 msgstr "მეორადი ხატულას აქტივაცია"
 
-#: gtk/a11y/gtkatspiaction.c:512
+#: gtk/a11y/gtkatspiaction.c:560
 msgctxt "accessibility"
 msgid "Activates the secondary icon of the entry"
 msgstr "ჩანაწერის მეორადი ხატულას აქტივაცია"
 
-#: gtk/a11y/gtkatspiaction.c:611
+#: gtk/a11y/gtkatspiaction.c:659
 msgctxt "accessibility"
 msgid "Peek"
 msgstr "ჭვრეტა"
 
-#: gtk/a11y/gtkatspiaction.c:612
+#: gtk/a11y/gtkatspiaction.c:660
 msgctxt "accessibility"
 msgid "Shows the contents of the password entry"
 msgstr "პაროლის ჩვენება"
 
-#: gtk/a11y/gtkatspiaction.c:698
+#: gtk/a11y/gtkatspiaction.c:746
 msgctxt "accessibility"
 msgid "Clear"
 msgstr "გაწმენდა"
 
-#: gtk/a11y/gtkatspiaction.c:699
+#: gtk/a11y/gtkatspiaction.c:747
 msgctxt "accessibility"
 msgid "Clears the contents of the entry"
 msgstr "ელემენტის შიგთავსის გასუფთავება"
 
-#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:871
+#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:904
 msgctxt "accessibility"
 msgid "application"
 msgstr "აპლიკაცია"
@@ -1125,7 +1132,7 @@ msgstr "Sans 12"
 msgid "Pick a Font"
 msgstr "აირჩიეთ შრიფტი"
 
-#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3848
+#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3818
 #: gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:284
 msgid "Font"
 msgstr "შრიფტი"
@@ -1167,7 +1174,7 @@ msgstr ""
 "სისტემის წესები ცვლილებებს გიკრძალავთ.\n"
 "დაუკავშირდით თქვენს სისტემურ ადმინისტრატორს"
 
-#: gtk/deprecated/gtkshow.c:217
+#: gtk/deprecated/gtkshow.c:291
 msgid "Could not show link"
 msgstr "ბმულის ჩვენების შეცდომა"
 
@@ -1308,8 +1315,8 @@ msgstr ""
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:839 gtk/deprecated/gtkshortcutlabel.c:101
-#: gtk/deprecated/gtkshortcutlabel.c:137
+#: gtk/gtkaccelgroup.c:839 gtk/deprecated/gtkshortcutlabel.c:103
+#: gtk/deprecated/gtkshortcutlabel.c:139
 msgctxt "keyboard label"
 msgid "Shift"
 msgstr "Shift"
@@ -1319,8 +1326,8 @@ msgstr "Shift"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:858 gtk/deprecated/gtkshortcutlabel.c:104
-#: gtk/deprecated/gtkshortcutlabel.c:139
+#: gtk/gtkaccelgroup.c:858 gtk/deprecated/gtkshortcutlabel.c:106
+#: gtk/deprecated/gtkshortcutlabel.c:141
 msgctxt "keyboard label"
 msgid "Ctrl"
 msgstr "Ctrl"
@@ -1330,8 +1337,8 @@ msgstr "Ctrl"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:877 gtk/deprecated/gtkshortcutlabel.c:107
-#: gtk/deprecated/gtkshortcutlabel.c:141
+#: gtk/gtkaccelgroup.c:877 gtk/deprecated/gtkshortcutlabel.c:109
+#: gtk/deprecated/gtkshortcutlabel.c:143
 msgctxt "keyboard label"
 msgid "Alt"
 msgstr "Alt"
@@ -1341,8 +1348,8 @@ msgstr "Alt"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:895 gtk/deprecated/gtkshortcutlabel.c:113
-#: gtk/deprecated/gtkshortcutlabel.c:143
+#: gtk/gtkaccelgroup.c:895 gtk/deprecated/gtkshortcutlabel.c:115
+#: gtk/deprecated/gtkshortcutlabel.c:145
 msgctxt "keyboard label"
 msgid "Super"
 msgstr "Super"
@@ -1352,8 +1359,8 @@ msgstr "Super"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:909 gtk/deprecated/gtkshortcutlabel.c:116
-#: gtk/deprecated/gtkshortcutlabel.c:145
+#: gtk/gtkaccelgroup.c:909 gtk/deprecated/gtkshortcutlabel.c:118
+#: gtk/deprecated/gtkshortcutlabel.c:147
 msgctxt "keyboard label"
 msgid "Hyper"
 msgstr "Hyper"
@@ -1363,8 +1370,8 @@ msgstr "Hyper"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:924 gtk/deprecated/gtkshortcutlabel.c:110
-#: gtk/deprecated/gtkshortcutlabel.c:148
+#: gtk/gtkaccelgroup.c:924 gtk/deprecated/gtkshortcutlabel.c:112
+#: gtk/deprecated/gtkshortcutlabel.c:150
 msgctxt "keyboard label"
 msgid "Meta"
 msgstr "Meta"
@@ -1383,427 +1390,427 @@ msgctxt "keyboard label"
 msgid "Space"
 msgstr "გამოტოვება"
 
-#: gtk/gtkaccelgroup.c:954 gtk/deprecated/gtkshortcutlabel.c:176
+#: gtk/gtkaccelgroup.c:954 gtk/deprecated/gtkshortcutlabel.c:178
 msgctxt "keyboard label"
 msgid "Backslash"
 msgstr "Backslash"
 
-#: gtk/gtkaccessible.c:792
+#: gtk/gtkaccessible.c:825
 msgctxt "accessibility"
 msgid "alert"
 msgstr "გაფრთხილება"
 
-#: gtk/gtkaccessible.c:793
+#: gtk/gtkaccessible.c:826
 msgctxt "accessibility"
 msgid "alert dialog"
 msgstr "გაფრთხილების ფანჯარა"
 
-#: gtk/gtkaccessible.c:794
+#: gtk/gtkaccessible.c:827
 msgctxt "accessibility"
 msgid "banner"
 msgstr "ბანერი"
 
-#: gtk/gtkaccessible.c:795
+#: gtk/gtkaccessible.c:828
 msgctxt "accessibility"
 msgid "button"
 msgstr "ღილაკი"
 
-#: gtk/gtkaccessible.c:796
+#: gtk/gtkaccessible.c:829
 msgctxt "accessibility"
 msgid "caption"
 msgstr "წარწერა"
 
-#: gtk/gtkaccessible.c:797
+#: gtk/gtkaccessible.c:830
 msgctxt "accessibility"
 msgid "cell"
 msgstr "უჯრედი"
 
-#: gtk/gtkaccessible.c:798
+#: gtk/gtkaccessible.c:831
 msgctxt "accessibility"
 msgid "checkbox"
 msgstr "ჩასართავი"
 
-#: gtk/gtkaccessible.c:799
+#: gtk/gtkaccessible.c:832
 msgctxt "accessibility"
 msgid "column header"
 msgstr "სვეტის თავსართი"
 
-#: gtk/gtkaccessible.c:800
+#: gtk/gtkaccessible.c:833
 msgctxt "accessibility"
 msgid "combo box"
 msgstr "combo box"
 
-#: gtk/gtkaccessible.c:801
+#: gtk/gtkaccessible.c:834
 msgctxt "accessibility"
 msgid "command"
 msgstr "ბრძანება"
 
-#: gtk/gtkaccessible.c:802
+#: gtk/gtkaccessible.c:835
 msgctxt "accessibility"
 msgid "composite"
 msgstr "კომპოზიტი"
 
-#: gtk/gtkaccessible.c:803
+#: gtk/gtkaccessible.c:836
 msgctxt "accessibility"
 msgid "dialog"
 msgstr "ფანჯარა"
 
-#: gtk/gtkaccessible.c:804
+#: gtk/gtkaccessible.c:837
 msgctxt "accessibility"
 msgid "document"
 msgstr "დოკუმენტი"
 
-#: gtk/gtkaccessible.c:805
+#: gtk/gtkaccessible.c:838
 msgctxt "accessibility"
 msgid "feed"
 msgstr "ლენტა"
 
-#: gtk/gtkaccessible.c:806
+#: gtk/gtkaccessible.c:839
 msgctxt "accessibility"
 msgid "form"
 msgstr "ფორმა"
 
-#: gtk/gtkaccessible.c:807
+#: gtk/gtkaccessible.c:840
 msgctxt "accessibility"
 msgid "generic"
 msgstr "ზოგადი"
 
-#: gtk/gtkaccessible.c:808
+#: gtk/gtkaccessible.c:841
 msgctxt "accessibility"
 msgid "grid"
 msgstr "ბადე"
 
-#: gtk/gtkaccessible.c:809
+#: gtk/gtkaccessible.c:842
 msgctxt "accessibility"
 msgid "grid cell"
 msgstr "ბადის უჯრედი"
 
-#: gtk/gtkaccessible.c:810
+#: gtk/gtkaccessible.c:843
 msgctxt "accessibility"
 msgid "group"
 msgstr "ჯგუფი"
 
-#: gtk/gtkaccessible.c:811
+#: gtk/gtkaccessible.c:844
 msgctxt "accessibility"
 msgid "heading"
 msgstr "სათაური"
 
-#: gtk/gtkaccessible.c:812
+#: gtk/gtkaccessible.c:845
 msgctxt "accessibility"
 msgid "image"
 msgstr "გამოსახულება"
 
-#: gtk/gtkaccessible.c:813
+#: gtk/gtkaccessible.c:846
 msgctxt "accessibility"
 msgid "input"
 msgstr "შეტანა"
 
-#: gtk/gtkaccessible.c:814
+#: gtk/gtkaccessible.c:847
 msgctxt "accessibility"
 msgid "label"
 msgstr "ჭდე"
 
-#: gtk/gtkaccessible.c:815
+#: gtk/gtkaccessible.c:848
 msgctxt "accessibility"
 msgid "landmark"
 msgstr "ორიენტირი"
 
-#: gtk/gtkaccessible.c:816
+#: gtk/gtkaccessible.c:849
 msgctxt "accessibility"
 msgid "legend"
 msgstr "შინაარსი"
 
-#: gtk/gtkaccessible.c:817
+#: gtk/gtkaccessible.c:850
 msgctxt "accessibility"
 msgid "link"
 msgstr "ბმული"
 
-#: gtk/gtkaccessible.c:818
+#: gtk/gtkaccessible.c:851
 msgctxt "accessibility"
 msgid "list"
 msgstr "სია"
 
-#: gtk/gtkaccessible.c:819
+#: gtk/gtkaccessible.c:852
 msgctxt "accessibility"
 msgid "list box"
 msgstr "სიის ყუთი"
 
-#: gtk/gtkaccessible.c:820
+#: gtk/gtkaccessible.c:853
 msgctxt "accessibility"
 msgid "list item"
 msgstr "სიის ჩანაწერი"
 
-#: gtk/gtkaccessible.c:821
+#: gtk/gtkaccessible.c:854
 msgctxt "accessibility"
 msgid "log"
 msgstr "ჟურნალი"
 
-#: gtk/gtkaccessible.c:822
+#: gtk/gtkaccessible.c:855
 msgctxt "accessibility"
 msgid "main"
 msgstr "მთავარი"
 
-#: gtk/gtkaccessible.c:823
+#: gtk/gtkaccessible.c:856
 msgctxt "accessibility"
 msgid "marquee"
 msgstr "სეფა"
 
-#: gtk/gtkaccessible.c:824
+#: gtk/gtkaccessible.c:857
 msgctxt "accessibility"
 msgid "math"
 msgstr "მათემატიკა"
 
-#: gtk/gtkaccessible.c:825
+#: gtk/gtkaccessible.c:858
 msgctxt "accessibility"
 msgid "meter"
 msgstr "მთვლელი"
 
-#: gtk/gtkaccessible.c:826
+#: gtk/gtkaccessible.c:859
 msgctxt "accessibility"
 msgid "menu"
 msgstr "მენიუ"
 
-#: gtk/gtkaccessible.c:827
+#: gtk/gtkaccessible.c:860
 msgctxt "accessibility"
 msgid "menu bar"
 msgstr "მენიუს  ზოლი"
 
-#: gtk/gtkaccessible.c:828
+#: gtk/gtkaccessible.c:861
 msgctxt "accessibility"
 msgid "menu item"
 msgstr "მენიუს პუნქტი"
 
-#: gtk/gtkaccessible.c:829
+#: gtk/gtkaccessible.c:862
 msgctxt "accessibility"
 msgid "menu item checkbox"
 msgstr "მენიუს ჩასართავი პუნქტი"
 
-#: gtk/gtkaccessible.c:830
+#: gtk/gtkaccessible.c:863
 msgctxt "accessibility"
 msgid "menu item radio"
 msgstr "მენიუს გადასართავი პუნქტი"
 
-#: gtk/gtkaccessible.c:831
+#: gtk/gtkaccessible.c:864
 msgctxt "accessibility"
 msgid "navigation"
 msgstr "ნავიგაცია"
 
-#: gtk/gtkaccessible.c:832
+#: gtk/gtkaccessible.c:865
 msgctxt "accessibility"
 msgid "none"
 msgstr "არა"
 
-#: gtk/gtkaccessible.c:833
+#: gtk/gtkaccessible.c:866
 msgctxt "accessibility"
 msgid "note"
 msgstr "შენიშვნა"
 
-#: gtk/gtkaccessible.c:834
+#: gtk/gtkaccessible.c:867
 msgctxt "accessibility"
 msgid "option"
 msgstr "მორგება"
 
-#: gtk/gtkaccessible.c:835
+#: gtk/gtkaccessible.c:868
 msgctxt "accessibility"
 msgid "presentation"
 msgstr "პრეზენტაცია"
 
-#: gtk/gtkaccessible.c:836
+#: gtk/gtkaccessible.c:869
 msgctxt "accessibility"
 msgid "progress bar"
 msgstr "მიმდინარეობა"
 
-#: gtk/gtkaccessible.c:837
+#: gtk/gtkaccessible.c:870
 msgctxt "accessibility"
 msgid "radio"
 msgstr "რადიო"
 
-#: gtk/gtkaccessible.c:838
+#: gtk/gtkaccessible.c:871
 msgctxt "accessibility"
 msgid "radio group"
 msgstr "რადიოების ჯგუფი"
 
-#: gtk/gtkaccessible.c:839
+#: gtk/gtkaccessible.c:872
 msgctxt "accessibility"
 msgid "range"
 msgstr "დიაპაზონი"
 
-#: gtk/gtkaccessible.c:840
+#: gtk/gtkaccessible.c:873
 msgctxt "accessibility"
 msgid "region"
 msgstr "რეგიონი"
 
-#: gtk/gtkaccessible.c:841
+#: gtk/gtkaccessible.c:874
 msgctxt "accessibility"
 msgid "row"
 msgstr "მწკრივი"
 
-#: gtk/gtkaccessible.c:842
+#: gtk/gtkaccessible.c:875
 msgctxt "accessibility"
 msgid "row group"
 msgstr "მწკრივების ჯგუფი"
 
-#: gtk/gtkaccessible.c:843
+#: gtk/gtkaccessible.c:876
 msgctxt "accessibility"
 msgid "row header"
 msgstr "მწკრივის თავსართი"
 
-#: gtk/gtkaccessible.c:844
+#: gtk/gtkaccessible.c:877
 msgctxt "accessibility"
 msgid "scroll bar"
 msgstr "ჩოჩიას ზოლი"
 
-#: gtk/gtkaccessible.c:845
+#: gtk/gtkaccessible.c:878
 msgctxt "accessibility"
 msgid "search"
 msgstr "ძებნა"
 
-#: gtk/gtkaccessible.c:846
+#: gtk/gtkaccessible.c:879
 msgctxt "accessibility"
 msgid "search box"
 msgstr "ძებნის ზოლი"
 
-#: gtk/gtkaccessible.c:847
+#: gtk/gtkaccessible.c:880
 msgctxt "accessibility"
 msgid "section"
 msgstr "სექცია"
 
-#: gtk/gtkaccessible.c:848
+#: gtk/gtkaccessible.c:881
 msgctxt "accessibility"
 msgid "section head"
 msgstr "სექციის თავსართი"
 
-#: gtk/gtkaccessible.c:849
+#: gtk/gtkaccessible.c:882
 msgctxt "accessibility"
 msgid "select"
 msgstr "არჩევა"
 
-#: gtk/gtkaccessible.c:850
+#: gtk/gtkaccessible.c:883
 msgctxt "accessibility"
 msgid "separator"
 msgstr "გამყოფი"
 
-#: gtk/gtkaccessible.c:851
+#: gtk/gtkaccessible.c:884
 msgctxt "accessibility"
 msgid "slider"
 msgstr "ცოცია"
 
-#: gtk/gtkaccessible.c:852
+#: gtk/gtkaccessible.c:885
 msgctxt "accessibility"
 msgid "spin button"
 msgstr "ასარჩევი ზოლი"
 
-#: gtk/gtkaccessible.c:853
+#: gtk/gtkaccessible.c:886
 msgctxt "accessibility"
 msgid "status"
 msgstr "სტატუსი"
 
-#: gtk/gtkaccessible.c:854
+#: gtk/gtkaccessible.c:887
 msgctxt "accessibility"
 msgid "structure"
 msgstr "სტრუქტურა"
 
-#: gtk/gtkaccessible.c:855
+#: gtk/gtkaccessible.c:888
 msgctxt "accessibility"
 msgid "switch"
 msgstr "გადართვა"
 
-#: gtk/gtkaccessible.c:856
+#: gtk/gtkaccessible.c:889
 msgctxt "accessibility"
 msgid "tab"
 msgstr "ჩანართი"
 
-#: gtk/gtkaccessible.c:857
+#: gtk/gtkaccessible.c:890
 msgctxt "accessibility"
 msgid "table"
 msgstr "ცხრილი"
 
-#: gtk/gtkaccessible.c:858
+#: gtk/gtkaccessible.c:891
 msgctxt "accessibility"
 msgid "tab list"
 msgstr "ჩანართების სია"
 
-#: gtk/gtkaccessible.c:859
+#: gtk/gtkaccessible.c:892
 msgctxt "accessibility"
 msgid "tab panel"
 msgstr "ჩანართების პანელი"
 
-#: gtk/gtkaccessible.c:860
+#: gtk/gtkaccessible.c:893
 msgctxt "accessibility"
 msgid "text box"
 msgstr "ტექსტის ადგილი"
 
-#: gtk/gtkaccessible.c:861
+#: gtk/gtkaccessible.c:894
 msgctxt "accessibility"
 msgid "time"
 msgstr "დრო"
 
-#: gtk/gtkaccessible.c:862
+#: gtk/gtkaccessible.c:895
 msgctxt "accessibility"
 msgid "timer"
 msgstr "წამმზომი"
 
-#: gtk/gtkaccessible.c:863
+#: gtk/gtkaccessible.c:896
 msgctxt "accessibility"
 msgid "tool bar"
 msgstr "ხელსაწყოს ზოლი"
 
-#: gtk/gtkaccessible.c:864
+#: gtk/gtkaccessible.c:897
 msgctxt "accessibility"
 msgid "tool tip"
 msgstr "მინიშნება"
 
-#: gtk/gtkaccessible.c:865
+#: gtk/gtkaccessible.c:898
 msgctxt "accessibility"
 msgid "tree"
 msgstr "ხე"
 
-#: gtk/gtkaccessible.c:866
+#: gtk/gtkaccessible.c:899
 msgctxt "accessibility"
 msgid "tree grid"
 msgstr "ხის ბადე"
 
-#: gtk/gtkaccessible.c:867
+#: gtk/gtkaccessible.c:900
 msgctxt "accessibility"
 msgid "tree item"
 msgstr "ხის ელემენტი"
 
-#: gtk/gtkaccessible.c:868
+#: gtk/gtkaccessible.c:901
 msgctxt "accessibility"
 msgid "widget"
 msgstr "ვიჯეტი"
 
-#: gtk/gtkaccessible.c:869
+#: gtk/gtkaccessible.c:902
 msgctxt "accessibility"
 msgid "window"
 msgstr "ფანჯარა"
 
-#: gtk/gtkaccessible.c:870
+#: gtk/gtkaccessible.c:903
 msgctxt "accessibility"
 msgid "toggle button"
 msgstr "გადამრთველი"
 
-#: gtk/gtkaccessible.c:872
+#: gtk/gtkaccessible.c:905
 msgctxt "accessibility"
 msgid "paragraph"
 msgstr "პარაგრაფი"
 
-#: gtk/gtkaccessible.c:873
+#: gtk/gtkaccessible.c:906
 msgctxt "accessibility"
 msgid "block quote"
 msgstr "ბრჭყალის ბლოკი"
 
-#: gtk/gtkaccessible.c:874
+#: gtk/gtkaccessible.c:907
 msgctxt "accessibility"
 msgid "article"
 msgstr "სტატია"
 
-#: gtk/gtkaccessible.c:875
+#: gtk/gtkaccessible.c:908
 msgctxt "accessibility"
 msgid "comment"
 msgstr "კომენტარი"
 
-#: gtk/gtkaccessible.c:876
+#: gtk/gtkaccessible.c:909
 msgctxt "accessibility"
 msgid "terminal"
 msgstr "ტერმინალი"
@@ -2227,7 +2234,7 @@ msgstr "მარჯვენა:"
 msgid "Paper Margins"
 msgstr "გვერდის ველები"
 
-#: gtk/gtkentry.c:3688
+#: gtk/gtkentry.c:3684
 msgid "Insert Emoji"
 msgstr "ემოჯის ჩასმა"
 
@@ -2295,38 +2302,33 @@ msgstr "საქაღალდე ამ სახელით უკვე 
 msgid "A file with that name already exists"
 msgstr "ფაილი ამ სახელით უკვე არსებობს"
 
-#: gtk/gtkfilechoosernative.c:520 gtk/gtkfilechoosernative.c:593
-#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:5018
+#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:4988
 #: gtk/gtkfiledialog.c:911 gtk/gtkmessagedialog.c:170
 #: gtk/gtkmessagedialog.c:179 gtk/gtkmountoperation.c:608
 #: gtk/print/gtkpagesetupunixdialog.c:282 gtk/print/gtkprintbackend.c:638
 #: gtk/print/gtkprintunixdialog.c:680 gtk/print/gtkprintunixdialog.c:837
-#: gtk/gtkwindow.c:6295 gtk/ui/gtkappchooserdialog.ui:48
+#: gtk/gtkwindow.c:6321 gtk/ui/gtkappchooserdialog.ui:48
 #: gtk/ui/gtkassistant.ui:52 gtk/ui/gtkcolorchooserdialog.ui:36
 #: gtk/ui/gtkfontchooserdialog.ui:29
 msgid "_Cancel"
 msgstr "გაუქმება"
 
-#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:587
+#: gtk/gtkfilechoosernative.c:522 gtk/gtkfilechoosernative.c:588
 #: gtk/gtkfiledialog.c:883 gtk/gtkplacessidebar.c:3149
 #: gtk/gtkplacessidebar.c:3234 gtk/gtkplacesview.c:1646
 msgid "_Open"
 msgstr "გახსნა"
 
-#: gtk/gtkfilechoosernative.c:587 gtk/gtkfiledialog.c:888
+#: gtk/gtkfilechoosernative.c:588 gtk/gtkfiledialog.c:888
 msgid "_Save"
 msgstr "შენახვა"
 
-#: gtk/gtkfilechoosernativeportal.c:501
+#: gtk/gtkfilechoosernativeportal.c:499
 #, c-format
 msgid "The session bus is not available"
 msgstr "სესიების მატარებელი ხელმისაწვდომი არაა"
 
-#: gtk/gtkfilechoosernativeportal.c:520
-#, c-format
-msgid "The create-folder action is not supported with portals"
-msgstr "ქმედება create-folder პორტალებთან მხარდაჭერილი არაა"
-
 #: gtk/gtkfilechoosernativequartz.c:348 gtk/ui/gtkfilechooserwidget.ui:299
 msgid "Select which types of files are shown"
 msgstr "ფაილის ტიპების შერჩევა საჩვენებლად"
@@ -2399,7 +2401,7 @@ msgid "If you delete an item, it will be permanently lost."
 msgstr "თუ წაშლით ელემენტს, ის სამუდამოდ დაიკარგება."
 
 #: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:1816
-#: gtk/gtklabel.c:5912 gtk/gtktext.c:6331 gtk/gtktextview.c:9328
+#: gtk/gtklabel.c:5897 gtk/gtktext.c:6330 gtk/gtktextview.c:9327
 msgid "_Delete"
 msgstr "_წაშლა"
 
@@ -2453,7 +2455,7 @@ msgid "Sort _Folders Before Files"
 msgstr "საქაღალდეების ფაილებამდე ჩვენება"
 
 #: gtk/gtkfilechooserwidget.c:1956 gtk/gtkfilechooserwidget.c:1986
-#: gtk/gtkfilechooserwidget.c:3891
+#: gtk/gtkfilechooserwidget.c:3861
 msgid "Unknown"
 msgstr "უცნობი"
 
@@ -2462,7 +2464,7 @@ msgid "Home"
 msgstr "სახლი"
 
 #. this is the header for the location column in the print dialog
-#: gtk/gtkfilechooserwidget.c:2196 gtk/gtkfilechooserwidget.c:7450
+#: gtk/gtkfilechooserwidget.c:2196 gtk/gtkfilechooserwidget.c:7420
 #: gtk/inspector/css-node-tree.ui:76 gtk/print/ui/gtkprintunixdialog.ui:111
 msgid "Location"
 msgstr "მდებარეობა"
@@ -2485,8 +2487,8 @@ msgstr "ძებნა"
 msgid "Enter location or URL"
 msgstr "შეიყვანეთ მდებარეობა ან URL-ი"
 
-#: gtk/gtkfilechooserwidget.c:3445 gtk/gtkfilechooserwidget.c:5805
-#: gtk/gtkfilechooserwidget.c:7472
+#: gtk/gtkfilechooserwidget.c:3445 gtk/gtkfilechooserwidget.c:5775
+#: gtk/gtkfilechooserwidget.c:7442
 msgid "Modified"
 msgstr "შეიცვალა"
 
@@ -2500,128 +2502,128 @@ msgid "Could not read the contents of the folder"
 msgstr "საქაღალდის შემცველობის წაკითხვის შეცდომა"
 
 #. Translators: see g_date_time_format() for details on the format
-#: gtk/gtkfilechooserwidget.c:3785 gtk/gtkfilechooserwidget.c:3829
+#: gtk/gtkfilechooserwidget.c:3757 gtk/gtkfilechooserwidget.c:3800
 msgid "%H:%M"
 msgstr "%H:%M"
 
-#: gtk/gtkfilechooserwidget.c:3787 gtk/gtkfilechooserwidget.c:3831
+#: gtk/gtkfilechooserwidget.c:3759 gtk/gtkfilechooserwidget.c:3802
 msgid "%l:%M %p"
 msgstr "%l:%M %p"
 
-#: gtk/gtkfilechooserwidget.c:3791
+#: gtk/gtkfilechooserwidget.c:3763
 msgid "Yesterday"
 msgstr "გუშინ"
 
-#: gtk/gtkfilechooserwidget.c:3800
+#: gtk/gtkfilechooserwidget.c:3772
 #, no-c-format
 msgid "%-e %b"
 msgstr "%-e %b"
 
-#: gtk/gtkfilechooserwidget.c:3804
+#: gtk/gtkfilechooserwidget.c:3776
 msgid "%-e %b %Y"
 msgstr "%-e %b %Y"
 
-#: gtk/gtkfilechooserwidget.c:3846 gtk/gtkfilechooserwidget.c:3854
+#: gtk/gtkfilechooserwidget.c:3816 gtk/gtkfilechooserwidget.c:3824
 msgid "Program"
 msgstr "პროგრამა"
 
-#: gtk/gtkfilechooserwidget.c:3847
+#: gtk/gtkfilechooserwidget.c:3817
 msgid "Audio"
 msgstr "აუდიო"
 
-#: gtk/gtkfilechooserwidget.c:3849 gtk/gtkfilefilter.c:1022
+#: gtk/gtkfilechooserwidget.c:3819 gtk/gtkfilefilter.c:1069
 msgid "Image"
 msgstr "გამოსახულება"
 
-#: gtk/gtkfilechooserwidget.c:3850
+#: gtk/gtkfilechooserwidget.c:3820
 msgid "Archive"
 msgstr "არქივი"
 
-#: gtk/gtkfilechooserwidget.c:3851
+#: gtk/gtkfilechooserwidget.c:3821
 msgid "Markup"
 msgstr "მარქაფი"
 
-#: gtk/gtkfilechooserwidget.c:3852 gtk/gtkfilechooserwidget.c:3853
+#: gtk/gtkfilechooserwidget.c:3822 gtk/gtkfilechooserwidget.c:3823
 msgid "Text"
 msgstr "ტექსტი"
 
-#: gtk/gtkfilechooserwidget.c:3855
+#: gtk/gtkfilechooserwidget.c:3825
 msgid "Video"
 msgstr "ვიდეო"
 
-#: gtk/gtkfilechooserwidget.c:3856
+#: gtk/gtkfilechooserwidget.c:3826
 msgid "Contacts"
 msgstr "კონტაქტები"
 
-#: gtk/gtkfilechooserwidget.c:3857
+#: gtk/gtkfilechooserwidget.c:3827
 msgid "Calendar"
 msgstr "კალენდარი"
 
-#: gtk/gtkfilechooserwidget.c:3858
+#: gtk/gtkfilechooserwidget.c:3828
 msgid "Document"
 msgstr "დოკუმენტი"
 
-#: gtk/gtkfilechooserwidget.c:3859
+#: gtk/gtkfilechooserwidget.c:3829
 msgid "Presentation"
 msgstr "პრეზენტაცია"
 
-#: gtk/gtkfilechooserwidget.c:3860
+#: gtk/gtkfilechooserwidget.c:3830
 msgid "Spreadsheet"
 msgstr "ელცხრილი"
 
-#: gtk/gtkfilechooserwidget.c:5010 gtk/print/gtkprintunixdialog.c:671
+#: gtk/gtkfilechooserwidget.c:4980 gtk/print/gtkprintunixdialog.c:671
 #, c-format
 msgid "A file named “%s” already exists.  Do you want to replace it?"
 msgstr "ფაილი %s უკვე არსებობს. გნებავთ გადავაწერო?"
 
-#: gtk/gtkfilechooserwidget.c:5012 gtk/print/gtkprintunixdialog.c:675
+#: gtk/gtkfilechooserwidget.c:4982 gtk/print/gtkprintunixdialog.c:675
 #, c-format
 msgid ""
 "The file already exists in “%s”.  Replacing it will overwrite its contents."
 msgstr ""
 "ფაილი \"%s\"-ში უკვე არსებობს.  მისი ჩანაცვლება არსებულ შემცველობას წაშლის."
 
-#: gtk/gtkfilechooserwidget.c:5018 gtk/print/gtkprintunixdialog.c:683
+#: gtk/gtkfilechooserwidget.c:4988 gtk/print/gtkprintunixdialog.c:683
 msgid "_Replace"
 msgstr "_შეცვლა"
 
-#: gtk/gtkfilechooserwidget.c:5173
+#: gtk/gtkfilechooserwidget.c:5143
 msgid "You do not have access to the specified folder."
 msgstr "თქვენ არ გაქვთ წვდომა მითითებულ საქაღალდესთან."
 
-#: gtk/gtkfilechooserwidget.c:5752
+#: gtk/gtkfilechooserwidget.c:5722
 msgid "Could not send the search request"
 msgstr "შეუძლებელია ძიების მოთხოვნის გაგზავნა"
 
-#: gtk/gtkfilechooserwidget.c:6033
+#: gtk/gtkfilechooserwidget.c:6003
 msgid "Accessed"
 msgstr "ბოლო წვდომა"
 
-#: gtk/gtkfilechooserwidget.c:7428
+#: gtk/gtkfilechooserwidget.c:7398
 msgid "_Size"
 msgstr "_ზომა"
 
-#: gtk/gtkfilechooserwidget.c:7432
+#: gtk/gtkfilechooserwidget.c:7402
 msgid "T_ype"
 msgstr "ტი_პი"
 
-#: gtk/gtkfilechooserwidget.c:7436
+#: gtk/gtkfilechooserwidget.c:7406
 msgid "_Time"
 msgstr "_დრო"
 
-#: gtk/gtkfilechooserwidget.c:7442 gtk/gtkplacessidebar.c:2306
+#: gtk/gtkfilechooserwidget.c:7412 gtk/gtkplacessidebar.c:2306
 #: gtk/inspector/a11y.ui:43 gtk/inspector/actions.ui:18
 #: gtk/inspector/css-node-tree.ui:22 gtk/inspector/prop-list.ui:24
 #: gtk/ui/gtkfilechooserwidget.ui:394 gtk/print/ui/gtkprintunixdialog.ui:80
 msgid "Name"
 msgstr "სახელი"
 
-#: gtk/gtkfilechooserwidget.c:7459 gtk/inspector/resource-list.ui:82
+#: gtk/gtkfilechooserwidget.c:7429 gtk/inspector/resource-list.ui:82
 #: gtk/ui/gtkfontchooserwidget.ui:216 gtk/ui/gtkfontchooserwidget.ui:382
 msgid "Size"
 msgstr "ზომა"
 
-#: gtk/gtkfilechooserwidget.c:7465 gtk/inspector/misc-info.ui:57
+#: gtk/gtkfilechooserwidget.c:7435 gtk/inspector/misc-info.ui:57
 #: gtk/inspector/prop-list.ui:35 gtk/inspector/statistics.ui:36
 msgid "Type"
 msgstr "ტიპი"
@@ -2651,15 +2653,15 @@ msgstr "მონიშნეთ საქაღალდეები"
 msgid "Select a Folder"
 msgstr "აირჩიეთ საქაღალდე"
 
-#: gtk/gtkfiledialog.c:1385 gtk/gtkfiledialog.c:1499
+#: gtk/gtkfiledialog.c:1395 gtk/gtkfiledialog.c:1512 gtk/gtkfiledialog.c:1621
 msgid "Encoding"
 msgstr "კოდირება"
 
-#: gtk/gtkfiledialog.c:1510
+#: gtk/gtkfiledialog.c:1632
 msgid "Line Ending"
 msgstr "ხაზის ბოლო"
 
-#: gtk/gtkfilefilter.c:1035
+#: gtk/gtkfilefilter.c:1082
 msgid "Unspecified"
 msgstr "მიუთითებელი"
 
@@ -2751,31 +2753,31 @@ msgstr "დახურვა"
 msgid "Close the infobar"
 msgstr "საინფორმაციო ზოლის დახურვა"
 
-#: gtk/gtklabel.c:5909 gtk/gtktext.c:6319 gtk/gtktextview.c:9316
+#: gtk/gtklabel.c:5894 gtk/gtktext.c:6318 gtk/gtktextview.c:9315
 msgid "Cu_t"
 msgstr "ამოჭრა"
 
-#: gtk/gtklabel.c:5910 gtk/gtktext.c:6323 gtk/gtktextview.c:9320
+#: gtk/gtklabel.c:5895 gtk/gtktext.c:6322 gtk/gtktextview.c:9319
 msgid "_Copy"
 msgstr "_კოპირება"
 
-#: gtk/gtklabel.c:5911 gtk/gtktext.c:6327 gtk/gtktextview.c:9324
+#: gtk/gtklabel.c:5896 gtk/gtktext.c:6326 gtk/gtktextview.c:9323
 msgid "_Paste"
 msgstr "ჩ_ასმა"
 
-#: gtk/gtklabel.c:5917 gtk/gtktext.c:6340 gtk/gtktextview.c:9349
+#: gtk/gtklabel.c:5902 gtk/gtktext.c:6339 gtk/gtktextview.c:9348
 msgid "Select _All"
 msgstr "ყველაფრის _მონიშვნა"
 
-#: gtk/gtklabel.c:5922
+#: gtk/gtklabel.c:5907
 msgid "_Open Link"
 msgstr "_ბმულის გახსნა"
 
-#: gtk/gtklabel.c:5926
+#: gtk/gtklabel.c:5911
 msgid "Copy _Link Address"
 msgstr "დაა_კოპირე ბმულის მისამართი"
 
-#: gtk/gtklabel.c:5970 gtk/gtktext.c:2878 gtk/gtktextview.c:9398
+#: gtk/gtklabel.c:5955 gtk/gtktext.c:2877 gtk/gtktextview.c:9397
 msgid "Context menu"
 msgstr "კონტექსტური მენიუ"
 
@@ -2846,7 +2848,7 @@ msgid "Play"
 msgstr "დაკვრა"
 
 #: gtk/gtkmessagedialog.c:162 gtk/gtkmessagedialog.c:180
-#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6296
+#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6322
 msgid "_OK"
 msgstr "_დიახ"
 
@@ -2939,27 +2941,27 @@ msgid "Cannot kill process with PID %d. Operation is not implemented."
 msgstr "პროცესის, PID-ით %d მოკვლა შეუძლებელია. ოპერაცია განხორციელებული არაა."
 
 #. translators: this string is a name for the 'less' command
-#: gtk/gtkmountoperation-x11.c:986
+#: gtk/gtkmountoperation-x11.c:988
 msgid "Terminal Pager"
 msgstr "ტერმინალის პეიჯერი"
 
-#: gtk/gtkmountoperation-x11.c:987
+#: gtk/gtkmountoperation-x11.c:989
 msgid "Top Command"
 msgstr "ზედა ბრძანება"
 
-#: gtk/gtkmountoperation-x11.c:988
+#: gtk/gtkmountoperation-x11.c:990
 msgid "Bourne Again Shell"
 msgstr "Bourne Again Shell"
 
-#: gtk/gtkmountoperation-x11.c:989
+#: gtk/gtkmountoperation-x11.c:991
 msgid "Bourne Shell"
 msgstr "Bourne Shell"
 
-#: gtk/gtkmountoperation-x11.c:990
+#: gtk/gtkmountoperation-x11.c:992
 msgid "Z Shell"
 msgstr "Z Shell"
 
-#: gtk/gtkmountoperation-x11.c:1090
+#: gtk/gtkmountoperation-x11.c:1092
 #, c-format
 msgid "Cannot end process with PID %d: %s"
 msgstr "პროცესის, PID-ით %d, დასრულების შეცდომა: %s"
@@ -3028,7 +3030,7 @@ msgstr "გვერდის პარამეტრები"
 msgid "Hide Text"
 msgstr "ტექსტის დამალვა"
 
-#: gtk/gtkpasswordentry.c:173 gtk/gtkpasswordentry.c:624
+#: gtk/gtkpasswordentry.c:173 gtk/gtkpasswordentry.c:620
 msgid "Show Text"
 msgstr "ტექსტის ჩვენება"
 
@@ -3036,7 +3038,7 @@ msgstr "ტექსტის ჩვენება"
 msgid "Caps Lock is on"
 msgstr "CapsLock ჩართულია"
 
-#: gtk/gtkpasswordentry.c:700
+#: gtk/gtkpasswordentry.c:696
 msgid "_Show Text"
 msgstr "ტექსტის ჩვენება"
 
@@ -3636,7 +3638,7 @@ msgstr "ჩანაწერის გასუფთავება"
 #. * this string very short, ideally just a single character, since it will
 #. * be rendered as part of the key.
 #.
-#: gtk/deprecated/gtkshortcutlabel.c:79
+#: gtk/deprecated/gtkshortcutlabel.c:81
 msgctxt "keyboard side marker"
 msgid "L"
 msgstr "მარცხ"
@@ -3646,70 +3648,70 @@ msgstr "მარცხ"
 #. * this string very short, ideally just a single character, since it will
 #. * be rendered as part of the key.
 #.
-#: gtk/deprecated/gtkshortcutlabel.c:92
+#: gtk/deprecated/gtkshortcutlabel.c:94
 msgctxt "keyboard side marker"
 msgid "R"
 msgstr "მარჯ"
 
-#: gtk/deprecated/gtkshortcutssection.c:437
+#: gtk/deprecated/gtkshortcutssection.c:449
 msgid "_Show All"
 msgstr "_ყველას ჩვენება"
 
-#: gtk/deprecated/gtkshortcutsshortcut.c:145
+#: gtk/deprecated/gtkshortcutsshortcut.c:147
 msgid "Two finger pinch"
 msgstr "ორი თითის გასმა"
 
-#: gtk/deprecated/gtkshortcutsshortcut.c:149
+#: gtk/deprecated/gtkshortcutsshortcut.c:151
 msgid "Two finger stretch"
 msgstr "ორი თითის გაფარჩხვა"
 
-#: gtk/deprecated/gtkshortcutsshortcut.c:153
+#: gtk/deprecated/gtkshortcutsshortcut.c:155
 msgid "Rotate clockwise"
 msgstr "საათის ისრის მიმართულებით შემობრუნება"
 
-#: gtk/deprecated/gtkshortcutsshortcut.c:157
+#: gtk/deprecated/gtkshortcutsshortcut.c:159
 msgid "Rotate counterclockwise"
 msgstr "საათის ისრის საწინააღმდეგო მიმართულებით შემობრუნება"
 
-#: gtk/deprecated/gtkshortcutsshortcut.c:161
+#: gtk/deprecated/gtkshortcutsshortcut.c:163
 msgid "Two finger swipe left"
 msgstr "ორი თითის გასმა მარცხნივ"
 
-#: gtk/deprecated/gtkshortcutsshortcut.c:165
+#: gtk/deprecated/gtkshortcutsshortcut.c:167
 msgid "Two finger swipe right"
 msgstr "ორი თითის გასმა მარჯვნივ"
 
-#: gtk/deprecated/gtkshortcutsshortcut.c:169
+#: gtk/deprecated/gtkshortcutsshortcut.c:171
 msgid "Swipe left"
 msgstr "გაუსვით მარცხნივ"
 
-#: gtk/deprecated/gtkshortcutsshortcut.c:173
+#: gtk/deprecated/gtkshortcutsshortcut.c:175
 msgid "Swipe right"
 msgstr "გაუსვით მარჯვნივ"
 
 #. Translators: This is placeholder text for the search entry in the shortcuts window
-#: gtk/deprecated/gtkshortcutswindow.c:898
-#: gtk/deprecated/gtkshortcutswindow.c:965
-#: gtk/deprecated/gtkshortcutswindow.c:971
+#: gtk/deprecated/gtkshortcutswindow.c:903
+#: gtk/deprecated/gtkshortcutswindow.c:970
+#: gtk/deprecated/gtkshortcutswindow.c:976
 msgid "Search Shortcuts"
 msgstr "ძებნის მალსახმობები"
 
 #. Translators: This is the window title for the shortcuts window in normal mode
-#: gtk/deprecated/gtkshortcutswindow.c:930 gtk/inspector/window.ui:496
+#: gtk/deprecated/gtkshortcutswindow.c:935 gtk/inspector/window.ui:496
 msgid "Shortcuts"
 msgstr "მალსახმობები"
 
 #. Translators: This is the window title for the shortcuts window in search mode
-#: gtk/deprecated/gtkshortcutswindow.c:935
+#: gtk/deprecated/gtkshortcutswindow.c:940
 msgid "Search Results"
 msgstr "ძებნს შედეგები"
 
-#: gtk/deprecated/gtkshortcutswindow.c:1033 gtk/ui/gtkemojichooser.ui:352
+#: gtk/deprecated/gtkshortcutswindow.c:1038 gtk/ui/gtkemojichooser.ui:352
 #: gtk/ui/gtkfilechooserwidget.ui:253
 msgid "No Results Found"
 msgstr "შედეგების გარეშე"
 
-#: gtk/deprecated/gtkshortcutswindow.c:1044 gtk/ui/gtkemojichooser.ui:362
+#: gtk/deprecated/gtkshortcutswindow.c:1049 gtk/ui/gtkemojichooser.ui:362
 #: gtk/ui/gtkfilechooserwidget.ui:263 gtk/ui/gtkplacesview.ui:207
 msgid "Try a different search"
 msgstr "სცადეთ სხვა ძებნა"
@@ -3719,11 +3721,11 @@ msgctxt "accessibility"
 msgid "Sidebar"
 msgstr "გვერდითა ზოლი"
 
-#: gtk/gtktext.c:6345
+#: gtk/gtktext.c:6344
 msgid "Change di_rection"
 msgstr "მიმა_რთულების შეცვლა"
 
-#: gtk/gtktext.c:6350 gtk/gtktextview.c:9354
+#: gtk/gtktext.c:6349 gtk/gtktextview.c:9353
 msgid "Insert _Emoji"
 msgstr "ემოჯის _ჩასმა"
 
@@ -3863,42 +3865,40 @@ msgctxt "Encoding name"
 msgid "Vietnamese"
 msgstr "ვიეტნამური"
 
-#: gtk/gtktextencoding.c:162
+#: gtk/gtktextencoding.c:163
 msgctxt "Line ending name"
 msgid "Unchanged"
 msgstr "შეუცვლელი"
 
-#: gtk/gtktextencoding.c:163
+#: gtk/gtktextencoding.c:164
 msgctxt "Line ending name"
 msgid "Unix/Linux"
 msgstr "Unix/Linux"
 
-#: gtk/gtktextencoding.c:164
-#| msgctxt "accessibility"
-#| msgid "window"
+#: gtk/gtktextencoding.c:165
 msgctxt "Line ending name"
 msgid "Windows"
 msgstr "Windows"
 
-#: gtk/gtktextencoding.c:165
+#: gtk/gtktextencoding.c:166
 msgctxt "Line ending name"
 msgid "Mac OS Classic"
 msgstr "Mac OS Classic"
 
-#: gtk/gtktextview.c:9336
+#: gtk/gtktextview.c:9335
 msgid "_Undo"
 msgstr "_დაბრუნება"
 
-#: gtk/gtktextview.c:9340
+#: gtk/gtktextview.c:9339
 msgid "_Redo"
 msgstr "_გამეორება"
 
-#: gtk/gtkwindow.c:6284
+#: gtk/gtkwindow.c:6310
 #, c-format
 msgid "Do you want to use GTK Inspector?"
 msgstr "გნებავთ GTK-ის ინსპექტორის გამოყენება?"
 
-#: gtk/gtkwindow.c:6286
+#: gtk/gtkwindow.c:6312
 #, c-format
 msgid ""
 "GTK Inspector is an interactive debugger that lets you explore and modify "
@@ -3909,7 +3909,7 @@ msgstr ""
 "ნებისმიერი GTK აპლიკაციის შიდა პარამეტრები დაათვალიეროთ და შეცვალოთ. მისი "
 "გამოყენებით ასევე შეიძლება პროგრამა ავარიულად დასრულდეს."
 
-#: gtk/gtkwindow.c:6291
+#: gtk/gtkwindow.c:6317
 msgid "Don’t show this message again"
 msgstr "მეტჯერ აღარ მაჩვენო ეს გაფრთხილება"
 
@@ -4095,17 +4095,17 @@ msgstr "CSS-ის თვისება"
 msgid "IM Context is hardcoded by GTK_IM_MODULE"
 msgstr "IM-ის კონტექსტი GTK_IM_MODULE-ში ხელითაა ჩაწერილი"
 
-#: gtk/inspector/general.c:575
+#: gtk/inspector/general.c:577
 msgctxt "GL renderer"
 msgid "None"
 msgstr "არცერთი"
 
-#: gtk/inspector/general.c:664
+#: gtk/inspector/general.c:674
 msgctxt "GL version"
 msgid "Unknown"
 msgstr "უცნობი"
 
-#: gtk/inspector/general.c:910 gtk/inspector/general.c:949
+#: gtk/inspector/general.c:928 gtk/inspector/general.c:967
 msgctxt "Vulkan device"
 msgid "None"
 msgstr "არცერთი"
@@ -7503,7 +7503,7 @@ msgstr ""
 
 #: tools/gtk-builder-tool-enumerate.c:56 tools/gtk-builder-tool-preview.c:179
 #: tools/gtk-builder-tool-preview.c:180 tools/gtk-builder-tool-screenshot.c:360
-#: tools/gtk-builder-tool-simplify.c:2658 tools/gtk-builder-tool-validate.c:267
+#: tools/gtk-builder-tool-simplify.c:2709 tools/gtk-builder-tool-validate.c:267
 #: tools/gtk-image-tool-compare.c:43 tools/gtk-image-tool-info.c:79
 #: tools/gtk-path-tool-render.c:121 tools/gtk-rendernode-tool-compare.c:67
 #: tools/gtk-rendernode-tool-extract.c:294 tools/gtk-rendernode-tool-info.c:226
@@ -7551,7 +7551,7 @@ msgid "Preview the file."
 msgstr "ფაილის გადახედვა."
 
 #: tools/gtk-builder-tool-preview.c:208 tools/gtk-builder-tool-screenshot.c:391
-#: tools/gtk-builder-tool-simplify.c:2681 tools/gtk-builder-tool-validate.c:293
+#: tools/gtk-builder-tool-simplify.c:2733 tools/gtk-builder-tool-validate.c:293
 #, c-format
 msgid "No .ui file specified\n"
 msgstr ".ui ფაილი მითითებული არაა\n"
@@ -7625,76 +7625,81 @@ msgstr ".ui ფაილის რენდერი გამოსახულ
 msgid "Can only render a single .ui file to a single output file\n"
 msgstr "ერთი .ui ფაილის მხოლოდ ერთ გამოტანის ფაილში რენდერი შეგიძლიათ\n"
 
-#: tools/gtk-builder-tool-simplify.c:444
+#: tools/gtk-builder-tool-simplify.c:447
 #, c-format
 msgid "%s:%d: Couldn’t parse value for property '%s': %s\n"
 msgstr "%s:%d: მნიშვნელობის დამუშავების შეცდომა თვისებისთვის '%s': %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:658
+#: tools/gtk-builder-tool-simplify.c:666
 #, c-format
 msgid "Property %s not found"
 msgstr "თვისება %s ვერ მოიძებნა"
 
-#: tools/gtk-builder-tool-simplify.c:661
+#: tools/gtk-builder-tool-simplify.c:669
 #, c-format
 msgid "Packing property %s not found"
 msgstr "შემკრები თვისება %s ვერ მოიძებნა"
 
-#: tools/gtk-builder-tool-simplify.c:664
+#: tools/gtk-builder-tool-simplify.c:672
 #, c-format
 msgid "Cell property %s not found"
 msgstr "უჯრედის თვისება %s ვერ მოიძებნა"
 
-#: tools/gtk-builder-tool-simplify.c:667
+#: tools/gtk-builder-tool-simplify.c:675
 #, c-format
 msgid "Layout property %s not found"
 msgstr "განლაგების თვისება %s ვერ მოიძებნა"
 
-#: tools/gtk-builder-tool-simplify.c:1400
+#: tools/gtk-builder-tool-simplify.c:1408
 #, c-format
 msgid "%s only accepts three children"
 msgstr "%s მხოლოდ სამ შვილს იღებს"
 
-#: tools/gtk-builder-tool-simplify.c:1773
+#: tools/gtk-builder-tool-simplify.c:1796
 #, c-format
 msgid "%s only accepts one center child"
 msgstr "%s, მხოლოდ, ერთ ცენტრალურ შვილს იღებს"
 
-#: tools/gtk-builder-tool-simplify.c:2584
+#: tools/gtk-builder-tool-simplify.c:2606
+#, c-format
+msgid "Unable to create temporary file: %s\n"
+msgstr "შექმნის შეცდომა დროებითი ფაილისთვის: %s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2620
 #, c-format
 msgid "Can’t load “%s”: %s\n"
 msgstr "\"%s\"-ის ჩატვირთვის შეცდომა: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2595
-#: tools/gtk-builder-tool-simplify.c:2601
-#: tools/gtk-builder-tool-simplify.c:2607
+#: tools/gtk-builder-tool-simplify.c:2632
+#: tools/gtk-builder-tool-simplify.c:2642
+#: tools/gtk-builder-tool-simplify.c:2651
 #, c-format
 msgid "Can’t parse “%s”: %s\n"
 msgstr "\"%s\"-ის დამუშავების შეცდომა: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2633
+#: tools/gtk-builder-tool-simplify.c:2677
 #, c-format
 msgid "Failed to read “%s”: %s\n"
 msgstr "\"%s\"-ის წაკითხვის შეცდომა: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2639
+#: tools/gtk-builder-tool-simplify.c:2684
 #, c-format
 msgid "Failed to write “%s”: “%s”\n"
 msgstr "\"%s\"-ის ჩაწერის შეცდომა: \"%s\"\n"
 
-#: tools/gtk-builder-tool-simplify.c:2656
+#: tools/gtk-builder-tool-simplify.c:2707
 msgid "Replace the file"
 msgstr "ფაილის ჩანაცვლება"
 
-#: tools/gtk-builder-tool-simplify.c:2657
+#: tools/gtk-builder-tool-simplify.c:2708
 msgid "Convert from GTK 3 to GTK 4"
 msgstr "გადაიყვანეთ GTK 3-დან GTK 4-ზე"
 
-#: tools/gtk-builder-tool-simplify.c:2668
+#: tools/gtk-builder-tool-simplify.c:2719
 msgid "Simplify the file."
 msgstr "ფაილის გამარტივება."
 
-#: tools/gtk-builder-tool-simplify.c:2687
+#: tools/gtk-builder-tool-simplify.c:2739
 #, c-format
 msgid "Can only simplify a single .ui file without --replace\n"
 msgstr "ფაილის გამარტივება მხოლოდ --replace-ის გარეშე შეგიძლიათ\n"
@@ -8570,6 +8575,10 @@ msgstr ""
 "თუ მართლა გნებავთ, ხატულების კეში აქ შექმნათ, --ignore-theme-index "
 "გამოიყენეთ.\n"
 
+#, c-format
+#~ msgid "The create-folder action is not supported with portals"
+#~ msgstr "ქმედება create-folder პორტალებთან მხარდაჭერილი არაა"
+
 #, c-format
 #~ msgid ""
 #~ "This GLES %d.%d implementation does not support half-float vertex data"
@@ -9926,9 +9935,6 @@ msgstr ""
 #~ msgid "Insufficient memory to save image to callback"
 #~ msgstr "მეხსიერების უკმარისობა გამოსახულების ფაილის შესანახად"
 
-#~ msgid "Failed to open temporary file"
-#~ msgstr "დროებითი ფაილი ვერ იხსნება"
-
 #~ msgid "Failed to open '%s' for writing: %s"
 #~ msgstr "ვერ იხსნება ფაილი \"%s\" ჩასაწერად: %s"
 
diff --git a/po/ne.po b/po/ne.po
index 0dac2495359d1d1e76a4c9b5b68f7648b064c010..b6dcfb6bc60c266d2d906bfe730427606d631011 100644
--- a/po/ne.po
+++ b/po/ne.po
@@ -11,8 +11,8 @@ msgid ""
 msgstr ""
 "Project-Id-Version: Gnome Nepali Translation Project\n"
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
-"POT-Creation-Date: 2022-05-03 08:53+0000\n"
-"PO-Revision-Date: 2022-05-08 14:28+0545\n"
+"POT-Creation-Date: 2025-02-13 02:10+0000\n"
+"PO-Revision-Date: 2025-02-23 12:36+0545\n"
 "Last-Translator: Pawan Chitrakar <chautari@gmail.com>\n"
 "Language-Team: Nepali Translation Team <chautari@gmail.com>\n"
 "Language: ne\n"
@@ -20,712 +20,741 @@ msgstr ""
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=2;plural=(n!=1);\n"
-"X-Generator: Poedit 3.0.1\n"
+"X-Generator: Poedit 3.5\n"
 
 #: gdk/broadway/gdkbroadway-server.c:135
 #, c-format
 msgid "Broadway display type not supported: %s"
 msgstr "ब्रोडवे प्रदर्शन प्रकार समर्थित छैन: %s"
 
-#: gdk/gdkclipboard.c:231
-#, fuzzy
+#: gdk/gdkclipboard.c:232
 msgid "This clipboard cannot store data."
-msgstr "खाली क्लिपबोर्डबाट पढ्न सकिँदैन ।."
+msgstr "यो क्लिपबोर्ड डाटा भण्डारण गर्न सक्दैन।."
 
-#: gdk/gdkclipboard.c:286 gdk/gdkclipboard.c:792 gdk/gdkclipboard.c:1092
+#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:781 gdk/gdkclipboard.c:1072
 msgid "Cannot read from empty clipboard."
 msgstr "खाली क्लिपबोर्डबाट पढ्न सकिँदैन ।."
 
-#: gdk/gdkclipboard.c:317 gdk/gdkclipboard.c:1142 gdk/gdkdrag.c:632
+#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1122 gdk/gdkdrag.c:606
 msgid "No compatible formats to transfer clipboard contents."
+msgstr "क्लिपबोर्ड सामग्रीहरू स्थानान्तरण गर्न कुनै मिल्दो ढाँचाहरू छैनन्।."
+
+#: gdk/gdkcolorstate.c:668
+#, c-format
+msgid "cicp: Narrow range or YUV not supported"
+msgstr ""
+
+#: gdk/gdkcolorstate.c:678
+#, c-format
+msgid "cicp: Unspecified parameters not supported"
+msgstr ""
+
+#: gdk/gdkcolorstate.c:724
+#, c-format
+#| msgid "Compressed icons are not supported"
+msgid "cicp: Transfer function %u not supported"
+msgstr ""
+
+#: gdk/gdkcolorstate.c:754
+#, c-format
+#| msgid "Format %s not supported"
+msgid "cicp: Color primaries %u not supported"
 msgstr ""
 
-#: gdk/gdkcontentprovider.c:105 gdk/gdkcontentproviderimpl.c:313 gdk/gdkcontentproviderimpl.c:532
+#: gdk/gdkcontentprovider.c:106 gdk/gdkcontentproviderimpl.c:313 gdk/gdkcontentproviderimpl.c:532
 #, c-format
 msgid "Cannot provide contents as “%s”"
 msgstr "\"%s\" को रूपमा सामग्री उपलब्ध गराउन सकिँदैन"
 
-#: gdk/gdkcontentprovider.c:126
+#: gdk/gdkcontentprovider.c:127
 #, c-format
 msgid "Cannot provide contents as %s"
 msgstr "%s को रूपमा सामग्री उपलब्ध गराउन सकिँदैन"
 
-#: gdk/gdkdisplay.c:154 gdk/gdkglcontext.c:436
+#: gdk/gdkdisplay.c:176 gdk/gdkglcontext.c:470
 msgid "The current backend does not support OpenGL"
 msgstr "हालको ब्याकइन्डले OpenGL समर्थन गर्दैन"
 
-#: gdk/gdkdisplay.c:1246
-msgid "GL support disabled via GDK_DEBUG"
+#: gdk/gdkdisplay.c:1317 gdk/gdkvulkancontext.c:1754
+msgid "Vulkan support disabled via GDK_DISABLE"
 msgstr ""
 
-#: gdk/gdkdisplay.c:1544
-#, fuzzy
+#: gdk/gdkdisplay.c:1371
+msgid "OpenGL support disabled via GDK_DISABLE"
+msgstr ""
+
+#: gdk/gdkdisplay.c:1685
 msgid "No EGL configuration available"
-msgstr "कन्फिगरेसन"
+msgstr "कुनै EGL कन्फिगरेसन उपलब्ध छैन"
 
-#: gdk/gdkdisplay.c:1552
-#, fuzzy
+#: gdk/gdkdisplay.c:1693
 msgid "Failed to get EGL configurations"
-msgstr "सर्भर सेटअप असफल"
+msgstr "EGL कन्फिगरेसनहरू प्राप्त गर्न असफल भयो"
 
-#: gdk/gdkdisplay.c:1582
+#: gdk/gdkdisplay.c:1723
 msgid "No EGL configuration with required features found"
-msgstr ""
+msgstr "आवश्यक सुविधाहरू भएको कुनै EGL कन्फिगरेसन फेला परेन"
 
-#: gdk/gdkdisplay.c:1589
-#, fuzzy
-#| msgid "No network locations found"
+#: gdk/gdkdisplay.c:1730
 msgid "No perfect EGL configuration found"
-msgstr "सञ्जाल स्थान  फेला परेन"
+msgstr "कुनै उत्तम EGL कन्फिगरेसन फेला परेन"
 
-#: gdk/gdkdisplay.c:1631
-msgid "EGL implementation is missing extension %2$s"
-msgid_plural "EGL implementation is missing %d extensions: %s"
-msgstr[0] ""
-msgstr[1] ""
+#: gdk/gdkdisplay.c:1772
+#, c-format
+msgid "EGL implementation is missing extension %s"
+msgid_plural "EGL implementation is missing %2$d extensions: %1$s"
+msgstr[0] "EGL कार्यान्वयन विस्तार हराइरहेको छ %s"
+msgstr[1] "ईजीएल कार्यान्वयनले%2$d एक्सटेन्सन हराइरहेको छ:%1$s"
 
-#: gdk/gdkdisplay.c:1664
-#, fuzzy
+#: gdk/gdkdisplay.c:1821
 msgid "libEGL not available in this sandbox"
-msgstr "उपलब्ध छैन"
+msgstr ""
 
-#: gdk/gdkdisplay.c:1665
-#, fuzzy
+#: gdk/gdkdisplay.c:1822
 #| msgid "Not available"
 msgid "libEGL not available"
-msgstr "उपलब्ध छैन"
+msgstr ""
 
-#: gdk/gdkdisplay.c:1675
-#, fuzzy
+#: gdk/gdkdisplay.c:1832
 msgid "Failed to create EGL display"
-msgstr "%s डाइरेक्टरी सिर्जना गर्न असफल भयो।"
+msgstr "ईजीएल प्रदर्शन सिर्जना गर्न असफल भयो"
 
-#: gdk/gdkdisplay.c:1685
-#, fuzzy
+#: gdk/gdkdisplay.c:1841
 msgid "Could not initialize EGL display"
-msgstr "थ्रड-सेफ पुस्तकालयहरू थालनी गर्न सकेन ।"
+msgstr "ईजीएल प्रदर्शन सुरुआत गर्न सकेन"
 
-#: gdk/gdkdisplay.c:1696
+#: gdk/gdkdisplay.c:1851
 #, c-format
 msgid "EGL version %d.%d is too old. GTK requires %d.%d"
-msgstr ""
+msgstr "ईजीएल संस्करण %d.%d धेरै पुरानो छ । जीटीकेलाई %d.%d आवश्यक छ"
 
 #: gdk/gdkdrop.c:130
 msgid "Drag’n’drop from other applications is not supported."
 msgstr ""
 
 #: gdk/gdkdrop.c:163
-#, fuzzy
 msgid "No compatible formats to transfer contents."
-msgstr "चयन गरिएको कक्षको ढाँचा, टिप्पणी,र सामग्री खाली गर्नुहोस्"
-
-#: gdk/gdkglcontext.c:333
-msgid "The EGL implementation does not support any allowed APIs"
 msgstr ""
 
-#: gdk/gdkglcontext.c:414 gdk/win32/gdkglcontext-win32-wgl.c:616 gdk/x11/gdkglcontext-glx.c:624
+#: gdk/gdkglcontext.c:430 gdk/x11/gdkglcontext-glx.c:651
+msgid "No GL API allowed."
+msgstr "जीएल एपीआई अनुमति छैन ।."
+
+#: gdk/gdkglcontext.c:453 gdk/win32/gdkglcontext-win32-wgl.c:762 gdk/win32/gdkglcontext-win32-wgl.c:905 gdk/win32/gdkglcontext-win32-wgl.c:949 gdk/x11/gdkglcontext-glx.c:697
 msgid "Unable to create a GL context"
 msgstr "जीएल विषयवस्तु सिर्जना गर्न अक्षम"
 
-#: gdk/gdkglcontext.c:1279
-msgid "Anything but OpenGL ES disabled via GDK_DEBUG"
+#: gdk/gdkglcontext.c:1338
+msgid "OpenGL ES API disabled via GDK_DISABLE"
 msgstr ""
 
-#: gdk/gdkglcontext.c:1288
+#: gdk/gdkglcontext.c:1350
+msgid "OpenGL API disabled via GDK_DISABLE"
+msgstr ""
+
+#: gdk/gdkglcontext.c:1361
 #, c-format
 msgid "Application does not support %s API"
 msgstr ""
 
 #. translators: This is about OpenGL backend names, like
 #. * "Trying to use X11 GLX, but EGL is already in use"
-#: gdk/gdkglcontext.c:1809
-#, fuzzy, c-format
+#.
+#: gdk/gdkglcontext.c:2171
+#, c-format
 msgid "Trying to use %s, but %s is already in use"
-msgstr "बाकस \"%s\" स्थापित र प्रयोग गर्न तयार छ"
+msgstr ""
 
-#: gdk/gdksurface.c:1240
-msgid "Vulkan support disabled via GDK_DEBUG"
+#: gdk/gdkglcontext.c:2182
+#, c-format
+msgid "Trying to use %s, but it is disabled via GDK_DISABLE"
 msgstr ""
 
-#: gdk/gdktexture.c:529
+#: gdk/gdktexture.c:672
 msgid "Unknown image format."
-msgstr "अज्ञात छवि ढाँचा "
+msgstr "अज्ञात छवि ढाँचा."
 
 #.
-#. * Translators, the strings in the “keyboard label” context are
+#. * Translators, the strings in the 'keyboard label' context are
 #. * display names for keyboard keys. Some of them have prefixes like
-#. * XF86 or ISO_ — these should be removed in the translation. Similarly,
-#. * underscores should be replaced by spaces. The prefix “KP_” stands
-#. * for “key pad” and you may want to include that in your translation.
+#. * XF86 or ISO_ - these should be removed in the translation. Similarly,
+#. * underscores should be replaced by spaces. The prefix 'KP_' stands
+#. * for 'key pad' and you may want to include that in your translation.
 #. * Here are some examples of English translations:
 #. * XF86AudioMute - Audio mute
 #. * Scroll_lock   - Scroll lock
 #. * KP_Space      - Space (keypad)
 #.
-#: gdk/keyname-table.h:6843
+#: gdk/keynamesprivate.h:6861
 msgctxt "keyboard label"
 msgid "BackSpace"
 msgstr "पछिजाने कुञ्जि"
 
-#: gdk/keyname-table.h:6844
+#: gdk/keynamesprivate.h:6862
 msgctxt "keyboard label"
 msgid "Tab"
 msgstr "ट्याब"
 
-#: gdk/keyname-table.h:6845
+#: gdk/keynamesprivate.h:6863
 msgctxt "keyboard label"
 msgid "Return"
 msgstr "फर्कनुहोस्"
 
-#: gdk/keyname-table.h:6846
+#: gdk/keynamesprivate.h:6864
 msgctxt "keyboard label"
 msgid "Pause"
 msgstr "Pause"
 
-#: gdk/keyname-table.h:6847
+#: gdk/keynamesprivate.h:6865
 msgctxt "keyboard label"
 msgid "Scroll_Lock"
 msgstr "स्क्रोल लक"
 
-#: gdk/keyname-table.h:6848
+#: gdk/keynamesprivate.h:6866
 msgctxt "keyboard label"
 msgid "Sys_Req"
 msgstr "Sys_Req"
 
-#: gdk/keyname-table.h:6849
+#: gdk/keynamesprivate.h:6867
 msgctxt "keyboard label"
 msgid "Escape"
 msgstr "इस्केप"
 
-#: gdk/keyname-table.h:6850
+#: gdk/keynamesprivate.h:6868
 msgctxt "keyboard label"
 msgid "Multi_key"
 msgstr "मल्टिकीइ"
 
-#: gdk/keyname-table.h:6851
+#: gdk/keynamesprivate.h:6869
 msgctxt "keyboard label"
 msgid "Home"
 msgstr "गृहपृष्ठ"
 
-#: gdk/keyname-table.h:6852
+#: gdk/keynamesprivate.h:6870
 msgctxt "keyboard label"
 msgid "Left"
 msgstr "देब्रे"
 
-#: gdk/keyname-table.h:6853
+#: gdk/keynamesprivate.h:6871
 msgctxt "keyboard label"
 msgid "Up"
 msgstr "माथि"
 
-#: gdk/keyname-table.h:6854
+#: gdk/keynamesprivate.h:6872
 msgctxt "keyboard label"
 msgid "Right"
 msgstr "दायाँ"
 
-#: gdk/keyname-table.h:6855
+#: gdk/keynamesprivate.h:6873
 msgctxt "keyboard label"
 msgid "Down"
 msgstr "तल"
 
-#: gdk/keyname-table.h:6856 gtk/gtkshortcutlabel.c:212
+#: gdk/keynamesprivate.h:6874 gtk/gtkshortcutlabel.c:217
 msgctxt "keyboard label"
 msgid "Page_Up"
 msgstr "पेज माथि"
 
-#: gdk/keyname-table.h:6857 gtk/gtkshortcutlabel.c:215
+#: gdk/keynamesprivate.h:6875 gtk/gtkshortcutlabel.c:220
 msgctxt "keyboard label"
 msgid "Page_Down"
 msgstr "पेज तल"
 
-#: gdk/keyname-table.h:6858
+#: gdk/keynamesprivate.h:6876
 msgctxt "keyboard label"
 msgid "End"
 msgstr "End"
 
-#: gdk/keyname-table.h:6859
+#: gdk/keynamesprivate.h:6877
 msgctxt "keyboard label"
 msgid "Begin"
 msgstr "सुरु"
 
-#: gdk/keyname-table.h:6860
+#: gdk/keynamesprivate.h:6878
 msgctxt "keyboard label"
 msgid "Print"
 msgstr "मुद्रण"
 
-#: gdk/keyname-table.h:6861
+#: gdk/keynamesprivate.h:6879
 msgctxt "keyboard label"
 msgid "Insert"
 msgstr "घुसाउ"
 
-#: gdk/keyname-table.h:6862
+#: gdk/keynamesprivate.h:6880
 msgctxt "keyboard label"
 msgid "Num_Lock"
 msgstr "नम लक"
 
-#. Translators: KP_ means “key pad” here
-#: gdk/keyname-table.h:6864
+#. Translators: KP_ means 'key pad' here
+#: gdk/keynamesprivate.h:6882
 msgctxt "keyboard label"
 msgid "KP_Space"
 msgstr "KP_खालीस्थान"
 
-#: gdk/keyname-table.h:6865
+#: gdk/keynamesprivate.h:6883
 msgctxt "keyboard label"
 msgid "KP_Tab"
 msgstr "KP_ट्याव"
 
-#: gdk/keyname-table.h:6866
+#: gdk/keynamesprivate.h:6884
 msgctxt "keyboard label"
 msgid "KP_Enter"
 msgstr "KP_प्रविष्टि"
 
-#: gdk/keyname-table.h:6867
+#: gdk/keynamesprivate.h:6885
 msgctxt "keyboard label"
 msgid "KP_Home"
 msgstr "KP_गृह"
 
-#: gdk/keyname-table.h:6868
+#: gdk/keynamesprivate.h:6886
 msgctxt "keyboard label"
 msgid "KP_Left"
 msgstr "KP_बाँया"
 
-#: gdk/keyname-table.h:6869
+#: gdk/keynamesprivate.h:6887
 msgctxt "keyboard label"
 msgid "KP_Up"
 msgstr "KP_माथि"
 
-#: gdk/keyname-table.h:6870
+#: gdk/keynamesprivate.h:6888
 msgctxt "keyboard label"
 msgid "KP_Right"
 msgstr "KP_दाँया"
 
-#: gdk/keyname-table.h:6871
+#: gdk/keynamesprivate.h:6889
 msgctxt "keyboard label"
 msgid "KP_Down"
 msgstr "KP_तल"
 
-#: gdk/keyname-table.h:6872
+#: gdk/keynamesprivate.h:6890
 msgctxt "keyboard label"
 msgid "KP_Page_Up"
 msgstr "KP_पृष्ठ_माथि"
 
-#: gdk/keyname-table.h:6873
+#: gdk/keynamesprivate.h:6891
 msgctxt "keyboard label"
 msgid "KP_Prior"
 msgstr "KP_अघि"
 
-#: gdk/keyname-table.h:6874
+#: gdk/keynamesprivate.h:6892
 msgctxt "keyboard label"
 msgid "KP_Page_Down"
 msgstr "KP_पृष्ठ_तल"
 
-#: gdk/keyname-table.h:6875
+#: gdk/keynamesprivate.h:6893
 msgctxt "keyboard label"
 msgid "KP_Next"
 msgstr "KP_अर्को"
 
-#: gdk/keyname-table.h:6876
+#: gdk/keynamesprivate.h:6894
 msgctxt "keyboard label"
 msgid "KP_End"
 msgstr "KP_समाप्त"
 
-#: gdk/keyname-table.h:6877
+#: gdk/keynamesprivate.h:6895
 msgctxt "keyboard label"
 msgid "KP_Begin"
 msgstr "KP_शुरु"
 
-#: gdk/keyname-table.h:6878
+#: gdk/keynamesprivate.h:6896
 msgctxt "keyboard label"
 msgid "KP_Insert"
 msgstr "KP_घुसाउ"
 
-#: gdk/keyname-table.h:6879
+#: gdk/keynamesprivate.h:6897
 msgctxt "keyboard label"
 msgid "KP_Delete"
 msgstr "KP_मेट्ने"
 
-#: gdk/keyname-table.h:6880
+#: gdk/keynamesprivate.h:6898
 msgctxt "keyboard label"
 msgid "Delete"
 msgstr "हटाउनुहोस"
 
-#: gdk/keyname-table.h:6881
+#: gdk/keynamesprivate.h:6899
 msgctxt "keyboard label"
 msgid "MonBrightnessUp"
 msgstr ""
 
-#: gdk/keyname-table.h:6882
+#: gdk/keynamesprivate.h:6900
 msgctxt "keyboard label"
 msgid "MonBrightnessDown"
 msgstr ""
 
-#: gdk/keyname-table.h:6883
+#: gdk/keynamesprivate.h:6901
 msgctxt "keyboard label"
 msgid "KbdBrightnessUp"
 msgstr ""
 
-#: gdk/keyname-table.h:6884
+#: gdk/keynamesprivate.h:6902
 msgctxt "keyboard label"
 msgid "KbdBrightnessDown"
 msgstr ""
 
-#: gdk/keyname-table.h:6885
+#: gdk/keynamesprivate.h:6903
 msgctxt "keyboard label"
 msgid "AudioMute"
 msgstr "ध्वनिमौन"
 
-#: gdk/keyname-table.h:6886
+#: gdk/keynamesprivate.h:6904
 msgctxt "keyboard label"
 msgid "AudioMicMute"
 msgstr "ध्वनिमाइकमौन"
 
-#: gdk/keyname-table.h:6887
+#: gdk/keynamesprivate.h:6905
 msgctxt "keyboard label"
 msgid "AudioLowerVolume"
 msgstr "ध्वनिघटाउ"
 
-#: gdk/keyname-table.h:6888
+#: gdk/keynamesprivate.h:6906
 msgctxt "keyboard label"
 msgid "AudioRaiseVolume"
 msgstr "ध्वनिबढाउ"
 
-#: gdk/keyname-table.h:6889
+#: gdk/keynamesprivate.h:6907
 msgctxt "keyboard label"
 msgid "AudioPlay"
 msgstr "अडियोप्ले"
 
-#: gdk/keyname-table.h:6890
+#: gdk/keynamesprivate.h:6908
 msgctxt "keyboard label"
 msgid "AudioStop"
 msgstr "अडियोस्टप"
 
-#: gdk/keyname-table.h:6891
+#: gdk/keynamesprivate.h:6909
 msgctxt "keyboard label"
 msgid "AudioNext"
 msgstr "अडियोनेक्स"
 
-#: gdk/keyname-table.h:6892
+#: gdk/keynamesprivate.h:6910
 msgctxt "keyboard label"
 msgid "AudioPrev"
 msgstr "अडियोप्रेभ"
 
-#: gdk/keyname-table.h:6893
+#: gdk/keynamesprivate.h:6911
 msgctxt "keyboard label"
 msgid "AudioRecord"
 msgstr "अडियोरेकर्ड"
 
-#: gdk/keyname-table.h:6894
+#: gdk/keynamesprivate.h:6912
 msgctxt "keyboard label"
 msgid "AudioPause"
 msgstr "अडियोपज"
 
-#: gdk/keyname-table.h:6895
+#: gdk/keynamesprivate.h:6913
 msgctxt "keyboard label"
 msgid "AudioRewind"
 msgstr "अडियोरिवाइन्ड"
 
-#: gdk/keyname-table.h:6896
+#: gdk/keynamesprivate.h:6914
 msgctxt "keyboard label"
 msgid "AudioMedia"
 msgstr "अडियोमेडिया"
 
-#: gdk/keyname-table.h:6897
+#: gdk/keynamesprivate.h:6915
 msgctxt "keyboard label"
 msgid "Eject"
 msgstr "निकाल"
 
-#: gdk/keyname-table.h:6898
+#: gdk/keynamesprivate.h:6916
 msgctxt "keyboard label"
 msgid "Explorer"
 msgstr "एक्सप्लोरर"
 
-#: gdk/keyname-table.h:6899
+#: gdk/keynamesprivate.h:6917
 msgctxt "keyboard label"
 msgid "Calculator"
 msgstr "गणकयन्त्र"
 
-#: gdk/keyname-table.h:6900
+#: gdk/keynamesprivate.h:6918
 msgctxt "keyboard label"
 msgid "Mail"
 msgstr "पत्र"
 
-#: gdk/keyname-table.h:6901
+#: gdk/keynamesprivate.h:6919
 msgctxt "keyboard label"
 msgid "WWW"
 msgstr "WWW"
 
-#: gdk/keyname-table.h:6902
+#: gdk/keynamesprivate.h:6920
 msgctxt "keyboard label"
 msgid "Search"
 msgstr "खोजी"
 
-#: gdk/keyname-table.h:6903
+#: gdk/keynamesprivate.h:6921
 msgctxt "keyboard label"
 msgid "Tools"
 msgstr "उपकरणहरू"
 
-#: gdk/keyname-table.h:6904
+#: gdk/keynamesprivate.h:6922
 msgctxt "keyboard label"
 msgid "ScreenSaver"
 msgstr "स्क्रिनसेभर"
 
-#: gdk/keyname-table.h:6905
+#: gdk/keynamesprivate.h:6923
 msgctxt "keyboard label"
 msgid "Battery"
 msgstr "बेटरि"
 
-#: gdk/keyname-table.h:6906
+#: gdk/keynamesprivate.h:6924
 msgctxt "keyboard label"
 msgid "Launch1"
 msgstr ""
 
-#: gdk/keyname-table.h:6907
+#: gdk/keynamesprivate.h:6925
 msgctxt "keyboard label"
 msgid "Forward"
 msgstr "पठाउनुहोस्"
 
-#: gdk/keyname-table.h:6908
+#: gdk/keynamesprivate.h:6926
 msgctxt "keyboard label"
 msgid "Back"
 msgstr "पछाडि"
 
-#: gdk/keyname-table.h:6909
+#: gdk/keynamesprivate.h:6927
 msgctxt "keyboard label"
 msgid "Sleep"
 msgstr "Sleep"
 
-#: gdk/keyname-table.h:6910
+#: gdk/keynamesprivate.h:6928
 msgctxt "keyboard label"
 msgid "Hibernate"
 msgstr "हाइवरनेट"
 
-#: gdk/keyname-table.h:6911
+#: gdk/keynamesprivate.h:6929
 msgctxt "keyboard label"
 msgid "WLAN"
 msgstr "WLAN"
 
-#: gdk/keyname-table.h:6912
+#: gdk/keynamesprivate.h:6930
 msgctxt "keyboard label"
 msgid "WebCam"
 msgstr "वेवक्याम"
 
-#: gdk/keyname-table.h:6913
+#: gdk/keynamesprivate.h:6931
 msgctxt "keyboard label"
 msgid "Display"
 msgstr "प्रदर्शन"
 
-#: gdk/keyname-table.h:6914
+#: gdk/keynamesprivate.h:6932
 msgctxt "keyboard label"
 msgid "TouchpadToggle"
 msgstr ""
 
-#: gdk/keyname-table.h:6915
+#: gdk/keynamesprivate.h:6933
 msgctxt "keyboard label"
 msgid "WakeUp"
 msgstr "जागागर्ने"
 
-#: gdk/keyname-table.h:6916
+#: gdk/keynamesprivate.h:6934
 msgctxt "keyboard label"
 msgid "Suspend"
 msgstr "निश्क्रिय गर्ने"
 
-#: gdk/loaders/gdkjpeg.c:63
+#: gdk/loaders/gdkjpeg.c:71
 #, c-format
 msgid "Error interpreting JPEG image file (%s)"
 msgstr "JPEG छवि फाइल (%s) व्याख्या गर्दा त्रुटि"
 
-#: gdk/loaders/gdkjpeg.c:190
-#, fuzzy, c-format
+#: gdk/loaders/gdkjpeg.c:185
+#, c-format
 #| msgid "Unsupported JPEG color space (%s)"
 msgid "Unsupported JPEG colorspace (%d)"
-msgstr "असमर्थित JPEG रङ खाली स्थान (%s)"
+msgstr ""
 
-#: gdk/loaders/gdkjpeg.c:199 gdk/loaders/gdkpng.c:265 gdk/loaders/gdktiff.c:453
-#, fuzzy, c-format
+#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:436 gdk/loaders/gdktiff.c:472
+#, c-format
 #| msgid "Not enough memory to load image"
 msgid "Not enough memory for image size %ux%u"
-msgstr "छवि लोड गर्न पर्याप्त स्मृति छैन"
+msgstr ""
 
-#: gdk/loaders/gdkpng.c:119
-#, fuzzy, c-format
+#: gdk/loaders/gdkpng.c:120
+#, c-format
 msgid "Error reading png (%s)"
-msgstr "PNG छवि फाइल पढ्दा घातक त्रुटि"
+msgstr "पीएनजी (%s) पढ्दा त्रुटि"
 
-#: gdk/loaders/gdkpng.c:216
-#, fuzzy, c-format
-#| msgid "Unsupported depth for ICO file: %d"
+#: gdk/loaders/gdkpng.c:357
+#, c-format
 msgid "Unsupported depth %u in png image"
-msgstr "ICO फाइलका लागि असमर्थित गहिराइ: %d"
+msgstr "पीएनजी छविमा असमर्थित गहिराइ %u"
 
-#: gdk/loaders/gdkpng.c:246
-#, fuzzy, c-format
-#| msgid "Unsupported JPEG color space (%s)"
+#: gdk/loaders/gdkpng.c:407
+#, c-format
 msgid "Unsupported color type %u in png image"
-msgstr "असमर्थित JPEG रङ खाली स्थान (%s)"
+msgstr "पीएनजी छविमा असमर्थित रङ प्रकार %u"
 
-#: gdk/loaders/gdktiff.c:340
+#: gdk/loaders/gdkpng.c:421
+#, c-format
+msgid "Image stride too large for image size %ux%u"
+msgstr "छवि साइज %ux%u का लागि छवि स्ट्राइड धेरै ठूलो छ"
+
+#: gdk/loaders/gdktiff.c:358
 msgid "Failed to load RGB data from TIFF file"
 msgstr "TIFF फाइल बाट RGB डेटा लोड गर्न असफल"
 
-#: gdk/loaders/gdktiff.c:383
-#, fuzzy
+#: gdk/loaders/gdktiff.c:401
 msgid "Could not load TIFF data"
-msgstr "TIFF छवि लोड गर्न असफल"
+msgstr "टीआईएफएफ डेटा लोड गर्न सकेन"
 
-#: gdk/loaders/gdktiff.c:465
+#: gdk/loaders/gdktiff.c:484
 #, c-format
 msgid "Reading data failed at row %d"
-msgstr ""
+msgstr "पङ्क्ति %d मा डेटा पढ्न असफल भयो"
 
-#: gdk/macos/gdkmacosclipboard.c:557 gdk/wayland/gdkclipboard-wayland.c:231
-#: gdk/wayland/gdkdrop-wayland.c:203 gdk/wayland/gdkprimary-wayland.c:313
-#: gdk/win32/gdkdrop-win32.c:1006 gdk/win32/gdkdrop-win32.c:1051 gdk/x11/gdkclipboard-x11.c:791
-#: gdk/x11/gdkdrop-x11.c:233
-#, fuzzy
+#: gdk/macos/gdkmacospasteboard.c:211 gdk/wayland/gdkclipboard-wayland.c:244 gdk/wayland/gdkdrop-wayland.c:205 gdk/wayland/gdkprimary-wayland.c:343
+#: gdk/win32/gdkdrop-win32.c:1018 gdk/win32/gdkdrop-win32.c:1067 gdk/x11/gdkclipboard-x11.c:799 gdk/x11/gdkdrop-x11.c:235
 msgid "No compatible transfer format found"
-msgstr "%s ढाँचाका लागि क्रमबाट हटाउने प्रकार्य फेला परेन"
+msgstr "अनुकूल स्थानान्तरण ढाँचा फेला परेन"
 
-#: gdk/macos/gdkmacosclipboard.c:643
+#: gdk/macos/gdkmacospasteboard.c:297
 #, c-format
 msgid "Failed to decode contents with mime-type of '%s'"
-msgstr ""
+msgstr "'%s' को माइम-प्रकारसँग सामग्री डिकोड गर्न असफल भयो"
 
-#: gdk/win32/gdkclipdrop-win32.c:721
+#: gdk/win32/gdkclipdrop-win32.c:719
 #, c-format
 msgid "Cannot claim clipboard ownership. OpenClipboard() timed out."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:731
+#: gdk/win32/gdkclipdrop-win32.c:729
 #, c-format
 msgid "Cannot claim clipboard ownership. Another process claimed it before us."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:745
+#: gdk/win32/gdkclipdrop-win32.c:743
 #, c-format
 msgid "Cannot claim clipboard ownership. OpenClipboard() failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:757
+#: gdk/win32/gdkclipdrop-win32.c:755
 #, c-format
 msgid "Cannot claim clipboard ownership. EmptyClipboard() failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:800
+#: gdk/win32/gdkclipdrop-win32.c:798
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() timed out."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:810 gdk/win32/gdkclipdrop-win32.c:841
+#: gdk/win32/gdkclipdrop-win32.c:808 gdk/win32/gdkclipdrop-win32.c:839
 #, c-format
 msgid "Cannot set clipboard data. Another process claimed clipboard ownership."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:824
+#: gdk/win32/gdkclipdrop-win32.c:822
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:876
+#: gdk/win32/gdkclipdrop-win32.c:874
 #, c-format
 msgid "Cannot get clipboard data. GlobalLock(0x%p) failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:887
+#: gdk/win32/gdkclipdrop-win32.c:885
 #, c-format
 msgid "Cannot get clipboard data. GlobalSize(0x%p) failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:900
+#: gdk/win32/gdkclipdrop-win32.c:898
 #, c-format
 msgid "Cannot get clipboard data. Failed to allocate %s bytes to store the data."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:932
+#: gdk/win32/gdkclipdrop-win32.c:930
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() timed out."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:942
+#: gdk/win32/gdkclipdrop-win32.c:940
 #, c-format
 msgid "Cannot get clipboard data. Clipboard ownership changed."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:952
+#: gdk/win32/gdkclipdrop-win32.c:950
 #, c-format
 msgid "Cannot get clipboard data. Clipboard data changed before we could get it."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:969
+#: gdk/win32/gdkclipdrop-win32.c:967
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:994
+#: gdk/win32/gdkclipdrop-win32.c:992
 #, c-format
 msgid "Cannot get clipboard data. No compatible transfer format found."
 msgstr ""
 
-#: gdk/win32/gdkclipdrop-win32.c:1004
+#: gdk/win32/gdkclipdrop-win32.c:1002
 #, c-format
 msgid "Cannot get clipboard data. GetClipboardData() failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkdrop-win32.c:937
+#: gdk/win32/gdkdrop-win32.c:949
 #, c-format
 msgid "Cannot get DnD data. GlobalLock(0x%p) failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkdrop-win32.c:946
+#: gdk/win32/gdkdrop-win32.c:958
 #, c-format
 msgid "Cannot get DnD data. GlobalSize(0x%p) failed: 0x%lx."
 msgstr ""
 
-#: gdk/win32/gdkdrop-win32.c:957
+#: gdk/win32/gdkdrop-win32.c:969
 #, c-format
 msgid "Cannot get DnD data. Failed to allocate %s bytes to store the data."
 msgstr ""
 
-#: gdk/win32/gdkdrop-win32.c:1025
+#: gdk/win32/gdkdrop-win32.c:1039
 #, c-format
 msgid "GDK surface 0x%p is not registered as a drop target"
 msgstr ""
 
-#: gdk/win32/gdkdrop-win32.c:1032
+#: gdk/win32/gdkdrop-win32.c:1047
 #, c-format
 msgid "Target context record 0x%p has no data object"
 msgstr "लक्ष्य विषयवस्तु रेकर्ड 0x%p सँग कुनै डाटा वस्तु छैन"
 
-#: gdk/win32/gdkdrop-win32.c:1070
+#: gdk/win32/gdkdrop-win32.c:1087
 #, c-format
 msgid "IDataObject_GetData (0x%x) failed, returning 0x%lx"
 msgstr ""
 
-#: gdk/win32/gdkdrop-win32.c:1102
+#: gdk/win32/gdkdrop-win32.c:1121
 #, c-format
 msgid "Failed to transmute DnD data W32 format 0x%x to %p (%s)"
 msgstr ""
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:276 gdk/win32/gdkglcontext-win32-wgl.c:293
-#, fuzzy
+#: gdk/win32/gdkglcontext-win32-wgl.c:681
 msgid "No GL implementation is available"
-msgstr "उपलब्ध"
+msgstr "जीएल कार्यान्वयन उपलब्ध छैन"
+
+#: gdk/win32/gdkglcontext-win32-wgl.c:771
+#, c-format
+msgid "WGL version %d.%d is too low, need at least %d.%d"
+msgstr ""
+
+#: gdk/win32/gdkglcontext-win32-wgl.c:789
+#, c-format
+msgid "GL implementation cannot share GL contexts"
+msgstr ""
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:582
+#: gdk/win32/gdkglcontext-win32-wgl.c:1069
 msgid "No available configurations for the given pixel format"
 msgstr ""
 
 #: gdk/win32/gdkhdataoutputstream-win32.c:63
-#, fuzzy
 msgid "writing a closed stream"
-msgstr "सञ्जाल स्ट्रीम अनपेक्षित रूपमा बन्द गरियो"
+msgstr "बन्द गरिएको प्रवाह लेख्दै"
 
 #: gdk/win32/gdkhdataoutputstream-win32.c:85
 msgid "g_try_realloc () failed"
 msgstr "g_try_realloc () failed"
 
 #: gdk/win32/gdkhdataoutputstream-win32.c:93 gdk/win32/gdkhdataoutputstream-win32.c:231
-#, fuzzy
 msgid "GlobalReAlloc() failed: "
-msgstr "असफल"
+msgstr ""
 
 #: gdk/win32/gdkhdataoutputstream-win32.c:105
 msgid "Ran out of buffer space (buffer size is fixed)"
@@ -748,47 +777,44 @@ msgstr "GlobalLock() असफल: "
 msgid "GlobalAlloc() failed: "
 msgstr "GlobalAlloc() असफल: "
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:296
+#: gdk/x11/gdkapplaunchcontext-x11.c:297
 #, c-format
 msgid "Starting “%s”"
 msgstr "\"%s\" सुरु गर्दै"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:309
+#: gdk/x11/gdkapplaunchcontext-x11.c:310
 #, c-format
 msgid "Opening “%s”"
 msgstr "“%s” खोल्नुहोस्"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:314
+#: gdk/x11/gdkapplaunchcontext-x11.c:315
 #, c-format
 msgid "Opening %d Item"
 msgid_plural "Opening %d Items"
 msgstr[0] "%d वस्तु खोल्दै"
 msgstr[1] "%d वस्तुहरू खोल्दै"
 
-#: gdk/x11/gdkclipboard-x11.c:461
+#: gdk/x11/gdkclipboard-x11.c:473
 msgid "Clipboard manager could not store selection."
 msgstr ""
 
-#: gdk/x11/gdkclipboard-x11.c:641
+#: gdk/x11/gdkclipboard-x11.c:649
 msgid "Cannot store clipboard. No clipboard manager is active."
 msgstr ""
 
-#: gdk/x11/gdkglcontext-glx.c:780
-#, fuzzy
+#: gdk/x11/gdkglcontext-glx.c:817
 msgid "No GLX configurations available"
-msgstr "उपलब्ध छैन"
+msgstr ""
 
-#: gdk/x11/gdkglcontext-glx.c:853
+#: gdk/x11/gdkglcontext-glx.c:904
 msgid "No GLX configuration with required features found"
 msgstr ""
 
-#: gdk/x11/gdkglcontext-glx.c:927
-#, fuzzy
-#| msgid "Format %s not supported"
+#: gdk/x11/gdkglcontext-glx.c:978
 msgid "GLX is not supported"
-msgstr "समर्थित छैन"
+msgstr "जीएलएक्स समर्थित छैन"
 
-#: gdk/x11/gdkselectioninputstream-x11.c:462
+#: gdk/x11/gdkselectioninputstream-x11.c:465
 #, c-format
 msgid "Format %s not supported"
 msgstr "ढाँचा %s समर्थित छैन"
@@ -814,6 +840,20 @@ msgstr ""
 msgid "Unsupported encoding “%s”"
 msgstr "असमर्थित सङ्केतन \"%s\""
 
+#: gsk/gl/gskglrenderer.c:215
+#, c-format
+msgid "This GLES %d.%d implementation does not support half-float vertex data"
+msgstr ""
+
+#: gsk/gpu/gskgldevice.c:252
+#, c-format
+msgid "OpenGL ES 3.0 is not supported by this renderer."
+msgstr ""
+
+#: gsk/gpu/gsknglrenderer.c:69
+msgid "OpenGL 3.3 required"
+msgstr "ओपनजीएल ३.३ आवश्यक"
+
 #: gtk/a11y/gtkatspiaction.c:239
 msgctxt "accessibility"
 msgid "Click"
@@ -830,10 +870,9 @@ msgid "Toggle"
 msgstr "टगल खोज"
 
 #: gtk/a11y/gtkatspiaction.c:291
-#, fuzzy
 msgctxt "accessibility"
 msgid "Toggles the switch"
-msgstr "अलार्मको आवाज टगल गर्दछ"
+msgstr "स्विच टगल गर्दछ"
 
 #: gtk/a11y/gtkatspiaction.c:371
 msgctxt "accessibility"
@@ -845,8 +884,7 @@ msgctxt "accessibility"
 msgid "Selects the color"
 msgstr "रङ्ग चयन गर्नुहोस्"
 
-#: gtk/a11y/gtkatspiaction.c:379 gtk/a11y/gtkatspiaction.c:439 gtk/a11y/gtkatspiaction.c:495
-#: gtk/a11y/gtkatspiaction.c:603 gtk/a11y/gtkatspiaction.c:690
+#: gtk/a11y/gtkatspiaction.c:379 gtk/a11y/gtkatspiaction.c:439 gtk/a11y/gtkatspiaction.c:495 gtk/a11y/gtkatspiaction.c:603 gtk/a11y/gtkatspiaction.c:690
 msgctxt "accessibility"
 msgid "Activate"
 msgstr "_सक्रिय बनाउ"
@@ -902,10 +940,9 @@ msgid "Peek"
 msgstr "टाकुरा"
 
 #: gtk/a11y/gtkatspiaction.c:612
-#, fuzzy
 msgctxt "accessibility"
 msgid "Shows the contents of the password entry"
-msgstr "प्रविष्टिको विषयवस्तु"
+msgstr ""
 
 #: gtk/a11y/gtkatspiaction.c:698
 msgctxt "accessibility"
@@ -917,7 +954,7 @@ msgctxt "accessibility"
 msgid "Clears the contents of the entry"
 msgstr "प्रविष्टिको सामग्री खाली गर्दछ"
 
-#: gtk/a11y/gtkatspiroot.c:255
+#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:869
 msgctxt "accessibility"
 msgid "application"
 msgstr "अनुप्रयोग"
@@ -928,131 +965,305 @@ msgid "Not a data: URL"
 msgstr "डाटा होइन: URL"
 
 #: gtk/css/gtkcssdataurl.c:82
-#, fuzzy, c-format
+#, c-format
 msgid "Malformed data: URL"
-msgstr "डाटा होइन: URL"
+msgstr "विकृत डेटा: यूआरएल"
 
 #: gtk/css/gtkcssdataurl.c:140
-#, fuzzy, c-format
+#, c-format
 #| msgid "Could not clear list"
 msgid "Could not unescape string"
-msgstr "स्ट्रिङ"
+msgstr "स्ट्रिङ हटाउन सकेनस्ट्रिङ हटाउन सकेन"
+
+#: gtk/deprecated/gtkappchooserbutton.c:323
+msgid "Other app…"
+msgstr "अन्य अनुप्रयोग…"
+
+#: gtk/deprecated/gtkappchooserdialog.c:215 gtk/deprecated/gtkappchooserdialog.c:266
+msgid "Select Application"
+msgstr "एप्लिकेसन छनोट गर्नुहोस्"
+
+#. Translators: %s is a filename
+#: gtk/deprecated/gtkappchooserdialog.c:222
+#, c-format
+msgid "Opening “%s”."
+msgstr "“%s” खोल्नुहोस्."
+
+#: gtk/deprecated/gtkappchooserdialog.c:223
+#, c-format
+msgid "No applications found for “%s”"
+msgstr "“%s” को लागि अनुप्रयोग भेटिएन"
+
+#. Translators: %s is a file type description
+#: gtk/deprecated/gtkappchooserdialog.c:228
+#, c-format
+msgid "Opening “%s” files."
+msgstr "\"%s\" फाइल खोल्दैछ।."
+
+#: gtk/deprecated/gtkappchooserdialog.c:230
+#, c-format
+msgid "No applications found for “%s” files"
+msgstr "“%s” फाईलको लागि अनुप्रयोग भेटिएन"
+
+#: gtk/deprecated/gtkappchooserdialog.c:432
+msgid "Failed to start GNOME Software"
+msgstr "जिनोम सफ्टवेयर शुरु गर्न असक्षम"
+
+#: gtk/deprecated/gtkappchooserwidget.c:525
+msgid "Default App"
+msgstr "पूर्वनिर्धारित अनुप्रयोग"
+
+#: gtk/deprecated/gtkappchooserwidget.c:575
+#, c-format
+#| msgid "No applications found for “%s”."
+msgid "No apps found for “%s”."
+msgstr "\"%s\" का लागि कुनै अनुप्रयोग फेला परेन ।."
+
+#: gtk/deprecated/gtkappchooserwidget.c:658
+#| msgid "Recommended Applications"
+msgid "Recommended Apps"
+msgstr "सिफारिस गरिएका अनुप्रयोगहरू"
+
+#: gtk/deprecated/gtkappchooserwidget.c:673
+#| msgid "Related Applications"
+msgid "Related Apps"
+msgstr "सम्बन्धित अनुप्रयोगहरू"
+
+#: gtk/deprecated/gtkappchooserwidget.c:687
+msgid "Other Apps"
+msgstr "अन्य अनुप्रयोग देखाउनुहोस्"
+
+#. This label is displayed in a treeview cell displaying
+#. * a disabled accelerator key combination.
+#.
+#: gtk/deprecated/gtkcellrendereraccel.c:294
+msgctxt "Accelerator"
+msgid "Disabled"
+msgstr "असक्षम पारिएको छ"
+
+#. This label is displayed in a treeview cell displaying
+#. * an accelerator key combination that is not valid according
+#. * to gtk_accelerator_valid().
+#.
+#: gtk/deprecated/gtkcellrendereraccel.c:304
+msgctxt "Accelerator"
+msgid "Invalid"
+msgstr "अवैध"
+
+#. This label is displayed in a treeview cell displaying an accelerator
+#. * when the cell is clicked to change the accelerator.
+#.
+#: gtk/deprecated/gtkcellrendereraccel.c:436 gtk/deprecated/gtkcellrendereraccel.c:729
+msgid "New accelerator…"
+msgstr "नयाँ एक्सेलेरेटर…"
+
+#: gtk/deprecated/gtkcellrendererprogress.c:132 gtk/deprecated/gtkcellrendererprogress.c:322 gtk/deprecated/gtkcellrendererprogress.c:352
+#, c-format
+msgctxt "progress bar label"
+msgid "%d %%"
+msgstr "%d %%"
+
+#: gtk/deprecated/gtkcolorbutton.c:183 gtk/deprecated/gtkcolorbutton.c:314 gtk/gtkcolordialog.c:409
+msgid "Pick a Color"
+msgstr "एउटा रङ छान्नुहोस्"
+
+#: gtk/deprecated/gtkcolorbutton.c:505 gtk/gtkcolorchooserwidget.c:321 gtk/gtkcolordialogbutton.c:335
+#, c-format
+msgid "Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"
+msgstr "रातो %d%%, हारियो %d%%, निलो %d%%, अल्फा %d%%"
+
+#: gtk/deprecated/gtkcolorbutton.c:511 gtk/gtkcolorchooserwidget.c:327 gtk/gtkcolordialogbutton.c:341
+#, c-format
+msgid "Red %d%%, Green %d%%, Blue %d%%"
+msgstr "रातो %d%%, हरियो %d%%, निलो %d%%"
+
+#: gtk/deprecated/gtkfontbutton.c:396
+msgid "Sans 12"
+msgstr "Sans 12"
+
+#: gtk/deprecated/gtkfontbutton.c:507 gtk/deprecated/gtkfontbutton.c:624 gtk/gtkfontdialog.c:594
+msgid "Pick a Font"
+msgstr "एउटा फन्ट छान्नुहोस्"
+
+#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3848 gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:285
+msgid "Font"
+msgstr "फन्ट"
+
+#: gtk/deprecated/gtkfontbutton.c:1155 gtk/gtkfontdialogbutton.c:652
+msgctxt "font"
+msgid "None"
+msgstr "None"
+
+#: gtk/deprecated/gtklockbutton.c:294 gtk/ui/gtklockbutton.ui:20
+msgid "Lock"
+msgstr "ताल्चा लगाउनुहोस्"
+
+#: gtk/deprecated/gtklockbutton.c:308 gtk/ui/gtklockbutton.ui:26
+msgid "Unlock"
+msgstr "ताल्चा खोल्नुहोस्"
+
+#: gtk/deprecated/gtklockbutton.c:322
+msgid ""
+"Dialog is unlocked.\n"
+"Click to prevent further changes"
+msgstr ""
+
+#: gtk/deprecated/gtklockbutton.c:336
+msgid ""
+"Dialog is locked.\n"
+"Click to make changes"
+msgstr ""
+
+#: gtk/deprecated/gtklockbutton.c:350
+msgid ""
+"System policy prevents changes.\n"
+"Contact your system administrator"
+msgstr ""
+"प्रणाली नीति परिवर्तन गर्न दिदैन ।\n"
+"तपाईँको प्रणाली प्रशासकलाई सम्पर्क गर्नुहोस्"
+
+#: gtk/deprecated/gtkshow.c:217
+msgid "Could not show link"
+msgstr "लिङ्क देखाउन सकेन"
+
+#: gtk/deprecated/gtkvolumebutton.c:236
+msgid "Muted"
+msgstr "मौन गरिएको"
+
+#: gtk/deprecated/gtkvolumebutton.c:240
+msgid "Full Volume"
+msgstr "पूर्ण भोल्युम"
+
+#. Translators: this is the percentage of the current volume,
+#. * as used in the tooltip, eg. "49 %".
+#. * Translate the "%d" to "%Id" if you want to use localised digits,
+#. * or otherwise translate the "%d" to "%d".
+#.
+#: gtk/deprecated/gtkvolumebutton.c:253
+#, c-format
+msgctxt "volume percentage"
+msgid "%d %%"
+msgstr "%d %%"
 
-#: gtk/gtkaboutdialog.c:124
+#: gtk/gtkaboutdialog.c:125 gtk/ui/gtkaboutdialog.ui:173
 msgid "License"
 msgstr "इजाजतपत्र"
 
-#: gtk/gtkaboutdialog.c:125
+#: gtk/gtkaboutdialog.c:126
 msgid "Custom License"
 msgstr "अनुकूल इजाजतपत्र"
 
-#: gtk/gtkaboutdialog.c:126
+#: gtk/gtkaboutdialog.c:127
 msgid "GNU General Public License, version 2 or later"
 msgstr "GNU सामान्य सार्वजनिक लाइसेन्स, संस्करण २ वा पछिल्लो"
 
-#: gtk/gtkaboutdialog.c:127
+#: gtk/gtkaboutdialog.c:128
 msgid "GNU General Public License, version 3 or later"
 msgstr "GNU सामान्य सार्वजनिक लाइसेन्स, संस्करण ३ वा पछिल्लो"
 
-#: gtk/gtkaboutdialog.c:128
+#: gtk/gtkaboutdialog.c:129
 msgid "GNU Lesser General Public License, version 2.1 or later"
 msgstr "GNU कम्ति साधारण सार्वजनिक इजाजतपत्र, संस्करण २. १ वा पछिल्लो"
 
-#: gtk/gtkaboutdialog.c:129
+#: gtk/gtkaboutdialog.c:130
 msgid "GNU Lesser General Public License, version 3 or later"
 msgstr "GNU कम्ति साधारण सार्वजनिक इजाजतपत्र, संस्करण ३ वा पछिल्लो"
 
-#: gtk/gtkaboutdialog.c:130
+#: gtk/gtkaboutdialog.c:131
 msgid "BSD 2-Clause License"
 msgstr "BSD २ बुदे अनुमतिपत्र"
 
-#: gtk/gtkaboutdialog.c:131
+#: gtk/gtkaboutdialog.c:132
 msgid "The MIT License (MIT)"
 msgstr "MIT इजाजतपत्र (MIT)"
 
-#: gtk/gtkaboutdialog.c:132
+#: gtk/gtkaboutdialog.c:133
 msgid "Artistic License 2.0"
 msgstr "Artistic अनुमतीपत्र २.०"
 
-#: gtk/gtkaboutdialog.c:133
+#: gtk/gtkaboutdialog.c:134
 msgid "GNU General Public License, version 2 only"
 msgstr "GNU सामान्य सार्वजनिक लाइसेन्स, संस्करण २ मात्र"
 
-#: gtk/gtkaboutdialog.c:134
+#: gtk/gtkaboutdialog.c:135
 msgid "GNU General Public License, version 3 only"
 msgstr "GNU सामान्य सार्वजनिक लाइसेन्स, संस्करण ३ मात्र"
 
-#: gtk/gtkaboutdialog.c:135
+#: gtk/gtkaboutdialog.c:136
 msgid "GNU Lesser General Public License, version 2.1 only"
 msgstr "GNU कम्ति साधारण सार्वजनिक इजाजतपत्र, संस्करण २. १ मात्र"
 
-#: gtk/gtkaboutdialog.c:136
+#: gtk/gtkaboutdialog.c:137
 msgid "GNU Lesser General Public License, version 3 only"
 msgstr "GNU कम्ति साधारण सार्वजनिक इजाजतपत्र, संस्करण ३ मात्र"
 
-#: gtk/gtkaboutdialog.c:137
+#: gtk/gtkaboutdialog.c:138
 msgid "GNU Affero General Public License, version 3 or later"
 msgstr "GNU Affero सामान्य सार्वजनिक ईजाजतपत्र संस्करण ३ वा पछिल्लो"
 
-#: gtk/gtkaboutdialog.c:138
+#: gtk/gtkaboutdialog.c:139
 msgid "GNU Affero General Public License, version 3 only"
 msgstr "GNU Affero सामान्य सार्वजनिक ईजाजतपत्र संस्करण ३ मात्र"
 
-#: gtk/gtkaboutdialog.c:139
+#: gtk/gtkaboutdialog.c:140
 msgid "BSD 3-Clause License"
 msgstr "BSD ३ बुदे अनुमतिपत्र"
 
-#: gtk/gtkaboutdialog.c:140
+#: gtk/gtkaboutdialog.c:141
 msgid "Apache License, Version 2.0"
 msgstr "Apache License, Version 2.0"
 
-#: gtk/gtkaboutdialog.c:141
+#: gtk/gtkaboutdialog.c:142
 msgid "Mozilla Public License 2.0"
 msgstr "मोजिला सार्वजनिक अनुमतीपत्र २.०"
 
-#: gtk/gtkaboutdialog.c:969
+#: gtk/gtkaboutdialog.c:143
+msgid "BSD Zero-Clause License"
+msgstr "बीएसडी जीरो-क्लॉज लाइसेंस"
+
+#: gtk/gtkaboutdialog.c:1028
 msgid "Website"
 msgstr "वेबसाइट"
 
-#: gtk/gtkaboutdialog.c:1005 gtk/ui/gtkapplication-quartz.ui:6
+#: gtk/gtkaboutdialog.c:1070 gtk/ui/gtkapplication-quartz.ui:6
 #, c-format
 msgid "About %s"
 msgstr "%s का बारेमा"
 
-#: gtk/gtkaboutdialog.c:2106
+#: gtk/gtkaboutdialog.c:2164
 msgid "Created by"
 msgstr "सिर्जिक"
 
-#: gtk/gtkaboutdialog.c:2109
+#: gtk/gtkaboutdialog.c:2167
 msgid "Documented by"
 msgstr "मिसिलिकरण"
 
-#: gtk/gtkaboutdialog.c:2119
+#: gtk/gtkaboutdialog.c:2177
 msgid "Translated by"
 msgstr "अनुवाद"
 
-#: gtk/gtkaboutdialog.c:2124
+#: gtk/gtkaboutdialog.c:2182
 msgid "Design by"
 msgstr "डिजाइन गर्ने"
 
 #. Translators: this is the license preamble; the string at the end
 #. * contains the name of the license as link text.
 #.
-#: gtk/gtkaboutdialog.c:2289
+#: gtk/gtkaboutdialog.c:2347
 #, c-format
 msgid ""
 "This program comes with absolutely no warranty.\n"
 "See the <a href=\"%s\">%s</a> for details."
 msgstr ""
 "यो कार्यक्रम पूर्णतया कुनै वारेन्टीसँग आउँदैन ।\n"
-"विस्तृत विवरणका लागि <a href=\"%s\">%s</a> हेर्नुहोस् ।"
+"विस्तृत विवरणका लागि <a href=\"%s\">%s</a> हेर्नुहोस् ।."
 
 #. This is the text that should appear next to menu accelerators
 #. * that use the shift key. If the text on this key isn't typically
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:837 gtk/gtkshortcutlabel.c:100 gtk/gtkshortcutlabel.c:136
+#: gtk/gtkaccelgroup.c:839 gtk/gtkshortcutlabel.c:101 gtk/gtkshortcutlabel.c:137
 msgctxt "keyboard label"
 msgid "Shift"
 msgstr "Shift"
@@ -1062,7 +1273,7 @@ msgstr "Shift"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:856 gtk/gtkshortcutlabel.c:103 gtk/gtkshortcutlabel.c:138
+#: gtk/gtkaccelgroup.c:858 gtk/gtkshortcutlabel.c:104 gtk/gtkshortcutlabel.c:139
 msgctxt "keyboard label"
 msgid "Ctrl"
 msgstr "Ctrl"
@@ -1072,7 +1283,7 @@ msgstr "Ctrl"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:875 gtk/gtkshortcutlabel.c:106 gtk/gtkshortcutlabel.c:140
+#: gtk/gtkaccelgroup.c:877 gtk/gtkshortcutlabel.c:107 gtk/gtkshortcutlabel.c:141
 msgctxt "keyboard label"
 msgid "Alt"
 msgstr "Alt"
@@ -1082,7 +1293,7 @@ msgstr "Alt"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:893 gtk/gtkshortcutlabel.c:112 gtk/gtkshortcutlabel.c:142
+#: gtk/gtkaccelgroup.c:895 gtk/gtkshortcutlabel.c:113 gtk/gtkshortcutlabel.c:143
 msgctxt "keyboard label"
 msgid "Super"
 msgstr "Super"
@@ -1092,7 +1303,7 @@ msgstr "Super"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:907 gtk/gtkshortcutlabel.c:115 gtk/gtkshortcutlabel.c:144
+#: gtk/gtkaccelgroup.c:909 gtk/gtkshortcutlabel.c:116 gtk/gtkshortcutlabel.c:145
 msgctxt "keyboard label"
 msgid "Hyper"
 msgstr "Hyper"
@@ -1102,7 +1313,7 @@ msgstr "Hyper"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:922 gtk/gtkshortcutlabel.c:109 gtk/gtkshortcutlabel.c:146
+#: gtk/gtkaccelgroup.c:924 gtk/gtkshortcutlabel.c:110 gtk/gtkshortcutlabel.c:148
 msgctxt "keyboard label"
 msgid "Meta"
 msgstr "Meta"
@@ -1111,485 +1322,463 @@ msgstr "Meta"
 #. * be used in accelerators such as "Ctrl+Shift+KP 1" in menus,
 #. * and therefore the translation needs to be very short.
 #.
-#: gtk/gtkaccelgroup.c:942
+#: gtk/gtkaccelgroup.c:944
 msgctxt "keyboard label"
 msgid "KP"
 msgstr "KP"
 
-#: gtk/gtkaccelgroup.c:949
+#: gtk/gtkaccelgroup.c:951
 msgctxt "keyboard label"
 msgid "Space"
 msgstr "खाली स्थान"
 
-#: gtk/gtkaccelgroup.c:952 gtk/gtkshortcutlabel.c:171
+#: gtk/gtkaccelgroup.c:954 gtk/gtkshortcutlabel.c:176
 msgctxt "keyboard label"
 msgid "Backslash"
 msgstr "ब्याकस्ल्यास"
 
-#: gtk/gtkaccessible.c:560
+#: gtk/gtkaccessible.c:790
 msgctxt "accessibility"
 msgid "alert"
 msgstr "सावधान"
 
-#: gtk/gtkaccessible.c:561
+#: gtk/gtkaccessible.c:791
 msgctxt "accessibility"
 msgid "alert dialog"
 msgstr "सावधान संवाद"
 
-#: gtk/gtkaccessible.c:562
+#: gtk/gtkaccessible.c:792
 msgctxt "accessibility"
 msgid "banner"
 msgstr "ब्यानर"
 
-#: gtk/gtkaccessible.c:563
+#: gtk/gtkaccessible.c:793
 msgctxt "accessibility"
 msgid "button"
 msgstr "बटन"
 
-#: gtk/gtkaccessible.c:564
+#: gtk/gtkaccessible.c:794
 msgctxt "accessibility"
 msgid "caption"
 msgstr "क्याप्सन"
 
-#: gtk/gtkaccessible.c:565
+#: gtk/gtkaccessible.c:795
 msgctxt "accessibility"
 msgid "cell"
 msgstr "कक्ष"
 
-#: gtk/gtkaccessible.c:566
+#: gtk/gtkaccessible.c:796
 msgctxt "accessibility"
 msgid "checkbox"
 msgstr "जाँचबाकस"
 
-#: gtk/gtkaccessible.c:567
+#: gtk/gtkaccessible.c:797
 msgctxt "accessibility"
 msgid "column header"
 msgstr "स्तम्भ हेडर"
 
-#: gtk/gtkaccessible.c:568
+#: gtk/gtkaccessible.c:798
 msgctxt "accessibility"
 msgid "combo box"
 msgstr "कम्बो बाकस"
 
-#: gtk/gtkaccessible.c:569
+#: gtk/gtkaccessible.c:799
 msgctxt "accessibility"
 msgid "command"
 msgstr "आदेश"
 
-#: gtk/gtkaccessible.c:570
+#: gtk/gtkaccessible.c:800
 msgctxt "accessibility"
 msgid "composite"
 msgstr "संमिश्रित"
 
-#: gtk/gtkaccessible.c:571
+#: gtk/gtkaccessible.c:801
 msgctxt "accessibility"
 msgid "dialog"
 msgstr "संवाद"
 
-#: gtk/gtkaccessible.c:572
+#: gtk/gtkaccessible.c:802
 msgctxt "accessibility"
 msgid "document"
 msgstr "कागजात"
 
-#: gtk/gtkaccessible.c:573
+#: gtk/gtkaccessible.c:803
 msgctxt "accessibility"
 msgid "feed"
 msgstr "फिड"
 
-#: gtk/gtkaccessible.c:574
+#: gtk/gtkaccessible.c:804
 msgctxt "accessibility"
 msgid "form"
 msgstr "फारम"
 
-#: gtk/gtkaccessible.c:575
+#: gtk/gtkaccessible.c:805
 msgctxt "accessibility"
 msgid "generic"
 msgstr "सामान्य"
 
-#: gtk/gtkaccessible.c:576
+#: gtk/gtkaccessible.c:806
 msgctxt "accessibility"
 msgid "grid"
 msgstr "ग्रिड"
 
-#: gtk/gtkaccessible.c:577
+#: gtk/gtkaccessible.c:807
 msgctxt "accessibility"
 msgid "grid cell"
 msgstr "ग्रिड कक्ष"
 
-#: gtk/gtkaccessible.c:578
+#: gtk/gtkaccessible.c:808
 msgctxt "accessibility"
 msgid "group"
 msgstr "समूह"
 
-#: gtk/gtkaccessible.c:579
+#: gtk/gtkaccessible.c:809
 msgctxt "accessibility"
 msgid "heading"
 msgstr "हेडिङ"
 
-#: gtk/gtkaccessible.c:580
+#: gtk/gtkaccessible.c:810
 msgctxt "accessibility"
 msgid "image"
 msgstr "छवि"
 
-#: gtk/gtkaccessible.c:581
+#: gtk/gtkaccessible.c:811
 msgctxt "accessibility"
 msgid "input"
 msgstr "आगत"
 
-#: gtk/gtkaccessible.c:582
+#: gtk/gtkaccessible.c:812
 msgctxt "accessibility"
 msgid "label"
 msgstr "लेबुल"
 
-#: gtk/gtkaccessible.c:583
+#: gtk/gtkaccessible.c:813
 msgctxt "accessibility"
 msgid "landmark"
 msgstr "भूमिनिसान"
 
-#: gtk/gtkaccessible.c:584
+#: gtk/gtkaccessible.c:814
 msgctxt "accessibility"
 msgid "legend"
 msgstr ""
 
-#: gtk/gtkaccessible.c:585
+#: gtk/gtkaccessible.c:815
 msgctxt "accessibility"
 msgid "link"
 msgstr "लिङ्क"
 
-#: gtk/gtkaccessible.c:586
+#: gtk/gtkaccessible.c:816
 msgctxt "accessibility"
 msgid "list"
 msgstr "सूची"
 
-#: gtk/gtkaccessible.c:587
+#: gtk/gtkaccessible.c:817
 msgctxt "accessibility"
 msgid "list box"
 msgstr "सुची बाकस"
 
-#: gtk/gtkaccessible.c:588
+#: gtk/gtkaccessible.c:818
 msgctxt "accessibility"
 msgid "list item"
 msgstr "सूची वस्तु"
 
-#: gtk/gtkaccessible.c:589
+#: gtk/gtkaccessible.c:819
 msgctxt "accessibility"
 msgid "log"
 msgstr "दैनिकि"
 
-#: gtk/gtkaccessible.c:590
+#: gtk/gtkaccessible.c:820
 msgctxt "accessibility"
 msgid "main"
 msgstr "मुख्य"
 
-#: gtk/gtkaccessible.c:591
+#: gtk/gtkaccessible.c:821
 msgctxt "accessibility"
 msgid "marquee"
 msgstr "मार्की"
 
-#: gtk/gtkaccessible.c:592
+#: gtk/gtkaccessible.c:822
 msgctxt "accessibility"
 msgid "math"
 msgstr "गणित"
 
-#: gtk/gtkaccessible.c:593
+#: gtk/gtkaccessible.c:823
 msgctxt "accessibility"
 msgid "meter"
 msgstr "मिटर"
 
-#: gtk/gtkaccessible.c:594
+#: gtk/gtkaccessible.c:824
 msgctxt "accessibility"
 msgid "menu"
 msgstr "मेनु"
 
-#: gtk/gtkaccessible.c:595
+#: gtk/gtkaccessible.c:825
 msgctxt "accessibility"
 msgid "menu bar"
 msgstr "मेनु पट्टि"
 
-#: gtk/gtkaccessible.c:596
+#: gtk/gtkaccessible.c:826
 msgctxt "accessibility"
 msgid "menu item"
 msgstr "मेनु वस्तु"
 
-#: gtk/gtkaccessible.c:597
-#, fuzzy
+#: gtk/gtkaccessible.c:827
 msgctxt "accessibility"
 msgid "menu item checkbox"
-msgstr "मेनु वस्तु"
+msgstr "मेनु वस्तु जाँचबाकस"
 
-#: gtk/gtkaccessible.c:598
-#, fuzzy
+#: gtk/gtkaccessible.c:828
 msgctxt "accessibility"
 msgid "menu item radio"
-msgstr "रेडियो मेनु वस्तु"
+msgstr "मेनु वस्तु रेडियो"
 
-#: gtk/gtkaccessible.c:599
+#: gtk/gtkaccessible.c:829
 msgctxt "accessibility"
 msgid "navigation"
 msgstr "नेभिगेशन"
 
-#: gtk/gtkaccessible.c:600
+#: gtk/gtkaccessible.c:830
 msgctxt "accessibility"
 msgid "none"
 msgstr "none"
 
-#: gtk/gtkaccessible.c:601
+#: gtk/gtkaccessible.c:831
 msgctxt "accessibility"
 msgid "note"
 msgstr "द्रष्टव्य"
 
-#: gtk/gtkaccessible.c:602
+#: gtk/gtkaccessible.c:832
 msgctxt "accessibility"
 msgid "option"
 msgstr "विकल्प"
 
-#: gtk/gtkaccessible.c:603
+#: gtk/gtkaccessible.c:833
 msgctxt "accessibility"
 msgid "presentation"
 msgstr "प्रस्तुतिकरण"
 
-#: gtk/gtkaccessible.c:604
+#: gtk/gtkaccessible.c:834
 msgctxt "accessibility"
 msgid "progress bar"
 msgstr "प्रगति पट्टि"
 
-#: gtk/gtkaccessible.c:605
+#: gtk/gtkaccessible.c:835
 msgctxt "accessibility"
 msgid "radio"
 msgstr "रेडियो"
 
-#: gtk/gtkaccessible.c:606
-#, fuzzy
+#: gtk/gtkaccessible.c:836
 msgctxt "accessibility"
 msgid "radio group"
-msgstr "रेडियो"
+msgstr ""
 
-#: gtk/gtkaccessible.c:607
+#: gtk/gtkaccessible.c:837
 msgctxt "accessibility"
 msgid "range"
 msgstr "दायरा"
 
-#: gtk/gtkaccessible.c:608
+#: gtk/gtkaccessible.c:838
 msgctxt "accessibility"
 msgid "region"
 msgstr "क्षेत्र"
 
-#: gtk/gtkaccessible.c:609
+#: gtk/gtkaccessible.c:839
 msgctxt "accessibility"
 msgid "row"
 msgstr "पङ्क्ति"
 
-#: gtk/gtkaccessible.c:610
+#: gtk/gtkaccessible.c:840
 msgctxt "accessibility"
 msgid "row group"
 msgstr "पङ्क्ति समूह"
 
-#: gtk/gtkaccessible.c:611
+#: gtk/gtkaccessible.c:841
 msgctxt "accessibility"
 msgid "row header"
 msgstr "पङ्क्ति हेडर"
 
-#: gtk/gtkaccessible.c:612
+#: gtk/gtkaccessible.c:842
 msgctxt "accessibility"
 msgid "scroll bar"
 msgstr "स्क्रोलपट्टी"
 
-#: gtk/gtkaccessible.c:613
+#: gtk/gtkaccessible.c:843
 msgctxt "accessibility"
 msgid "search"
 msgstr "खोजी गर्नुहोस्"
 
-#: gtk/gtkaccessible.c:614
+#: gtk/gtkaccessible.c:844
 msgctxt "accessibility"
 msgid "search box"
 msgstr "खोज बाकस"
 
-#: gtk/gtkaccessible.c:615
+#: gtk/gtkaccessible.c:845
 msgctxt "accessibility"
 msgid "section"
 msgstr "सेक्सन"
 
-#: gtk/gtkaccessible.c:616
+#: gtk/gtkaccessible.c:846
 msgctxt "accessibility"
 msgid "section head"
 msgstr "सेक्सन शिर्ष"
 
-#: gtk/gtkaccessible.c:617
+#: gtk/gtkaccessible.c:847
 msgctxt "accessibility"
 msgid "select"
 msgstr "चयन गर्नुहोस्"
 
-#: gtk/gtkaccessible.c:618
+#: gtk/gtkaccessible.c:848
 msgctxt "accessibility"
 msgid "separator"
 msgstr "विभाजक"
 
-#: gtk/gtkaccessible.c:619
+#: gtk/gtkaccessible.c:849
 msgctxt "accessibility"
 msgid "slider"
 msgstr "स्लाइडर"
 
-#: gtk/gtkaccessible.c:620
+#: gtk/gtkaccessible.c:850
 msgctxt "accessibility"
 msgid "spin button"
 msgstr "स्पिन बटन"
 
-#: gtk/gtkaccessible.c:621
+#: gtk/gtkaccessible.c:851
 msgctxt "accessibility"
 msgid "status"
 msgstr "स्थिति"
 
-#: gtk/gtkaccessible.c:622
+#: gtk/gtkaccessible.c:852
 msgctxt "accessibility"
 msgid "structure"
 msgstr "संरचना"
 
-#: gtk/gtkaccessible.c:623
+#: gtk/gtkaccessible.c:853
 msgctxt "accessibility"
 msgid "switch"
 msgstr "स्विच"
 
-#: gtk/gtkaccessible.c:624
+#: gtk/gtkaccessible.c:854
 msgctxt "accessibility"
 msgid "tab"
 msgstr "ट्याब"
 
-#: gtk/gtkaccessible.c:625
+#: gtk/gtkaccessible.c:855
 msgctxt "accessibility"
 msgid "table"
 msgstr "तालिका"
 
-#: gtk/gtkaccessible.c:626
+#: gtk/gtkaccessible.c:856
 msgctxt "accessibility"
 msgid "tab list"
 msgstr "ट्याब सूची"
 
-#: gtk/gtkaccessible.c:627
+#: gtk/gtkaccessible.c:857
 msgctxt "accessibility"
 msgid "tab panel"
 msgstr "ट्याब प्यानल"
 
-#: gtk/gtkaccessible.c:628
+#: gtk/gtkaccessible.c:858
 msgctxt "accessibility"
 msgid "text box"
 msgstr "पाठ बाकस"
 
-#: gtk/gtkaccessible.c:629
+#: gtk/gtkaccessible.c:859
 msgctxt "accessibility"
 msgid "time"
 msgstr "समय"
 
-#: gtk/gtkaccessible.c:630
+#: gtk/gtkaccessible.c:860
 msgctxt "accessibility"
 msgid "timer"
 msgstr "समयक"
 
-#: gtk/gtkaccessible.c:631
+#: gtk/gtkaccessible.c:861
 msgctxt "accessibility"
 msgid "tool bar"
 msgstr "उपकरणपट्टी"
 
-#: gtk/gtkaccessible.c:632
+#: gtk/gtkaccessible.c:862
 msgctxt "accessibility"
 msgid "tool tip"
 msgstr "टुल टिप"
 
-#: gtk/gtkaccessible.c:633
+#: gtk/gtkaccessible.c:863
 msgctxt "accessibility"
 msgid "tree"
 msgstr "ट्रि"
 
-#: gtk/gtkaccessible.c:634
-#, fuzzy
+#: gtk/gtkaccessible.c:864
 msgctxt "accessibility"
 msgid "tree grid"
-msgstr "ट्रि"
+msgstr ""
 
-#: gtk/gtkaccessible.c:635
+#: gtk/gtkaccessible.c:865
 msgctxt "accessibility"
 msgid "tree item"
 msgstr "ट्रि सामाग्री"
 
-#: gtk/gtkaccessible.c:636
+#: gtk/gtkaccessible.c:866
 msgctxt "accessibility"
 msgid "widget"
 msgstr "औजार"
 
-#: gtk/gtkaccessible.c:637
+#: gtk/gtkaccessible.c:867
 msgctxt "accessibility"
 msgid "window"
 msgstr "सञ्झ्याल"
 
-#: gtk/gtkappchooserbutton.c:316
-msgid "Other application…"
-msgstr "अन्य अनुप्रयोग…"
-
-#: gtk/gtkappchooserdialog.c:205 gtk/gtkappchooserdialog.c:256
-msgid "Select Application"
-msgstr "एप्लिकेसन छनोट गर्नुहोस्"
-
-#. Translators: %s is a filename
-#: gtk/gtkappchooserdialog.c:212
-#, c-format
-msgid "Opening “%s”."
-msgstr "“%s” खोल्नुहोस्."
-
-#: gtk/gtkappchooserdialog.c:213
-#, c-format
-msgid "No applications found for “%s”"
-msgstr "“%s” को लागि अनुप्रयोग भेटिएन"
-
-#. Translators: %s is a file type description
-#: gtk/gtkappchooserdialog.c:218
-#, c-format
-msgid "Opening “%s” files."
-msgstr "\"%s\" फाइल खोल्दैछ।."
-
-#: gtk/gtkappchooserdialog.c:220
-#, c-format
-msgid "No applications found for “%s” files"
-msgstr "“%s” फाईलको लागि अनुप्रयोग भेटिएन"
+#: gtk/gtkaccessible.c:868
+msgctxt "accessibility"
+msgid "toggle button"
+msgstr "टगल बटन"
 
-#: gtk/gtkappchooserdialog.c:422
-msgid "Failed to start GNOME Software"
-msgstr "जिनोम सफ्टवेयर शुरु गर्न असक्षम"
+#: gtk/gtkaccessible.c:870
+msgctxt "accessibility"
+msgid "paragraph"
+msgstr "अनुच्छेद"
 
-#: gtk/gtkappchooserwidget.c:519
-msgid "Default Application"
-msgstr "पूर्वनिर्धारित अनुप्रयोग"
+#: gtk/gtkaccessible.c:871
+msgctxt "accessibility"
+msgid "block quote"
+msgstr "बाक्लो उद्धरण"
 
-#: gtk/gtkappchooserwidget.c:569
-#, c-format
-msgid "No applications found for “%s”."
-msgstr "“%s” को लागि अनुप्रयोग भेटिएन।"
+#: gtk/gtkaccessible.c:872
+msgctxt "accessibility"
+msgid "article"
+msgstr "लेख"
 
-#: gtk/gtkappchooserwidget.c:652
-msgid "Recommended Applications"
-msgstr "सिफारिस गरिएको अनुप्रयोग"
+#: gtk/gtkaccessible.c:873
+msgctxt "accessibility"
+msgid "comment"
+msgstr "टिप्पणी"
 
-#: gtk/gtkappchooserwidget.c:667
-msgid "Related Applications"
-msgstr "सम्बन्धित अनुप्रयोगहरू"
+#: gtk/gtkaccessible.c:874
+msgctxt "accessibility"
+msgid "terminal"
+msgstr "टर्मिनल"
 
-#: gtk/gtkappchooserwidget.c:681
-msgid "Other Applications"
-msgstr "अन्य अनुप्रयोगहरू"
+#: gtk/gtkalertdialog.c:667 gtk/print/gtkcustompaperunixdialog.c:322 gtk/gtkmessagedialog.c:166 gtk/ui/gtkassistant.ui:40
+msgid "_Close"
+msgstr "_Close"
 
 #. Translators: This is the 'reason' given when inhibiting
 #. * suspend or screen locking, and the caller hasn't specified
 #. * a reason.
 #.
-#: gtk/gtkapplication-dbus.c:706
-#, fuzzy
+#: gtk/gtkapplication-dbus.c:724 gtk/gtkapplication-dbus.c:766
 msgid "Reason not specified"
-msgstr "कारण छैन."
+msgstr "कारण निर्दिष्ट गरिएको छैन"
 
-#: gtk/gtkbookmarksmanager.c:51
+#: gtk/gtkapplicationwindow.c:236
+msgid "Menu bar"
+msgstr "मेनु पट्टि"
+
+#: gtk/gtkbookmarksmanager.c:53
 #, c-format
 msgid "%s does not exist in the bookmarks list"
 msgstr "%s पुस्तकचिनो सूचीमा अवस्थित छैन ।."
 
-#: gtk/gtkbookmarksmanager.c:412
+#: gtk/gtkbookmarksmanager.c:414
 #, c-format
 msgid "%s already exists in the bookmarks list"
 msgstr "%s पुस्तकचिनो सूचीमा पहिले नै अवस्थित छ"
@@ -1613,7 +1802,7 @@ msgstr "पाठ <%s> भित्र देखा पर्दैन"
 #. * first day of the week to calendar:week_start:1 if you want Monday
 #. * to be the first day of the week, and so on.
 #.
-#: gtk/gtkcalendar.c:668
+#: gtk/gtkcalendar.c:670
 msgid "calendar:week_start:0"
 msgstr "calendar:week_start:0"
 
@@ -1627,21 +1816,10 @@ msgstr "calendar:week_start:0"
 #. * text direction of RTL and specify "calendar:YM", then the year
 #. * will appear to the right of the month.
 #.
-#: gtk/gtkcalendar.c:819
+#: gtk/gtkcalendar.c:821
 msgid "calendar:MY"
 msgstr "calendar:MY"
 
-#. Translators: This dictates how the year is displayed in
-#. * gtkcalendar widget.  See strftime() manual for the format.
-#. * Use only ASCII in the translation.
-#. *
-#. * "%Y" is appropriate for most locales.
-#.
-#: gtk/gtkcalendar.c:1406
-msgctxt "calendar year format"
-msgid "%Y"
-msgstr "%Y"
-
 #. Translators: this defines whether the day numbers should use
 #. * localized digits or the ones used in English (0123...).
 #. *
@@ -1652,12 +1830,23 @@ msgstr "%Y"
 #. * digits. That needs support from your system and locale definition
 #. * too.
 #.
-#: gtk/gtkcalendar.c:1443
+#: gtk/gtkcalendar.c:1002
 #, c-format
 msgctxt "calendar:day:digits"
 msgid "%d"
 msgstr "%d"
 
+#. Translators: This dictates how the year is displayed in
+#. * gtkcalendar widget.  See strftime() manual for the format.
+#. * Use only ASCII in the translation.
+#. *
+#. * "%Y" is appropriate for most locales.
+#.
+#: gtk/gtkcalendar.c:1106
+msgctxt "calendar year format"
+msgid "%Y"
+msgstr "%Y"
+
 #. Translators: this defines whether the week numbers should use
 #. * localized digits or the ones used in English (0123...).
 #. *
@@ -1666,298 +1855,257 @@ msgstr "%d"
 #. * Note that translating this doesn't guarantee that you get localized
 #. * digits. That needs support from your system and locale definition
 #. * too.
-#: gtk/gtkcalendar.c:1507
+#: gtk/gtkcalendar.c:1152
 #, c-format
 msgctxt "calendar:week:digits"
 msgid "%d"
 msgstr "%d"
 
-#. This label is displayed in a treeview cell displaying
-#. * a disabled accelerator key combination.
-#.
-#: gtk/gtkcellrendereraccel.c:295
-msgctxt "Accelerator"
-msgid "Disabled"
-msgstr "असक्षम पारिएको छ"
-
-#. This label is displayed in a treeview cell displaying
-#. * an accelerator key combination that is not valid according
-#. * to gtk_accelerator_valid().
-#.
-#: gtk/gtkcellrendereraccel.c:305
-msgctxt "Accelerator"
-msgid "Invalid"
-msgstr "अवैध"
-
-#. This label is displayed in a treeview cell displaying an accelerator
-#. * when the cell is clicked to change the acelerator.
-#.
-#: gtk/gtkcellrendereraccel.c:437 gtk/gtkcellrendereraccel.c:730
-msgid "New accelerator…"
-msgstr "नयाँ एक्सेलेरेटर…"
-
-#: gtk/gtkcellrendererprogress.c:128 gtk/gtkcellrendererprogress.c:318
-#: gtk/gtkcellrendererprogress.c:348
-#, c-format
-msgctxt "progress bar label"
-msgid "%d %%"
-msgstr "%d %%"
-
-#: gtk/gtkcolorbutton.c:181 gtk/gtkcolorbutton.c:311
-msgid "Pick a Color"
-msgstr "एउटा रङ छान्नुहोस्"
-
-#: gtk/gtkcolorbutton.c:500 gtk/gtkcolorchooserwidget.c:308
-#, c-format
-msgid "Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"
-msgstr "रातो %d%%, हारियो %d%%, निलो %d%%, अल्फा %d%%"
-
-#: gtk/gtkcolorbutton.c:506 gtk/gtkcolorchooserwidget.c:314
-#, c-format
-msgid "Red %d%%, Green %d%%, Blue %d%%"
-msgstr "रातो %d%%, हरियो %d%%, निलो %d%%"
-
-#: gtk/gtkcolorchooserwidget.c:371
+#: gtk/gtkcolorchooserwidget.c:384 gtk/gtkcoloreditor.c:171
 #, c-format
 msgid "Color: %s"
 msgstr "रङ्ग: %s"
 
-#: gtk/gtkcolorchooserwidget.c:436
+#: gtk/gtkcolorchooserwidget.c:449
 msgctxt "Color name"
 msgid "Very Light Blue"
 msgstr "धेरै हल्का निलो"
 
-#: gtk/gtkcolorchooserwidget.c:437
+#: gtk/gtkcolorchooserwidget.c:450
 msgctxt "Color name"
 msgid "Light Blue"
 msgstr "हल्का निलो"
 
-#: gtk/gtkcolorchooserwidget.c:438
+#: gtk/gtkcolorchooserwidget.c:451
 msgctxt "Color name"
 msgid "Blue"
 msgstr "नीलो"
 
-#: gtk/gtkcolorchooserwidget.c:439
+#: gtk/gtkcolorchooserwidget.c:452
 msgctxt "Color name"
 msgid "Dark Blue"
 msgstr "गाढा नीलो"
 
-#: gtk/gtkcolorchooserwidget.c:440
+#: gtk/gtkcolorchooserwidget.c:453
 msgctxt "Color name"
 msgid "Very Dark Blue"
 msgstr "धेरै गाढा नीलो"
 
-#: gtk/gtkcolorchooserwidget.c:441
+#: gtk/gtkcolorchooserwidget.c:454
 msgctxt "Color name"
 msgid "Very Light Green"
 msgstr "धेरै हल्का हरियो"
 
-#: gtk/gtkcolorchooserwidget.c:442
+#: gtk/gtkcolorchooserwidget.c:455
 msgctxt "Color name"
 msgid "Light Green"
 msgstr "हल्का हरियो"
 
-#: gtk/gtkcolorchooserwidget.c:443
+#: gtk/gtkcolorchooserwidget.c:456
 msgctxt "Color name"
 msgid "Green"
 msgstr "हरियो"
 
-#: gtk/gtkcolorchooserwidget.c:444
+#: gtk/gtkcolorchooserwidget.c:457
 msgctxt "Color name"
 msgid "Dark Green"
 msgstr "गाढा हरियो"
 
-#: gtk/gtkcolorchooserwidget.c:445
+#: gtk/gtkcolorchooserwidget.c:458
 msgctxt "Color name"
 msgid "Very Dark Green"
 msgstr "धेरै गाढा हरियो"
 
-#: gtk/gtkcolorchooserwidget.c:446
+#: gtk/gtkcolorchooserwidget.c:459
 msgctxt "Color name"
 msgid "Very Light Yellow"
 msgstr "धेरै हल्का पहेँलो"
 
-#: gtk/gtkcolorchooserwidget.c:447
+#: gtk/gtkcolorchooserwidget.c:460
 msgctxt "Color name"
 msgid "Light Yellow"
 msgstr "हल्का पहेँलो"
 
-#: gtk/gtkcolorchooserwidget.c:448
+#: gtk/gtkcolorchooserwidget.c:461
 msgctxt "Color name"
 msgid "Yellow"
 msgstr "पहेँलो"
 
-#: gtk/gtkcolorchooserwidget.c:449
+#: gtk/gtkcolorchooserwidget.c:462
 msgctxt "Color name"
 msgid "Dark Yellow"
 msgstr "गाढा पहेँलो"
 
-#: gtk/gtkcolorchooserwidget.c:450
+#: gtk/gtkcolorchooserwidget.c:463
 msgctxt "Color name"
 msgid "Very Dark Yellow"
 msgstr "धेरै गाढा पहेँलो"
 
-#: gtk/gtkcolorchooserwidget.c:451
+#: gtk/gtkcolorchooserwidget.c:464
 msgctxt "Color name"
 msgid "Very Light Orange"
 msgstr "धेरै फिक्का सुन्तला"
 
-#: gtk/gtkcolorchooserwidget.c:452
+#: gtk/gtkcolorchooserwidget.c:465
 msgctxt "Color name"
 msgid "Light Orange"
 msgstr "फिक्का सुन्तला"
 
-#: gtk/gtkcolorchooserwidget.c:453
+#: gtk/gtkcolorchooserwidget.c:466
 msgctxt "Color name"
 msgid "Orange"
 msgstr "सुन्तला"
 
-#: gtk/gtkcolorchooserwidget.c:454
+#: gtk/gtkcolorchooserwidget.c:467
 msgctxt "Color name"
 msgid "Dark Orange"
 msgstr "गाढा सुन्तला"
 
-#: gtk/gtkcolorchooserwidget.c:455
+#: gtk/gtkcolorchooserwidget.c:468
 msgctxt "Color name"
 msgid "Very Dark Orange"
 msgstr "धेरै गाढा सुन्तला"
 
-#: gtk/gtkcolorchooserwidget.c:456
+#: gtk/gtkcolorchooserwidget.c:469
 msgctxt "Color name"
 msgid "Very Light Red"
 msgstr "धेरै हल्का रातो"
 
-#: gtk/gtkcolorchooserwidget.c:457
+#: gtk/gtkcolorchooserwidget.c:470
 msgctxt "Color name"
 msgid "Light Red"
 msgstr "हल्का रातो"
 
-#: gtk/gtkcolorchooserwidget.c:458
+#: gtk/gtkcolorchooserwidget.c:471
 msgctxt "Color name"
 msgid "Red"
 msgstr "रातो"
 
-#: gtk/gtkcolorchooserwidget.c:459
+#: gtk/gtkcolorchooserwidget.c:472
 msgctxt "Color name"
 msgid "Dark Red"
 msgstr "गाढा रातो"
 
-#: gtk/gtkcolorchooserwidget.c:460
+#: gtk/gtkcolorchooserwidget.c:473
 msgctxt "Color name"
 msgid "Very Dark Red"
 msgstr "धेरै गाढा रातो"
 
-#: gtk/gtkcolorchooserwidget.c:461
+#: gtk/gtkcolorchooserwidget.c:474
 msgctxt "Color name"
 msgid "Very Light Purple"
 msgstr "धेरै हल्का बैजनी"
 
-#: gtk/gtkcolorchooserwidget.c:462
+#: gtk/gtkcolorchooserwidget.c:475
 msgctxt "Color name"
 msgid "Light Purple"
 msgstr "हल्का बैजनी"
 
-#: gtk/gtkcolorchooserwidget.c:463
+#: gtk/gtkcolorchooserwidget.c:476
 msgctxt "Color name"
 msgid "Purple"
 msgstr "बैजनी"
 
-#: gtk/gtkcolorchooserwidget.c:464
+#: gtk/gtkcolorchooserwidget.c:477
 msgctxt "Color name"
 msgid "Dark Purple"
 msgstr "बैजनी"
 
-#: gtk/gtkcolorchooserwidget.c:465
+#: gtk/gtkcolorchooserwidget.c:478
 msgctxt "Color name"
 msgid "Very Dark Purple"
 msgstr "धेरै गाढा बैजनी"
 
-#: gtk/gtkcolorchooserwidget.c:466
+#: gtk/gtkcolorchooserwidget.c:479
 msgctxt "Color name"
 msgid "Very Light Brown"
 msgstr "धेरै हल्का खैरो"
 
-#: gtk/gtkcolorchooserwidget.c:467
+#: gtk/gtkcolorchooserwidget.c:480
 msgctxt "Color name"
 msgid "Light Brown"
 msgstr "हल्का खैरो"
 
-#: gtk/gtkcolorchooserwidget.c:468
+#: gtk/gtkcolorchooserwidget.c:481
 msgctxt "Color name"
 msgid "Brown"
 msgstr "खैरो"
 
-#: gtk/gtkcolorchooserwidget.c:469
+#: gtk/gtkcolorchooserwidget.c:482
 msgctxt "Color name"
 msgid "Dark Brown"
 msgstr "गाढा खैरो"
 
-#: gtk/gtkcolorchooserwidget.c:470
+#: gtk/gtkcolorchooserwidget.c:483
 msgctxt "Color name"
 msgid "Very Dark Brown"
 msgstr "धेरै गाढा खैरो"
 
-#: gtk/gtkcolorchooserwidget.c:471
+#: gtk/gtkcolorchooserwidget.c:484
 msgctxt "Color name"
 msgid "White"
 msgstr "सेतो"
 
-#: gtk/gtkcolorchooserwidget.c:472
+#: gtk/gtkcolorchooserwidget.c:485
 msgctxt "Color name"
 msgid "Light Gray 1"
 msgstr "हल्का खैरो १"
 
-#: gtk/gtkcolorchooserwidget.c:473
+#: gtk/gtkcolorchooserwidget.c:486
 msgctxt "Color name"
 msgid "Light Gray 2"
 msgstr "हल्का खैरो २"
 
-#: gtk/gtkcolorchooserwidget.c:474
+#: gtk/gtkcolorchooserwidget.c:487
 msgctxt "Color name"
 msgid "Light Gray 3"
 msgstr "हल्का खैरो ३"
 
-#: gtk/gtkcolorchooserwidget.c:475
+#: gtk/gtkcolorchooserwidget.c:488
 msgctxt "Color name"
 msgid "Light Gray 4"
 msgstr "हल्का खैरो ४"
 
-#: gtk/gtkcolorchooserwidget.c:476
+#: gtk/gtkcolorchooserwidget.c:489
 msgctxt "Color name"
 msgid "Dark Gray 1"
 msgstr "गाढा खैरो १"
 
-#: gtk/gtkcolorchooserwidget.c:477
+#: gtk/gtkcolorchooserwidget.c:490
 msgctxt "Color name"
 msgid "Dark Gray 2"
 msgstr "गाढा खैरो २"
 
-#: gtk/gtkcolorchooserwidget.c:478
+#: gtk/gtkcolorchooserwidget.c:491
 msgctxt "Color name"
 msgid "Dark Gray 3"
 msgstr "गाढा खैरो ३"
 
-#: gtk/gtkcolorchooserwidget.c:479
+#: gtk/gtkcolorchooserwidget.c:492
 msgctxt "Color name"
 msgid "Dark Gray 4"
 msgstr "गाढा खैरो ४"
 
-#: gtk/gtkcolorchooserwidget.c:480
+#: gtk/gtkcolorchooserwidget.c:493
 msgctxt "Color name"
 msgid "Black"
 msgstr "कालो"
 
 #. translators: label for the custom section in the color chooser
-#: gtk/gtkcolorchooserwidget.c:552
+#: gtk/gtkcolorchooserwidget.c:565
 msgid "Custom"
 msgstr "अनुकूल"
 
-#: gtk/gtkcolorchooserwidget.c:585
+#: gtk/gtkcolorchooserwidget.c:579
+msgid "Add Color"
+msgstr "रङ थप्नुहोस्"
+
+#: gtk/gtkcolorchooserwidget.c:601
 #, c-format
 msgid "Custom color %d: %s"
 msgstr "अनुकूल रङ %d: %s"
 
-#: gtk/gtkcolorswatch.c:231
+#: gtk/gtkcolorswatch.c:230
 msgid "Customize"
 msgstr "अनुकूलन"
 
@@ -1967,74 +2115,69 @@ msgstr "अनुकूलन"
 #. * Do *not* translate it to "predefinito:mm", if it
 #. * it isn't default:mm or default:inch it will not work
 #.
-#: gtk/gtkcustompaperunixdialog.c:112
+#: gtk/print/gtkcustompaperunixdialog.c:106
 msgid "default:mm"
 msgstr "default:mm"
 
-#: gtk/gtkcustompaperunixdialog.c:318
-#, fuzzy
+#: gtk/print/gtkcustompaperunixdialog.c:291
 msgid "Margins from Printer…"
-msgstr "सीमान्तहरू"
-
-#: gtk/gtkcustompaperunixdialog.c:348 gtk/gtkmessagedialog.c:162
-msgid "_Close"
-msgstr "_Close"
+msgstr "मुद्रकबाट मार्जिन…"
 
 #. And show the custom paper dialog
-#: gtk/gtkcustompaperunixdialog.c:402 gtk/gtkprintunixdialog.c:3029
+#: gtk/print/gtkcustompaperunixdialog.c:377 gtk/print/gtkprintunixdialog.c:2976
 msgid "Manage Custom Sizes"
 msgstr "अनुकुलन साइजहरू प्रबन्ध गर्नुहोस्"
 
-#: gtk/gtkcustompaperunixdialog.c:466 gtk/gtkpagesetupunixdialog.c:720
+#: gtk/print/gtkcustompaperunixdialog.c:440 gtk/print/gtkpagesetupunixdialog.c:720
 msgid "inch"
 msgstr "इन्च"
 
-#: gtk/gtkcustompaperunixdialog.c:468 gtk/gtkpagesetupunixdialog.c:718
+#: gtk/print/gtkcustompaperunixdialog.c:442 gtk/print/gtkpagesetupunixdialog.c:718
 msgid "mm"
 msgstr "(मिलिमिटर) mm"
 
-#: gtk/gtkcustompaperunixdialog.c:625
+#: gtk/print/gtkcustompaperunixdialog.c:598
 #, c-format
 msgid "Custom Size %d"
 msgstr "अनुकुलन साइज %d"
 
-#: gtk/gtkcustompaperunixdialog.c:939
+#: gtk/print/gtkcustompaperunixdialog.c:908
 msgid "_Width:"
 msgstr "_चौडाइ:"
 
-#: gtk/gtkcustompaperunixdialog.c:950
+#: gtk/print/gtkcustompaperunixdialog.c:917
 msgid "_Height:"
 msgstr "उचाइ:"
 
-#: gtk/gtkcustompaperunixdialog.c:961
+#: gtk/print/gtkcustompaperunixdialog.c:926
 msgid "Paper Size"
 msgstr "कागज साइज"
 
-#: gtk/gtkcustompaperunixdialog.c:970
+#: gtk/print/gtkcustompaperunixdialog.c:933
 msgid "_Top:"
 msgstr "_माथि:"
 
-#: gtk/gtkcustompaperunixdialog.c:981
+#: gtk/print/gtkcustompaperunixdialog.c:942
 msgid "_Bottom:"
 msgstr "_तल:"
 
-#: gtk/gtkcustompaperunixdialog.c:992
+#: gtk/print/gtkcustompaperunixdialog.c:951
 msgid "_Left:"
 msgstr "_बायाँ:"
 
-#: gtk/gtkcustompaperunixdialog.c:1003
+#: gtk/print/gtkcustompaperunixdialog.c:960
 msgid "_Right:"
 msgstr "_दायाँ:"
 
-#: gtk/gtkcustompaperunixdialog.c:1039
+#: gtk/print/gtkcustompaperunixdialog.c:993
 msgid "Paper Margins"
 msgstr "कागज सिमान्तहरू"
 
-#: gtk/gtkentry.c:3743
+#: gtk/gtkentry.c:3685
 msgid "Insert Emoji"
 msgstr "ई-मोजि घुसाउनुहोस्"
 
-#: gtk/gtkfilechooserdialog.c:551
+#: gtk/gtkfilechooserdialog.c:557
 msgid "_Name"
 msgstr "नाम"
 
@@ -2048,7 +2191,7 @@ msgstr "“.” नाममा फाइल राख्न सकिँदै
 
 #: gtk/gtkfilechoosererrorstack.c:73
 msgid "A folder cannot be called “..”"
-msgstr "“..” नाममा फोल्डर राख्न सकिँदैन "
+msgstr "“..” नाममा फोल्डर राख्न सकिँदैन"
 
 #: gtk/gtkfilechoosererrorstack.c:77
 msgid "A file cannot be called “..”"
@@ -2084,7 +2227,7 @@ msgstr "\".\" बाट सुरु भएको फोल्डर नाम
 
 #: gtk/gtkfilechoosererrorstack.c:109
 msgid "File names starting with a “.” are hidden"
-msgstr "\".\" बाट सुरु भएको फाइल नामहरू लुकेका छन् ।"
+msgstr "\".\" बाट सुरु भएको फाइल नामहरू लुकेका छन्"
 
 #: gtk/gtkfilechoosererrorstack.c:113
 msgid "A folder with that name already exists"
@@ -2094,24 +2237,22 @@ msgstr "\"%s\" मा उही नामको नया फोल्डर प
 msgid "A file with that name already exists"
 msgstr "यो नामको फाइल पहिल्यै अवस्थित छ"
 
-#: gtk/gtkfilechoosernative.c:509 gtk/gtkfilechoosernative.c:580 gtk/gtkfilechooserwidget.c:1209
-#: gtk/gtkfilechooserwidget.c:5780 gtk/gtkmessagedialog.c:166 gtk/gtkmessagedialog.c:175
-#: gtk/gtkmountoperation.c:610 gtk/gtkpagesetupunixdialog.c:283 gtk/gtkprintbackend.c:642
-#: gtk/gtkprinteroptionwidget.c:713 gtk/gtkprintunixdialog.c:667 gtk/gtkprintunixdialog.c:823
-#: gtk/gtkwindow.c:6154 gtk/inspector/css-editor.c:248 gtk/inspector/recorder.c:1706
+#: gtk/gtkfilechoosernative.c:520 gtk/gtkfilechoosernative.c:600 gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:5018 gtk/gtkfiledialog.c:840
+#: gtk/gtkmessagedialog.c:170 gtk/gtkmessagedialog.c:179 gtk/gtkmountoperation.c:608 gtk/print/gtkpagesetupunixdialog.c:282 gtk/print/gtkprintbackend.c:638
+#: gtk/print/gtkprintunixdialog.c:682 gtk/print/gtkprintunixdialog.c:839 gtk/gtkwindow.c:6211 gtk/ui/gtkappchooserdialog.ui:48 gtk/ui/gtkassistant.ui:52
+#: gtk/ui/gtkcolorchooserdialog.ui:36 gtk/ui/gtkfontchooserdialog.ui:29
 msgid "_Cancel"
 msgstr "रद्द गर्नुहोस्"
 
-#: gtk/gtkfilechoosernative.c:510 gtk/gtkfilechoosernative.c:574 gtk/gtkplacessidebar.c:3128
-#: gtk/gtkplacessidebar.c:3213 gtk/gtkplacesview.c:1658
+#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594 gtk/gtkfiledialog.c:812 gtk/gtkplacessidebar.c:3149 gtk/gtkplacessidebar.c:3234 gtk/gtkplacesview.c:1645
 msgid "_Open"
 msgstr "खोल्नुहोस्"
 
-#: gtk/gtkfilechoosernative.c:574 gtk/inspector/css-editor.c:249 gtk/inspector/recorder.c:1707
+#: gtk/gtkfilechoosernative.c:594 gtk/gtkfiledialog.c:817
 msgid "_Save"
 msgstr "सङ्ग्रह गर्नुहोस्"
 
-#: gtk/gtkfilechoosernativequartz.c:338
+#: gtk/gtkfilechoosernativequartz.c:348 gtk/ui/gtkfilechooserwidget.ui:299
 msgid "Select which types of files are shown"
 msgstr "कुन प्रकारहरूको फाइलहरू देखाइएको छ चयन गर्नुहोस्"
 
@@ -2119,423 +2260,446 @@ msgstr "कुन प्रकारहरूको फाइलहरू दे
 #. * is a hostname. Nautilus and the panel contain the same string
 #. * to translate.
 #.
-#: gtk/gtkfilechooserutils.c:361
+#: gtk/gtkfilechooserutils.c:364
 #, c-format
 msgid "%1$s on %2$s"
 msgstr "%1$s %2$s सम्म"
 
-#: gtk/gtkfilechooserwidget.c:318
+#: gtk/gtkfilechooserwidget.c:365
 msgid "Type name of new folder"
 msgstr "नयाँ फोल्डरको नाम टाइप गर्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:723
+#: gtk/gtkfilechooserwidget.c:752
 msgid "The folder could not be created"
 msgstr "फोल्डर सिर्जना गर्न सकिएन"
 
-#: gtk/gtkfilechooserwidget.c:736
+#: gtk/gtkfilechooserwidget.c:765
 msgid "You need to choose a valid filename."
-msgstr "तपाईँले वैध फाइलनाम छनोट गर्नु आवश्यक हुन्छ ।"
+msgstr "तपाईँले वैध फाइलनाम छनोट गर्नु आवश्यक हुन्छ ।."
 
-#: gtk/gtkfilechooserwidget.c:739
+#: gtk/gtkfilechooserwidget.c:768
 #, c-format
 msgid "Cannot create a file under %s as it is not a folder"
 msgstr "फाइल सिर्जना गर्न सकेन %s"
 
-#: gtk/gtkfilechooserwidget.c:749
+#: gtk/gtkfilechooserwidget.c:778
 msgid "Cannot create file as the filename is too long"
 msgstr "फाइलनाम धेरै लामो भएकोले फाइल सिर्जना गर्न सकिँदैन"
 
-#: gtk/gtkfilechooserwidget.c:750
+#: gtk/gtkfilechooserwidget.c:779
 msgid "Try using a shorter name."
-msgstr "छोटो नाम प्रयोग गरेर प्रयास गर्नुहोस् ।"
+msgstr "छोटो नाम प्रयोग गरेर प्रयास गर्नुहोस् ।."
 
-#: gtk/gtkfilechooserwidget.c:760
+#: gtk/gtkfilechooserwidget.c:789
 msgid "You may only select folders"
 msgstr "तपाईँले फोल्डरहरू मात्र चयन गर्न सक्नुहुन्छ"
 
-#: gtk/gtkfilechooserwidget.c:761
+#: gtk/gtkfilechooserwidget.c:790
 msgid "The item that you selected is not a folder try using a different item."
-msgstr "तपाईँले चयन गर्नुभएको वस्तु फरक वस्तु प्रयोग गरेर प्रयास गरिएको फोल्डर होइन ।"
+msgstr "तपाईँले चयन गर्नुभएको वस्तु फरक वस्तु प्रयोग गरेर प्रयास गरिएको फोल्डर होइन ।."
 
-#: gtk/gtkfilechooserwidget.c:769
+#: gtk/gtkfilechooserwidget.c:798
 msgid "Invalid file name"
 msgstr "अवैध फाइल नाम"
 
-#: gtk/gtkfilechooserwidget.c:778
+#: gtk/gtkfilechooserwidget.c:807
 msgid "The folder contents could not be displayed"
 msgstr "फोल्डरको सामग्रीहरू प्रदर्शन गर्न सकिएन"
 
-#: gtk/gtkfilechooserwidget.c:786
+#: gtk/gtkfilechooserwidget.c:815
 msgid "The file could not be deleted"
 msgstr "फाइल मेट्न सकिएन"
 
-#: gtk/gtkfilechooserwidget.c:794
+#: gtk/gtkfilechooserwidget.c:823
 msgid "The file could not be moved to the Trash"
-msgstr "फाइललाई रद्दीटोकरीमा सार्न सकेन ।"
+msgstr "फाइललाई रद्दीटोकरीमा सार्न सकेन"
 
-#: gtk/gtkfilechooserwidget.c:1205
+#: gtk/gtkfilechooserwidget.c:1212
 #, c-format
 msgid "Are you sure you want to permanently delete “%s”?"
 msgstr "तपाईँ \"%s\" मेट्न निश्चित हुनुहुन्छ?"
 
-#: gtk/gtkfilechooserwidget.c:1208
-#, c-format
+#: gtk/gtkfilechooserwidget.c:1213
 msgid "If you delete an item, it will be permanently lost."
 msgstr "यदि तपाईँले वस्तु मेट्नु भयो भने, यो स्थायी रूपले हराउनेछ ।."
 
-#: gtk/gtkfilechooserwidget.c:1210 gtk/gtkfilechooserwidget.c:1826 gtk/gtklabel.c:5659
-#: gtk/gtktext.c:6077 gtk/gtktextview.c:8956
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:1816 gtk/gtklabel.c:5882 gtk/gtktext.c:6335 gtk/gtktextview.c:9237
 msgid "_Delete"
 msgstr "मेटाउ"
 
-#: gtk/gtkfilechooserwidget.c:1333
+#: gtk/gtkfilechooserwidget.c:1331
 msgid "The file could not be renamed"
 msgstr "फाइल पुन: नामकरण गर्न सकेन"
 
-#: gtk/gtkfilechooserwidget.c:1593
+#: gtk/gtkfilechooserwidget.c:1507
 msgid "Could not select file"
 msgstr "फाइल चयन गर्न सकेन"
 
-#: gtk/gtkfilechooserwidget.c:1806
+#: gtk/gtkfilechooserwidget.c:1727 gtk/ui/gtkfilechooserwidget.ui:66
+msgid "Grid View"
+msgstr "ग्रिड दृश्य"
+
+#: gtk/gtkfilechooserwidget.c:1733
+msgid "List View"
+msgstr "सूची दृश्य"
+
+#: gtk/gtkfilechooserwidget.c:1796
 msgid "_Visit File"
 msgstr "फाइलमा जानुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:1810
+#: gtk/gtkfilechooserwidget.c:1800
 msgid "_Open With File Manager"
 msgstr "फाइल प्रबन्धकसंग खोल्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:1814
+#: gtk/gtkfilechooserwidget.c:1804
 msgid "_Copy Location"
 msgstr "स्थान प्रतिलिपि गर्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:1818
+#: gtk/gtkfilechooserwidget.c:1808
 msgid "_Add to Bookmarks"
 msgstr "पुस्तकचिनोहरूलाई थप्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:1822 gtk/gtkplacessidebar.c:2310 gtk/gtkplacessidebar.c:3249
+#: gtk/gtkfilechooserwidget.c:1812 gtk/gtkplacessidebar.c:2312 gtk/gtkplacessidebar.c:3270 gtk/ui/gtkfilechooserwidget.ui:421
 msgid "_Rename"
 msgstr "पुन: नामकरण गर्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:1830
+#: gtk/gtkfilechooserwidget.c:1820
 msgid "_Move to Trash"
 msgstr "रद्दि टोकरीमा सार्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:1839
+#: gtk/gtkfilechooserwidget.c:1829
 msgid "Show _Hidden Files"
 msgstr "लुकाइएको फाइलहरू देखाउनुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:1843
-msgid "Show _Size Column"
-msgstr "स्तम्भ आकार देखाउनुस्"
-
-#: gtk/gtkfilechooserwidget.c:1847
-msgid "Show T_ype Column"
-msgstr "स्तम्भ प्रकार देखाउनुस्"
-
-#: gtk/gtkfilechooserwidget.c:1851
-msgid "Show _Time"
-msgstr "समय देखाउनुहोस्"
-
-#: gtk/gtkfilechooserwidget.c:1855
+#: gtk/gtkfilechooserwidget.c:1833
 msgid "Sort _Folders Before Files"
 msgstr "फाइल अगाडि फोल्डर क्रमबद्ध गर्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:2255 gtk/inspector/css-node-tree.ui:135
+#: gtk/gtkfilechooserwidget.c:1956 gtk/gtkfilechooserwidget.c:1986 gtk/gtkfilechooserwidget.c:3891
+msgid "Unknown"
+msgstr "अज्ञात"
+
+#: gtk/gtkfilechooserwidget.c:2041 gtk/gtkplacessidebar.c:1025
+msgid "Home"
+msgstr "गृहपृष्ठ"
+
+#. this is the header for the location column in the print dialog
+#: gtk/gtkfilechooserwidget.c:2196 gtk/gtkfilechooserwidget.c:7446 gtk/inspector/css-node-tree.ui:76 gtk/print/ui/gtkprintunixdialog.ui:111
 msgid "Location"
 msgstr "स्थान"
 
 #. Label
-#: gtk/gtkfilechooserwidget.c:2343
+#: gtk/gtkfilechooserwidget.c:2303
 msgid "_Name:"
 msgstr "नाम:"
 
-#: gtk/gtkfilechooserwidget.c:2879 gtk/gtkfilechooserwidget.c:2893
+#: gtk/gtkfilechooserwidget.c:2860 gtk/gtkfilechooserwidget.c:2874
 #, c-format
 msgid "Searching in %s"
 msgstr "%s खोजी गर्दैछ"
 
-#: gtk/gtkfilechooserwidget.c:2899
+#: gtk/gtkfilechooserwidget.c:2880
 msgid "Searching"
 msgstr "खोजी गर्दैछ"
 
-#: gtk/gtkfilechooserwidget.c:2905
+#: gtk/gtkfilechooserwidget.c:2886
 msgid "Enter location or URL"
 msgstr "यूआरएल वा स्थान प्रविष्ट गर्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:3793 gtk/gtkfilechooserwidget.c:6617
+#: gtk/gtkfilechooserwidget.c:3445 gtk/gtkfilechooserwidget.c:5805 gtk/gtkfilechooserwidget.c:7468
 msgid "Modified"
 msgstr "परिमार्जित"
 
-#: gtk/gtkfilechooserwidget.c:4052
+#: gtk/gtkfilechooserwidget.c:3630
 #, c-format
 msgid "Could not read the contents of %s"
 msgstr "%s को सामाग्री पढ्न सकेन"
 
-#: gtk/gtkfilechooserwidget.c:4056
+#: gtk/gtkfilechooserwidget.c:3634
 msgid "Could not read the contents of the folder"
 msgstr "फोल्डरको सामग्रीहरू पढ्न सकेन"
 
 #. Translators: see g_date_time_format() for details on the format
-#: gtk/gtkfilechooserwidget.c:4196 gtk/gtkfilechooserwidget.c:4239
+#: gtk/gtkfilechooserwidget.c:3785 gtk/gtkfilechooserwidget.c:3829
 msgid "%H:%M"
 msgstr "%H:%M"
 
-#: gtk/gtkfilechooserwidget.c:4198 gtk/gtkfilechooserwidget.c:4241
+#: gtk/gtkfilechooserwidget.c:3787 gtk/gtkfilechooserwidget.c:3831
 msgid "%l:%M %p"
 msgstr "%l∶%M %p"
 
-#: gtk/gtkfilechooserwidget.c:4202
+#: gtk/gtkfilechooserwidget.c:3791
 msgid "Yesterday"
 msgstr "हिजो"
 
-#: gtk/gtkfilechooserwidget.c:4210
+#: gtk/gtkfilechooserwidget.c:3800
+#, no-c-format
 msgid "%-e %b"
 msgstr "%-e %b"
 
-#: gtk/gtkfilechooserwidget.c:4214
+#: gtk/gtkfilechooserwidget.c:3804
 msgid "%-e %b %Y"
 msgstr "%-e %b %Y"
 
-#: gtk/gtkfilechooserwidget.c:4303 gtk/gtkfilechooserwidget.c:4311
+#: gtk/gtkfilechooserwidget.c:3846 gtk/gtkfilechooserwidget.c:3854
 msgid "Program"
 msgstr "कार्यक्रम"
 
-#: gtk/gtkfilechooserwidget.c:4304
+#: gtk/gtkfilechooserwidget.c:3847
 msgid "Audio"
 msgstr "अडियो"
 
-#: gtk/gtkfilechooserwidget.c:4305 gtk/gtkfontbutton.c:604 gtk/inspector/visual.ui:170
-msgid "Font"
-msgstr "फन्ट"
-
-#: gtk/gtkfilechooserwidget.c:4306
+#: gtk/gtkfilechooserwidget.c:3849 gtk/gtkfilefilter.c:1013
 msgid "Image"
 msgstr "तस्विर"
 
-#: gtk/gtkfilechooserwidget.c:4307
+#: gtk/gtkfilechooserwidget.c:3850
 msgid "Archive"
 msgstr "संग्रह"
 
-#: gtk/gtkfilechooserwidget.c:4308
+#: gtk/gtkfilechooserwidget.c:3851
 msgid "Markup"
 msgstr "मार्कअप"
 
-#: gtk/gtkfilechooserwidget.c:4309 gtk/gtkfilechooserwidget.c:4310
+#: gtk/gtkfilechooserwidget.c:3852 gtk/gtkfilechooserwidget.c:3853
 msgid "Text"
 msgstr "पाठ"
 
-#: gtk/gtkfilechooserwidget.c:4312
+#: gtk/gtkfilechooserwidget.c:3855
 msgid "Video"
 msgstr "भिडियो"
 
-#: gtk/gtkfilechooserwidget.c:4313
+#: gtk/gtkfilechooserwidget.c:3856
 msgid "Contacts"
 msgstr "सम्पर्कहरू"
 
-#: gtk/gtkfilechooserwidget.c:4314
+#: gtk/gtkfilechooserwidget.c:3857
 msgid "Calendar"
 msgstr "पात्रो"
 
-#: gtk/gtkfilechooserwidget.c:4315
+#: gtk/gtkfilechooserwidget.c:3858
 msgid "Document"
 msgstr "कागजात"
 
-#: gtk/gtkfilechooserwidget.c:4316
+#: gtk/gtkfilechooserwidget.c:3859
 msgid "Presentation"
 msgstr "प्रस्तुतिकरण"
 
-#: gtk/gtkfilechooserwidget.c:4317
+#: gtk/gtkfilechooserwidget.c:3860
 msgid "Spreadsheet"
 msgstr "स्प्रेडसिट"
 
-#: gtk/gtkfilechooserwidget.c:4348 gtk/gtkfilechooserwidget.c:4541
-msgid "Unknown"
-msgstr "अज्ञात"
-
-#: gtk/gtkfilechooserwidget.c:4580 gtk/gtkplacessidebar.c:1027
-msgid "Home"
-msgstr "गृहपृष्ठ"
-
-#: gtk/gtkfilechooserwidget.c:5773 gtk/gtkprintunixdialog.c:658
+#: gtk/gtkfilechooserwidget.c:5010 gtk/print/gtkprintunixdialog.c:673
 #, c-format
 msgid "A file named “%s” already exists.  Do you want to replace it?"
 msgstr "\"%s\" नाम गरिएको फाइल पहिले नै अवस्थित छ ।  तपाईँ यसलाई प्रतिस्थापन गर्न चाहनुहुन्छ?"
 
-#: gtk/gtkfilechooserwidget.c:5776 gtk/gtkprintunixdialog.c:662
-#, fuzzy, c-format
-#| msgid "The file already exists in \"%s\".  Replacing it will overwrite its contents."
+#: gtk/gtkfilechooserwidget.c:5012 gtk/print/gtkprintunixdialog.c:677
+#, c-format
 msgid "The file already exists in “%s”.  Replacing it will overwrite its contents."
-msgstr "फाइल नाम \"%s\" पहिल्यै अवस्थित छ। यसलाई बदल्नाले यसको सामग्रीहरूमा अधिलेखन हुन्छ।"
+msgstr "फाइल \"%s\" मा पहिल्यै अवस्थित छ ।  यसलाई बदल्दा यसका सामाग्री अधिलेखन हुनेछ ।."
 
-#: gtk/gtkfilechooserwidget.c:5781 gtk/gtkprintunixdialog.c:670
+#: gtk/gtkfilechooserwidget.c:5018 gtk/print/gtkprintunixdialog.c:685
 msgid "_Replace"
 msgstr "बदल्नुहोस्"
 
-#: gtk/gtkfilechooserwidget.c:5942
+#: gtk/gtkfilechooserwidget.c:5173
 msgid "You do not have access to the specified folder."
 msgstr "तपाईँसँग निर्दिष्ट गरिएको फोल्डरमा पहुँच छैन ।."
 
-#: gtk/gtkfilechooserwidget.c:6546
+#: gtk/gtkfilechooserwidget.c:5752
 msgid "Could not send the search request"
 msgstr "खोजी अनुरोध पठाउन सकेन"
 
-#: gtk/gtkfilechooserwidget.c:6856
+#: gtk/gtkfilechooserwidget.c:6033
 msgid "Accessed"
 msgstr "पहुँच प्राप्त"
 
-#: gtk/gtkfontbutton.c:395
-msgid "Sans 12"
-msgstr "Sans 12"
+#: gtk/gtkfilechooserwidget.c:7424
+msgid "_Size"
+msgstr "साइज"
 
-#: gtk/gtkfontbutton.c:508 gtk/gtkfontbutton.c:628
-msgid "Pick a Font"
-msgstr "एउटा फन्ट छान्नुहोस्"
+#: gtk/gtkfilechooserwidget.c:7428
+msgid "T_ype"
+msgstr "प्रकार"
 
-#: gtk/gtkfontbutton.c:1365
-msgctxt "font"
-msgid "None"
-msgstr "None"
+#: gtk/gtkfilechooserwidget.c:7432
+msgid "_Time"
+msgstr "समय"
+
+#: gtk/gtkfilechooserwidget.c:7438 gtk/gtkplacessidebar.c:2306 gtk/inspector/a11y.ui:43 gtk/inspector/actions.ui:18 gtk/inspector/css-node-tree.ui:22
+#: gtk/inspector/prop-list.ui:24 gtk/ui/gtkfilechooserwidget.ui:396 gtk/print/ui/gtkprintunixdialog.ui:80
+msgid "Name"
+msgstr "नाम"
+
+#: gtk/gtkfilechooserwidget.c:7455 gtk/inspector/resource-list.ui:82 gtk/ui/gtkfontchooserwidget.ui:216 gtk/ui/gtkfontchooserwidget.ui:385
+msgid "Size"
+msgstr "साइज"
 
-#: gtk/gtkfontchooserwidget.c:1531
+#: gtk/gtkfilechooserwidget.c:7461 gtk/inspector/misc-info.ui:57 gtk/inspector/prop-list.ui:35 gtk/inspector/statistics.ui:36
+msgid "Type"
+msgstr "वर्ग"
+
+#: gtk/gtkfiledialog.c:813
+msgid "Pick Files"
+msgstr "फाइल हरू उठाउनुहोस्"
+
+#: gtk/gtkfiledialog.c:813
+msgid "Pick a File"
+msgstr "फाईल टिप्नुहोस्"
+
+#: gtk/gtkfiledialog.c:818
+msgid "Save a File"
+msgstr "फाइल बचत गर्नुहोस्"
+
+#: gtk/gtkfiledialog.c:822 gtk/ui/gtkappchooserdialog.ui:53 gtk/ui/gtkcolorchooserdialog.ui:41 gtk/ui/gtkfontchooserdialog.ui:34
+msgid "_Select"
+msgstr "_चयन गर्नुहोस्"
+
+#: gtk/gtkfiledialog.c:823
+msgid "Select Folders"
+msgstr "फोल्डरहरू चयन गर्नुहोस्"
+
+#: gtk/gtkfiledialog.c:823
+msgid "Select a Folder"
+msgstr "फोल्डर चयन गर्नुहोस्"
+
+#: gtk/gtkfilefilter.c:1026
+msgid "Unspecified"
+msgstr "निर्दिष्ट नगरिएको"
+
+#: gtk/gtkfontchooserdialog.c:192 gtk/gtkfontchooserdialog.c:195
+msgid "Change Font Features"
+msgstr "फन्ट सुविधा हरू परिवर्तन गर्नुहोस्"
+
+#: gtk/gtkfontchooserwidget.c:1491
 msgctxt "Font variation axis"
 msgid "Width"
 msgstr "चौडाइ"
 
-#: gtk/gtkfontchooserwidget.c:1532
+#: gtk/gtkfontchooserwidget.c:1492
 msgctxt "Font variation axis"
 msgid "Weight"
 msgstr "तौल"
 
-#: gtk/gtkfontchooserwidget.c:1533
+#: gtk/gtkfontchooserwidget.c:1493
 msgctxt "Font variation axis"
 msgid "Italic"
 msgstr "इटालिक"
 
-#: gtk/gtkfontchooserwidget.c:1534
+#: gtk/gtkfontchooserwidget.c:1494
 msgctxt "Font variation axis"
 msgid "Slant"
 msgstr "छड्के"
 
-#: gtk/gtkfontchooserwidget.c:1535
-#, fuzzy
-#| msgid "Optical Size"
+#: gtk/gtkfontchooserwidget.c:1495
 msgctxt "Font variation axis"
 msgid "Optical Size"
 msgstr "अप्टिकल साइज"
 
-#: gtk/gtkfontchooserwidget.c:2139
+#: gtk/gtkfontchooserwidget.c:2053
+msgctxt "Font feature value"
+msgid "Default"
+msgstr "पुर्वनिर्धारित"
+
+#: gtk/gtkfontchooserwidget.c:2070
+msgctxt "Font feature value"
+msgid "Enable"
+msgstr "सक्षम पार्नुहोस्"
+
+#: gtk/gtkfontchooserwidget.c:2404
 msgid "Default"
 msgstr "पूर्वनिर्धारित"
 
-#: gtk/gtkfontchooserwidget.c:2185
+#: gtk/gtkfontchooserwidget.c:2466
 msgid "Ligatures"
 msgstr "लिगाचरस्"
 
-#: gtk/gtkfontchooserwidget.c:2186
-#, fuzzy
+#: gtk/gtkfontchooserwidget.c:2467
 msgid "Letter Case"
-msgstr "US Letter"
+msgstr ""
 
-#: gtk/gtkfontchooserwidget.c:2187
+#: gtk/gtkfontchooserwidget.c:2468
 msgid "Number Case"
 msgstr "संख्या केस"
 
-#: gtk/gtkfontchooserwidget.c:2188
+#: gtk/gtkfontchooserwidget.c:2469
 msgid "Number Spacing"
 msgstr "संख्या दूरी (अन्तराल)"
 
-#: gtk/gtkfontchooserwidget.c:2189
-msgid "Number Formatting"
-msgstr "संख्या ढाँचाबद्धता"
+#: gtk/gtkfontchooserwidget.c:2470
+msgid "Fractions"
+msgstr "भिन्नहरू"
+
+#: gtk/gtkfontchooserwidget.c:2471
+msgid "Style Variations"
+msgstr "शैली भिन्नताहरू"
 
-#: gtk/gtkfontchooserwidget.c:2190
-msgid "Character Variants"
-msgstr "वर्ण फरकप्रकार"
+#: gtk/gtkfontchooserwidget.c:2473
+#| msgid "Character Variants"
+msgid "Character Variations"
+msgstr "क्यारेक्टर भिन्नता"
 
-#: gtk/gtkglarea.c:284
+#: gtk/gtkglarea.c:316
 msgid "OpenGL context creation failed"
-msgstr "खुला जीएल विषयवस्तु सिर्जना गर्न असफल भयो ।"
+msgstr "खुला जीएल विषयवस्तु सिर्जना गर्न असफल भयो"
+
+#: gtk/deprecated/gtkinfobar.c:498 gtk/gtkwindowcontrols.c:357 gtk/gtkwindowhandle.c:250
+msgid "Close"
+msgstr "बन्द गर्नुहोस्"
 
-#: gtk/gtklabel.c:5656 gtk/gtktext.c:6065 gtk/gtktextview.c:8944
+#: gtk/deprecated/gtkinfobar.c:499
+#| msgid "Close the window"
+msgid "Close the infobar"
+msgstr "सूचनापट्टी बन्द गर्नुहोस्"
+
+#: gtk/gtklabel.c:5879 gtk/gtktext.c:6323 gtk/gtktextview.c:9225
 msgid "Cu_t"
 msgstr "काट्नुहोस्"
 
-#: gtk/gtklabel.c:5657 gtk/gtktext.c:6069 gtk/gtktextview.c:8948
+#: gtk/gtklabel.c:5880 gtk/gtktext.c:6327 gtk/gtktextview.c:9229
 msgid "_Copy"
 msgstr "प्रतिलिपि"
 
-#: gtk/gtklabel.c:5658 gtk/gtktext.c:6073 gtk/gtktextview.c:8952
+#: gtk/gtklabel.c:5881 gtk/gtktext.c:6331 gtk/gtktextview.c:9233
 msgid "_Paste"
 msgstr "_टाँस्नुहोस्"
 
-#: gtk/gtklabel.c:5664 gtk/gtktext.c:6086 gtk/gtktextview.c:8977
+#: gtk/gtklabel.c:5887 gtk/gtktext.c:6344 gtk/gtktextview.c:9258
 msgid "Select _All"
 msgstr "सबै_छान्नुहोस्"
 
-#: gtk/gtklabel.c:5669
+#: gtk/gtklabel.c:5892
 msgid "_Open Link"
 msgstr "लिङ्क खोल्नुहोस्"
 
-#: gtk/gtklabel.c:5673
+#: gtk/gtklabel.c:5896
 msgid "Copy _Link Address"
 msgstr "लिङ्क ठेगाना प्रतिलिपि बनाउनुहोस्"
 
-#: gtk/gtklinkbutton.c:259
+#: gtk/gtklabel.c:5940 gtk/gtktext.c:2851 gtk/gtktextview.c:9307
+msgid "Context menu"
+msgstr "विषयवस्तु मेनु"
+
+#: gtk/gtklinkbutton.c:273
 msgid "_Copy URL"
 msgstr "URL प्रतिलिपि गर्नुहोस्"
 
-#: gtk/gtklinkbutton.c:544
+#: gtk/gtklinkbutton.c:602
 msgid "Invalid URI"
 msgstr "अवैध URI"
 
-#: gtk/gtklockbutton.c:289
-msgid "Lock"
-msgstr "ताल्चा लगाउनुहोस्"
-
-#: gtk/gtklockbutton.c:303
-msgid "Unlock"
-msgstr "ताल्चा खोल्नुहोस्"
-
-#: gtk/gtklockbutton.c:317
-msgid ""
-"Dialog is unlocked.\n"
-"Click to prevent further changes"
-msgstr ""
-
-#: gtk/gtklockbutton.c:331
-msgid ""
-"Dialog is locked.\n"
-"Click to make changes"
-msgstr ""
-
-#: gtk/gtklockbutton.c:345
-msgid ""
-"System policy prevents changes.\n"
-"Contact your system administrator"
-msgstr ""
-"प्रणाली नीति परिवर्तन गर्न दिदैन ।\n"
-"तपाईँको प्रणाली प्रशासकलाई सम्पर्क गर्नुहोस्"
-
-#. Translate to default:RTL if you want your widgets
-#. * to be RTL, otherwise translate to default:LTR.
-#. * Do *not* translate it to "predefinito:LTR", if it
-#. * it isn't default:LTR or default:RTL it will not work
-#.
-#: gtk/gtkmain.c:775
-msgid "default:LTR"
-msgstr "default:LTR"
-
-#. hour:minutes:seconds
-#. Translators: This is a time format, like "9:05:02" for 9
-#. * hours, 5 minutes, and 2 seconds. You may change ":" to
-#. * the separator that your locale uses or use "%Id" instead
-#. * of "%d" if your locale uses localized digits.
-#.
-#: gtk/gtkmediacontrols.c:99
-#, c-format
-msgctxt "long time format"
-msgid "%d:%02d:%02d"
-msgstr "%d:%02d:%02d"
+#. hour:minutes:seconds
+#. Translators: This is a time format, like "9:05:02" for 9
+#. * hours, 5 minutes, and 2 seconds. You may change ":" to
+#. * the separator that your locale uses or use "%Id" instead
+#. * of "%d" if your locale uses localized digits.
+#.
+#: gtk/gtkmediacontrols.c:100
+#, c-format
+msgctxt "long time format"
+msgid "%d:%02d:%02d"
+msgstr "%d:%02d:%02d"
 
 #. -hour:minutes:seconds
 #. Translators: This is a time format, like "-9:05:02" for 9
@@ -2543,7 +2707,7 @@ msgstr "%d:%02d:%02d"
 #. * change ":" to the separator that your locale uses or use
 #. * "%Id" instead of "%d" if your locale uses localized digits.
 #.
-#: gtk/gtkmediacontrols.c:107
+#: gtk/gtkmediacontrols.c:108
 #, c-format
 msgctxt "long time format"
 msgid "-%d:%02d:%02d"
@@ -2555,7 +2719,7 @@ msgstr "-%d:%02d:%02d"
 #. * ":" to the separator that your locale uses or use "%Id"
 #. * instead of "%d" if your locale uses localized digits.
 #.
-#: gtk/gtkmediacontrols.c:118
+#: gtk/gtkmediacontrols.c:119
 #, c-format
 msgctxt "short time format"
 msgid "-%d:%02d"
@@ -2567,34 +2731,43 @@ msgstr "-%d:%02d"
 #. * separator that your locale uses or use "%Id" instead of
 #. * "%d" if your locale uses localized digits.
 #.
-#: gtk/gtkmediacontrols.c:127
+#: gtk/gtkmediacontrols.c:128
 #, c-format
 msgctxt "short time format"
 msgid "%d:%02d"
 msgstr "%d:%02d"
 
-#: gtk/gtkmessagedialog.c:158 gtk/gtkmessagedialog.c:176 gtk/gtkprintbackend.c:643
-#: gtk/gtkwindow.c:6155
+#: gtk/gtkmediacontrols.c:412
+msgctxt "media controls tooltip"
+msgid "Stop"
+msgstr "रोक्नुहोस्"
+
+#: gtk/gtkmediacontrols.c:417 gtk/ui/gtkmediacontrols.ui:28
+msgctxt "media controls tooltip"
+msgid "Play"
+msgstr "प्ले गर्नुहोस्"
+
+#: gtk/gtkmessagedialog.c:162 gtk/gtkmessagedialog.c:180 gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6212
 msgid "_OK"
 msgstr "_हो"
 
-#: gtk/gtkmessagedialog.c:170
+#: gtk/gtkmessagedialog.c:174
 msgid "_No"
 msgstr "होइन"
 
-#: gtk/gtkmessagedialog.c:171
+#: gtk/gtkmessagedialog.c:175
 msgid "_Yes"
 msgstr "हो"
 
-#: gtk/gtkmountoperation.c:611
+#: gtk/gtkmountoperation.c:609
 msgid "Co_nnect"
 msgstr "जडान गर्नुहोस्"
 
-#: gtk/gtkmountoperation.c:677
+#: gtk/gtkmountoperation.c:676
 msgid "Connect As"
 msgstr "जडान गर्नुहोस्"
 
-#: gtk/gtkmountoperation.c:686
+#: gtk/gtkmountoperation.c:685
 msgid "_Anonymous"
 msgstr "बेनामी"
 
@@ -2642,97 +2815,94 @@ msgstr "तपाईँ लगआउट हुदासम्म पासवर
 msgid "Remember _forever"
 msgstr "सधैँ याद गर्नुहोस्"
 
-#: gtk/gtkmountoperation.c:1207
+#: gtk/gtkmountoperation.c:1251
 #, c-format
 msgid "Unknown Application (PID %d)"
 msgstr "अज्ञात अनुप्रयोग  (PID %d)"
 
-#: gtk/gtkmountoperation.c:1406
+#. Use GTK_DIALOG_DESTROY_WITH_PARENT here since the parent dialog can be
+#. * indeed be destroyed via the GMountOperation::abort signal... for example,
+#. * this is triggered if the user yanks the device while we are showing
+#. * the dialog...
+#.
+#: gtk/gtkmountoperation.c:1396
 #, c-format
 msgid "Unable to end process"
 msgstr "प्रक्रिया अन्त्य असफल"
 
-#: gtk/gtkmountoperation.c:1436
+#: gtk/gtkmountoperation.c:1546
 msgid "_End Process"
 msgstr "प्रक्रिया अन्त्य"
 
-#: gtk/gtkmountoperation-stub.c:62
+#: gtk/gtkmountoperation-stub.c:61
 #, c-format
 msgid "Cannot kill process with PID %d. Operation is not implemented."
-msgstr "PID %d सँग प्रक्रिया नष्ट गर्न सकिँदैन । सञ्चालन कार्यान्वयन गरिएको छैन ।"
+msgstr "PID %d सँग प्रक्रिया नष्ट गर्न सकिँदैन । सञ्चालन कार्यान्वयन गरिएको छैन ।."
 
 #. translators: this string is a name for the 'less' command
-#: gtk/gtkmountoperation-x11.c:984
+#: gtk/gtkmountoperation-x11.c:986
 msgid "Terminal Pager"
 msgstr "टर्मिनल पेजर"
 
-#: gtk/gtkmountoperation-x11.c:985
+#: gtk/gtkmountoperation-x11.c:987
 msgid "Top Command"
 msgstr "माथिल्लो आदेश"
 
-#: gtk/gtkmountoperation-x11.c:986
+#: gtk/gtkmountoperation-x11.c:988
 msgid "Bourne Again Shell"
 msgstr "Bourne Again Shell"
 
-#: gtk/gtkmountoperation-x11.c:987
+#: gtk/gtkmountoperation-x11.c:989
 msgid "Bourne Shell"
 msgstr "Bourne Shell"
 
-#: gtk/gtkmountoperation-x11.c:988
+#: gtk/gtkmountoperation-x11.c:990
 msgid "Z Shell"
 msgstr "Z सेल"
 
-#: gtk/gtkmountoperation-x11.c:1085
+#: gtk/gtkmountoperation-x11.c:1090
 #, c-format
 msgid "Cannot end process with PID %d: %s"
 msgstr "PID %d सँग प्रक्रिया अन्त्य गर्न सकिँदैन: %s"
 
 #: gtk/gtknomediafile.c:48
 msgid "GTK could not find a media module. Check your installation."
-msgstr ""
+msgstr "जीटीकेले मिडिया मोड्युल फेला पार्न सकेन । तपाईँको स्थापना जाँच गर्नुहोस् ।."
 
-#: gtk/gtknotebook.c:1527
-msgid "Tab list"
-msgstr "ट्याब सूची"
-
-#: gtk/gtknotebook.c:3249
+#: gtk/gtknotebook.c:3304
 msgid "Previous tab"
 msgstr "अघिल्लो ट्याब"
 
-#: gtk/gtknotebook.c:3253
+#: gtk/gtknotebook.c:3308
 msgid "Next tab"
 msgstr "पछिल्लो ट्याब"
 
-#: gtk/gtknotebook.c:4073
-msgid "Tab"
-msgstr "ट्याब"
-
-#: gtk/gtknotebook.c:4371 gtk/gtknotebook.c:6579
+#: gtk/gtknotebook.c:4424 gtk/gtknotebook.c:6634
 #, c-format
 msgid "Page %u"
 msgstr "पृष्ठ %u"
 
-#: gtk/gtkpagesetup.c:609 gtk/gtkpapersize.c:942 gtk/gtkpapersize.c:982
+#: gtk/print/gtkpagesetup.c:611 gtk/print/gtkpapersize.c:942 gtk/print/gtkpapersize.c:982
 msgid "Not a valid page setup file"
 msgstr "वैध पृष्ठ सेट अप फाइल छैन"
 
-#: gtk/gtkpagesetupunixdialog.c:201 gtk/gtkprintunixdialog.c:752
+#: gtk/print/gtkpagesetupunixdialog.c:198 gtk/print/gtkprintunixdialog.c:768
 msgid "Manage Custom Sizes…"
 msgstr "अनुकुलन साइजहरू प्रबन्ध गर्नुहोस्…"
 
-#: gtk/gtkpagesetupunixdialog.c:284
+#: gtk/print/gtkpagesetupunixdialog.c:283 gtk/ui/gtkassistant.ui:98
 msgid "_Apply"
 msgstr "_लागू"
 
-#: gtk/gtkpagesetupunixdialog.c:318 gtk/gtkpagesetupunixdialog.c:570
+#: gtk/print/gtkpagesetupunixdialog.c:318 gtk/print/gtkpagesetupunixdialog.c:570
 msgid "Any Printer"
 msgstr "कुनै मुद्रणयन्त्र"
 
-#: gtk/gtkpagesetupunixdialog.c:319
+#: gtk/print/gtkpagesetupunixdialog.c:319
 msgid "For portable documents"
 msgstr "स्थानान्तरण योग्य कागजातका लागि"
 
-#: gtk/gtkpagesetupunixdialog.c:738
+#: gtk/print/gtkpagesetupunixdialog.c:738
 #, c-format
 msgid ""
 "Margins:\n"
@@ -2742,107 +2912,107 @@ msgid ""
 " Bottom: %s %s"
 msgstr ""
 "मार्ग:\n"
-"  बाँया:% s% s\n"
-"  दाँया:% s% s\n"
-"  शीर्ष:% s% s\n"
-"  तल:% s% s"
+"  बाँया:%s %s\n"
+"  दाँया:%s %s\n"
+"  शीर्ष:%s %s\n"
+"  तल:%s %s"
 
-#: gtk/gtkpagesetupunixdialog.c:784
+#: gtk/print/gtkpagesetupunixdialog.c:784 gtk/print/ui/gtkpagesetupunixdialog.ui:5 gtk/print/ui/gtkprintunixdialog.ui:782
 msgid "Page Setup"
 msgstr "पृष्ठ सेटअप"
 
-#: gtk/gtkpasswordentry.c:173
+#: gtk/gtkpasswordentry.c:168
 msgid "Hide Text"
 msgstr "प्रविष्टि पाठ लुकाउनुहोस्"
 
-#: gtk/gtkpasswordentry.c:178 gtk/gtkpasswordentry.c:629
+#: gtk/gtkpasswordentry.c:173 gtk/gtkpasswordentry.c:624
 msgid "Show Text"
 msgstr "पाठ देखाऊ"
 
-#: gtk/gtkpasswordentry.c:216
+#: gtk/gtkpasswordentry.c:215
 msgid "Caps Lock is on"
 msgstr "क्यप्स लक अन छ"
 
-#: gtk/gtkpasswordentry.c:705
+#: gtk/gtkpasswordentry.c:700
 msgid "_Show Text"
 msgstr "पाठ देखाऊ"
 
 #. translators: %s is the name of a cloud provider for files
-#: gtk/gtkplacessidebar.c:914
+#: gtk/gtkplacessidebar.c:912
 #, c-format
 msgid "Open %s"
 msgstr "%s खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:1005
+#: gtk/gtkplacessidebar.c:1003
 msgid "Recent"
 msgstr "हालसालै"
 
-#: gtk/gtkplacessidebar.c:1007
+#: gtk/gtkplacessidebar.c:1005
 msgid "Recent files"
 msgstr "हालैका फाइल"
 
-#: gtk/gtkplacessidebar.c:1016
+#: gtk/gtkplacessidebar.c:1014
 msgid "Starred"
 msgstr "तारा"
 
-#: gtk/gtkplacessidebar.c:1018
+#: gtk/gtkplacessidebar.c:1016
 msgid "Starred files"
 msgstr "तारा फाइलहरू"
 
-#: gtk/gtkplacessidebar.c:1029
+#: gtk/gtkplacessidebar.c:1027
 msgid "Open your personal folder"
 msgstr "तपाईँको व्यक्तिगत फोल्डर खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:1042
+#: gtk/gtkplacessidebar.c:1040
 msgid "Desktop"
 msgstr "डेस्कटप"
 
-#: gtk/gtkplacessidebar.c:1044
+#: gtk/gtkplacessidebar.c:1042
 msgid "Open the contents of your desktop in a folder"
 msgstr "तपाईँको डेस्कटपको फोल्डरमा भएको सामाग्री खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:1058
+#: gtk/gtkplacessidebar.c:1056
 msgid "Enter Location"
 msgstr "स्थान प्रविष्ट गर्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:1060
+#: gtk/gtkplacessidebar.c:1058
 msgid "Manually enter a location"
 msgstr "म्यानुअल रूपमा एक स्थान प्रविष्ट गर्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:1070
+#: gtk/gtkplacessidebar.c:1068
 msgid "Trash"
 msgstr "रद्दी टोकरी"
 
-#: gtk/gtkplacessidebar.c:1072
+#: gtk/gtkplacessidebar.c:1070
 msgid "Open the trash"
 msgstr "रद्दीटोकरी खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:1183 gtk/gtkplacessidebar.c:1211 gtk/gtkplacessidebar.c:1411
-#, fuzzy, c-format
+#: gtk/gtkplacessidebar.c:1181 gtk/gtkplacessidebar.c:1209 gtk/gtkplacessidebar.c:1409
+#, c-format
 msgid "Mount and open “%s”"
-msgstr "%s माउन्ट गर्न असफल भयो।."
+msgstr "माउन्ट र खोल्नुहोस् \"%s\""
 
-#: gtk/gtkplacessidebar.c:1306
+#: gtk/gtkplacessidebar.c:1304
 msgid "Open the contents of the file system"
 msgstr "फाइल प्रणालीको सामाग्री खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:1389
+#: gtk/gtkplacessidebar.c:1387
 msgid "New bookmark"
 msgstr "नयाँ पुस्तकचिनो"
 
-#: gtk/gtkplacessidebar.c:1391
+#: gtk/gtkplacessidebar.c:1389
 msgid "Add a new bookmark"
 msgstr "नयाँ पुस्तकचिनो थप्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:1456
+#: gtk/gtkplacessidebar.c:1454
 msgid "Other Locations"
 msgstr "अन्य स्थानहरू"
 
-#: gtk/gtkplacessidebar.c:1457
+#: gtk/gtkplacessidebar.c:1455
 msgid "Show other locations"
 msgstr "अन्य स्थानहरू देखाउनुहोस्"
 
-#: gtk/gtkplacessidebar.c:1962 gtk/gtkplacessidebar.c:2963
+#: gtk/gtkplacessidebar.c:1964 gtk/gtkplacessidebar.c:2984
 #, c-format
 msgid "Unable to start “%s”"
 msgstr "सुरु गर्न अक्षम: “%s”"
@@ -2850,210 +3020,205 @@ msgstr "सुरु गर्न अक्षम: “%s”"
 #. Translators: This means that unlocking an encrypted storage
 #. * device failed. %s is the name of the device.
 #.
-#: gtk/gtkplacessidebar.c:1998
+#: gtk/gtkplacessidebar.c:2000
 #, c-format
 msgid "Error unlocking “%s”"
 msgstr "\"%s\" ताल्चा बाट हटाउदै त्रुटि"
 
-#: gtk/gtkplacessidebar.c:2000
+#: gtk/gtkplacessidebar.c:2002
 #, c-format
 msgid "Unable to access “%s”"
 msgstr "\"%s\" पहुँच गर्न असक्षम"
 
-#: gtk/gtkplacessidebar.c:2231
+#: gtk/gtkplacessidebar.c:2233
 msgid "This name is already taken"
 msgstr "पहिल्यै प्रयोग भइसकेको नाम"
 
-#: gtk/gtkplacessidebar.c:2304 gtk/inspector/actions.ui:19 gtk/inspector/css-node-tree.ui:35
-#: gtk/inspector/prop-list.ui:24
-msgid "Name"
-msgstr "नाम"
-
-#: gtk/gtkplacessidebar.c:2504
+#: gtk/gtkplacessidebar.c:2525
 #, c-format
 msgid "Unable to unmount “%s”"
 msgstr "%s अनमाउन्ट गर्न असफल"
 
-#: gtk/gtkplacessidebar.c:2680
+#: gtk/gtkplacessidebar.c:2701
 #, c-format
 msgid "Unable to stop “%s”"
 msgstr "रोक्न असफल “%s”"
 
-#: gtk/gtkplacessidebar.c:2709
+#: gtk/gtkplacessidebar.c:2730
 #, c-format
 msgid "Unable to eject “%s”"
 msgstr "\"%s\" निकाल्न असक्षम"
 
-#: gtk/gtkplacessidebar.c:2738 gtk/gtkplacessidebar.c:2767
+#: gtk/gtkplacessidebar.c:2759 gtk/gtkplacessidebar.c:2788
 #, c-format
 msgid "Unable to eject %s"
 msgstr "%s निकाल्न असफल"
 
-#: gtk/gtkplacessidebar.c:2915
+#: gtk/gtkplacessidebar.c:2936
 #, c-format
 msgid "Unable to poll “%s” for media changes"
 msgstr "मिडिया परिवर्तनका लागि \"%s\" सर्वेक्षण गर्न असक्षम"
 
-#: gtk/gtkplacessidebar.c:3134 gtk/gtkplacessidebar.c:3221 gtk/gtkplacesview.c:1662
+#: gtk/gtkplacessidebar.c:3155 gtk/gtkplacessidebar.c:3242 gtk/gtkplacesview.c:1649
 msgid "Open in New _Tab"
 msgstr "नयाँ ट्याबमा खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3140 gtk/gtkplacessidebar.c:3230 gtk/gtkplacesview.c:1667
+#: gtk/gtkplacessidebar.c:3161 gtk/gtkplacessidebar.c:3251 gtk/gtkplacesview.c:1654
 msgid "Open in New _Window"
 msgstr "नयाँ सञ्झ्यालमा खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3241
+#: gtk/gtkplacessidebar.c:3262
 msgid "_Add Bookmark"
 msgstr "पुस्तकचिनो थप्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3245
+#: gtk/gtkplacessidebar.c:3266
 msgid "_Remove"
 msgstr "हटाउनुहोस्"
 
-#: gtk/gtkplacessidebar.c:3261 gtk/gtkplacesview.c:1692
+#: gtk/gtkplacessidebar.c:3282 gtk/gtkplacesview.c:1679
 msgid "_Mount"
 msgstr "माउन्ट गर्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3270 gtk/gtkplacesview.c:1681
+#: gtk/gtkplacessidebar.c:3291 gtk/gtkplacesview.c:1668
 msgid "_Unmount"
 msgstr "अनमाउण्ट गर्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3277
+#: gtk/gtkplacessidebar.c:3298
 msgid "_Eject"
 msgstr "निकाल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3287
+#: gtk/gtkplacessidebar.c:3308
 msgid "_Detect Media"
 msgstr "मिडिया पत्ता लगाउनुहोस्"
 
-#: gtk/gtkplacessidebar.c:3296
+#: gtk/gtkplacessidebar.c:3317
 msgid "_Start"
 msgstr "सुरु गर्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3298
+#: gtk/gtkplacessidebar.c:3319
 msgid "_Power On"
 msgstr "खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3299
+#: gtk/gtkplacessidebar.c:3320
 msgid "_Connect Drive"
 msgstr "ड्राइभ जडान गर्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3300
+#: gtk/gtkplacessidebar.c:3321
 msgid "_Start Multi-disk Device"
 msgstr "बहु-डिस्क यन्त्र सुरु गर्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3301
+#: gtk/gtkplacessidebar.c:3322
 msgid "_Unlock Device"
 msgstr "यन्त्र ताल्चा खोल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3311
+#: gtk/gtkplacessidebar.c:3332
 msgid "_Stop"
 msgstr "रोक्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3313
+#: gtk/gtkplacessidebar.c:3334
 msgid "_Safely Remove Drive"
 msgstr "ड्राइभ सुरक्षित तरिकाले निकाल्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3314
+#: gtk/gtkplacessidebar.c:3335
 msgid "_Disconnect Drive"
 msgstr "ड्राइभ विच्छेदन गर्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3315
+#: gtk/gtkplacessidebar.c:3336
 msgid "_Stop Multi-disk Device"
 msgstr "बहु-डिस्क यन्त्र रोक्नुहोस्"
 
-#: gtk/gtkplacessidebar.c:3316
+#: gtk/gtkplacessidebar.c:3337
 msgid "_Lock Device"
 msgstr "यन्त्र ताल्चा लगाउनुहोस्"
 
-#: gtk/gtkplacessidebar.c:3804 gtk/gtkplacesview.c:1103
+#: gtk/gtkplacessidebar.c:3827 gtk/gtkplacesview.c:1089
 msgid "Computer"
 msgstr "कमप्युटर"
 
-#: gtk/gtkplacesview.c:889
+#: gtk/gtkplacesview.c:875
 msgid "Searching for network locations"
 msgstr "सञ्जाल स्थान मात्रै खोज्नुहोस्"
 
-#: gtk/gtkplacesview.c:896
+#: gtk/gtkplacesview.c:882
 msgid "No network locations found"
 msgstr "सञ्जाल स्थान  फेला परेन"
 
 #. if it wasn't cancelled show a dialog
-#: gtk/gtkplacesview.c:1210 gtk/gtkplacesview.c:1307
+#: gtk/gtkplacesview.c:1196 gtk/gtkplacesview.c:1293
 msgid "Unable to access location"
 msgstr "स्थान पहुँच गर्न असक्षम"
 
 #. Restore from Cancel to Connect
-#: gtk/gtkplacesview.c:1228
+#: gtk/gtkplacesview.c:1214 gtk/ui/gtkplacesview.ui:250
 msgid "Con_nect"
 msgstr "जोड्नुहोस्"
 
 #. if it wasn't cancelled show a dialog
-#: gtk/gtkplacesview.c:1366
+#: gtk/gtkplacesview.c:1353
 msgid "Unable to unmount volume"
 msgstr "भोल्युम अनमाउन्ट गर्न असक्षम"
 
 #. Allow to cancel the operation
-#: gtk/gtkplacesview.c:1458
+#: gtk/gtkplacesview.c:1445
 msgid "Cance_l"
 msgstr "रद्द गर्नुहोस्"
 
-#: gtk/gtkplacesview.c:1605
+#: gtk/gtkplacesview.c:1592
 msgid "AppleTalk"
 msgstr "AppleTalk"
 
-#: gtk/gtkplacesview.c:1611
+#: gtk/gtkplacesview.c:1598
 msgid "File Transfer Protocol"
 msgstr "फाईल-ट्रान्स्फर प्रोटोकल"
 
 #. Translators: do not translate ftp:// and ftps://
-#: gtk/gtkplacesview.c:1613
+#: gtk/gtkplacesview.c:1600
 msgid "ftp:// or ftps://"
 msgstr "ftp:// or ftps://"
 
-#: gtk/gtkplacesview.c:1619
+#: gtk/gtkplacesview.c:1606
 msgid "Network File System"
 msgstr "सञ्जाल फाइल प्रणाली"
 
-#: gtk/gtkplacesview.c:1625
+#: gtk/gtkplacesview.c:1612
 msgid "Samba"
 msgstr "साम्बा"
 
-#: gtk/gtkplacesview.c:1631
+#: gtk/gtkplacesview.c:1618
 msgid "SSH File Transfer Protocol"
 msgstr "SSH फाईल-ट्रान्स्फर प्रोटोकल"
 
 #. Translators: do not translate sftp:// and ssh://
-#: gtk/gtkplacesview.c:1633
+#: gtk/gtkplacesview.c:1620
 msgid "sftp:// or ssh://"
 msgstr "sftp:// or ssh://"
 
-#: gtk/gtkplacesview.c:1639
+#: gtk/gtkplacesview.c:1626
 msgid "WebDAV"
 msgstr "WebDAV"
 
 #. Translators: do not translate dav:// and davs://
-#: gtk/gtkplacesview.c:1641
+#: gtk/gtkplacesview.c:1628
 msgid "dav:// or davs://"
 msgstr "dav:// वा davs://"
 
-#: gtk/gtkplacesview.c:1676
+#: gtk/gtkplacesview.c:1663
 msgid "_Disconnect"
 msgstr "जडान विच्छेद गर्नुहोस्"
 
-#: gtk/gtkplacesview.c:1687
+#: gtk/gtkplacesview.c:1674
 msgid "_Connect"
 msgstr "जडान गर्नुहोस्"
 
-#: gtk/gtkplacesview.c:1871
+#: gtk/gtkplacesview.c:1894
 msgid "Unable to get remote server location"
 msgstr "टाढाको सर्भर स्थान प्राप्त गर्न असक्षम भयो"
 
-#: gtk/gtkplacesview.c:2014 gtk/gtkplacesview.c:2023
+#: gtk/gtkplacesview.c:2038 gtk/gtkplacesview.c:2047
 msgid "Networks"
 msgstr "सञ्जाल"
 
-#: gtk/gtkplacesview.c:2014 gtk/gtkplacesview.c:2023
+#: gtk/gtkplacesview.c:2038 gtk/gtkplacesview.c:2047
 msgid "On This Computer"
 msgstr "यस कम्प्युटरमा"
 
@@ -3068,31 +3233,27 @@ msgid_plural "%s / %s available"
 msgstr[0] "%s / %s उपलब्ध छ"
 msgstr[1] "%s / %s उपलब्ध छ"
 
-#: gtk/gtkplacesviewrow.c:485
+#: gtk/gtkplacesviewrow.c:471
 msgid "Disconnect"
 msgstr "विच्छेदन गर्नुहोस्"
 
-#: gtk/gtkplacesviewrow.c:485
+#: gtk/gtkplacesviewrow.c:471 gtk/ui/gtkplacesviewrow.ui:53 gtk/ui/gtksidebarrow.ui:54
 msgid "Unmount"
 msgstr "अनमाउण्ट गर्नुहोस्"
 
-#: gtk/gtkprintbackend.c:641
+#: gtk/print/gtkprintbackend.c:637
 msgid "Authentication"
 msgstr "प्रमाणीकरण"
 
-#: gtk/gtkprintbackend.c:717
+#: gtk/print/gtkprintbackend.c:716
 msgid "_Remember password"
 msgstr "पासवर्ड सम्झनुहोस्"
 
-#: gtk/gtkprinteroptionwidget.c:710
+#: gtk/print/gtkprinteroptionwidget.c:703
 msgid "Select a filename"
 msgstr "फाइलनाम चयन गर्नुहोस्"
 
-#: gtk/gtkprinteroptionwidget.c:714
-msgid "_Select"
-msgstr "_चयन गर्नुहोस्"
-
-#: gtk/gtkprinteroptionwidget.c:939
+#: gtk/print/gtkprinteroptionwidget.c:947
 msgid "Not available"
 msgstr "उपलब्ध छैन"
 
@@ -3100,161 +3261,156 @@ msgstr "उपलब्ध छैन"
 #. * jobs. %s gets replaced by the application name, %d gets replaced
 #. * by the job number.
 #.
-#: gtk/gtkprintoperation.c:253
+#: gtk/print/gtkprintoperation.c:255
 #, c-format
 msgid "%s job #%d"
 msgstr "%s काम #%d"
 
-#: gtk/gtkprintoperation.c:1719
+#: gtk/print/gtkprintoperation.c:1702
 msgctxt "print operation status"
 msgid "Initial state"
 msgstr "सुरू स्थिति"
 
-#: gtk/gtkprintoperation.c:1720
-#, fuzzy
+#: gtk/print/gtkprintoperation.c:1703
 msgctxt "print operation status"
 msgid "Preparing to print"
-msgstr "मुद्रण तयारी गर्दै…"
+msgstr "मुद्रण तयारी गर्दै"
 
-#: gtk/gtkprintoperation.c:1721
-#, fuzzy
+#: gtk/print/gtkprintoperation.c:1704
 msgctxt "print operation status"
 msgid "Generating data"
-msgstr "कुञ्जी सिर्जना गर्दै"
+msgstr "डेटा सिर्जना गर्दैछ"
 
-#: gtk/gtkprintoperation.c:1722
+#: gtk/print/gtkprintoperation.c:1705
 msgctxt "print operation status"
 msgid "Sending data"
 msgstr "डेटा पठाउदै"
 
-#: gtk/gtkprintoperation.c:1723
+#: gtk/print/gtkprintoperation.c:1706
 msgctxt "print operation status"
 msgid "Waiting"
 msgstr "प्रतिक्षा गर्दैछ"
 
-#: gtk/gtkprintoperation.c:1724
-#, fuzzy
+#: gtk/print/gtkprintoperation.c:1707
 msgctxt "print operation status"
 msgid "Blocking on issue"
-msgstr "यो कार्यक्रमले लगआउट गर्न दिएन"
+msgstr "मुद्दा को अवरुद्ध करना"
 
-#: gtk/gtkprintoperation.c:1725
+#: gtk/print/gtkprintoperation.c:1708
 msgctxt "print operation status"
 msgid "Printing"
 msgstr "मुद्रण हुँदैछ"
 
-#: gtk/gtkprintoperation.c:1726
+#: gtk/print/gtkprintoperation.c:1709
 msgctxt "print operation status"
 msgid "Finished"
 msgstr "समाप्त भयो"
 
-#: gtk/gtkprintoperation.c:1727
+#: gtk/print/gtkprintoperation.c:1710
 msgctxt "print operation status"
 msgid "Finished with error"
 msgstr "त्रुटि साथ समाप्त भयो"
 
-#: gtk/gtkprintoperation.c:2270
+#: gtk/print/gtkprintoperation.c:2254
 #, c-format
 msgid "Preparing %d"
 msgstr "%d तयार गर्दै"
 
-#: gtk/gtkprintoperation.c:2272 gtk/gtkprintoperation.c:2890
+#: gtk/print/gtkprintoperation.c:2256 gtk/print/gtkprintoperation.c:2875
 #, c-format
 msgid "Preparing"
 msgstr "तयारी गर्दैछ"
 
-#: gtk/gtkprintoperation.c:2275
+#: gtk/print/gtkprintoperation.c:2259
 #, c-format
 msgid "Printing %d"
 msgstr "%d मुद्रण गर्दै"
 
-#: gtk/gtkprintoperation.c:2921
+#: gtk/print/gtkprintoperation.c:2908
 #, c-format
 msgid "Error creating print preview"
 msgstr "मुद्रण पूर्वावलोकन सिर्जना गर्दा त्रुटि"
 
-#: gtk/gtkprintoperation.c:2924
+#: gtk/print/gtkprintoperation.c:2911
 #, c-format
 msgid "The most probable reason is that a temporary file could not be created."
-msgstr "सबैभन्दा सम्भावित कारण अस्थायी फाइल सिर्जना गर्न सकिएन ।"
+msgstr "सबैभन्दा सम्भावित कारण अस्थायी फाइल सिर्जना गर्न सकिएन ।."
 
 #. window
-#: gtk/gtkprintoperation-portal.c:236 gtk/gtkprintoperation-portal.c:554
-#: gtk/gtkprintoperation-portal.c:623 gtk/gtkprintunixdialog.c:3069
+#: gtk/print/gtkprintoperation-portal.c:273 gtk/print/gtkprintoperation-portal.c:603 gtk/print/gtkprintoperation-portal.c:672 gtk/print/gtkprintunixdialog.c:3016
 msgid "Print"
 msgstr "मुद्रण"
 
-#: gtk/gtkprintoperation-unix.c:479 gtk/gtkprintoperation-win32.c:1503
+#: gtk/print/gtkprintoperation-unix.c:490 gtk/print/gtkprintoperation-win32.c:1508
 msgid "Application"
 msgstr "अनुप्रयोग"
 
-#: gtk/gtkprintoperation-win32.c:634
+#: gtk/print/gtkprintoperation-win32.c:636
 msgid "Printer offline"
 msgstr "मुद्रक अफलाइन"
 
-#: gtk/gtkprintoperation-win32.c:636
+#: gtk/print/gtkprintoperation-win32.c:638
 msgid "Out of paper"
 msgstr "कागज सकियो"
 
 #. Translators: this is a printer status.
-#: gtk/gtkprintoperation-win32.c:638 modules/printbackends/gtkprintbackendcups.c:2660
+#: gtk/print/gtkprintoperation-win32.c:640 modules/printbackends/gtkprintbackendcpdb.c:1533 modules/printbackends/gtkprintbackendcups.c:2639
 msgid "Paused"
 msgstr "पज गरिएको"
 
-#: gtk/gtkprintoperation-win32.c:640
+#: gtk/print/gtkprintoperation-win32.c:642
 msgid "Need user intervention"
 msgstr "आवश्यक प्रयोगकर्ता अवरोध"
 
-#: gtk/gtkprintoperation-win32.c:747
+#: gtk/print/gtkprintoperation-win32.c:749
 msgid "Custom size"
 msgstr "अनुकूल साइज"
 
-#: gtk/gtkprintoperation-win32.c:1595
+#: gtk/print/gtkprintoperation-win32.c:1600
 msgid "No printer found"
 msgstr "मुद्रणयन्त्र भेटिएन"
 
-#: gtk/gtkprintoperation-win32.c:1622
+#: gtk/print/gtkprintoperation-win32.c:1627
 msgid "Invalid argument to CreateDC"
 msgstr "CreateDC मा अमान्य तर्क"
 
-#: gtk/gtkprintoperation-win32.c:1658 gtk/gtkprintoperation-win32.c:1904
+#: gtk/print/gtkprintoperation-win32.c:1663 gtk/print/gtkprintoperation-win32.c:1909
 msgid "Error from StartDoc"
 msgstr "StartDoc बाट त्रुटि"
 
-#: gtk/gtkprintoperation-win32.c:1759 gtk/gtkprintoperation-win32.c:1782
-#: gtk/gtkprintoperation-win32.c:1830
+#: gtk/print/gtkprintoperation-win32.c:1764 gtk/print/gtkprintoperation-win32.c:1787 gtk/print/gtkprintoperation-win32.c:1835
 msgid "Not enough free memory"
 msgstr "पर्याप्त खाली स्मृति छैन"
 
-#: gtk/gtkprintoperation-win32.c:1835
+#: gtk/print/gtkprintoperation-win32.c:1840
 msgid "Invalid argument to PrintDlgEx"
 msgstr "PrintDlgEx मा अवैध आर्गुमेन्ट"
 
-#: gtk/gtkprintoperation-win32.c:1840
+#: gtk/print/gtkprintoperation-win32.c:1845
 msgid "Invalid pointer to PrintDlgEx"
 msgstr "PrintDlgEx मा अवैध सङ्केतक"
 
-#: gtk/gtkprintoperation-win32.c:1845
+#: gtk/print/gtkprintoperation-win32.c:1850
 msgid "Invalid handle to PrintDlgEx"
 msgstr "PrintDlgEx मा अवैध ह्याण्डल"
 
-#: gtk/gtkprintoperation-win32.c:1850
+#: gtk/print/gtkprintoperation-win32.c:1855
 msgid "Unspecified error"
 msgstr "निर्दिष्ट नगरिएको त्रुटि"
 
-#: gtk/gtkprintunixdialog.c:822
+#: gtk/print/gtkprintunixdialog.c:838
 msgid "Pre_view"
 msgstr "पूर्वावलोकन"
 
-#: gtk/gtkprintunixdialog.c:824
+#: gtk/print/gtkprintunixdialog.c:840
 msgid "_Print"
 msgstr "मुद्रण गर्नुहोस्"
 
-#: gtk/gtkprintunixdialog.c:952
+#: gtk/print/gtkprintunixdialog.c:967
 msgid "Getting printer information failed"
 msgstr "मुद्रणयन्त्र सुचना पाउन असफल"
 
-#: gtk/gtkprintunixdialog.c:1888
+#: gtk/print/gtkprintunixdialog.c:1891
 msgid "Getting printer information…"
 msgstr "मुद्रणयन्त्र जानकारि लिदै…"
 
@@ -3264,82 +3420,81 @@ msgstr "मुद्रणयन्त्र जानकारि लिदै
 #. Translators: These strings name the possible arrangements of
 #. * multiple pages on a sheet when printing
 #.
-#: gtk/gtkprintunixdialog.c:2814 modules/printbackends/gtkprintbackendcups.c:5675
+#: gtk/print/gtkprintunixdialog.c:2761 modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, top to bottom"
 msgstr "बाँया-दायाँ,माथि-तल"
 
-#: gtk/gtkprintunixdialog.c:2814 modules/printbackends/gtkprintbackendcups.c:5675
+#: gtk/print/gtkprintunixdialog.c:2761 modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, bottom to top"
 msgstr "बाँया-दायाँ,तल-माथि"
 
-#: gtk/gtkprintunixdialog.c:2815 modules/printbackends/gtkprintbackendcups.c:5676
+#: gtk/print/gtkprintunixdialog.c:2762 modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, top to bottom"
 msgstr "दायाँ-बाँया,माथि-तल"
 
-#: gtk/gtkprintunixdialog.c:2815 modules/printbackends/gtkprintbackendcups.c:5676
+#: gtk/print/gtkprintunixdialog.c:2762 modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, bottom to top"
 msgstr "दायाँ-बाँया,तल-माथि"
 
-#: gtk/gtkprintunixdialog.c:2816 modules/printbackends/gtkprintbackendcups.c:5677
+#: gtk/print/gtkprintunixdialog.c:2763 modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, left to right"
 msgstr "माथि-तल,बाँया-दायाँ"
 
-#: gtk/gtkprintunixdialog.c:2816 modules/printbackends/gtkprintbackendcups.c:5677
+#: gtk/print/gtkprintunixdialog.c:2763 modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, right to left"
 msgstr "माथि-तल,दायाँ-बाँया"
 
-#: gtk/gtkprintunixdialog.c:2817 modules/printbackends/gtkprintbackendcups.c:5678
+#: gtk/print/gtkprintunixdialog.c:2764 modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, left to right"
 msgstr "तल-माथि,बाँया-दायाँ"
 
-#: gtk/gtkprintunixdialog.c:2817 modules/printbackends/gtkprintbackendcups.c:5678
+#: gtk/print/gtkprintunixdialog.c:2764 modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, right to left"
 msgstr "तल-माथि,दायाँ-बाँया"
 
-#: gtk/gtkprintunixdialog.c:2821 gtk/gtkprintunixdialog.c:2834
+#: gtk/print/gtkprintunixdialog.c:2768 gtk/print/gtkprintunixdialog.c:2781
 msgid "Page Ordering"
 msgstr "पृष्ठ क्रमाङ्क"
 
-#: gtk/gtkprintunixdialog.c:2850
+#: gtk/print/gtkprintunixdialog.c:2797
 msgid "Left to right"
 msgstr "बायाँ - दायाँ"
 
-#: gtk/gtkprintunixdialog.c:2851
+#: gtk/print/gtkprintunixdialog.c:2798
 msgid "Right to left"
 msgstr "दायाँ - बायाँ"
 
-#: gtk/gtkprintunixdialog.c:2863
+#: gtk/print/gtkprintunixdialog.c:2810
 msgid "Top to bottom"
 msgstr "माथि- तल‍"
 
-#: gtk/gtkprintunixdialog.c:2864
+#: gtk/print/gtkprintunixdialog.c:2811
 msgid "Bottom to top"
 msgstr "तल ‍- माथि"
 
-#: gtk/gtkprogressbar.c:619
+#: gtk/gtkprogressbar.c:627
 #, c-format
 msgctxt "progress bar label"
 msgid "%.0f %%"
 msgstr "%.0f %%"
 
-#: gtk/gtkrecentmanager.c:1027 gtk/gtkrecentmanager.c:1040 gtk/gtkrecentmanager.c:1178
-#: gtk/gtkrecentmanager.c:1188 gtk/gtkrecentmanager.c:1238 gtk/gtkrecentmanager.c:1247
-#, fuzzy, c-format
+#: gtk/gtkrecentmanager.c:1030 gtk/gtkrecentmanager.c:1043 gtk/gtkrecentmanager.c:1181 gtk/gtkrecentmanager.c:1191 gtk/gtkrecentmanager.c:1241 gtk/gtkrecentmanager.c:1250
+#, c-format
 msgid "Unable to find an item with URI “%s”"
 msgstr "'%s' URI सँग एउटा वस्तु फेला पार्न असक्षम"
 
-#: gtk/gtkrecentmanager.c:1262
-#, fuzzy, c-format
+#: gtk/gtkrecentmanager.c:1265
+#, c-format
 msgid "Unable to move the item with URI “%s” to “%s”"
-msgstr "'%s' URI सँग एउटा वस्तु फेला पार्न असक्षम"
+msgstr "URI '%s' सँग वस्तु '%s' मा सार्न असक्षम"
 
-#: gtk/gtkrecentmanager.c:2323
+#: gtk/gtkrecentmanager.c:2330
 #, c-format
 msgid "No registered application with name “%s” for item with URI “%s” found"
 msgstr ""
 
-#: gtk/gtksearchentry.c:619
-msgid "Clear entry"
+#: gtk/gtksearchentry.c:836
+msgid "Clear Entry"
 msgstr "प्रविष्टि खाली गर्नुहोस्"
 
 #. Translators: This string is used to mark left/right variants of modifier
@@ -3347,7 +3502,7 @@ msgstr "प्रविष्टि खाली गर्नुहोस्"
 #. * this string very short, ideally just a single character, since it will
 #. * be rendered as part of the key.
 #.
-#: gtk/gtkshortcutlabel.c:78
+#: gtk/gtkshortcutlabel.c:79
 msgctxt "keyboard side marker"
 msgid "L"
 msgstr "L"
@@ -3357,12 +3512,12 @@ msgstr "L"
 #. * this string very short, ideally just a single character, since it will
 #. * be rendered as part of the key.
 #.
-#: gtk/gtkshortcutlabel.c:91
+#: gtk/gtkshortcutlabel.c:92
 msgctxt "keyboard side marker"
 msgid "R"
 msgstr "R"
 
-#: gtk/gtkshortcutssection.c:404
+#: gtk/gtkshortcutssection.c:435
 msgid "_Show All"
 msgstr "सबै देखाऊ"
 
@@ -3371,9 +3526,8 @@ msgid "Two finger pinch"
 msgstr "दुई औंली चिम्टि"
 
 #: gtk/gtkshortcutsshortcut.c:147
-#, fuzzy
 msgid "Two finger stretch"
-msgstr "दुई औला स्क्रोलिङ्ग"
+msgstr ""
 
 #: gtk/gtkshortcutsshortcut.c:151
 msgid "Rotate clockwise"
@@ -3399,85 +3553,61 @@ msgstr "बायाँ सार्नुहोस्"
 msgid "Swipe right"
 msgstr "दाँया सार्नुहोस्"
 
+#. Translators: This is placeholder text for the search entry in the shortcuts window
+#: gtk/gtkshortcutswindow.c:894 gtk/gtkshortcutswindow.c:961 gtk/gtkshortcutswindow.c:967
+msgid "Search Shortcuts"
+msgstr "सर्टकट खोजी"
+
 #. Translators: This is the window title for the shortcuts window in normal mode
-#: gtk/gtkshortcutswindow.c:874 gtk/inspector/window.ui:498
+#: gtk/gtkshortcutswindow.c:926 gtk/inspector/window.ui:498
 msgid "Shortcuts"
 msgstr "सर्टकटहरू"
 
 #. Translators: This is the window title for the shortcuts window in search mode
-#: gtk/gtkshortcutswindow.c:879
+#: gtk/gtkshortcutswindow.c:931
 msgid "Search Results"
 msgstr "नतिजा खोजी गर्नुहोस्"
 
-#. Translators: This is placeholder text for the search entry in the shortcuts window
-#: gtk/gtkshortcutswindow.c:909
-msgid "Search Shortcuts"
-msgstr "सर्टकट खोजी"
-
-#: gtk/gtkshortcutswindow.c:968
+#: gtk/gtkshortcutswindow.c:1029 gtk/ui/gtkemojichooser.ui:352 gtk/ui/gtkfilechooserwidget.ui:250
 msgid "No Results Found"
 msgstr "नतिजा भेटिएन"
 
-#: gtk/gtkshortcutswindow.c:974
+#: gtk/gtkshortcutswindow.c:1040 gtk/ui/gtkemojichooser.ui:365 gtk/ui/gtkfilechooserwidget.ui:263 gtk/ui/gtkplacesview.ui:218
 msgid "Try a different search"
 msgstr "फरक खोज कोशिश गर्नुहोस्"
 
-#: gtk/gtkshow.c:177
-msgid "Could not show link"
-msgstr "लिङ्क देखाउन सकेन"
+#: gtk/gtkstacksidebar.c:155
+msgctxt "accessibility"
+msgid "Sidebar"
+msgstr "छेउपट्टी"
 
-#: gtk/gtktext.c:6091 gtk/gtktextview.c:8982
+#: gtk/gtktext.c:6349 gtk/gtktextview.c:9263
 msgid "Insert _Emoji"
 msgstr "ई-मोजि घुसाउनुहोस्"
 
-#: gtk/gtktextview.c:8964
+#: gtk/gtktextview.c:9245
 msgid "_Undo"
 msgstr "पूर्वस्थितिमा फर्काउनुहोस्"
 
-#: gtk/gtktextview.c:8968
+#: gtk/gtktextview.c:9249
 msgid "_Redo"
 msgstr "फेरि गर्नुहोस्"
 
-#: gtk/gtktreeexpander.c:205 gtk/inspector/misc-info.ui:278
-msgid "Expand"
-msgstr "ठूलो बनाउनु"
-
-#: gtk/gtkvolumebutton.c:230
-msgid "Muted"
-msgstr "मौन गरिएको"
-
-#: gtk/gtkvolumebutton.c:234
-msgid "Full Volume"
-msgstr "पूर्ण भोल्युम"
-
-#. Translators: this is the percentage of the current volume,
-#. * as used in the tooltip, eg. "49 %".
-#. * Translate the "%d" to "%Id" if you want to use localised digits,
-#. * or otherwise translate the "%d" to "%d".
-#.
-#: gtk/gtkvolumebutton.c:247
-#, c-format
-msgctxt "volume percentage"
-msgid "%d %%"
-msgstr "%d %%"
-
-#: gtk/gtkwindow.c:6142
+#: gtk/gtkwindow.c:6200
 #, c-format
 msgid "Do you want to use GTK Inspector?"
 msgstr "तपाईँ GTK+ निरीक्षक प्रयोग गर्न चाहनुहुन्छ?"
 
-#: gtk/gtkwindow.c:6144
+#: gtk/gtkwindow.c:6202
 #, c-format
-msgid ""
-"GTK Inspector is an interactive debugger that lets you explore and modify the internals of any "
-"GTK application. Using it may cause the application to break or crash."
+msgid "GTK Inspector is an interactive debugger that lets you explore and modify the internals of any GTK application. Using it may cause the application to break or crash."
 msgstr ""
 
-#: gtk/gtkwindow.c:6149
+#: gtk/gtkwindow.c:6207
 msgid "Don’t show this message again"
 msgstr "यो सन्देश पुन: नदेखाउनुहोस्"
 
-#: gtk/gtkwindowcontrols.c:309 gtk/gtkwindowhandle.c:230
+#: gtk/gtkwindowcontrols.c:309 gtk/gtkwindowhandle.c:234
 msgid "Minimize"
 msgstr "सानो बनाउनुहोस्"
 
@@ -3485,7 +3615,7 @@ msgstr "सानो बनाउनुहोस्"
 msgid "Minimize the window"
 msgstr "सञ्झ्याल घटाउनुहोस्"
 
-#: gtk/gtkwindowcontrols.c:335 gtk/gtkwindowhandle.c:236
+#: gtk/gtkwindowcontrols.c:335 gtk/gtkwindowhandle.c:240
 msgid "Maximize"
 msgstr "ठूलो बनाउनुहोस्"
 
@@ -3493,42 +3623,44 @@ msgstr "ठूलो बनाउनुहोस्"
 msgid "Maximize the window"
 msgstr "सञ्झ्याललाई बढाउनुहोस्"
 
-#: gtk/gtkwindowcontrols.c:357 gtk/gtkwindowhandle.c:246
-msgid "Close"
-msgstr "बन्द गर्नुहोस्"
-
 #: gtk/gtkwindowcontrols.c:359
 msgid "Close the window"
 msgstr "सञ्झ्याल बन्द गर्नुहोस्"
 
-#: gtk/gtkwindowhandle.c:223
+#: gtk/gtkwindowhandle.c:227
 msgid "Restore"
 msgstr "पूर्वावस्थामा ल्याउनुहोस्"
 
-#: gtk/inspector/a11y.ui:16
+#: gtk/inspector/a11y.ui:17
 msgid "Role"
 msgstr "भुमिका"
 
-#: gtk/inspector/a11y.ui:40
-#, fuzzy
-#| msgid "Object"
-msgid "Object path"
-msgstr "त्रुटि: %s अवैध वस्तु मार्ग\n"
+#: gtk/inspector/a11y.ui:71
+msgid "Description"
+msgstr "ब्याख्या"
+
+#: gtk/inspector/a11y.ui:99 gtk/inspector/misc-info.ui:296 tools/gtk-path-tool-info.c:132
+msgid "Bounds"
+msgstr "सीमा"
 
-#: gtk/inspector/a11y.ui:66
+#: gtk/inspector/a11y.ui:125
+msgid "Object Path"
+msgstr "वस्तु मार्ग"
+
+#: gtk/inspector/a11y.ui:164
 msgid "Attribute"
 msgstr "विशेषता"
 
-#: gtk/inspector/a11y.ui:78 gtk/inspector/css-node-tree.ui:119 gtk/inspector/prop-list.ui:57
-#: gtk/inspector/recorder.ui:155 gtk/inspector/recorder.ui:221
+#: gtk/inspector/a11y.ui:176 gtk/inspector/css-node-tree.ui:70 gtk/inspector/prop-list.ui:57 gtk/inspector/recorder.ui:149 gtk/inspector/recorder.ui:192
+#: gtk/inspector/strv-editor.c:73
 msgid "Value"
 msgstr "मान"
 
-#: gtk/inspector/action-editor.c:123
+#: gtk/inspector/action-editor.c:133
 msgid "Activate"
 msgstr "_सक्रिय बनाउ"
 
-#: gtk/inspector/action-editor.c:135
+#: gtk/inspector/action-editor.c:145
 msgid "Set State"
 msgstr "स्थिति सेट गर्नुहोस्"
 
@@ -3536,15 +3668,15 @@ msgstr "स्थिति सेट गर्नुहोस्"
 msgid "Enabled"
 msgstr "सक्षम बनाइयो"
 
-#: gtk/inspector/actions.ui:41
+#: gtk/inspector/actions.ui:42
 msgid "Parameter Type"
 msgstr "परामिति प्रकार"
 
-#: gtk/inspector/actions.ui:52 gtk/inspector/css-node-tree.ui:74 gtk/inspector/misc-info.ui:121
+#: gtk/inspector/actions.ui:53 gtk/inspector/css-node-tree.ui:41 gtk/inspector/misc-info.ui:108
 msgid "State"
 msgstr "अवस्था"
 
-#: gtk/inspector/clipboard.c:211
+#: gtk/inspector/clipboard.c:211 gtk/inspector/misc-info.ui:245
 msgid "Show"
 msgstr "देखाउने"
 
@@ -3552,31 +3684,30 @@ msgstr "देखाउने"
 msgid "Hover to load"
 msgstr "होवर लोड गर्नुहोस्"
 
-#: gtk/inspector/clipboard.c:278
+#: gtk/inspector/clipboard.c:286
 msgctxt "clipboard"
 msgid "empty"
 msgstr "empty"
 
-#: gtk/inspector/clipboard.c:283 gtk/inspector/clipboard.c:325
+#: gtk/inspector/clipboard.c:291 gtk/inspector/clipboard.c:344
 msgctxt "clipboard"
 msgid "local"
 msgstr "स्थानीय"
 
-#: gtk/inspector/clipboard.c:285 gtk/inspector/clipboard.c:327
+#: gtk/inspector/clipboard.c:293 gtk/inspector/clipboard.c:346
 msgctxt "clipboard"
 msgid "remote"
 msgstr "टाढा"
 
-#: gtk/inspector/clipboard.ui:31
-#, fuzzy
+#: gtk/inspector/clipboard.ui:30
 msgid "Drag and hold here"
-msgstr "घिसार्नु"
+msgstr ""
 
-#: gtk/inspector/clipboard.ui:75 gtk/inspector/window.ui:574
+#: gtk/inspector/clipboard.ui:71 gtk/inspector/window.ui:574
 msgid "Clipboard"
 msgstr "क्लिपबोर्ड"
 
-#: gtk/inspector/clipboard.ui:114
+#: gtk/inspector/clipboard.ui:107
 msgid "Primary"
 msgstr "प्राथमिक"
 
@@ -3601,273 +3732,291 @@ msgid "Target"
 msgstr "लक्ष्य"
 
 #: gtk/inspector/controllers.c:156
-#, fuzzy
-#| msgid "Cumulative"
 msgctxt "propagation limit"
 msgid "Native"
-msgstr "प्राचिन _ढाँचा"
+msgstr "मूल"
 
-#: gtk/inspector/css-editor.c:129
+#: gtk/inspector/css-editor.c:135
 msgid "You can type here any CSS rule recognized by GTK."
 msgstr ""
 
-#: gtk/inspector/css-editor.c:130
+#: gtk/inspector/css-editor.c:136
 msgid "You can temporarily disable this custom CSS by clicking on the “Pause” button above."
 msgstr ""
 
-#: gtk/inspector/css-editor.c:131
+#: gtk/inspector/css-editor.c:137
 msgid "Changes are applied instantly and globally, for the whole application."
 msgstr ""
 
-#: gtk/inspector/css-editor.c:211
+#: gtk/inspector/css-editor.c:236
 #, c-format
 msgid "Saving CSS failed"
 msgstr "CSS बचत गर्दै"
 
-#: gtk/inspector/css-editor.ui:30
+#: gtk/inspector/css-editor.ui:37
 msgid "Disable this custom CSS"
 msgstr "अनुकुलन CSS अक्षम गर्नुहोस्"
 
-#: gtk/inspector/css-editor.ui:37
+#: gtk/inspector/css-editor.ui:44
 msgid "Save the current CSS"
 msgstr "हालको CSS बचत गर्नुहोस्"
 
-#: gtk/inspector/css-node-tree.ui:48
+#: gtk/inspector/css-editor.ui:51
+#| msgid "Show other locations"
+msgid "Show deprecations"
+msgstr ""
+
+#: gtk/inspector/css-node-tree.ui:28 tools/gtk-builder-tool-preview.c:178 tools/gtk-builder-tool-screenshot.c:359
 msgid "ID"
 msgstr "आईडी"
 
-#: gtk/inspector/css-node-tree.ui:61
+#: gtk/inspector/css-node-tree.ui:34
 msgid "Style Classes"
 msgstr "शैली वर्गहरू"
 
-#: gtk/inspector/css-node-tree.ui:104
+#: gtk/inspector/css-node-tree.ui:64
 msgid "CSS Property"
 msgstr "CSS गुण"
 
-#: gtk/inspector/general.c:330 gtk/inspector/general.c:411
+#: gtk/inspector/general.c:372
 msgctxt "GL version"
 msgid "None"
 msgstr "None"
 
-#: gtk/inspector/general.c:339
+#: gtk/inspector/general.c:464
 msgctxt "GL version"
-msgid "Disabled"
-msgstr "असक्षम पारिएको छ"
-
-#: gtk/inspector/general.c:340
-msgctxt "GL vendor"
-msgid "Disabled"
-msgstr "असक्षम पारिएको छ"
-
-#: gtk/inspector/general.c:412
-msgctxt "GL vendor"
-msgid "None"
-msgstr "None"
+msgid "Unknown"
+msgstr "अज्ञात"
 
-#: gtk/inspector/general.c:463
+#: gtk/inspector/general.c:526
 msgctxt "Vulkan device"
 msgid "Disabled"
 msgstr "असक्षम पारिएको छ"
 
-#: gtk/inspector/general.c:464 gtk/inspector/general.c:465
+#: gtk/inspector/general.c:527 gtk/inspector/general.c:528
 msgctxt "Vulkan version"
 msgid "Disabled"
 msgstr "असक्षम पारिएको छ"
 
-#: gtk/inspector/general.c:521
+#: gtk/inspector/general.c:579
 msgctxt "Vulkan device"
 msgid "None"
 msgstr "कुनै पनि होइन"
 
-#: gtk/inspector/general.c:522 gtk/inspector/general.c:523
+#: gtk/inspector/general.c:580 gtk/inspector/general.c:581
 msgctxt "Vulkan version"
 msgid "None"
 msgstr "कुनै पनि होइन"
 
-#: gtk/inspector/general.c:793
-#, fuzzy
+#: gtk/inspector/general.c:934
 msgid "IM Context is hardcoded by GTK_IM_MODULE"
-msgstr "gtk+ द्वारा प्रयोग गरिएको पूर्वनिर्धारित विषयवस्तुको आधार नाम ।"
+msgstr ""
 
-#: gtk/inspector/general.ui:32
+#: gtk/inspector/general.ui:31
 msgid "GTK Version"
 msgstr "जीटीके संस्करण"
 
-#: gtk/inspector/general.ui:58
-#, fuzzy
+#: gtk/inspector/general.ui:57
 msgid "GDK Backend"
-msgstr "जिडिकेका लागि पूर्वनिर्धारित प्रदर्शन"
+msgstr ""
 
-#: gtk/inspector/general.ui:84
-#, fuzzy
+#: gtk/inspector/general.ui:83
 msgid "GSK Renderer"
-msgstr "कोगल पाङ्गो रेन्डरर ट्रेस गर्नुहोस्"
+msgstr ""
 
-#: gtk/inspector/general.ui:110
-#, fuzzy
+#: gtk/inspector/general.ui:109
 msgid "Pango Fontmap"
-msgstr "प्याङ्गो समूहभित्र वर्णको आकार"
+msgstr ""
 
-#: gtk/inspector/general.ui:136
-#, fuzzy
+#: gtk/inspector/general.ui:135
 msgid "Media Backend"
-msgstr "ब्याकइन्ड ब्यस्त छ"
+msgstr ""
 
-#: gtk/inspector/general.ui:162
+#: gtk/inspector/general.ui:161
 msgid "Input Method"
 msgstr "आगत विधि"
 
-#: gtk/inspector/general.ui:202
+#: gtk/inspector/general.ui:198
 msgid "Application ID"
 msgstr "अनुप्रयोगहरु आईडी"
 
-#: gtk/inspector/general.ui:228
+#: gtk/inspector/general.ui:224
 msgid "Resource Path"
 msgstr "संसाधन मार्ग"
 
-#: gtk/inspector/general.ui:268
+#: gtk/inspector/general.ui:261 gtk/ui/gtkplacesview.ui:67
 msgid "Prefix"
 msgstr "PREFIX"
 
-#: gtk/inspector/general.ui:470
+#: gtk/inspector/general.ui:460
 msgid "Display"
 msgstr "प्रदर्शन"
 
-#: gtk/inspector/general.ui:497
+#: gtk/inspector/general.ui:487
 msgid "RGBA Visual"
 msgstr "RGBA दृश्य"
 
-#: gtk/inspector/general.ui:523
+#: gtk/inspector/general.ui:513
 msgid "Composited"
 msgstr "मिश्रित गरिएको"
 
-#: gtk/inspector/general.ui:575
+#: gtk/inspector/general.ui:538
+msgid "Protocols"
+msgstr "प्रोटोकल"
+
+#: gtk/inspector/general.ui:594
 msgid "GL Version"
 msgstr "GLसंस्करण"
 
-#: gtk/inspector/general.ui:625
-msgid "GL Vendor"
+#: gtk/inspector/general.ui:621
+#| msgid "GL Version"
+msgid "GL Backend Version"
+msgstr ""
+
+#: gtk/inspector/general.ui:671
+#| msgid "GL Vendor"
+msgid "GL Backend Vendor"
+msgstr ""
+
+#: gtk/inspector/general.ui:698
+msgid "GL_VENDOR"
 msgstr "GL विक्रेता"
 
-#: gtk/inspector/general.ui:665
+#: gtk/inspector/general.ui:727
+msgid "GL_RENDERER"
+msgstr "GL_RENDERER"
+
+#: gtk/inspector/general.ui:756
+msgid "GL_VERSION"
+msgstr "GLसंस्करण"
+
+#: gtk/inspector/general.ui:785
+msgid "GL_SHADING_LANGUAGE_VERSION"
+msgstr ""
+
+#: gtk/inspector/general.ui:813 gtk/inspector/general.ui:929
+msgid "Extensions"
+msgstr "विस्तारहरू"
+
+#: gtk/inspector/general.ui:849
 msgid "Vulkan Device"
 msgstr "भलकन यन्त्र"
 
-#: gtk/inspector/general.ui:692
-#, fuzzy
+#: gtk/inspector/general.ui:876
 msgid "Vulkan API version"
-msgstr "अभिलेखीकरण;सूचना;मैनुअल;मद्दत;API"
+msgstr ""
 
-#: gtk/inspector/general.ui:719
+#: gtk/inspector/general.ui:903
 msgid "Vulkan driver version"
 msgstr "भल्कन ड्राइभर संसकरण"
 
-#: gtk/inspector/menu.c:95
+#: gtk/inspector/menu.c:264
 msgid "Unnamed section"
 msgstr "नामकरण नगरिएको खण्ड"
 
-#: gtk/inspector/menu.ui:23
+#: gtk/inspector/menu.ui:26
 msgid "Label"
 msgstr "निसानी"
 
-#: gtk/inspector/menu.ui:36 gtk/inspector/shortcuts.ui:23
+#: gtk/inspector/menu.ui:31 gtk/inspector/shortcuts.ui:23
 msgid "Action"
 msgstr "क्रिया"
 
-#: gtk/inspector/menu.ui:49
+#: gtk/inspector/menu.ui:36
 msgid "Target"
 msgstr "लक्ष्य"
 
-#: gtk/inspector/menu.ui:62
+#: gtk/inspector/menu.ui:41
 msgid "Icon"
 msgstr "छविचित्र"
 
-#: gtk/inspector/misc-info.ui:32
+#: gtk/inspector/misc-info.ui:31
 msgid "Address"
 msgstr "ठेगाना"
 
-#: gtk/inspector/misc-info.ui:62 gtk/inspector/prop-list.ui:35 gtk/inspector/statistics.ui:46
-msgid "Type"
-msgstr "वर्ग"
-
-#: gtk/inspector/misc-info.ui:91
-#, fuzzy
+#: gtk/inspector/misc-info.ui:82
 msgid "Reference Count"
-msgstr "गणना"
+msgstr "सन्दर्भ गणना"
 
-#: gtk/inspector/misc-info.ui:151
+#: gtk/inspector/misc-info.ui:134
 msgid "Direction"
 msgstr "दिशा"
 
-#: gtk/inspector/misc-info.ui:181
-#, fuzzy
+#: gtk/inspector/misc-info.ui:160
 msgid "Buildable ID"
-msgstr "आइ डि:"
+msgstr ""
 
-#: gtk/inspector/misc-info.ui:211
-#, fuzzy
+#: gtk/inspector/misc-info.ui:186
 msgid "Mnemonic Label"
-msgstr "यो लेवलका लागि एम्नेमोनिक द्रुतसञ्चालक कि"
+msgstr ""
 
-#: gtk/inspector/misc-info.ui:240
+#: gtk/inspector/misc-info.ui:211
 msgid "Request Mode"
 msgstr "अनुरोध शैली"
 
-#: gtk/inspector/misc-info.ui:269
+#: gtk/inspector/misc-info.ui:236
 msgid "Measure map"
 msgstr "मानचित्र मापन"
 
-#: gtk/inspector/misc-info.ui:328
-msgid "Allocation"
-msgstr "निर्धारण"
+#: gtk/inspector/misc-info.ui:253
+msgid "Expand"
+msgstr "ठूलो बनाउनु"
 
-#: gtk/inspector/misc-info.ui:357
+#: gtk/inspector/misc-info.ui:321
 msgid "Baseline"
 msgstr "आधार पङ्ति"
 
-#: gtk/inspector/misc-info.ui:386
+#: gtk/inspector/misc-info.ui:346
 msgid "Surface"
 msgstr "सटह"
 
-#: gtk/inspector/misc-info.ui:405 gtk/inspector/misc-info.ui:444 gtk/inspector/misc-info.ui:483
-#: gtk/inspector/prop-editor.c:1162 gtk/inspector/prop-editor.c:1534 gtk/inspector/window.ui:396
+#: gtk/inspector/misc-info.ui:365 gtk/inspector/misc-info.ui:400 gtk/inspector/misc-info.ui:435 gtk/inspector/prop-editor.c:1153 gtk/inspector/prop-editor.c:1536
+#: gtk/inspector/window.ui:396
 msgid "Properties"
 msgstr "गुण"
 
-#: gtk/inspector/misc-info.ui:425
+#: gtk/inspector/misc-info.ui:381
 msgid "Renderer"
 msgstr "रेन्डरर"
 
-#: gtk/inspector/misc-info.ui:464
+#: gtk/inspector/misc-info.ui:416
 msgid "Frame Clock"
 msgstr "फ्रेम घडि"
 
-#: gtk/inspector/misc-info.ui:503
-#, fuzzy
+#: gtk/inspector/misc-info.ui:451
 msgid "Tick Callback"
-msgstr "कलब्याक"
+msgstr ""
 
-#: gtk/inspector/misc-info.ui:533
+#: gtk/inspector/misc-info.ui:477
 msgid "Frame Count"
 msgstr "फ्रेम गणना"
 
-#: gtk/inspector/misc-info.ui:562
+#: gtk/inspector/misc-info.ui:502
 msgid "Frame Rate"
 msgstr "फ्रेम दर"
 
-#: gtk/inspector/misc-info.ui:591
+#: gtk/inspector/misc-info.ui:527 gtk/inspector/visual.ui:315
+msgid "Scale"
+msgstr "नाप"
+
+#: gtk/inspector/misc-info.ui:552
+#| msgid "Color Name"
+msgid "Color state"
+msgstr "रङ स्थिति"
+
+#: gtk/inspector/misc-info.ui:577
 msgid "Mapped"
 msgstr "मानचित्रण गरियो"
 
-#: gtk/inspector/misc-info.ui:621
+#: gtk/inspector/misc-info.ui:603
 msgid "Realized"
 msgstr "साकार भयो"
 
-#: gtk/inspector/misc-info.ui:651
+#: gtk/inspector/misc-info.ui:629
 msgid "Is Toplevel"
 msgstr "उच्च तह हो"
 
-#: gtk/inspector/misc-info.ui:681
+#: gtk/inspector/misc-info.ui:655
 msgid "Child Visible"
 msgstr "शाखा देखिने"
 
@@ -3879,7 +4028,7 @@ msgstr "सूचक: %p"
 #. Translators: %s is a type name, for example
 #. * GtkPropertyExpression with value \"2.5\"
 #.
-#: gtk/inspector/prop-editor.c:834
+#: gtk/inspector/prop-editor.c:827
 #, c-format
 msgid "%s with value \"%s\""
 msgstr "%s सँग मान \"%s\""
@@ -3887,7 +4036,7 @@ msgstr "%s सँग मान \"%s\""
 #. Translators: Both %s are type names, for example
 #. * GtkPropertyExpression with type GObject
 #.
-#: gtk/inspector/prop-editor.c:845
+#: gtk/inspector/prop-editor.c:838
 #, c-format
 msgid "%s with type %s"
 msgstr "%s प्रकार %s सँग"
@@ -3895,7 +4044,7 @@ msgstr "%s प्रकार %s सँग"
 #. Translators: Both %s are type names, for example
 #. * GtkObjectExpression for GtkStringObject 0x23456789
 #.
-#: gtk/inspector/prop-editor.c:858
+#: gtk/inspector/prop-editor.c:851
 #, c-format
 msgid "%s for %s %p"
 msgstr "%s का लागि %s %p"
@@ -3903,71 +4052,71 @@ msgstr "%s का लागि %s %p"
 #. Translators: Both %s are type names, for example
 #. * GtkPropertyExpression with value type: gchararray
 #.
-#: gtk/inspector/prop-editor.c:888
+#: gtk/inspector/prop-editor.c:881
 #, c-format
 msgid "%s with value type %s"
 msgstr "मान प्रकार %s सँग %s"
 
-#: gtk/inspector/prop-editor.c:1242
+#: gtk/inspector/prop-editor.c:1230
 #, c-format
 msgid "Uneditable property type: %s"
 msgstr "सम्पादन अयोग्य गुण प्रकार: %s"
 
-#: gtk/inspector/prop-editor.c:1386
+#: gtk/inspector/prop-editor.c:1388
 msgctxt "column number"
 msgid "None"
 msgstr "कुनै पनि होइन"
 
-#: gtk/inspector/prop-editor.c:1423
+#: gtk/inspector/prop-editor.c:1425
 msgid "Attribute:"
 msgstr "विशेषता:"
 
-#: gtk/inspector/prop-editor.c:1426
+#: gtk/inspector/prop-editor.c:1428
 msgid "Model"
 msgstr "शैली"
 
-#: gtk/inspector/prop-editor.c:1431
+#: gtk/inspector/prop-editor.c:1433
 msgid "Column:"
 msgstr "स्तम्भ:"
 
 #. Translators: %s is a type name, for example
 #. * Action from 0x2345678 (GtkApplicationWindow)
 #.
-#: gtk/inspector/prop-editor.c:1530
+#: gtk/inspector/prop-editor.c:1532
 #, c-format
 msgid "Action from: %p (%s)"
 msgstr "यसबाट कार्य: %p (%s)"
 
-#: gtk/inspector/prop-editor.c:1585
+#: gtk/inspector/prop-editor.c:1587
 msgid "Reset"
 msgstr "रिसेट गर्नुहोस्"
 
-#: gtk/inspector/prop-editor.c:1593
+#: gtk/inspector/prop-editor.c:1595
 msgctxt "GtkSettings source"
 msgid "Default"
 msgstr "पुर्वनिर्धारित"
 
-#: gtk/inspector/prop-editor.c:1596
+#: gtk/inspector/prop-editor.c:1598
 msgctxt "GtkSettings source"
 msgid "Theme"
 msgstr "विषयवस्तु"
 
-#: gtk/inspector/prop-editor.c:1599
+#: gtk/inspector/prop-editor.c:1601
 msgctxt "GtkSettings source"
 msgid "XSettings"
-msgstr "X सेटिङ:"
+msgstr "X सेटिङ"
 
-#: gtk/inspector/prop-editor.c:1603
+#: gtk/inspector/prop-editor.c:1605
 msgctxt "GtkSettings source"
 msgid "Application"
 msgstr "अनुप्रयोग"
 
-#: gtk/inspector/prop-editor.c:1606
+#: gtk/inspector/prop-editor.c:1608
 msgctxt "GtkSettings source"
 msgid "Unknown"
 msgstr "अज्ञात"
 
-#: gtk/inspector/prop-editor.c:1609
+#: gtk/inspector/prop-editor.c:1611
 msgid "Source:"
 msgstr "स्रोत:"
 
@@ -3975,44 +4124,40 @@ msgstr "स्रोत:"
 msgid "Defined At"
 msgstr "परिभाषित"
 
-#: gtk/inspector/recorder.c:1677
-#, fuzzy, c-format
+#: gtk/inspector/recorder.c:2021
+#, c-format
 msgid "Saving RenderNode failed"
-msgstr "CSS बचत गर्दै"
+msgstr ""
 
 #: gtk/inspector/recorder.ui:20
-#, fuzzy
 msgid "Record frames"
-msgstr "प्रतिसेकेण्डमा फ्रेमहरू देखाउने "
+msgstr "फ्रेम हरू रेकर्ड गर्नुहोस्"
 
 #: gtk/inspector/recorder.ui:27
-#, fuzzy
 msgid "Clear recorded frames"
-msgstr "खाली गर्नुहोस्"
+msgstr ""
 
 #: gtk/inspector/recorder.ui:34
 msgid "Add debug nodes"
 msgstr "त्रुटि सच्याउने नोडहरू थप्नुहोस्"
 
 #: gtk/inspector/recorder.ui:42
-#, fuzzy
 msgid "Highlight event sequences"
-msgstr "घटना"
+msgstr ""
 
 #: gtk/inspector/recorder.ui:51
 msgid "Use a dark background"
 msgstr "पृष्ठभूमिका लागि प्रयोग गरिने गाढा  रङ"
 
 #: gtk/inspector/recorder.ui:59
-#, fuzzy
 msgid "Save selected node"
-msgstr "चयन गरिएको बचत गर्नुहोस्"
+msgstr "चयन गरिएको नोड बचत गर्नुहोस्"
 
 #: gtk/inspector/recorder.ui:67
 msgid "Copy to clipboard"
 msgstr "क्लिपबोर्डमा प्रतिलिपि गर्नुहोस्"
 
-#: gtk/inspector/recorder.ui:142 gtk/inspector/recorder.ui:208
+#: gtk/inspector/recorder.ui:144 gtk/inspector/recorder.ui:187
 msgid "Property"
 msgstr "गुण"
 
@@ -4024,10 +4169,6 @@ msgstr "पाथ"
 msgid "Count"
 msgstr "गणना"
 
-#: gtk/inspector/resource-list.ui:82
-msgid "Size"
-msgstr "साइज"
-
 #: gtk/inspector/resource-list.ui:121
 msgid "Name:"
 msgstr "नाम:"
@@ -4036,7 +4177,7 @@ msgstr "नाम:"
 msgid "Type:"
 msgstr "प्रकार:"
 
-#: gtk/inspector/resource-list.ui:164
+#: gtk/inspector/resource-list.ui:164 tools/gtk-image-tool-info.c:54
 msgid "Size:"
 msgstr "आकार:"
 
@@ -4044,62 +4185,71 @@ msgstr "आकार:"
 msgid "Trigger"
 msgstr "ट्रिगर"
 
-#: gtk/inspector/size-groups.c:225
+#: gtk/inspector/size-groups.c:228
 msgctxt "sizegroup mode"
 msgid "None"
 msgstr "None"
 
-#: gtk/inspector/size-groups.c:226
+#: gtk/inspector/size-groups.c:229
 msgctxt "sizegroup mode"
 msgid "Horizontal"
 msgstr "तेर्सो"
 
-#: gtk/inspector/size-groups.c:227
+#: gtk/inspector/size-groups.c:230
 msgctxt "sizegroup mode"
 msgid "Vertical"
 msgstr "ठाडो"
 
-#: gtk/inspector/size-groups.c:228
+#: gtk/inspector/size-groups.c:231
 msgctxt "sizegroup mode"
 msgid "Both"
 msgstr "दुवै"
 
-#: gtk/inspector/size-groups.c:240
+#: gtk/inspector/size-groups.c:243
 msgid "Mode"
 msgstr "मोड"
 
-#: gtk/inspector/statistics.c:400
+#: gtk/inspector/statistics.c:814
 msgid "GLib must be configured with -Dbuildtype=debug"
 msgstr ""
 
-#: gtk/inspector/statistics.ui:60
+#: gtk/inspector/statistics.ui:41
 msgid "Self 1"
 msgstr "आफै १"
 
-#: gtk/inspector/statistics.ui:71
+#: gtk/inspector/statistics.ui:46
 msgid "Cumulative 1"
 msgstr "क्युमुलेटिभ १"
 
-#: gtk/inspector/statistics.ui:82
+#: gtk/inspector/statistics.ui:51
 msgid "Self 2"
 msgstr "आफै २"
 
-#: gtk/inspector/statistics.ui:93
+#: gtk/inspector/statistics.ui:56
 msgid "Cumulative 2"
 msgstr "क्युमुलेटिभ २"
 
-#: gtk/inspector/statistics.ui:104
+#: gtk/inspector/statistics.ui:61
 msgid "Self"
 msgstr "आफै"
 
-#: gtk/inspector/statistics.ui:120
+#: gtk/inspector/statistics.ui:66
 msgid "Cumulative"
 msgstr "क्युमुलेटिभ"
 
-#: gtk/inspector/statistics.ui:151
+#: gtk/inspector/statistics.ui:88
 msgid "Enable statistics with GOBJECT_DEBUG=instance-count"
 msgstr ""
 
+#: gtk/inspector/strv-editor.c:83
+#, c-format
+msgid "Remove %s"
+msgstr "%s  हटाउनुहुन्छ"
+
+#: gtk/inspector/strv-editor.c:115
+msgid "Add"
+msgstr "थप्नुहोस्"
+
 #: gtk/inspector/tree-data.ui:10
 msgid "Show data"
 msgstr "डेटा देखाउनुहोस्"
@@ -4112,119 +4262,122 @@ msgstr "सोपानक्रम"
 msgid "Implements"
 msgstr "कार्यान्वयन गर्दछ"
 
-#: gtk/inspector/visual.c:603 gtk/inspector/visual.c:622
-#, fuzzy
+#: gtk/inspector/visual.c:690 gtk/inspector/visual.c:708
 msgid "Theme is hardcoded by GTK_THEME"
-msgstr "gtk+ द्वारा प्रयोग गरिएको पूर्वनिर्धारित विषयवस्तुको आधार नाम ।"
-
-#: gtk/inspector/visual.c:853
-#, fuzzy
-msgid "Backend does not support window scaling"
-msgstr "हालको ब्याकइन्डले OpenGL समर्थन गर्दैन"
-
-#: gtk/inspector/visual.c:1043
-msgid "GL rendering is disabled"
-msgstr "जिएल रेन्डरिङ असक्षम पारिएको"
+msgstr ""
 
-#: gtk/inspector/visual.ui:35
+#: gtk/inspector/visual.ui:34
 msgid "GTK Theme"
 msgstr "जीटीके विषयवस्तु"
 
-#: gtk/inspector/visual.ui:59
+#: gtk/inspector/visual.ui:58
 msgid "Dark Variant"
 msgstr "गाढा रङ्ग विविधता"
 
-#: gtk/inspector/visual.ui:84
+#: gtk/inspector/visual.ui:83
 msgid "Cursor Theme"
 msgstr "कर्सरको थिम"
 
-#: gtk/inspector/visual.ui:109
+#: gtk/inspector/visual.ui:108
 msgid "Cursor Size"
 msgstr "कर्सर आकार"
 
-#: gtk/inspector/visual.ui:145
+#: gtk/inspector/visual.ui:144
 msgid "Icon Theme"
 msgstr "प्रतिमा विषयवस्तु"
 
-#: gtk/inspector/visual.ui:195
-msgid "Font Scale"
-msgstr "वर्णको नाप"
-
-#: gtk/inspector/visual.ui:240
+#: gtk/inspector/visual.ui:169
 msgid "Text Direction"
 msgstr "पाठ निर्देशन"
 
-#: gtk/inspector/visual.ui:255
+#: gtk/inspector/visual.ui:184
 msgid "Left-to-Right"
 msgstr "बायाँ - दायाँ"
 
-#: gtk/inspector/visual.ui:256
+#: gtk/inspector/visual.ui:185
 msgid "Right-to-Left"
 msgstr "दायाँ - बायाँ"
 
-#: gtk/inspector/visual.ui:274
-msgid "Window Scaling"
-msgstr "सञ्झ्याल मापन"
-
-#: gtk/inspector/visual.ui:307
+#: gtk/inspector/visual.ui:202
 msgid "Animations"
 msgstr "एनिमेसनहरू"
 
-#: gtk/inspector/visual.ui:332
+#: gtk/inspector/visual.ui:227
 msgid "Slowdown"
 msgstr "ढिलो गर्नुहोस्"
 
-#: gtk/inspector/visual.ui:390
-#, fuzzy
-msgid "Show fps overlay"
-msgstr "माथि राखिने वस्तु"
+#: gtk/inspector/visual.ui:362
+msgid "Rendering"
+msgstr "रेन्डरिङ"
+
+#: gtk/inspector/visual.ui:377
+msgctxt "Font rendering"
+msgid "Automatic"
+msgstr "स्वाचालित"
+
+#: gtk/inspector/visual.ui:378
+msgctxt "Font rendering"
+msgid "Manual"
+msgstr "म्यानुअल"
 
-#: gtk/inspector/visual.ui:415
+#: gtk/inspector/visual.ui:405
+#| msgid "Frame Rate"
+msgid "Show Framerate"
+msgstr "फ्रेमदर देखाउनुहोस्"
+
+#: gtk/inspector/visual.ui:430
 msgid "Show Graphic Updates"
 msgstr "ग्राफिक अद्यावधिक देखाउनुहोस्"
 
-#: gtk/inspector/visual.ui:440
-#, fuzzy
-msgid "Show Fallback Rendering"
-msgstr "प्रतिमा विषयवस्तु नाम पछाडि हट्यो"
+#: gtk/inspector/visual.ui:450
+msgid "Tints all the places where the current renderer uses Cairo instead of the GPU."
+msgstr ""
+
+#: gtk/inspector/visual.ui:456
+msgid "Show Cairo Rendering"
+msgstr ""
 
-#: gtk/inspector/visual.ui:465
+#: gtk/inspector/visual.ui:481
 msgid "Show Baselines"
 msgstr "आधाररेखा देखाउनुहोस्"
 
-#: gtk/inspector/visual.ui:493
+#: gtk/inspector/visual.ui:509
 msgid "Show Layout Borders"
 msgstr "सजावट किनारा देखाउनुहोस्"
 
-#: gtk/inspector/visual.ui:550
+#: gtk/inspector/visual.ui:566
 msgid "CSS Padding"
 msgstr "सिएसएस गद्दा"
 
-#: gtk/inspector/visual.ui:560
+#: gtk/inspector/visual.ui:576
 msgid "CSS Border"
 msgstr "सिएसएस किनारा"
 
-#: gtk/inspector/visual.ui:570
+#: gtk/inspector/visual.ui:586
 msgid "CSS Margin"
 msgstr "सिएसएस सीमान्त"
 
-#: gtk/inspector/visual.ui:580
+#: gtk/inspector/visual.ui:596
 msgid "Widget Margin"
 msgstr "औजार सीमान्त"
 
-#: gtk/inspector/visual.ui:615
-#, fuzzy
+#: gtk/inspector/visual.ui:631
 msgid "Show Focus"
-msgstr "केन्द्रित छैन"
+msgstr ""
 
-#: gtk/inspector/visual.ui:654
-#, fuzzy
-msgid "Simulate Touchscreen"
-msgstr "एउटा इनग्रार्भिङ अभिलेख नक्कल गर्नुहोस्"
+#: gtk/inspector/visual.ui:656
+#| msgid "Accessibility"
+msgid "Show Accessibility warnings"
+msgstr ""
+
+#: gtk/inspector/visual.ui:681
+#| msgid "Show Graphic Updates"
+msgid "Show Graphics Offload"
+msgstr ""
 
-#: gtk/inspector/visual.ui:678
-msgid "Software GL"
-msgstr "सफ्टवेयर GL"
+#: gtk/inspector/visual.ui:713
+msgid "Inspect Inspector"
+msgstr ""
 
 #: gtk/inspector/window.ui:27
 msgid "Select an Object"
@@ -4251,45 +4404,38 @@ msgid "Objects"
 msgstr "वस्तुहरू"
 
 #: gtk/inspector/window.ui:231
-#, fuzzy
-#| msgctxt "printing option"
-#| msgid "Two Sided"
 msgid "Toggle Sidebar"
-msgstr "छेउपट्टी"
+msgstr "साइडबार टगल गर्नुहोस्"
 
 #: gtk/inspector/window.ui:253
-#, fuzzy
 msgid "Refresh action state"
-msgstr "ताजा पार्नुहोस्"
+msgstr ""
 
 #: gtk/inspector/window.ui:327
-#, fuzzy
 msgid "Previous object"
-msgstr "_अघिल्लो"
+msgstr "अघिल्लो वस्तुमा जानुहोस्"
 
 #: gtk/inspector/window.ui:334
 msgid "Child object"
 msgstr "शाखा वस्तु"
 
 #: gtk/inspector/window.ui:341
-#, fuzzy
 msgid "Previous sibling"
-msgstr "_अघिल्लो"
+msgstr "अघिल्लो भाइबहिनी"
 
 #: gtk/inspector/window.ui:347
 msgid "List Position"
 msgstr "स्थिति सूची"
 
 #: gtk/inspector/window.ui:356
-#, fuzzy
 msgid "Next sibling"
-msgstr "पछिल्लो"
+msgstr "अर्को भाइबहिनी"
 
 #: gtk/inspector/window.ui:386
 msgid "Miscellaneous"
 msgstr "विविध"
 
-#: gtk/inspector/window.ui:407
+#: gtk/inspector/window.ui:407 gtk/print/ui/gtkprintunixdialog.ui:451
 msgid "Layout"
 msgstr "ढाँचा"
 
@@ -4346,9 +4492,8 @@ msgid "Statistics"
 msgstr "तथ्याङ्क"
 
 #: gtk/inspector/window.ui:595
-#, fuzzy
 msgid "Logging"
-msgstr "लगइन समय सकियो"
+msgstr "लगइन गर्दै"
 
 #: gtk/inspector/window.ui:610
 msgid "CSS"
@@ -4358,1708 +4503,1545 @@ msgstr "CSS"
 msgid "Recorder"
 msgstr "रेकर्डर"
 
-#: gtk/open-type-layout.h:13
-#, fuzzy
+#: gtk/open-type-layout.h:14
 msgctxt "OpenType layout"
 msgid "Access All Alternates"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "सबै वैकल्पिक पहुँच गर्नुहोस्"
 
-#: gtk/open-type-layout.h:14
-#, fuzzy
+#: gtk/open-type-layout.h:15
 msgctxt "OpenType layout"
 msgid "Above-base Forms"
-msgstr "माथि- आधार चिन्ह स्थिति"
+msgstr "माथि- आधार आकार"
 
-#: gtk/open-type-layout.h:15
+#: gtk/open-type-layout.h:16
 msgctxt "OpenType layout"
 msgid "Above-base Mark Positioning"
 msgstr "माथि- आधार चिन्ह स्थिति"
 
-#: gtk/open-type-layout.h:16
-#, fuzzy
+#: gtk/open-type-layout.h:17
 msgctxt "OpenType layout"
 msgid "Above-base Substitutions"
-msgstr "माथि- आधार चिन्ह स्थिति"
+msgstr "माथि-आधार प्रतिस्थापनहरू"
 
-#: gtk/open-type-layout.h:17
-#, fuzzy
-#| msgid "Authentication"
+#: gtk/open-type-layout.h:18
 msgctxt "OpenType layout"
 msgid "Alternative Fractions"
-msgstr "बैकल्पिक बटन क्रम"
+msgstr "वैकल्पिक भिन्नहरू"
 
-#: gtk/open-type-layout.h:18
+#: gtk/open-type-layout.h:19
 msgctxt "OpenType layout"
 msgid "Akhands"
 msgstr "अखण्ड"
 
-#: gtk/open-type-layout.h:19
-#, fuzzy
+#: gtk/open-type-layout.h:20
 msgctxt "OpenType layout"
 msgid "Below-base Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "तल-आधार आकार"
 
-#: gtk/open-type-layout.h:20
-#, fuzzy
+#: gtk/open-type-layout.h:21
 msgctxt "OpenType layout"
 msgid "Below-base Mark Positioning"
-msgstr "माथि- आधार चिन्ह स्थिति"
+msgstr "तल-आधार पोजिशनिंग चिनो"
 
-#: gtk/open-type-layout.h:21
-#, fuzzy
+#: gtk/open-type-layout.h:22
 msgctxt "OpenType layout"
 msgid "Below-base Substitutions"
-msgstr "पङ्ति तल:"
+msgstr "तल-आधार प्रतिस्थापनहरू"
 
-#: gtk/open-type-layout.h:22
+#: gtk/open-type-layout.h:23
 msgctxt "OpenType layout"
 msgid "Contextual Alternates"
 msgstr "प्रासंगिक वैकल्पिक"
 
-#: gtk/open-type-layout.h:23
-#, fuzzy
+#: gtk/open-type-layout.h:24
 msgctxt "OpenType layout"
 msgid "Case-Sensitive Forms"
-msgstr "संवेदनशिल केस:"
+msgstr "संवेदनशिल केस आकार"
 
-#: gtk/open-type-layout.h:24
-#, fuzzy
+#: gtk/open-type-layout.h:25
 msgctxt "OpenType layout"
 msgid "Glyph Composition / Decomposition"
-msgstr "विच्छेदन"
+msgstr "ग्लिफ रचना / विच्छेदन"
 
-#: gtk/open-type-layout.h:25
+#: gtk/open-type-layout.h:26
 msgctxt "OpenType layout"
 msgid "Conjunct Form After Ro"
-msgstr ""
+msgstr "आरओ पछि संयोजन आकार"
 
-#: gtk/open-type-layout.h:26
-#, fuzzy
+#: gtk/open-type-layout.h:27
 msgctxt "OpenType layout"
 msgid "Conjunct Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "संयोजन आकार"
 
-#: gtk/open-type-layout.h:27
+#: gtk/open-type-layout.h:28
 msgctxt "OpenType layout"
 msgid "Contextual Ligatures"
 msgstr "प्रासंगिक लिगाचरस्"
 
-#: gtk/open-type-layout.h:28
-#, fuzzy
+#: gtk/open-type-layout.h:29
 msgctxt "OpenType layout"
 msgid "Centered CJK Punctuation"
-msgstr "विराम चिन्ह"
+msgstr "केन्द्रित सीजेके विराम चिन्ह"
 
-#: gtk/open-type-layout.h:29
-#, fuzzy
+#: gtk/open-type-layout.h:30
 msgctxt "OpenType layout"
 msgid "Capital Spacing"
-msgstr "अस्ट्रेलियन क्यापिटल टेर्रिटोरी"
+msgstr "ठुलो-वर्ण खाली स्थान"
 
-#: gtk/open-type-layout.h:30
-#, fuzzy
+#: gtk/open-type-layout.h:31
 msgctxt "OpenType layout"
 msgid "Contextual Swash"
-msgstr "प्रासंगिक मेनु"
+msgstr "सान्दर्भिक स्वाश"
 
-#: gtk/open-type-layout.h:31
-#, fuzzy
+#: gtk/open-type-layout.h:32
 msgctxt "OpenType layout"
 msgid "Cursive Positioning"
-msgstr "चिन्ह स्थिति"
+msgstr "कर्सिभ पोजिसनिङ"
 
-#: gtk/open-type-layout.h:32
+#: gtk/open-type-layout.h:33
 msgctxt "OpenType layout"
 msgid "Petite Capitals From Capitals"
 msgstr "मसिना ठुला वर्णहरू बाट ठुला वर्णहरू"
 
-#: gtk/open-type-layout.h:33
-#, fuzzy
+#: gtk/open-type-layout.h:34
 msgctxt "OpenType layout"
 msgid "Small Capitals From Capitals"
 msgstr "मसिना ठुला वर्णहरू बाट ठुला वर्णहरू"
 
-#: gtk/open-type-layout.h:34
+#: gtk/open-type-layout.h:35
 msgctxt "OpenType layout"
 msgid "Distances"
-msgstr ""
+msgstr "दुरी"
 
-#: gtk/open-type-layout.h:35
-#, fuzzy
+#: gtk/open-type-layout.h:36
 msgctxt "OpenType layout"
 msgid "Discretionary Ligatures"
-msgstr "लिगाचरस्"
+msgstr "विवेकाधीन लिगाचर"
 
-#: gtk/open-type-layout.h:36
+#: gtk/open-type-layout.h:37
 msgctxt "OpenType layout"
 msgid "Denominators"
-msgstr ""
+msgstr "भाजक"
 
-#: gtk/open-type-layout.h:37
-#, fuzzy
+#: gtk/open-type-layout.h:38
 msgctxt "OpenType layout"
 msgid "Dotless Forms"
-msgstr "थोप्लोरहित %s"
+msgstr "थोप्लोरहित आकार"
 
-#: gtk/open-type-layout.h:38
-#, fuzzy
+#: gtk/open-type-layout.h:39
 msgctxt "OpenType layout"
 msgid "Expert Forms"
-msgstr "JIS2004 Forms"
+msgstr "निपूर्ण आकार"
 
-#: gtk/open-type-layout.h:39
+#: gtk/open-type-layout.h:40
 msgctxt "OpenType layout"
 msgid "Final Glyph on Line Alternates"
-msgstr ""
+msgstr "लाइन अल्टरनेटमा अन्तिम ग्लिफ"
 
-#: gtk/open-type-layout.h:40
-#, fuzzy
+#: gtk/open-type-layout.h:41
 msgctxt "OpenType layout"
 msgid "Terminal Forms #2"
-msgstr "टर्मिनल"
+msgstr "टर्मिनल आकार #२"
 
-#: gtk/open-type-layout.h:41
-#, fuzzy
+#: gtk/open-type-layout.h:42
 msgctxt "OpenType layout"
 msgid "Terminal Forms #3"
-msgstr "टर्मिनल"
+msgstr "टर्मिनल आकार #३"
 
-#: gtk/open-type-layout.h:42
-#, fuzzy
+#: gtk/open-type-layout.h:43
 msgctxt "OpenType layout"
 msgid "Terminal Forms"
-msgstr "टर्मिनल"
+msgstr "टर्मिनल आकार"
 
-#: gtk/open-type-layout.h:43
-#, fuzzy
+#: gtk/open-type-layout.h:44
 msgctxt "OpenType layout"
 msgid "Flattened accent forms"
-msgstr "स्थानियकरण फारम"
+msgstr "चपटा उच्चारण फारमहरू"
 
-#: gtk/open-type-layout.h:44
-#, fuzzy
-#| msgid "Actions"
+#: gtk/open-type-layout.h:45
 msgctxt "OpenType layout"
 msgid "Fractions"
-msgstr "मिश्रित भिन्नहरू प्रयोग गर्नुहोस्"
+msgstr "भिन्नहरू"
 
-#: gtk/open-type-layout.h:45
-#, fuzzy
+#: gtk/open-type-layout.h:46
 msgctxt "OpenType layout"
 msgid "Full Widths"
-msgstr "पूरा"
+msgstr "पुर्ण चौडाई"
 
-#: gtk/open-type-layout.h:46
-#, fuzzy
+#: gtk/open-type-layout.h:47
 msgctxt "OpenType layout"
 msgid "Half Forms"
-msgstr "आधा"
+msgstr "आधा आकार"
 
-#: gtk/open-type-layout.h:47
+#: gtk/open-type-layout.h:48
 msgctxt "OpenType layout"
 msgid "Halant Forms"
 msgstr "हलन्ट ढाचाँ"
 
-#: gtk/open-type-layout.h:48
-#, fuzzy
+#: gtk/open-type-layout.h:49
 msgctxt "OpenType layout"
 msgid "Alternate Half Widths"
-msgstr "वैकल्पिक ठाडो आधा म्याट्रिक्स"
+msgstr "वैकल्पिक आधा चौडाइ"
 
-#: gtk/open-type-layout.h:49
-#, fuzzy
+#: gtk/open-type-layout.h:50
 msgctxt "OpenType layout"
 msgid "Historical Forms"
-msgstr "ऐतिहासिक"
+msgstr "ऐतिहासिक आकार"
 
-#: gtk/open-type-layout.h:50
-#, fuzzy
+#: gtk/open-type-layout.h:51
 msgctxt "OpenType layout"
 msgid "Horizontal Kana Alternates"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "तेर्सो काना वैकल्पिक"
 
-#: gtk/open-type-layout.h:51
-#, fuzzy
+#: gtk/open-type-layout.h:52
 msgctxt "OpenType layout"
 msgid "Historical Ligatures"
-msgstr "लिगाचरस्"
+msgstr "ऐतिहासिक लिगेचरहरू"
 
-#: gtk/open-type-layout.h:52
+#: gtk/open-type-layout.h:53
 msgctxt "OpenType layout"
 msgid "Hangul"
 msgstr "हनगुल"
 
-#: gtk/open-type-layout.h:53
-#, fuzzy
+#: gtk/open-type-layout.h:54
 msgctxt "OpenType layout"
 msgid "Hojo Kanji Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "होजो खांजी फारमहरू"
 
-#: gtk/open-type-layout.h:54
-#, fuzzy
+#: gtk/open-type-layout.h:55
 msgctxt "OpenType layout"
 msgid "Half Widths"
-msgstr "आधा"
+msgstr "आधा चौडाई"
 
-#: gtk/open-type-layout.h:55
+#: gtk/open-type-layout.h:56
 msgctxt "OpenType layout"
 msgid "Initial Forms"
 msgstr "सुरुको ढाचाँ"
 
-#: gtk/open-type-layout.h:56
-#, fuzzy
+#: gtk/open-type-layout.h:57
 msgctxt "OpenType layout"
 msgid "Isolated Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "पृथक आकार"
 
-#: gtk/open-type-layout.h:57
+#: gtk/open-type-layout.h:58
 msgctxt "OpenType layout"
 msgid "Italics"
 msgstr "छड्के"
 
-#: gtk/open-type-layout.h:58
-#, fuzzy
+#: gtk/open-type-layout.h:59
 msgctxt "OpenType layout"
 msgid "Justification Alternates"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "औचित्य वैकल्पिक"
 
-#: gtk/open-type-layout.h:59
+#: gtk/open-type-layout.h:60
 msgctxt "OpenType layout"
 msgid "JIS78 Forms"
 msgstr "JIS78 Forms"
 
-#: gtk/open-type-layout.h:60
+#: gtk/open-type-layout.h:61
 msgctxt "OpenType layout"
 msgid "JIS83 Forms"
 msgstr "JIS83 Forms"
 
-#: gtk/open-type-layout.h:61
+#: gtk/open-type-layout.h:62
 msgctxt "OpenType layout"
 msgid "JIS90 Forms"
 msgstr "JIS90 Forms"
 
-#: gtk/open-type-layout.h:62
+#: gtk/open-type-layout.h:63
 msgctxt "OpenType layout"
 msgid "JIS2004 Forms"
 msgstr "JIS2004 Forms"
 
-#: gtk/open-type-layout.h:63
-#, fuzzy
-#| msgid "Warning"
+#: gtk/open-type-layout.h:64
 msgctxt "OpenType layout"
 msgid "Kerning"
-msgstr "चेतावनी"
+msgstr "कर्निङ"
 
-#: gtk/open-type-layout.h:64
-#, fuzzy
+#: gtk/open-type-layout.h:65
 msgctxt "OpenType layout"
 msgid "Left Bounds"
-msgstr "दायाँ सीमा"
+msgstr "बायाँ सीमा"
 
-#: gtk/open-type-layout.h:65
-#, fuzzy
-#| msgctxt "cover page"
-#| msgid "Standard"
+#: gtk/open-type-layout.h:66
 msgctxt "OpenType layout"
 msgid "Standard Ligatures"
-msgstr "लिगाचरस्"
+msgstr "मानक लिगेचर"
 
-#: gtk/open-type-layout.h:66
-#, fuzzy
+#: gtk/open-type-layout.h:67
 msgctxt "OpenType layout"
 msgid "Leading Jamo Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "जामो आकार"
 
-#: gtk/open-type-layout.h:67
+#: gtk/open-type-layout.h:68
 msgctxt "OpenType layout"
 msgid "Lining Figures"
-msgstr ""
+msgstr "अस्तर आकृतिहरू"
 
-#: gtk/open-type-layout.h:68
+#: gtk/open-type-layout.h:69
 msgctxt "OpenType layout"
 msgid "Localized Forms"
 msgstr "स्थानियकरण फारम"
 
-#: gtk/open-type-layout.h:69
-#, fuzzy
-#| msgid "LRM _Left-to-right mark"
+#: gtk/open-type-layout.h:70
 msgctxt "OpenType layout"
 msgid "Left-to-right alternates"
-msgstr "LRM _बायाँ-बाट-दायाँ चिनो"
+msgstr "बायाँ-देखि-दायाँ वैकल्पिक"
 
-#: gtk/open-type-layout.h:70
-#, fuzzy
-#| msgid "LRM _Left-to-right mark"
+#: gtk/open-type-layout.h:71
 msgctxt "OpenType layout"
 msgid "Left-to-right mirrored forms"
-msgstr "LRM _बायाँ-बाट-दायाँ चिनो"
+msgstr "बायाँ-देखि-दायाँ प्रतिबिम्बित आकार"
 
-#: gtk/open-type-layout.h:71
+#: gtk/open-type-layout.h:72
 msgctxt "OpenType layout"
 msgid "Mark Positioning"
 msgstr "चिन्ह स्थिति"
 
-#: gtk/open-type-layout.h:72
-#, fuzzy
+#: gtk/open-type-layout.h:73
 msgctxt "OpenType layout"
 msgid "Medial Forms #2"
-msgstr "स्थानियकरण फारम"
+msgstr "मेडियल आकार #२"
 
-#: gtk/open-type-layout.h:73
+#: gtk/open-type-layout.h:74
 msgctxt "OpenType layout"
 msgid "Medial Forms"
 msgstr "बिचको ढाचाँ"
 
-#: gtk/open-type-layout.h:74
-#, fuzzy
+#: gtk/open-type-layout.h:75
 msgctxt "OpenType layout"
 msgid "Mathematical Greek"
-msgstr "ग्रीक"
+msgstr "गणितीय ग्रीक"
 
-#: gtk/open-type-layout.h:75
-#, fuzzy
+#: gtk/open-type-layout.h:76
 msgctxt "OpenType layout"
 msgid "Mark to Mark Positioning"
-msgstr "चिन्ह स्थिति"
+msgstr "मार्क पोजिसनिङमा चिनो लगाउनुहोस्"
 
-#: gtk/open-type-layout.h:76
-#, fuzzy
+#: gtk/open-type-layout.h:77
 msgctxt "OpenType layout"
 msgid "Mark Positioning via Substitution"
-msgstr "माथि- आधार चिन्ह स्थिति"
+msgstr "प्रतिस्थापन मार्फत पोजिशनिङ चिनो"
 
-#: gtk/open-type-layout.h:77
-#, fuzzy
+#: gtk/open-type-layout.h:78
 msgctxt "OpenType layout"
 msgid "Alternate Annotation Forms"
-msgstr "वैकल्पिक"
+msgstr "वैकल्पिक एनोटेसन आकार"
 
-#: gtk/open-type-layout.h:78
-#, fuzzy
+#: gtk/open-type-layout.h:79
 msgctxt "OpenType layout"
 msgid "NLC Kanji Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "एनएलसी खांजी आकार"
 
-#: gtk/open-type-layout.h:79
+#: gtk/open-type-layout.h:80
 msgctxt "OpenType layout"
 msgid "Nukta Forms"
 msgstr "नुक्ता ढाँचा"
 
-#: gtk/open-type-layout.h:80
+#: gtk/open-type-layout.h:81
 msgctxt "OpenType layout"
 msgid "Numerators"
-msgstr ""
+msgstr "गणक"
 
-#: gtk/open-type-layout.h:81
+#: gtk/open-type-layout.h:82
 msgctxt "OpenType layout"
 msgid "Oldstyle Figures"
-msgstr ""
+msgstr "पुरानो शैलीका आकृतिहरू"
 
-#: gtk/open-type-layout.h:82
-#, fuzzy
+#: gtk/open-type-layout.h:83
 msgctxt "OpenType layout"
 msgid "Optical Bounds"
-msgstr "दायाँ सीमा"
+msgstr "अप्टिकल सीमा"
 
-#: gtk/open-type-layout.h:83
+#: gtk/open-type-layout.h:84
 msgctxt "OpenType layout"
 msgid "Ordinals"
 msgstr "अर्डिनलहरू"
 
-#: gtk/open-type-layout.h:84
+#: gtk/open-type-layout.h:85
 msgctxt "OpenType layout"
 msgid "Ornaments"
-msgstr ""
+msgstr "गहना"
 
-#: gtk/open-type-layout.h:85
-#, fuzzy
+#: gtk/open-type-layout.h:86
 msgctxt "OpenType layout"
 msgid "Proportional Alternate Widths"
-msgstr "वैकल्पिक"
+msgstr "आनुपातिक वैकल्पिक चौडाइ"
 
-#: gtk/open-type-layout.h:86
+#: gtk/open-type-layout.h:87
 msgctxt "OpenType layout"
 msgid "Petite Capitals"
 msgstr "मसिना ठुला वर्णहरू"
 
-#: gtk/open-type-layout.h:87
-#, fuzzy
+#: gtk/open-type-layout.h:88
 msgctxt "OpenType layout"
 msgid "Proportional Kana"
-msgstr "काना पूरक"
+msgstr "समानुपातिक काना"
 
-#: gtk/open-type-layout.h:88
-#, fuzzy
-#| msgid "Properties"
+#: gtk/open-type-layout.h:89
 msgctxt "OpenType layout"
 msgid "Proportional Figures"
-msgstr "गुण: "
+msgstr "समानुपातिक आकृतिहरू"
 
-#: gtk/open-type-layout.h:89
-#, fuzzy
+#: gtk/open-type-layout.h:90
 msgctxt "OpenType layout"
 msgid "Pre-Base Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "पूर्व-आधार आकार"
 
-#: gtk/open-type-layout.h:90
-#, fuzzy
+#: gtk/open-type-layout.h:91
 msgctxt "OpenType layout"
 msgid "Pre-base Substitutions"
-msgstr "आधार तास: ~a"
+msgstr "पुर्व तल-आधार प्रतिस्थापनहरू"
 
-#: gtk/open-type-layout.h:91
-#, fuzzy
+#: gtk/open-type-layout.h:92
 msgctxt "OpenType layout"
 msgid "Post-base Forms"
-msgstr "लाई पोस्ट गर्नुहोस्:"
+msgstr "पोस्ट-आधार आकार"
 
-#: gtk/open-type-layout.h:92
-#, fuzzy
+#: gtk/open-type-layout.h:93
 msgctxt "OpenType layout"
 msgid "Post-base Substitutions"
-msgstr "लाई पोस्ट गर्नुहोस्:"
+msgstr "पोस्ट-आधार प्रतिस्थापनहरू"
 
-#: gtk/open-type-layout.h:93
+#: gtk/open-type-layout.h:94
 msgctxt "OpenType layout"
 msgid "Proportional Widths"
-msgstr ""
+msgstr "समानुपातिक चौडाइ"
 
-#: gtk/open-type-layout.h:94
+#: gtk/open-type-layout.h:95
 msgctxt "OpenType layout"
 msgid "Quarter Widths"
 msgstr "चौथाइ चौडाई"
 
-#: gtk/open-type-layout.h:95
+#: gtk/open-type-layout.h:96
 msgctxt "OpenType layout"
 msgid "Randomize"
 msgstr "अनियमित गर्नुहोस्"
 
-#: gtk/open-type-layout.h:96
-#, fuzzy
+#: gtk/open-type-layout.h:97
 msgctxt "OpenType layout"
 msgid "Required Contextual Alternates"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "आवश्यक सान्दर्भिक वैकल्पिक"
 
-#: gtk/open-type-layout.h:97
+#: gtk/open-type-layout.h:98
 msgctxt "OpenType layout"
 msgid "Rakar Forms"
 msgstr "र-कार ढाचाँहरू"
 
-#: gtk/open-type-layout.h:98
-#, fuzzy
+#: gtk/open-type-layout.h:99
 msgctxt "OpenType layout"
 msgid "Required Ligatures"
-msgstr "लिगाचरस्"
+msgstr "आवश्यक लिगाचरहरू"
 
-#: gtk/open-type-layout.h:99
+#: gtk/open-type-layout.h:100
 msgctxt "OpenType layout"
 msgid "Reph Forms"
 msgstr "रेफ ढाँचा"
 
-#: gtk/open-type-layout.h:100
+#: gtk/open-type-layout.h:101
 msgctxt "OpenType layout"
 msgid "Right Bounds"
 msgstr "दायाँ सीमा"
 
-#: gtk/open-type-layout.h:101
-#, fuzzy
-#| msgid "RLM _Right-to-left mark"
+#: gtk/open-type-layout.h:102
 msgctxt "OpenType layout"
 msgid "Right-to-left alternates"
-msgstr "LRM _बायाँ-बाट-दायाँ चिनो"
+msgstr "दायाँ-देखि-बायाँ वैकल्पिक"
 
-#: gtk/open-type-layout.h:102
-#, fuzzy
-#| msgid "RLM _Right-to-left mark"
+#: gtk/open-type-layout.h:103
 msgctxt "OpenType layout"
 msgid "Right-to-left mirrored forms"
-msgstr "LRM _बायाँ-बाट-दायाँ चिनो"
+msgstr "दायाँ-देखि-बायाँ प्रतिबिम्बित आकार"
 
-#: gtk/open-type-layout.h:103
-#, fuzzy
+#: gtk/open-type-layout.h:104
 msgctxt "OpenType layout"
 msgid "Ruby Notation Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "रूबी नोटेसन आकार"
 
-#: gtk/open-type-layout.h:104
-#, fuzzy
+#: gtk/open-type-layout.h:105
 msgctxt "OpenType layout"
 msgid "Required Variation Alternates"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "आवश्यक भिन्नता वैकल्पिक"
 
-#: gtk/open-type-layout.h:105
-#, fuzzy
+#: gtk/open-type-layout.h:106
 msgctxt "OpenType layout"
 msgid "Stylistic Alternates"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "शैलीगत विकल्प"
 
-#: gtk/open-type-layout.h:106
+#: gtk/open-type-layout.h:107
 msgctxt "OpenType layout"
 msgid "Scientific Inferiors"
 msgstr "वैज्ञानिक हीनताबोध"
 
-#: gtk/open-type-layout.h:107
+#: gtk/open-type-layout.h:108
 msgctxt "OpenType layout"
 msgid "Optical size"
 msgstr "अप्टिकल साइज"
 
-#: gtk/open-type-layout.h:108
-#, fuzzy
+#: gtk/open-type-layout.h:109
 msgctxt "OpenType layout"
 msgid "Small Capitals"
 msgstr "मसिना ठुला वर्णहरू"
 
-#: gtk/open-type-layout.h:109
-#, fuzzy
-msgctxt "OpenType layout"
-msgid "Simplified Forms"
-msgstr "सरलीकृत"
-
 #: gtk/open-type-layout.h:110
 msgctxt "OpenType layout"
-msgid "Stylistic Set 1"
-msgstr "शैलीगत सेट "
+msgid "Simplified Forms"
+msgstr "सरलीकृत आकार"
 
 #: gtk/open-type-layout.h:111
 msgctxt "OpenType layout"
-msgid "Stylistic Set 2"
-msgstr "शैलीगत सेट २"
-
-#: gtk/open-type-layout.h:112
-msgctxt "OpenType layout"
-msgid "Stylistic Set 3"
-msgstr "शैलीगत सेट ३"
-
-#: gtk/open-type-layout.h:113
-msgctxt "OpenType layout"
-msgid "Stylistic Set 4"
-msgstr "शैलीगत सेट ४"
-
-#: gtk/open-type-layout.h:114
-msgctxt "OpenType layout"
-msgid "Stylistic Set 5"
-msgstr "शैलीगत सेट ५"
-
-#: gtk/open-type-layout.h:115
-msgctxt "OpenType layout"
-msgid "Stylistic Set 6"
-msgstr "शैलीगत सेट ६"
-
-#: gtk/open-type-layout.h:116
-msgctxt "OpenType layout"
-msgid "Stylistic Set 7"
-msgstr "शैलीगत सेट ७"
-
-#: gtk/open-type-layout.h:117
-msgctxt "OpenType layout"
-msgid "Stylistic Set 8"
-msgstr "शैलीगत सेट ८"
-
-#: gtk/open-type-layout.h:118
-msgctxt "OpenType layout"
-msgid "Stylistic Set 9"
-msgstr "शैलीगत सेट ९"
-
-#: gtk/open-type-layout.h:119
-msgctxt "OpenType layout"
-msgid "Stylistic Set 10"
-msgstr "शैलीगत सेट १०"
-
-#: gtk/open-type-layout.h:120
-msgctxt "OpenType layout"
-msgid "Stylistic Set 11"
-msgstr "शैलीगत सेट ११"
-
-#: gtk/open-type-layout.h:121
-msgctxt "OpenType layout"
-msgid "Stylistic Set 12"
-msgstr "शैलीगत सेट १२"
-
-#: gtk/open-type-layout.h:122
-msgctxt "OpenType layout"
-msgid "Stylistic Set 13"
-msgstr "शैलीगत सेट १३"
-
-#: gtk/open-type-layout.h:123
-msgctxt "OpenType layout"
-msgid "Stylistic Set 14"
-msgstr "शैलीगत सेट १४"
-
-#: gtk/open-type-layout.h:124
-msgctxt "OpenType layout"
-msgid "Stylistic Set 15"
-msgstr "शैलीगत सेट १५"
-
-#: gtk/open-type-layout.h:125
-msgctxt "OpenType layout"
-msgid "Stylistic Set 16"
-msgstr "शैलीगत सेट १६"
-
-#: gtk/open-type-layout.h:126
-msgctxt "OpenType layout"
-msgid "Stylistic Set 17"
-msgstr "शैलीगत सेट १७"
-
-#: gtk/open-type-layout.h:127
-msgctxt "OpenType layout"
-msgid "Stylistic Set 18"
-msgstr "शैलीगत सेट १८"
-
-#: gtk/open-type-layout.h:128
-msgctxt "OpenType layout"
-msgid "Stylistic Set 19"
-msgstr "शैलीगत सेट १९"
-
-#: gtk/open-type-layout.h:129
-msgctxt "OpenType layout"
-msgid "Stylistic Set 20"
-msgstr "शैलीगत सेट २०"
-
-#: gtk/open-type-layout.h:130
-msgctxt "OpenType layout"
 msgid "Math script style alternates"
-msgstr ""
+msgstr "गणित स्क्रिप्ट शैली वैकल्पिक"
 
-#: gtk/open-type-layout.h:131
-#, fuzzy
+#: gtk/open-type-layout.h:112
 msgctxt "OpenType layout"
 msgid "Stretching Glyph Decomposition"
-msgstr "विच्छेदन"
+msgstr "स्ट्रेचिंग ग्लिफ विच्छेदन"
 
-#: gtk/open-type-layout.h:132
+#: gtk/open-type-layout.h:113
 msgctxt "OpenType layout"
 msgid "Subscript"
 msgstr "सबस्क्रिप्ट"
 
-#: gtk/open-type-layout.h:133
+#: gtk/open-type-layout.h:114
 msgctxt "OpenType layout"
 msgid "Superscript"
 msgstr "सुपरस्क्रिप्ट"
 
-#: gtk/open-type-layout.h:134
+#: gtk/open-type-layout.h:115
 msgctxt "OpenType layout"
 msgid "Swash"
-msgstr ""
+msgstr "स्वाश"
 
-#: gtk/open-type-layout.h:135
+#: gtk/open-type-layout.h:116
 msgctxt "OpenType layout"
 msgid "Titling"
-msgstr ""
+msgstr "टिलटिङ्ग"
 
-#: gtk/open-type-layout.h:136
-#, fuzzy
+#: gtk/open-type-layout.h:117
 msgctxt "OpenType layout"
 msgid "Trailing Jamo Forms"
-msgstr "ट्रेलिङ खालीस्थान हटाउनुहोस्"
+msgstr "जामो आकार"
 
-#: gtk/open-type-layout.h:137
-#, fuzzy
+#: gtk/open-type-layout.h:118
 msgctxt "OpenType layout"
 msgid "Traditional Name Forms"
-msgstr "परम्परागत"
+msgstr "परम्परागत नाम आकार"
 
-#: gtk/open-type-layout.h:138
+#: gtk/open-type-layout.h:119
 msgctxt "OpenType layout"
 msgid "Tabular Figures"
-msgstr ""
+msgstr "टेबुलर आकृतिहरू"
 
-#: gtk/open-type-layout.h:139
-#, fuzzy
+#: gtk/open-type-layout.h:120
 msgctxt "OpenType layout"
 msgid "Traditional Forms"
-msgstr "परम्परागत"
+msgstr "परम्परागत आकार"
 
-#: gtk/open-type-layout.h:140
-#, fuzzy
+#: gtk/open-type-layout.h:121
 msgctxt "OpenType layout"
 msgid "Third Widths"
-msgstr "तेस्रो"
+msgstr "तेस्रो चौडाई"
 
-#: gtk/open-type-layout.h:141
+#: gtk/open-type-layout.h:122
 msgctxt "OpenType layout"
 msgid "Unicase"
 msgstr "युनिकेस"
 
-#: gtk/open-type-layout.h:142
-#, fuzzy
+#: gtk/open-type-layout.h:123
 msgctxt "OpenType layout"
 msgid "Alternate Vertical Metrics"
-msgstr "वैकल्पिक ठाडो आधा म्याट्रिक्स"
+msgstr "वैकल्पिक ठाडो मेट्रिक्स"
 
-#: gtk/open-type-layout.h:143
-#, fuzzy
+#: gtk/open-type-layout.h:124
 msgctxt "OpenType layout"
 msgid "Vattu Variants"
-msgstr "वर्ण फरकप्रकार"
+msgstr "वाट्टु फरकप्रकार"
 
-#: gtk/open-type-layout.h:144
-#, fuzzy
-#| msgctxt "sizegroup mode"
-#| msgid "Vertical"
+#: gtk/open-type-layout.h:125
 msgctxt "OpenType layout"
 msgid "Vertical Writing"
-msgstr "लेखिदै"
+msgstr "ठाडो लेखन"
 
-#: gtk/open-type-layout.h:145
+#: gtk/open-type-layout.h:126
 msgctxt "OpenType layout"
 msgid "Alternate Vertical Half Metrics"
 msgstr "वैकल्पिक ठाडो आधा म्याट्रिक्स"
 
-#: gtk/open-type-layout.h:146
-#, fuzzy
+#: gtk/open-type-layout.h:127
 msgctxt "OpenType layout"
 msgid "Vowel Jamo Forms"
-msgstr "स्थानियकरण फारम"
+msgstr "जामो आकार"
 
-#: gtk/open-type-layout.h:147
-#, fuzzy
+#: gtk/open-type-layout.h:128
 msgctxt "OpenType layout"
 msgid "Vertical Kana Alternates"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "ठाडो काना वैकल्पिक"
 
-#: gtk/open-type-layout.h:148
-#, fuzzy
-#| msgctxt "sizegroup mode"
-#| msgid "Vertical"
+#: gtk/open-type-layout.h:129
 msgctxt "OpenType layout"
 msgid "Vertical Kerning"
-msgstr "ठाडो:"
+msgstr "ठाडो कर्निङ"
 
-#: gtk/open-type-layout.h:149
-#, fuzzy
+#: gtk/open-type-layout.h:130
 msgctxt "OpenType layout"
 msgid "Proportional Alternate Vertical Metrics"
-msgstr "वैकल्पिक ठाडो आधा म्याट्रिक्स"
+msgstr "समानुपातिक वैकल्पिक ठाडो मेट्रिक्स"
 
-#: gtk/open-type-layout.h:150
-#, fuzzy
+#: gtk/open-type-layout.h:131
 msgctxt "OpenType layout"
 msgid "Vertical Alternates and Rotation"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "ठाडो वैकल्पिक र परिक्रमण"
 
-#: gtk/open-type-layout.h:151
-#, fuzzy
+#: gtk/open-type-layout.h:132
 msgctxt "OpenType layout"
 msgid "Vertical Alternates for Rotation"
-msgstr "प्रासंगिक वैकल्पिक"
+msgstr "परिक्रमणका लागि ठाडो वैकल्पिक"
 
-#: gtk/open-type-layout.h:152
-#, fuzzy
+#: gtk/open-type-layout.h:133
 msgctxt "OpenType layout"
 msgid "Slashed Zero"
-msgstr "ZWS शून्य चौडाइ खाली स्थान"
+msgstr "शून्यमा काटियो"
 
-#: gtk/paper_names_offsets.c:4
+#: gtk/print/paper_names_offsets.c:4
 msgctxt "paper size"
 msgid "asme_f"
 msgstr "asme_f"
 
-#: gtk/paper_names_offsets.c:5
+#: gtk/print/paper_names_offsets.c:5
 msgctxt "paper size"
 msgid "A0×2"
 msgstr "A0×2"
 
-#: gtk/paper_names_offsets.c:6
+#: gtk/print/paper_names_offsets.c:6
 msgctxt "paper size"
 msgid "A0"
 msgstr "A0"
 
-#: gtk/paper_names_offsets.c:7
+#: gtk/print/paper_names_offsets.c:7
 msgctxt "paper size"
 msgid "A0×3"
 msgstr "A0×3"
 
-#: gtk/paper_names_offsets.c:8
+#: gtk/print/paper_names_offsets.c:8
 msgctxt "paper size"
 msgid "A1"
 msgstr "A1"
 
-#: gtk/paper_names_offsets.c:9
+#: gtk/print/paper_names_offsets.c:9
 msgctxt "paper size"
 msgid "A10"
 msgstr "A10"
 
-#: gtk/paper_names_offsets.c:10
+#: gtk/print/paper_names_offsets.c:10
 msgctxt "paper size"
 msgid "A1×3"
 msgstr "A1×3"
 
-#: gtk/paper_names_offsets.c:11
+#: gtk/print/paper_names_offsets.c:11
 msgctxt "paper size"
 msgid "A1×4"
 msgstr "A1×4"
 
-#: gtk/paper_names_offsets.c:12
+#: gtk/print/paper_names_offsets.c:12
 msgctxt "paper size"
 msgid "A2"
 msgstr "A2"
 
-#: gtk/paper_names_offsets.c:13
+#: gtk/print/paper_names_offsets.c:13
 msgctxt "paper size"
 msgid "A2×3"
 msgstr "A2×3"
 
-#: gtk/paper_names_offsets.c:14
+#: gtk/print/paper_names_offsets.c:14
 msgctxt "paper size"
 msgid "A2×4"
 msgstr "A2×4"
 
-#: gtk/paper_names_offsets.c:15
+#: gtk/print/paper_names_offsets.c:15
 msgctxt "paper size"
 msgid "A2×5"
 msgstr "A2×5"
 
-#: gtk/paper_names_offsets.c:16
+#: gtk/print/paper_names_offsets.c:16
 msgctxt "paper size"
 msgid "A3"
 msgstr "A3"
 
-#: gtk/paper_names_offsets.c:17
+#: gtk/print/paper_names_offsets.c:17
 msgctxt "paper size"
 msgid "A3 Extra"
 msgstr "A3 Extra"
 
-#: gtk/paper_names_offsets.c:18
+#: gtk/print/paper_names_offsets.c:18
 msgctxt "paper size"
 msgid "A3×3"
 msgstr "A3×3"
 
-#: gtk/paper_names_offsets.c:19
+#: gtk/print/paper_names_offsets.c:19
 msgctxt "paper size"
 msgid "A3×4"
 msgstr "A3×4"
 
-#: gtk/paper_names_offsets.c:20
+#: gtk/print/paper_names_offsets.c:20
 msgctxt "paper size"
 msgid "A3×5"
 msgstr "A3×5"
 
-#: gtk/paper_names_offsets.c:21
+#: gtk/print/paper_names_offsets.c:21
 msgctxt "paper size"
 msgid "A3×6"
 msgstr "A3×6"
 
-#: gtk/paper_names_offsets.c:22
+#: gtk/print/paper_names_offsets.c:22
 msgctxt "paper size"
 msgid "A3×7"
 msgstr "A3×7"
 
-#: gtk/paper_names_offsets.c:23
+#: gtk/print/paper_names_offsets.c:23
 msgctxt "paper size"
 msgid "A4"
 msgstr "A4"
 
-#: gtk/paper_names_offsets.c:24
+#: gtk/print/paper_names_offsets.c:24
 msgctxt "paper size"
 msgid "A4 Extra"
 msgstr "A4 Extra"
 
-#: gtk/paper_names_offsets.c:25
+#: gtk/print/paper_names_offsets.c:25
 msgctxt "paper size"
 msgid "A4 Tab"
 msgstr "A4 Tab"
 
-#: gtk/paper_names_offsets.c:26
+#: gtk/print/paper_names_offsets.c:26
 msgctxt "paper size"
 msgid "A4×3"
 msgstr "A4×3"
 
-#: gtk/paper_names_offsets.c:27
+#: gtk/print/paper_names_offsets.c:27
 msgctxt "paper size"
 msgid "A4×4"
 msgstr "A4×4"
 
-#: gtk/paper_names_offsets.c:28
+#: gtk/print/paper_names_offsets.c:28
 msgctxt "paper size"
 msgid "A4×5"
 msgstr "A4×5"
 
-#: gtk/paper_names_offsets.c:29
+#: gtk/print/paper_names_offsets.c:29
 msgctxt "paper size"
 msgid "A4×6"
 msgstr "A4×6"
 
-#: gtk/paper_names_offsets.c:30
+#: gtk/print/paper_names_offsets.c:30
 msgctxt "paper size"
 msgid "A4×7"
 msgstr "A4×7"
 
-#: gtk/paper_names_offsets.c:31
+#: gtk/print/paper_names_offsets.c:31
 msgctxt "paper size"
 msgid "A4×8"
 msgstr "A4×8"
 
-#: gtk/paper_names_offsets.c:32
+#: gtk/print/paper_names_offsets.c:32
 msgctxt "paper size"
 msgid "A4×9"
 msgstr "A4×9"
 
-#: gtk/paper_names_offsets.c:33
+#: gtk/print/paper_names_offsets.c:33
 msgctxt "paper size"
 msgid "A5"
 msgstr "A5"
 
-#: gtk/paper_names_offsets.c:34
+#: gtk/print/paper_names_offsets.c:34
 msgctxt "paper size"
 msgid "A5 Extra"
 msgstr "A5 Extra"
 
-#: gtk/paper_names_offsets.c:35
+#: gtk/print/paper_names_offsets.c:35
 msgctxt "paper size"
 msgid "A6"
 msgstr "A6"
 
-#: gtk/paper_names_offsets.c:36
+#: gtk/print/paper_names_offsets.c:36
 msgctxt "paper size"
 msgid "A7"
 msgstr "A7"
 
-#: gtk/paper_names_offsets.c:37
+#: gtk/print/paper_names_offsets.c:37
 msgctxt "paper size"
 msgid "A8"
 msgstr "A8"
 
-#: gtk/paper_names_offsets.c:38
+#: gtk/print/paper_names_offsets.c:38
 msgctxt "paper size"
 msgid "A9"
 msgstr "A9"
 
-#: gtk/paper_names_offsets.c:39
+#: gtk/print/paper_names_offsets.c:39
 msgctxt "paper size"
 msgid "B0"
 msgstr "B0"
 
-#: gtk/paper_names_offsets.c:40
+#: gtk/print/paper_names_offsets.c:40
 msgctxt "paper size"
 msgid "B1"
 msgstr "B1"
 
-#: gtk/paper_names_offsets.c:41
+#: gtk/print/paper_names_offsets.c:41
 msgctxt "paper size"
 msgid "B10"
 msgstr "B10"
 
-#: gtk/paper_names_offsets.c:42
+#: gtk/print/paper_names_offsets.c:42
 msgctxt "paper size"
 msgid "B2"
 msgstr "B2"
 
-#: gtk/paper_names_offsets.c:43
+#: gtk/print/paper_names_offsets.c:43
 msgctxt "paper size"
 msgid "B3"
 msgstr "B3"
 
-#: gtk/paper_names_offsets.c:44
+#: gtk/print/paper_names_offsets.c:44
 msgctxt "paper size"
 msgid "B4"
 msgstr "B4"
 
-#: gtk/paper_names_offsets.c:45
+#: gtk/print/paper_names_offsets.c:45
 msgctxt "paper size"
 msgid "B5"
 msgstr "B5"
 
-#: gtk/paper_names_offsets.c:46
+#: gtk/print/paper_names_offsets.c:46
 msgctxt "paper size"
 msgid "B5 Extra"
 msgstr "B5 Extra"
 
-#: gtk/paper_names_offsets.c:47
+#: gtk/print/paper_names_offsets.c:47
 msgctxt "paper size"
 msgid "B6"
 msgstr "B6"
 
-#: gtk/paper_names_offsets.c:48
+#: gtk/print/paper_names_offsets.c:48
 msgctxt "paper size"
 msgid "B6/C4"
 msgstr "B6/C4"
 
-#: gtk/paper_names_offsets.c:49
+#: gtk/print/paper_names_offsets.c:49
 msgctxt "paper size"
 msgid "B7"
 msgstr "B7"
 
-#: gtk/paper_names_offsets.c:50
+#: gtk/print/paper_names_offsets.c:50
 msgctxt "paper size"
 msgid "B8"
 msgstr "B8"
 
-#: gtk/paper_names_offsets.c:51
+#: gtk/print/paper_names_offsets.c:51
 msgctxt "paper size"
 msgid "B9"
 msgstr "B9"
 
-#: gtk/paper_names_offsets.c:52
+#: gtk/print/paper_names_offsets.c:52
 msgctxt "paper size"
 msgid "C0"
 msgstr "C0"
 
-#: gtk/paper_names_offsets.c:53
+#: gtk/print/paper_names_offsets.c:53
 msgctxt "paper size"
 msgid "C1"
 msgstr "C1"
 
-#: gtk/paper_names_offsets.c:54
+#: gtk/print/paper_names_offsets.c:54
 msgctxt "paper size"
 msgid "C10"
 msgstr "C10"
 
-#: gtk/paper_names_offsets.c:55
+#: gtk/print/paper_names_offsets.c:55
 msgctxt "paper size"
 msgid "C2"
 msgstr "C2"
 
-#: gtk/paper_names_offsets.c:56
+#: gtk/print/paper_names_offsets.c:56
 msgctxt "paper size"
 msgid "C3"
 msgstr "C3"
 
-#: gtk/paper_names_offsets.c:57
+#: gtk/print/paper_names_offsets.c:57
 msgctxt "paper size"
 msgid "C4"
 msgstr "C4"
 
-#: gtk/paper_names_offsets.c:58
+#: gtk/print/paper_names_offsets.c:58
 msgctxt "paper size"
 msgid "C5"
 msgstr "C5"
 
-#: gtk/paper_names_offsets.c:59
+#: gtk/print/paper_names_offsets.c:59
 msgctxt "paper size"
 msgid "C6"
 msgstr "C6"
 
-#: gtk/paper_names_offsets.c:60
+#: gtk/print/paper_names_offsets.c:60
 msgctxt "paper size"
 msgid "C6/C5"
 msgstr "C6/C5"
 
-#: gtk/paper_names_offsets.c:61
+#: gtk/print/paper_names_offsets.c:61
 msgctxt "paper size"
 msgid "C7"
 msgstr "C7"
 
-#: gtk/paper_names_offsets.c:62
+#: gtk/print/paper_names_offsets.c:62
 msgctxt "paper size"
 msgid "C7/C6"
 msgstr "C7/C6"
 
-#: gtk/paper_names_offsets.c:63
+#: gtk/print/paper_names_offsets.c:63
 msgctxt "paper size"
 msgid "C8"
 msgstr "C8"
 
-#: gtk/paper_names_offsets.c:64
+#: gtk/print/paper_names_offsets.c:64
 msgctxt "paper size"
 msgid "C9"
 msgstr "C9"
 
-#: gtk/paper_names_offsets.c:65
+#: gtk/print/paper_names_offsets.c:65
 msgctxt "paper size"
 msgid "DL Envelope"
 msgstr "DL खाम"
 
-#: gtk/paper_names_offsets.c:66
+#: gtk/print/paper_names_offsets.c:66
 msgctxt "paper size"
 msgid "RA0"
 msgstr "RA0"
 
-#: gtk/paper_names_offsets.c:67
+#: gtk/print/paper_names_offsets.c:67
 msgctxt "paper size"
 msgid "RA1"
 msgstr "RA1"
 
-#: gtk/paper_names_offsets.c:68
+#: gtk/print/paper_names_offsets.c:68
 msgctxt "paper size"
 msgid "RA2"
 msgstr "RA2"
 
-#: gtk/paper_names_offsets.c:69
+#: gtk/print/paper_names_offsets.c:69
 msgctxt "paper size"
 msgid "RA3"
 msgstr "RA3"
 
-#: gtk/paper_names_offsets.c:70
+#: gtk/print/paper_names_offsets.c:70
 msgctxt "paper size"
 msgid "RA4"
 msgstr "RA4"
 
-#: gtk/paper_names_offsets.c:71
+#: gtk/print/paper_names_offsets.c:71
 msgctxt "paper size"
 msgid "SRA0"
 msgstr "SRA0"
 
-#: gtk/paper_names_offsets.c:72
+#: gtk/print/paper_names_offsets.c:72
 msgctxt "paper size"
 msgid "SRA1"
 msgstr "SRA1"
 
-#: gtk/paper_names_offsets.c:73
+#: gtk/print/paper_names_offsets.c:73
 msgctxt "paper size"
 msgid "SRA2"
 msgstr "SRA2"
 
-#: gtk/paper_names_offsets.c:74
+#: gtk/print/paper_names_offsets.c:74
 msgctxt "paper size"
 msgid "SRA3"
 msgstr "SRA3"
 
-#: gtk/paper_names_offsets.c:75
+#: gtk/print/paper_names_offsets.c:75
 msgctxt "paper size"
 msgid "SRA4"
 msgstr "SRA4"
 
-#: gtk/paper_names_offsets.c:76
+#: gtk/print/paper_names_offsets.c:76
 msgctxt "paper size"
 msgid "JB0"
 msgstr "JB0"
 
-#: gtk/paper_names_offsets.c:77
+#: gtk/print/paper_names_offsets.c:77
 msgctxt "paper size"
 msgid "JB1"
 msgstr "JB1"
 
-#: gtk/paper_names_offsets.c:78
+#: gtk/print/paper_names_offsets.c:78
 msgctxt "paper size"
 msgid "JB10"
 msgstr "JB10"
 
-#: gtk/paper_names_offsets.c:79
+#: gtk/print/paper_names_offsets.c:79
 msgctxt "paper size"
 msgid "JB2"
 msgstr "JB2"
 
-#: gtk/paper_names_offsets.c:80
+#: gtk/print/paper_names_offsets.c:80
 msgctxt "paper size"
 msgid "JB3"
 msgstr "JB3"
 
-#: gtk/paper_names_offsets.c:81
+#: gtk/print/paper_names_offsets.c:81
 msgctxt "paper size"
 msgid "JB4"
 msgstr "JB4"
 
-#: gtk/paper_names_offsets.c:82
+#: gtk/print/paper_names_offsets.c:82
 msgctxt "paper size"
 msgid "JB5"
 msgstr "JB5"
 
-#: gtk/paper_names_offsets.c:83
+#: gtk/print/paper_names_offsets.c:83
 msgctxt "paper size"
 msgid "JB6"
 msgstr "JB6"
 
-#: gtk/paper_names_offsets.c:84
+#: gtk/print/paper_names_offsets.c:84
 msgctxt "paper size"
 msgid "JB7"
 msgstr "JB7"
 
-#: gtk/paper_names_offsets.c:85
+#: gtk/print/paper_names_offsets.c:85
 msgctxt "paper size"
 msgid "JB8"
 msgstr "JB8"
 
-#: gtk/paper_names_offsets.c:86
+#: gtk/print/paper_names_offsets.c:86
 msgctxt "paper size"
 msgid "JB9"
 msgstr "JB9"
 
-#: gtk/paper_names_offsets.c:87
+#: gtk/print/paper_names_offsets.c:87
 msgctxt "paper size"
 msgid "jis exec"
 msgstr "jis exec"
 
-#: gtk/paper_names_offsets.c:88
+#: gtk/print/paper_names_offsets.c:88
 msgctxt "paper size"
 msgid "Choukei 2 Envelope"
 msgstr "चोकिइ २ खाम"
 
-#: gtk/paper_names_offsets.c:89
+#: gtk/print/paper_names_offsets.c:89
 msgctxt "paper size"
 msgid "Choukei 3 Envelope"
 msgstr "चोकिइ ३ खाम"
 
-#: gtk/paper_names_offsets.c:90
+#: gtk/print/paper_names_offsets.c:90
 msgctxt "paper size"
 msgid "Choukei 4 Envelope"
 msgstr "चोकिइ ४ खाम"
 
-#: gtk/paper_names_offsets.c:91
+#: gtk/print/paper_names_offsets.c:91
 msgctxt "paper size"
 msgid "Choukei 40 Envelope"
 msgstr "चोकिइ ४० खाम"
 
-#: gtk/paper_names_offsets.c:92
+#: gtk/print/paper_names_offsets.c:92
 msgctxt "paper size"
 msgid "hagaki (postcard)"
 msgstr "hagaki(पोस्टकार्ड)"
 
-#: gtk/paper_names_offsets.c:93
+#: gtk/print/paper_names_offsets.c:93
 msgctxt "paper size"
 msgid "kahu Envelope"
 msgstr "kahu खाम"
 
-#: gtk/paper_names_offsets.c:94
+#: gtk/print/paper_names_offsets.c:94
 msgctxt "paper size"
 msgid "kaku2 Envelope"
 msgstr "kaku2 खाम"
 
-#: gtk/paper_names_offsets.c:95
+#: gtk/print/paper_names_offsets.c:95
 msgctxt "paper size"
 msgid "kaku3 Envelope"
 msgstr "kaku3 खाम"
 
-#: gtk/paper_names_offsets.c:96
+#: gtk/print/paper_names_offsets.c:96
 msgctxt "paper size"
 msgid "kaku4 Envelope"
 msgstr "kaku4 खाम"
 
-#: gtk/paper_names_offsets.c:97
+#: gtk/print/paper_names_offsets.c:97
 msgctxt "paper size"
 msgid "kaku5 Envelope"
 msgstr "kaku5 खाम"
 
-#: gtk/paper_names_offsets.c:98
+#: gtk/print/paper_names_offsets.c:98
 msgctxt "paper size"
 msgid "kaku7 Envelope"
 msgstr "kaku7 खाम"
 
-#: gtk/paper_names_offsets.c:99
+#: gtk/print/paper_names_offsets.c:99
 msgctxt "paper size"
 msgid "kaku8 Envelope"
 msgstr "kaku8 खाम"
 
-#: gtk/paper_names_offsets.c:100
+#: gtk/print/paper_names_offsets.c:100
 msgctxt "paper size"
 msgid "oufuku (reply postcard)"
 msgstr "ओउफुकु (जवाफ पोष्टकार्ड)"
 
-#: gtk/paper_names_offsets.c:101
+#: gtk/print/paper_names_offsets.c:101
 msgctxt "paper size"
 msgid "you4 Envelope"
 msgstr "you4 खाम"
 
-#: gtk/paper_names_offsets.c:102
+#: gtk/print/paper_names_offsets.c:102
 msgctxt "paper size"
 msgid "you6 Envelope"
 msgstr "you6 खाम"
 
-#: gtk/paper_names_offsets.c:103
+#: gtk/print/paper_names_offsets.c:103
 msgctxt "paper size"
 msgid "10×11"
 msgstr "१०×१०"
 
-#: gtk/paper_names_offsets.c:104
+#: gtk/print/paper_names_offsets.c:104
 msgctxt "paper size"
 msgid "10×13"
 msgstr "१०×१३"
 
-#: gtk/paper_names_offsets.c:105
+#: gtk/print/paper_names_offsets.c:105
 msgctxt "paper size"
 msgid "10×14"
 msgstr "१०× १४"
 
-#: gtk/paper_names_offsets.c:106
+#: gtk/print/paper_names_offsets.c:106
 msgctxt "paper size"
 msgid "10×15"
 msgstr "१०×१५"
 
-#: gtk/paper_names_offsets.c:107
+#: gtk/print/paper_names_offsets.c:107
 msgctxt "paper size"
 msgid "11×12"
 msgstr "११×१२"
 
-#: gtk/paper_names_offsets.c:108
+#: gtk/print/paper_names_offsets.c:108
 msgctxt "paper size"
 msgid "11×15"
 msgstr "११×१५"
 
-#: gtk/paper_names_offsets.c:109
+#: gtk/print/paper_names_offsets.c:109
 msgctxt "paper size"
 msgid "12×19"
 msgstr "१२×१९"
 
-#: gtk/paper_names_offsets.c:110
+#: gtk/print/paper_names_offsets.c:110
 msgctxt "paper size"
 msgid "5×7"
 msgstr "५×५"
 
-#: gtk/paper_names_offsets.c:111
+#: gtk/print/paper_names_offsets.c:111
 msgctxt "paper size"
 msgid "6×9 Envelope"
 msgstr "६ x१ खाम"
 
-#: gtk/paper_names_offsets.c:112
+#: gtk/print/paper_names_offsets.c:112
 msgctxt "paper size"
 msgid "7×9 Envelope"
 msgstr "७x९ खाम"
 
-#: gtk/paper_names_offsets.c:113
+#: gtk/print/paper_names_offsets.c:113
 msgctxt "paper size"
 msgid "8×10 Envelope"
 msgstr "८×१० खाम"
 
-#: gtk/paper_names_offsets.c:114
+#: gtk/print/paper_names_offsets.c:114
 msgctxt "paper size"
 msgid "9×11 Envelope"
 msgstr "९×११ खाम"
 
-#: gtk/paper_names_offsets.c:115
+#: gtk/print/paper_names_offsets.c:115
 msgctxt "paper size"
 msgid "9×12 Envelope"
 msgstr "९×१२ खाम"
 
-#: gtk/paper_names_offsets.c:116
+#: gtk/print/paper_names_offsets.c:116
 msgctxt "paper size"
 msgid "a2 Envelope"
 msgstr "a2 खाम"
 
-#: gtk/paper_names_offsets.c:117
+#: gtk/print/paper_names_offsets.c:117
 msgctxt "paper size"
 msgid "Arch A"
 msgstr "Arch A"
 
-#: gtk/paper_names_offsets.c:118
+#: gtk/print/paper_names_offsets.c:118
 msgctxt "paper size"
 msgid "Arch B"
 msgstr "Arch B"
 
-#: gtk/paper_names_offsets.c:119
+#: gtk/print/paper_names_offsets.c:119
 msgctxt "paper size"
 msgid "Arch C"
 msgstr "Arch C"
 
-#: gtk/paper_names_offsets.c:120
+#: gtk/print/paper_names_offsets.c:120
 msgctxt "paper size"
 msgid "Arch D"
 msgstr "Arch D"
 
-#: gtk/paper_names_offsets.c:121
+#: gtk/print/paper_names_offsets.c:121
 msgctxt "paper size"
 msgid "Arch E"
 msgstr "Arch E"
 
-#: gtk/paper_names_offsets.c:122
+#: gtk/print/paper_names_offsets.c:122
 msgctxt "paper size"
 msgid "b-plus"
 msgstr "b-plus"
 
-#: gtk/paper_names_offsets.c:123
+#: gtk/print/paper_names_offsets.c:123
 msgctxt "paper size"
 msgid "c"
 msgstr "c"
 
-#: gtk/paper_names_offsets.c:124
+#: gtk/print/paper_names_offsets.c:124
 msgctxt "paper size"
 msgid "c5 Envelope"
 msgstr "c5 खाम"
 
-#: gtk/paper_names_offsets.c:125
+#: gtk/print/paper_names_offsets.c:125
 msgctxt "paper size"
 msgid "d"
 msgstr "d"
 
-#: gtk/paper_names_offsets.c:126
+#: gtk/print/paper_names_offsets.c:126
 msgctxt "paper size"
 msgid "e"
 msgstr "e"
 
-#: gtk/paper_names_offsets.c:127
+#: gtk/print/paper_names_offsets.c:127
 msgctxt "paper size"
 msgid "edp"
 msgstr "edp"
 
-#: gtk/paper_names_offsets.c:128
+#: gtk/print/paper_names_offsets.c:128
 msgctxt "paper size"
 msgid "European edp"
 msgstr "युरोपेली edp"
 
-#: gtk/paper_names_offsets.c:129
+#: gtk/print/paper_names_offsets.c:129
 msgctxt "paper size"
 msgid "Executive"
 msgstr "कार्यकारी"
 
-#: gtk/paper_names_offsets.c:130
+#: gtk/print/paper_names_offsets.c:130
 msgctxt "paper size"
 msgid "f"
 msgstr "f"
 
-#: gtk/paper_names_offsets.c:131
+#: gtk/print/paper_names_offsets.c:131
 msgctxt "paper size"
 msgid "Fan-Fold European"
 msgstr "Fan-Fold European"
 
-#: gtk/paper_names_offsets.c:132
+#: gtk/print/paper_names_offsets.c:132
 msgctxt "paper size"
 msgid "Fan-Fold US"
 msgstr "Fan-Fold US"
 
-#: gtk/paper_names_offsets.c:133
+#: gtk/print/paper_names_offsets.c:133
 msgctxt "paper size"
 msgid "Fan-Fold German Legal"
 msgstr "Fan-Fold German Legal"
 
-#: gtk/paper_names_offsets.c:134
-#, fuzzy
+#: gtk/print/paper_names_offsets.c:134
 msgctxt "paper size"
 msgid "Government Legal"
-msgstr "कानूनी"
+msgstr ""
 
-#: gtk/paper_names_offsets.c:135
+#: gtk/print/paper_names_offsets.c:135
 msgctxt "paper size"
 msgid "Government Letter"
 msgstr "सरकारी चिठ्ठी"
 
-#: gtk/paper_names_offsets.c:136
+#: gtk/print/paper_names_offsets.c:136
 msgctxt "paper size"
 msgid "Index 3×5"
 msgstr "अनुक्रमणिका ३x५"
 
-#: gtk/paper_names_offsets.c:137
+#: gtk/print/paper_names_offsets.c:137
 msgctxt "paper size"
 msgid "Index 4×6 (postcard)"
 msgstr "अनुक्रमणिका ४×६"
 
-#: gtk/paper_names_offsets.c:138
+#: gtk/print/paper_names_offsets.c:138
 msgctxt "paper size"
 msgid "Index 4×6 ext"
 msgstr "अनुक्रमणिका ४×६ ext"
 
-#: gtk/paper_names_offsets.c:139
+#: gtk/print/paper_names_offsets.c:139
 msgctxt "paper size"
 msgid "Index 5×8"
 msgstr "अनुक्रमणिका ५x८"
 
-#: gtk/paper_names_offsets.c:140
+#: gtk/print/paper_names_offsets.c:140
 msgctxt "paper size"
 msgid "Invoice"
 msgstr "चलान"
 
-#: gtk/paper_names_offsets.c:141
+#: gtk/print/paper_names_offsets.c:141
 msgctxt "paper size"
 msgid "Tabloid"
 msgstr "Tabloid"
 
-#: gtk/paper_names_offsets.c:142
+#: gtk/print/paper_names_offsets.c:142
 msgctxt "paper size"
 msgid "US Legal"
 msgstr "US Legal"
 
-#: gtk/paper_names_offsets.c:143
+#: gtk/print/paper_names_offsets.c:143
 msgctxt "paper size"
 msgid "US Legal Extra"
 msgstr "US Legal Extra"
 
-#: gtk/paper_names_offsets.c:144
+#: gtk/print/paper_names_offsets.c:144
 msgctxt "paper size"
 msgid "US Letter"
 msgstr "US Letter"
 
-#: gtk/paper_names_offsets.c:145
+#: gtk/print/paper_names_offsets.c:145
 msgctxt "paper size"
 msgid "US Letter Extra"
 msgstr "US Letter Extra"
 
-#: gtk/paper_names_offsets.c:146
+#: gtk/print/paper_names_offsets.c:146
 msgctxt "paper size"
 msgid "US Letter Plus"
 msgstr "US Letter Plus"
 
-#: gtk/paper_names_offsets.c:147
+#: gtk/print/paper_names_offsets.c:147
 msgctxt "paper size"
 msgid "Monarch Envelope"
 msgstr "Monarch Envelope"
 
-#: gtk/paper_names_offsets.c:148
+#: gtk/print/paper_names_offsets.c:148
 msgctxt "paper size"
 msgid "#10 Envelope"
 msgstr "#१० खाम"
 
-#: gtk/paper_names_offsets.c:149
+#: gtk/print/paper_names_offsets.c:149
 msgctxt "paper size"
 msgid "#11 Envelope"
 msgstr "#११ खाम"
 
-#: gtk/paper_names_offsets.c:150
+#: gtk/print/paper_names_offsets.c:150
 msgctxt "paper size"
 msgid "#12 Envelope"
 msgstr "#१२ खाम"
 
-#: gtk/paper_names_offsets.c:151
+#: gtk/print/paper_names_offsets.c:151
 msgctxt "paper size"
 msgid "#14 Envelope"
 msgstr "#१४ खाम"
 
-#: gtk/paper_names_offsets.c:152
+#: gtk/print/paper_names_offsets.c:152
 msgctxt "paper size"
 msgid "#9 Envelope"
 msgstr "#९ खाम"
 
-#: gtk/paper_names_offsets.c:153
+#: gtk/print/paper_names_offsets.c:153
 msgctxt "paper size"
 msgid "Oficio"
 msgstr "Oficio"
 
-#: gtk/paper_names_offsets.c:154
+#: gtk/print/paper_names_offsets.c:154
 msgctxt "paper size"
 msgid "Personal Envelope"
 msgstr "व्यक्तिगत खाम"
 
-#: gtk/paper_names_offsets.c:155
+#: gtk/print/paper_names_offsets.c:155
 msgctxt "paper size"
 msgid "Quarto"
 msgstr "Quarto"
 
-#: gtk/paper_names_offsets.c:156
+#: gtk/print/paper_names_offsets.c:156
 msgctxt "paper size"
 msgid "Super A"
 msgstr "Super A"
 
-#: gtk/paper_names_offsets.c:157
+#: gtk/print/paper_names_offsets.c:157
 msgctxt "paper size"
 msgid "Super B"
 msgstr "Super B"
 
-#: gtk/paper_names_offsets.c:158
+#: gtk/print/paper_names_offsets.c:158
 msgctxt "paper size"
 msgid "Wide Format"
 msgstr "चौडा ढाचाँ"
 
-#: gtk/paper_names_offsets.c:159
+#: gtk/print/paper_names_offsets.c:159
 msgctxt "paper size"
 msgid "Photo L"
 msgstr "फोटो L"
 
-#: gtk/paper_names_offsets.c:160
+#: gtk/print/paper_names_offsets.c:160
 msgctxt "paper size"
 msgid "Dai-pa-kai"
 msgstr "डाइ-पा-काइ"
 
-#: gtk/paper_names_offsets.c:161
+#: gtk/print/paper_names_offsets.c:161
 msgctxt "paper size"
 msgid "Folio"
 msgstr "फोलिओ"
 
-#: gtk/paper_names_offsets.c:162
+#: gtk/print/paper_names_offsets.c:162
 msgctxt "paper size"
 msgid "Folio sp"
 msgstr "फोलिओ एसपी"
 
-#: gtk/paper_names_offsets.c:163
+#: gtk/print/paper_names_offsets.c:163
 msgctxt "paper size"
 msgid "Invite Envelope"
 msgstr "निमन्त्रणा खाम"
 
-#: gtk/paper_names_offsets.c:164
+#: gtk/print/paper_names_offsets.c:164
 msgctxt "paper size"
 msgid "Italian Envelope"
 msgstr "इटालेली खाम"
 
-#: gtk/paper_names_offsets.c:165
+#: gtk/print/paper_names_offsets.c:165
 msgctxt "paper size"
 msgid "juuro-ku-kai"
 msgstr "juuro-ku-kai"
 
-#: gtk/paper_names_offsets.c:166
+#: gtk/print/paper_names_offsets.c:166
 msgctxt "paper size"
 msgid "Large Photo"
 msgstr "ठूलो फोटो"
 
-#: gtk/paper_names_offsets.c:167
+#: gtk/print/paper_names_offsets.c:167
 msgctxt "paper size"
 msgid "Medium Photo"
 msgstr "मझौला तस्वीर"
 
-#: gtk/paper_names_offsets.c:168
+#: gtk/print/paper_names_offsets.c:168
 msgctxt "paper size"
 msgid "pa-kai"
 msgstr "पा-काइ"
 
-#: gtk/paper_names_offsets.c:169
+#: gtk/print/paper_names_offsets.c:169
 msgctxt "paper size"
 msgid "Postfix Envelope"
 msgstr "Postfix खाम"
 
-#: gtk/paper_names_offsets.c:170
+#: gtk/print/paper_names_offsets.c:170
 msgctxt "paper size"
 msgid "Small Photo"
 msgstr "सानो फोटो"
 
-#: gtk/paper_names_offsets.c:171
+#: gtk/print/paper_names_offsets.c:171
 msgctxt "paper size"
 msgid "Wide Photo"
 msgstr "फराकिलो फोटो"
 
-#: gtk/paper_names_offsets.c:172
+#: gtk/print/paper_names_offsets.c:172
 msgctxt "paper size"
 msgid "prc1 Envelope"
 msgstr "prc1 खाम"
 
-#: gtk/paper_names_offsets.c:173
+#: gtk/print/paper_names_offsets.c:173
 msgctxt "paper size"
 msgid "prc10 Envelope"
 msgstr "prc10 खाम"
 
-#: gtk/paper_names_offsets.c:174
+#: gtk/print/paper_names_offsets.c:174
 msgctxt "paper size"
 msgid "prc 16k"
 msgstr "prc 16k"
 
-#: gtk/paper_names_offsets.c:175
+#: gtk/print/paper_names_offsets.c:175
 msgctxt "paper size"
 msgid "prc2 Envelope"
 msgstr "prc2 खाम"
 
-#: gtk/paper_names_offsets.c:176
+#: gtk/print/paper_names_offsets.c:176
 msgctxt "paper size"
 msgid "prc3 Envelope"
 msgstr "prc3 खाम"
 
-#: gtk/paper_names_offsets.c:177
+#: gtk/print/paper_names_offsets.c:177
 msgctxt "paper size"
 msgid "prc 32k"
 msgstr "prc 32k"
 
-#: gtk/paper_names_offsets.c:178
+#: gtk/print/paper_names_offsets.c:178
 msgctxt "paper size"
 msgid "prc4 Envelope"
 msgstr "prc4 खाम"
 
-#: gtk/paper_names_offsets.c:179
+#: gtk/print/paper_names_offsets.c:179
 msgctxt "paper size"
 msgid "prc5 Envelope"
 msgstr "prc5 खाम"
 
-#: gtk/paper_names_offsets.c:180
+#: gtk/print/paper_names_offsets.c:180
 msgctxt "paper size"
 msgid "prc6 Envelope"
 msgstr "prc6 खाम"
 
-#: gtk/paper_names_offsets.c:181
+#: gtk/print/paper_names_offsets.c:181
 msgctxt "paper size"
 msgid "prc7 Envelope"
 msgstr "prc7 खाम"
 
-#: gtk/paper_names_offsets.c:182
+#: gtk/print/paper_names_offsets.c:182
 msgctxt "paper size"
 msgid "prc8 Envelope"
 msgstr "prc8 खाम"
 
-#: gtk/paper_names_offsets.c:183
+#: gtk/print/paper_names_offsets.c:183
 msgctxt "paper size"
 msgid "prc9 Envelope"
 msgstr "prc9 खाम"
 
-#: gtk/paper_names_offsets.c:184
+#: gtk/print/paper_names_offsets.c:184
 msgctxt "paper size"
 msgid "ROC 16k"
 msgstr "ROC 16k"
 
-#: gtk/paper_names_offsets.c:185
+#: gtk/print/paper_names_offsets.c:185
 msgctxt "paper size"
 msgid "ROC 8k"
 msgstr "ROC 8k"
 
+#: gtk/ui/gtkaboutdialog.ui:68
+msgid "About"
+msgstr "बारेमा"
+
+#: gtk/ui/gtkaboutdialog.ui:129
+msgid "Credits"
+msgstr "श्रेयहरू"
+
+#: gtk/ui/gtkaboutdialog.ui:221
+msgid "System"
+msgstr "प्रणाली"
+
+#: gtk/ui/gtkappchooserdialog.ui:4
+msgid "Select App"
+msgstr "अनुप्रयोग चयन गर्नुहोस्"
+
+#: gtk/ui/gtkappchooserdialog.ui:63
+msgid "_View All Apps"
+msgstr "सबै अनुप्रयोगहरू हेर्नुहोस्"
+
+#: gtk/ui/gtkappchooserdialog.ui:69
+#| msgid "_Find New Applications"
+msgid "_Find New Apps"
+msgstr ""
+
+#: gtk/ui/gtkappchooserwidget.ui:100
+msgid "No applications found."
+msgstr "अनुप्रयोग पाईएन."
+
 #: gtk/ui/gtkapplication-quartz.ui:13
 msgid "Preferences"
 msgstr "अभिरुचीहरू"
@@ -6069,7 +6051,6 @@ msgid "Services"
 msgstr "सेवाहरू"
 
 #: gtk/ui/gtkapplication-quartz.ui:25
-#, c-format
 msgid "Hide %s"
 msgstr "%s लुकाउनुहोस्"
 
@@ -6082,506 +6063,890 @@ msgid "Show All"
 msgstr "सबै देखाऊ"
 
 #: gtk/ui/gtkapplication-quartz.ui:42
-#, c-format
 msgid "Quit %s"
 msgstr "%s अन्त्य गर्नुहोस्"
 
-#: gtk/ui/gtkprintunixdialog.ui:493
-msgid "All sheets"
-msgstr "सबै पानाहरू"
+#: gtk/ui/gtkassistant.ui:64
+msgid "_Finish"
+msgstr "समाप्त (_F)"
 
-#: gtk/ui/gtkprintunixdialog.ui:494
-msgid "Even sheets"
-msgstr "जोर पानाहरू"
+#: gtk/ui/gtkassistant.ui:75
+msgid "_Back"
+msgstr "पछाडि"
 
-#: gtk/ui/gtkprintunixdialog.ui:495
-msgid "Odd sheets"
-msgstr "बिजोर पानाहरू"
+#: gtk/ui/gtkassistant.ui:86
+msgid "_Next"
+msgstr "_पछिल्लो"
 
-#: gtk/ui/gtkprintunixdialog.ui:675
-msgid "Portrait"
-msgstr "पोर्ट्रेट"
+#: gtk/ui/gtkcolorchooserdialog.ui:4
+msgid "Select a Color"
+msgstr "रङ्ग चयन गर्नुहोस्"
 
-#: gtk/ui/gtkprintunixdialog.ui:676
-msgid "Landscape"
-msgstr "ल्याण्डस्केप"
+#: gtk/ui/gtkcoloreditor.ui:43 gtk/ui/gtkcoloreditor.ui:53
+msgid "Pick a color from the screen"
+msgstr "पर्दाबाट रङ लिनुहोस्"
 
-#: gtk/ui/gtkprintunixdialog.ui:677
-msgid "Reverse portrait"
-msgstr "पोट्रेट उल्टाउनुहोस्"
+#: gtk/ui/gtkcoloreditor.ui:84
+msgid "Hexadecimal color or color name"
+msgstr ""
 
-#: gtk/ui/gtkprintunixdialog.ui:678
-msgid "Reverse landscape"
-msgstr "ल्याण्डस्केप उल्टाउनुहोस्"
+#: gtk/ui/gtkcoloreditor.ui:99
+msgid "Hue"
+msgstr "ह्यु"
 
-#: modules/media/gtkffmediafile.c:220
-#, fuzzy, c-format
-#| msgid "Unspecified error"
-msgid "Unspecified error decoding video"
-msgstr "निर्दिष्ट नगरिएको त्रुटि"
+#: gtk/ui/gtkcoloreditor.ui:115
+msgid "Alpha value"
+msgstr "अल्फा मान"
 
-#: modules/media/gtkffmediafile.c:322 modules/media/gtkffmediafile.c:496
-msgid "Not enough memory"
-msgstr "प्रशस्त स्मृति छैन"
+#: gtk/ui/gtkcoloreditor.ui:133
+#| msgid "Saturation"
+msgid "Saturation and value"
+msgstr ""
 
-#: modules/media/gtkffmediafile.c:519
-#, fuzzy
-#| msgid "Not a valid page setup file"
-msgid "Not a video file"
-msgstr "भिडियो फाइललाई MPEG2 मा रूपान्तरण गर्दैछ"
+#: gtk/ui/gtkcoloreditor.ui:157
+msgctxt "Color channel"
+msgid "A"
+msgstr "A"
+
+#: gtk/ui/gtkcoloreditor.ui:193
+msgctxt "Color channel"
+msgid "H"
+msgstr "H"
+
+#: gtk/ui/gtkcoloreditor.ui:230
+msgctxt "Color Channel"
+msgid "S"
+msgstr "S"
+
+#: gtk/ui/gtkcoloreditor.ui:239
+msgctxt "Color Channel"
+msgid "V"
+msgstr "V"
+
+#: gtk/ui/gtkdropdown.ui:25
+msgid "(None)"
+msgstr "(कुनै पनि होइन)"
+
+#: gtk/ui/gtkdropdown.ui:78
+msgid "Search…"
+msgstr "खोजी गर्नुहोस्…"
+
+#: gtk/ui/gtkemojichooser.ui:70 gtk/ui/gtkemojichooser.ui:240
+msgctxt "emoji category"
+msgid "Smileys & People"
+msgstr "स्माइलीहरू र मानव"
+
+#: gtk/ui/gtkemojichooser.ui:95 gtk/ui/gtkemojichooser.ui:249
+msgctxt "emoji category"
+msgid "Body & Clothing"
+msgstr "शरिर र लुगा"
+
+#: gtk/ui/gtkemojichooser.ui:120 gtk/ui/gtkemojichooser.ui:258
+msgctxt "emoji category"
+msgid "Animals & Nature"
+msgstr "प्रकृति र जनावर"
+
+#: gtk/ui/gtkemojichooser.ui:134 gtk/ui/gtkemojichooser.ui:267
+msgctxt "emoji category"
+msgid "Food & Drink"
+msgstr "खाद्य र पेय"
+
+#: gtk/ui/gtkemojichooser.ui:148 gtk/ui/gtkemojichooser.ui:276
+msgctxt "emoji category"
+msgid "Travel & Places"
+msgstr "यात्रा र स्थानहरू"
+
+#: gtk/ui/gtkemojichooser.ui:162 gtk/ui/gtkemojichooser.ui:285
+msgctxt "emoji category"
+msgid "Activities"
+msgstr "गतिविधिहरू"
+
+#: gtk/ui/gtkemojichooser.ui:176 gtk/ui/gtkemojichooser.ui:294
+msgctxt "emoji category"
+msgid "Objects"
+msgstr "वस्तुहरू"
 
-#: modules/media/gtkffmediafile.c:538
-#, fuzzy
-#| msgid "Unsupported icon type"
-msgid "Unsupported video codec"
-msgstr "कोडेक:"
+#: gtk/ui/gtkemojichooser.ui:190 gtk/ui/gtkemojichooser.ui:303
+msgctxt "emoji category"
+msgid "Symbols"
+msgstr "प्रतीक"
 
-#: modules/printbackends/gtkprintbackendcups.c:1152
-#: modules/printbackends/gtkprintbackendcups.c:1461
-msgid "Username:"
-msgstr "प्रयोगकर्ता नाम:"
+#: gtk/ui/gtkemojichooser.ui:204 gtk/ui/gtkemojichooser.ui:312
+msgctxt "emoji category"
+msgid "Flags"
+msgstr "झन्डा"
 
-#: modules/printbackends/gtkprintbackendcups.c:1153
-#: modules/printbackends/gtkprintbackendcups.c:1470
-msgid "Password:"
-msgstr "पासवर्ड:"
+#: gtk/ui/gtkemojichooser.ui:231
+msgctxt "emoji category"
+msgid "Recent"
+msgstr "हालसालै"
 
-#: modules/printbackends/gtkprintbackendcups.c:1192
-#: modules/printbackends/gtkprintbackendcups.c:1483
-#, c-format
-msgid "Authentication is required to print document “%s” on printer %s"
-msgstr "%s मुद्रकमा कागजात \"%s\" मुद्रण गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkfilechooserwidget.ui:71
+msgid "Create Folder"
+msgstr "फोल्डर सिर्जना गर्नुहोस्"
 
-#: modules/printbackends/gtkprintbackendcups.c:1194
-#, c-format
-msgid "Authentication is required to print a document on %s"
-msgstr "%s मा कागजात मुद्रण गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkfilechooserwidget.ui:202
+msgid "Remote location — only searching the current folder"
+msgstr "टाढाको स्थान — हालको फोल्डरमात्र खोजी गरिरहेको"
 
-#: modules/printbackends/gtkprintbackendcups.c:1198
-#, c-format
-msgid "Authentication is required to get attributes of job “%s”"
-msgstr "\"%s\" कामको विशेषता प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkfilechooserwidget.ui:334
+msgid "Folder Name"
+msgstr "फोल्डरको नाम"
 
-#: modules/printbackends/gtkprintbackendcups.c:1200
-msgid "Authentication is required to get attributes of a job"
-msgstr "कामको विशेषता प्राप्त गर्न प्रमाणीकरण आवश्यक हुन्छ"
+#: gtk/ui/gtkfilechooserwidget.ui:360
+msgid "_Create"
+msgstr "सिर्जना गर्नुहोस्"
 
-#: modules/printbackends/gtkprintbackendcups.c:1204
-#, c-format
-msgid "Authentication is required to get attributes of printer %s"
-msgstr "%s मुद्रकको विशेषता प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkfontchooserdialog.ui:4
+msgid "Select Font"
+msgstr "फन्ट चयन गर्नुहोस्"
 
-#: modules/printbackends/gtkprintbackendcups.c:1206
-msgid "Authentication is required to get attributes of a printer"
-msgstr "मुद्रकको विशेषता प्राप्त गर्न प्रमाणीकरण आवश्यक हुन्छ"
+#: gtk/ui/gtkfontchooserwidget.ui:66
+msgid "Search font name"
+msgstr "फन्ट नाम खोज्नुहोस्"
 
-#: modules/printbackends/gtkprintbackendcups.c:1209
-#, c-format
-msgid "Authentication is required to get default printer of %s"
-msgstr "%s को पूर्वनिर्धारित मुद्रक प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkfontchooserwidget.ui:79
+msgid "Filters"
+msgstr "फिल्टर"
 
-#: modules/printbackends/gtkprintbackendcups.c:1212
-#, c-format
-msgid "Authentication is required to get printers from %s"
-msgstr "%s बाट मुद्रक प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkfontchooserwidget.ui:91
+msgid "Filter by"
+msgstr "यसद्वारा फिल्टर"
 
-#: modules/printbackends/gtkprintbackendcups.c:1217
-#, c-format
-msgid "Authentication is required to get a file from %s"
-msgstr "%s बाट फाइल प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkfontchooserwidget.ui:101
+msgid "Monospace"
+msgstr "मोनोस्पेस"
 
-#: modules/printbackends/gtkprintbackendcups.c:1219
-#, c-format
-msgid "Authentication is required on %s"
-msgstr "%s प्रमाणिकरण आवश्यक छ ।"
+#: gtk/ui/gtkfontchooserwidget.ui:106
+msgid "Language"
+msgstr "भाषा"
 
-#: modules/printbackends/gtkprintbackendcups.c:1455
-msgid "Domain:"
-msgstr "डोमेन:"
+#: gtk/ui/gtkfontchooserwidget.ui:197 gtk/ui/gtkfontchooserwidget.ui:199 gtk/ui/gtkfontchooserwidget.ui:352 gtk/ui/gtkfontchooserwidget.ui:356
+#| msgid "Preview text"
+msgid "Preview Font"
+msgstr ""
 
-#: modules/printbackends/gtkprintbackendcups.c:1485
-#, c-format
-msgid "Authentication is required to print document “%s”"
-msgstr "कागजात \"%s\" मुद्रण गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkfontchooserwidget.ui:295
+msgid "No Fonts Found"
+msgstr "फन्टहरू फेला परेन"
 
-#: modules/printbackends/gtkprintbackendcups.c:1490
-#, c-format
-msgid "Authentication is required to print this document on printer %s"
-msgstr "%s मुद्रकमा यो कागजात मुद्रण गर्न प्रमाणीकरण आवश्यक छ"
+#: gtk/ui/gtkmediacontrols.ui:47
+msgctxt "media controls"
+msgid "Position"
+msgstr "अवस्था"
 
-#: modules/printbackends/gtkprintbackendcups.c:1492
-msgid "Authentication is required to print this document"
-msgstr "यो कागजात मुद्रण गर्न प्रमाणीकरण आवश्यक हुन्छ"
+#: gtk/ui/gtkmediacontrols.ui:65
+msgctxt "media controls"
+msgid "Volume"
+msgstr "भोल्युम"
 
-#: modules/printbackends/gtkprintbackendcups.c:2589
-#, c-format
-msgid "Printer “%s” is low on toner."
-msgstr "मुद्रणयन्त्र\"%s\" मा टोनर कम छ ।"
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:30
+msgid "_Format for:"
+msgstr "यसका लागि ढाँचा:"
 
-#: modules/printbackends/gtkprintbackendcups.c:2593
-#, c-format
-msgid "Printer “%s” has no toner left."
-msgstr "मुद्रणयन्त्र “%s” मा टोनर सकियो"
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:54 gtk/print/ui/gtkprintunixdialog.ui:704
+msgid "_Paper size:"
+msgstr "कागज साइज:"
 
-#. Translators: "Developer" like on photo development context
-#: modules/printbackends/gtkprintbackendcups.c:2598
-#, c-format
-msgid "Printer “%s” is low on developer."
-msgstr "विकासकर्तामा मुद्रक \"%s\" कम छ।."
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:89
+msgid "_Orientation:"
+msgstr "अभिमूखीकरण:"
 
-#. Translators: "Developer" like on photo development context
-#: modules/printbackends/gtkprintbackendcups.c:2603
-#, c-format
-msgid "Printer “%s” is out of developer."
-msgstr "मुद्रणयन्त्र\"%s\" मा विकासकर्ता छैन ।."
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:101 gtk/print/ui/gtkprintunixdialog.ui:744
+msgid "Portrait"
+msgstr "पोर्ट्रेट"
 
-#. Translators: "marker" is one color bin of the printer
-#: modules/printbackends/gtkprintbackendcups.c:2608
-#, c-format
-msgid "Printer “%s” is low on at least one marker supply."
-msgstr "मुद्रक \"%s\" कम्तिमा एउटा मार्कर आपूर्तिमा कम छ।"
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:112 gtk/print/ui/gtkprintunixdialog.ui:746
+msgid "Reverse portrait"
+msgstr "पोट्रेट उल्टाउनुहोस्"
 
-#. Translators: "marker" is one color bin of the printer
-#: modules/printbackends/gtkprintbackendcups.c:2613
-#, c-format
-msgid "Printer “%s” is out of at least one marker supply."
-msgstr "मुद्रणयन्त्र “%s” मा कम्तीमा एउटा मार्कर आपूर्ति सकियो ।."
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:124 gtk/print/ui/gtkprintunixdialog.ui:745
+msgid "Landscape"
+msgstr "ल्याण्डस्केप"
 
-#: modules/printbackends/gtkprintbackendcups.c:2617
-#, c-format
-msgid "The cover is open on printer “%s”."
-msgstr "मुद्रणयन्त्र  “%s” मा कवर खुला छ ।"
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:135 gtk/print/ui/gtkprintunixdialog.ui:747
+msgid "Reverse landscape"
+msgstr "ल्याण्डस्केप उल्टाउनुहोस्"
 
-#: modules/printbackends/gtkprintbackendcups.c:2621
-#, c-format
-msgid "The door is open on printer “%s”."
-msgstr "मुद्रणयन्त्र  “%s” मा ढोका खुला छ ।"
+#: gtk/ui/gtkplacesview.ui:16
+msgid "Server Addresses"
+msgstr "सर्भर ठेगानाहरू"
 
-#: modules/printbackends/gtkprintbackendcups.c:2625
-#, c-format
-msgid "Printer “%s” is low on paper."
-msgstr "मुद्रणयन्त्र\"%s\" कागज मा कम छ ।"
+#: gtk/ui/gtkplacesview.ui:28
+msgid "Server addresses are made up of a protocol prefix and an address. Examples:"
+msgstr "सर्भर ठेगाना प्रोटोकल उपसर्ग र ठेगानाबाट बनेको हुन्छ । उदाहरण:"
 
-#: modules/printbackends/gtkprintbackendcups.c:2629
-#, c-format
-msgid "Printer “%s” is out of paper."
-msgstr "मुद्रणयन्त्र\"%s\" मा कागज छैन ।"
+#: gtk/ui/gtkplacesview.ui:54
+msgid "Available Protocols"
+msgstr "उपलब्ध प्रोटोकल"
 
-#: modules/printbackends/gtkprintbackendcups.c:2633
-#, c-format
-msgid "Printer “%s” is currently offline."
-msgstr "मुद्रक \"%s\" हाल अफलाइन छ।"
+#. Translators: Server as any successfully connected network address
+#: gtk/ui/gtkplacesview.ui:106
+msgid "No recent servers found"
+msgstr "हालको सर्भर भेटिएन"
 
-#: modules/printbackends/gtkprintbackendcups.c:2637
-#, c-format
-msgid "There is a problem on printer “%s”."
-msgstr "\"%s\" मुद्रणयन्त्रमा त्रुटि छ ।."
+#: gtk/ui/gtkplacesview.ui:129
+msgid "Recent Servers"
+msgstr "हालको सर्भर"
 
-#. Translators: this is a printer status.
-#: modules/printbackends/gtkprintbackendcups.c:2657
-msgid "Paused; Rejecting Jobs"
-msgstr "पज गरिएको; कार्य अस्वीकार गर्दै"
+#: gtk/ui/gtkplacesview.ui:209
+msgid "No results found"
+msgstr "नतिजा भेटिएन"
 
-#. Translators: this is a printer status.
-#: modules/printbackends/gtkprintbackendcups.c:2663
-msgid "Rejecting Jobs"
-msgstr "कार्य अस्वीकार गर्दै"
+#: gtk/ui/gtkplacesview.ui:240
+msgid "Connect to _Server"
+msgstr "सर्भरमा जडान गर्नुहोस्"
 
-#. Translators: this string connects multiple printer states together.
-#: modules/printbackends/gtkprintbackendcups.c:2704
-msgid "; "
-msgstr "; "
+#: gtk/ui/gtkplacesview.ui:265
+msgid "Enter server address…"
+msgstr "सर्भर ठेगाना प्रवेश गर्नुहोस्…"
 
-#: modules/printbackends/gtkprintbackendcups.c:4612
-#: modules/printbackends/gtkprintbackendcups.c:4679
-msgctxt "printing option"
-msgid "Two Sided"
-msgstr "दुबैपट्टी"
+#. this is the header for the printer status column in the print dialog
+#: gtk/print/ui/gtkprintunixdialog.ui:142
+msgid "Status"
+msgstr "वस्तुस्थिति"
 
-#: modules/printbackends/gtkprintbackendcups.c:4613
-msgctxt "printing option"
-msgid "Paper Type"
+#: gtk/print/ui/gtkprintunixdialog.ui:196
+msgid "Range"
+msgstr "दायरा"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:214
+msgid "_All Pages"
+msgstr "सबै पृष्ठहरू"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:227
+msgid "C_urrent Page"
+msgstr "हालको पृष्ठ"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:241
+msgid "Se_lection"
+msgstr "चयन"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:256
+msgid "Pag_es:"
+msgstr "पृष्ठहरू:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:260 gtk/print/ui/gtkprintunixdialog.ui:273
+msgid ""
+"Specify one or more page ranges,\n"
+" e.g. 1–3, 7, 11"
+msgstr ""
+"एक वा बढी पृष्ठ दायरा निर्दिष्ट गर्नुहोस्,\n"
+" जस्तै: १–३, ७, ११"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:299
+msgid "Copies"
+msgstr "प्रतिलिपिहरू"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:317
+msgid "Copie_s:"
+msgstr "प्रतिलिपिहरू:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:340
+msgid "C_ollate"
+msgstr "कोलेट गर्नुहोस्"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:351
+msgid "_Reverse"
+msgstr "फर्काउनुहोस्"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:424
+msgid "General"
+msgstr "सामान्य"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:470
+msgid "T_wo-sided:"
+msgstr "दुई-किनारा भएको:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:492
+msgid "Pages per _side:"
+msgstr "प्रति किनारा पृष्ठहरू:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:516
+msgid "Page or_dering:"
+msgstr "पृष्ठ क्रम:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:539
+msgid "_Only print:"
+msgstr "मुद्रण मात्र:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:555
+msgid "All sheets"
+msgstr "सबै पानाहरू"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:556
+msgid "Even sheets"
+msgstr "जोर पानाहरू"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:557
+msgid "Odd sheets"
+msgstr "बिजोर पानाहरू"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:571
+msgid "Sc_ale:"
+msgstr "मापन गर्नुहोस्:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:619
+msgid "Paper"
+msgstr "कागज"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:638
+msgid "Paper _type:"
+msgstr "कागज प्रकार:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:660
+msgid "Paper _source:"
+msgstr "कागज स्रोत:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:682
+msgid "Output t_ray:"
+msgstr "निर्गत ट्रे:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:727
+msgid "Or_ientation:"
+msgstr "अभीमुखिकरण:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:805
+msgid "Job Details"
+msgstr "कार्य विवरणहरू"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:820
+msgid "Pri_ority:"
+msgstr "प्राथमिकता:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:841
+msgid "_Billing info:"
+msgstr "बिलिङ सूचना:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:874
+msgid "Print Document"
+msgstr "कागजात मुद्रण गर्नुहोस्"
+
+#. this is one of the choices for the print at option in the print dialog
+#: gtk/print/ui/gtkprintunixdialog.ui:887
+msgid "_Now"
+msgstr "अहिले"
+
+#. this is one of the choices for the print at option in the print dialog. It also serves as the label for an entry that allows the user to enter a time.
+#: gtk/print/ui/gtkprintunixdialog.ui:901
+msgid "A_t:"
+msgstr "मा:"
+
+#. Ability to parse the am/pm format depends on actual locale. You can remove the am/pm values below for your locale if they are not supported.
+#: gtk/print/ui/gtkprintunixdialog.ui:903 gtk/print/ui/gtkprintunixdialog.ui:905 gtk/print/ui/gtkprintunixdialog.ui:921 gtk/print/ui/gtkprintunixdialog.ui:923
+msgid ""
+"Specify the time of print,\n"
+" e.g. 15∶30, 2∶35 pm, 14∶15∶20, 11∶46∶30 am, 4 pm"
+msgstr ""
+"मुद्रणको समय निर्दिष्ट गर्नुहोस्\n"
+"  जस्तै: १५:३०,२:३५ पिएम, १४:१५:२०, ११:४६:३० एएम, ४ पिएम"
+
+#. this is one of the choices for the print at option in the print dialog. It means that the print job will not be printed until it explicitly gets 'released'.
+#: gtk/print/ui/gtkprintunixdialog.ui:935
+msgid "On _hold"
+msgstr "व्यस्त छ"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:937 gtk/print/ui/gtkprintunixdialog.ui:938
+msgid "Hold the job until it is explicitly released"
+msgstr ""
+
+#: gtk/print/ui/gtkprintunixdialog.ui:965
+msgid "Add Cover Page"
+msgstr "आवरण पृष्ठ थप्नुहोस्"
+
+#. this is the label used for the option in the print dialog that controls the front cover page.
+#: gtk/print/ui/gtkprintunixdialog.ui:980
+msgid "Be_fore:"
+msgstr "अगाडि:"
+
+#. this is the label used for the option in the print dialog that controls the back cover page.
+#: gtk/print/ui/gtkprintunixdialog.ui:1001
+msgid "_After:"
+msgstr "पछि:"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:1030
+msgid "Job"
+msgstr "काम"
+
+#. This will appear as a tab label in the print dialog.
+#: gtk/print/ui/gtkprintunixdialog.ui:1060
+msgid "Image Quality"
+msgstr "छवि गुणस्तर"
+
+#. This will appear as a tab label in the print dialog.
+#: gtk/print/ui/gtkprintunixdialog.ui:1089
+msgid "Color"
+msgstr "रङ्ग"
+
+#. This will appear as a tab label in the print dialog. It's a typographical term, as in "Binding and finishing"
+#: gtk/print/ui/gtkprintunixdialog.ui:1118
+msgid "Finishing"
+msgstr "सकिदै"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:1147
+msgid "Advanced"
+msgstr "उन्नत"
+
+#: gtk/print/ui/gtkprintunixdialog.ui:1163
+msgid "Some of the settings in the dialog conflict"
+msgstr "संवाद द्वन्द्वमा केही सेटिङहरू"
+
+#: modules/printbackends/gtkprintbackendcpdb.c:542 modules/printbackends/gtkprintbackendcups.c:5670
+msgctxt "Print job priority"
+msgid "Urgent"
+msgstr "जरूरी"
+
+#: modules/printbackends/gtkprintbackendcpdb.c:543 modules/printbackends/gtkprintbackendcups.c:5671
+msgctxt "Print job priority"
+msgid "High"
+msgstr "उच्च"
+
+#: modules/printbackends/gtkprintbackendcpdb.c:544 modules/printbackends/gtkprintbackendcups.c:5672
+msgctxt "Print job priority"
+msgid "Medium"
+msgstr "मध्यम"
+
+#: modules/printbackends/gtkprintbackendcpdb.c:545 modules/printbackends/gtkprintbackendcups.c:5673
+msgctxt "Print job priority"
+msgid "Low"
+msgstr "न्यून"
+
+#. Translators, this is the label used for the option in the print
+#. * dialog that controls the front cover page.
+#.
+#: modules/printbackends/gtkprintbackendcpdb.c:567 modules/printbackends/gtkprintbackendcups.c:5816
+msgctxt "printer option"
+msgid "Before"
+msgstr "अगाडि छ"
+
+#. Translators, this is the label used for the option in the print
+#. * dialog that controls the back cover page.
+#.
+#: modules/printbackends/gtkprintbackendcpdb.c:574 modules/printbackends/gtkprintbackendcups.c:5831
+msgctxt "printer option"
+msgid "After"
+msgstr "पछि"
+
+#: modules/printbackends/gtkprintbackendcpdb.c:597
+msgid "Print at"
+msgstr "मुद्रण"
+
+#: modules/printbackends/gtkprintbackendcpdb.c:607
+msgid "Print at time"
+msgstr "मुद्रण समय"
+
+#: modules/printbackends/gtkprintbackendcpdb.c:670
+msgctxt "print option"
+msgid "Borderless"
+msgstr "किनारारहित"
+
+#. Translators: this is a printer status.
+#: modules/printbackends/gtkprintbackendcpdb.c:1530 modules/printbackends/gtkprintbackendcups.c:2636
+msgid "Paused; Rejecting Jobs"
+msgstr "पज गरिएको; कार्य अस्वीकार गर्दै"
+
+#. Translators: this is a printer status.
+#: modules/printbackends/gtkprintbackendcpdb.c:1536 modules/printbackends/gtkprintbackendcups.c:2642
+msgid "Rejecting Jobs"
+msgstr "कार्य अस्वीकार गर्दै"
+
+#: modules/printbackends/gtkprintbackendcups.c:1142 modules/printbackends/gtkprintbackendcups.c:1449
+msgid "Username:"
+msgstr "प्रयोगकर्ता नाम:"
+
+#: modules/printbackends/gtkprintbackendcups.c:1143 modules/printbackends/gtkprintbackendcups.c:1458
+msgid "Password:"
+msgstr "पासवर्ड:"
+
+#: modules/printbackends/gtkprintbackendcups.c:1181 modules/printbackends/gtkprintbackendcups.c:1471
+#, c-format
+msgid "Authentication is required to print document “%s” on printer %s"
+msgstr "%s मुद्रकमा कागजात \"%s\" मुद्रण गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1183
+#, c-format
+msgid "Authentication is required to print a document on %s"
+msgstr "%s मा कागजात मुद्रण गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1187
+#, c-format
+msgid "Authentication is required to get attributes of job “%s”"
+msgstr "\"%s\" कामको विशेषता प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1189
+msgid "Authentication is required to get attributes of a job"
+msgstr "कामको विशेषता प्राप्त गर्न प्रमाणीकरण आवश्यक हुन्छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1193
+#, c-format
+msgid "Authentication is required to get attributes of printer %s"
+msgstr "%s मुद्रकको विशेषता प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1195
+msgid "Authentication is required to get attributes of a printer"
+msgstr "मुद्रकको विशेषता प्राप्त गर्न प्रमाणीकरण आवश्यक हुन्छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1198
+#, c-format
+msgid "Authentication is required to get default printer of %s"
+msgstr "%s को पूर्वनिर्धारित मुद्रक प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1201
+#, c-format
+msgid "Authentication is required to get printers from %s"
+msgstr "%s बाट मुद्रक प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1206
+#, c-format
+msgid "Authentication is required to get a file from %s"
+msgstr "%s बाट फाइल प्राप्त गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1208
+#, c-format
+msgid "Authentication is required on %s"
+msgstr "%s प्रमाणिकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1443
+msgid "Domain:"
+msgstr "डोमेन:"
+
+#: modules/printbackends/gtkprintbackendcups.c:1473
+#, c-format
+msgid "Authentication is required to print document “%s”"
+msgstr "कागजात \"%s\" मुद्रण गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1478
+#, c-format
+msgid "Authentication is required to print this document on printer %s"
+msgstr "%s मुद्रकमा यो कागजात मुद्रण गर्न प्रमाणीकरण आवश्यक छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:1480
+msgid "Authentication is required to print this document"
+msgstr "यो कागजात मुद्रण गर्न प्रमाणीकरण आवश्यक हुन्छ"
+
+#: modules/printbackends/gtkprintbackendcups.c:2568
+#, c-format
+msgid "Printer “%s” is low on toner."
+msgstr "मुद्रणयन्त्र\"%s\" मा टोनर कम छ ।."
+
+#: modules/printbackends/gtkprintbackendcups.c:2572
+#, c-format
+msgid "Printer “%s” has no toner left."
+msgstr "मुद्रणयन्त्र “%s” मा टोनर सकियो."
+
+#. Translators: "Developer" like on photo development context
+#: modules/printbackends/gtkprintbackendcups.c:2577
+#, c-format
+msgid "Printer “%s” is low on developer."
+msgstr "विकासकर्तामा मुद्रक \"%s\" कम छ।."
+
+#. Translators: "Developer" like on photo development context
+#: modules/printbackends/gtkprintbackendcups.c:2582
+#, c-format
+msgid "Printer “%s” is out of developer."
+msgstr "मुद्रणयन्त्र\"%s\" मा विकासकर्ता छैन ।."
+
+#. Translators: "marker" is one color bin of the printer
+#: modules/printbackends/gtkprintbackendcups.c:2587
+#, c-format
+msgid "Printer “%s” is low on at least one marker supply."
+msgstr "मुद्रक \"%s\" कम्तिमा एउटा मार्कर आपूर्तिमा कम छ।."
+
+#. Translators: "marker" is one color bin of the printer
+#: modules/printbackends/gtkprintbackendcups.c:2592
+#, c-format
+msgid "Printer “%s” is out of at least one marker supply."
+msgstr "मुद्रणयन्त्र “%s” मा कम्तीमा एउटा मार्कर आपूर्ति सकियो ।."
+
+#: modules/printbackends/gtkprintbackendcups.c:2596
+#, c-format
+msgid "The cover is open on printer “%s”."
+msgstr "मुद्रणयन्त्र  “%s” मा कवर खुला छ ।."
+
+#: modules/printbackends/gtkprintbackendcups.c:2600
+#, c-format
+msgid "The door is open on printer “%s”."
+msgstr "मुद्रणयन्त्र  “%s” मा ढोका खुला छ ।."
+
+#: modules/printbackends/gtkprintbackendcups.c:2604
+#, c-format
+msgid "Printer “%s” is low on paper."
+msgstr "मुद्रणयन्त्र\"%s\" कागज मा कम छ ।."
+
+#: modules/printbackends/gtkprintbackendcups.c:2608
+#, c-format
+msgid "Printer “%s” is out of paper."
+msgstr "मुद्रणयन्त्र\"%s\" मा कागज छैन ।."
+
+#: modules/printbackends/gtkprintbackendcups.c:2612
+#, c-format
+msgid "Printer “%s” is currently offline."
+msgstr "मुद्रक \"%s\" हाल अफलाइन छ।."
+
+#: modules/printbackends/gtkprintbackendcups.c:2616
+#, c-format
+msgid "There is a problem on printer “%s”."
+msgstr "\"%s\" मुद्रणयन्त्रमा त्रुटि छ ।."
+
+#. Translators: this string connects multiple printer states together.
+#: modules/printbackends/gtkprintbackendcups.c:2683
+msgid "; "
+msgstr "; "
+
+#: modules/printbackends/gtkprintbackendcups.c:4611 modules/printbackends/gtkprintbackendcups.c:4678
+msgctxt "printing option"
+msgid "Two Sided"
+msgstr "दुबैपट्टी"
+
+#: modules/printbackends/gtkprintbackendcups.c:4612
+msgctxt "printing option"
+msgid "Paper Type"
 msgstr "कागजको प्रकार"
 
-#: modules/printbackends/gtkprintbackendcups.c:4614
+#: modules/printbackends/gtkprintbackendcups.c:4613
 msgctxt "printing option"
 msgid "Paper Source"
 msgstr "कागज श्रोत"
 
-#: modules/printbackends/gtkprintbackendcups.c:4615
-#: modules/printbackends/gtkprintbackendcups.c:4680
+#: modules/printbackends/gtkprintbackendcups.c:4614 modules/printbackends/gtkprintbackendcups.c:4679
 msgctxt "printing option"
 msgid "Output Tray"
-msgstr "निर्गत ट्रे "
+msgstr "निर्गत ट्रे"
 
-#: modules/printbackends/gtkprintbackendcups.c:4616
+#: modules/printbackends/gtkprintbackendcups.c:4615
 msgctxt "printing option"
 msgid "Resolution"
 msgstr "रिजोल्युसन"
 
-#: modules/printbackends/gtkprintbackendcups.c:4617
+#: modules/printbackends/gtkprintbackendcups.c:4616
 msgctxt "printing option"
 msgid "GhostScript pre-filtering"
 msgstr "घोस्टस्क्रिप्ट प्रि-फिल्टरिङ"
 
-#: modules/printbackends/gtkprintbackendcups.c:4626
+#: modules/printbackends/gtkprintbackendcups.c:4625
 msgctxt "printing option value"
 msgid "One Sided"
 msgstr "एकापट्टी"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4628
+#: modules/printbackends/gtkprintbackendcups.c:4627
 msgctxt "printing option value"
 msgid "Long Edge (Standard)"
 msgstr "लामो धार भएको"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4630
+#: modules/printbackends/gtkprintbackendcups.c:4629
 msgctxt "printing option value"
 msgid "Short Edge (Flip)"
 msgstr "छोटो किनारा (फ्लिप)"
 
 #. Translators: this is an option of "Paper Source"
-#: modules/printbackends/gtkprintbackendcups.c:4632
-#: modules/printbackends/gtkprintbackendcups.c:4634
-#: modules/printbackends/gtkprintbackendcups.c:4642
+#: modules/printbackends/gtkprintbackendcups.c:4631 modules/printbackends/gtkprintbackendcups.c:4633 modules/printbackends/gtkprintbackendcups.c:4641
 msgctxt "printing option value"
 msgid "Auto Select"
 msgstr "स्वतः छान्ने"
 
 #. Translators: this is an option of "Paper Source"
 #. Translators: this is an option of "Resolution"
-#: modules/printbackends/gtkprintbackendcups.c:4636
-#: modules/printbackends/gtkprintbackendcups.c:4638
-#: modules/printbackends/gtkprintbackendcups.c:4640
-#: modules/printbackends/gtkprintbackendcups.c:4644
+#: modules/printbackends/gtkprintbackendcups.c:4635 modules/printbackends/gtkprintbackendcups.c:4637 modules/printbackends/gtkprintbackendcups.c:4639
+#: modules/printbackends/gtkprintbackendcups.c:4643
 msgctxt "printing option value"
 msgid "Printer Default"
 msgstr "पूर्वानिर्धारण मुद्रण"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4646
+#: modules/printbackends/gtkprintbackendcups.c:4645
 msgctxt "printing option value"
 msgid "Embed GhostScript fonts only"
 msgstr "घोस्टस्क्रिप्ट फन्टहरू मात्र सम्मिलित गर्नुहोस्"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4648
+#: modules/printbackends/gtkprintbackendcups.c:4647
 msgctxt "printing option value"
 msgid "Convert to PS level 1"
 msgstr "पीएस स्तर १ रूपान्तरण"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4650
+#: modules/printbackends/gtkprintbackendcups.c:4649
 msgctxt "printing option value"
 msgid "Convert to PS level 2"
 msgstr "पीएस स्तर २ रूपान्तरण"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4652
+#: modules/printbackends/gtkprintbackendcups.c:4651
 msgctxt "printing option value"
 msgid "No pre-filtering"
 msgstr "पूर्व-फिल्टर छैन"
 
 #. Translators: "Miscellaneous" is the label for a button, that opens
 #. up an extra panel of settings in a print dialog.
-#: modules/printbackends/gtkprintbackendcups.c:4661
+#: modules/printbackends/gtkprintbackendcups.c:4660
 msgctxt "printing option group"
 msgid "Miscellaneous"
 msgstr "विविध"
 
-#: modules/printbackends/gtkprintbackendcups.c:4688
+#: modules/printbackends/gtkprintbackendcups.c:4687
 msgctxt "sides"
 msgid "One Sided"
 msgstr "एकापट्टी"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4690
+#: modules/printbackends/gtkprintbackendcups.c:4689
 msgctxt "sides"
 msgid "Long Edge (Standard)"
 msgstr "लामो धार भएको"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4692
+#: modules/printbackends/gtkprintbackendcups.c:4691
 msgctxt "sides"
 msgid "Short Edge (Flip)"
 msgstr "छोटो किनारा (फ्लिप)"
 
 #. Translators: Top output bin
-#: modules/printbackends/gtkprintbackendcups.c:4695
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4694
 msgctxt "output-bin"
 msgid "Top Bin"
-msgstr "_माथि:"
+msgstr "शीर्ष बिन"
 
 #. Translators: Middle output bin
-#: modules/printbackends/gtkprintbackendcups.c:4697
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4696
 msgctxt "output-bin"
 msgid "Middle Bin"
-msgstr "बीचको:"
+msgstr "मध्य बिन"
 
 #. Translators: Bottom output bin
-#: modules/printbackends/gtkprintbackendcups.c:4699
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4698
 msgctxt "output-bin"
 msgid "Bottom Bin"
-msgstr "_तल:"
+msgstr "तलको बिन"
 
 #. Translators: Side output bin
-#: modules/printbackends/gtkprintbackendcups.c:4701
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4700
 msgctxt "output-bin"
 msgid "Side Bin"
-msgstr "साइड बाट साइड "
+msgstr "छेउको बिन"
 
 #. Translators: Left output bin
-#: modules/printbackends/gtkprintbackendcups.c:4703
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4702
 msgctxt "output-bin"
 msgid "Left Bin"
-msgstr "_बायाँ:"
+msgstr "बायाँ बिन"
 
 #. Translators: Right output bin
-#: modules/printbackends/gtkprintbackendcups.c:4705
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4704
 msgctxt "output-bin"
 msgid "Right Bin"
-msgstr "_दायाँ:"
+msgstr "दायाँ बिन"
 
 #. Translators: Center output bin
-#: modules/printbackends/gtkprintbackendcups.c:4707
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4706
 msgctxt "output-bin"
 msgid "Center Bin"
-msgstr "केन्द्र"
+msgstr "केन्द्र बिन"
 
 #. Translators: Rear output bin
-#: modules/printbackends/gtkprintbackendcups.c:4709
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4708
 msgctxt "output-bin"
 msgid "Rear Bin"
-msgstr "पछाडि"
+msgstr "रियर बिन"
 
 #. Translators: Output bin where one sided output is oriented in the face-up position
-#: modules/printbackends/gtkprintbackendcups.c:4711
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4710
 msgctxt "output-bin"
 msgid "Face Up Bin"
-msgstr "आकृति"
+msgstr "फेस अप बिन"
 
 #. Translators: Output bin where one sided output is oriented in the face-down position
-#: modules/printbackends/gtkprintbackendcups.c:4713
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4712
 msgctxt "output-bin"
 msgid "Face Down Bin"
-msgstr "आकृति"
+msgstr "फेस डाउन बिन"
 
 #. Translators: Large capacity output bin
-#: modules/printbackends/gtkprintbackendcups.c:4715
-#, fuzzy
+#: modules/printbackends/gtkprintbackendcups.c:4714
 msgctxt "output-bin"
 msgid "Large Capacity Bin"
-msgstr "ठूलो"
+msgstr "ठूलो क्षमताको बिन"
 
 #. Translators: Output stacker number %d
-#: modules/printbackends/gtkprintbackendcups.c:4737
-#, fuzzy, c-format
+#: modules/printbackends/gtkprintbackendcups.c:4736
+#, c-format
 msgctxt "output-bin"
 msgid "Stacker %d"
-msgstr "%'d / %'d"
+msgstr ""
 
 #. Translators: Output mailbox number %d
-#: modules/printbackends/gtkprintbackendcups.c:4741
+#: modules/printbackends/gtkprintbackendcups.c:4740
 #, c-format
 msgctxt "output-bin"
 msgid "Mailbox %d"
 msgstr "पत्रमञ्जूषा %d"
 
 #. Translators: Private mailbox
-#: modules/printbackends/gtkprintbackendcups.c:4745
+#: modules/printbackends/gtkprintbackendcups.c:4744
 msgctxt "output-bin"
 msgid "My Mailbox"
 msgstr "मेरो पत्रमञ्जूषा"
 
 #. Translators: Output tray number %d
-#: modules/printbackends/gtkprintbackendcups.c:4749
-#, fuzzy, c-format
+#: modules/printbackends/gtkprintbackendcups.c:4748
+#, c-format
 msgctxt "output-bin"
 msgid "Tray %d"
-msgstr "निर्गत ट्रे "
+msgstr ""
 
-#: modules/printbackends/gtkprintbackendcups.c:5226
+#: modules/printbackends/gtkprintbackendcups.c:5225
 msgid "Printer Default"
 msgstr "पूर्वानिर्धारण मुद्रण"
 
-#. Translators: These strings name the possible values of the
-#. * job priority option in the print dialog
-#.
-#: modules/printbackends/gtkprintbackendcups.c:5670
-msgid "Urgent"
-msgstr "जरूरी"
-
-#: modules/printbackends/gtkprintbackendcups.c:5670
-msgid "High"
-msgstr "उच्च"
-
-#: modules/printbackends/gtkprintbackendcups.c:5670
-msgid "Medium"
-msgstr "मध्यम"
-
-#: modules/printbackends/gtkprintbackendcups.c:5670
-msgid "Low"
-msgstr "कम"
-
 #. Translators, this string is used to label the job priority option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5700
+#: modules/printbackends/gtkprintbackendcups.c:5704
 msgid "Job Priority"
 msgstr "कार्य प्राथमिकता"
 
 #. Translators, this string is used to label the billing info entry
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5711
+#: modules/printbackends/gtkprintbackendcups.c:5715
 msgid "Billing Info"
 msgstr "बिलिङ सूचना"
 
 #. Translators, these strings are names for various 'standard' cover
 #. * pages that the printing system may support.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5735
+#: modules/printbackends/gtkprintbackendcups.c:5739
 msgctxt "cover page"
 msgid "None"
 msgstr "None"
 
-#: modules/printbackends/gtkprintbackendcups.c:5736
+#: modules/printbackends/gtkprintbackendcups.c:5740
 msgctxt "cover page"
 msgid "Classified"
 msgstr "वर्गीकृत"
 
-#: modules/printbackends/gtkprintbackendcups.c:5737
+#: modules/printbackends/gtkprintbackendcups.c:5741
 msgctxt "cover page"
 msgid "Confidential"
 msgstr "विश्वसनीय"
 
-#: modules/printbackends/gtkprintbackendcups.c:5738
+#: modules/printbackends/gtkprintbackendcups.c:5742
 msgctxt "cover page"
 msgid "Secret"
 msgstr "गोप्य"
 
-#: modules/printbackends/gtkprintbackendcups.c:5739
+#: modules/printbackends/gtkprintbackendcups.c:5743
 msgctxt "cover page"
 msgid "Standard"
 msgstr "मानक"
 
-#: modules/printbackends/gtkprintbackendcups.c:5740
+#: modules/printbackends/gtkprintbackendcups.c:5744
 msgctxt "cover page"
 msgid "Top Secret"
 msgstr "अति गोप्य"
 
-#: modules/printbackends/gtkprintbackendcups.c:5741
+#: modules/printbackends/gtkprintbackendcups.c:5745
 msgctxt "cover page"
 msgid "Unclassified"
 msgstr "वर्गिकृत नगरिएको"
@@ -6589,7 +6954,7 @@ msgstr "वर्गिकृत नगरिएको"
 #. Translators, this string is used to label the pages-per-sheet option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5753
+#: modules/printbackends/gtkprintbackendcups.c:5757
 msgctxt "printer option"
 msgid "Pages per Sheet"
 msgstr "पृष्ठहरू प्रति पाना"
@@ -6597,40 +6962,24 @@ msgstr "पृष्ठहरू प्रति पाना"
 #. Translators, this string is used to label the option in the print
 #. * dialog that controls in what order multiple pages are arranged
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5770
+#: modules/printbackends/gtkprintbackendcups.c:5774
 msgctxt "printer option"
 msgid "Page Ordering"
 msgstr "पृष्ठ क्रमाङ्क"
 
-#. Translators, this is the label used for the option in the print
-#. * dialog that controls the front cover page.
+#. Translators: this is the name of the option that controls when
+#. * a print job is printed. Possible values are 'now', a specified time,
+#. * or 'on hold'
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5812
+#: modules/printbackends/gtkprintbackendcups.c:5851
 msgctxt "printer option"
-msgid "Before"
-msgstr "अगाडि छ"
-
-#. Translators, this is the label used for the option in the print
-#. * dialog that controls the back cover page.
-#.
-#: modules/printbackends/gtkprintbackendcups.c:5827
-msgctxt "printer option"
-msgid "After"
-msgstr "पछि"
-
-#. Translators: this is the name of the option that controls when
-#. * a print job is printed. Possible values are 'now', a specified time,
-#. * or 'on hold'
-#.
-#: modules/printbackends/gtkprintbackendcups.c:5847
-msgctxt "printer option"
-msgid "Print at"
-msgstr "मुद्रण"
+msgid "Print at"
+msgstr "मुद्रण"
 
 #. Translators: this is the name of the option that allows the user
 #. * to specify a time when a print job will be printed.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5858
+#: modules/printbackends/gtkprintbackendcups.c:5862
 msgctxt "printer option"
 msgid "Print at time"
 msgstr "मुद्रण समय"
@@ -6640,253 +6989,1041 @@ msgstr "मुद्रण समय"
 #. * the width and height in points. E.g: "Custom
 #. * 230.4x142.9"
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5905
+#: modules/printbackends/gtkprintbackendcups.c:5909
 #, c-format
 msgid "Custom %s×%s"
 msgstr "अनुकूल %s×%s"
 
 #. TRANSLATORS: this is the ICC color profile to use for this job
-#: modules/printbackends/gtkprintbackendcups.c:6016
+#: modules/printbackends/gtkprintbackendcups.c:6020
 msgctxt "printer option"
 msgid "Printer Profile"
 msgstr "मुद्रण प्रोफाइल"
 
 #. TRANSLATORS: this is when color profile information is unavailable
-#: modules/printbackends/gtkprintbackendcups.c:6023
+#: modules/printbackends/gtkprintbackendcups.c:6027
 msgctxt "printer option value"
 msgid "Unavailable"
 msgstr "अनुपलब्ध"
 
-#: modules/printbackends/gtkprintbackendfile.c:234
+#: modules/printbackends/gtkprintbackendfile.c:263
 msgid "output"
 msgstr "आगत"
 
-#: modules/printbackends/gtkprintbackendfile.c:511
+#: modules/printbackends/gtkprintbackendfile.c:543
 msgid "Print to File"
 msgstr "फाइलमा मुद्रण गर्नुहोस्"
 
-#: modules/printbackends/gtkprintbackendfile.c:637
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PDF"
 msgstr "PDF"
 
-#: modules/printbackends/gtkprintbackendfile.c:637
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PostScript"
 msgstr "पोस्टस्क्रिप्ट"
 
-#: modules/printbackends/gtkprintbackendfile.c:637
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "SVG"
 msgstr "SVG"
 
-#: modules/printbackends/gtkprintbackendfile.c:650
+#: modules/printbackends/gtkprintbackendfile.c:688
 msgid "Pages per _sheet:"
 msgstr "प्रति पाना पृष्ठहरू:"
 
-#: modules/printbackends/gtkprintbackendfile.c:710
+#: modules/printbackends/gtkprintbackendfile.c:758
 msgid "File"
 msgstr "फाइल"
 
-#: modules/printbackends/gtkprintbackendfile.c:720
+#: modules/printbackends/gtkprintbackendfile.c:768
 msgid "_Output format"
 msgstr "निर्गत ढाँचा"
 
-#: modules/printbackends/gtkprintbackendlpr.c:377
-msgid "Print to LPR"
-msgstr "LPR मा मुद्रण गर्नुहोस्"
-
-#: modules/printbackends/gtkprintbackendlpr.c:406
-msgid "Pages Per Sheet"
-msgstr "प्रति पाना पृष्ठहरू"
-
-#: modules/printbackends/gtkprintbackendlpr.c:412
-msgid "Command Line"
-msgstr "आदेश लाइन"
-
 #. TRANSLATORS: when we're running an old CUPS, and
 #. * it hasn't registered the device with colord
-#: modules/printbackends/gtkprintercups.c:275
+#: modules/printbackends/gtkprintercups.c:272
 msgid "Color management unavailable"
 msgstr "रङ व्यवस्थापन अनुपलब्ध"
 
 #. TRANSLATORS: when there is no color profile available
-#: modules/printbackends/gtkprintercups.c:287
+#: modules/printbackends/gtkprintercups.c:284
 msgid "No profile available"
 msgstr "प्रोफाइल उपलब्ध छैन"
 
 #. TRANSLATORS: when the color profile has no title
-#: modules/printbackends/gtkprintercups.c:298
+#: modules/printbackends/gtkprintercups.c:295
 msgid "Unspecified profile"
 msgstr "निर्दिष्ट नगरिएको प्रोफाइल"
 
 #: tools/encodesymbolic.c:41
 msgid "Output to this directory instead of cwd"
-msgstr "cwd को साटोमा यो निर्देशिकामा निर्गत"
+msgstr "यो cwd को साटोमा यो निर्देशिकामा निर्गत"
 
 #: tools/encodesymbolic.c:42
 msgid "Generate debug output"
 msgstr "त्रुटि सच्याउने निर्गत सक्षम पार्नुहोस्"
 
-#: tools/encodesymbolic.c:92
+#: tools/encodesymbolic.c:95
 #, c-format
 msgid "Invalid size %s\n"
 msgstr "अवैध साईज %s\n"
 
-#: tools/encodesymbolic.c:104 tools/encodesymbolic.c:113
+#: tools/encodesymbolic.c:107 tools/encodesymbolic.c:116
 #, c-format
 msgid "Can’t load file: %s\n"
 msgstr "फाइल लोड गर्न सकिँदैन: %s\n"
 
-#: tools/encodesymbolic.c:141 tools/encodesymbolic.c:147
+#: tools/encodesymbolic.c:144 tools/encodesymbolic.c:162
 #, c-format
 msgid "Can’t save file %s: %s\n"
 msgstr "फाइल बचत गर्नसकिएन %s: %s\n"
 
-#: tools/encodesymbolic.c:153
+#: tools/encodesymbolic.c:168
 #, c-format
 msgid "Can’t close stream"
 msgstr "प्रवाह बन्द गर्न सकिँदैन"
 
-#: tools/gtk-builder-tool.c:34
-#, c-format
+#: tools/gtk-builder-tool.c:36
+#, c-format
+#| msgid ""
+#| "Usage:\n"
+#| "  gtk-builder-tool [COMMAND] [OPTION…] FILE\n"
+#| "\n"
+#| "Commands:\n"
+#| "  validate     Validate the file\n"
+#| "  simplify     Simplify the file\n"
+#| "  enumerate    List all named objects\n"
+#| "  preview      Preview the file\n"
+#| "\n"
+#| "Simplify Options:\n"
+#| "  --replace    Replace the file\n"
+#| "  --3to4       Convert from GTK 3 to GTK 4\n"
+#| "\n"
+#| "Preview Options:\n"
+#| "  --id=ID      Preview only the named object\n"
+#| "  --css=FILE   Use style from CSS file\n"
+#| "\n"
+#| "Perform various tasks on GtkBuilder .ui files.\n"
 msgid ""
 "Usage:\n"
-"  gtk-builder-tool [COMMAND] [OPTION…] FILE\n"
+"  gtk4-builder-tool [COMMAND] [OPTION…] FILE\n"
+"\n"
+"Perform various tasks on GtkBuilder .ui files.\n"
 "\n"
 "Commands:\n"
 "  validate     Validate the file\n"
 "  simplify     Simplify the file\n"
 "  enumerate    List all named objects\n"
 "  preview      Preview the file\n"
+"  render       Take a screenshot of the file\n"
+"  screenshot   Take a screenshot of the file\n"
 "\n"
-"Simplify Options:\n"
-"  --replace    Replace the file\n"
-"  --3to4       Convert from GTK 3 to GTK 4\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-enumerate.c:56 tools/gtk-builder-tool-preview.c:179 tools/gtk-builder-tool-preview.c:180 tools/gtk-builder-tool-screenshot.c:360
+#: tools/gtk-builder-tool-simplify.c:2623 tools/gtk-builder-tool-validate.c:261 tools/gtk-image-tool-compare.c:43 tools/gtk-image-tool-info.c:68
+#: tools/gtk-path-tool-render.c:121 tools/gtk-rendernode-tool-compare.c:67 tools/gtk-rendernode-tool-extract.c:294 tools/gtk-rendernode-tool-info.c:226
+#: tools/gtk-rendernode-tool-show.c:116
+msgid "FILE"
+msgstr "FILE"
+
+#: tools/gtk-builder-tool-enumerate.c:64
+msgid "Print all named objects."
+msgstr "सबै नाम करण गरिएका वस्तुहरू मुद्रण गर्नुहोस् ।."
+
+#: tools/gtk-builder-tool-preview.c:128 tools/gtk-builder-tool-screenshot.c:236
+#, c-format
+msgid "No object with ID '%s' found\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-preview.c:130
+#, c-format
+msgid "No previewable object found\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-preview.c:136
+#, c-format
+msgid "Objects of type %s can't be previewed\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-preview.c:178
+msgid "Preview only the named object"
+msgstr ""
+
+#: tools/gtk-builder-tool-preview.c:179 tools/gtk-builder-tool-screenshot.c:360
+msgid "Use style from CSS file"
+msgstr ""
+
+#: tools/gtk-builder-tool-preview.c:187 tools/gtk-builder-tool-screenshot.c:370 tools/gtk-builder-tool-validate.c:268 tools/gtk-rendernode-tool-benchmark.c:108
+#: tools/gtk-rendernode-tool-render.c:262 tools/gtk-rendernode-tool-show.c:123
+#, c-format
+msgid "Could not initialize windowing system\n"
+msgstr "सञ्झ्याल प्रणाली सुरुआत गर्न सकेन\n"
+
+#: tools/gtk-builder-tool-preview.c:195
+#| msgid "Preview text"
+msgid "Preview the file."
+msgstr ""
+
+#: tools/gtk-builder-tool-preview.c:208 tools/gtk-builder-tool-screenshot.c:391 tools/gtk-builder-tool-simplify.c:2646 tools/gtk-builder-tool-validate.c:287
+#, c-format
+msgid "No .ui file specified\n"
+msgstr "कुनै .ui फाइल निर्दिष्ट गरिएको छैन\n"
+
+#: tools/gtk-builder-tool-preview.c:214
+#, c-format
+msgid "Can only preview a single .ui file\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:238
+#, c-format
+msgid "No object found\n"
+msgstr "वस्तु फेला परेन\n"
+
+#: tools/gtk-builder-tool-screenshot.c:244
+#, c-format
+msgid "Objects of type %s can't be screenshot\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:298
+#, c-format
+#| msgid "Failed to write hash table\n"
+msgid "Failed to take a screenshot\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:309
+#, c-format
+msgid ""
+"File %s exists.\n"
+"Use --force to overwrite.\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:332 tools/gtk-rendernode-tool-render.c:230
+#, c-format
+msgid "Output written to %s.\n"
+msgstr "'%s' मा लेखिएको निर्गत ।\n"
+
+#: tools/gtk-builder-tool-screenshot.c:336 tools/gtk-rendernode-tool-render.c:234
+#, c-format
+#| msgid "Failed to open file %s : %s\n"
+msgid "Failed to save %s: %s\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:359
+msgid "Screenshot only the named object"
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:361
+msgid "Save as node file instead of png"
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:362
+#| msgid "Overwrite an existing cache, even if up to date"
+msgid "Overwrite existing file"
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:363 tools/gtk-image-tool-compare.c:46 tools/gtk-image-tool-convert.c:89 tools/gtk-image-tool-relabel.c:86
+#: tools/gtk-image-tool-show.c:119 tools/gtk-rendernode-tool-benchmark.c:99 tools/gtk-rendernode-tool-render.c:255
+msgid "FILE…"
+msgstr "फाईल…"
+
+#: tools/gtk-builder-tool-screenshot.c:378
+msgid "Render a .ui file to an image."
+msgstr ""
+
+#: tools/gtk-builder-tool-screenshot.c:397
+#, c-format
+msgid "Can only render a single .ui file to a single output file\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-simplify.c:444
+#, c-format
+msgid "%s:%d: Couldn’t parse value for property '%s': %s\n"
+msgstr "%s:%d: विशेषता '%s' का लागि मान पद वर्णन गर्न सकेन: %s\n"
+
+#: tools/gtk-builder-tool-simplify.c:658
+#, c-format
+msgid "Property %s not found"
+msgstr ""
+
+#: tools/gtk-builder-tool-simplify.c:661
+#, c-format
+msgid "Packing property %s not found"
+msgstr ""
+
+#: tools/gtk-builder-tool-simplify.c:664
+#, c-format
+msgid "Cell property %s not found"
+msgstr ""
+
+#: tools/gtk-builder-tool-simplify.c:667
+#, c-format
+msgid "Layout property %s not found"
+msgstr ""
+
+#: tools/gtk-builder-tool-simplify.c:1400
+#, c-format
+msgid "%s only accepts three children"
+msgstr ""
+
+#: tools/gtk-builder-tool-simplify.c:1773
+#, c-format
+msgid "%s only accepts one center child"
+msgstr ""
+
+#: tools/gtk-builder-tool-simplify.c:2549
+#, c-format
+msgid "Can’t load “%s”: %s\n"
+msgstr "\"%s\" लोड गर्न सकिँदैन: %s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2560 tools/gtk-builder-tool-simplify.c:2566 tools/gtk-builder-tool-simplify.c:2572
+#, c-format
+msgid "Can’t parse “%s”: %s\n"
+msgstr "\"%s\" पद वर्णन गर्न सकिँदैन: %s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2598
+#, c-format
+msgid "Failed to read “%s”: %s\n"
+msgstr "\"%s\" पढ्न असफल भयो: %s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2604
+#, c-format
+#| msgid "Failed to write %s: “%s”\n"
+msgid "Failed to write “%s”: “%s”\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-simplify.c:2621
+msgid "Replace the file"
+msgstr "फाइल प्रतिस्थापन गर्नुहोस्"
+
+#: tools/gtk-builder-tool-simplify.c:2622
+msgid "Convert from GTK 3 to GTK 4"
+msgstr "GTK 3 बाट GTK 4 मा रूपान्तरण गर्नुहोस्"
+
+#: tools/gtk-builder-tool-simplify.c:2633
+msgid "Simplify the file."
+msgstr "फाइल सरल पार्नुहोस् ।."
+
+#: tools/gtk-builder-tool-simplify.c:2652
+#, c-format
+msgid "Can only simplify a single .ui file without --replace\n"
+msgstr ""
+
+#: tools/gtk-builder-tool-validate.c:45
+#, c-format
+msgid "Failed to lookup template parent type %s\n"
+msgstr "टेम्प्लेट मूल प्रकार %s खोज्न असफल भयो\n"
+
+#: tools/gtk-builder-tool-validate.c:123
+msgid "Deprecated types:\n"
+msgstr "अवमूल्यन गरिएका प्रकारहरू:\n"
+
+#: tools/gtk-builder-tool-validate.c:167
+#, c-format
+msgid "Failed to create an instance of the template type %s\n"
+msgstr "टेम्प्लेट प्रकार %s को दृष्टान्त सिर्जना गर्न असफल भयो\n"
+
+#: tools/gtk-builder-tool-validate.c:276
+msgid "Validate the file."
+msgstr "फाइल प्रमाणित गर्नुहोस् ।."
+
+#: tools/gtk-image-tool.c:36
+#, c-format
+msgid ""
+"Usage:\n"
+"  gtk4-image-tool [COMMAND] [OPTION…] FILE…\n"
 "\n"
-"Preview Options:\n"
-"  --id=ID      Preview only the named object\n"
-"  --css=FILE   Use style from CSS file\n"
+"Perform various tasks on images.\n"
+"\n"
+"Commands:\n"
+"  compare      Show differences between two images\n"
+"  convert      Convert the image to a different format or color state\n"
+"  info         Show general information about the image\n"
+"  relabel      Change the color state of the image without conversion\n"
+"  show         Show the image\n"
 "\n"
-"Perform various tasks on GtkBuilder .ui files.\n"
 msgstr ""
 "प्रयोग:\n"
-"  gtk-builder-tool  [आदेश] [विकल्पहरू...] फाइल\n"
+"जीटीके ४-छवि-उपकरण [COMMAND] [OPTION…] FILE…\n"
+"\n"
+"छविहरूमा विभिन्न कार्यहरू सम्पादन गर्नुहोस् ।\n"
 "\n"
 "आदेश:\n"
-"  प्रमाणिकरण     फाइल लाई प्रमाणित गर्नुहोस्\n"
-"  सरलिकृत     फाइललाई सरलिकृत गर्नुहोस्\n"
-"  इनयुमरेट     सबै नामकरण गरिएको वस्तु कोर्नुहोस्\n"
-"  पूर्वावलोकन     फाइल पूर्वावलोकन पूर्वावलोकन गर्नुहोस्\n"
+"दुई छविहरू बीच भिन्नता देखाउनुहोस् तुलना गर्नुहोस्\n"
+"छविलाई फरक ढाँचा वा रङ स्थितिमा रूपान्तरण गर्नुहोस्\n"
+"जानकारी छविको बारेमा सामान्य जानकारी देखाउनुहोस्\n"
+"पुन: लेबल रूपान्तरण बिना छविको रङ स्थिति परिवर्तन गर्नुहोस्\n"
+"छवि देखाउनुहोस्\n"
+
+#: tools/gtk-image-tool-compare.c:43 tools/gtk-rendernode-tool-compare.c:67
+msgid "Output file"
+msgstr "निर्गत फाइल"
+
+#: tools/gtk-image-tool-compare.c:57
+msgid "Compare two images"
+msgstr "दुई छविहरू तुलना गर्नुहोस्"
+
+#: tools/gtk-image-tool-compare.c:70 tools/gtk-image-tool-convert.c:113 tools/gtk-image-tool-info.c:90 tools/gtk-image-tool-relabel.c:109 tools/gtk-image-tool-show.c:141
+#, c-format
+msgid "No image file specified\n"
+msgstr "छवि फाइल निर्दिष्ट गरिएको छैन\n"
+
+#: tools/gtk-image-tool-compare.c:76
+#, c-format
+msgid "Can only accept two image files\n"
+msgstr "दुई छवि फाइल मात्र स्वीकार गर्न सकिन्छ\n"
+
+#: tools/gtk-image-tool-compare.c:85 tools/gtk-rendernode-tool-compare.c:111
+#, c-format
+msgid "Failed to load %s: %s\n"
+msgstr "%s लोड गर्न असफल भयो: %s\n"
+
+#: tools/gtk-image-tool-compare.c:96 tools/gtk-rendernode-tool-compare.c:122
+#, c-format
+msgid "Could not save diff image to %s\n"
+msgstr "फरक छवि %s मा बचत गर्न सकेन\n"
+
+#: tools/gtk-image-tool-compare.c:106 tools/gtk-rendernode-tool-compare.c:132
+#, c-format
+msgid "Differences witten to %s.\n"
+msgstr "%s मा भिन्नताहरू छन्।\n"
+
+#: tools/gtk-image-tool-compare.c:108 tools/gtk-rendernode-tool-compare.c:134
+#, c-format
+msgid "The images are different.\n"
+msgstr "छविहरू फरक छन्।\n"
+
+#: tools/gtk-image-tool-compare.c:111 tools/gtk-rendernode-tool-compare.c:137
+#, c-format
+msgid "No differences.\n"
+msgstr "कुनै भिन्नता छैन।.\n"
+
+#: tools/gtk-image-tool-convert.c:86
+msgid "Format to use"
+msgstr "प्रयोग गरिने ढाँचा"
+
+#: tools/gtk-image-tool-convert.c:86
+msgid "FORMAT"
+msgstr "ढाँचा"
+
+#: tools/gtk-image-tool-convert.c:87 tools/gtk-image-tool-relabel.c:84
+msgid "Color state to use"
+msgstr "प्रयोग गरिने रङ स्थिति"
+
+#: tools/gtk-image-tool-convert.c:87 tools/gtk-image-tool-relabel.c:84
+#| msgid "COLORS"
+msgid "COLORSTATE"
+msgstr "COLORSTATE"
+
+#: tools/gtk-image-tool-convert.c:88 tools/gtk-image-tool-relabel.c:85
+msgid "Color state to use, as cicp tuple"
+msgstr "प्रयोग गरिने रङ स्थिति, सीआईसीपी टुपलको रूपमा"
+
+#: tools/gtk-image-tool-convert.c:88 tools/gtk-image-tool-relabel.c:85
+msgid "CICP"
+msgstr "CICP"
+
+#: tools/gtk-image-tool-convert.c:100
+msgid "Convert the image to a different format or color state."
+msgstr "छविलाई फरक ढाँचा वा रङ स्थितिमा रूपान्तरण गर्नुहोस् ।."
+
+#: tools/gtk-image-tool-convert.c:119 tools/gtk-image-tool-relabel.c:115
+#, c-format
+msgid "Can only accept a single image file and output file\n"
+msgstr "एकल छवि फाइल र निर्गत फाइल मात्र स्वीकार गर्न सकिन्छ\n"
+
+#: tools/gtk-image-tool-convert.c:133
+#, c-format
+msgid ""
+"Not a memory format: %s\n"
+"Possible values:\n"
+"  %s\n"
+msgstr ""
+
+#: tools/gtk-image-tool-convert.c:150
+#, c-format
+msgid ""
+"Not a color state: %s\n"
+"Possible values:\n"
+"  %s\n"
+msgstr ""
+
+#: tools/gtk-image-tool-convert.c:160 tools/gtk-image-tool-relabel.c:140
+#, c-format
+msgid "Can't specify both --color-state and --cicp\n"
+msgstr ""
+
+#: tools/gtk-image-tool-convert.c:168 tools/gtk-image-tool-relabel.c:148
+#, c-format
+msgid "Not a supported cicp tuple: %s\n"
+msgstr ""
+
+#: tools/gtk-image-tool-info.c:55
+msgid "Format:"
+msgstr "ढाँचा:"
+
+#: tools/gtk-image-tool-info.c:56
+#| msgid "Color Name"
+msgid "Color state:"
+msgstr "रङ स्थिति:"
+
+#: tools/gtk-image-tool-info.c:77
+#| msgid "Could not retrieve information about the file"
+msgid "Provide information about the image."
+msgstr ""
+
+#: tools/gtk-image-tool-info.c:96
+#, fuzzy, c-format
+msgid "Can only accept a single image file\n"
+msgstr "एकल छवि फाइल र निर्गत फाइल मात्र स्वीकार गर्न सकिन्छ\n"
+
+#: tools/gtk-image-tool-relabel.c:96
+#, fuzzy
+msgid "Change the color state of the image without conversion."
+msgstr ""
+"प्रयोग:\n"
+"जीटीके ४-छवि-उपकरण [COMMAND] [OPTION…] FILE…\n"
 "\n"
-"सरलिकृत विकल्पहरू:\n"
-"  --replace    फाइल बदल्नुहोस्\n"
-"  --3to4       GTK ३ बाट GTK ४ मा रुपान्तरण गर्नुहोस्\n"
+"छविहरूमा विभिन्न कार्यहरू सम्पादन गर्नुहोस् ।\n"
 "\n"
-"पूर्वावलोकन विकल्पहरू:\n"
-"  --id=ID      पूर्वावलोकन नामकरण गरिएको वस्तु मात्र\n"
-"  --css=FILE   सीएसएस फाइलबाट शैली प्रयोग गर्नुहोस्\n"
+"आदेश:\n"
+"दुई छविहरू बीच भिन्नता देखाउनुहोस् तुलना गर्नुहोस्\n"
+"छविलाई फरक ढाँचा वा रङ स्थितिमा रूपान्तरण गर्नुहोस्\n"
+"जानकारी छविको बारेमा सामान्य जानकारी देखाउनुहोस्\n"
+"पुन: लेबल रूपान्तरण बिना छविको रङ स्थिति परिवर्तन गर्नुहोस्\n"
+"छवि देखाउनुहोस्\n"
+
+#: tools/gtk-image-tool-relabel.c:130
+#, c-format
+msgid ""
+"Not a color state: %s\n"
+"Possible values: %s\n"
+msgstr ""
+
+#: tools/gtk-image-tool-show.c:117 tools/gtk-rendernode-tool-show.c:115
+msgid "Don't add a titlebar"
+msgstr "शीर्षकपट्टी नथप्नुहोस्"
+
+#: tools/gtk-image-tool-show.c:128
+msgid "Show one or more images."
+msgstr ""
+
+#: tools/gtk-image-tool-utils.c:234
+#, c-format
+msgid "cicp must be 4 numbers, separated by /\n"
+msgstr ""
+
+#: tools/gtk-launch.c:40
+msgid "Show program version"
+msgstr "प्रोग्राम संस्करण देखाउनुहोस्"
+
+#. Translators: this message will appear immediately after the
+#. usage string - Usage: COMMAND [OPTION…] <THIS_MESSAGE>
+#: tools/gtk-launch.c:74
+msgid "APPLICATION [URI…] — launch an APPLICATION"
+msgstr "अनुप्रयोग [URI…] — एउटा अनुप्रयोग सुरुआत गर्नुहोस्"
+
+#. Translators: this message will appear after the usage string
+#. and before the list of options.
+#: tools/gtk-launch.c:78
+msgid ""
+"Launch an application (specified by its desktop file name),\n"
+"optionally passing one or more URIs as arguments."
+msgstr ""
+"एउटा अनुप्रयोग सुरु गर्नुहोस् (यसको डेस्कटप फाइल नाम द्वारा निर्दिष्ट),\n"
+"वैकल्पिक रूपमा तर्कको रूपमा एक वा बढी URI हरू पास गर्दै।."
+
+#: tools/gtk-launch.c:88
+#, c-format
+msgid "Error parsing commandline options: %s\n"
+msgstr "आदेश रेखा विकल्प पार्स गर्दा त्रुटि: %s\n"
+
+#: tools/gtk-launch.c:90 tools/gtk-launch.c:111
+#, c-format
+msgid "Try “%s --help” for more information."
+msgstr "थप जानकारीको लागि '%s --help' प्रयास गर्नुहोस्।."
+
+#. Translators: the %s is the program name. This error message
+#. means the user is calling gtk-launch without any argument.
+#: tools/gtk-launch.c:109
+#, c-format
+msgid "%s: missing application name"
+msgstr "%s: अनुप्रयोग नाम हराइरहेको छ"
+
+#: tools/gtk-launch.c:137
+#, c-format
+msgid "Creating AppInfo from id not supported on non unix operating systems"
+msgstr "गैर-युनिक्स सञ्चालन प्रणालीमा समर्थित नभएको आईडीबाट अनुप्रयोगइन्फो सिर्जना गर्दैछ"
+
+#. Translators: the first %s is the program name, the second one
+#. is the application name.
+#: tools/gtk-launch.c:145
+#, c-format
+msgid "%s: no such application %s"
+msgstr "सन्देश पठाउदा त्रुटि “%s”: %s"
+
+#. Translators: the first %s is the program name, the second one
+#. is the error message.
+#: tools/gtk-launch.c:163
+#, c-format
+msgid "%s: error launching application: %s\n"
+msgstr "%s: अनुप्रयोग सुरुआत गर्दा त्रुटि: %s\n"
+
+#: tools/gtk-path-tool.c:35
+#, c-format
+msgid ""
+"Usage:\n"
+"  gtk4-path-tool [COMMAND] [OPTION…] PATH\n"
+"\n"
+"Perform various tasks on paths.\n"
 "\n"
-"GtkBuilder .ui फाइलमा विभिन्न कार्यहरू सम्पादन गर्नुहोस् ।\n"
+"Commands:\n"
+"  decompose    Decompose the path\n"
+"  reverse      Reverse the path\n"
+"  restrict     Restrict the path to a segment\n"
+"  show         Display the path in a window\n"
+"  render       Render the path as an image\n"
+"  info         Print information about the path\n"
+"\n"
+msgstr ""
+
+#: tools/gtk-path-tool-decompose.c:84
+msgid "Allow quadratic Bézier curves"
+msgstr ""
+
+#: tools/gtk-path-tool-decompose.c:85
+msgid "Allow cubic Bézier curves"
+msgstr ""
+
+#: tools/gtk-path-tool-decompose.c:86
+msgid "Allow conic Bézier curves"
+msgstr ""
+
+#: tools/gtk-path-tool-decompose.c:87 tools/gtk-path-tool-info.c:88 tools/gtk-path-tool-render.c:125 tools/gtk-path-tool-restrict.c:38 tools/gtk-path-tool-reverse.c:34
+#: tools/gtk-path-tool-show.c:147
+msgid "PATH"
+msgstr "मार्ग"
+
+#: tools/gtk-path-tool-decompose.c:99
+msgid "Decompose a path."
+msgstr ""
+
+#: tools/gtk-path-tool-decompose.c:112 tools/gtk-path-tool-info.c:113 tools/gtk-path-tool-restrict.c:64 tools/gtk-path-tool-reverse.c:58
+msgid "No paths given."
+msgstr "कुनै बाटो दिइएको छैन ।."
+
+#: tools/gtk-path-tool-decompose.c:140 tools/gtk-path-tool-restrict.c:94 tools/gtk-path-tool-reverse.c:78
+msgid "That didn't work out."
+msgstr "त्यसले काम गरेन ।."
 
-#: tools/gtk-builder-tool-simplify.c:440
+#: tools/gtk-path-tool-info.c:100
+msgid "Print information about a path."
+msgstr "मार्गको बारेमा सूचना मुद्रण गर्नुहोस् ।."
+
+#: tools/gtk-path-tool-info.c:121
+msgid "Path is empty."
+msgstr "बाटो खाली छ ।."
+
+#: tools/gtk-path-tool-info.c:127
+msgid "Path is closed"
+msgstr "बाटो बन्द गरिएको छ"
+
+#: tools/gtk-path-tool-info.c:129
+msgid "Path length"
+msgstr "मार्ग लम्बाइ"
+
+#: tools/gtk-path-tool-info.c:138
 #, c-format
-msgid "%s:%d: Couldn’t parse value for property '%s': %s\n"
-msgstr "%s:%d: विशेषता '%s' का लागि मान पद वर्णन गर्न सकेन: %s\n"
+msgid "%d contours"
+msgstr ""
 
-#: tools/gtk-builder-tool-simplify.c:649
+#: tools/gtk-path-tool-info.c:140
 #, c-format
-msgid "%s:%d: %sproperty %s::%s not found\n"
-msgstr "%s:%d: %sगुण %s::%s फेला परेन\n"
+msgid "%d operations"
+msgstr "%d सञ्चालन"
 
-#: tools/gtk-builder-tool-simplify.c:2286
+#: tools/gtk-path-tool-info.c:144
 #, c-format
-msgid "Can’t load “%s”: %s\n"
-msgstr "\"%s\" लोड गर्न सकिँदैन: %s\n"
+msgid "%d lines"
+msgstr "%d रेखाहरू"
 
-#: tools/gtk-builder-tool-simplify.c:2297 tools/gtk-builder-tool-simplify.c:2303
+#: tools/gtk-path-tool-info.c:149
 #, c-format
-msgid "Can’t parse “%s”: %s\n"
-msgstr "\"%s\" पद वर्णन गर्न सकिँदैन: %s\n"
+msgid "%d quadratics"
+msgstr "%d चतुर्भुज"
 
-#: tools/gtk-builder-tool-simplify.c:2309
-#, fuzzy, c-format
-#| msgid "Can’t parse “%s”: %s\n"
-msgid "Can’t parse “%s”\n"
-msgstr "\"%s\" पद वर्णन गर्न सकिँदैन: %s\n"
+#: tools/gtk-path-tool-info.c:154
+#, c-format
+msgid "%d cubics"
+msgstr "%d घन"
 
-#: tools/gtk-builder-tool-simplify.c:2333
+#: tools/gtk-path-tool-info.c:159
 #, c-format
-msgid "Failed to read “%s”: %s\n"
-msgstr "\"%s\" पढ्न असफल भयो: %s\n"
+msgid "%d conics"
+msgstr ""
+
+#: tools/gtk-path-tool-render.c:117 tools/gtk-path-tool-show.c:140
+msgid "Fill the path (the default)"
+msgstr "बाटो भर्नुहोस् (पूर्वनिर्धारित)"
+
+#: tools/gtk-path-tool-render.c:118 tools/gtk-path-tool-show.c:141
+msgid "Stroke the path"
+msgstr "बाटो स्ट्रोक गर्नुहोस्"
+
+#: tools/gtk-path-tool-render.c:119 tools/gtk-path-tool-show.c:142
+msgid "Show path points"
+msgstr "बाटो बिन्दु देखाउनुहोस्"
+
+#: tools/gtk-path-tool-render.c:120 tools/gtk-path-tool-show.c:143
+msgid "Show control points"
+msgstr "नियन्त्रण बिन्दु देखाउनुहोस्"
+
+#: tools/gtk-path-tool-render.c:121
+msgid "The output file"
+msgstr "निर्गत फाइल"
+
+#: tools/gtk-path-tool-render.c:122 tools/gtk-path-tool-show.c:144
+msgid "Foreground color"
+msgstr "दृष्य जगतको रङ्ग"
 
-#: tools/gtk-builder-tool-simplify.c:2339
+#: tools/gtk-path-tool-render.c:122 tools/gtk-path-tool-render.c:123 tools/gtk-path-tool-render.c:124 tools/gtk-path-tool-show.c:144 tools/gtk-path-tool-show.c:145
+#: tools/gtk-path-tool-show.c:146
+msgid "COLOR"
+msgstr "रङ्ग"
+
+#: tools/gtk-path-tool-render.c:123 tools/gtk-path-tool-show.c:145
+msgid "Background color"
+msgstr "पृष्ठभूमिको रङ्ग"
+
+#: tools/gtk-path-tool-render.c:124 tools/gtk-path-tool-show.c:146
+msgid "Point color"
+msgstr "बिन्दु रङ"
+
+#: tools/gtk-path-tool-render.c:129 tools/gtk-path-tool-show.c:151
+msgid "Fill rule (winding, even-odd)"
+msgstr "नियम भर्नुहोस् (घुमाउरो, सम-विषम)"
+
+#: tools/gtk-path-tool-render.c:129 tools/gtk-path-tool-render.c:133 tools/gtk-path-tool-render.c:134 tools/gtk-path-tool-render.c:135 tools/gtk-path-tool-render.c:136
+#: tools/gtk-path-tool-render.c:137 tools/gtk-path-tool-render.c:138 tools/gtk-path-tool-show.c:151 tools/gtk-path-tool-show.c:155 tools/gtk-path-tool-show.c:156
+#: tools/gtk-path-tool-show.c:157 tools/gtk-path-tool-show.c:158 tools/gtk-path-tool-show.c:159 tools/gtk-path-tool-show.c:160
+msgid "VALUE"
+msgstr "मान"
+
+#: tools/gtk-path-tool-render.c:133 tools/gtk-path-tool-show.c:155
+msgid "Line width (number)"
+msgstr "रेखा चौडाइ (सङ्ख्या)"
+
+#: tools/gtk-path-tool-render.c:134 tools/gtk-path-tool-show.c:156
+msgid "Line cap (butt, round, square)"
+msgstr "रेखा टोपी (बट, राउन्ड, स्क्वायर)"
+
+#: tools/gtk-path-tool-render.c:135 tools/gtk-path-tool-show.c:157
+msgid "Line join (miter, miter-clip, round, bevel, arcs)"
+msgstr "रेखा सामेल हुनुहोस् (मिटर, मिटर-क्लिप, राउन्ड, बेभेल, आर्क्स)"
+
+#: tools/gtk-path-tool-render.c:136 tools/gtk-path-tool-show.c:158
+msgid "Miter limit (number)"
+msgstr "मिटर सीमा (सङ्ख्या)"
+
+#: tools/gtk-path-tool-render.c:137 tools/gtk-path-tool-show.c:159
+msgid "Dash pattern (comma-separated numbers)"
+msgstr "ड्यास ढाँचा (अल्पविराम-पृथक संख्याहरू)"
+
+#: tools/gtk-path-tool-render.c:138 tools/gtk-path-tool-show.c:160
+msgid "Dash offset (number)"
+msgstr "ड्यास अफसेट (नम्बर)"
+
+#: tools/gtk-path-tool-render.c:161 tools/gtk-path-tool-show.c:172
+msgid "Could not initialize windowing system"
+msgstr "सञ्झ्याल प्रणाली सुरुआत गर्न सकेन"
+
+#: tools/gtk-path-tool-render.c:168
+msgid "Render the path to a png image."
+msgstr "पीएनजी छविमा बाटो रेन्डर गर्नुहोस् ।."
+
+#: tools/gtk-path-tool-render.c:173 tools/gtk-path-tool-show.c:183
+msgid "Options related to filling"
+msgstr "भर्न सँग सम्बन्धित विकल्पहरू"
+
+#: tools/gtk-path-tool-render.c:174 tools/gtk-path-tool-show.c:184
+msgid "Show help for fill options"
+msgstr "भरण विकल्पका लागि मद्दत देखाउनुहोस्"
+
+#: tools/gtk-path-tool-render.c:181 tools/gtk-path-tool-show.c:191
+msgid "Options related to stroking"
+msgstr "स्ट्रोकिङसँग सम्बन्धित विकल्पहरू"
+
+#: tools/gtk-path-tool-render.c:182 tools/gtk-path-tool-show.c:192
+msgid "Show help for stroke options"
+msgstr "स्ट्रोक विकल्पका लागि मद्दत देखाउनुहोस्"
+
+#: tools/gtk-path-tool-render.c:199 tools/gtk-path-tool-show.c:209
+msgid "No path specified"
+msgstr "बाटो निर्दिष्ट गरिएको छैन"
+
+#: tools/gtk-path-tool-render.c:205
+msgid "Can only render a single path"
+msgstr "एउटा मात्र बाटो रेन्डर गर्न सकिन्छ"
+
+#: tools/gtk-path-tool-render.c:250 tools/gtk-path-tool-show.c:221
+msgid "fill rule"
+msgstr "नियम भर्नुहोस्"
+
+#: tools/gtk-path-tool-render.c:255 tools/gtk-path-tool-show.c:226
+msgid "line cap"
+msgstr "लाइन क्याप"
+
+#: tools/gtk-path-tool-render.c:256 tools/gtk-path-tool-show.c:227
+msgid "line join"
+msgstr "रेखा सामेल हुनुहोस्"
+
+#: tools/gtk-path-tool-render.c:310
 #, c-format
-msgid "Failed to write %s: “%s”\n"
+msgid "Saving png to '%s' failed"
+msgstr "'%s' मा पीएनजी बचत गर्न असफल भयो"
+
+#: tools/gtk-path-tool-render.c:317
+#, c-format
+msgid "Output written to '%s'."
+msgstr "निर्गत '%s' मा लेखिएको छ।."
+
+#: tools/gtk-path-tool-restrict.c:36
+msgid "Beginning of segment"
+msgstr "खण्डको सुरुआत"
+
+#: tools/gtk-path-tool-restrict.c:36 tools/gtk-path-tool-restrict.c:37
+msgid "LENGTH"
+msgstr "लम्बाइ"
+
+#: tools/gtk-path-tool-restrict.c:37
+msgid "End of segment"
+msgstr "खण्डको अन्त्य"
+
+#: tools/gtk-path-tool-restrict.c:51
+msgid "Restrict a path to a segment."
+msgstr "खण्डका लागि बाटो सीमित गर्नुहोस् ।."
+
+#: tools/gtk-path-tool-reverse.c:45
+msgid "Reverse a path."
+msgstr "एउटा बाटो उल्टाउनुहोस्।."
+
+#: tools/gtk-path-tool-show.c:46 tools/gtk-path-tool-show.c:88
+msgid "Path Preview"
+msgstr "बाटो पूर्वावलोकन"
+
+#: tools/gtk-path-tool-show.c:180
+msgid "Display the path."
+msgstr "बाटो प्रदर्शन गर्नुहोस् ।."
+
+#: tools/gtk-path-tool-show.c:215
+msgid "Can only show a single path"
+msgstr "एउटा मात्र बाटो देखाउन सकिन्छ"
+
+#: tools/gtk-path-tool-utils.c:58
+#, c-format
+msgid "Failed to read from standard input: %s\n"
+msgstr "मानक आगतबाट पढ्न असफल भयो: %s\n"
+
+#: tools/gtk-path-tool-utils.c:64
+#, c-format
+msgid "Error reading from standard input: %s\n"
 msgstr ""
-"\"%s\" लेख्न असफल भयो: %s\n"
+"मानक आगतबाट पढ्दा त्रुटि: %s\n"
 "\n"
 
-#: tools/gtk-builder-tool-simplify.c:2379
+#: tools/gtk-path-tool-utils.c:83
 #, c-format
-msgid "No .ui file specified\n"
-msgstr "कुनै .ui फाइल निर्दिष्ट गरिएको छैन\n"
+msgid "Failed to parse '%s' as path.\n"
+msgstr ""
+"बाटोको रूपमा '%s' पद वर्णन गर्न असफल भयो ।\n"
+"\n"
 
-#: tools/gtk-builder-tool-simplify.c:2385
+#: tools/gtk-path-tool-utils.c:109
 #, c-format
-msgid "Can only simplify a single .ui file without --replace\n"
+msgid "Failed to parse '%s' as %s."
+msgstr "'%s' लाई %s को रूपमा पद वर्णन गर्न असफल भयो."
+
+#: tools/gtk-path-tool-utils.c:111
+msgid "Possible values: "
+msgstr "संभाव्य मान: "
+
+#: tools/gtk-path-tool-utils.c:135
+#, c-format
+msgid "Could not parse '%s' as color"
+msgstr "रङको रूपमा '%s' पद वर्णन गर्न सकेन"
+
+#: tools/gtk-path-tool-utils.c:163
+#, c-format
+msgid "Failed to parse '%s' as number"
+msgstr "सङ्ख्याको रूपमा '%s' पद वर्णन गर्न असफल भयो"
+
+#: tools/gtk-rendernode-tool.c:35
+#, c-format
+msgid ""
+"Usage:\n"
+"  gtk4-rendernode-tool [COMMAND] [OPTION…] FILE\n"
+"\n"
+"Perform various tasks on GTK render nodes.\n"
+"\n"
+"Commands:\n"
+"  benchmark    Benchmark rendering of a node\n"
+"  compare      Compare nodes or images\n"
+"  extract      Extract data urls\n"
+"  info         Provide information about the node\n"
+"  show         Show the node\n"
+"  render       Take a screenshot of the node\n"
+"\n"
+msgstr ""
+
+#: tools/gtk-rendernode-tool-benchmark.c:96
+msgid "Add renderer to benchmark"
+msgstr "बेन्चमार्कमा रेन्डरर थप्नुहोस्"
+
+#: tools/gtk-rendernode-tool-benchmark.c:96 tools/gtk-rendernode-tool-compare.c:65 tools/gtk-rendernode-tool-render.c:254
+msgid "RENDERER"
+msgstr "रेन्डरर"
+
+#: tools/gtk-rendernode-tool-benchmark.c:97
+msgid "Number of runs with each renderer"
+msgstr "प्रत्येक रेन्डररसँग रनको सङ्ख्या"
+
+#: tools/gtk-rendernode-tool-benchmark.c:97
+msgid "RUNS"
+msgstr "चल्ने आदेश"
+
+#: tools/gtk-rendernode-tool-benchmark.c:98
+msgid "Don’t download result/wait for GPU to finish"
+msgstr ""
+
+#: tools/gtk-rendernode-tool-benchmark.c:116
+msgid "Benchmark rendering of a .node file."
+msgstr ""
+
+#: tools/gtk-rendernode-tool-benchmark.c:129 tools/gtk-rendernode-tool-extract.c:316 tools/gtk-rendernode-tool-info.c:248 tools/gtk-rendernode-tool-render.c:283
+#: tools/gtk-rendernode-tool-show.c:144
+#, c-format
+msgid "No .node file specified\n"
+msgstr "कुनै  .node फाइल निर्दिष्ट गरिएको छैन\n"
+
+#: tools/gtk-rendernode-tool-benchmark.c:135
+#, c-format
+msgid "Can only benchmark a single .node file\n"
+msgstr ""
+
+#: tools/gtk-rendernode-tool-compare.c:65 tools/gtk-rendernode-tool-render.c:254
+#| msgid "Renderer"
+msgid "Renderer to use"
+msgstr ""
+
+#: tools/gtk-rendernode-tool-compare.c:70
+msgid "FILE1 FILE2"
+msgstr "FILE1 FILE2"
+
+#: tools/gtk-rendernode-tool-compare.c:82
+msgid "Compare .node or .png files."
 msgstr ""
 
-#: tools/gtk-launch.c:40
-msgid "Show program version"
-msgstr "प्रोग्राम संस्करण देखाउनुहोस्।."
+#: tools/gtk-rendernode-tool-compare.c:95
+#, c-format
+msgid "Must specify two files\n"
+msgstr "दुई फाइल निर्दिष्ट गर्नुपर्दछ\n"
+
+#: tools/gtk-rendernode-tool-compare.c:102 tools/gtk-rendernode-tool-render.c:209
+#, c-format
+msgid "Failed to create renderer: %s\n"
+msgstr "रेन्डरर सिर्जना गर्न असफल: %s\n"
+
+#: tools/gtk-rendernode-tool-extract.c:73 tools/gtk-rendernode-tool-extract.c:149
+#, c-format
+msgid "Failed to write %s\n"
+msgstr "%s लेख्न असफल भयो\n"
+
+#: tools/gtk-rendernode-tool-extract.c:292
+msgid "Directory to use"
+msgstr "प्रयोग गरिने डाइरेक्टरी"
+
+#: tools/gtk-rendernode-tool-extract.c:292
+msgid "DIRECTORY"
+msgstr "निर्देशिका"
+
+#: tools/gtk-rendernode-tool-extract.c:293
+#, fuzzy
+msgid "Be verbose"
+msgstr "भर्बोज निर्गत सक्षम पार्नुहोस्"
+
+#: tools/gtk-rendernode-tool-extract.c:303
+msgid "Extract data urls from the render node."
+msgstr ""
+
+#: tools/gtk-rendernode-tool-extract.c:322 tools/gtk-rendernode-tool-info.c:254
+#, c-format
+msgid "Can only accept a single .node file\n"
+msgstr ""
+
+#: tools/gtk-rendernode-tool-info.c:193
+msgid "Number of nodes:"
+msgstr "नोड्सको सङ्ख्या:"
+
+#: tools/gtk-rendernode-tool-info.c:200
+msgid "Depth:"
+msgstr "गहिराइ:"
+
+#: tools/gtk-rendernode-tool-info.c:203
+msgid "Bounds:"
+msgstr "सीमा:"
+
+#: tools/gtk-rendernode-tool-info.c:204
+msgid "Origin:"
+msgstr "मूलमा:"
+
+#: tools/gtk-rendernode-tool-info.c:208 tools/gtk-rendernode-tool-info.c:214
+msgid "Opaque part:"
+msgstr ""
 
-#. Translators: this message will appear immediately after the
-#. usage string - Usage: COMMAND [OPTION…] <THIS_MESSAGE>
-#: tools/gtk-launch.c:72
-msgid "APPLICATION [URI…] — launch an APPLICATION"
-msgstr "अनुप्रयोग [URI…] — एउटा अनुप्रयोग सुरुआत गर्नुहोस्"
+#: tools/gtk-rendernode-tool-info.c:235
+#| msgid "Could not retrieve information about the file"
+msgid "Provide information about the render node."
+msgstr ""
 
-#. Translators: this message will appear after the usage string
-#. and before the list of options.
-#: tools/gtk-launch.c:76
+#: tools/gtk-rendernode-tool-render.c:170
+#, c-format
 msgid ""
-"Launch an application (specified by its desktop file name),\n"
-"optionally passing one or more URIs as arguments."
+"File %s exists.\n"
+"If you want to overwrite, specify the filename.\n"
 msgstr ""
 
-#: tools/gtk-launch.c:86
+#: tools/gtk-rendernode-tool-render.c:184 tools/gtk-rendernode-tool-render.c:196
 #, c-format
-msgid "Error parsing commandline options: %s\n"
-msgstr "आदेश रेखा विकल्प पार्स गर्दा त्रुटि: %s\n"
+#| msgid "Failed to open file %s : %s\n"
+msgid "Failed to generate SVG: %s\n"
+msgstr ""
 
-#: tools/gtk-launch.c:88 tools/gtk-launch.c:109
-#, c-format
-msgid "Try “%s --help” for more information."
-msgstr "थप जानकारीको लागि '%s --help' प्रयास गर्नुहोस्।"
+#: tools/gtk-rendernode-tool-render.c:270
+msgid "Render a .node file to an image."
+msgstr "छविमा .node फाइल रेन्डर गर्नुहोस् ।."
 
-#. Translators: the %s is the program name. This error message
-#. means the user is calling gtk-launch without any argument.
-#: tools/gtk-launch.c:107
+#: tools/gtk-rendernode-tool-render.c:289
 #, c-format
-msgid "%s: missing application name"
-msgstr "%s: अनुप्रयोग नाम हराइरहेको छ"
+msgid "Can only render a single .node file to a single output file\n"
+msgstr "एकल निर्गत फाइलमा एकल.node फाइल मात्र रेन्डर गर्न सकिन्छ\n"
 
-#: tools/gtk-launch.c:136
+#: tools/gtk-rendernode-tool-show.c:131
+msgid "Show the render node."
+msgstr "रेन्डर नोड देखाउनुहोस् ।."
+
+#: tools/gtk-rendernode-tool-show.c:150
 #, c-format
-msgid "Creating AppInfo from id not supported on non unix operating systems"
-msgstr ""
+msgid "Can only preview a single .node file\n"
+msgstr "एकल .node फाइल मात्र पूर्वावलोकन गर्न सकिन्छ\n"
 
-#. Translators: the first %s is the program name, the second one
-#. is the application name.
-#: tools/gtk-launch.c:144
+#: tools/gtk-rendernode-tool-utils.c:54
 #, c-format
-msgid "%s: no such application %s"
-msgstr "सन्देश पठाउदा त्रुटि “%s”: %s"
+msgid "Error at %s: %s\n"
+msgstr "%s खोल्दा त्रुटि: %s\n"
 
-#. Translators: the first %s is the program name, the second one
-#. is the error message.
-#: tools/gtk-launch.c:162
+#: tools/gtk-rendernode-tool-utils.c:72
 #, c-format
-msgid "%s: error launching application: %s\n"
-msgstr "%s: अनुप्रयोग सुरुआत गर्दा त्रुटि: %s\n"
+msgid "Failed to load node file: %s\n"
+msgstr "नोड फाइल लोड गर्न असफल: %s\n"
 
 #: tools/updateiconcache.c:1391
 #, c-format
@@ -6938,55 +8075,55 @@ msgstr "%s लाई %s पुन: नामाकरण गर्न सके
 msgid "Could not rename %s back to %s: %s.\n"
 msgstr "%sलाई %s मा पुन: नामकरण गर्न सकेन: %s.\n"
 
-#: tools/updateiconcache.c:1618
+#: tools/updateiconcache.c:1614
 #, c-format
 msgid "Cache file created successfully.\n"
 msgstr "क्याश फाइल सफलतापूर्वक सिर्जना गरियो ।\n"
 
-#: tools/updateiconcache.c:1657
+#: tools/updateiconcache.c:1653
 msgid "Overwrite an existing cache, even if up to date"
 msgstr "एउटा अवस्थित क्याशलाई अधिलेखन गर्नुहोस्, यदि अद्यावधिक भए पनि"
 
-#: tools/updateiconcache.c:1658
+#: tools/updateiconcache.c:1654
 msgid "Don’t check for the existence of index.theme"
 msgstr "अवस्थित index.theme को लागि जाँच नगर्नुहोस्"
 
-#: tools/updateiconcache.c:1659
+#: tools/updateiconcache.c:1655
 msgid "Don’t include image data in the cache"
 msgstr "क्याशमा छवि डेटा समावेश नगर्नुहोस्"
 
-#: tools/updateiconcache.c:1660
+#: tools/updateiconcache.c:1656
 msgid "Include image data in the cache"
 msgstr "क्याशमा छवि डेटा समावेश गर्नुहोस्"
 
-#: tools/updateiconcache.c:1661
+#: tools/updateiconcache.c:1657
 msgid "Output a C header file"
 msgstr "सी हेडर फाइल निर्गत गर्नुहोस्"
 
-#: tools/updateiconcache.c:1662
+#: tools/updateiconcache.c:1658
 msgid "Turn off verbose output"
 msgstr "भरबोस निर्गत बन्द गर्नुहोस्"
 
-#: tools/updateiconcache.c:1663
+#: tools/updateiconcache.c:1659
 msgid "Validate existing icon cache"
 msgstr "अवस्थित प्रतिमा क्याश प्रमाणीत गर्नुहोस्"
 
-#: tools/updateiconcache.c:1728
+#: tools/updateiconcache.c:1725
 #, c-format
 msgid "File not found: %s\n"
 msgstr "फाइल फेला परेन: %s\n"
 
-#: tools/updateiconcache.c:1734
+#: tools/updateiconcache.c:1731
 #, c-format
 msgid "Not a valid icon cache: %s\n"
 msgstr "वैध प्रतिमा क्याश होइन: %s\n"
 
-#: tools/updateiconcache.c:1747
+#: tools/updateiconcache.c:1744
 #, c-format
 msgid "No theme index file.\n"
 msgstr "विषयवस्तु अनुक्रमणिका फाइल होइन ।\n"
 
-#: tools/updateiconcache.c:1751
+#: tools/updateiconcache.c:1748
 #, fuzzy, c-format
 msgid ""
 "No theme index file in “%s”.\n"
@@ -6995,6 +8132,182 @@ msgstr ""
 "'%s' मा विषयवस्तु अनुक्रमाणिका फाइल छैन ।\n"
 "यदि तपाईँ यहाँ साँच्चै एउटा प्रतिमा क्याश सिर्जना गर्न चाहनुहुन्छ भने, --ignore-theme-index प्रयोग गर्नुहोस् ।\n"
 
+#~ msgid "Other application…"
+#~ msgstr "अन्य अनुप्रयोग…"
+
+#~ msgid "Default Application"
+#~ msgstr "पूर्वनिर्धारित अनुप्रयोग"
+
+#~ msgid "Show _Size Column"
+#~ msgstr "स्तम्भ आकार देखाउनुस्"
+
+#~ msgid "Show T_ype Column"
+#~ msgstr "स्तम्भ प्रकार देखाउनुस्"
+
+#~ msgid "Number Formatting"
+#~ msgstr "संख्या ढाँचाबद्धता"
+
+#~ msgid "default:LTR"
+#~ msgstr "default:LTR"
+
+#~ msgid "Tab list"
+#~ msgstr "ट्याब सूची"
+
+#~ msgid "Tab"
+#~ msgstr "ट्याब"
+
+#~ msgctxt "GL version"
+#~ msgid "Disabled"
+#~ msgstr "असक्षम पारिएको छ"
+
+#~ msgctxt "GL vendor"
+#~ msgid "Disabled"
+#~ msgstr "असक्षम पारिएको छ"
+
+#~ msgctxt "GL vendor"
+#~ msgid "None"
+#~ msgstr "None"
+
+#~ msgid "Allocation"
+#~ msgstr "निर्धारण"
+
+#, fuzzy
+#~ msgid "Backend does not support window scaling"
+#~ msgstr "हालको ब्याकइन्डले OpenGL समर्थन गर्दैन"
+
+#~ msgid "GL rendering is disabled"
+#~ msgstr "जिएल रेन्डरिङ असक्षम पारिएको"
+
+#~ msgid "Window Scaling"
+#~ msgstr "सञ्झ्याल मापन"
+
+#, fuzzy
+#~ msgid "Show fps overlay"
+#~ msgstr "माथि राखिने वस्तु"
+
+#, fuzzy
+#~ msgid "Simulate Touchscreen"
+#~ msgstr "एउटा इनग्रार्भिङ अभिलेख नक्कल गर्नुहोस्"
+
+#~ msgid "Software GL"
+#~ msgstr "सफ्टवेयर GL"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 1"
+#~ msgstr "शैलीगत सेट "
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 2"
+#~ msgstr "शैलीगत सेट २"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 3"
+#~ msgstr "शैलीगत सेट ३"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 4"
+#~ msgstr "शैलीगत सेट ४"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 5"
+#~ msgstr "शैलीगत सेट ५"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 6"
+#~ msgstr "शैलीगत सेट ६"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 7"
+#~ msgstr "शैलीगत सेट ७"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 8"
+#~ msgstr "शैलीगत सेट ८"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 9"
+#~ msgstr "शैलीगत सेट ९"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 10"
+#~ msgstr "शैलीगत सेट १०"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 11"
+#~ msgstr "शैलीगत सेट ११"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 12"
+#~ msgstr "शैलीगत सेट १२"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 13"
+#~ msgstr "शैलीगत सेट १३"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 14"
+#~ msgstr "शैलीगत सेट १४"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 15"
+#~ msgstr "शैलीगत सेट १५"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 16"
+#~ msgstr "शैलीगत सेट १६"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 17"
+#~ msgstr "शैलीगत सेट १७"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 18"
+#~ msgstr "शैलीगत सेट १८"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 19"
+#~ msgstr "शैलीगत सेट १९"
+
+#~ msgctxt "OpenType layout"
+#~ msgid "Stylistic Set 20"
+#~ msgstr "शैलीगत सेट २०"
+
+#, fuzzy, c-format
+#~| msgid "Unspecified error"
+#~ msgid "Unspecified error decoding video"
+#~ msgstr "निर्दिष्ट नगरिएको त्रुटि"
+
+#~ msgid "Not enough memory"
+#~ msgstr "प्रशस्त स्मृति छैन"
+
+#, fuzzy
+#~| msgid "Not a valid page setup file"
+#~ msgid "Not a video file"
+#~ msgstr "भिडियो फाइललाई MPEG2 मा रूपान्तरण गर्दैछ"
+
+#, fuzzy
+#~| msgid "Unsupported icon type"
+#~ msgid "Unsupported video codec"
+#~ msgstr "कोडेक:"
+
+#~ msgid "Print to LPR"
+#~ msgstr "LPR मा मुद्रण गर्नुहोस्"
+
+#~ msgid "Pages Per Sheet"
+#~ msgstr "प्रति पाना पृष्ठहरू"
+
+#~ msgid "Command Line"
+#~ msgstr "आदेश लाइन"
+
+#, c-format
+#~ msgid "%s:%d: %sproperty %s::%s not found\n"
+#~ msgstr "%s:%d: %sगुण %s::%s फेला परेन\n"
+
+#, fuzzy, c-format
+#~| msgid "Can’t parse “%s”: %s\n"
+#~ msgid "Can’t parse “%s”\n"
+#~ msgstr "\"%s\" पद वर्णन गर्न सकिँदैन: %s\n"
+
 #~ msgid "Show text"
 #~ msgstr "पाठ देखाऊ"
 
@@ -7238,10 +8551,6 @@ msgstr ""
 #~ msgid "Unknown"
 #~ msgstr "अज्ञात"
 
-#~ msgctxt "Script"
-#~ msgid "Balinese"
-#~ msgstr "बालिनिज"
-
 #~ msgctxt "Script"
 #~ msgid "Cuneiform"
 #~ msgstr "क्युनिफोर्म"
@@ -7566,312 +8875,9 @@ msgstr ""
 #~ msgid "Khitan small script"
 #~ msgstr "खिताङ सानो लिपि"
 
-#~ msgid "About"
-#~ msgstr "बारेमा"
-
-#~ msgid "Credits"
-#~ msgstr "श्रेयहरू"
-
-#~ msgid "System"
-#~ msgstr "प्रणाली"
-
-#~ msgid "_View All Applications"
-#~ msgstr "सबै अनुप्रयोगहरू हेर्नुहोस्"
-
-#~ msgid "_Find New Applications"
-#~ msgstr "नयाँ अनुप्रयोग फेला पार्ने"
-
-#~ msgid "No applications found."
-#~ msgstr "अनुप्रयोग पाईएन."
-
-#~ msgid "_Finish"
-#~ msgstr "समाप्त (_F)"
-
-#~ msgid "_Back"
-#~ msgstr "पछाडि"
-
-#~ msgid "_Next"
-#~ msgstr "_पछिल्लो"
-
-#~ msgid "Select a Color"
-#~ msgstr "रङ्ग चयन गर्नुहोस्"
-
-#~ msgid "Pick a color from the screen"
-#~ msgstr "पर्दाबाट रङ लिनुहोस्"
-
-#, fuzzy
-#~ msgid "Hexadecimal color or color name"
-#~ msgstr "रङ नाम:"
-
-#~ msgid "Hue"
-#~ msgstr "ह्यु"
-
-#~ msgid "Alpha value"
-#~ msgstr "अल्फा मान"
-
-#, fuzzy
-#~| msgid "Saturation"
-#~ msgid "Saturation and value"
-#~ msgstr "अतितृप्ति:"
-
-#~ msgctxt "Color channel"
-#~ msgid "A"
-#~ msgstr "A"
-
-#~ msgctxt "Color channel"
-#~ msgid "H"
-#~ msgstr "H"
-
-#~ msgctxt "Color Channel"
-#~ msgid "S"
-#~ msgstr "S"
-
-#~ msgctxt "Color Channel"
-#~ msgid "V"
-#~ msgstr "V"
-
-#~ msgid "(None)"
-#~ msgstr "(कुनै पनि होइन)"
-
-#, fuzzy
-#~| msgid "Search"
-#~ msgid "Search…"
-#~ msgstr "खोजी गर्नुहोस्:"
-
-#~ msgctxt "emoji category"
-#~ msgid "Smileys & People"
-#~ msgstr "स्माइलीहरू र मानव"
-
-#~ msgctxt "emoji category"
-#~ msgid "Body & Clothing"
-#~ msgstr "शरिर र लुगा"
-
-#~ msgctxt "emoji category"
-#~ msgid "Animals & Nature"
-#~ msgstr "प्रकृति र जनावर"
-
-#~ msgctxt "emoji category"
-#~ msgid "Food & Drink"
-#~ msgstr "खाद्य र पेय"
-
-#~ msgctxt "emoji category"
-#~ msgid "Travel & Places"
-#~ msgstr "यात्रा र स्थानहरू"
-
-#~ msgctxt "emoji category"
-#~ msgid "Activities"
-#~ msgstr "गतिविधिहरू"
-
-#~ msgctxt "emoji category"
-#~ msgid "Objects"
-#~ msgstr "वस्तुहरू"
-
-#~ msgctxt "emoji category"
-#~ msgid "Symbols"
-#~ msgstr "प्रतीक"
-
-#~ msgctxt "emoji category"
-#~ msgid "Flags"
-#~ msgstr "झन्डा"
-
-#~ msgctxt "emoji category"
-#~ msgid "Recent"
-#~ msgstr "हालसालै"
-
-#~ msgid "Create Folder"
-#~ msgstr "फोल्डर सिर्जना गर्नुहोस्"
-
-#~ msgid "Remote location — only searching the current folder"
-#~ msgstr "टाढाको स्थान — हालको फोल्डरमात्र खोजी गरिरहेको"
-
-#~ msgid "Folder Name"
-#~ msgstr "फोल्डरको नाम"
-
-#~ msgid "_Create"
-#~ msgstr "सिर्जना गर्नुहोस्"
-
-#~ msgid "Select Font"
-#~ msgstr "फन्ट चयन गर्नुहोस्"
-
-#~ msgid "Search font name"
-#~ msgstr "फन्ट नाम खोज्नुहोस्"
-
-#~ msgid "Filter by"
-#~ msgstr "यसद्वारा फिल्टर"
-
-#~ msgid "Monospace"
-#~ msgstr "मोनोस्पेस"
-
-#~ msgid "Language"
-#~ msgstr "भाषा"
-
-#~ msgid "Preview text"
-#~ msgstr "पाठको पूर्वदृश्य हो"
-
 #~ msgid "horizontal"
 #~ msgstr "तेर्सो"
 
-#~ msgid "No Fonts Found"
-#~ msgstr "फन्टहरू फेला परेन"
-
-#~ msgid "_Format for:"
-#~ msgstr "यसका लागि ढाँचा:"
-
-#~ msgid "_Paper size:"
-#~ msgstr "कागज साइज:"
-
-#~ msgid "_Orientation:"
-#~ msgstr "अभिमूखीकरण:"
-
-#~ msgid "Server Addresses"
-#~ msgstr "सर्भर ठेगानाहरू"
-
-#~ msgid "Server addresses are made up of a protocol prefix and an address. Examples:"
-#~ msgstr "सर्भर ठेगाना प्रोटोकल उपसर्ग र ठेगानाबाट बनेको हुन्छ । उदाहरण:"
-
-#~ msgid "Available Protocols"
-#~ msgstr "उपलब्ध प्रोटोकल"
-
-#~ msgid "No recent servers found"
-#~ msgstr "हालको सर्भर भेटिएन"
-
-#~ msgid "Recent Servers"
-#~ msgstr "हालको सर्भर"
-
-#~ msgid "No results found"
-#~ msgstr "नतिजा भेटिएन"
-
-#~ msgid "Connect to _Server"
-#~ msgstr "सर्भरमा जडान गर्नुहोस्"
-
-#~ msgid "Enter server address…"
-#~ msgstr "सर्भर ठेगाना प्रवेश गर्नुहोस्…"
-
-#~ msgid "Status"
-#~ msgstr "वस्तुस्थिति"
-
-#~ msgid "Range"
-#~ msgstr "दायरा"
-
-#~ msgid "_All Pages"
-#~ msgstr "सबै पृष्ठहरू"
-
-#~ msgid "C_urrent Page"
-#~ msgstr "हालको पृष्ठ"
-
-#~ msgid "Se_lection"
-#~ msgstr "चयन"
-
-#~ msgid "Pag_es:"
-#~ msgstr "पृष्ठहरू:"
-
-#~ msgid ""
-#~ "Specify one or more page ranges,\n"
-#~ " e.g. 1–3, 7, 11"
-#~ msgstr ""
-#~ "एक वा बढी पृष्ठ दायरा निर्दिष्ट गर्नुहोस्,\n"
-#~ " जस्तै: १–३, ७, ११"
-
-#~ msgid "Copies"
-#~ msgstr "प्रतिलिपिहरू"
-
-#~ msgid "Copie_s:"
-#~ msgstr "प्रतिलिपिहरू:"
-
-#~ msgid "C_ollate"
-#~ msgstr "कोलेट गर्नुहोस्"
-
-#~ msgid "_Reverse"
-#~ msgstr "फर्काउनुहोस्"
-
-#~ msgid "General"
-#~ msgstr "सामान्य"
-
-#~ msgid "T_wo-sided:"
-#~ msgstr "दुई-किनारा भएको:"
-
-#~ msgid "Pages per _side:"
-#~ msgstr "प्रति किनारा पृष्ठहरू:"
-
-#~ msgid "Page or_dering:"
-#~ msgstr "पृष्ठ क्रम:"
-
-#~ msgid "_Only print:"
-#~ msgstr "मुद्रण मात्र:"
-
-#~ msgid "Sc_ale:"
-#~ msgstr "मापन गर्नुहोस्:"
-
-#~ msgid "Paper"
-#~ msgstr "कागज"
-
-#~ msgid "Paper _type:"
-#~ msgstr "कागज प्रकार:"
-
-#~ msgid "Paper _source:"
-#~ msgstr "कागज स्रोत:"
-
-#~ msgid "Output t_ray:"
-#~ msgstr "निर्गत ट्रे:"
-
-#~ msgid "Or_ientation:"
-#~ msgstr "अभीमुखिकरण:"
-
-#~ msgid "Job Details"
-#~ msgstr "कार्य विवरणहरू"
-
-#~ msgid "Pri_ority:"
-#~ msgstr "प्राथमिकता:"
-
-#~ msgid "_Billing info:"
-#~ msgstr "बिलिङ सूचना:"
-
-#~ msgid "Print Document"
-#~ msgstr "कागजात मुद्रण गर्नुहोस्"
-
-#~ msgid "_Now"
-#~ msgstr "अहिले"
-
-#~ msgid "A_t:"
-#~ msgstr "मा:"
-
-#~ msgid ""
-#~ "Specify the time of print,\n"
-#~ " e.g. 15∶30, 2∶35 pm, 14∶15∶20, 11∶46∶30 am, 4 pm"
-#~ msgstr ""
-#~ "मुद्रणको समय निर्दिष्ट गर्नुहोस्\n"
-#~ "  जस्तै: १५:३०,२:३५ पिएम, १४:१५:२०, ११:४६:३० एएम, ४ पिएम"
-
-#~ msgid "On _hold"
-#~ msgstr "व्यस्त छ"
-
-#~ msgid "Add Cover Page"
-#~ msgstr "आवरण पृष्ठ थप्नुहोस्"
-
-#~ msgid "Be_fore:"
-#~ msgstr "अगाडि:"
-
-#~ msgid "_After:"
-#~ msgstr "पछि:"
-
-#~ msgid "Job"
-#~ msgstr "काम"
-
-#~ msgid "Image Quality"
-#~ msgstr "छवि गुणस्तर"
-
-#~ msgid "Color"
-#~ msgstr "रङ्ग"
-
-#~ msgid "Finishing"
-#~ msgstr "सकिदै"
-
-#~ msgid "Advanced"
-#~ msgstr "उन्नत"
-
-#~ msgid "Some of the settings in the dialog conflict"
-#~ msgstr "संवाद द्वन्द्वमा केही सेटिङहरू"
-
 #~ msgid "Online"
 #~ msgstr "अनलाइन"
 
@@ -7901,9 +8907,6 @@ msgstr ""
 #~ msgid "Size of the palette in 8 bit mode"
 #~ msgstr "८ बिट मोडमा रङदानीको साइज"
 
-#~ msgid "COLORS"
-#~ msgstr "COLORS"
-
 #, fuzzy
 #~ msgctxt "Action description"
 #~ msgid "Toggles the cell"
@@ -8098,10 +9101,6 @@ msgstr ""
 #~ msgid "P_ause"
 #~ msgstr "%p"
 
-#~ msgctxt "Stock label, media"
-#~ msgid "_Play"
-#~ msgstr "प्ले गर्नुहोस्"
-
 #, fuzzy
 #~ msgctxt "Stock label, media"
 #~ msgid "_Record"
@@ -8132,10 +9131,6 @@ msgstr ""
 #~ msgid "_Print"
 #~ msgstr "मुद्रण गर्नुहोस्"
 
-#~ msgctxt "Stock label"
-#~ msgid "Print Pre_view"
-#~ msgstr "मुद्रण पूर्वावलोकन"
-
 #~ msgctxt "Stock label"
 #~ msgid "_Properties"
 #~ msgstr "गुणहरू"
@@ -8254,14 +9249,6 @@ msgstr ""
 #~ msgid "Forget association"
 #~ msgstr "संघ"
 
-#, fuzzy
-#~ msgid "Packing property %s::%s not found\n"
-#~ msgstr "'%s' गुण लेख्न योग्य छैन:%s"
-
-#, fuzzy
-#~ msgid "Cell property %s::%s not found\n"
-#~ msgstr "कक्ष %s मा लक्ष्य खोज्नेले एउटा समाधान फेला पार्यो।"
-
 #~ msgctxt "year measurement template"
 #~ msgid "2000"
 #~ msgstr "२०००"
@@ -8344,9 +9331,6 @@ msgstr ""
 #~ msgid "Lighter Gray"
 #~ msgstr "बढी उज्यालो:"
 
-#~ msgid "Custom color"
-#~ msgstr "अनुकूल रङ्ग"
-
 #, fuzzy
 #~ msgid "Create a custom color"
 #~ msgstr "अनुकूल रङ जस्तै"
@@ -8379,18 +9363,8 @@ msgstr ""
 #~ msgid "Paste"
 #~ msgstr "टाँस्नुहोस्"
 
-#~ msgid "Select a File"
-#~ msgstr "एउटा फाइल चयन गर्नुहोस्"
-
-#~ msgid "Other…"
-#~ msgstr "अन्य…"
-
-#~ msgid ""
-#~ "The folder could not be created, as a file with the same name already exists.  Try using a "
-#~ "different name for the folder, or rename the file first."
-#~ msgstr ""
-#~ "फोल्डर सिर्जना गर्न सकिएन, किनभने उही नामको एउटा फाइल पहिल्यै अवस्थित छ। फोल्डरका लागि एउटा भिन्न "
-#~ "नाम प्रयोग गरेर प्रयास गर्नुहोस् वा पहिले फाइलको पुन: नामकरण गर्नुहोस्।"
+#~ msgid "The folder could not be created, as a file with the same name already exists.  Try using a different name for the folder, or rename the file first."
+#~ msgstr "फोल्डर सिर्जना गर्न सकिएन, किनभने उही नामको एउटा फाइल पहिल्यै अवस्थित छ। फोल्डरका लागि एउटा भिन्न नाम प्रयोग गरेर प्रयास गर्नुहोस् वा पहिले फाइलको पुन: नामकरण गर्नुहोस्।"
 
 #~ msgid "Enter location"
 #~ msgstr "स्थान प्रविष्ट गर्नुहोस्"
@@ -8683,12 +9657,6 @@ msgstr ""
 #~ msgid "Visual"
 #~ msgstr "दृश्यात्मक"
 
-#~ msgid "Color Name"
-#~ msgstr "रङ्गको नाम"
-
-#~ msgid "Files"
-#~ msgstr "फाइलहरू"
-
 #~ msgid "Font Family"
 #~ msgstr "फन्ट परिवार"
 
@@ -8713,9 +9681,6 @@ msgstr ""
 #~ msgid "Select which type of documents are shown"
 #~ msgstr "कुन प्रकारको कागजातहरू देखाइन्छ चयन गर्नुहोस्"
 
-#~ msgid "Volume"
-#~ msgstr "भोल्युम"
-
 #~ msgid "Turns volume up or down"
 #~ msgstr "भोल्युम बढाउनुहोस् या घटाउनुहोस्"
 
@@ -8818,9 +9783,6 @@ msgstr ""
 #~ msgid "DISPLAY"
 #~ msgstr "DISPLAY"
 
-#~ msgid "X screen to use"
-#~ msgstr "प्रयोग गरिने X स्क्रिन"
-
 #~ msgid "SCREEN"
 #~ msgstr "SCREEN"
 
@@ -8855,17 +9817,11 @@ msgstr ""
 #~ msgid "Received invalid color data\n"
 #~ msgstr "प्राप्त अवैध रङ डेटा\n"
 
-#~ msgid ""
-#~ "Select the color you want from the outer ring. Select the darkness or lightness of that "
-#~ "color using the inner triangle."
-#~ msgstr ""
-#~ "तपाईँले बाहिरी घेराबाट चाहेको रङ चयन गर्नुहोस्। भित्री त्रिकोण प्रयोग गर्ने रङको अँध्यारोपन वा चम्किलोपन "
-#~ "चयन गर्नुहोस्।"
+#~ msgid "Select the color you want from the outer ring. Select the darkness or lightness of that color using the inner triangle."
+#~ msgstr "तपाईँले बाहिरी घेराबाट चाहेको रङ चयन गर्नुहोस्। भित्री त्रिकोण प्रयोग गर्ने रङको अँध्यारोपन वा चम्किलोपन चयन गर्नुहोस्।"
 
 #~ msgid "Click the eyedropper, then click a color anywhere on your screen to select that color."
-#~ msgstr ""
-#~ "आइड्रपरमा क्लिक गर्नुहोस्, त्यसपछि त्यो रङ चयन गर्न तपाईँको पर्दामा कुनै पनि ठाउँमा एउटा रङमा क्लिक "
-#~ "गर्नुहोस्।"
+#~ msgstr "आइड्रपरमा क्लिक गर्नुहोस्, त्यसपछि त्यो रङ चयन गर्न तपाईँको पर्दामा कुनै पनि ठाउँमा एउटा रङमा क्लिक गर्नुहोस्।"
 
 #~ msgid "Position on the color wheel."
 #~ msgstr "रङ चक्रमा स्थिति"
@@ -8886,12 +9842,8 @@ msgstr ""
 #~ msgid "Transparency of the color."
 #~ msgstr "रङको पारदर्शीता"
 
-#~ msgid ""
-#~ "You can enter an HTML-style hexadecimal color value, or simply a color name such as "
-#~ "'orange' in this entry."
-#~ msgstr ""
-#~ "तपाईँले एउटा HTML-शैली हेक्जाडेसिमल रङ मान प्रविष्ट गर्न सक्नहुन्छ, वा कुनै एउटा रङ नाम जस्तो कि यो "
-#~ "प्रविष्टिमा 'सुन्तला रङ'"
+#~ msgid "You can enter an HTML-style hexadecimal color value, or simply a color name such as 'orange' in this entry."
+#~ msgstr "तपाईँले एउटा HTML-शैली हेक्जाडेसिमल रङ मान प्रविष्ट गर्न सक्नहुन्छ, वा कुनै एउटा रङ नाम जस्तो कि यो प्रविष्टिमा 'सुन्तला रङ'"
 
 #, fuzzy
 #~ msgid "_Palette:"
@@ -8901,29 +9853,19 @@ msgstr ""
 #~ msgstr "रङ चक्र"
 
 #~ msgid ""
-#~ "The previously-selected color, for comparison to the color you're selecting now. You can "
-#~ "drag this color to a palette entry, or select this color as current by dragging it to the "
-#~ "other color swatch alongside."
+#~ "The previously-selected color, for comparison to the color you're selecting now. You can drag this color to a palette entry, or select this color as current by dragging "
+#~ "it to the other color swatch alongside."
 #~ msgstr ""
-#~ "तपाईँले अहिले चयन गरिरहेको रङको तुलनामा, पूर्व-चयन गरिएको रङ। तपाईँले यो रङलाई एउटा रङदानी प्रविष्टिमा "
-#~ "तान्न सक्नुहुन्छ, वासँगै रहेको अन्य रङ सम्म तानेर हालको रूपमा यो रङ चयन गर्न सक्नुहुन्छ।"
+#~ "तपाईँले अहिले चयन गरिरहेको रङको तुलनामा, पूर्व-चयन गरिएको रङ। तपाईँले यो रङलाई एउटा रङदानी प्रविष्टिमा तान्न सक्नुहुन्छ, वासँगै रहेको अन्य रङ सम्म तानेर हालको रूपमा यो रङ चयन गर्न सक्नुहुन्छ।"
 
-#~ msgid ""
-#~ "The color you've chosen. You can drag this color to a palette entry to save it for use in "
-#~ "the future."
-#~ msgstr ""
-#~ "तपाईँले रोजेको रङ। भविष्यमा प्रयोगका लागि यसलाई बचत गर्न तपाईँले यो रङलाई एउटा रङदानी प्रविष्टिमा "
-#~ "तान्न सक्नुहुन्छ।"
+#~ msgid "The color you've chosen. You can drag this color to a palette entry to save it for use in the future."
+#~ msgstr "तपाईँले रोजेको रङ। भविष्यमा प्रयोगका लागि यसलाई बचत गर्न तपाईँले यो रङलाई एउटा रङदानी प्रविष्टिमा तान्न सक्नुहुन्छ।"
 
 #~ msgid "_Save color here"
 #~ msgstr "यहाँ रङ बचत गर्नुहोस्"
 
-#~ msgid ""
-#~ "Click this palette entry to make it the current color. To change this entry, drag a color "
-#~ "swatch here or right-click it and select \"Save color here.\""
-#~ msgstr ""
-#~ "यसलाई हालको रङ बनाउन यो रङदानीमा क्लिक गर्नुहोस्। यो प्रविष्टि परिवर्तन गर्न, एउटा रङ खण्डलाई यहाँ "
-#~ "तान्नुहोस् वा यसलाई दायाँ-क्लिक गर्नुहोस् र \"यहाँ रङ बचत गर्नुहोस्\" चयन गर्नुहोस्।"
+#~ msgid "Click this palette entry to make it the current color. To change this entry, drag a color swatch here or right-click it and select \"Save color here.\""
+#~ msgstr "यसलाई हालको रङ बनाउन यो रङदानीमा क्लिक गर्नुहोस्। यो प्रविष्टि परिवर्तन गर्न, एउटा रङ खण्डलाई यहाँ तान्नुहोस् वा यसलाई दायाँ-क्लिक गर्नुहोस् र \"यहाँ रङ बचत गर्नुहोस्\" चयन गर्नुहोस्।"
 
 #~ msgid "_Insert Unicode Control Character"
 #~ msgstr "युनिकोड नियन्त्रण क्यारेक्टर घुसाउनुहोस्"
@@ -8932,12 +9874,6 @@ msgstr ""
 #~ msgid "Num Lock is on"
 #~ msgstr "स्थान खोल्नुहोस्"
 
-#~ msgid "Could not retrieve information about the file"
-#~ msgstr "फाइलका बारेमा जानकारी पुन: प्राप्त गर्न सकेन"
-
-#~ msgid "Could not add a bookmark"
-#~ msgstr "एउटा पुस्तकचिनो थप्न सकेन"
-
 #~ msgid "Could not remove bookmark"
 #~ msgstr "पुस्तकचिनो हटाउन सकेन"
 
@@ -8956,9 +9892,6 @@ msgstr ""
 #~ msgid "Remove the selected bookmark"
 #~ msgstr "चयन गरिएको पुस्तकचिनो हटाउनुहोस्"
 
-#~ msgid "Remove"
-#~ msgstr "हटाउनुहोस्"
-
 #~ msgid "Rename..."
 #~ msgstr "पुन: नामकरण गर्नुहोस्..."
 
@@ -8966,9 +9899,6 @@ msgstr ""
 #~ msgid "_Places"
 #~ msgstr "बदल्नुहोस्"
 
-#~ msgid "_Add"
-#~ msgstr "थप्नुहोस्"
-
 #~ msgid "Add the selected folder to the Bookmarks"
 #~ msgstr "पुस्तकचिनोहरूमा चयन गरिएको फोल्डर थप्नुहोस्"
 
@@ -9124,9 +10054,6 @@ msgstr ""
 #~ msgid "Could not get information for file '%s': %s"
 #~ msgstr "फाइल '%s' का लागि जानकारी प्राप्त गर्न सकेन: %s"
 
-#~ msgid "Failed to open file '%s': %s"
-#~ msgstr "फाइल '%s' खोल्न असफल: %s"
-
 #~ msgid "Failed to load image '%s': reason not known, probably a corrupt image file"
 #~ msgstr "छवि '%s' लोड गर्न असफल: कारण अज्ञात, संभवत एउटा नष्ट छवि फाइल"
 
@@ -9145,17 +10072,12 @@ msgstr ""
 #~ msgid "Unable to load image-loading module: %s: %s"
 #~ msgstr "छवि-लोडिङ मोड्युल लोड गर्न असफल: %s: %s"
 
-#~ msgid ""
-#~ "Image-loading module %s does not export the proper interface; perhaps it's from a different "
-#~ "GTK version?"
+#~ msgid "Image-loading module %s does not export the proper interface; perhaps it's from a different GTK version?"
 #~ msgstr "छवि-लोडिङ मोड्युल %s ले उचित इन्टरफेस निर्यात गर्दैन; सायद यो फरक GTK संस्करण बाट हो ?"
 
 #~ msgid "Couldn't recognize the image file format for file '%s'"
 #~ msgstr "फाइल '%s' का लागि छवि फाइल ढाँचा पहिचान गर्न सकेन"
 
-#~ msgid "Failed to load image '%s': %s"
-#~ msgstr "छवि '%s' लोड गर्न असफल: %s"
-
 #~ msgid "Error writing to image file: %s"
 #~ msgstr "छवि फाइलमा लेख्दा त्रुटि: %s"
 
@@ -9168,9 +10090,6 @@ msgstr ""
 #~ msgid "Failed to open temporary file"
 #~ msgstr "अस्थायी फाइल खोल्न असफल"
 
-#~ msgid "Failed to read from temporary file"
-#~ msgstr "अस्थायी फाइलबाट पढ्न असफल"
-
 #~ msgid "Failed to open '%s' for writing: %s"
 #~ msgstr "लेख्नका लागि '%s' खोल्न असफल: %s"
 
@@ -9181,11 +10100,8 @@ msgstr ""
 #~ msgstr "एउटा बफरमा छवि बचत गर्न अपर्याप्त स्मृति"
 
 #, fuzzy
-#~ msgid ""
-#~ "Internal error: Image loader module '%s' failed to complete an operation, but didn't give a "
-#~ "reason for the failure"
-#~ msgstr ""
-#~ "आन्तरिक त्रुटि: छवि लोडर मोड्युल '%s' ले एउटा छवि लोड सुरु गर्न असफल भयो, तर असफलताका लागि कारण दिएन।"
+#~ msgid "Internal error: Image loader module '%s' failed to complete an operation, but didn't give a reason for the failure"
+#~ msgstr "आन्तरिक त्रुटि: छवि लोडर मोड्युल '%s' ले एउटा छवि लोड सुरु गर्न असफल भयो, तर असफलताका लागि कारण दिएन।"
 
 #~ msgid "Incremental loading of image type '%s' is not supported"
 #~ msgstr "छवि प्रकार '%s' को बढ्दो लोडिङ समर्थित छैन"
@@ -9302,9 +10218,6 @@ msgstr ""
 #~ msgid "Icon has zero height"
 #~ msgstr "प्रतिमासँग शून्य उचाइ"
 
-#~ msgid "Compressed icons are not supported"
-#~ msgstr "सङ्कुचित प्रतिमाहरू समर्थित छैनन्"
-
 #~ msgid "Not enough memory to load ICO file"
 #~ msgstr "ICO फाइल लोड गर्न पर्याप्त स्मृति छैन"
 
@@ -9430,12 +10343,8 @@ msgstr ""
 #~ msgid "Insufficient memory to load PNG file"
 #~ msgstr "PNG फाइल लोड गर्न अपर्याप्त स्मृति"
 
-#~ msgid ""
-#~ "Insufficient memory to store a %ld by %ld image; try exiting some applications to reduce "
-#~ "memory usage"
-#~ msgstr ""
-#~ "एउटा %ld छवि द्धारा %ld भण्डारण गर्न अपर्याप्त स्मृति; स्मृति उपयोग घटाउन केही अनुप्रयोगहरू निष्काशन गरेर "
-#~ "प्रयास गर्नुहोस्"
+#~ msgid "Insufficient memory to store a %ld by %ld image; try exiting some applications to reduce memory usage"
+#~ msgstr "एउटा %ld छवि द्धारा %ld भण्डारण गर्न अपर्याप्त स्मृति; स्मृति उपयोग घटाउन केही अनुप्रयोगहरू निष्काशन गरेर प्रयास गर्नुहोस्"
 
 #~ msgid "Fatal error reading PNG image file"
 #~ msgstr "PNG छवि फाइल पढ्दा घातक त्रुटि"
@@ -9728,8 +10637,7 @@ msgstr ""
 #~ msgstr "फोल्डर पढ्न-योग्य होइन: %s"
 
 #~ msgid ""
-#~ "The file \"%s\" resides on another machine (called %s) and may not be available to this "
-#~ "program.\n"
+#~ "The file \"%s\" resides on another machine (called %s) and may not be available to this program.\n"
 #~ "Are you sure that you want to select it?"
 #~ msgstr ""
 #~ "फाइल \"%s\" अर्को मेशिनमा छ ( %s भनिने) र यो कार्यक्रममा उपलब्ध नहुनसक्छ।\n"
@@ -9784,12 +10692,8 @@ msgstr ""
 #~ msgid "Rename file \"%s\" to:"
 #~ msgstr "मा फाइल \"%s\" को पुन: नामकरण गर्नुहोस्:"
 
-#~ msgid ""
-#~ "The filename \"%s\" couldn't be converted to UTF-8. (try setting the environment variable "
-#~ "G_FILENAME_ENCODING): %s"
-#~ msgstr ""
-#~ "फाइलनाम \"%s\" लाई युटिएफ-८ मा रूपान्तरण गर्न सकिएन।(परिवेश चल G_FILENAME_ENCODING सेट गरेर प्रयास "
-#~ "गर्नुहोस्): %s"
+#~ msgid "The filename \"%s\" couldn't be converted to UTF-8. (try setting the environment variable G_FILENAME_ENCODING): %s"
+#~ msgstr "फाइलनाम \"%s\" लाई युटिएफ-८ मा रूपान्तरण गर्न सकिएन।(परिवेश चल G_FILENAME_ENCODING सेट गरेर प्रयास गर्नुहोस्): %s"
 
 #~ msgid "Invalid UTF-8"
 #~ msgstr "अवैध UTF-8"
@@ -10071,9 +10975,7 @@ msgstr ""
 #~ msgid "This file system does not support mounting"
 #~ msgstr "यो फाइल प्रणालीले माउण्टिङ समर्थन गर्दैन"
 
-#~ msgid ""
-#~ "The name \"%s\" is not valid because it contains the character \"%s\". Please use a "
-#~ "different name."
+#~ msgid "The name \"%s\" is not valid because it contains the character \"%s\". Please use a different name."
 #~ msgstr "नाम \"%s\" अवैध छ किनभने यसमा \"%s\" क्यारेक्टर समाहित छ। कृपया एउटा भिन्न नाम प्रयोग गर्नुहोस्।"
 
 #~ msgid "Bookmark saving failed: %s"
@@ -10102,9 +11004,6 @@ msgstr ""
 #~ msgid "PNM image format is invalid"
 #~ msgstr "PNM छवि ढाँचा अवैध छ"
 
-#~ msgid "Could not get information about '%s': %s"
-#~ msgstr "'%s' का बारेमा सूचना प्राप्त गर्न सकेन: %s"
-
 #~ msgid "Folder"
 #~ msgstr "फोल्डर"
 
@@ -10120,13 +11019,6 @@ msgstr ""
 #~ msgid "Save in Location"
 #~ msgstr "स्थानमा बचत गर्नुहोस्"
 
-#~ msgid ""
-#~ "Error creating folder \"%s\": %s\n"
-#~ "%s"
-#~ msgstr ""
-#~ "फोल्डर \"%s\" सिर्जना गर्दा त्रुटि: %s\n"
-#~ "%s"
-
 #~ msgid "You probably used symbols not allowed in filenames."
 #~ msgstr "संभवत: तपाईँले फाइलनामहरूमा अनुमति नदिइएको प्रतीकहरू प्रयोग गर्नुभयो।"
 
diff --git a/po/pl.po b/po/pl.po
index 8288ee22b11bf3f5f01551ef75f597c29f096eab..076ed691ed8f27ba821032a7bfa9fc0c9c7ff448 100644
--- a/po/pl.po
+++ b/po/pl.po
@@ -1,5 +1,5 @@
 # Polish translation for gtk.
-# Copyright © 1998-2024 the gtk authors.
+# Copyright © 1998-2025 the gtk authors.
 # This file is distributed under the same license as the gtk package.
 # Krzysztof Krzyżaniak <eloy@venco.com.pl>, 1998.
 # Tomasz Kłoczko <kloczek@rudy.mif.pg.gda.pl>, 1999.
@@ -8,16 +8,16 @@
 # Artur Flinta <aflinta@at.kernel.pl>, 2003-2006.
 # Wadim Dziedzic <wdziedzic@aviary.pl>, 2007-2009.
 # Tomasz Dominikowski <dominikowski@gmail.com>, 2007-2009.
-# Piotr DrÄ…g <piotrdrag@gmail.com>, 2010-2024.
+# Piotr DrÄ…g <piotrdrag@gmail.com>, 2010-2025.
 # Wojciech Szczęsny <wszczesny@aviary.pl>, 2013.
-# Aviary.pl <community-poland@mozilla.org>, 2007-2024.
+# Aviary.pl <community-poland@mozilla.org>, 2007-2025.
 #
 msgid ""
 msgstr ""
 "Project-Id-Version: gtk\n"
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
-"POT-Creation-Date: 2024-09-17 05:42+0000\n"
-"PO-Revision-Date: 2024-09-17 18:44+0200\n"
+"POT-Creation-Date: 2025-02-16 03:15+0000\n"
+"PO-Revision-Date: 2025-02-16 17:58+100\n"
 "Last-Translator: Piotr DrÄ…g <piotrdrag@gmail.com>\n"
 "Language-Team: Polish <community-poland@mozilla.org>\n"
 "Language: pl\n"
@@ -27,39 +27,51 @@ msgstr ""
 "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 "
 "|| n%100>=20) ? 1 : 2);\n"
 
+#: gdk/android/gdkandroidclipboard.c:174
+msgid "No compatible formats to transfer contents of content provider."
+msgstr "Brak zgodnych formatów do przesłania zawartości dostawcy."
+
+#: gdk/android/gdkandroidclipboard.c:623 gdk/macos/gdkmacospasteboard.c:161
+#: gdk/wayland/gdkclipboard-wayland.c:244 gdk/wayland/gdkdrop-wayland.c:205
+#: gdk/wayland/gdkprimary-wayland.c:343 gdk/win32/gdkdrop-win32.c:1014
+#: gdk/win32/gdkdrop-win32.c:1063 gdk/x11/gdkclipboard-x11.c:801
+#: gdk/x11/gdkdrop-x11.c:237
+msgid "No compatible transfer format found"
+msgstr "Nie odnaleziono zgodnego formatu przesyłania"
+
 #: gdk/broadway/gdkbroadway-server.c:135
 #, c-format
 msgid "Broadway display type not supported: %s"
 msgstr "Nieobsługiwany typ ekranu Broadway: %s"
 
-#: gdk/gdkclipboard.c:232
+#: gdk/gdkclipboard.c:231
 msgid "This clipboard cannot store data."
 msgstr "Ten schowek nie może przechowywać danych."
 
-#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:781 gdk/gdkclipboard.c:1072
+#: gdk/gdkclipboard.c:286 gdk/gdkclipboard.c:780 gdk/gdkclipboard.c:1071
 msgid "Cannot read from empty clipboard."
 msgstr "Nie można odczytać z pustego schowka."
 
-#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1122 gdk/gdkdrag.c:606
+#: gdk/gdkclipboard.c:317 gdk/gdkclipboard.c:1121 gdk/gdkdrag.c:606
 msgid "No compatible formats to transfer clipboard contents."
 msgstr "Brak zgodnych formatów do przesłania zawartości schowka."
 
-#: gdk/gdkcolorstate.c:668
+#: gdk/gdkcolorstate.c:921
 #, c-format
 msgid "cicp: Narrow range or YUV not supported"
 msgstr "cicp: wąski zakres lub kolory YUV jest nieobsługiwane"
 
-#: gdk/gdkcolorstate.c:678
+#: gdk/gdkcolorstate.c:931
 #, c-format
 msgid "cicp: Unspecified parameters not supported"
 msgstr "cicp: nieokreślone parametry są nieobsługiwane"
 
-#: gdk/gdkcolorstate.c:724
+#: gdk/gdkcolorstate.c:977
 #, c-format
 msgid "cicp: Transfer function %u not supported"
 msgstr "cicp: funkcja przesyłania %u jest nieobsługiwana"
 
-#: gdk/gdkcolorstate.c:754
+#: gdk/gdkcolorstate.c:1007
 #, c-format
 msgid "cicp: Color primaries %u not supported"
 msgstr "cicp: kolory podstawowe %u są nieobsługiwane"
@@ -75,35 +87,35 @@ msgstr "Nie można dostarczyć zawartości jako „%s”"
 msgid "Cannot provide contents as %s"
 msgstr "Nie można dostarczyć zawartości jako %s"
 
-#: gdk/gdkdisplay.c:176 gdk/gdkglcontext.c:472
+#: gdk/gdkdisplay.c:176 gdk/gdkglcontext.c:466
 msgid "The current backend does not support OpenGL"
 msgstr "Bieżący mechanizm nie obsługuje OpenGL"
 
-#: gdk/gdkdisplay.c:1315 gdk/gdkvulkancontext.c:1668
+#: gdk/gdkdisplay.c:1364 gdk/gdkvulkancontext.c:1726
 msgid "Vulkan support disabled via GDK_DISABLE"
 msgstr "Obsługa Vulkan została wyłączona przez zmienną GDK_DISABLE"
 
-#: gdk/gdkdisplay.c:1369
+#: gdk/gdkdisplay.c:1418
 msgid "OpenGL support disabled via GDK_DISABLE"
 msgstr "Obsługa OpenGL została wyłączona przez zmienną GDK_DISABLE"
 
-#: gdk/gdkdisplay.c:1683
+#: gdk/gdkdisplay.c:1732
 msgid "No EGL configuration available"
 msgstr "Brak dostępnej konfiguracji EGL"
 
-#: gdk/gdkdisplay.c:1691
+#: gdk/gdkdisplay.c:1740
 msgid "Failed to get EGL configurations"
 msgstr "Uzyskanie konfiguracji EGL się nie powiodło"
 
-#: gdk/gdkdisplay.c:1721
+#: gdk/gdkdisplay.c:1770
 msgid "No EGL configuration with required features found"
 msgstr "Nie odnaleziono konfiguracji EGL z wymaganymi funkcjami"
 
-#: gdk/gdkdisplay.c:1728
+#: gdk/gdkdisplay.c:1777
 msgid "No perfect EGL configuration found"
 msgstr "Nie odnaleziono doskonałej konfiguracji EGL"
 
-#: gdk/gdkdisplay.c:1770
+#: gdk/gdkdisplay.c:1819
 #, c-format
 msgid "EGL implementation is missing extension %s"
 msgid_plural "EGL implementation is missing %2$d extensions: %1$s"
@@ -111,23 +123,23 @@ msgstr[0] "W implementacji EGL brakuje rozszerzenia %s"
 msgstr[1] "W implementacji EGL brakuje %2$d rozszerzeń: %1$s"
 msgstr[2] "W implementacji EGL brakuje %2$d rozszerzeń: %1$s"
 
-#: gdk/gdkdisplay.c:1819
+#: gdk/gdkdisplay.c:1868
 msgid "libEGL not available in this sandbox"
 msgstr "libEGL nie jest dostępne w tej izolacji"
 
-#: gdk/gdkdisplay.c:1820
+#: gdk/gdkdisplay.c:1869
 msgid "libEGL not available"
 msgstr "libEGL jest niedostępne"
 
-#: gdk/gdkdisplay.c:1830
+#: gdk/gdkdisplay.c:1879
 msgid "Failed to create EGL display"
 msgstr "Utworzenie ekranu EGL się nie powiodło"
 
-#: gdk/gdkdisplay.c:1839
+#: gdk/gdkdisplay.c:1888
 msgid "Could not initialize EGL display"
 msgstr "Nie można zainicjować ekranu EGL"
 
-#: gdk/gdkdisplay.c:1849
+#: gdk/gdkdisplay.c:1898
 #, c-format
 msgid "EGL version %d.%d is too old. GTK requires %d.%d"
 msgstr "Wersja EGL, %d.%d, jest za stara. GTK wymaga wersji %d.%d"
@@ -140,25 +152,25 @@ msgstr "Przeciąganie z innych programów nie jest obsługiwane."
 msgid "No compatible formats to transfer contents."
 msgstr "Brak zgodnych formatów do przesłania zawartości."
 
-#: gdk/gdkglcontext.c:432 gdk/x11/gdkglcontext-glx.c:651
+#: gdk/gdkglcontext.c:426 gdk/x11/gdkglcontext-glx.c:653
 msgid "No GL API allowed."
 msgstr "Żadne API GL nie jest dozwolone."
 
-#: gdk/gdkglcontext.c:455 gdk/win32/gdkglcontext-win32-wgl.c:723
-#: gdk/win32/gdkglcontext-win32-wgl.c:866
-#: gdk/win32/gdkglcontext-win32-wgl.c:910 gdk/x11/gdkglcontext-glx.c:697
+#: gdk/gdkglcontext.c:449 gdk/win32/gdkglcontext-win32-wgl.c:746
+#: gdk/win32/gdkglcontext-win32-wgl.c:889
+#: gdk/win32/gdkglcontext-win32-wgl.c:933 gdk/x11/gdkglcontext-glx.c:699
 msgid "Unable to create a GL context"
 msgstr "Nie można utworzyć kontekstu GL"
 
-#: gdk/gdkglcontext.c:1340
+#: gdk/gdkglcontext.c:1327
 msgid "OpenGL ES API disabled via GDK_DISABLE"
 msgstr "API OpenGL ES zostało wyłączone przez zmienną GDK_DISABLE"
 
-#: gdk/gdkglcontext.c:1352
+#: gdk/gdkglcontext.c:1339
 msgid "OpenGL API disabled via GDK_DISABLE"
 msgstr "API OpenGL zostało wyłączone przez zmienną GDK_DISABLE"
 
-#: gdk/gdkglcontext.c:1363
+#: gdk/gdkglcontext.c:1350
 #, c-format
 msgid "Application does not support %s API"
 msgstr "Program nie obsługuje API %s"
@@ -166,12 +178,12 @@ msgstr "Program nie obsługuje API %s"
 #. translators: This is about OpenGL backend names, like
 #. * "Trying to use X11 GLX, but EGL is already in use"
 #.
-#: gdk/gdkglcontext.c:2175
+#: gdk/gdkglcontext.c:2127
 #, c-format
 msgid "Trying to use %s, but %s is already in use"
 msgstr "Próbowanie użycia %s, ale %s jest już używane"
 
-#: gdk/gdkglcontext.c:2186
+#: gdk/gdkglcontext.c:2138
 #, c-format
 msgid "Trying to use %s, but it is disabled via GDK_DISABLE"
 msgstr "Próbowanie użycia %s, ale jest wyłączone przez zmienną GDK_DISABLE"
@@ -256,12 +268,12 @@ msgctxt "keyboard label"
 msgid "Down"
 msgstr "W dół"
 
-#: gdk/keynamesprivate.h:6874 gtk/gtkshortcutlabel.c:217
+#: gdk/keynamesprivate.h:6874 gtk/deprecated/gtkshortcutlabel.c:219
 msgctxt "keyboard label"
 msgid "Page_Up"
 msgstr "Page Up"
 
-#: gdk/keynamesprivate.h:6875 gtk/gtkshortcutlabel.c:220
+#: gdk/keynamesprivate.h:6875 gtk/deprecated/gtkshortcutlabel.c:222
 msgctxt "keyboard label"
 msgid "Page_Down"
 msgstr "Page Down"
@@ -557,37 +569,37 @@ msgctxt "keyboard label"
 msgid "Suspend"
 msgstr "Uśpienie"
 
-#: gdk/loaders/gdkjpeg.c:65
+#: gdk/loaders/gdkjpeg.c:71
 #, c-format
 msgid "Error interpreting JPEG image file (%s)"
 msgstr "Błąd podczas interpretowania pliku obrazu JPEG (%s)"
 
-#: gdk/loaders/gdkjpeg.c:179
+#: gdk/loaders/gdkjpeg.c:185
 #, c-format
 msgid "Unsupported JPEG colorspace (%d)"
 msgstr "Nieobsługiwana przestrzeń kolorów JPEG (%d)"
 
-#: gdk/loaders/gdkjpeg.c:188 gdk/loaders/gdkpng.c:436 gdk/loaders/gdktiff.c:472
+#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:468 gdk/loaders/gdktiff.c:472
 #, c-format
 msgid "Not enough memory for image size %ux%u"
 msgstr "Za mało pamięci na obraz o rozmiarze %u×%u"
 
-#: gdk/loaders/gdkpng.c:120
+#: gdk/loaders/gdkpng.c:119
 #, c-format
 msgid "Error reading png (%s)"
 msgstr "Błąd podczas odczytywania pliku PNG (%s)"
 
-#: gdk/loaders/gdkpng.c:357
+#: gdk/loaders/gdkpng.c:389
 #, c-format
 msgid "Unsupported depth %u in png image"
 msgstr "Nieobsługiwana głębia %u w obrazie PNG"
 
-#: gdk/loaders/gdkpng.c:407
+#: gdk/loaders/gdkpng.c:439
 #, c-format
 msgid "Unsupported color type %u in png image"
 msgstr "Nieobsługiwany typ kolorów %u w obrazie PNG"
 
-#: gdk/loaders/gdkpng.c:421
+#: gdk/loaders/gdkpng.c:453
 #, c-format
 msgid "Image stride too large for image size %ux%u"
 msgstr "Odstęp obrazu jest za duży dla obrazu o rozmiarze %u×%u"
@@ -605,78 +617,71 @@ msgstr "Nie można wczytać danych TIFF"
 msgid "Reading data failed at row %d"
 msgstr "Odczytanie danych nie powiodło się w %d. rzędzie"
 
-#: gdk/macos/gdkmacospasteboard.c:211 gdk/wayland/gdkclipboard-wayland.c:238
-#: gdk/wayland/gdkdrop-wayland.c:205 gdk/wayland/gdkprimary-wayland.c:337
-#: gdk/win32/gdkdrop-win32.c:1018 gdk/win32/gdkdrop-win32.c:1067
-#: gdk/x11/gdkclipboard-x11.c:799 gdk/x11/gdkdrop-x11.c:235
-msgid "No compatible transfer format found"
-msgstr "Nie odnaleziono zgodnego formatu przesyłania"
-
-#: gdk/macos/gdkmacospasteboard.c:297
+#: gdk/macos/gdkmacospasteboard.c:255
 #, c-format
 msgid "Failed to decode contents with mime-type of '%s'"
 msgstr "Dekodowanie treści o typie MIME „%s” się nie powiodło"
 
-#: gdk/win32/gdkclipdrop-win32.c:719
+#: gdk/win32/gdkclipdrop-win32.c:684
 #, c-format
 msgid "Cannot claim clipboard ownership. OpenClipboard() timed out."
 msgstr ""
 "Nie można zostać właścicielem schowka. OpenClipboard() przekroczyło czas "
 "oczekiwania."
 
-#: gdk/win32/gdkclipdrop-win32.c:729
+#: gdk/win32/gdkclipdrop-win32.c:694
 #, c-format
 msgid "Cannot claim clipboard ownership. Another process claimed it before us."
 msgstr ""
 "Nie można zostać właścicielem schowka. Inny proces został właścicielem przed "
 "nami."
 
-#: gdk/win32/gdkclipdrop-win32.c:743
+#: gdk/win32/gdkclipdrop-win32.c:708
 #, c-format
 msgid "Cannot claim clipboard ownership. OpenClipboard() failed: 0x%lx."
 msgstr ""
 "Nie można zostać właścicielem schowka. OpenClipboard() się nie powiodło: "
 "0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:755
+#: gdk/win32/gdkclipdrop-win32.c:718
 #, c-format
 msgid "Cannot claim clipboard ownership. EmptyClipboard() failed: 0x%lx."
 msgstr ""
 "Nie można zostać właścicielem schowka. EmptyClipboard() się nie powiodło: "
 "0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:798
+#: gdk/win32/gdkclipdrop-win32.c:760
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() timed out."
 msgstr ""
 "Nie można ustawić danych schowka. OpenClipboard() przekroczyło czas "
 "oczekiwania."
 
-#: gdk/win32/gdkclipdrop-win32.c:808 gdk/win32/gdkclipdrop-win32.c:839
+#: gdk/win32/gdkclipdrop-win32.c:770 gdk/win32/gdkclipdrop-win32.c:801
 #, c-format
 msgid "Cannot set clipboard data. Another process claimed clipboard ownership."
 msgstr ""
 "Nie można ustawić danych schowka. Inny proces jest właścicielem schowka."
 
-#: gdk/win32/gdkclipdrop-win32.c:822
+#: gdk/win32/gdkclipdrop-win32.c:784
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr ""
 "Nie można ustawić danych schowka. OpenClipboard() się nie powiodło: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:874
+#: gdk/win32/gdkclipdrop-win32.c:836
 #, c-format
 msgid "Cannot get clipboard data. GlobalLock(0x%p) failed: 0x%lx."
 msgstr ""
 "Nie można pobrać danych schowka. GlobalLock(0x%p) się nie powiodło: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:885
+#: gdk/win32/gdkclipdrop-win32.c:847
 #, c-format
 msgid "Cannot get clipboard data. GlobalSize(0x%p) failed: 0x%lx."
 msgstr ""
 "Nie można pobrać danych schowka. GlobalSize(0x%p) się nie powiodło: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:898
+#: gdk/win32/gdkclipdrop-win32.c:860
 #, c-format
 msgid ""
 "Cannot get clipboard data. Failed to allocate %s bytes to store the data."
@@ -684,19 +689,19 @@ msgstr ""
 "Nie można pobrać danych schowka. Przydzielenie %s B do przechowania danych "
 "się nie powiodło."
 
-#: gdk/win32/gdkclipdrop-win32.c:930
+#: gdk/win32/gdkclipdrop-win32.c:893
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() timed out."
 msgstr ""
 "Nie można pobrać danych schowka. OpenClipboard() przekroczyło czas "
 "oczekiwania."
 
-#: gdk/win32/gdkclipdrop-win32.c:940
+#: gdk/win32/gdkclipdrop-win32.c:903
 #, c-format
 msgid "Cannot get clipboard data. Clipboard ownership changed."
 msgstr "Nie można pobrać danych schowka. Właściciel schowka się zmienił."
 
-#: gdk/win32/gdkclipdrop-win32.c:950
+#: gdk/win32/gdkclipdrop-win32.c:913
 #, c-format
 msgid ""
 "Cannot get clipboard data. Clipboard data changed before we could get it."
@@ -704,131 +709,131 @@ msgstr ""
 "Nie można pobrać danych schowka. Dane schowka zmieniły się, zanim było można "
 "je pobrać."
 
-#: gdk/win32/gdkclipdrop-win32.c:967
+#: gdk/win32/gdkclipdrop-win32.c:928
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr ""
 "Nie można pobrać danych schowka. OpenClipboard() się nie powiodło: 0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:992
+#: gdk/win32/gdkclipdrop-win32.c:953
 #, c-format
 msgid "Cannot get clipboard data. No compatible transfer format found."
 msgstr ""
 "Nie można pobrać danych schowka. Nie odnaleziono zgodnego formatu "
 "przesyłania."
 
-#: gdk/win32/gdkclipdrop-win32.c:1002
+#: gdk/win32/gdkclipdrop-win32.c:963
 #, c-format
 msgid "Cannot get clipboard data. GetClipboardData() failed: 0x%lx."
 msgstr ""
 "Nie można pobrać danych schowka. GetClipboardData() się nie powiodło: 0x%lx."
 
-#: gdk/win32/gdkdrop-win32.c:949
+#: gdk/win32/gdkdrop-win32.c:945
 #, c-format
 msgid "Cannot get DnD data. GlobalLock(0x%p) failed: 0x%lx."
 msgstr ""
 "Nie można pobrać danych przeciągania. GlobalLock(0x%p) się nie powiodło: "
 "0x%lx."
 
-#: gdk/win32/gdkdrop-win32.c:958
+#: gdk/win32/gdkdrop-win32.c:954
 #, c-format
 msgid "Cannot get DnD data. GlobalSize(0x%p) failed: 0x%lx."
 msgstr ""
 "Nie można pobrać danych przeciągania. GlobalSize(0x%p) się nie powiodło: "
 "0x%lx."
 
-#: gdk/win32/gdkdrop-win32.c:969
+#: gdk/win32/gdkdrop-win32.c:965
 #, c-format
 msgid "Cannot get DnD data. Failed to allocate %s bytes to store the data."
 msgstr ""
 "Nie można pobrać danych przeciągania. Przydzielenie %s B do przechowania "
 "danych się nie powiodło."
 
-#: gdk/win32/gdkdrop-win32.c:1039
+#: gdk/win32/gdkdrop-win32.c:1035
 #, c-format
 msgid "GDK surface 0x%p is not registered as a drop target"
 msgstr "Powierzchnia GDK 0x%p nie jest zarejestrowana jako cel upuszczania"
 
-#: gdk/win32/gdkdrop-win32.c:1047
+#: gdk/win32/gdkdrop-win32.c:1043
 #, c-format
 msgid "Target context record 0x%p has no data object"
 msgstr "Docelowy wpisu kontekstu 0x%p nie ma obiektu danych"
 
-#: gdk/win32/gdkdrop-win32.c:1087
+#: gdk/win32/gdkdrop-win32.c:1083
 #, c-format
 msgid "IDataObject_GetData (0x%x) failed, returning 0x%lx"
 msgstr "IDataObject_GetData (0x%x) się nie powiodło, zwracanie 0x%lx"
 
-#: gdk/win32/gdkdrop-win32.c:1121
+#: gdk/win32/gdkdrop-win32.c:1122
 #, c-format
 msgid "Failed to transmute DnD data W32 format 0x%x to %p (%s)"
 msgstr ""
 "Przekształcenie formatu W32 danych przeciągania 0x%x do %p się nie powiodło "
 "(%s)"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:645
+#: gdk/win32/gdkglcontext-win32-wgl.c:668
 msgid "No GL implementation is available"
 msgstr "Brak dostępnej implementacji GL"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:732
+#: gdk/win32/gdkglcontext-win32-wgl.c:755
 #, c-format
 msgid "WGL version %d.%d is too low, need at least %d.%d"
 msgstr "Wersja WGL, %d.%d, jest za niska, wymagana jest co najmniej %d.%d"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:750
+#: gdk/win32/gdkglcontext-win32-wgl.c:773
 #, c-format
 msgid "GL implementation cannot share GL contexts"
 msgstr "Implementacja GL nie może dzielić się kontekstami GL"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:1030
+#: gdk/win32/gdkglcontext-win32-wgl.c:1053
 msgid "No available configurations for the given pixel format"
 msgstr "Brak dostępnych konfiguracji dla podanego formatu pikseli"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:63
+#: gdk/win32/gdkhdataoutputstream-win32.c:64
 msgid "writing a closed stream"
 msgstr "zapisywanie do zamkniętego potoku"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:85
+#: gdk/win32/gdkhdataoutputstream-win32.c:86
 msgid "g_try_realloc () failed"
 msgstr "g_try_realloc () się nie powiodło"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:93
-#: gdk/win32/gdkhdataoutputstream-win32.c:231
+#: gdk/win32/gdkhdataoutputstream-win32.c:94
+#: gdk/win32/gdkhdataoutputstream-win32.c:233
 msgid "GlobalReAlloc() failed: "
 msgstr "GlobalReAlloc() się nie powiodło: "
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:105
+#: gdk/win32/gdkhdataoutputstream-win32.c:106
 msgid "Ran out of buffer space (buffer size is fixed)"
 msgstr "Skończyło się miejsce w buforze (rozmiar bufora jest stały)"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:203
+#: gdk/win32/gdkhdataoutputstream-win32.c:204
 msgid "Can’t transmute a single handle"
 msgstr "Nie można przekształcić jednego uchwytu"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:215
+#: gdk/win32/gdkhdataoutputstream-win32.c:217
 #, c-format
 msgid "Failed to transmute %zu bytes of data from %s to %u"
 msgstr "Przekształcenie %zu B danych z %s do %u się nie powiodło"
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:250
+#: gdk/win32/gdkhdataoutputstream-win32.c:252
 msgid "GlobalLock() failed: "
 msgstr "GlobalLock() się nie powiodło: "
 
-#: gdk/win32/gdkhdataoutputstream-win32.c:364
+#: gdk/win32/gdkhdataoutputstream-win32.c:367
 msgid "GlobalAlloc() failed: "
 msgstr "GlobalAlloc() się nie powiodło: "
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:297
+#: gdk/x11/gdkapplaunchcontext-x11.c:299
 #, c-format
 msgid "Starting “%s”"
 msgstr "Uruchamianie „%s”"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:310
+#: gdk/x11/gdkapplaunchcontext-x11.c:312
 #, c-format
 msgid "Opening “%s”"
 msgstr "Otwieranie „%s”"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:315
+#: gdk/x11/gdkapplaunchcontext-x11.c:317
 #, c-format
 msgid "Opening %d Item"
 msgid_plural "Opening %d Items"
@@ -836,173 +841,166 @@ msgstr[0] "Otwieranie %d elementu"
 msgstr[1] "Otwieranie %d elementów"
 msgstr[2] "Otwieranie %d elementów"
 
-#: gdk/x11/gdkclipboard-x11.c:473
+#: gdk/x11/gdkclipboard-x11.c:475
 msgid "Clipboard manager could not store selection."
 msgstr "Menedżer schowka nie może przechować zaznaczenia."
 
-#: gdk/x11/gdkclipboard-x11.c:649
+#: gdk/x11/gdkclipboard-x11.c:651
 msgid "Cannot store clipboard. No clipboard manager is active."
 msgstr "Nie można przechować schowka. Żaden menedżer schowka nie jest aktywny."
 
-#: gdk/x11/gdkglcontext-glx.c:817
+#: gdk/x11/gdkglcontext-glx.c:819
 msgid "No GLX configurations available"
 msgstr "Brak dostępnych konfiguracji GLX"
 
-#: gdk/x11/gdkglcontext-glx.c:904
+#: gdk/x11/gdkglcontext-glx.c:906
 msgid "No GLX configuration with required features found"
 msgstr "Nie odnaleziono konfiguracji GLX z wymaganymi funkcjami"
 
-#: gdk/x11/gdkglcontext-glx.c:978
+#: gdk/x11/gdkglcontext-glx.c:982
 msgid "GLX is not supported"
 msgstr "GLX jest nieobsługiwane"
 
-#: gdk/x11/gdkselectioninputstream-x11.c:465
+#: gdk/x11/gdkselectioninputstream-x11.c:467
 #, c-format
 msgid "Format %s not supported"
 msgstr "Format %s jest nieobsługiwany"
 
-#: gdk/x11/gdktextlistconverter-x11.c:65 gdk/x11/gdktextlistconverter-x11.c:105
+#: gdk/x11/gdktextlistconverter-x11.c:67 gdk/x11/gdktextlistconverter-x11.c:107
 msgid "Not enough space in destination"
 msgstr "Za mało miejsca w miejscu docelowym"
 
-#: gdk/x11/gdktextlistconverter-x11.c:91 gdk/x11/gdktextlistconverter-x11.c:195
+#: gdk/x11/gdktextlistconverter-x11.c:93 gdk/x11/gdktextlistconverter-x11.c:197
 msgid "Need complete input to do conversion"
 msgstr "Do konwersji wymagane jest pełne wejście"
 
-#: gdk/x11/gdktextlistconverter-x11.c:216
-#: gdk/x11/gdktextlistconverter-x11.c:250
+#: gdk/x11/gdktextlistconverter-x11.c:218
+#: gdk/x11/gdktextlistconverter-x11.c:252
 msgid "Invalid byte sequence in conversion input"
 msgstr "Nieprawidłowa sekwencja bajtów w wejściu konwersji"
 
-#: gdk/x11/gdktextlistconverter-x11.c:242
+#: gdk/x11/gdktextlistconverter-x11.c:244
 msgid "Invalid formats in compound text conversion."
 msgstr "Nieprawidłowe formaty w konwersji złożonego tekstu."
 
-#: gdk/x11/gdktextlistconverter-x11.c:259
+#: gdk/x11/gdktextlistconverter-x11.c:261
 #, c-format
 msgid "Unsupported encoding “%s”"
 msgstr "Nieobsługiwane kodowanie „%s”"
 
-#: gsk/gl/gskglrenderer.c:215
-#, c-format
-msgid "This GLES %d.%d implementation does not support half-float vertex data"
-msgstr ""
-"Ta implementacja GLES %d.%d nie obsługuje półzmiennoprzecinkowych danych "
-"wierzchołkowych"
-
-#: gsk/gpu/gskgldevice.c:252
+#: gsk/gpu/gskgldevice.c:253
 #, c-format
 msgid "OpenGL ES 3.0 is not supported by this renderer."
 msgstr "OpenGL ES 3.0 nie jest obsługiwane przez ten mechanizm rysowania."
 
-#: gsk/gpu/gsknglrenderer.c:68
+#: gsk/gpu/gskglrenderer.c:66
 msgid "OpenGL 3.3 required"
 msgstr "Wymagane jest OpenGL 3.3"
 
-#: gtk/a11y/gtkatspiaction.c:239
+#: gtk/a11y/gtkatspiaction.c:285
 msgctxt "accessibility"
 msgid "Click"
 msgstr "Kliknij"
 
-#: gtk/a11y/gtkatspiaction.c:240
+#: gtk/a11y/gtkatspiaction.c:286
 msgctxt "accessibility"
 msgid "Clicks the button"
 msgstr "Klika przycisk"
 
-#: gtk/a11y/gtkatspiaction.c:290
+#: gtk/a11y/gtkatspiaction.c:336
 msgctxt "accessibility"
 msgid "Toggle"
 msgstr "Przełącz"
 
-#: gtk/a11y/gtkatspiaction.c:291
+#: gtk/a11y/gtkatspiaction.c:337
 msgctxt "accessibility"
 msgid "Toggles the switch"
 msgstr "Przełącza przełącznik"
 
-#: gtk/a11y/gtkatspiaction.c:371
+#: gtk/a11y/gtkatspiaction.c:418
 msgctxt "accessibility"
 msgid "Select"
 msgstr "Wybierz"
 
-#: gtk/a11y/gtkatspiaction.c:372
+#: gtk/a11y/gtkatspiaction.c:419
 msgctxt "accessibility"
 msgid "Selects the color"
 msgstr "Wybiera kolor"
 
-#: gtk/a11y/gtkatspiaction.c:379 gtk/a11y/gtkatspiaction.c:439
-#: gtk/a11y/gtkatspiaction.c:495 gtk/a11y/gtkatspiaction.c:603
-#: gtk/a11y/gtkatspiaction.c:690
+#: gtk/a11y/gtkatspiaction.c:426 gtk/a11y/gtkatspiaction.c:487
+#: gtk/a11y/gtkatspiaction.c:543 gtk/a11y/gtkatspiaction.c:651
+#: gtk/a11y/gtkatspiaction.c:738
 msgctxt "accessibility"
 msgid "Activate"
 msgstr "Aktywuj"
 
-#: gtk/a11y/gtkatspiaction.c:380
+#: gtk/a11y/gtkatspiaction.c:427
 msgctxt "accessibility"
 msgid "Activates the color"
 msgstr "Aktywuje kolor"
 
-#: gtk/a11y/gtkatspiaction.c:387
+#: gtk/a11y/gtkatspiaction.c:434
 msgctxt "accessibility"
 msgid "Customize"
 msgstr "Dostosuj"
 
-#: gtk/a11y/gtkatspiaction.c:388
+#: gtk/a11y/gtkatspiaction.c:435
 msgctxt "accessibility"
 msgid "Customizes the color"
 msgstr "Dostosowuje kolor"
 
-#: gtk/a11y/gtkatspiaction.c:440
+#: gtk/a11y/gtkatspiaction.c:488
 msgctxt "accessibility"
 msgid "Activates the expander"
 msgstr "Aktywuje element rozwijajÄ…cy"
 
-#: gtk/a11y/gtkatspiaction.c:496 gtk/a11y/gtkatspiaction.c:604
-#: gtk/a11y/gtkatspiaction.c:691
+#: gtk/a11y/gtkatspiaction.c:544 gtk/a11y/gtkatspiaction.c:652
+#: gtk/a11y/gtkatspiaction.c:739
 msgctxt "accessibility"
 msgid "Activates the entry"
 msgstr "Aktywuje wpis"
 
-#: gtk/a11y/gtkatspiaction.c:503
+#: gtk/a11y/gtkatspiaction.c:551
 msgctxt "accessibility"
 msgid "Activate primary icon"
 msgstr "Aktywuj główną ikonę"
 
-#: gtk/a11y/gtkatspiaction.c:504
+#: gtk/a11y/gtkatspiaction.c:552
 msgctxt "accessibility"
 msgid "Activates the primary icon of the entry"
 msgstr "Aktywuje główną ikonę wpisu"
 
-#: gtk/a11y/gtkatspiaction.c:511
+#: gtk/a11y/gtkatspiaction.c:559
 msgctxt "accessibility"
 msgid "Activate secondary icon"
 msgstr "Aktywuj drugorzędną ikonę"
 
-#: gtk/a11y/gtkatspiaction.c:512
+#: gtk/a11y/gtkatspiaction.c:560
 msgctxt "accessibility"
 msgid "Activates the secondary icon of the entry"
 msgstr "Aktywuje drugorzędną ikonę wpisu"
 
-#: gtk/a11y/gtkatspiaction.c:611
+#: gtk/a11y/gtkatspiaction.c:659
 msgctxt "accessibility"
 msgid "Peek"
 msgstr "Odkryj"
 
-#: gtk/a11y/gtkatspiaction.c:612
+#: gtk/a11y/gtkatspiaction.c:660
 msgctxt "accessibility"
 msgid "Shows the contents of the password entry"
 msgstr "Wyświetla treść pola hasła"
 
-#: gtk/a11y/gtkatspiaction.c:698
+#: gtk/a11y/gtkatspiaction.c:746
 msgctxt "accessibility"
 msgid "Clear"
 msgstr "Wyczyść"
 
-#: gtk/a11y/gtkatspiaction.c:699
+#: gtk/a11y/gtkatspiaction.c:747
 msgctxt "accessibility"
 msgid "Clears the contents of the entry"
 msgstr "Czyści treść pola"
 
-#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:869
+#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:906
 msgctxt "accessibility"
 msgid "application"
 msgstr "program"
@@ -1117,13 +1115,13 @@ msgid "Pick a Color"
 msgstr "Wybór koloru"
 
 #: gtk/deprecated/gtkcolorbutton.c:505 gtk/gtkcolorchooserwidget.c:321
-#: gtk/gtkcolordialogbutton.c:335
+#: gtk/gtkcolordialogbutton.c:334
 #, c-format
 msgid "Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"
 msgstr "Czerwony %d%%, zielony %d%%, niebieski %d%%, alfa %d%%"
 
 #: gtk/deprecated/gtkcolorbutton.c:511 gtk/gtkcolorchooserwidget.c:327
-#: gtk/gtkcolordialogbutton.c:341
+#: gtk/gtkcolordialogbutton.c:340
 #, c-format
 msgid "Red %d%%, Green %d%%, Blue %d%%"
 msgstr "Czerwony %d%%, zielony %d%%, niebieski %d%%"
@@ -1133,16 +1131,16 @@ msgid "Sans 12"
 msgstr "Sans 12"
 
 #: gtk/deprecated/gtkfontbutton.c:507 gtk/deprecated/gtkfontbutton.c:624
-#: gtk/gtkfontdialog.c:594
+#: gtk/gtkfontdialog.c:590
 msgid "Pick a Font"
 msgstr "Wybór czcionki"
 
-#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3847
-#: gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:285
+#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3818
+#: gtk/gtkfontdialogbutton.c:125 gtk/inspector/visual.ui:284
 msgid "Font"
 msgstr "Czcionka"
 
-#: gtk/deprecated/gtkfontbutton.c:1155 gtk/gtkfontdialogbutton.c:652
+#: gtk/deprecated/gtkfontbutton.c:1155 gtk/gtkfontdialogbutton.c:654
 msgctxt "font"
 msgid "None"
 msgstr "Brak"
@@ -1179,7 +1177,7 @@ msgstr ""
 "Ustawienia systemu uniemożliwiają wprowadzanie zmian.\n"
 "Proszę skontaktować się z administratorem komputera."
 
-#: gtk/deprecated/gtkshow.c:217
+#: gtk/deprecated/gtkshow.c:291
 msgid "Could not show link"
 msgstr "Nie można wyświetlić odnośnika"
 
@@ -1202,112 +1200,112 @@ msgctxt "volume percentage"
 msgid "%d %%"
 msgstr "%d%%"
 
-#: gtk/gtkaboutdialog.c:125 gtk/ui/gtkaboutdialog.ui:173
+#: gtk/gtkaboutdialog.c:124 gtk/ui/gtkaboutdialog.ui:173
 msgid "License"
 msgstr "Licencja"
 
-#: gtk/gtkaboutdialog.c:126
+#: gtk/gtkaboutdialog.c:125
 msgid "Custom License"
 msgstr "Niestandardowa licencja"
 
-#: gtk/gtkaboutdialog.c:127
+#: gtk/gtkaboutdialog.c:126
 msgid "GNU General Public License, version 2 or later"
 msgstr "Powszechna licencja publiczna GNU, wersja 2 lub późniejsza"
 
-#: gtk/gtkaboutdialog.c:128
+#: gtk/gtkaboutdialog.c:127
 msgid "GNU General Public License, version 3 or later"
 msgstr "Powszechna licencja publiczna GNU, wersja 3 lub późniejsza"
 
-#: gtk/gtkaboutdialog.c:129
+#: gtk/gtkaboutdialog.c:128
 msgid "GNU Lesser General Public License, version 2.1 or later"
 msgstr ""
 "Pomniejsza powszechna licencja publiczna GNU, wersja 2.1 lub późniejsza"
 
-#: gtk/gtkaboutdialog.c:130
+#: gtk/gtkaboutdialog.c:129
 msgid "GNU Lesser General Public License, version 3 or later"
 msgstr "Pomniejsza powszechna licencja publiczna GNU, wersja 3 lub późniejsza"
 
-#: gtk/gtkaboutdialog.c:131
+#: gtk/gtkaboutdialog.c:130
 msgid "BSD 2-Clause License"
 msgstr "2-klauzulowa licencja BSD"
 
-#: gtk/gtkaboutdialog.c:132
+#: gtk/gtkaboutdialog.c:131
 msgid "The MIT License (MIT)"
 msgstr "Licencja MIT"
 
-#: gtk/gtkaboutdialog.c:133
+#: gtk/gtkaboutdialog.c:132
 msgid "Artistic License 2.0"
 msgstr "Licencja twórcza 2.0"
 
-#: gtk/gtkaboutdialog.c:134
+#: gtk/gtkaboutdialog.c:133
 msgid "GNU General Public License, version 2 only"
 msgstr "Powszechna licencja publiczna GNU, tylko w wersji 2"
 
-#: gtk/gtkaboutdialog.c:135
+#: gtk/gtkaboutdialog.c:134
 msgid "GNU General Public License, version 3 only"
 msgstr "Powszechna licencja publiczna GNU, tylko w wersji 3"
 
-#: gtk/gtkaboutdialog.c:136
+#: gtk/gtkaboutdialog.c:135
 msgid "GNU Lesser General Public License, version 2.1 only"
 msgstr "Pomniejsza powszechna licencja publiczna GNU, tylko w wersji 2.1"
 
-#: gtk/gtkaboutdialog.c:137
+#: gtk/gtkaboutdialog.c:136
 msgid "GNU Lesser General Public License, version 3 only"
 msgstr "Pomniejsza powszechna licencja publiczna GNU, tylko w wersji 3"
 
-#: gtk/gtkaboutdialog.c:138
+#: gtk/gtkaboutdialog.c:137
 msgid "GNU Affero General Public License, version 3 or later"
 msgstr "Powszechna licencja publiczna GNU Affero, wersja 3 lub późniejsza"
 
-#: gtk/gtkaboutdialog.c:139
+#: gtk/gtkaboutdialog.c:138
 msgid "GNU Affero General Public License, version 3 only"
 msgstr "Powszechna licencja publiczna GNU Affero, tylko w wersji 3"
 
-#: gtk/gtkaboutdialog.c:140
+#: gtk/gtkaboutdialog.c:139
 msgid "BSD 3-Clause License"
 msgstr "3-klauzulowa licencja BSD"
 
-#: gtk/gtkaboutdialog.c:141
+#: gtk/gtkaboutdialog.c:140
 msgid "Apache License, Version 2.0"
 msgstr "Licencja Apache w wersji 2.0"
 
-#: gtk/gtkaboutdialog.c:142
+#: gtk/gtkaboutdialog.c:141
 msgid "Mozilla Public License 2.0"
 msgstr "Licencja publiczna Mozilli 2.0"
 
-#: gtk/gtkaboutdialog.c:143
+#: gtk/gtkaboutdialog.c:142
 msgid "BSD Zero-Clause License"
 msgstr "0-klauzulowa licencja BSD"
 
-#: gtk/gtkaboutdialog.c:1028
+#: gtk/gtkaboutdialog.c:1026
 msgid "Website"
 msgstr "Witryna"
 
-#: gtk/gtkaboutdialog.c:1064 gtk/ui/gtkapplication-quartz.ui:6
+#: gtk/gtkaboutdialog.c:1068 gtk/ui/gtkapplication-quartz.ui:6
 #, c-format
 msgid "About %s"
 msgstr "O programie %s"
 
-#: gtk/gtkaboutdialog.c:2158
+#: gtk/gtkaboutdialog.c:2162
 msgid "Created by"
 msgstr "Program"
 
-#: gtk/gtkaboutdialog.c:2161
+#: gtk/gtkaboutdialog.c:2165
 msgid "Documented by"
 msgstr "Dokumentacja"
 
-#: gtk/gtkaboutdialog.c:2171
+#: gtk/gtkaboutdialog.c:2175
 msgid "Translated by"
 msgstr "Tłumaczenie"
 
-#: gtk/gtkaboutdialog.c:2176
+#: gtk/gtkaboutdialog.c:2180
 msgid "Design by"
 msgstr "Projekt"
 
 #. Translators: this is the license preamble; the string at the end
 #. * contains the name of the license as link text.
 #.
-#: gtk/gtkaboutdialog.c:2341
+#: gtk/gtkaboutdialog.c:2345
 #, c-format
 msgid ""
 "This program comes with absolutely no warranty.\n"
@@ -1321,8 +1319,8 @@ msgstr ""
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:839 gtk/gtkshortcutlabel.c:101
-#: gtk/gtkshortcutlabel.c:137
+#: gtk/gtkaccelgroup.c:839 gtk/deprecated/gtkshortcutlabel.c:103
+#: gtk/deprecated/gtkshortcutlabel.c:139
 msgctxt "keyboard label"
 msgid "Shift"
 msgstr "Shift"
@@ -1332,8 +1330,8 @@ msgstr "Shift"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:858 gtk/gtkshortcutlabel.c:104
-#: gtk/gtkshortcutlabel.c:139
+#: gtk/gtkaccelgroup.c:858 gtk/deprecated/gtkshortcutlabel.c:106
+#: gtk/deprecated/gtkshortcutlabel.c:141
 msgctxt "keyboard label"
 msgid "Ctrl"
 msgstr "Ctrl"
@@ -1343,8 +1341,8 @@ msgstr "Ctrl"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:877 gtk/gtkshortcutlabel.c:107
-#: gtk/gtkshortcutlabel.c:141
+#: gtk/gtkaccelgroup.c:877 gtk/deprecated/gtkshortcutlabel.c:109
+#: gtk/deprecated/gtkshortcutlabel.c:143
 msgctxt "keyboard label"
 msgid "Alt"
 msgstr "Alt"
@@ -1354,8 +1352,8 @@ msgstr "Alt"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:895 gtk/gtkshortcutlabel.c:113
-#: gtk/gtkshortcutlabel.c:143
+#: gtk/gtkaccelgroup.c:895 gtk/deprecated/gtkshortcutlabel.c:115
+#: gtk/deprecated/gtkshortcutlabel.c:145
 msgctxt "keyboard label"
 msgid "Super"
 msgstr "Super"
@@ -1365,8 +1363,8 @@ msgstr "Super"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:909 gtk/gtkshortcutlabel.c:116
-#: gtk/gtkshortcutlabel.c:145
+#: gtk/gtkaccelgroup.c:909 gtk/deprecated/gtkshortcutlabel.c:118
+#: gtk/deprecated/gtkshortcutlabel.c:147
 msgctxt "keyboard label"
 msgid "Hyper"
 msgstr "Hyper"
@@ -1376,8 +1374,8 @@ msgstr "Hyper"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:924 gtk/gtkshortcutlabel.c:110
-#: gtk/gtkshortcutlabel.c:148
+#: gtk/gtkaccelgroup.c:924 gtk/deprecated/gtkshortcutlabel.c:112
+#: gtk/deprecated/gtkshortcutlabel.c:150
 msgctxt "keyboard label"
 msgid "Meta"
 msgstr "Meta"
@@ -1396,432 +1394,432 @@ msgctxt "keyboard label"
 msgid "Space"
 msgstr "Spacja"
 
-#: gtk/gtkaccelgroup.c:954 gtk/gtkshortcutlabel.c:176
+#: gtk/gtkaccelgroup.c:954 gtk/deprecated/gtkshortcutlabel.c:178
 msgctxt "keyboard label"
 msgid "Backslash"
 msgstr "\\"
 
-#: gtk/gtkaccessible.c:790
+#: gtk/gtkaccessible.c:827
 msgctxt "accessibility"
 msgid "alert"
 msgstr "alarm"
 
-#: gtk/gtkaccessible.c:791
+#: gtk/gtkaccessible.c:828
 msgctxt "accessibility"
 msgid "alert dialog"
 msgstr "okno alarmu"
 
-#: gtk/gtkaccessible.c:792
+#: gtk/gtkaccessible.c:829
 msgctxt "accessibility"
 msgid "banner"
 msgstr "baner"
 
-#: gtk/gtkaccessible.c:793
+#: gtk/gtkaccessible.c:830
 msgctxt "accessibility"
 msgid "button"
 msgstr "przycisk"
 
-#: gtk/gtkaccessible.c:794
+#: gtk/gtkaccessible.c:831
 msgctxt "accessibility"
 msgid "caption"
 msgstr "podpis"
 
-#: gtk/gtkaccessible.c:795
+#: gtk/gtkaccessible.c:832
 msgctxt "accessibility"
 msgid "cell"
 msgstr "komórka"
 
-#: gtk/gtkaccessible.c:796
+#: gtk/gtkaccessible.c:833
 msgctxt "accessibility"
 msgid "checkbox"
 msgstr "pole wyboru"
 
-#: gtk/gtkaccessible.c:797
+#: gtk/gtkaccessible.c:834
 msgctxt "accessibility"
 msgid "column header"
 msgstr "nagłówek kolumny"
 
-#: gtk/gtkaccessible.c:798
+#: gtk/gtkaccessible.c:835
 msgctxt "accessibility"
 msgid "combo box"
 msgstr "pole rozwijane"
 
-#: gtk/gtkaccessible.c:799
+#: gtk/gtkaccessible.c:836
 msgctxt "accessibility"
 msgid "command"
 msgstr "polecenie"
 
-#: gtk/gtkaccessible.c:800
+#: gtk/gtkaccessible.c:837
 msgctxt "accessibility"
 msgid "composite"
 msgstr "składane"
 
-#: gtk/gtkaccessible.c:801
+#: gtk/gtkaccessible.c:838
 msgctxt "accessibility"
 msgid "dialog"
 msgstr "okno dialogowe"
 
-#: gtk/gtkaccessible.c:802
+#: gtk/gtkaccessible.c:839
 msgctxt "accessibility"
 msgid "document"
 msgstr "dokument"
 
-#: gtk/gtkaccessible.c:803
+#: gtk/gtkaccessible.c:840
 msgctxt "accessibility"
 msgid "feed"
 msgstr "kanał"
 
-#: gtk/gtkaccessible.c:804
+#: gtk/gtkaccessible.c:841
 msgctxt "accessibility"
 msgid "form"
 msgstr "formularz"
 
-#: gtk/gtkaccessible.c:805
+#: gtk/gtkaccessible.c:842
 msgctxt "accessibility"
 msgid "generic"
 msgstr "ogólne"
 
-#: gtk/gtkaccessible.c:806
+#: gtk/gtkaccessible.c:843
 msgctxt "accessibility"
 msgid "grid"
 msgstr "siatka"
 
-#: gtk/gtkaccessible.c:807
+#: gtk/gtkaccessible.c:844
 msgctxt "accessibility"
 msgid "grid cell"
 msgstr "komórka siatki"
 
-#: gtk/gtkaccessible.c:808
+#: gtk/gtkaccessible.c:845
 msgctxt "accessibility"
 msgid "group"
 msgstr "grupa"
 
-#: gtk/gtkaccessible.c:809
+#: gtk/gtkaccessible.c:846
 msgctxt "accessibility"
 msgid "heading"
 msgstr "nagłówek"
 
-#: gtk/gtkaccessible.c:810
+#: gtk/gtkaccessible.c:847
 msgctxt "accessibility"
 msgid "image"
 msgstr "obraz"
 
-#: gtk/gtkaccessible.c:811
+#: gtk/gtkaccessible.c:848
 msgctxt "accessibility"
 msgid "input"
 msgstr "wejście"
 
-#: gtk/gtkaccessible.c:812
+#: gtk/gtkaccessible.c:849
 msgctxt "accessibility"
 msgid "label"
 msgstr "etykieta"
 
-#: gtk/gtkaccessible.c:813
+#: gtk/gtkaccessible.c:850
 msgctxt "accessibility"
 msgid "landmark"
 msgstr "punkt orientacyjny"
 
-#: gtk/gtkaccessible.c:814
+#: gtk/gtkaccessible.c:851
 msgctxt "accessibility"
 msgid "legend"
 msgstr "legenda"
 
-#: gtk/gtkaccessible.c:815
+#: gtk/gtkaccessible.c:852
 msgctxt "accessibility"
 msgid "link"
 msgstr "odnośnik"
 
-#: gtk/gtkaccessible.c:816
+#: gtk/gtkaccessible.c:853
 msgctxt "accessibility"
 msgid "list"
 msgstr "lista"
 
-#: gtk/gtkaccessible.c:817
+#: gtk/gtkaccessible.c:854
 msgctxt "accessibility"
 msgid "list box"
 msgstr "pole listy"
 
-#: gtk/gtkaccessible.c:818
+#: gtk/gtkaccessible.c:855
 msgctxt "accessibility"
 msgid "list item"
 msgstr "element listy"
 
-#: gtk/gtkaccessible.c:819
+#: gtk/gtkaccessible.c:856
 msgctxt "accessibility"
 msgid "log"
 msgstr "dziennik"
 
-#: gtk/gtkaccessible.c:820
+#: gtk/gtkaccessible.c:857
 msgctxt "accessibility"
 msgid "main"
 msgstr "główne"
 
-#: gtk/gtkaccessible.c:821
+#: gtk/gtkaccessible.c:858
 msgctxt "accessibility"
 msgid "marquee"
 msgstr "obwódka"
 
-#: gtk/gtkaccessible.c:822
+#: gtk/gtkaccessible.c:859
 msgctxt "accessibility"
 msgid "math"
 msgstr "matematyka"
 
-#: gtk/gtkaccessible.c:823
+#: gtk/gtkaccessible.c:860
 msgctxt "accessibility"
 msgid "meter"
 msgstr "licznik"
 
-#: gtk/gtkaccessible.c:824
+#: gtk/gtkaccessible.c:861
 msgctxt "accessibility"
 msgid "menu"
 msgstr "menu"
 
-#: gtk/gtkaccessible.c:825
+#: gtk/gtkaccessible.c:862
 msgctxt "accessibility"
 msgid "menu bar"
 msgstr "pasek menu"
 
-#: gtk/gtkaccessible.c:826
+#: gtk/gtkaccessible.c:863
 msgctxt "accessibility"
 msgid "menu item"
 msgstr "element menu"
 
-#: gtk/gtkaccessible.c:827
+#: gtk/gtkaccessible.c:864
 msgctxt "accessibility"
 msgid "menu item checkbox"
 msgstr "pole wyboru elementu menu"
 
-#: gtk/gtkaccessible.c:828
+#: gtk/gtkaccessible.c:865
 msgctxt "accessibility"
 msgid "menu item radio"
 msgstr "pole pojedynczego wyboru elementu menu"
 
-#: gtk/gtkaccessible.c:829
+#: gtk/gtkaccessible.c:866
 msgctxt "accessibility"
 msgid "navigation"
 msgstr "nawigacja"
 
-#: gtk/gtkaccessible.c:830
+#: gtk/gtkaccessible.c:867
 msgctxt "accessibility"
 msgid "none"
 msgstr "brak"
 
-#: gtk/gtkaccessible.c:831
+#: gtk/gtkaccessible.c:868
 msgctxt "accessibility"
 msgid "note"
 msgstr "uwaga"
 
-#: gtk/gtkaccessible.c:832
+#: gtk/gtkaccessible.c:869
 msgctxt "accessibility"
 msgid "option"
 msgstr "opcja"
 
-#: gtk/gtkaccessible.c:833
+#: gtk/gtkaccessible.c:870
 msgctxt "accessibility"
 msgid "presentation"
 msgstr "prezentacja"
 
-#: gtk/gtkaccessible.c:834
+#: gtk/gtkaccessible.c:871
 msgctxt "accessibility"
 msgid "progress bar"
 msgstr "pasek postępu"
 
-#: gtk/gtkaccessible.c:835
+#: gtk/gtkaccessible.c:872
 msgctxt "accessibility"
 msgid "radio"
 msgstr "pole pojedynczego wyboru"
 
-#: gtk/gtkaccessible.c:836
+#: gtk/gtkaccessible.c:873
 msgctxt "accessibility"
 msgid "radio group"
 msgstr "grupa pól pojedynczego wyboru"
 
-#: gtk/gtkaccessible.c:837
+#: gtk/gtkaccessible.c:874
 msgctxt "accessibility"
 msgid "range"
 msgstr "zakres"
 
-#: gtk/gtkaccessible.c:838
+#: gtk/gtkaccessible.c:875
 msgctxt "accessibility"
 msgid "region"
 msgstr "obszar"
 
-#: gtk/gtkaccessible.c:839
+#: gtk/gtkaccessible.c:876
 msgctxt "accessibility"
 msgid "row"
 msgstr "rzÄ…d"
 
-#: gtk/gtkaccessible.c:840
+#: gtk/gtkaccessible.c:877
 msgctxt "accessibility"
 msgid "row group"
 msgstr "grupa rzędów"
 
-#: gtk/gtkaccessible.c:841
+#: gtk/gtkaccessible.c:878
 msgctxt "accessibility"
 msgid "row header"
 msgstr "nagłówek rzędu"
 
-#: gtk/gtkaccessible.c:842
+#: gtk/gtkaccessible.c:879
 msgctxt "accessibility"
 msgid "scroll bar"
 msgstr "pasek przewijania"
 
-#: gtk/gtkaccessible.c:843
+#: gtk/gtkaccessible.c:880
 msgctxt "accessibility"
 msgid "search"
 msgstr "wyszukiwanie"
 
-#: gtk/gtkaccessible.c:844
+#: gtk/gtkaccessible.c:881
 msgctxt "accessibility"
 msgid "search box"
 msgstr "pole wyszukiwania"
 
-#: gtk/gtkaccessible.c:845
+#: gtk/gtkaccessible.c:882
 msgctxt "accessibility"
 msgid "section"
 msgstr "sekcja"
 
-#: gtk/gtkaccessible.c:846
+#: gtk/gtkaccessible.c:883
 msgctxt "accessibility"
 msgid "section head"
 msgstr "nagłówek sekcji"
 
-#: gtk/gtkaccessible.c:847
+#: gtk/gtkaccessible.c:884
 msgctxt "accessibility"
 msgid "select"
 msgstr "wybór"
 
-#: gtk/gtkaccessible.c:848
+#: gtk/gtkaccessible.c:885
 msgctxt "accessibility"
 msgid "separator"
 msgstr "separator"
 
-#: gtk/gtkaccessible.c:849
+#: gtk/gtkaccessible.c:886
 msgctxt "accessibility"
 msgid "slider"
 msgstr "suwak"
 
-#: gtk/gtkaccessible.c:850
+#: gtk/gtkaccessible.c:887
 msgctxt "accessibility"
 msgid "spin button"
 msgstr "przycisk liczbowy"
 
-#: gtk/gtkaccessible.c:851
+#: gtk/gtkaccessible.c:888
 msgctxt "accessibility"
 msgid "status"
 msgstr "stan"
 
-#: gtk/gtkaccessible.c:852
+#: gtk/gtkaccessible.c:889
 msgctxt "accessibility"
 msgid "structure"
 msgstr "struktura"
 
-#: gtk/gtkaccessible.c:853
+#: gtk/gtkaccessible.c:890
 msgctxt "accessibility"
 msgid "switch"
 msgstr "przełącznik"
 
-#: gtk/gtkaccessible.c:854
+#: gtk/gtkaccessible.c:891
 msgctxt "accessibility"
 msgid "tab"
 msgstr "tabulacja"
 
-#: gtk/gtkaccessible.c:855
+#: gtk/gtkaccessible.c:892
 msgctxt "accessibility"
 msgid "table"
 msgstr "tabela"
 
-#: gtk/gtkaccessible.c:856
+#: gtk/gtkaccessible.c:893
 msgctxt "accessibility"
 msgid "tab list"
 msgstr "lista tabeli"
 
-#: gtk/gtkaccessible.c:857
+#: gtk/gtkaccessible.c:894
 msgctxt "accessibility"
 msgid "tab panel"
 msgstr "panel tabeli"
 
-#: gtk/gtkaccessible.c:858
+#: gtk/gtkaccessible.c:895
 msgctxt "accessibility"
 msgid "text box"
 msgstr "pole tekstowe"
 
-#: gtk/gtkaccessible.c:859
+#: gtk/gtkaccessible.c:896
 msgctxt "accessibility"
 msgid "time"
 msgstr "czas"
 
-#: gtk/gtkaccessible.c:860
+#: gtk/gtkaccessible.c:897
 msgctxt "accessibility"
 msgid "timer"
 msgstr "minutnik"
 
-#: gtk/gtkaccessible.c:861
+#: gtk/gtkaccessible.c:898
 msgctxt "accessibility"
 msgid "tool bar"
 msgstr "pasek narzędziowy"
 
-#: gtk/gtkaccessible.c:862
+#: gtk/gtkaccessible.c:899
 msgctxt "accessibility"
 msgid "tool tip"
 msgstr "podpowiedź"
 
-#: gtk/gtkaccessible.c:863
+#: gtk/gtkaccessible.c:900
 msgctxt "accessibility"
 msgid "tree"
 msgstr "drzewo"
 
-#: gtk/gtkaccessible.c:864
+#: gtk/gtkaccessible.c:901
 msgctxt "accessibility"
 msgid "tree grid"
 msgstr "siatka drzewa"
 
-#: gtk/gtkaccessible.c:865
+#: gtk/gtkaccessible.c:902
 msgctxt "accessibility"
 msgid "tree item"
 msgstr "element drzewa"
 
-#: gtk/gtkaccessible.c:866
+#: gtk/gtkaccessible.c:903
 msgctxt "accessibility"
 msgid "widget"
 msgstr "widżet"
 
-#: gtk/gtkaccessible.c:867
+#: gtk/gtkaccessible.c:904
 msgctxt "accessibility"
 msgid "window"
 msgstr "okno"
 
-#: gtk/gtkaccessible.c:868
+#: gtk/gtkaccessible.c:905
 msgctxt "accessibility"
 msgid "toggle button"
 msgstr "przycisk przełączania"
 
-#: gtk/gtkaccessible.c:870
+#: gtk/gtkaccessible.c:907
 msgctxt "accessibility"
 msgid "paragraph"
 msgstr "akapit"
 
-#: gtk/gtkaccessible.c:871
+#: gtk/gtkaccessible.c:908
 msgctxt "accessibility"
 msgid "block quote"
 msgstr "cytat blokowy"
 
-#: gtk/gtkaccessible.c:872
+#: gtk/gtkaccessible.c:909
 msgctxt "accessibility"
 msgid "article"
 msgstr "artykuł"
 
-#: gtk/gtkaccessible.c:873
+#: gtk/gtkaccessible.c:910
 msgctxt "accessibility"
 msgid "comment"
 msgstr "komentarz"
 
-#: gtk/gtkaccessible.c:874
+#: gtk/gtkaccessible.c:911
 msgctxt "accessibility"
 msgid "terminal"
 msgstr "terminal"
 
-#: gtk/gtkalertdialog.c:667 gtk/print/gtkcustompaperunixdialog.c:322
+#: gtk/gtkalertdialog.c:666 gtk/print/gtkcustompaperunixdialog.c:322
 #: gtk/gtkmessagedialog.c:166 gtk/ui/gtkassistant.ui:40
 msgid "_Close"
 msgstr "Za_mknij"
@@ -1830,11 +1828,11 @@ msgstr "Za_mknij"
 #. * suspend or screen locking, and the caller hasn't specified
 #. * a reason.
 #.
-#: gtk/gtkapplication-dbus.c:721 gtk/gtkapplication-dbus.c:763
+#: gtk/gtkapplication-dbus.c:728 gtk/gtkapplication-dbus.c:770
 msgid "Reason not specified"
 msgstr "Nie podano powodu"
 
-#: gtk/gtkapplicationwindow.c:236
+#: gtk/gtkapplicationwindow.c:235
 msgid "Menu bar"
 msgstr "Pasek menu"
 
@@ -1867,7 +1865,7 @@ msgstr "Tekst nie może pojawiać się wewnątrz <%s>"
 #. * first day of the week to calendar:week_start:1 if you want Monday
 #. * to be the first day of the week, and so on.
 #.
-#: gtk/gtkcalendar.c:670
+#: gtk/gtkcalendar.c:669
 msgid "calendar:week_start:0"
 msgstr "calendar:week_start:1"
 
@@ -1881,7 +1879,7 @@ msgstr "calendar:week_start:1"
 #. * text direction of RTL and specify "calendar:YM", then the year
 #. * will appear to the right of the month.
 #.
-#: gtk/gtkcalendar.c:821
+#: gtk/gtkcalendar.c:820
 msgid "calendar:MY"
 msgstr "calendar:MY"
 
@@ -1895,7 +1893,7 @@ msgstr "calendar:MY"
 #. * digits. That needs support from your system and locale definition
 #. * too.
 #.
-#: gtk/gtkcalendar.c:1002
+#: gtk/gtkcalendar.c:1001
 #, c-format
 msgctxt "calendar:day:digits"
 msgid "%d"
@@ -1907,7 +1905,7 @@ msgstr "%d"
 #. *
 #. * "%Y" is appropriate for most locales.
 #.
-#: gtk/gtkcalendar.c:1106
+#: gtk/gtkcalendar.c:1105
 msgctxt "calendar year format"
 msgid "%Y"
 msgstr "%Y"
@@ -1920,7 +1918,7 @@ msgstr "%Y"
 #. * Note that translating this doesn't guarantee that you get localized
 #. * digits. That needs support from your system and locale definition
 #. * too.
-#: gtk/gtkcalendar.c:1152
+#: gtk/gtkcalendar.c:1151
 #, c-format
 msgctxt "calendar:week:digits"
 msgid "%d"
@@ -2189,7 +2187,7 @@ msgid "Margins from Printer…"
 msgstr "Marginesy z drukarki…"
 
 #. And show the custom paper dialog
-#: gtk/print/gtkcustompaperunixdialog.c:377 gtk/print/gtkprintunixdialog.c:2975
+#: gtk/print/gtkcustompaperunixdialog.c:377 gtk/print/gtkprintunixdialog.c:2949
 msgid "Manage Custom Sizes"
 msgstr "ZarzÄ…dzanie niestandardowymi rozmiarami"
 
@@ -2240,11 +2238,15 @@ msgstr "_Prawy:"
 msgid "Paper Margins"
 msgstr "Marginesy papieru"
 
-#: gtk/gtkentry.c:3685
+#: gtk/gtkentry.c:3684
 msgid "Insert Emoji"
 msgstr "Wstawia emoji"
 
-#: gtk/gtkfilechooserdialog.c:557
+#: gtk/gtkfilechooserdialog.c:481
+msgid "Search"
+msgstr "Wyszukaj"
+
+#: gtk/gtkfilechooserdialog.c:562
 msgid "_Name"
 msgstr "_Nazwa"
 
@@ -2304,28 +2306,33 @@ msgstr "Katalog o tej nazwie już istnieje"
 msgid "A file with that name already exists"
 msgstr "Plik o tej nazwie już istnieje"
 
-#: gtk/gtkfilechoosernative.c:520 gtk/gtkfilechoosernative.c:600
-#: gtk/gtkfilechooserwidget.c:1213 gtk/gtkfilechooserwidget.c:5017
-#: gtk/gtkfiledialog.c:840 gtk/gtkmessagedialog.c:170
+#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:4988
+#: gtk/gtkfiledialog.c:913 gtk/gtkmessagedialog.c:170
 #: gtk/gtkmessagedialog.c:179 gtk/gtkmountoperation.c:608
 #: gtk/print/gtkpagesetupunixdialog.c:282 gtk/print/gtkprintbackend.c:638
-#: gtk/print/gtkprintunixdialog.c:682 gtk/print/gtkprintunixdialog.c:839
-#: gtk/gtkwindow.c:6211 gtk/ui/gtkappchooserdialog.ui:48
+#: gtk/print/gtkprintunixdialog.c:680 gtk/print/gtkprintunixdialog.c:837
+#: gtk/gtkwindow.c:6327 gtk/ui/gtkappchooserdialog.ui:48
 #: gtk/ui/gtkassistant.ui:52 gtk/ui/gtkcolorchooserdialog.ui:36
-#: gtk/ui/gtkfontchooserdialog.ui:27
+#: gtk/ui/gtkfontchooserdialog.ui:29
 msgid "_Cancel"
 msgstr "_Anuluj"
 
-#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594
-#: gtk/gtkfiledialog.c:812 gtk/gtkplacessidebar.c:3149
-#: gtk/gtkplacessidebar.c:3234 gtk/gtkplacesview.c:1645
+#: gtk/gtkfilechoosernative.c:522 gtk/gtkfilechoosernative.c:588
+#: gtk/gtkfiledialog.c:885 gtk/gtkplacessidebar.c:3149
+#: gtk/gtkplacessidebar.c:3234 gtk/gtkplacesview.c:1646
 msgid "_Open"
 msgstr "_Otwórz"
 
-#: gtk/gtkfilechoosernative.c:594 gtk/gtkfiledialog.c:817
+#: gtk/gtkfilechoosernative.c:588 gtk/gtkfiledialog.c:890
 msgid "_Save"
 msgstr "_Zapisz"
 
+#: gtk/gtkfilechoosernativeportal.c:499
+#, c-format
+msgid "The session bus is not available"
+msgstr "Magistrala sesji jest niedostępna"
+
 #: gtk/gtkfilechoosernativequartz.c:348 gtk/ui/gtkfilechooserwidget.ui:299
 msgid "Select which types of files are shown"
 msgstr "Wybór typów wyświetlanych plików"
@@ -2339,242 +2346,242 @@ msgstr "Wybór typów wyświetlanych plików"
 msgid "%1$s on %2$s"
 msgstr "%1$s na %2$s"
 
-#: gtk/gtkfilechooserwidget.c:364
+#: gtk/gtkfilechooserwidget.c:365
 msgid "Type name of new folder"
 msgstr "Nazwa nowego katalogu"
 
-#: gtk/gtkfilechooserwidget.c:751
+#: gtk/gtkfilechooserwidget.c:752
 msgid "The folder could not be created"
 msgstr "Nie można utworzyć katalogu"
 
-#: gtk/gtkfilechooserwidget.c:764
+#: gtk/gtkfilechooserwidget.c:765
 msgid "You need to choose a valid filename."
 msgstr "Należy wybrać prawidłową nazwę pliku."
 
-#: gtk/gtkfilechooserwidget.c:767
+#: gtk/gtkfilechooserwidget.c:768
 #, c-format
 msgid "Cannot create a file under %s as it is not a folder"
 msgstr "Nie można utworzyć pliku w %s, ponieważ nie jest katalogiem"
 
-#: gtk/gtkfilechooserwidget.c:777
+#: gtk/gtkfilechooserwidget.c:778
 msgid "Cannot create file as the filename is too long"
 msgstr "Nie można utworzyć pliku, ponieważ jego nazwa jest za długa"
 
-#: gtk/gtkfilechooserwidget.c:778
+#: gtk/gtkfilechooserwidget.c:779
 msgid "Try using a shorter name."
 msgstr "Proszę spróbować krótszej nazwy."
 
-#: gtk/gtkfilechooserwidget.c:788
+#: gtk/gtkfilechooserwidget.c:789
 msgid "You may only select folders"
 msgstr "Można wybierać tylko katalogi"
 
-#: gtk/gtkfilechooserwidget.c:789
+#: gtk/gtkfilechooserwidget.c:790
 msgid "The item that you selected is not a folder try using a different item."
 msgstr ""
 "Wybrany element nie jest katalogiem, proszę spróbować użyć innego elementu."
 
-#: gtk/gtkfilechooserwidget.c:797
+#: gtk/gtkfilechooserwidget.c:798
 msgid "Invalid file name"
 msgstr "Nieprawidłowa nazwa pliku"
 
-#: gtk/gtkfilechooserwidget.c:806
+#: gtk/gtkfilechooserwidget.c:807
 msgid "The folder contents could not be displayed"
 msgstr "Nie można wyświetlić zawartości katalogu"
 
-#: gtk/gtkfilechooserwidget.c:814
+#: gtk/gtkfilechooserwidget.c:815
 msgid "The file could not be deleted"
 msgstr "Nie można usunąć pliku"
 
-#: gtk/gtkfilechooserwidget.c:822
+#: gtk/gtkfilechooserwidget.c:823
 msgid "The file could not be moved to the Trash"
 msgstr "Nie można przenieść pliku do kosza"
 
-#: gtk/gtkfilechooserwidget.c:1211
+#: gtk/gtkfilechooserwidget.c:1212
 #, c-format
 msgid "Are you sure you want to permanently delete “%s”?"
 msgstr "Na pewno trwale usunąć „%s”?"
 
-#: gtk/gtkfilechooserwidget.c:1212
+#: gtk/gtkfilechooserwidget.c:1213
 msgid "If you delete an item, it will be permanently lost."
 msgstr "Jeśli element zostanie usunięty, to zostanie on bezpowrotnie utracony."
 
-#: gtk/gtkfilechooserwidget.c:1213 gtk/gtkfilechooserwidget.c:1815
-#: gtk/gtklabel.c:5883 gtk/gtktext.c:6334 gtk/gtktextview.c:9237
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:1816
+#: gtk/gtklabel.c:5897 gtk/gtktext.c:6330 gtk/gtktextview.c:9327
 msgid "_Delete"
 msgstr "_Usuń"
 
-#: gtk/gtkfilechooserwidget.c:1330
+#: gtk/gtkfilechooserwidget.c:1331
 msgid "The file could not be renamed"
 msgstr "Nie można zmienić nazwy pliku"
 
-#: gtk/gtkfilechooserwidget.c:1506
+#: gtk/gtkfilechooserwidget.c:1507
 msgid "Could not select file"
 msgstr "Nie można wybrać pliku"
 
-#: gtk/gtkfilechooserwidget.c:1726 gtk/ui/gtkfilechooserwidget.ui:66
+#: gtk/gtkfilechooserwidget.c:1727 gtk/ui/gtkfilechooserwidget.ui:66
 msgid "Grid View"
 msgstr "Widok siatki"
 
-#: gtk/gtkfilechooserwidget.c:1732
+#: gtk/gtkfilechooserwidget.c:1733
 msgid "List View"
 msgstr "Widok listy"
 
-#: gtk/gtkfilechooserwidget.c:1795
+#: gtk/gtkfilechooserwidget.c:1796
 msgid "_Visit File"
 msgstr "Od_wiedź plik"
 
-#: gtk/gtkfilechooserwidget.c:1799
+#: gtk/gtkfilechooserwidget.c:1800
 msgid "_Open With File Manager"
 msgstr "_Otwórz w menedżerze plików"
 
-#: gtk/gtkfilechooserwidget.c:1803
+#: gtk/gtkfilechooserwidget.c:1804
 msgid "_Copy Location"
 msgstr "S_kopiuj położenie"
 
-#: gtk/gtkfilechooserwidget.c:1807
+#: gtk/gtkfilechooserwidget.c:1808
 msgid "_Add to Bookmarks"
 msgstr "_Dodaj zakładkę"
 
-#: gtk/gtkfilechooserwidget.c:1811 gtk/gtkplacessidebar.c:2312
-#: gtk/gtkplacessidebar.c:3270 gtk/ui/gtkfilechooserwidget.ui:421
+#: gtk/gtkfilechooserwidget.c:1812 gtk/gtkplacessidebar.c:2312
+#: gtk/gtkplacessidebar.c:3270 gtk/ui/gtkfilechooserwidget.ui:417
 msgid "_Rename"
 msgstr "Z_mień nazwę"
 
-#: gtk/gtkfilechooserwidget.c:1819
+#: gtk/gtkfilechooserwidget.c:1820
 msgid "_Move to Trash"
 msgstr "_PrzenieÅ› do kosza"
 
-#: gtk/gtkfilechooserwidget.c:1828
+#: gtk/gtkfilechooserwidget.c:1829
 msgid "Show _Hidden Files"
 msgstr "_Ukryte pliki"
 
-#: gtk/gtkfilechooserwidget.c:1832
+#: gtk/gtkfilechooserwidget.c:1833
 msgid "Sort _Folders Before Files"
 msgstr "K_atalogi przed plikami"
 
-#: gtk/gtkfilechooserwidget.c:1955 gtk/gtkfilechooserwidget.c:1985
-#: gtk/gtkfilechooserwidget.c:3890
+#: gtk/gtkfilechooserwidget.c:1956 gtk/gtkfilechooserwidget.c:1986
+#: gtk/gtkfilechooserwidget.c:3861
 msgid "Unknown"
 msgstr "Nieznane"
 
-#: gtk/gtkfilechooserwidget.c:2040 gtk/gtkplacessidebar.c:1025
+#: gtk/gtkfilechooserwidget.c:2041 gtk/gtkplacessidebar.c:1025
 msgid "Home"
 msgstr "Katalog domowy"
 
 #. this is the header for the location column in the print dialog
-#: gtk/gtkfilechooserwidget.c:2195 gtk/gtkfilechooserwidget.c:7439
+#: gtk/gtkfilechooserwidget.c:2196 gtk/gtkfilechooserwidget.c:7420
 #: gtk/inspector/css-node-tree.ui:76 gtk/print/ui/gtkprintunixdialog.ui:111
 msgid "Location"
 msgstr "Położenie"
 
 #. Label
-#: gtk/gtkfilechooserwidget.c:2302
+#: gtk/gtkfilechooserwidget.c:2303
 msgid "_Name:"
 msgstr "_Nazwa:"
 
-#: gtk/gtkfilechooserwidget.c:2859 gtk/gtkfilechooserwidget.c:2873
+#: gtk/gtkfilechooserwidget.c:2860 gtk/gtkfilechooserwidget.c:2874
 #, c-format
 msgid "Searching in %s"
 msgstr "Wyszukiwanie w „%s”"
 
-#: gtk/gtkfilechooserwidget.c:2879
+#: gtk/gtkfilechooserwidget.c:2880
 msgid "Searching"
 msgstr "Wyszukiwanie"
 
-#: gtk/gtkfilechooserwidget.c:2885
+#: gtk/gtkfilechooserwidget.c:2886
 msgid "Enter location or URL"
 msgstr "Proszę wprowadzić położenie lub adres URL"
 
-#: gtk/gtkfilechooserwidget.c:3444 gtk/gtkfilechooserwidget.c:5804
-#: gtk/gtkfilechooserwidget.c:7461
+#: gtk/gtkfilechooserwidget.c:3445 gtk/gtkfilechooserwidget.c:5775
+#: gtk/gtkfilechooserwidget.c:7442
 msgid "Modified"
 msgstr "Modyfikacja"
 
-#: gtk/gtkfilechooserwidget.c:3629
+#: gtk/gtkfilechooserwidget.c:3630
 #, c-format
 msgid "Could not read the contents of %s"
 msgstr "Nie można odczytać zawartości „%s”"
 
-#: gtk/gtkfilechooserwidget.c:3633
+#: gtk/gtkfilechooserwidget.c:3634
 msgid "Could not read the contents of the folder"
 msgstr "Nie można odczytać zawartości katalogu"
 
 #. Translators: see g_date_time_format() for details on the format
-#: gtk/gtkfilechooserwidget.c:3784 gtk/gtkfilechooserwidget.c:3828
+#: gtk/gtkfilechooserwidget.c:3757 gtk/gtkfilechooserwidget.c:3800
 msgid "%H:%M"
 msgstr "%H∶%M"
 
-#: gtk/gtkfilechooserwidget.c:3786 gtk/gtkfilechooserwidget.c:3830
+#: gtk/gtkfilechooserwidget.c:3759 gtk/gtkfilechooserwidget.c:3802
 msgid "%l:%M %p"
 msgstr "%-l∶%M %p"
 
-#: gtk/gtkfilechooserwidget.c:3790
+#: gtk/gtkfilechooserwidget.c:3763
 msgid "Yesterday"
 msgstr "Wczoraj"
 
-#: gtk/gtkfilechooserwidget.c:3799
+#: gtk/gtkfilechooserwidget.c:3772
 #, no-c-format
 msgid "%-e %b"
 msgstr "%-d %b"
 
-#: gtk/gtkfilechooserwidget.c:3803
+#: gtk/gtkfilechooserwidget.c:3776
 msgid "%-e %b %Y"
 msgstr "%-d %b %Y"
 
-#: gtk/gtkfilechooserwidget.c:3845 gtk/gtkfilechooserwidget.c:3853
+#: gtk/gtkfilechooserwidget.c:3816 gtk/gtkfilechooserwidget.c:3824
 msgid "Program"
 msgstr "Program"
 
-#: gtk/gtkfilechooserwidget.c:3846
+#: gtk/gtkfilechooserwidget.c:3817
 msgid "Audio"
 msgstr "Dźwięk"
 
-#: gtk/gtkfilechooserwidget.c:3848 gtk/gtkfilefilter.c:1013
+#: gtk/gtkfilechooserwidget.c:3819 gtk/gtkfilefilter.c:1069
 msgid "Image"
 msgstr "Obraz"
 
-#: gtk/gtkfilechooserwidget.c:3849
+#: gtk/gtkfilechooserwidget.c:3820
 msgid "Archive"
 msgstr "Archiwum"
 
-#: gtk/gtkfilechooserwidget.c:3850
+#: gtk/gtkfilechooserwidget.c:3821
 msgid "Markup"
 msgstr "Hipertekst"
 
-#: gtk/gtkfilechooserwidget.c:3851 gtk/gtkfilechooserwidget.c:3852
+#: gtk/gtkfilechooserwidget.c:3822 gtk/gtkfilechooserwidget.c:3823
 msgid "Text"
 msgstr "Tekst"
 
-#: gtk/gtkfilechooserwidget.c:3854
+#: gtk/gtkfilechooserwidget.c:3825
 msgid "Video"
 msgstr "Wideo"
 
-#: gtk/gtkfilechooserwidget.c:3855
+#: gtk/gtkfilechooserwidget.c:3826
 msgid "Contacts"
 msgstr "Kontakty"
 
-#: gtk/gtkfilechooserwidget.c:3856
+#: gtk/gtkfilechooserwidget.c:3827
 msgid "Calendar"
 msgstr "Kalendarz"
 
-#: gtk/gtkfilechooserwidget.c:3857
+#: gtk/gtkfilechooserwidget.c:3828
 msgid "Document"
 msgstr "Dokument"
 
-#: gtk/gtkfilechooserwidget.c:3858
+#: gtk/gtkfilechooserwidget.c:3829
 msgid "Presentation"
 msgstr "Prezentacja"
 
-#: gtk/gtkfilechooserwidget.c:3859
+#: gtk/gtkfilechooserwidget.c:3830
 msgid "Spreadsheet"
 msgstr "Arkusz kalkulacyjny"
 
-#: gtk/gtkfilechooserwidget.c:5009 gtk/print/gtkprintunixdialog.c:673
+#: gtk/gtkfilechooserwidget.c:4980 gtk/print/gtkprintunixdialog.c:671
 #, c-format
 msgid "A file named “%s” already exists.  Do you want to replace it?"
 msgstr "Plik o nazwie „%s” już istnieje. Zastąpić go?"
 
-#: gtk/gtkfilechooserwidget.c:5011 gtk/print/gtkprintunixdialog.c:677
+#: gtk/gtkfilechooserwidget.c:4982 gtk/print/gtkprintunixdialog.c:675
 #, c-format
 msgid ""
 "The file already exists in “%s”.  Replacing it will overwrite its contents."
@@ -2582,77 +2589,85 @@ msgstr ""
 "Plik już istnieje w „%s”. Zastąpienie go spowoduje nadpisanie jego "
 "zawartości."
 
-#: gtk/gtkfilechooserwidget.c:5017 gtk/print/gtkprintunixdialog.c:685
+#: gtk/gtkfilechooserwidget.c:4988 gtk/print/gtkprintunixdialog.c:683
 msgid "_Replace"
 msgstr "_ZastÄ…p"
 
-#: gtk/gtkfilechooserwidget.c:5172
+#: gtk/gtkfilechooserwidget.c:5143
 msgid "You do not have access to the specified folder."
 msgstr "Brak dostępu do podanego katalogu."
 
-#: gtk/gtkfilechooserwidget.c:5751
+#: gtk/gtkfilechooserwidget.c:5722
 msgid "Could not send the search request"
 msgstr "Nie można wysłać żądania wyszukiwania"
 
-#: gtk/gtkfilechooserwidget.c:6032
+#: gtk/gtkfilechooserwidget.c:6003
 msgid "Accessed"
 msgstr "Dostęp"
 
-#: gtk/gtkfilechooserwidget.c:7417
+#: gtk/gtkfilechooserwidget.c:7398
 msgid "_Size"
 msgstr "_Rozmiar"
 
-#: gtk/gtkfilechooserwidget.c:7421
+#: gtk/gtkfilechooserwidget.c:7402
 msgid "T_ype"
 msgstr "_Typ"
 
-#: gtk/gtkfilechooserwidget.c:7425
+#: gtk/gtkfilechooserwidget.c:7406
 msgid "_Time"
 msgstr "_Czas"
 
-#: gtk/gtkfilechooserwidget.c:7431 gtk/gtkplacessidebar.c:2306
+#: gtk/gtkfilechooserwidget.c:7412 gtk/gtkplacessidebar.c:2306
 #: gtk/inspector/a11y.ui:43 gtk/inspector/actions.ui:18
 #: gtk/inspector/css-node-tree.ui:22 gtk/inspector/prop-list.ui:24
-#: gtk/ui/gtkfilechooserwidget.ui:396 gtk/print/ui/gtkprintunixdialog.ui:80
+#: gtk/ui/gtkfilechooserwidget.ui:394 gtk/print/ui/gtkprintunixdialog.ui:80
 msgid "Name"
 msgstr "Nazwa"
 
-#: gtk/gtkfilechooserwidget.c:7448 gtk/inspector/resource-list.ui:82
-#: gtk/ui/gtkfontchooserwidget.ui:218 gtk/ui/gtkfontchooserwidget.ui:387
+#: gtk/gtkfilechooserwidget.c:7429 gtk/inspector/resource-list.ui:82
+#: gtk/ui/gtkfontchooserwidget.ui:216 gtk/ui/gtkfontchooserwidget.ui:382
 msgid "Size"
 msgstr "Rozmiar"
 
-#: gtk/gtkfilechooserwidget.c:7454 gtk/inspector/misc-info.ui:57
+#: gtk/gtkfilechooserwidget.c:7435 gtk/inspector/misc-info.ui:57
 #: gtk/inspector/prop-list.ui:35 gtk/inspector/statistics.ui:36
 msgid "Type"
 msgstr "Typ"
 
-#: gtk/gtkfiledialog.c:813
+#: gtk/gtkfiledialog.c:886
 msgid "Pick Files"
 msgstr "Wybór plików"
 
-#: gtk/gtkfiledialog.c:813
+#: gtk/gtkfiledialog.c:886
 msgid "Pick a File"
 msgstr "Wybór pliku"
 
-#: gtk/gtkfiledialog.c:818
+#: gtk/gtkfiledialog.c:891
 msgid "Save a File"
 msgstr "Zapis pliku"
 
-#: gtk/gtkfiledialog.c:822 gtk/ui/gtkappchooserdialog.ui:53
-#: gtk/ui/gtkcolorchooserdialog.ui:41 gtk/ui/gtkfontchooserdialog.ui:32
+#: gtk/gtkfiledialog.c:895 gtk/ui/gtkappchooserdialog.ui:53
+#: gtk/ui/gtkcolorchooserdialog.ui:41 gtk/ui/gtkfontchooserdialog.ui:34
 msgid "_Select"
 msgstr "_Wybierz"
 
-#: gtk/gtkfiledialog.c:823
+#: gtk/gtkfiledialog.c:896
 msgid "Select Folders"
 msgstr "Wybór katalogów"
 
-#: gtk/gtkfiledialog.c:823
+#: gtk/gtkfiledialog.c:896
 msgid "Select a Folder"
 msgstr "Wybór katalogu"
 
-#: gtk/gtkfilefilter.c:1026
+#: gtk/gtkfiledialog.c:1397 gtk/gtkfiledialog.c:1514 gtk/gtkfiledialog.c:1623
+msgid "Encoding"
+msgstr "Kodowanie"
+
+#: gtk/gtkfiledialog.c:1634
+msgid "Line Ending"
+msgstr "Koniec wiersza"
+
+#: gtk/gtkfilefilter.c:1082
 msgid "Unspecified"
 msgstr "Nieokreślone"
 
@@ -2695,35 +2710,39 @@ msgctxt "Font feature value"
 msgid "Enable"
 msgstr "Włączone"
 
-#: gtk/gtkfontchooserwidget.c:2403
+#: gtk/gtkfontchooserwidget.c:2406
 msgid "Default"
 msgstr "Domyślne"
 
-#: gtk/gtkfontchooserwidget.c:2465
+#: gtk/gtkfontchooserwidget.c:2469
 msgid "Ligatures"
 msgstr "Ligatury"
 
-#: gtk/gtkfontchooserwidget.c:2466
+#: gtk/gtkfontchooserwidget.c:2470
 msgid "Letter Case"
 msgstr "Wielkość liter"
 
-#: gtk/gtkfontchooserwidget.c:2467
+#: gtk/gtkfontchooserwidget.c:2471
 msgid "Number Case"
 msgstr "Wielkość cyfr"
 
-#: gtk/gtkfontchooserwidget.c:2468
+#: gtk/gtkfontchooserwidget.c:2472
 msgid "Number Spacing"
 msgstr "Odstępy cyfr"
 
-#: gtk/gtkfontchooserwidget.c:2469
+#: gtk/gtkfontchooserwidget.c:2473
+msgid "Numeric Extras"
+msgstr "Dodatki liczbowe"
+
+#: gtk/gtkfontchooserwidget.c:2474
 msgid "Fractions"
 msgstr "Ułamki"
 
-#: gtk/gtkfontchooserwidget.c:2470
+#: gtk/gtkfontchooserwidget.c:2475
 msgid "Style Variations"
 msgstr "Odmiany stylów"
 
-#: gtk/gtkfontchooserwidget.c:2472
+#: gtk/gtkfontchooserwidget.c:2477
 msgid "Character Variations"
 msgstr "Odmiany znaków"
 
@@ -2731,8 +2750,8 @@ msgstr "Odmiany znaków"
 msgid "OpenGL context creation failed"
 msgstr "Utworzenie kontekstu OpenGL się nie powiodło"
 
-#: gtk/deprecated/gtkinfobar.c:498 gtk/gtkwindowcontrols.c:357
-#: gtk/gtkwindowhandle.c:250
+#: gtk/deprecated/gtkinfobar.c:498 gtk/gtkwindowcontrols.c:370
+#: gtk/gtkwindowhandle.c:253
 msgid "Close"
 msgstr "Zamknij"
 
@@ -2740,31 +2759,31 @@ msgstr "Zamknij"
 msgid "Close the infobar"
 msgstr "Zamknij pasek informacyjny"
 
-#: gtk/gtklabel.c:5880 gtk/gtktext.c:6322 gtk/gtktextview.c:9225
+#: gtk/gtklabel.c:5894 gtk/gtktext.c:6318 gtk/gtktextview.c:9315
 msgid "Cu_t"
 msgstr "_Wytnij"
 
-#: gtk/gtklabel.c:5881 gtk/gtktext.c:6326 gtk/gtktextview.c:9229
+#: gtk/gtklabel.c:5895 gtk/gtktext.c:6322 gtk/gtktextview.c:9319
 msgid "_Copy"
 msgstr "S_kopiuj"
 
-#: gtk/gtklabel.c:5882 gtk/gtktext.c:6330 gtk/gtktextview.c:9233
+#: gtk/gtklabel.c:5896 gtk/gtktext.c:6326 gtk/gtktextview.c:9323
 msgid "_Paste"
 msgstr "Wk_lej"
 
-#: gtk/gtklabel.c:5888 gtk/gtktext.c:6343 gtk/gtktextview.c:9258
+#: gtk/gtklabel.c:5902 gtk/gtktext.c:6339 gtk/gtktextview.c:9348
 msgid "Select _All"
 msgstr "Z_aznacz wszystko"
 
-#: gtk/gtklabel.c:5893
+#: gtk/gtklabel.c:5907
 msgid "_Open Link"
 msgstr "_Otwórz odnośnik"
 
-#: gtk/gtklabel.c:5897
+#: gtk/gtklabel.c:5911
 msgid "Copy _Link Address"
 msgstr "S_kopiuj adres odnośnika"
 
-#: gtk/gtklabel.c:5941 gtk/gtktext.c:2851 gtk/gtktextview.c:9307
+#: gtk/gtklabel.c:5955 gtk/gtktext.c:2877 gtk/gtktextview.c:9397
 msgid "Context menu"
 msgstr "Menu kontekstowe"
 
@@ -2835,7 +2854,7 @@ msgid "Play"
 msgstr "Odtwarza"
 
 #: gtk/gtkmessagedialog.c:162 gtk/gtkmessagedialog.c:180
-#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6212
+#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6328
 msgid "_OK"
 msgstr "_OK"
 
@@ -2929,27 +2948,27 @@ msgstr ""
 "Nie można usunąć procesu o PID %d. Działanie nie jest zaimplementowane."
 
 #. translators: this string is a name for the 'less' command
-#: gtk/gtkmountoperation-x11.c:986
+#: gtk/gtkmountoperation-x11.c:988
 msgid "Terminal Pager"
 msgstr "Stronicowanie terminala"
 
-#: gtk/gtkmountoperation-x11.c:987
+#: gtk/gtkmountoperation-x11.c:989
 msgid "Top Command"
 msgstr "Polecenie top"
 
-#: gtk/gtkmountoperation-x11.c:988
+#: gtk/gtkmountoperation-x11.c:990
 msgid "Bourne Again Shell"
 msgstr "Powłoka Bourne Again"
 
-#: gtk/gtkmountoperation-x11.c:989
+#: gtk/gtkmountoperation-x11.c:991
 msgid "Bourne Shell"
 msgstr "Powłoka Bourne"
 
-#: gtk/gtkmountoperation-x11.c:990
+#: gtk/gtkmountoperation-x11.c:992
 msgid "Z Shell"
 msgstr "Powłoka Z"
 
-#: gtk/gtkmountoperation-x11.c:1090
+#: gtk/gtkmountoperation-x11.c:1092
 #, c-format
 msgid "Cannot end process with PID %d: %s"
 msgstr "Nie można zakończyć procesu o PID %d: %s"
@@ -2960,15 +2979,15 @@ msgstr ""
 "GTK nie może odnaleźć modułu multimediów. Proszę sprawdzić poprawność "
 "instalacji."
 
-#: gtk/gtknotebook.c:3304
+#: gtk/gtknotebook.c:3303
 msgid "Previous tab"
 msgstr "Poprzednia karta"
 
-#: gtk/gtknotebook.c:3308
+#: gtk/gtknotebook.c:3307
 msgid "Next tab"
 msgstr "Następna karta"
 
-#: gtk/gtknotebook.c:4424 gtk/gtknotebook.c:6634
+#: gtk/gtknotebook.c:4423 gtk/gtknotebook.c:6633
 #, c-format
 msgid "Page %u"
 msgstr "%u. strona"
@@ -2978,7 +2997,7 @@ msgstr "%u. strona"
 msgid "Not a valid page setup file"
 msgstr "Nieprawidłowy plik ustawień strony"
 
-#: gtk/print/gtkpagesetupunixdialog.c:198 gtk/print/gtkprintunixdialog.c:768
+#: gtk/print/gtkpagesetupunixdialog.c:198 gtk/print/gtkprintunixdialog.c:766
 msgid "Manage Custom Sizes…"
 msgstr "Zarządzaj niestandardowymi rozmiarami…"
 
@@ -3012,7 +3031,7 @@ msgstr ""
 
 #: gtk/print/gtkpagesetupunixdialog.c:784
 #: gtk/print/ui/gtkpagesetupunixdialog.ui:5
-#: gtk/print/ui/gtkprintunixdialog.ui:782
+#: gtk/print/ui/gtkprintunixdialog.ui:783
 msgid "Page Setup"
 msgstr "Ustawienia strony"
 
@@ -3020,7 +3039,7 @@ msgstr "Ustawienia strony"
 msgid "Hide Text"
 msgstr "Ukrywa tekst"
 
-#: gtk/gtkpasswordentry.c:173 gtk/gtkpasswordentry.c:624
+#: gtk/gtkpasswordentry.c:173 gtk/gtkpasswordentry.c:620
 msgid "Show Text"
 msgstr "Wyświetla tekst"
 
@@ -3028,7 +3047,7 @@ msgstr "Wyświetla tekst"
 msgid "Caps Lock is on"
 msgstr "Klawisz Caps Lock jest włączony"
 
-#: gtk/gtkpasswordentry.c:700
+#: gtk/gtkpasswordentry.c:696
 msgid "_Show Text"
 msgstr "_Wyświetlanie tekstu"
 
@@ -3156,12 +3175,12 @@ msgid "Unable to poll “%s” for media changes"
 msgstr "Nie można odpytać „%s” o zmiany nośnika"
 
 #: gtk/gtkplacessidebar.c:3155 gtk/gtkplacessidebar.c:3242
-#: gtk/gtkplacesview.c:1649
+#: gtk/gtkplacesview.c:1650
 msgid "Open in New _Tab"
 msgstr "O_twórz w nowej karcie"
 
 #: gtk/gtkplacessidebar.c:3161 gtk/gtkplacessidebar.c:3251
-#: gtk/gtkplacesview.c:1654
+#: gtk/gtkplacesview.c:1655
 msgid "Open in New _Window"
 msgstr "Otwórz w nowy_m oknie"
 
@@ -3173,11 +3192,11 @@ msgstr "_Dodaj zakładkę"
 msgid "_Remove"
 msgstr "_Usuń"
 
-#: gtk/gtkplacessidebar.c:3282 gtk/gtkplacesview.c:1679
+#: gtk/gtkplacessidebar.c:3282 gtk/gtkplacesview.c:1680
 msgid "_Mount"
 msgstr "Za_montuj"
 
-#: gtk/gtkplacessidebar.c:3291 gtk/gtkplacesview.c:1668
+#: gtk/gtkplacessidebar.c:3291 gtk/gtkplacesview.c:1669
 msgid "_Unmount"
 msgstr "O_dmontuj"
 
@@ -3229,94 +3248,98 @@ msgstr "Zatrzymaj napęd wielody_skowy"
 msgid "_Lock Device"
 msgstr "_Zablokuj urzÄ…dzenie"
 
-#: gtk/gtkplacessidebar.c:3827 gtk/gtkplacesview.c:1089
+#: gtk/gtkplacessidebar.c:3828 gtk/gtkplacesview.c:1090
 msgid "Computer"
 msgstr "Komputer"
 
-#: gtk/gtkplacesview.c:875
+#: gtk/gtkplacesview.c:593
+msgid "Remove server"
+msgstr "Usuwa serwer"
+
+#: gtk/gtkplacesview.c:876
 msgid "Searching for network locations"
 msgstr "Wyszukiwanie położeń sieciowych"
 
-#: gtk/gtkplacesview.c:882
+#: gtk/gtkplacesview.c:883
 msgid "No network locations found"
 msgstr "Brak położeń sieciowych"
 
 #. if it wasn't cancelled show a dialog
-#: gtk/gtkplacesview.c:1196 gtk/gtkplacesview.c:1293
+#: gtk/gtkplacesview.c:1197 gtk/gtkplacesview.c:1294
 msgid "Unable to access location"
 msgstr "Nie można uzyskać dostępu do położenia"
 
 #. Restore from Cancel to Connect
-#: gtk/gtkplacesview.c:1214 gtk/ui/gtkplacesview.ui:250
+#: gtk/gtkplacesview.c:1215 gtk/ui/gtkplacesview.ui:237
 msgid "Con_nect"
 msgstr "P_ołącz"
 
 #. if it wasn't cancelled show a dialog
-#: gtk/gtkplacesview.c:1353
+#: gtk/gtkplacesview.c:1354
 msgid "Unable to unmount volume"
 msgstr "Nie można odmontować woluminu"
 
 #. Allow to cancel the operation
-#: gtk/gtkplacesview.c:1445
+#: gtk/gtkplacesview.c:1446
 msgid "Cance_l"
 msgstr "_Anuluj"
 
-#: gtk/gtkplacesview.c:1592
+#: gtk/gtkplacesview.c:1593
 msgid "AppleTalk"
 msgstr "AppleTalk"
 
-#: gtk/gtkplacesview.c:1598
+#: gtk/gtkplacesview.c:1599
 msgid "File Transfer Protocol"
 msgstr "FTP"
 
 #. Translators: do not translate ftp:// and ftps://
-#: gtk/gtkplacesview.c:1600
+#: gtk/gtkplacesview.c:1601
 msgid "ftp:// or ftps://"
 msgstr "ftp:// lub ftps://"
 
-#: gtk/gtkplacesview.c:1606
+#: gtk/gtkplacesview.c:1607
 msgid "Network File System"
 msgstr "NFS"
 
-#: gtk/gtkplacesview.c:1612
+#: gtk/gtkplacesview.c:1613
 msgid "Samba"
 msgstr "Samba"
 
-#: gtk/gtkplacesview.c:1618
+#: gtk/gtkplacesview.c:1619
 msgid "SSH File Transfer Protocol"
 msgstr "SFTP"
 
 #. Translators: do not translate sftp:// and ssh://
-#: gtk/gtkplacesview.c:1620
+#: gtk/gtkplacesview.c:1621
 msgid "sftp:// or ssh://"
 msgstr "sftp:// lub ssh://"
 
-#: gtk/gtkplacesview.c:1626
+#: gtk/gtkplacesview.c:1627
 msgid "WebDAV"
 msgstr "WebDAV"
 
 #. Translators: do not translate dav:// and davs://
-#: gtk/gtkplacesview.c:1628
+#: gtk/gtkplacesview.c:1629
 msgid "dav:// or davs://"
 msgstr "dav:// lub davs://"
 
-#: gtk/gtkplacesview.c:1663
+#: gtk/gtkplacesview.c:1664
 msgid "_Disconnect"
 msgstr "_Rozłącz"
 
-#: gtk/gtkplacesview.c:1674
+#: gtk/gtkplacesview.c:1675
 msgid "_Connect"
 msgstr "P_ołącz"
 
-#: gtk/gtkplacesview.c:1894
+#: gtk/gtkplacesview.c:1895
 msgid "Unable to get remote server location"
 msgstr "Nie można uzyskać położenia zdalnego serwera"
 
-#: gtk/gtkplacesview.c:2038 gtk/gtkplacesview.c:2047
+#: gtk/gtkplacesview.c:2039 gtk/gtkplacesview.c:2048
 msgid "Networks"
 msgstr "Sieci"
 
-#: gtk/gtkplacesview.c:2038 gtk/gtkplacesview.c:2047
+#: gtk/gtkplacesview.c:2039 gtk/gtkplacesview.c:2048
 msgid "On This Computer"
 msgstr "Na tym komputerze"
 
@@ -3349,11 +3372,11 @@ msgstr "Uwierzytelnianie"
 msgid "_Remember password"
 msgstr "_Zapamiętanie hasła"
 
-#: gtk/print/gtkprinteroptionwidget.c:703
+#: gtk/print/gtkprinteroptionwidget.c:576
 msgid "Select a filename"
 msgstr "Wybór nazwy pliku"
 
-#: gtk/print/gtkprinteroptionwidget.c:947
+#: gtk/print/gtkprinteroptionwidget.c:820
 msgid "Not available"
 msgstr "Niedostępne"
 
@@ -3361,164 +3384,164 @@ msgstr "Niedostępne"
 #. * jobs. %s gets replaced by the application name, %d gets replaced
 #. * by the job number.
 #.
-#: gtk/print/gtkprintoperation.c:252
+#: gtk/print/gtkprintoperation.c:255
 #, c-format
 msgid "%s job #%d"
 msgstr "%s: %d. zadanie"
 
-#: gtk/print/gtkprintoperation.c:1699
+#: gtk/print/gtkprintoperation.c:1702
 msgctxt "print operation status"
 msgid "Initial state"
 msgstr "Stan poczÄ…tkowy"
 
-#: gtk/print/gtkprintoperation.c:1700
+#: gtk/print/gtkprintoperation.c:1703
 msgctxt "print operation status"
 msgid "Preparing to print"
 msgstr "Przygotowywanie do drukowania"
 
-#: gtk/print/gtkprintoperation.c:1701
+#: gtk/print/gtkprintoperation.c:1704
 msgctxt "print operation status"
 msgid "Generating data"
 msgstr "Tworzenie danych"
 
-#: gtk/print/gtkprintoperation.c:1702
+#: gtk/print/gtkprintoperation.c:1705
 msgctxt "print operation status"
 msgid "Sending data"
 msgstr "Wysyłanie danych"
 
-#: gtk/print/gtkprintoperation.c:1703
+#: gtk/print/gtkprintoperation.c:1706
 msgctxt "print operation status"
 msgid "Waiting"
 msgstr "Oczekiwanie"
 
-#: gtk/print/gtkprintoperation.c:1704
+#: gtk/print/gtkprintoperation.c:1707
 msgctxt "print operation status"
 msgid "Blocking on issue"
 msgstr "Blokowanie z powodu problemu"
 
-#: gtk/print/gtkprintoperation.c:1705
+#: gtk/print/gtkprintoperation.c:1708
 msgctxt "print operation status"
 msgid "Printing"
 msgstr "Drukowanie"
 
-#: gtk/print/gtkprintoperation.c:1706
+#: gtk/print/gtkprintoperation.c:1709
 msgctxt "print operation status"
 msgid "Finished"
 msgstr "Ukończono"
 
-#: gtk/print/gtkprintoperation.c:1707
+#: gtk/print/gtkprintoperation.c:1710
 msgctxt "print operation status"
 msgid "Finished with error"
 msgstr "Ukończono z błędem"
 
-#: gtk/print/gtkprintoperation.c:2250
+#: gtk/print/gtkprintoperation.c:2254
 #, c-format
 msgid "Preparing %d"
 msgstr "Przygotowywanie %d"
 
-#: gtk/print/gtkprintoperation.c:2252 gtk/print/gtkprintoperation.c:2871
+#: gtk/print/gtkprintoperation.c:2256 gtk/print/gtkprintoperation.c:2875
 #, c-format
 msgid "Preparing"
 msgstr "Przygotowywanie"
 
-#: gtk/print/gtkprintoperation.c:2255
+#: gtk/print/gtkprintoperation.c:2259
 #, c-format
 msgid "Printing %d"
 msgstr "Drukowanie %d"
 
-#: gtk/print/gtkprintoperation.c:2904
+#: gtk/print/gtkprintoperation.c:2908
 #, c-format
 msgid "Error creating print preview"
 msgstr "Błąd podczas tworzenia podglądu wydruku"
 
-#: gtk/print/gtkprintoperation.c:2907
+#: gtk/print/gtkprintoperation.c:2911
 #, c-format
 msgid "The most probable reason is that a temporary file could not be created."
 msgstr "Najprawdopodobniej plik tymczasowy nie mógł zostać utworzony."
 
 #. window
-#: gtk/print/gtkprintoperation-portal.c:264
-#: gtk/print/gtkprintoperation-portal.c:594
-#: gtk/print/gtkprintoperation-portal.c:663 gtk/print/gtkprintunixdialog.c:3015
+#: gtk/print/gtkprintoperation-portal.c:273
+#: gtk/print/gtkprintoperation-portal.c:603
+#: gtk/print/gtkprintoperation-portal.c:672 gtk/print/gtkprintunixdialog.c:2989
 msgid "Print"
 msgstr "Wydruk"
 
-#: gtk/print/gtkprintoperation-unix.c:481
-#: gtk/print/gtkprintoperation-win32.c:1505
+#: gtk/print/gtkprintoperation-unix.c:490
+#: gtk/print/gtkprintoperation-win32.c:1498
 msgid "Application"
 msgstr "Program"
 
-#: gtk/print/gtkprintoperation-win32.c:636
+#: gtk/print/gtkprintoperation-win32.c:626
 msgid "Printer offline"
 msgstr "Drukarka jest w trybie offline"
 
-#: gtk/print/gtkprintoperation-win32.c:638
+#: gtk/print/gtkprintoperation-win32.c:628
 msgid "Out of paper"
 msgstr "Brak papieru"
 
 #. Translators: this is a printer status.
-#: gtk/print/gtkprintoperation-win32.c:640
+#: gtk/print/gtkprintoperation-win32.c:630
 #: modules/printbackends/gtkprintbackendcpdb.c:1533
 #: modules/printbackends/gtkprintbackendcups.c:2639
 msgid "Paused"
 msgstr "Wstrzymane"
 
-#: gtk/print/gtkprintoperation-win32.c:642
+#: gtk/print/gtkprintoperation-win32.c:632
 msgid "Need user intervention"
 msgstr "Wymagana jest interwencja użytkownika"
 
-#: gtk/print/gtkprintoperation-win32.c:749
+#: gtk/print/gtkprintoperation-win32.c:739
 msgid "Custom size"
 msgstr "Niestandardowy rozmiar"
 
-#: gtk/print/gtkprintoperation-win32.c:1597
+#: gtk/print/gtkprintoperation-win32.c:1590
 msgid "No printer found"
 msgstr "Nie odnaleziono drukarki"
 
-#: gtk/print/gtkprintoperation-win32.c:1624
+#: gtk/print/gtkprintoperation-win32.c:1617
 msgid "Invalid argument to CreateDC"
 msgstr "Nieprawidłowy parametr do CreateDC"
 
-#: gtk/print/gtkprintoperation-win32.c:1660
-#: gtk/print/gtkprintoperation-win32.c:1906
+#: gtk/print/gtkprintoperation-win32.c:1653
+#: gtk/print/gtkprintoperation-win32.c:1899
 msgid "Error from StartDoc"
 msgstr "Błąd z StartDoc"
 
-#: gtk/print/gtkprintoperation-win32.c:1761
-#: gtk/print/gtkprintoperation-win32.c:1784
-#: gtk/print/gtkprintoperation-win32.c:1832
+#: gtk/print/gtkprintoperation-win32.c:1754
+#: gtk/print/gtkprintoperation-win32.c:1777
+#: gtk/print/gtkprintoperation-win32.c:1825
 msgid "Not enough free memory"
 msgstr "Za mało wolnej pamięci"
 
-#: gtk/print/gtkprintoperation-win32.c:1837
+#: gtk/print/gtkprintoperation-win32.c:1830
 msgid "Invalid argument to PrintDlgEx"
 msgstr "Nieprawidłowy parametr do PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1842
+#: gtk/print/gtkprintoperation-win32.c:1835
 msgid "Invalid pointer to PrintDlgEx"
 msgstr "Nieprawidłowy wskaźnik do PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1847
+#: gtk/print/gtkprintoperation-win32.c:1840
 msgid "Invalid handle to PrintDlgEx"
 msgstr "Nieprawidłowy uchwyt do PrintDlgEx"
 
-#: gtk/print/gtkprintoperation-win32.c:1852
+#: gtk/print/gtkprintoperation-win32.c:1845
 msgid "Unspecified error"
 msgstr "Nieokreślony błąd"
 
-#: gtk/print/gtkprintunixdialog.c:838
+#: gtk/print/gtkprintunixdialog.c:836
 msgid "Pre_view"
 msgstr "P_odglÄ…d"
 
-#: gtk/print/gtkprintunixdialog.c:840
+#: gtk/print/gtkprintunixdialog.c:838
 msgid "_Print"
 msgstr "Wy_drukuj"
 
-#: gtk/print/gtkprintunixdialog.c:966
+#: gtk/print/gtkprintunixdialog.c:954
 msgid "Getting printer information failed"
 msgstr "Pobranie informacji o drukarce się nie powiodło"
 
-#: gtk/print/gtkprintunixdialog.c:1890
+#: gtk/print/gtkprintunixdialog.c:1878
 msgid "Getting printer information…"
 msgstr "Pobieranie informacji o drukarce…"
 
@@ -3528,67 +3551,71 @@ msgstr "Pobieranie informacji o drukarce…"
 #. Translators: These strings name the possible arrangements of
 #. * multiple pages on a sheet when printing
 #.
-#: gtk/print/gtkprintunixdialog.c:2760
-#: modules/printbackends/gtkprintbackendcups.c:5677
+#: gtk/print/gtkprintunixdialog.c:2734
+#: modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, top to bottom"
 msgstr "Od lewej do prawej, z góry do dołu"
 
-#: gtk/print/gtkprintunixdialog.c:2760
-#: modules/printbackends/gtkprintbackendcups.c:5677
+#: gtk/print/gtkprintunixdialog.c:2734
+#: modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, bottom to top"
 msgstr "Od lewej do prawej, z dołu na górę"
 
-#: gtk/print/gtkprintunixdialog.c:2761
-#: modules/printbackends/gtkprintbackendcups.c:5678
+#: gtk/print/gtkprintunixdialog.c:2735
+#: modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, top to bottom"
 msgstr "Od prawej do lewej, z góry na dół"
 
-#: gtk/print/gtkprintunixdialog.c:2761
-#: modules/printbackends/gtkprintbackendcups.c:5678
+#: gtk/print/gtkprintunixdialog.c:2735
+#: modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, bottom to top"
 msgstr "Od prawej do lewej, z dołu na górę"
 
-#: gtk/print/gtkprintunixdialog.c:2762
-#: modules/printbackends/gtkprintbackendcups.c:5679
+#: gtk/print/gtkprintunixdialog.c:2736
+#: modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, left to right"
 msgstr "Z góry do dołu, od lewej do prawej"
 
-#: gtk/print/gtkprintunixdialog.c:2762
-#: modules/printbackends/gtkprintbackendcups.c:5679
+#: gtk/print/gtkprintunixdialog.c:2736
+#: modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, right to left"
 msgstr "Z góry do dołu, od prawej do lewej"
 
-#: gtk/print/gtkprintunixdialog.c:2763
-#: modules/printbackends/gtkprintbackendcups.c:5680
+#: gtk/print/gtkprintunixdialog.c:2737
+#: modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, left to right"
 msgstr "Z dołu do góry, od lewej do prawej"
 
-#: gtk/print/gtkprintunixdialog.c:2763
-#: modules/printbackends/gtkprintbackendcups.c:5680
+#: gtk/print/gtkprintunixdialog.c:2737
+#: modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, right to left"
 msgstr "Z dołu do góry, od prawej do lewej"
 
-#: gtk/print/gtkprintunixdialog.c:2767 gtk/print/gtkprintunixdialog.c:2780
+#: gtk/print/gtkprintunixdialog.c:2741 gtk/print/gtkprintunixdialog.c:2754
 msgid "Page Ordering"
 msgstr "Kolejność stron"
 
-#: gtk/print/gtkprintunixdialog.c:2796
+#: gtk/print/gtkprintunixdialog.c:2770
 msgid "Left to right"
 msgstr "Od lewej do prawej"
 
-#: gtk/print/gtkprintunixdialog.c:2797
+#: gtk/print/gtkprintunixdialog.c:2771
 msgid "Right to left"
 msgstr "Od prawej do lewej"
 
-#: gtk/print/gtkprintunixdialog.c:2809
+#: gtk/print/gtkprintunixdialog.c:2783
 msgid "Top to bottom"
 msgstr "Z góry do dołu"
 
-#: gtk/print/gtkprintunixdialog.c:2810
+#: gtk/print/gtkprintunixdialog.c:2784
 msgid "Bottom to top"
 msgstr "Z dołu do góry"
 
-#: gtk/gtkprogressbar.c:627
+#: gtk/gtkprintdialog.c:1755
+msgid "Failed to create the read file descriptor"
+msgstr "Utworzenie deskryptora pliku odczytu się nie powiodło"
+
+#: gtk/gtkprogressbar.c:626
 #, c-format
 msgctxt "progress bar label"
 msgid "%.0f %%"
@@ -3613,7 +3640,7 @@ msgstr ""
 "Nie odnaleziono zarejestrowanego programu o nazwie „%s” dla elementu "
 "o adresie URI „%s”"
 
-#: gtk/gtksearchentry.c:836
+#: gtk/gtksearchentry.c:835
 msgid "Clear Entry"
 msgstr "Czyści wpis"
 
@@ -3622,7 +3649,7 @@ msgstr "Czyści wpis"
 #. * this string very short, ideally just a single character, since it will
 #. * be rendered as part of the key.
 #.
-#: gtk/gtkshortcutlabel.c:79
+#: gtk/deprecated/gtkshortcutlabel.c:81
 msgctxt "keyboard side marker"
 msgid "L"
 msgstr "L"
@@ -3632,96 +3659,257 @@ msgstr "L"
 #. * this string very short, ideally just a single character, since it will
 #. * be rendered as part of the key.
 #.
-#: gtk/gtkshortcutlabel.c:92
+#: gtk/deprecated/gtkshortcutlabel.c:94
 msgctxt "keyboard side marker"
 msgid "R"
 msgstr "P"
 
-#: gtk/gtkshortcutssection.c:435
+#: gtk/deprecated/gtkshortcutssection.c:449
 msgid "_Show All"
 msgstr "_Wyświetl wszystkie"
 
-#: gtk/gtkshortcutsshortcut.c:143
+#: gtk/deprecated/gtkshortcutsshortcut.c:147
 msgid "Two finger pinch"
 msgstr "Ściśnięcie dwoma palcami"
 
-#: gtk/gtkshortcutsshortcut.c:147
+#: gtk/deprecated/gtkshortcutsshortcut.c:151
 msgid "Two finger stretch"
 msgstr "Rozciągnięcie dwoma palcami"
 
-#: gtk/gtkshortcutsshortcut.c:151
+#: gtk/deprecated/gtkshortcutsshortcut.c:155
 msgid "Rotate clockwise"
 msgstr "Obrócenie w prawo"
 
-#: gtk/gtkshortcutsshortcut.c:155
+#: gtk/deprecated/gtkshortcutsshortcut.c:159
 msgid "Rotate counterclockwise"
 msgstr "Obrócenie w lewo"
 
-#: gtk/gtkshortcutsshortcut.c:159
+#: gtk/deprecated/gtkshortcutsshortcut.c:163
 msgid "Two finger swipe left"
 msgstr "Przeciągnięcie dwoma palcami w lewo"
 
-#: gtk/gtkshortcutsshortcut.c:163
+#: gtk/deprecated/gtkshortcutsshortcut.c:167
 msgid "Two finger swipe right"
 msgstr "Przeciągnięcie dwoma palcami w prawo"
 
-#: gtk/gtkshortcutsshortcut.c:167
+#: gtk/deprecated/gtkshortcutsshortcut.c:171
 msgid "Swipe left"
 msgstr "Przeciągnięcie w lewo"
 
-#: gtk/gtkshortcutsshortcut.c:171
+#: gtk/deprecated/gtkshortcutsshortcut.c:175
 msgid "Swipe right"
 msgstr "Przeciągnięcie w prawo"
 
 #. Translators: This is placeholder text for the search entry in the shortcuts window
-#: gtk/gtkshortcutswindow.c:894 gtk/gtkshortcutswindow.c:961
-#: gtk/gtkshortcutswindow.c:967
+#: gtk/deprecated/gtkshortcutswindow.c:903
+#: gtk/deprecated/gtkshortcutswindow.c:970
+#: gtk/deprecated/gtkshortcutswindow.c:976
 msgid "Search Shortcuts"
 msgstr "Wyszukiwanie skrótów"
 
 #. Translators: This is the window title for the shortcuts window in normal mode
-#: gtk/gtkshortcutswindow.c:926 gtk/inspector/window.ui:498
+#: gtk/deprecated/gtkshortcutswindow.c:935 gtk/inspector/window.ui:496
 msgid "Shortcuts"
 msgstr "Skróty"
 
 #. Translators: This is the window title for the shortcuts window in search mode
-#: gtk/gtkshortcutswindow.c:931
+#: gtk/deprecated/gtkshortcutswindow.c:940
 msgid "Search Results"
 msgstr "Wyniki wyszukiwania"
 
-#: gtk/gtkshortcutswindow.c:1029 gtk/ui/gtkemojichooser.ui:350
-#: gtk/ui/gtkfilechooserwidget.ui:250
+#: gtk/deprecated/gtkshortcutswindow.c:1038 gtk/ui/gtkemojichooser.ui:352
+#: gtk/ui/gtkfilechooserwidget.ui:253
 msgid "No Results Found"
 msgstr "Brak wyników"
 
-#: gtk/gtkshortcutswindow.c:1040 gtk/ui/gtkemojichooser.ui:363
-#: gtk/ui/gtkfilechooserwidget.ui:263 gtk/ui/gtkplacesview.ui:218
+#: gtk/deprecated/gtkshortcutswindow.c:1049 gtk/ui/gtkemojichooser.ui:362
+#: gtk/ui/gtkfilechooserwidget.ui:263 gtk/ui/gtkplacesview.ui:207
 msgid "Try a different search"
 msgstr "Proszę spróbować innych słów"
 
-#: gtk/gtkstacksidebar.c:154
+#: gtk/gtkstacksidebar.c:157
 msgctxt "accessibility"
 msgid "Sidebar"
 msgstr "Panel boczny"
 
-#: gtk/gtktext.c:6348 gtk/gtktextview.c:9263
+#: gtk/gtktext.c:6344
+msgid "Change di_rection"
+msgstr "Z_mień kierunek"
+
+#: gtk/gtktext.c:6349 gtk/gtktextview.c:9353
 msgid "Insert _Emoji"
 msgstr "Wstaw _emoji"
 
-#: gtk/gtktextview.c:9245
+#: gtk/gtktextencoding.c:31
+msgctxt "Encoding name"
+msgid "Automatically Detected"
+msgstr "Automatycznie wykryte"
+
+#: gtk/gtktextencoding.c:32
+msgctxt "Encoding name"
+msgid "ASCII"
+msgstr "ASCII"
+
+#: gtk/gtktextencoding.c:34 gtk/gtktextencoding.c:47 gtk/gtktextencoding.c:74
+#: gtk/gtktextencoding.c:95
+msgctxt "Encoding name"
+msgid "Western"
+msgstr "zachodnie"
+
+#: gtk/gtktextencoding.c:35 gtk/gtktextencoding.c:75 gtk/gtktextencoding.c:93
+msgctxt "Encoding name"
+msgid "Central European"
+msgstr "środkowoeuropejskie"
+
+#: gtk/gtktextencoding.c:36
+msgctxt "Encoding name"
+msgid "South European"
+msgstr "południowoeuropejskie"
+
+#: gtk/gtktextencoding.c:37 gtk/gtktextencoding.c:45 gtk/gtktextencoding.c:100
+msgctxt "Encoding name"
+msgid "Baltic"
+msgstr "bałtyckie"
+
+#: gtk/gtktextencoding.c:38 gtk/gtktextencoding.c:76 gtk/gtktextencoding.c:83
+#: gtk/gtktextencoding.c:85 gtk/gtktextencoding.c:94
+msgctxt "Encoding name"
+msgid "Cyrillic"
+msgstr "cyrylica"
+
+#: gtk/gtktextencoding.c:39 gtk/gtktextencoding.c:79 gtk/gtktextencoding.c:99
+msgctxt "Encoding name"
+msgid "Arabic"
+msgstr "arabskie"
+
+#: gtk/gtktextencoding.c:40 gtk/gtktextencoding.c:96
+msgctxt "Encoding name"
+msgid "Greek"
+msgstr "greckie"
+
+#: gtk/gtktextencoding.c:41
+msgctxt "Encoding name"
+msgid "Hebrew Visual"
+msgstr "hebrajskie (wizualne)"
+
+#: gtk/gtktextencoding.c:42 gtk/gtktextencoding.c:77 gtk/gtktextencoding.c:97
+msgctxt "Encoding name"
+msgid "Turkish"
+msgstr "tureckie"
+
+#: gtk/gtktextencoding.c:43
+msgctxt "Encoding name"
+msgid "Nordic"
+msgstr "nordyckie"
+
+#: gtk/gtktextencoding.c:44 gtk/gtktextencoding.c:89
+msgctxt "Encoding name"
+msgid "Thai"
+msgstr "tajskie"
+
+#: gtk/gtktextencoding.c:46
+msgctxt "Encoding name"
+msgid "Celtic"
+msgstr "celtyckie"
+
+#: gtk/gtktextencoding.c:48
+msgctxt "Encoding name"
+msgid "Romanian"
+msgstr "rumuńskie"
+
+#: gtk/gtktextencoding.c:50 gtk/gtktextencoding.c:51 gtk/gtktextencoding.c:52
+#: gtk/gtktextencoding.c:53 gtk/gtktextencoding.c:54 gtk/gtktextencoding.c:55
+#: gtk/gtktextencoding.c:56 gtk/gtktextencoding.c:57
+msgctxt "Encoding name"
+msgid "Unicode"
+msgstr "unikod"
+
+#: gtk/gtktextencoding.c:59
+msgctxt "Encoding name"
+msgid "Armenian"
+msgstr "ormiańskie"
+
+#: gtk/gtktextencoding.c:60 gtk/gtktextencoding.c:61 gtk/gtktextencoding.c:67
+msgctxt "Encoding name"
+msgid "Chinese Traditional"
+msgstr "chińskie (tradycyjne)"
+
+#: gtk/gtktextencoding.c:62
+msgctxt "Encoding name"
+msgid "Cyrillic/Russian"
+msgstr "cyrylica/rosyjskie"
+
+#: gtk/gtktextencoding.c:63 gtk/gtktextencoding.c:64 gtk/gtktextencoding.c:65
+#: gtk/gtktextencoding.c:81 gtk/gtktextencoding.c:87
+msgctxt "Encoding name"
+msgid "Japanese"
+msgstr "japońskie"
+
+#: gtk/gtktextencoding.c:66 gtk/gtktextencoding.c:82 gtk/gtktextencoding.c:84
+#: gtk/gtktextencoding.c:90
+msgctxt "Encoding name"
+msgid "Korean"
+msgstr "koreańskie"
+
+#: gtk/gtktextencoding.c:69 gtk/gtktextencoding.c:70 gtk/gtktextencoding.c:71
+msgctxt "Encoding name"
+msgid "Chinese Simplified"
+msgstr "chińskie (uproszczone)"
+
+#: gtk/gtktextencoding.c:72
+msgctxt "Encoding name"
+msgid "Georgian"
+msgstr "gruzińskie"
+
+#: gtk/gtktextencoding.c:78 gtk/gtktextencoding.c:98
+msgctxt "Encoding name"
+msgid "Hebrew"
+msgstr "hebrajskie"
+
+#: gtk/gtktextencoding.c:86
+msgctxt "Encoding name"
+msgid "Cyrillic/Ukrainian"
+msgstr "cyrylica/ukraińskie"
+
+#: gtk/gtktextencoding.c:88 gtk/gtktextencoding.c:91 gtk/gtktextencoding.c:101
+msgctxt "Encoding name"
+msgid "Vietnamese"
+msgstr "wietnamskie"
+
+#: gtk/gtktextencoding.c:163
+msgctxt "Line ending name"
+msgid "Unchanged"
+msgstr "Bez zmiany"
+
+#: gtk/gtktextencoding.c:164
+msgctxt "Line ending name"
+msgid "Unix/Linux"
+msgstr "UNIX/Linux"
+
+#: gtk/gtktextencoding.c:165
+msgctxt "Line ending name"
+msgid "Windows"
+msgstr "Windows"
+
+#: gtk/gtktextencoding.c:166
+msgctxt "Line ending name"
+msgid "Mac OS Classic"
+msgstr "Klasyczny system Mac OS"
+
+#: gtk/gtktextview.c:9335
 msgid "_Undo"
 msgstr "Cof_nij"
 
-#: gtk/gtktextview.c:9249
+#: gtk/gtktextview.c:9339
 msgid "_Redo"
 msgstr "P_onów"
 
-#: gtk/gtkwindow.c:6200
+#: gtk/gtkwindow.c:6316
 #, c-format
 msgid "Do you want to use GTK Inspector?"
 msgstr "Użyć Inspektora GTK?"
 
-#: gtk/gtkwindow.c:6202
+#: gtk/gtkwindow.c:6318
 #, c-format
 msgid ""
 "GTK Inspector is an interactive debugger that lets you explore and modify "
@@ -3732,31 +3920,31 @@ msgstr ""
 "i modyfikowanie wnętrza programu GTK. Jego użycie może spowodować awarię lub "
 "uszkodzenie programu."
 
-#: gtk/gtkwindow.c:6207
+#: gtk/gtkwindow.c:6323
 msgid "Don’t show this message again"
 msgstr "Bez wyświetlania ponownie"
 
-#: gtk/gtkwindowcontrols.c:309 gtk/gtkwindowhandle.c:234
+#: gtk/gtkwindowcontrols.c:322 gtk/gtkwindowhandle.c:237
 msgid "Minimize"
 msgstr "Zminimalizuj"
 
-#: gtk/gtkwindowcontrols.c:311
+#: gtk/gtkwindowcontrols.c:324
 msgid "Minimize the window"
 msgstr "Zminimalizuj okno"
 
-#: gtk/gtkwindowcontrols.c:335 gtk/gtkwindowhandle.c:240
+#: gtk/gtkwindowcontrols.c:348 gtk/gtkwindowhandle.c:243
 msgid "Maximize"
 msgstr "Zmaksymalizuj"
 
-#: gtk/gtkwindowcontrols.c:337
+#: gtk/gtkwindowcontrols.c:350
 msgid "Maximize the window"
 msgstr "Zmaksymalizuj okno"
 
-#: gtk/gtkwindowcontrols.c:359
+#: gtk/gtkwindowcontrols.c:372
 msgid "Close the window"
 msgstr "Zamknij okno"
 
-#: gtk/gtkwindowhandle.c:227
+#: gtk/gtkwindowhandle.c:230
 msgid "Restore"
 msgstr "Przywróć"
 
@@ -3816,17 +4004,17 @@ msgstr "Wyświetlanie"
 msgid "Hover to load"
 msgstr "Najechanie wczytuje"
 
-#: gtk/inspector/clipboard.c:278
+#: gtk/inspector/clipboard.c:286
 msgctxt "clipboard"
 msgid "empty"
 msgstr "pusty"
 
-#: gtk/inspector/clipboard.c:283 gtk/inspector/clipboard.c:325
+#: gtk/inspector/clipboard.c:291 gtk/inspector/clipboard.c:344
 msgctxt "clipboard"
 msgid "local"
 msgstr "lokalny"
 
-#: gtk/inspector/clipboard.c:285 gtk/inspector/clipboard.c:327
+#: gtk/inspector/clipboard.c:293 gtk/inspector/clipboard.c:346
 msgctxt "clipboard"
 msgid "remote"
 msgstr "zdalny"
@@ -3835,7 +4023,7 @@ msgstr "zdalny"
 msgid "Drag and hold here"
 msgstr "Można tutaj przeciągnąć i przytrzymać"
 
-#: gtk/inspector/clipboard.ui:71 gtk/inspector/window.ui:574
+#: gtk/inspector/clipboard.ui:71 gtk/inspector/window.ui:572
 msgid "Clipboard"
 msgstr "Schowek"
 
@@ -3914,137 +4102,150 @@ msgstr "Klasy stylu"
 msgid "CSS Property"
 msgstr "Właściwość CSS"
 
-#: gtk/inspector/general.c:372
-msgctxt "GL version"
+#: gtk/inspector/general.c:446
+msgid "IM Context is hardcoded by GTK_IM_MODULE"
+msgstr ""
+"Kontekst metody wprowadzania jest zakodowany przez zmiennÄ… GTK_IM_MODULE"
+
+#: gtk/inspector/general.c:577
+msgctxt "GL renderer"
 msgid "None"
 msgstr "Brak"
 
-#: gtk/inspector/general.c:464
+#: gtk/inspector/general.c:674
 msgctxt "GL version"
 msgid "Unknown"
 msgstr "Nieznana"
 
-#: gtk/inspector/general.c:526
-msgctxt "Vulkan device"
-msgid "Disabled"
-msgstr "Wyłączone"
-
-#: gtk/inspector/general.c:527 gtk/inspector/general.c:528
-msgctxt "Vulkan version"
-msgid "Disabled"
-msgstr "Wyłączone"
-
-#: gtk/inspector/general.c:579
+#: gtk/inspector/general.c:928 gtk/inspector/general.c:967
 msgctxt "Vulkan device"
 msgid "None"
 msgstr "Brak"
 
-#: gtk/inspector/general.c:580 gtk/inspector/general.c:581
-msgctxt "Vulkan version"
-msgid "None"
-msgstr "Brak"
-
-#: gtk/inspector/general.c:934
-msgid "IM Context is hardcoded by GTK_IM_MODULE"
-msgstr ""
-"Kontekst metody wprowadzania jest zakodowany przez zmiennÄ… GTK_IM_MODULE"
+#: gtk/inspector/general.ui:13
+msgid "Copy to clipboard as gitlab markdown"
+msgstr "Kopiuje do schowka jako kod Markdown serwisu GitLab"
 
-#: gtk/inspector/general.ui:31
+#: gtk/inspector/general.ui:45
 msgid "GTK Version"
 msgstr "Wersja GTK"
 
-#: gtk/inspector/general.ui:57
+#: gtk/inspector/general.ui:71
 msgid "GDK Backend"
 msgstr "Mechanizm GDK"
 
-#: gtk/inspector/general.ui:83
+#: gtk/inspector/general.ui:97
 msgid "GSK Renderer"
 msgstr "Mechanizm rysowania GSK"
 
-#: gtk/inspector/general.ui:109
+#: gtk/inspector/general.ui:123
 msgid "Pango Fontmap"
 msgstr "Mapa czcionki Pango"
 
-#: gtk/inspector/general.ui:135
+#: gtk/inspector/general.ui:149
 msgid "Media Backend"
 msgstr "Mechanizm multimediów"
 
-#: gtk/inspector/general.ui:161
+#: gtk/inspector/general.ui:175
 msgid "Input Method"
 msgstr "Metoda wprowadzania"
 
-#: gtk/inspector/general.ui:198
+#: gtk/inspector/general.ui:212
 msgid "Application ID"
 msgstr "Identyfikator programu"
 
-#: gtk/inspector/general.ui:224
+#: gtk/inspector/general.ui:238
 msgid "Resource Path"
 msgstr "Ścieżka do zasobu"
 
-#: gtk/inspector/general.ui:261 gtk/ui/gtkplacesview.ui:67
+#: gtk/inspector/general.ui:275 gtk/ui/gtkplacesview.ui:63
 msgid "Prefix"
 msgstr "Przedrostek"
 
-#: gtk/inspector/general.ui:460
+#: gtk/inspector/general.ui:302
+msgid "Environment"
+msgstr "Åšrodowisko"
+
+#: gtk/inspector/general.ui:405
 msgid "Display"
 msgstr "Ekran"
 
-#: gtk/inspector/general.ui:487
+#: gtk/inspector/general.ui:432
 msgid "RGBA Visual"
 msgstr "Wizualne RGBA"
 
-#: gtk/inspector/general.ui:513
+#: gtk/inspector/general.ui:458
 msgid "Composited"
 msgstr "Składane"
 
-#: gtk/inspector/general.ui:538
+#: gtk/inspector/general.ui:483
 msgid "Protocols"
 msgstr "Protokoły"
 
-#: gtk/inspector/general.ui:594
+#: gtk/inspector/general.ui:539
+msgid "GL Renderer"
+msgstr "Mechanizm rysowania GL"
+
+#: gtk/inspector/general.ui:568
+msgid "GL Vendor"
+msgstr "Dostawca GL"
+
+#: gtk/inspector/general.ui:597
 msgid "GL Version"
 msgstr "Wersja GL"
 
-#: gtk/inspector/general.ui:621
-msgid "GL Backend Version"
-msgstr "Wersja mechanizmu GL"
-
-#: gtk/inspector/general.ui:671
+#: gtk/inspector/general.ui:624
 msgid "GL Backend Vendor"
 msgstr "Dostawca mechanizmu GL"
 
-#: gtk/inspector/general.ui:698
-msgid "GL_VENDOR"
-msgstr "DOSTAWCA_GL"
+#: gtk/inspector/general.ui:651
+msgid "GL Backend Version"
+msgstr "Wersja mechanizmu GL"
 
-#: gtk/inspector/general.ui:727
-msgid "GL_RENDERER"
-msgstr "MECHANIZM_RYSOWANIA_GL"
+#: gtk/inspector/general.ui:701
+msgid "GL Full Version"
+msgstr "Pełna wersja GL"
 
-#: gtk/inspector/general.ui:756
-msgid "GL_VERSION"
-msgstr "WERSJA_GL"
+#: gtk/inspector/general.ui:730
+msgid "GLSL Version"
+msgstr "Wersja GLSL"
 
-#: gtk/inspector/general.ui:785
-msgid "GL_SHADING_LANGUAGE_VERSION"
-msgstr "WERSJA_JĘZYKA_CIENIOWANIA_GL"
+#: gtk/inspector/general.ui:759
+msgid "GL Extensions"
+msgstr "Rozszerzenia GL"
 
-#: gtk/inspector/general.ui:813 gtk/inspector/general.ui:929
-msgid "Extensions"
-msgstr "Rozszerzenia"
+#: gtk/inspector/general.ui:847
+msgid "EGL Extensions"
+msgstr "Rozszerzenia EGL"
 
-#: gtk/inspector/general.ui:849
+#: gtk/inspector/general.ui:934
+msgid "GL Features"
+msgstr "Funkcje GL"
+
+#: gtk/inspector/general.ui:970
 msgid "Vulkan Device"
 msgstr "UrzÄ…dzenie Vulkan"
 
-#: gtk/inspector/general.ui:876
-msgid "Vulkan API version"
+#: gtk/inspector/general.ui:997
+msgid "Vulkan API Version"
 msgstr "Wersja API Vulkan"
 
-#: gtk/inspector/general.ui:903
-msgid "Vulkan driver version"
+#: gtk/inspector/general.ui:1024
+msgid "Vulkan Driver Version"
 msgstr "Wersja sterownika Vulkan"
 
+#: gtk/inspector/general.ui:1073
+msgid "Vulkan Layers"
+msgstr "Warstwy Vulkan"
+
+#: gtk/inspector/general.ui:1142
+msgid "Vulkan Extensions"
+msgstr "Rozszerzenia Vulkan"
+
+#: gtk/inspector/general.ui:1229
+msgid "Vulkan Features"
+msgstr "Funkcje Vulkan"
+
 #: gtk/inspector/menu.c:264
 msgid "Unnamed section"
 msgstr "Sekcja bez nazwy"
@@ -4107,7 +4308,7 @@ msgstr "Powierzchnia"
 
 #: gtk/inspector/misc-info.ui:365 gtk/inspector/misc-info.ui:400
 #: gtk/inspector/misc-info.ui:435 gtk/inspector/prop-editor.c:1153
-#: gtk/inspector/prop-editor.c:1536 gtk/inspector/window.ui:396
+#: gtk/inspector/prop-editor.c:1536 gtk/inspector/window.ui:394
 msgid "Properties"
 msgstr "Właściwości"
 
@@ -4131,7 +4332,7 @@ msgstr "Liczba klatek"
 msgid "Frame Rate"
 msgstr "Liczba klatek na sekundÄ™"
 
-#: gtk/inspector/misc-info.ui:527 gtk/inspector/visual.ui:315
+#: gtk/inspector/misc-info.ui:527 gtk/inspector/visual.ui:314
 msgid "Scale"
 msgstr "Skalowanie"
 
@@ -4259,7 +4460,7 @@ msgstr "Źródło:"
 msgid "Defined At"
 msgstr "Określone w"
 
-#: gtk/inspector/recorder.c:2021
+#: gtk/inspector/recorder.c:2036
 #, c-format
 msgid "Saving RenderNode failed"
 msgstr "Zapisanie węzła rysowania się nie powiodło"
@@ -4312,7 +4513,7 @@ msgstr "Nazwa:"
 msgid "Type:"
 msgstr "Typ:"
 
-#: gtk/inspector/resource-list.ui:164 tools/gtk-image-tool-info.c:54
+#: gtk/inspector/resource-list.ui:164 tools/gtk-image-tool-info.c:56
 msgid "Size:"
 msgstr "Rozmiar:"
 
@@ -4425,45 +4626,46 @@ msgstr "Motyw ikon"
 msgid "Text Direction"
 msgstr "Kierunek tekstu"
 
+#. translators: these strings must be separated by newlines
 #: gtk/inspector/visual.ui:184
-msgid "Left-to-Right"
-msgstr "Od lewej do prawej"
-
-#: gtk/inspector/visual.ui:185
-msgid "Right-to-Left"
-msgstr "Od prawej do lewej"
+msgid ""
+"Left-to-Right\n"
+"Right-to-Left"
+msgstr ""
+"Od lewej do prawej\n"
+"Od prawej do lewej"
 
-#: gtk/inspector/visual.ui:202
+#: gtk/inspector/visual.ui:201
 msgid "Animations"
 msgstr "Animacje"
 
-#: gtk/inspector/visual.ui:227
+#: gtk/inspector/visual.ui:226
 msgid "Slowdown"
 msgstr "Spowolnienie"
 
-#: gtk/inspector/visual.ui:362
+#: gtk/inspector/visual.ui:361
 msgid "Rendering"
 msgstr "Rysowanie"
 
-#: gtk/inspector/visual.ui:377
+#. translators: these strings must be separated by newlines
+#: gtk/inspector/visual.ui:376
 msgctxt "Font rendering"
-msgid "Automatic"
-msgstr "Automatyczne"
-
-#: gtk/inspector/visual.ui:378
-msgctxt "Font rendering"
-msgid "Manual"
-msgstr "Ręczne"
+msgid ""
+"Automatic\n"
+"Manual"
+msgstr ""
+"Automatyczne\n"
+"Ręczne"
 
-#: gtk/inspector/visual.ui:405
+#: gtk/inspector/visual.ui:403
 msgid "Show Framerate"
 msgstr "Wyświetlanie liczby klatek na sekundę"
 
-#: gtk/inspector/visual.ui:430
+#: gtk/inspector/visual.ui:428
 msgid "Show Graphic Updates"
 msgstr "Wyświetlanie aktualizacji grafiki"
 
-#: gtk/inspector/visual.ui:450
+#: gtk/inspector/visual.ui:448
 msgid ""
 "Tints all the places where the current renderer uses Cairo instead of the "
 "GPU."
@@ -4471,47 +4673,47 @@ msgstr ""
 "Zabarwia wszystkie miejsca, w których obecny mechanizm rysowania używa "
 "biblioteki Cairo zamiast procesora graficznego."
 
-#: gtk/inspector/visual.ui:456
+#: gtk/inspector/visual.ui:454
 msgid "Show Cairo Rendering"
 msgstr "Wyświetlanie rysowania przez Cairo"
 
-#: gtk/inspector/visual.ui:481
+#: gtk/inspector/visual.ui:479
 msgid "Show Baselines"
 msgstr "Wyświetlanie linii bazowych"
 
-#: gtk/inspector/visual.ui:509
+#: gtk/inspector/visual.ui:507
 msgid "Show Layout Borders"
 msgstr "Wyświetlanie krawędzi układu"
 
-#: gtk/inspector/visual.ui:566
+#: gtk/inspector/visual.ui:564
 msgid "CSS Padding"
 msgstr "Wypełnienie CSS"
 
-#: gtk/inspector/visual.ui:576
+#: gtk/inspector/visual.ui:574
 msgid "CSS Border"
 msgstr "Krawędź CSS"
 
-#: gtk/inspector/visual.ui:586
+#: gtk/inspector/visual.ui:584
 msgid "CSS Margin"
 msgstr "Margines CSS"
 
-#: gtk/inspector/visual.ui:596
+#: gtk/inspector/visual.ui:594
 msgid "Widget Margin"
 msgstr "Margines widżetu"
 
-#: gtk/inspector/visual.ui:631
+#: gtk/inspector/visual.ui:629
 msgid "Show Focus"
 msgstr "Wyświetlanie aktywności"
 
-#: gtk/inspector/visual.ui:656
+#: gtk/inspector/visual.ui:654
 msgid "Show Accessibility warnings"
 msgstr "Wyświetlanie ostrzeżeń ułatwień dostępu"
 
-#: gtk/inspector/visual.ui:681
+#: gtk/inspector/visual.ui:679
 msgid "Show Graphics Offload"
 msgstr "Wyświetlanie rozładowywania grafiki"
 
-#: gtk/inspector/visual.ui:713
+#: gtk/inspector/visual.ui:711
 msgid "Inspect Inspector"
 msgstr "Zbadaj inspektora"
 
@@ -4563,79 +4765,79 @@ msgstr "Poprzednie rodzeństwo"
 msgid "List Position"
 msgstr "Położenie na liście"
 
-#: gtk/inspector/window.ui:356
+#: gtk/inspector/window.ui:354
 msgid "Next sibling"
 msgstr "Następne rodzeństwo"
 
-#: gtk/inspector/window.ui:386
+#: gtk/inspector/window.ui:384
 msgid "Miscellaneous"
 msgstr "Różne"
 
-#: gtk/inspector/window.ui:407 gtk/print/ui/gtkprintunixdialog.ui:451
+#: gtk/inspector/window.ui:405 gtk/print/ui/gtkprintunixdialog.ui:451
 msgid "Layout"
 msgstr "Układ"
 
-#: gtk/inspector/window.ui:418
+#: gtk/inspector/window.ui:416
 msgid "CSS Nodes"
 msgstr "Węzły CSS"
 
-#: gtk/inspector/window.ui:429
+#: gtk/inspector/window.ui:427
 msgid "Size Groups"
 msgstr "Grupy rozmiarów"
 
-#: gtk/inspector/window.ui:438 gtk/inspector/window.ui:447
+#: gtk/inspector/window.ui:436 gtk/inspector/window.ui:445
 msgid "Data"
 msgstr "Dane"
 
-#: gtk/inspector/window.ui:457
+#: gtk/inspector/window.ui:455
 msgid "Actions"
 msgstr "Działania"
 
-#: gtk/inspector/window.ui:468
+#: gtk/inspector/window.ui:466
 msgid "Menu"
 msgstr "Menu"
 
-#: gtk/inspector/window.ui:477
+#: gtk/inspector/window.ui:475
 msgid "Controllers"
 msgstr "Kontrolery"
 
-#: gtk/inspector/window.ui:487
+#: gtk/inspector/window.ui:485
 msgid "Magnifier"
 msgstr "Lupa"
 
-#: gtk/inspector/window.ui:508
+#: gtk/inspector/window.ui:506
 msgid "Accessibility"
 msgstr "Ułatwienia dostępu"
 
-#: gtk/inspector/window.ui:532
+#: gtk/inspector/window.ui:530
 msgid "Global"
 msgstr "Globalne"
 
-#: gtk/inspector/window.ui:545
+#: gtk/inspector/window.ui:543
 msgid "Information"
 msgstr "Informacja"
 
-#: gtk/inspector/window.ui:554
+#: gtk/inspector/window.ui:552
 msgid "Settings"
 msgstr "Ustawienia"
 
-#: gtk/inspector/window.ui:563
+#: gtk/inspector/window.ui:561
 msgid "Resources"
 msgstr "Zasoby"
 
-#: gtk/inspector/window.ui:584
+#: gtk/inspector/window.ui:582
 msgid "Statistics"
 msgstr "Statystyki"
 
-#: gtk/inspector/window.ui:595
+#: gtk/inspector/window.ui:593
 msgid "Logging"
 msgstr "Dziennik"
 
-#: gtk/inspector/window.ui:610
+#: gtk/inspector/window.ui:608
 msgid "CSS"
 msgstr "CSS"
 
-#: gtk/inspector/window.ui:619
+#: gtk/inspector/window.ui:617
 msgid "Recorder"
 msgstr "Nagrywanie"
 
@@ -6157,7 +6359,7 @@ msgstr "O programie"
 msgid "Credits"
 msgstr "Zasługi"
 
-#: gtk/ui/gtkaboutdialog.ui:219
+#: gtk/ui/gtkaboutdialog.ui:221
 msgid "System"
 msgstr "System"
 
@@ -6201,6 +6403,38 @@ msgstr "Wyświetl wszystkie"
 msgid "Quit %s"
 msgstr "Zakończ program %s"
 
+#: gtk/ui/gtkapplication-quartz.ui:50
+msgid "_Edit"
+msgstr "_Edycja"
+
+#: gtk/ui/gtkapplication-quartz.ui:53
+msgid "Undo"
+msgstr "Cofnij"
+
+#: gtk/ui/gtkapplication-quartz.ui:57
+msgid "Redo"
+msgstr "Ponów"
+
+#: gtk/ui/gtkapplication-quartz.ui:63
+msgid "Cut"
+msgstr "Wytnij"
+
+#: gtk/ui/gtkapplication-quartz.ui:67
+msgid "Copy"
+msgstr "Skopiuj"
+
+#: gtk/ui/gtkapplication-quartz.ui:71
+msgid "Paste"
+msgstr "Wklej"
+
+#: gtk/ui/gtkapplication-quartz.ui:75
+msgid "Delete"
+msgstr "Usuń"
+
+#: gtk/ui/gtkapplication-quartz.ui:79
+msgid "Select All"
+msgstr "Zaznacz wszystko"
+
 #: gtk/ui/gtkassistant.ui:64
 msgid "_Finish"
 msgstr "_Ukończ"
@@ -6319,7 +6553,7 @@ msgstr "Ostatnio używane"
 msgid "Create Folder"
 msgstr "Tworzy katalog"
 
-#: gtk/ui/gtkfilechooserwidget.ui:202
+#: gtk/ui/gtkfilechooserwidget.ui:205
 msgid "Remote location — only searching the current folder"
 msgstr "Zdalne położenie — przeszukiwanie tylko bieżącego katalogu"
 
@@ -6327,7 +6561,7 @@ msgstr "Zdalne położenie — przeszukiwanie tylko bieżącego katalogu"
 msgid "Folder Name"
 msgstr "Nazwa katalogu"
 
-#: gtk/ui/gtkfilechooserwidget.ui:360
+#: gtk/ui/gtkfilechooserwidget.ui:358
 msgid "_Create"
 msgstr "_Utwórz"
 
@@ -6355,21 +6589,21 @@ msgstr "Czcionka o stałej szerokości znaków"
 msgid "Language"
 msgstr "Język"
 
-#: gtk/ui/gtkfontchooserwidget.ui:199 gtk/ui/gtkfontchooserwidget.ui:201
-#: gtk/ui/gtkfontchooserwidget.ui:354 gtk/ui/gtkfontchooserwidget.ui:358
+#: gtk/ui/gtkfontchooserwidget.ui:197 gtk/ui/gtkfontchooserwidget.ui:199
+#: gtk/ui/gtkfontchooserwidget.ui:349 gtk/ui/gtkfontchooserwidget.ui:353
 msgid "Preview Font"
 msgstr "PodglÄ…d czcionki"
 
-#: gtk/ui/gtkfontchooserwidget.ui:297
+#: gtk/ui/gtkfontchooserwidget.ui:295
 msgid "No Fonts Found"
 msgstr "Brak czcionek"
 
-#: gtk/ui/gtkmediacontrols.ui:47
+#: gtk/ui/gtkmediacontrols.ui:45
 msgctxt "media controls"
 msgid "Position"
 msgstr "Pozycja"
 
-#: gtk/ui/gtkmediacontrols.ui:65
+#: gtk/ui/gtkmediacontrols.ui:61
 msgctxt "media controls"
 msgid "Volume"
 msgstr "Głośność"
@@ -6411,36 +6645,40 @@ msgstr "Odwrócona poziomo"
 msgid "Server Addresses"
 msgstr "Adres serwera"
 
-#: gtk/ui/gtkplacesview.ui:28
+#: gtk/ui/gtkplacesview.ui:26
 msgid ""
 "Server addresses are made up of a protocol prefix and an address. Examples:"
 msgstr "Adres serwera składa się z przedrostka protokołu i adresu. Przykłady:"
 
-#: gtk/ui/gtkplacesview.ui:54
+#: gtk/ui/gtkplacesview.ui:52
 msgid "Available Protocols"
 msgstr "Dostępne protokoły"
 
 #. Translators: Server as any successfully connected network address
-#: gtk/ui/gtkplacesview.ui:106
+#: gtk/ui/gtkplacesview.ui:100
 msgid "No recent servers found"
 msgstr "Brak ostatnio używanych serwerów"
 
-#: gtk/ui/gtkplacesview.ui:129
+#: gtk/ui/gtkplacesview.ui:123
 msgid "Recent Servers"
 msgstr "Ostatnio używane serwery"
 
-#: gtk/ui/gtkplacesview.ui:209
+#: gtk/ui/gtkplacesview.ui:201
 msgid "No results found"
 msgstr "Brak wyników"
 
-#: gtk/ui/gtkplacesview.ui:240
+#: gtk/ui/gtkplacesview.ui:229
 msgid "Connect to _Server"
 msgstr "Połącz z _serwerem"
 
-#: gtk/ui/gtkplacesview.ui:265
+#: gtk/ui/gtkplacesview.ui:252
 msgid "Enter server address…"
 msgstr "Adres serwera…"
 
+#: gtk/ui/gtkplacesview.ui:265
+msgid "Show recent servers"
+msgstr "Wyświetla ostatnio używane serwery"
+
 #. this is the header for the printer status column in the print dialog
 #: gtk/print/ui/gtkprintunixdialog.ui:142
 msgid "Status"
@@ -6547,37 +6785,37 @@ msgstr "_Tacka wyjściowa:"
 msgid "Or_ientation:"
 msgstr "Orienta_cja:"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:805
+#: gtk/print/ui/gtkprintunixdialog.ui:806
 msgid "Job Details"
 msgstr "Szczegóły zadania"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:820
+#: gtk/print/ui/gtkprintunixdialog.ui:821
 msgid "Pri_ority:"
 msgstr "Pri_orytet:"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:841
+#: gtk/print/ui/gtkprintunixdialog.ui:842
 msgid "_Billing info:"
 msgstr "Informacje o opłatac_h:"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:874
+#: gtk/print/ui/gtkprintunixdialog.ui:875
 msgid "Print Document"
 msgstr "Wydruk dokumentu"
 
 #. this is one of the choices for the print at option in the print dialog
-#: gtk/print/ui/gtkprintunixdialog.ui:887
+#: gtk/print/ui/gtkprintunixdialog.ui:888
 msgid "_Now"
 msgstr "_Teraz"
 
 #. this is one of the choices for the print at option in the print dialog. It also serves as the label for an entry that allows the user to enter a time.
-#: gtk/print/ui/gtkprintunixdialog.ui:901
+#: gtk/print/ui/gtkprintunixdialog.ui:902
 msgid "A_t:"
 msgstr "_O:"
 
 #. Ability to parse the am/pm format depends on actual locale. You can remove the am/pm values below for your locale if they are not supported.
-#: gtk/print/ui/gtkprintunixdialog.ui:903
-#: gtk/print/ui/gtkprintunixdialog.ui:905
-#: gtk/print/ui/gtkprintunixdialog.ui:921
-#: gtk/print/ui/gtkprintunixdialog.ui:923
+#: gtk/print/ui/gtkprintunixdialog.ui:904
+#: gtk/print/ui/gtkprintunixdialog.ui:906
+#: gtk/print/ui/gtkprintunixdialog.ui:922
+#: gtk/print/ui/gtkprintunixdialog.ui:924
 msgid ""
 "Specify the time of print,\n"
 " e.g. 15∶30, 2∶35 pm, 14∶15∶20, 11∶46∶30 am, 4 pm"
@@ -6586,76 +6824,76 @@ msgstr ""
 " przykładowo: 15∶30, 14∶15∶20, 11∶46∶30"
 
 #. this is one of the choices for the print at option in the print dialog. It means that the print job will not be printed until it explicitly gets 'released'.
-#: gtk/print/ui/gtkprintunixdialog.ui:935
+#: gtk/print/ui/gtkprintunixdialog.ui:936
 msgid "On _hold"
 msgstr "Wstrzy_many"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:937
 #: gtk/print/ui/gtkprintunixdialog.ui:938
+#: gtk/print/ui/gtkprintunixdialog.ui:939
 msgid "Hold the job until it is explicitly released"
 msgstr "Wstrzymuje zadanie do czasu jego jawnego zwolnienia"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:965
+#: gtk/print/ui/gtkprintunixdialog.ui:966
 msgid "Add Cover Page"
 msgstr "Strona tytułowa"
 
 #. this is the label used for the option in the print dialog that controls the front cover page.
-#: gtk/print/ui/gtkprintunixdialog.ui:980
+#: gtk/print/ui/gtkprintunixdialog.ui:981
 msgid "Be_fore:"
 msgstr "P_rzed:"
 
 #. this is the label used for the option in the print dialog that controls the back cover page.
-#: gtk/print/ui/gtkprintunixdialog.ui:1001
+#: gtk/print/ui/gtkprintunixdialog.ui:1002
 msgid "_After:"
 msgstr "_Po:"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:1030
+#: gtk/print/ui/gtkprintunixdialog.ui:1031
 msgid "Job"
 msgstr "Zadanie"
 
 #. This will appear as a tab label in the print dialog.
-#: gtk/print/ui/gtkprintunixdialog.ui:1060
+#: gtk/print/ui/gtkprintunixdialog.ui:1061
 msgid "Image Quality"
 msgstr "Jakość obrazu"
 
 #. This will appear as a tab label in the print dialog.
-#: gtk/print/ui/gtkprintunixdialog.ui:1089
+#: gtk/print/ui/gtkprintunixdialog.ui:1090
 msgid "Color"
 msgstr "Kolor"
 
 #. This will appear as a tab label in the print dialog. It's a typographical term, as in "Binding and finishing"
-#: gtk/print/ui/gtkprintunixdialog.ui:1118
+#: gtk/print/ui/gtkprintunixdialog.ui:1119
 msgid "Finishing"
 msgstr "Kończenie"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:1147
+#: gtk/print/ui/gtkprintunixdialog.ui:1148
 msgid "Advanced"
 msgstr "Zaawansowane"
 
-#: gtk/print/ui/gtkprintunixdialog.ui:1163
+#: gtk/print/ui/gtkprintunixdialog.ui:1164
 msgid "Some of the settings in the dialog conflict"
 msgstr "Część ustawień w oknie jest sprzecznych"
 
 #: modules/printbackends/gtkprintbackendcpdb.c:542
-#: modules/printbackends/gtkprintbackendcups.c:5668
+#: modules/printbackends/gtkprintbackendcups.c:5670
 msgctxt "Print job priority"
 msgid "Urgent"
 msgstr "Pilne"
 
 #: modules/printbackends/gtkprintbackendcpdb.c:543
-#: modules/printbackends/gtkprintbackendcups.c:5669
+#: modules/printbackends/gtkprintbackendcups.c:5671
 msgctxt "Print job priority"
 msgid "High"
 msgstr "Wysoki"
 
 #: modules/printbackends/gtkprintbackendcpdb.c:544
-#: modules/printbackends/gtkprintbackendcups.c:5670
+#: modules/printbackends/gtkprintbackendcups.c:5672
 msgctxt "Print job priority"
 msgid "Medium"
 msgstr "Åšredni"
 
 #: modules/printbackends/gtkprintbackendcpdb.c:545
-#: modules/printbackends/gtkprintbackendcups.c:5671
+#: modules/printbackends/gtkprintbackendcups.c:5673
 msgctxt "Print job priority"
 msgid "Low"
 msgstr "Niski"
@@ -6664,7 +6902,7 @@ msgstr "Niski"
 #. * dialog that controls the front cover page.
 #.
 #: modules/printbackends/gtkprintbackendcpdb.c:567
-#: modules/printbackends/gtkprintbackendcups.c:5814
+#: modules/printbackends/gtkprintbackendcups.c:5816
 msgctxt "printer option"
 msgid "Before"
 msgstr "Przed"
@@ -6673,7 +6911,7 @@ msgstr "Przed"
 #. * dialog that controls the back cover page.
 #.
 #: modules/printbackends/gtkprintbackendcpdb.c:574
-#: modules/printbackends/gtkprintbackendcups.c:5829
+#: modules/printbackends/gtkprintbackendcups.c:5831
 msgctxt "printer option"
 msgid "After"
 msgstr "Po"
@@ -6851,266 +7089,266 @@ msgstr "Wystąpił problem z drukarką „%s”."
 msgid "; "
 msgstr ", "
 
-#: modules/printbackends/gtkprintbackendcups.c:4609
-#: modules/printbackends/gtkprintbackendcups.c:4676
+#: modules/printbackends/gtkprintbackendcups.c:4611
+#: modules/printbackends/gtkprintbackendcups.c:4678
 msgctxt "printing option"
 msgid "Two Sided"
 msgstr "Dwustronne"
 
-#: modules/printbackends/gtkprintbackendcups.c:4610
+#: modules/printbackends/gtkprintbackendcups.c:4612
 msgctxt "printing option"
 msgid "Paper Type"
 msgstr "Rodzaj papieru"
 
-#: modules/printbackends/gtkprintbackendcups.c:4611
+#: modules/printbackends/gtkprintbackendcups.c:4613
 msgctxt "printing option"
 msgid "Paper Source"
 msgstr "Źródło papieru"
 
-#: modules/printbackends/gtkprintbackendcups.c:4612
-#: modules/printbackends/gtkprintbackendcups.c:4677
+#: modules/printbackends/gtkprintbackendcups.c:4614
+#: modules/printbackends/gtkprintbackendcups.c:4679
 msgctxt "printing option"
 msgid "Output Tray"
 msgstr "Tacka wyjściowa"
 
-#: modules/printbackends/gtkprintbackendcups.c:4613
+#: modules/printbackends/gtkprintbackendcups.c:4615
 msgctxt "printing option"
 msgid "Resolution"
 msgstr "Rozdzielczość"
 
-#: modules/printbackends/gtkprintbackendcups.c:4614
+#: modules/printbackends/gtkprintbackendcups.c:4616
 msgctxt "printing option"
 msgid "GhostScript pre-filtering"
 msgstr "Wstępne filtrowanie GhostScript"
 
-#: modules/printbackends/gtkprintbackendcups.c:4623
+#: modules/printbackends/gtkprintbackendcups.c:4625
 msgctxt "printing option value"
 msgid "One Sided"
 msgstr "Jednostronne"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4625
+#: modules/printbackends/gtkprintbackendcups.c:4627
 msgctxt "printing option value"
 msgid "Long Edge (Standard)"
 msgstr "Grzbiet wzdłuż dłuższej krawędzi (standard)"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4627
+#: modules/printbackends/gtkprintbackendcups.c:4629
 msgctxt "printing option value"
 msgid "Short Edge (Flip)"
 msgstr "Grzbiet wzdłuż krótszej krawędzi (obrót)"
 
 #. Translators: this is an option of "Paper Source"
-#: modules/printbackends/gtkprintbackendcups.c:4629
 #: modules/printbackends/gtkprintbackendcups.c:4631
-#: modules/printbackends/gtkprintbackendcups.c:4639
+#: modules/printbackends/gtkprintbackendcups.c:4633
+#: modules/printbackends/gtkprintbackendcups.c:4641
 msgctxt "printing option value"
 msgid "Auto Select"
 msgstr "Wybór automatyczny"
 
 #. Translators: this is an option of "Paper Source"
 #. Translators: this is an option of "Resolution"
-#: modules/printbackends/gtkprintbackendcups.c:4633
 #: modules/printbackends/gtkprintbackendcups.c:4635
 #: modules/printbackends/gtkprintbackendcups.c:4637
-#: modules/printbackends/gtkprintbackendcups.c:4641
+#: modules/printbackends/gtkprintbackendcups.c:4639
+#: modules/printbackends/gtkprintbackendcups.c:4643
 msgctxt "printing option value"
 msgid "Printer Default"
 msgstr "Domyślne drukarki"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4643
+#: modules/printbackends/gtkprintbackendcups.c:4645
 msgctxt "printing option value"
 msgid "Embed GhostScript fonts only"
 msgstr "Osadzanie tylko czcionek GhostScript"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4645
+#: modules/printbackends/gtkprintbackendcups.c:4647
 msgctxt "printing option value"
 msgid "Convert to PS level 1"
 msgstr "Konwertowanie do „PS level 1”"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4647
+#: modules/printbackends/gtkprintbackendcups.c:4649
 msgctxt "printing option value"
 msgid "Convert to PS level 2"
 msgstr "Konwertowanie do „PS level 2”"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4649
+#: modules/printbackends/gtkprintbackendcups.c:4651
 msgctxt "printing option value"
 msgid "No pre-filtering"
 msgstr "Bez wstępnego filtrowania"
 
 #. Translators: "Miscellaneous" is the label for a button, that opens
 #. up an extra panel of settings in a print dialog.
-#: modules/printbackends/gtkprintbackendcups.c:4658
+#: modules/printbackends/gtkprintbackendcups.c:4660
 msgctxt "printing option group"
 msgid "Miscellaneous"
 msgstr "Różne"
 
-#: modules/printbackends/gtkprintbackendcups.c:4685
+#: modules/printbackends/gtkprintbackendcups.c:4687
 msgctxt "sides"
 msgid "One Sided"
 msgstr "Jednostronne"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4687
+#: modules/printbackends/gtkprintbackendcups.c:4689
 msgctxt "sides"
 msgid "Long Edge (Standard)"
 msgstr "Grzbiet wzdłuż dłuższej krawędzi (standard)"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4689
+#: modules/printbackends/gtkprintbackendcups.c:4691
 msgctxt "sides"
 msgid "Short Edge (Flip)"
 msgstr "Grzbiet wzdłuż krótszej krawędzi (obrót)"
 
 #. Translators: Top output bin
-#: modules/printbackends/gtkprintbackendcups.c:4692
+#: modules/printbackends/gtkprintbackendcups.c:4694
 msgctxt "output-bin"
 msgid "Top Bin"
 msgstr "Górny pojemnik"
 
 #. Translators: Middle output bin
-#: modules/printbackends/gtkprintbackendcups.c:4694
+#: modules/printbackends/gtkprintbackendcups.c:4696
 msgctxt "output-bin"
 msgid "Middle Bin"
 msgstr "Åšrodkowy pojemnik"
 
 #. Translators: Bottom output bin
-#: modules/printbackends/gtkprintbackendcups.c:4696
+#: modules/printbackends/gtkprintbackendcups.c:4698
 msgctxt "output-bin"
 msgid "Bottom Bin"
 msgstr "Dolny pojemnik"
 
 #. Translators: Side output bin
-#: modules/printbackends/gtkprintbackendcups.c:4698
+#: modules/printbackends/gtkprintbackendcups.c:4700
 msgctxt "output-bin"
 msgid "Side Bin"
 msgstr "Boczny pojemnik"
 
 #. Translators: Left output bin
-#: modules/printbackends/gtkprintbackendcups.c:4700
+#: modules/printbackends/gtkprintbackendcups.c:4702
 msgctxt "output-bin"
 msgid "Left Bin"
 msgstr "Lewy pojemnik"
 
 #. Translators: Right output bin
-#: modules/printbackends/gtkprintbackendcups.c:4702
+#: modules/printbackends/gtkprintbackendcups.c:4704
 msgctxt "output-bin"
 msgid "Right Bin"
 msgstr "Prawy pojemnik"
 
 #. Translators: Center output bin
-#: modules/printbackends/gtkprintbackendcups.c:4704
+#: modules/printbackends/gtkprintbackendcups.c:4706
 msgctxt "output-bin"
 msgid "Center Bin"
 msgstr "Centralny pojemnik"
 
 #. Translators: Rear output bin
-#: modules/printbackends/gtkprintbackendcups.c:4706
+#: modules/printbackends/gtkprintbackendcups.c:4708
 msgctxt "output-bin"
 msgid "Rear Bin"
 msgstr "Tylny pojemnik"
 
 #. Translators: Output bin where one sided output is oriented in the face-up position
-#: modules/printbackends/gtkprintbackendcups.c:4708
+#: modules/printbackends/gtkprintbackendcups.c:4710
 msgctxt "output-bin"
 msgid "Face Up Bin"
 msgstr "Pojemnik wierzchem do góry"
 
 #. Translators: Output bin where one sided output is oriented in the face-down position
-#: modules/printbackends/gtkprintbackendcups.c:4710
+#: modules/printbackends/gtkprintbackendcups.c:4712
 msgctxt "output-bin"
 msgid "Face Down Bin"
 msgstr "Pojemnik wierzchem do dołu"
 
 #. Translators: Large capacity output bin
-#: modules/printbackends/gtkprintbackendcups.c:4712
+#: modules/printbackends/gtkprintbackendcups.c:4714
 msgctxt "output-bin"
 msgid "Large Capacity Bin"
 msgstr "Pojemnik o dużej pojemności"
 
 #. Translators: Output stacker number %d
-#: modules/printbackends/gtkprintbackendcups.c:4734
+#: modules/printbackends/gtkprintbackendcups.c:4736
 #, c-format
 msgctxt "output-bin"
 msgid "Stacker %d"
 msgstr "%d. stertnik"
 
 #. Translators: Output mailbox number %d
-#: modules/printbackends/gtkprintbackendcups.c:4738
+#: modules/printbackends/gtkprintbackendcups.c:4740
 #, c-format
 msgctxt "output-bin"
 msgid "Mailbox %d"
 msgstr "%d. skrzynka pocztowa"
 
 #. Translators: Private mailbox
-#: modules/printbackends/gtkprintbackendcups.c:4742
+#: modules/printbackends/gtkprintbackendcups.c:4744
 msgctxt "output-bin"
 msgid "My Mailbox"
 msgstr "Prywatna skrzynka pocztowa"
 
 #. Translators: Output tray number %d
-#: modules/printbackends/gtkprintbackendcups.c:4746
+#: modules/printbackends/gtkprintbackendcups.c:4748
 #, c-format
 msgctxt "output-bin"
 msgid "Tray %d"
 msgstr "%d. tacka"
 
-#: modules/printbackends/gtkprintbackendcups.c:5223
+#: modules/printbackends/gtkprintbackendcups.c:5225
 msgid "Printer Default"
 msgstr "Domyślne drukarki"
 
 #. Translators, this string is used to label the job priority option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5702
+#: modules/printbackends/gtkprintbackendcups.c:5704
 msgid "Job Priority"
 msgstr "Priorytet"
 
 #. Translators, this string is used to label the billing info entry
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5713
+#: modules/printbackends/gtkprintbackendcups.c:5715
 msgid "Billing Info"
 msgstr "Informacje o opłatach"
 
 #. Translators, these strings are names for various 'standard' cover
 #. * pages that the printing system may support.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5737
+#: modules/printbackends/gtkprintbackendcups.c:5739
 msgctxt "cover page"
 msgid "None"
 msgstr "Brak"
 
-#: modules/printbackends/gtkprintbackendcups.c:5738
+#: modules/printbackends/gtkprintbackendcups.c:5740
 msgctxt "cover page"
 msgid "Classified"
 msgstr "Niejawne"
 
-#: modules/printbackends/gtkprintbackendcups.c:5739
+#: modules/printbackends/gtkprintbackendcups.c:5741
 msgctxt "cover page"
 msgid "Confidential"
 msgstr "Poufne"
 
-#: modules/printbackends/gtkprintbackendcups.c:5740
+#: modules/printbackends/gtkprintbackendcups.c:5742
 msgctxt "cover page"
 msgid "Secret"
 msgstr "Tajne"
 
-#: modules/printbackends/gtkprintbackendcups.c:5741
+#: modules/printbackends/gtkprintbackendcups.c:5743
 msgctxt "cover page"
 msgid "Standard"
 msgstr "Standardowe"
 
-#: modules/printbackends/gtkprintbackendcups.c:5742
+#: modules/printbackends/gtkprintbackendcups.c:5744
 msgctxt "cover page"
 msgid "Top Secret"
 msgstr "Ściśle tajne"
 
-#: modules/printbackends/gtkprintbackendcups.c:5743
+#: modules/printbackends/gtkprintbackendcups.c:5745
 msgctxt "cover page"
 msgid "Unclassified"
 msgstr "Jawne"
@@ -7118,7 +7356,7 @@ msgstr "Jawne"
 #. Translators, this string is used to label the pages-per-sheet option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5755
+#: modules/printbackends/gtkprintbackendcups.c:5757
 msgctxt "printer option"
 msgid "Pages per Sheet"
 msgstr "Stron na kartkÄ™"
@@ -7126,7 +7364,7 @@ msgstr "Stron na kartkÄ™"
 #. Translators, this string is used to label the option in the print
 #. * dialog that controls in what order multiple pages are arranged
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5772
+#: modules/printbackends/gtkprintbackendcups.c:5774
 msgctxt "printer option"
 msgid "Page Ordering"
 msgstr "Kolejność stron"
@@ -7135,7 +7373,7 @@ msgstr "Kolejność stron"
 #. * a print job is printed. Possible values are 'now', a specified time,
 #. * or 'on hold'
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5849
+#: modules/printbackends/gtkprintbackendcups.c:5851
 msgctxt "printer option"
 msgid "Print at"
 msgstr "Wydruk o"
@@ -7143,7 +7381,7 @@ msgstr "Wydruk o"
 #. Translators: this is the name of the option that allows the user
 #. * to specify a time when a print job will be printed.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5860
+#: modules/printbackends/gtkprintbackendcups.c:5862
 msgctxt "printer option"
 msgid "Print at time"
 msgstr "Wydruk o czasie"
@@ -7153,52 +7391,52 @@ msgstr "Wydruk o czasie"
 #. * the width and height in points. E.g: "Custom
 #. * 230.4x142.9"
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5907
+#: modules/printbackends/gtkprintbackendcups.c:5909
 #, c-format
 msgid "Custom %s×%s"
 msgstr "Niestandardowy %s×%s"
 
 #. TRANSLATORS: this is the ICC color profile to use for this job
-#: modules/printbackends/gtkprintbackendcups.c:6018
+#: modules/printbackends/gtkprintbackendcups.c:6020
 msgctxt "printer option"
 msgid "Printer Profile"
 msgstr "Profil drukarki"
 
 #. TRANSLATORS: this is when color profile information is unavailable
-#: modules/printbackends/gtkprintbackendcups.c:6025
+#: modules/printbackends/gtkprintbackendcups.c:6027
 msgctxt "printer option value"
 msgid "Unavailable"
 msgstr "Niedostępny"
 
-#: modules/printbackends/gtkprintbackendfile.c:238
+#: modules/printbackends/gtkprintbackendfile.c:263
 msgid "output"
 msgstr "dane-wyjściowe"
 
-#: modules/printbackends/gtkprintbackendfile.c:510
+#: modules/printbackends/gtkprintbackendfile.c:543
 msgid "Print to File"
 msgstr "Wydruk do pliku"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PDF"
 msgstr "PDF"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PostScript"
 msgstr "PostScript"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "SVG"
 msgstr "SVG"
 
-#: modules/printbackends/gtkprintbackendfile.c:649
+#: modules/printbackends/gtkprintbackendfile.c:688
 msgid "Pages per _sheet:"
 msgstr "Stron _na kartkÄ™:"
 
-#: modules/printbackends/gtkprintbackendfile.c:709
+#: modules/printbackends/gtkprintbackendfile.c:758
 msgid "File"
 msgstr "Plik"
 
-#: modules/printbackends/gtkprintbackendfile.c:719
+#: modules/printbackends/gtkprintbackendfile.c:768
 msgid "_Output format"
 msgstr "_Format wyjściowy"
 
@@ -7279,8 +7517,8 @@ msgstr ""
 
 #: tools/gtk-builder-tool-enumerate.c:56 tools/gtk-builder-tool-preview.c:179
 #: tools/gtk-builder-tool-preview.c:180 tools/gtk-builder-tool-screenshot.c:360
-#: tools/gtk-builder-tool-simplify.c:2623 tools/gtk-builder-tool-validate.c:261
-#: tools/gtk-image-tool-compare.c:43 tools/gtk-image-tool-info.c:68
+#: tools/gtk-builder-tool-simplify.c:2709 tools/gtk-builder-tool-validate.c:267
+#: tools/gtk-image-tool-compare.c:43 tools/gtk-image-tool-info.c:79
 #: tools/gtk-path-tool-render.c:121 tools/gtk-rendernode-tool-compare.c:67
 #: tools/gtk-rendernode-tool-extract.c:294 tools/gtk-rendernode-tool-info.c:226
 #: tools/gtk-rendernode-tool-show.c:116
@@ -7315,7 +7553,7 @@ msgid "Use style from CSS file"
 msgstr "Używa stylu z pliku CSS"
 
 #: tools/gtk-builder-tool-preview.c:187 tools/gtk-builder-tool-screenshot.c:370
-#: tools/gtk-builder-tool-validate.c:268
+#: tools/gtk-builder-tool-validate.c:274
 #: tools/gtk-rendernode-tool-benchmark.c:108
 #: tools/gtk-rendernode-tool-render.c:262 tools/gtk-rendernode-tool-show.c:123
 #, c-format
@@ -7327,7 +7565,7 @@ msgid "Preview the file."
 msgstr "Wyświetla podgląd pliku."
 
 #: tools/gtk-builder-tool-preview.c:208 tools/gtk-builder-tool-screenshot.c:391
-#: tools/gtk-builder-tool-simplify.c:2646 tools/gtk-builder-tool-validate.c:287
+#: tools/gtk-builder-tool-simplify.c:2733 tools/gtk-builder-tool-validate.c:293
 #, c-format
 msgid "No .ui file specified\n"
 msgstr "Nie podano pliku .ui\n"
@@ -7401,76 +7639,81 @@ msgstr "Rysuje plik .ui do obrazu."
 msgid "Can only render a single .ui file to a single output file\n"
 msgstr "Można narysować tylko jeden plik .ui do jednego pliku wyjściowego\n"
 
-#: tools/gtk-builder-tool-simplify.c:444
+#: tools/gtk-builder-tool-simplify.c:447
 #, c-format
 msgid "%s:%d: Couldn’t parse value for property '%s': %s\n"
 msgstr "%s:%d: nie można przetworzyć wartości dla właściwości „%s”: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:658
+#: tools/gtk-builder-tool-simplify.c:666
 #, c-format
 msgid "Property %s not found"
 msgstr "Nie odnaleziono właściwości %s"
 
-#: tools/gtk-builder-tool-simplify.c:661
+#: tools/gtk-builder-tool-simplify.c:669
 #, c-format
 msgid "Packing property %s not found"
 msgstr "Nie odnaleziono właściwości pakującej %s"
 
-#: tools/gtk-builder-tool-simplify.c:664
+#: tools/gtk-builder-tool-simplify.c:672
 #, c-format
 msgid "Cell property %s not found"
 msgstr "Nie odnaleziono właściwości komórki %s"
 
-#: tools/gtk-builder-tool-simplify.c:667
+#: tools/gtk-builder-tool-simplify.c:675
 #, c-format
 msgid "Layout property %s not found"
 msgstr "Nie odnaleziono właściwości układu %s"
 
-#: tools/gtk-builder-tool-simplify.c:1400
+#: tools/gtk-builder-tool-simplify.c:1408
 #, c-format
 msgid "%s only accepts three children"
 msgstr "%s przyjmuje wyłącznie trzy elementy potomne"
 
-#: tools/gtk-builder-tool-simplify.c:1773
+#: tools/gtk-builder-tool-simplify.c:1796
 #, c-format
 msgid "%s only accepts one center child"
 msgstr "%s przyjmuje wyłącznie jeden wyśrodkowany element potomny"
 
-#: tools/gtk-builder-tool-simplify.c:2549
+#: tools/gtk-builder-tool-simplify.c:2606
+#, c-format
+msgid "Unable to create temporary file: %s\n"
+msgstr "Nie można utworzyć pliku tymczasowego: %s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2620
 #, c-format
 msgid "Can’t load “%s”: %s\n"
 msgstr "Nie można wczytać pliku „%s”: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2560
-#: tools/gtk-builder-tool-simplify.c:2566
-#: tools/gtk-builder-tool-simplify.c:2572
+#: tools/gtk-builder-tool-simplify.c:2632
+#: tools/gtk-builder-tool-simplify.c:2642
+#: tools/gtk-builder-tool-simplify.c:2651
 #, c-format
 msgid "Can’t parse “%s”: %s\n"
 msgstr "Nie można przetworzyć pliku „%s”: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2598
+#: tools/gtk-builder-tool-simplify.c:2677
 #, c-format
 msgid "Failed to read “%s”: %s\n"
 msgstr "Otwarcie pliku „%s” się nie powiodło: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2604
+#: tools/gtk-builder-tool-simplify.c:2684
 #, c-format
 msgid "Failed to write “%s”: “%s”\n"
 msgstr "Zapisanie „%s” się nie powiodło: „%s”\n"
 
-#: tools/gtk-builder-tool-simplify.c:2621
+#: tools/gtk-builder-tool-simplify.c:2707
 msgid "Replace the file"
 msgstr "Zastępuje plik"
 
-#: tools/gtk-builder-tool-simplify.c:2622
+#: tools/gtk-builder-tool-simplify.c:2708
 msgid "Convert from GTK 3 to GTK 4"
 msgstr "Konwertuje z biblioteki GTK 3 do GTK 4"
 
-#: tools/gtk-builder-tool-simplify.c:2633
+#: tools/gtk-builder-tool-simplify.c:2719
 msgid "Simplify the file."
 msgstr "Upraszcza plik."
 
-#: tools/gtk-builder-tool-simplify.c:2652
+#: tools/gtk-builder-tool-simplify.c:2739
 #, c-format
 msgid "Can only simplify a single .ui file without --replace\n"
 msgstr "Bez opcji --replace można uprościć tylko jeden plik .ui\n"
@@ -7484,12 +7727,12 @@ msgstr "Wyszukanie typu nadrzędnego szablonu %s się nie powiodło\n"
 msgid "Deprecated types:\n"
 msgstr "Przestarzałe typy:\n"
 
-#: tools/gtk-builder-tool-validate.c:167
+#: tools/gtk-builder-tool-validate.c:170
 #, c-format
 msgid "Failed to create an instance of the template type %s\n"
 msgstr "Utworzenie wystąpienia typu szablonu %s się nie powiodło\n"
 
-#: tools/gtk-builder-tool-validate.c:276
+#: tools/gtk-builder-tool-validate.c:282
 msgid "Validate the file."
 msgstr "Sprawdza poprawność pliku."
 
@@ -7531,7 +7774,7 @@ msgid "Compare two images"
 msgstr "Porównuje dwa obrazy"
 
 #: tools/gtk-image-tool-compare.c:70 tools/gtk-image-tool-convert.c:113
-#: tools/gtk-image-tool-info.c:90 tools/gtk-image-tool-relabel.c:109
+#: tools/gtk-image-tool-info.c:101 tools/gtk-image-tool-relabel.c:109
 #: tools/gtk-image-tool-show.c:141
 #, c-format
 msgid "No image file specified\n"
@@ -7632,19 +7875,24 @@ msgstr "Nie można podać opcji --color-state i --cicp jednocześnie\n"
 msgid "Not a supported cicp tuple: %s\n"
 msgstr "Nie jest obsługiwaną krotką cicp: %s\n"
 
-#: tools/gtk-image-tool-info.c:55
+#: tools/gtk-image-tool-info.c:57
 msgid "Format:"
 msgstr "Format:"
 
-#: tools/gtk-image-tool-info.c:56
+#: tools/gtk-image-tool-info.c:63 tools/gtk-image-tool-info.c:65
+#: tools/gtk-image-tool-info.c:67
 msgid "Color state:"
 msgstr "Stan kolorów:"
 
-#: tools/gtk-image-tool-info.c:77
+#: tools/gtk-image-tool-info.c:67
+msgid "unknown"
+msgstr "nieznany"
+
+#: tools/gtk-image-tool-info.c:88
 msgid "Provide information about the image."
 msgstr "Podaje informacje o obrazie."
 
-#: tools/gtk-image-tool-info.c:96
+#: tools/gtk-image-tool-info.c:107
 #, c-format
 msgid "Can only accept a single image file\n"
 msgstr "Może przyjąć tylko jeden plik obrazu\n"
@@ -7670,7 +7918,7 @@ msgstr "Bez dodawania paska tytułowego"
 msgid "Show one or more images."
 msgstr "Wyświetla jeden lub więcej obrazów."
 
-#: tools/gtk-image-tool-utils.c:234
+#: tools/gtk-image-tool-utils.c:255
 #, c-format
 msgid "cicp must be 4 numbers, separated by /\n"
 msgstr "cicp musi być czterema liczbami rozdzielonymi znakiem /\n"
@@ -8226,105 +8474,105 @@ msgstr "Błąd w %s: %s\n"
 msgid "Failed to load node file: %s\n"
 msgstr "Wczytanie pliku węzła się nie powiodło: %s\n"
 
-#: tools/updateiconcache.c:1391
+#: tools/updateiconcache.c:1402
 #, c-format
 msgid "Failed to write header\n"
 msgstr "Zapisanie nagłówka się nie powiodło\n"
 
-#: tools/updateiconcache.c:1397
+#: tools/updateiconcache.c:1408
 #, c-format
 msgid "Failed to write hash table\n"
 msgstr "Zapisanie tablicy mieszającej się nie powiodło\n"
 
-#: tools/updateiconcache.c:1403
+#: tools/updateiconcache.c:1414
 #, c-format
 msgid "Failed to write folder index\n"
 msgstr "Zapisanie indeksu katalogu się nie powiodło\n"
 
-#: tools/updateiconcache.c:1411
+#: tools/updateiconcache.c:1422
 #, c-format
 msgid "Failed to rewrite header\n"
 msgstr "Przepisanie nagłówka się nie powiodło\n"
 
-#: tools/updateiconcache.c:1505
+#: tools/updateiconcache.c:1516
 #, c-format
 msgid "Failed to open file %s : %s\n"
 msgstr "Otwarcie pliku „%s” się nie powiodło: %s\n"
 
-#: tools/updateiconcache.c:1513 tools/updateiconcache.c:1543
+#: tools/updateiconcache.c:1524 tools/updateiconcache.c:1554
 #, c-format
 msgid "Failed to write cache file: %s\n"
 msgstr "Zapisanie pliku pamięci podręcznej się nie powiodło: %s\n"
 
-#: tools/updateiconcache.c:1553
+#: tools/updateiconcache.c:1564
 #, c-format
 msgid "The generated cache was invalid.\n"
 msgstr "Utworzona pamięć podręczna była nieprawidłowa.\n"
 
-#: tools/updateiconcache.c:1567
+#: tools/updateiconcache.c:1578
 #, c-format
 msgid "Could not rename %s to %s: %s, removing %s then.\n"
 msgstr "Nie można zmienić nazwy %s na %s: %s, usuwanie %s.\n"
 
-#: tools/updateiconcache.c:1581
+#: tools/updateiconcache.c:1592
 #, c-format
 msgid "Could not rename %s to %s: %s\n"
 msgstr "Nie można zmienić nazwy %s na %s: %s\n"
 
-#: tools/updateiconcache.c:1591
+#: tools/updateiconcache.c:1602
 #, c-format
 msgid "Could not rename %s back to %s: %s.\n"
 msgstr "Nie można zmienić nazwy %s z powrotem na %s: %s.\n"
 
-#: tools/updateiconcache.c:1614
+#: tools/updateiconcache.c:1625
 #, c-format
 msgid "Cache file created successfully.\n"
 msgstr "Pomyślnie utworzono plik pamięci podręcznej.\n"
 
-#: tools/updateiconcache.c:1653
+#: tools/updateiconcache.c:1664
 msgid "Overwrite an existing cache, even if up to date"
 msgstr "Zastąpienie istniejącej pamięci podręcznej, nawet gdy jest aktualna"
 
-#: tools/updateiconcache.c:1654
+#: tools/updateiconcache.c:1665
 msgid "Don’t check for the existence of index.theme"
 msgstr "Bez sprawdzania istnienia pliku index.theme"
 
-#: tools/updateiconcache.c:1655
+#: tools/updateiconcache.c:1666
 msgid "Don’t include image data in the cache"
 msgstr "Bez włączania danych obrazów w pamięci podręcznej"
 
-#: tools/updateiconcache.c:1656
+#: tools/updateiconcache.c:1667
 msgid "Include image data in the cache"
 msgstr "Włączenia danych obrazów w pamięci podręcznej"
 
-#: tools/updateiconcache.c:1657
+#: tools/updateiconcache.c:1668
 msgid "Output a C header file"
 msgstr "Wyjście do pliku nagłówkowego C"
 
-#: tools/updateiconcache.c:1658
+#: tools/updateiconcache.c:1669
 msgid "Turn off verbose output"
 msgstr "Wyłączenie rozwlekłego wyjścia"
 
-#: tools/updateiconcache.c:1659
+#: tools/updateiconcache.c:1670
 msgid "Validate existing icon cache"
 msgstr "Sprawdzenie istniejącej pamięci podręcznej ikon"
 
-#: tools/updateiconcache.c:1724
+#: tools/updateiconcache.c:1736
 #, c-format
 msgid "File not found: %s\n"
 msgstr "Nie odnaleziono pliku: %s\n"
 
-#: tools/updateiconcache.c:1730
+#: tools/updateiconcache.c:1742
 #, c-format
 msgid "Not a valid icon cache: %s\n"
 msgstr "Nieprawidłowa pamięć podręczna ikon: %s\n"
 
-#: tools/updateiconcache.c:1743
+#: tools/updateiconcache.c:1755
 #, c-format
 msgid "No theme index file.\n"
 msgstr "Brak pliku indeksu motywu.\n"
 
-#: tools/updateiconcache.c:1747
+#: tools/updateiconcache.c:1759
 #, c-format
 msgid ""
 "No theme index file in “%s”.\n"
diff --git a/po/sl.po b/po/sl.po
index 1283ad9c41774afa0907041def086f9acf58ef0c..783d287a3c181637e724191dca19602117adb44d 100644
--- a/po/sl.po
+++ b/po/sl.po
@@ -11,18 +11,30 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gtk+ master\n"
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
-"POT-Creation-Date: 2025-01-24 21:07+0000\n"
-"PO-Revision-Date: 2025-01-24 22:13+0100\n"
+"POT-Creation-Date: 2025-02-01 15:17+0000\n"
+"PO-Revision-Date: 2025-02-02 10:14+0100\n"
 "Last-Translator: Martin Srebotnjak <miles@filmsi.net>\n"
 "Language-Team: Slovenian GNOME Translation Team <gnome-si@googlegroups.com>\n"
 "Language: sl_SI\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
-"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || "
-"n%100==4 ? 3 : 0);\n"
+"Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || n"
+"%100==4 ? 3 : 0);\n"
 "X-Poedit-SourceCharset: utf-8\n"
-"X-Generator: Poedit 3.4.2\n"
+"X-Generator: Poedit 2.2.1\n"
+
+#: gdk/android/gdkandroidclipboard.c:174
+msgid "No compatible formats to transfer contents of content provider."
+msgstr "Ni združljivih zapisov za prenos vsebine ponudnika vsebine."
+
+#: gdk/android/gdkandroidclipboard.c:623 gdk/macos/gdkmacospasteboard.c:161
+#: gdk/wayland/gdkclipboard-wayland.c:244 gdk/wayland/gdkdrop-wayland.c:205
+#: gdk/wayland/gdkprimary-wayland.c:343 gdk/win32/gdkdrop-win32.c:1014
+#: gdk/win32/gdkdrop-win32.c:1063 gdk/x11/gdkclipboard-x11.c:801
+#: gdk/x11/gdkdrop-x11.c:237
+msgid "No compatible transfer format found"
+msgstr "Ni najdenega skladnega zapisa za prenos."
 
 #: gdk/broadway/gdkbroadway-server.c:135
 #, c-format
@@ -138,13 +150,13 @@ msgstr "Funkcija Poteg/Spust iz drugih programov ni podprta."
 msgid "No compatible formats to transfer contents."
 msgstr "Ni skladnih zapisov za prenos vsebine."
 
-#: gdk/gdkglcontext.c:427 gdk/x11/gdkglcontext-glx.c:651
+#: gdk/gdkglcontext.c:427 gdk/x11/gdkglcontext-glx.c:653
 msgid "No GL API allowed."
 msgstr "API GL ni dovoljen."
 
 #: gdk/gdkglcontext.c:450 gdk/win32/gdkglcontext-win32-wgl.c:746
 #: gdk/win32/gdkglcontext-win32-wgl.c:889
-#: gdk/win32/gdkglcontext-win32-wgl.c:933 gdk/x11/gdkglcontext-glx.c:697
+#: gdk/win32/gdkglcontext-win32-wgl.c:933 gdk/x11/gdkglcontext-glx.c:699
 msgid "Unable to create a GL context"
 msgstr "Ni mogoče ustvariti vsebine GL"
 
@@ -565,7 +577,7 @@ msgstr "Napaka med tolmačenjem slikovne datoteke JPEG (%s)"
 msgid "Unsupported JPEG colorspace (%d)"
 msgstr "Nepodprt barvni prostor JPEG (%d) "
 
-#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:435 gdk/loaders/gdktiff.c:472
+#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:468 gdk/loaders/gdktiff.c:472
 #, c-format
 msgid "Not enough memory for image size %ux%u"
 msgstr "Ni dovolj pomnilnika za sliko velikosti %ux%u"
@@ -575,17 +587,17 @@ msgstr "Ni dovolj pomnilnika za sliko velikosti %ux%u"
 msgid "Error reading png (%s)"
 msgstr "Napaka branja zapisa png (%s)"
 
-#: gdk/loaders/gdkpng.c:356
+#: gdk/loaders/gdkpng.c:389
 #, c-format
 msgid "Unsupported depth %u in png image"
 msgstr "Slika PNG ima nepodprto barvno globino %u"
 
-#: gdk/loaders/gdkpng.c:406
+#: gdk/loaders/gdkpng.c:439
 #, c-format
 msgid "Unsupported color type %u in png image"
 msgstr "Nepodprta barvna globina %u v sliki PNG"
 
-#: gdk/loaders/gdkpng.c:420
+#: gdk/loaders/gdkpng.c:453
 #, c-format
 msgid "Image stride too large for image size %ux%u"
 msgstr "Korak slike je prevelik za velikost slike %ux%u"
@@ -603,13 +615,6 @@ msgstr "Ni mogoče naložiti podatkov slike TIFF"
 msgid "Reading data failed at row %d"
 msgstr "Ni mogoče pridobiti podatkov v vrstici %d"
 
-#: gdk/macos/gdkmacospasteboard.c:161 gdk/wayland/gdkclipboard-wayland.c:244
-#: gdk/wayland/gdkdrop-wayland.c:205 gdk/wayland/gdkprimary-wayland.c:343
-#: gdk/win32/gdkdrop-win32.c:1014 gdk/win32/gdkdrop-win32.c:1063
-#: gdk/x11/gdkclipboard-x11.c:799 gdk/x11/gdkdrop-x11.c:235
-msgid "No compatible transfer format found"
-msgstr "Ni najdenega skladnega zapisa za prenos."
-
 #: gdk/macos/gdkmacospasteboard.c:255
 #, c-format
 msgid "Failed to decode contents with mime-type of '%s'"
@@ -660,8 +665,8 @@ msgstr ""
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr ""
-"Ni mogoče določiti podatkov odložišča. Ukaz OpenClipboard() je spodletel: "
-"0x%lx."
+"Ni mogoče določiti podatkov odložišča. Ukaz OpenClipboard() je spodletel: 0x"
+"%lx."
 
 #: gdk/win32/gdkclipdrop-win32.c:836
 #, c-format
@@ -711,8 +716,8 @@ msgstr ""
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr ""
-"Ni mogoče pridobiti podatkov odložišča. Ukaz OpenClipboard() je spodletel: "
-"0x%lx."
+"Ni mogoče pridobiti podatkov odložišča. Ukaz OpenClipboard() je spodletel: 0x"
+"%lx."
 
 #: gdk/win32/gdkclipdrop-win32.c:953
 #, c-format
@@ -820,17 +825,17 @@ msgstr "Izvedba GlobalLock() je spodletela: "
 msgid "GlobalAlloc() failed: "
 msgstr "Izvedba GlobalAlloc() je spodletela: "
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:297
+#: gdk/x11/gdkapplaunchcontext-x11.c:299
 #, c-format
 msgid "Starting “%s”"
 msgstr "Poteka zaganjanje »%s«"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:310
+#: gdk/x11/gdkapplaunchcontext-x11.c:312
 #, c-format
 msgid "Opening “%s”"
 msgstr "Poteka odpiranj »%s«"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:315
+#: gdk/x11/gdkapplaunchcontext-x11.c:317
 #, c-format
 msgid "Opening %d Item"
 msgid_plural "Opening %d Items"
@@ -839,49 +844,49 @@ msgstr[1] "Odpiranje %d predmeta"
 msgstr[2] "Odpiranje %d predmetov"
 msgstr[3] "Odpiranje %d predmetov"
 
-#: gdk/x11/gdkclipboard-x11.c:473
+#: gdk/x11/gdkclipboard-x11.c:475
 msgid "Clipboard manager could not store selection."
 msgstr "Upravljalnik odložišča ne uspe shraniti izbire."
 
-#: gdk/x11/gdkclipboard-x11.c:649
+#: gdk/x11/gdkclipboard-x11.c:651
 msgid "Cannot store clipboard. No clipboard manager is active."
 msgstr "Ni mogoče shraniti odložišča. Ni dejavnega upravljalnika."
 
-#: gdk/x11/gdkglcontext-glx.c:817
+#: gdk/x11/gdkglcontext-glx.c:819
 msgid "No GLX configurations available"
 msgstr "Nastavitve GLX niso na voljo"
 
-#: gdk/x11/gdkglcontext-glx.c:904
+#: gdk/x11/gdkglcontext-glx.c:906
 msgid "No GLX configuration with required features found"
 msgstr "Ni mogoče najti nastavitev GLX za zahtevane možnosti"
 
-#: gdk/x11/gdkglcontext-glx.c:978
+#: gdk/x11/gdkglcontext-glx.c:982
 msgid "GLX is not supported"
 msgstr "Podpora GLX ni na voljo"
 
-#: gdk/x11/gdkselectioninputstream-x11.c:465
+#: gdk/x11/gdkselectioninputstream-x11.c:467
 #, c-format
 msgid "Format %s not supported"
 msgstr "Zapis %s ni podprt."
 
-#: gdk/x11/gdktextlistconverter-x11.c:65 gdk/x11/gdktextlistconverter-x11.c:105
+#: gdk/x11/gdktextlistconverter-x11.c:67 gdk/x11/gdktextlistconverter-x11.c:107
 msgid "Not enough space in destination"
 msgstr "Na ciljnem mestu ni dovolj prostora"
 
-#: gdk/x11/gdktextlistconverter-x11.c:91 gdk/x11/gdktextlistconverter-x11.c:195
+#: gdk/x11/gdktextlistconverter-x11.c:93 gdk/x11/gdktextlistconverter-x11.c:197
 msgid "Need complete input to do conversion"
 msgstr "Zahtevan je celoten vhod za izvedbo pretvarjanja"
 
-#: gdk/x11/gdktextlistconverter-x11.c:216
-#: gdk/x11/gdktextlistconverter-x11.c:250
+#: gdk/x11/gdktextlistconverter-x11.c:218
+#: gdk/x11/gdktextlistconverter-x11.c:252
 msgid "Invalid byte sequence in conversion input"
 msgstr "Neveljavno zaporedje bajtov na vhodu pretvorbe"
 
-#: gdk/x11/gdktextlistconverter-x11.c:242
+#: gdk/x11/gdktextlistconverter-x11.c:244
 msgid "Invalid formats in compound text conversion."
 msgstr "Neveljavni zapisi pri sestavljeni pretvorbi besedila."
 
-#: gdk/x11/gdktextlistconverter-x11.c:259
+#: gdk/x11/gdktextlistconverter-x11.c:261
 #, c-format
 msgid "Unsupported encoding “%s”"
 msgstr "Nepodprto kodiranje »%s«."
@@ -1175,7 +1180,7 @@ msgstr ""
 "Sistemska pravila prepovedujejo spremembe.\n"
 "Stopite v stik s skrbnikom sistema."
 
-#: gtk/deprecated/gtkshow.c:217
+#: gtk/deprecated/gtkshow.c:291
 msgid "Could not show link"
 msgstr "Povezave ni mogoče pokazati"
 
@@ -2303,25 +2308,25 @@ msgstr "Mapa z enakim imenom že obstaja."
 msgid "A file with that name already exists"
 msgstr "Datoteka s tem imenom že obstaja."
 
-#: gtk/gtkfilechoosernative.c:520 gtk/gtkfilechoosernative.c:593
+#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594
 #: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:4988
 #: gtk/gtkfiledialog.c:911 gtk/gtkmessagedialog.c:170
 #: gtk/gtkmessagedialog.c:179 gtk/gtkmountoperation.c:608
 #: gtk/print/gtkpagesetupunixdialog.c:282 gtk/print/gtkprintbackend.c:638
 #: gtk/print/gtkprintunixdialog.c:680 gtk/print/gtkprintunixdialog.c:837
-#: gtk/gtkwindow.c:6301 gtk/ui/gtkappchooserdialog.ui:48
+#: gtk/gtkwindow.c:6321 gtk/ui/gtkappchooserdialog.ui:48
 #: gtk/ui/gtkassistant.ui:52 gtk/ui/gtkcolorchooserdialog.ui:36
 #: gtk/ui/gtkfontchooserdialog.ui:29
 msgid "_Cancel"
 msgstr "_Prekliči"
 
-#: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:587
+#: gtk/gtkfilechoosernative.c:522 gtk/gtkfilechoosernative.c:588
 #: gtk/gtkfiledialog.c:883 gtk/gtkplacessidebar.c:3149
 #: gtk/gtkplacessidebar.c:3234 gtk/gtkplacesview.c:1646
 msgid "_Open"
 msgstr "_Odpri"
 
-#: gtk/gtkfilechoosernative.c:587 gtk/gtkfiledialog.c:888
+#: gtk/gtkfilechoosernative.c:588 gtk/gtkfiledialog.c:888
 msgid "_Save"
 msgstr "_Shrani"
 
@@ -2532,7 +2537,7 @@ msgstr "Program"
 msgid "Audio"
 msgstr "Zvok"
 
-#: gtk/gtkfilechooserwidget.c:3819 gtk/gtkfilefilter.c:1022
+#: gtk/gtkfilechooserwidget.c:3819 gtk/gtkfilefilter.c:1069
 msgid "Image"
 msgstr "Slika"
 
@@ -2661,7 +2666,7 @@ msgstr "Kodiranje znakov"
 msgid "Line Ending"
 msgstr "Konec vrstice"
 
-#: gtk/gtkfilefilter.c:1035
+#: gtk/gtkfilefilter.c:1082
 msgid "Unspecified"
 msgstr "Nedoločeno"
 
@@ -2848,7 +2853,7 @@ msgid "Play"
 msgstr "Predvajaj"
 
 #: gtk/gtkmessagedialog.c:162 gtk/gtkmessagedialog.c:180
-#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6302
+#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6322
 msgid "_OK"
 msgstr "_V redu"
 
@@ -2941,27 +2946,27 @@ msgid "Cannot kill process with PID %d. Operation is not implemented."
 msgstr "Opravila s PID %d ni mogoče uničiti. Dejanje ni podprto."
 
 #. translators: this string is a name for the 'less' command
-#: gtk/gtkmountoperation-x11.c:986
+#: gtk/gtkmountoperation-x11.c:988
 msgid "Terminal Pager"
 msgstr "Pozivnik terminala"
 
-#: gtk/gtkmountoperation-x11.c:987
+#: gtk/gtkmountoperation-x11.c:989
 msgid "Top Command"
 msgstr "Vrhnji ukaz"
 
-#: gtk/gtkmountoperation-x11.c:988
+#: gtk/gtkmountoperation-x11.c:990
 msgid "Bourne Again Shell"
 msgstr "Lupina Bourne Again"
 
-#: gtk/gtkmountoperation-x11.c:989
+#: gtk/gtkmountoperation-x11.c:991
 msgid "Bourne Shell"
 msgstr "Lupina Bourne"
 
-#: gtk/gtkmountoperation-x11.c:990
+#: gtk/gtkmountoperation-x11.c:992
 msgid "Z Shell"
 msgstr "Lupina Z"
 
-#: gtk/gtkmountoperation-x11.c:1090
+#: gtk/gtkmountoperation-x11.c:1092
 #, c-format
 msgid "Cannot end process with PID %d: %s"
 msgstr "Opravila s PID %d ni mogoče končati: %s"
@@ -3897,12 +3902,12 @@ msgstr "_Razveljavi"
 msgid "_Redo"
 msgstr "_Ponovno uveljavi"
 
-#: gtk/gtkwindow.c:6290
+#: gtk/gtkwindow.c:6310
 #, c-format
 msgid "Do you want to use GTK Inspector?"
 msgstr "Ali želite uporabljati nadzorni program GTK+?"
 
-#: gtk/gtkwindow.c:6292
+#: gtk/gtkwindow.c:6312
 #, c-format
 msgid ""
 "GTK Inspector is an interactive debugger that lets you explore and modify "
@@ -3913,7 +3918,7 @@ msgstr ""
 "nastavitev kateregakoli programa GTK. Neustrezna raba lahko povzroči napačno "
 "delovanje oziroma sesutje okolja."
 
-#: gtk/gtkwindow.c:6297
+#: gtk/gtkwindow.c:6317
 msgid "Don’t show this message again"
 msgstr "Sporočila ne pokaži več"
 
@@ -4098,17 +4103,17 @@ msgstr "Lastnosti CSS"
 msgid "IM Context is hardcoded by GTK_IM_MODULE"
 msgstr "Vsebina IM je določena z vrednostjo GTK_IM_MODULE"
 
-#: gtk/inspector/general.c:575
+#: gtk/inspector/general.c:577
 msgctxt "GL renderer"
 msgid "None"
 msgstr "Brez"
 
-#: gtk/inspector/general.c:664
+#: gtk/inspector/general.c:674
 msgctxt "GL version"
 msgid "Unknown"
 msgstr "Neznano"
 
-#: gtk/inspector/general.c:910 gtk/inspector/general.c:949
+#: gtk/inspector/general.c:928 gtk/inspector/general.c:967
 msgctxt "Vulkan device"
 msgid "None"
 msgstr "Neopredeljeno"
diff --git a/po/zh_TW.po b/po/zh_TW.po
index 5f0fd1521d0842b4819cd84b6bef36fc84558ecd..c7c8db3acb26e9d94f2258d4e92100151b88e5ca 100644
--- a/po/zh_TW.po
+++ b/po/zh_TW.po
@@ -10,16 +10,17 @@ msgid ""
 msgstr ""
 "Project-Id-Version: gtk+ 4.6\n"
 "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/gtk/-/issues/\n"
-"POT-Creation-Date: 2023-02-04 15:56+0000\n"
-"PO-Revision-Date: 2023-02-05 00:24+0800\n"
-"Last-Translator: Cheng-Chia Tseng <pswo10680@gmail.com>\n"
-"Language-Team: Chinese - Taiwan <chinese-l10n@googlegroups.com>\n"
+"POT-Creation-Date: 2025-01-13 00:43+0000\n"
+"PO-Revision-Date: 2025-02-03 14:20+0000\n"
+"Last-Translator: Chao-Hsiung Liao <pesder@mail.edu.tw>\n"
+"Language-Team: Chinese (Traditional Han script) <http://"
+"darkbear.mercusysddns.com/projects/gnome-47/gtk-po-ui-gtk-4-16/zh_Hant/>\n"
 "Language: zh_TW\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=0;\n"
-"X-Generator: Poedit 3.2.2\n"
+"X-Generator: Weblate 5.9.2\n"
 "X-Project-Style: gnome\n"
 
 #: gdk/broadway/gdkbroadway-server.c:135
@@ -31,14 +32,34 @@ msgstr "Broadway 顯示類型不支援:%s"
 msgid "This clipboard cannot store data."
 msgstr "剪貼簿無法儲存資料。"
 
-#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:785 gdk/gdkclipboard.c:1085
+#: gdk/gdkclipboard.c:287 gdk/gdkclipboard.c:781 gdk/gdkclipboard.c:1072
 msgid "Cannot read from empty clipboard."
 msgstr "無法從空白剪貼簿讀取。"
 
-#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1135 gdk/gdkdrag.c:618
+#: gdk/gdkclipboard.c:318 gdk/gdkclipboard.c:1122 gdk/gdkdrag.c:606
 msgid "No compatible formats to transfer clipboard contents."
 msgstr "沒有可傳輸剪貼簿內容的相容格式。"
 
+#: gdk/gdkcolorstate.c:668
+#, c-format
+msgid "cicp: Narrow range or YUV not supported"
+msgstr "cicp:不支援 窄範圍或 YUV"
+
+#: gdk/gdkcolorstate.c:678
+#, c-format
+msgid "cicp: Unspecified parameters not supported"
+msgstr "cicp:不支援未指定的參數"
+
+#: gdk/gdkcolorstate.c:724
+#, c-format
+msgid "cicp: Transfer function %u not supported"
+msgstr "cicp:不支援傳遞函數 %u"
+
+#: gdk/gdkcolorstate.c:754
+#, c-format
+msgid "cicp: Color primaries %u not supported"
+msgstr "cicp:不支援原色 %u"
+
 #: gdk/gdkcontentprovider.c:106 gdk/gdkcontentproviderimpl.c:313
 #: gdk/gdkcontentproviderimpl.c:532
 #, c-format
@@ -50,53 +71,57 @@ msgstr "無法提供「%s」類的內容"
 msgid "Cannot provide contents as %s"
 msgstr "無法提供 %s 類的內容"
 
-#: gdk/gdkdisplay.c:154 gdk/gdkglcontext.c:435
+#: gdk/gdkdisplay.c:176 gdk/gdkglcontext.c:470
 msgid "The current backend does not support OpenGL"
 msgstr "目前的後端不支援 OpenGL"
 
-#: gdk/gdkdisplay.c:1244
-msgid "GL support disabled via GDK_DEBUG"
-msgstr "GL 支援已透過 GDK_DEBUG 停用"
+#: gdk/gdkdisplay.c:1317 gdk/gdkvulkancontext.c:1754
+msgid "Vulkan support disabled via GDK_DISABLE"
+msgstr "Vulkan 支援已透過 GDK_DISABLE 停用"
 
-#: gdk/gdkdisplay.c:1542
+#: gdk/gdkdisplay.c:1371
+msgid "OpenGL support disabled via GDK_DISABLE"
+msgstr "OpenGL 支援已透過 GDK_DISABLE 停用"
+
+#: gdk/gdkdisplay.c:1685
 msgid "No EGL configuration available"
 msgstr "沒有 EGL 組態可用"
 
-#: gdk/gdkdisplay.c:1550
+#: gdk/gdkdisplay.c:1693
 msgid "Failed to get EGL configurations"
 msgstr "無法取得 EGL 組態"
 
-#: gdk/gdkdisplay.c:1580
+#: gdk/gdkdisplay.c:1723
 msgid "No EGL configuration with required features found"
 msgstr "找不到需要功能的 EGL 組態"
 
-#: gdk/gdkdisplay.c:1587
+#: gdk/gdkdisplay.c:1730
 msgid "No perfect EGL configuration found"
 msgstr "找不到完好的 EGL 組態"
 
-#: gdk/gdkdisplay.c:1629
+#: gdk/gdkdisplay.c:1772
 #, c-format
 msgid "EGL implementation is missing extension %s"
 msgid_plural "EGL implementation is missing %2$d extensions: %1$s"
 msgstr[0] "EGL 實作遺失 %2$d 項擴充功能:%1$s"
 
-#: gdk/gdkdisplay.c:1662
+#: gdk/gdkdisplay.c:1821
 msgid "libEGL not available in this sandbox"
 msgstr "此沙盒中無法使用 libEGL"
 
-#: gdk/gdkdisplay.c:1663
+#: gdk/gdkdisplay.c:1822
 msgid "libEGL not available"
 msgstr "無法使用 libEGL"
 
-#: gdk/gdkdisplay.c:1673
+#: gdk/gdkdisplay.c:1832
 msgid "Failed to create EGL display"
 msgstr "無法建立 EGL 顯示"
 
-#: gdk/gdkdisplay.c:1683
+#: gdk/gdkdisplay.c:1841
 msgid "Could not initialize EGL display"
 msgstr "無法初始化 EGL 顯示"
 
-#: gdk/gdkdisplay.c:1694
+#: gdk/gdkdisplay.c:1851
 #, c-format
 msgid "EGL version %d.%d is too old. GTK requires %d.%d"
 msgstr "EGL 版本 %d.%d 過舊。GTK 需要 %d.%d"
@@ -109,500 +134,475 @@ msgstr "不支援從其他應用程式拖放內容。"
 msgid "No compatible formats to transfer contents."
 msgstr "沒有可傳輸內容的相容格式。"
 
-#: gdk/gdkglcontext.c:394 gdk/x11/gdkglcontext-glx.c:618
+#: gdk/gdkglcontext.c:430 gdk/x11/gdkglcontext-glx.c:651
 msgid "No GL API allowed."
 msgstr "沒有允許的 GL API。"
 
-#: gdk/gdkglcontext.c:418 gdk/win32/gdkglcontext-win32-wgl.c:611
-#: gdk/x11/gdkglcontext-glx.c:652
+#: gdk/gdkglcontext.c:453 gdk/win32/gdkglcontext-win32-wgl.c:762
+#: gdk/win32/gdkglcontext-win32-wgl.c:905
+#: gdk/win32/gdkglcontext-win32-wgl.c:949 gdk/x11/gdkglcontext-glx.c:697
 msgid "Unable to create a GL context"
 msgstr "無法建立 GL 脈絡"
 
-#: gdk/gdkglcontext.c:1286
-msgid "Anything but OpenGL ES disabled via GDK_DEBUG"
-msgstr "OpenGL ES 以外的其他項目已透過 GDK_DEBUG 停用"
+#: gdk/gdkglcontext.c:1338
+msgid "OpenGL ES API disabled via GDK_DISABLE"
+msgstr "OpenGL ES API 已透過 GDK_DISABLE 停用"
+
+#: gdk/gdkglcontext.c:1350
+msgid "OpenGL API disabled via GDK_DISABLE"
+msgstr "通過 GDK_DISABLE 停用 OpenGL API"
 
-#: gdk/gdkglcontext.c:1295
+#: gdk/gdkglcontext.c:1361
 #, c-format
 msgid "Application does not support %s API"
 msgstr "應用程式不支援 %s API"
 
 #. translators: This is about OpenGL backend names, like
 #. * "Trying to use X11 GLX, but EGL is already in use"
-#: gdk/gdkglcontext.c:1841
+#.
+#: gdk/gdkglcontext.c:2171
 #, c-format
 msgid "Trying to use %s, but %s is already in use"
 msgstr "嘗試使用 %s,但是 %s 已經正在使用"
 
-#: gdk/gdksurface.c:1226
-msgid "Vulkan support disabled via GDK_DEBUG"
-msgstr "Vulkan 支援已透過 GDK_DEBUG 停用"
+#: gdk/gdkglcontext.c:2182
+#, c-format
+msgid "Trying to use %s, but it is disabled via GDK_DISABLE"
+msgstr "嘗試使用 %s,但是它已透過 GDK_DISABLE 停用"
 
-#: gdk/gdktexture.c:525
+#: gdk/gdktexture.c:672
 msgid "Unknown image format."
 msgstr "未知影像格式。"
 
 #.
-#. * Translators, the strings in the “keyboard label” context are
+#. * Translators, the strings in the 'keyboard label' context are
 #. * display names for keyboard keys. Some of them have prefixes like
-#. * XF86 or ISO_ — these should be removed in the translation. Similarly,
-#. * underscores should be replaced by spaces. The prefix “KP_” stands
-#. * for “key pad” and you may want to include that in your translation.
+#. * XF86 or ISO_ - these should be removed in the translation. Similarly,
+#. * underscores should be replaced by spaces. The prefix 'KP_' stands
+#. * for 'key pad' and you may want to include that in your translation.
 #. * Here are some examples of English translations:
 #. * XF86AudioMute - Audio mute
 #. * Scroll_lock   - Scroll lock
 #. * KP_Space      - Space (keypad)
 #.
-#: gdk/keynamesprivate.h:6843
+#: gdk/keynamesprivate.h:6861
 msgctxt "keyboard label"
 msgid "BackSpace"
 msgstr "BackSpace"
 
-#: gdk/keynamesprivate.h:6844
+#: gdk/keynamesprivate.h:6862
 msgctxt "keyboard label"
 msgid "Tab"
 msgstr "Tab"
 
-#: gdk/keynamesprivate.h:6845
+#: gdk/keynamesprivate.h:6863
 msgctxt "keyboard label"
 msgid "Return"
 msgstr "Enter"
 
-#: gdk/keynamesprivate.h:6846
+#: gdk/keynamesprivate.h:6864
 msgctxt "keyboard label"
 msgid "Pause"
 msgstr "Pause"
 
-#: gdk/keynamesprivate.h:6847
+#: gdk/keynamesprivate.h:6865
 msgctxt "keyboard label"
 msgid "Scroll_Lock"
 msgstr "Scroll Lock"
 
-#: gdk/keynamesprivate.h:6848
+#: gdk/keynamesprivate.h:6866
 msgctxt "keyboard label"
 msgid "Sys_Req"
 msgstr "Sys Req"
 
-#: gdk/keynamesprivate.h:6849
+#: gdk/keynamesprivate.h:6867
 msgctxt "keyboard label"
 msgid "Escape"
 msgstr "Escape"
 
-#: gdk/keynamesprivate.h:6850
+#: gdk/keynamesprivate.h:6868
 msgctxt "keyboard label"
 msgid "Multi_key"
 msgstr "Multi_key"
 
-#: gdk/keynamesprivate.h:6851
+#: gdk/keynamesprivate.h:6869
 msgctxt "keyboard label"
 msgid "Home"
 msgstr "Home"
 
-#: gdk/keynamesprivate.h:6852
+#: gdk/keynamesprivate.h:6870
 msgctxt "keyboard label"
 msgid "Left"
 msgstr "方向鍵左"
 
-#: gdk/keynamesprivate.h:6853
+#: gdk/keynamesprivate.h:6871
 msgctxt "keyboard label"
 msgid "Up"
 msgstr "方向鍵上"
 
-#: gdk/keynamesprivate.h:6854
+#: gdk/keynamesprivate.h:6872
 msgctxt "keyboard label"
 msgid "Right"
 msgstr "方向鍵右"
 
-#: gdk/keynamesprivate.h:6855
+#: gdk/keynamesprivate.h:6873
 msgctxt "keyboard label"
 msgid "Down"
 msgstr "方向鍵下"
 
-#: gdk/keynamesprivate.h:6856 gtk/gtkshortcutlabel.c:217
+#: gdk/keynamesprivate.h:6874 gtk/gtkshortcutlabel.c:217
 msgctxt "keyboard label"
 msgid "Page_Up"
 msgstr "Page Up"
 
-#: gdk/keynamesprivate.h:6857 gtk/gtkshortcutlabel.c:220
+#: gdk/keynamesprivate.h:6875 gtk/gtkshortcutlabel.c:220
 msgctxt "keyboard label"
 msgid "Page_Down"
 msgstr "Page Down"
 
-#: gdk/keynamesprivate.h:6858
+#: gdk/keynamesprivate.h:6876
 msgctxt "keyboard label"
 msgid "End"
 msgstr "End"
 
-#: gdk/keynamesprivate.h:6859
+#: gdk/keynamesprivate.h:6877
 msgctxt "keyboard label"
 msgid "Begin"
 msgstr "Begin"
 
-#: gdk/keynamesprivate.h:6860
+#: gdk/keynamesprivate.h:6878
 msgctxt "keyboard label"
 msgid "Print"
 msgstr "Print"
 
-#: gdk/keynamesprivate.h:6861
+#: gdk/keynamesprivate.h:6879
 msgctxt "keyboard label"
 msgid "Insert"
 msgstr "Insert"
 
-#: gdk/keynamesprivate.h:6862
+#: gdk/keynamesprivate.h:6880
 msgctxt "keyboard label"
 msgid "Num_Lock"
 msgstr "Num Lock"
 
-#. Translators: KP_ means “key pad” here
-#: gdk/keynamesprivate.h:6864
-#, fuzzy
+#. Translators: KP_ means 'key pad' here
+#: gdk/keynamesprivate.h:6882
 msgctxt "keyboard label"
 msgid "KP_Space"
 msgstr "KP_Space"
 
-#: gdk/keynamesprivate.h:6865
-#, fuzzy
+#: gdk/keynamesprivate.h:6883
 msgctxt "keyboard label"
 msgid "KP_Tab"
 msgstr "KP_Tab"
 
-#: gdk/keynamesprivate.h:6866
-#, fuzzy
+#: gdk/keynamesprivate.h:6884
 msgctxt "keyboard label"
 msgid "KP_Enter"
 msgstr "KP_Enter"
 
-#: gdk/keynamesprivate.h:6867
-#, fuzzy
+#: gdk/keynamesprivate.h:6885
 msgctxt "keyboard label"
 msgid "KP_Home"
 msgstr "KP_Home"
 
-#: gdk/keynamesprivate.h:6868
+#: gdk/keynamesprivate.h:6886
 msgctxt "keyboard label"
 msgid "KP_Left"
 msgstr "方向鍵左(KP)"
 
-#: gdk/keynamesprivate.h:6869
+#: gdk/keynamesprivate.h:6887
 msgctxt "keyboard label"
 msgid "KP_Up"
 msgstr "方向鍵上(KP)"
 
-#: gdk/keynamesprivate.h:6870
+#: gdk/keynamesprivate.h:6888
 msgctxt "keyboard label"
 msgid "KP_Right"
 msgstr "方向鍵右(KP)"
 
-#: gdk/keynamesprivate.h:6871
+#: gdk/keynamesprivate.h:6889
 msgctxt "keyboard label"
 msgid "KP_Down"
 msgstr "方向鍵下(KP)"
 
-#: gdk/keynamesprivate.h:6872
-#, fuzzy
+#: gdk/keynamesprivate.h:6890
 msgctxt "keyboard label"
 msgid "KP_Page_Up"
 msgstr "KP_Page_Up"
 
-#: gdk/keynamesprivate.h:6873
-#, fuzzy
+#: gdk/keynamesprivate.h:6891
 msgctxt "keyboard label"
 msgid "KP_Prior"
 msgstr "KP_Prior"
 
-#: gdk/keynamesprivate.h:6874
-#, fuzzy
+#: gdk/keynamesprivate.h:6892
 msgctxt "keyboard label"
 msgid "KP_Page_Down"
 msgstr "KP_Page_Down"
 
-#: gdk/keynamesprivate.h:6875
-#, fuzzy
+#: gdk/keynamesprivate.h:6893
 msgctxt "keyboard label"
 msgid "KP_Next"
 msgstr "KP_Next"
 
-#: gdk/keynamesprivate.h:6876
-#, fuzzy
+#: gdk/keynamesprivate.h:6894
 msgctxt "keyboard label"
 msgid "KP_End"
 msgstr "KP_End"
 
-#: gdk/keynamesprivate.h:6877
-#, fuzzy
+#: gdk/keynamesprivate.h:6895
 msgctxt "keyboard label"
 msgid "KP_Begin"
 msgstr "KP_Begin"
 
-#: gdk/keynamesprivate.h:6878
-#, fuzzy
+#: gdk/keynamesprivate.h:6896
 msgctxt "keyboard label"
 msgid "KP_Insert"
 msgstr "KP_Insert"
 
-#: gdk/keynamesprivate.h:6879
-#, fuzzy
+#: gdk/keynamesprivate.h:6897
 msgctxt "keyboard label"
 msgid "KP_Delete"
 msgstr "KP_Delete"
 
-#: gdk/keynamesprivate.h:6880
+#: gdk/keynamesprivate.h:6898
 msgctxt "keyboard label"
 msgid "Delete"
 msgstr "Delete"
 
-#: gdk/keynamesprivate.h:6881
-#, fuzzy
+#: gdk/keynamesprivate.h:6899
 msgctxt "keyboard label"
 msgid "MonBrightnessUp"
 msgstr "螢幕亮度增加"
 
-#: gdk/keynamesprivate.h:6882
-#, fuzzy
+#: gdk/keynamesprivate.h:6900
 msgctxt "keyboard label"
 msgid "MonBrightnessDown"
 msgstr "螢幕亮度降低"
 
-#: gdk/keynamesprivate.h:6883
-#, fuzzy
+#: gdk/keynamesprivate.h:6901
 msgctxt "keyboard label"
 msgid "KbdBrightnessUp"
 msgstr "鍵盤亮度增加"
 
-#: gdk/keynamesprivate.h:6884
-#, fuzzy
+#: gdk/keynamesprivate.h:6902
 msgctxt "keyboard label"
 msgid "KbdBrightnessDown"
 msgstr "鍵盤亮度降低"
 
-#: gdk/keynamesprivate.h:6885
-#, fuzzy
+#: gdk/keynamesprivate.h:6903
 msgctxt "keyboard label"
 msgid "AudioMute"
 msgstr "音量靜音"
 
-#: gdk/keynamesprivate.h:6886
-#, fuzzy
+#: gdk/keynamesprivate.h:6904
 msgctxt "keyboard label"
 msgid "AudioMicMute"
 msgstr "音量麥克風靜音"
 
-#: gdk/keynamesprivate.h:6887
+#: gdk/keynamesprivate.h:6905
 msgctxt "keyboard label"
 msgid "AudioLowerVolume"
 msgstr "音量減鍵"
 
-#: gdk/keynamesprivate.h:6888
+#: gdk/keynamesprivate.h:6906
 msgctxt "keyboard label"
 msgid "AudioRaiseVolume"
 msgstr "音量增鍵"
 
-#: gdk/keynamesprivate.h:6889
-#, fuzzy
+#: gdk/keynamesprivate.h:6907
 msgctxt "keyboard label"
 msgid "AudioPlay"
 msgstr "音效播放"
 
-#: gdk/keynamesprivate.h:6890
-#, fuzzy
+#: gdk/keynamesprivate.h:6908
 msgctxt "keyboard label"
 msgid "AudioStop"
 msgstr "音效停止"
 
-#: gdk/keynamesprivate.h:6891
-#, fuzzy
+#: gdk/keynamesprivate.h:6909
 msgctxt "keyboard label"
 msgid "AudioNext"
-msgstr "音效下一首"
+msgstr "音樂下一首"
 
-#: gdk/keynamesprivate.h:6892
-#, fuzzy
+#: gdk/keynamesprivate.h:6910
 msgctxt "keyboard label"
 msgid "AudioPrev"
-msgstr "音效上一首"
+msgstr "音樂上一首"
 
-#: gdk/keynamesprivate.h:6893
-#, fuzzy
+#: gdk/keynamesprivate.h:6911
 msgctxt "keyboard label"
 msgid "AudioRecord"
 msgstr "音效錄製"
 
-#: gdk/keynamesprivate.h:6894
-#, fuzzy
+#: gdk/keynamesprivate.h:6912
 msgctxt "keyboard label"
 msgid "AudioPause"
 msgstr "音效暫停"
 
-#: gdk/keynamesprivate.h:6895
-#, fuzzy
+#: gdk/keynamesprivate.h:6913
 msgctxt "keyboard label"
 msgid "AudioRewind"
 msgstr "音效倒轉"
 
-#: gdk/keynamesprivate.h:6896
-#, fuzzy
+#: gdk/keynamesprivate.h:6914
 msgctxt "keyboard label"
 msgid "AudioMedia"
 msgstr "音效媒體"
 
-#: gdk/keynamesprivate.h:6897
+#: gdk/keynamesprivate.h:6915
 msgctxt "keyboard label"
 msgid "Eject"
 msgstr "退出鍵"
 
-#: gdk/keynamesprivate.h:6898
+#: gdk/keynamesprivate.h:6916
 msgctxt "keyboard label"
 msgid "Explorer"
 msgstr "檔案鍵"
 
-#: gdk/keynamesprivate.h:6899
+#: gdk/keynamesprivate.h:6917
 msgctxt "keyboard label"
 msgid "Calculator"
 msgstr "計算機鍵"
 
-#: gdk/keynamesprivate.h:6900
+#: gdk/keynamesprivate.h:6918
 msgctxt "keyboard label"
 msgid "Mail"
 msgstr "郵件鍵"
 
-#: gdk/keynamesprivate.h:6901
+#: gdk/keynamesprivate.h:6919
 msgctxt "keyboard label"
 msgid "WWW"
 msgstr "WWW 鍵"
 
-#: gdk/keynamesprivate.h:6902
+#: gdk/keynamesprivate.h:6920
 msgctxt "keyboard label"
 msgid "Search"
 msgstr "搜尋鍵"
 
-#: gdk/keynamesprivate.h:6903
+#: gdk/keynamesprivate.h:6921
 msgctxt "keyboard label"
 msgid "Tools"
 msgstr "工具鍵"
 
-#: gdk/keynamesprivate.h:6904
-#, fuzzy
+#: gdk/keynamesprivate.h:6922
 msgctxt "keyboard label"
 msgid "ScreenSaver"
 msgstr "螢幕保護程式"
 
-#: gdk/keynamesprivate.h:6905
-#, fuzzy
+#: gdk/keynamesprivate.h:6923
 msgctxt "keyboard label"
 msgid "Battery"
 msgstr "電池"
 
-#: gdk/keynamesprivate.h:6906
-#, fuzzy
+#: gdk/keynamesprivate.h:6924
 msgctxt "keyboard label"
 msgid "Launch1"
 msgstr "執行1"
 
-#: gdk/keynamesprivate.h:6907
+#: gdk/keynamesprivate.h:6925
 msgctxt "keyboard label"
 msgid "Forward"
 msgstr "前進鍵"
 
-#: gdk/keynamesprivate.h:6908
+#: gdk/keynamesprivate.h:6926
 msgctxt "keyboard label"
 msgid "Back"
 msgstr "返回鍵"
 
-#: gdk/keynamesprivate.h:6909
-#, fuzzy
+#: gdk/keynamesprivate.h:6927
 msgctxt "keyboard label"
 msgid "Sleep"
 msgstr "睡眠"
 
-#: gdk/keynamesprivate.h:6910
-#, fuzzy
+#: gdk/keynamesprivate.h:6928
 msgctxt "keyboard label"
 msgid "Hibernate"
 msgstr "休眠"
 
-#: gdk/keynamesprivate.h:6911
-#, fuzzy
+#: gdk/keynamesprivate.h:6929
 msgctxt "keyboard label"
 msgid "WLAN"
 msgstr "無線區域網路"
 
-#: gdk/keynamesprivate.h:6912
-#, fuzzy
+#: gdk/keynamesprivate.h:6930
 msgctxt "keyboard label"
 msgid "WebCam"
 msgstr "網路攝影機"
 
-#: gdk/keynamesprivate.h:6913
-#, fuzzy
+#: gdk/keynamesprivate.h:6931
 msgctxt "keyboard label"
 msgid "Display"
 msgstr "顯示"
 
-#: gdk/keynamesprivate.h:6914
-#, fuzzy
+#: gdk/keynamesprivate.h:6932
 msgctxt "keyboard label"
 msgid "TouchpadToggle"
-msgstr "觸控板"
+msgstr "觸控板切換"
 
-#: gdk/keynamesprivate.h:6915
-#, fuzzy
+#: gdk/keynamesprivate.h:6933
 msgctxt "keyboard label"
 msgid "WakeUp"
 msgstr "喚醒"
 
-#: gdk/keynamesprivate.h:6916
-#, fuzzy
+#: gdk/keynamesprivate.h:6934
 msgctxt "keyboard label"
 msgid "Suspend"
 msgstr "暫停"
 
-#: gdk/loaders/gdkjpeg.c:63
+#: gdk/loaders/gdkjpeg.c:71
 #, c-format
 msgid "Error interpreting JPEG image file (%s)"
 msgstr "解譯 JPEG 影像檔時出錯 (%s)"
 
-#: gdk/loaders/gdkjpeg.c:194
+#: gdk/loaders/gdkjpeg.c:185
 #, c-format
 msgid "Unsupported JPEG colorspace (%d)"
 msgstr "不支援的 JPEG 色彩空間 (%d)"
 
-#: gdk/loaders/gdkjpeg.c:203 gdk/loaders/gdkpng.c:266 gdk/loaders/gdktiff.c:453
+#: gdk/loaders/gdkjpeg.c:194 gdk/loaders/gdkpng.c:436 gdk/loaders/gdktiff.c:472
 #, c-format
 msgid "Not enough memory for image size %ux%u"
 msgstr "對於影像大小 %ux%u 記憶體不足"
 
-#: gdk/loaders/gdkpng.c:119
+#: gdk/loaders/gdkpng.c:120
 #, c-format
 msgid "Error reading png (%s)"
 msgstr "讀取 png 時出錯 (%s)"
 
-#: gdk/loaders/gdkpng.c:217
+#: gdk/loaders/gdkpng.c:357
 #, c-format
 msgid "Unsupported depth %u in png image"
 msgstr "不支援 png 影像中的 %u 深度"
 
-#: gdk/loaders/gdkpng.c:247
+#: gdk/loaders/gdkpng.c:407
 #, c-format
 msgid "Unsupported color type %u in png image"
 msgstr "不支援 png 影像中的 %u 色彩空間"
 
-#: gdk/loaders/gdktiff.c:340
+#: gdk/loaders/gdkpng.c:421
+#, c-format
+msgid "Image stride too large for image size %ux%u"
+msgstr "對於影像大小 %ux%u 圖片步幅太大"
+
+#: gdk/loaders/gdktiff.c:358
 msgid "Failed to load RGB data from TIFF file"
 msgstr "無法從 TIFF 檔載入 RGB 資料"
 
-#: gdk/loaders/gdktiff.c:383
+#: gdk/loaders/gdktiff.c:401
 msgid "Could not load TIFF data"
 msgstr "無法載入 TIFF 資料"
 
-#: gdk/loaders/gdktiff.c:465
+#: gdk/loaders/gdktiff.c:484
 #, c-format
 msgid "Reading data failed at row %d"
 msgstr "第 %d 列資料讀取失敗"
 
-#: gdk/macos/gdkmacospasteboard.c:211 gdk/wayland/gdkclipboard-wayland.c:240
-#: gdk/wayland/gdkdrop-wayland.c:208 gdk/wayland/gdkprimary-wayland.c:336
-#: gdk/win32/gdkdrop-win32.c:1018 gdk/win32/gdkdrop-win32.c:1063
-#: gdk/x11/gdkclipboard-x11.c:805 gdk/x11/gdkdrop-x11.c:235
+#: gdk/macos/gdkmacospasteboard.c:211 gdk/wayland/gdkclipboard-wayland.c:244
+#: gdk/wayland/gdkdrop-wayland.c:205 gdk/wayland/gdkprimary-wayland.c:343
+#: gdk/win32/gdkdrop-win32.c:1018 gdk/win32/gdkdrop-win32.c:1067
+#: gdk/x11/gdkclipboard-x11.c:799 gdk/x11/gdkdrop-x11.c:235
 msgid "No compatible transfer format found"
 msgstr "找不到相容的傳輸格式"
 
@@ -611,84 +611,84 @@ msgstr "找不到相容的傳輸格式"
 msgid "Failed to decode contents with mime-type of '%s'"
 msgstr "無法解碼「%s」MIME 類型的內容"
 
-#: gdk/win32/gdkclipdrop-win32.c:721
+#: gdk/win32/gdkclipdrop-win32.c:719
 #, c-format
 msgid "Cannot claim clipboard ownership. OpenClipboard() timed out."
 msgstr "無法宣告剪貼簿的擁有權。OpenClipboard() 逾時。"
 
-#: gdk/win32/gdkclipdrop-win32.c:731
+#: gdk/win32/gdkclipdrop-win32.c:729
 #, c-format
 msgid "Cannot claim clipboard ownership. Another process claimed it before us."
 msgstr "無法宣告剪貼簿的擁有權。其他處理程序在之前已先行宣告。"
 
-#: gdk/win32/gdkclipdrop-win32.c:745
+#: gdk/win32/gdkclipdrop-win32.c:743
 #, c-format
 msgid "Cannot claim clipboard ownership. OpenClipboard() failed: 0x%lx."
 msgstr "無法宣告剪貼簿的擁有權。OpenClipboard() 失敗:0x%lx。"
 
-#: gdk/win32/gdkclipdrop-win32.c:757
+#: gdk/win32/gdkclipdrop-win32.c:755
 #, c-format
 msgid "Cannot claim clipboard ownership. EmptyClipboard() failed: 0x%lx."
 msgstr "無法宣告剪貼簿的擁有權。EmptyClipboard() 失敗:0x%lx。"
 
-#: gdk/win32/gdkclipdrop-win32.c:800
+#: gdk/win32/gdkclipdrop-win32.c:798
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() timed out."
 msgstr "無法設定剪貼簿資料。OpenClipboard() 逾時。"
 
-#: gdk/win32/gdkclipdrop-win32.c:810 gdk/win32/gdkclipdrop-win32.c:841
+#: gdk/win32/gdkclipdrop-win32.c:808 gdk/win32/gdkclipdrop-win32.c:839
 #, c-format
 msgid "Cannot set clipboard data. Another process claimed clipboard ownership."
 msgstr "無法設定剪貼簿資料。其他處理程序已宣告剪貼簿的擁有權。"
 
-#: gdk/win32/gdkclipdrop-win32.c:824
+#: gdk/win32/gdkclipdrop-win32.c:822
 #, c-format
 msgid "Cannot set clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr "無法設定剪貼簿資料。OpenClipboard() 失敗:0x%lx。"
 
-#: gdk/win32/gdkclipdrop-win32.c:876
+#: gdk/win32/gdkclipdrop-win32.c:874
 #, c-format
 msgid "Cannot get clipboard data. GlobalLock(0x%p) failed: 0x%lx."
 msgstr "無法取得剪貼簿資料。GlobalLock(0x%p) 失敗:0x%lx。"
 
-#: gdk/win32/gdkclipdrop-win32.c:887
+#: gdk/win32/gdkclipdrop-win32.c:885
 #, c-format
 msgid "Cannot get clipboard data. GlobalSize(0x%p) failed: 0x%lx."
 msgstr "無法取得剪貼簿資料。GlobalSize(0x%p) 失敗:0x%lx."
 
-#: gdk/win32/gdkclipdrop-win32.c:900
+#: gdk/win32/gdkclipdrop-win32.c:898
 #, c-format
 msgid ""
 "Cannot get clipboard data. Failed to allocate %s bytes to store the data."
 msgstr "無法取得剪貼簿資料。無法配置 %s 位元組儲存資料。"
 
-#: gdk/win32/gdkclipdrop-win32.c:932
+#: gdk/win32/gdkclipdrop-win32.c:930
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() timed out."
 msgstr "無法取得剪貼簿資料。OpenClipboard() 逾時。"
 
-#: gdk/win32/gdkclipdrop-win32.c:942
+#: gdk/win32/gdkclipdrop-win32.c:940
 #, c-format
 msgid "Cannot get clipboard data. Clipboard ownership changed."
 msgstr "無法取得剪貼簿資料。剪貼簿的擁有權已變更。"
 
-#: gdk/win32/gdkclipdrop-win32.c:952
+#: gdk/win32/gdkclipdrop-win32.c:950
 #, c-format
 msgid ""
 "Cannot get clipboard data. Clipboard data changed before we could get it."
 msgstr "無法取得剪貼簿資料。剪貼簿的資料在取得前已經變更。"
 
-#: gdk/win32/gdkclipdrop-win32.c:969
+#: gdk/win32/gdkclipdrop-win32.c:967
 #, c-format
 msgid "Cannot get clipboard data. OpenClipboard() failed: 0x%lx."
 msgstr "無法取得剪貼簿資料。OpenClipboard() 失敗:0x%lx。"
 
-#: gdk/win32/gdkclipdrop-win32.c:994
+#: gdk/win32/gdkclipdrop-win32.c:992
 #, c-format
 msgid "Cannot get clipboard data. No compatible transfer format found."
 msgstr "無法取得剪貼簿資料。找不到相容的傳輸格式。"
 
-#: gdk/win32/gdkclipdrop-win32.c:1004
+#: gdk/win32/gdkclipdrop-win32.c:1002
 #, c-format
 msgid "Cannot get clipboard data. GetClipboardData() failed: 0x%lx."
 msgstr "無法取得剪貼簿資料。GetClipboardData() 失敗:0x%lx。"
@@ -708,32 +708,41 @@ msgstr "無法取得 DnD 資料。GlobalSize(0x%p) 失敗:0x%lx。"
 msgid "Cannot get DnD data. Failed to allocate %s bytes to store the data."
 msgstr "無法取得 DnD 資料。無法配置 %s 位元組儲存資料。"
 
-#: gdk/win32/gdkdrop-win32.c:1037
+#: gdk/win32/gdkdrop-win32.c:1039
 #, c-format
 msgid "GDK surface 0x%p is not registered as a drop target"
 msgstr "GDK surface 0x%p 未註冊為 drop 目標"
 
-#: gdk/win32/gdkdrop-win32.c:1044
+#: gdk/win32/gdkdrop-win32.c:1047
 #, c-format
 msgid "Target context record 0x%p has no data object"
 msgstr "目標情境記錄 0x%p 沒有資料物件"
 
-#: gdk/win32/gdkdrop-win32.c:1082
+#: gdk/win32/gdkdrop-win32.c:1087
 #, c-format
 msgid "IDataObject_GetData (0x%x) failed, returning 0x%lx"
 msgstr "IDataObject_GetData (0x%x) 失敗,回傳 0x%lx"
 
-#: gdk/win32/gdkdrop-win32.c:1114
+#: gdk/win32/gdkdrop-win32.c:1121
 #, c-format
 msgid "Failed to transmute DnD data W32 format 0x%x to %p (%s)"
 msgstr "無法將 DnD 資料 W32 格式 0x%x 變成 %p (%s)"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:276
-#: gdk/win32/gdkglcontext-win32-wgl.c:293
+#: gdk/win32/gdkglcontext-win32-wgl.c:681
 msgid "No GL implementation is available"
 msgstr "沒有 GL 實作可用"
 
-#: gdk/win32/gdkglcontext-win32-wgl.c:577
+#: gdk/win32/gdkglcontext-win32-wgl.c:771
+#, c-format
+msgid "WGL version %d.%d is too low, need at least %d.%d"
+msgstr "WGL 版本 %d.%d 過舊。至少需要 %d.%d"
+
+#: gdk/win32/gdkglcontext-win32-wgl.c:789
+#, c-format
+msgid "GL implementation cannot share GL contexts"
+msgstr "GL 實作無法共用 GL 脈絡"
+
+#: gdk/win32/gdkglcontext-win32-wgl.c:1069
 msgid "No available configurations for the given pixel format"
 msgstr "指定的像素格式沒有可用的設定"
 
@@ -771,43 +780,43 @@ msgstr "GlobalLock() 失敗:"
 msgid "GlobalAlloc() failed: "
 msgstr "GlobalAlloc() 失敗:"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:299
+#: gdk/x11/gdkapplaunchcontext-x11.c:297
 #, c-format
 msgid "Starting “%s”"
 msgstr "正在啟動「%s」"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:312
+#: gdk/x11/gdkapplaunchcontext-x11.c:310
 #, c-format
 msgid "Opening “%s”"
 msgstr "正在開啟「%s」"
 
-#: gdk/x11/gdkapplaunchcontext-x11.c:317
+#: gdk/x11/gdkapplaunchcontext-x11.c:315
 #, c-format
 msgid "Opening %d Item"
 msgid_plural "Opening %d Items"
 msgstr[0] "正在開啟 %d 個項目"
 
-#: gdk/x11/gdkclipboard-x11.c:475
+#: gdk/x11/gdkclipboard-x11.c:473
 msgid "Clipboard manager could not store selection."
 msgstr "剪貼簿管理員無法儲存選擇內容。"
 
-#: gdk/x11/gdkclipboard-x11.c:655
+#: gdk/x11/gdkclipboard-x11.c:649
 msgid "Cannot store clipboard. No clipboard manager is active."
 msgstr "無法儲存剪貼簿。沒有作用中的剪貼簿管理器。"
 
-#: gdk/x11/gdkglcontext-glx.c:769
+#: gdk/x11/gdkglcontext-glx.c:817
 msgid "No GLX configurations available"
 msgstr "沒有 GLX 組態可用"
 
-#: gdk/x11/gdkglcontext-glx.c:842
+#: gdk/x11/gdkglcontext-glx.c:904
 msgid "No GLX configuration with required features found"
 msgstr "找不到需要功能的 GLX 組態"
 
-#: gdk/x11/gdkglcontext-glx.c:916
+#: gdk/x11/gdkglcontext-glx.c:978
 msgid "GLX is not supported"
 msgstr "不支援 GLX"
 
-#: gdk/x11/gdkselectioninputstream-x11.c:469
+#: gdk/x11/gdkselectioninputstream-x11.c:465
 #, c-format
 msgid "Format %s not supported"
 msgstr "不支援 %s 格式"
@@ -834,11 +843,20 @@ msgstr "複合文字轉換中的格式無效。"
 msgid "Unsupported encoding “%s”"
 msgstr "不支援的「%s」編碼方式"
 
-#: gsk/gl/gskglrenderer.c:132
+#: gsk/gl/gskglrenderer.c:215
 #, c-format
 msgid "This GLES %d.%d implementation does not support half-float vertex data"
 msgstr "這個 GLES %d.%d 實作不支援半浮點頂點資料"
 
+#: gsk/gpu/gskgldevice.c:252
+#, c-format
+msgid "OpenGL ES 3.0 is not supported by this renderer."
+msgstr "此繪製器不支援 OpenGL ES 3.0。"
+
+#: gsk/gpu/gsknglrenderer.c:69
+msgid "OpenGL 3.3 required"
+msgstr "需要 OpenGL 3.3"
+
 #: gtk/a11y/gtkatspiaction.c:239
 msgctxt "accessibility"
 msgid "Click"
@@ -942,7 +960,7 @@ msgctxt "accessibility"
 msgid "Clears the contents of the entry"
 msgstr "清除項目的內容"
 
-#: gtk/a11y/gtkatspiroot.c:256
+#: gtk/a11y/gtkatspiroot.c:263 gtk/gtkaccessible.c:869
 msgctxt "accessibility"
 msgid "application"
 msgstr "應用程式"
@@ -966,34 +984,34 @@ msgstr "無法反跳脫字串"
 msgid "Other app…"
 msgstr "其他程式…"
 
-#: gtk/deprecated/gtkappchooserdialog.c:210
-#: gtk/deprecated/gtkappchooserdialog.c:261
+#: gtk/deprecated/gtkappchooserdialog.c:215
+#: gtk/deprecated/gtkappchooserdialog.c:266
 msgid "Select Application"
 msgstr "選擇應用程式"
 
 #. Translators: %s is a filename
-#: gtk/deprecated/gtkappchooserdialog.c:217
+#: gtk/deprecated/gtkappchooserdialog.c:222
 #, c-format
 msgid "Opening “%s”."
 msgstr "正在開啟「%s」。"
 
-#: gtk/deprecated/gtkappchooserdialog.c:218
+#: gtk/deprecated/gtkappchooserdialog.c:223
 #, c-format
 msgid "No applications found for “%s”"
 msgstr "沒有應用程式可開啟「%s」"
 
 #. Translators: %s is a file type description
-#: gtk/deprecated/gtkappchooserdialog.c:223
+#: gtk/deprecated/gtkappchooserdialog.c:228
 #, c-format
 msgid "Opening “%s” files."
 msgstr "正在開啟「%s」檔案。"
 
-#: gtk/deprecated/gtkappchooserdialog.c:225
+#: gtk/deprecated/gtkappchooserdialog.c:230
 #, c-format
 msgid "No applications found for “%s” files"
 msgstr "沒有應用程式可開啟「%s」檔案"
 
-#: gtk/deprecated/gtkappchooserdialog.c:427
+#: gtk/deprecated/gtkappchooserdialog.c:432
 msgid "Failed to start GNOME Software"
 msgstr "無法啟動 GNOME《軟體》"
 
@@ -1036,7 +1054,7 @@ msgid "Invalid"
 msgstr "無效"
 
 #. This label is displayed in a treeview cell displaying an accelerator
-#. * when the cell is clicked to change the acelerator.
+#. * when the cell is clicked to change the accelerator.
 #.
 #: gtk/deprecated/gtkcellrendereraccel.c:436
 #: gtk/deprecated/gtkcellrendereraccel.c:729
@@ -1051,19 +1069,19 @@ msgctxt "progress bar label"
 msgid "%d %%"
 msgstr "%d %%"
 
-#: gtk/deprecated/gtkcolorbutton.c:183 gtk/deprecated/gtkcolorbutton.c:311
-#: gtk/gtkcolordialog.c:411
+#: gtk/deprecated/gtkcolorbutton.c:183 gtk/deprecated/gtkcolorbutton.c:314
+#: gtk/gtkcolordialog.c:409
 msgid "Pick a Color"
 msgstr "挑選色彩"
 
-#: gtk/deprecated/gtkcolorbutton.c:502 gtk/gtkcolorchooserwidget.c:312
-#: gtk/gtkcolordialogbutton.c:299
+#: gtk/deprecated/gtkcolorbutton.c:505 gtk/gtkcolorchooserwidget.c:321
+#: gtk/gtkcolordialogbutton.c:335
 #, c-format
 msgid "Red %d%%, Green %d%%, Blue %d%%, Alpha %d%%"
 msgstr "紅 %d%%, 綠 %d%%, 藍 %d%%, Alpha %d%%"
 
-#: gtk/deprecated/gtkcolorbutton.c:508 gtk/gtkcolorchooserwidget.c:318
-#: gtk/gtkcolordialogbutton.c:305
+#: gtk/deprecated/gtkcolorbutton.c:511 gtk/gtkcolorchooserwidget.c:327
+#: gtk/gtkcolordialogbutton.c:341
 #, c-format
 msgid "Red %d%%, Green %d%%, Blue %d%%"
 msgstr "紅 %d%%, 綠 %d%%, 藍 %d%%"
@@ -1072,30 +1090,30 @@ msgstr "紅 %d%%, 綠 %d%%, 藍 %d%%"
 msgid "Sans 12"
 msgstr "Sans 12"
 
-#: gtk/deprecated/gtkfontbutton.c:507 gtk/deprecated/gtkfontbutton.c:621
-#: gtk/gtkfontdialog.c:596
+#: gtk/deprecated/gtkfontbutton.c:507 gtk/deprecated/gtkfontbutton.c:624
+#: gtk/gtkfontdialog.c:594
 msgid "Pick a Font"
 msgstr "挑選字型"
 
-#: gtk/deprecated/gtkfontbutton.c:597 gtk/gtkfilechooserwidget.c:3856
-#: gtk/gtkfontdialogbutton.c:115 gtk/inspector/visual.ui:170
+#: gtk/deprecated/gtkfontbutton.c:600 gtk/gtkfilechooserwidget.c:3848
+#: gtk/gtkfontdialogbutton.c:126 gtk/inspector/visual.ui:285
 msgid "Font"
 msgstr "å­—åž‹"
 
-#: gtk/deprecated/gtkfontbutton.c:1152 gtk/gtkfontdialogbutton.c:613
+#: gtk/deprecated/gtkfontbutton.c:1155 gtk/gtkfontdialogbutton.c:652
 msgctxt "font"
 msgid "None"
 msgstr "沒有"
 
-#: gtk/deprecated/gtklockbutton.c:288 gtk/ui/gtklockbutton.ui:20
+#: gtk/deprecated/gtklockbutton.c:294 gtk/ui/gtklockbutton.ui:20
 msgid "Lock"
 msgstr "鎖定"
 
-#: gtk/deprecated/gtklockbutton.c:300 gtk/ui/gtklockbutton.ui:26
+#: gtk/deprecated/gtklockbutton.c:308 gtk/ui/gtklockbutton.ui:26
 msgid "Unlock"
 msgstr "解除鎖定"
 
-#: gtk/deprecated/gtklockbutton.c:312
+#: gtk/deprecated/gtklockbutton.c:322
 msgid ""
 "Dialog is unlocked.\n"
 "Click to prevent further changes"
@@ -1103,7 +1121,7 @@ msgstr ""
 "對話視窗已解除鎖定。\n"
 "點選以防止進一步變更"
 
-#: gtk/deprecated/gtklockbutton.c:324
+#: gtk/deprecated/gtklockbutton.c:336
 msgid ""
 "Dialog is locked.\n"
 "Click to make changes"
@@ -1111,7 +1129,7 @@ msgstr ""
 "對話視窗已解除鎖定。\n"
 "點選以進行變更"
 
-#: gtk/deprecated/gtklockbutton.c:336
+#: gtk/deprecated/gtklockbutton.c:350
 msgid ""
 "System policy prevents changes.\n"
 "Contact your system administrator"
@@ -1119,111 +1137,134 @@ msgstr ""
 "系統原則不允許進行變更。\n"
 "請聯絡您的管理員"
 
-#: gtk/deprecated/gtkshow.c:178
+#: gtk/deprecated/gtkshow.c:217
 msgid "Could not show link"
 msgstr "無法顯示連結"
 
-#: gtk/gtkaboutdialog.c:126 gtk/ui/gtkaboutdialog.ui:163
+#: gtk/deprecated/gtkvolumebutton.c:236
+msgid "Muted"
+msgstr "靜音"
+
+#: gtk/deprecated/gtkvolumebutton.c:240
+msgid "Full Volume"
+msgstr "最大音量"
+
+#. Translators: this is the percentage of the current volume,
+#. * as used in the tooltip, eg. "49 %".
+#. * Translate the "%d" to "%Id" if you want to use localised digits,
+#. * or otherwise translate the "%d" to "%d".
+#.
+#: gtk/deprecated/gtkvolumebutton.c:253
+#, c-format
+msgctxt "volume percentage"
+msgid "%d %%"
+msgstr "%d %%"
+
+#: gtk/gtkaboutdialog.c:125 gtk/ui/gtkaboutdialog.ui:173
 msgid "License"
 msgstr "授權條款"
 
-#: gtk/gtkaboutdialog.c:127
+#: gtk/gtkaboutdialog.c:126
 msgid "Custom License"
 msgstr "自訂的授權條款"
 
-#: gtk/gtkaboutdialog.c:128
+#: gtk/gtkaboutdialog.c:127
 msgid "GNU General Public License, version 2 or later"
 msgstr "《GNU 通用公眾授權條款 2 版》或後續版本"
 
-#: gtk/gtkaboutdialog.c:129
+#: gtk/gtkaboutdialog.c:128
 msgid "GNU General Public License, version 3 or later"
 msgstr "《GNU 通用公眾授權條款 3 版》或後續版本"
 
-#: gtk/gtkaboutdialog.c:130
+#: gtk/gtkaboutdialog.c:129
 msgid "GNU Lesser General Public License, version 2.1 or later"
 msgstr "《GNU 較寬鬆通用公眾授權條款 2.1 版》或後續版本"
 
-#: gtk/gtkaboutdialog.c:131
+#: gtk/gtkaboutdialog.c:130
 msgid "GNU Lesser General Public License, version 3 or later"
 msgstr "《GNU 較寬鬆通用公眾授權條款 3 版》或後續版本"
 
-#: gtk/gtkaboutdialog.c:132
+#: gtk/gtkaboutdialog.c:131
 msgid "BSD 2-Clause License"
 msgstr "《BSD 2-Clause 授權條款》"
 
-#: gtk/gtkaboutdialog.c:133
+#: gtk/gtkaboutdialog.c:132
 msgid "The MIT License (MIT)"
 msgstr "《MIT 授權條款》"
 
-#: gtk/gtkaboutdialog.c:134
+#: gtk/gtkaboutdialog.c:133
 msgid "Artistic License 2.0"
 msgstr "《Artistic 授權條款 2.0》"
 
-#: gtk/gtkaboutdialog.c:135
+#: gtk/gtkaboutdialog.c:134
 msgid "GNU General Public License, version 2 only"
 msgstr "僅限《GNU 通用公眾授權條款 2 版》"
 
-#: gtk/gtkaboutdialog.c:136
+#: gtk/gtkaboutdialog.c:135
 msgid "GNU General Public License, version 3 only"
 msgstr "僅限《GNU 通用公眾授權條款 3 版》"
 
-#: gtk/gtkaboutdialog.c:137
+#: gtk/gtkaboutdialog.c:136
 msgid "GNU Lesser General Public License, version 2.1 only"
 msgstr "僅限《GNU 較寬鬆通用公眾授權條款 2.1 版》"
 
-#: gtk/gtkaboutdialog.c:138
+#: gtk/gtkaboutdialog.c:137
 msgid "GNU Lesser General Public License, version 3 only"
 msgstr "僅限《GNU 較寬鬆通用公眾授權條款 3 版》"
 
-#: gtk/gtkaboutdialog.c:139
+#: gtk/gtkaboutdialog.c:138
 msgid "GNU Affero General Public License, version 3 or later"
 msgstr "《GNU Affero 通用公眾授權條款 3 版》或後續版本"
 
-#: gtk/gtkaboutdialog.c:140
+#: gtk/gtkaboutdialog.c:139
 msgid "GNU Affero General Public License, version 3 only"
 msgstr "僅限《GNU Affero 通用公眾授權條款 3 版》"
 
-#: gtk/gtkaboutdialog.c:141
+#: gtk/gtkaboutdialog.c:140
 msgid "BSD 3-Clause License"
 msgstr "《BSD 3-Clause 授權條款》"
 
-#: gtk/gtkaboutdialog.c:142
+#: gtk/gtkaboutdialog.c:141
 msgid "Apache License, Version 2.0"
 msgstr "《Apache 授權條款 2.0 版》"
 
-#: gtk/gtkaboutdialog.c:143
+#: gtk/gtkaboutdialog.c:142
 msgid "Mozilla Public License 2.0"
 msgstr "《Mozilla 公眾授權條款 2.0》"
 
-#: gtk/gtkaboutdialog.c:967
+#: gtk/gtkaboutdialog.c:143
+msgid "BSD Zero-Clause License"
+msgstr "《BSD Zero-Clause 授權條款》"
+
+#: gtk/gtkaboutdialog.c:1028
 msgid "Website"
 msgstr "網站"
 
-#: gtk/gtkaboutdialog.c:1003 gtk/ui/gtkapplication-quartz.ui:6
+#: gtk/gtkaboutdialog.c:1070 gtk/ui/gtkapplication-quartz.ui:6
 #, c-format
 msgid "About %s"
 msgstr "關於 %s"
 
-#: gtk/gtkaboutdialog.c:2093
+#: gtk/gtkaboutdialog.c:2164
 msgid "Created by"
 msgstr "製作者"
 
-#: gtk/gtkaboutdialog.c:2096
+#: gtk/gtkaboutdialog.c:2167
 msgid "Documented by"
 msgstr "文件編寫者"
 
-#: gtk/gtkaboutdialog.c:2106
+#: gtk/gtkaboutdialog.c:2177
 msgid "Translated by"
 msgstr "翻譯者"
 
-#: gtk/gtkaboutdialog.c:2111
+#: gtk/gtkaboutdialog.c:2182
 msgid "Design by"
 msgstr "設計者"
 
 #. Translators: this is the license preamble; the string at the end
 #. * contains the name of the license as link text.
 #.
-#: gtk/gtkaboutdialog.c:2276
+#: gtk/gtkaboutdialog.c:2347
 #, c-format
 msgid ""
 "This program comes with absolutely no warranty.\n"
@@ -1237,7 +1278,7 @@ msgstr ""
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:837 gtk/gtkshortcutlabel.c:101
+#: gtk/gtkaccelgroup.c:839 gtk/gtkshortcutlabel.c:101
 #: gtk/gtkshortcutlabel.c:137
 msgctxt "keyboard label"
 msgid "Shift"
@@ -1248,7 +1289,7 @@ msgstr "Shift"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:856 gtk/gtkshortcutlabel.c:104
+#: gtk/gtkaccelgroup.c:858 gtk/gtkshortcutlabel.c:104
 #: gtk/gtkshortcutlabel.c:139
 msgctxt "keyboard label"
 msgid "Ctrl"
@@ -1259,7 +1300,7 @@ msgstr "Ctrl"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:875 gtk/gtkshortcutlabel.c:107
+#: gtk/gtkaccelgroup.c:877 gtk/gtkshortcutlabel.c:107
 #: gtk/gtkshortcutlabel.c:141
 msgctxt "keyboard label"
 msgid "Alt"
@@ -1270,7 +1311,7 @@ msgstr "Alt"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:893 gtk/gtkshortcutlabel.c:113
+#: gtk/gtkaccelgroup.c:895 gtk/gtkshortcutlabel.c:113
 #: gtk/gtkshortcutlabel.c:143
 msgctxt "keyboard label"
 msgid "Super"
@@ -1281,9 +1322,8 @@ msgstr "超級鍵"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:907 gtk/gtkshortcutlabel.c:116
+#: gtk/gtkaccelgroup.c:909 gtk/gtkshortcutlabel.c:116
 #: gtk/gtkshortcutlabel.c:145
-#, fuzzy
 msgctxt "keyboard label"
 msgid "Hyper"
 msgstr "Hyper"
@@ -1293,9 +1333,8 @@ msgstr "Hyper"
 #. * translated on keyboards used for your language, don't translate
 #. * this.
 #.
-#: gtk/gtkaccelgroup.c:922 gtk/gtkshortcutlabel.c:110
+#: gtk/gtkaccelgroup.c:924 gtk/gtkshortcutlabel.c:110
 #: gtk/gtkshortcutlabel.c:148
-#, fuzzy
 msgctxt "keyboard label"
 msgid "Meta"
 msgstr "Meta"
@@ -1304,413 +1343,442 @@ msgstr "Meta"
 #. * be used in accelerators such as "Ctrl+Shift+KP 1" in menus,
 #. * and therefore the translation needs to be very short.
 #.
-#: gtk/gtkaccelgroup.c:942
+#: gtk/gtkaccelgroup.c:944
 msgctxt "keyboard label"
 msgid "KP"
 msgstr "小鍵盤"
 
-#: gtk/gtkaccelgroup.c:949
+#: gtk/gtkaccelgroup.c:951
 msgctxt "keyboard label"
 msgid "Space"
 msgstr "空格鍵"
 
-#: gtk/gtkaccelgroup.c:952 gtk/gtkshortcutlabel.c:176
-#, fuzzy
+#: gtk/gtkaccelgroup.c:954 gtk/gtkshortcutlabel.c:176
 msgctxt "keyboard label"
 msgid "Backslash"
 msgstr "Backslash"
 
-#: gtk/gtkaccessible.c:623
+#: gtk/gtkaccessible.c:790
 msgctxt "accessibility"
 msgid "alert"
 msgstr "警示"
 
-#: gtk/gtkaccessible.c:624
+#: gtk/gtkaccessible.c:791
 msgctxt "accessibility"
 msgid "alert dialog"
 msgstr "警示對話框"
 
-#: gtk/gtkaccessible.c:625
+#: gtk/gtkaccessible.c:792
 msgctxt "accessibility"
 msgid "banner"
 msgstr "æ©«å¹…"
 
-#: gtk/gtkaccessible.c:626
+#: gtk/gtkaccessible.c:793
 msgctxt "accessibility"
 msgid "button"
 msgstr "按鈕"
 
-#: gtk/gtkaccessible.c:627
+#: gtk/gtkaccessible.c:794
 msgctxt "accessibility"
 msgid "caption"
 msgstr "描述"
 
-#: gtk/gtkaccessible.c:628
+#: gtk/gtkaccessible.c:795
 msgctxt "accessibility"
 msgid "cell"
 msgstr "儲存格"
 
-#: gtk/gtkaccessible.c:629
+#: gtk/gtkaccessible.c:796
 msgctxt "accessibility"
 msgid "checkbox"
 msgstr "勾選框"
 
-#: gtk/gtkaccessible.c:630
+#: gtk/gtkaccessible.c:797
 msgctxt "accessibility"
 msgid "column header"
 msgstr "欄位標頭"
 
-#: gtk/gtkaccessible.c:631
+#: gtk/gtkaccessible.c:798
 msgctxt "accessibility"
 msgid "combo box"
 msgstr "組合方塊"
 
-#: gtk/gtkaccessible.c:632
+#: gtk/gtkaccessible.c:799
 msgctxt "accessibility"
 msgid "command"
 msgstr "指令"
 
-#: gtk/gtkaccessible.c:633
+#: gtk/gtkaccessible.c:800
 msgctxt "accessibility"
 msgid "composite"
 msgstr "組合"
 
-#: gtk/gtkaccessible.c:634
+#: gtk/gtkaccessible.c:801
 msgctxt "accessibility"
 msgid "dialog"
 msgstr "對話框"
 
-#: gtk/gtkaccessible.c:635
+#: gtk/gtkaccessible.c:802
 msgctxt "accessibility"
 msgid "document"
 msgstr "文件"
 
-#: gtk/gtkaccessible.c:636
+#: gtk/gtkaccessible.c:803
 msgctxt "accessibility"
 msgid "feed"
 msgstr "消息來源"
 
-#: gtk/gtkaccessible.c:637
+#: gtk/gtkaccessible.c:804
 msgctxt "accessibility"
 msgid "form"
 msgstr "表單"
 
-#: gtk/gtkaccessible.c:638
+#: gtk/gtkaccessible.c:805
 msgctxt "accessibility"
 msgid "generic"
 msgstr "一般"
 
-#: gtk/gtkaccessible.c:639
+#: gtk/gtkaccessible.c:806
 msgctxt "accessibility"
 msgid "grid"
 msgstr "網格"
 
-#: gtk/gtkaccessible.c:640
+#: gtk/gtkaccessible.c:807
 msgctxt "accessibility"
 msgid "grid cell"
 msgstr "網格單元格"
 
-#: gtk/gtkaccessible.c:641
+#: gtk/gtkaccessible.c:808
 msgctxt "accessibility"
 msgid "group"
 msgstr "群組"
 
-#: gtk/gtkaccessible.c:642
+#: gtk/gtkaccessible.c:809
 msgctxt "accessibility"
 msgid "heading"
 msgstr "標題"
 
-#: gtk/gtkaccessible.c:643
+#: gtk/gtkaccessible.c:810
 msgctxt "accessibility"
 msgid "image"
 msgstr "圖片"
 
-#: gtk/gtkaccessible.c:644
+#: gtk/gtkaccessible.c:811
 msgctxt "accessibility"
 msgid "input"
 msgstr "輸入"
 
-#: gtk/gtkaccessible.c:645
+#: gtk/gtkaccessible.c:812
 msgctxt "accessibility"
 msgid "label"
 msgstr "標籤"
 
-#: gtk/gtkaccessible.c:646
+#: gtk/gtkaccessible.c:813
 msgctxt "accessibility"
 msgid "landmark"
 msgstr "地標"
 
-#: gtk/gtkaccessible.c:647
+#: gtk/gtkaccessible.c:814
 msgctxt "accessibility"
 msgid "legend"
 msgstr "圖例"
 
-#: gtk/gtkaccessible.c:648
+#: gtk/gtkaccessible.c:815
 msgctxt "accessibility"
 msgid "link"
 msgstr "連結"
 
-#: gtk/gtkaccessible.c:649
+#: gtk/gtkaccessible.c:816
 msgctxt "accessibility"
 msgid "list"
 msgstr "列表"
 
-#: gtk/gtkaccessible.c:650
+#: gtk/gtkaccessible.c:817
 msgctxt "accessibility"
 msgid "list box"
 msgstr "列表方塊"
 
-#: gtk/gtkaccessible.c:651
+#: gtk/gtkaccessible.c:818
 msgctxt "accessibility"
 msgid "list item"
 msgstr "列表項目"
 
-#: gtk/gtkaccessible.c:652
+#: gtk/gtkaccessible.c:819
 msgctxt "accessibility"
 msgid "log"
 msgstr "紀錄"
 
-#: gtk/gtkaccessible.c:653
+#: gtk/gtkaccessible.c:820
 msgctxt "accessibility"
 msgid "main"
 msgstr "主要"
 
-#: gtk/gtkaccessible.c:654
+#: gtk/gtkaccessible.c:821
 msgctxt "accessibility"
 msgid "marquee"
 msgstr "跑馬燈"
 
-#: gtk/gtkaccessible.c:655
+#: gtk/gtkaccessible.c:822
 msgctxt "accessibility"
 msgid "math"
 msgstr "數學"
 
-#: gtk/gtkaccessible.c:656
+#: gtk/gtkaccessible.c:823
 msgctxt "accessibility"
 msgid "meter"
 msgstr "ç±³"
 
-#: gtk/gtkaccessible.c:657
+#: gtk/gtkaccessible.c:824
 msgctxt "accessibility"
 msgid "menu"
 msgstr "選單"
 
-#: gtk/gtkaccessible.c:658
+#: gtk/gtkaccessible.c:825
 msgctxt "accessibility"
 msgid "menu bar"
 msgstr "選單列"
 
-#: gtk/gtkaccessible.c:659
+#: gtk/gtkaccessible.c:826
 msgctxt "accessibility"
 msgid "menu item"
 msgstr "選單項目"
 
-#: gtk/gtkaccessible.c:660
+#: gtk/gtkaccessible.c:827
 msgctxt "accessibility"
 msgid "menu item checkbox"
 msgstr "選單項目勾選框"
 
-#: gtk/gtkaccessible.c:661
+#: gtk/gtkaccessible.c:828
 msgctxt "accessibility"
 msgid "menu item radio"
 msgstr "單選選單項目"
 
-#: gtk/gtkaccessible.c:662
+#: gtk/gtkaccessible.c:829
 msgctxt "accessibility"
 msgid "navigation"
 msgstr "導覽"
 
-#: gtk/gtkaccessible.c:663
+#: gtk/gtkaccessible.c:830
 msgctxt "accessibility"
 msgid "none"
 msgstr "ç„¡"
 
-#: gtk/gtkaccessible.c:664
+#: gtk/gtkaccessible.c:831
 msgctxt "accessibility"
 msgid "note"
 msgstr "備註"
 
-#: gtk/gtkaccessible.c:665
+#: gtk/gtkaccessible.c:832
 msgctxt "accessibility"
 msgid "option"
 msgstr "選項"
 
-#: gtk/gtkaccessible.c:666
+#: gtk/gtkaccessible.c:833
 msgctxt "accessibility"
 msgid "presentation"
 msgstr "ç°¡å ±"
 
-#: gtk/gtkaccessible.c:667
+#: gtk/gtkaccessible.c:834
 msgctxt "accessibility"
 msgid "progress bar"
 msgstr "進度列"
 
-#: gtk/gtkaccessible.c:668
+#: gtk/gtkaccessible.c:835
 msgctxt "accessibility"
 msgid "radio"
 msgstr "單選"
 
-#: gtk/gtkaccessible.c:669
+#: gtk/gtkaccessible.c:836
 msgctxt "accessibility"
 msgid "radio group"
 msgstr "單選群組"
 
-#: gtk/gtkaccessible.c:670
+#: gtk/gtkaccessible.c:837
 msgctxt "accessibility"
 msgid "range"
 msgstr "範圍"
 
-#: gtk/gtkaccessible.c:671
+#: gtk/gtkaccessible.c:838
 msgctxt "accessibility"
 msgid "region"
 msgstr "區域"
 
-#: gtk/gtkaccessible.c:672
+#: gtk/gtkaccessible.c:839
 msgctxt "accessibility"
 msgid "row"
 msgstr "列"
 
-#: gtk/gtkaccessible.c:673
+#: gtk/gtkaccessible.c:840
 msgctxt "accessibility"
 msgid "row group"
 msgstr "列群組"
 
-#: gtk/gtkaccessible.c:674
+#: gtk/gtkaccessible.c:841
 msgctxt "accessibility"
 msgid "row header"
 msgstr "列標頭"
 
-#: gtk/gtkaccessible.c:675
+#: gtk/gtkaccessible.c:842
 msgctxt "accessibility"
 msgid "scroll bar"
 msgstr "捲動列"
 
-#: gtk/gtkaccessible.c:676
+#: gtk/gtkaccessible.c:843
 msgctxt "accessibility"
 msgid "search"
 msgstr "搜尋"
 
-#: gtk/gtkaccessible.c:677
+#: gtk/gtkaccessible.c:844
 msgctxt "accessibility"
 msgid "search box"
 msgstr "搜尋方塊"
 
-#: gtk/gtkaccessible.c:678
+#: gtk/gtkaccessible.c:845
 msgctxt "accessibility"
 msgid "section"
 msgstr "章節"
 
-#: gtk/gtkaccessible.c:679
+#: gtk/gtkaccessible.c:846
 msgctxt "accessibility"
 msgid "section head"
 msgstr "章節標頭"
 
-#: gtk/gtkaccessible.c:680
+#: gtk/gtkaccessible.c:847
 msgctxt "accessibility"
 msgid "select"
 msgstr "選擇"
 
-#: gtk/gtkaccessible.c:681
+#: gtk/gtkaccessible.c:848
 msgctxt "accessibility"
 msgid "separator"
 msgstr "分隔線"
 
-#: gtk/gtkaccessible.c:682
+#: gtk/gtkaccessible.c:849
 msgctxt "accessibility"
 msgid "slider"
 msgstr "滑動鈕"
 
-#: gtk/gtkaccessible.c:683
+#: gtk/gtkaccessible.c:850
 msgctxt "accessibility"
 msgid "spin button"
 msgstr "微調按鈕"
 
-#: gtk/gtkaccessible.c:684
+#: gtk/gtkaccessible.c:851
 msgctxt "accessibility"
 msgid "status"
 msgstr "狀態"
 
-#: gtk/gtkaccessible.c:685
+#: gtk/gtkaccessible.c:852
 msgctxt "accessibility"
 msgid "structure"
 msgstr "結構"
 
-#: gtk/gtkaccessible.c:686
+#: gtk/gtkaccessible.c:853
 msgctxt "accessibility"
 msgid "switch"
 msgstr "開關"
 
-#: gtk/gtkaccessible.c:687
+#: gtk/gtkaccessible.c:854
 msgctxt "accessibility"
 msgid "tab"
 msgstr "分頁"
 
-#: gtk/gtkaccessible.c:688
+#: gtk/gtkaccessible.c:855
 msgctxt "accessibility"
 msgid "table"
 msgstr "表格"
 
-#: gtk/gtkaccessible.c:689
+#: gtk/gtkaccessible.c:856
 msgctxt "accessibility"
 msgid "tab list"
 msgstr "分頁列表"
 
-#: gtk/gtkaccessible.c:690
+#: gtk/gtkaccessible.c:857
 msgctxt "accessibility"
 msgid "tab panel"
 msgstr "分頁窗格"
 
-#: gtk/gtkaccessible.c:691
+#: gtk/gtkaccessible.c:858
 msgctxt "accessibility"
 msgid "text box"
 msgstr "文字方塊"
 
-#: gtk/gtkaccessible.c:692
+#: gtk/gtkaccessible.c:859
 msgctxt "accessibility"
 msgid "time"
 msgstr "時間"
 
-#: gtk/gtkaccessible.c:693
+#: gtk/gtkaccessible.c:860
 msgctxt "accessibility"
 msgid "timer"
 msgstr "計時器"
 
-#: gtk/gtkaccessible.c:694
+#: gtk/gtkaccessible.c:861
 msgctxt "accessibility"
 msgid "tool bar"
 msgstr "工具列"
 
-#: gtk/gtkaccessible.c:695
+#: gtk/gtkaccessible.c:862
 msgctxt "accessibility"
 msgid "tool tip"
 msgstr "工具提示"
 
-#: gtk/gtkaccessible.c:696
+#: gtk/gtkaccessible.c:863
 msgctxt "accessibility"
 msgid "tree"
 msgstr "樹狀"
 
-#: gtk/gtkaccessible.c:697
+#: gtk/gtkaccessible.c:864
 msgctxt "accessibility"
 msgid "tree grid"
 msgstr "樹狀網格"
 
-#: gtk/gtkaccessible.c:698
+#: gtk/gtkaccessible.c:865
 msgctxt "accessibility"
 msgid "tree item"
 msgstr "樹狀項目"
 
-#: gtk/gtkaccessible.c:699
+#: gtk/gtkaccessible.c:866
 msgctxt "accessibility"
 msgid "widget"
 msgstr "視窗元件"
 
-#: gtk/gtkaccessible.c:700
+#: gtk/gtkaccessible.c:867
 msgctxt "accessibility"
 msgid "window"
 msgstr "視窗"
 
-#: gtk/gtkalertdialog.c:668 gtk/gtkcustompaperunixdialog.c:328
+#: gtk/gtkaccessible.c:868
+msgctxt "accessibility"
+msgid "toggle button"
+msgstr "切換按鈕"
+
+#: gtk/gtkaccessible.c:870
+msgctxt "accessibility"
+msgid "paragraph"
+msgstr "段落"
+
+#: gtk/gtkaccessible.c:871
+msgctxt "accessibility"
+msgid "block quote"
+msgstr "區塊引用"
+
+#: gtk/gtkaccessible.c:872
+msgctxt "accessibility"
+msgid "article"
+msgstr "垂直"
+
+#: gtk/gtkaccessible.c:873
+msgctxt "accessibility"
+msgid "comment"
+msgstr "備註"
+
+#: gtk/gtkaccessible.c:874
+msgctxt "accessibility"
+msgid "terminal"
+msgstr "終端機"
+
+#: gtk/gtkalertdialog.c:667 gtk/print/gtkcustompaperunixdialog.c:322
 #: gtk/gtkmessagedialog.c:166 gtk/ui/gtkassistant.ui:40
 msgid "_Close"
 msgstr "關閉(_C)"
@@ -1719,10 +1787,14 @@ msgstr "關閉(_C)"
 #. * suspend or screen locking, and the caller hasn't specified
 #. * a reason.
 #.
-#: gtk/gtkapplication-dbus.c:706
+#: gtk/gtkapplication-dbus.c:724 gtk/gtkapplication-dbus.c:766
 msgid "Reason not specified"
 msgstr "沒有指定原因"
 
+#: gtk/gtkapplicationwindow.c:236
+msgid "Menu bar"
+msgstr "選單列"
+
 #: gtk/gtkbookmarksmanager.c:53
 #, c-format
 msgid "%s does not exist in the bookmarks list"
@@ -1752,7 +1824,7 @@ msgstr "文字可能不會出現在 <%s> 內"
 #. * first day of the week to calendar:week_start:1 if you want Monday
 #. * to be the first day of the week, and so on.
 #.
-#: gtk/gtkcalendar.c:656
+#: gtk/gtkcalendar.c:670
 msgid "calendar:week_start:0"
 msgstr "calendar:week_start:0"
 
@@ -1766,21 +1838,10 @@ msgstr "calendar:week_start:0"
 #. * text direction of RTL and specify "calendar:YM", then the year
 #. * will appear to the right of the month.
 #.
-#: gtk/gtkcalendar.c:807
+#: gtk/gtkcalendar.c:821
 msgid "calendar:MY"
 msgstr "calendar:YM"
 
-#. Translators: This dictates how the year is displayed in
-#. * gtkcalendar widget.  See strftime() manual for the format.
-#. * Use only ASCII in the translation.
-#. *
-#. * "%Y" is appropriate for most locales.
-#.
-#: gtk/gtkcalendar.c:1394
-msgctxt "calendar year format"
-msgid "%Y"
-msgstr "%Y"
-
 #. Translators: this defines whether the day numbers should use
 #. * localized digits or the ones used in English (0123...).
 #. *
@@ -1791,12 +1852,23 @@ msgstr "%Y"
 #. * digits. That needs support from your system and locale definition
 #. * too.
 #.
-#: gtk/gtkcalendar.c:1431
+#: gtk/gtkcalendar.c:1002
 #, c-format
 msgctxt "calendar:day:digits"
 msgid "%d"
 msgstr "%d"
 
+#. Translators: This dictates how the year is displayed in
+#. * gtkcalendar widget.  See strftime() manual for the format.
+#. * Use only ASCII in the translation.
+#. *
+#. * "%Y" is appropriate for most locales.
+#.
+#: gtk/gtkcalendar.c:1106
+msgctxt "calendar year format"
+msgid "%Y"
+msgstr "%Y"
+
 #. Translators: this defines whether the week numbers should use
 #. * localized digits or the ones used in English (0123...).
 #. *
@@ -1805,253 +1877,257 @@ msgstr "%d"
 #. * Note that translating this doesn't guarantee that you get localized
 #. * digits. That needs support from your system and locale definition
 #. * too.
-#: gtk/gtkcalendar.c:1496
+#: gtk/gtkcalendar.c:1152
 #, c-format
 msgctxt "calendar:week:digits"
 msgid "%d"
 msgstr "%d"
 
-#: gtk/gtkcolorchooserwidget.c:375
+#: gtk/gtkcolorchooserwidget.c:384 gtk/gtkcoloreditor.c:171
 #, c-format
 msgid "Color: %s"
 msgstr "色彩:%s"
 
-#: gtk/gtkcolorchooserwidget.c:440
+#: gtk/gtkcolorchooserwidget.c:449
 msgctxt "Color name"
 msgid "Very Light Blue"
 msgstr "極淡藍"
 
-#: gtk/gtkcolorchooserwidget.c:441
+#: gtk/gtkcolorchooserwidget.c:450
 msgctxt "Color name"
 msgid "Light Blue"
 msgstr "淡藍色"
 
-#: gtk/gtkcolorchooserwidget.c:442
+#: gtk/gtkcolorchooserwidget.c:451
 msgctxt "Color name"
 msgid "Blue"
 msgstr "藍色"
 
-#: gtk/gtkcolorchooserwidget.c:443
+#: gtk/gtkcolorchooserwidget.c:452
 msgctxt "Color name"
 msgid "Dark Blue"
 msgstr "深藍色"
 
-#: gtk/gtkcolorchooserwidget.c:444
+#: gtk/gtkcolorchooserwidget.c:453
 msgctxt "Color name"
 msgid "Very Dark Blue"
 msgstr "極深藍"
 
-#: gtk/gtkcolorchooserwidget.c:445
+#: gtk/gtkcolorchooserwidget.c:454
 msgctxt "Color name"
 msgid "Very Light Green"
 msgstr "極淡綠"
 
-#: gtk/gtkcolorchooserwidget.c:446
+#: gtk/gtkcolorchooserwidget.c:455
 msgctxt "Color name"
 msgid "Light Green"
 msgstr "淡綠色"
 
-#: gtk/gtkcolorchooserwidget.c:447
+#: gtk/gtkcolorchooserwidget.c:456
 msgctxt "Color name"
 msgid "Green"
 msgstr "綠色"
 
-#: gtk/gtkcolorchooserwidget.c:448
+#: gtk/gtkcolorchooserwidget.c:457
 msgctxt "Color name"
 msgid "Dark Green"
 msgstr "深綠色"
 
-#: gtk/gtkcolorchooserwidget.c:449
+#: gtk/gtkcolorchooserwidget.c:458
 msgctxt "Color name"
 msgid "Very Dark Green"
 msgstr "極深綠"
 
-#: gtk/gtkcolorchooserwidget.c:450
+#: gtk/gtkcolorchooserwidget.c:459
 msgctxt "Color name"
 msgid "Very Light Yellow"
 msgstr "極淡黃"
 
-#: gtk/gtkcolorchooserwidget.c:451
+#: gtk/gtkcolorchooserwidget.c:460
 msgctxt "Color name"
 msgid "Light Yellow"
 msgstr "淡黃色"
 
-#: gtk/gtkcolorchooserwidget.c:452
+#: gtk/gtkcolorchooserwidget.c:461
 msgctxt "Color name"
 msgid "Yellow"
 msgstr "黃色"
 
-#: gtk/gtkcolorchooserwidget.c:453
+#: gtk/gtkcolorchooserwidget.c:462
 msgctxt "Color name"
 msgid "Dark Yellow"
 msgstr "深黃色"
 
-#: gtk/gtkcolorchooserwidget.c:454
+#: gtk/gtkcolorchooserwidget.c:463
 msgctxt "Color name"
 msgid "Very Dark Yellow"
 msgstr "極深黃"
 
-#: gtk/gtkcolorchooserwidget.c:455
+#: gtk/gtkcolorchooserwidget.c:464
 msgctxt "Color name"
 msgid "Very Light Orange"
 msgstr "極淡橘"
 
-#: gtk/gtkcolorchooserwidget.c:456
+#: gtk/gtkcolorchooserwidget.c:465
 msgctxt "Color name"
 msgid "Light Orange"
 msgstr "淡橘色"
 
-#: gtk/gtkcolorchooserwidget.c:457
+#: gtk/gtkcolorchooserwidget.c:466
 msgctxt "Color name"
 msgid "Orange"
 msgstr "橘色"
 
-#: gtk/gtkcolorchooserwidget.c:458
+#: gtk/gtkcolorchooserwidget.c:467
 msgctxt "Color name"
 msgid "Dark Orange"
 msgstr "深橘色"
 
-#: gtk/gtkcolorchooserwidget.c:459
+#: gtk/gtkcolorchooserwidget.c:468
 msgctxt "Color name"
 msgid "Very Dark Orange"
 msgstr "極深橘"
 
-#: gtk/gtkcolorchooserwidget.c:460
+#: gtk/gtkcolorchooserwidget.c:469
 msgctxt "Color name"
 msgid "Very Light Red"
 msgstr "極淡紅"
 
-#: gtk/gtkcolorchooserwidget.c:461
+#: gtk/gtkcolorchooserwidget.c:470
 msgctxt "Color name"
 msgid "Light Red"
 msgstr "淡紅色"
 
-#: gtk/gtkcolorchooserwidget.c:462
+#: gtk/gtkcolorchooserwidget.c:471
 msgctxt "Color name"
 msgid "Red"
 msgstr "紅色"
 
-#: gtk/gtkcolorchooserwidget.c:463
+#: gtk/gtkcolorchooserwidget.c:472
 msgctxt "Color name"
 msgid "Dark Red"
 msgstr "深紅色"
 
-#: gtk/gtkcolorchooserwidget.c:464
+#: gtk/gtkcolorchooserwidget.c:473
 msgctxt "Color name"
 msgid "Very Dark Red"
 msgstr "極深紅"
 
-#: gtk/gtkcolorchooserwidget.c:465
+#: gtk/gtkcolorchooserwidget.c:474
 msgctxt "Color name"
 msgid "Very Light Purple"
 msgstr "極淡紫"
 
-#: gtk/gtkcolorchooserwidget.c:466
+#: gtk/gtkcolorchooserwidget.c:475
 msgctxt "Color name"
 msgid "Light Purple"
 msgstr "淡紫色"
 
-#: gtk/gtkcolorchooserwidget.c:467
+#: gtk/gtkcolorchooserwidget.c:476
 msgctxt "Color name"
 msgid "Purple"
 msgstr "紫色"
 
-#: gtk/gtkcolorchooserwidget.c:468
+#: gtk/gtkcolorchooserwidget.c:477
 msgctxt "Color name"
 msgid "Dark Purple"
 msgstr "深紫色"
 
-#: gtk/gtkcolorchooserwidget.c:469
+#: gtk/gtkcolorchooserwidget.c:478
 msgctxt "Color name"
 msgid "Very Dark Purple"
 msgstr "極深紫"
 
-#: gtk/gtkcolorchooserwidget.c:470
+#: gtk/gtkcolorchooserwidget.c:479
 msgctxt "Color name"
 msgid "Very Light Brown"
 msgstr "極淡棕"
 
-#: gtk/gtkcolorchooserwidget.c:471
+#: gtk/gtkcolorchooserwidget.c:480
 msgctxt "Color name"
 msgid "Light Brown"
 msgstr "淡棕色"
 
-#: gtk/gtkcolorchooserwidget.c:472
+#: gtk/gtkcolorchooserwidget.c:481
 msgctxt "Color name"
 msgid "Brown"
 msgstr "棕色"
 
-#: gtk/gtkcolorchooserwidget.c:473
+#: gtk/gtkcolorchooserwidget.c:482
 msgctxt "Color name"
 msgid "Dark Brown"
 msgstr "深棕色"
 
-#: gtk/gtkcolorchooserwidget.c:474
+#: gtk/gtkcolorchooserwidget.c:483
 msgctxt "Color name"
 msgid "Very Dark Brown"
 msgstr "極深棕"
 
-#: gtk/gtkcolorchooserwidget.c:475
+#: gtk/gtkcolorchooserwidget.c:484
 msgctxt "Color name"
 msgid "White"
 msgstr "白色"
 
-#: gtk/gtkcolorchooserwidget.c:476
+#: gtk/gtkcolorchooserwidget.c:485
 msgctxt "Color name"
 msgid "Light Gray 1"
 msgstr "淡灰色 1"
 
-#: gtk/gtkcolorchooserwidget.c:477
+#: gtk/gtkcolorchooserwidget.c:486
 msgctxt "Color name"
 msgid "Light Gray 2"
 msgstr "淡灰色 2"
 
-#: gtk/gtkcolorchooserwidget.c:478
+#: gtk/gtkcolorchooserwidget.c:487
 msgctxt "Color name"
 msgid "Light Gray 3"
 msgstr "淡灰色 3"
 
-#: gtk/gtkcolorchooserwidget.c:479
+#: gtk/gtkcolorchooserwidget.c:488
 msgctxt "Color name"
 msgid "Light Gray 4"
 msgstr "淡灰色 4"
 
-#: gtk/gtkcolorchooserwidget.c:480
+#: gtk/gtkcolorchooserwidget.c:489
 msgctxt "Color name"
 msgid "Dark Gray 1"
 msgstr "深灰色 1"
 
-#: gtk/gtkcolorchooserwidget.c:481
+#: gtk/gtkcolorchooserwidget.c:490
 msgctxt "Color name"
 msgid "Dark Gray 2"
 msgstr "深灰色 2"
 
-#: gtk/gtkcolorchooserwidget.c:482
+#: gtk/gtkcolorchooserwidget.c:491
 msgctxt "Color name"
 msgid "Dark Gray 3"
 msgstr "深灰色 3"
 
-#: gtk/gtkcolorchooserwidget.c:483
+#: gtk/gtkcolorchooserwidget.c:492
 msgctxt "Color name"
 msgid "Dark Gray 4"
 msgstr "深灰色 4"
 
-#: gtk/gtkcolorchooserwidget.c:484
+#: gtk/gtkcolorchooserwidget.c:493
 msgctxt "Color name"
 msgid "Black"
 msgstr "黑色"
 
 #. translators: label for the custom section in the color chooser
-#: gtk/gtkcolorchooserwidget.c:556
+#: gtk/gtkcolorchooserwidget.c:565
 msgid "Custom"
 msgstr "自訂"
 
-#: gtk/gtkcolorchooserwidget.c:589
+#: gtk/gtkcolorchooserwidget.c:579
+msgid "Add Color"
+msgstr "加入色彩"
+
+#: gtk/gtkcolorchooserwidget.c:601
 #, c-format
 msgid "Custom color %d: %s"
 msgstr "自訂色彩 %d:%s"
 
-#: gtk/gtkcolorswatch.c:231
+#: gtk/gtkcolorswatch.c:230
 msgid "Customize"
 msgstr "自訂"
 
@@ -2061,69 +2137,71 @@ msgstr "自訂"
 #. * Do *not* translate it to "predefinito:mm", if it
 #. * it isn't default:mm or default:inch it will not work
 #.
-#: gtk/gtkcustompaperunixdialog.c:112
+#: gtk/print/gtkcustompaperunixdialog.c:106
 msgid "default:mm"
 msgstr "default:mm"
 
-#: gtk/gtkcustompaperunixdialog.c:297
+#: gtk/print/gtkcustompaperunixdialog.c:291
 msgid "Margins from Printer…"
 msgstr "印表機邊界…"
 
 #. And show the custom paper dialog
-#: gtk/gtkcustompaperunixdialog.c:383 gtk/gtkprintunixdialog.c:3026
+#: gtk/print/gtkcustompaperunixdialog.c:377 gtk/print/gtkprintunixdialog.c:2976
 msgid "Manage Custom Sizes"
 msgstr "管理自訂大小"
 
-#: gtk/gtkcustompaperunixdialog.c:446 gtk/gtkpagesetupunixdialog.c:721
+#: gtk/print/gtkcustompaperunixdialog.c:440
+#: gtk/print/gtkpagesetupunixdialog.c:720
 msgid "inch"
 msgstr "英吋"
 
-#: gtk/gtkcustompaperunixdialog.c:448 gtk/gtkpagesetupunixdialog.c:719
+#: gtk/print/gtkcustompaperunixdialog.c:442
+#: gtk/print/gtkpagesetupunixdialog.c:718
 msgid "mm"
 msgstr "公釐"
 
-#: gtk/gtkcustompaperunixdialog.c:604
+#: gtk/print/gtkcustompaperunixdialog.c:598
 #, c-format
 msgid "Custom Size %d"
 msgstr "自訂大小 %d"
 
-#: gtk/gtkcustompaperunixdialog.c:914
+#: gtk/print/gtkcustompaperunixdialog.c:908
 msgid "_Width:"
 msgstr "寬度(_W):"
 
-#: gtk/gtkcustompaperunixdialog.c:923
+#: gtk/print/gtkcustompaperunixdialog.c:917
 msgid "_Height:"
 msgstr "高度(_H):"
 
-#: gtk/gtkcustompaperunixdialog.c:932
+#: gtk/print/gtkcustompaperunixdialog.c:926
 msgid "Paper Size"
 msgstr "紙張尺寸"
 
-#: gtk/gtkcustompaperunixdialog.c:939
+#: gtk/print/gtkcustompaperunixdialog.c:933
 msgid "_Top:"
 msgstr "上(_T):"
 
-#: gtk/gtkcustompaperunixdialog.c:948
+#: gtk/print/gtkcustompaperunixdialog.c:942
 msgid "_Bottom:"
 msgstr "下(_B):"
 
-#: gtk/gtkcustompaperunixdialog.c:957
+#: gtk/print/gtkcustompaperunixdialog.c:951
 msgid "_Left:"
 msgstr "左(_L):"
 
-#: gtk/gtkcustompaperunixdialog.c:966
+#: gtk/print/gtkcustompaperunixdialog.c:960
 msgid "_Right:"
 msgstr "右(_R):"
 
-#: gtk/gtkcustompaperunixdialog.c:999
+#: gtk/print/gtkcustompaperunixdialog.c:993
 msgid "Paper Margins"
 msgstr "紙張邊界"
 
-#: gtk/gtkentry.c:3672
+#: gtk/gtkentry.c:3685
 msgid "Insert Emoji"
 msgstr "插入繪文字"
 
-#: gtk/gtkfilechooserdialog.c:552
+#: gtk/gtkfilechooserdialog.c:557
 msgid "_Name"
 msgstr "名稱(_N)"
 
@@ -2184,28 +2262,28 @@ msgid "A file with that name already exists"
 msgstr "同樣名稱的檔案已經存在"
 
 #: gtk/gtkfilechoosernative.c:520 gtk/gtkfilechoosernative.c:600
-#: gtk/gtkfilechooserwidget.c:1168 gtk/gtkfilechooserwidget.c:5014
-#: gtk/gtkfiledialog.c:841 gtk/gtkmessagedialog.c:170
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:5018
+#: gtk/gtkfiledialog.c:840 gtk/gtkmessagedialog.c:170
 #: gtk/gtkmessagedialog.c:179 gtk/gtkmountoperation.c:608
-#: gtk/gtkpagesetupunixdialog.c:283 gtk/gtkprintbackend.c:638
-#: gtk/gtkprintunixdialog.c:657 gtk/gtkprintunixdialog.c:814
-#: gtk/gtkwindow.c:6155 gtk/ui/gtkappchooserdialog.ui:45
-#: gtk/ui/gtkassistant.ui:52 gtk/ui/gtkcolorchooserdialog.ui:33
-#: gtk/ui/gtkfontchooserdialog.ui:24
+#: gtk/print/gtkpagesetupunixdialog.c:282 gtk/print/gtkprintbackend.c:638
+#: gtk/print/gtkprintunixdialog.c:682 gtk/print/gtkprintunixdialog.c:839
+#: gtk/gtkwindow.c:6211 gtk/ui/gtkappchooserdialog.ui:48
+#: gtk/ui/gtkassistant.ui:52 gtk/ui/gtkcolorchooserdialog.ui:36
+#: gtk/ui/gtkfontchooserdialog.ui:29
 msgid "_Cancel"
 msgstr "取消(_C)"
 
 #: gtk/gtkfilechoosernative.c:521 gtk/gtkfilechoosernative.c:594
-#: gtk/gtkfiledialog.c:813 gtk/gtkplacessidebar.c:3145
-#: gtk/gtkplacessidebar.c:3230 gtk/gtkplacesview.c:1645
+#: gtk/gtkfiledialog.c:812 gtk/gtkplacessidebar.c:3149
+#: gtk/gtkplacessidebar.c:3234 gtk/gtkplacesview.c:1645
 msgid "_Open"
 msgstr "開啟(_O)"
 
-#: gtk/gtkfilechoosernative.c:594 gtk/gtkfiledialog.c:818
+#: gtk/gtkfilechoosernative.c:594 gtk/gtkfiledialog.c:817
 msgid "_Save"
 msgstr "儲存(_S)"
 
-#: gtk/gtkfilechoosernativequartz.c:340 gtk/ui/gtkfilechooserwidget.ui:546
+#: gtk/gtkfilechoosernativequartz.c:348 gtk/ui/gtkfilechooserwidget.ui:299
 msgid "Select which types of files are shown"
 msgstr "選取要顯示哪些種類的檔案"
 
@@ -2218,402 +2296,437 @@ msgstr "選取要顯示哪些種類的檔案"
 msgid "%1$s on %2$s"
 msgstr "%1$s æ–¼ %2$s"
 
-#: gtk/gtkfilechooserwidget.c:347
+#: gtk/gtkfilechooserwidget.c:365
 msgid "Type name of new folder"
 msgstr "請輸入新資料夾名稱"
 
-#: gtk/gtkfilechooserwidget.c:710
+#: gtk/gtkfilechooserwidget.c:752
 msgid "The folder could not be created"
 msgstr "無法建立資料夾"
 
-#: gtk/gtkfilechooserwidget.c:723
+#: gtk/gtkfilechooserwidget.c:765
 msgid "You need to choose a valid filename."
 msgstr "您需要選擇有效的檔案名稱。"
 
-#: gtk/gtkfilechooserwidget.c:726
+#: gtk/gtkfilechooserwidget.c:768
 #, c-format
 msgid "Cannot create a file under %s as it is not a folder"
 msgstr "不能在 %s 下建立檔案,因為它不是資料夾"
 
-#: gtk/gtkfilechooserwidget.c:736
+#: gtk/gtkfilechooserwidget.c:778
 msgid "Cannot create file as the filename is too long"
 msgstr "不能建立檔案,因為檔案名稱太長"
 
-#: gtk/gtkfilechooserwidget.c:737
+#: gtk/gtkfilechooserwidget.c:779
 msgid "Try using a shorter name."
 msgstr "試著使用較短的名稱。"
 
-#: gtk/gtkfilechooserwidget.c:747
+#: gtk/gtkfilechooserwidget.c:789
 msgid "You may only select folders"
 msgstr "您只能選取資料夾"
 
-#: gtk/gtkfilechooserwidget.c:748
+#: gtk/gtkfilechooserwidget.c:790
 msgid "The item that you selected is not a folder try using a different item."
 msgstr "您所選取的項目不是資料夾;請試著使用不同的項目。"
 
-#: gtk/gtkfilechooserwidget.c:756
+#: gtk/gtkfilechooserwidget.c:798
 msgid "Invalid file name"
 msgstr "無效的檔案名稱"
 
-#: gtk/gtkfilechooserwidget.c:765
+#: gtk/gtkfilechooserwidget.c:807
 msgid "The folder contents could not be displayed"
 msgstr "無法顯示資料夾內容"
 
-#: gtk/gtkfilechooserwidget.c:773
+#: gtk/gtkfilechooserwidget.c:815
 msgid "The file could not be deleted"
 msgstr "檔案無法被刪除"
 
-#: gtk/gtkfilechooserwidget.c:781
+#: gtk/gtkfilechooserwidget.c:823
 msgid "The file could not be moved to the Trash"
 msgstr "檔案無法丟進垃圾桶"
 
-#: gtk/gtkfilechooserwidget.c:1166
+#: gtk/gtkfilechooserwidget.c:1212
 #, c-format
 msgid "Are you sure you want to permanently delete “%s”?"
 msgstr "確定要永遠刪除「%s」嗎?"
 
-#: gtk/gtkfilechooserwidget.c:1167
+#: gtk/gtkfilechooserwidget.c:1213
 msgid "If you delete an item, it will be permanently lost."
 msgstr "如果刪除本項目,它會無法還原。"
 
-#: gtk/gtkfilechooserwidget.c:1168 gtk/gtkfilechooserwidget.c:1796
-#: gtk/gtklabel.c:5658 gtk/gtktext.c:6087 gtk/gtktextview.c:8994
+#: gtk/gtkfilechooserwidget.c:1214 gtk/gtkfilechooserwidget.c:1816
+#: gtk/gtklabel.c:5882 gtk/gtktext.c:6335 gtk/gtktextview.c:9237
 msgid "_Delete"
 msgstr "刪除(_D)"
 
-#: gtk/gtkfilechooserwidget.c:1281
+#: gtk/gtkfilechooserwidget.c:1331
 msgid "The file could not be renamed"
 msgstr "這個檔案無法重新命名"
 
-#: gtk/gtkfilechooserwidget.c:1487
+#: gtk/gtkfilechooserwidget.c:1507
 msgid "Could not select file"
 msgstr "無法選取檔案"
 
-#: gtk/gtkfilechooserwidget.c:1705 gtk/ui/gtkfilechooserwidget.ui:66
+#: gtk/gtkfilechooserwidget.c:1727 gtk/ui/gtkfilechooserwidget.ui:66
 msgid "Grid View"
 msgstr "圖示檢視"
 
-#: gtk/gtkfilechooserwidget.c:1711
+#: gtk/gtkfilechooserwidget.c:1733
 msgid "List View"
 msgstr "列表項目"
 
-#: gtk/gtkfilechooserwidget.c:1776
+#: gtk/gtkfilechooserwidget.c:1796
 msgid "_Visit File"
 msgstr "查閱檔案(_V)"
 
-#: gtk/gtkfilechooserwidget.c:1780
+#: gtk/gtkfilechooserwidget.c:1800
 msgid "_Open With File Manager"
 msgstr "以檔案管理員開啟(_O)"
 
-#: gtk/gtkfilechooserwidget.c:1784
+#: gtk/gtkfilechooserwidget.c:1804
 msgid "_Copy Location"
 msgstr "複製位置(_C)"
 
-#: gtk/gtkfilechooserwidget.c:1788
+#: gtk/gtkfilechooserwidget.c:1808
 msgid "_Add to Bookmarks"
 msgstr "加入書籤(_A)"
 
-#: gtk/gtkfilechooserwidget.c:1792 gtk/gtkplacessidebar.c:2309
-#: gtk/gtkplacessidebar.c:3266 gtk/ui/gtkfilechooserwidget.ui:665
+#: gtk/gtkfilechooserwidget.c:1812 gtk/gtkplacessidebar.c:2312
+#: gtk/gtkplacessidebar.c:3270 gtk/ui/gtkfilechooserwidget.ui:421
 msgid "_Rename"
 msgstr "重新命名(_R)"
 
-#: gtk/gtkfilechooserwidget.c:1800
+#: gtk/gtkfilechooserwidget.c:1820
 msgid "_Move to Trash"
 msgstr "丟進垃圾桶(_M)"
 
-#: gtk/gtkfilechooserwidget.c:1809
+#: gtk/gtkfilechooserwidget.c:1829
 msgid "Show _Hidden Files"
 msgstr "顯示隱藏檔(_H)"
 
-#: gtk/gtkfilechooserwidget.c:1813
-msgid "Show _Size Column"
-msgstr "顯示大小欄(_S)"
-
-#: gtk/gtkfilechooserwidget.c:1818
-msgid "Show T_ype Column"
-msgstr "顯示類型欄(_Y)"
-
-#: gtk/gtkfilechooserwidget.c:1823
-msgid "Show _Time"
-msgstr "顯示時間(_T)"
-
-#: gtk/gtkfilechooserwidget.c:1828
+#: gtk/gtkfilechooserwidget.c:1833
 msgid "Sort _Folders Before Files"
 msgstr "在檔案前列出資料夾(_F)"
 
-#: gtk/gtkfilechooserwidget.c:1962 gtk/gtkfilechooserwidget.c:1998
-#: gtk/gtkfilechooserwidget.c:3899
+#: gtk/gtkfilechooserwidget.c:1956 gtk/gtkfilechooserwidget.c:1986
+#: gtk/gtkfilechooserwidget.c:3891
 msgid "Unknown"
 msgstr "未知"
 
-#: gtk/gtkfilechooserwidget.c:2056 gtk/gtkplacessidebar.c:1026
+#: gtk/gtkfilechooserwidget.c:2041 gtk/gtkplacessidebar.c:1025
 msgid "Home"
 msgstr "家目錄"
 
 #. this is the header for the location column in the print dialog
-#: gtk/gtkfilechooserwidget.c:2223 gtk/inspector/css-node-tree.ui:76
-#: gtk/ui/gtkfilechooserwidget.ui:238 gtk/ui/gtkprintunixdialog.ui:114
+#: gtk/gtkfilechooserwidget.c:2196 gtk/gtkfilechooserwidget.c:7446
+#: gtk/inspector/css-node-tree.ui:76 gtk/print/ui/gtkprintunixdialog.ui:111
 msgid "Location"
 msgstr "位置"
 
 #. Label
-#: gtk/gtkfilechooserwidget.c:2330
+#: gtk/gtkfilechooserwidget.c:2303
 msgid "_Name:"
 msgstr "名稱(_N):"
 
-#: gtk/gtkfilechooserwidget.c:2870 gtk/gtkfilechooserwidget.c:2884
+#: gtk/gtkfilechooserwidget.c:2860 gtk/gtkfilechooserwidget.c:2874
 #, c-format
 msgid "Searching in %s"
 msgstr "在 %s 中搜尋"
 
-#: gtk/gtkfilechooserwidget.c:2890
+#: gtk/gtkfilechooserwidget.c:2880
 msgid "Searching"
 msgstr "正在搜尋"
 
-#: gtk/gtkfilechooserwidget.c:2896
+#: gtk/gtkfilechooserwidget.c:2886
 msgid "Enter location or URL"
 msgstr "輸入位置或 URL"
 
-#: gtk/gtkfilechooserwidget.c:3462 gtk/gtkfilechooserwidget.c:5799
-#: gtk/ui/gtkfilechooserwidget.ui:383
+#: gtk/gtkfilechooserwidget.c:3445 gtk/gtkfilechooserwidget.c:5805
+#: gtk/gtkfilechooserwidget.c:7468
 msgid "Modified"
 msgstr "修改時間"
 
-#: gtk/gtkfilechooserwidget.c:3643
+#: gtk/gtkfilechooserwidget.c:3630
 #, c-format
 msgid "Could not read the contents of %s"
 msgstr "無法讀取 %s 的內容"
 
-#: gtk/gtkfilechooserwidget.c:3647
+#: gtk/gtkfilechooserwidget.c:3634
 msgid "Could not read the contents of the folder"
 msgstr "無法讀取資料夾的內容"
 
 #. Translators: see g_date_time_format() for details on the format
-#: gtk/gtkfilechooserwidget.c:3794 gtk/gtkfilechooserwidget.c:3837
+#: gtk/gtkfilechooserwidget.c:3785 gtk/gtkfilechooserwidget.c:3829
 msgid "%H:%M"
 msgstr "%H:%M"
 
-#: gtk/gtkfilechooserwidget.c:3796 gtk/gtkfilechooserwidget.c:3839
+#: gtk/gtkfilechooserwidget.c:3787 gtk/gtkfilechooserwidget.c:3831
 msgid "%l:%M %p"
 msgstr "%p %I:%M"
 
-#: gtk/gtkfilechooserwidget.c:3800
+#: gtk/gtkfilechooserwidget.c:3791
 msgid "Yesterday"
 msgstr "昨天"
 
-#: gtk/gtkfilechooserwidget.c:3808
+#: gtk/gtkfilechooserwidget.c:3800
+#, no-c-format
 msgid "%-e %b"
 msgstr "%-m月%-e日"
 
-#: gtk/gtkfilechooserwidget.c:3812
+#: gtk/gtkfilechooserwidget.c:3804
 msgid "%-e %b %Y"
 msgstr "%Y年%-m月%-e日"
 
-#: gtk/gtkfilechooserwidget.c:3854 gtk/gtkfilechooserwidget.c:3862
+#: gtk/gtkfilechooserwidget.c:3846 gtk/gtkfilechooserwidget.c:3854
 msgid "Program"
 msgstr "程式"
 
-#: gtk/gtkfilechooserwidget.c:3855
+#: gtk/gtkfilechooserwidget.c:3847
 msgid "Audio"
 msgstr "音訊"
 
-#: gtk/gtkfilechooserwidget.c:3857
+#: gtk/gtkfilechooserwidget.c:3849 gtk/gtkfilefilter.c:1013
 msgid "Image"
 msgstr "影像"
 
-#: gtk/gtkfilechooserwidget.c:3858
+#: gtk/gtkfilechooserwidget.c:3850
 msgid "Archive"
 msgstr "壓縮檔"
 
-#: gtk/gtkfilechooserwidget.c:3859
+#: gtk/gtkfilechooserwidget.c:3851
 msgid "Markup"
 msgstr "標記語言"
 
-#: gtk/gtkfilechooserwidget.c:3860 gtk/gtkfilechooserwidget.c:3861
+#: gtk/gtkfilechooserwidget.c:3852 gtk/gtkfilechooserwidget.c:3853
 msgid "Text"
 msgstr "文字檔"
 
-#: gtk/gtkfilechooserwidget.c:3863
+#: gtk/gtkfilechooserwidget.c:3855
 msgid "Video"
 msgstr "視訊"
 
-#: gtk/gtkfilechooserwidget.c:3864
+#: gtk/gtkfilechooserwidget.c:3856
 msgid "Contacts"
 msgstr "聯絡人"
 
-#: gtk/gtkfilechooserwidget.c:3865
+#: gtk/gtkfilechooserwidget.c:3857
 msgid "Calendar"
 msgstr "行事曆"
 
-#: gtk/gtkfilechooserwidget.c:3866
+#: gtk/gtkfilechooserwidget.c:3858
 msgid "Document"
 msgstr "文件"
 
-#: gtk/gtkfilechooserwidget.c:3867
+#: gtk/gtkfilechooserwidget.c:3859
 msgid "Presentation"
 msgstr "ç°¡å ±"
 
-#: gtk/gtkfilechooserwidget.c:3868
+#: gtk/gtkfilechooserwidget.c:3860
 msgid "Spreadsheet"
 msgstr "試算表"
 
-#: gtk/gtkfilechooserwidget.c:5006 gtk/gtkprintunixdialog.c:648
+#: gtk/gtkfilechooserwidget.c:5010 gtk/print/gtkprintunixdialog.c:673
 #, c-format
 msgid "A file named “%s” already exists.  Do you want to replace it?"
 msgstr "已存在名為「%s」的檔案。您想要取代它嗎?"
 
-#: gtk/gtkfilechooserwidget.c:5008 gtk/gtkprintunixdialog.c:652
+#: gtk/gtkfilechooserwidget.c:5012 gtk/print/gtkprintunixdialog.c:677
 #, c-format
 msgid ""
 "The file already exists in “%s”.  Replacing it will overwrite its contents."
 msgstr "該檔案已存在於「%s」。取代它會覆蓋它的內容。"
 
-#: gtk/gtkfilechooserwidget.c:5014 gtk/gtkprintunixdialog.c:660
+#: gtk/gtkfilechooserwidget.c:5018 gtk/print/gtkprintunixdialog.c:685
 msgid "_Replace"
 msgstr "取代(_R)"
 
-#: gtk/gtkfilechooserwidget.c:5169
+#: gtk/gtkfilechooserwidget.c:5173
 msgid "You do not have access to the specified folder."
 msgstr "您沒有指定資料夾的取用權。"
 
-#: gtk/gtkfilechooserwidget.c:5746
+#: gtk/gtkfilechooserwidget.c:5752
 msgid "Could not send the search request"
 msgstr "無法傳送搜尋請求"
 
-#: gtk/gtkfilechooserwidget.c:6022
+#: gtk/gtkfilechooserwidget.c:6033
 msgid "Accessed"
 msgstr "存取時間"
 
-#: gtk/gtkfiledialog.c:814
+#: gtk/gtkfilechooserwidget.c:7424
+msgid "_Size"
+msgstr "大小(_S)"
+
+#: gtk/gtkfilechooserwidget.c:7428
+msgid "T_ype"
+msgstr "類型(_Y)"
+
+#: gtk/gtkfilechooserwidget.c:7432
+msgid "_Time"
+msgstr "時間(_T)"
+
+#: gtk/gtkfilechooserwidget.c:7438 gtk/gtkplacessidebar.c:2306
+#: gtk/inspector/a11y.ui:43 gtk/inspector/actions.ui:18
+#: gtk/inspector/css-node-tree.ui:22 gtk/inspector/prop-list.ui:24
+#: gtk/ui/gtkfilechooserwidget.ui:396 gtk/print/ui/gtkprintunixdialog.ui:80
+msgid "Name"
+msgstr "名稱"
+
+#: gtk/gtkfilechooserwidget.c:7455 gtk/inspector/resource-list.ui:82
+#: gtk/ui/gtkfontchooserwidget.ui:216 gtk/ui/gtkfontchooserwidget.ui:385
+msgid "Size"
+msgstr "大小"
+
+#: gtk/gtkfilechooserwidget.c:7461 gtk/inspector/misc-info.ui:57
+#: gtk/inspector/prop-list.ui:35 gtk/inspector/statistics.ui:36
+msgid "Type"
+msgstr "類型"
+
+#: gtk/gtkfiledialog.c:813
 msgid "Pick Files"
 msgstr "挑選檔案"
 
-#: gtk/gtkfiledialog.c:814
+#: gtk/gtkfiledialog.c:813
 msgid "Pick a File"
 msgstr "挑選一個檔案"
 
-#: gtk/gtkfiledialog.c:819
+#: gtk/gtkfiledialog.c:818
 msgid "Save a File"
 msgstr "儲存一個檔案"
 
-#: gtk/gtkfiledialog.c:823 gtk/ui/gtkappchooserdialog.ui:50
-#: gtk/ui/gtkcolorchooserdialog.ui:38 gtk/ui/gtkfontchooserdialog.ui:29
+#: gtk/gtkfiledialog.c:822 gtk/ui/gtkappchooserdialog.ui:53
+#: gtk/ui/gtkcolorchooserdialog.ui:41 gtk/ui/gtkfontchooserdialog.ui:34
 msgid "_Select"
 msgstr "選取(_S)"
 
-#: gtk/gtkfiledialog.c:824
+#: gtk/gtkfiledialog.c:823
 msgid "Select Folders"
 msgstr "選取資料夾"
 
-#: gtk/gtkfiledialog.c:824
+#: gtk/gtkfiledialog.c:823
 msgid "Select a Folder"
 msgstr "選取一個資料夾"
 
-#: gtk/gtkfontchooserdialog.c:187
+#: gtk/gtkfilefilter.c:1026
+msgid "Unspecified"
+msgstr "未指定"
+
+#: gtk/gtkfontchooserdialog.c:192 gtk/gtkfontchooserdialog.c:195
 msgid "Change Font Features"
 msgstr "更改字型特徵"
 
-#: gtk/gtkfontchooserwidget.c:1546
+#: gtk/gtkfontchooserwidget.c:1491
 msgctxt "Font variation axis"
 msgid "Width"
 msgstr "寬度"
 
-#: gtk/gtkfontchooserwidget.c:1547
+#: gtk/gtkfontchooserwidget.c:1492
 msgctxt "Font variation axis"
 msgid "Weight"
 msgstr "字重"
 
-#: gtk/gtkfontchooserwidget.c:1548
+#: gtk/gtkfontchooserwidget.c:1493
 msgctxt "Font variation axis"
 msgid "Italic"
 msgstr "義式斜體"
 
-#: gtk/gtkfontchooserwidget.c:1549
+#: gtk/gtkfontchooserwidget.c:1494
 msgctxt "Font variation axis"
 msgid "Slant"
 msgstr "斜體"
 
-#: gtk/gtkfontchooserwidget.c:1550
+#: gtk/gtkfontchooserwidget.c:1495
 msgctxt "Font variation axis"
 msgid "Optical Size"
 msgstr "最適大小"
 
-#: gtk/gtkfontchooserwidget.c:2102
+#: gtk/gtkfontchooserwidget.c:2053
 msgctxt "Font feature value"
 msgid "Default"
 msgstr "預設"
 
-#: gtk/gtkfontchooserwidget.c:2119
+#: gtk/gtkfontchooserwidget.c:2070
 msgctxt "Font feature value"
 msgid "Enable"
 msgstr "啟用"
 
-#: gtk/gtkfontchooserwidget.c:2447
+#: gtk/gtkfontchooserwidget.c:2404
 msgid "Default"
 msgstr "預設值"
 
-#: gtk/gtkfontchooserwidget.c:2509
+#: gtk/gtkfontchooserwidget.c:2466
 msgid "Ligatures"
 msgstr "連字"
 
-#: gtk/gtkfontchooserwidget.c:2510
+#: gtk/gtkfontchooserwidget.c:2467
 msgid "Letter Case"
 msgstr "字母大小寫"
 
-#: gtk/gtkfontchooserwidget.c:2511
+#: gtk/gtkfontchooserwidget.c:2468
 msgid "Number Case"
 msgstr "數字大小寫"
 
-#: gtk/gtkfontchooserwidget.c:2512
+#: gtk/gtkfontchooserwidget.c:2469
 msgid "Number Spacing"
 msgstr "數字間隔"
 
-#: gtk/gtkfontchooserwidget.c:2513
+#: gtk/gtkfontchooserwidget.c:2470
 msgid "Fractions"
 msgstr "小數點"
 
-#: gtk/gtkfontchooserwidget.c:2514
+#: gtk/gtkfontchooserwidget.c:2471
 msgid "Style Variations"
 msgstr "樣式變體"
 
-#: gtk/gtkfontchooserwidget.c:2516
+#: gtk/gtkfontchooserwidget.c:2473
 msgid "Character Variations"
 msgstr "字元變體"
 
-#: gtk/gtkglarea.c:286
+#: gtk/gtkglarea.c:316
 msgid "OpenGL context creation failed"
 msgstr "OpenGL 脈絡建立失敗"
 
-#: gtk/gtklabel.c:5655 gtk/gtktext.c:6075 gtk/gtktextview.c:8982
+#: gtk/deprecated/gtkinfobar.c:498 gtk/gtkwindowcontrols.c:357
+#: gtk/gtkwindowhandle.c:250
+msgid "Close"
+msgstr "關閉"
+
+#: gtk/deprecated/gtkinfobar.c:499
+msgid "Close the infobar"
+msgstr "關閉資訊列"
+
+#: gtk/gtklabel.c:5879 gtk/gtktext.c:6323 gtk/gtktextview.c:9225
 msgid "Cu_t"
 msgstr "剪下(_T)"
 
-#: gtk/gtklabel.c:5656 gtk/gtktext.c:6079 gtk/gtktextview.c:8986
+#: gtk/gtklabel.c:5880 gtk/gtktext.c:6327 gtk/gtktextview.c:9229
 msgid "_Copy"
 msgstr "複製(_C)"
 
-#: gtk/gtklabel.c:5657 gtk/gtktext.c:6083 gtk/gtktextview.c:8990
+#: gtk/gtklabel.c:5881 gtk/gtktext.c:6331 gtk/gtktextview.c:9233
 msgid "_Paste"
 msgstr "貼上(_P)"
 
-#: gtk/gtklabel.c:5663 gtk/gtktext.c:6096 gtk/gtktextview.c:9015
+#: gtk/gtklabel.c:5887 gtk/gtktext.c:6344 gtk/gtktextview.c:9258
 msgid "Select _All"
 msgstr "全選(_A)"
 
-#: gtk/gtklabel.c:5668
+#: gtk/gtklabel.c:5892
 msgid "_Open Link"
 msgstr "開啟連結(_O)"
 
-#: gtk/gtklabel.c:5672
+#: gtk/gtklabel.c:5896
 msgid "Copy _Link Address"
 msgstr "複製連結位址(_L)"
 
-#: gtk/gtklinkbutton.c:255
+#: gtk/gtklabel.c:5940 gtk/gtktext.c:2851 gtk/gtktextview.c:9307
+msgid "Context menu"
+msgstr "情境選單"
+
+#: gtk/gtklinkbutton.c:273
 msgid "_Copy URL"
 msgstr "複製 URL(_C)"
 
-#: gtk/gtklinkbutton.c:544
+#: gtk/gtklinkbutton.c:602
 msgid "Invalid URI"
 msgstr "無效的 URI"
 
@@ -2665,8 +2778,18 @@ msgctxt "short time format"
 msgid "%d:%02d"
 msgstr "%d:%02d"
 
+#: gtk/gtkmediacontrols.c:412
+msgctxt "media controls tooltip"
+msgid "Stop"
+msgstr "停止"
+
+#: gtk/gtkmediacontrols.c:417 gtk/ui/gtkmediacontrols.ui:28
+msgctxt "media controls tooltip"
+msgid "Play"
+msgstr "播放"
+
 #: gtk/gtkmessagedialog.c:162 gtk/gtkmessagedialog.c:180
-#: gtk/gtkprintbackend.c:639 gtk/gtkwindow.c:6156
+#: gtk/print/gtkprintbackend.c:639 gtk/gtkwindow.c:6212
 msgid "_OK"
 msgstr "確定(_O)"
 
@@ -2759,27 +2882,27 @@ msgid "Cannot kill process with PID %d. Operation is not implemented."
 msgstr "不能終結 PID 為 %d 的程序。此操作尚未實作。"
 
 #. translators: this string is a name for the 'less' command
-#: gtk/gtkmountoperation-x11.c:987
+#: gtk/gtkmountoperation-x11.c:986
 msgid "Terminal Pager"
 msgstr "終端機換頁器"
 
-#: gtk/gtkmountoperation-x11.c:988
+#: gtk/gtkmountoperation-x11.c:987
 msgid "Top Command"
 msgstr "Top 指令"
 
-#: gtk/gtkmountoperation-x11.c:989
+#: gtk/gtkmountoperation-x11.c:988
 msgid "Bourne Again Shell"
 msgstr "Bourne Again Shell"
 
-#: gtk/gtkmountoperation-x11.c:990
+#: gtk/gtkmountoperation-x11.c:989
 msgid "Bourne Shell"
 msgstr "Bourne Shell"
 
-#: gtk/gtkmountoperation-x11.c:991
+#: gtk/gtkmountoperation-x11.c:990
 msgid "Z Shell"
 msgstr "Z Shell"
 
-#: gtk/gtkmountoperation-x11.c:1091
+#: gtk/gtkmountoperation-x11.c:1090
 #, c-format
 msgid "Cannot end process with PID %d: %s"
 msgstr "不能結束 PID 為 %d 的程序:%s"
@@ -2788,48 +2911,42 @@ msgstr "不能結束 PID 為 %d 的程序:%s"
 msgid "GTK could not find a media module. Check your installation."
 msgstr "GTK 找不到媒體模組。請檢查安裝是否完整。"
 
-#: gtk/gtknotebook.c:1490
-msgid "Tab list"
-msgstr "分頁列表"
-
-#: gtk/gtknotebook.c:3213
+#: gtk/gtknotebook.c:3304
 msgid "Previous tab"
 msgstr "上個分頁"
 
-#: gtk/gtknotebook.c:3217
+#: gtk/gtknotebook.c:3308
 msgid "Next tab"
 msgstr "下個分頁"
 
-#: gtk/gtknotebook.c:4037
-msgid "Tab"
-msgstr "分頁"
-
-#: gtk/gtknotebook.c:4333 gtk/gtknotebook.c:6539
+#: gtk/gtknotebook.c:4424 gtk/gtknotebook.c:6634
 #, c-format
 msgid "Page %u"
 msgstr "第 %u 頁"
 
-#: gtk/gtkpagesetup.c:609 gtk/gtkpapersize.c:942 gtk/gtkpapersize.c:982
+#: gtk/print/gtkpagesetup.c:611 gtk/print/gtkpapersize.c:942
+#: gtk/print/gtkpapersize.c:982
 msgid "Not a valid page setup file"
 msgstr "不是有效的頁面配置檔案"
 
-#: gtk/gtkpagesetupunixdialog.c:199 gtk/gtkprintunixdialog.c:743
+#: gtk/print/gtkpagesetupunixdialog.c:198 gtk/print/gtkprintunixdialog.c:768
 msgid "Manage Custom Sizes…"
 msgstr "管理自訂大小…"
 
-#: gtk/gtkpagesetupunixdialog.c:284 gtk/ui/gtkassistant.ui:98
+#: gtk/print/gtkpagesetupunixdialog.c:283 gtk/ui/gtkassistant.ui:98
 msgid "_Apply"
 msgstr "套用(_A)"
 
-#: gtk/gtkpagesetupunixdialog.c:319 gtk/gtkpagesetupunixdialog.c:571
+#: gtk/print/gtkpagesetupunixdialog.c:318
+#: gtk/print/gtkpagesetupunixdialog.c:570
 msgid "Any Printer"
 msgstr "任何印表機"
 
-#: gtk/gtkpagesetupunixdialog.c:320
+#: gtk/print/gtkpagesetupunixdialog.c:319
 msgid "For portable documents"
 msgstr "用於可攜式文件"
 
-#: gtk/gtkpagesetupunixdialog.c:739
+#: gtk/print/gtkpagesetupunixdialog.c:738
 #, c-format
 msgid ""
 "Margins:\n"
@@ -2844,104 +2961,105 @@ msgstr ""
 " 上:%s %s\n"
 " 下:%s %s"
 
-#: gtk/gtkpagesetupunixdialog.c:785 gtk/ui/gtkpagesetupunixdialog.ui:5
-#: gtk/ui/gtkprintunixdialog.ui:709
+#: gtk/print/gtkpagesetupunixdialog.c:784
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:5
+#: gtk/print/ui/gtkprintunixdialog.ui:782
 msgid "Page Setup"
 msgstr "頁面配置"
 
-#: gtk/gtkpasswordentry.c:170
+#: gtk/gtkpasswordentry.c:168
 msgid "Hide Text"
 msgstr "隱藏文字"
 
-#: gtk/gtkpasswordentry.c:175 gtk/gtkpasswordentry.c:619
+#: gtk/gtkpasswordentry.c:173 gtk/gtkpasswordentry.c:624
 msgid "Show Text"
 msgstr "顯示文字"
 
-#: gtk/gtkpasswordentry.c:214
+#: gtk/gtkpasswordentry.c:215
 msgid "Caps Lock is on"
 msgstr "Caps Lock 已開啟"
 
-#: gtk/gtkpasswordentry.c:695
+#: gtk/gtkpasswordentry.c:700
 msgid "_Show Text"
 msgstr "顯示文字(_S)"
 
 #. translators: %s is the name of a cloud provider for files
-#: gtk/gtkplacessidebar.c:913
+#: gtk/gtkplacessidebar.c:912
 #, c-format
 msgid "Open %s"
 msgstr "開啟 %s"
 
-#: gtk/gtkplacessidebar.c:1004
+#: gtk/gtkplacessidebar.c:1003
 msgid "Recent"
 msgstr "最近"
 
-#: gtk/gtkplacessidebar.c:1006
+#: gtk/gtkplacessidebar.c:1005
 msgid "Recent files"
 msgstr "最近的檔案"
 
-#: gtk/gtkplacessidebar.c:1015
+#: gtk/gtkplacessidebar.c:1014
 msgid "Starred"
 msgstr "星標"
 
-#: gtk/gtkplacessidebar.c:1017
+#: gtk/gtkplacessidebar.c:1016
 msgid "Starred files"
 msgstr "加上星標的檔案"
 
-#: gtk/gtkplacessidebar.c:1028
+#: gtk/gtkplacessidebar.c:1027
 msgid "Open your personal folder"
 msgstr "開啟您的個人資料夾"
 
-#: gtk/gtkplacessidebar.c:1041
+#: gtk/gtkplacessidebar.c:1040
 msgid "Desktop"
 msgstr "桌面"
 
-#: gtk/gtkplacessidebar.c:1043
+#: gtk/gtkplacessidebar.c:1042
 msgid "Open the contents of your desktop in a folder"
 msgstr "以資料夾形式開啟桌面中的內容"
 
-#: gtk/gtkplacessidebar.c:1057
+#: gtk/gtkplacessidebar.c:1056
 msgid "Enter Location"
 msgstr "輸入位置"
 
-#: gtk/gtkplacessidebar.c:1059
+#: gtk/gtkplacessidebar.c:1058
 msgid "Manually enter a location"
 msgstr "手動輸入位置"
 
-#: gtk/gtkplacessidebar.c:1069
+#: gtk/gtkplacessidebar.c:1068
 msgid "Trash"
 msgstr "垃圾桶"
 
-#: gtk/gtkplacessidebar.c:1071
+#: gtk/gtkplacessidebar.c:1070
 msgid "Open the trash"
 msgstr "開啟垃圾桶"
 
-#: gtk/gtkplacessidebar.c:1182 gtk/gtkplacessidebar.c:1210
-#: gtk/gtkplacessidebar.c:1410
+#: gtk/gtkplacessidebar.c:1181 gtk/gtkplacessidebar.c:1209
+#: gtk/gtkplacessidebar.c:1409
 #, c-format
 msgid "Mount and open “%s”"
 msgstr "掛載並開啟「%s」"
 
-#: gtk/gtkplacessidebar.c:1305
+#: gtk/gtkplacessidebar.c:1304
 msgid "Open the contents of the file system"
 msgstr "開啟檔案系統的內容"
 
-#: gtk/gtkplacessidebar.c:1388
+#: gtk/gtkplacessidebar.c:1387
 msgid "New bookmark"
 msgstr "新書籤"
 
-#: gtk/gtkplacessidebar.c:1390
+#: gtk/gtkplacessidebar.c:1389
 msgid "Add a new bookmark"
 msgstr "新增書籤"
 
-#: gtk/gtkplacessidebar.c:1455
+#: gtk/gtkplacessidebar.c:1454
 msgid "Other Locations"
 msgstr "其他位置"
 
-#: gtk/gtkplacessidebar.c:1456
+#: gtk/gtkplacessidebar.c:1455
 msgid "Show other locations"
 msgstr "顯示其他位置"
 
-#: gtk/gtkplacessidebar.c:1961 gtk/gtkplacessidebar.c:2980
+#: gtk/gtkplacessidebar.c:1964 gtk/gtkplacessidebar.c:2984
 #, c-format
 msgid "Unable to start “%s”"
 msgstr "無法啟動 「%s」"
@@ -2949,127 +3067,120 @@ msgstr "無法啟動 「%s」"
 #. Translators: This means that unlocking an encrypted storage
 #. * device failed. %s is the name of the device.
 #.
-#: gtk/gtkplacessidebar.c:1997
+#: gtk/gtkplacessidebar.c:2000
 #, c-format
 msgid "Error unlocking “%s”"
 msgstr "解鎖「%s」時發生錯誤"
 
-#: gtk/gtkplacessidebar.c:1999
+#: gtk/gtkplacessidebar.c:2002
 #, c-format
 msgid "Unable to access “%s”"
 msgstr "無法存取「%s」"
 
-#: gtk/gtkplacessidebar.c:2230
+#: gtk/gtkplacessidebar.c:2233
 msgid "This name is already taken"
 msgstr "這個名稱已被使用"
 
-#: gtk/gtkplacessidebar.c:2303 gtk/inspector/actions.ui:19
-#: gtk/inspector/css-node-tree.ui:22 gtk/inspector/prop-list.ui:24
-#: gtk/ui/gtkfilechooserwidget.ui:176 gtk/ui/gtkfilechooserwidget.ui:640
-#: gtk/ui/gtkprintunixdialog.ui:83
-msgid "Name"
-msgstr "名稱"
-
-#: gtk/gtkplacessidebar.c:2521
+#: gtk/gtkplacessidebar.c:2525
 #, c-format
 msgid "Unable to unmount “%s”"
 msgstr "無法卸載 %s"
 
-#: gtk/gtkplacessidebar.c:2697
+#: gtk/gtkplacessidebar.c:2701
 #, c-format
 msgid "Unable to stop “%s”"
 msgstr "無法關閉「%s」"
 
-#: gtk/gtkplacessidebar.c:2726
+#: gtk/gtkplacessidebar.c:2730
 #, c-format
 msgid "Unable to eject “%s”"
 msgstr "無法退出 「%s」"
 
-#: gtk/gtkplacessidebar.c:2755 gtk/gtkplacessidebar.c:2784
+#: gtk/gtkplacessidebar.c:2759 gtk/gtkplacessidebar.c:2788
 #, c-format
 msgid "Unable to eject %s"
 msgstr "無法退出 %s"
 
-#: gtk/gtkplacessidebar.c:2932
+#: gtk/gtkplacessidebar.c:2936
 #, c-format
 msgid "Unable to poll “%s” for media changes"
 msgstr "無法監測「%s」的媒體變更"
 
-#: gtk/gtkplacessidebar.c:3151 gtk/gtkplacessidebar.c:3238
+#: gtk/gtkplacessidebar.c:3155 gtk/gtkplacessidebar.c:3242
 #: gtk/gtkplacesview.c:1649
 msgid "Open in New _Tab"
 msgstr "在新分頁中開啟(_T)"
 
-#: gtk/gtkplacessidebar.c:3157 gtk/gtkplacessidebar.c:3247
+#: gtk/gtkplacessidebar.c:3161 gtk/gtkplacessidebar.c:3251
 #: gtk/gtkplacesview.c:1654
 msgid "Open in New _Window"
 msgstr "在新視窗中開啟(_W)"
 
-#: gtk/gtkplacessidebar.c:3258
+#: gtk/gtkplacessidebar.c:3262
 msgid "_Add Bookmark"
 msgstr "加入書籤(_A)"
 
-#: gtk/gtkplacessidebar.c:3262
+#: gtk/gtkplacessidebar.c:3266
 msgid "_Remove"
 msgstr "移除(_R)"
 
-#: gtk/gtkplacessidebar.c:3278 gtk/gtkplacesview.c:1679
+#: gtk/gtkplacessidebar.c:3282 gtk/gtkplacesview.c:1679
 msgid "_Mount"
 msgstr "掛載(_M)"
 
-#: gtk/gtkplacessidebar.c:3287 gtk/gtkplacesview.c:1668
+#: gtk/gtkplacessidebar.c:3291 gtk/gtkplacesview.c:1668
 msgid "_Unmount"
 msgstr "卸載(_U)"
 
-#: gtk/gtkplacessidebar.c:3294
+#: gtk/gtkplacessidebar.c:3298
 msgid "_Eject"
 msgstr "退出(_E)"
 
-#: gtk/gtkplacessidebar.c:3304
+#: gtk/gtkplacessidebar.c:3308
 msgid "_Detect Media"
 msgstr "偵測媒體(_D)"
 
-#: gtk/gtkplacessidebar.c:3313
+#: gtk/gtkplacessidebar.c:3317
 msgid "_Start"
 msgstr "啟動(_S)"
 
-#: gtk/gtkplacessidebar.c:3315
+#: gtk/gtkplacessidebar.c:3319
 msgid "_Power On"
 msgstr "開啟電源(_P)"
 
-#: gtk/gtkplacessidebar.c:3316
+#: gtk/gtkplacessidebar.c:3320
 msgid "_Connect Drive"
 msgstr "連接裝置(_C)"
 
-#: gtk/gtkplacessidebar.c:3317
+#: gtk/gtkplacessidebar.c:3321
 msgid "_Start Multi-disk Device"
 msgstr "啟動多磁碟裝置(_S)"
 
-#: gtk/gtkplacessidebar.c:3318
+#: gtk/gtkplacessidebar.c:3322
 msgid "_Unlock Device"
 msgstr "解鎖裝置(_U)"
 
-#: gtk/gtkplacessidebar.c:3328
+#: gtk/gtkplacessidebar.c:3332
 msgid "_Stop"
 msgstr "關閉(_S)"
 
-#: gtk/gtkplacessidebar.c:3330
+#: gtk/gtkplacessidebar.c:3334
 msgid "_Safely Remove Drive"
 msgstr "安全地移除裝置(_S)"
 
-#: gtk/gtkplacessidebar.c:3331
+#: gtk/gtkplacessidebar.c:3335
 msgid "_Disconnect Drive"
 msgstr "中斷裝置連接(_D)"
 
-#: gtk/gtkplacessidebar.c:3332
+#: gtk/gtkplacessidebar.c:3336
 msgid "_Stop Multi-disk Device"
 msgstr "關閉多磁碟裝置(_S)"
 
-#: gtk/gtkplacessidebar.c:3333
+#: gtk/gtkplacessidebar.c:3337
 msgid "_Lock Device"
 msgstr "鎖定裝置(_L)"
 
-#: gtk/gtkplacessidebar.c:3822 gtk/gtkplacesview.c:1089
+#: gtk/gtkplacessidebar.c:3827 gtk/gtkplacesview.c:1089
 msgid "Computer"
 msgstr "電腦"
 
@@ -3148,15 +3259,15 @@ msgstr "中斷連接(_D)"
 msgid "_Connect"
 msgstr "連接(_C)"
 
-#: gtk/gtkplacesview.c:1891
+#: gtk/gtkplacesview.c:1894
 msgid "Unable to get remote server location"
 msgstr "無法取得遠端伺服器位置"
 
-#: gtk/gtkplacesview.c:2034 gtk/gtkplacesview.c:2043
+#: gtk/gtkplacesview.c:2038 gtk/gtkplacesview.c:2047
 msgid "Networks"
 msgstr "網路"
 
-#: gtk/gtkplacesview.c:2034 gtk/gtkplacesview.c:2043
+#: gtk/gtkplacesview.c:2038 gtk/gtkplacesview.c:2047
 msgid "On This Computer"
 msgstr "本機"
 
@@ -3175,23 +3286,23 @@ msgid "Disconnect"
 msgstr "中斷連線"
 
 #: gtk/gtkplacesviewrow.c:471 gtk/ui/gtkplacesviewrow.ui:53
-#: gtk/ui/gtksidebarrow.ui:51
+#: gtk/ui/gtksidebarrow.ui:54
 msgid "Unmount"
 msgstr "卸載"
 
-#: gtk/gtkprintbackend.c:637
+#: gtk/print/gtkprintbackend.c:637
 msgid "Authentication"
 msgstr "核對身分"
 
-#: gtk/gtkprintbackend.c:716
+#: gtk/print/gtkprintbackend.c:716
 msgid "_Remember password"
 msgstr "記住密碼(_R)"
 
-#: gtk/gtkprinteroptionwidget.c:715
+#: gtk/print/gtkprinteroptionwidget.c:703
 msgid "Select a filename"
 msgstr "選擇檔案名稱"
 
-#: gtk/gtkprinteroptionwidget.c:932
+#: gtk/print/gtkprinteroptionwidget.c:947
 msgid "Not available"
 msgstr "不存在"
 
@@ -3199,159 +3310,164 @@ msgstr "不存在"
 #. * jobs. %s gets replaced by the application name, %d gets replaced
 #. * by the job number.
 #.
-#: gtk/gtkprintoperation.c:253
+#: gtk/print/gtkprintoperation.c:255
 #, c-format
 msgid "%s job #%d"
 msgstr "%s 的工作 #%d"
 
-#: gtk/gtkprintoperation.c:1683
+#: gtk/print/gtkprintoperation.c:1702
 msgctxt "print operation status"
 msgid "Initial state"
 msgstr "初始化狀態"
 
-#: gtk/gtkprintoperation.c:1684
+#: gtk/print/gtkprintoperation.c:1703
 msgctxt "print operation status"
 msgid "Preparing to print"
 msgstr "正在準備列印"
 
-#: gtk/gtkprintoperation.c:1685
+#: gtk/print/gtkprintoperation.c:1704
 msgctxt "print operation status"
 msgid "Generating data"
 msgstr "正在產生資料"
 
-#: gtk/gtkprintoperation.c:1686
+#: gtk/print/gtkprintoperation.c:1705
 msgctxt "print operation status"
 msgid "Sending data"
 msgstr "正在傳送資料"
 
-#: gtk/gtkprintoperation.c:1687
+#: gtk/print/gtkprintoperation.c:1706
 msgctxt "print operation status"
 msgid "Waiting"
 msgstr "正在等待"
 
-#: gtk/gtkprintoperation.c:1688
+#: gtk/print/gtkprintoperation.c:1707
 msgctxt "print operation status"
 msgid "Blocking on issue"
 msgstr "因問題被阻擋"
 
-#: gtk/gtkprintoperation.c:1689
+#: gtk/print/gtkprintoperation.c:1708
 msgctxt "print operation status"
 msgid "Printing"
 msgstr "正在列印"
 
-#: gtk/gtkprintoperation.c:1690
+#: gtk/print/gtkprintoperation.c:1709
 msgctxt "print operation status"
 msgid "Finished"
 msgstr "已完成"
 
-#: gtk/gtkprintoperation.c:1691
+#: gtk/print/gtkprintoperation.c:1710
 msgctxt "print operation status"
 msgid "Finished with error"
 msgstr "已完成但發生錯誤"
 
-#: gtk/gtkprintoperation.c:2234
+#: gtk/print/gtkprintoperation.c:2254
 #, c-format
 msgid "Preparing %d"
 msgstr "正在準備 %d"
 
-#: gtk/gtkprintoperation.c:2236 gtk/gtkprintoperation.c:2855
+#: gtk/print/gtkprintoperation.c:2256 gtk/print/gtkprintoperation.c:2875
 #, c-format
 msgid "Preparing"
 msgstr "正在準備"
 
-#: gtk/gtkprintoperation.c:2239
+#: gtk/print/gtkprintoperation.c:2259
 #, c-format
 msgid "Printing %d"
 msgstr "正在列印 %d"
 
-#: gtk/gtkprintoperation.c:2888
+#: gtk/print/gtkprintoperation.c:2908
 #, c-format
 msgid "Error creating print preview"
 msgstr "建立列印預覽時發生錯誤"
 
-#: gtk/gtkprintoperation.c:2891
+#: gtk/print/gtkprintoperation.c:2911
 #, c-format
 msgid "The most probable reason is that a temporary file could not be created."
 msgstr "最可能的原因是無法建立暫存檔案。"
 
 #. window
-#: gtk/gtkprintoperation-portal.c:236 gtk/gtkprintoperation-portal.c:554
-#: gtk/gtkprintoperation-portal.c:623 gtk/gtkprintunixdialog.c:3066
+#: gtk/print/gtkprintoperation-portal.c:273
+#: gtk/print/gtkprintoperation-portal.c:603
+#: gtk/print/gtkprintoperation-portal.c:672 gtk/print/gtkprintunixdialog.c:3016
 msgid "Print"
 msgstr "列印"
 
-#: gtk/gtkprintoperation-unix.c:481 gtk/gtkprintoperation-win32.c:1504
+#: gtk/print/gtkprintoperation-unix.c:490
+#: gtk/print/gtkprintoperation-win32.c:1508
 msgid "Application"
 msgstr "應用程式"
 
-#: gtk/gtkprintoperation-win32.c:635
+#: gtk/print/gtkprintoperation-win32.c:636
 msgid "Printer offline"
 msgstr "印表機離線"
 
-#: gtk/gtkprintoperation-win32.c:637
+#: gtk/print/gtkprintoperation-win32.c:638
 msgid "Out of paper"
 msgstr "沒有紙"
 
 #. Translators: this is a printer status.
-#: gtk/gtkprintoperation-win32.c:639
-#: modules/printbackends/gtkprintbackendcups.c:2638
+#: gtk/print/gtkprintoperation-win32.c:640
+#: modules/printbackends/gtkprintbackendcpdb.c:1533
+#: modules/printbackends/gtkprintbackendcups.c:2639
 msgid "Paused"
 msgstr "已暫停"
 
-#: gtk/gtkprintoperation-win32.c:641
+#: gtk/print/gtkprintoperation-win32.c:642
 msgid "Need user intervention"
 msgstr "需要使用者干預"
 
-#: gtk/gtkprintoperation-win32.c:748
+#: gtk/print/gtkprintoperation-win32.c:749
 msgid "Custom size"
 msgstr "自訂大小"
 
-#: gtk/gtkprintoperation-win32.c:1596
+#: gtk/print/gtkprintoperation-win32.c:1600
 msgid "No printer found"
 msgstr "找不到印表機"
 
-#: gtk/gtkprintoperation-win32.c:1623
+#: gtk/print/gtkprintoperation-win32.c:1627
 msgid "Invalid argument to CreateDC"
 msgstr "給 CreateDC 的引數無效"
 
-#: gtk/gtkprintoperation-win32.c:1659 gtk/gtkprintoperation-win32.c:1905
+#: gtk/print/gtkprintoperation-win32.c:1663
+#: gtk/print/gtkprintoperation-win32.c:1909
 msgid "Error from StartDoc"
 msgstr "來自 StartDoc 的錯誤"
 
-#: gtk/gtkprintoperation-win32.c:1760 gtk/gtkprintoperation-win32.c:1783
-#: gtk/gtkprintoperation-win32.c:1831
+#: gtk/print/gtkprintoperation-win32.c:1764
+#: gtk/print/gtkprintoperation-win32.c:1787
+#: gtk/print/gtkprintoperation-win32.c:1835
 msgid "Not enough free memory"
 msgstr "可用記憶體不足"
 
-#: gtk/gtkprintoperation-win32.c:1836
+#: gtk/print/gtkprintoperation-win32.c:1840
 msgid "Invalid argument to PrintDlgEx"
 msgstr "給 PrintDlgEx 的參數無效"
 
-#: gtk/gtkprintoperation-win32.c:1841
+#: gtk/print/gtkprintoperation-win32.c:1845
 msgid "Invalid pointer to PrintDlgEx"
 msgstr "給 PrintDlgEx 的指標無效"
 
-#: gtk/gtkprintoperation-win32.c:1846
+#: gtk/print/gtkprintoperation-win32.c:1850
 msgid "Invalid handle to PrintDlgEx"
 msgstr "給 PrintDlgEx 的處理無效"
 
-#: gtk/gtkprintoperation-win32.c:1851
+#: gtk/print/gtkprintoperation-win32.c:1855
 msgid "Unspecified error"
 msgstr "無法指定的錯誤"
 
-#: gtk/gtkprintunixdialog.c:813
+#: gtk/print/gtkprintunixdialog.c:838
 msgid "Pre_view"
 msgstr "預覽(_V)"
 
-#: gtk/gtkprintunixdialog.c:815
+#: gtk/print/gtkprintunixdialog.c:840
 msgid "_Print"
 msgstr "列印(_P)"
 
-#: gtk/gtkprintunixdialog.c:943
+#: gtk/print/gtkprintunixdialog.c:967
 msgid "Getting printer information failed"
 msgstr "無法取得印表機資訊"
 
-#: gtk/gtkprintunixdialog.c:1866
+#: gtk/print/gtkprintunixdialog.c:1891
 msgid "Getting printer information…"
 msgstr "取得印表機資訊…"
 
@@ -3361,92 +3477,92 @@ msgstr "取得印表機資訊…"
 #. Translators: These strings name the possible arrangements of
 #. * multiple pages on a sheet when printing
 #.
-#: gtk/gtkprintunixdialog.c:2811
-#: modules/printbackends/gtkprintbackendcups.c:5646
+#: gtk/print/gtkprintunixdialog.c:2761
+#: modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, top to bottom"
 msgstr "由左至右,由上至下"
 
-#: gtk/gtkprintunixdialog.c:2811
-#: modules/printbackends/gtkprintbackendcups.c:5646
+#: gtk/print/gtkprintunixdialog.c:2761
+#: modules/printbackends/gtkprintbackendcups.c:5679
 msgid "Left to right, bottom to top"
 msgstr "由左至右,由下至上"
 
-#: gtk/gtkprintunixdialog.c:2812
-#: modules/printbackends/gtkprintbackendcups.c:5647
+#: gtk/print/gtkprintunixdialog.c:2762
+#: modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, top to bottom"
 msgstr "由右至左,由上至下"
 
-#: gtk/gtkprintunixdialog.c:2812
-#: modules/printbackends/gtkprintbackendcups.c:5647
+#: gtk/print/gtkprintunixdialog.c:2762
+#: modules/printbackends/gtkprintbackendcups.c:5680
 msgid "Right to left, bottom to top"
 msgstr "由右至左,由下至上"
 
-#: gtk/gtkprintunixdialog.c:2813
-#: modules/printbackends/gtkprintbackendcups.c:5648
+#: gtk/print/gtkprintunixdialog.c:2763
+#: modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, left to right"
 msgstr "由上至下,由左至右"
 
-#: gtk/gtkprintunixdialog.c:2813
-#: modules/printbackends/gtkprintbackendcups.c:5648
+#: gtk/print/gtkprintunixdialog.c:2763
+#: modules/printbackends/gtkprintbackendcups.c:5681
 msgid "Top to bottom, right to left"
 msgstr "由上至下,由右至左"
 
-#: gtk/gtkprintunixdialog.c:2814
-#: modules/printbackends/gtkprintbackendcups.c:5649
+#: gtk/print/gtkprintunixdialog.c:2764
+#: modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, left to right"
 msgstr "由下至上,由左至右"
 
-#: gtk/gtkprintunixdialog.c:2814
-#: modules/printbackends/gtkprintbackendcups.c:5649
+#: gtk/print/gtkprintunixdialog.c:2764
+#: modules/printbackends/gtkprintbackendcups.c:5682
 msgid "Bottom to top, right to left"
 msgstr "由下至上,由右至左"
 
-#: gtk/gtkprintunixdialog.c:2818 gtk/gtkprintunixdialog.c:2831
+#: gtk/print/gtkprintunixdialog.c:2768 gtk/print/gtkprintunixdialog.c:2781
 msgid "Page Ordering"
 msgstr "頁面順序"
 
-#: gtk/gtkprintunixdialog.c:2847
+#: gtk/print/gtkprintunixdialog.c:2797
 msgid "Left to right"
 msgstr "左至右"
 
-#: gtk/gtkprintunixdialog.c:2848
+#: gtk/print/gtkprintunixdialog.c:2798
 msgid "Right to left"
 msgstr "右至左"
 
-#: gtk/gtkprintunixdialog.c:2860
+#: gtk/print/gtkprintunixdialog.c:2810
 msgid "Top to bottom"
 msgstr "由上至下"
 
-#: gtk/gtkprintunixdialog.c:2861
+#: gtk/print/gtkprintunixdialog.c:2811
 msgid "Bottom to top"
 msgstr "由下至上"
 
-#: gtk/gtkprogressbar.c:608
+#: gtk/gtkprogressbar.c:627
 #, c-format
 msgctxt "progress bar label"
 msgid "%.0f %%"
 msgstr "%.0f %%"
 
-#: gtk/gtkrecentmanager.c:1023 gtk/gtkrecentmanager.c:1036
-#: gtk/gtkrecentmanager.c:1174 gtk/gtkrecentmanager.c:1184
-#: gtk/gtkrecentmanager.c:1234 gtk/gtkrecentmanager.c:1243
+#: gtk/gtkrecentmanager.c:1030 gtk/gtkrecentmanager.c:1043
+#: gtk/gtkrecentmanager.c:1181 gtk/gtkrecentmanager.c:1191
+#: gtk/gtkrecentmanager.c:1241 gtk/gtkrecentmanager.c:1250
 #, c-format
 msgid "Unable to find an item with URI “%s”"
 msgstr "無法找到有 URI「%s」的項目"
 
-#: gtk/gtkrecentmanager.c:1258
+#: gtk/gtkrecentmanager.c:1265
 #, c-format
 msgid "Unable to move the item with URI “%s” to “%s”"
 msgstr "無法將 URI「%s」的項目移至「%s」"
 
-#: gtk/gtkrecentmanager.c:2319
+#: gtk/gtkrecentmanager.c:2330
 #, c-format
 msgid "No registered application with name “%s” for item with URI “%s” found"
 msgstr "找不到 URI「%2$s」,名稱「%1$s」的註冊應用程式"
 
-#: gtk/gtksearchentry.c:626
-msgid "Clear entry"
-msgstr "清除輸入"
+#: gtk/gtksearchentry.c:836
+msgid "Clear Entry"
+msgstr "清除記錄"
 
 #. Translators: This string is used to mark left/right variants of modifier
 #. * keys in the shortcut window (e.g. Control_L vs Control_R). Please keep
@@ -3468,7 +3584,7 @@ msgctxt "keyboard side marker"
 msgid "R"
 msgstr "R"
 
-#: gtk/gtkshortcutssection.c:404
+#: gtk/gtkshortcutssection.c:435
 msgid "_Show All"
 msgstr "顯示全部(_S)"
 
@@ -3504,77 +3620,55 @@ msgstr "向左輕掃"
 msgid "Swipe right"
 msgstr "向右輕掃"
 
+#. Translators: This is placeholder text for the search entry in the shortcuts window
+#: gtk/gtkshortcutswindow.c:894 gtk/gtkshortcutswindow.c:961
+#: gtk/gtkshortcutswindow.c:967
+msgid "Search Shortcuts"
+msgstr "搜尋捷徑鍵"
+
 #. Translators: This is the window title for the shortcuts window in normal mode
-#: gtk/gtkshortcutswindow.c:874 gtk/inspector/window.ui:498
+#: gtk/gtkshortcutswindow.c:926 gtk/inspector/window.ui:498
 msgid "Shortcuts"
 msgstr "捷徑鍵"
 
 #. Translators: This is the window title for the shortcuts window in search mode
-#: gtk/gtkshortcutswindow.c:879
+#: gtk/gtkshortcutswindow.c:931
 msgid "Search Results"
 msgstr "搜尋結果"
 
-#. Translators: This is placeholder text for the search entry in the shortcuts window
-#: gtk/gtkshortcutswindow.c:909
-msgid "Search Shortcuts"
-msgstr "搜尋捷徑鍵"
-
-#: gtk/gtkshortcutswindow.c:968 gtk/ui/gtkemojichooser.ui:349
-#: gtk/ui/gtkfilechooserwidget.ui:497
+#: gtk/gtkshortcutswindow.c:1029 gtk/ui/gtkemojichooser.ui:352
+#: gtk/ui/gtkfilechooserwidget.ui:250
 msgid "No Results Found"
 msgstr "找不到結果"
 
-#: gtk/gtkshortcutswindow.c:974 gtk/ui/gtkemojichooser.ui:362
-#: gtk/ui/gtkfilechooserwidget.ui:510 gtk/ui/gtkplacesview.ui:218
+#: gtk/gtkshortcutswindow.c:1040 gtk/ui/gtkemojichooser.ui:365
+#: gtk/ui/gtkfilechooserwidget.ui:263 gtk/ui/gtkplacesview.ui:218
 msgid "Try a different search"
 msgstr "請嘗試不同的搜尋內容"
 
-#: gtk/gtkstacksidebar.c:154
+#: gtk/gtkstacksidebar.c:155
 msgctxt "accessibility"
 msgid "Sidebar"
 msgstr "側邊欄"
 
-#: gtk/gtktext.c:6101 gtk/gtktextview.c:9020
+#: gtk/gtktext.c:6349 gtk/gtktextview.c:9263
 msgid "Insert _Emoji"
 msgstr "插入繪文字(_E)"
 
-#: gtk/gtktextview.c:9002
+#: gtk/gtktextview.c:9245
 msgid "_Undo"
 msgstr "還原(_U)"
 
-#: gtk/gtktextview.c:9006
+#: gtk/gtktextview.c:9249
 msgid "_Redo"
 msgstr "重做(_R)"
 
-#: gtk/gtktreeexpander.c:189 gtk/inspector/misc-info.ui:287
-msgid "Expand"
-msgstr "擴展"
-
-#: gtk/gtkvolumebutton.c:228
-msgid "Muted"
-msgstr "靜音"
-
-#: gtk/gtkvolumebutton.c:232
-msgid "Full Volume"
-msgstr "最大音量"
-
-#. Translators: this is the percentage of the current volume,
-#. * as used in the tooltip, eg. "49 %".
-#. * Translate the "%d" to "%Id" if you want to use localised digits,
-#. * or otherwise translate the "%d" to "%d".
-#.
-#: gtk/gtkvolumebutton.c:245
-#, c-format
-msgctxt "volume percentage"
-msgid "%d %%"
-msgstr "%d %%"
-
-#: gtk/gtkwindow.c:6144
+#: gtk/gtkwindow.c:6200
 #, c-format
 msgid "Do you want to use GTK Inspector?"
 msgstr "您是否要使用 GTK 檢查器?"
 
-#: gtk/gtkwindow.c:6146
+#: gtk/gtkwindow.c:6202
 #, c-format
 msgid ""
 "GTK Inspector is an interactive debugger that lets you explore and modify "
@@ -3584,11 +3678,11 @@ msgstr ""
 "GTK 檢查器是一個互動式除錯程式,讓您可以探索任何 GTK 應用程式中並修改其內部。"
 "使用它可能造成應用程式中斷或當機。"
 
-#: gtk/gtkwindow.c:6151
+#: gtk/gtkwindow.c:6207
 msgid "Don’t show this message again"
 msgstr "不再顯示這個訊息"
 
-#: gtk/gtkwindowcontrols.c:309 gtk/gtkwindowhandle.c:230
+#: gtk/gtkwindowcontrols.c:309 gtk/gtkwindowhandle.c:234
 msgid "Minimize"
 msgstr "最小化"
 
@@ -3596,7 +3690,7 @@ msgstr "最小化"
 msgid "Minimize the window"
 msgstr "最小化視窗"
 
-#: gtk/gtkwindowcontrols.c:335 gtk/gtkwindowhandle.c:236
+#: gtk/gtkwindowcontrols.c:335 gtk/gtkwindowhandle.c:240
 msgid "Maximize"
 msgstr "最大化"
 
@@ -3604,41 +3698,46 @@ msgstr "最大化"
 msgid "Maximize the window"
 msgstr "最大化視窗"
 
-#: gtk/gtkwindowcontrols.c:357 gtk/gtkwindowhandle.c:246
-msgid "Close"
-msgstr "關閉"
-
 #: gtk/gtkwindowcontrols.c:359
 msgid "Close the window"
 msgstr "關閉這個視窗"
 
-#: gtk/gtkwindowhandle.c:223
+#: gtk/gtkwindowhandle.c:227
 msgid "Restore"
 msgstr "還原"
 
-#: gtk/inspector/a11y.ui:16
+#: gtk/inspector/a11y.ui:17
 msgid "Role"
 msgstr "角色"
 
-#: gtk/inspector/a11y.ui:43
-msgid "Object path"
+#: gtk/inspector/a11y.ui:71
+msgid "Description"
+msgstr "描述"
+
+#: gtk/inspector/a11y.ui:99 gtk/inspector/misc-info.ui:296
+#: tools/gtk-path-tool-info.c:132
+msgid "Bounds"
+msgstr "邊界"
+
+#: gtk/inspector/a11y.ui:125
+msgid "Object Path"
 msgstr "物件路徑"
 
-#: gtk/inspector/a11y.ui:72
+#: gtk/inspector/a11y.ui:164
 msgid "Attribute"
 msgstr "屬性"
 
-#: gtk/inspector/a11y.ui:84 gtk/inspector/css-node-tree.ui:70
+#: gtk/inspector/a11y.ui:176 gtk/inspector/css-node-tree.ui:70
 #: gtk/inspector/prop-list.ui:57 gtk/inspector/recorder.ui:149
 #: gtk/inspector/recorder.ui:192 gtk/inspector/strv-editor.c:73
 msgid "Value"
 msgstr "數值"
 
-#: gtk/inspector/action-editor.c:123
+#: gtk/inspector/action-editor.c:133
 msgid "Activate"
 msgstr "使用"
 
-#: gtk/inspector/action-editor.c:135
+#: gtk/inspector/action-editor.c:145
 msgid "Set State"
 msgstr "設定狀態"
 
@@ -3646,16 +3745,16 @@ msgstr "設定狀態"
 msgid "Enabled"
 msgstr "已啟用"
 
-#: gtk/inspector/actions.ui:41
+#: gtk/inspector/actions.ui:42
 msgid "Parameter Type"
 msgstr "參數類型"
 
-#: gtk/inspector/actions.ui:52 gtk/inspector/css-node-tree.ui:41
-#: gtk/inspector/misc-info.ui:121
+#: gtk/inspector/actions.ui:53 gtk/inspector/css-node-tree.ui:41
+#: gtk/inspector/misc-info.ui:108
 msgid "State"
 msgstr "狀態"
 
-#: gtk/inspector/clipboard.c:211 gtk/inspector/misc-info.ui:278
+#: gtk/inspector/clipboard.c:211 gtk/inspector/misc-info.ui:245
 msgid "Show"
 msgstr "顯示"
 
@@ -3663,30 +3762,30 @@ msgstr "顯示"
 msgid "Hover to load"
 msgstr "停駐滑鼠載入"
 
-#: gtk/inspector/clipboard.c:278
+#: gtk/inspector/clipboard.c:286
 msgctxt "clipboard"
 msgid "empty"
 msgstr "空白"
 
-#: gtk/inspector/clipboard.c:283 gtk/inspector/clipboard.c:325
+#: gtk/inspector/clipboard.c:291 gtk/inspector/clipboard.c:344
 msgctxt "clipboard"
 msgid "local"
 msgstr "本機"
 
-#: gtk/inspector/clipboard.c:285 gtk/inspector/clipboard.c:327
+#: gtk/inspector/clipboard.c:293 gtk/inspector/clipboard.c:346
 msgctxt "clipboard"
 msgid "remote"
 msgstr "遠端"
 
-#: gtk/inspector/clipboard.ui:31
+#: gtk/inspector/clipboard.ui:30
 msgid "Drag and hold here"
 msgstr "拖曳至此不動"
 
-#: gtk/inspector/clipboard.ui:75 gtk/inspector/window.ui:574
+#: gtk/inspector/clipboard.ui:71 gtk/inspector/window.ui:574
 msgid "Clipboard"
 msgstr "剪貼簿"
 
-#: gtk/inspector/clipboard.ui:114
+#: gtk/inspector/clipboard.ui:107
 msgid "Primary"
 msgstr "主要"
 
@@ -3715,35 +3814,39 @@ msgctxt "propagation limit"
 msgid "Native"
 msgstr "原生"
 
-#: gtk/inspector/css-editor.c:128
+#: gtk/inspector/css-editor.c:135
 msgid "You can type here any CSS rule recognized by GTK."
 msgstr "您可以在這裡輸入任何 GTK 可識別之 CSS 規則。"
 
-#: gtk/inspector/css-editor.c:129
+#: gtk/inspector/css-editor.c:136
 msgid ""
 "You can temporarily disable this custom CSS by clicking on the “Pause” "
 "button above."
 msgstr "您可以點選上列「暫停」按鈕來暫時停用這個自訂 CSS。"
 
-#: gtk/inspector/css-editor.c:130
+#: gtk/inspector/css-editor.c:137
 msgid "Changes are applied instantly and globally, for the whole application."
 msgstr "變更會立即套用到全域,影響整個應用程式。"
 
-#: gtk/inspector/css-editor.c:206
+#: gtk/inspector/css-editor.c:236
 #, c-format
 msgid "Saving CSS failed"
 msgstr "儲存 CSS 失敗"
 
-#: gtk/inspector/css-editor.ui:30
+#: gtk/inspector/css-editor.ui:37
 msgid "Disable this custom CSS"
 msgstr "停用這個自訂 CSS"
 
-#: gtk/inspector/css-editor.ui:37
+#: gtk/inspector/css-editor.ui:44
 msgid "Save the current CSS"
 msgstr "儲存目前的 CSS"
 
+#: gtk/inspector/css-editor.ui:51
+msgid "Show deprecations"
+msgstr "顯示棄用"
+
 #: gtk/inspector/css-node-tree.ui:28 tools/gtk-builder-tool-preview.c:178
-#: tools/gtk-builder-tool-screenshot.c:358
+#: tools/gtk-builder-tool-screenshot.c:359
 msgid "ID"
 msgstr "ID"
 
@@ -3755,116 +3858,134 @@ msgstr "樣式類別"
 msgid "CSS Property"
 msgstr "CSS 屬性"
 
-#: gtk/inspector/general.c:332 gtk/inspector/general.c:413
+#: gtk/inspector/general.c:372
 msgctxt "GL version"
 msgid "None"
 msgstr "沒有"
 
-#: gtk/inspector/general.c:341
+#: gtk/inspector/general.c:464
 msgctxt "GL version"
-msgid "Disabled"
-msgstr "已停用"
-
-#: gtk/inspector/general.c:342
-msgctxt "GL vendor"
-msgid "Disabled"
-msgstr "已停用"
-
-#: gtk/inspector/general.c:414
-msgctxt "GL vendor"
-msgid "None"
-msgstr "沒有"
+msgid "Unknown"
+msgstr "不明"
 
-#: gtk/inspector/general.c:465
+#: gtk/inspector/general.c:526
 msgctxt "Vulkan device"
 msgid "Disabled"
 msgstr "已停用"
 
-#: gtk/inspector/general.c:466 gtk/inspector/general.c:467
+#: gtk/inspector/general.c:527 gtk/inspector/general.c:528
 msgctxt "Vulkan version"
 msgid "Disabled"
 msgstr "已停用"
 
-#: gtk/inspector/general.c:523
+#: gtk/inspector/general.c:579
 msgctxt "Vulkan device"
 msgid "None"
 msgstr "ç„¡"
 
-#: gtk/inspector/general.c:524 gtk/inspector/general.c:525
+#: gtk/inspector/general.c:580 gtk/inspector/general.c:581
 msgctxt "Vulkan version"
 msgid "None"
 msgstr "ç„¡"
 
-#: gtk/inspector/general.c:796
+#: gtk/inspector/general.c:934
 msgid "IM Context is hardcoded by GTK_IM_MODULE"
 msgstr "IM 輸入法情境由 GTK_IM_MODULE 硬寫碼"
 
-#: gtk/inspector/general.ui:32
+#: gtk/inspector/general.ui:31
 msgid "GTK Version"
 msgstr "GTK 版本"
 
-#: gtk/inspector/general.ui:58
+#: gtk/inspector/general.ui:57
 msgid "GDK Backend"
 msgstr "GDK 後端"
 
-#: gtk/inspector/general.ui:84
+#: gtk/inspector/general.ui:83
 msgid "GSK Renderer"
 msgstr "GSK 繪製器"
 
-#: gtk/inspector/general.ui:110
+#: gtk/inspector/general.ui:109
 msgid "Pango Fontmap"
 msgstr "Pango Fontmap"
 
-#: gtk/inspector/general.ui:136
+#: gtk/inspector/general.ui:135
 msgid "Media Backend"
 msgstr "媒體後端"
 
 # (Abel) 這個很特殊,人們看到簡寫 XIM 反而更易明白
-#: gtk/inspector/general.ui:162
+#: gtk/inspector/general.ui:161
 msgid "Input Method"
 msgstr "輸入法"
 
-#: gtk/inspector/general.ui:202
+#: gtk/inspector/general.ui:198
 msgid "Application ID"
 msgstr "應用程式 ID"
 
-#: gtk/inspector/general.ui:228
+#: gtk/inspector/general.ui:224
 msgid "Resource Path"
 msgstr "資源路徑"
 
-#: gtk/inspector/general.ui:268 gtk/ui/gtkplacesview.ui:67
+#: gtk/inspector/general.ui:261 gtk/ui/gtkplacesview.ui:67
 msgid "Prefix"
 msgstr "前置字元"
 
-#: gtk/inspector/general.ui:470
+#: gtk/inspector/general.ui:460
 msgid "Display"
 msgstr "顯示"
 
-#: gtk/inspector/general.ui:497
+#: gtk/inspector/general.ui:487
 msgid "RGBA Visual"
 msgstr "RGBA 視覺"
 
-#: gtk/inspector/general.ui:523
+#: gtk/inspector/general.ui:513
 msgid "Composited"
 msgstr "複合"
 
-#: gtk/inspector/general.ui:575
+#: gtk/inspector/general.ui:538
+msgid "Protocols"
+msgstr "傳輸協定"
+
+#: gtk/inspector/general.ui:594
 msgid "GL Version"
 msgstr "GL 版本"
 
-#: gtk/inspector/general.ui:625
-msgid "GL Vendor"
-msgstr "GL 廠商"
+#: gtk/inspector/general.ui:621
+msgid "GL Backend Version"
+msgstr "GL 後端版本"
+
+#: gtk/inspector/general.ui:671
+msgid "GL Backend Vendor"
+msgstr "GL 後端廠商"
+
+#: gtk/inspector/general.ui:698
+msgid "GL_VENDOR"
+msgstr "GL_VENDOR"
 
-#: gtk/inspector/general.ui:665
+#: gtk/inspector/general.ui:727
+msgid "GL_RENDERER"
+msgstr "GL_RENDERER"
+
+#: gtk/inspector/general.ui:756
+msgid "GL_VERSION"
+msgstr "GL_VERSION"
+
+#: gtk/inspector/general.ui:785
+msgid "GL_SHADING_LANGUAGE_VERSION"
+msgstr "GL_SHADING_LANGUAGE_VERSION"
+
+#: gtk/inspector/general.ui:813 gtk/inspector/general.ui:929
+msgid "Extensions"
+msgstr "擴充套件"
+
+#: gtk/inspector/general.ui:849
 msgid "Vulkan Device"
 msgstr "Vulkan 裝置"
 
-#: gtk/inspector/general.ui:692
+#: gtk/inspector/general.ui:876
 msgid "Vulkan API version"
 msgstr "Vulkan API 版本"
 
-#: gtk/inspector/general.ui:719
+#: gtk/inspector/general.ui:903
 msgid "Vulkan driver version"
 msgstr "Vulkan 驅動程式版本"
 
@@ -3888,90 +4009,93 @@ msgstr "目標"
 msgid "Icon"
 msgstr "圖示"
 
-#: gtk/inspector/misc-info.ui:32
+#: gtk/inspector/misc-info.ui:31
 msgid "Address"
 msgstr "位址"
 
-#: gtk/inspector/misc-info.ui:62 gtk/inspector/prop-list.ui:35
-#: gtk/inspector/statistics.ui:36 gtk/ui/gtkfilechooserwidget.ui:336
-msgid "Type"
-msgstr "類型"
-
-#: gtk/inspector/misc-info.ui:91
+#: gtk/inspector/misc-info.ui:82
 msgid "Reference Count"
 msgstr "參照計數"
 
-#: gtk/inspector/misc-info.ui:151
+#: gtk/inspector/misc-info.ui:134
 msgid "Direction"
 msgstr "方向"
 
-#: gtk/inspector/misc-info.ui:181
+#: gtk/inspector/misc-info.ui:160
 msgid "Buildable ID"
 msgstr "可組建識別號"
 
-#: gtk/inspector/misc-info.ui:211
+#: gtk/inspector/misc-info.ui:186
 msgid "Mnemonic Label"
 msgstr "助記符標籤"
 
-#: gtk/inspector/misc-info.ui:240
+#: gtk/inspector/misc-info.ui:211
 msgid "Request Mode"
 msgstr "請求模式"
 
-#: gtk/inspector/misc-info.ui:269
+#: gtk/inspector/misc-info.ui:236
 msgid "Measure map"
 msgstr "測量圖"
 
-#: gtk/inspector/misc-info.ui:338
-msgid "Allocation"
-msgstr "分配"
+#: gtk/inspector/misc-info.ui:253
+msgid "Expand"
+msgstr "擴展"
 
-#: gtk/inspector/misc-info.ui:367
+#: gtk/inspector/misc-info.ui:321
 msgid "Baseline"
 msgstr "基線"
 
-#: gtk/inspector/misc-info.ui:396
+#: gtk/inspector/misc-info.ui:346
 msgid "Surface"
 msgstr "表面"
 
-#: gtk/inspector/misc-info.ui:415 gtk/inspector/misc-info.ui:454
-#: gtk/inspector/misc-info.ui:493 gtk/inspector/prop-editor.c:1150
-#: gtk/inspector/prop-editor.c:1533 gtk/inspector/window.ui:396
+#: gtk/inspector/misc-info.ui:365 gtk/inspector/misc-info.ui:400
+#: gtk/inspector/misc-info.ui:435 gtk/inspector/prop-editor.c:1153
+#: gtk/inspector/prop-editor.c:1536 gtk/inspector/window.ui:396
 msgid "Properties"
 msgstr "屬性"
 
-#: gtk/inspector/misc-info.ui:435
+#: gtk/inspector/misc-info.ui:381
 msgid "Renderer"
 msgstr "繪製器"
 
-#: gtk/inspector/misc-info.ui:474
+#: gtk/inspector/misc-info.ui:416
 msgid "Frame Clock"
 msgstr "圖框時鐘"
 
-#: gtk/inspector/misc-info.ui:513
+#: gtk/inspector/misc-info.ui:451
 msgid "Tick Callback"
 msgstr "點擊回饋"
 
-#: gtk/inspector/misc-info.ui:543
+#: gtk/inspector/misc-info.ui:477
 msgid "Frame Count"
 msgstr "影格數"
 
-#: gtk/inspector/misc-info.ui:572
+#: gtk/inspector/misc-info.ui:502
 msgid "Frame Rate"
 msgstr "影格率"
 
-#: gtk/inspector/misc-info.ui:601
+#: gtk/inspector/misc-info.ui:527 gtk/inspector/visual.ui:315
+msgid "Scale"
+msgstr "縮放"
+
+#: gtk/inspector/misc-info.ui:552
+msgid "Color state"
+msgstr "色彩狀態"
+
+#: gtk/inspector/misc-info.ui:577
 msgid "Mapped"
 msgstr "映射"
 
-#: gtk/inspector/misc-info.ui:631
+#: gtk/inspector/misc-info.ui:603
 msgid "Realized"
 msgstr "實現"
 
-#: gtk/inspector/misc-info.ui:661
+#: gtk/inspector/misc-info.ui:629
 msgid "Is Toplevel"
 msgstr "是頂端層級"
 
-#: gtk/inspector/misc-info.ui:691
+#: gtk/inspector/misc-info.ui:655
 msgid "Child Visible"
 msgstr "子項可見性"
 
@@ -3983,7 +4107,7 @@ msgstr "指標:%p"
 #. Translators: %s is a type name, for example
 #. * GtkPropertyExpression with value \"2.5\"
 #.
-#: gtk/inspector/prop-editor.c:824
+#: gtk/inspector/prop-editor.c:827
 #, c-format
 msgid "%s with value \"%s\""
 msgstr "%s 包含數值「%s」"
@@ -3991,7 +4115,7 @@ msgstr "%s 包含數值「%s」"
 #. Translators: Both %s are type names, for example
 #. * GtkPropertyExpression with type GObject
 #.
-#: gtk/inspector/prop-editor.c:835
+#: gtk/inspector/prop-editor.c:838
 #, c-format
 msgid "%s with type %s"
 msgstr "%s 包含類型「%s」"
@@ -3999,7 +4123,7 @@ msgstr "%s 包含類型「%s」"
 #. Translators: Both %s are type names, for example
 #. * GtkObjectExpression for GtkStringObject 0x23456789
 #.
-#: gtk/inspector/prop-editor.c:848
+#: gtk/inspector/prop-editor.c:851
 #, c-format
 msgid "%s for %s %p"
 msgstr "%s æ–¼ %s %p"
@@ -4007,71 +4131,71 @@ msgstr "%s æ–¼ %s %p"
 #. Translators: Both %s are type names, for example
 #. * GtkPropertyExpression with value type: gchararray
 #.
-#: gtk/inspector/prop-editor.c:878
+#: gtk/inspector/prop-editor.c:881
 #, c-format
 msgid "%s with value type %s"
 msgstr "%s 包含數值類型「%s」"
 
-#: gtk/inspector/prop-editor.c:1227
+#: gtk/inspector/prop-editor.c:1230
 #, c-format
 msgid "Uneditable property type: %s"
 msgstr "無法編輯的屬性類型:%s"
 
-#: gtk/inspector/prop-editor.c:1385
+#: gtk/inspector/prop-editor.c:1388
 msgctxt "column number"
 msgid "None"
 msgstr "ç„¡"
 
-#: gtk/inspector/prop-editor.c:1422
+#: gtk/inspector/prop-editor.c:1425
 msgid "Attribute:"
 msgstr "特性:"
 
-#: gtk/inspector/prop-editor.c:1425
+#: gtk/inspector/prop-editor.c:1428
 msgid "Model"
 msgstr "型號"
 
-#: gtk/inspector/prop-editor.c:1430
+#: gtk/inspector/prop-editor.c:1433
 msgid "Column:"
 msgstr "欄:"
 
 #. Translators: %s is a type name, for example
 #. * Action from 0x2345678 (GtkApplicationWindow)
 #.
-#: gtk/inspector/prop-editor.c:1529
+#: gtk/inspector/prop-editor.c:1532
 #, c-format
 msgid "Action from: %p (%s)"
 msgstr "動作來源:%p (%s)"
 
-#: gtk/inspector/prop-editor.c:1584
+#: gtk/inspector/prop-editor.c:1587
 msgid "Reset"
 msgstr "重設"
 
-#: gtk/inspector/prop-editor.c:1592
+#: gtk/inspector/prop-editor.c:1595
 msgctxt "GtkSettings source"
 msgid "Default"
 msgstr "預設值"
 
-#: gtk/inspector/prop-editor.c:1595
+#: gtk/inspector/prop-editor.c:1598
 msgctxt "GtkSettings source"
 msgid "Theme"
 msgstr "主題"
 
-#: gtk/inspector/prop-editor.c:1598
+#: gtk/inspector/prop-editor.c:1601
 msgctxt "GtkSettings source"
 msgid "XSettings"
 msgstr "X設定值"
 
-#: gtk/inspector/prop-editor.c:1602
+#: gtk/inspector/prop-editor.c:1605
 msgctxt "GtkSettings source"
 msgid "Application"
 msgstr "應用程式"
 
-#: gtk/inspector/prop-editor.c:1605
+#: gtk/inspector/prop-editor.c:1608
 msgctxt "GtkSettings source"
 msgid "Unknown"
 msgstr "未知"
 
-#: gtk/inspector/prop-editor.c:1608
+#: gtk/inspector/prop-editor.c:1611
 msgid "Source:"
 msgstr "來源:"
 
@@ -4079,7 +4203,7 @@ msgstr "來源:"
 msgid "Defined At"
 msgstr "定義於"
 
-#: gtk/inspector/recorder.c:1829
+#: gtk/inspector/recorder.c:2021
 #, c-format
 msgid "Saving RenderNode failed"
 msgstr "儲存 RenderNode 失敗"
@@ -4124,11 +4248,6 @@ msgstr "路徑"
 msgid "Count"
 msgstr "計數"
 
-#: gtk/inspector/resource-list.ui:82 gtk/ui/gtkfilechooserwidget.ui:290
-#: gtk/ui/gtkfontchooserwidget.ui:204 gtk/ui/gtkfontchooserwidget.ui:351
-msgid "Size"
-msgstr "大小"
-
 #: gtk/inspector/resource-list.ui:121
 msgid "Name:"
 msgstr "名稱:"
@@ -4137,7 +4256,7 @@ msgstr "名稱:"
 msgid "Type:"
 msgstr "類型:"
 
-#: gtk/inspector/resource-list.ui:164
+#: gtk/inspector/resource-list.ui:164 tools/gtk-image-tool-info.c:54
 msgid "Size:"
 msgstr "大小:"
 
@@ -4145,27 +4264,27 @@ msgstr "大小:"
 msgid "Trigger"
 msgstr "觸發"
 
-#: gtk/inspector/size-groups.c:225
+#: gtk/inspector/size-groups.c:228
 msgctxt "sizegroup mode"
 msgid "None"
 msgstr "沒有"
 
-#: gtk/inspector/size-groups.c:226
+#: gtk/inspector/size-groups.c:229
 msgctxt "sizegroup mode"
 msgid "Horizontal"
 msgstr "æ°´å¹³"
 
-#: gtk/inspector/size-groups.c:227
+#: gtk/inspector/size-groups.c:230
 msgctxt "sizegroup mode"
 msgid "Vertical"
 msgstr "垂直"
 
-#: gtk/inspector/size-groups.c:228
+#: gtk/inspector/size-groups.c:231
 msgctxt "sizegroup mode"
 msgid "Both"
 msgstr "兩者"
 
-#: gtk/inspector/size-groups.c:240
+#: gtk/inspector/size-groups.c:243
 msgid "Mode"
 msgstr "模式"
 
@@ -4222,109 +4341,121 @@ msgstr "階層"
 msgid "Implements"
 msgstr "實作"
 
-#: gtk/inspector/visual.c:603 gtk/inspector/visual.c:622
+#: gtk/inspector/visual.c:690 gtk/inspector/visual.c:708
 msgid "Theme is hardcoded by GTK_THEME"
 msgstr "布景主題由 GTK_THEME 控制"
 
-#: gtk/inspector/visual.c:853
-msgid "Backend does not support window scaling"
-msgstr "後端不支援視窗縮放"
-
-#: gtk/inspector/visual.ui:35
+#: gtk/inspector/visual.ui:34
 msgid "GTK Theme"
 msgstr "GTK 主題"
 
-#: gtk/inspector/visual.ui:59
+#: gtk/inspector/visual.ui:58
 msgid "Dark Variant"
 msgstr "暗色系變體"
 
-#: gtk/inspector/visual.ui:84
+#: gtk/inspector/visual.ui:83
 msgid "Cursor Theme"
 msgstr "游標主題"
 
-#: gtk/inspector/visual.ui:109
+#: gtk/inspector/visual.ui:108
 msgid "Cursor Size"
 msgstr "游標大小"
 
-#: gtk/inspector/visual.ui:145
+#: gtk/inspector/visual.ui:144
 msgid "Icon Theme"
 msgstr "圖示主題"
 
-#: gtk/inspector/visual.ui:195
-msgid "Font Scale"
-msgstr "字型比例"
-
-#: gtk/inspector/visual.ui:240
+#: gtk/inspector/visual.ui:169
 msgid "Text Direction"
 msgstr "文字方向"
 
-#: gtk/inspector/visual.ui:255
+#: gtk/inspector/visual.ui:184
 msgid "Left-to-Right"
 msgstr "左至右"
 
-#: gtk/inspector/visual.ui:256
+#: gtk/inspector/visual.ui:185
 msgid "Right-to-Left"
 msgstr "右至左"
 
-#: gtk/inspector/visual.ui:274
-msgid "Window Scaling"
-msgstr "視窗縮放"
-
-#: gtk/inspector/visual.ui:307
+#: gtk/inspector/visual.ui:202
 msgid "Animations"
 msgstr "å‹•ç•«"
 
-#: gtk/inspector/visual.ui:332
+#: gtk/inspector/visual.ui:227
 msgid "Slowdown"
 msgstr "降速"
 
-#: gtk/inspector/visual.ui:390
-msgid "Show fps overlay"
-msgstr "顯示 fps 疊層"
+#: gtk/inspector/visual.ui:362
+msgid "Rendering"
+msgstr "繪製"
 
-#: gtk/inspector/visual.ui:415
+#: gtk/inspector/visual.ui:377
+msgctxt "Font rendering"
+msgid "Automatic"
+msgstr "自動"
+
+#: gtk/inspector/visual.ui:378
+msgctxt "Font rendering"
+msgid "Manual"
+msgstr "手動"
+
+#: gtk/inspector/visual.ui:405
+msgid "Show Framerate"
+msgstr "顯示影格率"
+
+#: gtk/inspector/visual.ui:430
 msgid "Show Graphic Updates"
 msgstr "顯示圖形更新"
 
-#: gtk/inspector/visual.ui:440
-msgid "Show Fallback Rendering"
-msgstr "顯示後備繪製"
+#: gtk/inspector/visual.ui:450
+msgid ""
+"Tints all the places where the current renderer uses Cairo instead of the "
+"GPU."
+msgstr "對目前的繪製器使用 Cairo 取代 GPU 對所有位置進行著色。"
+
+#: gtk/inspector/visual.ui:456
+msgid "Show Cairo Rendering"
+msgstr "顯示 Cairo 繪製"
 
-#: gtk/inspector/visual.ui:465
+#: gtk/inspector/visual.ui:481
 msgid "Show Baselines"
 msgstr "顯示基線"
 
-#: gtk/inspector/visual.ui:493
+#: gtk/inspector/visual.ui:509
 msgid "Show Layout Borders"
 msgstr "顯示配置邊框"
 
-#: gtk/inspector/visual.ui:550
+#: gtk/inspector/visual.ui:566
 msgid "CSS Padding"
 msgstr "CSS 留空"
 
-#: gtk/inspector/visual.ui:560
+#: gtk/inspector/visual.ui:576
 msgid "CSS Border"
 msgstr "CSS 邊框"
 
-#: gtk/inspector/visual.ui:570
+#: gtk/inspector/visual.ui:586
 msgid "CSS Margin"
 msgstr "CSS 邊界"
 
-#: gtk/inspector/visual.ui:580
+#: gtk/inspector/visual.ui:596
 msgid "Widget Margin"
 msgstr "視窗元件邊界"
 
-#: gtk/inspector/visual.ui:615
+#: gtk/inspector/visual.ui:631
 msgid "Show Focus"
 msgstr "顯示焦點"
 
-#: gtk/inspector/visual.ui:654
-msgid "Simulate Touchscreen"
-msgstr "模擬觸控螢幕"
+#: gtk/inspector/visual.ui:656
+msgid "Show Accessibility warnings"
+msgstr "顯示無障礙警示"
+
+#: gtk/inspector/visual.ui:681
+msgid "Show Graphics Offload"
+msgstr "顯示圖形降載"
 
-#: gtk/inspector/visual.ui:689
+#: gtk/inspector/visual.ui:713
 msgid "Inspect Inspector"
-msgstr ""
+msgstr "檢查檢查器"
 
 #: gtk/inspector/window.ui:27
 msgid "Select an Object"
@@ -4382,7 +4513,7 @@ msgstr "下一個同級項目"
 msgid "Miscellaneous"
 msgstr "雜項"
 
-#: gtk/inspector/window.ui:407 gtk/ui/gtkprintunixdialog.ui:393
+#: gtk/inspector/window.ui:407 gtk/print/ui/gtkprintunixdialog.ui:451
 msgid "Layout"
 msgstr "配置"
 
@@ -5050,925 +5181,925 @@ msgctxt "OpenType layout"
 msgid "Slashed Zero"
 msgstr "斜槓零"
 
-#: gtk/paper_names_offsets.c:4
+#: gtk/print/paper_names_offsets.c:4
 msgctxt "paper size"
 msgid "asme_f"
 msgstr "asme_f"
 
-#: gtk/paper_names_offsets.c:5
+#: gtk/print/paper_names_offsets.c:5
 msgctxt "paper size"
 msgid "A0×2"
 msgstr "A0×2"
 
-#: gtk/paper_names_offsets.c:6
+#: gtk/print/paper_names_offsets.c:6
 msgctxt "paper size"
 msgid "A0"
 msgstr "A0"
 
-#: gtk/paper_names_offsets.c:7
+#: gtk/print/paper_names_offsets.c:7
 msgctxt "paper size"
 msgid "A0×3"
 msgstr "A0×3"
 
-#: gtk/paper_names_offsets.c:8
+#: gtk/print/paper_names_offsets.c:8
 msgctxt "paper size"
 msgid "A1"
 msgstr "A1"
 
-#: gtk/paper_names_offsets.c:9
+#: gtk/print/paper_names_offsets.c:9
 msgctxt "paper size"
 msgid "A10"
 msgstr "A10"
 
-#: gtk/paper_names_offsets.c:10
+#: gtk/print/paper_names_offsets.c:10
 msgctxt "paper size"
 msgid "A1×3"
 msgstr "A1×3"
 
-#: gtk/paper_names_offsets.c:11
+#: gtk/print/paper_names_offsets.c:11
 msgctxt "paper size"
 msgid "A1×4"
 msgstr "A1×4"
 
-#: gtk/paper_names_offsets.c:12
+#: gtk/print/paper_names_offsets.c:12
 msgctxt "paper size"
 msgid "A2"
 msgstr "A2"
 
-#: gtk/paper_names_offsets.c:13
+#: gtk/print/paper_names_offsets.c:13
 msgctxt "paper size"
 msgid "A2×3"
 msgstr "A2×3"
 
-#: gtk/paper_names_offsets.c:14
+#: gtk/print/paper_names_offsets.c:14
 msgctxt "paper size"
 msgid "A2×4"
 msgstr "A2×4"
 
-#: gtk/paper_names_offsets.c:15
+#: gtk/print/paper_names_offsets.c:15
 msgctxt "paper size"
 msgid "A2×5"
 msgstr "A2×5"
 
-#: gtk/paper_names_offsets.c:16
+#: gtk/print/paper_names_offsets.c:16
 msgctxt "paper size"
 msgid "A3"
 msgstr "A3"
 
-#: gtk/paper_names_offsets.c:17
+#: gtk/print/paper_names_offsets.c:17
 msgctxt "paper size"
 msgid "A3 Extra"
 msgstr "A3 Extra"
 
-#: gtk/paper_names_offsets.c:18
+#: gtk/print/paper_names_offsets.c:18
 msgctxt "paper size"
 msgid "A3×3"
 msgstr "A3×3"
 
-#: gtk/paper_names_offsets.c:19
+#: gtk/print/paper_names_offsets.c:19
 msgctxt "paper size"
 msgid "A3×4"
 msgstr "A3×4"
 
-#: gtk/paper_names_offsets.c:20
+#: gtk/print/paper_names_offsets.c:20
 msgctxt "paper size"
 msgid "A3×5"
 msgstr "A3×5"
 
-#: gtk/paper_names_offsets.c:21
+#: gtk/print/paper_names_offsets.c:21
 msgctxt "paper size"
 msgid "A3×6"
 msgstr "A3×6"
 
-#: gtk/paper_names_offsets.c:22
+#: gtk/print/paper_names_offsets.c:22
 msgctxt "paper size"
 msgid "A3×7"
 msgstr "A3×7"
 
-#: gtk/paper_names_offsets.c:23
+#: gtk/print/paper_names_offsets.c:23
 msgctxt "paper size"
 msgid "A4"
 msgstr "A4"
 
-#: gtk/paper_names_offsets.c:24
+#: gtk/print/paper_names_offsets.c:24
 msgctxt "paper size"
 msgid "A4 Extra"
 msgstr "A4 Extra"
 
-#: gtk/paper_names_offsets.c:25
+#: gtk/print/paper_names_offsets.c:25
 msgctxt "paper size"
 msgid "A4 Tab"
 msgstr "A4 Tab"
 
-#: gtk/paper_names_offsets.c:26
+#: gtk/print/paper_names_offsets.c:26
 msgctxt "paper size"
 msgid "A4×3"
 msgstr "A4×3"
 
-#: gtk/paper_names_offsets.c:27
+#: gtk/print/paper_names_offsets.c:27
 msgctxt "paper size"
 msgid "A4×4"
 msgstr "A4×4"
 
-#: gtk/paper_names_offsets.c:28
+#: gtk/print/paper_names_offsets.c:28
 msgctxt "paper size"
 msgid "A4×5"
 msgstr "A4×5"
 
-#: gtk/paper_names_offsets.c:29
+#: gtk/print/paper_names_offsets.c:29
 msgctxt "paper size"
 msgid "A4×6"
 msgstr "A4×6"
 
-#: gtk/paper_names_offsets.c:30
+#: gtk/print/paper_names_offsets.c:30
 msgctxt "paper size"
 msgid "A4×7"
 msgstr "A4×7"
 
-#: gtk/paper_names_offsets.c:31
+#: gtk/print/paper_names_offsets.c:31
 msgctxt "paper size"
 msgid "A4×8"
 msgstr "A4×8"
 
-#: gtk/paper_names_offsets.c:32
+#: gtk/print/paper_names_offsets.c:32
 msgctxt "paper size"
 msgid "A4×9"
 msgstr "A4×9"
 
-#: gtk/paper_names_offsets.c:33
+#: gtk/print/paper_names_offsets.c:33
 msgctxt "paper size"
 msgid "A5"
 msgstr "A5"
 
-#: gtk/paper_names_offsets.c:34
+#: gtk/print/paper_names_offsets.c:34
 msgctxt "paper size"
 msgid "A5 Extra"
 msgstr "A5 Extra"
 
-#: gtk/paper_names_offsets.c:35
+#: gtk/print/paper_names_offsets.c:35
 msgctxt "paper size"
 msgid "A6"
 msgstr "A6"
 
-#: gtk/paper_names_offsets.c:36
+#: gtk/print/paper_names_offsets.c:36
 msgctxt "paper size"
 msgid "A7"
 msgstr "A7"
 
-#: gtk/paper_names_offsets.c:37
+#: gtk/print/paper_names_offsets.c:37
 msgctxt "paper size"
 msgid "A8"
 msgstr "A8"
 
-#: gtk/paper_names_offsets.c:38
+#: gtk/print/paper_names_offsets.c:38
 msgctxt "paper size"
 msgid "A9"
 msgstr "A9"
 
-#: gtk/paper_names_offsets.c:39
+#: gtk/print/paper_names_offsets.c:39
 msgctxt "paper size"
 msgid "B0"
 msgstr "B0"
 
-#: gtk/paper_names_offsets.c:40
+#: gtk/print/paper_names_offsets.c:40
 msgctxt "paper size"
 msgid "B1"
 msgstr "B1"
 
-#: gtk/paper_names_offsets.c:41
+#: gtk/print/paper_names_offsets.c:41
 msgctxt "paper size"
 msgid "B10"
 msgstr "B10"
 
-#: gtk/paper_names_offsets.c:42
+#: gtk/print/paper_names_offsets.c:42
 msgctxt "paper size"
 msgid "B2"
 msgstr "B2"
 
-#: gtk/paper_names_offsets.c:43
+#: gtk/print/paper_names_offsets.c:43
 msgctxt "paper size"
 msgid "B3"
 msgstr "B3"
 
-#: gtk/paper_names_offsets.c:44
+#: gtk/print/paper_names_offsets.c:44
 msgctxt "paper size"
 msgid "B4"
 msgstr "B4"
 
-#: gtk/paper_names_offsets.c:45
+#: gtk/print/paper_names_offsets.c:45
 msgctxt "paper size"
 msgid "B5"
 msgstr "B5"
 
-#: gtk/paper_names_offsets.c:46
+#: gtk/print/paper_names_offsets.c:46
 msgctxt "paper size"
 msgid "B5 Extra"
 msgstr "B5 Extra"
 
-#: gtk/paper_names_offsets.c:47
+#: gtk/print/paper_names_offsets.c:47
 msgctxt "paper size"
 msgid "B6"
 msgstr "B6"
 
-#: gtk/paper_names_offsets.c:48
+#: gtk/print/paper_names_offsets.c:48
 msgctxt "paper size"
 msgid "B6/C4"
 msgstr "B6/C4"
 
-#: gtk/paper_names_offsets.c:49
+#: gtk/print/paper_names_offsets.c:49
 msgctxt "paper size"
 msgid "B7"
 msgstr "B7"
 
-#: gtk/paper_names_offsets.c:50
+#: gtk/print/paper_names_offsets.c:50
 msgctxt "paper size"
 msgid "B8"
 msgstr "B8"
 
-#: gtk/paper_names_offsets.c:51
+#: gtk/print/paper_names_offsets.c:51
 msgctxt "paper size"
 msgid "B9"
 msgstr "B9"
 
-#: gtk/paper_names_offsets.c:52
+#: gtk/print/paper_names_offsets.c:52
 msgctxt "paper size"
 msgid "C0"
 msgstr "C0"
 
-#: gtk/paper_names_offsets.c:53
+#: gtk/print/paper_names_offsets.c:53
 msgctxt "paper size"
 msgid "C1"
 msgstr "C1"
 
-#: gtk/paper_names_offsets.c:54
+#: gtk/print/paper_names_offsets.c:54
 msgctxt "paper size"
 msgid "C10"
 msgstr "C10"
 
-#: gtk/paper_names_offsets.c:55
+#: gtk/print/paper_names_offsets.c:55
 msgctxt "paper size"
 msgid "C2"
 msgstr "C2"
 
-#: gtk/paper_names_offsets.c:56
+#: gtk/print/paper_names_offsets.c:56
 msgctxt "paper size"
 msgid "C3"
 msgstr "C3"
 
-#: gtk/paper_names_offsets.c:57
+#: gtk/print/paper_names_offsets.c:57
 msgctxt "paper size"
 msgid "C4"
 msgstr "C4"
 
-#: gtk/paper_names_offsets.c:58
+#: gtk/print/paper_names_offsets.c:58
 msgctxt "paper size"
 msgid "C5"
 msgstr "C5"
 
-#: gtk/paper_names_offsets.c:59
+#: gtk/print/paper_names_offsets.c:59
 msgctxt "paper size"
 msgid "C6"
 msgstr "C6"
 
-#: gtk/paper_names_offsets.c:60
+#: gtk/print/paper_names_offsets.c:60
 msgctxt "paper size"
 msgid "C6/C5"
 msgstr "C6/C5"
 
-#: gtk/paper_names_offsets.c:61
+#: gtk/print/paper_names_offsets.c:61
 msgctxt "paper size"
 msgid "C7"
 msgstr "C7"
 
-#: gtk/paper_names_offsets.c:62
+#: gtk/print/paper_names_offsets.c:62
 msgctxt "paper size"
 msgid "C7/C6"
 msgstr "C7/C6"
 
-#: gtk/paper_names_offsets.c:63
+#: gtk/print/paper_names_offsets.c:63
 msgctxt "paper size"
 msgid "C8"
 msgstr "C8"
 
-#: gtk/paper_names_offsets.c:64
+#: gtk/print/paper_names_offsets.c:64
 msgctxt "paper size"
 msgid "C9"
 msgstr "C9"
 
-#: gtk/paper_names_offsets.c:65
+#: gtk/print/paper_names_offsets.c:65
 msgctxt "paper size"
 msgid "DL Envelope"
 msgstr "DL 信封"
 
-#: gtk/paper_names_offsets.c:66
+#: gtk/print/paper_names_offsets.c:66
 msgctxt "paper size"
 msgid "RA0"
 msgstr "RA0"
 
-#: gtk/paper_names_offsets.c:67
+#: gtk/print/paper_names_offsets.c:67
 msgctxt "paper size"
 msgid "RA1"
 msgstr "RA1"
 
-#: gtk/paper_names_offsets.c:68
+#: gtk/print/paper_names_offsets.c:68
 msgctxt "paper size"
 msgid "RA2"
 msgstr "RA2"
 
-#: gtk/paper_names_offsets.c:69
+#: gtk/print/paper_names_offsets.c:69
 msgctxt "paper size"
 msgid "RA3"
 msgstr "RA3"
 
-#: gtk/paper_names_offsets.c:70
+#: gtk/print/paper_names_offsets.c:70
 msgctxt "paper size"
 msgid "RA4"
 msgstr "RA4"
 
-#: gtk/paper_names_offsets.c:71
+#: gtk/print/paper_names_offsets.c:71
 msgctxt "paper size"
 msgid "SRA0"
 msgstr "SRA0"
 
-#: gtk/paper_names_offsets.c:72
+#: gtk/print/paper_names_offsets.c:72
 msgctxt "paper size"
 msgid "SRA1"
 msgstr "SRA1"
 
-#: gtk/paper_names_offsets.c:73
+#: gtk/print/paper_names_offsets.c:73
 msgctxt "paper size"
 msgid "SRA2"
 msgstr "SRA2"
 
-#: gtk/paper_names_offsets.c:74
+#: gtk/print/paper_names_offsets.c:74
 msgctxt "paper size"
 msgid "SRA3"
 msgstr "SRA3"
 
-#: gtk/paper_names_offsets.c:75
+#: gtk/print/paper_names_offsets.c:75
 msgctxt "paper size"
 msgid "SRA4"
 msgstr "SRA4"
 
-#: gtk/paper_names_offsets.c:76
+#: gtk/print/paper_names_offsets.c:76
 msgctxt "paper size"
 msgid "JB0"
 msgstr "JB0"
 
-#: gtk/paper_names_offsets.c:77
+#: gtk/print/paper_names_offsets.c:77
 msgctxt "paper size"
 msgid "JB1"
 msgstr "JB1"
 
-#: gtk/paper_names_offsets.c:78
+#: gtk/print/paper_names_offsets.c:78
 msgctxt "paper size"
 msgid "JB10"
 msgstr "JB10"
 
-#: gtk/paper_names_offsets.c:79
+#: gtk/print/paper_names_offsets.c:79
 msgctxt "paper size"
 msgid "JB2"
 msgstr "JB2"
 
-#: gtk/paper_names_offsets.c:80
+#: gtk/print/paper_names_offsets.c:80
 msgctxt "paper size"
 msgid "JB3"
 msgstr "JB3"
 
-#: gtk/paper_names_offsets.c:81
+#: gtk/print/paper_names_offsets.c:81
 msgctxt "paper size"
 msgid "JB4"
 msgstr "JB4"
 
-#: gtk/paper_names_offsets.c:82
+#: gtk/print/paper_names_offsets.c:82
 msgctxt "paper size"
 msgid "JB5"
 msgstr "JB5"
 
-#: gtk/paper_names_offsets.c:83
+#: gtk/print/paper_names_offsets.c:83
 msgctxt "paper size"
 msgid "JB6"
 msgstr "JB6"
 
-#: gtk/paper_names_offsets.c:84
+#: gtk/print/paper_names_offsets.c:84
 msgctxt "paper size"
 msgid "JB7"
 msgstr "JB7"
 
-#: gtk/paper_names_offsets.c:85
+#: gtk/print/paper_names_offsets.c:85
 msgctxt "paper size"
 msgid "JB8"
 msgstr "JB8"
 
-#: gtk/paper_names_offsets.c:86
+#: gtk/print/paper_names_offsets.c:86
 msgctxt "paper size"
 msgid "JB9"
 msgstr "JB9"
 
-#: gtk/paper_names_offsets.c:87
+#: gtk/print/paper_names_offsets.c:87
 msgctxt "paper size"
 msgid "jis exec"
 msgstr "jis exec"
 
-#: gtk/paper_names_offsets.c:88
+#: gtk/print/paper_names_offsets.c:88
 msgctxt "paper size"
 msgid "Choukei 2 Envelope"
 msgstr "Choukei 2 信封"
 
-#: gtk/paper_names_offsets.c:89
+#: gtk/print/paper_names_offsets.c:89
 msgctxt "paper size"
 msgid "Choukei 3 Envelope"
 msgstr "Choukei 3 信封"
 
-#: gtk/paper_names_offsets.c:90
+#: gtk/print/paper_names_offsets.c:90
 msgctxt "paper size"
 msgid "Choukei 4 Envelope"
 msgstr "Choukei 4 信封"
 
-#: gtk/paper_names_offsets.c:91
+#: gtk/print/paper_names_offsets.c:91
 msgctxt "paper size"
 msgid "Choukei 40 Envelope"
 msgstr "Choukei 40 信封"
 
-#: gtk/paper_names_offsets.c:92
+#: gtk/print/paper_names_offsets.c:92
 msgctxt "paper size"
 msgid "hagaki (postcard)"
 msgstr "hagaki(明信片)"
 
-#: gtk/paper_names_offsets.c:93
+#: gtk/print/paper_names_offsets.c:93
 msgctxt "paper size"
 msgid "kahu Envelope"
 msgstr "kahu 信封"
 
-#: gtk/paper_names_offsets.c:94
+#: gtk/print/paper_names_offsets.c:94
 msgctxt "paper size"
 msgid "kaku2 Envelope"
 msgstr "kaku2 信封"
 
-#: gtk/paper_names_offsets.c:95
+#: gtk/print/paper_names_offsets.c:95
 msgctxt "paper size"
 msgid "kaku3 Envelope"
 msgstr "kaku3 信封"
 
-#: gtk/paper_names_offsets.c:96
+#: gtk/print/paper_names_offsets.c:96
 msgctxt "paper size"
 msgid "kaku4 Envelope"
 msgstr "kaku4 信封"
 
-#: gtk/paper_names_offsets.c:97
+#: gtk/print/paper_names_offsets.c:97
 msgctxt "paper size"
 msgid "kaku5 Envelope"
 msgstr "kaku5 信封"
 
-#: gtk/paper_names_offsets.c:98
+#: gtk/print/paper_names_offsets.c:98
 msgctxt "paper size"
 msgid "kaku7 Envelope"
 msgstr "kaku7 信封"
 
-#: gtk/paper_names_offsets.c:99
+#: gtk/print/paper_names_offsets.c:99
 msgctxt "paper size"
 msgid "kaku8 Envelope"
 msgstr "kaku8 信封"
 
-#: gtk/paper_names_offsets.c:100
+#: gtk/print/paper_names_offsets.c:100
 msgctxt "paper size"
 msgid "oufuku (reply postcard)"
 msgstr "oufuku(回郵明信片)"
 
-#: gtk/paper_names_offsets.c:101
+#: gtk/print/paper_names_offsets.c:101
 msgctxt "paper size"
 msgid "you4 Envelope"
 msgstr "you4 信封"
 
-#: gtk/paper_names_offsets.c:102
+#: gtk/print/paper_names_offsets.c:102
 msgctxt "paper size"
 msgid "you6 Envelope"
 msgstr "you6 信封"
 
-#: gtk/paper_names_offsets.c:103
+#: gtk/print/paper_names_offsets.c:103
 msgctxt "paper size"
 msgid "10×11"
 msgstr "10×11"
 
-#: gtk/paper_names_offsets.c:104
+#: gtk/print/paper_names_offsets.c:104
 msgctxt "paper size"
 msgid "10×13"
 msgstr "10×13"
 
-#: gtk/paper_names_offsets.c:105
+#: gtk/print/paper_names_offsets.c:105
 msgctxt "paper size"
 msgid "10×14"
 msgstr "10×14"
 
-#: gtk/paper_names_offsets.c:106
+#: gtk/print/paper_names_offsets.c:106
 msgctxt "paper size"
 msgid "10×15"
 msgstr "10×15"
 
-#: gtk/paper_names_offsets.c:107
+#: gtk/print/paper_names_offsets.c:107
 msgctxt "paper size"
 msgid "11×12"
 msgstr "11×12"
 
-#: gtk/paper_names_offsets.c:108
+#: gtk/print/paper_names_offsets.c:108
 msgctxt "paper size"
 msgid "11×15"
 msgstr "11×15"
 
-#: gtk/paper_names_offsets.c:109
+#: gtk/print/paper_names_offsets.c:109
 msgctxt "paper size"
 msgid "12×19"
 msgstr "12×19"
 
-#: gtk/paper_names_offsets.c:110
+#: gtk/print/paper_names_offsets.c:110
 msgctxt "paper size"
 msgid "5×7"
 msgstr "5×7"
 
-#: gtk/paper_names_offsets.c:111
+#: gtk/print/paper_names_offsets.c:111
 msgctxt "paper size"
 msgid "6×9 Envelope"
 msgstr "6x9 信封"
 
-#: gtk/paper_names_offsets.c:112
+#: gtk/print/paper_names_offsets.c:112
 msgctxt "paper size"
 msgid "7×9 Envelope"
 msgstr "7x9 信封"
 
-#: gtk/paper_names_offsets.c:113
+#: gtk/print/paper_names_offsets.c:113
 msgctxt "paper size"
 msgid "8×10 Envelope"
 msgstr "8x10 信封"
 
-#: gtk/paper_names_offsets.c:114
+#: gtk/print/paper_names_offsets.c:114
 msgctxt "paper size"
 msgid "9×11 Envelope"
 msgstr "9x11 信封"
 
-#: gtk/paper_names_offsets.c:115
+#: gtk/print/paper_names_offsets.c:115
 msgctxt "paper size"
 msgid "9×12 Envelope"
 msgstr "9x12 信封"
 
-#: gtk/paper_names_offsets.c:116
+#: gtk/print/paper_names_offsets.c:116
 msgctxt "paper size"
 msgid "a2 Envelope"
 msgstr "a2 信封"
 
-#: gtk/paper_names_offsets.c:117
+#: gtk/print/paper_names_offsets.c:117
 msgctxt "paper size"
 msgid "Arch A"
 msgstr "Arch A"
 
-#: gtk/paper_names_offsets.c:118
+#: gtk/print/paper_names_offsets.c:118
 msgctxt "paper size"
 msgid "Arch B"
 msgstr "Arch B"
 
-#: gtk/paper_names_offsets.c:119
+#: gtk/print/paper_names_offsets.c:119
 msgctxt "paper size"
 msgid "Arch C"
 msgstr "Arch C"
 
-#: gtk/paper_names_offsets.c:120
+#: gtk/print/paper_names_offsets.c:120
 msgctxt "paper size"
 msgid "Arch D"
 msgstr "Arch D"
 
-#: gtk/paper_names_offsets.c:121
+#: gtk/print/paper_names_offsets.c:121
 msgctxt "paper size"
 msgid "Arch E"
 msgstr "Arch E"
 
-#: gtk/paper_names_offsets.c:122
+#: gtk/print/paper_names_offsets.c:122
 msgctxt "paper size"
 msgid "b-plus"
 msgstr "b-plus"
 
-#: gtk/paper_names_offsets.c:123
+#: gtk/print/paper_names_offsets.c:123
 msgctxt "paper size"
 msgid "c"
 msgstr "c"
 
-#: gtk/paper_names_offsets.c:124
+#: gtk/print/paper_names_offsets.c:124
 msgctxt "paper size"
 msgid "c5 Envelope"
 msgstr "c5 信封"
 
-#: gtk/paper_names_offsets.c:125
+#: gtk/print/paper_names_offsets.c:125
 msgctxt "paper size"
 msgid "d"
 msgstr "d"
 
-#: gtk/paper_names_offsets.c:126
+#: gtk/print/paper_names_offsets.c:126
 msgctxt "paper size"
 msgid "e"
 msgstr "e"
 
-#: gtk/paper_names_offsets.c:127
+#: gtk/print/paper_names_offsets.c:127
 msgctxt "paper size"
 msgid "edp"
 msgstr "edp"
 
-#: gtk/paper_names_offsets.c:128
+#: gtk/print/paper_names_offsets.c:128
 msgctxt "paper size"
 msgid "European edp"
 msgstr "歐制 edp"
 
-#: gtk/paper_names_offsets.c:129
+#: gtk/print/paper_names_offsets.c:129
 msgctxt "paper size"
 msgid "Executive"
 msgstr "Executive"
 
-#: gtk/paper_names_offsets.c:130
+#: gtk/print/paper_names_offsets.c:130
 msgctxt "paper size"
 msgid "f"
 msgstr "f"
 
-#: gtk/paper_names_offsets.c:131
+#: gtk/print/paper_names_offsets.c:131
 msgctxt "paper size"
 msgid "Fan-Fold European"
 msgstr "折疊歐式"
 
-#: gtk/paper_names_offsets.c:132
+#: gtk/print/paper_names_offsets.c:132
 msgctxt "paper size"
 msgid "Fan-Fold US"
 msgstr "折疊美式"
 
-#: gtk/paper_names_offsets.c:133
+#: gtk/print/paper_names_offsets.c:133
 msgctxt "paper size"
 msgid "Fan-Fold German Legal"
 msgstr "德制 Fan-Fold Legal"
 
-#: gtk/paper_names_offsets.c:134
+#: gtk/print/paper_names_offsets.c:134
 msgctxt "paper size"
 msgid "Government Legal"
 msgstr "Government Legal"
 
-#: gtk/paper_names_offsets.c:135
+#: gtk/print/paper_names_offsets.c:135
 msgctxt "paper size"
 msgid "Government Letter"
 msgstr "Government Letter"
 
-#: gtk/paper_names_offsets.c:136
+#: gtk/print/paper_names_offsets.c:136
 msgctxt "paper size"
 msgid "Index 3×5"
 msgstr "索引卡 3x5"
 
-#: gtk/paper_names_offsets.c:137
+#: gtk/print/paper_names_offsets.c:137
 msgctxt "paper size"
 msgid "Index 4×6 (postcard)"
 msgstr "索引卡 4x6(明信片)"
 
-#: gtk/paper_names_offsets.c:138
+#: gtk/print/paper_names_offsets.c:138
 msgctxt "paper size"
 msgid "Index 4×6 ext"
 msgstr "索引卡 4x6 ext"
 
-#: gtk/paper_names_offsets.c:139
+#: gtk/print/paper_names_offsets.c:139
 msgctxt "paper size"
 msgid "Index 5×8"
 msgstr "索引卡 5x8"
 
-#: gtk/paper_names_offsets.c:140
+#: gtk/print/paper_names_offsets.c:140
 msgctxt "paper size"
 msgid "Invoice"
 msgstr "帳單"
 
-#: gtk/paper_names_offsets.c:141
+#: gtk/print/paper_names_offsets.c:141
 msgctxt "paper size"
 msgid "Tabloid"
 msgstr "小型報"
 
-#: gtk/paper_names_offsets.c:142
+#: gtk/print/paper_names_offsets.c:142
 msgctxt "paper size"
 msgid "US Legal"
 msgstr "美制 Legal"
 
-#: gtk/paper_names_offsets.c:143
+#: gtk/print/paper_names_offsets.c:143
 msgctxt "paper size"
 msgid "US Legal Extra"
 msgstr "美制 Legal Extra"
 
-#: gtk/paper_names_offsets.c:144
+#: gtk/print/paper_names_offsets.c:144
 msgctxt "paper size"
 msgid "US Letter"
 msgstr "美制 Letter"
 
-#: gtk/paper_names_offsets.c:145
+#: gtk/print/paper_names_offsets.c:145
 msgctxt "paper size"
 msgid "US Letter Extra"
 msgstr "美制 Letter Extra"
 
-#: gtk/paper_names_offsets.c:146
+#: gtk/print/paper_names_offsets.c:146
 msgctxt "paper size"
 msgid "US Letter Plus"
 msgstr "美制 Letter Plus"
 
-#: gtk/paper_names_offsets.c:147
+#: gtk/print/paper_names_offsets.c:147
 msgctxt "paper size"
 msgid "Monarch Envelope"
 msgstr "Monarch 信封"
 
-#: gtk/paper_names_offsets.c:148
+#: gtk/print/paper_names_offsets.c:148
 msgctxt "paper size"
 msgid "#10 Envelope"
 msgstr "#10 信封"
 
-#: gtk/paper_names_offsets.c:149
+#: gtk/print/paper_names_offsets.c:149
 msgctxt "paper size"
 msgid "#11 Envelope"
 msgstr "#11 信封"
 
-#: gtk/paper_names_offsets.c:150
+#: gtk/print/paper_names_offsets.c:150
 msgctxt "paper size"
 msgid "#12 Envelope"
 msgstr "#12 信封"
 
-#: gtk/paper_names_offsets.c:151
+#: gtk/print/paper_names_offsets.c:151
 msgctxt "paper size"
 msgid "#14 Envelope"
 msgstr "#14 信封"
 
-#: gtk/paper_names_offsets.c:152
+#: gtk/print/paper_names_offsets.c:152
 msgctxt "paper size"
 msgid "#9 Envelope"
 msgstr "#9 信封"
 
-#: gtk/paper_names_offsets.c:153
+#: gtk/print/paper_names_offsets.c:153
 msgctxt "paper size"
 msgid "Oficio"
 msgstr "Oficio"
 
-#: gtk/paper_names_offsets.c:154
+#: gtk/print/paper_names_offsets.c:154
 msgctxt "paper size"
 msgid "Personal Envelope"
 msgstr "個人信封"
 
-#: gtk/paper_names_offsets.c:155
+#: gtk/print/paper_names_offsets.c:155
 msgctxt "paper size"
 msgid "Quarto"
 msgstr "Quarto"
 
-#: gtk/paper_names_offsets.c:156
+#: gtk/print/paper_names_offsets.c:156
 msgctxt "paper size"
 msgid "Super A"
 msgstr "Super A"
 
-#: gtk/paper_names_offsets.c:157
+#: gtk/print/paper_names_offsets.c:157
 msgctxt "paper size"
 msgid "Super B"
 msgstr "Super B"
 
-#: gtk/paper_names_offsets.c:158
+#: gtk/print/paper_names_offsets.c:158
 msgctxt "paper size"
 msgid "Wide Format"
 msgstr "寬格式"
 
-#: gtk/paper_names_offsets.c:159
+#: gtk/print/paper_names_offsets.c:159
 msgctxt "paper size"
 msgid "Photo L"
 msgstr "相片 L"
 
-#: gtk/paper_names_offsets.c:160
+#: gtk/print/paper_names_offsets.c:160
 msgctxt "paper size"
 msgid "Dai-pa-kai"
 msgstr "Dai-pa-kai"
 
-#: gtk/paper_names_offsets.c:161
+#: gtk/print/paper_names_offsets.c:161
 msgctxt "paper size"
 msgid "Folio"
 msgstr "Folio"
 
-#: gtk/paper_names_offsets.c:162
+#: gtk/print/paper_names_offsets.c:162
 msgctxt "paper size"
 msgid "Folio sp"
 msgstr "Folio sp"
 
-#: gtk/paper_names_offsets.c:163
+#: gtk/print/paper_names_offsets.c:163
 msgctxt "paper size"
 msgid "Invite Envelope"
 msgstr "邀請信封"
 
-#: gtk/paper_names_offsets.c:164
+#: gtk/print/paper_names_offsets.c:164
 msgctxt "paper size"
 msgid "Italian Envelope"
 msgstr "義大利信封"
 
-#: gtk/paper_names_offsets.c:165
+#: gtk/print/paper_names_offsets.c:165
 msgctxt "paper size"
 msgid "juuro-ku-kai"
 msgstr "juuro-ku-kai"
 
-#: gtk/paper_names_offsets.c:166
+#: gtk/print/paper_names_offsets.c:166
 msgctxt "paper size"
 msgid "Large Photo"
 msgstr "大型相片"
 
-#: gtk/paper_names_offsets.c:167
+#: gtk/print/paper_names_offsets.c:167
 msgctxt "paper size"
 msgid "Medium Photo"
 msgstr "中型相片"
 
-#: gtk/paper_names_offsets.c:168
+#: gtk/print/paper_names_offsets.c:168
 msgctxt "paper size"
 msgid "pa-kai"
 msgstr "pa-kai"
 
-#: gtk/paper_names_offsets.c:169
+#: gtk/print/paper_names_offsets.c:169
 msgctxt "paper size"
 msgid "Postfix Envelope"
 msgstr "Postfix 信封"
 
-#: gtk/paper_names_offsets.c:170
+#: gtk/print/paper_names_offsets.c:170
 msgctxt "paper size"
 msgid "Small Photo"
 msgstr "小相片"
 
-#: gtk/paper_names_offsets.c:171
+#: gtk/print/paper_names_offsets.c:171
 msgctxt "paper size"
 msgid "Wide Photo"
 msgstr "寬相片"
 
-#: gtk/paper_names_offsets.c:172
+#: gtk/print/paper_names_offsets.c:172
 msgctxt "paper size"
 msgid "prc1 Envelope"
 msgstr "prc1 信封"
 
-#: gtk/paper_names_offsets.c:173
+#: gtk/print/paper_names_offsets.c:173
 msgctxt "paper size"
 msgid "prc10 Envelope"
 msgstr "prc10 信封"
 
-#: gtk/paper_names_offsets.c:174
+#: gtk/print/paper_names_offsets.c:174
 msgctxt "paper size"
 msgid "prc 16k"
 msgstr "prc 16k"
 
-#: gtk/paper_names_offsets.c:175
+#: gtk/print/paper_names_offsets.c:175
 msgctxt "paper size"
 msgid "prc2 Envelope"
 msgstr "prc2 信封"
 
-#: gtk/paper_names_offsets.c:176
+#: gtk/print/paper_names_offsets.c:176
 msgctxt "paper size"
 msgid "prc3 Envelope"
 msgstr "prc3 信封"
 
-#: gtk/paper_names_offsets.c:177
+#: gtk/print/paper_names_offsets.c:177
 msgctxt "paper size"
 msgid "prc 32k"
 msgstr "prc 32k"
 
-#: gtk/paper_names_offsets.c:178
+#: gtk/print/paper_names_offsets.c:178
 msgctxt "paper size"
 msgid "prc4 Envelope"
 msgstr "prc4 信封"
 
-#: gtk/paper_names_offsets.c:179
+#: gtk/print/paper_names_offsets.c:179
 msgctxt "paper size"
 msgid "prc5 Envelope"
 msgstr "prc5 信封"
 
-#: gtk/paper_names_offsets.c:180
+#: gtk/print/paper_names_offsets.c:180
 msgctxt "paper size"
 msgid "prc6 Envelope"
 msgstr "prc6 信封"
 
-#: gtk/paper_names_offsets.c:181
+#: gtk/print/paper_names_offsets.c:181
 msgctxt "paper size"
 msgid "prc7 Envelope"
 msgstr "prc7 信封"
 
-#: gtk/paper_names_offsets.c:182
+#: gtk/print/paper_names_offsets.c:182
 msgctxt "paper size"
 msgid "prc8 Envelope"
 msgstr "prc8 信封"
 
-#: gtk/paper_names_offsets.c:183
+#: gtk/print/paper_names_offsets.c:183
 msgctxt "paper size"
 msgid "prc9 Envelope"
 msgstr "prc9 信封"
 
-#: gtk/paper_names_offsets.c:184
+#: gtk/print/paper_names_offsets.c:184
 msgctxt "paper size"
 msgid "ROC 16k"
 msgstr "ROC 16k"
 
-#: gtk/paper_names_offsets.c:185
+#: gtk/print/paper_names_offsets.c:185
 msgctxt "paper size"
 msgid "ROC 8k"
 msgstr "ROC 8k"
 
-#: gtk/ui/gtkaboutdialog.ui:62
+#: gtk/ui/gtkaboutdialog.ui:68
 msgid "About"
 msgstr "關於"
 
-#: gtk/ui/gtkaboutdialog.ui:123
+#: gtk/ui/gtkaboutdialog.ui:129
 msgid "Credits"
 msgstr "銘謝"
 
-#: gtk/ui/gtkaboutdialog.ui:206
+#: gtk/ui/gtkaboutdialog.ui:221
 msgid "System"
 msgstr "系統"
 
@@ -5976,11 +6107,11 @@ msgstr "系統"
 msgid "Select App"
 msgstr "選取程式"
 
-#: gtk/ui/gtkappchooserdialog.ui:60
+#: gtk/ui/gtkappchooserdialog.ui:63
 msgid "_View All Apps"
 msgstr "檢視所有程式(_V)"
 
-#: gtk/ui/gtkappchooserdialog.ui:66
+#: gtk/ui/gtkappchooserdialog.ui:69
 msgid "_Find New Apps"
 msgstr "尋找新程式(_F)"
 
@@ -5997,7 +6128,6 @@ msgid "Services"
 msgstr "服務"
 
 #: gtk/ui/gtkapplication-quartz.ui:25
-#, c-format
 msgid "Hide %s"
 msgstr "隱藏 %s"
 
@@ -6010,7 +6140,6 @@ msgid "Show All"
 msgstr "顯示全部"
 
 #: gtk/ui/gtkapplication-quartz.ui:42
-#, c-format
 msgid "Quit %s"
 msgstr "結束 %s"
 
@@ -6034,96 +6163,96 @@ msgstr "選取一個色彩"
 msgid "Pick a color from the screen"
 msgstr "請從螢幕上挑選色彩"
 
-#: gtk/ui/gtkcoloreditor.ui:80
+#: gtk/ui/gtkcoloreditor.ui:84
 msgid "Hexadecimal color or color name"
 msgstr "十六進位色彩或色彩名稱"
 
-#: gtk/ui/gtkcoloreditor.ui:95
+#: gtk/ui/gtkcoloreditor.ui:99
 msgid "Hue"
 msgstr "色相"
 
-#: gtk/ui/gtkcoloreditor.ui:111
+#: gtk/ui/gtkcoloreditor.ui:115
 msgid "Alpha value"
 msgstr "透明度"
 
-#: gtk/ui/gtkcoloreditor.ui:129
+#: gtk/ui/gtkcoloreditor.ui:133
 msgid "Saturation and value"
 msgstr "飽和度"
 
-#: gtk/ui/gtkcoloreditor.ui:153
+#: gtk/ui/gtkcoloreditor.ui:157
 msgctxt "Color channel"
 msgid "A"
 msgstr "A"
 
-#: gtk/ui/gtkcoloreditor.ui:189
+#: gtk/ui/gtkcoloreditor.ui:193
 msgctxt "Color channel"
 msgid "H"
 msgstr "H"
 
-#: gtk/ui/gtkcoloreditor.ui:226
+#: gtk/ui/gtkcoloreditor.ui:230
 msgctxt "Color Channel"
 msgid "S"
 msgstr "S"
 
-#: gtk/ui/gtkcoloreditor.ui:235
+#: gtk/ui/gtkcoloreditor.ui:239
 msgctxt "Color Channel"
 msgid "V"
 msgstr "V"
 
-#: gtk/ui/gtkdropdown.ui:19
+#: gtk/ui/gtkdropdown.ui:25
 msgid "(None)"
 msgstr "(無)"
 
-#: gtk/ui/gtkdropdown.ui:68
+#: gtk/ui/gtkdropdown.ui:78
 msgid "Search…"
 msgstr "搜尋…"
 
-#: gtk/ui/gtkemojichooser.ui:69 gtk/ui/gtkemojichooser.ui:239
+#: gtk/ui/gtkemojichooser.ui:70 gtk/ui/gtkemojichooser.ui:240
 msgctxt "emoji category"
 msgid "Smileys & People"
 msgstr "表情和人物"
 
-#: gtk/ui/gtkemojichooser.ui:94 gtk/ui/gtkemojichooser.ui:248
+#: gtk/ui/gtkemojichooser.ui:95 gtk/ui/gtkemojichooser.ui:249
 msgctxt "emoji category"
 msgid "Body & Clothing"
 msgstr "身體和服飾"
 
-#: gtk/ui/gtkemojichooser.ui:119 gtk/ui/gtkemojichooser.ui:257
+#: gtk/ui/gtkemojichooser.ui:120 gtk/ui/gtkemojichooser.ui:258
 msgctxt "emoji category"
 msgid "Animals & Nature"
 msgstr "動物和自然"
 
-#: gtk/ui/gtkemojichooser.ui:133 gtk/ui/gtkemojichooser.ui:266
+#: gtk/ui/gtkemojichooser.ui:134 gtk/ui/gtkemojichooser.ui:267
 msgctxt "emoji category"
 msgid "Food & Drink"
 msgstr "食物和飲品"
 
-#: gtk/ui/gtkemojichooser.ui:147 gtk/ui/gtkemojichooser.ui:275
+#: gtk/ui/gtkemojichooser.ui:148 gtk/ui/gtkemojichooser.ui:276
 msgctxt "emoji category"
 msgid "Travel & Places"
 msgstr "旅行和地點"
 
-#: gtk/ui/gtkemojichooser.ui:161 gtk/ui/gtkemojichooser.ui:284
+#: gtk/ui/gtkemojichooser.ui:162 gtk/ui/gtkemojichooser.ui:285
 msgctxt "emoji category"
 msgid "Activities"
 msgstr "活動"
 
-#: gtk/ui/gtkemojichooser.ui:175 gtk/ui/gtkemojichooser.ui:293
+#: gtk/ui/gtkemojichooser.ui:176 gtk/ui/gtkemojichooser.ui:294
 msgctxt "emoji category"
 msgid "Objects"
 msgstr "物體"
 
-#: gtk/ui/gtkemojichooser.ui:189 gtk/ui/gtkemojichooser.ui:302
+#: gtk/ui/gtkemojichooser.ui:190 gtk/ui/gtkemojichooser.ui:303
 msgctxt "emoji category"
 msgid "Symbols"
 msgstr "符號"
 
-#: gtk/ui/gtkemojichooser.ui:203 gtk/ui/gtkemojichooser.ui:311
+#: gtk/ui/gtkemojichooser.ui:204 gtk/ui/gtkemojichooser.ui:312
 msgctxt "emoji category"
 msgid "Flags"
 msgstr "旗幟"
 
-#: gtk/ui/gtkemojichooser.ui:230
+#: gtk/ui/gtkemojichooser.ui:231
 msgctxt "emoji category"
 msgid "Recent"
 msgstr "最近"
@@ -6132,15 +6261,15 @@ msgstr "最近"
 msgid "Create Folder"
 msgstr "建立資料夾"
 
-#: gtk/ui/gtkfilechooserwidget.ui:449
+#: gtk/ui/gtkfilechooserwidget.ui:202
 msgid "Remote location — only searching the current folder"
 msgstr "遠端位置 — 僅搜尋目前的資料夾"
 
-#: gtk/ui/gtkfilechooserwidget.ui:578
+#: gtk/ui/gtkfilechooserwidget.ui:334
 msgid "Folder Name"
 msgstr "資料夾名稱"
 
-#: gtk/ui/gtkfilechooserwidget.ui:604
+#: gtk/ui/gtkfilechooserwidget.ui:360
 msgid "_Create"
 msgstr "建立(_C)"
 
@@ -6148,55 +6277,75 @@ msgstr "建立(_C)"
 msgid "Select Font"
 msgstr "選取字型"
 
-#: gtk/ui/gtkfontchooserwidget.ui:64
+#: gtk/ui/gtkfontchooserwidget.ui:66
 msgid "Search font name"
 msgstr "搜尋字型的名稱"
 
 #: gtk/ui/gtkfontchooserwidget.ui:79
+msgid "Filters"
+msgstr "篩選條件"
+
+#: gtk/ui/gtkfontchooserwidget.ui:91
 msgid "Filter by"
 msgstr "篩選條件"
 
-#: gtk/ui/gtkfontchooserwidget.ui:89
+#: gtk/ui/gtkfontchooserwidget.ui:101
 msgid "Monospace"
 msgstr "等寬字"
 
-#: gtk/ui/gtkfontchooserwidget.ui:95
+#: gtk/ui/gtkfontchooserwidget.ui:106
 msgid "Language"
 msgstr "語言"
 
-#: gtk/ui/gtkfontchooserwidget.ui:188 gtk/ui/gtkfontchooserwidget.ui:324
+#: gtk/ui/gtkfontchooserwidget.ui:197 gtk/ui/gtkfontchooserwidget.ui:199
+#: gtk/ui/gtkfontchooserwidget.ui:352 gtk/ui/gtkfontchooserwidget.ui:356
 msgid "Preview Font"
 msgstr "預覽字型"
 
-#: gtk/ui/gtkfontchooserwidget.ui:270
+#: gtk/ui/gtkfontchooserwidget.ui:295
 msgid "No Fonts Found"
 msgstr "找不到字型"
 
-#: gtk/ui/gtkpagesetupunixdialog.ui:27
+#: gtk/ui/gtkmediacontrols.ui:47
+msgctxt "media controls"
+msgid "Position"
+msgstr "位置"
+
+#: gtk/ui/gtkmediacontrols.ui:65
+msgctxt "media controls"
+msgid "Volume"
+msgstr "音量"
+
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:30
 msgid "_Format for:"
 msgstr "格式(_F)"
 
-#: gtk/ui/gtkpagesetupunixdialog.ui:51 gtk/ui/gtkprintunixdialog.ui:635
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:54
+#: gtk/print/ui/gtkprintunixdialog.ui:704
 msgid "_Paper size:"
 msgstr "紙張尺寸(_P):"
 
-#: gtk/ui/gtkpagesetupunixdialog.ui:86
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:89
 msgid "_Orientation:"
 msgstr "方向(_O):"
 
-#: gtk/ui/gtkpagesetupunixdialog.ui:98 gtk/ui/gtkprintunixdialog.ui:675
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:101
+#: gtk/print/ui/gtkprintunixdialog.ui:744
 msgid "Portrait"
 msgstr "直向"
 
-#: gtk/ui/gtkpagesetupunixdialog.ui:109 gtk/ui/gtkprintunixdialog.ui:677
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:112
+#: gtk/print/ui/gtkprintunixdialog.ui:746
 msgid "Reverse portrait"
 msgstr "直向倒轉"
 
-#: gtk/ui/gtkpagesetupunixdialog.ui:121 gtk/ui/gtkprintunixdialog.ui:676
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:124
+#: gtk/print/ui/gtkprintunixdialog.ui:745
 msgid "Landscape"
 msgstr "橫向"
 
-#: gtk/ui/gtkpagesetupunixdialog.ui:132 gtk/ui/gtkprintunixdialog.ui:678
+#: gtk/print/ui/gtkpagesetupunixdialog.ui:135
+#: gtk/print/ui/gtkprintunixdialog.ui:747
 msgid "Reverse landscape"
 msgstr "橫向倒轉"
 
@@ -6235,31 +6384,32 @@ msgid "Enter server address…"
 msgstr "輸入伺服器位址…"
 
 #. this is the header for the printer status column in the print dialog
-#: gtk/ui/gtkprintunixdialog.ui:145
+#: gtk/print/ui/gtkprintunixdialog.ui:142
 msgid "Status"
 msgstr "狀態"
 
-#: gtk/ui/gtkprintunixdialog.ui:199
+#: gtk/print/ui/gtkprintunixdialog.ui:196
 msgid "Range"
 msgstr "範圍"
 
-#: gtk/ui/gtkprintunixdialog.ui:212
+#: gtk/print/ui/gtkprintunixdialog.ui:214
 msgid "_All Pages"
 msgstr "所有頁面(_A)"
 
-#: gtk/ui/gtkprintunixdialog.ui:224
+#: gtk/print/ui/gtkprintunixdialog.ui:227
 msgid "C_urrent Page"
 msgstr "目前頁面(_U)"
 
-#: gtk/ui/gtkprintunixdialog.ui:237
+#: gtk/print/ui/gtkprintunixdialog.ui:241
 msgid "Se_lection"
 msgstr "選取區域(_L)"
 
-#: gtk/ui/gtkprintunixdialog.ui:250
+#: gtk/print/ui/gtkprintunixdialog.ui:256
 msgid "Pag_es:"
 msgstr "頁面(_E):"
 
-#: gtk/ui/gtkprintunixdialog.ui:251 gtk/ui/gtkprintunixdialog.ui:264
+#: gtk/print/ui/gtkprintunixdialog.ui:260
+#: gtk/print/ui/gtkprintunixdialog.ui:273
 msgid ""
 "Specify one or more page ranges,\n"
 " e.g. 1–3, 7, 11"
@@ -6267,107 +6417,109 @@ msgstr ""
 "指定一個或多個頁面範圍,\n"
 "例如 1-3,7,11"
 
-#: gtk/ui/gtkprintunixdialog.ui:287
+#: gtk/print/ui/gtkprintunixdialog.ui:299
 msgid "Copies"
 msgstr "份數"
 
-#: gtk/ui/gtkprintunixdialog.ui:302
+#: gtk/print/ui/gtkprintunixdialog.ui:317
 msgid "Copie_s:"
 msgstr "份數(_S):"
 
-#: gtk/ui/gtkprintunixdialog.ui:325
+#: gtk/print/ui/gtkprintunixdialog.ui:340
 msgid "C_ollate"
 msgstr "順序分頁(_O)"
 
-#: gtk/ui/gtkprintunixdialog.ui:336
+#: gtk/print/ui/gtkprintunixdialog.ui:351
 msgid "_Reverse"
 msgstr "反序(_R)"
 
-#: gtk/ui/gtkprintunixdialog.ui:366
+#: gtk/print/ui/gtkprintunixdialog.ui:424
 msgid "General"
 msgstr "一般"
 
-#: gtk/ui/gtkprintunixdialog.ui:408
+#: gtk/print/ui/gtkprintunixdialog.ui:470
 msgid "T_wo-sided:"
 msgstr "雙面(_W):"
 
-#: gtk/ui/gtkprintunixdialog.ui:430
+#: gtk/print/ui/gtkprintunixdialog.ui:492
 msgid "Pages per _side:"
 msgstr "每一面的頁數(_S):"
 
-#: gtk/ui/gtkprintunixdialog.ui:454
+#: gtk/print/ui/gtkprintunixdialog.ui:516
 msgid "Page or_dering:"
 msgstr "頁面排序(_D):"
 
-#: gtk/ui/gtkprintunixdialog.ui:477
+#: gtk/print/ui/gtkprintunixdialog.ui:539
 msgid "_Only print:"
 msgstr "列印範圍(_O):"
 
-#: gtk/ui/gtkprintunixdialog.ui:493
+#: gtk/print/ui/gtkprintunixdialog.ui:555
 msgid "All sheets"
 msgstr "所有頁面"
 
-#: gtk/ui/gtkprintunixdialog.ui:494
+#: gtk/print/ui/gtkprintunixdialog.ui:556
 msgid "Even sheets"
 msgstr "偶數頁"
 
-#: gtk/ui/gtkprintunixdialog.ui:495
+#: gtk/print/ui/gtkprintunixdialog.ui:557
 msgid "Odd sheets"
 msgstr "奇數頁"
 
-#: gtk/ui/gtkprintunixdialog.ui:509
+#: gtk/print/ui/gtkprintunixdialog.ui:571
 msgid "Sc_ale:"
 msgstr "比例(_A):"
 
-#: gtk/ui/gtkprintunixdialog.ui:554
+#: gtk/print/ui/gtkprintunixdialog.ui:619
 msgid "Paper"
 msgstr "紙張"
 
-#: gtk/ui/gtkprintunixdialog.ui:569
+#: gtk/print/ui/gtkprintunixdialog.ui:638
 msgid "Paper _type:"
 msgstr "紙張類型(_T):"
 
-#: gtk/ui/gtkprintunixdialog.ui:591
+#: gtk/print/ui/gtkprintunixdialog.ui:660
 msgid "Paper _source:"
 msgstr "紙張來源(_S):"
 
-#: gtk/ui/gtkprintunixdialog.ui:613
+#: gtk/print/ui/gtkprintunixdialog.ui:682
 msgid "Output t_ray:"
 msgstr "出紙匣(_R):"
 
-#: gtk/ui/gtkprintunixdialog.ui:658
+#: gtk/print/ui/gtkprintunixdialog.ui:727
 msgid "Or_ientation:"
 msgstr "方向(_I):"
 
-#: gtk/ui/gtkprintunixdialog.ui:732
+#: gtk/print/ui/gtkprintunixdialog.ui:805
 msgid "Job Details"
 msgstr "列印工作詳細資料"
 
-#: gtk/ui/gtkprintunixdialog.ui:747
+#: gtk/print/ui/gtkprintunixdialog.ui:820
 msgid "Pri_ority:"
 msgstr "優先權(_O):"
 
-#: gtk/ui/gtkprintunixdialog.ui:768
+#: gtk/print/ui/gtkprintunixdialog.ui:841
 msgid "_Billing info:"
 msgstr "帳目資訊(_B):"
 
-#: gtk/ui/gtkprintunixdialog.ui:801
+#: gtk/print/ui/gtkprintunixdialog.ui:874
 msgid "Print Document"
 msgstr "列印文件"
 
 #. this is one of the choices for the print at option in the print dialog
-#: gtk/ui/gtkprintunixdialog.ui:814
+#: gtk/print/ui/gtkprintunixdialog.ui:887
 msgid "_Now"
 msgstr "現在(_N)"
 
 #. this is one of the choices for the print at option in the print dialog. It also serves as the label for an entry that allows the user to enter a time.
-#: gtk/ui/gtkprintunixdialog.ui:828
+#: gtk/print/ui/gtkprintunixdialog.ui:901
 msgid "A_t:"
 msgstr "於(_T):"
 
 #. Ability to parse the am/pm format depends on actual locale. You can remove the am/pm values below for your locale if they are not supported.
-#: gtk/ui/gtkprintunixdialog.ui:830 gtk/ui/gtkprintunixdialog.ui:832
-#: gtk/ui/gtkprintunixdialog.ui:848 gtk/ui/gtkprintunixdialog.ui:850
+#: gtk/print/ui/gtkprintunixdialog.ui:903
+#: gtk/print/ui/gtkprintunixdialog.ui:905
+#: gtk/print/ui/gtkprintunixdialog.ui:921
+#: gtk/print/ui/gtkprintunixdialog.ui:923
 msgid ""
 "Specify the time of print,\n"
 " e.g. 15∶30, 2∶35 pm, 14∶15∶20, 11∶46∶30 am, 4 pm"
@@ -6376,529 +6528,529 @@ msgstr ""
 " 例如 15:30, 2:35 pm, 14:15:20, 11:46:30 am, 4 pm"
 
 #. this is one of the choices for the print at option in the print dialog. It means that the print job will not be printed until it explicitly gets 'released'.
-#: gtk/ui/gtkprintunixdialog.ui:862
+#: gtk/print/ui/gtkprintunixdialog.ui:935
 msgid "On _hold"
 msgstr "擱置(_H)"
 
-#: gtk/ui/gtkprintunixdialog.ui:864 gtk/ui/gtkprintunixdialog.ui:865
+#: gtk/print/ui/gtkprintunixdialog.ui:937
+#: gtk/print/ui/gtkprintunixdialog.ui:938
 msgid "Hold the job until it is explicitly released"
 msgstr "保留此工作直到它被明確的釋出"
 
-#: gtk/ui/gtkprintunixdialog.ui:892
+#: gtk/print/ui/gtkprintunixdialog.ui:965
 msgid "Add Cover Page"
 msgstr "加入封面"
 
 #. this is the label used for the option in the print dialog that controls the front cover page.
-#: gtk/ui/gtkprintunixdialog.ui:907
+#: gtk/print/ui/gtkprintunixdialog.ui:980
 msgid "Be_fore:"
 msgstr "這頁之前(_F):"
 
 #. this is the label used for the option in the print dialog that controls the back cover page.
-#: gtk/ui/gtkprintunixdialog.ui:928
+#: gtk/print/ui/gtkprintunixdialog.ui:1001
 msgid "_After:"
 msgstr "這頁之後(_A):"
 
-#: gtk/ui/gtkprintunixdialog.ui:957
+#: gtk/print/ui/gtkprintunixdialog.ui:1030
 msgid "Job"
 msgstr "列印工作"
 
 #. This will appear as a tab label in the print dialog.
-#: gtk/ui/gtkprintunixdialog.ui:987
+#: gtk/print/ui/gtkprintunixdialog.ui:1060
 msgid "Image Quality"
 msgstr "影像品質"
 
 #. This will appear as a tab label in the print dialog.
-#: gtk/ui/gtkprintunixdialog.ui:1016
+#: gtk/print/ui/gtkprintunixdialog.ui:1089
 msgid "Color"
 msgstr "色彩"
 
 #. This will appear as a tab label in the print dialog. It's a typographical term, as in "Binding and finishing"
-#: gtk/ui/gtkprintunixdialog.ui:1045
+#: gtk/print/ui/gtkprintunixdialog.ui:1118
 msgid "Finishing"
 msgstr "加工完成階段"
 
-#: gtk/ui/gtkprintunixdialog.ui:1074
+#: gtk/print/ui/gtkprintunixdialog.ui:1147
 msgid "Advanced"
 msgstr "進階"
 
-#: gtk/ui/gtkprintunixdialog.ui:1090
+#: gtk/print/ui/gtkprintunixdialog.ui:1163
 msgid "Some of the settings in the dialog conflict"
 msgstr "對話框中某些設定有衝突"
 
-#: modules/media/gtkffmediafile.c:253
-#, c-format
-msgid "Unspecified error decoding media"
-msgstr "解碼媒體時發生未指定的錯誤"
+#: modules/printbackends/gtkprintbackendcpdb.c:542
+#: modules/printbackends/gtkprintbackendcups.c:5670
+msgctxt "Print job priority"
+msgid "Urgent"
+msgstr "緊急"
 
-#: modules/media/gtkffmediafile.c:286
-#, c-format
-msgid "Cannot find decoder: %s"
-msgstr "找不到解碼器:%s"
+#: modules/printbackends/gtkprintbackendcpdb.c:543
+#: modules/printbackends/gtkprintbackendcups.c:5671
+msgctxt "Print job priority"
+msgid "High"
+msgstr "高"
 
-#: modules/media/gtkffmediafile.c:296 modules/media/gtkffmediafile.c:363
-msgid "Failed to allocate a codec context"
-msgstr "無法分配編解碼器情境"
+#: modules/printbackends/gtkprintbackendcpdb.c:544
+#: modules/printbackends/gtkprintbackendcups.c:5672
+msgctxt "Print job priority"
+msgid "Medium"
+msgstr "中"
 
-#: modules/media/gtkffmediafile.c:341
-#, c-format
-msgid "Cannot find encoder: %s"
-msgstr "找不到編碼器:%s"
+#: modules/printbackends/gtkprintbackendcpdb.c:545
+#: modules/printbackends/gtkprintbackendcups.c:5673
+msgctxt "Print job priority"
+msgid "Low"
+msgstr "低"
+
+#. Translators, this is the label used for the option in the print
+#. * dialog that controls the front cover page.
+#.
+#: modules/printbackends/gtkprintbackendcpdb.c:567
+#: modules/printbackends/gtkprintbackendcups.c:5816
+msgctxt "printer option"
+msgid "Before"
+msgstr "封面"
+
+#. Translators, this is the label used for the option in the print
+#. * dialog that controls the back cover page.
+#.
+#: modules/printbackends/gtkprintbackendcpdb.c:574
+#: modules/printbackends/gtkprintbackendcups.c:5831
+msgctxt "printer option"
+msgid "After"
+msgstr "封底"
 
-#: modules/media/gtkffmediafile.c:352
-msgid "Cannot add new stream"
-msgstr "無法加入新的串流"
+#: modules/printbackends/gtkprintbackendcpdb.c:597
+msgid "Print at"
+msgstr "列印於"
 
-#: modules/media/gtkffmediafile.c:485 modules/media/gtkffmediafile.c:942
-msgid "Failed to allocate an audio frame"
-msgstr "無法分配音訊格幀"
+#: modules/printbackends/gtkprintbackendcpdb.c:607
+msgid "Print at time"
+msgstr "於指定時刻列印"
 
-#: modules/media/gtkffmediafile.c:650 modules/media/gtkffmediafile.c:898
-msgid "Not enough memory"
-msgstr "記憶體不足"
+#: modules/printbackends/gtkprintbackendcpdb.c:670
+msgctxt "print option"
+msgid "Borderless"
+msgstr "無邊框"
 
-#: modules/media/gtkffmediafile.c:821
-msgid "Could not allocate resampler context"
-msgstr "無法分配重新取樣器情境"
+#. Translators: this is a printer status.
+#: modules/printbackends/gtkprintbackendcpdb.c:1530
+#: modules/printbackends/gtkprintbackendcups.c:2636
+msgid "Paused; Rejecting Jobs"
+msgstr "已暫停;正在拒絕工作"
 
-#: modules/media/gtkffmediafile.c:868
-msgid "No audio output found"
-msgstr "找不到音訊輸出裝置"
+#. Translators: this is a printer status.
+#: modules/printbackends/gtkprintbackendcpdb.c:1536
+#: modules/printbackends/gtkprintbackendcups.c:2642
+msgid "Rejecting Jobs"
+msgstr "正在拒絕工作"
 
-#: modules/printbackends/gtkprintbackendcups.c:1141
-#: modules/printbackends/gtkprintbackendcups.c:1448
+#: modules/printbackends/gtkprintbackendcups.c:1142
+#: modules/printbackends/gtkprintbackendcups.c:1449
 msgid "Username:"
 msgstr "使用者名稱:"
 
-#: modules/printbackends/gtkprintbackendcups.c:1142
-#: modules/printbackends/gtkprintbackendcups.c:1457
+#: modules/printbackends/gtkprintbackendcups.c:1143
+#: modules/printbackends/gtkprintbackendcups.c:1458
 msgid "Password:"
 msgstr "密碼:"
 
-#: modules/printbackends/gtkprintbackendcups.c:1180
-#: modules/printbackends/gtkprintbackendcups.c:1470
+#: modules/printbackends/gtkprintbackendcups.c:1181
+#: modules/printbackends/gtkprintbackendcups.c:1471
 #, c-format
 msgid "Authentication is required to print document “%s” on printer %s"
 msgstr "要在印表機 %2$s 列印文件「%1$s」需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1182
+#: modules/printbackends/gtkprintbackendcups.c:1183
 #, c-format
 msgid "Authentication is required to print a document on %s"
 msgstr "要在 %s 列印文件需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1186
+#: modules/printbackends/gtkprintbackendcups.c:1187
 #, c-format
 msgid "Authentication is required to get attributes of job “%s”"
 msgstr "要取得工作「%s」的屬性需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1188
+#: modules/printbackends/gtkprintbackendcups.c:1189
 msgid "Authentication is required to get attributes of a job"
 msgstr "要取得工作的屬性需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1192
+#: modules/printbackends/gtkprintbackendcups.c:1193
 #, c-format
 msgid "Authentication is required to get attributes of printer %s"
 msgstr "要取得印表機「%s」的屬性需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1194
+#: modules/printbackends/gtkprintbackendcups.c:1195
 msgid "Authentication is required to get attributes of a printer"
 msgstr "要取得印表機的屬性需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1197
+#: modules/printbackends/gtkprintbackendcups.c:1198
 #, c-format
 msgid "Authentication is required to get default printer of %s"
 msgstr "要取得 %s 的預設印表機需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1200
+#: modules/printbackends/gtkprintbackendcups.c:1201
 #, c-format
 msgid "Authentication is required to get printers from %s"
 msgstr "要從 %s 取得印表機需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1205
+#: modules/printbackends/gtkprintbackendcups.c:1206
 #, c-format
 msgid "Authentication is required to get a file from %s"
 msgstr "從 %s 取得檔案需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1207
+#: modules/printbackends/gtkprintbackendcups.c:1208
 #, c-format
 msgid "Authentication is required on %s"
 msgstr "%s 需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1442
+#: modules/printbackends/gtkprintbackendcups.c:1443
 msgid "Domain:"
 msgstr "網域:"
 
-#: modules/printbackends/gtkprintbackendcups.c:1472
+#: modules/printbackends/gtkprintbackendcups.c:1473
 #, c-format
 msgid "Authentication is required to print document “%s”"
 msgstr "要列印文件「%s」需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1477
+#: modules/printbackends/gtkprintbackendcups.c:1478
 #, c-format
 msgid "Authentication is required to print this document on printer %s"
 msgstr "要在印表機 %s 列印文件需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:1479
+#: modules/printbackends/gtkprintbackendcups.c:1480
 msgid "Authentication is required to print this document"
 msgstr "要列印這份文件需要核對身分"
 
-#: modules/printbackends/gtkprintbackendcups.c:2567
+#: modules/printbackends/gtkprintbackendcups.c:2568
 #, c-format
 msgid "Printer “%s” is low on toner."
 msgstr "印表機「%s」碳粉不足。"
 
-#: modules/printbackends/gtkprintbackendcups.c:2571
+#: modules/printbackends/gtkprintbackendcups.c:2572
 #, c-format
 msgid "Printer “%s” has no toner left."
 msgstr "印表機「%s」碳粉用完。"
 
 #. Translators: "Developer" like on photo development context
-#: modules/printbackends/gtkprintbackendcups.c:2576
+#: modules/printbackends/gtkprintbackendcups.c:2577
 #, c-format
 msgid "Printer “%s” is low on developer."
 msgstr "印表機「%s」顯像劑不足。"
 
 #. Translators: "Developer" like on photo development context
-#: modules/printbackends/gtkprintbackendcups.c:2581
+#: modules/printbackends/gtkprintbackendcups.c:2582
 #, c-format
 msgid "Printer “%s” is out of developer."
 msgstr "印表機「%s」顯像劑用完。"
 
 #. Translators: "marker" is one color bin of the printer
-#: modules/printbackends/gtkprintbackendcups.c:2586
+#: modules/printbackends/gtkprintbackendcups.c:2587
 #, c-format
 msgid "Printer “%s” is low on at least one marker supply."
 msgstr "印表機「%s」至少有一個墨水不足。"
 
 #. Translators: "marker" is one color bin of the printer
-#: modules/printbackends/gtkprintbackendcups.c:2591
+#: modules/printbackends/gtkprintbackendcups.c:2592
 #, c-format
 msgid "Printer “%s” is out of at least one marker supply."
 msgstr "印表機「%s」至少有一個墨水用完。"
 
-#: modules/printbackends/gtkprintbackendcups.c:2595
+#: modules/printbackends/gtkprintbackendcups.c:2596
 #, c-format
 msgid "The cover is open on printer “%s”."
 msgstr "印表機「%s」的外殼是打開的。"
 
-#: modules/printbackends/gtkprintbackendcups.c:2599
+#: modules/printbackends/gtkprintbackendcups.c:2600
 #, c-format
 msgid "The door is open on printer “%s”."
 msgstr "印表機「%s」的紙匣門是打開的。"
 
-#: modules/printbackends/gtkprintbackendcups.c:2603
+#: modules/printbackends/gtkprintbackendcups.c:2604
 #, c-format
 msgid "Printer “%s” is low on paper."
 msgstr "印表機「%s」紙張不足。"
 
-#: modules/printbackends/gtkprintbackendcups.c:2607
+#: modules/printbackends/gtkprintbackendcups.c:2608
 #, c-format
 msgid "Printer “%s” is out of paper."
 msgstr "印表機「%s」紙張用完。"
 
-#: modules/printbackends/gtkprintbackendcups.c:2611
+#: modules/printbackends/gtkprintbackendcups.c:2612
 #, c-format
 msgid "Printer “%s” is currently offline."
 msgstr "印表機「%s」目前離線。"
 
-#: modules/printbackends/gtkprintbackendcups.c:2615
+#: modules/printbackends/gtkprintbackendcups.c:2616
 #, c-format
 msgid "There is a problem on printer “%s”."
 msgstr "印表機「%s」發生問題。"
 
-#. Translators: this is a printer status.
-#: modules/printbackends/gtkprintbackendcups.c:2635
-msgid "Paused; Rejecting Jobs"
-msgstr "已暫停;正在拒絕工作"
-
-#. Translators: this is a printer status.
-#: modules/printbackends/gtkprintbackendcups.c:2641
-msgid "Rejecting Jobs"
-msgstr "正在拒絕工作"
-
 #. Translators: this string connects multiple printer states together.
-#: modules/printbackends/gtkprintbackendcups.c:2682
+#: modules/printbackends/gtkprintbackendcups.c:2683
 msgid "; "
 msgstr "ï¼›"
 
-#: modules/printbackends/gtkprintbackendcups.c:4583
-#: modules/printbackends/gtkprintbackendcups.c:4650
+#: modules/printbackends/gtkprintbackendcups.c:4611
+#: modules/printbackends/gtkprintbackendcups.c:4678
 msgctxt "printing option"
 msgid "Two Sided"
 msgstr "雙面"
 
-#: modules/printbackends/gtkprintbackendcups.c:4584
+#: modules/printbackends/gtkprintbackendcups.c:4612
 msgctxt "printing option"
 msgid "Paper Type"
 msgstr "紙張類型"
 
-#: modules/printbackends/gtkprintbackendcups.c:4585
+#: modules/printbackends/gtkprintbackendcups.c:4613
 msgctxt "printing option"
 msgid "Paper Source"
 msgstr "紙張來源"
 
-#: modules/printbackends/gtkprintbackendcups.c:4586
-#: modules/printbackends/gtkprintbackendcups.c:4651
+#: modules/printbackends/gtkprintbackendcups.c:4614
+#: modules/printbackends/gtkprintbackendcups.c:4679
 msgctxt "printing option"
 msgid "Output Tray"
 msgstr "出紙匣"
 
-#: modules/printbackends/gtkprintbackendcups.c:4587
+#: modules/printbackends/gtkprintbackendcups.c:4615
 msgctxt "printing option"
 msgid "Resolution"
 msgstr "解析度"
 
-#: modules/printbackends/gtkprintbackendcups.c:4588
+#: modules/printbackends/gtkprintbackendcups.c:4616
 msgctxt "printing option"
 msgid "GhostScript pre-filtering"
 msgstr "GhostScript 前置過濾器"
 
-#: modules/printbackends/gtkprintbackendcups.c:4597
+#: modules/printbackends/gtkprintbackendcups.c:4625
 msgctxt "printing option value"
 msgid "One Sided"
 msgstr "單面"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4599
+#: modules/printbackends/gtkprintbackendcups.c:4627
 msgctxt "printing option value"
 msgid "Long Edge (Standard)"
 msgstr "長邊 (標準)"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4601
+#: modules/printbackends/gtkprintbackendcups.c:4629
 msgctxt "printing option value"
 msgid "Short Edge (Flip)"
 msgstr "短邊(翻轉)"
 
 #. Translators: this is an option of "Paper Source"
-#: modules/printbackends/gtkprintbackendcups.c:4603
-#: modules/printbackends/gtkprintbackendcups.c:4605
-#: modules/printbackends/gtkprintbackendcups.c:4613
+#: modules/printbackends/gtkprintbackendcups.c:4631
+#: modules/printbackends/gtkprintbackendcups.c:4633
+#: modules/printbackends/gtkprintbackendcups.c:4641
 msgctxt "printing option value"
 msgid "Auto Select"
 msgstr "自動選擇"
 
 #. Translators: this is an option of "Paper Source"
 #. Translators: this is an option of "Resolution"
-#: modules/printbackends/gtkprintbackendcups.c:4607
-#: modules/printbackends/gtkprintbackendcups.c:4609
-#: modules/printbackends/gtkprintbackendcups.c:4611
-#: modules/printbackends/gtkprintbackendcups.c:4615
+#: modules/printbackends/gtkprintbackendcups.c:4635
+#: modules/printbackends/gtkprintbackendcups.c:4637
+#: modules/printbackends/gtkprintbackendcups.c:4639
+#: modules/printbackends/gtkprintbackendcups.c:4643
 msgctxt "printing option value"
 msgid "Printer Default"
 msgstr "印表機預設值"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4617
+#: modules/printbackends/gtkprintbackendcups.c:4645
 msgctxt "printing option value"
 msgid "Embed GhostScript fonts only"
 msgstr "只有內嵌的 GhostScript 字型"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4619
+#: modules/printbackends/gtkprintbackendcups.c:4647
 msgctxt "printing option value"
 msgid "Convert to PS level 1"
 msgstr "轉換為 PS 等級 1"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4621
+#: modules/printbackends/gtkprintbackendcups.c:4649
 msgctxt "printing option value"
 msgid "Convert to PS level 2"
 msgstr "轉換為 PS 等級 2"
 
 #. Translators: this is an option of "GhostScript"
-#: modules/printbackends/gtkprintbackendcups.c:4623
+#: modules/printbackends/gtkprintbackendcups.c:4651
 msgctxt "printing option value"
 msgid "No pre-filtering"
 msgstr "無前置過濾器"
 
 #. Translators: "Miscellaneous" is the label for a button, that opens
 #. up an extra panel of settings in a print dialog.
-#: modules/printbackends/gtkprintbackendcups.c:4632
+#: modules/printbackends/gtkprintbackendcups.c:4660
 msgctxt "printing option group"
 msgid "Miscellaneous"
 msgstr "雜項"
 
-#: modules/printbackends/gtkprintbackendcups.c:4659
+#: modules/printbackends/gtkprintbackendcups.c:4687
 msgctxt "sides"
 msgid "One Sided"
 msgstr "單面"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4661
+#: modules/printbackends/gtkprintbackendcups.c:4689
 msgctxt "sides"
 msgid "Long Edge (Standard)"
 msgstr "長邊 (標準)"
 
 #. Translators: this is an option of "Two Sided"
-#: modules/printbackends/gtkprintbackendcups.c:4663
+#: modules/printbackends/gtkprintbackendcups.c:4691
 msgctxt "sides"
 msgid "Short Edge (Flip)"
 msgstr "短邊 (翻轉)"
 
 #. Translators: Top output bin
-#: modules/printbackends/gtkprintbackendcups.c:4666
+#: modules/printbackends/gtkprintbackendcups.c:4694
 msgctxt "output-bin"
 msgid "Top Bin"
 msgstr "上出紙槽"
 
 #. Translators: Middle output bin
-#: modules/printbackends/gtkprintbackendcups.c:4668
+#: modules/printbackends/gtkprintbackendcups.c:4696
 msgctxt "output-bin"
 msgid "Middle Bin"
 msgstr "中出紙槽"
 
 #. Translators: Bottom output bin
-#: modules/printbackends/gtkprintbackendcups.c:4670
+#: modules/printbackends/gtkprintbackendcups.c:4698
 msgctxt "output-bin"
 msgid "Bottom Bin"
 msgstr "下出紙槽"
 
 #. Translators: Side output bin
-#: modules/printbackends/gtkprintbackendcups.c:4672
+#: modules/printbackends/gtkprintbackendcups.c:4700
 msgctxt "output-bin"
 msgid "Side Bin"
 msgstr "側出紙槽"
 
 #. Translators: Left output bin
-#: modules/printbackends/gtkprintbackendcups.c:4674
+#: modules/printbackends/gtkprintbackendcups.c:4702
 msgctxt "output-bin"
 msgid "Left Bin"
 msgstr "左出紙槽"
 
 #. Translators: Right output bin
-#: modules/printbackends/gtkprintbackendcups.c:4676
+#: modules/printbackends/gtkprintbackendcups.c:4704
 msgctxt "output-bin"
 msgid "Right Bin"
 msgstr "右出紙槽"
 
 #. Translators: Center output bin
-#: modules/printbackends/gtkprintbackendcups.c:4678
+#: modules/printbackends/gtkprintbackendcups.c:4706
 msgctxt "output-bin"
 msgid "Center Bin"
 msgstr "中央出紙槽"
 
 #. Translators: Rear output bin
-#: modules/printbackends/gtkprintbackendcups.c:4680
+#: modules/printbackends/gtkprintbackendcups.c:4708
 msgctxt "output-bin"
 msgid "Rear Bin"
 msgstr "後出紙槽"
 
 #. Translators: Output bin where one sided output is oriented in the face-up position
-#: modules/printbackends/gtkprintbackendcups.c:4682
+#: modules/printbackends/gtkprintbackendcups.c:4710
 msgctxt "output-bin"
 msgid "Face Up Bin"
 msgstr "朝上出紙槽"
 
 #. Translators: Output bin where one sided output is oriented in the face-down position
-#: modules/printbackends/gtkprintbackendcups.c:4684
+#: modules/printbackends/gtkprintbackendcups.c:4712
 msgctxt "output-bin"
 msgid "Face Down Bin"
 msgstr "朝下出紙槽"
 
 #. Translators: Large capacity output bin
-#: modules/printbackends/gtkprintbackendcups.c:4686
+#: modules/printbackends/gtkprintbackendcups.c:4714
 msgctxt "output-bin"
 msgid "Large Capacity Bin"
 msgstr "大容量出紙槽"
 
 #. Translators: Output stacker number %d
-#: modules/printbackends/gtkprintbackendcups.c:4708
+#: modules/printbackends/gtkprintbackendcups.c:4736
 #, c-format
 msgctxt "output-bin"
 msgid "Stacker %d"
 msgstr "堆疊器 %d"
 
 #. Translators: Output mailbox number %d
-#: modules/printbackends/gtkprintbackendcups.c:4712
+#: modules/printbackends/gtkprintbackendcups.c:4740
 #, c-format
 msgctxt "output-bin"
 msgid "Mailbox %d"
 msgstr "ä¿¡ç®± %d"
 
 #. Translators: Private mailbox
-#: modules/printbackends/gtkprintbackendcups.c:4716
+#: modules/printbackends/gtkprintbackendcups.c:4744
 msgctxt "output-bin"
 msgid "My Mailbox"
 msgstr "我的信箱"
 
 #. Translators: Output tray number %d
-#: modules/printbackends/gtkprintbackendcups.c:4720
+#: modules/printbackends/gtkprintbackendcups.c:4748
 #, c-format
 msgctxt "output-bin"
 msgid "Tray %d"
 msgstr "出紙匣 %d"
 
-#: modules/printbackends/gtkprintbackendcups.c:5197
+#: modules/printbackends/gtkprintbackendcups.c:5225
 msgid "Printer Default"
 msgstr "印表機預設"
 
-#. Translators: These strings name the possible values of the
-#. * job priority option in the print dialog
-#.
-#: modules/printbackends/gtkprintbackendcups.c:5641
-msgid "Urgent"
-msgstr "緊急"
-
-#: modules/printbackends/gtkprintbackendcups.c:5641
-msgid "High"
-msgstr "高"
-
-#: modules/printbackends/gtkprintbackendcups.c:5641
-msgid "Medium"
-msgstr "中"
-
-#: modules/printbackends/gtkprintbackendcups.c:5641
-msgid "Low"
-msgstr "低"
-
 #. Translators, this string is used to label the job priority option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5671
+#: modules/printbackends/gtkprintbackendcups.c:5704
 msgid "Job Priority"
 msgstr "工作優先權"
 
 #. Translators, this string is used to label the billing info entry
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5682
+#: modules/printbackends/gtkprintbackendcups.c:5715
 msgid "Billing Info"
 msgstr "計費資訊"
 
 #. Translators, these strings are names for various 'standard' cover
 #. * pages that the printing system may support.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5706
+#: modules/printbackends/gtkprintbackendcups.c:5739
 msgctxt "cover page"
 msgid "None"
 msgstr "ç„¡"
 
-#: modules/printbackends/gtkprintbackendcups.c:5707
+#: modules/printbackends/gtkprintbackendcups.c:5740
 msgctxt "cover page"
 msgid "Classified"
 msgstr "保密"
 
-#: modules/printbackends/gtkprintbackendcups.c:5708
+#: modules/printbackends/gtkprintbackendcups.c:5741
 msgctxt "cover page"
 msgid "Confidential"
 msgstr "機密"
 
-#: modules/printbackends/gtkprintbackendcups.c:5709
+#: modules/printbackends/gtkprintbackendcups.c:5742
 msgctxt "cover page"
 msgid "Secret"
 msgstr "極機密"
 
-#: modules/printbackends/gtkprintbackendcups.c:5710
+#: modules/printbackends/gtkprintbackendcups.c:5743
 msgctxt "cover page"
 msgid "Standard"
 msgstr "標準"
 
-#: modules/printbackends/gtkprintbackendcups.c:5711
+#: modules/printbackends/gtkprintbackendcups.c:5744
 msgctxt "cover page"
 msgid "Top Secret"
 msgstr "絕對機密"
 
-#: modules/printbackends/gtkprintbackendcups.c:5712
+#: modules/printbackends/gtkprintbackendcups.c:5745
 msgctxt "cover page"
 msgid "Unclassified"
 msgstr "非保密"
@@ -6906,7 +7058,7 @@ msgstr "非保密"
 #. Translators, this string is used to label the pages-per-sheet option
 #. * in the print dialog
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5724
+#: modules/printbackends/gtkprintbackendcups.c:5757
 msgctxt "printer option"
 msgid "Pages per Sheet"
 msgstr "每張紙的頁數"
@@ -6914,32 +7066,16 @@ msgstr "每張紙的頁數"
 #. Translators, this string is used to label the option in the print
 #. * dialog that controls in what order multiple pages are arranged
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5741
+#: modules/printbackends/gtkprintbackendcups.c:5774
 msgctxt "printer option"
 msgid "Page Ordering"
 msgstr "頁面順序"
 
-#. Translators, this is the label used for the option in the print
-#. * dialog that controls the front cover page.
-#.
-#: modules/printbackends/gtkprintbackendcups.c:5783
-msgctxt "printer option"
-msgid "Before"
-msgstr "封面"
-
-#. Translators, this is the label used for the option in the print
-#. * dialog that controls the back cover page.
-#.
-#: modules/printbackends/gtkprintbackendcups.c:5798
-msgctxt "printer option"
-msgid "After"
-msgstr "封底"
-
 #. Translators: this is the name of the option that controls when
 #. * a print job is printed. Possible values are 'now', a specified time,
 #. * or 'on hold'
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5818
+#: modules/printbackends/gtkprintbackendcups.c:5851
 msgctxt "printer option"
 msgid "Print at"
 msgstr "列印於"
@@ -6947,7 +7083,7 @@ msgstr "列印於"
 #. Translators: this is the name of the option that allows the user
 #. * to specify a time when a print job will be printed.
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5829
+#: modules/printbackends/gtkprintbackendcups.c:5862
 msgctxt "printer option"
 msgid "Print at time"
 msgstr "於指定時刻列印"
@@ -6957,67 +7093,55 @@ msgstr "於指定時刻列印"
 #. * the width and height in points. E.g: "Custom
 #. * 230.4x142.9"
 #.
-#: modules/printbackends/gtkprintbackendcups.c:5876
+#: modules/printbackends/gtkprintbackendcups.c:5909
 #, c-format
 msgid "Custom %s×%s"
 msgstr "自訂 %sx%s"
 
 #. TRANSLATORS: this is the ICC color profile to use for this job
-#: modules/printbackends/gtkprintbackendcups.c:5987
+#: modules/printbackends/gtkprintbackendcups.c:6020
 msgctxt "printer option"
 msgid "Printer Profile"
 msgstr "印表機設定檔"
 
 #. TRANSLATORS: this is when color profile information is unavailable
-#: modules/printbackends/gtkprintbackendcups.c:5994
+#: modules/printbackends/gtkprintbackendcups.c:6027
 msgctxt "printer option value"
 msgid "Unavailable"
 msgstr "無法使用"
 
-#: modules/printbackends/gtkprintbackendfile.c:238
+#: modules/printbackends/gtkprintbackendfile.c:263
 msgid "output"
 msgstr "輸出"
 
-#: modules/printbackends/gtkprintbackendfile.c:510
+#: modules/printbackends/gtkprintbackendfile.c:543
 msgid "Print to File"
 msgstr "列印至檔案"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PDF"
 msgstr "PDF"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "PostScript"
 msgstr "PostScript"
 
-#: modules/printbackends/gtkprintbackendfile.c:636
+#: modules/printbackends/gtkprintbackendfile.c:675
 msgid "SVG"
 msgstr "SVG"
 
-#: modules/printbackends/gtkprintbackendfile.c:649
+#: modules/printbackends/gtkprintbackendfile.c:688
 msgid "Pages per _sheet:"
 msgstr "每張紙的頁數(_S):"
 
-#: modules/printbackends/gtkprintbackendfile.c:709
+#: modules/printbackends/gtkprintbackendfile.c:758
 msgid "File"
 msgstr "檔案"
 
-#: modules/printbackends/gtkprintbackendfile.c:719
+#: modules/printbackends/gtkprintbackendfile.c:768
 msgid "_Output format"
 msgstr "輸出格式(_O)"
 
-#: modules/printbackends/gtkprintbackendlpr.c:375
-msgid "Print to LPR"
-msgstr "列印至 LPR"
-
-#: modules/printbackends/gtkprintbackendlpr.c:404
-msgid "Pages Per Sheet"
-msgstr "每張紙的頁數"
-
-#: modules/printbackends/gtkprintbackendlpr.c:410
-msgid "Command Line"
-msgstr "命令行"
-
 #. TRANSLATORS: when we're running an old CUPS, and
 #. * it hasn't registered the device with colord
 #: modules/printbackends/gtkprintercups.c:272
@@ -7042,31 +7166,31 @@ msgstr "輸出到這個目錄而不是 cwd"
 msgid "Generate debug output"
 msgstr "產生除錯輸出"
 
-#: tools/encodesymbolic.c:92
+#: tools/encodesymbolic.c:95
 #, c-format
 msgid "Invalid size %s\n"
 msgstr "無效的大小 %s\n"
 
-#: tools/encodesymbolic.c:104 tools/encodesymbolic.c:113
+#: tools/encodesymbolic.c:107 tools/encodesymbolic.c:116
 #, c-format
 msgid "Can’t load file: %s\n"
 msgstr "不能載入檔案:%s\n"
 
-#: tools/encodesymbolic.c:141 tools/encodesymbolic.c:147
+#: tools/encodesymbolic.c:144 tools/encodesymbolic.c:162
 #, c-format
 msgid "Can’t save file %s: %s\n"
 msgstr "不能儲存檔案 %s:%s\n"
 
-#: tools/encodesymbolic.c:153
+#: tools/encodesymbolic.c:168
 #, c-format
 msgid "Can’t close stream"
 msgstr "不能關閉串流"
 
 #: tools/gtk-builder-tool.c:36
-#, fuzzy, c-format
+#, c-format
 msgid ""
 "Usage:\n"
-"  gtk-builder-tool [COMMAND] [OPTION…] FILE\n"
+"  gtk4-builder-tool [COMMAND] [OPTION…] FILE\n"
 "\n"
 "Perform various tasks on GtkBuilder .ui files.\n"
 "\n"
@@ -7075,32 +7199,31 @@ msgid ""
 "  simplify     Simplify the file\n"
 "  enumerate    List all named objects\n"
 "  preview      Preview the file\n"
+"  render       Take a screenshot of the file\n"
 "  screenshot   Take a screenshot of the file\n"
 "\n"
 msgstr ""
 "用法:\n"
-"  gtk-builder-tool [COMMAND] [OPTION…] FILE\n"
+"  gtk4-builder-tool [COMMAND] [OPTION…] FILE\n"
+"\n"
+"進行各種 GtkBuilder .ui 檔案工作。\n"
 "\n"
 "命令:\n"
 "  validate    驗證檔案\n"
 "  simplify    簡化檔案\n"
 "  enumerate   列出所有命名的物件\n"
 "  preview     預覧檔案\n"
+"  render       對檔案進行快照\n"
+"  screenshot   對檔案進行快照\n"
 "\n"
-"簡化選項:\n"
-"  --replace    取代檔案\n"
-"  --3to4       從 GTK 3 轉換至 GTK 4\n"
-"\n"
-"預覽選項:\n"
-"  --id=ID            只預覽已命名物件\n"
-"  --css=FILE         使用 CSS 檔案的樣式\n"
-"\n"
-"進行各種 GtkBuilder .ui 檔案工作。\n"
 
 #: tools/gtk-builder-tool-enumerate.c:56 tools/gtk-builder-tool-preview.c:179
-#: tools/gtk-builder-tool-preview.c:180 tools/gtk-builder-tool-screenshot.c:359
-#: tools/gtk-builder-tool-screenshot.c:362
-#: tools/gtk-builder-tool-simplify.c:2362 tools/gtk-builder-tool-validate.c:260
+#: tools/gtk-builder-tool-preview.c:180 tools/gtk-builder-tool-screenshot.c:360
+#: tools/gtk-builder-tool-simplify.c:2623 tools/gtk-builder-tool-validate.c:261
+#: tools/gtk-image-tool-compare.c:43 tools/gtk-image-tool-info.c:68
+#: tools/gtk-path-tool-render.c:121 tools/gtk-rendernode-tool-compare.c:67
+#: tools/gtk-rendernode-tool-extract.c:294 tools/gtk-rendernode-tool-info.c:226
+#: tools/gtk-rendernode-tool-show.c:116
 msgid "FILE"
 msgstr "FILE"
 
@@ -7108,95 +7231,389 @@ msgstr "FILE"
 msgid "Print all named objects."
 msgstr "列出所有命名的物件。"
 
+#: tools/gtk-builder-tool-preview.c:128 tools/gtk-builder-tool-screenshot.c:236
+#, c-format
+msgid "No object with ID '%s' found\n"
+msgstr "找不到 ID 為「%s」 的物件\n"
+
+#: tools/gtk-builder-tool-preview.c:130
+#, c-format
+msgid "No previewable object found\n"
+msgstr "找不到可預覽的物件\n"
+
+#: tools/gtk-builder-tool-preview.c:136
+#, c-format
+msgid "Objects of type %s can't be previewed\n"
+msgstr "無法預覽類型 %s 的物件\n"
+
 #: tools/gtk-builder-tool-preview.c:178
 msgid "Preview only the named object"
 msgstr "僅對命名的物件作預覽"
 
-#: tools/gtk-builder-tool-preview.c:179 tools/gtk-builder-tool-screenshot.c:359
-msgid "Use style from CSS file"
-msgstr "使用 CSS 檔提供的樣式"
+#: tools/gtk-builder-tool-preview.c:179 tools/gtk-builder-tool-screenshot.c:360
+msgid "Use style from CSS file"
+msgstr "使用 CSS 檔提供的樣式"
+
+#: tools/gtk-builder-tool-preview.c:187 tools/gtk-builder-tool-screenshot.c:370
+#: tools/gtk-builder-tool-validate.c:268
+#: tools/gtk-rendernode-tool-benchmark.c:108
+#: tools/gtk-rendernode-tool-render.c:262 tools/gtk-rendernode-tool-show.c:123
+#, c-format
+msgid "Could not initialize windowing system\n"
+msgstr "無法初始化視窗系統\n"
+
+#: tools/gtk-builder-tool-preview.c:195
+msgid "Preview the file."
+msgstr "預覽檔案。"
+
+#: tools/gtk-builder-tool-preview.c:208 tools/gtk-builder-tool-screenshot.c:391
+#: tools/gtk-builder-tool-simplify.c:2646 tools/gtk-builder-tool-validate.c:287
+#, c-format
+msgid "No .ui file specified\n"
+msgstr "未指定 .ui 檔案\n"
+
+#: tools/gtk-builder-tool-preview.c:214
+#, c-format
+msgid "Can only preview a single .ui file\n"
+msgstr "只能預覽一個 .ui 檔案\n"
+
+#: tools/gtk-builder-tool-screenshot.c:238
+#, c-format
+msgid "No object found\n"
+msgstr "找不到物件\n"
+
+#: tools/gtk-builder-tool-screenshot.c:244
+#, c-format
+msgid "Objects of type %s can't be screenshot\n"
+msgstr "無法進行類型 %s 物件的快照\n"
+
+#: tools/gtk-builder-tool-screenshot.c:298
+#, c-format
+msgid "Failed to take a screenshot\n"
+msgstr "進行快照失敗\n"
+
+#: tools/gtk-builder-tool-screenshot.c:309
+#, c-format
+msgid ""
+"File %s exists.\n"
+"Use --force to overwrite.\n"
+msgstr ""
+"檔案 %s 已存在。\n"
+"使用 --force 進行覆蓋。\n"
+
+#: tools/gtk-builder-tool-screenshot.c:332
+#: tools/gtk-rendernode-tool-render.c:230
+#, c-format
+msgid "Output written to %s.\n"
+msgstr "輸出寫入至 %s。\n"
+
+#: tools/gtk-builder-tool-screenshot.c:336
+#: tools/gtk-rendernode-tool-render.c:234
+#, c-format
+msgid "Failed to save %s: %s\n"
+msgstr "儲存 %s 失敗:%s\n"
+
+#: tools/gtk-builder-tool-screenshot.c:359
+msgid "Screenshot only the named object"
+msgstr "僅對命名的物件作螢幕快照"
+
+#: tools/gtk-builder-tool-screenshot.c:361
+msgid "Save as node file instead of png"
+msgstr "另存為節點檔而非 PNG"
+
+#: tools/gtk-builder-tool-screenshot.c:362
+msgid "Overwrite existing file"
+msgstr "覆寫既有的檔案"
+
+#: tools/gtk-builder-tool-screenshot.c:363 tools/gtk-image-tool-compare.c:46
+#: tools/gtk-image-tool-convert.c:89 tools/gtk-image-tool-relabel.c:86
+#: tools/gtk-image-tool-show.c:119 tools/gtk-rendernode-tool-benchmark.c:99
+#: tools/gtk-rendernode-tool-render.c:255
+msgid "FILE…"
+msgstr "檔案…"
+
+#: tools/gtk-builder-tool-screenshot.c:378
+msgid "Render a .ui file to an image."
+msgstr "將 .ui 檔案呈現為圖片。"
+
+#: tools/gtk-builder-tool-screenshot.c:397
+#, c-format
+msgid "Can only render a single .ui file to a single output file\n"
+msgstr "只能將單一 .ui 檔案呈現為單一輸出檔案\n"
+
+#: tools/gtk-builder-tool-simplify.c:444
+#, c-format
+msgid "%s:%d: Couldn’t parse value for property '%s': %s\n"
+msgstr "%s:%d:無法解析「%s」屬性的數值:%s\n"
+
+#: tools/gtk-builder-tool-simplify.c:658
+#, c-format
+msgid "Property %s not found"
+msgstr "找不到屬性 %s"
+
+#: tools/gtk-builder-tool-simplify.c:661
+#, c-format
+msgid "Packing property %s not found"
+msgstr "找不到包裝屬性 %s"
+
+#: tools/gtk-builder-tool-simplify.c:664
+#, c-format
+msgid "Cell property %s not found"
+msgstr "找不到儲存格屬性 %s"
+
+#: tools/gtk-builder-tool-simplify.c:667
+#, c-format
+msgid "Layout property %s not found"
+msgstr "找不到配置屬性 %s"
+
+#: tools/gtk-builder-tool-simplify.c:1400
+#, c-format
+msgid "%s only accepts three children"
+msgstr "%s 只接受 3 個子項"
+
+#: tools/gtk-builder-tool-simplify.c:1773
+#, c-format
+msgid "%s only accepts one center child"
+msgstr "%s 只接受一個中央子項"
+
+#: tools/gtk-builder-tool-simplify.c:2549
+#, c-format
+msgid "Can’t load “%s”: %s\n"
+msgstr "無法載入「%s」:%s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2560
+#: tools/gtk-builder-tool-simplify.c:2566
+#: tools/gtk-builder-tool-simplify.c:2572
+#, c-format
+msgid "Can’t parse “%s”: %s\n"
+msgstr "無法解析「%s」:%s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2598
+#, c-format
+msgid "Failed to read “%s”: %s\n"
+msgstr "無法讀取「%s」:%s\n"
+
+#: tools/gtk-builder-tool-simplify.c:2604
+#, c-format
+msgid "Failed to write “%s”: “%s”\n"
+msgstr "無法寫入「%s」:「%s」\n"
+
+#: tools/gtk-builder-tool-simplify.c:2621
+msgid "Replace the file"
+msgstr "取代檔案"
+
+#: tools/gtk-builder-tool-simplify.c:2622
+msgid "Convert from GTK 3 to GTK 4"
+msgstr "從 GTK 3 轉換至 GTK 4"
+
+#: tools/gtk-builder-tool-simplify.c:2633
+msgid "Simplify the file."
+msgstr "簡化檔案。"
+
+#: tools/gtk-builder-tool-simplify.c:2652
+#, c-format
+msgid "Can only simplify a single .ui file without --replace\n"
+msgstr "沒有 --replace 時,只能簡化一個 .ui 檔案\n"
+
+#: tools/gtk-builder-tool-validate.c:45
+#, c-format
+msgid "Failed to lookup template parent type %s\n"
+msgstr "無法查詢範本父類型 %s\n"
+
+#: tools/gtk-builder-tool-validate.c:123
+msgid "Deprecated types:\n"
+msgstr "已廢棄的類型:\n"
+
+#: tools/gtk-builder-tool-validate.c:167
+#, c-format
+msgid "Failed to create an instance of the template type %s\n"
+msgstr "無法建立範本類型為 %s 的實體\n"
+
+#: tools/gtk-builder-tool-validate.c:276
+msgid "Validate the file."
+msgstr "驗證文件。"
+
+#: tools/gtk-image-tool.c:36
+#, c-format
+msgid ""
+"Usage:\n"
+"  gtk4-image-tool [COMMAND] [OPTION…] FILE…\n"
+"\n"
+"Perform various tasks on images.\n"
+"\n"
+"Commands:\n"
+"  compare      Show differences between two images\n"
+"  convert      Convert the image to a different format or color state\n"
+"  info         Show general information about the image\n"
+"  relabel      Change the color state of the image without conversion\n"
+"  show         Show the image\n"
+"\n"
+msgstr ""
+"用法:\n"
+"gtk4-image-tool [命令] [選項...]檔。。。\n"
+"\n"
+"對影像執行各種任務。\n"
+"\n"
+"命令:\n"
+"  compare      顯示兩個影像之間的差異\n"
+"  convert      將影像轉換為其他格式或顏色狀態\n"
+"  info         顯示有關影像的一般資訊\n"
+"  relabel      更改影像的色彩狀態而不進行轉換\n"
+"  show         顯示影像\n"
+"\n"
+
+#: tools/gtk-image-tool-compare.c:43 tools/gtk-rendernode-tool-compare.c:67
+msgid "Output file"
+msgstr "輸出檔案"
 
-#: tools/gtk-builder-tool-preview.c:195
-msgid "Preview the file."
-msgstr "預覽檔案。"
+#: tools/gtk-image-tool-compare.c:57
+msgid "Compare two images"
+msgstr "比較兩張影像"
 
-#: tools/gtk-builder-tool-screenshot.c:358
-msgid "Screenshot only the named object"
-msgstr "僅對命名的物件作螢幕快照"
+#: tools/gtk-image-tool-compare.c:70 tools/gtk-image-tool-convert.c:113
+#: tools/gtk-image-tool-info.c:90 tools/gtk-image-tool-relabel.c:109
+#: tools/gtk-image-tool-show.c:141
+#, c-format
+msgid "No image file specified\n"
+msgstr "未指定影像檔案\n"
 
-#: tools/gtk-builder-tool-screenshot.c:360
-msgid "Save as node file instead of png"
-msgstr "另存為節點檔而非 PNG"
+#: tools/gtk-image-tool-compare.c:76
+#, c-format
+msgid "Can only accept two image files\n"
+msgstr "只能接受兩個影像檔\n"
 
-#: tools/gtk-builder-tool-screenshot.c:361
-msgid "Overwrite existing file"
-msgstr "覆寫既有的檔案"
+#: tools/gtk-image-tool-compare.c:85 tools/gtk-rendernode-tool-compare.c:111
+#, c-format
+msgid "Failed to load %s: %s\n"
+msgstr "載入 %s 失敗:%s\n"
+
+#: tools/gtk-image-tool-compare.c:96 tools/gtk-rendernode-tool-compare.c:122
+#, c-format
+msgid "Could not save diff image to %s\n"
+msgstr "無法將差異圖影像儲存到 %s\n"
 
-#: tools/gtk-builder-tool-screenshot.c:377
-msgid "Take a screenshot of the file."
-msgstr "擷取檔案的螢幕快照。"
+#: tools/gtk-image-tool-compare.c:106 tools/gtk-rendernode-tool-compare.c:132
+#, c-format
+msgid "Differences witten to %s.\n"
+msgstr "差異寫入至 %s。\n"
 
-#: tools/gtk-builder-tool-simplify.c:444
+#: tools/gtk-image-tool-compare.c:108 tools/gtk-rendernode-tool-compare.c:134
 #, c-format
-msgid "%s:%d: Couldn’t parse value for property '%s': %s\n"
-msgstr "%s:%d:無法解析「%s」屬性的數值:%s\n"
+msgid "The images are different.\n"
+msgstr "影像是不同的。\n"
 
-#: tools/gtk-builder-tool-simplify.c:653
+#: tools/gtk-image-tool-compare.c:111 tools/gtk-rendernode-tool-compare.c:137
 #, c-format
-msgid "%s:%d: %sproperty %s::%s not found\n"
-msgstr "%s:%d:找不到 %sproperty %s::%s\n"
+msgid "No differences.\n"
+msgstr "沒有不同。\n"
+
+#: tools/gtk-image-tool-convert.c:86
+msgid "Format to use"
+msgstr "要使用的格式"
+
+#: tools/gtk-image-tool-convert.c:86
+msgid "FORMAT"
+msgstr "格式"
+
+#: tools/gtk-image-tool-convert.c:87 tools/gtk-image-tool-relabel.c:84
+msgid "Color state to use"
+msgstr "要使用的色彩狀態"
 
-#: tools/gtk-builder-tool-simplify.c:2290
+#: tools/gtk-image-tool-convert.c:87 tools/gtk-image-tool-relabel.c:84
+msgid "COLORSTATE"
+msgstr "色彩狀態"
+
+#: tools/gtk-image-tool-convert.c:88 tools/gtk-image-tool-relabel.c:85
+msgid "Color state to use, as cicp tuple"
+msgstr "要使用的色彩狀態,作為 cicp 元組"
+
+#: tools/gtk-image-tool-convert.c:88 tools/gtk-image-tool-relabel.c:85
+msgid "CICP"
+msgstr "CICP"
+
+#: tools/gtk-image-tool-convert.c:100
+msgid "Convert the image to a different format or color state."
+msgstr "將影像轉換為其他格式或色彩狀態。"
+
+#: tools/gtk-image-tool-convert.c:119 tools/gtk-image-tool-relabel.c:115
 #, c-format
-msgid "Can’t load “%s”: %s\n"
-msgstr "無法載入「%s」:%s\n"
+msgid "Can only accept a single image file and output file\n"
+msgstr "只能接受單一影像檔和輸出檔\n"
 
-#: tools/gtk-builder-tool-simplify.c:2301
-#: tools/gtk-builder-tool-simplify.c:2307
+#: tools/gtk-image-tool-convert.c:133
 #, c-format
-msgid "Can’t parse “%s”: %s\n"
-msgstr "無法解析「%s」:%s\n"
+msgid ""
+"Not a memory format: %s\n"
+"Possible values:\n"
+"  %s\n"
+msgstr ""
+"不是記憶體格式: %s\n"
+"可能的值:\n"
+"%s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2313
+#: tools/gtk-image-tool-convert.c:150
 #, c-format
-msgid "Can’t parse “%s”\n"
-msgstr "無法解析「%s」\n"
+msgid ""
+"Not a color state: %s\n"
+"Possible values:\n"
+"  %s\n"
+msgstr ""
+"不是色彩狀態: %s\n"
+"可能的值:\n"
+"%s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2337
+#: tools/gtk-image-tool-convert.c:160 tools/gtk-image-tool-relabel.c:140
 #, c-format
-msgid "Failed to read “%s”: %s\n"
-msgstr "無法讀取「%s」:%s\n"
+msgid "Can't specify both --color-state and --cicp\n"
+msgstr "無法同時指定 --color-state 和 --cicp\n"
 
-#: tools/gtk-builder-tool-simplify.c:2343
+#: tools/gtk-image-tool-convert.c:168 tools/gtk-image-tool-relabel.c:148
 #, c-format
-msgid "Failed to write %s: “%s”\n"
-msgstr "無法寫入「%s」:%s\n"
+msgid "Not a supported cicp tuple: %s\n"
+msgstr "不支援的 cicp 元組: %s\n"
 
-#: tools/gtk-builder-tool-simplify.c:2360
-msgid "Replace the file"
-msgstr "取代檔案"
+#: tools/gtk-image-tool-info.c:55
+msgid "Format:"
+msgstr "格式:"
 
-#: tools/gtk-builder-tool-simplify.c:2361
-msgid "Convert from GTK 3 to GTK 4"
-msgstr "從 GTK 3 轉換至 GTK 4"
+#: tools/gtk-image-tool-info.c:56
+msgid "Color state:"
+msgstr "色彩狀態:"
 
-#: tools/gtk-builder-tool-simplify.c:2372
-msgid "Simplify the file."
-msgstr "簡化檔案。"
+#: tools/gtk-image-tool-info.c:77
+msgid "Provide information about the image."
+msgstr "提供有關影像的資訊。"
 
-#: tools/gtk-builder-tool-simplify.c:2385
+#: tools/gtk-image-tool-info.c:96
 #, c-format
-msgid "No .ui file specified\n"
-msgstr "未指定 .ui 檔案\n"
+msgid "Can only accept a single image file\n"
+msgstr "只能接受單一影像檔檔\n"
 
-#: tools/gtk-builder-tool-simplify.c:2391
+#: tools/gtk-image-tool-relabel.c:96
+msgid "Change the color state of the image without conversion."
+msgstr "更改影像的色彩狀態而不進行轉換。"
+
+#: tools/gtk-image-tool-relabel.c:130
 #, c-format
-msgid "Can only simplify a single .ui file without --replace\n"
-msgstr "沒有 --replace 時,只能簡化一個 .ui 檔案\n"
+msgid ""
+"Not a color state: %s\n"
+"Possible values: %s\n"
+msgstr ""
+"不是色彩狀態: %s\n"
+"可能的值: %s\n"
 
-#: tools/gtk-builder-tool-validate.c:269
-msgid "Validate the file."
-msgstr "驗證文件。"
+#: tools/gtk-image-tool-show.c:117 tools/gtk-rendernode-tool-show.c:115
+msgid "Don't add a titlebar"
+msgstr "不要加入標題列"
+
+#: tools/gtk-image-tool-show.c:128
+msgid "Show one or more images."
+msgstr "顯示一張或多張影像。"
+
+#: tools/gtk-image-tool-utils.c:234
+#, c-format
+msgid "cicp must be 4 numbers, separated by /\n"
+msgstr "cicp 必須是 4 個數字,用 / 分隔\n"
 
 #: tools/gtk-launch.c:40
 msgid "Show program version"
@@ -7254,6 +7671,498 @@ msgstr "%s:沒有應用程式 %s"
 msgid "%s: error launching application: %s\n"
 msgstr "%s:執行應用程式時發生錯誤:%s\n"
 
+#: tools/gtk-path-tool.c:35
+#, c-format
+msgid ""
+"Usage:\n"
+"  gtk4-path-tool [COMMAND] [OPTION…] PATH\n"
+"\n"
+"Perform various tasks on paths.\n"
+"\n"
+"Commands:\n"
+"  decompose    Decompose the path\n"
+"  reverse      Reverse the path\n"
+"  restrict     Restrict the path to a segment\n"
+"  show         Display the path in a window\n"
+"  render       Render the path as an image\n"
+"  info         Print information about the path\n"
+"\n"
+msgstr ""
+"用法:\n"
+"  gtk4-path-tool [命令] [選項...]路徑\n"
+"\n"
+"在路徑上執行各種任務。\n"
+"\n"
+"命令:\n"
+"  decompose    分解路徑\n"
+"  reverse      反轉路徑\n"
+"  restrict     限制段的路徑\n"
+"  show         在視窗中顯示路徑\n"
+"  render       將路徑繪製為圖片\n"
+"  info         列印有關路徑的資訊\n"
+"\n"
+
+#: tools/gtk-path-tool-decompose.c:84
+msgid "Allow quadratic Bézier curves"
+msgstr "允許二次貝茲曲線"
+
+#: tools/gtk-path-tool-decompose.c:85
+msgid "Allow cubic Bézier curves"
+msgstr "允許三次貝茲曲線"
+
+#: tools/gtk-path-tool-decompose.c:86
+msgid "Allow conic Bézier curves"
+msgstr "允許圓錐貝茲曲線"
+
+#: tools/gtk-path-tool-decompose.c:87 tools/gtk-path-tool-info.c:88
+#: tools/gtk-path-tool-render.c:125 tools/gtk-path-tool-restrict.c:38
+#: tools/gtk-path-tool-reverse.c:34 tools/gtk-path-tool-show.c:147
+msgid "PATH"
+msgstr "路徑"
+
+#: tools/gtk-path-tool-decompose.c:99
+msgid "Decompose a path."
+msgstr "分解路徑。"
+
+#: tools/gtk-path-tool-decompose.c:112 tools/gtk-path-tool-info.c:113
+#: tools/gtk-path-tool-restrict.c:64 tools/gtk-path-tool-reverse.c:58
+msgid "No paths given."
+msgstr "沒有指定路徑。"
+
+#: tools/gtk-path-tool-decompose.c:140 tools/gtk-path-tool-restrict.c:94
+#: tools/gtk-path-tool-reverse.c:78
+msgid "That didn't work out."
+msgstr "那沒有作用。"
+
+#: tools/gtk-path-tool-info.c:100
+msgid "Print information about a path."
+msgstr "顯示有關路徑的資訊。"
+
+#: tools/gtk-path-tool-info.c:121
+msgid "Path is empty."
+msgstr "路徑為空。"
+
+#: tools/gtk-path-tool-info.c:127
+msgid "Path is closed"
+msgstr "路徑已關閉"
+
+#: tools/gtk-path-tool-info.c:129
+msgid "Path length"
+msgstr "路徑長度"
+
+#: tools/gtk-path-tool-info.c:138
+#, c-format
+msgid "%d contours"
+msgstr "%d 等值線"
+
+#: tools/gtk-path-tool-info.c:140
+#, c-format
+msgid "%d operations"
+msgstr "%d 操作"
+
+#: tools/gtk-path-tool-info.c:144
+#, c-format
+msgid "%d lines"
+msgstr "%d 線條"
+
+#: tools/gtk-path-tool-info.c:149
+#, c-format
+msgid "%d quadratics"
+msgstr "%d 二次函數"
+
+#: tools/gtk-path-tool-info.c:154
+#, c-format
+msgid "%d cubics"
+msgstr "%d ç«‹æ–¹"
+
+#: tools/gtk-path-tool-info.c:159
+#, c-format
+msgid "%d conics"
+msgstr "%d 圓錐"
+
+#: tools/gtk-path-tool-render.c:117 tools/gtk-path-tool-show.c:140
+msgid "Fill the path (the default)"
+msgstr "填滿路徑 (預設值)"
+
+#: tools/gtk-path-tool-render.c:118 tools/gtk-path-tool-show.c:141
+msgid "Stroke the path"
+msgstr "描邊路徑"
+
+#: tools/gtk-path-tool-render.c:119 tools/gtk-path-tool-show.c:142
+msgid "Show path points"
+msgstr "顯示路徑點"
+
+#: tools/gtk-path-tool-render.c:120 tools/gtk-path-tool-show.c:143
+msgid "Show control points"
+msgstr "顯示控制點"
+
+#: tools/gtk-path-tool-render.c:121
+msgid "The output file"
+msgstr "輸出檔案"
+
+#: tools/gtk-path-tool-render.c:122 tools/gtk-path-tool-show.c:144
+msgid "Foreground color"
+msgstr "前景色"
+
+#: tools/gtk-path-tool-render.c:122 tools/gtk-path-tool-render.c:123
+#: tools/gtk-path-tool-render.c:124 tools/gtk-path-tool-show.c:144
+#: tools/gtk-path-tool-show.c:145 tools/gtk-path-tool-show.c:146
+msgid "COLOR"
+msgstr "色彩"
+
+#: tools/gtk-path-tool-render.c:123 tools/gtk-path-tool-show.c:145
+msgid "Background color"
+msgstr "背景色"
+
+#: tools/gtk-path-tool-render.c:124 tools/gtk-path-tool-show.c:146
+msgid "Point color"
+msgstr "指標色彩"
+
+#: tools/gtk-path-tool-render.c:129 tools/gtk-path-tool-show.c:151
+msgid "Fill rule (winding, even-odd)"
+msgstr "填滿規則 (繞線,偶數-奇數)"
+
+#: tools/gtk-path-tool-render.c:129 tools/gtk-path-tool-render.c:133
+#: tools/gtk-path-tool-render.c:134 tools/gtk-path-tool-render.c:135
+#: tools/gtk-path-tool-render.c:136 tools/gtk-path-tool-render.c:137
+#: tools/gtk-path-tool-render.c:138 tools/gtk-path-tool-show.c:151
+#: tools/gtk-path-tool-show.c:155 tools/gtk-path-tool-show.c:156
+#: tools/gtk-path-tool-show.c:157 tools/gtk-path-tool-show.c:158
+#: tools/gtk-path-tool-show.c:159 tools/gtk-path-tool-show.c:160
+msgid "VALUE"
+msgstr "數值"
+
+#: tools/gtk-path-tool-render.c:133 tools/gtk-path-tool-show.c:155
+msgid "Line width (number)"
+msgstr "線條寬度 (數位)"
+
+#: tools/gtk-path-tool-render.c:134 tools/gtk-path-tool-show.c:156
+msgid "Line cap (butt, round, square)"
+msgstr "線條頂點(平頭、圓形、方頭)"
+
+#: tools/gtk-path-tool-render.c:135 tools/gtk-path-tool-show.c:157
+msgid "Line join (miter, miter-clip, round, bevel, arcs)"
+msgstr "線條連接 (斜接、斜接夾、圓形、斜角、圓弧)"
+
+#: tools/gtk-path-tool-render.c:136 tools/gtk-path-tool-show.c:158
+msgid "Miter limit (number)"
+msgstr "斜接限制 (數字)"
+
+#: tools/gtk-path-tool-render.c:137 tools/gtk-path-tool-show.c:159
+msgid "Dash pattern (comma-separated numbers)"
+msgstr "破折號樣式 (逗號分隔的數字)"
+
+#: tools/gtk-path-tool-render.c:138 tools/gtk-path-tool-show.c:160
+msgid "Dash offset (number)"
+msgstr "破折號偏移 (數字)"
+
+#: tools/gtk-path-tool-render.c:161 tools/gtk-path-tool-show.c:172
+msgid "Could not initialize windowing system"
+msgstr "無法初始化視窗系統"
+
+#: tools/gtk-path-tool-render.c:168
+msgid "Render the path to a png image."
+msgstr "將路徑繪製為 png 影像。"
+
+#: tools/gtk-path-tool-render.c:173 tools/gtk-path-tool-show.c:183
+msgid "Options related to filling"
+msgstr "與填滿相關的選項"
+
+#: tools/gtk-path-tool-render.c:174 tools/gtk-path-tool-show.c:184
+msgid "Show help for fill options"
+msgstr "顯示填滿選項的求助資訊"
+
+#: tools/gtk-path-tool-render.c:181 tools/gtk-path-tool-show.c:191
+msgid "Options related to stroking"
+msgstr "與描邊相關的選項"
+
+#: tools/gtk-path-tool-render.c:182 tools/gtk-path-tool-show.c:192
+msgid "Show help for stroke options"
+msgstr "顯示描邊選項的求助"
+
+#: tools/gtk-path-tool-render.c:199 tools/gtk-path-tool-show.c:209
+msgid "No path specified"
+msgstr "沒有指定路徑"
+
+#: tools/gtk-path-tool-render.c:205
+msgid "Can only render a single path"
+msgstr "只能呈現單一路徑"
+
+#: tools/gtk-path-tool-render.c:250 tools/gtk-path-tool-show.c:221
+msgid "fill rule"
+msgstr "填滿規則"
+
+#: tools/gtk-path-tool-render.c:255 tools/gtk-path-tool-show.c:226
+msgid "line cap"
+msgstr "線條頂點"
+
+#: tools/gtk-path-tool-render.c:256 tools/gtk-path-tool-show.c:227
+msgid "line join"
+msgstr "線條銜接"
+
+#: tools/gtk-path-tool-render.c:310
+#, c-format
+msgid "Saving png to '%s' failed"
+msgstr "將 png 儲存到「%s」失敗"
+
+#: tools/gtk-path-tool-render.c:317
+#, c-format
+msgid "Output written to '%s'."
+msgstr "輸出寫入至「%s」。"
+
+#: tools/gtk-path-tool-restrict.c:36
+msgid "Beginning of segment"
+msgstr "區段開始"
+
+#: tools/gtk-path-tool-restrict.c:36 tools/gtk-path-tool-restrict.c:37
+msgid "LENGTH"
+msgstr "長度"
+
+#: tools/gtk-path-tool-restrict.c:37
+msgid "End of segment"
+msgstr "區段結尾"
+
+#: tools/gtk-path-tool-restrict.c:51
+msgid "Restrict a path to a segment."
+msgstr "限制區段的路徑。"
+
+#: tools/gtk-path-tool-reverse.c:45
+msgid "Reverse a path."
+msgstr "倒轉路徑。"
+
+#: tools/gtk-path-tool-show.c:46 tools/gtk-path-tool-show.c:88
+msgid "Path Preview"
+msgstr "路徑預覽"
+
+#: tools/gtk-path-tool-show.c:180
+msgid "Display the path."
+msgstr "顯示路徑。"
+
+#: tools/gtk-path-tool-show.c:215
+msgid "Can only show a single path"
+msgstr "只能顯示單一路徑"
+
+#: tools/gtk-path-tool-utils.c:58
+#, c-format
+msgid "Failed to read from standard input: %s\n"
+msgstr "無法讀取標準輸入:%s\n"
+
+#: tools/gtk-path-tool-utils.c:64
+#, c-format
+msgid "Error reading from standard input: %s\n"
+msgstr "從標準輸入讀取時發生錯誤:%s\n"
+
+#: tools/gtk-path-tool-utils.c:83
+#, c-format
+msgid "Failed to parse '%s' as path.\n"
+msgstr "無法將「%s」解析為路徑。\n"
+
+#: tools/gtk-path-tool-utils.c:109
+#, c-format
+msgid "Failed to parse '%s' as %s."
+msgstr "無法將「%s」解析為 %s。"
+
+#: tools/gtk-path-tool-utils.c:111
+msgid "Possible values: "
+msgstr "可能的數值: "
+
+#: tools/gtk-path-tool-utils.c:135
+#, c-format
+msgid "Could not parse '%s' as color"
+msgstr "無法將「%s」解析為色彩"
+
+#: tools/gtk-path-tool-utils.c:163
+#, c-format
+msgid "Failed to parse '%s' as number"
+msgstr "無法將「%s」 解析為數字"
+
+#: tools/gtk-rendernode-tool.c:35
+#, c-format
+msgid ""
+"Usage:\n"
+"  gtk4-rendernode-tool [COMMAND] [OPTION…] FILE\n"
+"\n"
+"Perform various tasks on GTK render nodes.\n"
+"\n"
+"Commands:\n"
+"  benchmark    Benchmark rendering of a node\n"
+"  compare      Compare nodes or images\n"
+"  extract      Extract data urls\n"
+"  info         Provide information about the node\n"
+"  show         Show the node\n"
+"  render       Take a screenshot of the node\n"
+"\n"
+msgstr ""
+"用法:\n"
+"gtk4-rendernode-tool [命令] [選項...]檔案\n"
+"\n"
+"在 GTK 繪製節點上執行各種任務。\n"
+"\n"
+"命令:\n"
+"  benchmark    節點的基準測試繪製\n"
+"  compare      比較節點或影像\n"
+"  extract      提取數據 urls\n"
+"  info         提供有關節點的資訊\n"
+"  show         顯示節點\n"
+"  render       截取節點的快照\n"
+"\n"
+
+#: tools/gtk-rendernode-tool-benchmark.c:96
+msgid "Add renderer to benchmark"
+msgstr "將繪製器加入到基準測試中"
+
+#: tools/gtk-rendernode-tool-benchmark.c:96
+#: tools/gtk-rendernode-tool-compare.c:65
+#: tools/gtk-rendernode-tool-render.c:254
+msgid "RENDERER"
+msgstr "繪製器"
+
+#: tools/gtk-rendernode-tool-benchmark.c:97
+msgid "Number of runs with each renderer"
+msgstr "每個繪製器的運行次數"
+
+#: tools/gtk-rendernode-tool-benchmark.c:97
+msgid "RUNS"
+msgstr "執行"
+
+#: tools/gtk-rendernode-tool-benchmark.c:98
+msgid "Don’t download result/wait for GPU to finish"
+msgstr "不下載結果/等待 GPU 完成"
+
+#: tools/gtk-rendernode-tool-benchmark.c:116
+msgid "Benchmark rendering of a .node file."
+msgstr ".node 檔案的基準繪製。"
+
+#: tools/gtk-rendernode-tool-benchmark.c:129
+#: tools/gtk-rendernode-tool-extract.c:316 tools/gtk-rendernode-tool-info.c:248
+#: tools/gtk-rendernode-tool-render.c:283 tools/gtk-rendernode-tool-show.c:144
+#, c-format
+msgid "No .node file specified\n"
+msgstr "未指定 .node 檔案\n"
+
+#: tools/gtk-rendernode-tool-benchmark.c:135
+#, c-format
+msgid "Can only benchmark a single .node file\n"
+msgstr "只能對單一 .node 檔案進行基準測試\n"
+
+#: tools/gtk-rendernode-tool-compare.c:65
+#: tools/gtk-rendernode-tool-render.c:254
+msgid "Renderer to use"
+msgstr "要使用的繪製器"
+
+#: tools/gtk-rendernode-tool-compare.c:70
+msgid "FILE1 FILE2"
+msgstr "FILE1 FILE2"
+
+#: tools/gtk-rendernode-tool-compare.c:82
+msgid "Compare .node or .png files."
+msgstr "比較 .node 或 .png 檔案。"
+
+#: tools/gtk-rendernode-tool-compare.c:95
+#, c-format
+msgid "Must specify two files\n"
+msgstr "必須指定兩個檔案\n"
+
+#: tools/gtk-rendernode-tool-compare.c:102
+#: tools/gtk-rendernode-tool-render.c:209
+#, c-format
+msgid "Failed to create renderer: %s\n"
+msgstr "無法建立繪製器: %s\n"
+
+#: tools/gtk-rendernode-tool-extract.c:73
+#: tools/gtk-rendernode-tool-extract.c:149
+#, c-format
+msgid "Failed to write %s\n"
+msgstr "寫入 %s 失敗\n"
+
+#: tools/gtk-rendernode-tool-extract.c:292
+msgid "Directory to use"
+msgstr "要使用的目錄"
+
+#: tools/gtk-rendernode-tool-extract.c:292
+msgid "DIRECTORY"
+msgstr "目錄"
+
+#: tools/gtk-rendernode-tool-extract.c:293
+msgid "Be verbose"
+msgstr "詳細顯示"
+
+#: tools/gtk-rendernode-tool-extract.c:303
+msgid "Extract data urls from the render node."
+msgstr "從繪製節點提取資料網址。"
+
+#: tools/gtk-rendernode-tool-extract.c:322 tools/gtk-rendernode-tool-info.c:254
+#, c-format
+msgid "Can only accept a single .node file\n"
+msgstr "只能接受單一 .node 檔案\n"
+
+#: tools/gtk-rendernode-tool-info.c:193
+msgid "Number of nodes:"
+msgstr "節點數:"
+
+#: tools/gtk-rendernode-tool-info.c:200
+msgid "Depth:"
+msgstr "深度:"
+
+#: tools/gtk-rendernode-tool-info.c:203
+msgid "Bounds:"
+msgstr "邊界︰"
+
+#: tools/gtk-rendernode-tool-info.c:204
+msgid "Origin:"
+msgstr "來源:"
+
+#: tools/gtk-rendernode-tool-info.c:208 tools/gtk-rendernode-tool-info.c:214
+msgid "Opaque part:"
+msgstr "不透明部分:"
+
+#: tools/gtk-rendernode-tool-info.c:235
+msgid "Provide information about the render node."
+msgstr "提供有關繪製節點的資訊。"
+
+#: tools/gtk-rendernode-tool-render.c:170
+#, c-format
+msgid ""
+"File %s exists.\n"
+"If you want to overwrite, specify the filename.\n"
+msgstr ""
+"檔案 %s 已存在。\n"
+"如果要覆蓋,請指定檔案名稱。\n"
+
+#: tools/gtk-rendernode-tool-render.c:184
+#: tools/gtk-rendernode-tool-render.c:196
+#, c-format
+msgid "Failed to generate SVG: %s\n"
+msgstr "無法產生 SVG: %s\n"
+
+#: tools/gtk-rendernode-tool-render.c:270
+msgid "Render a .node file to an image."
+msgstr "將 .node 檔案繪製為影像。"
+
+#: tools/gtk-rendernode-tool-render.c:289
+#, c-format
+msgid "Can only render a single .node file to a single output file\n"
+msgstr "只能將單一 .node 檔案繪製為單一輸出檔案\n"
+
+#: tools/gtk-rendernode-tool-show.c:131
+msgid "Show the render node."
+msgstr "顯示繪製節點。"
+
+#: tools/gtk-rendernode-tool-show.c:150
+#, c-format
+msgid "Can only preview a single .node file\n"
+msgstr "只能預覽單一 .node 檔案\n"
+
+#: tools/gtk-rendernode-tool-utils.c:54
+#, c-format
+msgid "Error at %s: %s\n"
+msgstr "%s 處的錯誤: %s\n"
+
+#: tools/gtk-rendernode-tool-utils.c:72
+#, c-format
+msgid "Failed to load node file: %s\n"
+msgstr "無法載入節點檔案: %s\n"
+
 #: tools/updateiconcache.c:1391
 #, c-format
 msgid "Failed to write header\n"
@@ -7337,22 +8246,22 @@ msgstr "關閉詳細輸出"
 msgid "Validate existing icon cache"
 msgstr "核對既存的圖示快取"
 
-#: tools/updateiconcache.c:1724
+#: tools/updateiconcache.c:1725
 #, c-format
 msgid "File not found: %s\n"
 msgstr "找不到檔案:%s\n"
 
-#: tools/updateiconcache.c:1730
+#: tools/updateiconcache.c:1731
 #, c-format
 msgid "Not a valid icon cache: %s\n"
 msgstr "不是有效的快取:%s\n"
 
-#: tools/updateiconcache.c:1743
+#: tools/updateiconcache.c:1744
 #, c-format
 msgid "No theme index file.\n"
 msgstr "沒有主題索引檔案。\n"
 
-#: tools/updateiconcache.c:1747
+#: tools/updateiconcache.c:1748
 #, c-format
 msgid ""
 "No theme index file in “%s”.\n"
@@ -7361,6 +8270,95 @@ msgstr ""
 "在「%s」中沒有布景主題的索引檔。\n"
 "如果您想在這裡建立圖示快取,請使用 --ignore-theme-index 選項。\n"
 
+#~ msgid "Show _Size Column"
+#~ msgstr "顯示大小欄(_S)"
+
+#~ msgid "Show T_ype Column"
+#~ msgstr "顯示類型欄(_Y)"
+
+#~ msgid "Tab list"
+#~ msgstr "分頁列表"
+
+#~ msgid "Tab"
+#~ msgstr "分頁"
+
+#~ msgctxt "GL version"
+#~ msgid "Disabled"
+#~ msgstr "已停用"
+
+#~ msgctxt "GL vendor"
+#~ msgid "Disabled"
+#~ msgstr "已停用"
+
+#~ msgctxt "GL vendor"
+#~ msgid "None"
+#~ msgstr "沒有"
+
+#~ msgid "Allocation"
+#~ msgstr "分配"
+
+#~ msgid "Backend does not support window scaling"
+#~ msgstr "後端不支援視窗縮放"
+
+#~ msgid "Window Scaling"
+#~ msgstr "視窗縮放"
+
+#~ msgid "Show fps overlay"
+#~ msgstr "顯示 fps 疊層"
+
+#~ msgid "Simulate Touchscreen"
+#~ msgstr "模擬觸控螢幕"
+
+#, c-format
+#~ msgid "Unspecified error decoding media"
+#~ msgstr "解碼媒體時發生未指定的錯誤"
+
+#, c-format
+#~ msgid "Cannot find decoder: %s"
+#~ msgstr "找不到解碼器:%s"
+
+#~ msgid "Failed to allocate a codec context"
+#~ msgstr "無法分配編解碼器情境"
+
+#, c-format
+#~ msgid "Cannot find encoder: %s"
+#~ msgstr "找不到編碼器:%s"
+
+#~ msgid "Cannot add new stream"
+#~ msgstr "無法加入新的串流"
+
+#~ msgid "Failed to allocate an audio frame"
+#~ msgstr "無法分配音訊格幀"
+
+#~ msgid "Not enough memory"
+#~ msgstr "記憶體不足"
+
+#~ msgid "Could not allocate resampler context"
+#~ msgstr "無法分配重新取樣器情境"
+
+#~ msgid "No audio output found"
+#~ msgstr "找不到音訊輸出裝置"
+
+#~ msgid "Print to LPR"
+#~ msgstr "列印至 LPR"
+
+#~ msgid "Pages Per Sheet"
+#~ msgstr "每張紙的頁數"
+
+#~ msgid "Command Line"
+#~ msgstr "命令行"
+
+#~ msgid "Take a screenshot of the file."
+#~ msgstr "擷取檔案的螢幕快照。"
+
+#, c-format
+#~ msgid "%s:%d: %sproperty %s::%s not found\n"
+#~ msgstr "%s:%d:找不到 %sproperty %s::%s\n"
+
+#, c-format
+#~ msgid "Can’t parse “%s”\n"
+#~ msgstr "無法解析「%s」\n"
+
 #~ msgid "Other application…"
 #~ msgstr "其他應用程式…"
 
@@ -7717,10 +8715,6 @@ msgstr ""
 #~ msgid "Unknown"
 #~ msgstr "未知"
 
-#~ msgctxt "Script"
-#~ msgid "Balinese"
-#~ msgstr "峇里文"
-
 #~ msgctxt "Script"
 #~ msgid "Cuneiform"
 #~ msgstr "楔形文字"
@@ -8124,9 +9118,6 @@ msgstr ""
 #~ msgid "Size of the palette in 8 bit mode"
 #~ msgstr "8 位元模式表示的色盤的大小"
 
-#~ msgid "COLORS"
-#~ msgstr "色彩"
-
 #~ msgctxt "Action description"
 #~ msgid "Toggles the cell"
 #~ msgstr "切換儲存格"
@@ -8325,10 +9316,6 @@ msgstr ""
 #~ msgid "P_ause"
 #~ msgstr "暫停(_A)"
 
-#~ msgctxt "Stock label, media"
-#~ msgid "_Play"
-#~ msgstr "播放(_P)"
-
 #~ msgctxt "Stock label, media"
 #~ msgid "_Record"
 #~ msgstr "錄製(_R)"
@@ -8357,10 +9344,6 @@ msgstr ""
 #~ msgid "_Print"
 #~ msgstr "列印(_P)"
 
-#~ msgctxt "Stock label"
-#~ msgid "Print Pre_view"
-#~ msgstr "預覽列印(_V)"
-
 #~ msgctxt "Stock label"
 #~ msgid "_Properties"
 #~ msgstr "屬性(_P)"
@@ -8542,9 +9525,6 @@ msgstr ""
 #~ msgid "Lighter Gray"
 #~ msgstr "較淡灰色"
 
-#~ msgid "Custom color"
-#~ msgstr "自訂色彩"
-
 #~ msgid "Create a custom color"
 #~ msgstr "建立自訂色彩"
 
@@ -8611,9 +9591,6 @@ msgstr ""
 #~ msgid "Show Widget Resizes"
 #~ msgstr "顯示元件重設大小"
 
-#~ msgid "Color Name"
-#~ msgstr "色彩名稱"
-
 #~ msgid "Font Family"
 #~ msgstr "字族"
 
@@ -8626,9 +9603,6 @@ msgstr ""
 #~ msgid "Time of print"
 #~ msgstr "列印時刻"
 
-#~ msgid "Volume"
-#~ msgstr "音量"
-
 #~ msgid "Turns volume up or down"
 #~ msgstr "提高或降低音量"
 
@@ -8656,12 +9630,6 @@ msgstr ""
 #~ msgid "Forget association"
 #~ msgstr "消除關聯"
 
-#~ msgid "Packing property %s::%s not found\n"
-#~ msgstr "找不到包裝屬性 %s::%s\n"
-
-#~ msgid "Cell property %s::%s not found\n"
-#~ msgstr "找不到儲存格屬性 %s::%s\n"
-
 #~ msgctxt "year measurement template"
 #~ msgid "2000"
 #~ msgstr "2000"
@@ -9110,9 +10078,6 @@ msgstr ""
 #~ msgid "Transparency of the color."
 #~ msgstr "目前選擇顏色的透明度。"
 
-#~ msgid "Color _name:"
-#~ msgstr "顏色名稱(_N):"
-
 #~ msgid ""
 #~ "You can enter an HTML-style hexadecimal color value, or simply a color "
 #~ "name such as “orange” in this entry."
diff --git a/subprojects/wayland-protocols.wrap b/subprojects/wayland-protocols.wrap
index 8e82a5b7683843c01a53653756706d5530d3d711..e5946f39d8fd7c11c0d0e4a4640b0377a6ecacf9 100644
--- a/subprojects/wayland-protocols.wrap
+++ b/subprojects/wayland-protocols.wrap
@@ -1,5 +1,5 @@
 [wrap-git]
 directory=wayland-protocols
 url=https://gitlab.freedesktop.org/wayland/wayland-protocols.git
-revision=1.36
+revision=1.41
 depth=1
diff --git a/subprojects/wayland-protocols/.editorconfig b/subprojects/wayland-protocols/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..7e0c0a0fc72a73d75e622d33e22b98f63c89a631
--- /dev/null
+++ b/subprojects/wayland-protocols/.editorconfig
@@ -0,0 +1,6 @@
+root = true
+
+[*.xml]
+indent_style = space
+indent_size = 2
+tab_width = 8
diff --git a/subprojects/wayland-protocols/.gitlab-ci.yml b/subprojects/wayland-protocols/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..5c9e82378da51c553f9cf6604346862b6e726189
--- /dev/null
+++ b/subprojects/wayland-protocols/.gitlab-ci.yml
@@ -0,0 +1,71 @@
+.templates_sha: &template_sha d11c0dd4c1c9a69c14b4af9b50cdd12b89d24672
+
+include:
+  - project: 'freedesktop/ci-templates'
+    ref: *template_sha
+    file: '/templates/debian.yml'
+  - project: 'freedesktop/ci-templates'
+    ref: *template_sha
+    file: '/templates/ci-fairy.yml'
+
+stages:
+  - review
+  - containers-build
+  - test
+
+variables:
+  FDO_UPSTREAM_REPO: wayland/wayland-protocols
+
+workflow:
+  rules:
+    - if: $CI_PIPELINE_SOURCE == "merge_request_event"
+    - if: $CI_COMMIT_BRANCH && $CI_OPEN_MERGE_REQUESTS
+      when: never
+    - if: $CI_COMMIT_BRANCH
+
+.debian:
+  variables:
+    FDO_DISTRIBUTION_VERSION: bookworm
+    FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config meson git ca-certificates libffi-dev libexpat1-dev libxml2-dev'
+    FDO_DISTRIBUTION_TAG: '2024-09-05.0'
+    FDO_DISTRIBUTION_EXEC: 'env FDO_CI_CONCURRENT=${FDO_CI_CONCURRENT} ./.gitlab-ci/debian-install.sh'
+
+check-commit:
+  extends:
+    - .fdo.ci-fairy
+  stage: review
+  script:
+    - ci-fairy check-commits --signed-off-by --junit-xml=results.xml
+  variables:
+    GIT_DEPTH: 100
+  rules:
+    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
+      when: always
+    - when: never
+  artifacts:
+    reports:
+      junit: results.xml
+
+container_build:
+  extends:
+    - .debian
+    - .fdo.container-build@debian
+  stage: containers-build
+  variables:
+    GIT_STRATEGY: none
+
+test-meson:
+  stage: test
+  extends:
+    - .debian
+    - .fdo.distribution-image@debian
+  script:
+    - meson build
+    - ninja -C build
+    - meson test -C build
+    - ninja -C build install
+  artifacts:
+    name: wayland-protocols-$CI_COMMIT_SHA
+    when: always
+    paths:
+    - $CI_PROJECT_DIR/build/meson-logs
diff --git a/subprojects/wayland-protocols/.gitlab-ci/debian-install.sh b/subprojects/wayland-protocols/.gitlab-ci/debian-install.sh
new file mode 100755
index 0000000000000000000000000000000000000000..a66624f8cde994b2761500a29cbfe39a386cae3a
--- /dev/null
+++ b/subprojects/wayland-protocols/.gitlab-ci/debian-install.sh
@@ -0,0 +1,14 @@
+#!/bin/sh -eux
+
+# Note: don't forget to bump FDO_DISTRIBUTION_TAG when editing this file!
+
+git clone --branch 1.23.1 --depth=1 https://gitlab.freedesktop.org/wayland/wayland
+cd wayland/
+git show -s HEAD
+meson build/ -Dtests=false -Ddocumentation=false
+ninja -j${FDO_CI_CONCURRENT:-4} -C build/ install
+cd ..
+rm -rf wayland/
+
+echo "/usr/local/lib" >/etc/ld.so.conf.d/local.conf
+ldconfig
diff --git a/subprojects/wayland-protocols/.gitlab/merge_request_templates/New protocol.md b/subprojects/wayland-protocols/.gitlab/merge_request_templates/New protocol.md
new file mode 100644
index 0000000000000000000000000000000000000000..8c0880bc3bb22967eac43cba56a8597546438144
--- /dev/null
+++ b/subprojects/wayland-protocols/.gitlab/merge_request_templates/New protocol.md	
@@ -0,0 +1,9 @@
+
+
+#### Requirements for merging
+
+- [ ] Review
+- [ ] Implementations
+- [ ] ACKs from members
+
+/label ~"New Protocol" ~"In 30 day discussion period" ~"Needs acks" ~"Needs implementations" ~"Needs review"
diff --git a/subprojects/wayland-protocols/.mailmap b/subprojects/wayland-protocols/.mailmap
new file mode 100644
index 0000000000000000000000000000000000000000..bdb791e72a11b2715f0b02257e505e9e57ba3115
--- /dev/null
+++ b/subprojects/wayland-protocols/.mailmap
@@ -0,0 +1,3 @@
+Faith Ekstrand <faith@gfxstrand.net> <jason@jlekstrand.net>
+Faith Ekstrand <faith@gfxstrand.net> <jason.ekstrand@intel.com>
+Faith Ekstrand <faith@gfxstrand.net> <jason.ekstrand@collabora.com>
diff --git a/subprojects/wayland-protocols/COPYING b/subprojects/wayland-protocols/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..8ab3291e38567bf638567900ccf84fc1330c1cd9
--- /dev/null
+++ b/subprojects/wayland-protocols/COPYING
@@ -0,0 +1,33 @@
+Copyright © 2008-2013 Kristian Høgsberg
+Copyright © 2010-2013 Intel Corporation
+Copyright © 2013      Rafael Antognolli
+Copyright © 2013      Jasper St. Pierre
+Copyright © 2014      Jonas Ådahl
+Copyright © 2014      Jason Ekstrand
+Copyright © 2014-2015 Collabora, Ltd.
+Copyright © 2015      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.
+
+---
+
+The above is the version of the MIT "Expat" License used by X.org:
+
+    http://cgit.freedesktop.org/xorg/xserver/tree/COPYING
diff --git a/subprojects/wayland-protocols/GOVERNANCE.md b/subprojects/wayland-protocols/GOVERNANCE.md
new file mode 100644
index 0000000000000000000000000000000000000000..407cd50515434befa4cf6de830baff908cd4eeef
--- /dev/null
+++ b/subprojects/wayland-protocols/GOVERNANCE.md
@@ -0,0 +1,217 @@
+# wayland-protocols governance
+
+This document governs the maintenance of wayland-protocols and serves to outline
+the broader process for standardization of protocol extensions in the Wayland
+ecosystem.
+
+## 1. Membership
+
+Membership in wayland-protocols is offered to stakeholders in the Wayland
+ecosystem who have an interest in participating in protocol extension
+standardization.
+
+### 1.1. Membership requirements
+
+1. Membership is extended to projects, rather than individuals.
+2. Member projects represent general-purpose projects with a stake in multiple
+   Wayland protocols (e.g. compositors, GUI toolkits, etc), rather than
+   special-purpose applications with a stake in only one or two.
+3. Each member project must provide named individuals as point of contact
+   for that project who can be reached to discuss protocol-related matters.
+4. During a vote, if any points-of-contact for the same member project
+   disagree, the member project's vote is considered blank.
+
+### 1.2. Becoming a member
+
+1. New member projects who meet the criteria outlined in 1.1 are established by
+   invitation from an existing member. Projects hoping to join should reach out
+   to an existing member project or point of contact, asking for this
+   invitation.
+2. Prospective new member projects shall file a merge request tagged
+   `governance` adding themselves to the list in `MEMBERS.md`, noting their
+   sponsor member.
+3. A point of contact for the sponsor member shall respond acknowledging their
+   sponsorship of the membership.
+4. A 14 day discussion period for comments from wayland-protocols members will
+   be held.
+5. At the conclusion of the discussion period, the new membership is
+   established unless their application was NACKed by a 1/2 majority of all
+   existing member projects.
+6. Member projects may vary their point(s) of contact by proposing the addition
+   and/or removal of points of contact in a merge request tagged `governance`,
+   subject to approval as in points 4 and 5 above.
+
+### 1.3. Ceasing membership
+
+1. A member project, or point of contact, may step down by submitting a merge
+   request tagged `governance` removing themselves from `MEMBERS.md`.
+2. A removal vote may be called for by an existing member project or point of
+   contact, by filing a merge request tagged `governance`, removing the
+   specific member project or point of contact from `MEMBERS.md`. This begins a
+   14 day voting & discussion period.
+3. At the conclusion of the voting period, the member is removed if the votes
+   total 2/3rds of all current member projects.
+4. Removed members are not eligible to apply for membership again for a period
+   of 1 year.
+5. Following a failed vote, the member project who called for the vote cannot
+   call for a re-vote or propose any other removal for 90 days.
+
+## 2. Protocols
+
+### 2.1. Protocol namespaces
+
+1. Namespaces are implemented in practice by prefixing each interface name in a
+   protocol definition (XML) with the namespace name, and an underscore (e.g.
+   "xdg_wm_base").
+2. Protocols in a namespace may optionally use the namespace followed by a dash
+   in the name (e.g. "xdg-shell").
+3. The "xdg" namespace is established for protocols letting clients
+   configure their surfaces as "windows", allowing clients to affect how they
+   are managed.
+4. The "wp" namespace is established for protocols generally useful to Wayland
+   implementations (i.e. "plumbing" protocols).
+5. The "ext" namespace is established as a general catch-all for protocols that
+   fit into no other namespace.
+
+#### 2.1.1 Experimental protocol namespacing
+
+1. Experimental protocols begin with the "xx" namespace and do not include any relation
+   to namespaces specified in section 2.1.
+2. Namespacing of experimental protocols is determined upon promotion.
+
+### 2.2. Protocol inclusion requirements
+
+1. All protocols found in the "xdg" and "wp" namespaces at the time of writing
+   are grandfathered into their respective namespace without further discussion.
+2. Protocols in the "xdg" and "wp" namespace are eligible for inclusion only if
+   ACKed by at least 3 members.
+3. Protocols in the "xdg" and "wp" namespace are ineligible for inclusion if
+   NACKed by any member.
+4. Protocols in the "xdg" and "wp" namespaces must have at least 3 open-source
+   implementations (either 1 client + 2 servers, or 2 clients + 1 server) to be
+   eligible for inclusion.
+5. Protocols in the "ext" namespace are eligible for inclusion only if ACKed by
+   at least 2 member projects.
+6. Protocols in the "ext" namespace must have at least one open-source client &
+   one open-source server implementation to be eligible for inclusion.
+7. "Open-source" is defined as distributed with an Open Source Initiative
+   approved license.
+8. All protocols are eligible for inclusion only if formally reviewed in-depth
+   by at least one member project. For the purposes of this clause, reviews from
+   the individual protocol author(s) are disregarded.
+
+#### 2.2.1 Experimental protocol inclusion requirements
+
+1. Experimental protocols must be valid XML which can be consumed by wayland-scanner.
+2. All such protocols must be created with a proposal merge request outlining the
+   need for and purpose of the protocol.
+3. All such protocols must be clearly tagged as experimental.
+
+### 2.3. Introducing new protocols
+
+1. A new protocol may be proposed by submitting a merge request to the
+   wayland-protocols Gitlab repository.
+2. Protocol proposal posts must include justification for their inclusion in
+   their namespace per the requirements outlined in section 2.2.
+3. An indefinite discussion period for comments from wayland-protocols members
+   will be held, with a minimum duration of 30 days beginning from the time when
+   the MR was opened. Protocols which require a certain level of implementation
+   status, ACKs from members, and so on, should use this time to acquire them.
+4. When the proposed protocol meets all requirements for inclusion per section
+   2.2, and the minimum discussion period has elapsed, the sponsoring member may
+   merge their changes into the wayland-protocol repository.
+5. Amendments to existing protocols may be proposed by the same process, with
+   no minimum discussion period.
+6. Declaring a protocol stable may be proposed by the same process, with the
+   regular 30 day minimum discussion period.
+7. A member project has the option to invoke the 30 day discussion period for any
+   staging protocol proposal which has been in use without substantive changes
+   for a period of one year.
+
+### 2.4. Development stalemate resolution
+
+1. In the event that a discussion thread reaches a stalemate which cannot be
+   resolved, a tie-breaking vote can be requested by the protocol author or
+   any member project.
+2. All member projects are eligible to vote in stalemate tie-breakers. Each project
+   may cast a single vote.
+3. Tie-breaker voting periods last no fewer than seven days.
+4. Tie-breaker votes must be between two choices.
+5. Any member project may elect to extend the voting period by an additional seven days.
+   This option may only be invoked once per member project per tie-breaker and shall
+   not be used without cause.
+6. At the end of the voting period, the choice with the most votes is declared
+   the winner, and development proceeds using that idea.
+7. In the event of a tie, the protocol author casts the deciding vote.
+
+### 2.5. Representation of non-members
+
+1. A protocol proposed by a non-member inherently begins at a
+   responsibility deficit as compared to one initiated by a member project.
+2. To address this, any protocol proposed by a non-member intended for `staging/` or
+   `stable/` may have a sponsor designated from a member project
+3. The sponsor should have a strong understanding of the protocol they
+   represent as well as the time required to drive it.
+4. The sponsor shall be responsible for representing the protocol and its
+   author in all cases which require membership, e.g., stalemate voting.
+5. The member projects shall provide a sponsor for a non-member project upon request.
+6. An author may make a one-time request for a different sponsor at any point.
+
+### 2.3.1 Introducing new experimental protocols
+
+1. Experimental protocols are merged into wayland-protocols after a two
+   week review period upon the author's request unless a NACK has been given or
+   a WAIT is in progress.
+2. If all NACKs are removed from an experimental protocol, the two week review period is
+   started anew.
+
+### 2.3.2 Experimental protocol removal policy
+
+1. Unmaintained experimental protocols are removed after a three month period of
+   inactivity by its author, as determined by all of the following being true:
+   * No changes have been made to the protocol by the author
+   * No comments have been made to the protocol merge request by the author
+   * No mails have been sent to the mailing list persuant to the protocol by the author
+2. A notification of intent to remove shall be given to the author in the protocol
+   merge request, and the protocol shall only be removed following a one week grace period
+   of continued inactivity.
+
+### 2.3.3 Experimental protocol promotion
+
+1. A merged experimental protocol may be promoted to `staging/`
+   upon request if it meets the requirements for landing as a
+   `staging/` protocol.
+2. Upon promotion, an experimental protocol is removed from `experimental/`.
+
+## 3. NACKs
+
+1. Expressing a NACK is the sole purview of listed points-of-contact from member projects,
+   as specified in MEMBERS.md.
+   A NACK must be grounded in technical reasoning, and it constitutes the final resort
+   to block protocols which would harm the ecosystem or the project.
+2. Any non-point-of-contact mentioning a NACK on a non-governance protocol issue, merge request,
+   or mailing list thread, for any purpose, shall be banned from the project for a
+   period of no fewer than three months. Additional penalties for repeat infractions
+   may be imposed at the discretion of a membership majority. A warning, delivered in private
+   if at all possible, shall be issued instead of a ban for first-time violations of this rule.
+   Any comments violating this rule shall be explicitly marked by member projects to indicate that
+   the NACK is invalid and has no bearing.
+3. Any member project mentioning a NACK on a non-governance protocol issue, merge request,
+   or mailing list thread, for any reason that may be considered non-technical,
+   may undergo trial by eligible member projects upon receiving a written accusation of
+   impropriety. This accusation may be public or private, and it may occur by any method
+   of written communication.
+   If this NACK is determined by 2/3 majority of eligible member projects to be used improperly,
+   the offending point-of-contact shall be removed.
+4. Eligible member projects during such review periods are those who have opted not to recuse themselves.
+
+## 4. Amending this document
+
+1. An amendment to this document may be proposed by any member project by
+   submitting a merge request on Gitlab.
+2. A 30 day discussion period for comments from wayland-protocols members will
+   be held.
+3. At the conclusion of the discussion period, an amendment will become
+   effective if it's ACKed by at least 2/3rds of all wayland-protocols member
+   projects, and NACKed by none. The sponsoring member may merge their change
+   to the wayland-protocols repository at this point.
diff --git a/subprojects/wayland-protocols/MEMBERS.md b/subprojects/wayland-protocols/MEMBERS.md
new file mode 100644
index 0000000000000000000000000000000000000000..2946f817c4ae40077567e9e6c236ee9db3b68b67
--- /dev/null
+++ b/subprojects/wayland-protocols/MEMBERS.md
@@ -0,0 +1,17 @@
+# wayland-protocols members
+
+- GTK/Mutter: Jonas Ã…dahl <jadahl@gmail.com> (@jadahl),
+  Carlos Garnacho <carlosg@gnome.org> (@carlosg)
+- KWin: Vlad Zahorodnii <vlad.zahorodnii@kde.org> (@zzag),
+  David Edmundson <david@davidedmundson.co.uk> (@davidedmundson)
+- mesa: Daniel Stone <daniel@fooishbar.org> (@daniels),
+  Mike Blumenkrantz <michael.blumenkrantz@gmail.com> (@zmike)
+- Mir: Christopher James Halse Rogers <raof@ubuntu.com> (@RAOF),
+  Alan Griffiths <alan.griffiths@canonical.com>
+- Qt: Eskil Abrahamsen Blomfeldt <eskil.abrahamsen-blomfeldt@qt.io>
+  (@eskilblomfeldt)
+- Smithay/Cosmic: Victoria Brekenfeld <wayland@drakulix.de> (@drakulix)
+- Weston: Pekka Paalanen <pekka.paalanen@collabora.com> (@pq),
+  Derek Foreman <derek.foreman@collabora.com> (@derekf)
+- wlroots/Sway: Simon Ser <contact@emersion.fr> (@emersion),
+  Simon Zeni <simon@bl4ckb0ne.ca> (@bl4ckb0ne)
diff --git a/subprojects/wayland-protocols/README.md b/subprojects/wayland-protocols/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..dd1a7ac1501d16e9e782b8b1548d3d1277f5a939
--- /dev/null
+++ b/subprojects/wayland-protocols/README.md
@@ -0,0 +1,316 @@
+# Wayland protocols
+
+wayland-protocols contains Wayland protocols that add functionality not
+available in the Wayland core protocol. Such protocols either add
+completely new functionality, or extend the functionality of some other
+protocol either in Wayland core, or some other protocol in
+wayland-protocols.
+
+A protocol in wayland-protocols consists of a directory containing a set
+of XML files containing the protocol specification, and a README file
+containing detailed state and a list of maintainers.
+
+wayland-protocols is a standardization body formed of various Wayland
+compositor and client developers. The governance rules are described in
+[GOVERNANCE.md] and the current members are listed in [MEMBERS.md].
+
+## Protocol phases
+
+Protocols in general have three phases: the development phase, the testing
+phase, and the stable phase.
+
+In the development phase, a protocol may be added to wayland-protocols
+as `experimental/`. It is actively being developed, for example by
+iterating over it in a [merge request] or planning it in an [issue].
+Extensions in this phase can have backward incompatible changes.
+
+During this phase, patches for clients and compositors are written as a test
+vehicle. Such patches should be merged with caution in clients and compositors,
+because the protocol can still change.
+
+When a protocol has reached a stage where it is ready for wider adoption,
+and after the [GOVERNANCE section 2.3] requirements have been met, it enters
+the "testing" phase. At this point, the protocol is added to the `staging/`
+directory of wayland-protocols and made part of a release. What this means is
+that implementation is encouraged in clients and compositors where the
+functionality it specifies is wanted.
+
+Extensions in staging cannot have backward incompatible changes, in that
+sense they are equal to stable extensions. However, they may be completely
+replaced with a new major version, or a different protocol extension altogether,
+if design flaws are found in the testing phase.
+
+After a staging protocol has been sufficiently tested in the wild and
+proven adequate, its maintainers and the community at large may declare it
+"stable", meaning it is unexpected to become superseded by a new major
+version.
+
+## Deprecation
+
+A protocol may be deprecated, if it has been replaced by some other
+protocol, or declared undesirable for some other reason. No more changes
+will be made to a deprecated protocol.
+
+## Legacy protocol phases
+
+An "unstable" protocol refers to a protocol categorization policy
+previously used by wayland-protocols, where protocols initially
+placed in the `unstable/` directory had certain naming conventions were
+applied, requiring a backward incompatible change to be declared "stable".
+
+During this phase, protocol extension interface names were, in addition to
+the major version postfix, also prefixed with `z` to distinguish them from
+stable protocols.
+
+## Protocol directory tree structure
+
+Depending on which stage a protocol is in, the protocol is placed within
+the toplevel directory containing the protocols with the same stage.
+Stable protocols are placed in the `stable/` directory, staging protocols
+are placed in the `staging/` directory, and deprecated protocols are
+placed in the `deprecated/` directory.
+
+Unstable protocols (see [Legacy protocol phases]) can be found in the
+`unstable/` directory, but new ones should never be placed here.
+
+## Protocol development procedure
+
+To propose a new protocol, create a GitLab merge request adding the
+relevant files and `meson.build` entry to the repository with the
+explanation and motivation in the commit message. Protocols are
+organized in namespaces describing their scope ("wp", "xdg" and "ext").
+There are different requirements for each namespace, see [GOVERNANCE
+section 2] for more information.
+
+If the new protocol is just an idea, open an issue on the GitLab issue
+tracker. If the protocol isn't ready for complete review yet and is an
+RFC, create a merge request and add the "Draft:" prefix in the title.
+
+To propose changes to existing protocols, create a GitLab merge request.
+Please make sure you CC the authors and maintainers of the protocol, who
+are named in the protocol's README.
+
+Please include a `Signed-off-by` line at the end of the commit to certify
+that you wrote it or otherwise have the right to pass it on as an
+open-source patch. See the [Developer Certificate of Origin] for a formal
+definition.
+
+## Protocol development recommendations
+
+It is recommended that protocols be small and specific in scope in order to
+minimize sites of friction.
+
+Development discussion should be approached with a fresh, productive mindset
+and an openness to explore contrary ideas.
+
+Development discussions must remain civil and technical in nature at all times.
+
+## Interface naming convention
+
+All protocols should avoid using generic namespaces or no namespaces in
+the protocol interface names in order to minimize risk that the generated
+C API collides with other C API. Interface names that may collide with
+interface names from other protocols should also be avoided.
+
+For generic protocols not limited to certain configurations (such as
+specific desktop environment or operating system) the `wp_` prefix
+should be used on all interfaces in the protocol.
+
+For protocols allowing clients to configure how their windows are
+managed, the `xdg_` prefix should be used.
+
+For operating system specific protocols, the interfaces should be
+prefixed with both `wp_` and the operating system, for example
+`wp_linux_`, or `wp_freebsd_`, etc.
+
+For more information about namespaces, see [GOVERNANCE section 2.1].
+
+Each new non-experimental protocol XML file must include a major version
+postfix, starting with `-v1`. The purpose of this postfix is to make it
+possible to distinguish between backward incompatible major versions of
+the same protocol.
+
+The interfaces in the protocol XML file should as well have the same
+major version postfix in their names.
+
+For example, the protocol `foo-bar` may have a XML file
+`foo-bar/foo-bar-v1.xml`, consisting of the interface `wp_foo_bar_v1`,
+corresponding to the major version 1, as well as the newer version
+`foo-bar/foo-bar-v2.xml` consisting of the interface `wp_foo_bar_v2`,
+corresponding to the major version 2.
+
+## Include a disclaimer
+
+Include the following disclaimer:
+
+```
+Warning! The protocol described in this file is currently in the testing
+phase. Backward compatible changes may be added together with the
+corresponding interface version bump. Backward incompatible changes can
+only be done by creating a new major version of the extension.
+```
+
+## Use of RFC 2119 keywords
+
+Descriptions of all new protocols must use (in lowercase) and adhere to the
+proper meaning of the keywords described in [RFC 2119].
+
+All protocol descriptions that follow the guidelines in RFC 2119 must
+incorporate the following text in their toplevel protocol description section:
+
+```
+The key words "must", "must not", "required", "shall", "shall not", "should",
+"should not", "recommended",  "may", and "optional" in this document are to
+be interpreted as described in IETF RFC 2119.
+```
+
+Note that not all existing protocol descriptions conform to RFC 2119. Protocol
+maintainers are encouraged to audit their descriptions, update them as needed
+to follow RFC 2119 guidelines, and mark them as conformant in the way described
+in the previous paragraph.
+
+## Backward compatible protocol changes
+
+A protocol may receive backward compatible additions and changes. This
+is to be done in the general Wayland way, using `version` and `since` XML
+element attributes.
+
+## Backward incompatible protocol changes for experimental protocols
+
+A protocol in the experimental phase should expect to see backward incompatible
+changes at any time.
+
+Assuming a backward incompatible change is needed here, the procedure for how to
+do so is the following:
+
+- Increase the major version number in the protocol XML by 1.
+- Increase the major version number in all of the interfaces in the
+  XML by 1.
+- Reset the interface version number (interface version attribute) of all
+  the interfaces to 1.
+- Remove all of the `since` attributes.
+
+## Backward incompatible protocol changes for testing protocols
+
+While not preferred, a protocol may at any stage, especially during the
+testing phase, when it is located in the `staging/` directory, see
+backward incompatible changes.
+
+Assuming a backward incompatible change is needed, the procedure for how to
+do so is the following:
+
+- Make a copy of the XML file with the major version increased by 1.
+- Increase the major version number in the protocol XML by 1.
+- Increase the major version number in all of the interfaces in the
+  XML by 1.
+- Reset the interface version number (interface version attribute) of all
+  the interfaces to 1.
+- Remove all of the `since` attributes.
+
+## Experimental Protocols: Development Recommendations
+
+Implementations choosing to support experimental protocols must work to
+support the latest version of the protocol at all times. It is therefore
+recommended that developers only opt-in to supporting protocols they
+have time and resources to actively develop.
+
+A runtime option to enable features may also be useful to ensure users
+do not opt-in to potentially broken behavior.
+
+There is no expectation or requirement for stability between experimental
+protocol versions. It is therefore strongly advised that such consumer
+projects add build-time compile options to enable such protocols in order
+to avoid compile errors from protocol version mismatches.
+
+## Promoting a protocol from experimental
+
+The author of an experimental protocol can request that it be promoted at any point
+when it meets the requirements for `staging/`. At such time,
+the namespace prefix should be determined, and then the protocol should be
+renamed and merged into the appropriate directory, deleting the `experimental/`
+entry.
+
+## Declaring a protocol stable
+
+Once it has been concluded that a protocol been proven adequate in
+production, and that it is deemed unlikely to receive any backward
+incompatible changes, it may be declared stable.
+
+The procedure of doing this is the following:
+
+- Create a new directory in the `stable/` toplevel directory with the
+  same name as the protocol directory in the `staging/` directory.
+- Copy the final version of the XML that is the version that was
+  decided to be declared stable into the new directory. The target name
+  should be the same name as the protocol directory plus the version and
+  the `.xml` suffix.
+- Remove the disclaimer about the protocol being in the testing phase.
+- Update the `README` file in the staging directory and create a new
+  `README` file in the new directory.
+- Replace the disclaimer in the protocol files left in the staging/
+  directory with the following:
+
+```
+Disclaimer: This protocol extension has been marked stable. This copy is
+no longer used and only retained for backwards compatibility. The
+canonical version can be found in the stable/ directory.
+```
+
+Note that the major version of the stable protocol extension, as well as
+all the interface versions and names, must remain unchanged.
+
+There are other requirements for declaring a protocol stable, see
+[GOVERNANCE section 2.3].
+
+## Releases
+
+Each release of wayland-protocols finalizes the version of the protocols
+to their state they had at that time.
+
+## Gitlab conventions
+
+### Triaging merge requests
+
+New merge requests should be triaged. Doing so requires the one doing the
+triage to add a set of initial labels:
+
+~"New Protocol" - For a new protocol being added. If it's an amendment to
+an existing protocol, apply the label of the corresponding protocol
+instead. If none exist, create it.
+
+~"Needs acks" - If the protocol needs one or more acknowledgements.
+
+~"Needs implementations" - If there are not enough implementations of the
+protocol.
+
+~"Needs review" - If the protocol is in need of review.
+
+~"In 30 day discussion period" - If the protocol needs a 30 day discussion
+period.
+
+For the meaning and requirement of acknowledgments and available
+implementations, see the [GOVERNANCE.md] document.
+
+### Managing merge requests
+
+When merge requests get their needed feedback and items, remove the
+corresponding label that marks it as needing something. For example, if a
+merge request receives all the required acknowledgments, remove the
+~"Needs acks" label, or if 30 days passed since opening, remove any
+~"In 30 day discussion period" label.
+
+### Nacking a merge request
+
+If the inclusion of a merge request is denied due to one or more Nacks, add
+the ~Nacked label.
+
+[GOVERNANCE.md]: GOVERNANCE.md
+[MEMBERS.md]: MEMBERS.md
+[merge request]: https://gitlab.freedesktop.org/wayland/wayland-protocols/merge_requests
+[issue]: https://gitlab.freedesktop.org/wayland/wayland-protocols/issues
+[GOVERNANCE section 2.3]: GOVERNANCE.md#2.3-introducing-new-protocols
+[Legacy protocol phases]: #legacy-protocol-phases
+[GOVERNANCE section 2]: GOVERNANCE.md#2-protocols
+[Developer Certificate of Origin]: https://developercertificate.org/
+[GOVERNANCE section 2.1]: GOVERNANCE.md#21-protocol-namespaces
+[RFC 2119]: https://www.rfc-editor.org/info/rfc2119
diff --git a/subprojects/wayland-protocols/include/wayland-protocols/meson.build b/subprojects/wayland-protocols/include/wayland-protocols/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..95af9dea0cff6793167c213657b4ca70b08e0b1b
--- /dev/null
+++ b/subprojects/wayland-protocols/include/wayland-protocols/meson.build
@@ -0,0 +1,18 @@
+header_install_dir = get_option('includedir') / 'wayland-protocols'
+foreach protocol_file : protocol_files
+	header_name = fs.name(protocol_file).replace('.xml', '-enum.h')
+	custom_target(
+		header_name,
+		output: header_name,
+		input: '../..' / protocol_file,
+		command: [
+			prog_scanner,
+			'--strict',
+			'enum-header',
+			'@INPUT@',
+			'@OUTPUT@',
+		],
+		install: true,
+		install_dir: header_install_dir,
+	)
+endforeach
diff --git a/subprojects/wayland-protocols/meson.build b/subprojects/wayland-protocols/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..fd74b0a487bae341fc27443a878eb2d95c86a853
--- /dev/null
+++ b/subprojects/wayland-protocols/meson.build
@@ -0,0 +1,168 @@
+project('wayland-protocols',
+	version: '1.41',
+	meson_version: '>= 0.58.0',
+	license: 'MIT/Expat',
+)
+
+wayland_protocols_version = meson.project_version()
+
+fs = import('fs')
+
+dep_scanner = dependency('wayland-scanner',
+    version: get_option('tests') ? '>=1.23.0' : '>=1.20.0',
+    native: true,
+    fallback: 'wayland'
+)
+prog_scanner = find_program(dep_scanner.get_variable(pkgconfig: 'wayland_scanner', internal: 'wayland_scanner'))
+
+stable_protocols = {
+	'presentation-time': [''],
+	'viewporter': [''],
+	'xdg-shell': [''],
+	'linux-dmabuf': ['v1'],
+	'tablet': ['v2'],
+}
+
+unstable_protocols = {
+	'fullscreen-shell': ['v1'],
+	'idle-inhibit': ['v1'],
+	'input-method': ['v1'],
+	'input-timestamps': ['v1'],
+	'keyboard-shortcuts-inhibit': ['v1'],
+	'linux-dmabuf': ['v1'],
+	'linux-explicit-synchronization': ['v1'],
+	'pointer-constraints': ['v1'],
+	'pointer-gestures': ['v1'],
+	'primary-selection': ['v1'],
+	'relative-pointer': ['v1'],
+	'tablet': ['v1', 'v2'],
+	'text-input': ['v1', 'v3'],
+	'xdg-decoration': ['v1'],
+	'xdg-foreign': ['v1', 'v2'],
+	'xdg-output': ['v1'],
+	'xdg-shell': ['v5', 'v6'],
+	'xwayland-keyboard-grab': ['v1'],
+}
+
+staging_protocols = {
+	'color-management': ['v1'],
+	'commit-timing': ['v1'],
+	'content-type': ['v1'],
+	'cursor-shape': ['v1'],
+	'drm-lease': ['v1'],
+	'ext-data-control': ['v1'],
+	'ext-foreign-toplevel-list': ['v1'],
+	'ext-idle-notify': ['v1'],
+	'ext-image-capture-source': ['v1'],
+	'ext-image-copy-capture': ['v1'],
+	'ext-session-lock': ['v1'],
+	'ext-transient-seat': ['v1'],
+	'fifo': ['v1'],
+	'fractional-scale': ['v1'],
+	'linux-drm-syncobj': ['v1'],
+	'security-context': ['v1'],
+	'single-pixel-buffer': ['v1'],
+	'tearing-control': ['v1'],
+	'xdg-activation': ['v1'],
+	'xdg-dialog': ['v1'],
+	'xdg-system-bell': ['v1'],
+	'xdg-toplevel-drag': ['v1'],
+	'xdg-toplevel-icon': ['v1'],
+	'xwayland-shell': ['v1'],
+	'alpha-modifier': ['v1'],
+	'ext-workspace': ['v1'],
+}
+
+protocol_files = []
+
+foreach name, versions : stable_protocols
+	foreach version : versions
+		if version == ''
+			protocol_files += ['stable/@0@/@0@.xml'.format(name)]
+		else
+			protocol_files += ['stable/@0@/@0@-@1@.xml'.format(name, version)]
+		endif
+	endforeach
+endforeach
+
+foreach name, versions : staging_protocols
+	foreach version : versions
+		protocol_files += [
+			'staging/@0@/@0@-@1@.xml'.format(name, version)
+		]
+	endforeach
+endforeach
+
+foreach name, versions : unstable_protocols
+	foreach version : versions
+		protocol_files += [
+			'unstable/@0@/@0@-unstable-@1@.xml'.format(name, version)
+		]
+	endforeach
+endforeach
+
+# Check that each protocol has a README
+foreach protocol_file : protocol_files
+	dir = fs.parent(protocol_file)
+	if not fs.is_file(dir + '/README')
+		error('Missing README in @0@'.format(protocol_file))
+	endif
+endforeach
+
+foreach protocol_file : protocol_files
+	protocol_install_dir = fs.parent(join_paths(
+		get_option('datadir'),
+		'wayland-protocols',
+		protocol_file,
+	))
+	install_data(
+		protocol_file,
+		install_dir: protocol_install_dir,
+	)
+endforeach
+
+include_dirs = []
+if dep_scanner.version().version_compare('>=1.22.90')
+	subdir('include/wayland-protocols')
+	include_dirs = ['include']
+endif
+
+wayland_protocols_srcdir = meson.current_source_dir()
+
+pkgconfig_configuration = configuration_data()
+pkgconfig_configuration.set('prefix', get_option('prefix'))
+pkgconfig_configuration.set('datarootdir', '${prefix}/@0@'.format(get_option('datadir')))
+pkgconfig_configuration.set('abs_top_srcdir', wayland_protocols_srcdir)
+pkgconfig_configuration.set('PACKAGE', 'wayland-protocols')
+pkgconfig_configuration.set('WAYLAND_PROTOCOLS_VERSION', wayland_protocols_version)
+
+pkg_install_dir = join_paths(get_option('datadir'), 'pkgconfig')
+configure_file(
+	input: 'wayland-protocols.pc.in',
+	output: 'wayland-protocols.pc',
+	configuration: pkgconfig_configuration,
+	install_dir: pkg_install_dir,
+)
+
+configure_file(
+	input: 'wayland-protocols-uninstalled.pc.in',
+	output: 'wayland-protocols-uninstalled.pc',
+	configuration: pkgconfig_configuration,
+)
+
+wayland_protocols = declare_dependency(
+	include_directories: include_dirs,
+	variables: {
+		'pkgdatadir': wayland_protocols_srcdir,
+	},
+)
+
+meson.override_dependency('wayland-protocols', wayland_protocols)
+
+if get_option('tests')
+	subdir('tests')
+endif
+
+summary({
+	'Headers': include_dirs.length() > 0,
+}, bool_yn: true)
diff --git a/subprojects/wayland-protocols/meson_options.txt b/subprojects/wayland-protocols/meson_options.txt
new file mode 100644
index 0000000000000000000000000000000000000000..f361d3b3c89a4042150025014ca17213e2724e8b
--- /dev/null
+++ b/subprojects/wayland-protocols/meson_options.txt
@@ -0,0 +1,4 @@
+option('tests',
+       type: 'boolean',
+       value: true,
+       description: 'Build the tests')
diff --git a/subprojects/wayland-protocols/stable/linux-dmabuf/README b/subprojects/wayland-protocols/stable/linux-dmabuf/README
new file mode 100644
index 0000000000000000000000000000000000000000..0c5cce50d68fa36d56defd6c5f66b6d5618a9efd
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/linux-dmabuf/README
@@ -0,0 +1,5 @@
+Linux DMA-BUF protocol
+
+Maintainers:
+Pekka Paalanen <pekka.paalanen@collabora.co.uk> (@pq)
+Daniel Stone <daniels@collabora.com> (@daniels)
diff --git a/subprojects/wayland-protocols/stable/linux-dmabuf/feedback.rst b/subprojects/wayland-protocols/stable/linux-dmabuf/feedback.rst
new file mode 100644
index 0000000000000000000000000000000000000000..a3f94ed456db6a755adbf661f4d80bc2684842c6
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/linux-dmabuf/feedback.rst
@@ -0,0 +1,218 @@
+.. Copyright 2021 Simon Ser
+
+.. contents::
+
+
+linux-dmabuf feedback introduction
+==================================
+
+linux-dmabuf feedback allows compositors and clients to negotiate optimal buffer
+allocation parameters. This document will assume that the compositor is using a
+rendering API such as OpenGL or Vulkan and KMS as the presentation API: even if
+linux-dmabuf feedback isn't restricted to this use-case, it's the most common.
+
+linux-dmabuf feedback introduces the following concepts:
+
+1. A main device. This is the render device that the compositor is using to
+   perform composition. Compositors should always be able to display a buffer
+   submitted by a client, so this device can be used as a fallback in case none
+   of the more optimized code-paths work. Clients should allocate buffers such
+   that they can be imported and textured from the main device.
+
+2. One or more tranches. Each tranche consists of a target device, allocation
+   flags and a set of format/modifier pairs. A tranche can be seen as a set of
+   formats/modifier pairs that are compatible with the target device.
+
+   A tranche can have the ``scanout`` flag. It means that the target device is
+   a KMS device, and that buffers allocated with one of the format/modifier
+   pairs in the tranche are eligible for direct scanout.
+
+   Clients should use the tranches in order to allocate buffers with the most
+   appropriate format/modifier and also to avoid allocating in private device
+   memory when cross-device operations are going to happen.
+
+linux-dmabuf feedback implementation notes
+==========================================
+
+This section contains recommendations for client and compositor implementations.
+
+For clients
+-----------
+
+Clients are expected to either pick a fixed DRM format beforehand, or
+perform the following steps repeatedly until they find a suitable format.
+
+Basic clients may only support static buffer allocation on startup. These
+clients should do the following:
+
+1. Send a ``get_default_feedback`` request to get global feedback.
+2. Select the device indicated by ``main_device`` for allocation.
+3. For each tranche:
+
+   1. If ``tranche_target_device`` doesn't match the allocation device, ignore
+      the tranche.
+   2. Accumulate allocation flags from ``tranche_flags``.
+   3. Accumulate format/modifier pairs received via ``tranche_formats`` in a
+      list.
+   4. When the ``tranche_done`` event is received, try to allocate the buffer
+      with the accumulated list of modifiers and allocation flags. If that
+      fails, proceed with the next tranche. If that succeeds, stop the loop.
+
+4. Destroy the feedback object.
+
+Tranches are ordered by preference: the more optimized tranches come first. As
+such, clients should use the first tranche that happens to work.
+
+Some clients may have already selected the device they want to use beforehand.
+These clients can ignore the ``main_device`` event, and ignore tranches whose
+``tranche_target_device`` doesn't match the selected device. Such clients need
+to be prepared for the ``wp_linux_buffer_params.create`` request to potentially
+fail.
+
+If the client allocates a buffer without specifying explicit modifiers on a
+device different from the one indicated by ``main_device``, then the client
+must force a linear layout.
+
+Some clients might support re-negotiating the buffer format/modifier on the
+fly. These clients should send a ``get_surface_feedback`` request and keep the
+feedback object alive after the initial allocation. Each time a new set of
+feedback parameters is received (ended by the ``done`` event), they should
+perform the same steps as basic clients described above. They should detect
+when the optimal allocation parameters didn't change (same
+format/modifier/flags) to avoid needlessly re-allocating their buffers.
+
+Some clients might additionally support switching the device used for
+allocations on the fly. Such clients should send a ``get_surface_feedback``
+request. For each tranche, select the device indicated by
+``tranche_target_device`` for allocation. Accumulate allocation flags (received
+via ``tranche_flags``) and format/modifier pairs (received via
+``tranche_formats``) as usual. When the ``tranche_done`` event is received, try
+to allocate the buffer with the accumulated list of modifiers and the
+allocation flags. Try to import the resulting buffer by sending a
+``wp_linux_buffer_params.create`` request (this might fail). Repeat with each
+tranche until an allocation and import succeeds. Each time a new set of
+feedback parameters is received, they should perform these steps again. They
+should detect when the optimal allocation parameters didn't change (same
+device/format/modifier/flags) to avoid needlessly re-allocating their buffers.
+
+For compositors
+---------------
+
+Basic compositors may only support texturing the DMA-BUFs via a rendering API
+such as OpenGL or Vulkan. Such compositors can send a single tranche as a reply
+to both ``get_default_feedback`` and ``get_surface_feedback``. Set the
+``main_device`` to the rendering device. Send the tranche with
+``tranche_target_device`` set to the rendering device and all of the DRM
+format/modifier pairs supported by the rendering API. Do not set the
+``scanout`` flag in the ``tranche_flags`` event.
+
+Some compositors may support direct scan-out for full-screen surfaces. These
+compositors can re-send the feedback parameters when a surface becomes
+full-screen or leaves full-screen mode if the client has used the
+``get_surface_feedback`` request. The non-full-screen feedback parameters are
+the same as basic compositors described above. The full-screen feedback
+parameters have two tranches: one with the format/modifier pairs supported by
+the KMS plane, with the ``scanout`` flag set in the ``tranche_flags`` event and
+with ``tranche_target_device`` set to the KMS scan-out device; the other with
+the rest of the format/modifier pairs (supported for texturing, but not for
+scan-out), without the ``scanout`` flag set in the ``tranche_flags`` event, and
+with the ``tranche_target_device`` set to the rendering device.
+
+Some compositors may support direct scan-out for all surfaces. These
+compositors can send two tranches for surfaces that become candidates for
+direct scan-out, similarly to compositors supporting direct scan-out for
+fullscreen surfaces. When a surface stops being a candidate for direct
+scan-out, compositors should re-send the feedback parameters optimized for
+texturing only.  The way candidates for direct scan-out are selected is
+compositor policy, a possible implementation is to select as many surfaces as
+there are available hardware planes, starting from surfaces closer to the eye.
+
+Some compositors may support multiple devices at the same time. If the
+compositor supports rendering with a fixed device and direct scan-out on a
+secondary device, it may send a separate tranche for surfaces displayed on
+the secondary device that are candidates for direct scan-out. The
+``tranche_target_device`` for this tranche will be the secondary device and
+will not match the ``main_device``.
+
+Some compositors may support switching their rendering device at runtime or
+changing their rendering device depending on the surface. When the rendering
+device changes for a surface, such compositors may re-send the feedback
+parameters with a different ``main_device``. However there is a risk that
+clients don't support switching their device at runtime and continue using the
+previous device. For this reason, compositors should always have a fallback
+rendering device that they initially send as ``main_device``, such that these
+clients use said fallback device.
+
+Compositors should not change the ``main_device`` on-the-fly when explicit
+modifiers are not supported, because there's a risk of importing buffers
+with an implicit non-linear modifier as a linear buffer, resulting in
+misinterpreted buffer contents.
+
+Compositors should not send feedback parameters if they don't have a fallback
+path. For instance, compositors shouldn't send a format/modifier supported for
+direct scan-out but not supported by the rendering API for texturing.
+
+Compositors can decide to use multiple tranches to describe the allocation
+parameters optimized for texturing. For example, if there are formats which
+have a fast texturing path and formats which have a slower texturing path, the
+compositor can decide to expose two separate tranches.
+
+Compositors can decide to use intermediate tranches to describe code-paths
+slower than direct scan-out but faster than texturing. For instance, a
+compositor could insert an intermediate tranche if it's possible to use a
+mem2mem device to convert buffers to be able to use scan-out.
+
+``dev_t`` encoding
+==================
+
+The protocol carries ``dev_t`` values on the wire using arrays. A compositor
+written in C can encode the values as follows:
+
+.. code-block:: c
+
+    struct stat drm_node_stat;
+    struct wl_array dev_array = {
+        .size = sizeof(drm_node_stat.st_rdev),
+        .data = &drm_node_stat.st_rdev,
+    };
+
+A client can decode the values as follows:
+
+.. code-block:: c
+
+    dev_t dev;
+    assert(dev_array->size == sizeof(dev));
+    memcpy(&dev, dev_array->data, sizeof(dev));
+
+Because two DRM nodes can refer to the same DRM device while having different
+``dev_t`` values, clients should use ``drmDevicesEqual`` to compare two
+devices.
+
+``format_table`` encoding
+=========================
+
+The ``format_table`` event carries a file descriptor containing a list of
+format + modifier pairs. The list is an array of pairs which can be accessed
+with this C structure definition:
+
+.. code-block:: c
+
+    struct dmabuf_format_modifier {
+        uint32_t format;
+        uint32_t pad; /* unused */
+        uint64_t modifier;
+    };
+
+Integration with other APIs
+===========================
+
+- libdrm: ``drmGetDeviceFromDevId`` returns a ``drmDevice`` from a device ID.
+- EGL: the `EGL_EXT_device_drm_render_node`_ extension may be used to query the
+  DRM device render node used by a given EGL display. When unavailable, the
+  older `EGL_EXT_device_drm`_ extension may be used as a fallback.
+- Vulkan: the `VK_EXT_physical_device_drm`_ extension may be used to query the
+  DRM device used by a given ``VkPhysicalDevice``.
+
+.. _EGL_EXT_device_drm: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_drm.txt
+.. _EGL_EXT_device_drm_render_node: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_drm_render_node.txt
+.. _VK_EXT_physical_device_drm: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_physical_device_drm.html
diff --git a/subprojects/wayland-protocols/stable/linux-dmabuf/linux-dmabuf-v1.xml b/subprojects/wayland-protocols/stable/linux-dmabuf/linux-dmabuf-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..12d09fb28f263924402ab826dcd4746ecee4c506
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/linux-dmabuf/linux-dmabuf-v1.xml
@@ -0,0 +1,585 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="linux_dmabuf_v1">
+
+  <copyright>
+    Copyright © 2014, 2015 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_linux_dmabuf_v1" version="5">
+    <description summary="factory for creating dmabuf-based wl_buffers">
+      This interface offers ways to create generic dmabuf-based wl_buffers.
+
+      For more information about dmabuf, see:
+      https://www.kernel.org/doc/html/next/userspace-api/dma-buf-alloc-exchange.html
+
+      Clients can use the get_surface_feedback request to get dmabuf feedback
+      for a particular surface. If the client wants to retrieve feedback not
+      tied to a surface, they can use the get_default_feedback request.
+
+      The following are required from clients:
+
+      - Clients must ensure that either all data in the dma-buf is
+        coherent for all subsequent read access or that coherency is
+        correctly handled by the underlying kernel-side dma-buf
+        implementation.
+
+      - Don't make any more attachments after sending the buffer to the
+        compositor. Making more attachments later increases the risk of
+        the compositor not being able to use (re-import) an existing
+        dmabuf-based wl_buffer.
+
+      The underlying graphics stack must ensure the following:
+
+      - The dmabuf file descriptors relayed to the server will stay valid
+        for the whole lifetime of the wl_buffer. This means the server may
+        at any time use those fds to import the dmabuf into any kernel
+        sub-system that might accept it.
+
+      However, when the underlying graphics stack fails to deliver the
+      promise, because of e.g. a device hot-unplug which raises internal
+      errors, after the wl_buffer has been successfully created the
+      compositor must not raise protocol errors to the client when dmabuf
+      import later fails.
+
+      To create a wl_buffer from one or more dmabufs, a client creates a
+      zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params
+      request. All planes required by the intended format are added with
+      the 'add' request. Finally, a 'create' or 'create_immed' request is
+      issued, which has the following outcome depending on the import success.
+
+      The 'create' request,
+      - on success, triggers a 'created' event which provides the final
+        wl_buffer to the client.
+      - on failure, triggers a 'failed' event to convey that the server
+        cannot use the dmabufs received from the client.
+
+      For the 'create_immed' request,
+      - on success, the server immediately imports the added dmabufs to
+        create a wl_buffer. No event is sent from the server in this case.
+      - on failure, the server can choose to either:
+        - terminate the client by raising a fatal error.
+        - mark the wl_buffer as failed, and send a 'failed' event to the
+          client. If the client uses a failed wl_buffer as an argument to any
+          request, the behaviour is compositor implementation-defined.
+
+      For all DRM formats and unless specified in another protocol extension,
+      pre-multiplied alpha is used for pixel values.
+
+      Unless specified otherwise in another protocol extension, implicit
+      synchronization is used. In other words, compositors and clients must
+      wait and signal fences implicitly passed via the DMA-BUF's reservation
+      mechanism.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind the factory">
+        Objects created through this interface, especially wl_buffers, will
+        remain valid.
+      </description>
+    </request>
+
+    <request name="create_params">
+      <description summary="create a temporary object for buffer parameters">
+        This temporary object is used to collect multiple dmabuf handles into
+        a single batch to create a wl_buffer. It can only be used once and
+        should be destroyed after a 'created' or 'failed' event has been
+        received.
+      </description>
+      <arg name="params_id" type="new_id" interface="zwp_linux_buffer_params_v1"
+           summary="the new temporary"/>
+    </request>
+
+    <event name="format" deprecated-since="4">
+      <description summary="supported buffer format">
+        This event advertises one buffer format that the server supports.
+        All the supported formats are advertised once when the client
+        binds to this interface. A roundtrip after binding guarantees
+        that the client has received all supported formats.
+
+        For the definition of the format codes, see the
+        zwp_linux_buffer_params_v1::create request.
+
+        Starting version 4, the format event is deprecated and must not be
+        sent by compositors. Instead, use get_default_feedback or
+        get_surface_feedback.
+      </description>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+    </event>
+
+    <event name="modifier" since="3" deprecated-since="4">
+      <description summary="supported buffer format modifier">
+        This event advertises the formats that the server supports, along with
+        the modifiers supported for each format. All the supported modifiers
+        for all the supported formats are advertised once when the client
+        binds to this interface. A roundtrip after binding guarantees that
+        the client has received all supported format-modifier pairs.
+
+        For legacy support, DRM_FORMAT_MOD_INVALID (that is, modifier_hi ==
+        0x00ffffff and modifier_lo == 0xffffffff) is allowed in this event.
+        It indicates that the server can support the format with an implicit
+        modifier. When a plane has DRM_FORMAT_MOD_INVALID as its modifier, it
+        is as if no explicit modifier is specified. The effective modifier
+        will be derived from the dmabuf.
+
+        A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for
+        a given format supports both explicit modifiers and implicit modifiers.
+
+        For the definition of the format and modifier codes, see the
+        zwp_linux_buffer_params_v1::create and zwp_linux_buffer_params_v1::add
+        requests.
+
+        Starting version 4, the modifier event is deprecated and must not be
+        sent by compositors. Instead, use get_default_feedback or
+        get_surface_feedback.
+      </description>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="modifier_hi" type="uint"
+           summary="high 32 bits of layout modifier"/>
+      <arg name="modifier_lo" type="uint"
+           summary="low 32 bits of layout modifier"/>
+    </event>
+
+    <!-- Version 4 additions -->
+
+    <request name="get_default_feedback" since="4">
+      <description summary="get default feedback">
+        This request creates a new wp_linux_dmabuf_feedback object not bound
+        to a particular surface. This object will deliver feedback about dmabuf
+        parameters to use if the client doesn't support per-surface feedback
+        (see get_surface_feedback).
+      </description>
+      <arg name="id" type="new_id" interface="zwp_linux_dmabuf_feedback_v1"/>
+    </request>
+
+    <request name="get_surface_feedback" since="4">
+      <description summary="get feedback for a surface">
+        This request creates a new wp_linux_dmabuf_feedback object for the
+        specified wl_surface. This object will deliver feedback about dmabuf
+        parameters to use for buffers attached to this surface.
+
+        If the surface is destroyed before the wp_linux_dmabuf_feedback object,
+        the feedback object becomes inert.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_linux_dmabuf_feedback_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_linux_buffer_params_v1" version="5">
+    <description summary="parameters for creating a dmabuf-based wl_buffer">
+      This temporary object is a collection of dmabufs and other
+      parameters that together form a single logical buffer. The temporary
+      object may eventually create one wl_buffer unless cancelled by
+      destroying it before requesting 'create'.
+
+      Single-planar formats only require one dmabuf, however
+      multi-planar formats may require more than one dmabuf. For all
+      formats, an 'add' request must be called once per plane (even if the
+      underlying dmabuf fd is identical).
+
+      You must use consecutive plane indices ('plane_idx' argument for 'add')
+      from zero to the number of planes used by the drm_fourcc format code.
+      All planes required by the format must be given exactly once, but can
+      be given in any order. Each plane index can only be set once; subsequent
+      calls with a plane index which has already been set will result in a
+      plane_set error being generated.
+    </description>
+
+    <enum name="error">
+      <entry name="already_used" value="0"
+             summary="the dmabuf_batch object has already been used to create a wl_buffer"/>
+      <entry name="plane_idx" value="1"
+             summary="plane index out of bounds"/>
+      <entry name="plane_set" value="2"
+             summary="the plane index was already set"/>
+      <entry name="incomplete" value="3"
+             summary="missing or too many planes to create a buffer"/>
+      <entry name="invalid_format" value="4"
+             summary="format not supported"/>
+      <entry name="invalid_dimensions" value="5"
+             summary="invalid width or height"/>
+      <entry name="out_of_bounds" value="6"
+             summary="offset + stride * height goes out of dmabuf bounds"/>
+      <entry name="invalid_wl_buffer" value="7"
+             summary="invalid wl_buffer resulted from importing dmabufs via
+               the create_immed request on given buffer_params"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete this object, used or not">
+        Cleans up the temporary data sent to the server for dmabuf-based
+        wl_buffer creation.
+      </description>
+    </request>
+
+    <request name="add">
+      <description summary="add a dmabuf to the temporary set">
+        This request adds one dmabuf to the set in this
+        zwp_linux_buffer_params_v1.
+
+        The 64-bit unsigned value combined from modifier_hi and modifier_lo
+        is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the
+        fb modifier, which is defined in drm_mode.h of Linux UAPI.
+        This is an opaque token. Drivers use this token to express tiling,
+        compression, etc. driver-specific modifications to the base format
+        defined by the DRM fourcc code.
+
+        Starting from version 4, the invalid_format protocol error is sent if
+        the format + modifier pair was not advertised as supported.
+
+        Starting from version 5, the invalid_format protocol error is sent if
+        all planes don't use the same modifier.
+
+        This request raises the PLANE_IDX error if plane_idx is too large.
+        The error PLANE_SET is raised if attempting to set a plane that
+        was already set.
+      </description>
+      <arg name="fd" type="fd" summary="dmabuf fd"/>
+      <arg name="plane_idx" type="uint" summary="plane index"/>
+      <arg name="offset" type="uint" summary="offset in bytes"/>
+      <arg name="stride" type="uint" summary="stride in bytes"/>
+      <arg name="modifier_hi" type="uint"
+           summary="high 32 bits of layout modifier"/>
+      <arg name="modifier_lo" type="uint"
+           summary="low 32 bits of layout modifier"/>
+    </request>
+
+    <enum name="flags" bitfield="true">
+      <entry name="y_invert" value="1" summary="contents are y-inverted"/>
+      <entry name="interlaced" value="2" summary="content is interlaced"/>
+      <entry name="bottom_first" value="4" summary="bottom field first"/>
+    </enum>
+
+    <request name="create">
+      <description summary="create a wl_buffer from the given dmabufs">
+        This asks for creation of a wl_buffer from the added dmabuf
+        buffers. The wl_buffer is not created immediately but returned via
+        the 'created' event if the dmabuf sharing succeeds. The sharing
+        may fail at runtime for reasons a client cannot predict, in
+        which case the 'failed' event is triggered.
+
+        The 'format' argument is a DRM_FORMAT code, as defined by the
+        libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the
+        authoritative source on how the format codes should work.
+
+        The 'flags' is a bitfield of the flags defined in enum "flags".
+        'y_invert' means the that the image needs to be y-flipped.
+
+        Flag 'interlaced' means that the frame in the buffer is not
+        progressive as usual, but interlaced. An interlaced buffer as
+        supported here must always contain both top and bottom fields.
+        The top field always begins on the first pixel row. The temporal
+        ordering between the two fields is top field first, unless
+        'bottom_first' is specified. It is undefined whether 'bottom_first'
+        is ignored if 'interlaced' is not set.
+
+        This protocol does not convey any information about field rate,
+        duration, or timing, other than the relative ordering between the
+        two fields in one buffer. A compositor may have to estimate the
+        intended field rate from the incoming buffer rate. It is undefined
+        whether the time of receiving wl_surface.commit with a new buffer
+        attached, applying the wl_surface state, wl_surface.frame callback
+        trigger, presentation, or any other point in the compositor cycle
+        is used to measure the frame or field times. There is no support
+        for detecting missed or late frames/fields/buffers either, and
+        there is no support whatsoever for cooperating with interlaced
+        compositor output.
+
+        The composited image quality resulting from the use of interlaced
+        buffers is explicitly undefined. A compositor may use elaborate
+        hardware features or software to deinterlace and create progressive
+        output frames from a sequence of interlaced input buffers, or it
+        may produce substandard image quality. However, compositors that
+        cannot guarantee reasonable image quality in all cases are recommended
+        to just reject all interlaced buffers.
+
+        Any argument errors, including non-positive width or height,
+        mismatch between the number of planes and the format, bad
+        format, bad offset or stride, may be indicated by fatal protocol
+        errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS,
+        OUT_OF_BOUNDS.
+
+        Dmabuf import errors in the server that are not obvious client
+        bugs are returned via the 'failed' event as non-fatal. This
+        allows attempting dmabuf sharing and falling back in the client
+        if it fails.
+
+        This request can be sent only once in the object's lifetime, after
+        which the only legal request is destroy. This object should be
+        destroyed after issuing a 'create' request. Attempting to use this
+        object after issuing 'create' raises ALREADY_USED protocol error.
+
+        It is not mandatory to issue 'create'. If a client wants to
+        cancel the buffer creation, it can just destroy this object.
+      </description>
+      <arg name="width" type="int" summary="base plane width in pixels"/>
+      <arg name="height" type="int" summary="base plane height in pixels"/>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="flags" type="uint" enum="flags" summary="see enum flags"/>
+    </request>
+
+    <event name="created">
+      <description summary="buffer creation succeeded">
+        This event indicates that the attempted buffer creation was
+        successful. It provides the new wl_buffer referencing the dmabuf(s).
+
+        Upon receiving this event, the client should destroy the
+        zwp_linux_buffer_params_v1 object.
+      </description>
+      <arg name="buffer" type="new_id" interface="wl_buffer"
+           summary="the newly created wl_buffer"/>
+    </event>
+
+    <event name="failed">
+      <description summary="buffer creation failed">
+        This event indicates that the attempted buffer creation has
+        failed. It usually means that one of the dmabuf constraints
+        has not been fulfilled.
+
+        Upon receiving this event, the client should destroy the
+        zwp_linux_buffer_params_v1 object.
+      </description>
+    </event>
+
+    <request name="create_immed" since="2">
+      <description summary="immediately create a wl_buffer from the given
+                     dmabufs">
+        This asks for immediate creation of a wl_buffer by importing the
+        added dmabufs.
+
+        In case of import success, no event is sent from the server, and the
+        wl_buffer is ready to be used by the client.
+
+        Upon import failure, either of the following may happen, as seen fit
+        by the implementation:
+        - the client is terminated with one of the following fatal protocol
+          errors:
+          - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS,
+            in case of argument errors such as mismatch between the number
+            of planes and the format, bad format, non-positive width or
+            height, or bad offset or stride.
+          - INVALID_WL_BUFFER, in case the cause for failure is unknown or
+            platform specific.
+        - the server creates an invalid wl_buffer, marks it as failed and
+          sends a 'failed' event to the client. The result of using this
+          invalid wl_buffer as an argument in any request by the client is
+          defined by the compositor implementation.
+
+        This takes the same arguments as a 'create' request, and obeys the
+        same restrictions.
+      </description>
+      <arg name="buffer_id" type="new_id" interface="wl_buffer"
+           summary="id for the newly created wl_buffer"/>
+      <arg name="width" type="int" summary="base plane width in pixels"/>
+      <arg name="height" type="int" summary="base plane height in pixels"/>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="flags" type="uint" enum="flags" summary="see enum flags"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_linux_dmabuf_feedback_v1" version="5">
+    <description summary="dmabuf feedback">
+      This object advertises dmabuf parameters feedback. This includes the
+      preferred devices and the supported formats/modifiers.
+
+      The parameters are sent once when this object is created and whenever they
+      change. The done event is always sent once after all parameters have been
+      sent. When a single parameter changes, all parameters are re-sent by the
+      compositor.
+
+      Compositors can re-send the parameters when the current client buffer
+      allocations are sub-optimal. Compositors should not re-send the
+      parameters if re-allocating the buffers would not result in a more optimal
+      configuration. In particular, compositors should avoid sending the exact
+      same parameters multiple times in a row.
+
+      The tranche_target_device and tranche_formats events are grouped by
+      tranches of preference. For each tranche, a tranche_target_device, one
+      tranche_flags and one or more tranche_formats events are sent, followed
+      by a tranche_done event finishing the list. The tranches are sent in
+      descending order of preference. All formats and modifiers in the same
+      tranche have the same preference.
+
+      To send parameters, the compositor sends one main_device event, tranches
+      (each consisting of one tranche_target_device event, one tranche_flags
+      event, tranche_formats events and then a tranche_done event), then one
+      done event.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the feedback object">
+        Using this request a client can tell the server that it is not going to
+        use the wp_linux_dmabuf_feedback object anymore.
+      </description>
+    </request>
+
+    <event name="done">
+      <description summary="all feedback has been sent">
+        This event is sent after all parameters of a wp_linux_dmabuf_feedback
+        object have been sent.
+
+        This allows changes to the wp_linux_dmabuf_feedback parameters to be
+        seen as atomic, even if they happen via multiple events.
+      </description>
+    </event>
+
+    <event name="format_table">
+      <description summary="format and modifier table">
+        This event provides a file descriptor which can be memory-mapped to
+        access the format and modifier table.
+
+        The table contains a tightly packed array of consecutive format +
+        modifier pairs. Each pair is 16 bytes wide. It contains a format as a
+        32-bit unsigned integer, followed by 4 bytes of unused padding, and a
+        modifier as a 64-bit unsigned integer. The native endianness is used.
+
+        The client must map the file descriptor in read-only private mode.
+
+        Compositors are not allowed to mutate the table file contents once this
+        event has been sent. Instead, compositors must create a new, separate
+        table file and re-send feedback parameters. Compositors are allowed to
+        store duplicate format + modifier pairs in the table.
+      </description>
+      <arg name="fd" type="fd" summary="table file descriptor"/>
+      <arg name="size" type="uint" summary="table size, in bytes"/>
+    </event>
+
+    <event name="main_device">
+      <description summary="preferred main device">
+        This event advertises the main device that the server prefers to use
+        when direct scan-out to the target device isn't possible. The
+        advertised main device may be different for each
+        wp_linux_dmabuf_feedback object, and may change over time.
+
+        There is exactly one main device. The compositor must send at least
+        one preference tranche with tranche_target_device equal to main_device.
+
+        Clients need to create buffers that the main device can import and
+        read from, otherwise creating the dmabuf wl_buffer will fail (see the
+        wp_linux_buffer_params.create and create_immed requests for details).
+        The main device will also likely be kept active by the compositor,
+        so clients can use it instead of waking up another device for power
+        savings.
+
+        In general the device is a DRM node. The DRM node type (primary vs.
+        render) is unspecified. Clients must not rely on the compositor sending
+        a particular node type. Clients cannot check two devices for equality
+        by comparing the dev_t value.
+
+        If explicit modifiers are not supported and the client performs buffer
+        allocations on a different device than the main device, then the client
+        must force the buffer to have a linear layout.
+      </description>
+      <arg name="device" type="array" summary="device dev_t value"/>
+    </event>
+
+    <event name="tranche_done">
+      <description summary="a preference tranche has been sent">
+        This event splits tranche_target_device and tranche_formats events in
+        preference tranches. It is sent after a set of tranche_target_device
+        and tranche_formats events; it represents the end of a tranche. The
+        next tranche will have a lower preference.
+      </description>
+    </event>
+
+    <event name="tranche_target_device">
+      <description summary="target device">
+        This event advertises the target device that the server prefers to use
+        for a buffer created given this tranche. The advertised target device
+        may be different for each preference tranche, and may change over time.
+
+        There is exactly one target device per tranche.
+
+        The target device may be a scan-out device, for example if the
+        compositor prefers to directly scan-out a buffer created given this
+        tranche. The target device may be a rendering device, for example if
+        the compositor prefers to texture from said buffer.
+
+        The client can use this hint to allocate the buffer in a way that makes
+        it accessible from the target device, ideally directly. The buffer must
+        still be accessible from the main device, either through direct import
+        or through a potentially more expensive fallback path. If the buffer
+        can't be directly imported from the main device then clients must be
+        prepared for the compositor changing the tranche priority or making
+        wl_buffer creation fail (see the wp_linux_buffer_params.create and
+        create_immed requests for details).
+
+        If the device is a DRM node, the DRM node type (primary vs. render) is
+        unspecified. Clients must not rely on the compositor sending a
+        particular node type. Clients cannot check two devices for equality by
+        comparing the dev_t value.
+
+        This event is tied to a preference tranche, see the tranche_done event.
+      </description>
+      <arg name="device" type="array" summary="device dev_t value"/>
+    </event>
+
+    <event name="tranche_formats">
+      <description summary="supported buffer format modifier">
+        This event advertises the format + modifier combinations that the
+        compositor supports.
+
+        It carries an array of indices, each referring to a format + modifier
+        pair in the last received format table (see the format_table event).
+        Each index is a 16-bit unsigned integer in native endianness.
+
+        For legacy support, DRM_FORMAT_MOD_INVALID is an allowed modifier.
+        It indicates that the server can support the format with an implicit
+        modifier. When a buffer has DRM_FORMAT_MOD_INVALID as its modifier, it
+        is as if no explicit modifier is specified. The effective modifier
+        will be derived from the dmabuf.
+
+        A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for
+        a given format supports both explicit modifiers and implicit modifiers.
+
+        Compositors must not send duplicate format + modifier pairs within the
+        same tranche or across two different tranches with the same target
+        device and flags.
+
+        This event is tied to a preference tranche, see the tranche_done event.
+
+        For the definition of the format and modifier codes, see the
+        wp_linux_buffer_params.create request.
+      </description>
+      <arg name="indices" type="array" summary="array of 16-bit indexes"/>
+    </event>
+
+    <enum name="tranche_flags" bitfield="true">
+      <entry name="scanout" value="1" summary="direct scan-out tranche"/>
+    </enum>
+
+    <event name="tranche_flags">
+      <description summary="tranche flags">
+        This event sets tranche-specific flags.
+
+        The scanout flag is a hint that direct scan-out may be attempted by the
+        compositor on the target device if the client appropriately allocates a
+        buffer. How to allocate a buffer that can be scanned out on the target
+        device is implementation-defined.
+
+        This event is tied to a preference tranche, see the tranche_done event.
+      </description>
+      <arg name="flags" type="uint" enum="tranche_flags" summary="tranche flags"/>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/stable/presentation-time/README b/subprojects/wayland-protocols/stable/presentation-time/README
new file mode 100644
index 0000000000000000000000000000000000000000..b0ecbe0d329b77cdca6a19d3563bf93636943990
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/presentation-time/README
@@ -0,0 +1,5 @@
+Presentation time protocol
+
+Maintainers:
+Pekka Paalanen <pekka.paalanen@collabora.co.uk> (@pq)
+
diff --git a/subprojects/wayland-protocols/stable/presentation-time/presentation-time.xml b/subprojects/wayland-protocols/stable/presentation-time/presentation-time.xml
new file mode 100644
index 0000000000000000000000000000000000000000..c2431c500367fe7237b9c9e50b3d2255d6108082
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/presentation-time/presentation-time.xml
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="presentation_time">
+<!-- wrap:70 -->
+
+  <copyright>
+    Copyright © 2013-2014 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="wp_presentation" version="2">
+    <description summary="timed presentation related wl_surface requests">
+
+<!-- Introduction -->
+
+      The main feature of this interface is accurate presentation
+      timing feedback to ensure smooth video playback while maintaining
+      audio/video synchronization. Some features use the concept of a
+      presentation clock, which is defined in the
+      presentation.clock_id event.
+
+      A content update for a wl_surface is submitted by a
+      wl_surface.commit request. Request 'feedback' associates with
+      the wl_surface.commit and provides feedback on the content
+      update, particularly the final realized presentation time.
+
+<!-- Completing presentation -->
+
+      When the final realized presentation time is available, e.g.
+      after a framebuffer flip completes, the requested
+      presentation_feedback.presented events are sent. The final
+      presentation time can differ from the compositor's predicted
+      display update time and the update's target time, especially
+      when the compositor misses its target vertical blanking period.
+    </description>
+
+    <enum name="error">
+      <description summary="fatal presentation errors">
+        These fatal protocol errors may be emitted in response to
+        illegal presentation requests.
+      </description>
+      <entry name="invalid_timestamp" value="0"
+             summary="invalid value in tv_nsec"/>
+      <entry name="invalid_flag" value="1"
+             summary="invalid flag"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the presentation interface">
+        Informs the server that the client will no longer be using
+        this protocol object. Existing objects created by this object
+        are not affected.
+      </description>
+    </request>
+
+    <request name="feedback">
+      <description summary="request presentation feedback information">
+        Request presentation feedback for the current content submission
+        on the given surface. This creates a new presentation_feedback
+        object, which will deliver the feedback information once. If
+        multiple presentation_feedback objects are created for the same
+        submission, they will all deliver the same information.
+
+        For details on what information is returned, see the
+        presentation_feedback interface.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="target surface"/>
+      <arg name="callback" type="new_id" interface="wp_presentation_feedback"
+           summary="new feedback object"/>
+    </request>
+
+    <event name="clock_id">
+      <description summary="clock ID for timestamps">
+        This event tells the client in which clock domain the
+        compositor interprets the timestamps used by the presentation
+        extension. This clock is called the presentation clock.
+
+        The compositor sends this event when the client binds to the
+        presentation interface. The presentation clock does not change
+        during the lifetime of the client connection.
+
+        The clock identifier is platform dependent. On POSIX platforms, the
+        identifier value is one of the clockid_t values accepted by
+        clock_gettime(). clock_gettime() is defined by POSIX.1-2001.
+
+        Timestamps in this clock domain are expressed as tv_sec_hi,
+        tv_sec_lo, tv_nsec triples, each component being an unsigned
+        32-bit value. Whole seconds are in tv_sec which is a 64-bit
+        value combined from tv_sec_hi and tv_sec_lo, and the
+        additional fractional part in tv_nsec as nanoseconds. Hence,
+        for valid timestamps tv_nsec must be in [0, 999999999].
+
+        Note that clock_id applies only to the presentation clock,
+        and implies nothing about e.g. the timestamps used in the
+        Wayland core protocol input events.
+
+        Compositors should prefer a clock which does not jump and is
+        not slewed e.g. by NTP. The absolute value of the clock is
+        irrelevant. Precision of one millisecond or better is
+        recommended. Clients must be able to query the current clock
+        value directly, not by asking the compositor.
+      </description>
+      <arg name="clk_id" type="uint" summary="platform clock identifier"/>
+    </event>
+
+  </interface>
+
+  <interface name="wp_presentation_feedback" version="2">
+    <description summary="presentation time feedback event">
+      A presentation_feedback object returns an indication that a
+      wl_surface content update has become visible to the user.
+      One object corresponds to one content update submission
+      (wl_surface.commit). There are two possible outcomes: the
+      content update is presented to the user, and a presentation
+      timestamp delivered; or, the user did not see the content
+      update because it was superseded or its surface destroyed,
+      and the content update is discarded.
+
+      Once a presentation_feedback object has delivered a 'presented'
+      or 'discarded' event it is automatically destroyed.
+    </description>
+
+    <event name="sync_output">
+      <description summary="presentation synchronized to this output">
+        As presentation can be synchronized to only one output at a
+        time, this event tells which output it was. This event is only
+        sent prior to the presented event.
+
+        As clients may bind to the same global wl_output multiple
+        times, this event is sent for each bound instance that matches
+        the synchronized output. If a client has not bound to the
+        right wl_output global at all, this event is not sent.
+      </description>
+      <arg name="output" type="object" interface="wl_output"
+           summary="presentation output"/>
+    </event>
+
+    <enum name="kind" bitfield="true">
+      <description summary="bitmask of flags in presented event">
+        These flags provide information about how the presentation of
+        the related content update was done. The intent is to help
+        clients assess the reliability of the feedback and the visual
+        quality with respect to possible tearing and timings.
+      </description>
+      <entry name="vsync" value="0x1">
+        <description summary="presentation was vsync'd">
+          The presentation was synchronized to the "vertical retrace" by
+          the display hardware such that tearing does not happen.
+          Relying on software scheduling is not acceptable for this
+          flag. If presentation is done by a copy to the active
+          frontbuffer, then it must guarantee that tearing cannot
+          happen.
+        </description>
+      </entry>
+      <entry name="hw_clock" value="0x2">
+        <description summary="hardware provided the presentation timestamp">
+          The display hardware provided measurements that the hardware
+          driver converted into a presentation timestamp. Sampling a
+          clock in software is not acceptable for this flag.
+        </description>
+      </entry>
+      <entry name="hw_completion" value="0x4">
+        <description summary="hardware signalled the start of the presentation">
+          The display hardware signalled that it started using the new
+          image content. The opposite of this is e.g. a timer being used
+          to guess when the display hardware has switched to the new
+          image content.
+        </description>
+      </entry>
+      <entry name="zero_copy" value="0x8">
+        <description summary="presentation was done zero-copy">
+          The presentation of this update was done zero-copy. This means
+          the buffer from the client was given to display hardware as
+          is, without copying it. Compositing with OpenGL counts as
+          copying, even if textured directly from the client buffer.
+          Possible zero-copy cases include direct scanout of a
+          fullscreen surface and a surface on a hardware overlay.
+        </description>
+      </entry>
+    </enum>
+
+    <event name="presented" type="destructor">
+      <description summary="the content update was displayed">
+        The associated content update was displayed to the user at the
+        indicated time (tv_sec_hi/lo, tv_nsec). For the interpretation of
+        the timestamp, see presentation.clock_id event.
+
+        The timestamp corresponds to the time when the content update
+        turned into light the first time on the surface's main output.
+        Compositors may approximate this from the framebuffer flip
+        completion events from the system, and the latency of the
+        physical display path if known.
+
+        This event is preceded by all related sync_output events
+        telling which output's refresh cycle the feedback corresponds
+        to, i.e. the main output for the surface. Compositors are
+        recommended to choose the output containing the largest part
+        of the wl_surface, or keeping the output they previously
+        chose. Having a stable presentation output association helps
+        clients predict future output refreshes (vblank).
+
+        The 'refresh' argument gives the compositor's prediction of how
+        many nanoseconds after tv_sec, tv_nsec the very next output
+        refresh may occur. This is to further aid clients in
+        predicting future refreshes, i.e., estimating the timestamps
+        targeting the next few vblanks. If such prediction cannot
+        usefully be done, the argument is zero.
+
+        For version 2 and later, if the output does not have a constant
+        refresh rate, explicit video mode switches excluded, then the
+        refresh argument must be either an appropriate rate picked by the
+        compositor (e.g. fastest rate), or 0 if no such rate exists.
+        For version 1, if the output does not have a constant refresh rate,
+        the refresh argument must be zero.
+
+        The 64-bit value combined from seq_hi and seq_lo is the value
+        of the output's vertical retrace counter when the content
+        update was first scanned out to the display. This value must
+        be compatible with the definition of MSC in
+        GLX_OML_sync_control specification. Note, that if the display
+        path has a non-zero latency, the time instant specified by
+        this counter may differ from the timestamp's.
+
+        If the output does not have a concept of vertical retrace or a
+        refresh cycle, or the output device is self-refreshing without
+        a way to query the refresh count, then the arguments seq_hi
+        and seq_lo must be zero.
+      </description>
+      <arg name="tv_sec_hi" type="uint"
+           summary="high 32 bits of the seconds part of the presentation timestamp"/>
+      <arg name="tv_sec_lo" type="uint"
+           summary="low 32 bits of the seconds part of the presentation timestamp"/>
+      <arg name="tv_nsec" type="uint"
+           summary="nanoseconds part of the presentation timestamp"/>
+      <arg name="refresh" type="uint" summary="nanoseconds till next refresh"/>
+      <arg name="seq_hi" type="uint"
+           summary="high 32 bits of refresh counter"/>
+      <arg name="seq_lo" type="uint"
+           summary="low 32 bits of refresh counter"/>
+      <arg name="flags" type="uint" enum="kind" summary="combination of 'kind' values"/>
+    </event>
+
+    <event name="discarded" type="destructor">
+      <description summary="the content update was not displayed">
+        The content update was never displayed to the user.
+      </description>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/stable/tablet/README b/subprojects/wayland-protocols/stable/tablet/README
new file mode 100644
index 0000000000000000000000000000000000000000..5c6a5b975a00bfe7694ddddd144561c5f11d606b
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/tablet/README
@@ -0,0 +1,4 @@
+Tablet protocol
+
+Maintainers:
+Peter Hutterer <peter.hutterer@who-t.net> (@whot)
diff --git a/subprojects/wayland-protocols/stable/tablet/tablet-v2.xml b/subprojects/wayland-protocols/stable/tablet/tablet-v2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..58329f72da2371a162cf89e74135c1d7376b4142
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/tablet/tablet-v2.xml
@@ -0,0 +1,1178 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="tablet_v2">
+
+  <copyright>
+    Copyright 2014 © Stephen "Lyude" Chandler Paul
+    Copyright 2015-2016 © 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.
+  </copyright>
+
+  <description summary="Wayland protocol for graphics tablets">
+    This description provides a high-level overview of the interplay between
+    the interfaces defined this protocol. For details, see the protocol
+    specification.
+
+    More than one tablet may exist, and device-specifics matter. Tablets are
+    not represented by a single virtual device like wl_pointer. A client
+    binds to the tablet manager object which is just a proxy object. From
+    that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+    and that returns the actual interface that has all the tablets. With
+    this indirection, we can avoid merging wp_tablet into the actual Wayland
+    protocol, a long-term benefit.
+
+    The wp_tablet_seat sends a "tablet added" event for each tablet
+    connected. That event is followed by descriptive events about the
+    hardware; currently that includes events for name, vid/pid and
+    a wp_tablet.path event that describes a local path. This path can be
+    used to uniquely identify a tablet or get more information through
+    libwacom. Emulated or nested tablets can skip any of those, e.g. a
+    virtual tablet may not have a vid/pid. The sequence of descriptive
+    events is terminated by a wp_tablet.done event to signal that a client
+    may now finalize any initialization for that tablet.
+
+    Events from tablets require a tool in proximity. Tools are also managed
+    by the tablet seat; a "tool added" event is sent whenever a tool is new
+    to the compositor. That event is followed by a number of descriptive
+    events about the hardware; currently that includes capabilities,
+    hardware id and serial number, and tool type. Similar to the tablet
+    interface, a wp_tablet_tool.done event is sent to terminate that initial
+    sequence.
+
+    Any event from a tool happens on the wp_tablet_tool interface. When the
+    tool gets into proximity of the tablet, a proximity_in event is sent on
+    the wp_tablet_tool interface, listing the tablet and the surface. That
+    event is followed by a motion event with the coordinates. After that,
+    it's the usual motion, axis, button, etc. events. The protocol's
+    serialisation means events are grouped by wp_tablet_tool.frame events.
+
+    Two special events (that don't exist in X) are down and up. They signal
+    "tip touching the surface". For tablets without real proximity
+    detection, the sequence is: proximity_in, motion, down, frame.
+
+    When the tool leaves proximity, a proximity_out event is sent. If any
+    button is still down, a button release event is sent before this
+    proximity event. These button events are sent in the same frame as the
+    proximity event to signal to the client that the buttons were held when
+    the tool left proximity.
+
+    If the tool moves out of the surface but stays in proximity (i.e.
+    between windows), compositor-specific grab policies apply. This usually
+    means that the proximity-out is delayed until all buttons are released.
+
+    Moving a tool physically from one tablet to the other has no real effect
+    on the protocol, since we already have the tool object from the "tool
+    added" event. All the information is already there and the proximity
+    events on both tablets are all a client needs to reconstruct what
+    happened.
+
+    Some extra axes are normalized, i.e. the client knows the range as
+    specified in the protocol (e.g. [0, 65535]), the granularity however is
+    unknown. The current normalized axes are pressure, distance, and slider.
+
+    Other extra axes are in physical units as specified in the protocol.
+    The current extra axes with physical units are tilt, rotation and
+    wheel rotation.
+
+    Since tablets work independently of the pointer controlled by the mouse,
+    the focus handling is independent too and controlled by proximity.
+    The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
+    This cursor surface may be the same as the mouse cursor, and it may be
+    the same across tools but it is possible to be more fine-grained. For
+    example, a client may set different cursors for the pen and eraser.
+
+    Tools are generally independent of tablets and it is
+    compositor-specific policy when a tool can be removed. Common approaches
+    will likely include some form of removing a tool when all tablets the
+    tool was used on are removed.
+  </description>
+
+  <interface name="zwp_tablet_manager_v2" version="1">
+    <description summary="controller object for graphic tablet devices">
+      An object that provides access to the graphics tablets available on this
+      system. All tablets are associated with a seat, to get access to the
+      actual tablets, use wp_tablet_manager.get_tablet_seat.
+    </description>
+
+    <request name="get_tablet_seat">
+      <description summary="get the tablet seat">
+	Get the wp_tablet_seat object for the given seat. This object
+	provides access to all graphics tablets in this seat.
+      </description>
+      <arg name="tablet_seat" type="new_id" interface="zwp_tablet_seat_v2"/>
+      <arg name="seat" type="object" interface="wl_seat" summary="The wl_seat object to retrieve the tablets for" />
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="release the memory for the tablet manager object">
+	Destroy the wp_tablet_manager object. Objects created from this
+	object are unaffected and should be destroyed separately.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="zwp_tablet_seat_v2" version="1">
+    <description summary="controller object for graphic tablet devices of a seat">
+      An object that provides access to the graphics tablets available on this
+      seat. After binding to this interface, the compositor sends a set of
+      wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="release the memory for the tablet seat object">
+	Destroy the wp_tablet_seat object. Objects created from this
+	object are unaffected and should be destroyed separately.
+      </description>
+    </request>
+
+    <event name="tablet_added">
+      <description summary="new device notification">
+	This event is sent whenever a new tablet becomes available on this
+	seat. This event only provides the object id of the tablet, any
+	static information about the tablet (device name, vid/pid, etc.) is
+	sent through the wp_tablet interface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_tablet_v2" summary="the newly added graphics tablet"/>
+    </event>
+
+    <event name="tool_added">
+      <description summary="a new tool has been used with a tablet">
+	This event is sent whenever a tool that has not previously been used
+	with a tablet comes into use. This event only provides the object id
+	of the tool; any static information about the tool (capabilities,
+	type, etc.) is sent through the wp_tablet_tool interface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_tablet_tool_v2" summary="the newly added tablet tool"/>
+    </event>
+
+    <event name="pad_added">
+      <description summary="new pad notification">
+	This event is sent whenever a new pad is known to the system. Typically,
+	pads are physically attached to tablets and a pad_added event is
+	sent immediately after the wp_tablet_seat.tablet_added.
+	However, some standalone pad devices logically attach to tablets at
+	runtime, and the client must wait for wp_tablet_pad.enter to know
+	the tablet a pad is attached to.
+
+	This event only provides the object id of the pad. All further
+	features (buttons, strips, rings) are sent through the wp_tablet_pad
+	interface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_tablet_pad_v2" summary="the newly added pad"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_tool_v2" version="1">
+    <description summary="a physical tablet tool">
+      An object that represents a physical tool that has been, or is
+      currently in use with a tablet in this seat. Each wp_tablet_tool
+      object stays valid until the client destroys it; the compositor
+      reuses the wp_tablet_tool object to indicate that the object's
+      respective physical tool has come into proximity of a tablet again.
+
+      A wp_tablet_tool object's relation to a physical tool depends on the
+      tablet's ability to report serial numbers. If the tablet supports
+      this capability, then the object represents a specific physical tool
+      and can be identified even when used on multiple tablets.
+
+      A tablet tool has a number of static characteristics, e.g. tool type,
+      hardware_serial and capabilities. These capabilities are sent in an
+      event sequence after the wp_tablet_seat.tool_added event before any
+      actual events from this tool. This initial event sequence is
+      terminated by a wp_tablet_tool.done event.
+
+      Tablet tool events are grouped by wp_tablet_tool.frame events.
+      Any events received before a wp_tablet_tool.frame event should be
+      considered part of the same hardware state change.
+    </description>
+
+    <request name="set_cursor">
+      <description summary="set the tablet tool's surface">
+	Sets the surface of the cursor used for this tool on the given
+	tablet. This request only takes effect if the tool is in proximity
+	of one of the requesting client's surfaces or the surface parameter
+	is the current pointer surface. If there was a previous surface set
+	with this request it is replaced. If surface is NULL, the cursor
+	image is hidden.
+
+	The parameters hotspot_x and hotspot_y define the position of the
+	pointer surface relative to the pointer location. Its top-left corner
+	is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+	coordinates of the pointer location, in surface-local coordinates.
+
+	On surface.attach requests to the pointer surface, hotspot_x and
+	hotspot_y are decremented by the x and y parameters passed to the
+	request. Attach must be confirmed by wl_surface.commit as usual.
+
+	The hotspot can also be updated by passing the currently set pointer
+	surface to this request with new values for hotspot_x and hotspot_y.
+
+	The current and pending input regions of the wl_surface are cleared,
+	and wl_surface.set_input_region is ignored until the wl_surface is no
+	longer used as the cursor. When the use as a cursor ends, the current
+	and pending input regions become undefined, and the wl_surface is
+	unmapped.
+
+	This request gives the surface the role of a wp_tablet_tool cursor. A
+	surface may only ever be used as the cursor surface for one
+	wp_tablet_tool. If the surface already has another role or has
+	previously been used as cursor surface for a different tool, a
+	protocol error is raised.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the proximity_in event"/>
+      <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+      <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/>
+      <arg name="hotspot_y" type="int" summary="surface-local y coordinate"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the tool object">
+	This destroys the client's resource for this tool object.
+      </description>
+    </request>
+
+    <enum name="type">
+      <description summary="a physical tool type">
+	Describes the physical type of a tool. The physical type of a tool
+	generally defines its base usage.
+
+	The mouse tool represents a mouse-shaped tool that is not a relative
+	device but bound to the tablet's surface, providing absolute
+	coordinates.
+
+	The lens tool is a mouse-shaped tool with an attached lens to
+	provide precision focus.
+      </description>
+      <entry name="pen" value="0x140" summary="Pen"/>
+      <entry name="eraser" value="0x141" summary="Eraser"/>
+      <entry name="brush" value="0x142" summary="Brush"/>
+      <entry name="pencil" value="0x143" summary="Pencil"/>
+      <entry name="airbrush" value="0x144" summary="Airbrush"/>
+      <entry name="finger" value="0x145" summary="Finger"/>
+      <entry name="mouse" value="0x146" summary="Mouse"/>
+      <entry name="lens" value="0x147" summary="Lens"/>
+    </enum>
+
+    <event name="type">
+      <description summary="tool type">
+	The tool type is the high-level type of the tool and usually decides
+	the interaction expected from this tool.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="tool_type" type="uint" enum="type" summary="the physical tool type"/>
+    </event>
+
+    <event name="hardware_serial">
+      <description summary="unique hardware serial number of the tool">
+	If the physical tool can be identified by a unique 64-bit serial
+	number, this event notifies the client of this serial number.
+
+	If multiple tablets are available in the same seat and the tool is
+	uniquely identifiable by the serial number, that tool may move
+	between tablets.
+
+	Otherwise, if the tool has no serial number and this event is
+	missing, the tool is tied to the tablet it first comes into
+	proximity with. Even if the physical tool is used on multiple
+	tablets, separate wp_tablet_tool objects will be created, one per
+	tablet.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="hardware_serial_hi" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+      <arg name="hardware_serial_lo" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+    </event>
+
+    <event name="hardware_id_wacom">
+      <description summary="hardware id notification in Wacom's format">
+	This event notifies the client of a hardware id available on this tool.
+
+	The hardware id is a device-specific 64-bit id that provides extra
+	information about the tool in use, beyond the wl_tool.type
+	enumeration. The format of the id is specific to tablets made by
+	Wacom Inc. For example, the hardware id of a Wacom Grip
+	Pen (a stylus) is 0x802.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="hardware_id_hi" type="uint" summary="the hardware id, most significant bits"/>
+      <arg name="hardware_id_lo" type="uint" summary="the hardware id, least significant bits"/>
+    </event>
+
+    <enum name="capability">
+      <description summary="capability flags for a tool">
+	Describes extra capabilities on a tablet.
+
+	Any tool must provide x and y values, extra axes are
+	device-specific.
+      </description>
+      <entry name="tilt" value="1" summary="Tilt axes"/>
+      <entry name="pressure" value="2" summary="Pressure axis"/>
+      <entry name="distance" value="3" summary="Distance axis"/>
+      <entry name="rotation" value="4" summary="Z-rotation axis"/>
+      <entry name="slider" value="5" summary="Slider axis"/>
+      <entry name="wheel" value="6" summary="Wheel axis"/>
+    </enum>
+
+    <event name="capability">
+      <description summary="tool capability notification">
+	This event notifies the client of any capabilities of this tool,
+	beyond the main set of x/y axes and tip up/down detection.
+
+	One event is sent for each extra capability available on this tool.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="capability" type="uint" enum="capability" summary="the capability"/>
+    </event>
+
+    <event name="done">
+      <description summary="tool description events sequence complete">
+	This event signals the end of the initial burst of descriptive
+	events. A client may consider the static description of the tool to
+	be complete and finalize initialization of the tool.
+      </description>
+    </event>
+
+    <event name="removed">
+      <description summary="tool removed">
+	This event is sent when the tool is removed from the system and will
+	send no further events. Should the physical tool come back into
+	proximity later, a new wp_tablet_tool object will be created.
+
+	It is compositor-dependent when a tool is removed. A compositor may
+	remove a tool on proximity out, tablet removal or any other reason.
+	A compositor may also keep a tool alive until shutdown.
+
+	If the tool is currently in proximity, a proximity_out event will be
+	sent before the removed event. See wp_tablet_tool.proximity_out for
+	the handling of any buttons logically down.
+
+	When this event is received, the client must wp_tablet_tool.destroy
+	the object.
+      </description>
+    </event>
+
+    <event name="proximity_in">
+      <description summary="proximity in event">
+	Notification that this tool is focused on a certain surface.
+
+	This event can be received when the tool has moved from one surface to
+	another, or when the tool has come back into proximity above the
+	surface.
+
+	If any button is logically down when the tool comes into proximity,
+	the respective button event is sent after the proximity_in event but
+	within the same frame as the proximity_in event.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="tablet" type="object" interface="zwp_tablet_v2" summary="The tablet the tool is in proximity of"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="The current surface the tablet tool is over"/>
+    </event>
+
+    <event name="proximity_out">
+      <description summary="proximity out event">
+	Notification that this tool has either left proximity, or is no
+	longer focused on a certain surface.
+
+	When the tablet tool leaves proximity of the tablet, button release
+	events are sent for each button that was held down at the time of
+	leaving proximity. These events are sent before the proximity_out
+	event but within the same wp_tablet.frame.
+
+	If the tool stays within proximity of the tablet, but the focus
+	changes from one surface to another, a button release event may not
+	be sent until the button is actually released or the tool leaves the
+	proximity of the tablet.
+      </description>
+    </event>
+
+    <event name="down">
+      <description summary="tablet tool is making contact">
+	Sent whenever the tablet tool comes in contact with the surface of the
+	tablet.
+
+	If the tool is already in contact with the tablet when entering the
+	input region, the client owning said region will receive a
+	wp_tablet.proximity_in event, followed by a wp_tablet.down
+	event and a wp_tablet.frame event.
+
+	Note that this event describes logical contact, not physical
+	contact. On some devices, a compositor may not consider a tool in
+	logical contact until a minimum physical pressure threshold is
+	exceeded.
+      </description>
+      <arg name="serial" type="uint"/>
+    </event>
+
+    <event name="up">
+      <description summary="tablet tool is no longer making contact">
+	Sent whenever the tablet tool stops making contact with the surface of
+	the tablet, or when the tablet tool moves out of the input region
+	and the compositor grab (if any) is dismissed.
+
+	If the tablet tool moves out of the input region while in contact
+	with the surface of the tablet and the compositor does not have an
+	ongoing grab on the surface, the client owning said region will
+	receive a wp_tablet.up event, followed by a wp_tablet.proximity_out
+	event and a wp_tablet.frame event. If the compositor has an ongoing
+	grab on this device, this event sequence is sent whenever the grab
+	is dismissed in the future.
+
+	Note that this event describes logical contact, not physical
+	contact. On some devices, a compositor may not consider a tool out
+	of logical contact until physical pressure falls below a specific
+	threshold.
+      </description>
+    </event>
+
+    <event name="motion">
+      <description summary="motion event">
+	Sent whenever a tablet tool moves.
+      </description>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="pressure">
+      <description summary="pressure change event">
+	Sent whenever the pressure axis on a tool changes. The value of this
+	event is normalized to a value between 0 and 65535.
+
+	Note that pressure may be nonzero even when a tool is not in logical
+	contact. See the down and up events for more details.
+      </description>
+      <arg name="pressure" type="uint" summary="The current pressure value"/>
+    </event>
+
+    <event name="distance">
+      <description summary="distance change event">
+	Sent whenever the distance axis on a tool changes. The value of this
+	event is normalized to a value between 0 and 65535.
+
+	Note that distance may be nonzero even when a tool is not in logical
+	contact. See the down and up events for more details.
+      </description>
+      <arg name="distance" type="uint" summary="The current distance value"/>
+    </event>
+
+    <event name="tilt">
+      <description summary="tilt change event">
+	Sent whenever one or both of the tilt axes on a tool change. Each tilt
+	value is in degrees, relative to the z-axis of the tablet.
+	The angle is positive when the top of a tool tilts along the
+	positive x or y axis.
+      </description>
+      <arg name="tilt_x" type="fixed" summary="The current value of the X tilt axis"/>
+      <arg name="tilt_y" type="fixed" summary="The current value of the Y tilt axis"/>
+    </event>
+
+    <event name="rotation">
+      <description summary="z-rotation change event">
+	Sent whenever the z-rotation axis on the tool changes. The
+	rotation value is in degrees clockwise from the tool's
+	logical neutral position.
+      </description>
+      <arg name="degrees" type="fixed" summary="The current rotation of the Z axis"/>
+    </event>
+
+    <event name="slider">
+      <description summary="Slider position change event">
+	Sent whenever the slider position on the tool changes. The
+	value is normalized between -65535 and 65535, with 0 as the logical
+	neutral position of the slider.
+
+	The slider is available on e.g. the Wacom Airbrush tool.
+      </description>
+      <arg name="position" type="int" summary="The current position of slider"/>
+    </event>
+
+    <event name="wheel">
+      <description summary="Wheel delta event">
+	Sent whenever the wheel on the tool emits an event. This event
+	contains two values for the same axis change. The degrees value is
+	in the same orientation as the wl_pointer.vertical_scroll axis. The
+	clicks value is in discrete logical clicks of the mouse wheel. This
+	value may be zero if the movement of the wheel was less
+	than one logical click.
+
+	Clients should choose either value and avoid mixing degrees and
+	clicks. The compositor may accumulate values smaller than a logical
+	click and emulate click events when a certain threshold is met.
+	Thus, wl_tablet_tool.wheel events with non-zero clicks values may
+	have different degrees values.
+      </description>
+      <arg name="degrees" type="fixed" summary="The wheel delta in degrees"/>
+      <arg name="clicks" type="int" summary="The wheel delta in discrete clicks"/>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+	Describes the physical state of a button that produced the button event.
+      </description>
+      <entry name="released" value="0" summary="button is not pressed"/>
+      <entry name="pressed" value="1" summary="button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="button event">
+	Sent whenever a button on the tool is pressed or released.
+
+	If a button is held down when the tool moves in or out of proximity,
+	button events are generated by the compositor. See
+	wp_tablet_tool.proximity_in and wp_tablet_tool.proximity_out for
+	details.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="button" type="uint" summary="The button whose state has changed"/>
+      <arg name="state" type="uint" enum="button_state" summary="Whether the button was pressed or released"/>
+    </event>
+
+    <event name="frame">
+      <description summary="frame event">
+	Marks the end of a series of axis and/or button updates from the
+	tablet. The Wayland protocol requires axis updates to be sent
+	sequentially, however all events within a frame should be considered
+	one hardware event.
+      </description>
+      <arg name="time" type="uint" summary="The time of the event with millisecond granularity"/>
+    </event>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+  </interface>
+
+  <interface name="zwp_tablet_v2" version="1">
+    <description summary="graphics tablet device">
+      The wp_tablet interface represents one graphics tablet device. The
+      tablet interface itself does not generate events; all events are
+      generated by wp_tablet_tool objects when in proximity above a tablet.
+
+      A tablet has a number of static characteristics, e.g. device name and
+      pid/vid. These capabilities are sent in an event sequence after the
+      wp_tablet_seat.tablet_added event. This initial event sequence is
+      terminated by a wp_tablet.done event.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the tablet object">
+	This destroys the client's resource for this tablet object.
+      </description>
+    </request>
+
+    <event name="name">
+      <description summary="tablet device name">
+        A descriptive name for the tablet device.
+
+	If the device has no descriptive name, this event is not sent.
+
+	This event is sent in the initial burst of events before the
+        wp_tablet.done event.
+      </description>
+      <arg name="name" type="string" summary="the device name"/>
+    </event>
+
+    <event name="id">
+      <description summary="tablet device USB vendor/product id">
+	The USB vendor and product IDs for the tablet device.
+
+	If the device has no USB vendor/product ID, this event is not sent.
+	This can happen for virtual devices or non-USB devices, for instance.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet.done event.
+      </description>
+      <arg name="vid" type="uint" summary="USB vendor id"/>
+      <arg name="pid" type="uint" summary="USB product id"/>
+    </event>
+
+    <event name="path">
+      <description summary="path to the device">
+	A system-specific device path that indicates which device is behind
+	this wp_tablet. This information may be used to gather additional
+	information about the device, e.g. through libwacom.
+
+	A device may have more than one device path. If so, multiple
+	wp_tablet.path events are sent. A device may be emulated and not
+	have a device path, and in that case this event will not be sent.
+
+	The format of the path is unspecified, it may be a device node, a
+	sysfs path, or some other identifier. It is up to the client to
+	identify the string provided.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet.done event.
+      </description>
+      <arg name="path" type="string" summary="path to local device"/>
+    </event>
+
+    <event name="done">
+      <description summary="tablet description events sequence complete">
+	This event is sent immediately to signal the end of the initial
+	burst of descriptive events. A client may consider the static
+	description of the tablet to be complete and finalize initialization
+	of the tablet.
+      </description>
+    </event>
+
+    <event name="removed">
+      <description summary="tablet removed event">
+	Sent when the tablet has been removed from the system. When a tablet
+	is removed, some tools may be removed.
+
+	When this event is received, the client must wp_tablet.destroy
+	the object.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_pad_ring_v2" version="1">
+    <description summary="pad ring">
+      A circular interaction area, such as the touch ring on the Wacom Intuos
+      Pro series tablets.
+
+      Events on a ring are logically grouped by the wl_tablet_pad_ring.frame
+      event.
+    </description>
+
+    <request name="set_feedback">
+      <description summary="set compositor feedback">
+	Request that the compositor use the provided feedback string
+	associated with this ring. This request should be issued immediately
+	after a wp_tablet_pad_group.mode_switch event from the corresponding
+	group is received, or whenever the ring is mapped to a different
+	action. See wp_tablet_pad_group.mode_switch for more details.
+
+	Clients are encouraged to provide context-aware descriptions for
+	the actions associated with the ring; compositors may use this
+	information to offer visual feedback about the button layout
+	(eg. on-screen displays).
+
+	The provided string 'description' is a UTF-8 encoded string to be
+	associated with this ring, and is considered user-visible; general
+	internationalization rules apply.
+
+	The serial argument will be that of the last
+	wp_tablet_pad_group.mode_switch event received for the group of this
+	ring. Requests providing other serials than the most recent one will be
+	ignored.
+      </description>
+      <arg name="description" type="string" summary="ring description"/>
+      <arg name="serial" type="uint" summary="serial of the mode switch event"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the ring object">
+	This destroys the client's resource for this ring object.
+      </description>
+    </request>
+
+    <enum name="source">
+      <description summary="ring axis source">
+	Describes the source types for ring events. This indicates to the
+	client how a ring event was physically generated; a client may
+	adjust the user interface accordingly. For example, events
+	from a "finger" source may trigger kinetic scrolling.
+      </description>
+      <entry name="finger" value="1" summary="finger"/>
+    </enum>
+
+    <event name="source">
+      <description summary="ring event source">
+	Source information for ring events.
+
+	This event does not occur on its own. It is sent before a
+	wp_tablet_pad_ring.frame event and carries the source information
+	for all events within that frame.
+
+	The source specifies how this event was generated. If the source is
+	wp_tablet_pad_ring.source.finger, a wp_tablet_pad_ring.stop event
+	will be sent when the user lifts the finger off the device.
+
+	This event is optional. If the source is unknown for an interaction,
+	no event is sent.
+      </description>
+      <arg name="source" type="uint" enum="source" summary="the event source"/>
+    </event>
+
+    <event name="angle">
+      <description summary="angle changed">
+	Sent whenever the angle on a ring changes.
+
+	The angle is provided in degrees clockwise from the logical
+	north of the ring in the pad's current rotation.
+      </description>
+      <arg name="degrees" type="fixed" summary="the current angle in degrees"/>
+    </event>
+
+    <event name="stop">
+      <description summary="interaction stopped">
+	Stop notification for ring events.
+
+	For some wp_tablet_pad_ring.source types, a wp_tablet_pad_ring.stop
+	event is sent to notify a client that the interaction with the ring
+	has terminated. This enables the client to implement kinetic scrolling.
+	See the wp_tablet_pad_ring.source documentation for information on
+	when this event may be generated.
+
+	Any wp_tablet_pad_ring.angle events with the same source after this
+	event should be considered as the start of a new interaction.
+      </description>
+    </event>
+
+    <event name="frame">
+      <description summary="end of a ring event sequence">
+	Indicates the end of a set of ring events that logically belong
+	together. A client is expected to accumulate the data in all events
+	within the frame before proceeding.
+
+	All wp_tablet_pad_ring events before a wp_tablet_pad_ring.frame event belong
+	logically together. For example, on termination of a finger interaction
+	on a ring the compositor will send a wp_tablet_pad_ring.source event,
+	a wp_tablet_pad_ring.stop event and a wp_tablet_pad_ring.frame event.
+
+	A wp_tablet_pad_ring.frame event is sent for every logical event
+	group, even if the group only contains a single wp_tablet_pad_ring
+	event. Specifically, a client may get a sequence: angle, frame,
+	angle, frame, etc.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_pad_strip_v2" version="1">
+    <description summary="pad strip">
+      A linear interaction area, such as the strips found in Wacom Cintiq
+      models.
+
+      Events on a strip are logically grouped by the wl_tablet_pad_strip.frame
+      event.
+    </description>
+
+    <request name="set_feedback">
+      <description summary="set compositor feedback">
+	Requests the compositor to use the provided feedback string
+	associated with this strip. This request should be issued immediately
+	after a wp_tablet_pad_group.mode_switch event from the corresponding
+	group is received, or whenever the strip is mapped to a different
+	action. See wp_tablet_pad_group.mode_switch for more details.
+
+	Clients are encouraged to provide context-aware descriptions for
+	the actions associated with the strip, and compositors may use this
+	information to offer visual feedback about the button layout
+	(eg. on-screen displays).
+
+	The provided string 'description' is a UTF-8 encoded string to be
+	associated with this ring, and is considered user-visible; general
+	internationalization rules apply.
+
+	The serial argument will be that of the last
+	wp_tablet_pad_group.mode_switch event received for the group of this
+	strip. Requests providing other serials than the most recent one will be
+	ignored.
+      </description>
+      <arg name="description" type="string" summary="strip description"/>
+      <arg name="serial" type="uint" summary="serial of the mode switch event"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the strip object">
+	This destroys the client's resource for this strip object.
+      </description>
+    </request>
+
+    <enum name="source">
+      <description summary="strip axis source">
+	Describes the source types for strip events. This indicates to the
+	client how a strip event was physically generated; a client may
+	adjust the user interface accordingly. For example, events
+	from a "finger" source may trigger kinetic scrolling.
+      </description>
+      <entry name="finger" value="1" summary="finger"/>
+    </enum>
+
+    <event name="source">
+      <description summary="strip event source">
+	Source information for strip events.
+
+	This event does not occur on its own. It is sent before a
+	wp_tablet_pad_strip.frame event and carries the source information
+	for all events within that frame.
+
+	The source specifies how this event was generated. If the source is
+	wp_tablet_pad_strip.source.finger, a wp_tablet_pad_strip.stop event
+	will be sent when the user lifts their finger off the device.
+
+	This event is optional. If the source is unknown for an interaction,
+	no event is sent.
+      </description>
+      <arg name="source" type="uint" enum="source" summary="the event source"/>
+    </event>
+
+    <event name="position">
+      <description summary="position changed">
+	Sent whenever the position on a strip changes.
+
+	The position is normalized to a range of [0, 65535], the 0-value
+	represents the top-most and/or left-most position of the strip in
+	the pad's current rotation.
+      </description>
+      <arg name="position" type="uint" summary="the current position"/>
+    </event>
+
+    <event name="stop">
+      <description summary="interaction stopped">
+	Stop notification for strip events.
+
+	For some wp_tablet_pad_strip.source types, a wp_tablet_pad_strip.stop
+	event is sent to notify a client that the interaction with the strip
+	has terminated. This enables the client to implement kinetic
+	scrolling. See the wp_tablet_pad_strip.source documentation for
+	information on when this event may be generated.
+
+	Any wp_tablet_pad_strip.position events with the same source after this
+	event should be considered as the start of a new interaction.
+      </description>
+    </event>
+
+    <event name="frame">
+      <description summary="end of a strip event sequence">
+	Indicates the end of a set of events that represent one logical
+	hardware strip event. A client is expected to accumulate the data
+	in all events within the frame before proceeding.
+
+	All wp_tablet_pad_strip events before a wp_tablet_pad_strip.frame event belong
+	logically together. For example, on termination of a finger interaction
+	on a strip the compositor will send a wp_tablet_pad_strip.source event,
+	a wp_tablet_pad_strip.stop event and a wp_tablet_pad_strip.frame
+	event.
+
+	A wp_tablet_pad_strip.frame event is sent for every logical event
+	group, even if the group only contains a single wp_tablet_pad_strip
+	event. Specifically, a client may get a sequence: position, frame,
+	position, frame, etc.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_pad_group_v2" version="1">
+    <description summary="a set of buttons, rings and strips">
+      A pad group describes a distinct (sub)set of buttons, rings and strips
+      present in the tablet. The criteria of this grouping is usually positional,
+      eg. if a tablet has buttons on the left and right side, 2 groups will be
+      presented. The physical arrangement of groups is undisclosed and may
+      change on the fly.
+
+      Pad groups will announce their features during pad initialization. Between
+      the corresponding wp_tablet_pad.group event and wp_tablet_pad_group.done, the
+      pad group will announce the buttons, rings and strips contained in it,
+      plus the number of supported modes.
+
+      Modes are a mechanism to allow multiple groups of actions for every element
+      in the pad group. The number of groups and available modes in each is
+      persistent across device plugs. The current mode is user-switchable, it
+      will be announced through the wp_tablet_pad_group.mode_switch event both
+      whenever it is switched, and after wp_tablet_pad.enter.
+
+      The current mode logically applies to all elements in the pad group,
+      although it is at clients' discretion whether to actually perform different
+      actions, and/or issue the respective .set_feedback requests to notify the
+      compositor. See the wp_tablet_pad_group.mode_switch event for more details.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pad object">
+	Destroy the wp_tablet_pad_group object. Objects created from this object
+	are unaffected and should be destroyed separately.
+      </description>
+    </request>
+
+    <event name="buttons">
+      <description summary="buttons announced">
+	Sent on wp_tablet_pad_group initialization to announce the available
+	buttons in the group. Button indices start at 0, a button may only be
+	in one group at a time.
+
+	This event is first sent in the initial burst of events before the
+	wp_tablet_pad_group.done event.
+
+	Some buttons are reserved by the compositor. These buttons may not be
+	assigned to any wp_tablet_pad_group. Compositors may broadcast this
+	event in the case of changes to the mapping of these reserved buttons.
+	If the compositor happens to reserve all buttons in a group, this event
+	will be sent with an empty array.
+      </description>
+      <arg name="buttons" type="array" summary="buttons in this group"/>
+    </event>
+
+    <event name="ring">
+      <description summary="ring announced">
+	Sent on wp_tablet_pad_group initialization to announce available rings.
+	One event is sent for each ring available on this pad group.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad_group.done event.
+      </description>
+      <arg name="ring" type="new_id" interface="zwp_tablet_pad_ring_v2"/>
+    </event>
+
+    <event name="strip">
+      <description summary="strip announced">
+	Sent on wp_tablet_pad initialization to announce available strips.
+	One event is sent for each strip available on this pad group.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad_group.done event.
+      </description>
+      <arg name="strip" type="new_id" interface="zwp_tablet_pad_strip_v2"/>
+    </event>
+
+    <event name="modes">
+      <description summary="mode-switch ability announced">
+	Sent on wp_tablet_pad_group initialization to announce that the pad
+	group may switch between modes. A client may use a mode to store a
+	specific configuration for buttons, rings and strips and use the
+	wl_tablet_pad_group.mode_switch event to toggle between these
+	configurations. Mode indices start at 0.
+
+	Switching modes is compositor-dependent. See the
+	wp_tablet_pad_group.mode_switch event for more details.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad_group.done event. This event is only sent when more than
+	more than one mode is available.
+      </description>
+      <arg name="modes" type="uint" summary="the number of modes"/>
+    </event>
+
+    <event name="done">
+      <description summary="tablet group description events sequence complete">
+	This event is sent immediately to signal the end of the initial
+	burst of descriptive events. A client may consider the static
+	description of the tablet to be complete and finalize initialization
+	of the tablet group.
+      </description>
+    </event>
+
+    <event name="mode_switch">
+      <description summary="mode switch event">
+	Notification that the mode was switched.
+
+	A mode applies to all buttons, rings and strips in a group
+	simultaneously, but a client is not required to assign different actions
+	for each mode. For example, a client may have mode-specific button
+	mappings but map the ring to vertical scrolling in all modes. Mode
+	indices start at 0.
+
+	Switching modes is compositor-dependent. The compositor may provide
+	visual cues to the user about the mode, e.g. by toggling LEDs on
+	the tablet device. Mode-switching may be software-controlled or
+	controlled by one or more physical buttons. For example, on a Wacom
+	Intuos Pro, the button inside the ring may be assigned to switch
+	between modes.
+
+	The compositor will also send this event after wp_tablet_pad.enter on
+	each group in order to notify of the current mode. Groups that only
+	feature one mode will use mode=0 when emitting this event.
+
+	If a button action in the new mode differs from the action in the
+	previous mode, the client should immediately issue a
+	wp_tablet_pad.set_feedback request for each changed button.
+
+	If a ring or strip action in the new mode differs from the action
+	in the previous mode, the client should immediately issue a
+	wp_tablet_ring.set_feedback or wp_tablet_strip.set_feedback request
+	for each changed ring or strip.
+      </description>
+      <arg name="time" type="uint" summary="the time of the event with millisecond granularity"/>
+      <arg name="serial" type="uint"/>
+      <arg name="mode" type="uint" summary="the new mode of the pad"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_pad_v2" version="1">
+    <description summary="a set of buttons, rings and strips">
+      A pad device is a set of buttons, rings and strips
+      usually physically present on the tablet device itself. Some
+      exceptions exist where the pad device is physically detached, e.g. the
+      Wacom ExpressKey Remote.
+
+      Pad devices have no axes that control the cursor and are generally
+      auxiliary devices to the tool devices used on the tablet surface.
+
+      A pad device has a number of static characteristics, e.g. the number
+      of rings. These capabilities are sent in an event sequence after the
+      wp_tablet_seat.pad_added event before any actual events from this pad.
+      This initial event sequence is terminated by a wp_tablet_pad.done
+      event.
+
+      All pad features (buttons, rings and strips) are logically divided into
+      groups and all pads have at least one group. The available groups are
+      notified through the wp_tablet_pad.group event; the compositor will
+      emit one event per group before emitting wp_tablet_pad.done.
+
+      Groups may have multiple modes. Modes allow clients to map multiple
+      actions to a single pad feature. Only one mode can be active per group,
+      although different groups may have different active modes.
+    </description>
+
+    <request name="set_feedback">
+      <description summary="set compositor feedback">
+	Requests the compositor to use the provided feedback string
+	associated with this button. This request should be issued immediately
+	after a wp_tablet_pad_group.mode_switch event from the corresponding
+	group is received, or whenever a button is mapped to a different
+	action. See wp_tablet_pad_group.mode_switch for more details.
+
+	Clients are encouraged to provide context-aware descriptions for
+	the actions associated with each button, and compositors may use
+	this information to offer visual feedback on the button layout
+	(e.g. on-screen displays).
+
+	Button indices start at 0. Setting the feedback string on a button
+	that is reserved by the compositor (i.e. not belonging to any
+	wp_tablet_pad_group) does not generate an error but the compositor
+	is free to ignore the request.
+
+	The provided string 'description' is a UTF-8 encoded string to be
+	associated with this ring, and is considered user-visible; general
+	internationalization rules apply.
+
+	The serial argument will be that of the last
+	wp_tablet_pad_group.mode_switch event received for the group of this
+	button. Requests providing other serials than the most recent one will
+	be ignored.
+      </description>
+      <arg name="button" type="uint" summary="button index"/>
+      <arg name="description" type="string" summary="button description"/>
+      <arg name="serial" type="uint" summary="serial of the mode switch event"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pad object">
+	Destroy the wp_tablet_pad object. Objects created from this object
+	are unaffected and should be destroyed separately.
+      </description>
+    </request>
+
+    <event name="group">
+      <description summary="group announced">
+	Sent on wp_tablet_pad initialization to announce available groups.
+	One event is sent for each pad group available.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad.done event. At least one group will be announced.
+      </description>
+      <arg name="pad_group" type="new_id" interface="zwp_tablet_pad_group_v2"/>
+    </event>
+
+    <event name="path">
+      <description summary="path to the device">
+	A system-specific device path that indicates which device is behind
+	this wp_tablet_pad. This information may be used to gather additional
+	information about the device, e.g. through libwacom.
+
+	The format of the path is unspecified, it may be a device node, a
+	sysfs path, or some other identifier. It is up to the client to
+	identify the string provided.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad.done event.
+      </description>
+      <arg name="path" type="string" summary="path to local device"/>
+    </event>
+
+    <event name="buttons">
+      <description summary="buttons announced">
+	Sent on wp_tablet_pad initialization to announce the available
+	buttons.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad.done event. This event is only sent when at least one
+	button is available.
+      </description>
+      <arg name="buttons" type="uint" summary="the number of buttons"/>
+    </event>
+
+    <event name="done">
+      <description summary="pad description event sequence complete">
+	This event signals the end of the initial burst of descriptive
+	events. A client may consider the static description of the pad to
+	be complete and finalize initialization of the pad.
+      </description>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+	Describes the physical state of a button that caused the button
+	event.
+      </description>
+      <entry name="released" value="0" summary="the button is not pressed"/>
+      <entry name="pressed" value="1" summary="the button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="physical button state">
+	Sent whenever the physical state of a button changes.
+      </description>
+      <arg name="time" type="uint" summary="the time of the event with millisecond granularity"/>
+      <arg name="button" type="uint" summary="the index of the button that changed state"/>
+      <arg name="state" type="uint" enum="button_state"/>
+    </event>
+
+    <event name="enter">
+      <description summary="enter event">
+	Notification that this pad is focused on the specified surface.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="tablet" type="object" interface="zwp_tablet_v2" summary="the tablet the pad is attached to"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface the pad is focused on"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+	Notification that this pad is no longer focused on the specified
+	surface.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the leave event"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface the pad is no longer focused on"/>
+    </event>
+
+    <event name="removed">
+      <description summary="pad removed event">
+	Sent when the pad has been removed from the system. When a tablet
+	is removed its pad(s) will be removed too.
+
+	When this event is received, the client must destroy all rings, strips
+	and groups that were offered by this pad, and issue wp_tablet_pad.destroy
+	the pad itself.
+      </description>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/stable/viewporter/README b/subprojects/wayland-protocols/stable/viewporter/README
new file mode 100644
index 0000000000000000000000000000000000000000..e262a57a17d11d4347617ac69ae5ac17f7bef6df
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/viewporter/README
@@ -0,0 +1,7 @@
+Viewporter: cropping and scaling extension for surface contents
+
+Previously known as wl_scaler.
+
+Maintainers:
+Pekka Paalanen <pekka.paalanen@collabora.co.uk> (@pq)
+
diff --git a/subprojects/wayland-protocols/stable/viewporter/viewporter.xml b/subprojects/wayland-protocols/stable/viewporter/viewporter.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1374aeca0657b08dc3180865ccd384b16023f058
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/viewporter/viewporter.xml
@@ -0,0 +1,177 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="viewporter">
+
+  <copyright>
+    Copyright © 2013-2016 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="wp_viewporter" version="1">
+    <description summary="surface cropping and scaling">
+      The global interface exposing surface cropping and scaling
+      capabilities is used to instantiate an interface extension for a
+      wl_surface object. This extended interface will then allow
+      cropping and scaling the surface contents, effectively
+      disconnecting the direct relationship between the buffer and the
+      surface size.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the cropping and scaling interface">
+	Informs the server that the client will not be using this
+	protocol object anymore. This does not affect any other objects,
+	wp_viewport objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="viewport_exists" value="0"
+             summary="the surface already has a viewport object associated"/>
+    </enum>
+
+    <request name="get_viewport">
+      <description summary="extend surface interface for crop and scale">
+	Instantiate an interface extension for the given wl_surface to
+	crop and scale its content. If the given wl_surface already has
+	a wp_viewport object associated, the viewport_exists
+	protocol error is raised.
+      </description>
+      <arg name="id" type="new_id" interface="wp_viewport"
+           summary="the new viewport interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_viewport" version="1">
+    <description summary="crop and scale interface to a wl_surface">
+      An additional interface to a wl_surface object, which allows the
+      client to specify the cropping and scaling of the surface
+      contents.
+
+      This interface works with two concepts: the source rectangle (src_x,
+      src_y, src_width, src_height), and the destination size (dst_width,
+      dst_height). The contents of the source rectangle are scaled to the
+      destination size, and content outside the source rectangle is ignored.
+      This state is double-buffered, see wl_surface.commit.
+
+      The two parts of crop and scale state are independent: the source
+      rectangle, and the destination size. Initially both are unset, that
+      is, no scaling is applied. The whole of the current wl_buffer is
+      used as the source, and the surface size is as defined in
+      wl_surface.attach.
+
+      If the destination size is set, it causes the surface size to become
+      dst_width, dst_height. The source (rectangle) is scaled to exactly
+      this size. This overrides whatever the attached wl_buffer size is,
+      unless the wl_buffer is NULL. If the wl_buffer is NULL, the surface
+      has no content and therefore no size. Otherwise, the size is always
+      at least 1x1 in surface local coordinates.
+
+      If the source rectangle is set, it defines what area of the wl_buffer is
+      taken as the source. If the source rectangle is set and the destination
+      size is not set, then src_width and src_height must be integers, and the
+      surface size becomes the source rectangle size. This results in cropping
+      without scaling. If src_width or src_height are not integers and
+      destination size is not set, the bad_size protocol error is raised when
+      the surface state is applied.
+
+      The coordinate transformations from buffer pixel coordinates up to
+      the surface-local coordinates happen in the following order:
+        1. buffer_transform (wl_surface.set_buffer_transform)
+        2. buffer_scale (wl_surface.set_buffer_scale)
+        3. crop and scale (wp_viewport.set*)
+      This means, that the source rectangle coordinates of crop and scale
+      are given in the coordinates after the buffer transform and scale,
+      i.e. in the coordinates that would be the surface-local coordinates
+      if the crop and scale was not applied.
+
+      If src_x or src_y are negative, the bad_value protocol error is raised.
+      Otherwise, if the source rectangle is partially or completely outside of
+      the non-NULL wl_buffer, then the out_of_buffer protocol error is raised
+      when the surface state is applied. A NULL wl_buffer does not raise the
+      out_of_buffer error.
+
+      If the wl_surface associated with the wp_viewport is destroyed,
+      all wp_viewport requests except 'destroy' raise the protocol error
+      no_surface.
+
+      If the wp_viewport object is destroyed, the crop and scale
+      state is removed from the wl_surface. The change will be applied
+      on the next wl_surface.commit.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove scaling and cropping from the surface">
+	The associated wl_surface's crop and scale state is removed.
+	The change is applied on the next wl_surface.commit.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_value" value="0"
+	     summary="negative or zero values in width or height"/>
+      <entry name="bad_size" value="1"
+	     summary="destination size is not integer"/>
+      <entry name="out_of_buffer" value="2"
+	     summary="source rectangle extends outside of the content area"/>
+      <entry name="no_surface" value="3"
+	     summary="the wl_surface was destroyed"/>
+    </enum>
+
+    <request name="set_source">
+      <description summary="set the source rectangle for cropping">
+	Set the source rectangle of the associated wl_surface. See
+	wp_viewport for the description, and relation to the wl_buffer
+	size.
+
+	If all of x, y, width and height are -1.0, the source rectangle is
+	unset instead. Any other set of values where width or height are zero
+	or negative, or x or y are negative, raise the bad_value protocol
+	error.
+
+	The crop and scale state is double-buffered, see wl_surface.commit.
+      </description>
+      <arg name="x" type="fixed" summary="source rectangle x"/>
+      <arg name="y" type="fixed" summary="source rectangle y"/>
+      <arg name="width" type="fixed" summary="source rectangle width"/>
+      <arg name="height" type="fixed" summary="source rectangle height"/>
+    </request>
+
+    <request name="set_destination">
+      <description summary="set the surface size for scaling">
+	Set the destination size of the associated wl_surface. See
+	wp_viewport for the description, and relation to the wl_buffer
+	size.
+
+	If width is -1 and height is -1, the destination size is unset
+	instead. Any other pair of values for width and height that
+	contains zero or negative values raises the bad_value protocol
+	error.
+
+	The crop and scale state is double-buffered, see wl_surface.commit.
+      </description>
+      <arg name="width" type="int" summary="surface width"/>
+      <arg name="height" type="int" summary="surface height"/>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/stable/xdg-shell/README b/subprojects/wayland-protocols/stable/xdg-shell/README
new file mode 100644
index 0000000000000000000000000000000000000000..9ce6188f8db3bcca5d25e26aacdf221d1a8fdd0c
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/xdg-shell/README
@@ -0,0 +1,5 @@
+xdg shell protocol
+
+Maintainers:
+Jonas Ã…dahl <jadahl@gmail.com> (@jadahl)
+Mike Blumenkrantz <michael.blumenkrantz@gmail.com> (@zmike)
diff --git a/subprojects/wayland-protocols/stable/xdg-shell/xdg-shell.xml b/subprojects/wayland-protocols/stable/xdg-shell/xdg-shell.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1caf6f10016e4e6e68a2249a3273d0e566199217
--- /dev/null
+++ b/subprojects/wayland-protocols/stable/xdg-shell/xdg-shell.xml
@@ -0,0 +1,1383 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_shell">
+
+  <copyright>
+    Copyright © 2008-2013 Kristian Høgsberg
+    Copyright © 2013      Rafael Antognolli
+    Copyright © 2013      Jasper St. Pierre
+    Copyright © 2010-2013 Intel Corporation
+    Copyright © 2015-2017 Samsung Electronics Co., Ltd
+    Copyright © 2015-2017 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.
+  </copyright>
+
+  <interface name="xdg_wm_base" version="6">
+    <description summary="create desktop-style surfaces">
+      The xdg_wm_base interface is exposed as a global object enabling clients
+      to turn their wl_surfaces into windows in a desktop environment. It
+      defines the basic functionality needed for clients and the compositor to
+      create windows that can be dragged, resized, maximized, etc, as well as
+      creating transient windows such as popup menus.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+      <entry name="defunct_surfaces" value="1"
+	     summary="xdg_wm_base was destroyed before children"/>
+      <entry name="not_the_topmost_popup" value="2"
+	     summary="the client tried to map or destroy a non-topmost popup"/>
+      <entry name="invalid_popup_parent" value="3"
+	     summary="the client specified an invalid popup parent surface"/>
+      <entry name="invalid_surface_state" value="4"
+	     summary="the client provided an invalid surface state"/>
+      <entry name="invalid_positioner" value="5"
+	     summary="the client provided an invalid positioner"/>
+      <entry name="unresponsive" value="6"
+	     summary="the client didn’t respond to a ping event in time"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy xdg_wm_base">
+	Destroy this xdg_wm_base object.
+
+	Destroying a bound xdg_wm_base object while there are surfaces
+	still alive created by this xdg_wm_base object instance is illegal
+	and will result in a defunct_surfaces error.
+      </description>
+    </request>
+
+    <request name="create_positioner">
+      <description summary="create a positioner object">
+	Create a positioner object. A positioner object is used to position
+	surfaces relative to some parent surface. See the interface description
+	and xdg_surface.get_popup for details.
+      </description>
+      <arg name="id" type="new_id" interface="xdg_positioner"/>
+    </request>
+
+    <request name="get_xdg_surface">
+      <description summary="create a shell surface from a surface">
+	This creates an xdg_surface for the given surface. While xdg_surface
+	itself is not a role, the corresponding surface may only be assigned
+	a role extending xdg_surface, such as xdg_toplevel or xdg_popup. It is
+	illegal to create an xdg_surface for a wl_surface which already has an
+	assigned role and this will result in a role error.
+
+	This creates an xdg_surface for the given surface. An xdg_surface is
+	used as basis to define a role to a given surface, such as xdg_toplevel
+	or xdg_popup. It also manages functionality shared between xdg_surface
+	based surface roles.
+
+	See the documentation of xdg_surface for more details about what an
+	xdg_surface is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="xdg_surface"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+
+    <request name="pong">
+      <description summary="respond to a ping event">
+	A client must respond to a ping event with a pong request or
+	the client may be deemed unresponsive. See xdg_wm_base.ping
+	and xdg_wm_base.error.unresponsive.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the ping event"/>
+    </request>
+
+    <event name="ping">
+      <description summary="check if the client is alive">
+	The ping event asks the client if it's still alive. Pass the
+	serial specified in the event back to the compositor by sending
+	a "pong" request back with the specified serial. See xdg_wm_base.pong.
+
+	Compositors can use this to determine if the client is still
+	alive. It's unspecified what will happen if the client doesn't
+	respond to the ping request, or in what timeframe. Clients should
+	try to respond in a reasonable amount of time. The “unresponsive”
+	error is provided for compositors that wish to disconnect unresponsive
+	clients.
+
+	A compositor is free to ping in any way it wants, but a client must
+	always respond to any xdg_wm_base object it created.
+      </description>
+      <arg name="serial" type="uint" summary="pass this to the pong request"/>
+    </event>
+  </interface>
+
+  <interface name="xdg_positioner" version="6">
+    <description summary="child surface positioner">
+      The xdg_positioner provides a collection of rules for the placement of a
+      child surface relative to a parent surface. Rules can be defined to ensure
+      the child surface remains within the visible area's borders, and to
+      specify how the child surface changes its position, such as sliding along
+      an axis, or flipping around a rectangle. These positioner-created rules are
+      constrained by the requirement that a child surface must intersect with or
+      be at least partially adjacent to its parent surface.
+
+      See the various requests for details about possible rules.
+
+      At the time of the request, the compositor makes a copy of the rules
+      specified by the xdg_positioner. Thus, after the request is complete the
+      xdg_positioner object can be destroyed or reused; further changes to the
+      object will have no effect on previous usages.
+
+      For an xdg_positioner object to be considered complete, it must have a
+      non-zero size set by set_size, and a non-zero anchor rectangle set by
+      set_anchor_rect. Passing an incomplete xdg_positioner object when
+      positioning a surface raises an invalid_positioner error.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_input" value="0" summary="invalid input provided"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_positioner object">
+	Notify the compositor that the xdg_positioner will no longer be used.
+      </description>
+    </request>
+
+    <request name="set_size">
+      <description summary="set the size of the to-be positioned rectangle">
+	Set the size of the surface that is to be positioned with the positioner
+	object. The size is in surface-local coordinates and corresponds to the
+	window geometry. See xdg_surface.set_window_geometry.
+
+	If a zero or negative size is set the invalid_input error is raised.
+      </description>
+      <arg name="width" type="int" summary="width of positioned rectangle"/>
+      <arg name="height" type="int" summary="height of positioned rectangle"/>
+    </request>
+
+    <request name="set_anchor_rect">
+      <description summary="set the anchor rectangle within the parent surface">
+	Specify the anchor rectangle within the parent surface that the child
+	surface will be placed relative to. The rectangle is relative to the
+	window geometry as defined by xdg_surface.set_window_geometry of the
+	parent surface.
+
+	When the xdg_positioner object is used to position a child surface, the
+	anchor rectangle may not extend outside the window geometry of the
+	positioned child's parent surface.
+
+	If a negative size is set the invalid_input error is raised.
+      </description>
+      <arg name="x" type="int" summary="x position of anchor rectangle"/>
+      <arg name="y" type="int" summary="y position of anchor rectangle"/>
+      <arg name="width" type="int" summary="width of anchor rectangle"/>
+      <arg name="height" type="int" summary="height of anchor rectangle"/>
+    </request>
+
+    <enum name="anchor">
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="3"/>
+      <entry name="right" value="4"/>
+      <entry name="top_left" value="5"/>
+      <entry name="bottom_left" value="6"/>
+      <entry name="top_right" value="7"/>
+      <entry name="bottom_right" value="8"/>
+    </enum>
+
+    <request name="set_anchor">
+      <description summary="set anchor rectangle anchor">
+	Defines the anchor point for the anchor rectangle. The specified anchor
+	is used derive an anchor point that the child surface will be
+	positioned relative to. If a corner anchor is set (e.g. 'top_left' or
+	'bottom_right'), the anchor point will be at the specified corner;
+	otherwise, the derived anchor point will be centered on the specified
+	edge, or in the center of the anchor rectangle if no edge is specified.
+      </description>
+      <arg name="anchor" type="uint" enum="anchor"
+	   summary="anchor"/>
+    </request>
+
+    <enum name="gravity">
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="3"/>
+      <entry name="right" value="4"/>
+      <entry name="top_left" value="5"/>
+      <entry name="bottom_left" value="6"/>
+      <entry name="top_right" value="7"/>
+      <entry name="bottom_right" value="8"/>
+    </enum>
+
+    <request name="set_gravity">
+      <description summary="set child surface gravity">
+	Defines in what direction a surface should be positioned, relative to
+	the anchor point of the parent surface. If a corner gravity is
+	specified (e.g. 'bottom_right' or 'top_left'), then the child surface
+	will be placed towards the specified gravity; otherwise, the child
+	surface will be centered over the anchor point on any axis that had no
+	gravity specified. If the gravity is not in the ‘gravity’ enum, an
+	invalid_input error is raised.
+      </description>
+      <arg name="gravity" type="uint" enum="gravity"
+	   summary="gravity direction"/>
+    </request>
+
+    <enum name="constraint_adjustment" bitfield="true">
+      <description summary="constraint adjustments">
+	The constraint adjustment value define ways the compositor will adjust
+	the position of the surface, if the unadjusted position would result
+	in the surface being partly constrained.
+
+	Whether a surface is considered 'constrained' is left to the compositor
+	to determine. For example, the surface may be partly outside the
+	compositor's defined 'work area', thus necessitating the child surface's
+	position be adjusted until it is entirely inside the work area.
+
+	The adjustments can be combined, according to a defined precedence: 1)
+	Flip, 2) Slide, 3) Resize.
+      </description>
+      <entry name="none" value="0">
+	<description summary="don't move the child surface when constrained">
+	  Don't alter the surface position even if it is constrained on some
+	  axis, for example partially outside the edge of an output.
+	</description>
+      </entry>
+      <entry name="slide_x" value="1">
+	<description summary="move along the x axis until unconstrained">
+	  Slide the surface along the x axis until it is no longer constrained.
+
+	  First try to slide towards the direction of the gravity on the x axis
+	  until either the edge in the opposite direction of the gravity is
+	  unconstrained or the edge in the direction of the gravity is
+	  constrained.
+
+	  Then try to slide towards the opposite direction of the gravity on the
+	  x axis until either the edge in the direction of the gravity is
+	  unconstrained or the edge in the opposite direction of the gravity is
+	  constrained.
+	</description>
+      </entry>
+      <entry name="slide_y" value="2">
+	<description summary="move along the y axis until unconstrained">
+	  Slide the surface along the y axis until it is no longer constrained.
+
+	  First try to slide towards the direction of the gravity on the y axis
+	  until either the edge in the opposite direction of the gravity is
+	  unconstrained or the edge in the direction of the gravity is
+	  constrained.
+
+	  Then try to slide towards the opposite direction of the gravity on the
+	  y axis until either the edge in the direction of the gravity is
+	  unconstrained or the edge in the opposite direction of the gravity is
+	  constrained.
+	</description>
+      </entry>
+      <entry name="flip_x" value="4">
+	<description summary="invert the anchor and gravity on the x axis">
+	  Invert the anchor and gravity on the x axis if the surface is
+	  constrained on the x axis. For example, if the left edge of the
+	  surface is constrained, the gravity is 'left' and the anchor is
+	  'left', change the gravity to 'right' and the anchor to 'right'.
+
+	  If the adjusted position also ends up being constrained, the resulting
+	  position of the flip_x adjustment will be the one before the
+	  adjustment.
+	</description>
+      </entry>
+      <entry name="flip_y" value="8">
+	<description summary="invert the anchor and gravity on the y axis">
+	  Invert the anchor and gravity on the y axis if the surface is
+	  constrained on the y axis. For example, if the bottom edge of the
+	  surface is constrained, the gravity is 'bottom' and the anchor is
+	  'bottom', change the gravity to 'top' and the anchor to 'top'.
+
+	  The adjusted position is calculated given the original anchor
+	  rectangle and offset, but with the new flipped anchor and gravity
+	  values.
+
+	  If the adjusted position also ends up being constrained, the resulting
+	  position of the flip_y adjustment will be the one before the
+	  adjustment.
+	</description>
+      </entry>
+      <entry name="resize_x" value="16">
+	<description summary="horizontally resize the surface">
+	  Resize the surface horizontally so that it is completely
+	  unconstrained.
+	</description>
+      </entry>
+      <entry name="resize_y" value="32">
+	<description summary="vertically resize the surface">
+	  Resize the surface vertically so that it is completely unconstrained.
+	</description>
+      </entry>
+    </enum>
+
+    <request name="set_constraint_adjustment">
+      <description summary="set the adjustment to be done when constrained">
+	Specify how the window should be positioned if the originally intended
+	position caused the surface to be constrained, meaning at least
+	partially outside positioning boundaries set by the compositor. The
+	adjustment is set by constructing a bitmask describing the adjustment to
+	be made when the surface is constrained on that axis.
+
+	If no bit for one axis is set, the compositor will assume that the child
+	surface should not change its position on that axis when constrained.
+
+	If more than one bit for one axis is set, the order of how adjustments
+	are applied is specified in the corresponding adjustment descriptions.
+
+	The default adjustment is none.
+      </description>
+      <arg name="constraint_adjustment" type="uint" enum="constraint_adjustment"
+	   summary="bit mask of constraint adjustments"/>
+    </request>
+
+    <request name="set_offset">
+      <description summary="set surface position offset">
+	Specify the surface position offset relative to the position of the
+	anchor on the anchor rectangle and the anchor on the surface. For
+	example if the anchor of the anchor rectangle is at (x, y), the surface
+	has the gravity bottom|right, and the offset is (ox, oy), the calculated
+	surface position will be (x + ox, y + oy). The offset position of the
+	surface is the one used for constraint testing. See
+	set_constraint_adjustment.
+
+	An example use case is placing a popup menu on top of a user interface
+	element, while aligning the user interface element of the parent surface
+	with some user interface element placed somewhere in the popup surface.
+      </description>
+      <arg name="x" type="int" summary="surface position x offset"/>
+      <arg name="y" type="int" summary="surface position y offset"/>
+    </request>
+
+    <!-- Version 3 additions -->
+
+    <request name="set_reactive" since="3">
+      <description summary="continuously reconstrain the surface">
+	When set reactive, the surface is reconstrained if the conditions used
+	for constraining changed, e.g. the parent window moved.
+
+	If the conditions changed and the popup was reconstrained, an
+	xdg_popup.configure event is sent with updated geometry, followed by an
+	xdg_surface.configure event.
+      </description>
+    </request>
+
+    <request name="set_parent_size" since="3">
+      <description summary="">
+	Set the parent window geometry the compositor should use when
+	positioning the popup. The compositor may use this information to
+	determine the future state the popup should be constrained using. If
+	this doesn't match the dimension of the parent the popup is eventually
+	positioned against, the behavior is undefined.
+
+	The arguments are given in the surface-local coordinate space.
+      </description>
+      <arg name="parent_width" type="int"
+	   summary="future window geometry width of parent"/>
+      <arg name="parent_height" type="int"
+	   summary="future window geometry height of parent"/>
+    </request>
+
+    <request name="set_parent_configure" since="3">
+      <description summary="set parent configure this is a response to">
+	Set the serial of an xdg_surface.configure event this positioner will be
+	used in response to. The compositor may use this information together
+	with set_parent_size to determine what future state the popup should be
+	constrained using.
+      </description>
+      <arg name="serial" type="uint"
+	   summary="serial of parent configure event"/>
+    </request>
+  </interface>
+
+  <interface name="xdg_surface" version="6">
+    <description summary="desktop user interface surface base interface">
+      An interface that may be implemented by a wl_surface, for
+      implementations that provide a desktop-style user interface.
+
+      It provides a base set of functionality required to construct user
+      interface elements requiring management by the compositor, such as
+      toplevel windows, menus, etc. The types of functionality are split into
+      xdg_surface roles.
+
+      Creating an xdg_surface does not set the role for a wl_surface. In order
+      to map an xdg_surface, the client must create a role-specific object
+      using, e.g., get_toplevel, get_popup. The wl_surface for any given
+      xdg_surface can have at most one role, and may not be assigned any role
+      not based on xdg_surface.
+
+      A role must be assigned before any other requests are made to the
+      xdg_surface object.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xdg_surface state to take effect.
+
+      Creating an xdg_surface from a wl_surface which has a buffer attached or
+      committed is a client error, and any attempts by a client to attach or
+      manipulate a buffer prior to the first xdg_surface.configure call must
+      also be treated as errors.
+
+      After creating a role-specific object and setting it up (e.g. by sending
+      the title, app ID, size constraints, parent, etc), the client must
+      perform an initial commit without any buffer attached. The compositor
+      will reply with initial wl_surface state such as
+      wl_surface.preferred_buffer_scale followed by an xdg_surface.configure
+      event. The client must acknowledge it and is then allowed to attach a
+      buffer to map the surface.
+
+      Mapping an xdg_surface-based role surface is defined as making it
+      possible for the surface to be shown by the compositor. Note that
+      a mapped surface is not guaranteed to be visible once it is mapped.
+
+      For an xdg_surface to be mapped by the compositor, the following
+      conditions must be met:
+      (1) the client has assigned an xdg_surface-based role to the surface
+      (2) the client has set and committed the xdg_surface state and the
+	  role-dependent state to the surface
+      (3) the client has committed a buffer to the surface
+
+      A newly-unmapped surface is considered to have met condition (1) out
+      of the 3 required conditions for mapping a surface if its role surface
+      has not been destroyed, i.e. the client must perform the initial commit
+      again before attaching a buffer.
+    </description>
+
+    <enum name="error">
+      <entry name="not_constructed" value="1"
+	     summary="Surface was not fully constructed"/>
+      <entry name="already_constructed" value="2"
+	     summary="Surface was already constructed"/>
+      <entry name="unconfigured_buffer" value="3"
+	     summary="Attaching a buffer to an unconfigured surface"/>
+      <entry name="invalid_serial" value="4"
+	     summary="Invalid serial number when acking a configure event"/>
+      <entry name="invalid_size" value="5"
+	     summary="Width or height was zero or negative"/>
+      <entry name="defunct_role_object" value="6"
+	     summary="Surface was destroyed before its role object"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_surface">
+	Destroy the xdg_surface object. An xdg_surface must only be destroyed
+	after its role object has been destroyed, otherwise
+	a defunct_role_object error is raised.
+      </description>
+    </request>
+
+    <request name="get_toplevel">
+      <description summary="assign the xdg_toplevel surface role">
+	This creates an xdg_toplevel object for the given xdg_surface and gives
+	the associated wl_surface the xdg_toplevel role.
+
+	See the documentation of xdg_toplevel for more details about what an
+	xdg_toplevel is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="xdg_toplevel"/>
+    </request>
+
+    <request name="get_popup">
+      <description summary="assign the xdg_popup surface role">
+	This creates an xdg_popup object for the given xdg_surface and gives
+	the associated wl_surface the xdg_popup role.
+
+	If null is passed as a parent, a parent surface must be specified using
+	some other protocol, before committing the initial state.
+
+	See the documentation of xdg_popup for more details about what an
+	xdg_popup is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="xdg_popup"/>
+      <arg name="parent" type="object" interface="xdg_surface" allow-null="true"/>
+      <arg name="positioner" type="object" interface="xdg_positioner"/>
+    </request>
+
+    <request name="set_window_geometry">
+      <description summary="set the new window geometry">
+	The window geometry of a surface is its "visible bounds" from the
+	user's perspective. Client-side decorations often have invisible
+	portions like drop-shadows which should be ignored for the
+	purposes of aligning, placing and constraining windows.
+
+	The window geometry is double-buffered state, see wl_surface.commit.
+
+	When maintaining a position, the compositor should treat the (x, y)
+	coordinate of the window geometry as the top left corner of the window.
+	A client changing the (x, y) window geometry coordinate should in
+	general not alter the position of the window.
+
+	Once the window geometry of the surface is set, it is not possible to
+	unset it, and it will remain the same until set_window_geometry is
+	called again, even if a new subsurface or buffer is attached.
+
+	If never set, the value is the full bounds of the surface,
+	including any subsurfaces. This updates dynamically on every
+	commit. This unset is meant for extremely simple clients.
+
+	The arguments are given in the surface-local coordinate space of
+	the wl_surface associated with this xdg_surface, and may extend outside
+	of the wl_surface itself to mark parts of the subsurface tree as part of
+	the window geometry.
+
+	When applied, the effective window geometry will be the set window
+	geometry clamped to the bounding rectangle of the combined
+	geometry of the surface of the xdg_surface and the associated
+	subsurfaces.
+
+	The effective geometry will not be recalculated unless a new call to
+	set_window_geometry is done and the new pending surface state is
+	subsequently applied.
+
+	The width and height of the effective window geometry must be
+	greater than zero. Setting an invalid size will raise an
+	invalid_size error.
+      </description>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="ack_configure">
+      <description summary="ack a configure event">
+	When a configure event is received, if a client commits the
+	surface in response to the configure event, then the client
+	must make an ack_configure request sometime before the commit
+	request, passing along the serial of the configure event.
+
+	For instance, for toplevel surfaces the compositor might use this
+	information to move a surface to the top left only when the client has
+	drawn itself for the maximized or fullscreen state.
+
+	If the client receives multiple configure events before it
+	can respond to one, it only has to ack the last configure event.
+	Acking a configure event that was never sent raises an invalid_serial
+	error.
+
+	A client is not required to commit immediately after sending
+	an ack_configure request - it may even ack_configure several times
+	before its next surface commit.
+
+	A client may send multiple ack_configure requests before committing, but
+	only the last request sent before a commit indicates which configure
+	event the client really is responding to.
+
+	Sending an ack_configure request consumes the serial number sent with
+	the request, as well as serial numbers sent by all configure events
+	sent on this xdg_surface prior to the configure event referenced by
+	the committed serial.
+
+	It is an error to issue multiple ack_configure requests referencing a
+	serial from the same configure event, or to issue an ack_configure
+	request referencing a serial from a configure event issued before the
+	event identified by the last ack_configure request for the same
+	xdg_surface. Doing so will raise an invalid_serial error.
+      </description>
+      <arg name="serial" type="uint" summary="the serial from the configure event"/>
+    </request>
+
+    <event name="configure">
+      <description summary="suggest a surface change">
+	The configure event marks the end of a configure sequence. A configure
+	sequence is a set of one or more events configuring the state of the
+	xdg_surface, including the final xdg_surface.configure event.
+
+	Where applicable, xdg_surface surface roles will during a configure
+	sequence extend this event as a latched state sent as events before the
+	xdg_surface.configure event. Such events should be considered to make up
+	a set of atomically applied configuration states, where the
+	xdg_surface.configure commits the accumulated state.
+
+	Clients should arrange their surface for the new states, and then send
+	an ack_configure request with the serial sent in this configure event at
+	some point before committing the new surface.
+
+	If the client receives multiple configure events before it can respond
+	to one, it is free to discard all but the last event it received.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the configure event"/>
+    </event>
+
+  </interface>
+
+  <interface name="xdg_toplevel" version="6">
+    <description summary="toplevel surface">
+      This interface defines an xdg_surface role which allows a surface to,
+      among other things, set window-like properties such as maximize,
+      fullscreen, and minimize, set application-specific metadata like title and
+      id, and well as trigger user interactive operations such as interactive
+      resize and move.
+
+      A xdg_toplevel by default is responsible for providing the full intended
+      visual representation of the toplevel, which depending on the window
+      state, may mean things like a title bar, window controls and drop shadow.
+
+      Unmapping an xdg_toplevel means that the surface cannot be shown
+      by the compositor until it is explicitly mapped again.
+      All active operations (e.g., move, resize) are canceled and all
+      attributes (e.g. title, state, stacking, ...) are discarded for
+      an xdg_toplevel surface when it is unmapped. The xdg_toplevel returns to
+      the state it had right after xdg_surface.get_toplevel. The client
+      can re-map the toplevel by performing a commit without any buffer
+      attached, waiting for a configure event and handling it as usual (see
+      xdg_surface description).
+
+      Attaching a null buffer to a toplevel unmaps the surface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_toplevel">
+	This request destroys the role surface and unmaps the surface;
+	see "Unmapping" behavior in interface section for details.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="invalid_resize_edge" value="0" summary="provided value is
+        not a valid variant of the resize_edge enum"/>
+      <entry name="invalid_parent" value="1"
+        summary="invalid parent toplevel"/>
+      <entry name="invalid_size" value="2"
+	summary="client provided an invalid min or max size"/>
+    </enum>
+
+    <request name="set_parent">
+      <description summary="set the parent of this surface">
+	Set the "parent" of this surface. This surface should be stacked
+	above the parent surface and all other ancestor surfaces.
+
+	Parent surfaces should be set on dialogs, toolboxes, or other
+	"auxiliary" surfaces, so that the parent is raised when the dialog
+	is raised.
+
+	Setting a null parent for a child surface unsets its parent. Setting
+	a null parent for a surface which currently has no parent is a no-op.
+
+	Only mapped surfaces can have child surfaces. Setting a parent which
+	is not mapped is equivalent to setting a null parent. If a surface
+	becomes unmapped, its children's parent is set to the parent of
+	the now-unmapped surface. If the now-unmapped surface has no parent,
+	its children's parent is unset. If the now-unmapped surface becomes
+	mapped again, its parent-child relationship is not restored.
+
+	The parent toplevel must not be one of the child toplevel's
+	descendants, and the parent must be different from the child toplevel,
+	otherwise the invalid_parent protocol error is raised.
+      </description>
+      <arg name="parent" type="object" interface="xdg_toplevel" allow-null="true"/>
+    </request>
+
+    <request name="set_title">
+      <description summary="set surface title">
+	Set a short title for the surface.
+
+	This string may be used to identify the surface in a task bar,
+	window list, or other user interface elements provided by the
+	compositor.
+
+	The string must be encoded in UTF-8.
+      </description>
+      <arg name="title" type="string"/>
+    </request>
+
+    <request name="set_app_id">
+      <description summary="set application ID">
+	Set an application identifier for the surface.
+
+	The app ID identifies the general class of applications to which
+	the surface belongs. The compositor can use this to group multiple
+	surfaces together, or to determine how to launch a new application.
+
+	For D-Bus activatable applications, the app ID is used as the D-Bus
+	service name.
+
+	The compositor shell will try to group application surfaces together
+	by their app ID. As a best practice, it is suggested to select app
+	ID's that match the basename of the application's .desktop file.
+	For example, "org.freedesktop.FooViewer" where the .desktop file is
+	"org.freedesktop.FooViewer.desktop".
+
+	Like other properties, a set_app_id request can be sent after the
+	xdg_toplevel has been mapped to update the property.
+
+	See the desktop-entry specification [0] for more details on
+	application identifiers and how they relate to well-known D-Bus
+	names and .desktop files.
+
+	[0] https://standards.freedesktop.org/desktop-entry-spec/
+      </description>
+      <arg name="app_id" type="string"/>
+    </request>
+
+    <request name="show_window_menu">
+      <description summary="show the window menu">
+	Clients implementing client-side decorations might want to show
+	a context menu when right-clicking on the decorations, giving the
+	user a menu that they can use to maximize or minimize the window.
+
+	This request asks the compositor to pop up such a window menu at
+	the given position, relative to the local surface coordinates of
+	the parent surface. There are no guarantees as to what menu items
+	the window menu contains, or even if a window menu will be drawn
+	at all.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
+      <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
+    </request>
+
+    <request name="move">
+      <description summary="start an interactive move">
+	Start an interactive, user-driven move of the surface.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event. The passed
+	serial is used to determine the type of interactive move (touch,
+	pointer, etc).
+
+	The server may ignore move requests depending on the state of
+	the surface (e.g. fullscreen or maximized), or if the passed serial
+	is no longer valid.
+
+	If triggered, the surface will lose the focus of the device
+	(wl_pointer, wl_touch, etc) used for the move. It is up to the
+	compositor to visually indicate that the move is taking place, such as
+	updating a pointer cursor, during the move. There is no guarantee
+	that the device focus will return when the move is completed.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+    </request>
+
+    <enum name="resize_edge">
+      <description summary="edge values for resizing">
+	These values are used to indicate which edge of a surface
+	is being dragged in a resize operation.
+      </description>
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="4"/>
+      <entry name="top_left" value="5"/>
+      <entry name="bottom_left" value="6"/>
+      <entry name="right" value="8"/>
+      <entry name="top_right" value="9"/>
+      <entry name="bottom_right" value="10"/>
+    </enum>
+
+    <request name="resize">
+      <description summary="start an interactive resize">
+	Start a user-driven, interactive resize of the surface.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event. The passed
+	serial is used to determine the type of interactive resize (touch,
+	pointer, etc).
+
+	The server may ignore resize requests depending on the state of
+	the surface (e.g. fullscreen or maximized).
+
+	If triggered, the client will receive configure events with the
+	"resize" state enum value and the expected sizes. See the "resize"
+	enum value for more details about what is required. The client
+	must also acknowledge configure events using "ack_configure". After
+	the resize is completed, the client will receive another "configure"
+	event without the resize state.
+
+	If triggered, the surface also will lose the focus of the device
+	(wl_pointer, wl_touch, etc) used for the resize. It is up to the
+	compositor to visually indicate that the resize is taking place,
+	such as updating a pointer cursor, during the resize. There is no
+	guarantee that the device focus will return when the resize is
+	completed.
+
+	The edges parameter specifies how the surface should be resized, and
+	is one of the values of the resize_edge enum. Values not matching
+	a variant of the enum will cause the invalid_resize_edge protocol error.
+	The compositor may use this information to update the surface position
+	for example when dragging the top left corner. The compositor may also
+	use this information to adapt its behavior, e.g. choose an appropriate
+	cursor image.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="edges" type="uint" enum="resize_edge" summary="which edge or corner is being dragged"/>
+    </request>
+
+    <enum name="state">
+      <description summary="types of state on the surface">
+	The different state values used on the surface. This is designed for
+	state values like maximized, fullscreen. It is paired with the
+	configure event to ensure that both the client and the compositor
+	setting the state can be synchronized.
+
+	States set in this way are double-buffered, see wl_surface.commit.
+      </description>
+      <entry name="maximized" value="1" summary="the surface is maximized">
+	<description summary="the surface is maximized">
+	  The surface is maximized. The window geometry specified in the configure
+	  event must be obeyed by the client, or the xdg_wm_base.invalid_surface_state
+	  error is raised.
+
+	  The client should draw without shadow or other
+	  decoration outside of the window geometry.
+	</description>
+      </entry>
+      <entry name="fullscreen" value="2" summary="the surface is fullscreen">
+	<description summary="the surface is fullscreen">
+	  The surface is fullscreen. The window geometry specified in the
+	  configure event is a maximum; the client cannot resize beyond it. For
+	  a surface to cover the whole fullscreened area, the geometry
+	  dimensions must be obeyed by the client. For more details, see
+	  xdg_toplevel.set_fullscreen.
+	</description>
+      </entry>
+      <entry name="resizing" value="3" summary="the surface is being resized">
+	<description summary="the surface is being resized">
+	  The surface is being resized. The window geometry specified in the
+	  configure event is a maximum; the client cannot resize beyond it.
+	  Clients that have aspect ratio or cell sizing configuration can use
+	  a smaller size, however.
+	</description>
+      </entry>
+      <entry name="activated" value="4" summary="the surface is now activated">
+	<description summary="the surface is now activated">
+	  Client window decorations should be painted as if the window is
+	  active. Do not assume this means that the window actually has
+	  keyboard or pointer focus.
+	</description>
+      </entry>
+      <entry name="tiled_left" value="5" since="2">
+	<description summary="the surface’s left edge is tiled">
+	  The window is currently in a tiled layout and the left edge is
+	  considered to be adjacent to another part of the tiling grid.
+
+	  The client should draw without shadow or other decoration outside of
+	  the window geometry on the left edge.
+	</description>
+      </entry>
+      <entry name="tiled_right" value="6" since="2">
+	<description summary="the surface’s right edge is tiled">
+	  The window is currently in a tiled layout and the right edge is
+	  considered to be adjacent to another part of the tiling grid.
+
+	  The client should draw without shadow or other decoration outside of
+	  the window geometry on the right edge.
+	</description>
+      </entry>
+      <entry name="tiled_top" value="7" since="2">
+	<description summary="the surface’s top edge is tiled">
+	  The window is currently in a tiled layout and the top edge is
+	  considered to be adjacent to another part of the tiling grid.
+
+	  The client should draw without shadow or other decoration outside of
+	  the window geometry on the top edge.
+	</description>
+      </entry>
+      <entry name="tiled_bottom" value="8" since="2">
+	<description summary="the surface’s bottom edge is tiled">
+	  The window is currently in a tiled layout and the bottom edge is
+	  considered to be adjacent to another part of the tiling grid.
+
+	  The client should draw without shadow or other decoration outside of
+	  the window geometry on the bottom edge.
+	</description>
+      </entry>
+      <entry name="suspended" value="9" since="6">
+        <description summary="surface repaint is suspended">
+	  The surface is currently not ordinarily being repainted; for
+	  example because its content is occluded by another window, or its
+	  outputs are switched off due to screen locking.
+	</description>
+      </entry>
+    </enum>
+
+    <request name="set_max_size">
+      <description summary="set the maximum size">
+	Set a maximum size for the window.
+
+	The client can specify a maximum size so that the compositor does
+	not try to configure the window beyond this size.
+
+	The width and height arguments are in window geometry coordinates.
+	See xdg_surface.set_window_geometry.
+
+	Values set in this way are double-buffered, see wl_surface.commit.
+
+	The compositor can use this information to allow or disallow
+	different states like maximize or fullscreen and draw accurate
+	animations.
+
+	Similarly, a tiling window manager may use this information to
+	place and resize client windows in a more effective way.
+
+	The client should not rely on the compositor to obey the maximum
+	size. The compositor may decide to ignore the values set by the
+	client and request a larger size.
+
+	If never set, or a value of zero in the request, means that the
+	client has no expected maximum size in the given dimension.
+	As a result, a client wishing to reset the maximum size
+	to an unspecified state can use zero for width and height in the
+	request.
+
+	Requesting a maximum size to be smaller than the minimum size of
+	a surface is illegal and will result in an invalid_size error.
+
+	The width and height must be greater than or equal to zero. Using
+	strictly negative values for width or height will result in a
+	invalid_size error.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="set_min_size">
+      <description summary="set the minimum size">
+	Set a minimum size for the window.
+
+	The client can specify a minimum size so that the compositor does
+	not try to configure the window below this size.
+
+	The width and height arguments are in window geometry coordinates.
+	See xdg_surface.set_window_geometry.
+
+	Values set in this way are double-buffered, see wl_surface.commit.
+
+	The compositor can use this information to allow or disallow
+	different states like maximize or fullscreen and draw accurate
+	animations.
+
+	Similarly, a tiling window manager may use this information to
+	place and resize client windows in a more effective way.
+
+	The client should not rely on the compositor to obey the minimum
+	size. The compositor may decide to ignore the values set by the
+	client and request a smaller size.
+
+	If never set, or a value of zero in the request, means that the
+	client has no expected minimum size in the given dimension.
+	As a result, a client wishing to reset the minimum size
+	to an unspecified state can use zero for width and height in the
+	request.
+
+	Requesting a minimum size to be larger than the maximum size of
+	a surface is illegal and will result in an invalid_size error.
+
+	The width and height must be greater than or equal to zero. Using
+	strictly negative values for width and height will result in a
+	invalid_size error.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="set_maximized">
+      <description summary="maximize the window">
+	Maximize the surface.
+
+	After requesting that the surface should be maximized, the compositor
+	will respond by emitting a configure event. Whether this configure
+	actually sets the window maximized is subject to compositor policies.
+	The client must then update its content, drawing in the configured
+	state. The client must also acknowledge the configure when committing
+	the new content (see ack_configure).
+
+	It is up to the compositor to decide how and where to maximize the
+	surface, for example which output and what region of the screen should
+	be used.
+
+	If the surface was already maximized, the compositor will still emit
+	a configure event with the "maximized" state.
+
+	If the surface is in a fullscreen state, this request has no direct
+	effect. It may alter the state the surface is returned to when
+	unmaximized unless overridden by the compositor.
+      </description>
+    </request>
+
+    <request name="unset_maximized">
+      <description summary="unmaximize the window">
+	Unmaximize the surface.
+
+	After requesting that the surface should be unmaximized, the compositor
+	will respond by emitting a configure event. Whether this actually
+	un-maximizes the window is subject to compositor policies.
+	If available and applicable, the compositor will include the window
+	geometry dimensions the window had prior to being maximized in the
+	configure event. The client must then update its content, drawing it in
+	the configured state. The client must also acknowledge the configure
+	when committing the new content (see ack_configure).
+
+	It is up to the compositor to position the surface after it was
+	unmaximized; usually the position the surface had before maximizing, if
+	applicable.
+
+	If the surface was already not maximized, the compositor will still
+	emit a configure event without the "maximized" state.
+
+	If the surface is in a fullscreen state, this request has no direct
+	effect. It may alter the state the surface is returned to when
+	unmaximized unless overridden by the compositor.
+      </description>
+    </request>
+
+    <request name="set_fullscreen">
+      <description summary="set the window as fullscreen on an output">
+	Make the surface fullscreen.
+
+	After requesting that the surface should be fullscreened, the
+	compositor will respond by emitting a configure event. Whether the
+	client is actually put into a fullscreen state is subject to compositor
+	policies. The client must also acknowledge the configure when
+	committing the new content (see ack_configure).
+
+	The output passed by the request indicates the client's preference as
+	to which display it should be set fullscreen on. If this value is NULL,
+	it's up to the compositor to choose which display will be used to map
+	this surface.
+
+	If the surface doesn't cover the whole output, the compositor will
+	position the surface in the center of the output and compensate with
+	with border fill covering the rest of the output. The content of the
+	border fill is undefined, but should be assumed to be in some way that
+	attempts to blend into the surrounding area (e.g. solid black).
+
+	If the fullscreened surface is not opaque, the compositor must make
+	sure that other screen content not part of the same surface tree (made
+	up of subsurfaces, popups or similarly coupled surfaces) are not
+	visible below the fullscreened surface.
+      </description>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+
+    <request name="unset_fullscreen">
+      <description summary="unset the window as fullscreen">
+	Make the surface no longer fullscreen.
+
+	After requesting that the surface should be unfullscreened, the
+	compositor will respond by emitting a configure event.
+	Whether this actually removes the fullscreen state of the client is
+	subject to compositor policies.
+
+	Making a surface unfullscreen sets states for the surface based on the following:
+	* the state(s) it may have had before becoming fullscreen
+	* any state(s) decided by the compositor
+	* any state(s) requested by the client while the surface was fullscreen
+
+	The compositor may include the previous window geometry dimensions in
+	the configure event, if applicable.
+
+	The client must also acknowledge the configure when committing the new
+	content (see ack_configure).
+      </description>
+    </request>
+
+    <request name="set_minimized">
+      <description summary="set the window as minimized">
+	Request that the compositor minimize your surface. There is no
+	way to know if the surface is currently minimized, nor is there
+	any way to unset minimization on this surface.
+
+	If you are looking to throttle redrawing when minimized, please
+	instead use the wl_surface.frame event for this, as this will
+	also work with live previews on windows in Alt-Tab, Expose or
+	similar compositor features.
+      </description>
+    </request>
+
+    <event name="configure">
+      <description summary="suggest a surface change">
+	This configure event asks the client to resize its toplevel surface or
+	to change its state. The configured state should not be applied
+	immediately. See xdg_surface.configure for details.
+
+	The width and height arguments specify a hint to the window
+	about how its surface should be resized in window geometry
+	coordinates. See set_window_geometry.
+
+	If the width or height arguments are zero, it means the client
+	should decide its own window dimension. This may happen when the
+	compositor needs to configure the state of the surface but doesn't
+	have any information about any previous or expected dimension.
+
+	The states listed in the event specify how the width/height
+	arguments should be interpreted, and possibly how it should be
+	drawn.
+
+	Clients must send an ack_configure in response to this event. See
+	xdg_surface.configure and xdg_surface.ack_configure for details.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="states" type="array"/>
+    </event>
+
+    <event name="close">
+      <description summary="surface wants to be closed">
+	The close event is sent by the compositor when the user
+	wants the surface to be closed. This should be equivalent to
+	the user clicking the close button in client-side decorations,
+	if your application has any.
+
+	This is only a request that the user intends to close the
+	window. The client may choose to ignore this request, or show
+	a dialog to ask the user to save their data, etc.
+      </description>
+    </event>
+
+    <!-- Version 4 additions -->
+
+    <event name="configure_bounds" since="4">
+      <description summary="recommended window geometry bounds">
+	The configure_bounds event may be sent prior to a xdg_toplevel.configure
+	event to communicate the bounds a window geometry size is recommended
+	to constrain to.
+
+	The passed width and height are in surface coordinate space. If width
+	and height are 0, it means bounds is unknown and equivalent to as if no
+	configure_bounds event was ever sent for this surface.
+
+	The bounds can for example correspond to the size of a monitor excluding
+	any panels or other shell components, so that a surface isn't created in
+	a way that it cannot fit.
+
+	The bounds may change at any point, and in such a case, a new
+	xdg_toplevel.configure_bounds will be sent, followed by
+	xdg_toplevel.configure and xdg_surface.configure.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </event>
+
+    <!-- Version 5 additions -->
+
+    <enum name="wm_capabilities" since="5">
+      <entry name="window_menu" value="1" summary="show_window_menu is available"/>
+      <entry name="maximize" value="2" summary="set_maximized and unset_maximized are available"/>
+      <entry name="fullscreen" value="3" summary="set_fullscreen and unset_fullscreen are available"/>
+      <entry name="minimize" value="4" summary="set_minimized is available"/>
+    </enum>
+
+    <event name="wm_capabilities" since="5">
+      <description summary="compositor capabilities">
+	This event advertises the capabilities supported by the compositor. If
+	a capability isn't supported, clients should hide or disable the UI
+	elements that expose this functionality. For instance, if the
+	compositor doesn't advertise support for minimized toplevels, a button
+	triggering the set_minimized request should not be displayed.
+
+	The compositor will ignore requests it doesn't support. For instance,
+	a compositor which doesn't advertise support for minimized will ignore
+	set_minimized requests.
+
+	Compositors must send this event once before the first
+	xdg_surface.configure event. When the capabilities change, compositors
+	must send this event again and then send an xdg_surface.configure
+	event.
+
+	The configured state should not be applied immediately. See
+	xdg_surface.configure for details.
+
+	The capabilities are sent as an array of 32-bit unsigned integers in
+	native endianness.
+      </description>
+      <arg name="capabilities" type="array" summary="array of 32-bit capabilities"/>
+    </event>
+  </interface>
+
+  <interface name="xdg_popup" version="6">
+    <description summary="short-lived, popup surfaces for menus">
+      A popup surface is a short-lived, temporary surface. It can be used to
+      implement for example menus, popovers, tooltips and other similar user
+      interface concepts.
+
+      A popup can be made to take an explicit grab. See xdg_popup.grab for
+      details.
+
+      When the popup is dismissed, a popup_done event will be sent out, and at
+      the same time the surface will be unmapped. See the xdg_popup.popup_done
+      event for details.
+
+      Explicitly destroying the xdg_popup object will also dismiss the popup and
+      unmap the surface. Clients that want to dismiss the popup when another
+      surface of their own is clicked should dismiss the popup using the destroy
+      request.
+
+      A newly created xdg_popup will be stacked on top of all previously created
+      xdg_popup surfaces associated with the same xdg_toplevel.
+
+      The parent of an xdg_popup must be mapped (see the xdg_surface
+      description) before the xdg_popup itself.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xdg_popup state to take effect.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_grab" value="0"
+	     summary="tried to grab after being mapped"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove xdg_popup interface">
+	This destroys the popup. Explicitly destroying the xdg_popup
+	object will also dismiss the popup, and unmap the surface.
+
+	If this xdg_popup is not the "topmost" popup, the
+	xdg_wm_base.not_the_topmost_popup protocol error will be sent.
+      </description>
+    </request>
+
+    <request name="grab">
+      <description summary="make the popup take an explicit grab">
+	This request makes the created popup take an explicit grab. An explicit
+	grab will be dismissed when the user dismisses the popup, or when the
+	client destroys the xdg_popup. This can be done by the user clicking
+	outside the surface, using the keyboard, or even locking the screen
+	through closing the lid or a timeout.
+
+	If the compositor denies the grab, the popup will be immediately
+	dismissed.
+
+	This request must be used in response to some sort of user action like a
+	button press, key press, or touch down event. The serial number of the
+	event should be passed as 'serial'.
+
+	The parent of a grabbing popup must either be an xdg_toplevel surface or
+	another xdg_popup with an explicit grab. If the parent is another
+	xdg_popup it means that the popups are nested, with this popup now being
+	the topmost popup.
+
+	Nested popups must be destroyed in the reverse order they were created
+	in, e.g. the only popup you are allowed to destroy at all times is the
+	topmost one.
+
+	When compositors choose to dismiss a popup, they may dismiss every
+	nested grabbing popup as well. When a compositor dismisses popups, it
+	will follow the same dismissing order as required from the client.
+
+	If the topmost grabbing popup is destroyed, the grab will be returned to
+	the parent of the popup, if that parent previously had an explicit grab.
+
+	If the parent is a grabbing popup which has already been dismissed, this
+	popup will be immediately dismissed. If the parent is a popup that did
+	not take an explicit grab, an error will be raised.
+
+	During a popup grab, the client owning the grab will receive pointer
+	and touch events for all their surfaces as normal (similar to an
+	"owner-events" grab in X11 parlance), while the top most grabbing popup
+	will always have keyboard focus.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat"
+	   summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+    </request>
+
+    <event name="configure">
+      <description summary="configure the popup surface">
+	This event asks the popup surface to configure itself given the
+	configuration. The configured state should not be applied immediately.
+	See xdg_surface.configure for details.
+
+	The x and y arguments represent the position the popup was placed at
+	given the xdg_positioner rule, relative to the upper left corner of the
+	window geometry of the parent surface.
+
+	For version 2 or older, the configure event for an xdg_popup is only
+	ever sent once for the initial configuration. Starting with version 3,
+	it may be sent again if the popup is setup with an xdg_positioner with
+	set_reactive requested, or in response to xdg_popup.reposition requests.
+      </description>
+      <arg name="x" type="int"
+	   summary="x position relative to parent surface window geometry"/>
+      <arg name="y" type="int"
+	   summary="y position relative to parent surface window geometry"/>
+      <arg name="width" type="int" summary="window geometry width"/>
+      <arg name="height" type="int" summary="window geometry height"/>
+    </event>
+
+    <event name="popup_done">
+      <description summary="popup interaction is done">
+	The popup_done event is sent out when a popup is dismissed by the
+	compositor. The client should destroy the xdg_popup object at this
+	point.
+      </description>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="reposition" since="3">
+      <description summary="recalculate the popup's location">
+	Reposition an already-mapped popup. The popup will be placed given the
+	details in the passed xdg_positioner object, and a
+	xdg_popup.repositioned followed by xdg_popup.configure and
+	xdg_surface.configure will be emitted in response. Any parameters set
+	by the previous positioner will be discarded.
+
+	The passed token will be sent in the corresponding
+	xdg_popup.repositioned event. The new popup position will not take
+	effect until the corresponding configure event is acknowledged by the
+	client. See xdg_popup.repositioned for details. The token itself is
+	opaque, and has no other special meaning.
+
+	If multiple reposition requests are sent, the compositor may skip all
+	but the last one.
+
+	If the popup is repositioned in response to a configure event for its
+	parent, the client should send an xdg_positioner.set_parent_configure
+	and possibly an xdg_positioner.set_parent_size request to allow the
+	compositor to properly constrain the popup.
+
+	If the popup is repositioned together with a parent that is being
+	resized, but not in response to a configure event, the client should
+	send an xdg_positioner.set_parent_size request.
+      </description>
+      <arg name="positioner" type="object" interface="xdg_positioner"/>
+      <arg name="token" type="uint" summary="reposition request token"/>
+    </request>
+
+    <event name="repositioned" since="3">
+      <description summary="signal the completion of a repositioned request">
+	The repositioned event is sent as part of a popup configuration
+	sequence, together with xdg_popup.configure and lastly
+	xdg_surface.configure to notify the completion of a reposition request.
+
+	The repositioned event is to notify about the completion of a
+	xdg_popup.reposition request. The token argument is the token passed
+	in the xdg_popup.reposition request.
+
+	Immediately after this event is emitted, xdg_popup.configure and
+	xdg_surface.configure will be sent with the updated size and position,
+	as well as a new configure serial.
+
+	The client should optionally update the content of the popup, but must
+	acknowledge the new popup configuration for the new position to take
+	effect. See xdg_surface.ack_configure for details.
+      </description>
+      <arg name="token" type="uint" summary="reposition request token"/>
+    </event>
+
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/alpha-modifier/README b/subprojects/wayland-protocols/staging/alpha-modifier/README
new file mode 100644
index 0000000000000000000000000000000000000000..e918a024cea537b4ad860b8dd36b22bcac3fd86b
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/alpha-modifier/README
@@ -0,0 +1,4 @@
+Alpha modifier protocol
+
+Maintainers:
+Xaver Hugl <xaver.hugl@kde.org> (@Zamundaaa)
diff --git a/subprojects/wayland-protocols/staging/alpha-modifier/alpha-modifier-v1.xml b/subprojects/wayland-protocols/staging/alpha-modifier/alpha-modifier-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ab0a401d1ab04edf05f32fed42a2dba29c389ff9
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/alpha-modifier/alpha-modifier-v1.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="alpha_modifier_v1">
+  <copyright>
+    Copyright © 2024 Xaver Hugl
+
+    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.
+  </copyright>
+
+  <interface name="wp_alpha_modifier_v1" version="1">
+    <description summary="surface alpha modifier manager">
+      This interface allows a client to set a factor for the alpha values on a
+      surface, which can be used to offload such operations to the compositor,
+      which can in turn for example offload them to KMS.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the alpha modifier manager object">
+        Destroy the alpha modifier manager. This doesn't destroy objects
+        created with the manager.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="already_constructed" value="0"
+             summary="wl_surface already has a alpha modifier object"/>
+    </enum>
+
+    <request name="get_surface">
+      <description summary="create a new alpha modifier surface object">
+        Create a new alpha modifier surface object associated with the
+        given wl_surface. If there is already such an object associated with
+        the wl_surface, the already_constructed error will be raised.
+      </description>
+      <arg name="id" type="new_id" interface="wp_alpha_modifier_surface_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_alpha_modifier_surface_v1" version="1">
+    <description summary="alpha modifier object for a surface">
+      This interface allows the client to set a factor for the alpha values on
+      a surface, which can be used to offload such operations to the compositor.
+      The default factor is UINT32_MAX.
+
+      This object has to be destroyed before the associated wl_surface. Once the
+      wl_surface is destroyed, all request on this object will raise the
+      no_surface error.
+    </description>
+
+    <enum name="error">
+      <entry name="no_surface" value="0" summary="wl_surface was destroyed"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the alpha modifier object">
+        This destroys the object, and is equivalent to set_multiplier with
+        a value of UINT32_MAX, with the same double-buffered semantics as
+        set_multiplier.
+      </description>
+    </request>
+
+    <request name="set_multiplier">
+      <description summary="specify the alpha multiplier">
+        Sets the alpha multiplier for the surface. The alpha multiplier is
+        double-buffered state, see wl_surface.commit for details.
+
+        This factor is applied in the compositor's blending space, as an
+        additional step after the processing of per-pixel alpha values for the
+        wl_surface. The exact meaning of the factor is thus undefined, unless
+        the blending space is specified in a different extension.
+
+        This multiplier is applied even if the buffer attached to the
+        wl_surface doesn't have an alpha channel; in that case an alpha value
+        of one is used instead.
+
+        Zero means completely transparent, UINT32_MAX means completely opaque.
+      </description>
+      <arg name="factor" type="uint"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/color-management/README b/subprojects/wayland-protocols/staging/color-management/README
new file mode 100644
index 0000000000000000000000000000000000000000..e14f2a8cb0d4efa5ea23aceb509b5cb694066a7e
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/color-management/README
@@ -0,0 +1,11 @@
+Color management and HDR protocol
+
+Maintainers:
+Sebastian Wick <sebastian at sebastianwick.net>
+Pekka Paalanen <pekka.paalanen@collabora.com>
+
+
+Historical credits not mentioned in the first commit:
+
+- Niels Ole Salscheider, for an early protocol version
+  https://lists.freedesktop.org/archives/wayland-devel/2014-October/017755.html
diff --git a/gdk/wayland/protocol/xx-color-management-v4.xml b/subprojects/wayland-protocols/staging/color-management/color-management-v1.xml
similarity index 70%
rename from gdk/wayland/protocol/xx-color-management-v4.xml
rename to subprojects/wayland-protocols/staging/color-management/color-management-v1.xml
index 17f217cee606267a5c524067f9c4ab2974683449..7f8da78f1238d23fcce195d63e650209d8e78799 100644
--- a/gdk/wayland/protocol/xx-color-management-v4.xml
+++ b/subprojects/wayland-protocols/staging/color-management/color-management-v1.xml
@@ -6,6 +6,7 @@
     Copyright 2020 AMD
     Copyright 2020-2024 Collabora, Ltd.
     Copyright 2024 Xaver Hugl
+    Copyright 2022-2025 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"),
@@ -63,20 +64,27 @@
     color encoding terminology where possible. The glossary in the color-and-hdr
     repository shall be the authority on the definition of terms in this
     protocol.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
   </description>
 
-  <interface name="xx_color_manager_v4" version="1">
+  <interface name="wp_color_manager_v1" version="1">
     <description summary="color manager singleton">
-      A global interface used for getting color management extensions for
-      wl_surface and wl_output objects, and for creating client defined image
-      description objects. The extension interfaces allow
+      A singleton global interface used for getting color management extensions
+      for wl_surface and wl_output objects, and for creating client defined
+      image description objects. The extension interfaces allow
       getting the image description of outputs and setting the image
       description of surfaces.
+
+      Compositors should never remove this global.
     </description>
 
     <request name="destroy" type="destructor">
       <description summary="destroy the color manager">
-        Destroy the xx_color_manager_v4 object. This does not affect any other
+        Destroy the wp_color_manager_v1 object. This does not affect any other
         objects in any way.
       </description>
     </request>
@@ -116,9 +124,9 @@
       <description summary="compositor supported features"/>
 
       <entry name="icc_v2_v4" value="0"
-             summary="new_icc_creator request"/>
+             summary="create_icc_creator request"/>
       <entry name="parametric" value="1"
-             summary="new_parametric_creator request"/>
+             summary="create_parametric_creator request"/>
       <entry name="set_primaries" value="2"
              summary="parametric set_primaries request"/>
       <entry name="set_tf_power" value="3"
@@ -140,6 +148,8 @@
           is supported as well.
         </description>
       </entry>
+      <entry name="windows_scrgb" value="7"
+             summary="get_windows_scrgb request"/>
     </enum>
 
     <enum name="primaries">
@@ -148,10 +158,12 @@
         is the authority, when it comes to the exact values of primaries and
         authoritative specifications, where an equivalent code point exists.
 
+        A value of 0 is invalid and will never be present in the list of enums.
+
         Descriptions do list the specifications for convenience.
       </description>
 
-      <entry name="srgb" value="0">
+      <entry name="srgb" value="1">
         <description summary="Color primaries for the sRGB color space as defined by the BT.709 standard">
           Color primaries as defined by
           - Rec. ITU-R BT.709-6
@@ -164,7 +176,7 @@
           Equivalent to H.273 ColourPrimaries code point 1.
         </description>
       </entry>
-      <entry name="pal_m" value="1">
+      <entry name="pal_m" value="2">
         <description summary="Color primaries for PAL-M as defined by the BT.470 standard">
           Color primaries as defined by
           - Rec. ITU-R BT.470-6 System M (historical)
@@ -175,7 +187,7 @@
           Equivalent to H.273 ColourPrimaries code point 4.
         </description>
       </entry>
-      <entry name="pal" value="2">
+      <entry name="pal" value="3">
         <description summary="Color primaries for PAL as defined by the BT.601 standard">
           Color primaries as defined by
           - Rec. ITU-R BT.470-6 System B, G (historical)
@@ -185,7 +197,7 @@
           Equivalent to H.273 ColourPrimaries code point 5.
         </description>
       </entry>
-      <entry name="ntsc" value="3">
+      <entry name="ntsc" value="4">
         <description summary="Color primaries for NTSC as defined by the BT.601 standard">
           Color primaries as defined by
           - Rec. ITU-R BT.601-7 525
@@ -196,13 +208,13 @@
           Equivalent to H.273 ColourPrimaries code point 6 and 7.
         </description>
       </entry>
-      <entry name="generic_film" value="4">
+      <entry name="generic_film" value="5">
         <description summary="Generic film with colour filters using Illuminant C">
           Color primaries as defined by H.273 for generic film.
           Equivalent to H.273 ColourPrimaries code point 8.
         </description>
       </entry>
-      <entry name="bt2020" value="5">
+      <entry name="bt2020" value="6">
         <description summary="Color primaries as defined by the BT.2020 and BT.2100 standard">
           Color primaries as defined by
           - Rec. ITU-R BT.2020-2
@@ -210,7 +222,7 @@
           Equivalent to H.273 ColourPrimaries code point 9.
         </description>
       </entry>
-      <entry name="cie1931_xyz" value="6">
+      <entry name="cie1931_xyz" value="7">
         <description summary="Color primaries of the full CIE 1931 XYZ color space">
           Color primaries as defined as the maximum of the CIE 1931 XYZ color
           space by
@@ -219,21 +231,21 @@
           Equivalent to H.273 ColourPrimaries code point 10.
         </description>
       </entry>
-      <entry name="dci_p3" value="7">
+      <entry name="dci_p3" value="8">
         <description summary="Color primaries of the DCI P3 color space as defined by the SMPTE RP 431 standard">
           Color primaries as defined by Digital Cinema System and published in
           SMPTE RP 431-2 (2011). Equivalent to H.273 ColourPrimaries code point
           11.
         </description>
       </entry>
-      <entry name="display_p3" value="8">
+      <entry name="display_p3" value="9">
         <description summary="Color primaries of Display P3 variant of the DCI-P3 color space as defined by the SMPTE EG 432 standard">
           Color primaries as defined by Digital Cinema System and published in
           SMPTE EG 432-1 (2010).
           Equivalent to H.273 ColourPrimaries code point 12.
         </description>
       </entry>
-      <entry name="adobe_rgb" value="9">
+      <entry name="adobe_rgb" value="10">
         <description summary="Color primaries of the Adobe RGB color space as defined by the ISO 12640 standard">
           Color primaries as defined by Adobe as "Adobe RGB" and later published
           by ISO 12640-4 (2011).
@@ -243,23 +255,32 @@
 
     <enum name="transfer_function">
       <description summary="named transfer functions">
-        Named transfer functions used to encode well-known transfer
+        Named transfer functions used to represent well-known transfer
         characteristics. H.273 is the authority, when it comes to the exact
         formulas and authoritative specifications, where an equivalent code
         point exists.
 
+        A value of 0 is invalid and will never be present in the list of enums.
+
         Descriptions do list the specifications for convenience.
       </description>
 
-      <entry name="bt709" value="0">
-        <description summary="BT.709 transfer function">
-          Transfer characteristics as defined by
+      <entry name="bt1886" value="1">
+        <description summary="BT.1886 display transfer characteristic">
+          Rec. ITU-R BT.1886 is the display transfer characteristic assumed by
+          - Rec. ITU-R BT.601-7 525 and 625
           - Rec. ITU-R BT.709-6
-          - Rec. ITU-R BT.1361-0 conventional colour gamut system (historical)
-          Equivalent to H.273 TransferCharacteristics code point 1, 6, 14, 15.
+          - Rec. ITU-R BT.2020-2
+          These recommendations are referred to by H.273 TransferCharacteristics
+          code points 1, 6, 14, and 15, which are all equivalent.
+
+          This TF implies these default luminances from Rec. ITU-R BT.2035:
+          - primary color volume minimum: 0.01 cd/m²
+          - primary color volume maximum: 100 cd/m²
+          - reference white: 100 cd/m²
         </description>
       </entry>
-      <entry name="gamma22" value="1">
+      <entry name="gamma22" value="2">
         <description summary="Assumed display gamma 2.2 transfer function">
           Transfer characteristics as defined by
           - Rec. ITU-R BT.470-6 System M (historical)
@@ -271,52 +292,48 @@
           Equivalent to H.273 TransferCharacteristics code point 4.
         </description>
       </entry>
-      <entry name="gamma28" value="2">
+      <entry name="gamma28" value="3">
         <description summary="Assumed display gamma 2.8 transfer function">
           Transfer characteristics as defined by
           - Rec. ITU-R BT.470-6 System B, G (historical)
           Equivalent to H.273 TransferCharacteristics code point 5.
         </description>
       </entry>
-      <entry name="st240" value="3">
+      <entry name="st240" value="4">
         <description summary="SMPTE ST 240 transfer function">
           Transfer characteristics as defined by
           - SMPTE ST 240 (1999)
           Equivalent to H.273 TransferCharacteristics code point 7.
         </description>
       </entry>
-      <entry name="linear" value="4">
-        <description summary="linear transfer function">
-          Linear transfer characteristics.
-          Equivalent to H.273 TransferCharacteristics code point 8.
+      <entry name="ext_linear" value="5">
+        <description summary="extended linear transfer function">
+          Linear transfer function defined over all real numbers.
+          Normalised electrical values are equal the normalised optical values.
+
+          The differences to H.273 TransferCharacteristics code point 8 are
+          the definition over all real numbers.
         </description>
       </entry>
-      <entry name="log_100" value="5">
+      <entry name="log_100" value="6">
         <description summary="logarithmic 100:1 transfer function">
           Logarithmic transfer characteristic (100:1 range).
           Equivalent to H.273 TransferCharacteristics code point 9.
         </description>
       </entry>
-      <entry name="log_316" value="6">
+      <entry name="log_316" value="7">
         <description summary="logarithmic (100*Sqrt(10) : 1) transfer function">
           Logarithmic transfer characteristic (100 * Sqrt(10) : 1 range).
           Equivalent to H.273 TransferCharacteristics code point 10.
         </description>
       </entry>
-      <entry name="xvycc" value="7">
+      <entry name="xvycc" value="8">
         <description summary="IEC 61966-2-4 transfer function">
           Transfer characteristics as defined by
           - IEC 61966-2-4
           Equivalent to H.273 TransferCharacteristics code point 11.
         </description>
       </entry>
-      <entry name="bt1361" value="8">
-        <description summary="BT.1361 extended transfer function">
-          Transfer characteristics as defined by
-          - Rec. ITU-R BT.1361-0 extended colour gamut system (historical)
-          Equivalent to H.273 TransferCharacteristics code point 12.
-        </description>
-      </entry>
       <entry name="srgb" value="9">
         <description summary="sRGB piece-wise transfer function">
           Transfer characteristics as defined by
@@ -344,6 +361,12 @@
           - primary color volume minimum: 0.005 cd/m²
           - primary color volume maximum: 10000 cd/m²
           - reference white: 203 cd/m²
+
+          The difference between the primary color volume minimum and maximum
+          must be approximately 10000 cd/m² as that is the swing of the EOTF
+          defined by ST 2084 and BT.2100. The default value for the
+          reference white is a protocol addition: it is suggested by
+          Report ITU-R BT.2408-7 and is not part of ST 2084 or BT.2100.
         </description>
       </entry>
       <entry name="st428" value="12">
@@ -364,87 +387,146 @@
           - primary color volume minimum: 0.005 cd/m²
           - primary color volume maximum: 1000 cd/m²
           - reference white: 203 cd/m²
-          Note: HLG is a scene referred signal. All absolute luminance values
-          used here for HLG assume a 1000 cd/m² display.
+
+          HLG is a relative display-referred signal with a specified
+          non-linear mapping to the display peak luminance (the HLG OOTF).
+          All absolute luminance values used here for HLG assume a 1000 cd/m²
+          peak display.
+
+          The default value for the reference white is a protocol addition:
+          it is suggested by Report ITU-R BT.2408-7 and is not part of
+          ARIB STD-B67 or BT.2100.
         </description>
       </entry>
     </enum>
 
     <request name="get_output">
       <description summary="create a color management interface for a wl_output">
-        This creates a new xx_color_management_output_v4 object for the
+        This creates a new wp_color_management_output_v1 object for the
         given wl_output.
 
-        See the xx_color_management_output_v4 interface for more details.
+        See the wp_color_management_output_v1 interface for more details.
       </description>
 
-      <arg name="id" type="new_id" interface="xx_color_management_output_v4"/>
+      <arg name="id" type="new_id" interface="wp_color_management_output_v1"/>
       <arg name="output" type="object" interface="wl_output"/>
     </request>
 
     <request name="get_surface">
       <description summary="create a color management interface for a wl_surface">
-        If a xx_color_management_surface_v4 object already exists for the given
+        If a wp_color_management_surface_v1 object already exists for the given
         wl_surface, the protocol error surface_exists is raised.
 
-        This creates a new color xx_color_management_surface_v4 object for the
+        This creates a new color wp_color_management_surface_v1 object for the
         given wl_surface.
 
-        See the xx_color_management_surface_v4 interface for more details.
+        See the wp_color_management_surface_v1 interface for more details.
       </description>
 
-      <arg name="id" type="new_id" interface="xx_color_management_surface_v4"/>
+      <arg name="id" type="new_id" interface="wp_color_management_surface_v1"/>
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>
 
-    <request name="get_feedback_surface">
+    <request name="get_surface_feedback">
       <description summary="create a color management feedback interface">
-        This creates a new color xx_color_management_feedback_surface_v4 object
+        This creates a new color wp_color_management_surface_feedback_v1 object
         for the given wl_surface.
 
-        See the xx_color_management_feedback_surface_v4 interface for more
+        See the wp_color_management_surface_feedback_v1 interface for more
         details.
       </description>
 
       <arg name="id" type="new_id"
-           interface="xx_color_management_feedback_surface_v4"/>
+           interface="wp_color_management_surface_feedback_v1"/>
       <arg name="surface" type="object" interface="wl_surface"/>
     </request>
 
-    <request name="new_icc_creator">
+    <request name="create_icc_creator">
       <description summary="make a new ICC-based image description creator object">
         Makes a new ICC-based image description creator object with all
         properties initially unset. The client can then use the object's
         interface to define all the required properties for an image description
-        and finally create a xx_image_description_v4 object.
+        and finally create a wp_image_description_v1 object.
 
         This request can be used when the compositor advertises
-        xx_color_manager_v4.feature.icc_v2_v4.
+        wp_color_manager_v1.feature.icc_v2_v4.
         Otherwise this request raises the protocol error unsupported_feature.
       </description>
 
       <arg name="obj"
-           type="new_id" interface="xx_image_description_creator_icc_v4"
+           type="new_id" interface="wp_image_description_creator_icc_v1"
            summary="the new creator object"/>
     </request>
 
-    <request name="new_parametric_creator">
+    <request name="create_parametric_creator">
       <description summary="make a new parametric image description creator object">
         Makes a new parametric image description creator object with all
         properties initially unset. The client can then use the object's
         interface to define all the required properties for an image description
-        and finally create a xx_image_description_v4 object.
+        and finally create a wp_image_description_v1 object.
 
         This request can be used when the compositor advertises
-        xx_color_manager_v4.feature.parametric.
+        wp_color_manager_v1.feature.parametric.
         Otherwise this request raises the protocol error unsupported_feature.
       </description>
 
       <arg name="obj"
-           type="new_id" interface="xx_image_description_creator_params_v4"
+           type="new_id" interface="wp_image_description_creator_params_v1"
            summary="the new creator object"/>
     </request>
 
+    <request name="create_windows_scrgb">
+      <description summary="create Windows-scRGB image description object">
+        This creates a pre-defined image description for the so-called
+        Windows-scRGB stimulus encoding. This comes from the Windows 10 handling
+        of its own definition of an scRGB color space for an HDR screen
+        driven in BT.2100/PQ signalling mode.
+
+        Windows-scRGB uses sRGB (BT.709) color primaries and white point.
+        The transfer characteristic is extended linear.
+
+        The nominal color channel value range is extended, meaning it includes
+        negative and greater than 1.0 values. Negative values are used to
+        escape the sRGB color gamut boundaries. To make use of the extended
+        range, the client needs to use a pixel format that can represent those
+        values, e.g. floating-point 16 bits per channel.
+
+        Nominal color value R=G=B=0.0 corresponds to BT.2100/PQ system
+        0 cd/m², and R=G=B=1.0 corresponds to BT.2100/PQ system 80 cd/m².
+        The maximum is R=G=B=125.0 corresponding to 10k cd/m².
+
+        Windows-scRGB is displayed by Windows 10 by converting it to
+        BT.2100/PQ, maintaining the CIE 1931 chromaticity and mapping the
+        luminance as above. No adjustment is made to the signal to account
+        for the viewing conditions.
+
+        The reference white level of Windows-scRGB is unknown. If a
+        reference white level must be assumed for compositor processing, it
+        should be R=G=B=2.5375 corresponding to 203 cd/m² of Report ITU-R
+        BT.2408-7.
+
+        The target color volume of Windows-scRGB is unknown. The color gamut
+        may be anything between sRGB and BT.2100.
+
+        Note: EGL_EXT_gl_colorspace_scrgb_linear definition differs from
+        Windows-scRGB by using R=G=B=1.0 as the reference white level, while
+        Windows-scRGB reference white level is unknown or varies. However,
+        it seems probable that Windows implements both
+        EGL_EXT_gl_colorspace_scrgb_linear and Vulkan
+        VK_COLOR_SPACE_EXTENDED_SRGB_LINEAR_EXT as Windows-scRGB.
+
+        This request can be used when the compositor advertises
+        wp_color_manager_v1.feature.windows_scrgb.
+        Otherwise this request raises the protocol error unsupported_feature.
+
+        The resulting image description object does not allow get_information
+        request. The wp_image_description_v1.ready event shall be sent.
+      </description>
+
+      <arg name="image_description"
+           type="new_id" interface="wp_image_description_v1"/>
+    </request>
+
     <event name="supported_intent">
       <description summary="supported rendering intent">
         When this object is created, it shall immediately send this event once
@@ -486,22 +568,29 @@
       <arg name="primaries" type="uint" enum="primaries"
            summary="Named color primaries"/>
     </event>
+
+    <event name="done">
+      <description summary="all features have been sent">
+        This event is sent when all supported rendering intents, features,
+        transfer functions and named primaries have been sent.
+      </description>
+    </event>
   </interface>
 
-  <interface name="xx_color_management_output_v4" version="1">
+  <interface name="wp_color_management_output_v1" version="1">
     <description summary="output color properties">
-      A xx_color_management_output_v4 describes the color properties of an
+      A wp_color_management_output_v1 describes the color properties of an
       output.
 
-      The xx_color_management_output_v4 is associated with the wl_output global
+      The wp_color_management_output_v1 is associated with the wl_output global
       underlying the wl_output object. Therefore the client destroying the
       wl_output object has no impact, but the compositor removing the output
-      global makes the xx_color_management_output_v4 object inert.
+      global makes the wp_color_management_output_v1 object inert.
     </description>
 
     <request name="destroy" type="destructor">
       <description summary="destroy the color management output">
-        Destroy the color xx_color_management_output_v4 object. This does not
+        Destroy the color wp_color_management_output_v1 object. This does not
         affect any remaining protocol objects.
       </description>
     </request>
@@ -520,12 +609,12 @@
 
     <request name="get_image_description">
       <description summary="get the image description of the output">
-        This creates a new xx_image_description_v4 object for the current image
+        This creates a new wp_image_description_v1 object for the current image
         description of the output. There always is exactly one image description
         active for an output so the client should destroy the image description
         created by earlier invocations of this request. This request is usually
         sent as a reaction to the image_description_changed event or when
-        creating a xx_color_management_output_v4 object.
+        creating a wp_color_management_output_v1 object.
 
         The image description of an output represents the color encoding the
         output expects. There might be performance and power advantages, as well
@@ -535,41 +624,41 @@
         of, then the color reproduction on those outputs might be considerably
         worse.
 
-        The created xx_image_description_v4 object preserves the image
+        The created wp_image_description_v1 object preserves the image
         description of the output from the time the object was created.
 
         The resulting image description object allows get_information request.
 
         If this protocol object is inert, the resulting image description object
-        shall immediately deliver the xx_image_description_v4.failed event with
+        shall immediately deliver the wp_image_description_v1.failed event with
         the no_output cause.
 
         If the interface version is inadequate for the output's image
         description, meaning that the client does not support all the events
         needed to deliver the crucial information, the resulting image
         description object shall immediately deliver the
-        xx_image_description_v4.failed event with the low_version cause.
+        wp_image_description_v1.failed event with the low_version cause.
 
         Otherwise the object shall immediately deliver the ready event.
       </description>
 
       <arg name="image_description"
-           type="new_id" interface="xx_image_description_v4"/>
+           type="new_id" interface="wp_image_description_v1"/>
     </request>
   </interface>
 
-  <interface name="xx_color_management_surface_v4" version="1">
+  <interface name="wp_color_management_surface_v1" version="1">
     <description summary="color management extension to a surface">
-        A xx_color_management_surface_v4 allows the client to set the color
+        A wp_color_management_surface_v1 allows the client to set the color
         space and HDR properties of a surface.
 
-        If the wl_surface associated with the xx_color_management_surface_v4 is
-        destroyed, the xx_color_management_surface_v4 object becomes inert.
+        If the wl_surface associated with the wp_color_management_surface_v1 is
+        destroyed, the wp_color_management_surface_v1 object becomes inert.
     </description>
 
     <request name="destroy" type="destructor">
       <description summary="destroy the color management interface for a surface">
-        Destroy the xx_color_management_surface_v4 object and do the same as
+        Destroy the wp_color_management_surface_v1 object and do the same as
         unset_image_description.
       </description>
     </request>
@@ -580,10 +669,14 @@
              summary="unsupported rendering intent"/>
       <entry name="image_description" value="1"
              summary="invalid image description"/>
+      <entry name="inert" value="2"
+             summary="forbidden request on inert object"/>
     </enum>
 
     <request name="set_image_description">
       <description summary="set the surface image description">
+        If this protocol object is inert, the protocol error inert is raised.
+
         Set the image description of the underlying surface. The image
         description and rendering intent are double-buffered state, see
         wl_surface.commit.
@@ -593,36 +686,47 @@
         description. Compositors might convert images to match their own or any
         other image descriptions.
 
-        Image description whose creation gracefully failed (received
-        xx_image_description_v4.failed) are forbidden in this request, and in
-        such case the protocol error image_description is raised.
+        Image descriptions which are not ready (see wp_image_description_v1)
+        are forbidden in this request, and in such case the protocol error
+        image_description is raised.
 
-        All image descriptions whose creation succeeded (received
-        xx_image_description_v4.ready) are allowed and must always be accepted
-        by the compositor.
+        All image descriptions which are ready (see wp_image_description_v1)
+        are allowed and must always be accepted by the compositor.
 
         A rendering intent provides the client's preference on how content
         colors should be mapped to each output. The render_intent value must
         be one advertised by the compositor with
-        xx_color_manager_v4.render_intent event, otherwise the protocol error
+        wp_color_manager_v1.render_intent event, otherwise the protocol error
         render_intent is raised.
 
+        When an image description is set on a surface, the Transfer
+        Characteristics of the image description defines the valid range of
+        the nominal (real-valued) color channel values. The processing of
+        out-of-range color channel values is undefined, but compositors are
+        recommended to clamp the values to the valid range when possible.
+
         By default, a surface does not have an associated image description
         nor a rendering intent. The handling of color on such surfaces is
         compositor implementation defined. Compositors should handle such
-        surfaces as sRGB but may handle them differently if they have specific
+        surfaces as sRGB, but may handle them differently if they have specific
         requirements.
+
+        Setting the image description has copy semantics; after this request,
+        the image description can be immediately destroyed without affecting
+        the pending state of the surface.
       </description>
 
       <arg name="image_description"
-           type="object" interface="xx_image_description_v4"/>
+           type="object" interface="wp_image_description_v1"/>
       <arg name="render_intent"
-           type="uint" enum="xx_color_manager_v4.render_intent"
+           type="uint" enum="wp_color_manager_v1.render_intent"
            summary="rendering intent"/>
     </request>
 
     <request name="unset_image_description">
       <description summary="remove the surface image description">
+        If this protocol object is inert, the protocol error inert is raised.
+
         This request removes any image description from the surface. See
         set_image_description for how a compositor handles a surface without
         an image description. This is double-buffered state, see
@@ -631,18 +735,18 @@
     </request>
   </interface>
 
-  <interface name="xx_color_management_feedback_surface_v4" version="1">
+  <interface name="wp_color_management_surface_feedback_v1" version="1">
     <description summary="color management extension to a surface">
-        A xx_color_management_feedback_surface_v4 allows the client to get the
-        preferred color description of a surface.
+        A wp_color_management_surface_feedback_v1 allows the client to get the
+        preferred image description of a surface.
 
         If the wl_surface associated with this object is destroyed, the
-        xx_color_management_feedback_surface_v4 object becomes inert.
+        wp_color_management_surface_feedback_v1 object becomes inert.
     </description>
 
     <request name="destroy" type="destructor">
       <description summary="destroy the color management interface for a surface">
-        Destroy the xx_color_management_feedback_surface_v4 object.
+        Destroy the wp_color_management_surface_feedback_v1 object.
       </description>
     </request>
 
@@ -650,6 +754,8 @@
       <description summary="protocol errors"/>
       <entry name="inert" value="0"
              summary="forbidden request on inert object"/>
+      <entry name="unsupported_feature" value="1"
+             summary="attempted to use an unsupported feature"/>
     </enum>
 
     <event name="preferred_changed">
@@ -659,17 +765,20 @@
         client for its wl_surface contents. This event is sent whenever the
         compositor changes the wl_surface's preferred image description.
 
-        This event is merely a notification. When the client wants to know
-        what the preferred image description is, it shall use the get_preferred
-        request.
+        This event sends the identity of the new preferred state as the argument,
+        so clients who are aware of the image description already can reuse it.
+        Otherwise, if the client client wants to know what the preferred image
+        description is, it shall use the get_preferred request.
 
         The preferred image description is not automatically used for anything.
         It is only a hint, and clients may set any valid image description with
-        set_image_description but there might be performance and color accuracy
+        set_image_description, but there might be performance and color accuracy
         improvements by providing the wl_surface contents in the preferred
         image description. Therefore clients that can, should render according
         to the preferred image description
       </description>
+
+      <arg name="identity" type="uint" summary="image description id number"/>
     </event>
 
     <request name="get_preferred">
@@ -682,36 +791,56 @@
         reproduction, if the image description of a content update matches the
         preferred image description.
 
-        This creates a new xx_image_description_v4 object for the currently
+        This creates a new wp_image_description_v1 object for the currently
         preferred image description for the wl_surface. The client should
         stop using and destroy the image descriptions created by earlier
         invocations of this request for the associated wl_surface.
         This request is usually sent as a reaction to the preferred_changed
-        event or when creating a xx_color_management_feedback_surface_v4 object
+        event or when creating a wp_color_management_surface_feedback_v1 object
         if the client is capable of adapting to image descriptions.
 
-        The created xx_image_description_v4 object preserves the preferred image
+        The created wp_image_description_v1 object preserves the preferred image
         description of the wl_surface from the time the object was created.
 
         The resulting image description object allows get_information request.
 
+        If the image description is parametric, the client should set it on its
+        wl_surface only if the image description is an exact match with the
+        client content. Particularly if everything else matches, but the target
+        color volume is greater than what the client needs, the client should
+        create its own parameric image description with its exact parameters.
+
         If the interface version is inadequate for the preferred image
         description, meaning that the client does not support all the
         events needed to deliver the crucial information, the resulting image
         description object shall immediately deliver the
-        xx_image_description_v4.failed event with the low_version cause,
+        wp_image_description_v1.failed event with the low_version cause,
         otherwise the object shall immediately deliver the ready event.
       </description>
 
       <arg name="image_description"
-           type="new_id" interface="xx_image_description_v4"/>
+           type="new_id" interface="wp_image_description_v1"/>
+    </request>
+
+    <request name="get_preferred_parametric">
+      <description summary="get the preferred image description">
+        The same description as for get_preferred applies, except the returned
+        image description is guaranteed to be parametric. This is meant for
+        clients that can only deal with parametric image descriptions.
+
+        If the compositor doesn't support parametric image descriptions, the
+        unsupported_feature error is emitted.
+      </description>
+
+      <arg name="image_description"
+           type="new_id" interface="wp_image_description_v1"/>
     </request>
   </interface>
 
-  <interface name="xx_image_description_creator_icc_v4" version="1">
+  <interface name="wp_image_description_creator_icc_v1" version="1">
     <description summary="holder of image description ICC information">
       This type of object is used for collecting all the information required
-      to create a xx_image_description_v4 object from an ICC file. A complete
+      to create a wp_image_description_v1 object from an ICC file. A complete
       set of required parameters consists of these properties:
       - ICC file
 
@@ -753,19 +882,19 @@
 
         If the particular combination of the information is not supported
         by the compositor, the resulting image description object shall
-        immediately deliver the xx_image_description_v4.failed event with the
+        immediately deliver the wp_image_description_v1.failed event with the
         'unsupported' cause. If a valid image description was created from the
-        information, the xx_image_description_v4.ready event will eventually
+        information, the wp_image_description_v1.ready event will eventually
         be sent instead.
 
-        This request destroys the xx_image_description_creator_icc_v4 object.
+        This request destroys the wp_image_description_creator_icc_v1 object.
 
         The resulting image description object does not allow get_information
         request.
       </description>
 
       <arg name="image_description"
-           type="new_id" interface="xx_image_description_v4"/>
+           type="new_id" interface="wp_image_description_v1"/>
     </request>
 
     <request name="set_icc_file">
@@ -774,23 +903,23 @@
         description.
 
         The data shall be found through the given fd at the given offset, having
-        the given length. The fd must seekable and readable. Violating these
+        the given length. The fd must be seekable and readable. Violating these
         requirements raises the bad_fd protocol error.
 
         If reading the data fails due to an error independent of the client, the
-        compositor shall send the xx_image_description_v4.failed event on the
-        created xx_image_description_v4 with the 'operating_system' cause.
+        compositor shall send the wp_image_description_v1.failed event on the
+        created wp_image_description_v1 with the 'operating_system' cause.
 
-        The maximum size of the ICC profile is 4 MB. If length is greater than
+        The maximum size of the ICC profile is 32 MB. If length is greater than
         that or zero, the protocol error bad_size is raised. If offset + length
         exceeds the file size, the protocol error out_of_file is raised.
 
         A compositor may read the file at any time starting from this request
         and only until whichever happens first:
-        - If create request was issued, the xx_image_description_v4 object
+        - If create request was issued, the wp_image_description_v1 object
           delivers either failed or ready event; or
         - if create request was not issued, this
-          xx_image_description_creator_icc_v4 object is destroyed.
+          wp_image_description_creator_icc_v1 object is destroyed.
 
         A compositor shall not modify the contents of the file, and the fd may
         be sealed for writes and size changes. The client must ensure to its
@@ -800,9 +929,9 @@
         The data must represent a valid ICC profile. The ICC profile version
         must be 2 or 4, it must be a 3 channel profile and the class must be
         Display or ColorSpace. Violating these requirements will not result in a
-        protocol error but will eventually send the
-        xx_image_description_v4.failed event on the created
-        xx_image_description_v4 with the 'unsupported' cause.
+        protocol error, but will eventually send the
+        wp_image_description_v1.failed event on the created
+        wp_image_description_v1 with the 'unsupported' cause.
 
         See the International Color Consortium specification ICC.1:2022 for more
         details about ICC profiles.
@@ -820,10 +949,10 @@
     </request>
   </interface>
 
-  <interface name="xx_image_description_creator_params_v4" version="1">
+  <interface name="wp_image_description_creator_params_v1" version="1">
     <description summary="holder of image description parameters">
       This type of object is used for collecting all the parameters required
-      to create a xx_image_description_v4 object. A complete set of required
+      to create a wp_image_description_v1 object. A complete set of required
       parameters consists of these properties:
       - transfer characteristic function (tf)
       - chromaticities of primaries and white point (primary color volume)
@@ -834,6 +963,9 @@
       - reference white luminance level
       - mastering display primaries and white point (target color volume)
       - mastering luminance range
+
+      The following properties are optional and will be ignored
+      if not explicitly set:
       - maximum content light level
       - maximum frame-average light level
 
@@ -853,20 +985,16 @@
 
       <entry name="incomplete_set" value="0"
              summary="incomplete parameter set"/>
-      <entry name="inconsistent_set" value="1"
-             summary="invalid combination of parameters"/>
-      <entry name="already_set" value="2"
+      <entry name="already_set" value="1"
              summary="property already set"/>
-      <entry name="unsupported_feature" value="3"
+      <entry name="unsupported_feature" value="2"
              summary="request not supported"/>
-      <entry name="invalid_tf" value="4"
+      <entry name="invalid_tf" value="3"
              summary="invalid transfer characteristic"/>
-      <entry name="invalid_primaries" value="5"
-             summary="invalid primaries or white point"/>
-      <entry name="invalid_luminance" value="6"
+      <entry name="invalid_primaries_named" value="4"
+             summary="invalid primaries named"/>
+      <entry name="invalid_luminance" value="5"
              summary="invalid luminance value or range"/>
-      <entry name="invalid_mastering" value="7"
-             summary="invalid mastering information"/>
     </enum>
 
     <request name="create" type="destructor">
@@ -878,17 +1006,23 @@
         complete, the protocol error incomplete_set is raised. For the
         definition of a complete set, see the description of this interface.
 
-        Also, the combination of the parameter set is verified. If the set is
-        not consistent, the protocol error inconsistent_set is raised.
+        The protocol error invalid_luminance is raised if any of the following
+        requirements is not met:
+        - When max_cll is set, it must be greater than min L and less or equal
+          to max L of the mastering luminance range.
+        - When max_fall is set, it must be greater than min L and less or equal
+          to max L of the mastering luminance range.
+        - When both max_cll and max_fall are set, max_fall must be less or equal
+          to max_cll.
 
         If the particular combination of the parameter set is not supported
         by the compositor, the resulting image description object shall
-        immediately deliver the xx_image_description_v4.failed event with the
+        immediately deliver the wp_image_description_v1.failed event with the
         'unsupported' cause. If a valid image description was created from the
-        parameter set, the xx_image_description_v4.ready event will eventually
+        parameter set, the wp_image_description_v1.ready event will eventually
         be sent instead.
 
-        This request destroys the xx_image_description_creator_params_v4
+        This request destroys the wp_image_description_creator_params_v1
         object.
 
         The resulting image description object does not allow get_information
@@ -896,7 +1030,7 @@
       </description>
 
       <arg name="image_description"
-           type="new_id" interface="xx_image_description_v4"/>
+           type="new_id" interface="wp_image_description_v1"/>
     </request>
 
     <request name="set_tf_named">
@@ -908,22 +1042,24 @@
         content should be encoded and decoded according to the industry standard
         practices for the transfer characteristic.
 
-        Only names advertised with xx_color_manager_v4 event supported_tf_named
+        Only names advertised with wp_color_manager_v1 event supported_tf_named
         are allowed. Other values shall raise the protocol error invalid_tf.
 
         If transfer characteristic has already been set on this object, the
         protocol error already_set is raised.
       </description>
 
-      <arg name="tf" type="uint" enum="xx_color_manager_v4.transfer_function"
+      <arg name="tf" type="uint" enum="wp_color_manager_v1.transfer_function"
            summary="named transfer function"/>
     </request>
 
     <request name="set_tf_power">
       <description summary="transfer characteristic as a power curve">
         Sets the color component transfer characteristic to a power curve with
-        the given exponent. This curve represents the conversion from electrical
-        to optical pixel or color values.
+        the given exponent. Negative values are handled by mirroring the
+        positive half of the curve through the origin. The valid domain and
+        range of the curve are all finite real numbers. This curve represents
+        the conversion from electrical to optical color channel values.
 
         When the resulting image description is attached to an image, the
         content should be encoded with the inverse of the power curve.
@@ -938,7 +1074,7 @@
         protocol error already_set is raised.
 
         This request can be used when the compositor advertises
-        xx_color_manager_v4.feature.set_tf_power. Otherwise this request raises
+        wp_color_manager_v1.feature.set_tf_power. Otherwise this request raises
         the protocol error unsupported_feature.
       </description>
 
@@ -951,15 +1087,15 @@
         This describes the primary color volume which is the basis for color
         value encoding.
 
-        Only names advertised with xx_color_manager_v4 event
+        Only names advertised with wp_color_manager_v1 event
         supported_primaries_named are allowed. Other values shall raise the
-        protocol error invalid_primaries.
+        protocol error invalid_primaries_named.
 
         If primaries have already been set on this object, the protocol error
         already_set is raised.
       </description>
 
-      <arg name="primaries" type="uint" enum="xx_color_manager_v4.primaries"
+      <arg name="primaries" type="uint" enum="wp_color_manager_v1.primaries"
            summary="named primaries"/>
     </request>
 
@@ -969,33 +1105,36 @@
         coordinates. This describes the primary color volume which is the basis
         for color value encoding.
 
-        Each coordinate value is multiplied by 10000 to get the argument value
-        to carry precision of 4 decimals.
+        Each coordinate value is multiplied by 1 million to get the argument
+        value to carry precision of 6 decimals.
 
         If primaries have already been set on this object, the protocol error
         already_set is raised.
 
         This request can be used if the compositor advertises
-        xx_color_manager_v4.feature.set_primaries. Otherwise this request raises
+        wp_color_manager_v1.feature.set_primaries. Otherwise this request raises
         the protocol error unsupported_feature.
       </description>
 
-      <arg name="r_x" type="int" summary="Red x * 10000"/>
-      <arg name="r_y" type="int" summary="Red y * 10000"/>
-      <arg name="g_x" type="int" summary="Green x * 10000"/>
-      <arg name="g_y" type="int" summary="Green y * 10000"/>
-      <arg name="b_x" type="int" summary="Blue x * 10000"/>
-      <arg name="b_y" type="int" summary="Blue y * 10000"/>
-      <arg name="w_x" type="int" summary="White x * 10000"/>
-      <arg name="w_y" type="int" summary="White y * 10000"/>
+      <arg name="r_x" type="int" summary="Red x * 1M"/>
+      <arg name="r_y" type="int" summary="Red y * 1M"/>
+      <arg name="g_x" type="int" summary="Green x * 1M"/>
+      <arg name="g_y" type="int" summary="Green y * 1M"/>
+      <arg name="b_x" type="int" summary="Blue x * 1M"/>
+      <arg name="b_y" type="int" summary="Blue y * 1M"/>
+      <arg name="w_x" type="int" summary="White x * 1M"/>
+      <arg name="w_y" type="int" summary="White y * 1M"/>
     </request>
 
     <request name="set_luminances">
       <description summary="primary color volume luminance range and reference white">
         Sets the primary color volume luminance range and the reference white
-        luminance level.
+        luminance level. These values include the minimum display emission
+        and ambient flare luminances, assumed to be optically additive and have
+        the chromaticity of the primary color volume white point.
 
-        The default luminances are
+        The default luminances from
+        https://www.color.org/chardata/rgb/srgb.xalter are
         - primary color volume minimum: 0.2 cd/m²
         - primary color volume maximum: 80 cd/m²
         - reference white: 80 cd/m²
@@ -1004,6 +1143,8 @@
         luminances.
 
         The default luminances get overwritten when this request is used.
+        With transfer_function.st2084_pq the given 'max_lum' value is ignored,
+        and 'max_lum' is taken as 'min_lum' + 10000 cd/m².
 
         'min_lum' and 'max_lum' specify the minimum and maximum luminances of
         the primary color volume as reproduced by the targeted display.
@@ -1018,9 +1159,12 @@
         description should produce the same output level, even though the
         'reference_lum' on both image representations can be different.
 
-        If 'max_lum' is less than the 'reference_lum', or 'reference_lum' is
-        less than or equal to 'min_lum', the protocol error invalid_luminance is
-        raised.
+        'reference_lum' may be higher than 'max_lum'. In that case reaching
+        the reference white output level in image content requires the
+        'extended_target_volume' feature support.
+
+        If 'max_lum' or 'reference_lum' are less than or equal to 'min_lum',
+        the protocol error invalid_luminance is raised.
 
         The minimum luminance is multiplied by 10000 to get the argument
         'min_lum' value and carries precision of 4 decimals. The maximum
@@ -1031,7 +1175,7 @@
         already_set is raised.
 
         This request can be used if the compositor advertises
-        xx_color_manager_v4.feature.set_luminances. Otherwise this request
+        wp_color_manager_v1.feature.set_luminances. Otherwise this request
         raises the protocol error unsupported_feature.
       </description>
 
@@ -1049,10 +1193,11 @@
         using CIE 1931 xy chromaticity coordinates. This is compatible with the
         SMPTE ST 2086 definition of HDR static metadata.
 
-        The mastering display primaries define the target color volume.
+        The mastering display primaries and mastering display luminances define
+        the target color volume.
 
         If mastering display primaries are not explicitly set, the target color
-        volume is assumed to be equal to the primary color volume.
+        volume is assumed to have the same primaries as the primary color volume.
 
         The target color volume is defined by all tristimulus values between 0.0
         and 1.0 (inclusive) of the color space defined by the given mastering
@@ -1071,50 +1216,72 @@
         has to be chosen (e.g. floating point to exceed the primary color
         volume, or abusing limited quantization range as with xvYCC).
 
-        Each coordinate value is multiplied by 10000 to get the argument value
-        to carry precision of 4 decimals.
+        Each coordinate value is multiplied by 1 million to get the argument
+        value to carry precision of 6 decimals.
 
         If mastering display primaries have already been set on this object, the
         protocol error already_set is raised.
 
         This request can be used if the compositor advertises
-        xx_color_manager_v4.feature.set_mastering_display_primaries. Otherwise
+        wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise
         this request raises the protocol error unsupported_feature. The
         advertisement implies support only for target color volumes fully
         contained within the primary color volume.
 
         If a compositor additionally supports target color volume exceeding the
         primary color volume, it must advertise
-        xx_color_manager_v4.feature.extended_target_volume. If a client uses
+        wp_color_manager_v1.feature.extended_target_volume. If a client uses
         target color volume exceeding the primary color volume and the
         compositor does not support it, the result is implementation defined.
         Compositors are recommended to detect this case and fail the image
         description gracefully, but it may as well result in color artifacts.
       </description>
 
-      <arg name="r_x" type="int" summary="Red x * 10000"/>
-      <arg name="r_y" type="int" summary="Red y * 10000"/>
-      <arg name="g_x" type="int" summary="Green x * 10000"/>
-      <arg name="g_y" type="int" summary="Green y * 10000"/>
-      <arg name="b_x" type="int" summary="Blue x * 10000"/>
-      <arg name="b_y" type="int" summary="Blue y * 10000"/>
-      <arg name="w_x" type="int" summary="White x * 10000"/>
-      <arg name="w_y" type="int" summary="White y * 10000"/>
+      <arg name="r_x" type="int" summary="Red x * 1M"/>
+      <arg name="r_y" type="int" summary="Red y * 1M"/>
+      <arg name="g_x" type="int" summary="Green x * 1M"/>
+      <arg name="g_y" type="int" summary="Green y * 1M"/>
+      <arg name="b_x" type="int" summary="Blue x * 1M"/>
+      <arg name="b_y" type="int" summary="Blue y * 1M"/>
+      <arg name="w_x" type="int" summary="White x * 1M"/>
+      <arg name="w_y" type="int" summary="White y * 1M"/>
     </request>
 
     <request name="set_mastering_luminance">
       <description summary="display mastering luminance range">
         Sets the luminance range that was used during the content mastering
-        process as the minimum and maximum absolute luminance L. This is
+        process as the minimum and maximum absolute luminance L. These values
+        include the minimum display emission and ambient flare luminances,
+        assumed to be optically additive and have the chromaticity of the
+        primary color volume white point. This should be
         compatible with the SMPTE ST 2086 definition of HDR static metadata.
 
-        The mastering luminance range is undefined by default.
+        The mastering display primaries and mastering display luminances define
+        the target color volume.
+
+        If mastering luminances are not explicitly set, the target color volume
+        is assumed to have the same min and max luminances as the primary color
+        volume.
 
         If max L is less than or equal to min L, the protocol error
         invalid_luminance is raised.
 
         Min L value is multiplied by 10000 to get the argument min_lum value
         and carry precision of 4 decimals. Max L value is unscaled for max_lum.
+
+        This request can be used if the compositor advertises
+        wp_color_manager_v1.feature.set_mastering_display_primaries. Otherwise
+        this request raises the protocol error unsupported_feature. The
+        advertisement implies support only for target color volumes fully
+        contained within the primary color volume.
+
+        If a compositor additionally supports target color volume exceeding the
+        primary color volume, it must advertise
+        wp_color_manager_v1.feature.extended_target_volume. If a client uses
+        target color volume exceeding the primary color volume and the
+        compositor does not support it, the result is implementation defined.
+        Compositors are recommended to detect this case and fail the image
+        description gracefully, but it may as well result in color artifacts.
       </description>
 
       <arg name="min_lum" type="uint" summary="min L (cd/m²) * 10000"/>
@@ -1125,11 +1292,6 @@
       <description summary="maximum content light level">
         Sets the maximum content light level (max_cll) as defined by CTA-861-H.
 
-        This can only be set when set_tf_cicp is used to set the transfer
-        characteristic to Rec. ITU-R BT.2100-2 perceptual quantization system.
-        Otherwise, 'create' request shall raise inconsistent_set protocol
-        error.
-
         max_cll is undefined by default.
       </description>
 
@@ -1141,10 +1303,6 @@
         Sets the maximum frame-average light level (max_fall) as defined by
         CTA-861-H.
 
-        This can only be set when set_tf_cicp is used to set the transfer
-        characteristic to Rec. ITU-R BT.2100-2 perceptual quantization system.
-        Otherwise, 'create' request shall raise inconsistent_set protocol error.
-
         max_fall is undefined by default.
       </description>
 
@@ -1152,15 +1310,15 @@
     </request>
   </interface>
 
-  <interface name="xx_image_description_v4" version="1">
+  <interface name="wp_image_description_v1" version="1">
     <description summary="Colorimetric image description">
       An image description carries information about the color encoding used on
       a surface when attached to a wl_surface via
-      xx_color_management_surface_v4.set_image_description. A compositor can use
+      wp_color_management_surface_v1.set_image_description. A compositor can use
       this information to decode pixel values into colorimetrically meaningful
       quantities.
 
-      Note, that the xx_image_description_v4 object is not ready to be used
+      Note, that the wp_image_description_v1 object is not ready to be used
       immediately after creation. The object eventually delivers either the
       'ready' or the 'failed' event, specified in all requests creating it. The
       object is deemed "ready" after receiving the 'ready' event.
@@ -1171,7 +1329,7 @@
       interfaces shall raise protocol errors defined there.
 
       Once created and regardless of how it was created, a
-      xx_image_description_v4 object always refers to one fixed image
+      wp_image_description_v1 object always refers to one fixed image
       description. It cannot change after creation.
     </description>
 
@@ -1179,8 +1337,8 @@
       <description summary="destroy the image description">
         Destroy this object. It is safe to destroy an object which is not ready.
 
-        Destroying a xx_image_description_v4 object has no side-effects, not
-        even if a xx_color_management_surface_v4.set_image_description has not
+        Destroying a wp_image_description_v1 object has no side-effects, not
+        even if a wp_color_management_surface_v1.set_image_description has not
         yet been followed by a wl_surface.commit.
       </description>
     </request>
@@ -1209,7 +1367,7 @@
 
     <event name="failed">
       <description summary="graceful error on creating the image description">
-        If creating a xx_image_description_v4 object fails for a reason that is
+        If creating a wp_image_description_v1 object fails for a reason that is
         not defined as a protocol error, this event is sent.
 
         The requests that create image description objects define whether and
@@ -1217,7 +1375,7 @@
         This event cannot be triggered after the image description was
         successfully formed.
 
-        Once this event has been sent, the xx_image_description_v4 object will
+        Once this event has been sent, the wp_image_description_v1 object will
         never become ready and it can only be destroyed.
       </description>
 
@@ -1229,11 +1387,11 @@
 
     <event name="ready">
       <description summary="indication that the object is ready to be used">
-        Once this event has been sent, the xx_image_description_v4 object is
+        Once this event has been sent, the wp_image_description_v1 object is
         deemed "ready". Ready objects can be used to send requests and can be
         used through other interfaces.
 
-        Every ready xx_image_description_v4 protocol object refers to an
+        Every ready wp_image_description_v1 protocol object refers to an
         underlying image description record in the compositor. Multiple protocol
         objects may end up referring to the same record. Clients may identify
         these "copies" by comparing their id numbers: if the numbers from two
@@ -1250,7 +1408,8 @@
         Image description id number is not a protocol object id. Zero is
         reserved as an invalid id number. It shall not be possible for a client
         to refer to an image description by its id number in protocol. The id
-        numbers might not be portable between Wayland connections.
+        numbers might not be portable between Wayland connections. A compositor
+        shall not send an invalid id number.
 
         This identity allows clients to de-duplicate image description records
         and avoid get_information request if they already have the image
@@ -1262,7 +1421,7 @@
 
     <request name="get_information">
       <description summary="get information about the image description">
-        Creates a xx_image_description_info_v4 object which delivers the
+        Creates a wp_image_description_info_v1 object which delivers the
         information that makes up the image description.
 
         Not all image description protocol objects allow get_information
@@ -1272,20 +1431,34 @@
       </description>
 
       <arg name="information"
-           type="new_id" interface="xx_image_description_info_v4"/>
+           type="new_id" interface="wp_image_description_info_v1"/>
     </request>
   </interface>
 
-  <interface name="xx_image_description_info_v4" version="1">
+  <interface name="wp_image_description_info_v1" version="1">
     <description summary="Colorimetric image description information">
       Sends all matching events describing an image description object exactly
       once and finally sends the 'done' event.
 
-      Once a xx_image_description_info_v4 object has delivered a 'done' event it
+      This means
+      - if the image description is parametric, it must send
+        - primaries
+        - named_primaries, if applicable
+        - at least one of tf_power and tf_named, as applicable
+        - luminances
+        - target_primaries
+        - target_luminance
+      - if the image description is parametric, it may send, if applicable,
+        - target_max_cll
+        - target_max_fall
+      - if the image description contains an ICC profile, it must send the
+        icc_file event
+
+      Once a wp_image_description_info_v1 object has delivered a 'done' event it
       is automatically destroyed.
 
-      Every xx_image_description_info_v4 created from the same
-      xx_image_description_v4 shall always return the exact same data.
+      Every wp_image_description_info_v1 created from the same
+      wp_image_description_v1 shall always return the exact same data.
     </description>
 
     <event name="done" type="destructor">
@@ -1316,18 +1489,18 @@
         Delivers the primary color volume primaries and white point using CIE
         1931 xy chromaticity coordinates.
 
-        Each coordinate value is multiplied by 10000 to get the argument value
-        to carry precision of 4 decimals.
+        Each coordinate value is multiplied by 1 million to get the argument
+        value to carry precision of 6 decimals.
       </description>
 
-      <arg name="r_x" type="int" summary="Red x * 10000"/>
-      <arg name="r_y" type="int" summary="Red y * 10000"/>
-      <arg name="g_x" type="int" summary="Green x * 10000"/>
-      <arg name="g_y" type="int" summary="Green y * 10000"/>
-      <arg name="b_x" type="int" summary="Blue x * 10000"/>
-      <arg name="b_y" type="int" summary="Blue y * 10000"/>
-      <arg name="w_x" type="int" summary="White x * 10000"/>
-      <arg name="w_y" type="int" summary="White y * 10000"/>
+      <arg name="r_x" type="int" summary="Red x * 1M"/>
+      <arg name="r_y" type="int" summary="Red y * 1M"/>
+      <arg name="g_x" type="int" summary="Green x * 1M"/>
+      <arg name="g_y" type="int" summary="Green y * 1M"/>
+      <arg name="b_x" type="int" summary="Blue x * 1M"/>
+      <arg name="b_y" type="int" summary="Blue y * 1M"/>
+      <arg name="w_x" type="int" summary="White x * 1M"/>
+      <arg name="w_y" type="int" summary="White y * 1M"/>
     </event>
 
     <event name="primaries_named">
@@ -1336,7 +1509,7 @@
         explicitly enumerated named set.
       </description>
 
-      <arg name="primaries" type="uint" enum="xx_color_manager_v4.primaries"
+      <arg name="primaries" type="uint" enum="wp_color_manager_v1.primaries"
            summary="named primaries"/>
     </event>
 
@@ -1360,14 +1533,16 @@
         named function.
       </description>
 
-      <arg name="tf" type="uint" enum="xx_color_manager_v4.transfer_function"
+      <arg name="tf" type="uint" enum="wp_color_manager_v1.transfer_function"
            summary="named transfer function"/>
     </event>
 
     <event name="luminances">
       <description summary="primary color volume luminance range and reference white">
         Delivers the primary color volume luminance range and the reference
-        white luminance level.
+        white luminance level. These values include the minimum display emission
+        and ambient flare luminances, assumed to be optically additive and have
+        the chromaticity of the primary color volume white point.
 
         The minimum luminance is multiplied by 10000 to get the argument
         'min_lum' value and carries precision of 4 decimals. The maximum
@@ -1393,25 +1568,28 @@
         volume is equal to the primary color volume, then this event is not
         sent.
 
-        Each coordinate value is multiplied by 10000 to get the argument value
-        to carry precision of 4 decimals.
+        Each coordinate value is multiplied by 1 million to get the argument
+        value to carry precision of 6 decimals.
       </description>
 
-      <arg name="r_x" type="int" summary="Red x * 10000"/>
-      <arg name="r_y" type="int" summary="Red y * 10000"/>
-      <arg name="g_x" type="int" summary="Green x * 10000"/>
-      <arg name="g_y" type="int" summary="Green y * 10000"/>
-      <arg name="b_x" type="int" summary="Blue x * 10000"/>
-      <arg name="b_y" type="int" summary="Blue y * 10000"/>
-      <arg name="w_x" type="int" summary="White x * 10000"/>
-      <arg name="w_y" type="int" summary="White y * 10000"/>
+      <arg name="r_x" type="int" summary="Red x * 1M"/>
+      <arg name="r_y" type="int" summary="Red y * 1M"/>
+      <arg name="g_x" type="int" summary="Green x * 1M"/>
+      <arg name="g_y" type="int" summary="Green y * 1M"/>
+      <arg name="b_x" type="int" summary="Blue x * 1M"/>
+      <arg name="b_y" type="int" summary="Blue y * 1M"/>
+      <arg name="w_x" type="int" summary="White x * 1M"/>
+      <arg name="w_y" type="int" summary="White y * 1M"/>
     </event>
 
     <event name="target_luminance">
       <description summary="target luminance range">
         Provides the luminance range that the image description is targeting as
-        the minimum and maximum absolute luminance L. This is compatible with
-        the SMPTE ST 2086 definition of HDR static metadata.
+        the minimum and maximum absolute luminance L. These values include the
+        minimum display emission and ambient flare luminances, assumed to be
+        optically additive and have the chromaticity of the primary color
+        volume white point. This should be compatible with the SMPTE ST 2086
+        definition of HDR static metadata.
 
         This luminance range is only theoretical and may not correspond to the
         luminance of light emitted on an actual display.
diff --git a/subprojects/wayland-protocols/staging/commit-timing/README b/subprojects/wayland-protocols/staging/commit-timing/README
new file mode 100644
index 0000000000000000000000000000000000000000..4f130a72c167625ae70866e965ab3e25fc4e7408
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/commit-timing/README
@@ -0,0 +1,4 @@
+Commit Timing Protocol
+
+Maintainers:
+Derek Foreman <derek.foreman@collabora.com> (@derekf)
diff --git a/subprojects/wayland-protocols/staging/commit-timing/commit-timing-v1.xml b/subprojects/wayland-protocols/staging/commit-timing/commit-timing-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cc42ea6961b5b3aa7eadf1edd7878b420ba7afbc
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/commit-timing/commit-timing-v1.xml
@@ -0,0 +1,124 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="commit_timing_v1">
+
+  <copyright>
+    Copyright © 2023 Valve Corporation
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="wp_commit_timing_manager_v1" version="1">
+    <description summary="commit timing">
+      When a compositor latches on to new content updates it will check for
+      any number of requirements of the available content updates (such as
+      fences of all buffers being signalled) to consider the update ready.
+
+      This protocol provides a method for adding a time constraint to surface
+      content. This constraint indicates to the compositor that a content
+      update should be presented as closely as possible to, but not before,
+      a specified time.
+
+      This protocol does not change the Wayland property that content
+      updates are applied in the order they are received, even when some
+      content updates contain timestamps and others do not.
+
+      To provide timestamps, this global factory interface must be used to
+      acquire a wp_commit_timing_v1 object for a surface, which may then be
+      used to provide timestamp information for commits.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+    <enum name="error">
+      <entry name="commit_timer_exists" value="0"
+             summary="commit timer already exists for surface"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the commit timing interface">
+        Informs the server that the client will no longer be using
+        this protocol object. Existing objects created by this object
+        are not affected.
+      </description>
+    </request>
+
+    <request name="get_timer">
+      <description summary="request commit timer interface for surface">
+        Establish a timing controller for a surface.
+
+        Only one commit timer can be created for a surface, or a
+        commit_timer_exists protocol error will be generated.
+      </description>
+      <arg name="id" type="new_id" interface="wp_commit_timer_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_commit_timer_v1" version="1">
+    <description summary="Surface commit timer">
+      An object to set a time constraint for a content update on a surface.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_timestamp" value="0"
+             summary="timestamp contains an invalid value"/>
+      <entry name="timestamp_exists" value="1"
+             summary="timestamp exists"/>
+      <entry name="surface_destroyed" value="2"
+             summary="the associated surface no longer exists"/>
+    </enum>
+
+    <request name="set_timestamp">
+      <description summary="Specify time the following commit takes effect">
+        Provide a timing constraint for a surface content update.
+
+        A set_timestamp request may be made before a wl_surface.commit to
+        tell the compositor that the content is intended to be presented
+        as closely as possible to, but not before, the specified time.
+        The time is in the domain of the compositor's presentation clock.
+
+        An invalid_timestamp error will be generated for invalid tv_nsec.
+
+        If a timestamp already exists on the surface, a timestamp_exists
+        error is generated.
+
+        Requesting set_timestamp after the commit_timer object's surface is
+        destroyed will generate a "surface_destroyed" error.
+      </description>
+      <arg name="tv_sec_hi" type="uint"
+           summary="high 32 bits of the seconds part of target time"/>
+      <arg name="tv_sec_lo" type="uint"
+           summary="low 32 bits of the seconds part of target time"/>
+      <arg name="tv_nsec" type="uint"
+           summary="nanoseconds part of target time"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="Destroy the timer">
+        Informs the server that the client will no longer be using
+        this protocol object.
+
+        Existing timing constraints are not affected by the destruction.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/content-type/README b/subprojects/wayland-protocols/staging/content-type/README
new file mode 100644
index 0000000000000000000000000000000000000000..797a9c9e53f3712390a983279d5dd19f06a12552
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/content-type/README
@@ -0,0 +1,5 @@
+Content type hint protocol
+
+Maintainers:
+Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> (@linkmauve)
+Xaver Hugl <xaver.hugl@gmail.com> (@Zamundaaa)
diff --git a/subprojects/wayland-protocols/staging/content-type/content-type-v1.xml b/subprojects/wayland-protocols/staging/content-type/content-type-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..65a1acb80f47ae857a9cbc4a51a73072d59c7011
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/content-type/content-type-v1.xml
@@ -0,0 +1,128 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="content_type_v1">
+  <copyright>
+    Copyright © 2021 Emmanuel Gil Peyrot
+    Copyright © 2022 Xaver Hugl
+
+    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.
+  </copyright>
+
+  <interface name="wp_content_type_manager_v1" version="1">
+    <description summary="surface content type manager">
+      This interface allows a client to describe the kind of content a surface
+      will display, to allow the compositor to optimize its behavior for it.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the content type manager object">
+        Destroy the content type manager. This doesn't destroy objects created
+        with the manager.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="already_constructed" value="0"
+             summary="wl_surface already has a content type object"/>
+    </enum>
+
+    <request name="get_surface_content_type">
+      <description summary="create a new content type object">
+        Create a new content type object associated with the given surface.
+
+        Creating a wp_content_type_v1 from a wl_surface which already has one
+        attached is a client error: already_constructed.
+      </description>
+      <arg name="id" type="new_id" interface="wp_content_type_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_content_type_v1" version="1">
+    <description summary="content type object for a surface">
+      The content type object allows the compositor to optimize for the kind
+      of content shown on the surface. A compositor may for example use it to
+      set relevant drm properties like "content type".
+
+      The client may request to switch to another content type at any time.
+      When the associated surface gets destroyed, this object becomes inert and
+      the client should destroy it.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the content type object">
+        Switch back to not specifying the content type of this surface. This is
+        equivalent to setting the content type to none, including double
+        buffering semantics. See set_content_type for details.
+      </description>
+    </request>
+
+    <enum name="type">
+      <description summary="possible content types">
+        These values describe the available content types for a surface.
+      </description>
+      <entry name="none" value="0">
+        <description summary="no content type applies">
+          The content type none means that either the application has no data
+          about the content type, or that the content doesn't fit into one of
+          the other categories.
+        </description>
+      </entry>
+      <entry name="photo" value="1">
+        <description summary="photo content type">
+          The content type photo describes content derived from digital still
+          pictures and may be presented with minimal processing.
+        </description>
+      </entry>
+      <entry name="video" value="2">
+        <description summary="video content type">
+          The content type video describes a video or animation and may be
+          presented with more accurate timing to avoid stutter. Where scaling
+          is needed, scaling methods more appropriate for video may be used.
+        </description>
+      </entry>
+      <entry name="game" value="3">
+        <description summary="game content type">
+          The content type game describes a running game. Its content may be
+          presented with reduced latency.
+        </description>
+      </entry>
+    </enum>
+
+    <request name="set_content_type">
+      <description summary="specify the content type">
+        Set the surface content type. This informs the compositor that the
+        client believes it is displaying buffers matching this content type.
+
+        This is purely a hint for the compositor, which can be used to adjust
+        its behavior or hardware settings to fit the presented content best.
+
+        The content type is double-buffered state, see wl_surface.commit for
+        details.
+      </description>
+      <arg name="content_type" type="uint" enum="type"
+           summary="the content type"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/cursor-shape/README b/subprojects/wayland-protocols/staging/cursor-shape/README
new file mode 100644
index 0000000000000000000000000000000000000000..7ca8f5e1d3b3acbce2d476d85cea70356a5259f3
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/cursor-shape/README
@@ -0,0 +1,4 @@
+cursor-shape protocol
+
+Maintainers:
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/staging/cursor-shape/cursor-shape-v1.xml b/subprojects/wayland-protocols/staging/cursor-shape/cursor-shape-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..8df2e4ba9eabe0f990a1138d853baf0423a278c0
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/cursor-shape/cursor-shape-v1.xml
@@ -0,0 +1,152 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="cursor_shape_v1">
+  <copyright>
+    Copyright 2018 The Chromium Authors
+    Copyright 2023 Simon Ser
+
+    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.
+  </copyright>
+
+  <interface name="wp_cursor_shape_manager_v1" version="1">
+    <description summary="cursor shape manager">
+      This global offers an alternative, optional way to set cursor images. This
+      new way uses enumerated cursors instead of a wl_surface like
+      wl_pointer.set_cursor does.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the manager">
+        Destroy the cursor shape manager.
+      </description>
+    </request>
+
+    <request name="get_pointer">
+      <description summary="manage the cursor shape of a pointer device">
+        Obtain a wp_cursor_shape_device_v1 for a wl_pointer object.
+
+        When the pointer capability is removed from the wl_seat, the
+        wp_cursor_shape_device_v1 object becomes inert.
+      </description>
+      <arg name="cursor_shape_device" type="new_id" interface="wp_cursor_shape_device_v1"/>
+      <arg name="pointer" type="object" interface="wl_pointer"/>
+    </request>
+
+    <request name="get_tablet_tool_v2">
+      <description summary="manage the cursor shape of a tablet tool device">
+        Obtain a wp_cursor_shape_device_v1 for a zwp_tablet_tool_v2 object.
+
+        When the zwp_tablet_tool_v2 is removed, the wp_cursor_shape_device_v1
+        object becomes inert.
+      </description>
+      <arg name="cursor_shape_device" type="new_id" interface="wp_cursor_shape_device_v1"/>
+      <arg name="tablet_tool" type="object" interface="zwp_tablet_tool_v2"/>
+    </request>
+  </interface>
+
+  <interface name="wp_cursor_shape_device_v1" version="1">
+    <description summary="cursor shape for a device">
+      This interface allows clients to set the cursor shape.
+    </description>
+
+    <enum name="shape">
+      <description summary="cursor shapes">
+        This enum describes cursor shapes.
+
+        The names are taken from the CSS W3C specification:
+        https://w3c.github.io/csswg-drafts/css-ui/#cursor
+      </description>
+      <entry name="default" value="1" summary="default cursor"/>
+      <entry name="context_menu" value="2" summary="a context menu is available for the object under the cursor"/>
+      <entry name="help" value="3" summary="help is available for the object under the cursor"/>
+      <entry name="pointer" value="4" summary="pointer that indicates a link or another interactive element"/>
+      <entry name="progress" value="5" summary="progress indicator"/>
+      <entry name="wait" value="6" summary="program is busy, user should wait"/>
+      <entry name="cell" value="7" summary="a cell or set of cells may be selected"/>
+      <entry name="crosshair" value="8" summary="simple crosshair"/>
+      <entry name="text" value="9" summary="text may be selected"/>
+      <entry name="vertical_text" value="10" summary="vertical text may be selected"/>
+      <entry name="alias" value="11" summary="drag-and-drop: alias of/shortcut to something is to be created"/>
+      <entry name="copy" value="12" summary="drag-and-drop: something is to be copied"/>
+      <entry name="move" value="13" summary="drag-and-drop: something is to be moved"/>
+      <entry name="no_drop" value="14" summary="drag-and-drop: the dragged item cannot be dropped at the current cursor location"/>
+      <entry name="not_allowed" value="15" summary="drag-and-drop: the requested action will not be carried out"/>
+      <entry name="grab" value="16" summary="drag-and-drop: something can be grabbed"/>
+      <entry name="grabbing" value="17" summary="drag-and-drop: something is being grabbed"/>
+      <entry name="e_resize" value="18" summary="resizing: the east border is to be moved"/>
+      <entry name="n_resize" value="19" summary="resizing: the north border is to be moved"/>
+      <entry name="ne_resize" value="20" summary="resizing: the north-east corner is to be moved"/>
+      <entry name="nw_resize" value="21" summary="resizing: the north-west corner is to be moved"/>
+      <entry name="s_resize" value="22" summary="resizing: the south border is to be moved"/>
+      <entry name="se_resize" value="23" summary="resizing: the south-east corner is to be moved"/>
+      <entry name="sw_resize" value="24" summary="resizing: the south-west corner is to be moved"/>
+      <entry name="w_resize" value="25" summary="resizing: the west border is to be moved"/>
+      <entry name="ew_resize" value="26" summary="resizing: the east and west borders are to be moved"/>
+      <entry name="ns_resize" value="27" summary="resizing: the north and south borders are to be moved"/>
+      <entry name="nesw_resize" value="28" summary="resizing: the north-east and south-west corners are to be moved"/>
+      <entry name="nwse_resize" value="29" summary="resizing: the north-west and south-east corners are to be moved"/>
+      <entry name="col_resize" value="30" summary="resizing: that the item/column can be resized horizontally"/>
+      <entry name="row_resize" value="31" summary="resizing: that the item/row can be resized vertically"/>
+      <entry name="all_scroll" value="32" summary="something can be scrolled in any direction"/>
+      <entry name="zoom_in" value="33" summary="something can be zoomed in"/>
+      <entry name="zoom_out" value="34" summary="something can be zoomed out"/>
+    </enum>
+
+    <enum name="error">
+      <entry name="invalid_shape" value="1"
+        summary="the specified shape value is invalid"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the cursor shape device">
+        Destroy the cursor shape device.
+
+        The device cursor shape remains unchanged.
+      </description>
+    </request>
+
+    <request name="set_shape">
+      <description summary="set device cursor to the shape">
+        Sets the device cursor to the specified shape. The compositor will
+        change the cursor image based on the specified shape.
+
+        The cursor actually changes only if the input device focus is one of
+        the requesting client's surfaces. If any, the previous cursor image
+        (surface or shape) is replaced.
+
+        The "shape" argument must be a valid enum entry, otherwise the
+        invalid_shape protocol error is raised.
+
+        This is similar to the wl_pointer.set_cursor and
+        zwp_tablet_tool_v2.set_cursor requests, but this request accepts a
+        shape instead of contents in the form of a surface. Clients can mix
+        set_cursor and set_shape requests.
+
+        The serial parameter must match the latest wl_pointer.enter or
+        zwp_tablet_tool_v2.proximity_in serial number sent to the client.
+        Otherwise the request will be ignored.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="shape" type="uint" enum="shape"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/drm-lease/README b/subprojects/wayland-protocols/staging/drm-lease/README
new file mode 100644
index 0000000000000000000000000000000000000000..86c3408fe50a4c8908b38bfc8e1345cbce05ae55
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/drm-lease/README
@@ -0,0 +1,6 @@
+Linux DRM lease
+
+Maintainers:
+Simon Zeni <simon@bl4ckb0ne.ca> (@bl4ckb0ne)
+Marius Vlad <marius.vlad@collabora.com> (@mvlad)
+Xaver Hugl <xaver.hugl@gmail.com> (@Zamundaaa)
diff --git a/subprojects/wayland-protocols/staging/drm-lease/drm-lease-v1.xml b/subprojects/wayland-protocols/staging/drm-lease/drm-lease-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1fca5382817932565f0063f83fe3bbed609120b3
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/drm-lease/drm-lease-v1.xml
@@ -0,0 +1,317 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="drm_lease_v1">
+  <copyright>
+    Copyright © 2018 NXP
+    Copyright © 2019 Status Research &amp; Development GmbH.
+    Copyright © 2021 Xaver Hugl
+
+    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.
+  </copyright>
+
+  <interface name="wp_drm_lease_device_v1" version="1">
+    <description summary="lease device">
+      This protocol is used by Wayland compositors which act as Direct
+      Rendering Manager (DRM) masters to lease DRM resources to Wayland
+      clients.
+
+      The compositor will advertise one wp_drm_lease_device_v1 global for each
+      DRM node. Some time after a client binds to the wp_drm_lease_device_v1
+      global, the compositor will send a drm_fd event followed by zero, one or
+      more connector events. After all currently available connectors have been
+      sent, the compositor will send a wp_drm_lease_device_v1.done event.
+
+      When the list of connectors available for lease changes the compositor
+      will send wp_drm_lease_device_v1.connector events for added connectors and
+      wp_drm_lease_connector_v1.withdrawn events for removed connectors,
+      followed by a wp_drm_lease_device_v1.done event.
+
+      The compositor will indicate when a device is gone by removing the global
+      via a wl_registry.global_remove event. Upon receiving this event, the
+      client should destroy any matching wp_drm_lease_device_v1 object.
+
+      To destroy a wp_drm_lease_device_v1 object, the client must first issue
+      a release request. Upon receiving this request, the compositor will
+      immediately send a released event and destroy the object. The client must
+      continue to process and discard drm_fd and connector events until it
+      receives the released event. Upon receiving the released event, the
+      client can safely cleanup any client-side resources.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <request name="create_lease_request">
+      <description summary="create a lease request object">
+        Creates a lease request object.
+
+        See the documentation for wp_drm_lease_request_v1 for details.
+      </description>
+      <arg name="id" type="new_id" interface="wp_drm_lease_request_v1" />
+    </request>
+
+    <request name="release">
+      <description summary="release this object">
+        Indicates the client no longer wishes to use this object. In response
+        the compositor will immediately send the released event and destroy
+        this object. It can however not guarantee that the client won't receive
+        connector events before the released event. The client must not send any
+        requests after this one, doing so will raise a wl_display error.
+        Existing connectors, lease request and leases will not be affected.
+      </description>
+    </request>
+
+    <event name="drm_fd">
+      <description summary="open a non-master fd for this DRM node">
+        The compositor will send this event when the wp_drm_lease_device_v1
+        global is bound, although there are no guarantees as to how long this
+        takes - the compositor might need to wait until regaining DRM master.
+        The included fd is a non-master DRM file descriptor opened for this
+        device and the compositor must not authenticate it.
+        The purpose of this event is to give the client the ability to
+        query DRM and discover information which may help them pick the
+        appropriate DRM device or select the appropriate connectors therein.
+      </description>
+      <arg name="fd" type="fd" summary="DRM file descriptor" />
+    </event>
+
+    <event name="connector">
+      <description summary="advertise connectors available for leases">
+        The compositor will use this event to advertise connectors available for
+        lease by clients. This object may be passed into a lease request to
+        indicate the client would like to lease that connector, see
+        wp_drm_lease_request_v1.request_connector for details. While the
+        compositor will make a best effort to not send disconnected connectors,
+        no guarantees can be made.
+
+        The compositor must send the drm_fd event before sending connectors.
+        After the drm_fd event it will send all available connectors but may
+        send additional connectors at any time.
+      </description>
+      <arg name="id" type="new_id" interface="wp_drm_lease_connector_v1" />
+    </event>
+
+    <event name="done">
+      <description summary="signals grouping of connectors">
+        The compositor will send this event to indicate that it has sent all
+        currently available connectors after the client binds to the global or
+        when it updates the connector list, for example on hotplug, drm master
+        change or when a leased connector becomes available again. It will
+        similarly send this event to group wp_drm_lease_connector_v1.withdrawn
+        events of connectors of this device.
+      </description>
+    </event>
+
+    <event name="released" type="destructor">
+      <description summary="the compositor has finished using the device">
+        This event is sent in response to the release request and indicates
+        that the compositor is done sending connector events.
+        The compositor will destroy this object immediately after sending the
+        event and it will become invalid. The client should release any
+        resources associated with this device after receiving this event.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="wp_drm_lease_connector_v1" version="1">
+    <description summary="a leasable DRM connector">
+      Represents a DRM connector which is available for lease. These objects are
+      created via wp_drm_lease_device_v1.connector events, and should be passed
+      to lease requests via wp_drm_lease_request_v1.request_connector.
+      Immediately after the wp_drm_lease_connector_v1 object is created the
+      compositor will send a name, a description, a connector_id and a done
+      event. When the description is updated the compositor will send a
+      description event followed by a done event.
+    </description>
+
+    <event name="name">
+      <description summary="name">
+        The compositor sends this event once the connector is created to
+        indicate the name of this connector. This will not change for the
+        duration of the Wayland session, but is not guaranteed to be consistent
+        between sessions.
+
+        If the compositor supports wl_output version 4 and this connector
+        corresponds to a wl_output, the compositor should use the same name as
+        for the wl_output.
+      </description>
+      <arg name="name" type="string" summary="connector name" />
+    </event>
+
+    <event name="description">
+      <description summary="description">
+        The compositor sends this event once the connector is created to provide
+        a human-readable description for this connector, which may be presented
+        to the user. The compositor may send this event multiple times over the
+        lifetime of this object to reflect changes in the description.
+      </description>
+      <arg name="description" type="string" summary="connector description" />
+    </event>
+
+    <event name="connector_id">
+      <description summary="connector_id">
+        The compositor sends this event once the connector is created to
+        indicate the DRM object ID which represents the underlying connector
+        that is being offered. Note that the final lease may include additional
+        object IDs, such as CRTCs and planes.
+      </description>
+      <arg name="connector_id" type="uint" summary="DRM connector ID" />
+    </event>
+
+    <event name="done">
+      <description summary="all properties have been sent">
+        This event is sent after all properties of a connector have been sent.
+        This allows changes to the properties to be seen as atomic even if they
+        happen via multiple events.
+      </description>
+    </event>
+
+    <event name="withdrawn">
+      <description summary="lease offer withdrawn">
+        Sent to indicate that the compositor will no longer honor requests for
+        DRM leases which include this connector. The client may still issue a
+        lease request including this connector, but the compositor will send
+        wp_drm_lease_v1.finished without issuing a lease fd. Compositors are
+        encouraged to send this event when they lose access to connector, for
+        example when the connector is hot-unplugged, when the connector gets
+        leased to a client or when the compositor loses DRM master.
+
+        If a client holds a lease for the connector, the status of the lease
+        remains the same. The client should destroy the object after receiving
+        this event.
+      </description>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy connector">
+        The client may send this request to indicate that it will not use this
+        connector. Clients are encouraged to send this after receiving the
+        "withdrawn" event so that the server can release the resources
+        associated with this connector offer. Neither existing lease requests
+        nor leases will be affected.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="wp_drm_lease_request_v1" version="1">
+    <description summary="DRM lease request">
+      A client that wishes to lease DRM resources will attach the list of
+      connectors advertised with wp_drm_lease_device_v1.connector that they
+      wish to lease, then use wp_drm_lease_request_v1.submit to submit the
+      request.
+    </description>
+
+    <enum name="error">
+      <entry name="wrong_device" value="0"
+             summary="requested a connector from a different lease device"/>
+      <entry name="duplicate_connector" value="1"
+             summary="requested a connector twice"/>
+      <entry name="empty_lease" value="2"
+             summary="requested a lease without requesting a connector"/>
+    </enum>
+
+    <request name="request_connector">
+      <description summary="request a connector for this lease">
+        Indicates that the client would like to lease the given connector.
+        This is only used as a suggestion, the compositor may choose to
+        include any resources in the lease it issues, or change the set of
+        leased resources at any time. Compositors are however encouraged to
+        include the requested connector and other resources necessary
+        to drive the connected output in the lease.
+
+        Requesting a connector that was created from a different lease device
+        than this lease request raises the wrong_device error. Requesting a
+        connector twice will raise the duplicate_connector error.
+      </description>
+      <arg name="connector" type="object"
+           interface="wp_drm_lease_connector_v1" />
+    </request>
+
+    <request name="submit" type="destructor">
+      <description summary="submit the lease request">
+        Submits the lease request and creates a new wp_drm_lease_v1 object.
+        After calling submit the compositor will immediately destroy this
+        object, issuing any more requests will cause a wl_display error.
+        The compositor doesn't make any guarantees about the events of the
+        lease object, clients cannot expect an immediate response.
+        Not requesting any connectors before submitting the lease request
+        will raise the empty_lease error.
+      </description>
+      <arg name="id" type="new_id" interface="wp_drm_lease_v1" />
+    </request>
+  </interface>
+
+  <interface name="wp_drm_lease_v1" version="1">
+    <description summary="a DRM lease">
+      A DRM lease object is used to transfer the DRM file descriptor to the
+      client and manage the lifetime of the lease.
+
+      Some time after the wp_drm_lease_v1 object is created, the compositor
+      will reply with the lease request's result. If the lease request is
+      granted, the compositor will send a lease_fd event. If the lease request
+      is denied, the compositor will send a finished event without a lease_fd
+      event.
+    </description>
+
+    <event name="lease_fd">
+      <description summary="shares the DRM file descriptor">
+        This event returns a file descriptor suitable for use with DRM-related
+        ioctls. The client should use drmModeGetLease to enumerate the DRM
+        objects which have been leased to them. The compositor guarantees it
+        will not use the leased DRM objects itself until it sends the finished
+        event. If the compositor cannot or will not grant a lease for the
+        requested connectors, it will not send this event, instead sending the
+        finished event.
+
+        The compositor will send this event at most once during this objects
+        lifetime.
+      </description>
+      <arg name="leased_fd" type="fd" summary="leased DRM file descriptor" />
+    </event>
+
+    <event name="finished">
+      <description summary="sent when the lease has been revoked">
+        The compositor uses this event to either reject a lease request, or if
+        it previously sent a lease_fd, to notify the client that the lease has
+        been revoked. If the client requires a new lease, they should destroy
+        this object and submit a new lease request. The compositor will send
+        no further events for this object after sending the finish event.
+        Compositors should revoke the lease when any of the leased resources
+        become unavailable, namely when a hot-unplug occurs or when the
+        compositor loses DRM master. Compositors may advertise the connector
+        for leasing again, if the resource is available, by sending the
+        connector event through the wp_drm_lease_device_v1 interface.
+      </description>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroys the lease object">
+        The client should send this to indicate that it no longer wishes to use
+        this lease. The compositor should use drmModeRevokeLease on the
+        appropriate file descriptor, if necessary.
+
+        Upon destruction, the compositor should advertise the connector for
+        leasing again by sending the connector event through the
+        wp_drm_lease_device_v1 interface.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/ext-data-control/README b/subprojects/wayland-protocols/staging/ext-data-control/README
new file mode 100644
index 0000000000000000000000000000000000000000..e0dce8970af7f9ef87b62215132ca1750d20e849
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-data-control/README
@@ -0,0 +1,4 @@
+data-control protocol
+
+Maintainers:
+Neal Gompa <neal@gompa.dev> (@Conan_Kudo)
diff --git a/subprojects/wayland-protocols/staging/ext-data-control/ext-data-control-v1.xml b/subprojects/wayland-protocols/staging/ext-data-control/ext-data-control-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..37ee577ed92e73936eb871e04baa4760e0264767
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-data-control/ext-data-control-v1.xml
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_data_control_v1">
+  <copyright>
+    Copyright © 2018 Simon Ser
+    Copyright © 2019 Ivan Molodetskikh
+    Copyright © 2024 Neal Gompa
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+  <description summary="control data devices">
+    This protocol allows a privileged client to control data devices. In
+    particular, the client will be able to manage the current selection and take
+    the role of a clipboard manager.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="ext_data_control_manager_v1" version="1">
+    <description summary="manager to control data devices">
+      This interface is a manager that allows creating per-seat data device
+      controls.
+    </description>
+
+    <request name="create_data_source">
+      <description summary="create a new data source">
+        Create a new data source.
+      </description>
+      <arg name="id" type="new_id" interface="ext_data_control_source_v1"
+        summary="data source to create"/>
+    </request>
+
+    <request name="get_data_device">
+      <description summary="get a data device for a seat">
+        Create a data device that can be used to manage a seat's selection.
+      </description>
+      <arg name="id" type="new_id" interface="ext_data_control_device_v1"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the manager">
+        All objects created by the manager will still remain valid, until their
+        appropriate destroy request has been called.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_data_control_device_v1" version="1">
+    <description summary="manage a data device for a seat">
+      This interface allows a client to manage a seat's selection.
+
+      When the seat is destroyed, this object becomes inert.
+    </description>
+
+    <request name="set_selection">
+      <description summary="copy data to the selection">
+        This request asks the compositor to set the selection to the data from
+        the source on behalf of the client.
+
+        The given source may not be used in any further set_selection or
+        set_primary_selection requests. Attempting to use a previously used
+        source triggers the used_source protocol error.
+
+        To unset the selection, set the source to NULL.
+      </description>
+      <arg name="source" type="object" interface="ext_data_control_source_v1"
+        allow-null="true"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy this data device">
+        Destroys the data device object.
+      </description>
+    </request>
+
+    <event name="data_offer">
+      <description summary="introduce a new ext_data_control_offer">
+        The data_offer event introduces a new ext_data_control_offer object,
+        which will subsequently be used in either the
+        ext_data_control_device.selection event (for the regular clipboard
+        selections) or the ext_data_control_device.primary_selection event (for
+        the primary clipboard selections). Immediately following the
+        ext_data_control_device.data_offer event, the new data_offer object
+        will send out ext_data_control_offer.offer events to describe the MIME
+        types it offers.
+      </description>
+      <arg name="id" type="new_id" interface="ext_data_control_offer_v1"/>
+    </event>
+
+    <event name="selection">
+      <description summary="advertise new selection">
+        The selection event is sent out to notify the client of a new
+        ext_data_control_offer for the selection for this device. The
+        ext_data_control_device.data_offer and the ext_data_control_offer.offer
+        events are sent out immediately before this event to introduce the data
+        offer object. The selection event is sent to a client when a new
+        selection is set. The ext_data_control_offer is valid until a new
+        ext_data_control_offer or NULL is received. The client must destroy the
+        previous selection ext_data_control_offer, if any, upon receiving this
+        event. Regardless, the previous selection will be ignored once a new
+        selection ext_data_control_offer is received.
+
+        The first selection event is sent upon binding the
+        ext_data_control_device object.
+      </description>
+      <arg name="id" type="object" interface="ext_data_control_offer_v1"
+        allow-null="true"/>
+    </event>
+
+    <event name="finished">
+      <description summary="this data control is no longer valid">
+        This data control object is no longer valid and should be destroyed by
+        the client.
+      </description>
+    </event>
+
+    <event name="primary_selection">
+      <description summary="advertise new primary selection">
+        The primary_selection event is sent out to notify the client of a new
+        ext_data_control_offer for the primary selection for this device. The
+        ext_data_control_device.data_offer and the ext_data_control_offer.offer
+        events are sent out immediately before this event to introduce the data
+        offer object. The primary_selection event is sent to a client when a
+        new primary selection is set. The ext_data_control_offer is valid until
+        a new ext_data_control_offer or NULL is received. The client must
+        destroy the previous primary selection ext_data_control_offer, if any,
+        upon receiving this event. Regardless, the previous primary selection
+        will be ignored once a new primary selection ext_data_control_offer is
+        received.
+
+        If the compositor supports primary selection, the first
+        primary_selection event is sent upon binding the
+        ext_data_control_device object.
+      </description>
+      <arg name="id" type="object" interface="ext_data_control_offer_v1"
+        allow-null="true"/>
+    </event>
+
+    <request name="set_primary_selection">
+      <description summary="copy data to the primary selection">
+        This request asks the compositor to set the primary selection to the
+        data from the source on behalf of the client.
+
+        The given source may not be used in any further set_selection or
+        set_primary_selection requests. Attempting to use a previously used
+        source triggers the used_source protocol error.
+
+        To unset the primary selection, set the source to NULL.
+
+        The compositor will ignore this request if it does not support primary
+        selection.
+      </description>
+      <arg name="source" type="object" interface="ext_data_control_source_v1"
+        allow-null="true"/>
+    </request>
+
+    <enum name="error">
+      <entry name="used_source" value="1"
+        summary="source given to set_selection or set_primary_selection was already used before"/>
+    </enum>
+  </interface>
+
+  <interface name="ext_data_control_source_v1" version="1">
+    <description summary="offer to transfer data">
+      The ext_data_control_source object is the source side of a
+      ext_data_control_offer. It is created by the source client in a data
+      transfer and provides a way to describe the offered data and a way to
+      respond to requests to transfer the data.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_offer" value="1"
+        summary="offer sent after ext_data_control_device.set_selection"/>
+    </enum>
+
+    <request name="offer">
+      <description summary="add an offered MIME type">
+        This request adds a MIME type to the set of MIME types advertised to
+        targets. Can be called several times to offer multiple types.
+
+        Calling this after ext_data_control_device.set_selection is a protocol
+        error.
+      </description>
+      <arg name="mime_type" type="string"
+        summary="MIME type offered by the data source"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy this source">
+        Destroys the data source object.
+      </description>
+    </request>
+
+    <event name="send">
+      <description summary="send the data">
+        Request for data from the client. Send the data as the specified MIME
+        type over the passed file descriptor, then close it.
+      </description>
+      <arg name="mime_type" type="string" summary="MIME type for the data"/>
+      <arg name="fd" type="fd" summary="file descriptor for the data"/>
+    </event>
+
+    <event name="cancelled">
+      <description summary="selection was cancelled">
+        This data source is no longer valid. The data source has been replaced
+        by another data source.
+
+        The client should clean up and destroy this data source.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="ext_data_control_offer_v1" version="1">
+    <description summary="offer to transfer data">
+      A ext_data_control_offer represents a piece of data offered for transfer
+      by another client (the source client). The offer describes the different
+      MIME types that the data can be converted to and provides the mechanism
+      for transferring the data directly from the source client.
+    </description>
+
+    <request name="receive">
+      <description summary="request that the data is transferred">
+        To transfer the offered data, the client issues this request and
+        indicates the MIME type it wants to receive. The transfer happens
+        through the passed file descriptor (typically created with the pipe
+        system call). The source client writes the data in the MIME type
+        representation requested and then closes the file descriptor.
+
+        The receiving client reads from the read end of the pipe until EOF and
+        then closes its end, at which point the transfer is complete.
+
+        This request may happen multiple times for different MIME types.
+      </description>
+      <arg name="mime_type" type="string"
+        summary="MIME type desired by receiver"/>
+      <arg name="fd" type="fd" summary="file descriptor for data transfer"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy this offer">
+        Destroys the data offer object.
+      </description>
+    </request>
+
+    <event name="offer">
+      <description summary="advertise offered MIME type">
+        Sent immediately after creating the ext_data_control_offer object.
+        One event per offered MIME type.
+      </description>
+      <arg name="mime_type" type="string" summary="offered MIME type"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/ext-foreign-toplevel-list/README b/subprojects/wayland-protocols/staging/ext-foreign-toplevel-list/README
new file mode 100644
index 0000000000000000000000000000000000000000..561c880d4f9b346086c012c43bf216ef02bfc8fe
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-foreign-toplevel-list/README
@@ -0,0 +1,4 @@
+Foreign toplevel list protocol
+
+Maintainers:
+i509VCB <mail@i509.me> (@i509VCB)
diff --git a/subprojects/wayland-protocols/staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml b/subprojects/wayland-protocols/staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..11b0113a9c32d47b79050f89aef52764ecf3cdbc
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-foreign-toplevel-list/ext-foreign-toplevel-list-v1.xml
@@ -0,0 +1,219 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_foreign_toplevel_list_v1">
+  <copyright>
+    Copyright © 2018 Ilia Bozhinov
+    Copyright © 2020 Isaac Freund
+    Copyright © 2022 wb9688
+    Copyright © 2023 i509VCB
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+  <description summary="list toplevels">
+    The purpose of this protocol is to provide protocol object handles for
+    toplevels, possibly originating from another client.
+
+    This protocol is intentionally minimalistic and expects additional
+    functionality (e.g. creating a screencopy source from a toplevel handle,
+    getting information about the state of the toplevel) to be implemented
+    in extension protocols.
+
+    The compositor may choose to restrict this protocol to a special client
+    launched by the compositor itself or expose it to all clients,
+    this is compositor policy.
+
+    The key words "must", "must not", "required", "shall", "shall not",
+    "should", "should not", "recommended",  "may", and "optional" in this
+    document are to be interpreted as described in IETF RFC 2119.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="ext_foreign_toplevel_list_v1" version="1">
+    <description summary="list toplevels">
+      A toplevel is defined as a surface with a role similar to xdg_toplevel.
+      XWayland surfaces may be treated like toplevels in this protocol.
+
+      After a client binds the ext_foreign_toplevel_list_v1, each mapped
+      toplevel window will be sent using the ext_foreign_toplevel_list_v1.toplevel
+      event.
+
+      Clients which only care about the current state can perform a roundtrip after
+      binding this global.
+
+      For each instance of ext_foreign_toplevel_list_v1, the compositor must
+      create a new ext_foreign_toplevel_handle_v1 object for each mapped toplevel.
+
+      If a compositor implementation sends the ext_foreign_toplevel_list_v1.finished
+      event after the global is bound, the compositor must not send any
+      ext_foreign_toplevel_list_v1.toplevel events.
+    </description>
+
+    <event name="toplevel">
+      <description summary="a toplevel has been created">
+        This event is emitted whenever a new toplevel window is created. It is
+        emitted for all toplevels, regardless of the app that has created them.
+
+        All initial properties of the toplevel (identifier, title, app_id) will be sent
+        immediately after this event using the corresponding events for
+        ext_foreign_toplevel_handle_v1. The compositor will use the
+        ext_foreign_toplevel_handle_v1.done event to indicate when all data has
+        been sent.
+      </description>
+      <arg name="toplevel" type="new_id" interface="ext_foreign_toplevel_handle_v1"/>
+    </event>
+
+    <event name="finished">
+      <description summary="the compositor has finished with the toplevel manager">
+        This event indicates that the compositor is done sending events
+        to this object. The client should destroy the object.
+        See ext_foreign_toplevel_list_v1.destroy for more information.
+
+        The compositor must not send any more toplevel events after this event.
+      </description>
+    </event>
+
+    <request name="stop">
+      <description summary="stop sending events">
+        This request indicates that the client no longer wishes to receive
+        events for new toplevels.
+
+        The Wayland protocol is asynchronous, meaning the compositor may send
+        further toplevel events until the stop request is processed.
+        The client should wait for a ext_foreign_toplevel_list_v1.finished
+        event before destroying this object.
+      </description>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the ext_foreign_toplevel_list_v1 object">
+        This request should be called either when the client will no longer
+        use the ext_foreign_toplevel_list_v1 or after the finished event
+        has been received to allow destruction of the object.
+
+        If a client wishes to destroy this object it should send a
+        ext_foreign_toplevel_list_v1.stop request and wait for a ext_foreign_toplevel_list_v1.finished
+        event, then destroy the handles and then this object.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_foreign_toplevel_handle_v1" version="1">
+    <description summary="a mapped toplevel">
+      A ext_foreign_toplevel_handle_v1 object represents a mapped toplevel
+      window. A single app may have multiple mapped toplevels.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the ext_foreign_toplevel_handle_v1 object">
+        This request should be used when the client will no longer use the handle
+        or after the closed event has been received to allow destruction of the
+        object.
+
+        When a handle is destroyed, a new handle may not be created by the server
+        until the toplevel is unmapped and then remapped. Destroying a toplevel handle
+        is not recommended unless the client is cleaning up child objects
+        before destroying the ext_foreign_toplevel_list_v1 object, the toplevel
+        was closed or the toplevel handle will not be used in the future.
+
+        Other protocols which extend the ext_foreign_toplevel_handle_v1
+        interface should require destructors for extension interfaces be
+        called before allowing the toplevel handle to be destroyed.
+      </description>
+    </request>
+
+    <event name="closed">
+      <description summary="the toplevel has been closed">
+        The server will emit no further events on the ext_foreign_toplevel_handle_v1
+        after this event. Any requests received aside from the destroy request must
+        be ignored. Upon receiving this event, the client should destroy the handle.
+
+        Other protocols which extend the ext_foreign_toplevel_handle_v1
+        interface must also ignore requests other than destructors.
+      </description>
+    </event>
+
+    <event name="done">
+      <description summary="all information about the toplevel has been sent">
+        This event is sent after all changes in the toplevel state have
+        been sent.
+
+        This allows changes to the ext_foreign_toplevel_handle_v1 properties
+        to be atomically applied. Other protocols which extend the
+        ext_foreign_toplevel_handle_v1 interface may use this event to also
+        atomically apply any pending state.
+
+        This event must not be sent after the ext_foreign_toplevel_handle_v1.closed
+        event.
+      </description>
+    </event>
+
+    <event name="title">
+      <description summary="title change">
+        The title of the toplevel has changed.
+
+        The configured state must not be applied immediately. See
+        ext_foreign_toplevel_handle_v1.done for details.
+      </description>
+      <arg name="title" type="string"/>
+    </event>
+
+    <event name="app_id">
+      <description summary="app_id change">
+        The app id of the toplevel has changed.
+
+        The configured state must not be applied immediately. See
+        ext_foreign_toplevel_handle_v1.done for details.
+      </description>
+      <arg name="app_id" type="string"/>
+    </event>
+
+    <event name="identifier">
+      <description summary="a stable identifier for a toplevel">
+        This identifier is used to check if two or more toplevel handles belong
+        to the same toplevel.
+
+        The identifier is useful for command line tools or privileged clients
+        which may need to reference an exact toplevel across processes or
+        instances of the ext_foreign_toplevel_list_v1 global.
+
+        The compositor must only send this event when the handle is created.
+
+        The identifier must be unique per toplevel and it's handles. Two different
+        toplevels must not have the same identifier. The identifier is only valid
+        as long as the toplevel is mapped. If the toplevel is unmapped the identifier
+        must not be reused. An identifier must not be reused by the compositor to
+        ensure there are no races when sharing identifiers between processes.
+
+        An identifier is a string that contains up to 32 printable ASCII bytes.
+        An identifier must not be an empty string. It is recommended that a
+        compositor includes an opaque generation value in identifiers. How the
+        generation value is used when generating the identifier is implementation
+        dependent.
+      </description>
+      <arg name="identifier" type="string"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/ext-idle-notify/README b/subprojects/wayland-protocols/staging/ext-idle-notify/README
new file mode 100644
index 0000000000000000000000000000000000000000..461279983a7a1dd62cb2d9aae021b63fab699bfd
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-idle-notify/README
@@ -0,0 +1,4 @@
+idle_notify protocol
+
+Maintainers:
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/staging/ext-idle-notify/ext-idle-notify-v1.xml b/subprojects/wayland-protocols/staging/ext-idle-notify/ext-idle-notify-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..db7d9c1650f48bea51e0ecdfdadbf756a4fa89cc
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-idle-notify/ext-idle-notify-v1.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_idle_notify_v1">
+  <copyright>
+    Copyright © 2015 Martin Gräßlin
+    Copyright © 2022 Simon Ser
+
+    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.
+  </copyright>
+
+  <interface name="ext_idle_notifier_v1" version="2">
+    <description summary="idle notification manager">
+      This interface allows clients to monitor user idle status.
+
+      After binding to this global, clients can create ext_idle_notification_v1
+      objects to get notified when the user is idle for a given amount of time.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the manager">
+        Destroy the manager object. All objects created via this interface
+        remain valid.
+      </description>
+    </request>
+
+    <request name="get_idle_notification">
+      <description summary="create a notification object">
+        Create a new idle notification object.
+
+        The notification object has a minimum timeout duration and is tied to a
+        seat. The client will be notified if the seat is inactive for at least
+        the provided timeout. See ext_idle_notification_v1 for more details.
+
+        A zero timeout is valid and means the client wants to be notified as
+        soon as possible when the seat is inactive.
+      </description>
+      <arg name="id" type="new_id" interface="ext_idle_notification_v1"/>
+      <arg name="timeout" type="uint" summary="minimum idle timeout in msec"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+
+    <!-- Version 2 additions -->
+
+    <request name="get_input_idle_notification" since="2">
+      <description summary="create a notification object">
+        Create a new idle notification object to track input from the
+        user, such as keyboard and mouse movement. Because this object is
+        meant to track user input alone, it ignores idle inhibitors.
+
+        The notification object has a minimum timeout duration and is tied to a
+        seat. The client will be notified if the seat is inactive for at least
+        the provided timeout. See ext_idle_notification_v1 for more details.
+
+        A zero timeout is valid and means the client wants to be notified as
+        soon as possible when the seat is inactive.
+      </description>
+      <arg name="id" type="new_id" interface="ext_idle_notification_v1"/>
+      <arg name="timeout" type="uint" summary="minimum idle timeout in msec"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+    
+  </interface>
+
+  <interface name="ext_idle_notification_v1" version="2">
+    <description summary="idle notification">
+      This interface is used by the compositor to send idle notification events
+      to clients.
+
+      Initially the notification object is not idle. The notification object
+      becomes idle when no user activity has happened for at least the timeout
+      duration, starting from the creation of the notification object. User
+      activity may include input events or a presence sensor, but is
+      compositor-specific.
+
+      How this notification responds to idle inhibitors depends on how
+      it was constructed. If constructed from the
+      get_idle_notification request, then if an idle inhibitor is
+      active (e.g. another client has created a zwp_idle_inhibitor_v1
+      on a visible surface), the compositor must not make the
+      notification object idle. However, if constructed from the
+      get_input_idle_notification request, then idle inhibitors are
+      ignored, and only input from the user, e.g. from a keyboard or
+      mouse, counts as activity.
+
+      When the notification object becomes idle, an idled event is sent. When
+      user activity starts again, the notification object stops being idle,
+      a resumed event is sent and the timeout is restarted.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the notification object">
+        Destroy the notification object.
+      </description>
+    </request>
+
+    <event name="idled">
+      <description summary="notification object is idle">
+        This event is sent when the notification object becomes idle.
+
+        It's a compositor protocol error to send this event twice without a
+        resumed event in-between.
+      </description>
+    </event>
+
+    <event name="resumed">
+      <description summary="notification object is no longer idle">
+        This event is sent when the notification object stops being idle.
+
+        It's a compositor protocol error to send this event twice without an
+        idled event in-between. It's a compositor protocol error to send this
+        event prior to any idled event.
+      </description>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/ext-image-capture-source/README b/subprojects/wayland-protocols/staging/ext-image-capture-source/README
new file mode 100644
index 0000000000000000000000000000000000000000..615e6381437fb42f7dde8bea1c32003deafc7304
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-image-capture-source/README
@@ -0,0 +1,5 @@
+Image Capture Source Protocol
+
+Maintainers:
+Andri Yngvason <andri@yngvason.is> (@andri)
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/staging/ext-image-capture-source/ext-image-capture-source-v1.xml b/subprojects/wayland-protocols/staging/ext-image-capture-source/ext-image-capture-source-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b31a5da3eb6d77eed9da508e388fae62232d9d8d
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-image-capture-source/ext-image-capture-source-v1.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_image_capture_source_v1">
+  <copyright>
+    Copyright © 2022 Andri Yngvason
+    Copyright © 2024 Simon Ser
+
+    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.
+  </copyright>
+
+  <description summary="opaque image capture source objects">
+    This protocol serves as an intermediary between capturing protocols and
+    potential image capture sources such as outputs and toplevels.
+
+    This protocol may be extended to support more image capture sources in the
+    future, thereby adding those image capture sources to other protocols that
+    use the image capture source object without having to modify those
+    protocols.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="ext_image_capture_source_v1" version="1">
+    <description summary="opaque image capture source object">
+      The image capture source object is an opaque descriptor for a capturable
+      resource.  This resource may be any sort of entity from which an image
+      may be derived.
+
+      Note, because ext_image_capture_source_v1 objects are created from multiple
+      independent factory interfaces, the ext_image_capture_source_v1 interface is
+      frozen at version 1.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete this object">
+        Destroys the image capture source. This request may be sent at any time
+        by the client.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_output_image_capture_source_manager_v1" version="1">
+    <description summary="image capture source manager for outputs">
+      A manager for creating image capture source objects for wl_output objects.
+    </description>
+
+    <request name="create_source">
+      <description summary="create source object for output">
+        Creates a source object for an output. Images captured from this source
+        will show the same content as the output. Some elements may be omitted,
+        such as cursors and overlays that have been marked as transparent to
+        capturing.
+      </description>
+      <arg name="source" type="new_id" interface="ext_image_capture_source_v1"/>
+      <arg name="output" type="object" interface="wl_output"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete this object">
+        Destroys the manager. This request may be sent at any time by the client
+        and objects created by the manager will remain valid after its
+        destruction.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_foreign_toplevel_image_capture_source_manager_v1" version="1">
+    <description summary="image capture source manager for foreign toplevels">
+      A manager for creating image capture source objects for
+      ext_foreign_toplevel_handle_v1 objects.
+    </description>
+
+    <request name="create_source">
+      <description summary="create source object for foreign toplevel">
+        Creates a source object for a foreign toplevel handle. Images captured
+        from this source will show the same content as the toplevel.
+      </description>
+      <arg name="source" type="new_id" interface="ext_image_capture_source_v1"/>
+      <arg name="toplevel_handle" type="object" interface="ext_foreign_toplevel_handle_v1"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete this object">
+        Destroys the manager. This request may be sent at any time by the client
+        and objects created by the manager will remain valid after its
+        destruction.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/ext-image-copy-capture/README b/subprojects/wayland-protocols/staging/ext-image-copy-capture/README
new file mode 100644
index 0000000000000000000000000000000000000000..c0556adcbd08af4ea80c7795d2dc9d5b729a5ec6
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-image-copy-capture/README
@@ -0,0 +1,5 @@
+Image Copy Capture protocol
+
+Maintainers:
+Andri Yngvason <andri@yngvason.is> (@andri)
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml b/subprojects/wayland-protocols/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1ac43696a086262d707ab7363c22eb77e4f9d092
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml
@@ -0,0 +1,456 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_image_copy_capture_v1">
+  <copyright>
+    Copyright © 2021-2023 Andri Yngvason
+    Copyright © 2024 Simon Ser
+
+    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.
+  </copyright>
+
+  <description summary="image capturing into client buffers">
+    This protocol allows clients to ask the compositor to capture image sources
+    such as outputs and toplevels into user submitted buffers.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="ext_image_copy_capture_manager_v1" version="1">
+    <description summary="manager to inform clients and begin capturing">
+      This object is a manager which offers requests to start capturing from a
+      source.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_option" value="1" summary="invalid option flag"/>
+    </enum>
+
+    <enum name="options" bitfield="true">
+      <entry name="paint_cursors" value="1" summary="paint cursors onto captured frames"/>
+    </enum>
+
+    <request name="create_session">
+      <description summary="capture an image capture source">
+        Create a capturing session for an image capture source.
+
+        If the paint_cursors option is set, cursors shall be composited onto
+        the captured frame. The cursor must not be composited onto the frame
+        if this flag is not set.
+
+        If the options bitfield is invalid, the invalid_option protocol error
+        is sent.
+      </description>
+      <arg name="session" type="new_id" interface="ext_image_copy_capture_session_v1"/>
+      <arg name="source" type="object" interface="ext_image_capture_source_v1"/>
+      <arg name="options" type="uint" enum="options"/>
+    </request>
+
+    <request name="create_pointer_cursor_session">
+      <description summary="capture the pointer cursor of an image capture source">
+        Create a cursor capturing session for the pointer of an image capture
+        source.
+      </description>
+      <arg name="session" type="new_id" interface="ext_image_copy_capture_cursor_session_v1"/>
+      <arg name="source" type="object" interface="ext_image_capture_source_v1"/>
+      <arg name="pointer" type="object" interface="wl_pointer"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the manager">
+        Destroy the manager object.
+
+        Other objects created via this interface are unaffected.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_image_copy_capture_session_v1" version="1">
+    <description summary="image copy capture session">
+      This object represents an active image copy capture session.
+
+      After a capture session is created, buffer constraint events will be
+      emitted from the compositor to tell the client which buffer types and
+      formats are supported for reading from the session. The compositor may
+      re-send buffer constraint events whenever they change.
+
+      To advertise buffer constraints, the compositor must send in no
+      particular order: zero or more shm_format and dmabuf_format events, zero
+      or one dmabuf_device event, and exactly one buffer_size event. Then the
+      compositor must send a done event.
+
+      When the client has received all the buffer constraints, it can create a
+      buffer accordingly, attach it to the capture session using the
+      attach_buffer request, set the buffer damage using the damage_buffer
+      request and then send the capture request.
+    </description>
+
+    <enum name="error">
+      <entry name="duplicate_frame" value="1"
+        summary="create_frame sent before destroying previous frame"/>
+    </enum>
+
+    <event name="buffer_size">
+      <description summary="image capture source dimensions">
+        Provides the dimensions of the source image in buffer pixel coordinates.
+
+        The client must attach buffers that match this size.
+      </description>
+      <arg name="width" type="uint" summary="buffer width"/>
+      <arg name="height" type="uint" summary="buffer height"/>
+    </event>
+
+    <event name="shm_format">
+      <description summary="shm buffer format">
+        Provides the format that must be used for shared-memory buffers.
+
+        This event may be emitted multiple times, in which case the client may
+        choose any given format.
+      </description>
+      <arg name="format" type="uint" enum="wl_shm.format" summary="shm format"/>
+    </event>
+
+    <event name="dmabuf_device">
+      <description summary="dma-buf device">
+        This event advertises the device buffers must be allocated on for
+        dma-buf buffers.
+
+        In general the device is a DRM node. The DRM node type (primary vs.
+        render) is unspecified. Clients must not rely on the compositor sending
+        a particular node type. Clients cannot check two devices for equality
+        by comparing the dev_t value.
+      </description>
+      <arg name="device" type="array" summary="device dev_t value"/>
+    </event>
+
+    <event name="dmabuf_format">
+      <description summary="dma-buf format">
+        Provides the format that must be used for dma-buf buffers.
+
+        The client may choose any of the modifiers advertised in the array of
+        64-bit unsigned integers.
+
+        This event may be emitted multiple times, in which case the client may
+        choose any given format.
+      </description>
+      <arg name="format" type="uint" summary="drm format code"/>
+      <arg name="modifiers" type="array" summary="drm format modifiers"/>
+    </event>
+
+    <event name="done">
+      <description summary="all constraints have been sent">
+        This event is sent once when all buffer constraint events have been
+        sent.
+
+        The compositor must always end a batch of buffer constraint events with
+        this event, regardless of whether it sends the initial constraints or
+        an update.
+      </description>
+    </event>
+
+    <event name="stopped">
+      <description summary="session is no longer available">
+        This event indicates that the capture session has stopped and is no
+        longer available. This can happen in a number of cases, e.g. when the
+        underlying source is destroyed, if the user decides to end the image
+        capture, or if an unrecoverable runtime error has occurred.
+
+        The client should destroy the session after receiving this event.
+      </description>
+    </event>
+
+    <request name="create_frame">
+      <description summary="create a frame">
+        Create a capture frame for this session.
+
+        At most one frame object can exist for a given session at any time. If
+        a client sends a create_frame request before a previous frame object
+        has been destroyed, the duplicate_frame protocol error is raised.
+      </description>
+      <arg name="frame" type="new_id" interface="ext_image_copy_capture_frame_v1"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete this object">
+        Destroys the session. This request can be sent at any time by the
+        client.
+
+        This request doesn't affect ext_image_copy_capture_frame_v1 objects created by
+        this object.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_image_copy_capture_frame_v1" version="1">
+    <description summary="image capture frame">
+      This object represents an image capture frame.
+
+      The client should attach a buffer, damage the buffer, and then send a
+      capture request.
+
+      If the capture is successful, the compositor must send the frame metadata
+      (transform, damage, presentation_time in any order) followed by the ready
+      event.
+
+      If the capture fails, the compositor must send the failed event.
+    </description>
+
+    <enum name="error">
+      <entry name="no_buffer" value="1" summary="capture sent without attach_buffer"/>
+      <entry name="invalid_buffer_damage" value="2" summary="invalid buffer damage"/>
+      <entry name="already_captured" value="3" summary="capture request has been sent"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy this object">
+        Destroys the frame. This request can be sent at any time by the
+        client.
+      </description>
+    </request>
+
+    <request name="attach_buffer">
+      <description summary="attach buffer to session">
+        Attach a buffer to the session.
+
+        The wl_buffer.release request is unused.
+
+        The new buffer replaces any previously attached buffer.
+
+        This request must not be sent after capture, or else the
+        already_captured protocol error is raised.
+      </description>
+      <arg name="buffer" type="object" interface="wl_buffer"/>
+    </request>
+
+    <request name="damage_buffer">
+      <description summary="damage buffer">
+        Apply damage to the buffer which is to be captured next. This request
+        may be sent multiple times to describe a region.
+
+        The client indicates the accumulated damage since this wl_buffer was
+        last captured. During capture, the compositor will update the buffer
+        with at least the union of the region passed by the client and the
+        region advertised by ext_image_copy_capture_frame_v1.damage.
+
+        When a wl_buffer is captured for the first time, or when the client
+        doesn't track damage, the client must damage the whole buffer.
+
+        This is for optimisation purposes. The compositor may use this
+        information to reduce copying.
+
+        These coordinates originate from the upper left corner of the buffer.
+
+        If x or y are strictly negative, or if width or height are negative or
+        zero, the invalid_buffer_damage protocol error is raised.
+
+        This request must not be sent after capture, or else the
+        already_captured protocol error is raised.
+      </description>
+      <arg name="x" type="int" summary="region x coordinate"/>
+      <arg name="y" type="int" summary="region y coordinate"/>
+      <arg name="width" type="int" summary="region width"/>
+      <arg name="height" type="int" summary="region height"/>
+    </request>
+
+    <request name="capture">
+      <description summary="capture a frame">
+        Capture a frame.
+
+        Unless this is the first successful captured frame performed in this
+        session, the compositor may wait an indefinite amount of time for the
+        source content to change before performing the copy.
+
+        This request may only be sent once, or else the already_captured
+        protocol error is raised. A buffer must be attached before this request
+        is sent, or else the no_buffer protocol error is raised.
+      </description>
+    </request>
+
+    <event name="transform">
+      <description summary="buffer transform">
+        This event is sent before the ready event and holds the transform that
+        the compositor has applied to the buffer contents.
+      </description>
+      <arg name="transform" type="uint" enum="wl_output.transform"/>
+    </event>
+
+    <event name="damage">
+      <description summary="buffer damaged region">
+        This event is sent before the ready event. It may be generated multiple
+        times to describe a region.
+
+        The first captured frame in a session will always carry full damage.
+        Subsequent frames' damaged regions describe which parts of the buffer
+        have changed since the last ready event.
+
+        These coordinates originate in the upper left corner of the buffer.
+      </description>
+      <arg name="x" type="int" summary="damage x coordinate"/>
+      <arg name="y" type="int" summary="damage y coordinate"/>
+      <arg name="width" type="int" summary="damage width"/>
+      <arg name="height" type="int" summary="damage height"/>
+    </event>
+
+    <event name="presentation_time">
+      <description summary="presentation time of the frame">
+        This event indicates the time at which the frame is presented to the
+        output in system monotonic time. This event is sent before the ready
+        event.
+
+        The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
+        each component being an unsigned 32-bit value. Whole seconds are in
+        tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo,
+        and the additional fractional part in tv_nsec as nanoseconds. Hence,
+        for valid timestamps tv_nsec must be in [0, 999999999].
+      </description>
+      <arg name="tv_sec_hi" type="uint"
+           summary="high 32 bits of the seconds part of the timestamp"/>
+      <arg name="tv_sec_lo" type="uint"
+           summary="low 32 bits of the seconds part of the timestamp"/>
+      <arg name="tv_nsec" type="uint"
+           summary="nanoseconds part of the timestamp"/>
+    </event>
+
+    <event name="ready">
+      <description summary="frame is available for reading">
+        Called as soon as the frame is copied, indicating it is available
+        for reading.
+
+        The buffer may be re-used by the client after this event.
+
+        After receiving this event, the client must destroy the object.
+      </description>
+    </event>
+
+    <enum name="failure_reason">
+      <entry name="unknown" value="0">
+        <description summary="unknown runtime error">
+          An unspecified runtime error has occurred. The client may retry.
+        </description>
+      </entry>
+      <entry name="buffer_constraints" value="1">
+        <description summary="buffer constraints mismatch">
+          The buffer submitted by the client doesn't match the latest session
+          constraints. The client should re-allocate its buffers and retry.
+        </description>
+      </entry>
+      <entry name="stopped" value="2">
+        <description summary="session is no longer available">
+          The session has stopped. See ext_image_copy_capture_session_v1.stopped.
+        </description>
+      </entry>
+    </enum>
+
+    <event name="failed">
+      <description summary="capture failed">
+        This event indicates that the attempted frame copy has failed.
+
+        After receiving this event, the client must destroy the object.
+      </description>
+      <arg name="reason" type="uint" enum="failure_reason"/>
+    </event>
+  </interface>
+
+  <interface name="ext_image_copy_capture_cursor_session_v1" version="1">
+    <description summary="cursor capture session">
+      This object represents a cursor capture session. It extends the base
+      capture session with cursor-specific metadata.
+    </description>
+
+    <enum name="error">
+      <entry name="duplicate_session" value="1" summary="get_capture_session sent twice"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete this object">
+        Destroys the session. This request can be sent at any time by the
+        client.
+
+        This request doesn't affect ext_image_copy_capture_frame_v1 objects created by
+        this object.
+      </description>
+    </request>
+
+    <request name="get_capture_session">
+      <description summary="get image copy capturer session">
+        Gets the image copy capture session for this cursor session.
+
+        The session will produce frames of the cursor image. The compositor may
+        pause the session when the cursor leaves the captured area.
+
+        This request must not be sent more than once, or else the
+        duplicate_session protocol error is raised.
+      </description>
+      <arg name="session" type="new_id" interface="ext_image_copy_capture_session_v1"/>
+    </request>
+
+    <event name="enter">
+      <description summary="cursor entered captured area">
+        Sent when a cursor enters the captured area. It shall be generated
+        before the "position" and "hotspot" events when and only when a cursor
+        enters the area.
+
+        The cursor enters the captured area when the cursor image intersects
+        with the captured area. Note, this is different from e.g.
+        wl_pointer.enter.
+      </description>
+    </event>
+
+    <event name="leave">
+      <description summary="cursor left captured area">
+        Sent when a cursor leaves the captured area. No "position" or "hotspot"
+        event is generated for the cursor until the cursor enters the captured
+        area again.
+      </description>
+    </event>
+
+    <event name="position">
+      <description summary="position changed">
+        Cursors outside the image capture source do not get captured and no
+        event will be generated for them.
+
+        The given position is the position of the cursor's hotspot and it is
+        relative to the main buffer's top left corner in transformed buffer
+        pixel coordinates. The coordinates may be negative or greater than the
+        main buffer size.
+      </description>
+      <arg name="x" type="int" summary="position x coordinates"/>
+      <arg name="y" type="int" summary="position y coordinates"/>
+    </event>
+
+    <event name="hotspot">
+      <description summary="hotspot changed">
+        The hotspot describes the offset between the cursor image and the
+        position of the input device.
+
+        The given coordinates are the hotspot's offset from the origin in
+        buffer coordinates.
+
+        Clients should not apply the hotspot immediately: the hotspot becomes
+        effective when the next ext_image_copy_capture_frame_v1.ready event is received.
+
+        Compositors may delay this event until the client captures a new frame.
+      </description>
+      <arg name="x" type="int" summary="hotspot x coordinates"/>
+      <arg name="y" type="int" summary="hotspot y coordinates"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/ext-session-lock/README b/subprojects/wayland-protocols/staging/ext-session-lock/README
new file mode 100644
index 0000000000000000000000000000000000000000..783b8307ebac52a2836a31b29a2a83b60ffd1d5e
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-session-lock/README
@@ -0,0 +1,4 @@
+ext session lock protocol
+
+Maintainers:
+Isaac Freund <mail@isaacfreund.com> (@ifreund)
diff --git a/subprojects/wayland-protocols/staging/ext-session-lock/ext-session-lock-v1.xml b/subprojects/wayland-protocols/staging/ext-session-lock/ext-session-lock-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..19c12d26ce712108e1c206522eab8568d9819dae
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-session-lock/ext-session-lock-v1.xml
@@ -0,0 +1,328 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_session_lock_v1">
+  <copyright>
+    Copyright 2021 Isaac Freund
+
+    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 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.
+  </copyright>
+
+  <description summary="secure session locking with arbitrary graphics">
+    This protocol allows for a privileged Wayland client to lock the session
+    and display arbitrary graphics while the session is locked.
+
+    The compositor may choose to restrict this protocol to a special client
+    launched by the compositor itself or expose it to all privileged clients,
+    this is compositor policy.
+
+    The client is responsible for performing authentication and informing the
+    compositor when the session should be unlocked. If the client dies while
+    the session is locked the session remains locked, possibly permanently
+    depending on compositor policy.
+
+    The key words "must", "must not", "required", "shall", "shall not",
+    "should", "should not", "recommended",  "may", and "optional" in this
+    document are to be interpreted as described in IETF RFC 2119.
+
+    Warning! The protocol described in this file is currently in the
+    testing phase. Backward compatible changes may be added together with
+    the corresponding interface version bump. Backward incompatible changes
+    can only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="ext_session_lock_manager_v1" version="1">
+    <description summary="used to lock the session">
+      This interface is used to request that the session be locked.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the session lock manager object">
+        This informs the compositor that the session lock manager object will
+        no longer be used. Existing objects created through this interface
+        remain valid.
+      </description>
+    </request>
+
+    <request name="lock">
+      <description summary="attempt to lock the session">
+        This request creates a session lock and asks the compositor to lock the
+        session. The compositor will send either the ext_session_lock_v1.locked
+        or ext_session_lock_v1.finished event on the created object in
+        response to this request.
+      </description>
+      <arg name="id" type="new_id" interface="ext_session_lock_v1"/>
+    </request>
+  </interface>
+
+  <interface name="ext_session_lock_v1" version="1">
+    <description summary="manage lock state and create lock surfaces">
+      In response to the creation of this object the compositor must send
+      either the locked or finished event.
+
+      The locked event indicates that the session is locked. This means
+      that the compositor must stop rendering and providing input to normal
+      clients. Instead the compositor must blank all outputs with an opaque
+      color such that their normal content is fully hidden.
+
+      The only surfaces that should be rendered while the session is locked
+      are the lock surfaces created through this interface and optionally,
+      at the compositor's discretion, special privileged surfaces such as
+      input methods or portions of desktop shell UIs.
+
+      The locked event must not be sent until a new "locked" frame (either
+      from a session lock surface or the compositor blanking the output) has
+      been presented on all outputs and no security sensitive normal/unlocked
+      content is possibly visible.
+
+      The finished event should be sent immediately on creation of this
+      object if the compositor decides that the locked event will not be sent.
+
+      The compositor may wait for the client to create and render session lock
+      surfaces before sending the locked event to avoid displaying intermediate
+      blank frames. However, it must impose a reasonable time limit if
+      waiting and send the locked event as soon as the hard requirements
+      described above can be met if the time limit expires. Clients should
+      immediately create lock surfaces for all outputs on creation of this
+      object to make this possible.
+
+      This behavior of the locked event is required in order to prevent
+      possible race conditions with clients that wish to suspend the system
+      or similar after locking the session. Without these semantics, clients
+      triggering a suspend after receiving the locked event would race with
+      the first "locked" frame being presented and normal/unlocked frames
+      might be briefly visible as the system is resumed if the suspend
+      operation wins the race.
+
+      If the client dies while the session is locked, the compositor must not
+      unlock the session in response. It is acceptable for the session to be
+      permanently locked if this happens. The compositor may choose to continue
+      to display the lock surfaces the client had mapped before it died or
+      alternatively fall back to a solid color, this is compositor policy.
+
+      Compositors may also allow a secure way to recover the session, the
+      details of this are compositor policy. Compositors may allow a new
+      client to create a ext_session_lock_v1 object and take responsibility
+      for unlocking the session, they may even start a new lock client
+      instance automatically.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_destroy" value="0"
+        summary="attempted to destroy session lock while locked"/>
+      <entry name="invalid_unlock" value="1"
+        summary="unlock requested but locked event was never sent"/>
+      <entry name="role" value="2"
+        summary="given wl_surface already has a role"/>
+      <entry name="duplicate_output" value="3"
+        summary="given output already has a lock surface"/>
+      <entry name="already_constructed" value="4"
+        summary="given wl_surface has a buffer attached or committed"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the session lock">
+        This informs the compositor that the lock object will no longer be
+        used. Existing objects created through this interface remain valid.
+
+        After this request is made, lock surfaces created through this object
+        should be destroyed by the client as they will no longer be used by
+        the compositor.
+
+        It is a protocol error to make this request if the locked event was
+        sent, the unlock_and_destroy request must be used instead.
+      </description>
+    </request>
+
+    <event name="locked">
+      <description summary="session successfully locked">
+        This client is now responsible for displaying graphics while the
+        session is locked and deciding when to unlock the session.
+
+        The locked event must not be sent until a new "locked" frame has been
+        presented on all outputs and no security sensitive normal/unlocked
+        content is possibly visible.
+
+        If this event is sent, making the destroy request is a protocol error,
+        the lock object must be destroyed using the unlock_and_destroy request.
+      </description>
+    </event>
+
+    <event name="finished">
+      <description summary="the session lock object should be destroyed">
+        The compositor has decided that the session lock should be destroyed
+        as it will no longer be used by the compositor. Exactly when this
+        event is sent is compositor policy, but it must never be sent more
+        than once for a given session lock object.
+
+        This might be sent because there is already another ext_session_lock_v1
+        object held by a client, or the compositor has decided to deny the
+        request to lock the session for some other reason. This might also
+        be sent because the compositor implements some alternative, secure
+        way to authenticate and unlock the session.
+
+        The finished event should be sent immediately on creation of this
+        object if the compositor decides that the locked event will not
+        be sent.
+
+        If the locked event is sent on creation of this object the finished
+        event may still be sent at some later time in this object's
+        lifetime. This is compositor policy.
+
+        Upon receiving this event, the client should make either the destroy
+        request or the unlock_and_destroy request, depending on whether or
+        not the locked event was received on this object.
+      </description>
+    </event>
+
+    <request name="get_lock_surface">
+      <description summary="create a lock surface for a given output">
+        The client is expected to create lock surfaces for all outputs
+        currently present and any new outputs as they are advertised. These
+        won't be displayed by the compositor unless the lock is successful
+        and the locked event is sent.
+
+        Providing a wl_surface which already has a role or already has a buffer
+        attached or committed is a protocol error, as is attaching/committing
+        a buffer before the first ext_session_lock_surface_v1.configure event.
+
+        Attempting to create more than one lock surface for a given output
+        is a duplicate_output protocol error.
+      </description>
+      <arg name="id" type="new_id" interface="ext_session_lock_surface_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="output" type="object" interface="wl_output"/>
+    </request>
+
+    <request name="unlock_and_destroy" type="destructor">
+      <description summary="unlock the session, destroying the object">
+        This request indicates that the session should be unlocked, for
+        example because the user has entered their password and it has been
+        verified by the client.
+
+        This request also informs the compositor that the lock object will
+        no longer be used and should be destroyed. Existing objects created
+        through this interface remain valid.
+
+        After this request is made, lock surfaces created through this object
+        should be destroyed by the client as they will no longer be used by
+        the compositor.
+
+        It is a protocol error to make this request if the locked event has
+        not been sent. In that case, the lock object must be destroyed using
+        the destroy request.
+
+        Note that a correct client that wishes to exit directly after unlocking
+        the session must use the wl_display.sync request to ensure the server
+        receives and processes the unlock_and_destroy request. Otherwise
+        there is no guarantee that the server has unlocked the session due
+        to the asynchronous nature of the Wayland protocol. For example,
+        the server might terminate the client with a protocol error before
+        it processes the unlock_and_destroy request.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_session_lock_surface_v1" version="1">
+    <description summary="a surface displayed while the session is locked">
+      The client may use lock surfaces to display a screensaver, render a
+      dialog to enter a password and unlock the session, or however else it
+      sees fit.
+
+      On binding this interface the compositor will immediately send the
+      first configure event. After making the ack_configure request in
+      response to this event the client should attach and commit the first
+      buffer. Committing the surface before acking the first configure is a
+      protocol error. Committing the surface with a null buffer at any time
+      is a protocol error.
+
+      The compositor is free to handle keyboard/pointer focus for lock
+      surfaces however it chooses. A reasonable way to do this would be to
+      give the first lock surface created keyboard focus and change keyboard
+      focus if the user clicks on other surfaces.
+    </description>
+
+    <enum name="error">
+      <entry name="commit_before_first_ack" value="0"
+        summary="surface committed before first ack_configure request"/>
+      <entry name="null_buffer" value="1"
+        summary="surface committed with a null buffer"/>
+      <entry name="dimensions_mismatch" value="2"
+        summary="failed to match ack'd width/height"/>
+      <entry name="invalid_serial" value="3"
+        summary="serial provided in ack_configure is invalid"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the lock surface object">
+        This informs the compositor that the lock surface object will no
+        longer be used.
+
+        It is recommended for a lock client to destroy lock surfaces if
+        their corresponding wl_output global is removed.
+
+        If a lock surface on an active output is destroyed before the
+        ext_session_lock_v1.unlock_and_destroy event is sent, the compositor
+        must fall back to rendering a solid color.
+      </description>
+    </request>
+
+    <request name="ack_configure">
+      <description summary="ack a configure event">
+        When a configure event is received, if a client commits the surface
+        in response to the configure event, then the client must make an
+        ack_configure request sometime before the commit request, passing
+        along the serial of the configure event.
+
+        If the client receives multiple configure events before it can
+        respond to one, it only has to ack the last configure event.
+
+        A client is not required to commit immediately after sending an
+        ack_configure request - it may even ack_configure several times
+        before its next surface commit.
+
+        A client may send multiple ack_configure requests before committing,
+        but only the last request sent before a commit indicates which
+        configure event the client really is responding to.
+
+        Sending an ack_configure request consumes the configure event
+        referenced by the given serial, as well as all older configure events
+        sent on this object.
+
+        It is a protocol error to issue multiple ack_configure requests
+        referencing the same configure event or to issue an ack_configure
+        request referencing a configure event older than the last configure
+        event acked for a given lock surface.
+      </description>
+      <arg name="serial" type="uint" summary="serial from the configure event"/>
+    </request>
+
+    <event name="configure">
+      <description summary="the client should resize its surface">
+        This event is sent once on binding the interface and may be sent again
+        at the compositor's discretion, for example if output geometry changes.
+
+        The width and height are in surface-local coordinates and are exact
+        requirements. Failing to match these surface dimensions in the next
+        commit after acking a configure is a protocol error.
+      </description>
+      <arg name="serial" type="uint" summary="serial for use in ack_configure"/>
+      <arg name="width" type="uint"/>
+      <arg name="height" type="uint"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/ext-transient-seat/README b/subprojects/wayland-protocols/staging/ext-transient-seat/README
new file mode 100644
index 0000000000000000000000000000000000000000..acc1bb6e72a934c2fe387356268ba08c237934c7
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-transient-seat/README
@@ -0,0 +1,4 @@
+Transient Seat
+
+Maintainers:
+Andri Yngvason <andri@yngvason.is> (@andri)
diff --git a/subprojects/wayland-protocols/staging/ext-transient-seat/ext-transient-seat-v1.xml b/subprojects/wayland-protocols/staging/ext-transient-seat/ext-transient-seat-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..579d8dbf1bc2df449e370b1764b333c937689907
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-transient-seat/ext-transient-seat-v1.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_transient_seat_v1">
+  <copyright>
+    Copyright © 2020 - 2023 Andri Yngvason
+
+    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.
+  </copyright>
+
+  <description summary="protocol for creating temporary seats">
+    The transient seat protocol can be used by privileged clients to create
+    independent seats that will be removed from the compositor when the client
+    destroys its transient seat.
+
+    This protocol is intended for use with virtual input protocols such as
+    "virtual_keyboard_unstable_v1" or "wlr_virtual_pointer_unstable_v1", both
+    of which allow the user to select a seat.
+
+    The "wl_seat" global created by this protocol does not generate input events
+    on its own, or have any capabilities except those assigned to it by other
+    protocol extensions, such as the ones mentioned above.
+
+    For example, a remote desktop server can create a seat with virtual inputs
+    for each remote user by following these steps for each new connection:
+     * Create a transient seat
+     * Wait for the transient seat to be created
+     * Locate a "wl_seat" global with a matching name
+     * Create virtual inputs using the resulting "wl_seat" global
+  </description>
+
+  <interface name="ext_transient_seat_manager_v1" version="1">
+    <description summary="transient seat manager">
+      The transient seat manager creates short-lived seats.
+    </description>
+
+    <request name="create">
+      <description summary="create a transient seat">
+        Create a new seat that is removed when the client side transient seat
+        object is destroyed.
+
+        The actual seat may be removed sooner, in which case the transient seat
+        object shall become inert.
+      </description>
+      <arg name="seat" type="new_id" interface="ext_transient_seat_v1"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the manager">
+        Destroy the manager.
+
+        All objects created by the manager will remain valid until they are
+        destroyed themselves.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_transient_seat_v1" version="1">
+    <description summary="transient seat handle">
+      When the transient seat handle is destroyed, the seat itself will also be
+      destroyed.
+    </description>
+
+    <event name="ready">
+      <description summary="transient seat is ready">
+        This event advertises the global name for the wl_seat to be used with
+        wl_registry_bind.
+
+        It is sent exactly once, immediately after the transient seat is created
+        and the new "wl_seat" global is advertised, if and only if the creation
+        of the transient seat was allowed.
+      </description>
+      <arg name="global_name" type="uint"/>
+    </event>
+
+    <event name="denied">
+      <description summary="transient seat creation denied">
+        The event informs the client that the compositor denied its request to
+        create a transient seat.
+
+        It is sent exactly once, immediately after the transient seat object is
+        created, if and only if the creation of the transient seat was denied.
+
+        After receiving this event, the client should destroy the object.
+      </description>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy transient seat">
+        When the transient seat object is destroyed by the client, the
+        associated seat created by the compositor is also destroyed.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/ext-workspace/README b/subprojects/wayland-protocols/staging/ext-workspace/README
new file mode 100644
index 0000000000000000000000000000000000000000..7d5f2a347f57995272b175219e409509f7d02397
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-workspace/README
@@ -0,0 +1,5 @@
+Workspace protocol
+
+Maintainers:
+Ilia Bozhinov <ammen99@gmail.com>
+Victoria Brekenfeld <wayland@drakulix.de>
\ No newline at end of file
diff --git a/subprojects/wayland-protocols/staging/ext-workspace/ext-workspace-v1.xml b/subprojects/wayland-protocols/staging/ext-workspace/ext-workspace-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b19c7701961d92f239cd20c50dfad421e0383772
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/ext-workspace/ext-workspace-v1.xml
@@ -0,0 +1,422 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="ext_workspace_v1">
+  <copyright>
+    Copyright © 2019 Christopher Billington
+    Copyright © 2020 Ilia Bozhinov
+    Copyright © 2022 Victoria Brekenfeld
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+  <interface name="ext_workspace_manager_v1" version="1">
+    <description summary="list and control workspaces">
+      Workspaces, also called virtual desktops, are groups of surfaces. A
+      compositor with a concept of workspaces may only show some such groups of
+      surfaces (those of 'active' workspaces) at a time. 'Activating' a
+      workspace is a request for the compositor to display that workspace's
+      surfaces as normal, whereas the compositor may hide or otherwise
+      de-emphasise surfaces that are associated only with 'inactive' workspaces.
+      Workspaces are grouped by which sets of outputs they correspond to, and
+      may contain surfaces only from those outputs. In this way, it is possible
+      for each output to have its own set of workspaces, or for all outputs (or
+      any other arbitrary grouping) to share workspaces. Compositors may
+      optionally conceptually arrange each group of workspaces in an
+      N-dimensional grid.
+
+      The purpose of this protocol is to enable the creation of taskbars and
+      docks by providing them with a list of workspaces and their properties,
+      and allowing them to activate and deactivate workspaces.
+
+      After a client binds the ext_workspace_manager_v1, each workspace will be
+      sent via the workspace event.
+    </description>
+
+    <event name="workspace_group">
+      <description summary="a workspace group has been created">
+        This event is emitted whenever a new workspace group has been created.
+
+        All initial details of the workspace group (outputs) will be
+        sent immediately after this event via the corresponding events in
+        ext_workspace_group_handle_v1 and ext_workspace_handle_v1.
+      </description>
+      <arg name="workspace_group" type="new_id" interface="ext_workspace_group_handle_v1"/>
+    </event>
+
+    <event name="workspace">
+      <description summary="workspace has been created">
+        This event is emitted whenever a new workspace has been created.
+
+        All initial details of the workspace (name, coordinates, state) will
+        be sent immediately after this event via the corresponding events in
+        ext_workspace_handle_v1.
+
+        Workspaces start off unassigned to any workspace group.
+      </description>
+      <arg name="workspace" type="new_id" interface="ext_workspace_handle_v1"/>
+    </event>
+  
+    <request name="commit">
+      <description summary="all requests about the workspaces have been sent">
+        The client must send this request after it has finished sending other
+        requests. The compositor must process a series of requests preceding a
+        commit request atomically.
+
+        This allows changes to the workspace properties to be seen as atomic,
+        even if they happen via multiple events, and even if they involve
+        multiple ext_workspace_handle_v1 objects, for example, deactivating one
+        workspace and activating another.
+      </description>
+    </request>
+
+    <event name="done">
+      <description summary="all information about the workspaces and workspace groups has been sent">
+        This event is sent after all changes in all workspaces and workspace groups have been
+        sent.
+
+        This allows changes to one or more ext_workspace_group_handle_v1
+        properties and ext_workspace_handle_v1 properties
+        to be seen as atomic, even if they happen via multiple events.
+        In particular, an output moving from one workspace group to
+        another sends an output_enter event and an output_leave event to the two
+        ext_workspace_group_handle_v1 objects in question. The compositor sends
+        the done event only after updating the output information in both
+        workspace groups.
+      </description>
+    </event>
+
+    <event name="finished" type="destructor">
+      <description summary="the compositor has finished with the workspace_manager">
+        This event indicates that the compositor is done sending events to the
+        ext_workspace_manager_v1. The server will destroy the object
+        immediately after sending this request.
+      </description>
+    </event>
+
+    <request name="stop">
+      <description summary="stop sending events">
+        Indicates the client no longer wishes to receive events for new
+        workspace groups. However the compositor may emit further workspace
+        events, until the finished event is emitted. The compositor is expected
+        to send the finished event eventually once the stop request has been processed.
+
+        The client must not send any requests after this one, doing so will raise a wl_display
+        invalid_object error.
+      </description>
+    </request>
+
+  </interface>
+
+  <interface name="ext_workspace_group_handle_v1" version="1">
+    <description summary="a workspace group assigned to a set of outputs">
+      A ext_workspace_group_handle_v1 object represents a workspace group
+      that is assigned a set of outputs and contains a number of workspaces.
+
+      The set of outputs assigned to the workspace group is conveyed to the client via
+      output_enter and output_leave events, and its workspaces are conveyed with
+      workspace events.
+
+      For example, a compositor which has a set of workspaces for each output may
+      advertise a workspace group (and its workspaces) per output, whereas a compositor
+      where a workspace spans all outputs may advertise a single workspace group for all
+      outputs.
+    </description>
+
+    <enum name="group_capabilities" bitfield="true">
+      <entry name="create_workspace" value="1" summary="create_workspace request is available"/>
+    </enum>
+
+    <event name="capabilities">
+      <description summary="compositor capabilities">
+        This event advertises the capabilities supported by the compositor. If
+        a capability isn't supported, clients should hide or disable the UI
+        elements that expose this functionality. For instance, if the
+        compositor doesn't advertise support for creating workspaces, a button
+        triggering the create_workspace request should not be displayed.
+
+        The compositor will ignore requests it doesn't support. For instance,
+        a compositor which doesn't advertise support for creating workspaces will ignore
+        create_workspace requests.
+
+        Compositors must send this event once after creation of an
+        ext_workspace_group_handle_v1. When the capabilities change, compositors
+        must send this event again.
+      </description>
+      <arg name="capabilities" type="uint" summary="capabilities" enum="group_capabilities"/>
+    </event>
+
+    <event name="output_enter">
+      <description summary="output assigned to workspace group">
+        This event is emitted whenever an output is assigned to the workspace
+        group or a new `wl_output` object is bound by the client, which was already
+        assigned to this workspace_group.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+    </event>
+
+    <event name="output_leave">
+      <description summary="output removed from workspace group">
+        This event is emitted whenever an output is removed from the workspace
+        group.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+    </event>
+
+    <event name="workspace_enter">
+      <description summary="workspace added to workspace group">
+        This event is emitted whenever a workspace is assigned to this group.
+        A workspace may only ever be assigned to a single group at a single point
+        in time, but can be re-assigned during it's lifetime.
+      </description>
+      <arg name="workspace" type="object" interface="ext_workspace_handle_v1"/>
+    </event>
+
+    <event name="workspace_leave">
+      <description summary="workspace removed from workspace group">
+        This event is emitted whenever a workspace is removed from this group.
+      </description>
+      <arg name="workspace" type="object" interface="ext_workspace_handle_v1"/>
+    </event>
+
+    <event name="removed">
+      <description summary="this workspace group has been removed">
+        This event is send when the group associated with the ext_workspace_group_handle_v1
+        has been removed. After sending this request the compositor will immediately consider
+        the object inert. Any requests will be ignored except the destroy request.
+        It is guaranteed there won't be any more events referencing this
+        ext_workspace_group_handle_v1.
+
+        The compositor must remove all workspaces belonging to a workspace group
+        via a workspace_leave event before removing the workspace group.
+      </description>
+    </event>
+
+    <request name="create_workspace">
+      <description summary="create a new workspace">
+        Request that the compositor create a new workspace with the given name
+        and assign it to this group.
+
+        There is no guarantee that the compositor will create a new workspace,
+        or that the created workspace will have the provided name.
+      </description>
+      <arg name="workspace" type="string"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the ext_workspace_group_handle_v1 object">
+        Destroys the ext_workspace_group_handle_v1 object.
+
+        This request should be send either when the client does not want to
+        use the workspace group object any more or after the removed event to finalize
+        the destruction of the object.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="ext_workspace_handle_v1" version="1">
+    <description summary="a workspace handing a group of surfaces">
+      A ext_workspace_handle_v1 object represents a workspace that handles a
+      group of surfaces.
+
+      Each workspace has:
+      - a name, conveyed to the client with the name event
+      - potentially an id conveyed with the id event
+      - a list of states, conveyed to the client with the state event
+      - and optionally a set of coordinates, conveyed to the client with the
+      coordinates event
+      
+      The client may request that the compositor activate or deactivate the workspace.
+
+      Each workspace can belong to only a single workspace group.
+      Depepending on the compositor policy, there might be workspaces with
+      the same name in different workspace groups, but these workspaces are still
+      separate (e.g. one of them might be active while the other is not).
+    </description>
+
+    <event name="id">
+      <description summary="workspace id">
+        If this event is emitted, it will be send immediately after the
+        ext_workspace_handle_v1 is created or when an id is assigned to
+        a workspace (at most once during it's lifetime).
+
+        An id will never change during the lifetime of the `ext_workspace_handle_v1`
+        and is guaranteed to be unique during it's lifetime.
+
+        Ids are not human-readable and shouldn't be displayed, use `name` for that purpose.
+
+        Compositors are expected to only send ids for workspaces likely stable across multiple
+        sessions and can be used by clients to store preferences for workspaces. Workspaces without
+        ids should be considered temporary and any data associated with them should be deleted once
+        the respective object is lost.
+      </description>
+      <arg name="id" type="string"/>
+    </event>
+
+    <event name="name">
+      <description summary="workspace name changed">
+        This event is emitted immediately after the ext_workspace_handle_v1 is
+        created and whenever the name of the workspace changes.
+
+        A name is meant to be human-readable and can be displayed to a user.
+        Unlike the id it is neither stable nor unique.
+      </description>
+      <arg name="name" type="string"/>
+    </event>
+
+    <event name="coordinates">
+      <description summary="workspace coordinates changed">
+        This event is used to organize workspaces into an N-dimensional grid
+        within a workspace group, and if supported, is emitted immediately after
+        the ext_workspace_handle_v1 is created and whenever the coordinates of
+        the workspace change. Compositors may not send this event if they do not
+        conceptually arrange workspaces in this way. If compositors simply
+        number workspaces, without any geometric interpretation, they may send
+        1D coordinates, which clients should not interpret as implying any
+        geometry. Sending an empty array means that the compositor no longer
+        orders the workspace geometrically.
+
+        Coordinates have an arbitrary number of dimensions N with an uint32
+        position along each dimension. By convention if N > 1, the first
+        dimension is X, the second Y, the third Z, and so on. The compositor may
+        chose to utilize these events for a more novel workspace layout
+        convention, however. No guarantee is made about the grid being filled or
+        bounded; there may be a workspace at coordinate 1 and another at
+        coordinate 1000 and none in between. Within a workspace group, however,
+        workspaces must have unique coordinates of equal dimensionality.
+      </description>
+      <arg name="coordinates" type="array"/>
+    </event>
+
+    <enum name="state" bitfield="true">
+      <description summary="types of states on the workspace">
+        The different states that a workspace can have.
+      </description>
+
+      <entry name="active" value="1" summary="the workspace is active"/>
+      <entry name="urgent" value="2" summary="the workspace requests attention"/>
+      <entry name="hidden" value="4">
+        <description summary="the workspace is not visible">
+          The workspace is not visible in its workspace group, and clients
+          attempting to visualize the compositor workspace state should not
+          display such workspaces.
+        </description>
+      </entry>
+    </enum>
+
+    <event name="state">
+      <description summary="the state of the workspace changed">
+        This event is emitted immediately after the ext_workspace_handle_v1 is
+        created and each time the workspace state changes, either because of a
+        compositor action or because of a request in this protocol.
+
+        Missing states convey the opposite meaning, e.g. an unset active bit
+        means the workspace is currently inactive.
+      </description>
+      <arg name="state" type="uint" enum="state"/>
+    </event>
+
+    <enum name="workspace_capabilities" bitfield="true">
+      <entry name="activate" value="1" summary="activate request is available"/>
+      <entry name="deactivate" value="2" summary="deactivate request is available"/>
+      <entry name="remove" value="4" summary="remove request is available"/>
+      <entry name="assign" value="8" summary="assign request is available"/>
+    </enum>
+
+    <event name="capabilities">
+      <description summary="compositor capabilities">
+        This event advertises the capabilities supported by the compositor. If
+        a capability isn't supported, clients should hide or disable the UI
+        elements that expose this functionality. For instance, if the
+        compositor doesn't advertise support for removing workspaces, a button
+        triggering the remove request should not be displayed.
+
+        The compositor will ignore requests it doesn't support. For instance,
+        a compositor which doesn't advertise support for remove will ignore
+        remove requests.
+
+        Compositors must send this event once after creation of an
+        ext_workspace_handle_v1 . When the capabilities change, compositors
+        must send this event again.
+      </description>
+      <arg name="capabilities" type="uint" summary="capabilities" enum="workspace_capabilities"/>
+    </event>
+
+    <event name="removed">
+      <description summary="this workspace has been removed">
+        This event is send when the workspace associated with the ext_workspace_handle_v1
+        has been removed. After sending this request, the compositor will immediately consider
+        the object inert. Any requests will be ignored except the destroy request.
+
+        It is guaranteed there won't be any more events referencing this
+        ext_workspace_handle_v1.
+
+        The compositor must only remove a workspaces not currently belonging to any
+        workspace_group.
+      </description>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the ext_workspace_handle_v1 object">
+        Destroys the ext_workspace_handle_v1 object.
+
+        This request should be made either when the client does not want to
+        use the workspace object any more or after the remove event to finalize
+        the destruction of the object.
+      </description>
+    </request>
+
+    <request name="activate">
+      <description summary="activate the workspace">
+        Request that this workspace be activated.
+
+        There is no guarantee the workspace will be actually activated, and
+        behaviour may be compositor-dependent. For example, activating a
+        workspace may or may not deactivate all other workspaces in the same
+        group.
+      </description>
+    </request>
+
+    <request name="deactivate">
+      <description summary="deactivate the workspace">
+        Request that this workspace be deactivated.
+
+        There is no guarantee the workspace will be actually deactivated.
+      </description>
+    </request>
+
+    <request name="assign">
+      <description summary="assign workspace to group">
+        Requests that this workspace is assigned to the given workspace group.
+
+        There is no guarantee the workspace will be assigned.
+      </description>
+      <arg name="workspace_group" type="object" interface="ext_workspace_group_handle_v1"/>
+    </request>
+
+    <request name="remove">
+      <description summary="remove the workspace">
+        Request that this workspace be removed.
+
+        There is no guarantee the workspace will be actually removed.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/fifo/README b/subprojects/wayland-protocols/staging/fifo/README
new file mode 100644
index 0000000000000000000000000000000000000000..01ac61f3da0815af480fb718526d5e744f227092
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/fifo/README
@@ -0,0 +1,4 @@
+Fifo Protocol
+
+Maintainers:
+Derek Foreman <derek.foreman@collabora.com> (@derekf)
diff --git a/subprojects/wayland-protocols/staging/fifo/fifo-v1.xml b/subprojects/wayland-protocols/staging/fifo/fifo-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3255929ad0d7f0fae233abe2b2d835e3bdbde70f
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/fifo/fifo-v1.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="fifo_v1">
+  <copyright>
+    Copyright © 2023 Valve Corporation
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="wp_fifo_manager_v1" version="1">
+    <description summary="protocol for fifo constraints">
+      When a Wayland compositor considers applying a content update,
+      it must ensure all the update's readiness constraints (fences, etc)
+      are met.
+
+      This protocol provides a way to use the completion of a display refresh
+      cycle as an additional readiness constraint.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <enum name="error">
+      <description summary="fatal presentation error">
+        These fatal protocol errors may be emitted in response to
+        illegal requests.
+      </description>
+      <entry name="already_exists" value="0"
+             summary="fifo manager already exists for surface"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the manager interface">
+        Informs the server that the client will no longer be using
+        this protocol object. Existing objects created by this object
+        are not affected.
+      </description>
+    </request>
+
+    <request name="get_fifo">
+      <description summary="request fifo interface for surface">
+        Establish a fifo object for a surface that may be used to add
+        display refresh constraints to content updates.
+
+        Only one such object may exist for a surface and attempting
+        to create more than one will result in an already_exists
+        protocol error. If a surface is acted on by multiple software
+        components, general best practice is that only the component
+        performing wl_surface.attach operations should use this protocol.
+      </description>
+      <arg name="id" type="new_id" interface="wp_fifo_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_fifo_v1" version="1">
+    <description summary="fifo interface">
+      A fifo object for a surface that may be used to add
+      display refresh constraints to content updates.
+    </description>
+
+    <enum name="error">
+      <description summary="fatal error">
+        These fatal protocol errors may be emitted in response to
+        illegal requests.
+      </description>
+      <entry name="surface_destroyed" value="0"
+             summary="the associated surface no longer exists"/>
+    </enum>
+
+    <request name="set_barrier">
+      <description summary="sets the start point for a fifo constraint">
+        When the content update containing the "set_barrier" is applied,
+        it sets a "fifo_barrier" condition on the surface associated with
+        the fifo object. The condition is cleared immediately after the
+        following latching deadline for non-tearing presentation.
+
+        The compositor may clear the condition early if it must do so to
+        ensure client forward progress assumptions.
+
+        To wait for this condition to clear, use the "wait_barrier" request.
+
+        "set_barrier" is double-buffered state, see wl_surface.commit.
+
+        Requesting set_barrier after the fifo object's surface is
+        destroyed will generate a "surface_destroyed" error.
+      </description>
+    </request>
+
+    <request name="wait_barrier">
+      <description summary="adds a fifo constraint to a content update">
+        Indicate that this content update is not ready while a
+        "fifo_barrier" condition is present on the surface.
+
+        This means that when the content update containing "set_barrier"
+        was made active at a latching deadline, it will be active for
+        at least one refresh cycle. A content update which is allowed to
+        tear might become active after a latching deadline if no content
+        update became active at the deadline.
+
+        The constraint must be ignored if the surface is a subsurface in
+        synchronized mode. If the surface is not being updated by the
+        compositor (off-screen, occluded) the compositor may ignore the
+        constraint. Clients must use an additional mechanism such as
+        frame callbacks or timestamps to ensure throttling occurs under
+        all conditions.
+
+        "wait_barrier" is double-buffered state, see wl_surface.commit.
+
+        Requesting "wait_barrier" after the fifo object's surface is
+        destroyed will generate a "surface_destroyed" error.
+      </description>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the fifo interface">
+        Informs the server that the client will no longer be using
+        this protocol object.
+
+        Surface state changes previously made by this protocol are
+        unaffected by this object's destruction.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/fractional-scale/README b/subprojects/wayland-protocols/staging/fractional-scale/README
new file mode 100644
index 0000000000000000000000000000000000000000..3b8500cb23f7d0cefbc817ddb4cf0dacfb940012
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/fractional-scale/README
@@ -0,0 +1,4 @@
+wp fractional scale protocol
+
+Maintainers:
+Kenny Levinsen <kl@kl.wtf> (@kennylevinsen)
diff --git a/subprojects/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml b/subprojects/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..350bfc01eafa03e0b8a9cebbb6c59c398201ba8c
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/fractional-scale/fractional-scale-v1.xml
@@ -0,0 +1,102 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="fractional_scale_v1">
+  <copyright>
+    Copyright © 2022 Kenny Levinsen
+
+    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.
+  </copyright>
+
+  <description summary="Protocol for requesting fractional surface scales">
+    This protocol allows a compositor to suggest for surfaces to render at
+    fractional scales.
+
+    A client can submit scaled content by utilizing wp_viewport. This is done by
+    creating a wp_viewport object for the surface and setting the destination
+    rectangle to the surface size before the scale factor is applied.
+
+    The buffer size is calculated by multiplying the surface size by the
+    intended scale.
+
+    The wl_surface buffer scale should remain set to 1.
+
+    If a surface has a surface-local size of 100 px by 50 px and wishes to
+    submit buffers with a scale of 1.5, then a buffer of 150px by 75 px should
+    be used and the wp_viewport destination rectangle should be 100 px by 50 px.
+
+    For toplevel surfaces, the size is rounded halfway away from zero. The
+    rounding algorithm for subsurface position and size is not defined.
+  </description>
+
+  <interface name="wp_fractional_scale_manager_v1" version="1">
+    <description summary="fractional surface scale information">
+      A global interface for requesting surfaces to use fractional scales.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind the fractional surface scale interface">
+        Informs the server that the client will not be using this protocol
+        object anymore. This does not affect any other objects,
+        wp_fractional_scale_v1 objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="fractional_scale_exists" value="0"
+        summary="the surface already has a fractional_scale object associated"/>
+    </enum>
+
+    <request name="get_fractional_scale">
+      <description summary="extend surface interface for scale information">
+        Create an add-on object for the the wl_surface to let the compositor
+        request fractional scales. If the given wl_surface already has a
+        wp_fractional_scale_v1 object associated, the fractional_scale_exists
+        protocol error is raised.
+      </description>
+      <arg name="id" type="new_id" interface="wp_fractional_scale_v1"
+           summary="the new surface scale info interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_fractional_scale_v1" version="1">
+    <description summary="fractional scale interface to a wl_surface">
+      An additional interface to a wl_surface object which allows the compositor
+      to inform the client of the preferred scale.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove surface scale information for surface">
+        Destroy the fractional scale object. When this object is destroyed,
+        preferred_scale events will no longer be sent.
+      </description>
+    </request>
+
+    <event name="preferred_scale">
+      <description summary="notify of new preferred scale">
+        Notification of a new preferred scale for this surface that the
+        compositor suggests that the client should use.
+
+        The sent scale is the numerator of a fraction with a denominator of 120.
+      </description>
+      <arg name="scale" type="uint" summary="the new preferred scale"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/linux-drm-syncobj/README b/subprojects/wayland-protocols/staging/linux-drm-syncobj/README
new file mode 100644
index 0000000000000000000000000000000000000000..25d6b93e7105296d7cd90a6c3a0bc9ee46ea2976
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/linux-drm-syncobj/README
@@ -0,0 +1,4 @@
+Linux DRM syncobj protocol
+
+Maintainers:
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml b/subprojects/wayland-protocols/staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2c491eaf43a767d65406cadd804963f1c3338648
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/linux-drm-syncobj/linux-drm-syncobj-v1.xml
@@ -0,0 +1,261 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="linux_drm_syncobj_v1">
+  <copyright>
+    Copyright 2016 The Chromium Authors.
+    Copyright 2017 Intel Corporation
+    Copyright 2018 Collabora, Ltd
+    Copyright 2021 Simon Ser
+
+    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.
+  </copyright>
+
+  <description summary="protocol for providing explicit synchronization">
+    This protocol allows clients to request explicit synchronization for
+    buffers. It is tied to the Linux DRM synchronization object framework.
+
+    Synchronization refers to co-ordination of pipelined operations performed
+    on buffers. Most GPU clients will schedule an asynchronous operation to
+    render to the buffer, then immediately send the buffer to the compositor
+    to be attached to a surface.
+
+    With implicit synchronization, ensuring that the rendering operation is
+    complete before the compositor displays the buffer is an implementation
+    detail handled by either the kernel or userspace graphics driver.
+
+    By contrast, with explicit synchronization, DRM synchronization object
+    timeline points mark when the asynchronous operations are complete. When
+    submitting a buffer, the client provides a timeline point which will be
+    waited on before the compositor accesses the buffer, and another timeline
+    point that the compositor will signal when it no longer needs to access the
+    buffer contents for the purposes of the surface commit.
+
+    Linux DRM synchronization objects are documented at:
+    https://dri.freedesktop.org/docs/drm/gpu/drm-mm.html#drm-sync-objects
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="wp_linux_drm_syncobj_manager_v1" version="1">
+    <description summary="global for providing explicit synchronization">
+      This global is a factory interface, allowing clients to request
+      explicit synchronization for buffers on a per-surface basis.
+
+      See wp_linux_drm_syncobj_surface_v1 for more information.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy explicit synchronization factory object">
+        Destroy this explicit synchronization factory object. Other objects
+        shall not be affected by this request.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="surface_exists" value="0"
+        summary="the surface already has a synchronization object associated"/>
+      <entry name="invalid_timeline" value="1"
+        summary="the timeline object could not be imported"/>
+    </enum>
+
+    <request name="get_surface">
+      <description summary="extend surface interface for explicit synchronization">
+        Instantiate an interface extension for the given wl_surface to provide
+        explicit synchronization.
+
+        If the given wl_surface already has an explicit synchronization object
+        associated, the surface_exists protocol error is raised.
+
+        Graphics APIs, like EGL or Vulkan, that manage the buffer queue and
+        commits of a wl_surface themselves, are likely to be using this
+        extension internally. If a client is using such an API for a
+        wl_surface, it should not directly use this extension on that surface,
+        to avoid raising a surface_exists protocol error.
+      </description>
+      <arg name="id" type="new_id" interface="wp_linux_drm_syncobj_surface_v1"
+        summary="the new synchronization surface object id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+        summary="the surface"/>
+    </request>
+
+    <request name="import_timeline">
+      <description summary="import a DRM syncobj timeline">
+        Import a DRM synchronization object timeline.
+
+        If the FD cannot be imported, the invalid_timeline error is raised.
+      </description>
+      <arg name="id" type="new_id" interface="wp_linux_drm_syncobj_timeline_v1"/>
+      <arg name="fd" type="fd" summary="drm_syncobj file descriptor"/>
+    </request>
+  </interface>
+
+  <interface name="wp_linux_drm_syncobj_timeline_v1" version="1">
+    <description summary="synchronization object timeline">
+      This object represents an explicit synchronization object timeline
+      imported by the client to the compositor.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the timeline">
+        Destroy the synchronization object timeline. Other objects are not
+        affected by this request, in particular timeline points set by
+        set_acquire_point and set_release_point are not unset.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="wp_linux_drm_syncobj_surface_v1" version="1">
+    <description summary="per-surface explicit synchronization">
+      This object is an add-on interface for wl_surface to enable explicit
+      synchronization.
+
+      Each surface can be associated with only one object of this interface at
+      any time.
+
+      Explicit synchronization is guaranteed to be supported for buffers
+      created with any version of the linux-dmabuf protocol. Compositors are
+      free to support explicit synchronization for additional buffer types.
+      If at surface commit time the attached buffer does not support explicit
+      synchronization, an unsupported_buffer error is raised.
+
+      As long as the wp_linux_drm_syncobj_surface_v1 object is alive, the
+      compositor may ignore implicit synchronization for buffers attached and
+      committed to the wl_surface. The delivery of wl_buffer.release events
+      for buffers attached to the surface becomes undefined.
+
+      Clients must set both acquire and release points if and only if a
+      non-null buffer is attached in the same surface commit. See the
+      no_buffer, no_acquire_point and no_release_point protocol errors.
+
+      If at surface commit time the acquire and release DRM syncobj timelines
+      are identical, the acquire point value must be strictly less than the
+      release point value, or else the conflicting_points protocol error is
+      raised.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the surface synchronization object">
+        Destroy this surface synchronization object.
+
+        Any timeline point set by this object with set_acquire_point or
+        set_release_point since the last commit may be discarded by the
+        compositor. Any timeline point set by this object before the last
+        commit will not be affected.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="no_surface" value="1"
+        summary="the associated wl_surface was destroyed"/>
+      <entry name="unsupported_buffer" value="2"
+        summary="the buffer does not support explicit synchronization"/>
+      <entry name="no_buffer" value="3" summary="no buffer was attached"/>
+      <entry name="no_acquire_point" value="4"
+        summary="no acquire timeline point was set"/>
+      <entry name="no_release_point" value="5"
+        summary="no release timeline point was set"/>
+      <entry name="conflicting_points" value="6"
+        summary="acquire and release timeline points are in conflict"/>
+    </enum>
+
+    <request name="set_acquire_point">
+      <description summary="set the acquire timeline point">
+        Set the timeline point that must be signalled before the compositor may
+        sample from the buffer attached with wl_surface.attach.
+
+        The 64-bit unsigned value combined from point_hi and point_lo is the
+        point value.
+
+        The acquire point is double-buffered state, and will be applied on the
+        next wl_surface.commit request for the associated surface. Thus, it
+        applies only to the buffer that is attached to the surface at commit
+        time.
+
+        If an acquire point has already been attached during the same commit
+        cycle, the new point replaces the old one.
+
+        If the associated wl_surface was destroyed, a no_surface error is
+        raised.
+
+        If at surface commit time there is a pending acquire timeline point set
+        but no pending buffer attached, a no_buffer error is raised. If at
+        surface commit time there is a pending buffer attached but no pending
+        acquire timeline point set, the no_acquire_point protocol error is
+        raised.
+      </description>
+      <arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/>
+      <arg name="point_hi" type="uint" summary="high 32 bits of the point value"/>
+      <arg name="point_lo" type="uint" summary="low 32 bits of the point value"/>
+    </request>
+
+    <request name="set_release_point">
+      <description summary="set the release timeline point">
+        Set the timeline point that must be signalled by the compositor when it
+        has finished its usage of the buffer attached with wl_surface.attach
+        for the relevant commit.
+
+        Once the timeline point is signaled, and assuming the associated buffer
+        is not pending release from other wl_surface.commit requests, no
+        additional explicit or implicit synchronization with the compositor is
+        required to safely re-use the buffer.
+
+        Note that clients cannot rely on the release point being always
+        signaled after the acquire point: compositors may release buffers
+        without ever reading from them. In addition, the compositor may use
+        different presentation paths for different commits, which may have
+        different release behavior. As a result, the compositor may signal the
+        release points in a different order than the client committed them.
+
+        Because signaling a timeline point also signals every previous point,
+        it is generally not safe to use the same timeline object for the
+        release points of multiple buffers. The out-of-order signaling
+        described above may lead to a release point being signaled before the
+        compositor has finished reading. To avoid this, it is strongly
+        recommended that each buffer should use a separate timeline for its
+        release points.
+
+        The 64-bit unsigned value combined from point_hi and point_lo is the
+        point value.
+
+        The release point is double-buffered state, and will be applied on the
+        next wl_surface.commit request for the associated surface. Thus, it
+        applies only to the buffer that is attached to the surface at commit
+        time.
+
+        If a release point has already been attached during the same commit
+        cycle, the new point replaces the old one.
+
+        If the associated wl_surface was destroyed, a no_surface error is
+        raised.
+
+        If at surface commit time there is a pending release timeline point set
+        but no pending buffer attached, a no_buffer error is raised. If at
+        surface commit time there is a pending buffer attached but no pending
+        release timeline point set, the no_release_point protocol error is
+        raised.
+      </description>
+      <arg name="timeline" type="object" interface="wp_linux_drm_syncobj_timeline_v1"/>
+      <arg name="point_hi" type="uint" summary="high 32 bits of the point value"/>
+      <arg name="point_lo" type="uint" summary="low 32 bits of the point value"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/security-context/README b/subprojects/wayland-protocols/staging/security-context/README
new file mode 100644
index 0000000000000000000000000000000000000000..53124a1a927f817bad5af30f3d5da0f6284934c7
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/security-context/README
@@ -0,0 +1,4 @@
+security_context protocol
+
+Maintainers:
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/staging/security-context/engines.md b/subprojects/wayland-protocols/staging/security-context/engines.md
new file mode 100644
index 0000000000000000000000000000000000000000..a53b1ed89205b8501ee1e116e5ad17a5f566c2ca
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/security-context/engines.md
@@ -0,0 +1,18 @@
+# security-context-v1 engines
+
+This document describes how some specific engine implementations populate the
+metadata in security-context-v1 and provide further metadata with out of band
+mechanisms.
+
+## [Flatpak]
+
+* `sandbox_engine` is always set to `org.flatpak`.
+* `app_id` is the Flatpak application ID (in reverse-DNS style). It is always
+  set.
+* `instance_id` is the Flatpak instance ID of the running sandbox. It is always
+  set.
+
+More metadata is stored in `$XDG_RUNTIME_DIR/.flatpak/$instance_id/info`. This
+file will be readable when `wp_security_context_v1.commit` is called.
+
+[Flatpak]: https://flatpak.org/
diff --git a/subprojects/wayland-protocols/staging/security-context/security-context-v1.xml b/subprojects/wayland-protocols/staging/security-context/security-context-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a9ca9b8c49383357e71f96ed3b3fd0ca6c85ced8
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/security-context/security-context-v1.xml
@@ -0,0 +1,180 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="security_context_v1">
+  <copyright>
+    Copyright © 2021 Simon Ser
+
+    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.
+  </copyright>
+
+  <interface name="wp_security_context_manager_v1" version="1">
+    <description summary="client security context manager">
+      This interface allows a client to register a new Wayland connection to
+      the compositor and attach a security context to it.
+
+      This is intended to be used by sandboxes. Sandbox engines attach a
+      security context to all connections coming from inside the sandbox. The
+      compositor can then restrict the features that the sandboxed connections
+      can use.
+
+      Compositors should forbid nesting multiple security contexts by not
+      exposing wp_security_context_manager_v1 global to clients with a security
+      context attached, or by sending the nested protocol error. Nested
+      security contexts are dangerous because they can potentially allow
+      privilege escalation of a sandboxed client.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_listen_fd" value="1"
+        summary="listening socket FD is invalid"/>
+      <entry name="nested" value="2"
+        summary="nested security contexts are forbidden"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the manager object">
+        Destroy the manager. This doesn't destroy objects created with the
+        manager.
+      </description>
+    </request>
+
+    <request name="create_listener">
+      <description summary="create a new security context">
+        Creates a new security context with a socket listening FD.
+
+        The compositor will accept new client connections on listen_fd.
+        listen_fd must be ready to accept new connections when this request is
+        sent by the client. In other words, the client must call bind(2) and
+        listen(2) before sending the FD.
+
+        close_fd is a FD that will signal hangup when the compositor should stop
+        accepting new connections on listen_fd.
+
+        The compositor must continue to accept connections on listen_fd when
+        the Wayland client which created the security context disconnects.
+
+        After sending this request, closing listen_fd and close_fd remains the
+        only valid operation on them.
+      </description>
+      <arg name="id" type="new_id" interface="wp_security_context_v1"/>
+      <arg name="listen_fd" type="fd" summary="listening socket FD"/>
+      <arg name="close_fd" type="fd" summary="FD signaling when done"/>
+    </request>
+  </interface>
+
+  <interface name="wp_security_context_v1" version="1">
+    <description summary="client security context">
+      The security context allows a client to register a new client and attach
+      security context metadata to the connections.
+
+      When both are set, the combination of the application ID and the sandbox
+      engine must uniquely identify an application. The same application ID
+      will be used across instances (e.g. if the application is restarted, or
+      if the application is started multiple times).
+
+      When both are set, the combination of the instance ID and the sandbox
+      engine must uniquely identify a running instance of an application.
+    </description>
+
+    <enum name="error">
+      <entry name="already_used" value="1"
+        summary="security context has already been committed"/>
+      <entry name="already_set" value="2"
+        summary="metadata has already been set"/>
+      <entry name="invalid_metadata" value="3"
+        summary="metadata is invalid"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the security context object">
+        Destroy the security context object.
+      </description>
+    </request>
+
+    <request name="set_sandbox_engine">
+      <description summary="set the sandbox engine">
+        Attach a unique sandbox engine name to the security context. The name
+        should follow the reverse-DNS style (e.g. "org.flatpak").
+
+        A list of well-known engines is maintained at:
+        https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/engines.md
+
+        It is a protocol error to call this request twice. The already_set
+        error is sent in this case.
+      </description>
+      <arg name="name" type="string" summary="the sandbox engine name"/>
+    </request>
+
+    <request name="set_app_id">
+      <description summary="set the application ID">
+        Attach an application ID to the security context.
+
+        The application ID is an opaque, sandbox-specific identifier for an
+        application. See the well-known engines document for more details:
+        https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/engines.md
+
+        The compositor may use the application ID to group clients belonging to
+        the same security context application.
+
+        Whether this request is optional or not depends on the sandbox engine used.
+
+        It is a protocol error to call this request twice. The already_set
+        error is sent in this case.
+      </description>
+      <arg name="app_id" type="string" summary="the application ID"/>
+    </request>
+
+    <request name="set_instance_id">
+      <description summary="set the instance ID">
+        Attach an instance ID to the security context.
+
+        The instance ID is an opaque, sandbox-specific identifier for a running
+        instance of an application. See the well-known engines document for
+        more details:
+        https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/engines.md
+
+        Whether this request is optional or not depends on the sandbox engine used.
+
+        It is a protocol error to call this request twice. The already_set
+        error is sent in this case.
+      </description>
+      <arg name="instance_id" type="string" summary="the instance ID"/>
+    </request>
+
+    <request name="commit">
+      <description summary="register the security context">
+        Atomically register the new client and attach the security context
+        metadata.
+
+        If the provided metadata is inconsistent or does not match with out of
+        band metadata (see
+        https://gitlab.freedesktop.org/wayland/wayland-protocols/-/blob/main/staging/security-context/engines.md),
+        the invalid_metadata error may be sent eventually.
+
+        It's a protocol error to send any request other than "destroy" after
+        this request. In this case, the already_used error is sent.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/single-pixel-buffer/README b/subprojects/wayland-protocols/staging/single-pixel-buffer/README
new file mode 100644
index 0000000000000000000000000000000000000000..b3a1b8687289d12b4c39542c16e9b2786f42e347
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/single-pixel-buffer/README
@@ -0,0 +1,4 @@
+Single-pixel buffer protocol
+
+Maintainers:
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/staging/single-pixel-buffer/single-pixel-buffer-v1.xml b/subprojects/wayland-protocols/staging/single-pixel-buffer/single-pixel-buffer-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b157155781450cba2280e1fd7bc3137c5c2616f2
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/single-pixel-buffer/single-pixel-buffer-v1.xml
@@ -0,0 +1,69 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="single_pixel_buffer_v1">
+  <copyright>
+    Copyright © 2022 Simon Ser
+
+    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.
+  </copyright>
+
+  <description summary="single pixel buffer factory">
+    This protocol extension allows clients to create single-pixel buffers.
+
+    Compositors supporting this protocol extension should also support the
+    viewporter protocol extension. Clients may use viewporter to scale a
+    single-pixel buffer to a desired size.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="wp_single_pixel_buffer_manager_v1" version="1">
+    <description summary="global factory for single-pixel buffers">
+      The wp_single_pixel_buffer_manager_v1 interface is a factory for
+      single-pixel buffers.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the manager">
+        Destroy the wp_single_pixel_buffer_manager_v1 object.
+
+        The child objects created via this interface are unaffected.
+      </description>
+    </request>
+
+    <request name="create_u32_rgba_buffer">
+      <description summary="create a 1×1 buffer from 32-bit RGBA values">
+        Create a single-pixel buffer from four 32-bit RGBA values.
+
+        Unless specified in another protocol extension, the RGBA values use
+        pre-multiplied alpha.
+
+        The width and height of the buffer are 1.
+      </description>
+      <arg name="id" type="new_id" interface="wl_buffer"/>
+      <arg name="r" type="uint" summary="value of the buffer's red channel"/>
+      <arg name="g" type="uint" summary="value of the buffer's green channel"/>
+      <arg name="b" type="uint" summary="value of the buffer's blue channel"/>
+      <arg name="a" type="uint" summary="value of the buffer's alpha channel"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/tearing-control/README b/subprojects/wayland-protocols/staging/tearing-control/README
new file mode 100644
index 0000000000000000000000000000000000000000..b221e587d00e8671c9536b519cff213841b92b52
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/tearing-control/README
@@ -0,0 +1,4 @@
+Tearing control protocol
+
+Maintainers:
+Xaver Hugl <xaver.hugl@gmail.com> (@Zamundaaa)
diff --git a/subprojects/wayland-protocols/staging/tearing-control/tearing-control-v1.xml b/subprojects/wayland-protocols/staging/tearing-control/tearing-control-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9c44fbfca5a0b9fca1dd9296925c5472773f4e65
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/tearing-control/tearing-control-v1.xml
@@ -0,0 +1,123 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="tearing_control_v1">
+  <copyright>
+    Copyright © 2021 Xaver Hugl
+
+    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.
+  </copyright>
+
+  <interface name="wp_tearing_control_manager_v1" version="1">
+    <description summary="protocol for tearing control">
+      For some use cases like games or drawing tablets it can make sense to
+      reduce latency by accepting tearing with the use of asynchronous page
+      flips. This global is a factory interface, allowing clients to inform
+      which type of presentation the content of their surfaces is suitable for.
+
+      Graphics APIs like EGL or Vulkan, that manage the buffer queue and commits
+      of a wl_surface themselves, are likely to be using this extension
+      internally. If a client is using such an API for a wl_surface, it should
+      not directly use this extension on that surface, to avoid raising a
+      tearing_control_exists protocol error.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy tearing control factory object">
+        Destroy this tearing control factory object. Other objects, including
+        wp_tearing_control_v1 objects created by this factory, are not affected
+        by this request.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="tearing_control_exists" value="0"
+             summary="the surface already has a tearing object associated"/>
+    </enum>
+
+    <request name="get_tearing_control">
+      <description summary="extend surface interface for tearing control">
+        Instantiate an interface extension for the given wl_surface to request
+        asynchronous page flips for presentation.
+
+        If the given wl_surface already has a wp_tearing_control_v1 object
+        associated, the tearing_control_exists protocol error is raised.
+      </description>
+      <arg name="id" type="new_id" interface="wp_tearing_control_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="wp_tearing_control_v1" version="1">
+    <description summary="per-surface tearing control interface">
+      An additional interface to a wl_surface object, which allows the client
+      to hint to the compositor if the content on the surface is suitable for
+      presentation with tearing.
+      The default presentation hint is vsync. See presentation_hint for more
+      details.
+
+      If the associated wl_surface is destroyed, this object becomes inert and
+      should be destroyed.
+    </description>
+
+    <enum name="presentation_hint">
+      <description summary="presentation hint values">
+        This enum provides information for if submitted frames from the client
+        may be presented with tearing.
+      </description>
+      <entry name="vsync" value="0">
+        <description summary="tearing-free presentation">
+          The content of this surface is meant to be synchronized to the
+          vertical blanking period. This should not result in visible tearing
+          and may result in a delay before a surface commit is presented.
+        </description>
+      </entry>
+      <entry name="async" value="1">
+        <description summary="asynchronous presentation">
+          The content of this surface is meant to be presented with minimal
+          latency and tearing is acceptable.
+        </description>
+      </entry>
+    </enum>
+
+    <request name="set_presentation_hint">
+      <description summary="set presentation hint">
+        Set the presentation hint for the associated wl_surface. This state is
+        double-buffered, see wl_surface.commit.
+
+        The compositor is free to dynamically respect or ignore this hint based
+        on various conditions like hardware capabilities, surface state and
+        user preferences.
+      </description>
+      <arg name="hint" type="uint" enum="presentation_hint"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy tearing control object">
+        Destroy this surface tearing object and revert the presentation hint to
+        vsync. The change will be applied on the next wl_surface.commit.
+      </description>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/xdg-activation/README b/subprojects/wayland-protocols/staging/xdg-activation/README
new file mode 100644
index 0000000000000000000000000000000000000000..17744f660cb22f54181f47bc2bd3045143d7fd02
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-activation/README
@@ -0,0 +1,4 @@
+XDG Activation protocol
+
+Maintainers:
+Aleix Pol Gonzalez <aleixpol@kde.org> (@apol)
diff --git a/subprojects/wayland-protocols/staging/xdg-activation/x11-interoperation.rst b/subprojects/wayland-protocols/staging/xdg-activation/x11-interoperation.rst
new file mode 100644
index 0000000000000000000000000000000000000000..3bd03ee202d55fadbfce02e45a125918f2b5f092
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-activation/x11-interoperation.rst
@@ -0,0 +1,63 @@
+Interoperation with X11
+=======================
+
+*This document is non-normative.*
+
+The former
+`X11 Startup notification protocol <https://cgit.freedesktop.org/startup-notification/tree/doc/startup-notification.txt>`_
+defines the use of the ``DESKTOP_STARTUP_ID`` environment variable to propagate
+startup sequences ("activation tokens" in this protocol) between launcher and
+launchee.
+
+These startup sequence IDs are defined as a globally unique string with a
+``[unique]_TIME[timestamp]`` format, where the ID as a whole is used for startup
+notification and the timestamp is used for focus requests and focus stealing
+prevention.
+
+In order to observe mixed usage scenarios where Wayland and X11 clients might
+be launching each other, it is possible for a compositor to manage a shared
+pool of activation tokens.
+
+Scenario 1. Wayland client spawns X11 client
+--------------------------------------------
+
+1. Wayland client requests token.
+2. Wayland client spawns X11 client, sets ``$DESKTOP_STARTUP_ID`` in its
+   environment with the token string.
+3. X11 client starts.
+4. X11 client sends startup-notification ``remove`` message with the activation
+   ``$DESKTOP_STARTUP_ID`` content.
+5. Compositor receives startup notification message, matches ID with
+   the common pool.
+6. The startup feedback is finished.
+7. X11 client requests focus.
+8. Compositor applies internal policies to allow/deny focus switch.
+
+Scenario 2. X11 client spawns Wayland client
+--------------------------------------------
+
+1. X11 client builds a "globally unique" ID
+2. X11 client sends startup-notification ``new`` message with the ID.
+3. Compositor receives startup notification message, adds the ID to
+   the common pool.
+4. X11 client spawns Wayland client, sets ``$DESKTOP_STARTUP_ID`` in its
+   environment.
+5. Wayland client starts.
+6. Wayland client requests surface activation with the activation token,
+   as received from ``$DESKTOP_STARTUP_ID``.
+7. Compositor receives the request, matches ID with the common pool
+8. The startup feedback is finished.
+9. Compositor applies internal policies to allow/deny focus switch.
+
+Caveats
+-------
+
+- For legacy reasons, the usage of ``$DESKTOP_STARTUP_ID`` (even if as a
+  fallback) should be observed in compositors and clients that are
+  concerned with X11 interoperation.
+
+- Depending on the X11 startup-notification implementation in use by the
+  compositor, the usage of the ``_TIME[timestamp]`` suffix may be mandatory
+  for its correct behavior in the first scenario, the startup-notification
+  reference library is one such implementation. Compositors may work
+  this around by adding a matching suffix to the generated activation tokens.
diff --git a/subprojects/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml b/subprojects/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9adcc274ef14a58a307270c8c7b15fb10c22f7e1
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-activation/xdg-activation-v1.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_activation_v1">
+
+  <copyright>
+    Copyright © 2020 Aleix Pol Gonzalez &lt;aleixpol@kde.org&gt;
+    Copyright © 2020 Carlos Garnacho &lt;carlosg@gnome.org&gt;
+
+    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.
+  </copyright>
+
+  <description summary="Protocol for requesting activation of surfaces">
+    The way for a client to pass focus to another toplevel is as follows.
+
+    The client that intends to activate another toplevel uses the
+    xdg_activation_v1.get_activation_token request to get an activation token.
+    This token is then forwarded to the client, which is supposed to activate
+    one of its surfaces, through a separate band of communication.
+
+    One established way of doing this is through the XDG_ACTIVATION_TOKEN
+    environment variable of a newly launched child process. The child process
+    should unset the environment variable again right after reading it out in
+    order to avoid propagating it to other child processes.
+
+    Another established way exists for Applications implementing the D-Bus
+    interface org.freedesktop.Application, which should get their token under
+    activation-token on their platform_data.
+
+    In general activation tokens may be transferred across clients through
+    means not described in this protocol.
+
+    The client to be activated will then pass the token
+    it received to the xdg_activation_v1.activate request. The compositor can
+    then use this token to decide how to react to the activation request.
+
+    The token the activating client gets may be ineffective either already at
+    the time it receives it, for example if it was not focused, for focus
+    stealing prevention. The activating client will have no way to discover
+    the validity of the token, and may still forward it to the to be activated
+    client.
+
+    The created activation token may optionally get information attached to it
+    that can be used by the compositor to identify the application that we
+    intend to activate. This can for example be used to display a visual hint
+    about what application is being started.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="xdg_activation_v1" version="1">
+    <description summary="interface for activating surfaces">
+      A global interface used for informing the compositor about applications
+      being activated or started, or for applications to request to be
+      activated.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_activation object">
+        Notify the compositor that the xdg_activation object will no longer be
+        used.
+
+        The child objects created via this interface are unaffected and should
+        be destroyed separately.
+      </description>
+    </request>
+
+    <request name="get_activation_token">
+      <description summary="requests a token">
+        Creates an xdg_activation_token_v1 object that will provide
+        the initiating client with a unique token for this activation. This
+        token should be offered to the clients to be activated.
+      </description>
+
+      <arg name="id" type="new_id" interface="xdg_activation_token_v1"/>
+    </request>
+
+    <request name="activate">
+      <description summary="notify new interaction being available">
+        Requests surface activation. It's up to the compositor to display
+        this information as desired, for example by placing the surface above
+        the rest.
+
+        The compositor may know who requested this by checking the activation
+        token and might decide not to follow through with the activation if it's
+        considered unwanted.
+
+        Compositors can ignore unknown activation tokens when an invalid
+        token is passed.
+      </description>
+      <arg name="token" type="string" summary="the activation token of the initiating client"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the wl_surface to activate"/>
+    </request>
+  </interface>
+
+  <interface name="xdg_activation_token_v1" version="1">
+    <description summary="an exported activation handle">
+      An object for setting up a token and receiving a token handle that can
+      be passed as an activation token to another client.
+
+      The object is created using the xdg_activation_v1.get_activation_token
+      request. This object should then be populated with the app_id, surface
+      and serial information and committed. The compositor shall then issue a
+      done event with the token. In case the request's parameters are invalid,
+      the compositor will provide an invalid token.
+    </description>
+
+    <enum name="error">
+      <entry name="already_used" value="0"
+             summary="The token has already been used previously"/>
+    </enum>
+
+    <request name="set_serial">
+      <description summary="specifies the seat and serial of the activating event">
+        Provides information about the seat and serial event that requested the
+        token.
+
+        The serial can come from an input or focus event. For instance, if a
+        click triggers the launch of a third-party client, the launcher client
+        should send a set_serial request with the serial and seat from the
+        wl_pointer.button event.
+
+        Some compositors might refuse to activate toplevels when the token
+        doesn't have a valid and recent enough event serial.
+
+        Must be sent before commit. This information is optional.
+      </description>
+      <arg name="serial" type="uint"
+           summary="the serial of the event that triggered the activation"/>
+      <arg name="seat" type="object" interface="wl_seat"
+           summary="the wl_seat of the event"/>
+    </request>
+
+    <request name="set_app_id">
+      <description summary="specifies the application being activated">
+        The requesting client can specify an app_id to associate the token
+        being created with it.
+
+        Must be sent before commit. This information is optional.
+      </description>
+      <arg name="app_id" type="string"
+           summary="the application id of the client being activated."/>
+    </request>
+
+    <request name="set_surface">
+      <description summary="specifies the surface requesting activation">
+        This request sets the surface requesting the activation. Note, this is
+        different from the surface that will be activated.
+
+        Some compositors might refuse to activate toplevels when the token
+        doesn't have a requesting surface.
+
+        Must be sent before commit. This information is optional.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the requesting surface"/>
+    </request>
+
+    <request name="commit">
+      <description summary="issues the token request">
+        Requests an activation token based on the different parameters that
+        have been offered through set_serial, set_surface and set_app_id.
+      </description>
+    </request>
+
+    <event name="done">
+      <description summary="the exported activation token">
+        The 'done' event contains the unique token of this activation request
+        and notifies that the provider is done.
+      </description>
+      <arg name="token" type="string" summary="the exported activation token"/>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_activation_token_v1 object">
+        Notify the compositor that the xdg_activation_token_v1 object will no
+        longer be used. The received token stays valid.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/xdg-dialog/README b/subprojects/wayland-protocols/staging/xdg-dialog/README
new file mode 100644
index 0000000000000000000000000000000000000000..c3b949f9eeb59c95546aeec58c5aa8f05798dcc5
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-dialog/README
@@ -0,0 +1,5 @@
+Dialog windows
+
+Maintainers:
+Carlos Garnacho <carlosg@gnome.org> (@carlosg)
+Jonas Ã…dahl <jadahl@gmail.com> (@jadahl)
diff --git a/subprojects/wayland-protocols/staging/xdg-dialog/xdg-dialog-v1.xml b/subprojects/wayland-protocols/staging/xdg-dialog/xdg-dialog-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fb3fc14e64e85aeb29b51a3fdd841703e34a635b
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-dialog/xdg-dialog-v1.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_dialog_v1">
+  <copyright>
+    Copyright © 2023 Carlos Garnacho
+
+    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.
+  </copyright>
+
+  <interface name="xdg_wm_dialog_v1" version="1">
+    <description summary="create dialogs related to other toplevels">
+      The xdg_wm_dialog_v1 interface is exposed as a global object allowing
+      to register surfaces with a xdg_toplevel role as "dialogs" relative to
+      another toplevel.
+
+      The compositor may let this relation influence how the surface is
+      placed, displayed or interacted with.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <enum name="error">
+      <entry name="already_used" value="0"
+             summary="the xdg_toplevel object has already been used to create a xdg_dialog_v1"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the dialog manager object">
+        Destroys the xdg_wm_dialog_v1 object. This does not affect
+        the xdg_dialog_v1 objects generated through it.
+      </description>
+    </request>
+
+    <request name="get_xdg_dialog">
+      <description summary="create a dialog object">
+        Creates a xdg_dialog_v1 object for the given toplevel. See the interface
+        description for more details.
+
+	Compositors must raise an already_used error if clients attempt to
+	create multiple xdg_dialog_v1 objects for the same xdg_toplevel.
+      </description>
+      <arg name="id" type="new_id" interface="xdg_dialog_v1"/>
+      <arg name="toplevel" type="object" interface="xdg_toplevel"/>
+    </request>
+  </interface>
+
+  <interface name="xdg_dialog_v1" version="1">
+    <description summary="dialog object">
+      A xdg_dialog_v1 object is an ancillary object tied to a xdg_toplevel. Its
+      purpose is hinting the compositor that the toplevel is a "dialog" (e.g. a
+      temporary window) relative to another toplevel (see
+      xdg_toplevel.set_parent). If the xdg_toplevel is destroyed, the xdg_dialog_v1
+      becomes inert.
+
+      Through this object, the client may provide additional hints about
+      the purpose of the secondary toplevel. This interface has no effect
+      on toplevels that are not attached to a parent toplevel.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the dialog object">
+        Destroys the xdg_dialog_v1 object. If this object is destroyed
+        before the related xdg_toplevel, the compositor should unapply its
+        effects.
+      </description>
+    </request>
+
+    <request name="set_modal">
+      <description summary="mark dialog as modal">
+        Hints that the dialog has "modal" behavior. Modal dialogs typically
+        require to be fully addressed by the user (i.e. closed) before resuming
+        interaction with the parent toplevel, and may require a distinct
+        presentation.
+
+        Clients must implement the logic to filter events in the parent
+        toplevel on their own.
+
+        Compositors may choose any policy in event delivery to the parent
+        toplevel, from delivering all events unfiltered to using them for
+        internal consumption.
+      </description>
+    </request>
+
+    <request name="unset_modal">
+      <description summary="mark dialog as not modal">
+        Drops the hint that this dialog has "modal" behavior. See
+        xdg_dialog_v1.set_modal for more details.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/xdg-system-bell/README b/subprojects/wayland-protocols/staging/xdg-system-bell/README
new file mode 100644
index 0000000000000000000000000000000000000000..a9276e16b369df825f0e284bdb53fced86e47616
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-system-bell/README
@@ -0,0 +1,5 @@
+system_bell protocol
+
+Maintainers:
+Jonas Ã…dahl <jadahl@gmail.com>
+Carlos Garnacho <carlosg@gnome.org>
diff --git a/gdk/wayland/protocol/xdg-system-bell-v1.xml b/subprojects/wayland-protocols/staging/xdg-system-bell/xdg-system-bell-v1.xml
similarity index 100%
rename from gdk/wayland/protocol/xdg-system-bell-v1.xml
rename to subprojects/wayland-protocols/staging/xdg-system-bell/xdg-system-bell-v1.xml
diff --git a/subprojects/wayland-protocols/staging/xdg-toplevel-drag/README b/subprojects/wayland-protocols/staging/xdg-toplevel-drag/README
new file mode 100644
index 0000000000000000000000000000000000000000..659295f5a49aac08a3c280a47f8ee57fbe991a28
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-toplevel-drag/README
@@ -0,0 +1,5 @@
+xdg toplevel drag protocol
+
+Maintainers:
+David Redondo <kde@david-redondo.de> (@davidre)
+Nick Yamane <nickdiego@igalia.com> (@nickdiego)
diff --git a/subprojects/wayland-protocols/staging/xdg-toplevel-drag/xdg-toplevel-drag-v1.xml b/subprojects/wayland-protocols/staging/xdg-toplevel-drag/xdg-toplevel-drag-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e14497df6d37ae694373a4f8c5e3777b68c3ee40
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-toplevel-drag/xdg-toplevel-drag-v1.xml
@@ -0,0 +1,142 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_toplevel_drag_v1">
+
+  <copyright>
+    Copyright 2023 David Redondo
+
+    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.
+  </copyright>
+
+  <interface name="xdg_toplevel_drag_manager_v1" version="1">
+    <description summary="Move a window during a drag">
+      This protocol enhances normal drag and drop with the ability to move a
+      window at the same time. This allows having detachable parts of a window
+      that when dragged out of it become a new window and can be dragged over
+      an existing window to be reattached.
+
+      A typical workflow would be when the user starts dragging on top of a
+      detachable part of a window, the client would create a wl_data_source and
+      a xdg_toplevel_drag_v1 object and start the drag as normal via
+      wl_data_device.start_drag. Once the client determines that the detachable
+      window contents should be detached from the originating window, it creates
+      a new xdg_toplevel with these contents and issues a
+      xdg_toplevel_drag_v1.attach request before mapping it. From now on the new
+      window is moved by the compositor during the drag as if the client called
+      xdg_toplevel.move.
+
+      Dragging an existing window is similar. The client creates a
+      xdg_toplevel_drag_v1 object and attaches the existing toplevel before
+      starting the drag.
+
+      Clients use the existing drag and drop mechanism to detect when a window
+      can be docked or undocked. If the client wants to snap a window into a
+      parent window it should delete or unmap the dragged top-level. If the
+      contents should be detached again it attaches a new toplevel as described
+      above. If a drag operation is cancelled without being dropped, clients
+      should revert to the previous state, deleting any newly created windows
+      as appropriate. When a drag operation ends as indicated by
+      wl_data_source.dnd_drop_performed the dragged toplevel window's final
+      position is determined as if a xdg_toplevel_move operation ended.
+
+      Warning! The protocol described in this file is currently in the testing
+      phase. Backward compatible changes may be added together with the
+      corresponding interface version bump. Backward incompatible changes can
+      only be done by creating a new major version of the extension.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_source" value="0"
+             summary="data_source already used for toplevel drag"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_toplevel_drag_manager_v1 object">
+        Destroy this xdg_toplevel_drag_manager_v1 object. Other objects,
+        including xdg_toplevel_drag_v1 objects created by this factory, are not
+        affected by this request.
+      </description>
+    </request>
+
+    <request name="get_xdg_toplevel_drag">
+      <description summary="get an xdg_toplevel_drag for a wl_data_source">
+        Create an xdg_toplevel_drag for a drag and drop operation that is going
+        to be started with data_source.
+
+        This request can only be made on sources used in drag-and-drop, so it
+        must be performed before wl_data_device.start_drag. Attempting to use
+        the source other than for drag-and-drop such as in
+        wl_data_device.set_selection will raise an invalid_source error.
+
+        Destroying data_source while a toplevel is attached to the
+        xdg_toplevel_drag is undefined.
+      </description>
+
+      <arg name="id" type="new_id" interface="xdg_toplevel_drag_v1"/>
+      <arg name="data_source" type="object" interface="wl_data_source"/>
+    </request>
+  </interface>
+
+  <interface name="xdg_toplevel_drag_v1" version="1">
+    <description summary="Object representing a toplevel move during a drag">
+    </description>
+
+    <enum name="error">
+      <entry name="toplevel_attached" value="0"
+             summary="valid toplevel already attached"/>
+      <entry name="ongoing_drag" value="1"
+             summary="drag has not ended" />
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy an xdg_toplevel_drag_v1 object">
+        Destroy this xdg_toplevel_drag_v1 object. This request must only be
+        called after the underlying wl_data_source drag has ended, as indicated
+        by the dnd_drop_performed or cancelled events. In any other case an
+        ongoing_drag error is raised.
+      </description>
+    </request>
+
+    <request name="attach">
+      <description summary="Move a toplevel with the drag operation">
+        Request that the window will be moved with the cursor during the drag
+        operation. The offset is a hint to the compositor how the toplevel
+        should be positioned relative to the cursor hotspot in surface local
+        coordinates and relative to the geometry of the toplevel being attached.
+        See xdg_surface.set_window_geometry. For example it might only
+        be used when an unmapped window is attached. The attached window
+        does not participate in the selection of the drag target.
+
+        If the toplevel is unmapped while it is attached, it is automatically
+        detached from the drag. In this case this request has to be called again
+        if the window should be attached after it is remapped.
+
+        This request can be called multiple times but issuing it while a
+        toplevel with an active role is attached raises a toplevel_attached
+        error.
+      </description>
+
+      <arg name="toplevel" type="object" interface="xdg_toplevel"/>
+      <arg name="x_offset" type="int" summary="dragged surface x offset"/>
+      <arg name="y_offset" type="int" summary="dragged surface y offset"/>
+    </request>
+
+  </interface>
+</protocol>
+
diff --git a/subprojects/wayland-protocols/staging/xdg-toplevel-icon/README b/subprojects/wayland-protocols/staging/xdg-toplevel-icon/README
new file mode 100644
index 0000000000000000000000000000000000000000..76a394f5da919a5ffa6190f65dfece6952b9f6ed
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-toplevel-icon/README
@@ -0,0 +1,4 @@
+xdg_toplevel_icon protocol
+
+Maintainers:
+Matthias Klumpp <matthias@tenstral.net> (@mak)
diff --git a/subprojects/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml b/subprojects/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..fc409fef7c67e7c0e05951f5f2fb57b60d191c50
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xdg-toplevel-icon/xdg-toplevel-icon-v1.xml
@@ -0,0 +1,205 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_toplevel_icon_v1">
+
+  <copyright>
+    Copyright © 2023-2024 Matthias Klumpp
+    Copyright ©      2024 David Edmundson
+
+    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.
+  </copyright>
+
+  <description summary="protocol to assign icons to toplevels">
+    This protocol allows clients to set icons for their toplevel surfaces
+    either via the XDG icon stock (using an icon name), or from pixel data.
+
+    A toplevel icon represents the individual toplevel (unlike the application
+    or launcher icon, which represents the application as a whole), and may be
+    shown in window switchers, window overviews and taskbars that list
+    individual windows.
+
+    This document adheres to RFC 2119 when using words like "must",
+    "should", "may", etc.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="xdg_toplevel_icon_manager_v1" version="1">
+    <description summary="interface to manage toplevel icons">
+      This interface allows clients to create toplevel window icons and set
+      them on toplevel windows to be displayed to the user.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the toplevel icon manager">
+        Destroy the toplevel icon manager.
+        This does not destroy objects created with the manager.
+      </description>
+    </request>
+
+    <request name="create_icon">
+      <description summary="create a new icon instance">
+        Creates a new icon object. This icon can then be attached to a
+        xdg_toplevel via the 'set_icon' request.
+      </description>
+      <arg name="id" type="new_id" interface="xdg_toplevel_icon_v1"/>
+    </request>
+
+    <request name="set_icon">
+      <description summary="set an icon on a toplevel window">
+        This request assigns the icon 'icon' to 'toplevel', or clears the
+        toplevel icon if 'icon' was null.
+        This state is double-buffered and is applied on the next
+        wl_surface.commit of the toplevel.
+
+        After making this call, the xdg_toplevel_icon_v1 provided as 'icon'
+        can be destroyed by the client without 'toplevel' losing its icon.
+        The xdg_toplevel_icon_v1 is immutable from this point, and any
+        future attempts to change it must raise the
+        'xdg_toplevel_icon_v1.immutable' protocol error.
+
+        The compositor must set the toplevel icon from either the pixel data
+        the icon provides, or by loading a stock icon using the icon name.
+        See the description of 'xdg_toplevel_icon_v1' for details.
+
+        If 'icon' is set to null, the icon of the respective toplevel is reset
+        to its default icon (usually the icon of the application, derived from
+        its desktop-entry file, or a placeholder icon).
+        If this request is passed an icon with no pixel buffers or icon name
+        assigned, the icon must be reset just like if 'icon' was null.
+      </description>
+      <arg name="toplevel" type="object" interface="xdg_toplevel" summary="the toplevel to act on"/>
+      <arg name="icon" type="object" interface="xdg_toplevel_icon_v1" allow-null="true"/>
+    </request>
+
+    <event name="icon_size">
+      <description summary="describes a supported &amp; preferred icon size">
+        This event indicates an icon size the compositor prefers to be
+        available if the client has scalable icons and can render to any size.
+
+        When the 'xdg_toplevel_icon_manager_v1' object is created, the
+        compositor may send one or more 'icon_size' events to describe the list
+        of preferred icon sizes. If the compositor has no size preference, it
+        may not send any 'icon_size' event, and it is up to the client to
+        decide a suitable icon size.
+
+        A sequence of 'icon_size' events must be finished with a 'done' event.
+        If the compositor has no size preferences, it must still send the
+        'done' event, without any preceding 'icon_size' events.
+      </description>
+      <arg name="size" type="int"
+	   summary="the edge size of the square icon in surface-local coordinates, e.g. 64"/>
+    </event>
+
+    <event name="done">
+      <description summary="all information has been sent">
+        This event is sent after all 'icon_size' events have been sent.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="xdg_toplevel_icon_v1" version="1">
+    <description summary="a toplevel window icon">
+      This interface defines a toplevel icon.
+      An icon can have a name, and multiple buffers.
+      In order to be applied, the icon must have either a name, or at least
+      one buffer assigned. Applying an empty icon (with no buffer or name) to
+      a toplevel should reset its icon to the default icon.
+
+      It is up to compositor policy whether to prefer using a buffer or loading
+      an icon via its name. See 'set_name' and 'add_buffer' for details.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_buffer"
+             summary="the provided buffer does not satisfy requirements"
+	     value="1"/>
+      <entry name="immutable"
+             summary="the icon has already been assigned to a toplevel and must not be changed"
+	     value="2"/>
+      <entry name="no_buffer"
+             summary="the provided buffer has been destroyed before the toplevel icon"
+             value="3"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the icon object">
+        Destroys the 'xdg_toplevel_icon_v1' object.
+        The icon must still remain set on every toplevel it was assigned to,
+        until the toplevel icon is reset explicitly.
+      </description>
+    </request>
+
+    <request name="set_name">
+      <description summary="set an icon name">
+        This request assigns an icon name to this icon.
+        Any previously set name is overridden.
+
+        The compositor must resolve 'icon_name' according to the lookup rules
+        described in the XDG icon theme specification[1] using the
+        environment's current icon theme.
+
+        If the compositor does not support icon names or cannot resolve
+        'icon_name' according to the XDG icon theme specification it must
+        fall back to using pixel buffer data instead.
+
+        If this request is made after the icon has been assigned to a toplevel
+        via 'set_icon', a 'immutable' error must be raised.
+
+        [1]: https://specifications.freedesktop.org/icon-theme-spec/icon-theme-spec-latest.html
+      </description>
+      <arg name="icon_name" type="string"/>
+    </request>
+
+    <request name="add_buffer">
+      <description summary="add icon data from a pixel buffer">
+        This request adds pixel data supplied as wl_buffer to the icon.
+
+        The client should add pixel data for all icon sizes and scales that
+        it can provide, or which are explicitly requested by the compositor
+        via 'icon_size' events on xdg_toplevel_icon_manager_v1.
+
+        The wl_buffer supplying pixel data as 'buffer' must be backed by wl_shm
+        and must be a square (width and height being equal).
+        If any of these buffer requirements are not fulfilled, a 'invalid_buffer'
+        error must be raised.
+
+        If this icon instance already has a buffer of the same size and scale
+        from a previous 'add_buffer' request, data from the last request
+        overrides the preexisting pixel data.
+
+        The wl_buffer must be kept alive for as long as the xdg_toplevel_icon
+        it is associated with is not destroyed, otherwise a 'no_buffer' error
+        is raised. The buffer contents must not be modified after it was
+        assigned to the icon. As a result, the region of the wl_shm_pool's
+        backing storage used for the wl_buffer must not be modified after this
+        request is sent. The wl_buffer.release event is unused.
+
+        If this request is made after the icon has been assigned to a toplevel
+        via 'set_icon', a 'immutable' error must be raised.
+      </description>
+      <arg name="buffer" type="object" interface="wl_buffer"/>
+      <arg name="scale" type="int"
+	   summary="the scaling factor of the icon, e.g. 1"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/staging/xwayland-shell/README b/subprojects/wayland-protocols/staging/xwayland-shell/README
new file mode 100644
index 0000000000000000000000000000000000000000..a10bd994e101cfe25d5da51b8a375675020944a5
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xwayland-shell/README
@@ -0,0 +1,4 @@
+Xwayland shell protocol
+
+Maintainers:
+Joshua Ashton <joshua@froggi.es> (@frog)
diff --git a/subprojects/wayland-protocols/staging/xwayland-shell/xwayland-shell-v1.xml b/subprojects/wayland-protocols/staging/xwayland-shell/xwayland-shell-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..99a2a947fa10c79cb92783e703b0d58661f98c25
--- /dev/null
+++ b/subprojects/wayland-protocols/staging/xwayland-shell/xwayland-shell-v1.xml
@@ -0,0 +1,161 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xwayland_shell_v1">
+
+  <copyright>
+    Copyright © 2022 Joshua Ashton
+
+    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.
+  </copyright>
+
+  <description summary="Protocol for associating X11 windows to wl_surfaces">
+    This protocol adds a xwayland_surface role which allows an Xwayland
+    server to associate an X11 window to a wl_surface.
+    
+    Before this protocol, this would be done via the Xwayland server
+    providing the wl_surface's resource id via the a client message with
+    the WL_SURFACE_ID atom on the X window.
+    This was problematic as a race could occur if the wl_surface
+    associated with a WL_SURFACE_ID for a window was destroyed before the
+    client message was processed by the compositor and another surface
+    (or other object) had taken its id due to recycling.
+    
+    This protocol solves the problem by moving the X11 window to wl_surface
+    association step to the Wayland side, which means that the association
+    cannot happen out-of-sync with the resource lifetime of the wl_surface.
+    
+    This protocol avoids duplicating the race on the other side by adding a
+    non-zero monotonic serial number which is entirely unique that is set on
+    both the wl_surface (via. xwayland_surface_v1's set_serial method) and
+    the X11 window (via. the `WL_SURFACE_SERIAL` client message) that can be
+    used to associate them, and synchronize the two timelines.
+
+    The key words "must", "must not", "required", "shall", "shall not",
+    "should", "should not", "recommended",  "may", and "optional" in this
+    document are to be interpreted as described in IETF RFC 2119.
+
+    Warning! The protocol described in this file is currently in the testing
+    phase. Backward compatible changes may be added together with the
+    corresponding interface version bump. Backward incompatible changes can
+    only be done by creating a new major version of the extension.
+  </description>
+
+  <interface name="xwayland_shell_v1" version="1">
+    <description summary="context object for Xwayland shell">
+      xwayland_shell_v1 is a singleton global object that
+      provides the ability to create a xwayland_surface_v1 object
+      for a given wl_surface.
+
+      This interface is intended to be bound by the Xwayland server.
+
+      A compositor must not allow clients other than Xwayland to
+      bind to this interface. A compositor should hide this global
+      from other clients' wl_registry.
+      A client the compositor does not consider to be an Xwayland
+      server attempting to bind this interface will result in
+      an implementation-defined error.
+
+      An Xwayland server that has bound this interface must not
+      set the `WL_SURFACE_ID` atom on a window.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the Xwayland shell object">
+        Destroy the xwayland_shell_v1 object.
+
+        The child objects created via this interface are unaffected.
+      </description>
+    </request>
+
+    <request name="get_xwayland_surface">
+      <description summary="assign the xwayland_surface surface role">
+        Create an xwayland_surface_v1 interface for a given wl_surface
+        object and gives it the xwayland_surface role.
+        
+        It is illegal to create an xwayland_surface_v1 for a wl_surface
+        which already has an assigned role and this will result in the
+        `role` protocol error.
+
+        See the documentation of xwayland_surface_v1 for more details
+        about what an xwayland_surface_v1 is and how it is used.
+      </description>
+
+      <arg name="id" type="new_id" interface="xwayland_surface_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="xwayland_surface_v1" version="1">
+    <description summary="interface for associating Xwayland windows to wl_surfaces">
+      An Xwayland surface is a surface managed by an Xwayland server.
+      It is used for associating surfaces to Xwayland windows.
+
+      The Xwayland server associated with actions in this interface is
+      determined by the Wayland client making the request.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xwayland_surface_v1 state to take effect.
+    </description>
+
+    <enum name="error">
+      <entry name="already_associated" value="0" summary="given wl_surface is already associated with an X11 window"/>
+      <entry name="invalid_serial" value="1" summary="serial was not valid"/>
+    </enum>
+
+    <request name="set_serial">
+      <description summary="associates a Xwayland window to a wl_surface">
+        Associates an Xwayland window to a wl_surface.
+        The association state is double-buffered, see wl_surface.commit.
+
+        The `serial_lo` and `serial_hi` parameters specify a non-zero
+        monotonic serial number which is entirely unique and provided by the
+        Xwayland server equal to the serial value provided by a client message
+        with a message type of the `WL_SURFACE_SERIAL` atom on the X11 window
+        for this surface to be associated to.
+
+        The serial value in the `WL_SURFACE_SERIAL` client message is specified
+        as having the lo-bits specified in `l[0]` and the hi-bits specified
+        in `l[1]`.
+
+        If the serial value provided by `serial_lo` and `serial_hi` is not
+        valid, the `invalid_serial` protocol error will be raised.
+
+        An X11 window may be associated with multiple surfaces throughout its
+        lifespan. (eg. unmapping and remapping a window).
+        
+        For each wl_surface, this state must not be committed more than once,
+        otherwise the `already_associated` protocol error will be raised.
+      </description>
+      <arg name="serial_lo" type="uint" summary="The lower 32-bits of the serial number associated with the X11 window"/>
+      <arg name="serial_hi" type="uint" summary="The upper 32-bits of the serial number associated with the X11 window"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the Xwayland surface object">
+        Destroy the xwayland_surface_v1 object.
+
+        Any already existing associations are unaffected by this action.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/tests/build-cxx.cc.in b/subprojects/wayland-protocols/tests/build-cxx.cc.in
new file mode 100644
index 0000000000000000000000000000000000000000..67aeb2be785e3341aff6124a478a1b8b045419c3
--- /dev/null
+++ b/subprojects/wayland-protocols/tests/build-cxx.cc.in
@@ -0,0 +1,14 @@
+#include "@PROTOCOL_CLIENT_INCLUDE_FILE@"
+#include "@PROTOCOL_SERVER_INCLUDE_FILE@"
+
+/* This is a build-test only */
+
+using namespace std;
+
+int
+main(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+	return 0;
+}
diff --git a/subprojects/wayland-protocols/tests/build-pedantic.c.in b/subprojects/wayland-protocols/tests/build-pedantic.c.in
new file mode 100644
index 0000000000000000000000000000000000000000..39b4127d326921f5f6dc44b753e5deaa3b695acf
--- /dev/null
+++ b/subprojects/wayland-protocols/tests/build-pedantic.c.in
@@ -0,0 +1,12 @@
+#include "@PROTOCOL_CLIENT_INCLUDE_FILE@"
+#include "@PROTOCOL_SERVER_INCLUDE_FILE@"
+
+/* This is a build-test only */
+
+int
+main(int argc, char **argv)
+{
+	(void)argc;
+	(void)argv;
+	return 0;
+}
diff --git a/subprojects/wayland-protocols/tests/meson.build b/subprojects/wayland-protocols/tests/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..aa216ec2cdc79f91508267e06669589f3ec13a8b
--- /dev/null
+++ b/subprojects/wayland-protocols/tests/meson.build
@@ -0,0 +1,143 @@
+prog_scan_sh = find_program('scan.sh')
+
+libwayland = [
+	dependency('wayland-client'),
+	dependency('wayland-server'),
+]
+
+# Check that each protocol passes through the scanner
+foreach protocol_file : protocol_files
+	protocol_path = join_paths(wayland_protocols_srcdir, protocol_file)
+	test_name = 'scan-@0@'.format(protocol_file.underscorify())
+	test(test_name, prog_scan_sh,
+		args: protocol_path,
+		env: [
+			'SCANNER=@0@'.format(prog_scanner.full_path()),
+		]
+	)
+endforeach
+
+# Check buildability
+
+add_languages('c', 'cpp', native: false)
+replace = find_program('replace.py')
+
+extra_linker_flags = meson.get_compiler('c').get_supported_link_arguments([
+	'-Wl,--unresolved-symbols=ignore-all',
+])
+
+foreach protocol_file : protocol_files
+	xml_file = fs.name(protocol_file)
+	xml_components = xml_file.split('.')
+	protocol_base_file_name = xml_components[0]
+
+	protocol_path = files(join_paths(wayland_protocols_srcdir, protocol_file))
+	client_header_path = '@0@-client.h'.format(protocol_base_file_name)
+	server_header_path = '@0@-server.h'.format(protocol_base_file_name)
+	code_path = '@0@-code.c'.format(protocol_base_file_name)
+	client_header = custom_target(
+		client_header_path,
+		output: client_header_path,
+		input: protocol_path,
+		command: [
+			prog_scanner,
+			'--strict',
+			'client-header',
+			'@INPUT@',
+			'@OUTPUT@',
+		],
+		install: false,
+	)
+	server_header = custom_target(
+		server_header_path,
+		output: server_header_path,
+		input: protocol_path,
+		command: [
+			prog_scanner,
+			'--strict',
+			'server-header',
+			'@INPUT@',
+			'@OUTPUT@',
+		],
+		install: false,
+	)
+	code = custom_target(
+		code_path,
+		output: code_path,
+		input: protocol_path,
+		command: [
+			prog_scanner,
+			'--strict',
+			'private-code',
+			'@INPUT@',
+			'@OUTPUT@',
+		],
+		install: false,
+	)
+
+	replace_command = [
+		replace,
+		'@INPUT@',
+		'@OUTPUT@',
+		'PROTOCOL_CLIENT_INCLUDE_FILE',
+		client_header.full_path(),
+		'PROTOCOL_SERVER_INCLUDE_FILE',
+		server_header.full_path(),
+	]
+
+	# Check that header can be included by a pedantic C99 compiler
+	test_name = 'test-build-pedantic-@0@'.format(protocol_file.underscorify())
+	test_name_source = '@0@.c'.format(test_name)
+	test_source = custom_target(
+		test_name_source,
+		input: 'build-pedantic.c.in',
+		output: test_name_source,
+		command: replace_command,
+	)
+	pedantic_test_executable = executable(
+		test_name,
+		[
+			test_source,
+			client_header,
+			server_header,
+			code
+		],
+		link_args: extra_linker_flags,
+		dependencies: libwayland,
+		c_args: [
+			'-std=c99',
+			'-pedantic',
+			'-Wall',
+			'-Werror' ],
+		install: false,
+	)
+	test(test_name, pedantic_test_executable)
+
+	# Check that the header
+	if not protocol_file.contains('xdg-foreign-unstable-v1')
+		test_name = 'test-build-cxx-@0@'.format(protocol_file.underscorify())
+		test_name_source = '@0@.cc'.format(test_name)
+		test_source = custom_target(
+			test_name_source,
+			input: 'build-cxx.cc.in',
+			output: test_name_source,
+			command: replace_command,
+		)
+		cxx_test_executable = executable(
+			test_name,
+			[
+				test_source,
+				client_header,
+				server_header,
+			],
+			link_args: extra_linker_flags,
+			dependencies: libwayland,
+			cpp_args: [
+				'-Wall',
+				'-Werror',
+			],
+			install: false,
+		)
+		test(test_name, cxx_test_executable)
+	endif
+endforeach
diff --git a/subprojects/wayland-protocols/tests/replace.py b/subprojects/wayland-protocols/tests/replace.py
new file mode 100755
index 0000000000000000000000000000000000000000..6ba2c2fc18d2797f8bc4970b89ec908b116c2da9
--- /dev/null
+++ b/subprojects/wayland-protocols/tests/replace.py
@@ -0,0 +1,23 @@
+#!/usr/bin/env python3
+
+import sys
+
+execpath, inpath, outpath, *dict_list = sys.argv
+
+dictionary = {}
+while dict_list:
+    key, value, *rest = dict_list
+    dictionary[key] = value
+    dict_list = rest
+
+infile = open(inpath, 'r')
+outfile = open(outpath, 'w')
+
+buf = infile.read()
+infile.close()
+
+for key, value in dictionary.items():
+    buf = buf.replace('@{}@'.format(key), value)
+
+outfile.write(buf)
+outfile.close()
diff --git a/subprojects/wayland-protocols/tests/scan.sh b/subprojects/wayland-protocols/tests/scan.sh
new file mode 100755
index 0000000000000000000000000000000000000000..cad688775909058e6386da56f04dea5b8577c162
--- /dev/null
+++ b/subprojects/wayland-protocols/tests/scan.sh
@@ -0,0 +1,11 @@
+#!/bin/sh -e
+
+if [ "x$SCANNER" = "x" ] ; then
+	echo "No scanner present, test skipped." 1>&2
+	exit 77
+fi
+
+$SCANNER client-header --strict $1 /dev/null
+$SCANNER server-header --strict $1 /dev/null
+$SCANNER private-code --strict $1 /dev/null
+$SCANNER public-code --strict $1 /dev/null
diff --git a/subprojects/wayland-protocols/unstable/fullscreen-shell/README b/subprojects/wayland-protocols/unstable/fullscreen-shell/README
new file mode 100644
index 0000000000000000000000000000000000000000..7ea38fcfd272de959e13cf6e2b89f1157d2d9635
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/fullscreen-shell/README
@@ -0,0 +1,4 @@
+Fullscreen shell protocol
+
+Maintainers:
+Faith Ekstrand <faith@gfxstrand.net> (@gfxstrand)
diff --git a/subprojects/wayland-protocols/unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml b/subprojects/wayland-protocols/unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..db70f09e72ff063f4851b28ac12389b97f3c09bb
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/fullscreen-shell/fullscreen-shell-unstable-v1.xml
@@ -0,0 +1,254 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="fullscreen_shell_unstable_v1">
+
+  <copyright>
+    Copyright © 2016 Yong Bakos
+    Copyright © 2015 Jason Ekstrand
+    Copyright © 2015 Jonas Ådahl
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_fullscreen_shell_v1" version="1">
+    <description summary="displays a single surface per output">
+      Displays a single surface per output.
+
+      This interface provides a mechanism for a single client to display
+      simple full-screen surfaces.  While there technically may be multiple
+      clients bound to this interface, only one of those clients should be
+      shown at a time.
+
+      To present a surface, the client uses either the present_surface or
+      present_surface_for_mode requests.  Presenting a surface takes effect
+      on the next wl_surface.commit.  See the individual requests for
+      details about scaling and mode switches.
+
+      The client can have at most one surface per output at any time.
+      Requesting a surface to be presented on an output that already has a
+      surface replaces the previously presented surface.  Presenting a null
+      surface removes its content and effectively disables the output.
+      Exactly what happens when an output is "disabled" is
+      compositor-specific.  The same surface may be presented on multiple
+      outputs simultaneously.
+
+      Once a surface is presented on an output, it stays on that output
+      until either the client removes it or the compositor destroys the
+      output.  This way, the client can update the output's contents by
+      simply attaching a new buffer.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="release" type="destructor">
+      <description summary="release the wl_fullscreen_shell interface">
+	Release the binding from the wl_fullscreen_shell interface.
+
+	This destroys the server-side object and frees this binding.  If
+	the client binds to wl_fullscreen_shell multiple times, it may wish
+	to free some of those bindings.
+      </description>
+    </request>
+
+    <enum name="capability">
+      <description summary="capabilities advertised by the compositor">
+	Various capabilities that can be advertised by the compositor.  They
+	are advertised one-at-a-time when the wl_fullscreen_shell interface is
+	bound.  See the wl_fullscreen_shell.capability event for more details.
+
+	ARBITRARY_MODES:
+	This is a hint to the client that indicates that the compositor is
+	capable of setting practically any mode on its outputs.  If this
+	capability is provided, wl_fullscreen_shell.present_surface_for_mode
+	will almost never fail and clients should feel free to set whatever
+	mode they like.  If the compositor does not advertise this, it may
+	still support some modes that are not advertised through wl_global.mode
+	but it is less likely.
+
+	CURSOR_PLANE:
+	This is a hint to the client that indicates that the compositor can
+	handle a cursor surface from the client without actually compositing.
+	This may be because of a hardware cursor plane or some other mechanism.
+	If the compositor does not advertise this capability then setting
+	wl_pointer.cursor may degrade performance or be ignored entirely.  If
+	CURSOR_PLANE is not advertised, it is recommended that the client draw
+	its own cursor and set wl_pointer.cursor(NULL).
+      </description>
+      <entry name="arbitrary_modes" value="1" summary="compositor is capable of almost any output mode"/>
+      <entry name="cursor_plane" value="2" summary="compositor has a separate cursor plane"/>
+    </enum>
+
+    <event name="capability">
+      <description summary="advertises a capability of the compositor">
+	Advertises a single capability of the compositor.
+
+	When the wl_fullscreen_shell interface is bound, this event is emitted
+	once for each capability advertised.  Valid capabilities are given by
+	the wl_fullscreen_shell.capability enum.  If clients want to take
+	advantage of any of these capabilities, they should use a
+	wl_display.sync request immediately after binding to ensure that they
+	receive all the capability events.
+      </description>
+      <arg name="capability" type="uint" enum="capability" />
+    </event>
+
+    <enum name="present_method">
+      <description summary="different method to set the surface fullscreen">
+	Hints to indicate to the compositor how to deal with a conflict
+	between the dimensions of the surface and the dimensions of the
+	output. The compositor is free to ignore this parameter.
+      </description>
+      <entry name="default" value="0" summary="no preference, apply default policy"/>
+      <entry name="center" value="1" summary="center the surface on the output"/>
+      <entry name="zoom" value="2" summary="scale the surface, preserving aspect ratio, to the largest size that will fit on the output" />
+      <entry name="zoom_crop" value="3" summary="scale the surface, preserving aspect ratio, to fully fill the output cropping if needed" />
+      <entry name="stretch" value="4" summary="scale the surface to the size of the output ignoring aspect ratio" />
+    </enum>
+
+    <request name="present_surface">
+      <description summary="present surface for display">
+	Present a surface on the given output.
+
+	If the output is null, the compositor will present the surface on
+	whatever display (or displays) it thinks best.  In particular, this
+	may replace any or all surfaces currently presented so it should
+	not be used in combination with placing surfaces on specific
+	outputs.
+
+	The method parameter is a hint to the compositor for how the surface
+	is to be presented.  In particular, it tells the compositor how to
+	handle a size mismatch between the presented surface and the
+	output.  The compositor is free to ignore this parameter.
+
+	The "zoom", "zoom_crop", and "stretch" methods imply a scaling
+	operation on the surface.  This will override any kind of output
+	scaling, so the buffer_scale property of the surface is effectively
+	ignored.
+
+	This request gives the surface the role of a fullscreen shell surface.
+	If the surface already has another role, it raises a role protocol
+	error.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+      <arg name="method" type="uint" enum="present_method" />
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+
+    <request name="present_surface_for_mode">
+      <description summary="present surface for display at a particular mode">
+	Presents a surface on the given output for a particular mode.
+
+	If the current size of the output differs from that of the surface,
+	the compositor will attempt to change the size of the output to
+	match the surface.  The result of the mode-switch operation will be
+	returned via the provided wl_fullscreen_shell_mode_feedback object.
+
+	If the current output mode matches the one requested or if the
+	compositor successfully switches the mode to match the surface,
+	then the mode_successful event will be sent and the output will
+	contain the contents of the given surface.  If the compositor
+	cannot match the output size to the surface size, the mode_failed
+	will be sent and the output will contain the contents of the
+	previously presented surface (if any).  If another surface is
+	presented on the given output before either of these has a chance
+	to happen, the present_cancelled event will be sent.
+
+	Due to race conditions and other issues unknown to the client, no
+	mode-switch operation is guaranteed to succeed.  However, if the
+	mode is one advertised by wl_output.mode or if the compositor
+	advertises the ARBITRARY_MODES capability, then the client should
+	expect that the mode-switch operation will usually succeed.
+
+	If the size of the presented surface changes, the resulting output
+	is undefined.  The compositor may attempt to change the output mode
+	to compensate.  However, there is no guarantee that a suitable mode
+	will be found and the client has no way to be notified of success
+	or failure.
+
+	The framerate parameter specifies the desired framerate for the
+	output in mHz.  The compositor is free to ignore this parameter.  A
+	value of 0 indicates that the client has no preference.
+
+	If the value of wl_output.scale differs from wl_surface.buffer_scale,
+	then the compositor may choose a mode that matches either the buffer
+	size or the surface size.  In either case, the surface will fill the
+	output.
+
+	This request gives the surface the role of a fullscreen shell surface.
+	If the surface already has another role, it raises a role protocol
+	error.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="output" type="object" interface="wl_output"/>
+      <arg name="framerate" type="int"/>
+      <arg name="feedback" type="new_id" interface="zwp_fullscreen_shell_mode_feedback_v1"/>
+    </request>
+
+    <enum name="error">
+      <description summary="wl_fullscreen_shell error values">
+	These errors can be emitted in response to wl_fullscreen_shell requests.
+      </description>
+      <entry name="invalid_method" value="0" summary="present_method is not known"/>
+      <entry name="role" value="1" summary="given wl_surface has another role"/>
+    </enum>
+  </interface>
+
+  <interface name="zwp_fullscreen_shell_mode_feedback_v1" version="1">
+    <event name="mode_successful" type="destructor">
+      <description summary="mode switch succeeded">
+	This event indicates that the attempted mode switch operation was
+	successful.  A surface of the size requested in the mode switch
+	will fill the output without scaling.
+
+	Upon receiving this event, the client should destroy the
+	wl_fullscreen_shell_mode_feedback object.
+      </description>
+    </event>
+
+    <event name="mode_failed" type="destructor">
+      <description summary="mode switch failed">
+	This event indicates that the attempted mode switch operation
+	failed.  This may be because the requested output mode is not
+	possible or it may mean that the compositor does not want to allow it.
+
+	Upon receiving this event, the client should destroy the
+	wl_fullscreen_shell_mode_feedback object.
+      </description>
+    </event>
+
+    <event name="present_cancelled" type="destructor">
+      <description summary="mode switch cancelled">
+	This event indicates that the attempted mode switch operation was
+	cancelled.  Most likely this is because the client requested a
+	second mode switch before the first one completed.
+
+	Upon receiving this event, the client should destroy the
+	wl_fullscreen_shell_mode_feedback object.
+      </description>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/idle-inhibit/README b/subprojects/wayland-protocols/unstable/idle-inhibit/README
new file mode 100644
index 0000000000000000000000000000000000000000..396e871626932970b058f0f25ad5d7da6aa03da4
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/idle-inhibit/README
@@ -0,0 +1,4 @@
+Screensaver inhibition protocol
+
+Maintainers:
+Bryce Harrington <bryce@osg.samsung.com>
diff --git a/subprojects/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml b/subprojects/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9c06cdcba6c06f978ac81ab70ad4b3f77911c4a4
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/idle-inhibit/idle-inhibit-unstable-v1.xml
@@ -0,0 +1,83 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="idle_inhibit_unstable_v1">
+
+  <copyright>
+    Copyright © 2015 Samsung Electronics Co., Ltd
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_idle_inhibit_manager_v1" version="1">
+    <description summary="control behavior when display idles">
+      This interface permits inhibiting the idle behavior such as screen
+      blanking, locking, and screensaving.  The client binds the idle manager
+      globally, then creates idle-inhibitor objects for each surface.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the idle inhibitor object">
+	Destroy the inhibit manager.
+      </description>
+    </request>
+
+    <request name="create_inhibitor">
+      <description summary="create a new inhibitor object">
+	Create a new inhibitor object associated with the given surface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_idle_inhibitor_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the surface that inhibits the idle behavior"/>
+    </request>
+
+  </interface>
+
+  <interface name="zwp_idle_inhibitor_v1" version="1">
+    <description summary="context object for inhibiting idle behavior">
+      An idle inhibitor prevents the output that the associated surface is
+      visible on from being set to a state where it is not visually usable due
+      to lack of user interaction (e.g. blanked, dimmed, locked, set to power
+      save, etc.)  Any screensaver processes are also blocked from displaying.
+
+      If the surface is destroyed, unmapped, becomes occluded, loses
+      visibility, or otherwise becomes not visually relevant for the user, the
+      idle inhibitor will not be honored by the compositor; if the surface
+      subsequently regains visibility the inhibitor takes effect once again.
+      Likewise, the inhibitor isn't honored if the system was already idled at
+      the time the inhibitor was established, although if the system later
+      de-idles and re-idles the inhibitor will take effect.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the idle inhibitor object">
+	Remove the inhibitor effect from the associated wl_surface.
+      </description>
+    </request>
+
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/input-method/README b/subprojects/wayland-protocols/unstable/input-method/README
new file mode 100644
index 0000000000000000000000000000000000000000..1dbdf872e9780501aa20829234ba97f39fe8c66f
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/input-method/README
@@ -0,0 +1,4 @@
+Input method protocol
+
+Maintainers:
+Jan Arne Petersen <janarne@gmail.com> (@jpetersen)
diff --git a/subprojects/wayland-protocols/unstable/input-method/input-method-unstable-v1.xml b/subprojects/wayland-protocols/unstable/input-method/input-method-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e9d93ba609efab7dae93d485caa2d3c787478033
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/input-method/input-method-unstable-v1.xml
@@ -0,0 +1,305 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="input_method_unstable_v1">
+
+  <copyright>
+    Copyright © 2012, 2013 Intel Corporation
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_input_method_context_v1" version="1">
+    <description summary="input method context">
+      Corresponds to a text input on the input method side. An input method context
+      is created on text input activation on the input method side. It allows
+      receiving information about the text input from the application via events.
+      Input method contexts do not keep state after deactivation and should be
+      destroyed after deactivation is handled.
+
+      Text is generally UTF-8 encoded, indices and lengths are in bytes.
+
+      Serials are used to synchronize the state between the text input and
+      an input method. New serials are sent by the text input in the
+      commit_state request and are used by the input method to indicate
+      the known text input state in events like preedit_string, commit_string,
+      and keysym. The text input can then ignore events from the input method
+      which are based on an outdated state (for example after a reset).
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="destroy" type="destructor"/>
+
+    <request name="commit_string">
+      <description summary="commit string">
+	Send the commit string text for insertion to the application.
+
+	The text to commit could be either just a single character after a key
+	press or the result of some composing (pre-edit). It could be also an
+	empty text when some text should be removed (see
+	delete_surrounding_text) or when the input cursor should be moved (see
+	cursor_position).
+
+	Any previously set composing text will be removed.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="text" type="string"/>
+    </request>
+
+    <request name="preedit_string">
+      <description summary="pre-edit string">
+	Send the pre-edit string text to the application text input.
+
+	The commit text can be used to replace the pre-edit text on reset (for
+	example on unfocus).
+
+	Previously sent preedit_style and preedit_cursor requests are also
+	processed by the text_input.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="text" type="string"/>
+      <arg name="commit" type="string"/>
+    </request>
+
+    <request name="preedit_styling">
+      <description summary="pre-edit styling">
+	Set the styling information on composing text. The style is applied for
+	length in bytes from index relative to the beginning of
+	the composing text (as byte offset). Multiple styles can
+	be applied to a composing text.
+
+	This request should be sent before sending a preedit_string request.
+      </description>
+      <arg name="index" type="uint"/>
+      <arg name="length" type="uint"/>
+      <arg name="style" type="uint"/>
+    </request>
+
+    <request name="preedit_cursor">
+      <description summary="pre-edit cursor">
+	Set the cursor position inside the composing text (as byte offset)
+	relative to the start of the composing text.
+
+	When index is negative no cursor should be displayed.
+
+	This request should be sent before sending a preedit_string request.
+      </description>
+      <arg name="index" type="int"/>
+    </request>
+
+    <request name="delete_surrounding_text">
+      <description summary="delete text">
+	Remove the surrounding text.
+
+	This request will be handled on the text_input side directly following
+	a commit_string request.
+      </description>
+      <arg name="index" type="int"/>
+      <arg name="length" type="uint"/>
+    </request>
+
+    <request name="cursor_position">
+      <description summary="set cursor to a new position">
+	Set the cursor and anchor to a new position. Index is the new cursor
+	position in bytes (when >= 0 this is relative to the end of the inserted text,
+	otherwise it is relative to the beginning of the inserted text). Anchor is
+	the new anchor position in bytes (when >= 0 this is relative to the end of the
+	inserted text, otherwise it is relative to the beginning of the inserted
+	text). When there should be no selected text, anchor should be the same
+	as index.
+
+	This request will be handled on the text_input side directly following
+	a commit_string request.
+      </description>
+      <arg name="index" type="int"/>
+      <arg name="anchor" type="int"/>
+    </request>
+
+    <request name="modifiers_map">
+      <arg name="map" type="array"/>
+    </request>
+
+    <request name="keysym">
+      <description summary="keysym">
+	Notify when a key event was sent. Key events should not be used for
+	normal text input operations, which should be done with commit_string,
+	delete_surrounding_text, etc. The key event follows the wl_keyboard key
+	event convention. Sym is an XKB keysym, state is a wl_keyboard key_state.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="time" type="uint"/>
+      <arg name="sym" type="uint"/>
+      <arg name="state" type="uint"/>
+      <arg name="modifiers" type="uint"/>
+    </request>
+
+    <request name="grab_keyboard">
+      <description summary="grab hardware keyboard">
+	Allow an input method to receive hardware keyboard input and process
+	key events to generate text events (with pre-edit) over the wire. This
+	allows input methods which compose multiple key events for inputting
+	text like it is done for CJK languages.
+      </description>
+      <arg name="keyboard" type="new_id" interface="wl_keyboard"/>
+    </request>
+
+    <request name="key">
+      <description summary="forward key event">
+	Forward a wl_keyboard::key event to the client that was not processed
+	by the input method itself. Should be used when filtering key events
+	with grab_keyboard.  The arguments should be the ones from the
+	wl_keyboard::key event.
+
+	For generating custom key events use the keysym request instead.
+      </description>
+      <arg name="serial" type="uint" summary="serial from wl_keyboard::key"/>
+      <arg name="time" type="uint" summary="time from wl_keyboard::key"/>
+      <arg name="key" type="uint" summary="key from wl_keyboard::key"/>
+      <arg name="state" type="uint" summary="state from wl_keyboard::key"/>
+    </request>
+
+    <request name="modifiers">
+      <description summary="forward modifiers event">
+	Forward a wl_keyboard::modifiers event to the client that was not
+	processed by the input method itself.  Should be used when filtering
+	key events with grab_keyboard. The arguments should be the ones
+	from the wl_keyboard::modifiers event.
+      </description>
+      <arg name="serial" type="uint" summary="serial from wl_keyboard::modifiers"/>
+      <arg name="mods_depressed" type="uint" summary="mods_depressed from wl_keyboard::modifiers"/>
+      <arg name="mods_latched" type="uint" summary="mods_latched from wl_keyboard::modifiers"/>
+      <arg name="mods_locked" type="uint" summary="mods_locked from wl_keyboard::modifiers"/>
+      <arg name="group" type="uint" summary="group from wl_keyboard::modifiers"/>
+    </request>
+
+    <request name="language">
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="language" type="string"/>
+    </request>
+
+    <request name="text_direction">
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="direction" type="uint"/>
+    </request>
+
+    <event name="surrounding_text">
+      <description summary="surrounding text event">
+	The plain surrounding text around the input position. Cursor is the
+	position in bytes within the surrounding text relative to the beginning
+	of the text. Anchor is the position in bytes of the selection anchor
+	within the surrounding text relative to the beginning of the text. If
+	there is no selected text then anchor is the same as cursor.
+      </description>
+      <arg name="text" type="string"/>
+      <arg name="cursor" type="uint"/>
+      <arg name="anchor" type="uint"/>
+    </event>
+
+    <event name="reset">
+    </event>
+
+    <event name="content_type">
+      <arg name="hint" type="uint"/>
+      <arg name="purpose" type="uint"/>
+    </event>
+
+    <event name="invoke_action">
+      <arg name="button" type="uint"/>
+      <arg name="index" type="uint"/>
+    </event>
+
+    <event name="commit_state">
+      <arg name="serial" type="uint" summary="serial of text input state"/>
+    </event>
+
+    <event name="preferred_language">
+      <arg name="language" type="string"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_input_method_v1" version="1">
+    <description summary="input method">
+      An input method object is responsible for composing text in response to
+      input from hardware or virtual keyboards. There is one input method
+      object per seat. On activate there is a new input method context object
+      created which allows the input method to communicate with the text input.
+    </description>
+
+    <event name="activate">
+      <description summary="activate event">
+	A text input was activated. Creates an input method context object
+	which allows communication with the text input.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_input_method_context_v1"/>
+    </event>
+
+    <event name="deactivate">
+      <description summary="deactivate event">
+	The text input corresponding to the context argument was deactivated.
+	The input method context should be destroyed after deactivation is
+	handled.
+      </description>
+      <arg name="context" type="object" interface="zwp_input_method_context_v1"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_input_panel_v1" version="1">
+    <description summary="interface for implementing keyboards">
+      Only one client can bind this interface at a time.
+    </description>
+
+    <request name="get_input_panel_surface">
+      <arg name="id" type="new_id" interface="zwp_input_panel_surface_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_input_panel_surface_v1" version="1">
+    <enum name="position">
+      <entry name="center_bottom" value="0"/>
+    </enum>
+
+    <request name="set_toplevel">
+      <description summary="set the surface type as a keyboard">
+	Set the input_panel_surface type to keyboard.
+
+	A keyboard surface is only shown when a text input is active.
+      </description>
+      <arg name="output" type="object" interface="wl_output"/>
+      <arg name="position" type="uint"/>
+    </request>
+
+    <request name="set_overlay_panel">
+      <description summary="set the surface type as an overlay panel">
+	Set the input_panel_surface to be an overlay panel.
+
+	This is shown near the input cursor above the application window when
+	a text input is active.
+      </description>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/input-timestamps/README b/subprojects/wayland-protocols/unstable/input-timestamps/README
new file mode 100644
index 0000000000000000000000000000000000000000..8ae94a00c06e6302e38bb8632f489c021b5d201a
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/input-timestamps/README
@@ -0,0 +1,4 @@
+High-resolution timestamps for input events.
+
+Maintainers:
+Alexandros Frantzis <alexandros.frantzis@collabora.com> (@afrantzis)
diff --git a/subprojects/wayland-protocols/unstable/input-timestamps/input-timestamps-unstable-v1.xml b/subprojects/wayland-protocols/unstable/input-timestamps/input-timestamps-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7c5e08280af52da3c73326216c6c8cd730a4573e
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/input-timestamps/input-timestamps-unstable-v1.xml
@@ -0,0 +1,145 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="input_timestamps_unstable_v1">
+
+  <copyright>
+    Copyright © 2017 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <description summary="High-resolution timestamps for input events">
+    This protocol specifies a way for a client to request and receive
+    high-resolution timestamps for input events.
+
+    Warning! The protocol described in this file is experimental and
+    backward incompatible changes may be made. Backward compatible changes
+    may be added together with the corresponding interface version bump.
+    Backward incompatible changes are done by bumping the version number in
+    the protocol and interface names and resetting the interface version.
+    Once the protocol is to be declared stable, the 'z' prefix and the
+    version number in the protocol and interface names are removed and the
+    interface version number is reset.
+  </description>
+
+  <interface name="zwp_input_timestamps_manager_v1" version="1">
+    <description summary="context object for high-resolution input timestamps">
+      A global interface used for requesting high-resolution timestamps
+      for input events.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the input timestamps manager object">
+        Informs the server that the client will no longer be using this
+        protocol object. Existing objects created by this object are not
+        affected.
+      </description>
+    </request>
+
+    <request name="get_keyboard_timestamps">
+      <description summary="subscribe to high-resolution keyboard timestamp events">
+        Creates a new input timestamps object that represents a subscription
+        to high-resolution timestamp events for all wl_keyboard events that
+        carry a timestamp.
+
+        If the associated wl_keyboard object is invalidated, either through
+        client action (e.g. release) or server-side changes, the input
+        timestamps object becomes inert and the client should destroy it
+        by calling zwp_input_timestamps_v1.destroy.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_input_timestamps_v1"/>
+      <arg name="keyboard" type="object" interface="wl_keyboard"
+           summary="the wl_keyboard object for which to get timestamp events"/>
+    </request>
+
+    <request name="get_pointer_timestamps">
+      <description summary="subscribe to high-resolution pointer timestamp events">
+        Creates a new input timestamps object that represents a subscription
+        to high-resolution timestamp events for all wl_pointer events that
+        carry a timestamp.
+
+        If the associated wl_pointer object is invalidated, either through
+        client action (e.g. release) or server-side changes, the input
+        timestamps object becomes inert and the client should destroy it
+        by calling zwp_input_timestamps_v1.destroy.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_input_timestamps_v1"/>
+      <arg name="pointer" type="object" interface="wl_pointer"
+           summary="the wl_pointer object for which to get timestamp events"/>
+    </request>
+
+    <request name="get_touch_timestamps">
+      <description summary="subscribe to high-resolution touch timestamp events">
+        Creates a new input timestamps object that represents a subscription
+        to high-resolution timestamp events for all wl_touch events that
+        carry a timestamp.
+
+        If the associated wl_touch object becomes invalid, either through
+        client action (e.g. release) or server-side changes, the input
+        timestamps object becomes inert and the client should destroy it
+        by calling zwp_input_timestamps_v1.destroy.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_input_timestamps_v1"/>
+      <arg name="touch" type="object" interface="wl_touch"
+           summary="the wl_touch object for which to get timestamp events"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_input_timestamps_v1" version="1">
+    <description summary="context object for input timestamps">
+      Provides high-resolution timestamp events for a set of subscribed input
+      events. The set of subscribed input events is determined by the
+      zwp_input_timestamps_manager_v1 request used to create this object.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the input timestamps object">
+        Informs the server that the client will no longer be using this
+        protocol object. After the server processes the request, no more
+        timestamp events will be emitted.
+      </description>
+    </request>
+
+    <event name="timestamp">
+      <description summary="high-resolution timestamp event">
+        The timestamp event is associated with the first subsequent input event
+        carrying a timestamp which belongs to the set of input events this
+        object is subscribed to.
+
+        The timestamp provided by this event is a high-resolution version of
+        the timestamp argument of the associated input event. The provided
+        timestamp is in the same clock domain and is at least as accurate as
+        the associated input event timestamp.
+
+        The timestamp is expressed as tv_sec_hi, tv_sec_lo, tv_nsec triples,
+        each component being an unsigned 32-bit value. Whole seconds are in
+        tv_sec which is a 64-bit value combined from tv_sec_hi and tv_sec_lo,
+        and the additional fractional part in tv_nsec as nanoseconds. Hence,
+        for valid timestamps tv_nsec must be in [0, 999999999].
+      </description>
+      <arg name="tv_sec_hi" type="uint"
+           summary="high 32 bits of the seconds part of the timestamp"/>
+      <arg name="tv_sec_lo" type="uint"
+           summary="low 32 bits of the seconds part of the timestamp"/>
+      <arg name="tv_nsec" type="uint"
+           summary="nanoseconds part of the timestamp"/>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/keyboard-shortcuts-inhibit/README b/subprojects/wayland-protocols/unstable/keyboard-shortcuts-inhibit/README
new file mode 100644
index 0000000000000000000000000000000000000000..7b68667f7152539915bcb60dd2255d1cf65405a0
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/keyboard-shortcuts-inhibit/README
@@ -0,0 +1,4 @@
+Compositor shortcuts inhibit protocol
+
+Maintainers:
+Olivier Fourdan <ofourdan@redhat.com> (@ofourdan)
diff --git a/subprojects/wayland-protocols/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml b/subprojects/wayland-protocols/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..27748764d835daeceb5ff76882783a45878638e5
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unstable-v1.xml
@@ -0,0 +1,143 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="keyboard_shortcuts_inhibit_unstable_v1">
+
+  <copyright>
+    Copyright © 2017 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.
+  </copyright>
+
+  <description summary="Protocol for inhibiting the compositor keyboard shortcuts">
+    This protocol specifies a way for a client to request the compositor
+    to ignore its own keyboard shortcuts for a given seat, so that all
+    key events from that seat get forwarded to a surface.
+
+    Warning! The protocol described in this file is experimental and
+    backward incompatible changes may be made. Backward compatible
+    changes may be added together with the corresponding interface
+    version bump.
+    Backward incompatible changes are done by bumping the version
+    number in the protocol and interface names and resetting the
+    interface version. Once the protocol is to be declared stable,
+    the 'z' prefix and the version number in the protocol and
+    interface names are removed and the interface version number is
+    reset.
+  </description>
+
+  <interface name="zwp_keyboard_shortcuts_inhibit_manager_v1" version="1">
+    <description summary="context object for keyboard grab_manager">
+      A global interface used for inhibiting the compositor keyboard shortcuts.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the keyboard shortcuts inhibitor object">
+	Destroy the keyboard shortcuts inhibitor manager.
+      </description>
+    </request>
+
+    <request name="inhibit_shortcuts">
+      <description summary="create a new keyboard shortcuts inhibitor object">
+	Create a new keyboard shortcuts inhibitor object associated with
+	the given surface for the given seat.
+
+	If shortcuts are already inhibited for the specified seat and surface,
+	a protocol error "already_inhibited" is raised by the compositor.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_keyboard_shortcuts_inhibitor_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the surface that inhibits the keyboard shortcuts behavior"/>
+      <arg name="seat" type="object" interface="wl_seat"
+	   summary="the wl_seat for which keyboard shortcuts should be disabled"/>
+    </request>
+
+    <enum name="error">
+      <entry name="already_inhibited"
+	     value="0"
+	     summary="the shortcuts are already inhibited for this surface"/>
+    </enum>
+  </interface>
+
+  <interface name="zwp_keyboard_shortcuts_inhibitor_v1" version="1">
+    <description summary="context object for keyboard shortcuts inhibitor">
+      A keyboard shortcuts inhibitor instructs the compositor to ignore
+      its own keyboard shortcuts when the associated surface has keyboard
+      focus. As a result, when the surface has keyboard focus on the given
+      seat, it will receive all key events originating from the specified
+      seat, even those which would normally be caught by the compositor for
+      its own shortcuts.
+
+      The Wayland compositor is however under no obligation to disable
+      all of its shortcuts, and may keep some special key combo for its own
+      use, including but not limited to one allowing the user to forcibly
+      restore normal keyboard events routing in the case of an unwilling
+      client. The compositor may also use the same key combo to reactivate
+      an existing shortcut inhibitor that was previously deactivated on
+      user request.
+
+      When the compositor restores its own keyboard shortcuts, an
+      "inactive" event is emitted to notify the client that the keyboard
+      shortcuts inhibitor is not effectively active for the surface and
+      seat any more, and the client should not expect to receive all
+      keyboard events.
+
+      When the keyboard shortcuts inhibitor is inactive, the client has
+      no way to forcibly reactivate the keyboard shortcuts inhibitor.
+
+      The user can chose to re-enable a previously deactivated keyboard
+      shortcuts inhibitor using any mechanism the compositor may offer,
+      in which case the compositor will send an "active" event to notify
+      the client.
+
+      If the surface is destroyed, unmapped, or loses the seat's keyboard
+      focus, the keyboard shortcuts inhibitor becomes irrelevant and the
+      compositor will restore its own keyboard shortcuts but no "inactive"
+      event is emitted in this case.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the keyboard shortcuts inhibitor object">
+	Remove the keyboard shortcuts inhibitor from the associated wl_surface.
+      </description>
+    </request>
+
+    <event name="active">
+      <description summary="shortcuts are inhibited">
+	This event indicates that the shortcut inhibitor is active.
+
+	The compositor sends this event every time compositor shortcuts
+	are inhibited on behalf of the surface. When active, the client
+	may receive input events normally reserved by the compositor
+	(see zwp_keyboard_shortcuts_inhibitor_v1).
+
+	This occurs typically when the initial request "inhibit_shortcuts"
+	first becomes active or when the user instructs the compositor to
+	re-enable and existing shortcuts inhibitor using any mechanism
+	offered by the compositor.
+      </description>
+    </event>
+
+    <event name="inactive">
+      <description summary="shortcuts are restored">
+	This event indicates that the shortcuts inhibitor is inactive,
+	normal shortcuts processing is restored by the compositor.
+       </description>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/linux-dmabuf/README b/subprojects/wayland-protocols/unstable/linux-dmabuf/README
new file mode 100644
index 0000000000000000000000000000000000000000..ce08fcaad09c9836a7d58642b894681523fe5396
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/linux-dmabuf/README
@@ -0,0 +1,9 @@
+Linux DMA-BUF protocol
+
+Maintainers:
+Pekka Paalanen <pekka.paalanen@collabora.co.uk> (@pq)
+Daniel Stone <daniels@collabora.com> (@daniels)
+
+Disclaimer: This protocol extension has been marked stable. This copy is
+no longer used and only retained for backwards compatibility. The
+canonical version can be found in the stable/ directory.
diff --git a/subprojects/wayland-protocols/unstable/linux-dmabuf/feedback.rst b/subprojects/wayland-protocols/unstable/linux-dmabuf/feedback.rst
new file mode 100644
index 0000000000000000000000000000000000000000..a3f94ed456db6a755adbf661f4d80bc2684842c6
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/linux-dmabuf/feedback.rst
@@ -0,0 +1,218 @@
+.. Copyright 2021 Simon Ser
+
+.. contents::
+
+
+linux-dmabuf feedback introduction
+==================================
+
+linux-dmabuf feedback allows compositors and clients to negotiate optimal buffer
+allocation parameters. This document will assume that the compositor is using a
+rendering API such as OpenGL or Vulkan and KMS as the presentation API: even if
+linux-dmabuf feedback isn't restricted to this use-case, it's the most common.
+
+linux-dmabuf feedback introduces the following concepts:
+
+1. A main device. This is the render device that the compositor is using to
+   perform composition. Compositors should always be able to display a buffer
+   submitted by a client, so this device can be used as a fallback in case none
+   of the more optimized code-paths work. Clients should allocate buffers such
+   that they can be imported and textured from the main device.
+
+2. One or more tranches. Each tranche consists of a target device, allocation
+   flags and a set of format/modifier pairs. A tranche can be seen as a set of
+   formats/modifier pairs that are compatible with the target device.
+
+   A tranche can have the ``scanout`` flag. It means that the target device is
+   a KMS device, and that buffers allocated with one of the format/modifier
+   pairs in the tranche are eligible for direct scanout.
+
+   Clients should use the tranches in order to allocate buffers with the most
+   appropriate format/modifier and also to avoid allocating in private device
+   memory when cross-device operations are going to happen.
+
+linux-dmabuf feedback implementation notes
+==========================================
+
+This section contains recommendations for client and compositor implementations.
+
+For clients
+-----------
+
+Clients are expected to either pick a fixed DRM format beforehand, or
+perform the following steps repeatedly until they find a suitable format.
+
+Basic clients may only support static buffer allocation on startup. These
+clients should do the following:
+
+1. Send a ``get_default_feedback`` request to get global feedback.
+2. Select the device indicated by ``main_device`` for allocation.
+3. For each tranche:
+
+   1. If ``tranche_target_device`` doesn't match the allocation device, ignore
+      the tranche.
+   2. Accumulate allocation flags from ``tranche_flags``.
+   3. Accumulate format/modifier pairs received via ``tranche_formats`` in a
+      list.
+   4. When the ``tranche_done`` event is received, try to allocate the buffer
+      with the accumulated list of modifiers and allocation flags. If that
+      fails, proceed with the next tranche. If that succeeds, stop the loop.
+
+4. Destroy the feedback object.
+
+Tranches are ordered by preference: the more optimized tranches come first. As
+such, clients should use the first tranche that happens to work.
+
+Some clients may have already selected the device they want to use beforehand.
+These clients can ignore the ``main_device`` event, and ignore tranches whose
+``tranche_target_device`` doesn't match the selected device. Such clients need
+to be prepared for the ``wp_linux_buffer_params.create`` request to potentially
+fail.
+
+If the client allocates a buffer without specifying explicit modifiers on a
+device different from the one indicated by ``main_device``, then the client
+must force a linear layout.
+
+Some clients might support re-negotiating the buffer format/modifier on the
+fly. These clients should send a ``get_surface_feedback`` request and keep the
+feedback object alive after the initial allocation. Each time a new set of
+feedback parameters is received (ended by the ``done`` event), they should
+perform the same steps as basic clients described above. They should detect
+when the optimal allocation parameters didn't change (same
+format/modifier/flags) to avoid needlessly re-allocating their buffers.
+
+Some clients might additionally support switching the device used for
+allocations on the fly. Such clients should send a ``get_surface_feedback``
+request. For each tranche, select the device indicated by
+``tranche_target_device`` for allocation. Accumulate allocation flags (received
+via ``tranche_flags``) and format/modifier pairs (received via
+``tranche_formats``) as usual. When the ``tranche_done`` event is received, try
+to allocate the buffer with the accumulated list of modifiers and the
+allocation flags. Try to import the resulting buffer by sending a
+``wp_linux_buffer_params.create`` request (this might fail). Repeat with each
+tranche until an allocation and import succeeds. Each time a new set of
+feedback parameters is received, they should perform these steps again. They
+should detect when the optimal allocation parameters didn't change (same
+device/format/modifier/flags) to avoid needlessly re-allocating their buffers.
+
+For compositors
+---------------
+
+Basic compositors may only support texturing the DMA-BUFs via a rendering API
+such as OpenGL or Vulkan. Such compositors can send a single tranche as a reply
+to both ``get_default_feedback`` and ``get_surface_feedback``. Set the
+``main_device`` to the rendering device. Send the tranche with
+``tranche_target_device`` set to the rendering device and all of the DRM
+format/modifier pairs supported by the rendering API. Do not set the
+``scanout`` flag in the ``tranche_flags`` event.
+
+Some compositors may support direct scan-out for full-screen surfaces. These
+compositors can re-send the feedback parameters when a surface becomes
+full-screen or leaves full-screen mode if the client has used the
+``get_surface_feedback`` request. The non-full-screen feedback parameters are
+the same as basic compositors described above. The full-screen feedback
+parameters have two tranches: one with the format/modifier pairs supported by
+the KMS plane, with the ``scanout`` flag set in the ``tranche_flags`` event and
+with ``tranche_target_device`` set to the KMS scan-out device; the other with
+the rest of the format/modifier pairs (supported for texturing, but not for
+scan-out), without the ``scanout`` flag set in the ``tranche_flags`` event, and
+with the ``tranche_target_device`` set to the rendering device.
+
+Some compositors may support direct scan-out for all surfaces. These
+compositors can send two tranches for surfaces that become candidates for
+direct scan-out, similarly to compositors supporting direct scan-out for
+fullscreen surfaces. When a surface stops being a candidate for direct
+scan-out, compositors should re-send the feedback parameters optimized for
+texturing only.  The way candidates for direct scan-out are selected is
+compositor policy, a possible implementation is to select as many surfaces as
+there are available hardware planes, starting from surfaces closer to the eye.
+
+Some compositors may support multiple devices at the same time. If the
+compositor supports rendering with a fixed device and direct scan-out on a
+secondary device, it may send a separate tranche for surfaces displayed on
+the secondary device that are candidates for direct scan-out. The
+``tranche_target_device`` for this tranche will be the secondary device and
+will not match the ``main_device``.
+
+Some compositors may support switching their rendering device at runtime or
+changing their rendering device depending on the surface. When the rendering
+device changes for a surface, such compositors may re-send the feedback
+parameters with a different ``main_device``. However there is a risk that
+clients don't support switching their device at runtime and continue using the
+previous device. For this reason, compositors should always have a fallback
+rendering device that they initially send as ``main_device``, such that these
+clients use said fallback device.
+
+Compositors should not change the ``main_device`` on-the-fly when explicit
+modifiers are not supported, because there's a risk of importing buffers
+with an implicit non-linear modifier as a linear buffer, resulting in
+misinterpreted buffer contents.
+
+Compositors should not send feedback parameters if they don't have a fallback
+path. For instance, compositors shouldn't send a format/modifier supported for
+direct scan-out but not supported by the rendering API for texturing.
+
+Compositors can decide to use multiple tranches to describe the allocation
+parameters optimized for texturing. For example, if there are formats which
+have a fast texturing path and formats which have a slower texturing path, the
+compositor can decide to expose two separate tranches.
+
+Compositors can decide to use intermediate tranches to describe code-paths
+slower than direct scan-out but faster than texturing. For instance, a
+compositor could insert an intermediate tranche if it's possible to use a
+mem2mem device to convert buffers to be able to use scan-out.
+
+``dev_t`` encoding
+==================
+
+The protocol carries ``dev_t`` values on the wire using arrays. A compositor
+written in C can encode the values as follows:
+
+.. code-block:: c
+
+    struct stat drm_node_stat;
+    struct wl_array dev_array = {
+        .size = sizeof(drm_node_stat.st_rdev),
+        .data = &drm_node_stat.st_rdev,
+    };
+
+A client can decode the values as follows:
+
+.. code-block:: c
+
+    dev_t dev;
+    assert(dev_array->size == sizeof(dev));
+    memcpy(&dev, dev_array->data, sizeof(dev));
+
+Because two DRM nodes can refer to the same DRM device while having different
+``dev_t`` values, clients should use ``drmDevicesEqual`` to compare two
+devices.
+
+``format_table`` encoding
+=========================
+
+The ``format_table`` event carries a file descriptor containing a list of
+format + modifier pairs. The list is an array of pairs which can be accessed
+with this C structure definition:
+
+.. code-block:: c
+
+    struct dmabuf_format_modifier {
+        uint32_t format;
+        uint32_t pad; /* unused */
+        uint64_t modifier;
+    };
+
+Integration with other APIs
+===========================
+
+- libdrm: ``drmGetDeviceFromDevId`` returns a ``drmDevice`` from a device ID.
+- EGL: the `EGL_EXT_device_drm_render_node`_ extension may be used to query the
+  DRM device render node used by a given EGL display. When unavailable, the
+  older `EGL_EXT_device_drm`_ extension may be used as a fallback.
+- Vulkan: the `VK_EXT_physical_device_drm`_ extension may be used to query the
+  DRM device used by a given ``VkPhysicalDevice``.
+
+.. _EGL_EXT_device_drm: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_drm.txt
+.. _EGL_EXT_device_drm_render_node: https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_device_drm_render_node.txt
+.. _VK_EXT_physical_device_drm: https://www.khronos.org/registry/vulkan/specs/1.2-extensions/man/html/VK_EXT_physical_device_drm.html
diff --git a/subprojects/wayland-protocols/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml b/subprojects/wayland-protocols/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6f11e925b68e0b48899a1f15733685732fca2725
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/linux-dmabuf/linux-dmabuf-unstable-v1.xml
@@ -0,0 +1,589 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="linux_dmabuf_unstable_v1">
+
+  <copyright>
+    Copyright © 2014, 2015 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_linux_dmabuf_v1" version="5">
+    <description summary="factory for creating dmabuf-based wl_buffers">
+      Following the interfaces from:
+      https://www.khronos.org/registry/egl/extensions/EXT/EGL_EXT_image_dma_buf_import.txt
+      https://www.khronos.org/registry/EGL/extensions/EXT/EGL_EXT_image_dma_buf_import_modifiers.txt
+      and the Linux DRM sub-system's AddFb2 ioctl.
+
+      This interface offers ways to create generic dmabuf-based wl_buffers.
+
+      Clients can use the get_surface_feedback request to get dmabuf feedback
+      for a particular surface. If the client wants to retrieve feedback not
+      tied to a surface, they can use the get_default_feedback request.
+
+      The following are required from clients:
+
+      - Clients must ensure that either all data in the dma-buf is
+        coherent for all subsequent read access or that coherency is
+        correctly handled by the underlying kernel-side dma-buf
+        implementation.
+
+      - Don't make any more attachments after sending the buffer to the
+        compositor. Making more attachments later increases the risk of
+        the compositor not being able to use (re-import) an existing
+        dmabuf-based wl_buffer.
+
+      The underlying graphics stack must ensure the following:
+
+      - The dmabuf file descriptors relayed to the server will stay valid
+        for the whole lifetime of the wl_buffer. This means the server may
+        at any time use those fds to import the dmabuf into any kernel
+        sub-system that might accept it.
+
+      However, when the underlying graphics stack fails to deliver the
+      promise, because of e.g. a device hot-unplug which raises internal
+      errors, after the wl_buffer has been successfully created the
+      compositor must not raise protocol errors to the client when dmabuf
+      import later fails.
+
+      To create a wl_buffer from one or more dmabufs, a client creates a
+      zwp_linux_dmabuf_params_v1 object with a zwp_linux_dmabuf_v1.create_params
+      request. All planes required by the intended format are added with
+      the 'add' request. Finally, a 'create' or 'create_immed' request is
+      issued, which has the following outcome depending on the import success.
+
+      The 'create' request,
+      - on success, triggers a 'created' event which provides the final
+        wl_buffer to the client.
+      - on failure, triggers a 'failed' event to convey that the server
+        cannot use the dmabufs received from the client.
+
+      For the 'create_immed' request,
+      - on success, the server immediately imports the added dmabufs to
+        create a wl_buffer. No event is sent from the server in this case.
+      - on failure, the server can choose to either:
+        - terminate the client by raising a fatal error.
+        - mark the wl_buffer as failed, and send a 'failed' event to the
+          client. If the client uses a failed wl_buffer as an argument to any
+          request, the behaviour is compositor implementation-defined.
+
+      For all DRM formats and unless specified in another protocol extension,
+      pre-multiplied alpha is used for pixel values.
+
+      Unless specified otherwise in another protocol extension, implicit
+      synchronization is used. In other words, compositors and clients must
+      wait and signal fences implicitly passed via the DMA-BUF's reservation
+      mechanism.
+
+      Disclaimer: This protocol extension has been marked stable. This copy is
+      no longer used and only retained for backwards compatibility. The
+      canonical version can be found in the stable/ directory.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind the factory">
+        Objects created through this interface, especially wl_buffers, will
+        remain valid.
+      </description>
+    </request>
+
+    <request name="create_params">
+      <description summary="create a temporary object for buffer parameters">
+        This temporary object is used to collect multiple dmabuf handles into
+        a single batch to create a wl_buffer. It can only be used once and
+        should be destroyed after a 'created' or 'failed' event has been
+        received.
+      </description>
+      <arg name="params_id" type="new_id" interface="zwp_linux_buffer_params_v1"
+           summary="the new temporary"/>
+    </request>
+
+    <event name="format">
+      <description summary="supported buffer format">
+        This event advertises one buffer format that the server supports.
+        All the supported formats are advertised once when the client
+        binds to this interface. A roundtrip after binding guarantees
+        that the client has received all supported formats.
+
+        For the definition of the format codes, see the
+        zwp_linux_buffer_params_v1::create request.
+
+        Starting version 4, the format event is deprecated and must not be
+        sent by compositors. Instead, use get_default_feedback or
+        get_surface_feedback.
+      </description>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+    </event>
+
+    <event name="modifier" since="3">
+      <description summary="supported buffer format modifier">
+        This event advertises the formats that the server supports, along with
+        the modifiers supported for each format. All the supported modifiers
+        for all the supported formats are advertised once when the client
+        binds to this interface. A roundtrip after binding guarantees that
+        the client has received all supported format-modifier pairs.
+
+        For legacy support, DRM_FORMAT_MOD_INVALID (that is, modifier_hi ==
+        0x00ffffff and modifier_lo == 0xffffffff) is allowed in this event.
+        It indicates that the server can support the format with an implicit
+        modifier. When a plane has DRM_FORMAT_MOD_INVALID as its modifier, it
+        is as if no explicit modifier is specified. The effective modifier
+        will be derived from the dmabuf.
+
+        A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for
+        a given format supports both explicit modifiers and implicit modifiers.
+
+        For the definition of the format and modifier codes, see the
+        zwp_linux_buffer_params_v1::create and zwp_linux_buffer_params_v1::add
+        requests.
+
+        Starting version 4, the modifier event is deprecated and must not be
+        sent by compositors. Instead, use get_default_feedback or
+        get_surface_feedback.
+      </description>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="modifier_hi" type="uint"
+           summary="high 32 bits of layout modifier"/>
+      <arg name="modifier_lo" type="uint"
+           summary="low 32 bits of layout modifier"/>
+    </event>
+
+    <!-- Version 4 additions -->
+
+    <request name="get_default_feedback" since="4">
+      <description summary="get default feedback">
+        This request creates a new wp_linux_dmabuf_feedback object not bound
+        to a particular surface. This object will deliver feedback about dmabuf
+        parameters to use if the client doesn't support per-surface feedback
+        (see get_surface_feedback).
+      </description>
+      <arg name="id" type="new_id" interface="zwp_linux_dmabuf_feedback_v1"/>
+    </request>
+
+    <request name="get_surface_feedback" since="4">
+      <description summary="get feedback for a surface">
+        This request creates a new wp_linux_dmabuf_feedback object for the
+        specified wl_surface. This object will deliver feedback about dmabuf
+        parameters to use for buffers attached to this surface.
+
+        If the surface is destroyed before the wp_linux_dmabuf_feedback object,
+        the feedback object becomes inert.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_linux_dmabuf_feedback_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_linux_buffer_params_v1" version="5">
+    <description summary="parameters for creating a dmabuf-based wl_buffer">
+      This temporary object is a collection of dmabufs and other
+      parameters that together form a single logical buffer. The temporary
+      object may eventually create one wl_buffer unless cancelled by
+      destroying it before requesting 'create'.
+
+      Single-planar formats only require one dmabuf, however
+      multi-planar formats may require more than one dmabuf. For all
+      formats, an 'add' request must be called once per plane (even if the
+      underlying dmabuf fd is identical).
+
+      You must use consecutive plane indices ('plane_idx' argument for 'add')
+      from zero to the number of planes used by the drm_fourcc format code.
+      All planes required by the format must be given exactly once, but can
+      be given in any order. Each plane index can be set only once.
+    </description>
+
+    <enum name="error">
+      <entry name="already_used" value="0"
+             summary="the dmabuf_batch object has already been used to create a wl_buffer"/>
+      <entry name="plane_idx" value="1"
+             summary="plane index out of bounds"/>
+      <entry name="plane_set" value="2"
+             summary="the plane index was already set"/>
+      <entry name="incomplete" value="3"
+             summary="missing or too many planes to create a buffer"/>
+      <entry name="invalid_format" value="4"
+             summary="format not supported"/>
+      <entry name="invalid_dimensions" value="5"
+             summary="invalid width or height"/>
+      <entry name="out_of_bounds" value="6"
+             summary="offset + stride * height goes out of dmabuf bounds"/>
+      <entry name="invalid_wl_buffer" value="7"
+             summary="invalid wl_buffer resulted from importing dmabufs via
+               the create_immed request on given buffer_params"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete this object, used or not">
+        Cleans up the temporary data sent to the server for dmabuf-based
+        wl_buffer creation.
+      </description>
+    </request>
+
+    <request name="add">
+      <description summary="add a dmabuf to the temporary set">
+        This request adds one dmabuf to the set in this
+        zwp_linux_buffer_params_v1.
+
+        The 64-bit unsigned value combined from modifier_hi and modifier_lo
+        is the dmabuf layout modifier. DRM AddFB2 ioctl calls this the
+        fb modifier, which is defined in drm_mode.h of Linux UAPI.
+        This is an opaque token. Drivers use this token to express tiling,
+        compression, etc. driver-specific modifications to the base format
+        defined by the DRM fourcc code.
+
+        Starting from version 4, the invalid_format protocol error is sent if
+        the format + modifier pair was not advertised as supported.
+
+        Starting from version 5, the invalid_format protocol error is sent if
+        all planes don't use the same modifier.
+
+        This request raises the PLANE_IDX error if plane_idx is too large.
+        The error PLANE_SET is raised if attempting to set a plane that
+        was already set.
+      </description>
+      <arg name="fd" type="fd" summary="dmabuf fd"/>
+      <arg name="plane_idx" type="uint" summary="plane index"/>
+      <arg name="offset" type="uint" summary="offset in bytes"/>
+      <arg name="stride" type="uint" summary="stride in bytes"/>
+      <arg name="modifier_hi" type="uint"
+           summary="high 32 bits of layout modifier"/>
+      <arg name="modifier_lo" type="uint"
+           summary="low 32 bits of layout modifier"/>
+    </request>
+
+    <enum name="flags" bitfield="true">
+      <entry name="y_invert" value="1" summary="contents are y-inverted"/>
+      <entry name="interlaced" value="2" summary="content is interlaced"/>
+      <entry name="bottom_first" value="4" summary="bottom field first"/>
+    </enum>
+
+    <request name="create">
+      <description summary="create a wl_buffer from the given dmabufs">
+        This asks for creation of a wl_buffer from the added dmabuf
+        buffers. The wl_buffer is not created immediately but returned via
+        the 'created' event if the dmabuf sharing succeeds. The sharing
+        may fail at runtime for reasons a client cannot predict, in
+        which case the 'failed' event is triggered.
+
+        The 'format' argument is a DRM_FORMAT code, as defined by the
+        libdrm's drm_fourcc.h. The Linux kernel's DRM sub-system is the
+        authoritative source on how the format codes should work.
+
+        The 'flags' is a bitfield of the flags defined in enum "flags".
+        'y_invert' means the that the image needs to be y-flipped.
+
+        Flag 'interlaced' means that the frame in the buffer is not
+        progressive as usual, but interlaced. An interlaced buffer as
+        supported here must always contain both top and bottom fields.
+        The top field always begins on the first pixel row. The temporal
+        ordering between the two fields is top field first, unless
+        'bottom_first' is specified. It is undefined whether 'bottom_first'
+        is ignored if 'interlaced' is not set.
+
+        This protocol does not convey any information about field rate,
+        duration, or timing, other than the relative ordering between the
+        two fields in one buffer. A compositor may have to estimate the
+        intended field rate from the incoming buffer rate. It is undefined
+        whether the time of receiving wl_surface.commit with a new buffer
+        attached, applying the wl_surface state, wl_surface.frame callback
+        trigger, presentation, or any other point in the compositor cycle
+        is used to measure the frame or field times. There is no support
+        for detecting missed or late frames/fields/buffers either, and
+        there is no support whatsoever for cooperating with interlaced
+        compositor output.
+
+        The composited image quality resulting from the use of interlaced
+        buffers is explicitly undefined. A compositor may use elaborate
+        hardware features or software to deinterlace and create progressive
+        output frames from a sequence of interlaced input buffers, or it
+        may produce substandard image quality. However, compositors that
+        cannot guarantee reasonable image quality in all cases are recommended
+        to just reject all interlaced buffers.
+
+        Any argument errors, including non-positive width or height,
+        mismatch between the number of planes and the format, bad
+        format, bad offset or stride, may be indicated by fatal protocol
+        errors: INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS,
+        OUT_OF_BOUNDS.
+
+        Dmabuf import errors in the server that are not obvious client
+        bugs are returned via the 'failed' event as non-fatal. This
+        allows attempting dmabuf sharing and falling back in the client
+        if it fails.
+
+        This request can be sent only once in the object's lifetime, after
+        which the only legal request is destroy. This object should be
+        destroyed after issuing a 'create' request. Attempting to use this
+        object after issuing 'create' raises ALREADY_USED protocol error.
+
+        It is not mandatory to issue 'create'. If a client wants to
+        cancel the buffer creation, it can just destroy this object.
+      </description>
+      <arg name="width" type="int" summary="base plane width in pixels"/>
+      <arg name="height" type="int" summary="base plane height in pixels"/>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="flags" type="uint" enum="flags" summary="see enum flags"/>
+    </request>
+
+    <event name="created">
+      <description summary="buffer creation succeeded">
+        This event indicates that the attempted buffer creation was
+        successful. It provides the new wl_buffer referencing the dmabuf(s).
+
+        Upon receiving this event, the client should destroy the
+        zwp_linux_buffer_params_v1 object.
+      </description>
+      <arg name="buffer" type="new_id" interface="wl_buffer"
+           summary="the newly created wl_buffer"/>
+    </event>
+
+    <event name="failed">
+      <description summary="buffer creation failed">
+        This event indicates that the attempted buffer creation has
+        failed. It usually means that one of the dmabuf constraints
+        has not been fulfilled.
+
+        Upon receiving this event, the client should destroy the
+        zwp_linux_buffer_params_v1 object.
+      </description>
+    </event>
+
+    <request name="create_immed" since="2">
+      <description summary="immediately create a wl_buffer from the given
+                     dmabufs">
+        This asks for immediate creation of a wl_buffer by importing the
+        added dmabufs.
+
+        In case of import success, no event is sent from the server, and the
+        wl_buffer is ready to be used by the client.
+
+        Upon import failure, either of the following may happen, as seen fit
+        by the implementation:
+        - the client is terminated with one of the following fatal protocol
+          errors:
+          - INCOMPLETE, INVALID_FORMAT, INVALID_DIMENSIONS, OUT_OF_BOUNDS,
+            in case of argument errors such as mismatch between the number
+            of planes and the format, bad format, non-positive width or
+            height, or bad offset or stride.
+          - INVALID_WL_BUFFER, in case the cause for failure is unknown or
+            platform specific.
+        - the server creates an invalid wl_buffer, marks it as failed and
+          sends a 'failed' event to the client. The result of using this
+          invalid wl_buffer as an argument in any request by the client is
+          defined by the compositor implementation.
+
+        This takes the same arguments as a 'create' request, and obeys the
+        same restrictions.
+      </description>
+      <arg name="buffer_id" type="new_id" interface="wl_buffer"
+           summary="id for the newly created wl_buffer"/>
+      <arg name="width" type="int" summary="base plane width in pixels"/>
+      <arg name="height" type="int" summary="base plane height in pixels"/>
+      <arg name="format" type="uint" summary="DRM_FORMAT code"/>
+      <arg name="flags" type="uint" enum="flags" summary="see enum flags"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_linux_dmabuf_feedback_v1" version="5">
+    <description summary="dmabuf feedback">
+      This object advertises dmabuf parameters feedback. This includes the
+      preferred devices and the supported formats/modifiers.
+
+      The parameters are sent once when this object is created and whenever they
+      change. The done event is always sent once after all parameters have been
+      sent. When a single parameter changes, all parameters are re-sent by the
+      compositor.
+
+      Compositors can re-send the parameters when the current client buffer
+      allocations are sub-optimal. Compositors should not re-send the
+      parameters if re-allocating the buffers would not result in a more optimal
+      configuration. In particular, compositors should avoid sending the exact
+      same parameters multiple times in a row.
+
+      The tranche_target_device and tranche_formats events are grouped by
+      tranches of preference. For each tranche, a tranche_target_device, one
+      tranche_flags and one or more tranche_formats events are sent, followed
+      by a tranche_done event finishing the list. The tranches are sent in
+      descending order of preference. All formats and modifiers in the same
+      tranche have the same preference.
+
+      To send parameters, the compositor sends one main_device event, tranches
+      (each consisting of one tranche_target_device event, one tranche_flags
+      event, tranche_formats events and then a tranche_done event), then one
+      done event.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the feedback object">
+        Using this request a client can tell the server that it is not going to
+        use the wp_linux_dmabuf_feedback object anymore.
+      </description>
+    </request>
+
+    <event name="done">
+      <description summary="all feedback has been sent">
+        This event is sent after all parameters of a wp_linux_dmabuf_feedback
+        object have been sent.
+
+        This allows changes to the wp_linux_dmabuf_feedback parameters to be
+        seen as atomic, even if they happen via multiple events.
+      </description>
+    </event>
+
+    <event name="format_table">
+      <description summary="format and modifier table">
+        This event provides a file descriptor which can be memory-mapped to
+        access the format and modifier table.
+
+        The table contains a tightly packed array of consecutive format +
+        modifier pairs. Each pair is 16 bytes wide. It contains a format as a
+        32-bit unsigned integer, followed by 4 bytes of unused padding, and a
+        modifier as a 64-bit unsigned integer. The native endianness is used.
+
+        The client must map the file descriptor in read-only private mode.
+
+        Compositors are not allowed to mutate the table file contents once this
+        event has been sent. Instead, compositors must create a new, separate
+        table file and re-send feedback parameters. Compositors are allowed to
+        store duplicate format + modifier pairs in the table.
+      </description>
+      <arg name="fd" type="fd" summary="table file descriptor"/>
+      <arg name="size" type="uint" summary="table size, in bytes"/>
+    </event>
+
+    <event name="main_device">
+      <description summary="preferred main device">
+        This event advertises the main device that the server prefers to use
+        when direct scan-out to the target device isn't possible. The
+        advertised main device may be different for each
+        wp_linux_dmabuf_feedback object, and may change over time.
+
+        There is exactly one main device. The compositor must send at least
+        one preference tranche with tranche_target_device equal to main_device.
+
+        Clients need to create buffers that the main device can import and
+        read from, otherwise creating the dmabuf wl_buffer will fail (see the
+        wp_linux_buffer_params.create and create_immed requests for details).
+        The main device will also likely be kept active by the compositor,
+        so clients can use it instead of waking up another device for power
+        savings.
+
+        In general the device is a DRM node. The DRM node type (primary vs.
+        render) is unspecified. Clients must not rely on the compositor sending
+        a particular node type. Clients cannot check two devices for equality
+        by comparing the dev_t value.
+
+        If explicit modifiers are not supported and the client performs buffer
+        allocations on a different device than the main device, then the client
+        must force the buffer to have a linear layout.
+      </description>
+      <arg name="device" type="array" summary="device dev_t value"/>
+    </event>
+
+    <event name="tranche_done">
+      <description summary="a preference tranche has been sent">
+        This event splits tranche_target_device and tranche_formats events in
+        preference tranches. It is sent after a set of tranche_target_device
+        and tranche_formats events; it represents the end of a tranche. The
+        next tranche will have a lower preference.
+      </description>
+    </event>
+
+    <event name="tranche_target_device">
+      <description summary="target device">
+        This event advertises the target device that the server prefers to use
+        for a buffer created given this tranche. The advertised target device
+        may be different for each preference tranche, and may change over time.
+
+        There is exactly one target device per tranche.
+
+        The target device may be a scan-out device, for example if the
+        compositor prefers to directly scan-out a buffer created given this
+        tranche. The target device may be a rendering device, for example if
+        the compositor prefers to texture from said buffer.
+
+        The client can use this hint to allocate the buffer in a way that makes
+        it accessible from the target device, ideally directly. The buffer must
+        still be accessible from the main device, either through direct import
+        or through a potentially more expensive fallback path. If the buffer
+        can't be directly imported from the main device then clients must be
+        prepared for the compositor changing the tranche priority or making
+        wl_buffer creation fail (see the wp_linux_buffer_params.create and
+        create_immed requests for details).
+
+        If the device is a DRM node, the DRM node type (primary vs. render) is
+        unspecified. Clients must not rely on the compositor sending a
+        particular node type. Clients cannot check two devices for equality by
+        comparing the dev_t value.
+
+        This event is tied to a preference tranche, see the tranche_done event.
+      </description>
+      <arg name="device" type="array" summary="device dev_t value"/>
+    </event>
+
+    <event name="tranche_formats">
+      <description summary="supported buffer format modifier">
+        This event advertises the format + modifier combinations that the
+        compositor supports.
+
+        It carries an array of indices, each referring to a format + modifier
+        pair in the last received format table (see the format_table event).
+        Each index is a 16-bit unsigned integer in native endianness.
+
+        For legacy support, DRM_FORMAT_MOD_INVALID is an allowed modifier.
+        It indicates that the server can support the format with an implicit
+        modifier. When a buffer has DRM_FORMAT_MOD_INVALID as its modifier, it
+        is as if no explicit modifier is specified. The effective modifier
+        will be derived from the dmabuf.
+
+        A compositor that sends valid modifiers and DRM_FORMAT_MOD_INVALID for
+        a given format supports both explicit modifiers and implicit modifiers.
+
+        Compositors must not send duplicate format + modifier pairs within the
+        same tranche or across two different tranches with the same target
+        device and flags.
+
+        This event is tied to a preference tranche, see the tranche_done event.
+
+        For the definition of the format and modifier codes, see the
+        wp_linux_buffer_params.create request.
+      </description>
+      <arg name="indices" type="array" summary="array of 16-bit indexes"/>
+    </event>
+
+    <enum name="tranche_flags" bitfield="true">
+      <entry name="scanout" value="1" summary="direct scan-out tranche"/>
+    </enum>
+
+    <event name="tranche_flags">
+      <description summary="tranche flags">
+        This event sets tranche-specific flags.
+
+        The scanout flag is a hint that direct scan-out may be attempted by the
+        compositor on the target device if the client appropriately allocates a
+        buffer. How to allocate a buffer that can be scanned out on the target
+        device is implementation-defined.
+
+        This event is tied to a preference tranche, see the tranche_done event.
+      </description>
+      <arg name="flags" type="uint" enum="tranche_flags" summary="tranche flags"/>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/linux-explicit-synchronization/README b/subprojects/wayland-protocols/unstable/linux-explicit-synchronization/README
new file mode 100644
index 0000000000000000000000000000000000000000..0c772738ed8cd33788e34910e2e260422b391615
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/linux-explicit-synchronization/README
@@ -0,0 +1,5 @@
+Linux explicit synchronization (dma-fence) protocol
+
+Maintainers:
+Daniel Stone <daniels@collabora.com> (@daniels)
+Alexandros Frantzis <alexandros.frantzis@collabora.com> (@afrantzis)
diff --git a/subprojects/wayland-protocols/unstable/linux-explicit-synchronization/linux-explicit-synchronization-unstable-v1.xml b/subprojects/wayland-protocols/unstable/linux-explicit-synchronization/linux-explicit-synchronization-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..35a973535b266c58c2748f80c68c78cea82e0d58
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/linux-explicit-synchronization/linux-explicit-synchronization-unstable-v1.xml
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="zwp_linux_explicit_synchronization_unstable_v1">
+
+  <copyright>
+    Copyright 2016 The Chromium Authors.
+    Copyright 2017 Intel Corporation
+    Copyright 2018 Collabora, Ltd
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_linux_explicit_synchronization_v1" version="2">
+    <description summary="protocol for providing explicit synchronization">
+      This global is a factory interface, allowing clients to request
+      explicit synchronization for buffers on a per-surface basis.
+
+      See zwp_linux_surface_synchronization_v1 for more information.
+
+      This interface is derived from Chromium's
+      zcr_linux_explicit_synchronization_v1.
+
+      Note: this protocol is superseded by linux-drm-syncobj.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy explicit synchronization factory object">
+        Destroy this explicit synchronization factory object. Other objects,
+        including zwp_linux_surface_synchronization_v1 objects created by this
+        factory, shall not be affected by this request.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="synchronization_exists" value="0"
+             summary="the surface already has a synchronization object associated"/>
+    </enum>
+
+    <request name="get_synchronization">
+      <description summary="extend surface interface for explicit synchronization">
+        Instantiate an interface extension for the given wl_surface to provide
+        explicit synchronization.
+
+        If the given wl_surface already has an explicit synchronization object
+        associated, the synchronization_exists protocol error is raised.
+
+        Graphics APIs, like EGL or Vulkan, that manage the buffer queue and
+        commits of a wl_surface themselves, are likely to be using this
+        extension internally. If a client is using such an API for a
+        wl_surface, it should not directly use this extension on that surface,
+        to avoid raising a synchronization_exists protocol error.
+      </description>
+
+      <arg name="id" type="new_id"
+           interface="zwp_linux_surface_synchronization_v1"
+           summary="the new synchronization interface id"/>
+      <arg name="surface" type="object" interface="wl_surface"
+           summary="the surface"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_linux_surface_synchronization_v1" version="2">
+    <description summary="per-surface explicit synchronization support">
+      This object implements per-surface explicit synchronization.
+
+      Synchronization refers to co-ordination of pipelined operations performed
+      on buffers. Most GPU clients will schedule an asynchronous operation to
+      render to the buffer, then immediately send the buffer to the compositor
+      to be attached to a surface.
+
+      In implicit synchronization, ensuring that the rendering operation is
+      complete before the compositor displays the buffer is an implementation
+      detail handled by either the kernel or userspace graphics driver.
+
+      By contrast, in explicit synchronization, dma_fence objects mark when the
+      asynchronous operations are complete. When submitting a buffer, the
+      client provides an acquire fence which will be waited on before the
+      compositor accesses the buffer. The Wayland server, through a
+      zwp_linux_buffer_release_v1 object, will inform the client with an event
+      which may be accompanied by a release fence, when the compositor will no
+      longer access the buffer contents due to the specific commit that
+      requested the release event.
+
+      Each surface can be associated with only one object of this interface at
+      any time.
+
+      In version 1 of this interface, explicit synchronization is only
+      guaranteed to be supported for buffers created with any version of the
+      wp_linux_dmabuf buffer factory. Version 2 additionally guarantees
+      explicit synchronization support for opaque EGL buffers, which is a type
+      of platform specific buffers described in the EGL_WL_bind_wayland_display
+      extension. Compositors are free to support explicit synchronization for
+      additional buffer types.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy synchronization object">
+        Destroy this explicit synchronization object.
+
+        Any fence set by this object with set_acquire_fence since the last
+        commit will be discarded by the server. Any fences set by this object
+        before the last commit are not affected.
+
+        zwp_linux_buffer_release_v1 objects created by this object are not
+        affected by this request.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="invalid_fence" value="0"
+             summary="the fence specified by the client could not be imported"/>
+      <entry name="duplicate_fence" value="1"
+             summary="multiple fences added for a single surface commit"/>
+      <entry name="duplicate_release" value="2"
+             summary="multiple releases added for a single surface commit"/>
+      <entry name="no_surface" value="3"
+             summary="the associated wl_surface was destroyed"/>
+      <entry name="unsupported_buffer" value="4"
+             summary="the buffer does not support explicit synchronization"/>
+      <entry name="no_buffer" value="5"
+             summary="no buffer was attached"/>
+    </enum>
+
+    <request name="set_acquire_fence">
+      <description summary="set the acquire fence">
+        Set the acquire fence that must be signaled before the compositor
+        may sample from the buffer attached with wl_surface.attach. The fence
+        is a dma_fence kernel object.
+
+        The acquire fence is double-buffered state, and will be applied on the
+        next wl_surface.commit request for the associated surface. Thus, it
+        applies only to the buffer that is attached to the surface at commit
+        time.
+
+        If the provided fd is not a valid dma_fence fd, then an INVALID_FENCE
+        error is raised.
+
+        If a fence has already been attached during the same commit cycle, a
+        DUPLICATE_FENCE error is raised.
+
+        If the associated wl_surface was destroyed, a NO_SURFACE error is
+        raised.
+
+        If at surface commit time the attached buffer does not support explicit
+        synchronization, an UNSUPPORTED_BUFFER error is raised.
+
+        If at surface commit time there is no buffer attached, a NO_BUFFER
+        error is raised.
+      </description>
+      <arg name="fd" type="fd" summary="acquire fence fd"/>
+    </request>
+
+    <request name="get_release">
+      <description summary="release fence for last-attached buffer">
+        Create a listener for the release of the buffer attached by the
+        client with wl_surface.attach. See zwp_linux_buffer_release_v1
+        documentation for more information.
+
+        The release object is double-buffered state, and will be associated
+        with the buffer that is attached to the surface at wl_surface.commit
+        time.
+
+        If a zwp_linux_buffer_release_v1 object has already been requested for
+        the surface in the same commit cycle, a DUPLICATE_RELEASE error is
+        raised.
+
+        If the associated wl_surface was destroyed, a NO_SURFACE error
+        is raised.
+
+        If at surface commit time there is no buffer attached, a NO_BUFFER
+        error is raised.
+      </description>
+      <arg name="release" type="new_id" interface="zwp_linux_buffer_release_v1"
+           summary="new zwp_linux_buffer_release_v1 object"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_linux_buffer_release_v1" version="1">
+    <description summary="buffer release explicit synchronization">
+      This object is instantiated in response to a
+      zwp_linux_surface_synchronization_v1.get_release request.
+
+      It provides an alternative to wl_buffer.release events, providing a
+      unique release from a single wl_surface.commit request. The release event
+      also supports explicit synchronization, providing a fence FD for the
+      client to synchronize against.
+
+      Exactly one event, either a fenced_release or an immediate_release, will
+      be emitted for the wl_surface.commit request. The compositor can choose
+      release by release which event it uses.
+
+      This event does not replace wl_buffer.release events; servers are still
+      required to send those events.
+
+      Once a buffer release object has delivered a 'fenced_release' or an
+      'immediate_release' event it is automatically destroyed.
+    </description>
+
+    <event name="fenced_release" type="destructor">
+      <description summary="release buffer with fence">
+        Sent when the compositor has finalised its usage of the associated
+        buffer for the relevant commit, providing a dma_fence which will be
+        signaled when all operations by the compositor on that buffer for that
+        commit have finished.
+
+        Once the fence has signaled, and assuming the associated buffer is not
+        pending release from other wl_surface.commit requests, no additional
+        explicit or implicit synchronization is required to safely reuse or
+        destroy the buffer.
+
+        This event destroys the zwp_linux_buffer_release_v1 object.
+      </description>
+      <arg name="fence" type="fd" summary="fence for last operation on buffer"/>
+    </event>
+
+    <event name="immediate_release" type="destructor">
+      <description summary="release buffer immediately">
+        Sent when the compositor has finalised its usage of the associated
+        buffer for the relevant commit, and either performed no operations
+        using it, or has a guarantee that all its operations on that buffer for
+        that commit have finished.
+
+        Once this event is received, and assuming the associated buffer is not
+        pending release from other wl_surface.commit requests, no additional
+        explicit or implicit synchronization is required to safely reuse or
+        destroy the buffer.
+
+        This event destroys the zwp_linux_buffer_release_v1 object.
+      </description>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/pointer-constraints/README b/subprojects/wayland-protocols/unstable/pointer-constraints/README
new file mode 100644
index 0000000000000000000000000000000000000000..390113314b8c940dc0be33038931bf091e9afeca
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/pointer-constraints/README
@@ -0,0 +1,4 @@
+Pointer constraints protocol
+
+Maintainers:
+Jonas Ã…dahl <jadahl@gmail.com> (@jadahl)
diff --git a/subprojects/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml b/subprojects/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..83b0a1c2cf7d3bb4a2dbacfb70d80770a9041a0b
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml
@@ -0,0 +1,334 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="pointer_constraints_unstable_v1">
+
+  <copyright>
+    Copyright © 2014      Jonas Ådahl
+    Copyright © 2015      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.
+  </copyright>
+
+  <description summary="protocol for constraining pointer motions">
+    This protocol specifies a set of interfaces used for adding constraints to
+    the motion of a pointer. Possible constraints include confining pointer
+    motions to a given region, or locking it to its current position.
+
+    In order to constrain the pointer, a client must first bind the global
+    interface "wp_pointer_constraints" which, if a compositor supports pointer
+    constraints, is exposed by the registry. Using the bound global object, the
+    client uses the request that corresponds to the type of constraint it wants
+    to make. See wp_pointer_constraints for more details.
+
+    Warning! The protocol described in this file is experimental and backward
+    incompatible changes may be made. Backward compatible changes may be added
+    together with the corresponding interface version bump. Backward
+    incompatible changes are done by bumping the version number in the protocol
+    and interface names and resetting the interface version. Once the protocol
+    is to be declared stable, the 'z' prefix and the version number in the
+    protocol and interface names are removed and the interface version number is
+    reset.
+  </description>
+
+  <interface name="zwp_pointer_constraints_v1" version="1">
+    <description summary="constrain the movement of a pointer">
+      The global interface exposing pointer constraining functionality. It
+      exposes two requests: lock_pointer for locking the pointer to its
+      position, and confine_pointer for locking the pointer to a region.
+
+      The lock_pointer and confine_pointer requests create the objects
+      wp_locked_pointer and wp_confined_pointer respectively, and the client can
+      use these objects to interact with the lock.
+
+      For any surface, only one lock or confinement may be active across all
+      wl_pointer objects of the same seat. If a lock or confinement is requested
+      when another lock or confinement is active or requested on the same surface
+      and with any of the wl_pointer objects of the same seat, an
+      'already_constrained' error will be raised.
+    </description>
+
+    <enum name="error">
+      <description summary="wp_pointer_constraints error values">
+	These errors can be emitted in response to wp_pointer_constraints
+	requests.
+      </description>
+      <entry name="already_constrained" value="1"
+	     summary="pointer constraint already requested on that surface"/>
+    </enum>
+
+    <enum name="lifetime">
+      <description summary="constraint lifetime">
+	These values represent different lifetime semantics. They are passed
+	as arguments to the factory requests to specify how the constraint
+	lifetimes should be managed.
+      </description>
+      <entry name="oneshot" value="1">
+	<description summary="the pointer constraint is defunct once deactivated">
+	  A oneshot pointer constraint will never reactivate once it has been
+	  deactivated. See the corresponding deactivation event
+	  (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for
+	  details.
+	</description>
+      </entry>
+      <entry name="persistent" value="2">
+	<description summary="the pointer constraint may reactivate">
+	  A persistent pointer constraint may again reactivate once it has
+	  been deactivated. See the corresponding deactivation event
+	  (wp_locked_pointer.unlocked and wp_confined_pointer.unconfined) for
+	  details.
+	</description>
+      </entry>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pointer constraints manager object">
+	Used by the client to notify the server that it will no longer use this
+	pointer constraints object.
+      </description>
+    </request>
+
+    <request name="lock_pointer">
+      <description summary="lock pointer to a position">
+	The lock_pointer request lets the client request to disable movements of
+	the virtual pointer (i.e. the cursor), effectively locking the pointer
+	to a position. This request may not take effect immediately; in the
+	future, when the compositor deems implementation-specific constraints
+	are satisfied, the pointer lock will be activated and the compositor
+	sends a locked event.
+
+	The protocol provides no guarantee that the constraints are ever
+	satisfied, and does not require the compositor to send an error if the
+	constraints cannot ever be satisfied. It is thus possible to request a
+	lock that will never activate.
+
+	There may not be another pointer constraint of any kind requested or
+	active on the surface for any of the wl_pointer objects of the seat of
+	the passed pointer when requesting a lock. If there is, an error will be
+	raised. See general pointer lock documentation for more details.
+
+	The intersection of the region passed with this request and the input
+	region of the surface is used to determine where the pointer must be
+	in order for the lock to activate. It is up to the compositor whether to
+	warp the pointer or require some kind of user interaction for the lock
+	to activate. If the region is null the surface input region is used.
+
+	A surface may receive pointer focus without the lock being activated.
+
+	The request creates a new object wp_locked_pointer which is used to
+	interact with the lock as well as receive updates about its state. See
+	the the description of wp_locked_pointer for further information.
+
+	Note that while a pointer is locked, the wl_pointer objects of the
+	corresponding seat will not emit any wl_pointer.motion events, but
+	relative motion events will still be emitted via wp_relative_pointer
+	objects of the same seat. wl_pointer.axis and wl_pointer.button events
+	are unaffected.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_locked_pointer_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="surface to lock pointer to"/>
+      <arg name="pointer" type="object" interface="wl_pointer"
+	   summary="the pointer that should be locked"/>
+      <arg name="region" type="object" interface="wl_region" allow-null="true"
+	   summary="region of surface"/>
+      <arg name="lifetime" type="uint" enum="lifetime" summary="lock lifetime"/>
+    </request>
+
+    <request name="confine_pointer">
+      <description summary="confine pointer to a region">
+	The confine_pointer request lets the client request to confine the
+	pointer cursor to a given region. This request may not take effect
+	immediately; in the future, when the compositor deems implementation-
+	specific constraints are satisfied, the pointer confinement will be
+	activated and the compositor sends a confined event.
+
+	The intersection of the region passed with this request and the input
+	region of the surface is used to determine where the pointer must be
+	in order for the confinement to activate. It is up to the compositor
+	whether to warp the pointer or require some kind of user interaction for
+	the confinement to activate. If the region is null the surface input
+	region is used.
+
+	The request will create a new object wp_confined_pointer which is used
+	to interact with the confinement as well as receive updates about its
+	state. See the the description of wp_confined_pointer for further
+	information.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_confined_pointer_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="surface to lock pointer to"/>
+      <arg name="pointer" type="object" interface="wl_pointer"
+	   summary="the pointer that should be confined"/>
+      <arg name="region" type="object" interface="wl_region" allow-null="true"
+	   summary="region of surface"/>
+      <arg name="lifetime" type="uint" enum="lifetime" summary="confinement lifetime"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_locked_pointer_v1" version="1">
+    <description summary="receive relative pointer motion events">
+      The wp_locked_pointer interface represents a locked pointer state.
+
+      While the lock of this object is active, the wl_pointer objects of the
+      associated seat will not emit any wl_pointer.motion events.
+
+      This object will send the event 'locked' when the lock is activated.
+      Whenever the lock is activated, it is guaranteed that the locked surface
+      will already have received pointer focus and that the pointer will be
+      within the region passed to the request creating this object.
+
+      To unlock the pointer, send the destroy request. This will also destroy
+      the wp_locked_pointer object.
+
+      If the compositor decides to unlock the pointer the unlocked event is
+      sent. See wp_locked_pointer.unlock for details.
+
+      When unlocking, the compositor may warp the cursor position to the set
+      cursor position hint. If it does, it will not result in any relative
+      motion events emitted via wp_relative_pointer.
+
+      If the surface the lock was requested on is destroyed and the lock is not
+      yet activated, the wp_locked_pointer object is now defunct and must be
+      destroyed.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the locked pointer object">
+	Destroy the locked pointer object. If applicable, the compositor will
+	unlock the pointer.
+      </description>
+    </request>
+
+    <request name="set_cursor_position_hint">
+      <description summary="set the pointer cursor position hint">
+	Set the cursor position hint relative to the top left corner of the
+	surface.
+
+	If the client is drawing its own cursor, it should update the position
+	hint to the position of its own cursor. A compositor may use this
+	information to warp the pointer upon unlock in order to avoid pointer
+	jumps.
+
+	The cursor position hint is double-buffered state, see
+	wl_surface.commit.
+      </description>
+      <arg name="surface_x" type="fixed"
+	   summary="surface-local x coordinate"/>
+      <arg name="surface_y" type="fixed"
+	   summary="surface-local y coordinate"/>
+    </request>
+
+    <request name="set_region">
+      <description summary="set a new lock region">
+	Set a new region used to lock the pointer.
+
+	The new lock region is double-buffered, see wl_surface.commit.
+
+	For details about the lock region, see wp_locked_pointer.
+      </description>
+      <arg name="region" type="object" interface="wl_region" allow-null="true"
+	   summary="region of surface"/>
+    </request>
+
+    <event name="locked">
+      <description summary="lock activation event">
+	Notification that the pointer lock of the seat's pointer is activated.
+      </description>
+    </event>
+
+    <event name="unlocked">
+      <description summary="lock deactivation event">
+	Notification that the pointer lock of the seat's pointer is no longer
+	active. If this is a oneshot pointer lock (see
+	wp_pointer_constraints.lifetime) this object is now defunct and should
+	be destroyed. If this is a persistent pointer lock (see
+	wp_pointer_constraints.lifetime) this pointer lock may again
+	reactivate in the future.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="zwp_confined_pointer_v1" version="1">
+    <description summary="confined pointer object">
+      The wp_confined_pointer interface represents a confined pointer state.
+
+      This object will send the event 'confined' when the confinement is
+      activated. Whenever the confinement is activated, it is guaranteed that
+      the surface the pointer is confined to will already have received pointer
+      focus and that the pointer will be within the region passed to the request
+      creating this object. It is up to the compositor to decide whether this
+      requires some user interaction and if the pointer will warp to within the
+      passed region if outside.
+
+      To unconfine the pointer, send the destroy request. This will also destroy
+      the wp_confined_pointer object.
+
+      If the compositor decides to unconfine the pointer the unconfined event is
+      sent. The wp_confined_pointer object is at this point defunct and should
+      be destroyed.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the confined pointer object">
+	Destroy the confined pointer object. If applicable, the compositor will
+	unconfine the pointer.
+      </description>
+    </request>
+
+    <request name="set_region">
+      <description summary="set a new confine region">
+	Set a new region used to confine the pointer.
+
+	The new confine region is double-buffered, see wl_surface.commit.
+
+	If the confinement is active when the new confinement region is applied
+	and the pointer ends up outside of newly applied region, the pointer may
+	warped to a position within the new confinement region. If warped, a
+	wl_pointer.motion event will be emitted, but no
+	wp_relative_pointer.relative_motion event.
+
+	The compositor may also, instead of using the new region, unconfine the
+	pointer.
+
+	For details about the confine region, see wp_confined_pointer.
+      </description>
+      <arg name="region" type="object" interface="wl_region" allow-null="true"
+	   summary="region of surface"/>
+    </request>
+
+    <event name="confined">
+      <description summary="pointer confined">
+	Notification that the pointer confinement of the seat's pointer is
+	activated.
+      </description>
+    </event>
+
+    <event name="unconfined">
+      <description summary="pointer unconfined">
+	Notification that the pointer confinement of the seat's pointer is no
+	longer active. If this is a oneshot pointer confinement (see
+	wp_pointer_constraints.lifetime) this object is now defunct and should
+	be destroyed. If this is a persistent pointer confinement (see
+	wp_pointer_constraints.lifetime) this pointer confinement may again
+	reactivate in the future.
+      </description>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/pointer-gestures/README b/subprojects/wayland-protocols/unstable/pointer-gestures/README
new file mode 100644
index 0000000000000000000000000000000000000000..83e6463f6160800a6f81d558c6f2357c52a55cba
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/pointer-gestures/README
@@ -0,0 +1,4 @@
+Pointer gestures protocol
+
+Maintainers:
+Carlos Garnacho <carlosg@gnome.org> (@carlosg)
diff --git a/subprojects/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml b/subprojects/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9c513a68caa76a05352a47b6eaee1d6b1e401bc1
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/pointer-gestures/pointer-gestures-unstable-v1.xml
@@ -0,0 +1,253 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="pointer_gestures_unstable_v1">
+
+  <interface name="zwp_pointer_gestures_v1" version="3">
+    <description summary="touchpad gestures">
+      A global interface to provide semantic touchpad gestures for a given
+      pointer.
+
+      Three gestures are currently supported: swipe, pinch, and hold.
+      Pinch and swipe gestures follow a three-stage cycle: begin, update,
+      end. Hold gestures follow a two-stage cycle: begin and end. All
+      gestures are identified by a unique id.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="get_swipe_gesture">
+      <description summary="get swipe gesture">
+	Create a swipe gesture object. See the
+	wl_pointer_gesture_swipe interface for details.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_pointer_gesture_swipe_v1"/>
+      <arg name="pointer" type="object" interface="wl_pointer"/>
+    </request>
+
+    <request name="get_pinch_gesture">
+      <description summary="get pinch gesture">
+	Create a pinch gesture object. See the
+	wl_pointer_gesture_pinch interface for details.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_pointer_gesture_pinch_v1"/>
+      <arg name="pointer" type="object" interface="wl_pointer"/>
+    </request>
+
+    <!-- Version 2 additions -->
+
+    <request name="release" type="destructor" since="2">
+      <description summary="destroy the pointer gesture object">
+	Destroy the pointer gesture object. Swipe, pinch and hold objects
+	created via this gesture object remain valid.
+      </description>
+    </request>
+
+    <!-- Version 3 additions -->
+
+    <request name="get_hold_gesture" since="3">
+      <description summary="get hold gesture">
+	Create a hold gesture object. See the
+	wl_pointer_gesture_hold interface for details.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_pointer_gesture_hold_v1"/>
+      <arg name="pointer" type="object" interface="wl_pointer"/>
+    </request>
+
+  </interface>
+
+  <interface name="zwp_pointer_gesture_swipe_v1" version="2">
+    <description summary="a swipe gesture object">
+      A swipe gesture object notifies a client about a multi-finger swipe
+      gesture detected on an indirect input device such as a touchpad.
+      The gesture is usually initiated by multiple fingers moving in the
+      same direction but once initiated the direction may change.
+      The precise conditions of when such a gesture is detected are
+      implementation-dependent.
+
+      A gesture consists of three stages: begin, update (optional) and end.
+      There cannot be multiple simultaneous hold, pinch or swipe gestures on a
+      same pointer/seat, how compositors prevent these situations is
+      implementation-dependent.
+
+      A gesture may be cancelled by the compositor or the hardware.
+      Clients should not consider performing permanent or irreversible
+      actions until the end of a gesture has been received.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pointer swipe gesture object"/>
+    </request>
+
+    <event name="begin">
+      <description summary="multi-finger swipe begin">
+	This event is sent when a multi-finger swipe gesture is detected
+	on the device.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="fingers" type="uint" summary="number of fingers"/>
+    </event>
+
+    <event name="update">
+      <description summary="multi-finger swipe motion">
+	This event is sent when a multi-finger swipe gesture changes the
+	position of the logical center.
+
+	The dx and dy coordinates are relative coordinates of the logical
+	center of the gesture compared to the previous event.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="dx" type="fixed" summary="delta x coordinate in surface coordinate space"/>
+      <arg name="dy" type="fixed" summary="delta y coordinate in surface coordinate space"/>
+    </event>
+
+    <event name="end">
+      <description summary="multi-finger swipe end">
+	This event is sent when a multi-finger swipe gesture ceases to
+	be valid. This may happen when one or more fingers are lifted or
+	the gesture is cancelled.
+
+	When a gesture is cancelled, the client should undo state changes
+	caused by this gesture. What causes a gesture to be cancelled is
+	implementation-dependent.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="cancelled" type="int" summary="1 if the gesture was cancelled, 0 otherwise"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_pointer_gesture_pinch_v1" version="2">
+    <description summary="a pinch gesture object">
+      A pinch gesture object notifies a client about a multi-finger pinch
+      gesture detected on an indirect input device such as a touchpad.
+      The gesture is usually initiated by multiple fingers moving towards
+      each other or away from each other, or by two or more fingers rotating
+      around a logical center of gravity. The precise conditions of when
+      such a gesture is detected are implementation-dependent.
+
+      A gesture consists of three stages: begin, update (optional) and end.
+      There cannot be multiple simultaneous hold, pinch or swipe gestures on a
+      same pointer/seat, how compositors prevent these situations is
+      implementation-dependent.
+
+      A gesture may be cancelled by the compositor or the hardware.
+      Clients should not consider performing permanent or irreversible
+      actions until the end of a gesture has been received.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pinch gesture object"/>
+    </request>
+
+    <event name="begin">
+      <description summary="multi-finger pinch begin">
+	This event is sent when a multi-finger pinch gesture is detected
+	on the device.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="fingers" type="uint" summary="number of fingers"/>
+    </event>
+
+    <event name="update">
+      <description summary="multi-finger pinch motion">
+	This event is sent when a multi-finger pinch gesture changes the
+	position of the logical center, the rotation or the relative scale.
+
+	The dx and dy coordinates are relative coordinates in the
+	surface coordinate space of the logical center of the gesture.
+
+	The scale factor is an absolute scale compared to the
+	pointer_gesture_pinch.begin event, e.g. a scale of 2 means the fingers
+	are now twice as far apart as on pointer_gesture_pinch.begin.
+
+	The rotation is the relative angle in degrees clockwise compared to the previous
+	pointer_gesture_pinch.begin or pointer_gesture_pinch.update event.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="dx" type="fixed" summary="delta x coordinate in surface coordinate space"/>
+      <arg name="dy" type="fixed" summary="delta y coordinate in surface coordinate space"/>
+      <arg name="scale" type="fixed" summary="scale relative to the initial finger position"/>
+      <arg name="rotation" type="fixed" summary="angle in degrees cw relative to the previous event"/>
+    </event>
+
+    <event name="end">
+      <description summary="multi-finger pinch end">
+	This event is sent when a multi-finger pinch gesture ceases to
+	be valid. This may happen when one or more fingers are lifted or
+	the gesture is cancelled.
+
+	When a gesture is cancelled, the client should undo state changes
+	caused by this gesture. What causes a gesture to be cancelled is
+	implementation-dependent.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="cancelled" type="int" summary="1 if the gesture was cancelled, 0 otherwise"/>
+    </event>
+
+  </interface>
+
+  <interface name="zwp_pointer_gesture_hold_v1" version="3">
+    <description summary="a hold gesture object">
+      A hold gesture object notifies a client about a single- or
+      multi-finger hold gesture detected on an indirect input device such as
+      a touchpad. The gesture is usually initiated by one or more fingers
+      being held down without significant movement. The precise conditions
+      of when such a gesture is detected are implementation-dependent.
+
+      In particular, this gesture may be used to cancel kinetic scrolling.
+
+      A hold gesture consists of two stages: begin and end. Unlike pinch and
+      swipe there is no update stage.
+      There cannot be multiple simultaneous hold, pinch or swipe gestures on a
+      same pointer/seat, how compositors prevent these situations is
+      implementation-dependent.
+
+      A gesture may be cancelled by the compositor or the hardware.
+      Clients should not consider performing permanent or irreversible
+      actions until the end of a gesture has been received.
+    </description>
+
+    <request name="destroy" type="destructor" since="3">
+      <description summary="destroy the hold gesture object"/>
+    </request>
+
+    <event name="begin" since="3">
+      <description summary="multi-finger hold begin">
+	This event is sent when a hold gesture is detected on the device.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="fingers" type="uint" summary="number of fingers"/>
+    </event>
+
+    <event name="end" since="3">
+      <description summary="multi-finger hold end">
+	This event is sent when a hold gesture ceases to
+	be valid. This may happen when the holding fingers are lifted or
+	the gesture is cancelled, for example if the fingers move past an
+	implementation-defined threshold, the finger count changes or the hold
+	gesture changes into a different type of gesture.
+
+	When a gesture is cancelled, the client may need to undo state changes
+	caused by this gesture. What causes a gesture to be cancelled is
+	implementation-dependent.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="cancelled" type="int" summary="1 if the gesture was cancelled, 0 otherwise"/>
+    </event>
+
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/primary-selection/README b/subprojects/wayland-protocols/unstable/primary-selection/README
new file mode 100644
index 0000000000000000000000000000000000000000..1954c99de71070fe92d684dc641a75e00d4d49b5
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/primary-selection/README
@@ -0,0 +1,4 @@
+Primary selection protocol
+
+Maintainers:
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml b/subprojects/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e5a39e34cec3dec8b30198fa00421871603bfb3e
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/primary-selection/primary-selection-unstable-v1.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wp_primary_selection_unstable_v1">
+  <copyright>
+    Copyright © 2015, 2016 Red Hat
+
+    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.
+  </copyright>
+
+  <description summary="Primary selection protocol">
+    This protocol provides the ability to have a primary selection device to
+    match that of the X server. This primary selection is a shortcut to the
+    common clipboard selection, where text just needs to be selected in order
+    to allow copying it elsewhere. The de facto way to perform this action
+    is the middle mouse button, although it is not limited to this one.
+
+    Clients wishing to honor primary selection should create a primary
+    selection source and set it as the selection through
+    wp_primary_selection_device.set_selection whenever the text selection
+    changes. In order to minimize calls in pointer-driven text selection,
+    it should happen only once after the operation finished. Similarly,
+    a NULL source should be set when text is unselected.
+
+    wp_primary_selection_offer objects are first announced through the
+    wp_primary_selection_device.data_offer event. Immediately after this event,
+    the primary data offer will emit wp_primary_selection_offer.offer events
+    to let know of the mime types being offered.
+
+    When the primary selection changes, the client with the keyboard focus
+    will receive wp_primary_selection_device.selection events. Only the client
+    with the keyboard focus will receive such events with a non-NULL
+    wp_primary_selection_offer. Across keyboard focus changes, previously
+    focused clients will receive wp_primary_selection_device.events with a
+    NULL wp_primary_selection_offer.
+
+    In order to request the primary selection data, the client must pass
+    a recent serial pertaining to the press event that is triggering the
+    operation, if the compositor deems the serial valid and recent, the
+    wp_primary_selection_source.send event will happen in the other end
+    to let the transfer begin. The client owning the primary selection
+    should write the requested data, and close the file descriptor
+    immediately.
+
+    If the primary selection owner client disappeared during the transfer,
+    the client reading the data will receive a
+    wp_primary_selection_device.selection event with a NULL
+    wp_primary_selection_offer, the client should take this as a hint
+    to finish the reads related to the no longer existing offer.
+
+    The primary selection owner should be checking for errors during
+    writes, merely cancelling the ongoing transfer if any happened.
+  </description>
+
+  <interface name="zwp_primary_selection_device_manager_v1" version="1">
+    <description summary="X primary selection emulation">
+      The primary selection device manager is a singleton global object that
+      provides access to the primary selection. It allows to create
+      wp_primary_selection_source objects, as well as retrieving the per-seat
+      wp_primary_selection_device objects.
+    </description>
+
+    <request name="create_source">
+      <description summary="create a new primary selection source">
+        Create a new primary selection source.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_primary_selection_source_v1"/>
+    </request>
+
+    <request name="get_device">
+      <description summary="create a new primary selection device">
+        Create a new data device for a given seat.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_primary_selection_device_v1"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the primary selection device manager">
+        Destroy the primary selection device manager.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="zwp_primary_selection_device_v1" version="1">
+    <request name="set_selection">
+      <description summary="set the primary selection">
+        Replaces the current selection. The previous owner of the primary
+        selection will receive a wp_primary_selection_source.cancelled event.
+
+        To unset the selection, set the source to NULL.
+      </description>
+      <arg name="source" type="object" interface="zwp_primary_selection_source_v1" allow-null="true"/>
+      <arg name="serial" type="uint" summary="serial of the event that triggered this request"/>
+    </request>
+
+    <event name="data_offer">
+      <description summary="introduce a new wp_primary_selection_offer">
+        Introduces a new wp_primary_selection_offer object that may be used
+        to receive the current primary selection. Immediately following this
+        event, the new wp_primary_selection_offer object will send
+        wp_primary_selection_offer.offer events to describe the offered mime
+        types.
+      </description>
+      <arg name="offer" type="new_id" interface="zwp_primary_selection_offer_v1"/>
+    </event>
+
+    <event name="selection">
+      <description summary="advertise a new primary selection">
+        The wp_primary_selection_device.selection event is sent to notify the
+        client of a new primary selection. This event is sent after the
+        wp_primary_selection.data_offer event introducing this object, and after
+        the offer has announced its mimetypes through
+        wp_primary_selection_offer.offer.
+
+        The data_offer is valid until a new offer or NULL is received
+        or until the client loses keyboard focus. The client must destroy the
+        previous selection data_offer, if any, upon receiving this event.
+      </description>
+      <arg name="id" type="object" interface="zwp_primary_selection_offer_v1" allow-null="true"/>
+    </event>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the primary selection device">
+        Destroy the primary selection device.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="zwp_primary_selection_offer_v1" version="1">
+    <description summary="offer to transfer primary selection contents">
+      A wp_primary_selection_offer represents an offer to transfer the contents
+      of the primary selection clipboard to the client. Similar to
+      wl_data_offer, the offer also describes the mime types that the data can
+      be converted to and provides the mechanisms for transferring the data
+      directly to the client.
+    </description>
+
+    <request name="receive">
+      <description summary="request that the data is transferred">
+        To transfer the contents of the primary selection clipboard, the client
+        issues this request and indicates the mime type that it wants to
+        receive. The transfer happens through the passed file descriptor
+        (typically created with the pipe system call). The source client writes
+        the data in the mime type representation requested and then closes the
+        file descriptor.
+
+        The receiving client reads from the read end of the pipe until EOF and
+        closes its end, at which point the transfer is complete.
+      </description>
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the primary selection offer">
+        Destroy the primary selection offer.
+      </description>
+    </request>
+
+    <event name="offer">
+      <description summary="advertise offered mime type">
+        Sent immediately after creating announcing the
+        wp_primary_selection_offer through
+        wp_primary_selection_device.data_offer. One event is sent per offered
+        mime type.
+      </description>
+      <arg name="mime_type" type="string"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_primary_selection_source_v1" version="1">
+    <description summary="offer to replace the contents of the primary selection">
+      The source side of a wp_primary_selection_offer, it provides a way to
+      describe the offered data and respond to requests to transfer the
+      requested contents of the primary selection clipboard.
+    </description>
+
+    <request name="offer">
+      <description summary="add an offered mime type">
+        This request adds a mime type to the set of mime types advertised to
+        targets. Can be called several times to offer multiple types.
+      </description>
+      <arg name="mime_type" type="string"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the primary selection source">
+        Destroy the primary selection source.
+      </description>
+    </request>
+
+    <event name="send">
+      <description summary="send the primary selection contents">
+        Request for the current primary selection contents from the client.
+        Send the specified mime type over the passed file descriptor, then
+        close it.
+      </description>
+      <arg name="mime_type" type="string"/>
+      <arg name="fd" type="fd"/>
+    </event>
+
+    <event name="cancelled">
+      <description summary="request for primary selection contents was canceled">
+        This primary selection source is no longer valid. The client should
+        clean up and destroy this primary selection source.
+      </description>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/relative-pointer/README b/subprojects/wayland-protocols/unstable/relative-pointer/README
new file mode 100644
index 0000000000000000000000000000000000000000..414ba2bd850e2a8fcd06b8ddcf185a7f3a2a4506
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/relative-pointer/README
@@ -0,0 +1,4 @@
+Relative pointer protocol
+
+Maintainers:
+Jonas Ã…dahl <jadahl@gmail.com> (@jadahl)
diff --git a/subprojects/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml b/subprojects/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ca6f81d12ac1de1960ae1417cf4179def59b69e9
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/relative-pointer/relative-pointer-unstable-v1.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="relative_pointer_unstable_v1">
+
+  <copyright>
+    Copyright © 2014      Jonas Ådahl
+    Copyright © 2015      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.
+  </copyright>
+
+  <description summary="protocol for relative pointer motion events">
+    This protocol specifies a set of interfaces used for making clients able to
+    receive relative pointer events not obstructed by barriers (such as the
+    monitor edge or other pointer barriers).
+
+    To start receiving relative pointer events, a client must first bind the
+    global interface "wp_relative_pointer_manager" which, if a compositor
+    supports relative pointer motion events, is exposed by the registry. After
+    having created the relative pointer manager proxy object, the client uses
+    it to create the actual relative pointer object using the
+    "get_relative_pointer" request given a wl_pointer. The relative pointer
+    motion events will then, when applicable, be transmitted via the proxy of
+    the newly created relative pointer object. See the documentation of the
+    relative pointer interface for more details.
+
+    Warning! The protocol described in this file is experimental and backward
+    incompatible changes may be made. Backward compatible changes may be added
+    together with the corresponding interface version bump. Backward
+    incompatible changes are done by bumping the version number in the protocol
+    and interface names and resetting the interface version. Once the protocol
+    is to be declared stable, the 'z' prefix and the version number in the
+    protocol and interface names are removed and the interface version number is
+    reset.
+  </description>
+
+  <interface name="zwp_relative_pointer_manager_v1" version="1">
+    <description summary="get relative pointer objects">
+      A global interface used for getting the relative pointer object for a
+      given pointer.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the relative pointer manager object">
+	Used by the client to notify the server that it will no longer use this
+	relative pointer manager object.
+      </description>
+    </request>
+
+    <request name="get_relative_pointer">
+      <description summary="get a relative pointer object">
+	Create a relative pointer interface given a wl_pointer object. See the
+	wp_relative_pointer interface for more details.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_relative_pointer_v1"/>
+      <arg name="pointer" type="object" interface="wl_pointer"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_relative_pointer_v1" version="1">
+    <description summary="relative pointer object">
+      A wp_relative_pointer object is an extension to the wl_pointer interface
+      used for emitting relative pointer events. It shares the same focus as
+      wl_pointer objects of the same seat and will only emit events when it has
+      focus.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="release the relative pointer object"/>
+    </request>
+
+    <event name="relative_motion">
+      <description summary="relative pointer motion">
+	Relative x/y pointer motion from the pointer of the seat associated with
+	this object.
+
+	A relative motion is in the same dimension as regular wl_pointer motion
+	events, except they do not represent an absolute position. For example,
+	moving a pointer from (x, y) to (x', y') would have the equivalent
+	relative motion (x' - x, y' - y). If a pointer motion caused the
+	absolute pointer position to be clipped by for example the edge of the
+	monitor, the relative motion is unaffected by the clipping and will
+	represent the unclipped motion.
+
+	This event also contains non-accelerated motion deltas. The
+	non-accelerated delta is, when applicable, the regular pointer motion
+	delta as it was before having applied motion acceleration and other
+	transformations such as normalization.
+
+	Note that the non-accelerated delta does not represent 'raw' events as
+	they were read from some device. Pointer motion acceleration is device-
+	and configuration-specific and non-accelerated deltas and accelerated
+	deltas may have the same value on some devices.
+
+	Relative motions are not coupled to wl_pointer.motion events, and can be
+	sent in combination with such events, but also independently. There may
+	also be scenarios where wl_pointer.motion is sent, but there is no
+	relative motion. The order of an absolute and relative motion event
+	originating from the same physical motion is not guaranteed.
+
+	If the client needs button events or focus state, it can receive them
+	from a wl_pointer object of the same seat that the wp_relative_pointer
+	object is associated with.
+      </description>
+      <arg name="utime_hi" type="uint"
+	   summary="high 32 bits of a 64 bit timestamp with microsecond granularity"/>
+      <arg name="utime_lo" type="uint"
+	   summary="low 32 bits of a 64 bit timestamp with microsecond granularity"/>
+      <arg name="dx" type="fixed"
+	   summary="the x component of the motion vector"/>
+      <arg name="dy" type="fixed"
+	   summary="the y component of the motion vector"/>
+      <arg name="dx_unaccel" type="fixed"
+	   summary="the x component of the unaccelerated motion vector"/>
+      <arg name="dy_unaccel" type="fixed"
+	   summary="the y component of the unaccelerated motion vector"/>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/tablet/README b/subprojects/wayland-protocols/unstable/tablet/README
new file mode 100644
index 0000000000000000000000000000000000000000..5c6a5b975a00bfe7694ddddd144561c5f11d606b
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/tablet/README
@@ -0,0 +1,4 @@
+Tablet protocol
+
+Maintainers:
+Peter Hutterer <peter.hutterer@who-t.net> (@whot)
diff --git a/subprojects/wayland-protocols/unstable/tablet/tablet-unstable-v1.xml b/subprojects/wayland-protocols/unstable/tablet/tablet-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6db9c05a41542216b835594e0ff219eda22ea1bd
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/tablet/tablet-unstable-v1.xml
@@ -0,0 +1,640 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="tablet_unstable_v1">
+
+  <copyright>
+    Copyright 2014 © Stephen "Lyude" Chandler Paul
+    Copyright 2015-2016 © 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.
+  </copyright>
+
+  <description summary="Wayland protocol for graphics tablets">
+    This description provides a high-level overview of the interplay between
+    the interfaces defined this protocol. For details, see the protocol
+    specification.
+
+    More than one tablet may exist, and device-specifics matter. Tablets are
+    not represented by a single virtual device like wl_pointer. A client
+    binds to the tablet manager object which is just a proxy object. From
+    that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+    and that returns the actual interface that has all the tablets. With
+    this indirection, we can avoid merging wp_tablet into the actual Wayland
+    protocol, a long-term benefit.
+
+    The wp_tablet_seat sends a "tablet added" event for each tablet
+    connected. That event is followed by descriptive events about the
+    hardware; currently that includes events for name, vid/pid and
+    a wp_tablet.path event that describes a local path. This path can be
+    used to uniquely identify a tablet or get more information through
+    libwacom. Emulated or nested tablets can skip any of those, e.g. a
+    virtual tablet may not have a vid/pid. The sequence of descriptive
+    events is terminated by a wp_tablet.done event to signal that a client
+    may now finalize any initialization for that tablet.
+
+    Events from tablets require a tool in proximity. Tools are also managed
+    by the tablet seat; a "tool added" event is sent whenever a tool is new
+    to the compositor. That event is followed by a number of descriptive
+    events about the hardware; currently that includes capabilities,
+    hardware id and serial number, and tool type. Similar to the tablet
+    interface, a wp_tablet_tool.done event is sent to terminate that initial
+    sequence.
+
+    Any event from a tool happens on the wp_tablet_tool interface. When the
+    tool gets into proximity of the tablet, a proximity_in event is sent on
+    the wp_tablet_tool interface, listing the tablet and the surface. That
+    event is followed by a motion event with the coordinates. After that,
+    it's the usual motion, axis, button, etc. events. The protocol's
+    serialisation means events are grouped by wp_tablet_tool.frame events.
+
+    Two special events (that don't exist in X) are down and up. They signal
+    "tip touching the surface". For tablets without real proximity
+    detection, the sequence is: proximity_in, motion, down, frame.
+
+    When the tool leaves proximity, a proximity_out event is sent. If any
+    button is still down, a button release event is sent before this
+    proximity event. These button events are sent in the same frame as the
+    proximity event to signal to the client that the buttons were held when
+    the tool left proximity.
+
+    If the tool moves out of the surface but stays in proximity (i.e.
+    between windows), compositor-specific grab policies apply. This usually
+    means that the proximity-out is delayed until all buttons are released.
+
+    Moving a tool physically from one tablet to the other has no real effect
+    on the protocol, since we already have the tool object from the "tool
+    added" event. All the information is already there and the proximity
+    events on both tablets are all a client needs to reconstruct what
+    happened.
+
+    Some extra axes are normalized, i.e. the client knows the range as
+    specified in the protocol (e.g. [0, 65535]), the granularity however is
+    unknown. The current normalized axes are pressure, distance, and slider.
+
+    Other extra axes are in physical units as specified in the protocol.
+    The current extra axes with physical units are tilt, rotation and
+    wheel rotation.
+
+    Since tablets work independently of the pointer controlled by the mouse,
+    the focus handling is independent too and controlled by proximity.
+    The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
+    This cursor surface may be the same as the mouse cursor, and it may be
+    the same across tools but it is possible to be more fine-grained. For
+    example, a client may set different cursors for the pen and eraser.
+
+    Tools are generally independent of tablets and it is
+    compositor-specific policy when a tool can be removed. Common approaches
+    will likely include some form of removing a tool when all tablets the
+    tool was used on are removed.
+
+    Warning! The protocol described in this file is experimental and
+    backward incompatible changes may be made. Backward compatible changes
+    may be added together with the corresponding interface version bump.
+    Backward incompatible changes are done by bumping the version number in
+    the protocol and interface names and resetting the interface version.
+    Once the protocol is to be declared stable, the 'z' prefix and the
+    version number in the protocol and interface names are removed and the
+    interface version number is reset.
+  </description>
+
+  <interface name="zwp_tablet_manager_v1" version="1">
+    <description summary="controller object for graphic tablet devices">
+      An object that provides access to the graphics tablets available on this
+      system. All tablets are associated with a seat, to get access to the
+      actual tablets, use wp_tablet_manager.get_tablet_seat.
+    </description>
+
+    <request name="get_tablet_seat">
+      <description summary="get the tablet seat">
+	Get the wp_tablet_seat object for the given seat. This object
+	provides access to all graphics tablets in this seat.
+      </description>
+      <arg name="tablet_seat" type="new_id" interface="zwp_tablet_seat_v1"/>
+      <arg name="seat" type="object" interface="wl_seat" summary="The wl_seat object to retrieve the tablets for" />
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="release the memory for the tablet manager object">
+	Destroy the wp_tablet_manager object. Objects created from this
+	object are unaffected and should be destroyed separately.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="zwp_tablet_seat_v1" version="1">
+    <description summary="controller object for graphic tablet devices of a seat">
+      An object that provides access to the graphics tablets available on this
+      seat. After binding to this interface, the compositor sends a set of
+      wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="release the memory for the tablet seat object">
+	Destroy the wp_tablet_seat object. Objects created from this
+	object are unaffected and should be destroyed separately.
+      </description>
+    </request>
+
+    <event name="tablet_added">
+      <description summary="new device notification">
+	This event is sent whenever a new tablet becomes available on this
+	seat. This event only provides the object id of the tablet, any
+	static information about the tablet (device name, vid/pid, etc.) is
+	sent through the wp_tablet interface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_tablet_v1" summary="the newly added graphics tablet"/>
+    </event>
+
+    <event name="tool_added">
+      <description summary="a new tool has been used with a tablet">
+	This event is sent whenever a tool that has not previously been used
+	with a tablet comes into use. This event only provides the object id
+	of the tool; any static information about the tool (capabilities,
+	type, etc.) is sent through the wp_tablet_tool interface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_tablet_tool_v1" summary="the newly added tablet tool"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_tool_v1" version="1">
+    <description summary="a physical tablet tool">
+      An object that represents a physical tool that has been, or is
+      currently in use with a tablet in this seat. Each wp_tablet_tool
+      object stays valid until the client destroys it; the compositor
+      reuses the wp_tablet_tool object to indicate that the object's
+      respective physical tool has come into proximity of a tablet again.
+
+      A wp_tablet_tool object's relation to a physical tool depends on the
+      tablet's ability to report serial numbers. If the tablet supports
+      this capability, then the object represents a specific physical tool
+      and can be identified even when used on multiple tablets.
+
+      A tablet tool has a number of static characteristics, e.g. tool type,
+      hardware_serial and capabilities. These capabilities are sent in an
+      event sequence after the wp_tablet_seat.tool_added event before any
+      actual events from this tool. This initial event sequence is
+      terminated by a wp_tablet_tool.done event.
+
+      Tablet tool events are grouped by wp_tablet_tool.frame events.
+      Any events received before a wp_tablet_tool.frame event should be
+      considered part of the same hardware state change.
+    </description>
+
+    <request name="set_cursor">
+      <description summary="set the tablet tool's surface">
+	Sets the surface of the cursor used for this tool on the given
+	tablet. This request only takes effect if the tool is in proximity
+	of one of the requesting client's surfaces or the surface parameter
+	is the current pointer surface. If there was a previous surface set
+	with this request it is replaced. If surface is NULL, the cursor
+	image is hidden.
+
+	The parameters hotspot_x and hotspot_y define the position of the
+	pointer surface relative to the pointer location. Its top-left corner
+	is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+	coordinates of the pointer location, in surface-local coordinates.
+
+	On surface.attach requests to the pointer surface, hotspot_x and
+	hotspot_y are decremented by the x and y parameters passed to the
+	request. Attach must be confirmed by wl_surface.commit as usual.
+
+	The hotspot can also be updated by passing the currently set pointer
+	surface to this request with new values for hotspot_x and hotspot_y.
+
+	The current and pending input regions of the wl_surface are cleared,
+	and wl_surface.set_input_region is ignored until the wl_surface is no
+	longer used as the cursor. When the use as a cursor ends, the current
+	and pending input regions become undefined, and the wl_surface is
+	unmapped.
+
+	This request gives the surface the role of a cursor. The role
+	assigned by this request is the same as assigned by
+	wl_pointer.set_cursor meaning the same surface can be
+	used both as a wl_pointer cursor and a wp_tablet cursor. If the
+	surface already has another role, it raises a protocol error.
+	The surface may be used on multiple tablets and across multiple
+	seats.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+      <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/>
+      <arg name="hotspot_y" type="int" summary="surface-local y coordinate"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the tool object">
+	This destroys the client's resource for this tool object.
+      </description>
+    </request>
+
+    <enum name="type">
+      <description summary="a physical tool type">
+	Describes the physical type of a tool. The physical type of a tool
+	generally defines its base usage.
+
+	The mouse tool represents a mouse-shaped tool that is not a relative
+	device but bound to the tablet's surface, providing absolute
+	coordinates.
+
+	The lens tool is a mouse-shaped tool with an attached lens to
+	provide precision focus.
+      </description>
+      <entry name="pen" value="0x140" summary="Pen"/>
+      <entry name="eraser" value="0x141" summary="Eraser"/>
+      <entry name="brush" value="0x142" summary="Brush"/>
+      <entry name="pencil" value="0x143" summary="Pencil"/>
+      <entry name="airbrush" value="0x144" summary="Airbrush"/>
+      <entry name="finger" value="0x145" summary="Finger"/>
+      <entry name="mouse" value="0x146" summary="Mouse"/>
+      <entry name="lens" value="0x147" summary="Lens"/>
+    </enum>
+
+    <event name="type">
+      <description summary="tool type">
+	The tool type is the high-level type of the tool and usually decides
+	the interaction expected from this tool.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="tool_type" type="uint" enum="type" summary="the physical tool type"/>
+    </event>
+
+    <event name="hardware_serial">
+      <description summary="unique hardware serial number of the tool">
+	If the physical tool can be identified by a unique 64-bit serial
+	number, this event notifies the client of this serial number.
+
+	If multiple tablets are available in the same seat and the tool is
+	uniquely identifiable by the serial number, that tool may move
+	between tablets.
+
+	Otherwise, if the tool has no serial number and this event is
+	missing, the tool is tied to the tablet it first comes into
+	proximity with. Even if the physical tool is used on multiple
+	tablets, separate wp_tablet_tool objects will be created, one per
+	tablet.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="hardware_serial_hi" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+      <arg name="hardware_serial_lo" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+    </event>
+
+    <event name="hardware_id_wacom">
+      <description summary="hardware id notification in Wacom's format">
+	This event notifies the client of a hardware id available on this tool.
+
+	The hardware id is a device-specific 64-bit id that provides extra
+	information about the tool in use, beyond the wl_tool.type
+	enumeration. The format of the id is specific to tablets made by
+	Wacom Inc. For example, the hardware id of a Wacom Grip
+	Pen (a stylus) is 0x802.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="hardware_id_hi" type="uint" summary="the hardware id, most significant bits"/>
+      <arg name="hardware_id_lo" type="uint" summary="the hardware id, least significant bits"/>
+    </event>
+
+    <enum name="capability">
+      <description summary="capability flags for a tool">
+	Describes extra capabilities on a tablet.
+
+	Any tool must provide x and y values, extra axes are
+	device-specific.
+      </description>
+      <entry name="tilt" value="1" summary="Tilt axes"/>
+      <entry name="pressure" value="2" summary="Pressure axis"/>
+      <entry name="distance" value="3" summary="Distance axis"/>
+      <entry name="rotation" value="4" summary="Z-rotation axis"/>
+      <entry name="slider" value="5" summary="Slider axis"/>
+      <entry name="wheel" value="6" summary="Wheel axis"/>
+    </enum>
+
+    <event name="capability">
+      <description summary="tool capability notification">
+	This event notifies the client of any capabilities of this tool,
+	beyond the main set of x/y axes and tip up/down detection.
+
+	One event is sent for each extra capability available on this tool.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="capability" type="uint" enum="capability" summary="the capability"/>
+    </event>
+
+    <event name="done">
+      <description summary="tool description events sequence complete">
+	This event signals the end of the initial burst of descriptive
+	events. A client may consider the static description of the tool to
+	be complete and finalize initialization of the tool.
+      </description>
+    </event>
+
+    <event name="removed">
+      <description summary="tool removed">
+	This event is sent when the tool is removed from the system and will
+	send no further events. Should the physical tool come back into
+	proximity later, a new wp_tablet_tool object will be created.
+
+	It is compositor-dependent when a tool is removed. A compositor may
+	remove a tool on proximity out, tablet removal or any other reason.
+	A compositor may also keep a tool alive until shutdown.
+
+	If the tool is currently in proximity, a proximity_out event will be
+	sent before the removed event. See wp_tablet_tool.proximity_out for
+	the handling of any buttons logically down.
+
+	When this event is received, the client must wp_tablet_tool.destroy
+	the object.
+      </description>
+    </event>
+
+    <event name="proximity_in">
+      <description summary="proximity in event">
+	Notification that this tool is focused on a certain surface.
+
+	This event can be received when the tool has moved from one surface to
+	another, or when the tool has come back into proximity above the
+	surface.
+
+	If any button is logically down when the tool comes into proximity,
+	the respective button event is sent after the proximity_in event but
+	within the same frame as the proximity_in event.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="tablet" type="object" interface="zwp_tablet_v1" summary="The tablet the tool is in proximity of"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="The current surface the tablet tool is over"/>
+    </event>
+
+    <event name="proximity_out">
+      <description summary="proximity out event">
+	Notification that this tool has either left proximity, or is no
+	longer focused on a certain surface.
+
+	When the tablet tool leaves proximity of the tablet, button release
+	events are sent for each button that was held down at the time of
+	leaving proximity. These events are sent before the proximity_out
+	event but within the same wp_tablet.frame.
+
+	If the tool stays within proximity of the tablet, but the focus
+	changes from one surface to another, a button release event may not
+	be sent until the button is actually released or the tool leaves the
+	proximity of the tablet.
+      </description>
+    </event>
+
+    <event name="down">
+      <description summary="tablet tool is making contact">
+	Sent whenever the tablet tool comes in contact with the surface of the
+	tablet.
+
+	If the tool is already in contact with the tablet when entering the
+	input region, the client owning said region will receive a
+	wp_tablet.proximity_in event, followed by a wp_tablet.down
+	event and a wp_tablet.frame event.
+
+	Note that this event describes logical contact, not physical
+	contact. On some devices, a compositor may not consider a tool in
+	logical contact until a minimum physical pressure threshold is
+	exceeded.
+      </description>
+      <arg name="serial" type="uint"/>
+    </event>
+
+    <event name="up">
+      <description summary="tablet tool is no longer making contact">
+	Sent whenever the tablet tool stops making contact with the surface of
+	the tablet, or when the tablet tool moves out of the input region
+	and the compositor grab (if any) is dismissed.
+
+	If the tablet tool moves out of the input region while in contact
+	with the surface of the tablet and the compositor does not have an
+	ongoing grab on the surface, the client owning said region will
+	receive a wp_tablet.up event, followed by a wp_tablet.proximity_out
+	event and a wp_tablet.frame event. If the compositor has an ongoing
+	grab on this device, this event sequence is sent whenever the grab
+	is dismissed in the future.
+
+	Note that this event describes logical contact, not physical
+	contact. On some devices, a compositor may not consider a tool out
+	of logical contact until physical pressure falls below a specific
+	threshold.
+      </description>
+    </event>
+
+    <event name="motion">
+      <description summary="motion event">
+	Sent whenever a tablet tool moves.
+      </description>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="pressure">
+      <description summary="pressure change event">
+	Sent whenever the pressure axis on a tool changes. The value of this
+	event is normalized to a value between 0 and 65535.
+
+	Note that pressure may be nonzero even when a tool is not in logical
+	contact. See the down and up events for more details.
+      </description>
+      <arg name="pressure" type="uint" summary="The current pressure value"/>
+    </event>
+
+    <event name="distance">
+      <description summary="distance change event">
+	Sent whenever the distance axis on a tool changes. The value of this
+	event is normalized to a value between 0 and 65535.
+
+	Note that distance may be nonzero even when a tool is not in logical
+	contact. See the down and up events for more details.
+      </description>
+      <arg name="distance" type="uint" summary="The current distance value"/>
+    </event>
+
+    <event name="tilt">
+      <description summary="tilt change event">
+	Sent whenever one or both of the tilt axes on a tool change. Each tilt
+	value is in 0.01 of a degree, relative to the z-axis of the tablet.
+	The angle is positive when the top of a tool tilts along the
+	positive x or y axis.
+      </description>
+      <arg name="tilt_x" type="int" summary="The current value of the X tilt axis"/>
+      <arg name="tilt_y" type="int" summary="The current value of the Y tilt axis"/>
+    </event>
+
+    <event name="rotation">
+      <description summary="z-rotation change event">
+	Sent whenever the z-rotation axis on the tool changes. The
+	rotation value is in 0.01 of a degree clockwise from the tool's
+	logical neutral position.
+      </description>
+      <arg name="degrees" type="int" summary="The current rotation of the Z axis"/>
+    </event>
+
+    <event name="slider">
+      <description summary="Slider position change event">
+	Sent whenever the slider position on the tool changes. The
+	value is normalized between -65535 and 65535, with 0 as the logical
+	neutral position of the slider.
+
+	The slider is available on e.g. the Wacom Airbrush tool.
+      </description>
+      <arg name="position" type="int" summary="The current position of slider"/>
+    </event>
+
+    <event name="wheel">
+      <description summary="Wheel delta event">
+	Sent whenever the wheel on the tool emits an event. This event
+	contains two values for the same axis change. The degrees value is
+	in 0.01 of a degree in the same orientation as the
+	wl_pointer.vertical_scroll axis. The clicks value is in discrete
+	logical clicks of the mouse wheel. This value may be zero if the
+	movement of the wheel was less than one logical click.
+
+	Clients should choose either value and avoid mixing degrees and
+	clicks. The compositor may accumulate values smaller than a logical
+	click and emulate click events when a certain threshold is met.
+	Thus, wl_tablet_tool.wheel events with non-zero clicks values may
+	have different degrees values.
+      </description>
+      <arg name="degrees" type="int" summary="The wheel delta in 0.01 of a degree"/>
+      <arg name="clicks" type="int" summary="The wheel delta in discrete clicks"/>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+	Describes the physical state of a button that produced the button event.
+      </description>
+      <entry name="released" value="0" summary="button is not pressed"/>
+      <entry name="pressed" value="1" summary="button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="button event">
+	Sent whenever a button on the tool is pressed or released.
+
+	If a button is held down when the tool moves in or out of proximity,
+	button events are generated by the compositor. See
+	wp_tablet_tool.proximity_in and wp_tablet_tool.proximity_out for
+	details.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="button" type="uint" summary="The button whose state has changed"/>
+      <arg name="state" type="uint" enum="button_state" summary="Whether the button was pressed or released"/>
+    </event>
+
+    <event name="frame">
+      <description summary="frame event">
+	Marks the end of a series of axis and/or button updates from the
+	tablet. The Wayland protocol requires axis updates to be sent
+	sequentially, however all events within a frame should be considered
+	one hardware event.
+      </description>
+      <arg name="time" type="uint" summary="The time of the event with millisecond granularity"/>
+    </event>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+  </interface>
+
+  <interface name="zwp_tablet_v1" version="1">
+    <description summary="graphics tablet device">
+      The wp_tablet interface represents one graphics tablet device. The
+      tablet interface itself does not generate events; all events are
+      generated by wp_tablet_tool objects when in proximity above a tablet.
+
+      A tablet has a number of static characteristics, e.g. device name and
+      pid/vid. These capabilities are sent in an event sequence after the
+      wp_tablet_seat.tablet_added event. This initial event sequence is
+      terminated by a wp_tablet.done event.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the tablet object">
+	This destroys the client's resource for this tablet object.
+      </description>
+    </request>
+
+    <event name="name">
+      <description summary="tablet device name">
+	This event is sent in the initial burst of events before the
+	wp_tablet.done event.
+      </description>
+      <arg name="name" type="string" summary="the device name"/>
+    </event>
+
+    <event name="id">
+      <description summary="tablet device USB vendor/product id">
+	This event is sent in the initial burst of events before the
+	wp_tablet.done event.
+      </description>
+      <arg name="vid" type="uint" summary="USB vendor id"/>
+      <arg name="pid" type="uint" summary="USB product id"/>
+    </event>
+
+    <event name="path">
+      <description summary="path to the device">
+	A system-specific device path that indicates which device is behind
+	this wp_tablet. This information may be used to gather additional
+	information about the device, e.g. through libwacom.
+
+	A device may have more than one device path. If so, multiple
+	wp_tablet.path events are sent. A device may be emulated and not
+	have a device path, and in that case this event will not be sent.
+
+	The format of the path is unspecified, it may be a device node, a
+	sysfs path, or some other identifier. It is up to the client to
+	identify the string provided.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet.done event.
+      </description>
+      <arg name="path" type="string" summary="path to local device"/>
+    </event>
+
+    <event name="done">
+      <description summary="tablet description events sequence complete">
+	This event is sent immediately to signal the end of the initial
+	burst of descriptive events. A client may consider the static
+	description of the tablet to be complete and finalize initialization
+	of the tablet.
+      </description>
+    </event>
+
+    <event name="removed">
+      <description summary="tablet removed event">
+	Sent when the tablet has been removed from the system. When a tablet
+	is removed, some tools may be removed.
+
+	When this event is received, the client must wp_tablet.destroy
+	the object.
+      </description>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml b/subprojects/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..d78b141fb516211376087fc250ef4454506a46ec
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/tablet/tablet-unstable-v2.xml
@@ -0,0 +1,1182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="tablet_unstable_v2">
+
+  <copyright>
+    Copyright 2014 © Stephen "Lyude" Chandler Paul
+    Copyright 2015-2016 © 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.
+  </copyright>
+
+  <description summary="Wayland protocol for graphics tablets">
+    This description provides a high-level overview of the interplay between
+    the interfaces defined this protocol. For details, see the protocol
+    specification.
+
+    More than one tablet may exist, and device-specifics matter. Tablets are
+    not represented by a single virtual device like wl_pointer. A client
+    binds to the tablet manager object which is just a proxy object. From
+    that, the client requests wp_tablet_manager.get_tablet_seat(wl_seat)
+    and that returns the actual interface that has all the tablets. With
+    this indirection, we can avoid merging wp_tablet into the actual Wayland
+    protocol, a long-term benefit.
+
+    The wp_tablet_seat sends a "tablet added" event for each tablet
+    connected. That event is followed by descriptive events about the
+    hardware; currently that includes events for name, vid/pid and
+    a wp_tablet.path event that describes a local path. This path can be
+    used to uniquely identify a tablet or get more information through
+    libwacom. Emulated or nested tablets can skip any of those, e.g. a
+    virtual tablet may not have a vid/pid. The sequence of descriptive
+    events is terminated by a wp_tablet.done event to signal that a client
+    may now finalize any initialization for that tablet.
+
+    Events from tablets require a tool in proximity. Tools are also managed
+    by the tablet seat; a "tool added" event is sent whenever a tool is new
+    to the compositor. That event is followed by a number of descriptive
+    events about the hardware; currently that includes capabilities,
+    hardware id and serial number, and tool type. Similar to the tablet
+    interface, a wp_tablet_tool.done event is sent to terminate that initial
+    sequence.
+
+    Any event from a tool happens on the wp_tablet_tool interface. When the
+    tool gets into proximity of the tablet, a proximity_in event is sent on
+    the wp_tablet_tool interface, listing the tablet and the surface. That
+    event is followed by a motion event with the coordinates. After that,
+    it's the usual motion, axis, button, etc. events. The protocol's
+    serialisation means events are grouped by wp_tablet_tool.frame events.
+
+    Two special events (that don't exist in X) are down and up. They signal
+    "tip touching the surface". For tablets without real proximity
+    detection, the sequence is: proximity_in, motion, down, frame.
+
+    When the tool leaves proximity, a proximity_out event is sent. If any
+    button is still down, a button release event is sent before this
+    proximity event. These button events are sent in the same frame as the
+    proximity event to signal to the client that the buttons were held when
+    the tool left proximity.
+
+    If the tool moves out of the surface but stays in proximity (i.e.
+    between windows), compositor-specific grab policies apply. This usually
+    means that the proximity-out is delayed until all buttons are released.
+
+    Moving a tool physically from one tablet to the other has no real effect
+    on the protocol, since we already have the tool object from the "tool
+    added" event. All the information is already there and the proximity
+    events on both tablets are all a client needs to reconstruct what
+    happened.
+
+    Some extra axes are normalized, i.e. the client knows the range as
+    specified in the protocol (e.g. [0, 65535]), the granularity however is
+    unknown. The current normalized axes are pressure, distance, and slider.
+
+    Other extra axes are in physical units as specified in the protocol.
+    The current extra axes with physical units are tilt, rotation and
+    wheel rotation.
+
+    Since tablets work independently of the pointer controlled by the mouse,
+    the focus handling is independent too and controlled by proximity.
+    The wp_tablet_tool.set_cursor request sets a tool-specific cursor.
+    This cursor surface may be the same as the mouse cursor, and it may be
+    the same across tools but it is possible to be more fine-grained. For
+    example, a client may set different cursors for the pen and eraser.
+
+    Tools are generally independent of tablets and it is
+    compositor-specific policy when a tool can be removed. Common approaches
+    will likely include some form of removing a tool when all tablets the
+    tool was used on are removed.
+
+    Disclaimer: This protocol extension has been marked stable. This copy is
+    no longer used and only retained for backwards compatibility. The
+    canonical version can be found in the stable/ directory.
+  </description>
+
+  <interface name="zwp_tablet_manager_v2" version="1">
+    <description summary="controller object for graphic tablet devices">
+      An object that provides access to the graphics tablets available on this
+      system. All tablets are associated with a seat, to get access to the
+      actual tablets, use wp_tablet_manager.get_tablet_seat.
+    </description>
+
+    <request name="get_tablet_seat">
+      <description summary="get the tablet seat">
+	Get the wp_tablet_seat object for the given seat. This object
+	provides access to all graphics tablets in this seat.
+      </description>
+      <arg name="tablet_seat" type="new_id" interface="zwp_tablet_seat_v2"/>
+      <arg name="seat" type="object" interface="wl_seat" summary="The wl_seat object to retrieve the tablets for" />
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="release the memory for the tablet manager object">
+	Destroy the wp_tablet_manager object. Objects created from this
+	object are unaffected and should be destroyed separately.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="zwp_tablet_seat_v2" version="1">
+    <description summary="controller object for graphic tablet devices of a seat">
+      An object that provides access to the graphics tablets available on this
+      seat. After binding to this interface, the compositor sends a set of
+      wp_tablet_seat.tablet_added and wp_tablet_seat.tool_added events.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="release the memory for the tablet seat object">
+	Destroy the wp_tablet_seat object. Objects created from this
+	object are unaffected and should be destroyed separately.
+      </description>
+    </request>
+
+    <event name="tablet_added">
+      <description summary="new device notification">
+	This event is sent whenever a new tablet becomes available on this
+	seat. This event only provides the object id of the tablet, any
+	static information about the tablet (device name, vid/pid, etc.) is
+	sent through the wp_tablet interface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_tablet_v2" summary="the newly added graphics tablet"/>
+    </event>
+
+    <event name="tool_added">
+      <description summary="a new tool has been used with a tablet">
+	This event is sent whenever a tool that has not previously been used
+	with a tablet comes into use. This event only provides the object id
+	of the tool; any static information about the tool (capabilities,
+	type, etc.) is sent through the wp_tablet_tool interface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_tablet_tool_v2" summary="the newly added tablet tool"/>
+    </event>
+
+    <event name="pad_added">
+      <description summary="new pad notification">
+	This event is sent whenever a new pad is known to the system. Typically,
+	pads are physically attached to tablets and a pad_added event is
+	sent immediately after the wp_tablet_seat.tablet_added.
+	However, some standalone pad devices logically attach to tablets at
+	runtime, and the client must wait for wp_tablet_pad.enter to know
+	the tablet a pad is attached to.
+
+	This event only provides the object id of the pad. All further
+	features (buttons, strips, rings) are sent through the wp_tablet_pad
+	interface.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_tablet_pad_v2" summary="the newly added pad"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_tool_v2" version="1">
+    <description summary="a physical tablet tool">
+      An object that represents a physical tool that has been, or is
+      currently in use with a tablet in this seat. Each wp_tablet_tool
+      object stays valid until the client destroys it; the compositor
+      reuses the wp_tablet_tool object to indicate that the object's
+      respective physical tool has come into proximity of a tablet again.
+
+      A wp_tablet_tool object's relation to a physical tool depends on the
+      tablet's ability to report serial numbers. If the tablet supports
+      this capability, then the object represents a specific physical tool
+      and can be identified even when used on multiple tablets.
+
+      A tablet tool has a number of static characteristics, e.g. tool type,
+      hardware_serial and capabilities. These capabilities are sent in an
+      event sequence after the wp_tablet_seat.tool_added event before any
+      actual events from this tool. This initial event sequence is
+      terminated by a wp_tablet_tool.done event.
+
+      Tablet tool events are grouped by wp_tablet_tool.frame events.
+      Any events received before a wp_tablet_tool.frame event should be
+      considered part of the same hardware state change.
+    </description>
+
+    <request name="set_cursor">
+      <description summary="set the tablet tool's surface">
+	Sets the surface of the cursor used for this tool on the given
+	tablet. This request only takes effect if the tool is in proximity
+	of one of the requesting client's surfaces or the surface parameter
+	is the current pointer surface. If there was a previous surface set
+	with this request it is replaced. If surface is NULL, the cursor
+	image is hidden.
+
+	The parameters hotspot_x and hotspot_y define the position of the
+	pointer surface relative to the pointer location. Its top-left corner
+	is always at (x, y) - (hotspot_x, hotspot_y), where (x, y) are the
+	coordinates of the pointer location, in surface-local coordinates.
+
+	On surface.attach requests to the pointer surface, hotspot_x and
+	hotspot_y are decremented by the x and y parameters passed to the
+	request. Attach must be confirmed by wl_surface.commit as usual.
+
+	The hotspot can also be updated by passing the currently set pointer
+	surface to this request with new values for hotspot_x and hotspot_y.
+
+	The current and pending input regions of the wl_surface are cleared,
+	and wl_surface.set_input_region is ignored until the wl_surface is no
+	longer used as the cursor. When the use as a cursor ends, the current
+	and pending input regions become undefined, and the wl_surface is
+	unmapped.
+
+	This request gives the surface the role of a wp_tablet_tool cursor. A
+	surface may only ever be used as the cursor surface for one
+	wp_tablet_tool. If the surface already has another role or has
+	previously been used as cursor surface for a different tool, a
+	protocol error is raised.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the proximity_in event"/>
+      <arg name="surface" type="object" interface="wl_surface" allow-null="true"/>
+      <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/>
+      <arg name="hotspot_y" type="int" summary="surface-local y coordinate"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the tool object">
+	This destroys the client's resource for this tool object.
+      </description>
+    </request>
+
+    <enum name="type">
+      <description summary="a physical tool type">
+	Describes the physical type of a tool. The physical type of a tool
+	generally defines its base usage.
+
+	The mouse tool represents a mouse-shaped tool that is not a relative
+	device but bound to the tablet's surface, providing absolute
+	coordinates.
+
+	The lens tool is a mouse-shaped tool with an attached lens to
+	provide precision focus.
+      </description>
+      <entry name="pen" value="0x140" summary="Pen"/>
+      <entry name="eraser" value="0x141" summary="Eraser"/>
+      <entry name="brush" value="0x142" summary="Brush"/>
+      <entry name="pencil" value="0x143" summary="Pencil"/>
+      <entry name="airbrush" value="0x144" summary="Airbrush"/>
+      <entry name="finger" value="0x145" summary="Finger"/>
+      <entry name="mouse" value="0x146" summary="Mouse"/>
+      <entry name="lens" value="0x147" summary="Lens"/>
+    </enum>
+
+    <event name="type">
+      <description summary="tool type">
+	The tool type is the high-level type of the tool and usually decides
+	the interaction expected from this tool.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="tool_type" type="uint" enum="type" summary="the physical tool type"/>
+    </event>
+
+    <event name="hardware_serial">
+      <description summary="unique hardware serial number of the tool">
+	If the physical tool can be identified by a unique 64-bit serial
+	number, this event notifies the client of this serial number.
+
+	If multiple tablets are available in the same seat and the tool is
+	uniquely identifiable by the serial number, that tool may move
+	between tablets.
+
+	Otherwise, if the tool has no serial number and this event is
+	missing, the tool is tied to the tablet it first comes into
+	proximity with. Even if the physical tool is used on multiple
+	tablets, separate wp_tablet_tool objects will be created, one per
+	tablet.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="hardware_serial_hi" type="uint" summary="the unique serial number of the tool, most significant bits"/>
+      <arg name="hardware_serial_lo" type="uint" summary="the unique serial number of the tool, least significant bits"/>
+    </event>
+
+    <event name="hardware_id_wacom">
+      <description summary="hardware id notification in Wacom's format">
+	This event notifies the client of a hardware id available on this tool.
+
+	The hardware id is a device-specific 64-bit id that provides extra
+	information about the tool in use, beyond the wl_tool.type
+	enumeration. The format of the id is specific to tablets made by
+	Wacom Inc. For example, the hardware id of a Wacom Grip
+	Pen (a stylus) is 0x802.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="hardware_id_hi" type="uint" summary="the hardware id, most significant bits"/>
+      <arg name="hardware_id_lo" type="uint" summary="the hardware id, least significant bits"/>
+    </event>
+
+    <enum name="capability">
+      <description summary="capability flags for a tool">
+	Describes extra capabilities on a tablet.
+
+	Any tool must provide x and y values, extra axes are
+	device-specific.
+      </description>
+      <entry name="tilt" value="1" summary="Tilt axes"/>
+      <entry name="pressure" value="2" summary="Pressure axis"/>
+      <entry name="distance" value="3" summary="Distance axis"/>
+      <entry name="rotation" value="4" summary="Z-rotation axis"/>
+      <entry name="slider" value="5" summary="Slider axis"/>
+      <entry name="wheel" value="6" summary="Wheel axis"/>
+    </enum>
+
+    <event name="capability">
+      <description summary="tool capability notification">
+	This event notifies the client of any capabilities of this tool,
+	beyond the main set of x/y axes and tip up/down detection.
+
+	One event is sent for each extra capability available on this tool.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_tool.done event.
+      </description>
+      <arg name="capability" type="uint" enum="capability" summary="the capability"/>
+    </event>
+
+    <event name="done">
+      <description summary="tool description events sequence complete">
+	This event signals the end of the initial burst of descriptive
+	events. A client may consider the static description of the tool to
+	be complete and finalize initialization of the tool.
+      </description>
+    </event>
+
+    <event name="removed">
+      <description summary="tool removed">
+	This event is sent when the tool is removed from the system and will
+	send no further events. Should the physical tool come back into
+	proximity later, a new wp_tablet_tool object will be created.
+
+	It is compositor-dependent when a tool is removed. A compositor may
+	remove a tool on proximity out, tablet removal or any other reason.
+	A compositor may also keep a tool alive until shutdown.
+
+	If the tool is currently in proximity, a proximity_out event will be
+	sent before the removed event. See wp_tablet_tool.proximity_out for
+	the handling of any buttons logically down.
+
+	When this event is received, the client must wp_tablet_tool.destroy
+	the object.
+      </description>
+    </event>
+
+    <event name="proximity_in">
+      <description summary="proximity in event">
+	Notification that this tool is focused on a certain surface.
+
+	This event can be received when the tool has moved from one surface to
+	another, or when the tool has come back into proximity above the
+	surface.
+
+	If any button is logically down when the tool comes into proximity,
+	the respective button event is sent after the proximity_in event but
+	within the same frame as the proximity_in event.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="tablet" type="object" interface="zwp_tablet_v2" summary="The tablet the tool is in proximity of"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="The current surface the tablet tool is over"/>
+    </event>
+
+    <event name="proximity_out">
+      <description summary="proximity out event">
+	Notification that this tool has either left proximity, or is no
+	longer focused on a certain surface.
+
+	When the tablet tool leaves proximity of the tablet, button release
+	events are sent for each button that was held down at the time of
+	leaving proximity. These events are sent before the proximity_out
+	event but within the same wp_tablet.frame.
+
+	If the tool stays within proximity of the tablet, but the focus
+	changes from one surface to another, a button release event may not
+	be sent until the button is actually released or the tool leaves the
+	proximity of the tablet.
+      </description>
+    </event>
+
+    <event name="down">
+      <description summary="tablet tool is making contact">
+	Sent whenever the tablet tool comes in contact with the surface of the
+	tablet.
+
+	If the tool is already in contact with the tablet when entering the
+	input region, the client owning said region will receive a
+	wp_tablet.proximity_in event, followed by a wp_tablet.down
+	event and a wp_tablet.frame event.
+
+	Note that this event describes logical contact, not physical
+	contact. On some devices, a compositor may not consider a tool in
+	logical contact until a minimum physical pressure threshold is
+	exceeded.
+      </description>
+      <arg name="serial" type="uint"/>
+    </event>
+
+    <event name="up">
+      <description summary="tablet tool is no longer making contact">
+	Sent whenever the tablet tool stops making contact with the surface of
+	the tablet, or when the tablet tool moves out of the input region
+	and the compositor grab (if any) is dismissed.
+
+	If the tablet tool moves out of the input region while in contact
+	with the surface of the tablet and the compositor does not have an
+	ongoing grab on the surface, the client owning said region will
+	receive a wp_tablet.up event, followed by a wp_tablet.proximity_out
+	event and a wp_tablet.frame event. If the compositor has an ongoing
+	grab on this device, this event sequence is sent whenever the grab
+	is dismissed in the future.
+
+	Note that this event describes logical contact, not physical
+	contact. On some devices, a compositor may not consider a tool out
+	of logical contact until physical pressure falls below a specific
+	threshold.
+      </description>
+    </event>
+
+    <event name="motion">
+      <description summary="motion event">
+	Sent whenever a tablet tool moves.
+      </description>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="pressure">
+      <description summary="pressure change event">
+	Sent whenever the pressure axis on a tool changes. The value of this
+	event is normalized to a value between 0 and 65535.
+
+	Note that pressure may be nonzero even when a tool is not in logical
+	contact. See the down and up events for more details.
+      </description>
+      <arg name="pressure" type="uint" summary="The current pressure value"/>
+    </event>
+
+    <event name="distance">
+      <description summary="distance change event">
+	Sent whenever the distance axis on a tool changes. The value of this
+	event is normalized to a value between 0 and 65535.
+
+	Note that distance may be nonzero even when a tool is not in logical
+	contact. See the down and up events for more details.
+      </description>
+      <arg name="distance" type="uint" summary="The current distance value"/>
+    </event>
+
+    <event name="tilt">
+      <description summary="tilt change event">
+	Sent whenever one or both of the tilt axes on a tool change. Each tilt
+	value is in degrees, relative to the z-axis of the tablet.
+	The angle is positive when the top of a tool tilts along the
+	positive x or y axis.
+      </description>
+      <arg name="tilt_x" type="fixed" summary="The current value of the X tilt axis"/>
+      <arg name="tilt_y" type="fixed" summary="The current value of the Y tilt axis"/>
+    </event>
+
+    <event name="rotation">
+      <description summary="z-rotation change event">
+	Sent whenever the z-rotation axis on the tool changes. The
+	rotation value is in degrees clockwise from the tool's
+	logical neutral position.
+      </description>
+      <arg name="degrees" type="fixed" summary="The current rotation of the Z axis"/>
+    </event>
+
+    <event name="slider">
+      <description summary="Slider position change event">
+	Sent whenever the slider position on the tool changes. The
+	value is normalized between -65535 and 65535, with 0 as the logical
+	neutral position of the slider.
+
+	The slider is available on e.g. the Wacom Airbrush tool.
+      </description>
+      <arg name="position" type="int" summary="The current position of slider"/>
+    </event>
+
+    <event name="wheel">
+      <description summary="Wheel delta event">
+	Sent whenever the wheel on the tool emits an event. This event
+	contains two values for the same axis change. The degrees value is
+	in the same orientation as the wl_pointer.vertical_scroll axis. The
+	clicks value is in discrete logical clicks of the mouse wheel. This
+	value may be zero if the movement of the wheel was less
+	than one logical click.
+
+	Clients should choose either value and avoid mixing degrees and
+	clicks. The compositor may accumulate values smaller than a logical
+	click and emulate click events when a certain threshold is met.
+	Thus, wl_tablet_tool.wheel events with non-zero clicks values may
+	have different degrees values.
+      </description>
+      <arg name="degrees" type="fixed" summary="The wheel delta in degrees"/>
+      <arg name="clicks" type="int" summary="The wheel delta in discrete clicks"/>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+	Describes the physical state of a button that produced the button event.
+      </description>
+      <entry name="released" value="0" summary="button is not pressed"/>
+      <entry name="pressed" value="1" summary="button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="button event">
+	Sent whenever a button on the tool is pressed or released.
+
+	If a button is held down when the tool moves in or out of proximity,
+	button events are generated by the compositor. See
+	wp_tablet_tool.proximity_in and wp_tablet_tool.proximity_out for
+	details.
+      </description>
+      <arg name="serial" type="uint"/>
+      <arg name="button" type="uint" summary="The button whose state has changed"/>
+      <arg name="state" type="uint" enum="button_state" summary="Whether the button was pressed or released"/>
+    </event>
+
+    <event name="frame">
+      <description summary="frame event">
+	Marks the end of a series of axis and/or button updates from the
+	tablet. The Wayland protocol requires axis updates to be sent
+	sequentially, however all events within a frame should be considered
+	one hardware event.
+      </description>
+      <arg name="time" type="uint" summary="The time of the event with millisecond granularity"/>
+    </event>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+  </interface>
+
+  <interface name="zwp_tablet_v2" version="1">
+    <description summary="graphics tablet device">
+      The wp_tablet interface represents one graphics tablet device. The
+      tablet interface itself does not generate events; all events are
+      generated by wp_tablet_tool objects when in proximity above a tablet.
+
+      A tablet has a number of static characteristics, e.g. device name and
+      pid/vid. These capabilities are sent in an event sequence after the
+      wp_tablet_seat.tablet_added event. This initial event sequence is
+      terminated by a wp_tablet.done event.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the tablet object">
+	This destroys the client's resource for this tablet object.
+      </description>
+    </request>
+
+    <event name="name">
+      <description summary="tablet device name">
+        A descriptive name for the tablet device.
+
+	If the device has no descriptive name, this event is not sent.
+
+	This event is sent in the initial burst of events before the
+        wp_tablet.done event.
+      </description>
+      <arg name="name" type="string" summary="the device name"/>
+    </event>
+
+    <event name="id">
+      <description summary="tablet device USB vendor/product id">
+	The USB vendor and product IDs for the tablet device.
+
+	If the device has no USB vendor/product ID, this event is not sent.
+	This can happen for virtual devices or non-USB devices, for instance.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet.done event.
+      </description>
+      <arg name="vid" type="uint" summary="USB vendor id"/>
+      <arg name="pid" type="uint" summary="USB product id"/>
+    </event>
+
+    <event name="path">
+      <description summary="path to the device">
+	A system-specific device path that indicates which device is behind
+	this wp_tablet. This information may be used to gather additional
+	information about the device, e.g. through libwacom.
+
+	A device may have more than one device path. If so, multiple
+	wp_tablet.path events are sent. A device may be emulated and not
+	have a device path, and in that case this event will not be sent.
+
+	The format of the path is unspecified, it may be a device node, a
+	sysfs path, or some other identifier. It is up to the client to
+	identify the string provided.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet.done event.
+      </description>
+      <arg name="path" type="string" summary="path to local device"/>
+    </event>
+
+    <event name="done">
+      <description summary="tablet description events sequence complete">
+	This event is sent immediately to signal the end of the initial
+	burst of descriptive events. A client may consider the static
+	description of the tablet to be complete and finalize initialization
+	of the tablet.
+      </description>
+    </event>
+
+    <event name="removed">
+      <description summary="tablet removed event">
+	Sent when the tablet has been removed from the system. When a tablet
+	is removed, some tools may be removed.
+
+	When this event is received, the client must wp_tablet.destroy
+	the object.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_pad_ring_v2" version="1">
+    <description summary="pad ring">
+      A circular interaction area, such as the touch ring on the Wacom Intuos
+      Pro series tablets.
+
+      Events on a ring are logically grouped by the wl_tablet_pad_ring.frame
+      event.
+    </description>
+
+    <request name="set_feedback">
+      <description summary="set compositor feedback">
+	Request that the compositor use the provided feedback string
+	associated with this ring. This request should be issued immediately
+	after a wp_tablet_pad_group.mode_switch event from the corresponding
+	group is received, or whenever the ring is mapped to a different
+	action. See wp_tablet_pad_group.mode_switch for more details.
+
+	Clients are encouraged to provide context-aware descriptions for
+	the actions associated with the ring; compositors may use this
+	information to offer visual feedback about the button layout
+	(eg. on-screen displays).
+
+	The provided string 'description' is a UTF-8 encoded string to be
+	associated with this ring, and is considered user-visible; general
+	internationalization rules apply.
+
+	The serial argument will be that of the last
+	wp_tablet_pad_group.mode_switch event received for the group of this
+	ring. Requests providing other serials than the most recent one will be
+	ignored.
+      </description>
+      <arg name="description" type="string" summary="ring description"/>
+      <arg name="serial" type="uint" summary="serial of the mode switch event"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the ring object">
+	This destroys the client's resource for this ring object.
+      </description>
+    </request>
+
+    <enum name="source">
+      <description summary="ring axis source">
+	Describes the source types for ring events. This indicates to the
+	client how a ring event was physically generated; a client may
+	adjust the user interface accordingly. For example, events
+	from a "finger" source may trigger kinetic scrolling.
+      </description>
+      <entry name="finger" value="1" summary="finger"/>
+    </enum>
+
+    <event name="source">
+      <description summary="ring event source">
+	Source information for ring events.
+
+	This event does not occur on its own. It is sent before a
+	wp_tablet_pad_ring.frame event and carries the source information
+	for all events within that frame.
+
+	The source specifies how this event was generated. If the source is
+	wp_tablet_pad_ring.source.finger, a wp_tablet_pad_ring.stop event
+	will be sent when the user lifts the finger off the device.
+
+	This event is optional. If the source is unknown for an interaction,
+	no event is sent.
+      </description>
+      <arg name="source" type="uint" enum="source" summary="the event source"/>
+    </event>
+
+    <event name="angle">
+      <description summary="angle changed">
+	Sent whenever the angle on a ring changes.
+
+	The angle is provided in degrees clockwise from the logical
+	north of the ring in the pad's current rotation.
+      </description>
+      <arg name="degrees" type="fixed" summary="the current angle in degrees"/>
+    </event>
+
+    <event name="stop">
+      <description summary="interaction stopped">
+	Stop notification for ring events.
+
+	For some wp_tablet_pad_ring.source types, a wp_tablet_pad_ring.stop
+	event is sent to notify a client that the interaction with the ring
+	has terminated. This enables the client to implement kinetic scrolling.
+	See the wp_tablet_pad_ring.source documentation for information on
+	when this event may be generated.
+
+	Any wp_tablet_pad_ring.angle events with the same source after this
+	event should be considered as the start of a new interaction.
+      </description>
+    </event>
+
+    <event name="frame">
+      <description summary="end of a ring event sequence">
+	Indicates the end of a set of ring events that logically belong
+	together. A client is expected to accumulate the data in all events
+	within the frame before proceeding.
+
+	All wp_tablet_pad_ring events before a wp_tablet_pad_ring.frame event belong
+	logically together. For example, on termination of a finger interaction
+	on a ring the compositor will send a wp_tablet_pad_ring.source event,
+	a wp_tablet_pad_ring.stop event and a wp_tablet_pad_ring.frame event.
+
+	A wp_tablet_pad_ring.frame event is sent for every logical event
+	group, even if the group only contains a single wp_tablet_pad_ring
+	event. Specifically, a client may get a sequence: angle, frame,
+	angle, frame, etc.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_pad_strip_v2" version="1">
+    <description summary="pad strip">
+      A linear interaction area, such as the strips found in Wacom Cintiq
+      models.
+
+      Events on a strip are logically grouped by the wl_tablet_pad_strip.frame
+      event.
+    </description>
+
+    <request name="set_feedback">
+      <description summary="set compositor feedback">
+	Requests the compositor to use the provided feedback string
+	associated with this strip. This request should be issued immediately
+	after a wp_tablet_pad_group.mode_switch event from the corresponding
+	group is received, or whenever the strip is mapped to a different
+	action. See wp_tablet_pad_group.mode_switch for more details.
+
+	Clients are encouraged to provide context-aware descriptions for
+	the actions associated with the strip, and compositors may use this
+	information to offer visual feedback about the button layout
+	(eg. on-screen displays).
+
+	The provided string 'description' is a UTF-8 encoded string to be
+	associated with this ring, and is considered user-visible; general
+	internationalization rules apply.
+
+	The serial argument will be that of the last
+	wp_tablet_pad_group.mode_switch event received for the group of this
+	strip. Requests providing other serials than the most recent one will be
+	ignored.
+      </description>
+      <arg name="description" type="string" summary="strip description"/>
+      <arg name="serial" type="uint" summary="serial of the mode switch event"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the strip object">
+	This destroys the client's resource for this strip object.
+      </description>
+    </request>
+
+    <enum name="source">
+      <description summary="strip axis source">
+	Describes the source types for strip events. This indicates to the
+	client how a strip event was physically generated; a client may
+	adjust the user interface accordingly. For example, events
+	from a "finger" source may trigger kinetic scrolling.
+      </description>
+      <entry name="finger" value="1" summary="finger"/>
+    </enum>
+
+    <event name="source">
+      <description summary="strip event source">
+	Source information for strip events.
+
+	This event does not occur on its own. It is sent before a
+	wp_tablet_pad_strip.frame event and carries the source information
+	for all events within that frame.
+
+	The source specifies how this event was generated. If the source is
+	wp_tablet_pad_strip.source.finger, a wp_tablet_pad_strip.stop event
+	will be sent when the user lifts their finger off the device.
+
+	This event is optional. If the source is unknown for an interaction,
+	no event is sent.
+      </description>
+      <arg name="source" type="uint" enum="source" summary="the event source"/>
+    </event>
+
+    <event name="position">
+      <description summary="position changed">
+	Sent whenever the position on a strip changes.
+
+	The position is normalized to a range of [0, 65535], the 0-value
+	represents the top-most and/or left-most position of the strip in
+	the pad's current rotation.
+      </description>
+      <arg name="position" type="uint" summary="the current position"/>
+    </event>
+
+    <event name="stop">
+      <description summary="interaction stopped">
+	Stop notification for strip events.
+
+	For some wp_tablet_pad_strip.source types, a wp_tablet_pad_strip.stop
+	event is sent to notify a client that the interaction with the strip
+	has terminated. This enables the client to implement kinetic
+	scrolling. See the wp_tablet_pad_strip.source documentation for
+	information on when this event may be generated.
+
+	Any wp_tablet_pad_strip.position events with the same source after this
+	event should be considered as the start of a new interaction.
+      </description>
+    </event>
+
+    <event name="frame">
+      <description summary="end of a strip event sequence">
+	Indicates the end of a set of events that represent one logical
+	hardware strip event. A client is expected to accumulate the data
+	in all events within the frame before proceeding.
+
+	All wp_tablet_pad_strip events before a wp_tablet_pad_strip.frame event belong
+	logically together. For example, on termination of a finger interaction
+	on a strip the compositor will send a wp_tablet_pad_strip.source event,
+	a wp_tablet_pad_strip.stop event and a wp_tablet_pad_strip.frame
+	event.
+
+	A wp_tablet_pad_strip.frame event is sent for every logical event
+	group, even if the group only contains a single wp_tablet_pad_strip
+	event. Specifically, a client may get a sequence: position, frame,
+	position, frame, etc.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_pad_group_v2" version="1">
+    <description summary="a set of buttons, rings and strips">
+      A pad group describes a distinct (sub)set of buttons, rings and strips
+      present in the tablet. The criteria of this grouping is usually positional,
+      eg. if a tablet has buttons on the left and right side, 2 groups will be
+      presented. The physical arrangement of groups is undisclosed and may
+      change on the fly.
+
+      Pad groups will announce their features during pad initialization. Between
+      the corresponding wp_tablet_pad.group event and wp_tablet_pad_group.done, the
+      pad group will announce the buttons, rings and strips contained in it,
+      plus the number of supported modes.
+
+      Modes are a mechanism to allow multiple groups of actions for every element
+      in the pad group. The number of groups and available modes in each is
+      persistent across device plugs. The current mode is user-switchable, it
+      will be announced through the wp_tablet_pad_group.mode_switch event both
+      whenever it is switched, and after wp_tablet_pad.enter.
+
+      The current mode logically applies to all elements in the pad group,
+      although it is at clients' discretion whether to actually perform different
+      actions, and/or issue the respective .set_feedback requests to notify the
+      compositor. See the wp_tablet_pad_group.mode_switch event for more details.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pad object">
+	Destroy the wp_tablet_pad_group object. Objects created from this object
+	are unaffected and should be destroyed separately.
+      </description>
+    </request>
+
+    <event name="buttons">
+      <description summary="buttons announced">
+	Sent on wp_tablet_pad_group initialization to announce the available
+	buttons in the group. Button indices start at 0, a button may only be
+	in one group at a time.
+
+	This event is first sent in the initial burst of events before the
+	wp_tablet_pad_group.done event.
+
+	Some buttons are reserved by the compositor. These buttons may not be
+	assigned to any wp_tablet_pad_group. Compositors may broadcast this
+	event in the case of changes to the mapping of these reserved buttons.
+	If the compositor happens to reserve all buttons in a group, this event
+	will be sent with an empty array.
+      </description>
+      <arg name="buttons" type="array" summary="buttons in this group"/>
+    </event>
+
+    <event name="ring">
+      <description summary="ring announced">
+	Sent on wp_tablet_pad_group initialization to announce available rings.
+	One event is sent for each ring available on this pad group.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad_group.done event.
+      </description>
+      <arg name="ring" type="new_id" interface="zwp_tablet_pad_ring_v2"/>
+    </event>
+
+    <event name="strip">
+      <description summary="strip announced">
+	Sent on wp_tablet_pad initialization to announce available strips.
+	One event is sent for each strip available on this pad group.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad_group.done event.
+      </description>
+      <arg name="strip" type="new_id" interface="zwp_tablet_pad_strip_v2"/>
+    </event>
+
+    <event name="modes">
+      <description summary="mode-switch ability announced">
+	Sent on wp_tablet_pad_group initialization to announce that the pad
+	group may switch between modes. A client may use a mode to store a
+	specific configuration for buttons, rings and strips and use the
+	wl_tablet_pad_group.mode_switch event to toggle between these
+	configurations. Mode indices start at 0.
+
+	Switching modes is compositor-dependent. See the
+	wp_tablet_pad_group.mode_switch event for more details.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad_group.done event. This event is only sent when more than
+	more than one mode is available.
+      </description>
+      <arg name="modes" type="uint" summary="the number of modes"/>
+    </event>
+
+    <event name="done">
+      <description summary="tablet group description events sequence complete">
+	This event is sent immediately to signal the end of the initial
+	burst of descriptive events. A client may consider the static
+	description of the tablet to be complete and finalize initialization
+	of the tablet group.
+      </description>
+    </event>
+
+    <event name="mode_switch">
+      <description summary="mode switch event">
+	Notification that the mode was switched.
+
+	A mode applies to all buttons, rings and strips in a group
+	simultaneously, but a client is not required to assign different actions
+	for each mode. For example, a client may have mode-specific button
+	mappings but map the ring to vertical scrolling in all modes. Mode
+	indices start at 0.
+
+	Switching modes is compositor-dependent. The compositor may provide
+	visual cues to the client about the mode, e.g. by toggling LEDs on
+	the tablet device. Mode-switching may be software-controlled or
+	controlled by one or more physical buttons. For example, on a Wacom
+	Intuos Pro, the button inside the ring may be assigned to switch
+	between modes.
+
+	The compositor will also send this event after wp_tablet_pad.enter on
+	each group in order to notify of the current mode. Groups that only
+	feature one mode will use mode=0 when emitting this event.
+
+	If a button action in the new mode differs from the action in the
+	previous mode, the client should immediately issue a
+	wp_tablet_pad.set_feedback request for each changed button.
+
+	If a ring or strip action in the new mode differs from the action
+	in the previous mode, the client should immediately issue a
+	wp_tablet_ring.set_feedback or wp_tablet_strip.set_feedback request
+	for each changed ring or strip.
+      </description>
+      <arg name="time" type="uint" summary="the time of the event with millisecond granularity"/>
+      <arg name="serial" type="uint"/>
+      <arg name="mode" type="uint" summary="the new mode of the pad"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_tablet_pad_v2" version="1">
+    <description summary="a set of buttons, rings and strips">
+      A pad device is a set of buttons, rings and strips
+      usually physically present on the tablet device itself. Some
+      exceptions exist where the pad device is physically detached, e.g. the
+      Wacom ExpressKey Remote.
+
+      Pad devices have no axes that control the cursor and are generally
+      auxiliary devices to the tool devices used on the tablet surface.
+
+      A pad device has a number of static characteristics, e.g. the number
+      of rings. These capabilities are sent in an event sequence after the
+      wp_tablet_seat.pad_added event before any actual events from this pad.
+      This initial event sequence is terminated by a wp_tablet_pad.done
+      event.
+
+      All pad features (buttons, rings and strips) are logically divided into
+      groups and all pads have at least one group. The available groups are
+      notified through the wp_tablet_pad.group event; the compositor will
+      emit one event per group before emitting wp_tablet_pad.done.
+
+      Groups may have multiple modes. Modes allow clients to map multiple
+      actions to a single pad feature. Only one mode can be active per group,
+      although different groups may have different active modes.
+    </description>
+
+    <request name="set_feedback">
+      <description summary="set compositor feedback">
+	Requests the compositor to use the provided feedback string
+	associated with this button. This request should be issued immediately
+	after a wp_tablet_pad_group.mode_switch event from the corresponding
+	group is received, or whenever a button is mapped to a different
+	action. See wp_tablet_pad_group.mode_switch for more details.
+
+	Clients are encouraged to provide context-aware descriptions for
+	the actions associated with each button, and compositors may use
+	this information to offer visual feedback on the button layout
+	(e.g. on-screen displays).
+
+	Button indices start at 0. Setting the feedback string on a button
+	that is reserved by the compositor (i.e. not belonging to any
+	wp_tablet_pad_group) does not generate an error but the compositor
+	is free to ignore the request.
+
+	The provided string 'description' is a UTF-8 encoded string to be
+	associated with this ring, and is considered user-visible; general
+	internationalization rules apply.
+
+	The serial argument will be that of the last
+	wp_tablet_pad_group.mode_switch event received for the group of this
+	button. Requests providing other serials than the most recent one will
+	be ignored.
+      </description>
+      <arg name="button" type="uint" summary="button index"/>
+      <arg name="description" type="string" summary="button description"/>
+      <arg name="serial" type="uint" summary="serial of the mode switch event"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pad object">
+	Destroy the wp_tablet_pad object. Objects created from this object
+	are unaffected and should be destroyed separately.
+      </description>
+    </request>
+
+    <event name="group">
+      <description summary="group announced">
+	Sent on wp_tablet_pad initialization to announce available groups.
+	One event is sent for each pad group available.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad.done event. At least one group will be announced.
+      </description>
+      <arg name="pad_group" type="new_id" interface="zwp_tablet_pad_group_v2"/>
+    </event>
+
+    <event name="path">
+      <description summary="path to the device">
+	A system-specific device path that indicates which device is behind
+	this wp_tablet_pad. This information may be used to gather additional
+	information about the device, e.g. through libwacom.
+
+	The format of the path is unspecified, it may be a device node, a
+	sysfs path, or some other identifier. It is up to the client to
+	identify the string provided.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad.done event.
+      </description>
+      <arg name="path" type="string" summary="path to local device"/>
+    </event>
+
+    <event name="buttons">
+      <description summary="buttons announced">
+	Sent on wp_tablet_pad initialization to announce the available
+	buttons.
+
+	This event is sent in the initial burst of events before the
+	wp_tablet_pad.done event. This event is only sent when at least one
+	button is available.
+      </description>
+      <arg name="buttons" type="uint" summary="the number of buttons"/>
+    </event>
+
+    <event name="done">
+      <description summary="pad description event sequence complete">
+	This event signals the end of the initial burst of descriptive
+	events. A client may consider the static description of the pad to
+	be complete and finalize initialization of the pad.
+      </description>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+	Describes the physical state of a button that caused the button
+	event.
+      </description>
+      <entry name="released" value="0" summary="the button is not pressed"/>
+      <entry name="pressed" value="1" summary="the button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="physical button state">
+	Sent whenever the physical state of a button changes.
+      </description>
+      <arg name="time" type="uint" summary="the time of the event with millisecond granularity"/>
+      <arg name="button" type="uint" summary="the index of the button that changed state"/>
+      <arg name="state" type="uint" enum="button_state"/>
+    </event>
+
+    <event name="enter">
+      <description summary="enter event">
+	Notification that this pad is focused on the specified surface.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="tablet" type="object" interface="zwp_tablet_v2" summary="the tablet the pad is attached to"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface the pad is focused on"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+	Notification that this pad is no longer focused on the specified
+	surface.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the leave event"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface the pad is no longer focused on"/>
+    </event>
+
+    <event name="removed">
+      <description summary="pad removed event">
+	Sent when the pad has been removed from the system. When a tablet
+	is removed its pad(s) will be removed too.
+
+	When this event is received, the client must destroy all rings, strips
+	and groups that were offered by this pad, and issue wp_tablet_pad.destroy
+	the pad itself.
+      </description>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/text-input/README b/subprojects/wayland-protocols/unstable/text-input/README
new file mode 100644
index 0000000000000000000000000000000000000000..cb72d7179e855f2aa2729761d7e52259a3f1700b
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/text-input/README
@@ -0,0 +1,4 @@
+Text input protocol
+
+Maintainers:
+Jan Arne Petersen <janarne@gmail.com> (@jpetersen)
diff --git a/subprojects/wayland-protocols/unstable/text-input/text-input-unstable-v1.xml b/subprojects/wayland-protocols/unstable/text-input/text-input-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6ee266522a5cd60219a25672451743c8b7c430cc
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/text-input/text-input-unstable-v1.xml
@@ -0,0 +1,385 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="text_input_unstable_v1">
+
+  <copyright>
+    Copyright © 2012, 2013 Intel Corporation
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zwp_text_input_v1" version="1">
+    <description summary="text input">
+      An object used for text input. Adds support for text input and input
+      methods to applications. A text_input object is created from a
+      wl_text_input_manager and corresponds typically to a text entry in an
+      application.
+
+      Requests are used to activate/deactivate the text_input object and set
+      state information like surrounding and selected text or the content type.
+      The information about entered text is sent to the text_input object via
+      the pre-edit and commit events. Using this interface removes the need
+      for applications to directly process hardware key events and compose text
+      out of them.
+
+      Text is generally UTF-8 encoded, indices and lengths are in bytes.
+
+      Serials are used to synchronize the state between the text input and
+      an input method. New serials are sent by the text input in the
+      commit_state request and are used by the input method to indicate
+      the known text input state in events like preedit_string, commit_string,
+      and keysym. The text input can then ignore events from the input method
+      which are based on an outdated state (for example after a reset).
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="activate">
+      <description summary="request activation">
+	Requests the text_input object to be activated (typically when the
+	text entry gets focus).
+
+	The seat argument is a wl_seat which maintains the focus for this
+	activation. The surface argument is a wl_surface assigned to the
+	text_input object and tracked for focus lost. The enter event
+	is emitted on successful activation.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+
+    <request name="deactivate">
+      <description summary="request deactivation">
+	Requests the text_input object to be deactivated (typically when the
+	text entry lost focus). The seat argument is a wl_seat which was used
+	for activation.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+
+    <request name="show_input_panel">
+      <description summary="show input panels">
+	Requests input panels (virtual keyboard) to show.
+      </description>
+    </request>
+
+    <request name="hide_input_panel">
+      <description summary="hide input panels">
+	Requests input panels (virtual keyboard) to hide.
+      </description>
+    </request>
+
+    <request name="reset">
+      <description summary="reset">
+	Should be called by an editor widget when the input state should be
+	reset, for example after the text was changed outside of the normal
+	input method flow.
+      </description>
+    </request>
+
+    <request name="set_surrounding_text">
+      <description summary="sets the surrounding text">
+	Sets the plain surrounding text around the input position. Text is
+	UTF-8 encoded. Cursor is the byte offset within the
+	surrounding text. Anchor is the byte offset of the
+	selection anchor within the surrounding text. If there is no selected
+	text anchor, then it is the same as cursor.
+      </description>
+      <arg name="text" type="string"/>
+      <arg name="cursor" type="uint"/>
+      <arg name="anchor" type="uint"/>
+    </request>
+
+    <enum name="content_hint" bitfield="true">
+      <description summary="content hint">
+	Content hint is a bitmask to allow to modify the behavior of the text
+	input.
+      </description>
+      <entry name="none" value="0x0" summary="no special behaviour"/>
+      <entry name="default" value="0x7" summary="auto completion, correction and capitalization"/>
+      <entry name="password" value="0xc0" summary="hidden and sensitive text"/>
+      <entry name="auto_completion" value="0x1" summary="suggest word completions"/>
+      <entry name="auto_correction" value="0x2" summary="suggest word corrections"/>
+      <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
+      <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
+      <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
+      <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
+      <entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
+      <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
+      <entry name="latin" value="0x100" summary="just latin characters should be entered"/>
+      <entry name="multiline" value="0x200" summary="the text input is multiline"/>
+    </enum>
+
+    <enum name="content_purpose">
+      <description summary="content purpose">
+	The content purpose allows to specify the primary purpose of a text
+	input.
+
+	This allows an input method to show special purpose input panels with
+	extra characters or to disallow some characters.
+      </description>
+      <entry name="normal" value="0" summary="default input, allowing all characters"/>
+      <entry name="alpha" value="1" summary="allow only alphabetic characters"/>
+      <entry name="digits" value="2" summary="allow only digits"/>
+      <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
+      <entry name="phone" value="4" summary="input a phone number"/>
+      <entry name="url" value="5" summary="input an URL"/>
+      <entry name="email" value="6" summary="input an email address"/>
+      <entry name="name" value="7" summary="input a name of a person"/>
+      <entry name="password" value="8" summary="input a password (combine with password or sensitive_data hint)"/>
+      <entry name="date" value="9" summary="input a date"/>
+      <entry name="time" value="10" summary="input a time"/>
+      <entry name="datetime" value="11" summary="input a date and time"/>
+      <entry name="terminal" value="12" summary="input for a terminal"/>
+    </enum>
+
+    <request name="set_content_type">
+      <description summary="set content purpose and hint">
+	Sets the content purpose and content hint. While the purpose is the
+	basic purpose of an input field, the hint flags allow to modify some
+	of the behavior.
+
+	When no content type is explicitly set, a normal content purpose with
+	default hints (auto completion, auto correction, auto capitalization)
+	should be assumed.
+      </description>
+      <arg name="hint" type="uint" enum="content_hint" />
+      <arg name="purpose" type="uint" enum="content_purpose" />
+    </request>
+
+    <request name="set_cursor_rectangle">
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="set_preferred_language">
+      <description summary="sets preferred language">
+	Sets a specific language. This allows for example a virtual keyboard to
+	show a language specific layout. The "language" argument is an RFC-3066
+	format language tag.
+
+	It could be used for example in a word processor to indicate the
+	language of the currently edited document or in an instant message
+	application which tracks languages of contacts.
+      </description>
+      <arg name="language" type="string"/>
+    </request>
+
+    <request name="commit_state">
+      <arg name="serial" type="uint" summary="used to identify the known state"/>
+    </request>
+
+    <request name="invoke_action">
+      <arg name="button" type="uint"/>
+      <arg name="index" type="uint"/>
+    </request>
+
+    <event name="enter">
+      <description summary="enter event">
+	Notify the text_input object when it received focus. Typically in
+	response to an activate request.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+	Notify the text_input object when it lost focus. Either in response
+	to a deactivate request or when the assigned surface lost focus or was
+	destroyed.
+      </description>
+    </event>
+
+    <event name="modifiers_map">
+      <description summary="modifiers map">
+	Transfer an array of 0-terminated modifier names. The position in
+	the array is the index of the modifier as used in the modifiers
+	bitmask in the keysym event.
+      </description>
+      <arg name="map" type="array"/>
+    </event>
+
+    <event name="input_panel_state">
+      <description summary="state of the input panel">
+	Notify when the visibility state of the input panel changed.
+      </description>
+      <arg name="state" type="uint"/>
+    </event>
+
+    <event name="preedit_string">
+      <description summary="pre-edit">
+	Notify when a new composing text (pre-edit) should be set around the
+	current cursor position. Any previously set composing text should
+	be removed.
+
+	The commit text can be used to replace the preedit text on reset
+	(for example on unfocus).
+
+	The text input should also handle all preedit_style and preedit_cursor
+	events occurring directly before preedit_string.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="text" type="string"/>
+      <arg name="commit" type="string"/>
+    </event>
+
+    <enum name="preedit_style">
+      <entry name="default" value="0" summary="default style for composing text"/>
+      <entry name="none" value="1" summary="style should be the same as in non-composing text"/>
+      <entry name="active" value="2"/>
+      <entry name="inactive" value="3"/>
+      <entry name="highlight" value="4"/>
+      <entry name="underline" value="5"/>
+      <entry name="selection" value="6"/>
+      <entry name="incorrect" value="7"/>
+    </enum>
+
+    <event name="preedit_styling">
+      <description summary="pre-edit styling">
+	Sets styling information on composing text. The style is applied for
+	length bytes from index relative to the beginning of the composing
+	text (as byte offset). Multiple styles can
+	be applied to a composing text by sending multiple preedit_styling
+	events.
+
+	This event is handled as part of a following preedit_string event.
+      </description>
+      <arg name="index" type="uint"/>
+      <arg name="length" type="uint"/>
+      <arg name="style" type="uint" enum="preedit_style" />
+    </event>
+
+    <event name="preedit_cursor">
+      <description summary="pre-edit cursor">
+	Sets the cursor position inside the composing text (as byte
+	offset) relative to the start of the composing text. When index is a
+	negative number no cursor is shown.
+
+	This event is handled as part of a following preedit_string event.
+      </description>
+      <arg name="index" type="int"/>
+    </event>
+
+    <event name="commit_string">
+      <description summary="commit">
+	Notify when text should be inserted into the editor widget. The text to
+	commit could be either just a single character after a key press or the
+	result of some composing (pre-edit). It could also be an empty text
+	when some text should be removed (see delete_surrounding_text) or when
+	the input cursor should be moved (see cursor_position).
+
+	Any previously set composing text should be removed.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="text" type="string"/>
+    </event>
+
+    <event name="cursor_position">
+      <description summary="set cursor to new position">
+	Notify when the cursor or anchor position should be modified.
+
+	This event should be handled as part of a following commit_string
+	event.
+      </description>
+      <arg name="index" type="int"/>
+      <arg name="anchor" type="int"/>
+    </event>
+
+    <event name="delete_surrounding_text">
+      <description summary="delete surrounding text">
+	Notify when the text around the current cursor position should be
+	deleted.
+
+	Index is relative to the current cursor (in bytes).
+	Length is the length of deleted text (in bytes).
+
+	This event should be handled as part of a following commit_string
+	event.
+      </description>
+      <arg name="index" type="int"/>
+      <arg name="length" type="uint"/>
+    </event>
+
+    <event name="keysym">
+      <description summary="keysym">
+	Notify when a key event was sent. Key events should not be used
+	for normal text input operations, which should be done with
+	commit_string, delete_surrounding_text, etc. The key event follows
+	the wl_keyboard key event convention. Sym is an XKB keysym, state a
+	wl_keyboard key_state. Modifiers are a mask for effective modifiers
+	(where the modifier indices are set by the modifiers_map event)
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="time" type="uint"/>
+      <arg name="sym" type="uint"/>
+      <arg name="state" type="uint"/>
+      <arg name="modifiers" type="uint"/>
+    </event>
+
+    <event name="language">
+      <description summary="language">
+	Sets the language of the input text. The "language" argument is an
+	RFC-3066 format language tag.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="language" type="string"/>
+    </event>
+
+    <enum name="text_direction">
+      <entry name="auto" value="0" summary="automatic text direction based on text and language"/>
+      <entry name="ltr" value="1" summary="left-to-right"/>
+      <entry name="rtl" value="2" summary="right-to-left"/>
+    </enum>
+
+    <event name="text_direction">
+      <description summary="text direction">
+	Sets the text direction of input text.
+
+	It is mainly needed for showing an input cursor on the correct side of
+	the editor when there is no input done yet and making sure neutral
+	direction text is laid out properly.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the latest known text input state"/>
+      <arg name="direction" type="uint" enum="text_direction" />
+    </event>
+  </interface>
+
+  <interface name="zwp_text_input_manager_v1" version="1">
+    <description summary="text input manager">
+      A factory for text_input objects. This object is a global singleton.
+    </description>
+
+    <request name="create_text_input">
+      <description summary="create text input">
+	Creates a new text_input object.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_text_input_v1"/>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml b/subprojects/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml
new file mode 100644
index 0000000000000000000000000000000000000000..1fae54d7ba7617a2e218835ec56f4813161df3af
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml
@@ -0,0 +1,457 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<protocol name="text_input_unstable_v3">
+  <copyright>
+    Copyright © 2012, 2013 Intel Corporation
+    Copyright © 2015, 2016 Jan Arne Petersen
+    Copyright © 2017, 2018 Red Hat, Inc.
+    Copyright © 2018       Purism SPC
+
+    Permission to use, copy, modify, distribute, and sell this
+    software and its documentation for any purpose is hereby granted
+    without fee, provided that the above copyright notice appear in
+    all copies and that both that copyright notice and this permission
+    notice appear in supporting documentation, and that the name of
+    the copyright holders not be used in advertising or publicity
+    pertaining to distribution of the software without specific,
+    written prior permission.  The copyright holders make no
+    representations about the suitability of this software for any
+    purpose.  It is provided "as is" without express or implied
+    warranty.
+
+    THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS
+    SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+    FITNESS, IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY
+    SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+    WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
+    AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
+    ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+    THIS SOFTWARE.
+  </copyright>
+
+  <description summary="Protocol for composing text">
+    This protocol allows compositors to act as input methods and to send text
+    to applications. A text input object is used to manage state of what are
+    typically text entry fields in the application.
+
+    This document adheres to the RFC 2119 when using words like "must",
+    "should", "may", etc.
+
+    Warning! The protocol described in this file is experimental and
+    backward incompatible changes may be made. Backward compatible changes
+    may be added together with the corresponding interface version bump.
+    Backward incompatible changes are done by bumping the version number in
+    the protocol and interface names and resetting the interface version.
+    Once the protocol is to be declared stable, the 'z' prefix and the
+    version number in the protocol and interface names are removed and the
+    interface version number is reset.
+  </description>
+
+  <interface name="zwp_text_input_v3" version="1">
+    <description summary="text input">
+      The zwp_text_input_v3 interface represents text input and input methods
+      associated with a seat. It provides enter/leave events to follow the
+      text input focus for a seat.
+
+      Requests are used to enable/disable the text-input object and set
+      state information like surrounding and selected text or the content type.
+      The information about the entered text is sent to the text-input object
+      via the preedit_string and commit_string events.
+
+      Text is valid UTF-8 encoded, indices and lengths are in bytes. Indices
+      must not point to middle bytes inside a code point: they must either
+      point to the first byte of a code point or to the end of the buffer.
+      Lengths must be measured between two valid indices.
+
+      Focus moving throughout surfaces will result in the emission of
+      zwp_text_input_v3.enter and zwp_text_input_v3.leave events. The focused
+      surface must commit zwp_text_input_v3.enable and
+      zwp_text_input_v3.disable requests as the keyboard focus moves across
+      editable and non-editable elements of the UI. Those two requests are not
+      expected to be paired with each other, the compositor must be able to
+      handle consecutive series of the same request.
+
+      State is sent by the state requests (set_surrounding_text,
+      set_content_type and set_cursor_rectangle) and a commit request. After an
+      enter event or disable request all state information is invalidated and
+      needs to be resent by the client.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="Destroy the wp_text_input">
+        Destroy the wp_text_input object. Also disables all surfaces enabled
+        through this wp_text_input object.
+      </description>
+    </request>
+
+    <request name="enable">
+      <description summary="Request text input to be enabled">
+        Requests text input on the surface previously obtained from the enter
+        event.
+
+        This request must be issued every time the active text input changes
+        to a new one, including within the current surface. Use
+        zwp_text_input_v3.disable when there is no longer any input focus on
+        the current surface.
+
+        Clients must not enable more than one text input on the single seat
+        and should disable the current text input before enabling the new one.
+        At most one instance of text input may be in enabled state per instance,
+        Requests to enable the another text input when some text input is active
+        must be ignored by compositor.
+
+        This request resets all state associated with previous enable, disable,
+        set_surrounding_text, set_text_change_cause, set_content_type, and
+        set_cursor_rectangle requests, as well as the state associated with
+        preedit_string, commit_string, and delete_surrounding_text events.
+
+        The set_surrounding_text, set_content_type and set_cursor_rectangle
+        requests must follow if the text input supports the necessary
+        functionality.
+
+        State set with this request is double-buffered. It will get applied on
+        the next zwp_text_input_v3.commit request, and stay valid until the
+        next committed enable or disable request.
+
+        The changes must be applied by the compositor after issuing a
+        zwp_text_input_v3.commit request.
+      </description>
+    </request>
+
+    <request name="disable">
+      <description summary="Disable text input on a surface">
+        Explicitly disable text input on the current surface (typically when
+        there is no focus on any text entry inside the surface).
+
+        State set with this request is double-buffered. It will get applied on
+        the next zwp_text_input_v3.commit request.
+      </description>
+    </request>
+
+    <request name="set_surrounding_text">
+      <description summary="sets the surrounding text">
+        Sets the surrounding plain text around the input, excluding the preedit
+        text.
+
+        The client should notify the compositor of any changes in any of the
+        values carried with this request, including changes caused by handling
+        incoming text-input events as well as changes caused by other
+        mechanisms like keyboard typing.
+
+        If the client is unaware of the text around the cursor, it should not
+        issue this request, to signify lack of support to the compositor.
+
+        Text is UTF-8 encoded, and should include the cursor position, the
+        complete selection and additional characters before and after them.
+        There is a maximum length of wayland messages, so text can not be
+        longer than 4000 bytes.
+
+        Cursor is the byte offset of the cursor within text buffer.
+
+        Anchor is the byte offset of the selection anchor within text buffer.
+        If there is no selected text, anchor is the same as cursor.
+
+        If any preedit text is present, it is replaced with a cursor for the
+        purpose of this event.
+
+        Values set with this request are double-buffered. They will get applied
+        on the next zwp_text_input_v3.commit request, and stay valid until the
+        next committed enable or disable request.
+
+        The initial state for affected fields is empty, meaning that the text
+        input does not support sending surrounding text. If the empty values
+        get applied, subsequent attempts to change them may have no effect.
+      </description>
+      <arg name="text" type="string"/>
+      <arg name="cursor" type="int"/>
+      <arg name="anchor" type="int"/>
+    </request>
+
+    <enum name="change_cause">
+      <description summary="text change reason">
+        Reason for the change of surrounding text or cursor posision.
+      </description>
+      <entry name="input_method" value="0" summary="input method caused the change"/>
+      <entry name="other" value="1" summary="something else than the input method caused the change"/>
+    </enum>
+
+    <request name="set_text_change_cause">
+      <description summary="indicates the cause of surrounding text change">
+        Tells the compositor why the text surrounding the cursor changed.
+
+        Whenever the client detects an external change in text, cursor, or
+        anchor posision, it must issue this request to the compositor. This
+        request is intended to give the input method a chance to update the
+        preedit text in an appropriate way, e.g. by removing it when the user
+        starts typing with a keyboard.
+
+        cause describes the source of the change.
+
+        The value set with this request is double-buffered. It must be applied
+        and reset to initial at the next zwp_text_input_v3.commit request.
+
+        The initial value of cause is input_method.
+      </description>
+      <arg name="cause" type="uint" enum="change_cause"/>
+    </request>
+
+    <enum name="content_hint" bitfield="true">
+      <description summary="content hint">
+        Content hint is a bitmask to allow to modify the behavior of the text
+        input.
+      </description>
+      <entry name="none" value="0x0" summary="no special behavior"/>
+      <entry name="completion" value="0x1" summary="suggest word completions"/>
+      <entry name="spellcheck" value="0x2" summary="suggest word corrections"/>
+      <entry name="auto_capitalization" value="0x4" summary="switch to uppercase letters at the start of a sentence"/>
+      <entry name="lowercase" value="0x8" summary="prefer lowercase letters"/>
+      <entry name="uppercase" value="0x10" summary="prefer uppercase letters"/>
+      <entry name="titlecase" value="0x20" summary="prefer casing for titles and headings (can be language dependent)"/>
+      <entry name="hidden_text" value="0x40" summary="characters should be hidden"/>
+      <entry name="sensitive_data" value="0x80" summary="typed text should not be stored"/>
+      <entry name="latin" value="0x100" summary="just Latin characters should be entered"/>
+      <entry name="multiline" value="0x200" summary="the text input is multiline"/>
+    </enum>
+
+    <enum name="content_purpose">
+      <description summary="content purpose">
+        The content purpose allows to specify the primary purpose of a text
+        input.
+
+        This allows an input method to show special purpose input panels with
+        extra characters or to disallow some characters.
+      </description>
+      <entry name="normal" value="0" summary="default input, allowing all characters"/>
+      <entry name="alpha" value="1" summary="allow only alphabetic characters"/>
+      <entry name="digits" value="2" summary="allow only digits"/>
+      <entry name="number" value="3" summary="input a number (including decimal separator and sign)"/>
+      <entry name="phone" value="4" summary="input a phone number"/>
+      <entry name="url" value="5" summary="input an URL"/>
+      <entry name="email" value="6" summary="input an email address"/>
+      <entry name="name" value="7" summary="input a name of a person"/>
+      <entry name="password" value="8" summary="input a password (combine with sensitive_data hint)"/>
+      <entry name="pin" value="9" summary="input is a numeric password (combine with sensitive_data hint)"/>
+      <entry name="date" value="10" summary="input a date"/>
+      <entry name="time" value="11" summary="input a time"/>
+      <entry name="datetime" value="12" summary="input a date and time"/>
+      <entry name="terminal" value="13" summary="input for a terminal"/>
+    </enum>
+
+    <request name="set_content_type">
+      <description summary="set content purpose and hint">
+        Sets the content purpose and content hint. While the purpose is the
+        basic purpose of an input field, the hint flags allow to modify some of
+        the behavior.
+
+        Values set with this request are double-buffered. They will get applied
+        on the next zwp_text_input_v3.commit request.
+        Subsequent attempts to update them may have no effect. The values
+        remain valid until the next committed enable or disable request.
+
+        The initial value for hint is none, and the initial value for purpose
+        is normal.
+      </description>
+      <arg name="hint" type="uint" enum="content_hint"/>
+      <arg name="purpose" type="uint" enum="content_purpose"/>
+    </request>
+
+    <request name="set_cursor_rectangle">
+      <description summary="set cursor position">
+        Marks an area around the cursor as a x, y, width, height rectangle in
+        surface local coordinates.
+
+        Allows the compositor to put a window with word suggestions near the
+        cursor, without obstructing the text being input.
+
+        If the client is unaware of the position of edited text, it should not
+        issue this request, to signify lack of support to the compositor.
+
+        Values set with this request are double-buffered. They will get applied
+        on the next zwp_text_input_v3.commit request, and stay valid until the
+        next committed enable or disable request.
+
+        The initial values describing a cursor rectangle are empty. That means
+        the text input does not support describing the cursor area. If the
+        empty values get applied, subsequent attempts to change them may have
+        no effect.
+      </description>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="commit">
+      <description summary="commit state">
+        Atomically applies state changes recently sent to the compositor.
+
+        The commit request establishes and updates the state of the client, and
+        must be issued after any changes to apply them.
+
+        Text input state (enabled status, content purpose, content hint,
+        surrounding text and change cause, cursor rectangle) is conceptually
+        double-buffered within the context of a text input, i.e. between a
+        committed enable request and the following committed enable or disable
+        request.
+
+        Protocol requests modify the pending state, as opposed to the current
+        state in use by the input method. A commit request atomically applies
+        all pending state, replacing the current state. After commit, the new
+        pending state is as documented for each related request.
+
+        Requests are applied in the order of arrival.
+
+        Neither current nor pending state are modified unless noted otherwise.
+
+        The compositor must count the number of commit requests coming from
+        each zwp_text_input_v3 object and use the count as the serial in done
+        events.
+      </description>
+    </request>
+
+    <event name="enter">
+      <description summary="enter event">
+        Notification that this seat's text-input focus is on a certain surface.
+
+        If client has created multiple text input objects, compositor must send
+        this event to all of them.
+
+        When the seat has the keyboard capability the text-input focus follows
+        the keyboard focus. This event sets the current surface for the
+        text-input object.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+        Notification that this seat's text-input focus is no longer on a
+        certain surface. The client should reset any preedit string previously
+        set.
+
+        The leave notification clears the current surface. It is sent before
+        the enter notification for the new focus. After leave event, compositor
+        must ignore requests from any text input instances until next enter
+        event.
+
+        When the seat has the keyboard capability the text-input focus follows
+        the keyboard focus.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </event>
+
+    <event name="preedit_string">
+      <description summary="pre-edit">
+        Notify when a new composing text (pre-edit) should be set at the
+        current cursor position. Any previously set composing text must be
+        removed. Any previously existing selected text must be removed.
+
+        The argument text contains the pre-edit string buffer.
+
+        The parameters cursor_begin and cursor_end are counted in bytes
+        relative to the beginning of the submitted text buffer. Cursor should
+        be hidden when both are equal to -1.
+
+        They could be represented by the client as a line if both values are
+        the same, or as a text highlight otherwise.
+
+        Values set with this event are double-buffered. They must be applied
+        and reset to initial on the next zwp_text_input_v3.done event.
+
+        The initial value of text is an empty string, and cursor_begin,
+        cursor_end and cursor_hidden are all 0.
+      </description>
+      <arg name="text" type="string" allow-null="true"/>
+      <arg name="cursor_begin" type="int"/>
+      <arg name="cursor_end" type="int"/>
+    </event>
+
+    <event name="commit_string">
+      <description summary="text commit">
+        Notify when text should be inserted into the editor widget. The text to
+        commit could be either just a single character after a key press or the
+        result of some composing (pre-edit).
+
+        Values set with this event are double-buffered. They must be applied
+        and reset to initial on the next zwp_text_input_v3.done event.
+
+        The initial value of text is an empty string.
+      </description>
+      <arg name="text" type="string" allow-null="true"/>
+    </event>
+
+    <event name="delete_surrounding_text">
+      <description summary="delete surrounding text">
+        Notify when the text around the current cursor position should be
+        deleted.
+
+        Before_length and after_length are the number of bytes before and after
+        the current cursor index (excluding the selection) to delete.
+
+        If a preedit text is present, in effect before_length is counted from
+        the beginning of it, and after_length from its end (see done event
+        sequence).
+
+        Values set with this event are double-buffered. They must be applied
+        and reset to initial on the next zwp_text_input_v3.done event.
+
+        The initial values of both before_length and after_length are 0.
+      </description>
+      <arg name="before_length" type="uint" summary="length of text before current cursor position"/>
+      <arg name="after_length" type="uint" summary="length of text after current cursor position"/>
+    </event>
+
+    <event name="done">
+      <description summary="apply changes">
+        Instruct the application to apply changes to state requested by the
+        preedit_string, commit_string and delete_surrounding_text events. The
+        state relating to these events is double-buffered, and each one
+        modifies the pending state. This event replaces the current state with
+        the pending state.
+
+        The application must proceed by evaluating the changes in the following
+        order:
+
+        1. Replace existing preedit string with the cursor.
+        2. Delete requested surrounding text.
+        3. Insert commit string with the cursor at its end.
+        4. Calculate surrounding text to send.
+        5. Insert new preedit text in cursor position.
+        6. Place cursor inside preedit text.
+
+        The serial number reflects the last state of the zwp_text_input_v3
+        object known to the compositor. The value of the serial argument must
+        be equal to the number of commit requests already issued on that object.
+
+        When the client receives a done event with a serial different than the
+        number of past commit requests, it must proceed with evaluating and
+        applying the changes as normal, except it should not change the current
+        state of the zwp_text_input_v3 object. All pending state requests
+        (set_surrounding_text, set_content_type and set_cursor_rectangle) on
+        the zwp_text_input_v3 object should be sent and committed after
+        receiving a zwp_text_input_v3.done event with a matching serial.
+      </description>
+      <arg name="serial" type="uint"/>
+    </event>
+  </interface>
+
+  <interface name="zwp_text_input_manager_v3" version="1">
+    <description summary="text input manager">
+      A factory for text-input objects. This object is a global singleton.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="Destroy the wp_text_input_manager">
+        Destroy the wp_text_input_manager object.
+      </description>
+    </request>
+
+    <request name="get_text_input">
+      <description summary="create a new text input object">
+        Creates a new text-input object for a given seat.
+      </description>
+      <arg name="id" type="new_id" interface="zwp_text_input_v3"/>
+      <arg name="seat" type="object" interface="wl_seat"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/xdg-decoration/README b/subprojects/wayland-protocols/unstable/xdg-decoration/README
new file mode 100644
index 0000000000000000000000000000000000000000..cdb45192faa49991cc97614cf44be3319d523d0d
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-decoration/README
@@ -0,0 +1,4 @@
+xdg_decoration protocol
+
+Maintainers:
+Simon Ser <contact@emersion.fr> (@emersion)
diff --git a/subprojects/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml b/subprojects/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..82ca247c745080fdcd582dc0f0b035a66572bf48
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
@@ -0,0 +1,160 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_decoration_unstable_v1">
+  <copyright>
+    Copyright © 2018 Simon Ser
+
+    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.
+  </copyright>
+
+  <interface name="zxdg_decoration_manager_v1" version="1">
+    <description summary="window decoration manager">
+      This interface allows a compositor to announce support for server-side
+      decorations.
+
+      A window decoration is a set of window controls as deemed appropriate by
+      the party managing them, such as user interface components used to move,
+      resize and change a window's state.
+
+      A client can use this protocol to request being decorated by a supporting
+      compositor.
+
+      If compositor and client do not negotiate the use of a server-side
+      decoration using this protocol, clients continue to self-decorate as they
+      see fit.
+
+      Warning! The protocol described in this file is experimental and
+      backward incompatible changes may be made. Backward compatible changes
+      may be added together with the corresponding interface version bump.
+      Backward incompatible changes are done by bumping the version number in
+      the protocol and interface names and resetting the interface version.
+      Once the protocol is to be declared stable, the 'z' prefix and the
+      version number in the protocol and interface names are removed and the
+      interface version number is reset.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the decoration manager object">
+        Destroy the decoration manager. This doesn't destroy objects created
+        with the manager.
+      </description>
+    </request>
+
+    <request name="get_toplevel_decoration">
+      <description summary="create a new toplevel decoration object">
+        Create a new decoration object associated with the given toplevel.
+
+        Creating an xdg_toplevel_decoration from an xdg_toplevel which has a
+        buffer attached or committed is a client error, and any attempts by a
+        client to attach or manipulate a buffer prior to the first
+        xdg_toplevel_decoration.configure event must also be treated as
+        errors.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_toplevel_decoration_v1"/>
+      <arg name="toplevel" type="object" interface="xdg_toplevel"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_toplevel_decoration_v1" version="1">
+    <description summary="decoration object for a toplevel surface">
+      The decoration object allows the compositor to toggle server-side window
+      decorations for a toplevel surface. The client can request to switch to
+      another mode.
+
+      The xdg_toplevel_decoration object must be destroyed before its
+      xdg_toplevel.
+    </description>
+
+    <enum name="error">
+      <entry name="unconfigured_buffer" value="0"
+        summary="xdg_toplevel has a buffer attached before configure"/>
+      <entry name="already_constructed" value="1"
+        summary="xdg_toplevel already has a decoration object"/>
+      <entry name="orphaned" value="2"
+        summary="xdg_toplevel destroyed before the decoration object"/>
+      <entry name="invalid_mode" value="3" summary="invalid mode"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the decoration object">
+        Switch back to a mode without any server-side decorations at the next
+        commit.
+      </description>
+    </request>
+
+    <enum name="mode">
+      <description summary="window decoration modes">
+        These values describe window decoration modes.
+      </description>
+      <entry name="client_side" value="1"
+        summary="no server-side window decoration"/>
+      <entry name="server_side" value="2"
+        summary="server-side window decoration"/>
+    </enum>
+
+    <request name="set_mode">
+      <description summary="set the decoration mode">
+        Set the toplevel surface decoration mode. This informs the compositor
+        that the client prefers the provided decoration mode.
+
+        After requesting a decoration mode, the compositor will respond by
+        emitting an xdg_surface.configure event. The client should then update
+        its content, drawing it without decorations if the received mode is
+        server-side decorations. The client must also acknowledge the configure
+        when committing the new content (see xdg_surface.ack_configure).
+
+        The compositor can decide not to use the client's mode and enforce a
+        different mode instead.
+
+        Clients whose decoration mode depend on the xdg_toplevel state may send
+        a set_mode request in response to an xdg_surface.configure event and wait
+        for the next xdg_surface.configure event to prevent unwanted state.
+        Such clients are responsible for preventing configure loops and must
+        make sure not to send multiple successive set_mode requests with the
+        same decoration mode.
+
+        If an invalid mode is supplied by the client, the invalid_mode protocol
+        error is raised by the compositor.
+      </description>
+      <arg name="mode" type="uint" enum="mode" summary="the decoration mode"/>
+    </request>
+
+    <request name="unset_mode">
+      <description summary="unset the decoration mode">
+        Unset the toplevel surface decoration mode. This informs the compositor
+        that the client doesn't prefer a particular decoration mode.
+
+        This request has the same semantics as set_mode.
+      </description>
+    </request>
+
+    <event name="configure">
+      <description summary="notify a decoration mode change">
+        The configure event configures the effective decoration mode. The
+        configured state should not be applied immediately. Clients must send an
+        ack_configure in response to this event. See xdg_surface.configure and
+        xdg_surface.ack_configure for details.
+
+        A configure event can be sent at any time. The specified mode must be
+        obeyed by the client.
+      </description>
+      <arg name="mode" type="uint" enum="mode" summary="the decoration mode"/>
+    </event>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/xdg-foreign/README b/subprojects/wayland-protocols/unstable/xdg-foreign/README
new file mode 100644
index 0000000000000000000000000000000000000000..29af57482b8a924b6e022940ac0fd091ec077f35
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-foreign/README
@@ -0,0 +1,4 @@
+xdg foreign protocol
+
+Maintainers:
+Jonas Ã…dahl <jadahl@gmail.com> (@jadahl)
diff --git a/subprojects/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml b/subprojects/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..913963aa524c02a97214393df46f251efbb7f7df
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v1.xml
@@ -0,0 +1,182 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_foreign_unstable_v1">
+
+  <copyright>
+    Copyright © 2015-2016 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.
+  </copyright>
+
+  <description summary="Protocol for exporting xdg surface handles">
+    This protocol specifies a way for making it possible to reference a surface
+    of a different client. With such a reference, a client can, by using the
+    interfaces provided by this protocol, manipulate the relationship between
+    its own surfaces and the surface of some other client. For example, stack
+    some of its own surface above the other clients surface.
+
+    In order for a client A to get a reference of a surface of client B, client
+    B must first export its surface using xdg_exporter.export. Upon doing this,
+    client B will receive a handle (a unique string) that it may share with
+    client A in some way (for example D-Bus). After client A has received the
+    handle from client B, it may use xdg_importer.import to create a reference
+    to the surface client B just exported. See the corresponding requests for
+    details.
+
+    A possible use case for this is out-of-process dialogs. For example when a
+    sandboxed client without file system access needs the user to select a file
+    on the file system, given sandbox environment support, it can export its
+    surface, passing the exported surface handle to an unsandboxed process that
+    can show a file browser dialog and stack it above the sandboxed client's
+    surface.
+
+    Warning! The protocol described in this file is experimental and backward
+    incompatible changes may be made. Backward compatible changes may be added
+    together with the corresponding interface version bump. Backward
+    incompatible changes are done by bumping the version number in the protocol
+    and interface names and resetting the interface version. Once the protocol
+    is to be declared stable, the 'z' prefix and the version number in the
+    protocol and interface names are removed and the interface version number is
+    reset.
+  </description>
+
+  <interface name="zxdg_exporter_v1" version="1">
+    <description summary="interface for exporting surfaces">
+      A global interface used for exporting surfaces that can later be imported
+      using xdg_importer.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_exporter object">
+	Notify the compositor that the xdg_exporter object will no longer be
+	used.
+      </description>
+    </request>
+
+    <request name="export">
+      <description summary="export a surface">
+	The export request exports the passed surface so that it can later be
+	imported via xdg_importer. When called, a new xdg_exported object will
+	be created and xdg_exported.handle will be sent immediately. See the
+	corresponding interface and event for details.
+
+	A surface may be exported multiple times, and each exported handle may
+	be used to create an xdg_imported multiple times. Only xdg_surface
+	surfaces may be exported.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_exported_v1"
+	   summary="the new xdg_exported object"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the surface to export"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_importer_v1" version="1">
+    <description summary="interface for importing surfaces">
+      A global interface used for importing surfaces exported by xdg_exporter.
+      With this interface, a client can create a reference to a surface of
+      another client.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_importer object">
+	Notify the compositor that the xdg_importer object will no longer be
+	used.
+      </description>
+    </request>
+
+    <request name="import">
+      <description summary="import a surface">
+	The import request imports a surface from any client given a handle
+	retrieved by exporting said surface using xdg_exporter.export. When
+	called, a new xdg_imported object will be created. This new object
+	represents the imported surface, and the importing client can
+	manipulate its relationship using it. See xdg_imported for details.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_imported_v1"
+	   summary="the new xdg_imported object"/>
+      <arg name="handle" type="string"
+	   summary="the exported surface handle"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_exported_v1" version="1">
+    <description summary="an exported surface handle">
+      An xdg_exported object represents an exported reference to a surface. The
+      exported surface may be referenced as long as the xdg_exported object not
+      destroyed. Destroying the xdg_exported invalidates any relationship the
+      importer may have established using xdg_imported.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unexport the exported surface">
+	Revoke the previously exported surface. This invalidates any
+	relationship the importer may have set up using the xdg_imported created
+	given the handle sent via xdg_exported.handle.
+      </description>
+    </request>
+
+    <event name="handle">
+      <description summary="the exported surface handle">
+	The handle event contains the unique handle of this exported surface
+	reference. It may be shared with any client, which then can use it to
+	import the surface by calling xdg_importer.import. A handle may be
+	used to import the surface multiple times.
+      </description>
+      <arg name="handle" type="string" summary="the exported surface handle"/>
+    </event>
+  </interface>
+
+  <interface name="zxdg_imported_v1" version="1">
+    <description summary="an imported surface handle">
+      An xdg_imported object represents an imported reference to surface exported
+      by some client. A client can use this interface to manipulate
+      relationships between its own surfaces and the imported surface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_imported object">
+	Notify the compositor that it will no longer use the xdg_imported
+	object. Any relationship that may have been set up will at this point
+	be invalidated.
+      </description>
+    </request>
+
+    <request name="set_parent_of">
+      <description summary="set as the parent of some surface">
+	Set the imported surface as the parent of some surface of the client.
+	The passed surface must be a toplevel xdg_surface. Calling this function
+	sets up a surface to surface relation with the same stacking and positioning
+	semantics as xdg_surface.set_parent.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the child surface"/>
+    </request>
+
+    <event name="destroyed">
+      <description summary="the imported surface handle has been destroyed">
+	The imported surface handle has been destroyed and any relationship set
+	up has been invalidated. This may happen for various reasons, for
+	example if the exported surface or the exported surface handle has been
+	destroyed, if the handle used for importing was invalid.
+      </description>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml b/subprojects/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml
new file mode 100644
index 0000000000000000000000000000000000000000..cc3271dca4d6211bf6d04c34c0ca973c52f9b552
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-foreign/xdg-foreign-unstable-v2.xml
@@ -0,0 +1,200 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_foreign_unstable_v2">
+
+  <copyright>
+    Copyright © 2015-2016 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.
+  </copyright>
+
+  <description summary="Protocol for exporting xdg surface handles">
+    This protocol specifies a way for making it possible to reference a surface
+    of a different client. With such a reference, a client can, by using the
+    interfaces provided by this protocol, manipulate the relationship between
+    its own surfaces and the surface of some other client. For example, stack
+    some of its own surface above the other clients surface.
+
+    In order for a client A to get a reference of a surface of client B, client
+    B must first export its surface using xdg_exporter.export_toplevel. Upon
+    doing this, client B will receive a handle (a unique string) that it may
+    share with client A in some way (for example D-Bus). After client A has
+    received the handle from client B, it may use xdg_importer.import_toplevel
+    to create a reference to the surface client B just exported. See the
+    corresponding requests for details.
+
+    A possible use case for this is out-of-process dialogs. For example when a
+    sandboxed client without file system access needs the user to select a file
+    on the file system, given sandbox environment support, it can export its
+    surface, passing the exported surface handle to an unsandboxed process that
+    can show a file browser dialog and stack it above the sandboxed client's
+    surface.
+
+    Warning! The protocol described in this file is experimental and backward
+    incompatible changes may be made. Backward compatible changes may be added
+    together with the corresponding interface version bump. Backward
+    incompatible changes are done by bumping the version number in the protocol
+    and interface names and resetting the interface version. Once the protocol
+    is to be declared stable, the 'z' prefix and the version number in the
+    protocol and interface names are removed and the interface version number is
+    reset.
+  </description>
+
+  <interface name="zxdg_exporter_v2" version="1">
+    <description summary="interface for exporting surfaces">
+      A global interface used for exporting surfaces that can later be imported
+      using xdg_importer.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_exporter object">
+	Notify the compositor that the xdg_exporter object will no longer be
+	used.
+      </description>
+    </request>
+
+    <enum name="error">
+      <description summary="error values">
+        These errors can be emitted in response to invalid xdg_exporter
+        requests.
+      </description>
+      <entry name="invalid_surface" value="0" summary="surface is not an xdg_toplevel"/>
+    </enum>
+
+    <request name="export_toplevel">
+      <description summary="export a toplevel surface">
+	The export_toplevel request exports the passed surface so that it can later be
+	imported via xdg_importer. When called, a new xdg_exported object will
+	be created and xdg_exported.handle will be sent immediately. See the
+	corresponding interface and event for details.
+
+	A surface may be exported multiple times, and each exported handle may
+	be used to create an xdg_imported multiple times. Only xdg_toplevel
+        equivalent surfaces may be exported, otherwise an invalid_surface
+        protocol error is sent.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_exported_v2"
+	   summary="the new xdg_exported object"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the surface to export"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_importer_v2" version="1">
+    <description summary="interface for importing surfaces">
+      A global interface used for importing surfaces exported by xdg_exporter.
+      With this interface, a client can create a reference to a surface of
+      another client.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_importer object">
+	Notify the compositor that the xdg_importer object will no longer be
+	used.
+      </description>
+    </request>
+
+    <request name="import_toplevel">
+      <description summary="import a toplevel surface">
+	The import_toplevel request imports a surface from any client given a handle
+	retrieved by exporting said surface using xdg_exporter.export_toplevel.
+	When called, a new xdg_imported object will be created. This new object
+	represents the imported surface, and the importing client can
+	manipulate its relationship using it. See xdg_imported for details.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_imported_v2"
+	   summary="the new xdg_imported object"/>
+      <arg name="handle" type="string"
+	   summary="the exported surface handle"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_exported_v2" version="1">
+    <description summary="an exported surface handle">
+      An xdg_exported object represents an exported reference to a surface. The
+      exported surface may be referenced as long as the xdg_exported object not
+      destroyed. Destroying the xdg_exported invalidates any relationship the
+      importer may have established using xdg_imported.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unexport the exported surface">
+	Revoke the previously exported surface. This invalidates any
+	relationship the importer may have set up using the xdg_imported created
+	given the handle sent via xdg_exported.handle.
+      </description>
+    </request>
+
+    <event name="handle">
+      <description summary="the exported surface handle">
+	The handle event contains the unique handle of this exported surface
+	reference. It may be shared with any client, which then can use it to
+	import the surface by calling xdg_importer.import_toplevel. A handle
+	may be used to import the surface multiple times.
+      </description>
+      <arg name="handle" type="string" summary="the exported surface handle"/>
+    </event>
+  </interface>
+
+  <interface name="zxdg_imported_v2" version="1">
+    <description summary="an imported surface handle">
+      An xdg_imported object represents an imported reference to surface exported
+      by some client. A client can use this interface to manipulate
+      relationships between its own surfaces and the imported surface.
+    </description>
+
+    <enum name="error">
+      <description summary="error values">
+        These errors can be emitted in response to invalid xdg_imported
+        requests.
+      </description>
+      <entry name="invalid_surface" value="0" summary="surface is not an xdg_toplevel"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_imported object">
+	Notify the compositor that it will no longer use the xdg_imported
+	object. Any relationship that may have been set up will at this point
+	be invalidated.
+      </description>
+    </request>
+
+    <request name="set_parent_of">
+      <description summary="set as the parent of some surface">
+        Set the imported surface as the parent of some surface of the client.
+        The passed surface must be an xdg_toplevel equivalent, otherwise an
+        invalid_surface protocol error is sent. Calling this function sets up
+        a surface to surface relation with the same stacking and positioning
+        semantics as xdg_toplevel.set_parent.
+      </description>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the child surface"/>
+    </request>
+
+    <event name="destroyed">
+      <description summary="the imported surface handle has been destroyed">
+	The imported surface handle has been destroyed and any relationship set
+	up has been invalidated. This may happen for various reasons, for
+	example if the exported surface or the exported surface handle has been
+	destroyed, if the handle used for importing was invalid.
+      </description>
+    </event>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/xdg-output/README b/subprojects/wayland-protocols/unstable/xdg-output/README
new file mode 100644
index 0000000000000000000000000000000000000000..b87800b35c004eaf743eed1096aded6043497bac
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-output/README
@@ -0,0 +1,4 @@
+xdg_output protocol
+
+Maintainers:
+Olivier Fourdan <ofourdan@redhat.com> (@ofourdan)
diff --git a/subprojects/wayland-protocols/unstable/xdg-output/xdg-output-unstable-v1.xml b/subprojects/wayland-protocols/unstable/xdg-output/xdg-output-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a7306e4193e2841926f2ca4d37d348476176cedd
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-output/xdg-output-unstable-v1.xml
@@ -0,0 +1,222 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_output_unstable_v1">
+
+  <copyright>
+    Copyright © 2017 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.
+  </copyright>
+
+  <description summary="Protocol to describe output regions">
+    This protocol aims at describing outputs in a way which is more in line
+    with the concept of an output on desktop oriented systems.
+
+    Some information are more specific to the concept of an output for
+    a desktop oriented system and may not make sense in other applications,
+    such as IVI systems for example.
+
+    Typically, the global compositor space on a desktop system is made of
+    a contiguous or overlapping set of rectangular regions.
+
+    The logical_position and logical_size events defined in this protocol
+    might provide information identical to their counterparts already
+    available from wl_output, in which case the information provided by this
+    protocol should be preferred to their equivalent in wl_output. The goal is
+    to move the desktop specific concepts (such as output location within the
+    global compositor space, etc.) out of the core wl_output protocol.
+
+    Warning! The protocol described in this file is experimental and
+    backward incompatible changes may be made. Backward compatible
+    changes may be added together with the corresponding interface
+    version bump.
+    Backward incompatible changes are done by bumping the version
+    number in the protocol and interface names and resetting the
+    interface version. Once the protocol is to be declared stable,
+    the 'z' prefix and the version number in the protocol and
+    interface names are removed and the interface version number is
+    reset.
+  </description>
+
+  <interface name="zxdg_output_manager_v1" version="3">
+    <description summary="manage xdg_output objects">
+      A global factory interface for xdg_output objects.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_output_manager object">
+	Using this request a client can tell the server that it is not
+	going to use the xdg_output_manager object anymore.
+
+	Any objects already created through this instance are not affected.
+      </description>
+    </request>
+
+    <request name="get_xdg_output">
+      <description summary="create an xdg output from a wl_output">
+	This creates a new xdg_output object for the given wl_output.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_output_v1"/>
+      <arg name="output" type="object" interface="wl_output"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_output_v1" version="3">
+    <description summary="compositor logical output region">
+      An xdg_output describes part of the compositor geometry.
+
+      This typically corresponds to a monitor that displays part of the
+      compositor space.
+
+      For objects version 3 onwards, after all xdg_output properties have been
+      sent (when the object is created and when properties are updated), a
+      wl_output.done event is sent. This allows changes to the output
+      properties to be seen as atomic, even if they happen via multiple events.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_output object">
+	Using this request a client can tell the server that it is not
+	going to use the xdg_output object anymore.
+      </description>
+    </request>
+
+    <event name="logical_position">
+      <description summary="position of the output within the global compositor space">
+	The position event describes the location of the wl_output within
+	the global compositor space.
+
+	The logical_position event is sent after creating an xdg_output
+	(see xdg_output_manager.get_xdg_output) and whenever the location
+	of the output changes within the global compositor space.
+      </description>
+      <arg name="x" type="int"
+	   summary="x position within the global compositor space"/>
+      <arg name="y" type="int"
+	   summary="y position within the global compositor space"/>
+    </event>
+
+    <event name="logical_size">
+      <description summary="size of the output in the global compositor space">
+	The logical_size event describes the size of the output in the
+	global compositor space.
+
+	Most regular Wayland clients should not pay attention to the
+	logical size and would rather rely on xdg_shell interfaces.
+
+	Some clients such as Xwayland, however, need this to configure
+	their surfaces in the global compositor space as the compositor
+	may apply a different scale from what is advertised by the output
+	scaling property (to achieve fractional scaling, for example).
+
+	For example, for a wl_output mode 3840×2160 and a scale factor 2:
+
+	- A compositor not scaling the monitor viewport in its compositing space
+	  will advertise a logical size of 3840×2160,
+
+	- A compositor scaling the monitor viewport with scale factor 2 will
+	  advertise a logical size of 1920×1080,
+
+	- A compositor scaling the monitor viewport using a fractional scale of
+	  1.5 will advertise a logical size of 2560×1440.
+
+	For example, for a wl_output mode 1920×1080 and a 90 degree rotation,
+	the compositor will advertise a logical size of 1080x1920.
+
+	The logical_size event is sent after creating an xdg_output
+	(see xdg_output_manager.get_xdg_output) and whenever the logical
+	size of the output changes, either as a result of a change in the
+	applied scale or because of a change in the corresponding output
+	mode(see wl_output.mode) or transform (see wl_output.transform).
+      </description>
+      <arg name="width" type="int"
+	   summary="width in global compositor space"/>
+      <arg name="height" type="int"
+	   summary="height in global compositor space"/>
+    </event>
+
+    <event name="done" deprecated-since="3">
+      <description summary="all information about the output have been sent">
+	This event is sent after all other properties of an xdg_output
+	have been sent.
+
+	This allows changes to the xdg_output properties to be seen as
+	atomic, even if they happen via multiple events.
+
+	For objects version 3 onwards, this event is deprecated. Compositors
+	are not required to send it anymore and must send wl_output.done
+	instead.
+      </description>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <event name="name" since="2">
+      <description summary="name of this output">
+	Many compositors will assign names to their outputs, show them to the
+	user, allow them to be configured by name, etc. The client may wish to
+	know this name as well to offer the user similar behaviors.
+
+	The naming convention is compositor defined, but limited to
+	alphanumeric characters and dashes (-). Each name is unique among all
+	wl_output globals, but if a wl_output global is destroyed the same name
+	may be reused later. The names will also remain consistent across
+	sessions with the same hardware and software configuration.
+
+	Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do
+	not assume that the name is a reflection of an underlying DRM
+	connector, X11 connection, etc.
+
+	The name event is sent after creating an xdg_output (see
+	xdg_output_manager.get_xdg_output). This event is only sent once per
+	xdg_output, and the name does not change over the lifetime of the
+	wl_output global.
+
+        This event is deprecated, instead clients should use wl_output.name.
+        Compositors must still support this event.
+      </description>
+      <arg name="name" type="string" summary="output name"/>
+    </event>
+
+    <event name="description" since="2">
+      <description summary="human-readable description of this output">
+	Many compositors can produce human-readable descriptions of their
+	outputs.  The client may wish to know this description as well, to
+	communicate the user for various purposes.
+
+	The description is a UTF-8 string with no convention defined for its
+	contents. Examples might include 'Foocorp 11" Display' or 'Virtual X11
+	output via :1'.
+
+	The description event is sent after creating an xdg_output (see
+	xdg_output_manager.get_xdg_output) and whenever the description
+	changes. The description is optional, and may not be sent at all.
+
+	For objects of version 2 and lower, this event is only sent once per
+	xdg_output, and the description does not change over the lifetime of
+	the wl_output global.
+
+	This event is deprecated, instead clients should use
+	wl_output.description. Compositors must still support this event.
+      </description>
+      <arg name="description" type="string" summary="output description"/>
+    </event>
+
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/xdg-shell/README b/subprojects/wayland-protocols/unstable/xdg-shell/README
new file mode 100644
index 0000000000000000000000000000000000000000..cf418ed38f83c71bd422c538ebb605c9939cc99b
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-shell/README
@@ -0,0 +1,9 @@
+xdg shell protocol
+
+Maintainers:
+Jasper St. Pierre <jstpierre@mecheye.net>
+
+Disclaimer: This protocol extension has been superseded by the copy in stable/.
+The stable version has made backwards-incompatible changes relative to this
+version. This version is deprecated and only retained for backwards
+compatibility.
diff --git a/subprojects/wayland-protocols/unstable/xdg-shell/xdg-shell-unstable-v5.xml b/subprojects/wayland-protocols/unstable/xdg-shell/xdg-shell-unstable-v5.xml
new file mode 100644
index 0000000000000000000000000000000000000000..5813d68ee53de8e963ec86a7351a49e388bb9d18
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-shell/xdg-shell-unstable-v5.xml
@@ -0,0 +1,631 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_shell_unstable_v5">
+
+  <copyright>
+    Copyright © 2008-2013 Kristian Høgsberg
+    Copyright © 2013      Rafael Antognolli
+    Copyright © 2013      Jasper St. Pierre
+    Copyright © 2010-2013 Intel Corporation
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="xdg_shell" version="1">
+    <description summary="create desktop-style surfaces">
+      xdg_shell allows clients to turn a wl_surface into a "real window"
+      which can be dragged, resized, stacked, and moved around by the
+      user. Everything about this interface is suited towards traditional
+      desktop environments.
+    </description>
+
+    <enum name="version">
+      <description summary="latest protocol version">
+	The 'current' member of this enum gives the version of the
+	protocol.  Implementations can compare this to the version
+	they implement using static_assert to ensure the protocol and
+	implementation versions match.
+      </description>
+      <entry name="current" value="5" summary="Always the latest version"/>
+    </enum>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+      <entry name="defunct_surfaces" value="1" summary="xdg_shell was destroyed before children"/>
+      <entry name="not_the_topmost_popup" value="2" summary="the client tried to map or destroy a non-topmost popup"/>
+      <entry name="invalid_popup_parent" value="3" summary="the client specified an invalid popup parent surface"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy xdg_shell">
+        Destroy this xdg_shell object.
+
+        Destroying a bound xdg_shell object while there are surfaces
+        still alive created by this xdg_shell object instance is illegal
+        and will result in a protocol error.
+      </description>
+    </request>
+
+    <request name="use_unstable_version">
+      <description summary="enable use of this unstable version">
+	Negotiate the unstable version of the interface.  This
+	mechanism is in place to ensure client and server agree on the
+	unstable versions of the protocol that they speak or exit
+	cleanly if they don't agree.  This request will go away once
+	the xdg-shell protocol is stable.
+      </description>
+      <arg name="version" type="int"/>
+    </request>
+
+    <request name="get_xdg_surface">
+      <description summary="create a shell surface from a surface">
+	This creates an xdg_surface for the given surface and gives it the
+	xdg_surface role. A wl_surface can only be given an xdg_surface role
+	once. If get_xdg_surface is called with a wl_surface that already has
+	an active xdg_surface associated with it, or if it had any other role,
+	an error is raised.
+
+	See the documentation of xdg_surface for more details about what an
+	xdg_surface is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="xdg_surface"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+
+    <request name="get_xdg_popup">
+      <description summary="create a popup for a surface">
+	This creates an xdg_popup for the given surface and gives it the
+	xdg_popup role. A wl_surface can only be given an xdg_popup role
+	once. If get_xdg_popup is called with a wl_surface that already has
+	an active xdg_popup associated with it, or if it had any other role,
+	an error is raised.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event.
+
+	See the documentation of xdg_popup for more details about what an
+	xdg_popup is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="xdg_popup"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+      <arg name="parent" type="object" interface="wl_surface"/>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+    </request>
+
+    <event name="ping">
+      <description summary="check if the client is alive">
+        The ping event asks the client if it's still alive. Pass the
+        serial specified in the event back to the compositor by sending
+        a "pong" request back with the specified serial.
+
+        Compositors can use this to determine if the client is still
+        alive. It's unspecified what will happen if the client doesn't
+        respond to the ping request, or in what timeframe. Clients should
+        try to respond in a reasonable amount of time.
+
+        A compositor is free to ping in any way it wants, but a client must
+        always respond to any xdg_shell object it created.
+      </description>
+      <arg name="serial" type="uint" summary="pass this to the pong request"/>
+    </event>
+
+    <request name="pong">
+      <description summary="respond to a ping event">
+	A client must respond to a ping event with a pong request or
+	the client may be deemed unresponsive.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the ping event"/>
+    </request>
+  </interface>
+
+  <interface name="xdg_surface" version="1">
+    <description summary="A desktop window">
+      An interface that may be implemented by a wl_surface, for
+      implementations that provide a desktop-style user interface.
+
+      It provides requests to treat surfaces like windows, allowing to set
+      properties like maximized, fullscreen, minimized, and to move and resize
+      them, and associate metadata like title and app id.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xdg_surface state to take effect. Prior to committing the new
+      state, it can set up initial configuration, such as maximizing or setting
+      a window geometry.
+
+      Even without attaching a buffer the compositor must respond to initial
+      committed configuration, for instance sending a configure event with
+      expected window geometry if the client maximized its surface during
+      initialization.
+
+      For a surface to be mapped by the compositor the client must have
+      committed both an xdg_surface state and a buffer.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="Destroy the xdg_surface">
+	Unmap and destroy the window. The window will be effectively
+	hidden from the user's point of view, and all state like
+	maximization, fullscreen, and so on, will be lost.
+      </description>
+    </request>
+
+    <request name="set_parent">
+      <description summary="set the parent of this surface">
+	Set the "parent" of this surface. This window should be stacked
+	above a parent. The parent surface must be mapped as long as this
+	surface is mapped.
+
+	Parent windows should be set on dialogs, toolboxes, or other
+	"auxiliary" surfaces, so that the parent is raised when the dialog
+	is raised.
+      </description>
+      <arg name="parent" type="object" interface="xdg_surface" allow-null="true"/>
+    </request>
+
+    <request name="set_title">
+      <description summary="set surface title">
+	Set a short title for the surface.
+
+	This string may be used to identify the surface in a task bar,
+	window list, or other user interface elements provided by the
+	compositor.
+
+	The string must be encoded in UTF-8.
+      </description>
+      <arg name="title" type="string"/>
+    </request>
+
+    <request name="set_app_id">
+      <description summary="set application ID">
+	Set an application identifier for the surface.
+
+	The app ID identifies the general class of applications to which
+	the surface belongs. The compositor can use this to group multiple
+	surfaces together, or to determine how to launch a new application.
+
+	For D-Bus activatable applications, the app ID is used as the D-Bus
+	service name.
+
+	The compositor shell will try to group application surfaces together
+	by their app ID.  As a best practice, it is suggested to select app
+	ID's that match the basename of the application's .desktop file.
+	For example, "org.freedesktop.FooViewer" where the .desktop file is
+	"org.freedesktop.FooViewer.desktop".
+
+	See the desktop-entry specification [0] for more details on
+	application identifiers and how they relate to well-known D-Bus
+	names and .desktop files.
+
+	[0] http://standards.freedesktop.org/desktop-entry-spec/
+      </description>
+      <arg name="app_id" type="string"/>
+    </request>
+
+    <request name="show_window_menu">
+      <description summary="show the window menu">
+        Clients implementing client-side decorations might want to show
+        a context menu when right-clicking on the decorations, giving the
+        user a menu that they can use to maximize or minimize the window.
+
+        This request asks the compositor to pop up such a window menu at
+        the given position, relative to the local surface coordinates of
+        the parent surface. There are no guarantees as to what menu items
+        the window menu contains.
+
+        This request must be used in response to some sort of user action
+        like a button press, key press, or touch down event.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
+      <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
+    </request>
+
+    <request name="move">
+      <description summary="start an interactive move">
+	Start an interactive, user-driven move of the surface.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event. The passed
+	serial is used to determine the type of interactive move (touch,
+	pointer, etc).
+
+	The server may ignore move requests depending on the state of
+	the surface (e.g. fullscreen or maximized), or if the passed serial
+	is no longer valid.
+
+	If triggered, the surface will lose the focus of the device
+	(wl_pointer, wl_touch, etc) used for the move. It is up to the
+	compositor to visually indicate that the move is taking place, such as
+	updating a pointer cursor, during the move. There is no guarantee
+	that the device focus will return when the move is completed.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+    </request>
+
+    <enum name="resize_edge">
+      <description summary="edge values for resizing">
+	These values are used to indicate which edge of a surface
+	is being dragged in a resize operation.
+      </description>
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="4"/>
+      <entry name="top_left" value="5"/>
+      <entry name="bottom_left" value="6"/>
+      <entry name="right" value="8"/>
+      <entry name="top_right" value="9"/>
+      <entry name="bottom_right" value="10"/>
+    </enum>
+
+    <request name="resize">
+      <description summary="start an interactive resize">
+	Start a user-driven, interactive resize of the surface.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event. The passed
+	serial is used to determine the type of interactive resize (touch,
+	pointer, etc).
+
+	The server may ignore resize requests depending on the state of
+	the surface (e.g. fullscreen or maximized).
+
+	If triggered, the client will receive configure events with the
+	"resize" state enum value and the expected sizes. See the "resize"
+	enum value for more details about what is required. The client
+	must also acknowledge configure events using "ack_configure". After
+	the resize is completed, the client will receive another "configure"
+	event without the resize state.
+
+	If triggered, the surface also will lose the focus of the device
+	(wl_pointer, wl_touch, etc) used for the resize. It is up to the
+	compositor to visually indicate that the resize is taking place,
+	such as updating a pointer cursor, during the resize. There is no
+	guarantee that the device focus will return when the resize is
+	completed.
+
+	The edges parameter specifies how the surface should be resized,
+	and is one of the values of the resize_edge enum. The compositor
+	may use this information to update the surface position for
+	example when dragging the top left corner. The compositor may also
+	use this information to adapt its behavior, e.g. choose an
+	appropriate cursor image.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
+    </request>
+
+    <enum name="state">
+      <description summary="types of state on the surface">
+        The different state values used on the surface. This is designed for
+        state values like maximized, fullscreen. It is paired with the
+        configure event to ensure that both the client and the compositor
+        setting the state can be synchronized.
+
+        States set in this way are double-buffered, see wl_surface.commit.
+
+        Desktop environments may extend this enum by taking up a range of
+        values and documenting the range they chose in this description.
+        They are not required to document the values for the range that they
+        chose. Ideally, any good extensions from a desktop environment should
+        make its way into standardization into this enum.
+
+        The current reserved ranges are:
+
+        0x0000 - 0x0FFF: xdg-shell core values, documented below.
+        0x1000 - 0x1FFF: GNOME
+        0x2000 - 0x2FFF: EFL
+      </description>
+      <entry name="maximized" value="1" summary="the surface is maximized">
+	<description summary="the surface is maximized">
+	  The surface is maximized. The window geometry specified in the configure
+	  event must be obeyed by the client.
+	</description>
+      </entry>
+      <entry name="fullscreen" value="2" summary="the surface is fullscreen">
+	<description summary="the surface is fullscreen">
+	  The surface is fullscreen. The window geometry specified in the configure
+	  event must be obeyed by the client.
+	</description>
+      </entry>
+      <entry name="resizing" value="3" summary="the surface is being resized">
+	<description summary="the surface is being resized">
+	  The surface is being resized. The window geometry specified in the
+	  configure event is a maximum; the client cannot resize beyond it.
+	  Clients that have aspect ratio or cell sizing configuration can use
+	  a smaller size, however.
+	</description>
+      </entry>
+      <entry name="activated" value="4" summary="the surface is now activated">
+	<description summary="the surface is now activated">
+	  Client window decorations should be painted as if the window is
+	  active. Do not assume this means that the window actually has
+	  keyboard or pointer focus.
+	</description>
+      </entry>
+    </enum>
+
+    <event name="configure">
+      <description summary="suggest a surface change">
+	The configure event asks the client to resize its surface or to
+	change its state.
+
+	The width and height arguments specify a hint to the window
+	about how its surface should be resized in window geometry
+	coordinates. See set_window_geometry.
+
+	If the width or height arguments are zero, it means the client
+	should decide its own window dimension. This may happen when the
+	compositor need to configure the state of the surface but doesn't
+	have any information about any previous or expected dimension.
+
+	The states listed in the event specify how the width/height
+	arguments should be interpreted, and possibly how it should be
+	drawn.
+
+	Clients should arrange their surface for the new size and
+	states, and then send a ack_configure request with the serial
+	sent in this configure event at some point before committing
+	the new surface.
+
+	If the client receives multiple configure events before it
+        can respond to one, it is free to discard all but the last
+        event it received.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="states" type="array"/>
+      <arg name="serial" type="uint"/>
+    </event>
+
+    <request name="ack_configure">
+      <description summary="ack a configure event">
+        When a configure event is received, if a client commits the
+        surface in response to the configure event, then the client
+        must make an ack_configure request sometime before the commit
+        request, passing along the serial of the configure event.
+
+        For instance, the compositor might use this information to move
+        a surface to the top left only when the client has drawn itself
+        for the maximized or fullscreen state.
+
+        If the client receives multiple configure events before it
+        can respond to one, it only has to ack the last configure event.
+
+        A client is not required to commit immediately after sending
+        an ack_configure request - it may even ack_configure several times
+        before its next surface commit.
+
+        The compositor expects that the most recently received
+        ack_configure request at the time of a commit indicates which
+        configure event the client is responding to.
+      </description>
+      <arg name="serial" type="uint" summary="the serial from the configure event"/>
+    </request>
+
+    <request name="set_window_geometry">
+      <description summary="set the new window geometry">
+        The window geometry of a window is its "visible bounds" from the
+        user's perspective. Client-side decorations often have invisible
+        portions like drop-shadows which should be ignored for the
+        purposes of aligning, placing and constraining windows.
+
+        The window geometry is double-buffered state, see wl_surface.commit.
+
+        Once the window geometry of the surface is set once, it is not
+        possible to unset it, and it will remain the same until
+        set_window_geometry is called again, even if a new subsurface or
+        buffer is attached.
+
+        If never set, the value is the full bounds of the surface,
+        including any subsurfaces. This updates dynamically on every
+        commit. This unset mode is meant for extremely simple clients.
+
+        If responding to a configure event, the window geometry in here
+        must respect the sizing negotiations specified by the states in
+        the configure event.
+
+        The arguments are given in the surface local coordinate space of
+        the wl_surface associated with this xdg_surface.
+
+        The width and height must be greater than zero.
+      </description>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="set_maximized">
+      <description summary="maximize the window">
+        Maximize the surface.
+
+        After requesting that the surface should be maximized, the compositor
+        will respond by emitting a configure event with the "maximized" state
+        and the required window geometry. The client should then update its
+        content, drawing it in a maximized state, i.e. without shadow or other
+        decoration outside of the window geometry. The client must also
+        acknowledge the configure when committing the new content (see
+        ack_configure).
+
+        It is up to the compositor to decide how and where to maximize the
+        surface, for example which output and what region of the screen should
+        be used.
+
+        If the surface was already maximized, the compositor will still emit
+        a configure event with the "maximized" state.
+
+        Note that unrelated compositor side state changes may cause
+        configure events to be emitted at any time, meaning trying to
+        match this request to a specific future configure event is
+        futile.
+      </description>
+    </request>
+
+    <request name="unset_maximized">
+      <description summary="unmaximize the window">
+        Unmaximize the surface.
+
+        After requesting that the surface should be unmaximized, the compositor
+        will respond by emitting a configure event without the "maximized"
+        state. If available, the compositor will include the window geometry
+        dimensions the window had prior to being maximized in the configure
+        request. The client must then update its content, drawing it in a
+        regular state, i.e. potentially with shadow, etc. The client must also
+        acknowledge the configure when committing the new content (see
+        ack_configure).
+
+        It is up to the compositor to position the surface after it was
+        unmaximized; usually the position the surface had before maximizing, if
+        applicable.
+
+        If the surface was already not maximized, the compositor will still
+        emit a configure event without the "maximized" state.
+
+        Note that unrelated compositor side state changes may cause
+        configure events to be emitted at any time, meaning trying to
+        match this request to a specific future configure event is
+        futile.
+      </description>
+    </request>
+
+    <request name="set_fullscreen">
+      <description summary="set the window as fullscreen on a monitor">
+	Make the surface fullscreen.
+
+        You can specify an output that you would prefer to be fullscreen.
+	If this value is NULL, it's up to the compositor to choose which
+        display will be used to map this surface.
+
+        If the surface doesn't cover the whole output, the compositor will
+        position the surface in the center of the output and compensate with
+        black borders filling the rest of the output.
+      </description>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+    <request name="unset_fullscreen" />
+
+    <request name="set_minimized">
+      <description summary="set the window as minimized">
+	Request that the compositor minimize your surface. There is no
+	way to know if the surface is currently minimized, nor is there
+	any way to unset minimization on this surface.
+
+	If you are looking to throttle redrawing when minimized, please
+	instead use the wl_surface.frame event for this, as this will
+	also work with live previews on windows in Alt-Tab, Expose or
+	similar compositor features.
+      </description>
+    </request>
+
+    <event name="close">
+      <description summary="surface wants to be closed">
+        The close event is sent by the compositor when the user
+        wants the surface to be closed. This should be equivalent to
+        the user clicking the close button in client-side decorations,
+        if your application has any...
+
+        This is only a request that the user intends to close your
+        window. The client may choose to ignore this request, or show
+        a dialog to ask the user to save their data...
+      </description>
+    </event>
+  </interface>
+
+  <interface name="xdg_popup" version="1">
+    <description summary="short-lived, popup surfaces for menus">
+      A popup surface is a short-lived, temporary surface that can be
+      used to implement menus. It takes an explicit grab on the surface
+      that will be dismissed when the user dismisses the popup. This can
+      be done by the user clicking outside the surface, using the keyboard,
+      or even locking the screen through closing the lid or a timeout.
+
+      When the popup is dismissed, a popup_done event will be sent out,
+      and at the same time the surface will be unmapped. The xdg_popup
+      object is now inert and cannot be reactivated, so clients should
+      destroy it. Explicitly destroying the xdg_popup object will also
+      dismiss the popup and unmap the surface.
+
+      Clients will receive events for all their surfaces during this
+      grab (which is an "owner-events" grab in X11 parlance). This is
+      done so that users can navigate through submenus and other
+      "nested" popup windows without having to dismiss the topmost
+      popup.
+
+      Clients that want to dismiss the popup when another surface of
+      their own is clicked should dismiss the popup using the destroy
+      request.
+
+      The parent surface must have either an xdg_surface or xdg_popup
+      role.
+
+      Specifying an xdg_popup for the parent means that the popups are
+      nested, with this popup now being the topmost popup. Nested
+      popups must be destroyed in the reverse order they were created
+      in, e.g. the only popup you are allowed to destroy at all times
+      is the topmost one.
+
+      If there is an existing popup when creating a new popup, the
+      parent must be the current topmost popup.
+
+      A parent surface must be mapped before the new popup is mapped.
+
+      When compositors choose to dismiss a popup, they will likely
+      dismiss every nested popup as well. When a compositor dismisses
+      popups, it will follow the same dismissing order as required
+      from the client.
+
+      The x and y arguments passed when creating the popup object specify
+      where the top left of the popup should be placed, relative to the
+      local surface coordinates of the parent surface. See
+      xdg_shell.get_xdg_popup.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xdg_popup state to take effect.
+
+      For a surface to be mapped by the compositor the client must have
+      committed both the xdg_popup state and a buffer.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove xdg_popup interface">
+	This destroys the popup. Explicitly destroying the xdg_popup
+	object will also dismiss the popup, and unmap the surface.
+
+	If this xdg_popup is not the "topmost" popup, a protocol error
+	will be sent.
+      </description>
+    </request>
+
+    <event name="popup_done">
+      <description summary="popup interaction is done">
+	The popup_done event is sent out when a popup is dismissed by the
+	compositor. The client should destroy the xdg_popup object at this
+	point.
+      </description>
+    </event>
+
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/xdg-shell/xdg-shell-unstable-v6.xml b/subprojects/wayland-protocols/unstable/xdg-shell/xdg-shell-unstable-v6.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2ae4e454cd03f43a7b3168a7037a3dbc1df5ac04
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xdg-shell/xdg-shell-unstable-v6.xml
@@ -0,0 +1,1059 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xdg_shell_unstable_v6">
+
+  <copyright>
+    Copyright © 2008-2013 Kristian Høgsberg
+    Copyright © 2013      Rafael Antognolli
+    Copyright © 2013      Jasper St. Pierre
+    Copyright © 2010-2013 Intel Corporation
+
+    Permission is hereby granted, free of charge, to any person obtaining a
+    copy of this software and associated documentation files (the "Software"),
+    to deal in the Software without restriction, including without limitation
+    the rights to use, copy, modify, merge, publish, distribute, sublicense,
+    and/or sell copies of the Software, and to permit persons to whom the
+    Software is furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the next
+    paragraph) shall be included in all copies or substantial portions of the
+    Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+    THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+    DEALINGS IN THE SOFTWARE.
+  </copyright>
+
+  <interface name="zxdg_shell_v6" version="1">
+    <description summary="create desktop-style surfaces">
+      xdg_shell allows clients to turn a wl_surface into a "real window"
+      which can be dragged, resized, stacked, and moved around by the
+      user. Everything about this interface is suited towards traditional
+      desktop environments.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+      <entry name="defunct_surfaces" value="1"
+	     summary="xdg_shell was destroyed before children"/>
+      <entry name="not_the_topmost_popup" value="2"
+	     summary="the client tried to map or destroy a non-topmost popup"/>
+      <entry name="invalid_popup_parent" value="3"
+	     summary="the client specified an invalid popup parent surface"/>
+      <entry name="invalid_surface_state" value="4"
+	     summary="the client provided an invalid surface state"/>
+      <entry name="invalid_positioner" value="5"
+	     summary="the client provided an invalid positioner"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy xdg_shell">
+	Destroy this xdg_shell object.
+
+	Destroying a bound xdg_shell object while there are surfaces
+	still alive created by this xdg_shell object instance is illegal
+	and will result in a protocol error.
+      </description>
+    </request>
+
+    <request name="create_positioner">
+      <description summary="create a positioner object">
+	Create a positioner object. A positioner object is used to position
+	surfaces relative to some parent surface. See the interface description
+	and xdg_surface.get_popup for details.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_positioner_v6"/>
+    </request>
+
+    <request name="get_xdg_surface">
+      <description summary="create a shell surface from a surface">
+	This creates an xdg_surface for the given surface. While xdg_surface
+	itself is not a role, the corresponding surface may only be assigned
+	a role extending xdg_surface, such as xdg_toplevel or xdg_popup.
+
+	This creates an xdg_surface for the given surface. An xdg_surface is
+	used as basis to define a role to a given surface, such as xdg_toplevel
+	or xdg_popup. It also manages functionality shared between xdg_surface
+	based surface roles.
+
+	See the documentation of xdg_surface for more details about what an
+	xdg_surface is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_surface_v6"/>
+      <arg name="surface" type="object" interface="wl_surface"/>
+    </request>
+
+    <request name="pong">
+      <description summary="respond to a ping event">
+	A client must respond to a ping event with a pong request or
+	the client may be deemed unresponsive. See xdg_shell.ping.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the ping event"/>
+    </request>
+
+    <event name="ping">
+      <description summary="check if the client is alive">
+	The ping event asks the client if it's still alive. Pass the
+	serial specified in the event back to the compositor by sending
+	a "pong" request back with the specified serial. See xdg_shell.ping.
+
+	Compositors can use this to determine if the client is still
+	alive. It's unspecified what will happen if the client doesn't
+	respond to the ping request, or in what timeframe. Clients should
+	try to respond in a reasonable amount of time.
+
+	A compositor is free to ping in any way it wants, but a client must
+	always respond to any xdg_shell object it created.
+      </description>
+      <arg name="serial" type="uint" summary="pass this to the pong request"/>
+    </event>
+  </interface>
+
+  <interface name="zxdg_positioner_v6" version="1">
+    <description summary="child surface positioner">
+      The xdg_positioner provides a collection of rules for the placement of a
+      child surface relative to a parent surface. Rules can be defined to ensure
+      the child surface remains within the visible area's borders, and to
+      specify how the child surface changes its position, such as sliding along
+      an axis, or flipping around a rectangle. These positioner-created rules are
+      constrained by the requirement that a child surface must intersect with or
+      be at least partially adjacent to its parent surface.
+
+      See the various requests for details about possible rules.
+
+      At the time of the request, the compositor makes a copy of the rules
+      specified by the xdg_positioner. Thus, after the request is complete the
+      xdg_positioner object can be destroyed or reused; further changes to the
+      object will have no effect on previous usages.
+
+      For an xdg_positioner object to be considered complete, it must have a
+      non-zero size set by set_size, and a non-zero anchor rectangle set by
+      set_anchor_rect. Passing an incomplete xdg_positioner object when
+      positioning a surface raises an error.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_input" value="0" summary="invalid input provided"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_positioner object">
+	Notify the compositor that the xdg_positioner will no longer be used.
+      </description>
+    </request>
+
+    <request name="set_size">
+      <description summary="set the size of the to-be positioned rectangle">
+	Set the size of the surface that is to be positioned with the positioner
+	object. The size is in surface-local coordinates and corresponds to the
+	window geometry. See xdg_surface.set_window_geometry.
+
+	If a zero or negative size is set the invalid_input error is raised.
+      </description>
+      <arg name="width" type="int" summary="width of positioned rectangle"/>
+      <arg name="height" type="int" summary="height of positioned rectangle"/>
+    </request>
+
+    <request name="set_anchor_rect">
+      <description summary="set the anchor rectangle within the parent surface">
+	Specify the anchor rectangle within the parent surface that the child
+	surface will be placed relative to. The rectangle is relative to the
+	window geometry as defined by xdg_surface.set_window_geometry of the
+	parent surface. The rectangle must be at least 1x1 large.
+
+	When the xdg_positioner object is used to position a child surface, the
+	anchor rectangle may not extend outside the window geometry of the
+	positioned child's parent surface.
+
+	If a zero or negative size is set the invalid_input error is raised.
+      </description>
+      <arg name="x" type="int" summary="x position of anchor rectangle"/>
+      <arg name="y" type="int" summary="y position of anchor rectangle"/>
+      <arg name="width" type="int" summary="width of anchor rectangle"/>
+      <arg name="height" type="int" summary="height of anchor rectangle"/>
+    </request>
+
+    <enum name="anchor" bitfield="true">
+      <entry name="none" value="0"
+	     summary="the center of the anchor rectangle"/>
+      <entry name="top" value="1"
+	     summary="the top edge of the anchor rectangle"/>
+      <entry name="bottom" value="2"
+	     summary="the bottom edge of the anchor rectangle"/>
+      <entry name="left" value="4"
+	     summary="the left edge of the anchor rectangle"/>
+      <entry name="right" value="8"
+	     summary="the right edge of the anchor rectangle"/>
+    </enum>
+
+    <request name="set_anchor">
+      <description summary="set anchor rectangle anchor edges">
+	Defines a set of edges for the anchor rectangle. These are used to
+	derive an anchor point that the child surface will be positioned
+	relative to. If two orthogonal edges are specified (e.g. 'top' and
+	'left'), then the anchor point will be the intersection of the edges
+	(e.g. the top left position of the rectangle); otherwise, the derived
+	anchor point will be centered on the specified edge, or in the center of
+	the anchor rectangle if no edge is specified.
+
+	If two parallel anchor edges are specified (e.g. 'left' and 'right'),
+	the invalid_input error is raised.
+      </description>
+      <arg name="anchor" type="uint" enum="anchor"
+	   summary="bit mask of anchor edges"/>
+    </request>
+
+    <enum name="gravity" bitfield="true">
+      <entry name="none" value="0"
+	     summary="center over the anchor edge"/>
+      <entry name="top" value="1"
+	     summary="position above the anchor edge"/>
+      <entry name="bottom" value="2"
+	     summary="position below the anchor edge"/>
+      <entry name="left" value="4"
+	     summary="position to the left of the anchor edge"/>
+      <entry name="right" value="8"
+	     summary="position to the right of the anchor edge"/>
+    </enum>
+
+    <request name="set_gravity">
+      <description summary="set child surface gravity">
+	Defines in what direction a surface should be positioned, relative to
+	the anchor point of the parent surface. If two orthogonal gravities are
+	specified (e.g. 'bottom' and 'right'), then the child surface will be
+	placed in the specified direction; otherwise, the child surface will be
+	centered over the anchor point on any axis that had no gravity
+	specified.
+
+	If two parallel gravities are specified (e.g. 'left' and 'right'), the
+	invalid_input error is raised.
+      </description>
+      <arg name="gravity" type="uint" enum="gravity"
+	   summary="bit mask of gravity directions"/>
+    </request>
+
+    <enum name="constraint_adjustment" bitfield="true">
+      <description summary="constraint adjustments">
+	The constraint adjustment value define ways the compositor will adjust
+	the position of the surface, if the unadjusted position would result
+	in the surface being partly constrained.
+
+	Whether a surface is considered 'constrained' is left to the compositor
+	to determine. For example, the surface may be partly outside the
+	compositor's defined 'work area', thus necessitating the child surface's
+	position be adjusted until it is entirely inside the work area.
+
+	The adjustments can be combined, according to a defined precedence: 1)
+	Flip, 2) Slide, 3) Resize.
+      </description>
+      <entry name="none" value="0">
+	<description summary="don't move the child surface when constrained">
+	  Don't alter the surface position even if it is constrained on some
+	  axis, for example partially outside the edge of a monitor.
+	</description>
+      </entry>
+      <entry name="slide_x" value="1">
+	<description summary="move along the x axis until unconstrained">
+	  Slide the surface along the x axis until it is no longer constrained.
+
+	  First try to slide towards the direction of the gravity on the x axis
+	  until either the edge in the opposite direction of the gravity is
+	  unconstrained or the edge in the direction of the gravity is
+	  constrained.
+
+	  Then try to slide towards the opposite direction of the gravity on the
+	  x axis until either the edge in the direction of the gravity is
+	  unconstrained or the edge in the opposite direction of the gravity is
+	  constrained.
+	</description>
+      </entry>
+      <entry name="slide_y" value="2">
+	<description summary="move along the y axis until unconstrained">
+	  Slide the surface along the y axis until it is no longer constrained.
+
+	  First try to slide towards the direction of the gravity on the y axis
+	  until either the edge in the opposite direction of the gravity is
+	  unconstrained or the edge in the direction of the gravity is
+	  constrained.
+
+	  Then try to slide towards the opposite direction of the gravity on the
+	  y axis until either the edge in the direction of the gravity is
+	  unconstrained or the edge in the opposite direction of the gravity is
+	  constrained.
+	</description>
+      </entry>
+      <entry name="flip_x" value="4">
+	<description summary="invert the anchor and gravity on the x axis">
+	  Invert the anchor and gravity on the x axis if the surface is
+	  constrained on the x axis. For example, if the left edge of the
+	  surface is constrained, the gravity is 'left' and the anchor is
+	  'left', change the gravity to 'right' and the anchor to 'right'.
+
+	  If the adjusted position also ends up being constrained, the resulting
+	  position of the flip_x adjustment will be the one before the
+	  adjustment.
+	</description>
+      </entry>
+      <entry name="flip_y" value="8">
+	<description summary="invert the anchor and gravity on the y axis">
+	  Invert the anchor and gravity on the y axis if the surface is
+	  constrained on the y axis. For example, if the bottom edge of the
+	  surface is constrained, the gravity is 'bottom' and the anchor is
+	  'bottom', change the gravity to 'top' and the anchor to 'top'.
+
+	  If the adjusted position also ends up being constrained, the resulting
+	  position of the flip_y adjustment will be the one before the
+	  adjustment.
+	</description>
+      </entry>
+      <entry name="resize_x" value="16">
+	<description summary="horizontally resize the surface">
+	  Resize the surface horizontally so that it is completely
+	  unconstrained.
+	</description>
+      </entry>
+      <entry name="resize_y" value="32">
+	<description summary="vertically resize the surface">
+	  Resize the surface vertically so that it is completely unconstrained.
+	</description>
+      </entry>
+    </enum>
+
+    <request name="set_constraint_adjustment">
+      <description summary="set the adjustment to be done when constrained">
+	Specify how the window should be positioned if the originally intended
+	position caused the surface to be constrained, meaning at least
+	partially outside positioning boundaries set by the compositor. The
+	adjustment is set by constructing a bitmask describing the adjustment to
+	be made when the surface is constrained on that axis.
+
+	If no bit for one axis is set, the compositor will assume that the child
+	surface should not change its position on that axis when constrained.
+
+	If more than one bit for one axis is set, the order of how adjustments
+	are applied is specified in the corresponding adjustment descriptions.
+
+	The default adjustment is none.
+      </description>
+      <arg name="constraint_adjustment" type="uint"
+	   summary="bit mask of constraint adjustments"/>
+    </request>
+
+    <request name="set_offset">
+      <description summary="set surface position offset">
+	Specify the surface position offset relative to the position of the
+	anchor on the anchor rectangle and the anchor on the surface. For
+	example if the anchor of the anchor rectangle is at (x, y), the surface
+	has the gravity bottom|right, and the offset is (ox, oy), the calculated
+	surface position will be (x + ox, y + oy). The offset position of the
+	surface is the one used for constraint testing. See
+	set_constraint_adjustment.
+
+	An example use case is placing a popup menu on top of a user interface
+	element, while aligning the user interface element of the parent surface
+	with some user interface element placed somewhere in the popup surface.
+      </description>
+      <arg name="x" type="int" summary="surface position x offset"/>
+      <arg name="y" type="int" summary="surface position y offset"/>
+    </request>
+  </interface>
+
+  <interface name="zxdg_surface_v6" version="1">
+    <description summary="desktop user interface surface base interface">
+      An interface that may be implemented by a wl_surface, for
+      implementations that provide a desktop-style user interface.
+
+      It provides a base set of functionality required to construct user
+      interface elements requiring management by the compositor, such as
+      toplevel windows, menus, etc. The types of functionality are split into
+      xdg_surface roles.
+
+      Creating an xdg_surface does not set the role for a wl_surface. In order
+      to map an xdg_surface, the client must create a role-specific object
+      using, e.g., get_toplevel, get_popup. The wl_surface for any given
+      xdg_surface can have at most one role, and may not be assigned any role
+      not based on xdg_surface.
+
+      A role must be assigned before any other requests are made to the
+      xdg_surface object.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xdg_surface state to take effect.
+
+      Creating an xdg_surface from a wl_surface which has a buffer attached or
+      committed is a client error, and any attempts by a client to attach or
+      manipulate a buffer prior to the first xdg_surface.configure call must
+      also be treated as errors.
+
+      For a surface to be mapped by the compositor, the following conditions
+      must be met: (1) the client has assigned an xdg_surface based role to the
+      surface, (2) the client has set and committed the xdg_surface state and
+      the role dependent state to the surface and (3) the client has committed a
+      buffer to the surface.
+    </description>
+
+    <enum name="error">
+      <entry name="not_constructed" value="1"/>
+      <entry name="already_constructed" value="2"/>
+      <entry name="unconfigured_buffer" value="3"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_surface">
+	Destroy the xdg_surface object. An xdg_surface must only be destroyed
+	after its role object has been destroyed. If the role object still
+        exists when this request is issued, the zxdg_shell_v6.defunct_surfaces
+        is raised.
+      </description>
+    </request>
+
+    <request name="get_toplevel">
+      <description summary="assign the xdg_toplevel surface role">
+	This creates an xdg_toplevel object for the given xdg_surface and gives
+	the associated wl_surface the xdg_toplevel role. If the surface already
+        had a role, the zxdg_shell_v6.role error is raised.
+
+	See the documentation of xdg_toplevel for more details about what an
+	xdg_toplevel is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_toplevel_v6"/>
+    </request>
+
+    <request name="get_popup">
+      <description summary="assign the xdg_popup surface role">
+	This creates an xdg_popup object for the given xdg_surface and gives the
+	associated wl_surface the xdg_popup role. If the surface already
+        had a role, the zxdg_shell_v6.role error is raised.
+
+	See the documentation of xdg_popup for more details about what an
+	xdg_popup is and how it is used.
+      </description>
+      <arg name="id" type="new_id" interface="zxdg_popup_v6"/>
+      <arg name="parent" type="object" interface="zxdg_surface_v6"/>
+      <arg name="positioner" type="object" interface="zxdg_positioner_v6"/>
+    </request>
+
+    <request name="set_window_geometry">
+      <description summary="set the new window geometry">
+	The window geometry of a surface is its "visible bounds" from the
+	user's perspective. Client-side decorations often have invisible
+	portions like drop-shadows which should be ignored for the
+	purposes of aligning, placing and constraining windows.
+
+	The window geometry is double-buffered state, see wl_surface.commit.
+
+	Once the window geometry of the surface is set, it is not possible to
+	unset it, and it will remain the same until set_window_geometry is
+	called again, even if a new subsurface or buffer is attached.
+
+	If never set, the value is the full bounds of the surface,
+	including any subsurfaces. This updates dynamically on every
+	commit. This unset is meant for extremely simple clients.
+
+	The arguments are given in the surface-local coordinate space of
+	the wl_surface associated with this xdg_surface.
+
+	The width and height must be greater than zero. Setting an invalid size
+	will raise an error. When applied, the effective window geometry will be
+	the set window geometry clamped to the bounding rectangle of the
+	combined geometry of the surface of the xdg_surface and the associated
+	subsurfaces.
+      </description>
+      <arg name="x" type="int"/>
+      <arg name="y" type="int"/>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="ack_configure">
+      <description summary="ack a configure event">
+	When a configure event is received, if a client commits the
+	surface in response to the configure event, then the client
+	must make an ack_configure request sometime before the commit
+	request, passing along the serial of the configure event.
+
+	For instance, for toplevel surfaces the compositor might use this
+	information to move a surface to the top left only when the client has
+	drawn itself for the maximized or fullscreen state.
+
+	If the client receives multiple configure events before it
+	can respond to one, it only has to ack the last configure event.
+
+	A client is not required to commit immediately after sending
+	an ack_configure request - it may even ack_configure several times
+	before its next surface commit.
+
+	A client may send multiple ack_configure requests before committing, but
+	only the last request sent before a commit indicates which configure
+	event the client really is responding to.
+
+        If an invalid serial is used, the zxdg_shell_v6.invalid_surface_state
+        error is raised.
+      </description>
+      <arg name="serial" type="uint" summary="the serial from the configure event"/>
+    </request>
+
+    <event name="configure">
+      <description summary="suggest a surface change">
+	The configure event marks the end of a configure sequence. A configure
+	sequence is a set of one or more events configuring the state of the
+	xdg_surface, including the final xdg_surface.configure event.
+
+	Where applicable, xdg_surface surface roles will during a configure
+	sequence extend this event as a latched state sent as events before the
+	xdg_surface.configure event. Such events should be considered to make up
+	a set of atomically applied configuration states, where the
+	xdg_surface.configure commits the accumulated state.
+
+	Clients should arrange their surface for the new states, and then send
+	an ack_configure request with the serial sent in this configure event at
+	some point before committing the new surface.
+
+	If the client receives multiple configure events before it can respond
+	to one, it is free to discard all but the last event it received.
+      </description>
+      <arg name="serial" type="uint" summary="serial of the configure event"/>
+    </event>
+  </interface>
+
+  <interface name="zxdg_toplevel_v6" version="1">
+    <description summary="toplevel surface">
+      This interface defines an xdg_surface role which allows a surface to,
+      among other things, set window-like properties such as maximize,
+      fullscreen, and minimize, set application-specific metadata like title and
+      id, and well as trigger user interactive operations such as interactive
+      resize and move.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the xdg_toplevel">
+	Unmap and destroy the window. The window will be effectively
+	hidden from the user's point of view, and all state like
+	maximization, fullscreen, and so on, will be lost.
+      </description>
+    </request>
+
+    <request name="set_parent">
+      <description summary="set the parent of this surface">
+	Set the "parent" of this surface. This window should be stacked
+	above a parent. The parent surface must be mapped as long as this
+	surface is mapped.
+
+	Parent windows should be set on dialogs, toolboxes, or other
+	"auxiliary" surfaces, so that the parent is raised when the dialog
+	is raised.
+      </description>
+      <arg name="parent" type="object" interface="zxdg_toplevel_v6" allow-null="true"/>
+    </request>
+
+    <request name="set_title">
+      <description summary="set surface title">
+	Set a short title for the surface.
+
+	This string may be used to identify the surface in a task bar,
+	window list, or other user interface elements provided by the
+	compositor.
+
+	The string must be encoded in UTF-8.
+      </description>
+      <arg name="title" type="string"/>
+    </request>
+
+    <request name="set_app_id">
+      <description summary="set application ID">
+	Set an application identifier for the surface.
+
+	The app ID identifies the general class of applications to which
+	the surface belongs. The compositor can use this to group multiple
+	surfaces together, or to determine how to launch a new application.
+
+	For D-Bus activatable applications, the app ID is used as the D-Bus
+	service name.
+
+	The compositor shell will try to group application surfaces together
+	by their app ID. As a best practice, it is suggested to select app
+	ID's that match the basename of the application's .desktop file.
+	For example, "org.freedesktop.FooViewer" where the .desktop file is
+	"org.freedesktop.FooViewer.desktop".
+
+	See the desktop-entry specification [0] for more details on
+	application identifiers and how they relate to well-known D-Bus
+	names and .desktop files.
+
+	[0] http://standards.freedesktop.org/desktop-entry-spec/
+      </description>
+      <arg name="app_id" type="string"/>
+    </request>
+
+    <request name="show_window_menu">
+      <description summary="show the window menu">
+	Clients implementing client-side decorations might want to show
+	a context menu when right-clicking on the decorations, giving the
+	user a menu that they can use to maximize or minimize the window.
+
+	This request asks the compositor to pop up such a window menu at
+	the given position, relative to the local surface coordinates of
+	the parent surface. There are no guarantees as to what menu items
+	the window menu contains.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="x" type="int" summary="the x position to pop up the window menu at"/>
+      <arg name="y" type="int" summary="the y position to pop up the window menu at"/>
+    </request>
+
+    <request name="move">
+      <description summary="start an interactive move">
+	Start an interactive, user-driven move of the surface.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event. The passed
+	serial is used to determine the type of interactive move (touch,
+	pointer, etc).
+
+	The server may ignore move requests depending on the state of
+	the surface (e.g. fullscreen or maximized), or if the passed serial
+	is no longer valid.
+
+	If triggered, the surface will lose the focus of the device
+	(wl_pointer, wl_touch, etc) used for the move. It is up to the
+	compositor to visually indicate that the move is taking place, such as
+	updating a pointer cursor, during the move. There is no guarantee
+	that the device focus will return when the move is completed.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+    </request>
+
+    <enum name="resize_edge">
+      <description summary="edge values for resizing">
+	These values are used to indicate which edge of a surface
+	is being dragged in a resize operation.
+      </description>
+      <entry name="none" value="0"/>
+      <entry name="top" value="1"/>
+      <entry name="bottom" value="2"/>
+      <entry name="left" value="4"/>
+      <entry name="top_left" value="5"/>
+      <entry name="bottom_left" value="6"/>
+      <entry name="right" value="8"/>
+      <entry name="top_right" value="9"/>
+      <entry name="bottom_right" value="10"/>
+    </enum>
+
+    <request name="resize">
+      <description summary="start an interactive resize">
+	Start a user-driven, interactive resize of the surface.
+
+	This request must be used in response to some sort of user action
+	like a button press, key press, or touch down event. The passed
+	serial is used to determine the type of interactive resize (touch,
+	pointer, etc).
+
+	The server may ignore resize requests depending on the state of
+	the surface (e.g. fullscreen or maximized).
+
+	If triggered, the client will receive configure events with the
+	"resize" state enum value and the expected sizes. See the "resize"
+	enum value for more details about what is required. The client
+	must also acknowledge configure events using "ack_configure". After
+	the resize is completed, the client will receive another "configure"
+	event without the resize state.
+
+	If triggered, the surface also will lose the focus of the device
+	(wl_pointer, wl_touch, etc) used for the resize. It is up to the
+	compositor to visually indicate that the resize is taking place,
+	such as updating a pointer cursor, during the resize. There is no
+	guarantee that the device focus will return when the resize is
+	completed.
+
+	The edges parameter specifies how the surface should be resized,
+	and is one of the values of the resize_edge enum. The compositor
+	may use this information to update the surface position for
+	example when dragging the top left corner. The compositor may also
+	use this information to adapt its behavior, e.g. choose an
+	appropriate cursor image.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+      <arg name="edges" type="uint" summary="which edge or corner is being dragged"/>
+    </request>
+
+    <enum name="state">
+      <description summary="types of state on the surface">
+	The different state values used on the surface. This is designed for
+	state values like maximized, fullscreen. It is paired with the
+	configure event to ensure that both the client and the compositor
+	setting the state can be synchronized.
+
+	States set in this way are double-buffered, see wl_surface.commit.
+      </description>
+      <entry name="maximized" value="1" summary="the surface is maximized">
+	<description summary="the surface is maximized">
+	  The surface is maximized. The window geometry specified in the configure
+	  event must be obeyed by the client. If the window geometry is not obyed,
+          the zxdg_shell_v6.invalid_surface_state error is raised.
+	</description>
+      </entry>
+      <entry name="fullscreen" value="2" summary="the surface is fullscreen">
+	<description summary="the surface is fullscreen">
+	  The surface is fullscreen. See set_fullscreen for more information.
+	</description>
+      </entry>
+      <entry name="resizing" value="3" summary="the surface is being resized">
+	<description summary="the surface is being resized">
+	  The surface is being resized. The window geometry specified in the
+	  configure event is a maximum; the client cannot resize beyond it. If the
+          client attempts to resize above it, the zxdg_shell_v6.invalid_surface_state
+          error is raised.
+	  Clients that have aspect ratio or cell sizing configuration can use
+	  a smaller size, however.
+	</description>
+      </entry>
+      <entry name="activated" value="4" summary="the surface is now activated">
+	<description summary="the surface is now activated">
+	  Client window decorations should be painted as if the window is
+	  active. Do not assume this means that the window actually has
+	  keyboard or pointer focus.
+	</description>
+      </entry>
+    </enum>
+
+    <request name="set_max_size">
+      <description summary="set the maximum size">
+	Set a maximum size for the window.
+
+	The client can specify a maximum size so that the compositor does
+	not try to configure the window beyond this size.
+
+	The width and height arguments are in window geometry coordinates.
+	See xdg_surface.set_window_geometry.
+
+	Values set in this way are double-buffered, see wl_surface.commit.
+
+	The compositor can use this information to allow or disallow
+	different states like maximize or fullscreen and draw accurate
+	animations.
+
+	Similarly, a tiling window manager may use this information to
+	place and resize client windows in a more effective way.
+
+	The client should not rely on the compositor to obey the maximum
+	size. The compositor may decide to ignore the values set by the
+	client and request a larger size.
+
+	If never set, or a value of zero in the request, means that the
+	client has no expected maximum size in the given dimension.
+	As a result, a client wishing to reset the maximum size
+	to an unspecified state can use zero for width and height in the
+	request.
+
+	Requesting a maximum size to be smaller than the minimum size of
+	a surface is illegal and will result in a protocol error.
+
+	The width and height must be greater than or equal to zero. Using
+	strictly negative values for width and height will result in the
+        zxdg_shell_v6.invalid_surface_state error being raised.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="set_min_size">
+      <description summary="set the minimum size">
+	Set a minimum size for the window.
+
+	The client can specify a minimum size so that the compositor does
+	not try to configure the window below this size.
+
+	The width and height arguments are in window geometry coordinates.
+	See xdg_surface.set_window_geometry.
+
+	Values set in this way are double-buffered, see wl_surface.commit.
+
+	The compositor can use this information to allow or disallow
+	different states like maximize or fullscreen and draw accurate
+	animations.
+
+	Similarly, a tiling window manager may use this information to
+	place and resize client windows in a more effective way.
+
+	The client should not rely on the compositor to obey the minimum
+	size. The compositor may decide to ignore the values set by the
+	client and request a smaller size.
+
+	If never set, or a value of zero in the request, means that the
+	client has no expected minimum size in the given dimension.
+	As a result, a client wishing to reset the minimum size
+	to an unspecified state can use zero for width and height in the
+	request.
+
+	Requesting a minimum size to be larger than the maximum size of
+	a surface is illegal and will result in a protocol error.
+
+	The width and height must be greater than or equal to zero. Using
+	strictly negative values for width and height will result in the
+        zxdg_shell_v6.invalid_surface_state error being raised.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+    </request>
+
+    <request name="set_maximized">
+      <description summary="maximize the window">
+	Maximize the surface.
+
+	After requesting that the surface should be maximized, the compositor
+	will respond by emitting a configure event with the "maximized" state
+	and the required window geometry. The client should then update its
+	content, drawing it in a maximized state, i.e. without shadow or other
+	decoration outside of the window geometry. The client must also
+	acknowledge the configure when committing the new content (see
+	ack_configure).
+
+	It is up to the compositor to decide how and where to maximize the
+	surface, for example which output and what region of the screen should
+	be used.
+
+	If the surface was already maximized, the compositor will still emit
+	a configure event with the "maximized" state.
+
+        Note that unrelated compositor side state changes may cause
+        configure events to be emitted at any time, meaning trying to
+        match this request to a specific future configure event is
+        futile.
+      </description>
+    </request>
+
+    <request name="unset_maximized">
+      <description summary="unmaximize the window">
+	Unmaximize the surface.
+
+	After requesting that the surface should be unmaximized, the compositor
+	will respond by emitting a configure event without the "maximized"
+	state. If available, the compositor will include the window geometry
+	dimensions the window had prior to being maximized in the configure
+	request. The client must then update its content, drawing it in a
+	regular state, i.e. potentially with shadow, etc. The client must also
+	acknowledge the configure when committing the new content (see
+	ack_configure).
+
+	It is up to the compositor to position the surface after it was
+	unmaximized; usually the position the surface had before maximizing, if
+	applicable.
+
+	If the surface was already not maximized, the compositor will still
+	emit a configure event without the "maximized" state.
+
+        Note that unrelated changes in the state of compositor may cause
+        configure events to be emitted by the compositor between processing
+        this request and emitting corresponding configure event, so trying
+        to match the request with the event is futile.
+      </description>
+    </request>
+
+    <request name="set_fullscreen">
+      <description summary="set the window as fullscreen on a monitor">
+	Make the surface fullscreen.
+
+	You can specify an output that you would prefer to be fullscreen.
+	If this value is NULL, it's up to the compositor to choose which
+	display will be used to map this surface.
+
+	If the surface doesn't cover the whole output, the compositor will
+	position the surface in the center of the output and compensate with
+	black borders filling the rest of the output.
+      </description>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"/>
+    </request>
+    <request name="unset_fullscreen" />
+
+    <request name="set_minimized">
+      <description summary="set the window as minimized">
+	Request that the compositor minimize your surface. There is no
+	way to know if the surface is currently minimized, nor is there
+	any way to unset minimization on this surface.
+
+	If you are looking to throttle redrawing when minimized, please
+	instead use the wl_surface.frame event for this, as this will
+	also work with live previews on windows in Alt-Tab, Expose or
+	similar compositor features.
+      </description>
+    </request>
+
+    <event name="configure">
+      <description summary="suggest a surface change">
+	This configure event asks the client to resize its toplevel surface or
+	to change its state. The configured state should not be applied
+	immediately. See xdg_surface.configure for details.
+
+	The width and height arguments specify a hint to the window
+	about how its surface should be resized in window geometry
+	coordinates. See set_window_geometry.
+
+	If the width or height arguments are zero, it means the client
+	should decide its own window dimension. This may happen when the
+	compositor needs to configure the state of the surface but doesn't
+	have any information about any previous or expected dimension.
+
+	The states listed in the event specify how the width/height
+	arguments should be interpreted, and possibly how it should be
+	drawn.
+
+	Clients must send an ack_configure in response to this event. See
+	xdg_surface.configure and xdg_surface.ack_configure for details.
+      </description>
+      <arg name="width" type="int"/>
+      <arg name="height" type="int"/>
+      <arg name="states" type="array"/>
+    </event>
+
+    <event name="close">
+      <description summary="surface wants to be closed">
+	The close event is sent by the compositor when the user
+	wants the surface to be closed. This should be equivalent to
+	the user clicking the close button in client-side decorations,
+	if your application has any.
+
+	This is only a request that the user intends to close the
+	window. The client may choose to ignore this request, or show
+	a dialog to ask the user to save their data, etc.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="zxdg_popup_v6" version="1">
+    <description summary="short-lived, popup surfaces for menus">
+      A popup surface is a short-lived, temporary surface. It can be used to
+      implement for example menus, popovers, tooltips and other similar user
+      interface concepts.
+
+      A popup can be made to take an explicit grab. See xdg_popup.grab for
+      details.
+
+      When the popup is dismissed, a popup_done event will be sent out, and at
+      the same time the surface will be unmapped. See the xdg_popup.popup_done
+      event for details.
+
+      Explicitly destroying the xdg_popup object will also dismiss the popup and
+      unmap the surface. Clients that want to dismiss the popup when another
+      surface of their own is clicked should dismiss the popup using the destroy
+      request.
+
+      The parent surface must have either the xdg_toplevel or xdg_popup surface
+      role.
+
+      A newly created xdg_popup will be stacked on top of all previously created
+      xdg_popup surfaces associated with the same xdg_toplevel.
+
+      The parent of an xdg_popup must be mapped (see the xdg_surface
+      description) before the xdg_popup itself.
+
+      The x and y arguments passed when creating the popup object specify
+      where the top left of the popup should be placed, relative to the
+      local surface coordinates of the parent surface. See
+      xdg_surface.get_popup. An xdg_popup must intersect with or be at least
+      partially adjacent to its parent surface.
+
+      The client must call wl_surface.commit on the corresponding wl_surface
+      for the xdg_popup state to take effect.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_grab" value="0"
+	     summary="tried to grab after being mapped"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove xdg_popup interface">
+	This destroys the popup. Explicitly destroying the xdg_popup
+	object will also dismiss the popup, and unmap the surface.
+
+	If this xdg_popup is not the "topmost" popup, a protocol error
+	will be sent.
+      </description>
+    </request>
+
+    <request name="grab">
+      <description summary="make the popup take an explicit grab">
+	This request makes the created popup take an explicit grab. An explicit
+	grab will be dismissed when the user dismisses the popup, or when the
+	client destroys the xdg_popup. This can be done by the user clicking
+	outside the surface, using the keyboard, or even locking the screen
+	through closing the lid or a timeout.
+
+	If the compositor denies the grab, the popup will be immediately
+	dismissed.
+
+	This request must be used in response to some sort of user action like a
+	button press, key press, or touch down event. The serial number of the
+	event should be passed as 'serial'.
+
+	The parent of a grabbing popup must either be an xdg_toplevel surface or
+	another xdg_popup with an explicit grab. If the parent is another
+	xdg_popup it means that the popups are nested, with this popup now being
+	the topmost popup.
+
+	Nested popups must be destroyed in the reverse order they were created
+	in, e.g. the only popup you are allowed to destroy at all times is the
+	topmost one.
+
+	When compositors choose to dismiss a popup, they may dismiss every
+	nested grabbing popup as well. When a compositor dismisses popups, it
+	will follow the same dismissing order as required from the client.
+
+	The parent of a grabbing popup must either be another xdg_popup with an
+	active explicit grab, or an xdg_popup or xdg_toplevel, if there are no
+	explicit grabs already taken.
+
+	If the topmost grabbing popup is destroyed, the grab will be returned to
+	the parent of the popup, if that parent previously had an explicit grab.
+
+	If the parent is a grabbing popup which has already been dismissed, this
+	popup will be immediately dismissed. If the parent is a popup that did
+	not take an explicit grab, an error will be raised.
+
+	During a popup grab, the client owning the grab will receive pointer
+	and touch events for all their surfaces as normal (similar to an
+	"owner-events" grab in X11 parlance), while the top most grabbing popup
+	will always have keyboard focus.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat"
+	   summary="the wl_seat of the user event"/>
+      <arg name="serial" type="uint" summary="the serial of the user event"/>
+    </request>
+
+    <event name="configure">
+      <description summary="configure the popup surface">
+	This event asks the popup surface to configure itself given the
+	configuration. The configured state should not be applied immediately.
+	See xdg_surface.configure for details.
+
+	The x and y arguments represent the position the popup was placed at
+	given the xdg_positioner rule, relative to the upper left corner of the
+	window geometry of the parent surface.
+      </description>
+      <arg name="x" type="int"
+	   summary="x position relative to parent surface window geometry"/>
+      <arg name="y" type="int"
+	   summary="y position relative to parent surface window geometry"/>
+      <arg name="width" type="int" summary="window geometry width"/>
+      <arg name="height" type="int" summary="window geometry height"/>
+    </event>
+
+    <event name="popup_done">
+      <description summary="popup interaction is done">
+	The popup_done event is sent out when a popup is dismissed by the
+	compositor. The client should destroy the xdg_popup object at this
+	point.
+      </description>
+    </event>
+
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/unstable/xwayland-keyboard-grab/README b/subprojects/wayland-protocols/unstable/xwayland-keyboard-grab/README
new file mode 100644
index 0000000000000000000000000000000000000000..3f5f2f7f7c60fe8eb2bf7d2d9b4675b93967359e
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xwayland-keyboard-grab/README
@@ -0,0 +1,4 @@
+Xwayland keyboard grabbing protocol
+
+Maintainers:
+Olivier Fourdan <ofourdan@redhat.com> (@ofourdan)
diff --git a/subprojects/wayland-protocols/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml b/subprojects/wayland-protocols/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml
new file mode 100644
index 0000000000000000000000000000000000000000..be4992fd72db99a0902606161d108eb39ceef56f
--- /dev/null
+++ b/subprojects/wayland-protocols/unstable/xwayland-keyboard-grab/xwayland-keyboard-grab-unstable-v1.xml
@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="xwayland_keyboard_grab_unstable_v1">
+
+  <copyright>
+    Copyright © 2017 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.
+  </copyright>
+
+  <description summary="Protocol for grabbing the keyboard from Xwayland">
+    This protocol is application-specific to meet the needs of the X11
+    protocol through Xwayland. It provides a way for Xwayland to request
+    all keyboard events to be forwarded to a surface even when the
+    surface does not have keyboard focus.
+
+    In the X11 protocol, a client may request an "active grab" on the
+    keyboard. On success, all key events are reported only to the
+    grabbing X11 client. For details, see XGrabKeyboard(3).
+
+    The core Wayland protocol does not have a notion of an active
+    keyboard grab. When running in Xwayland, X11 applications may
+    acquire an active grab inside Xwayland but that cannot be translated
+    to the Wayland compositor who may set the input focus to some other
+    surface. In doing so, it breaks the X11 client assumption that all
+    key events are reported to the grabbing client.
+
+    This protocol specifies a way for Xwayland to request all keyboard
+    be directed to the given surface. The protocol does not guarantee
+    that the compositor will honor this request and it does not
+    prescribe user interfaces on how to handle the respond. For example,
+    a compositor may inform the user that all key events are now
+    forwarded to the given client surface, or it may ask the user for
+    permission to do so.
+
+    Compositors are required to restrict access to this application
+    specific protocol to Xwayland alone.
+
+    Warning! The protocol described in this file is experimental and
+    backward incompatible changes may be made. Backward compatible
+    changes may be added together with the corresponding interface
+    version bump.
+    Backward incompatible changes are done by bumping the version
+    number in the protocol and interface names and resetting the
+    interface version. Once the protocol is to be declared stable,
+    the 'z' prefix and the version number in the protocol and
+    interface names are removed and the interface version number is
+    reset.
+  </description>
+
+  <interface name="zwp_xwayland_keyboard_grab_manager_v1" version="1">
+    <description summary="context object for keyboard grab manager">
+      A global interface used for grabbing the keyboard.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the keyboard grab manager">
+	Destroy the keyboard grab manager.
+      </description>
+    </request>
+
+    <request name="grab_keyboard">
+      <description summary="grab the keyboard to a surface">
+	The grab_keyboard request asks for a grab of the keyboard, forcing
+	the keyboard focus for the given seat upon the given surface.
+
+	The protocol provides no guarantee that the grab is ever satisfied,
+	and does not require the compositor to send an error if the grab
+	cannot ever be satisfied. It is thus possible to request a keyboard
+	grab that will never be effective.
+
+	The protocol:
+
+	* does not guarantee that the grab itself is applied for a surface,
+	  the grab request may be silently ignored by the compositor,
+	* does not guarantee that any events are sent to this client even
+	  if the grab is applied to a surface,
+	* does not guarantee that events sent to this client are exhaustive,
+	  a compositor may filter some events for its own consumption,
+	* does not guarantee that events sent to this client are continuous,
+	  a compositor may change and reroute keyboard events while the grab
+	  is nominally active.
+      </description>
+
+      <arg name="id" type="new_id" interface="zwp_xwayland_keyboard_grab_v1"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="surface to report keyboard events to"/>
+      <arg name="seat" type="object" interface="wl_seat"
+	   summary="the seat for which the keyboard should be grabbed"/>
+    </request>
+  </interface>
+
+  <interface name="zwp_xwayland_keyboard_grab_v1" version="1">
+    <description summary="interface for grabbing the keyboard">
+      A global interface used for grabbing the keyboard.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the grabbed keyboard object">
+	Destroy the grabbed keyboard object. If applicable, the compositor
+	will ungrab the keyboard.
+      </description>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland-protocols/wayland-protocols-uninstalled.pc.in b/subprojects/wayland-protocols/wayland-protocols-uninstalled.pc.in
new file mode 100644
index 0000000000000000000000000000000000000000..cf7adf257a79c894d19f7241c354840d818b70b9
--- /dev/null
+++ b/subprojects/wayland-protocols/wayland-protocols-uninstalled.pc.in
@@ -0,0 +1,5 @@
+pkgdatadir=@abs_top_srcdir@
+
+Name: Wayland Protocols
+Description: Wayland protocol files (not installed)
+Version: @WAYLAND_PROTOCOLS_VERSION@
diff --git a/subprojects/wayland-protocols/wayland-protocols.pc.in b/subprojects/wayland-protocols/wayland-protocols.pc.in
new file mode 100644
index 0000000000000000000000000000000000000000..4571fa8180b163a4f887f70af697876dcfa01726
--- /dev/null
+++ b/subprojects/wayland-protocols/wayland-protocols.pc.in
@@ -0,0 +1,7 @@
+prefix=@prefix@
+datarootdir=@datarootdir@
+pkgdatadir=${pc_sysrootdir}${datarootdir}/@PACKAGE@
+
+Name: Wayland Protocols
+Description: Wayland protocol files
+Version: @WAYLAND_PROTOCOLS_VERSION@
diff --git a/subprojects/wayland.wrap b/subprojects/wayland.wrap
index 2311fdaeb5c00b7343b74b4cd9ef82adfff82ffb..f2133c9f7422ee5f16dcb45a2426ebb16c9cd5b1 100644
--- a/subprojects/wayland.wrap
+++ b/subprojects/wayland.wrap
@@ -2,7 +2,7 @@
 directory = wayland
 url = https://gitlab.freedesktop.org/wayland/wayland.git
 push-url = git@gitlab.freedesktop.org:wayland/wayland
-revision = 1.21.0
+revision = 1.23.0
 depth = 1
 
 [provide]
diff --git a/subprojects/wayland/.editorconfig b/subprojects/wayland/.editorconfig
new file mode 100644
index 0000000000000000000000000000000000000000..d92e5e965f3c7a5946fc70fcd2b883dc827d49cc
--- /dev/null
+++ b/subprojects/wayland/.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/subprojects/wayland/.gitignore b/subprojects/wayland/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..4fefe5d33e88f4fdffb68cd36edd740a12be2b03
--- /dev/null
+++ b/subprojects/wayland/.gitignore
@@ -0,0 +1,8 @@
+*.announce
+*.sig
+*.swp
+*.log
+*.tar.xz
+*~
+cscope.out
+ctags
diff --git a/subprojects/wayland/.gitlab-ci.yml b/subprojects/wayland/.gitlab-ci.yml
new file mode 100644
index 0000000000000000000000000000000000000000..7dc7e33f2f406837060f700526f49996c67ea7a5
--- /dev/null
+++ b/subprojects/wayland/.gitlab-ci.yml
@@ -0,0 +1,350 @@
+# This file uses the freedesktop ci-templates to build Wayland and run our
+# tests in CI.
+#
+# ci-templates uses a multi-stage build process. First, the base container
+# image is built which contains the core distribution, the toolchain, and
+# all our build dependencies. This container is aggressively cached; if a
+# container image matching $FDO_DISTRIBUTION_TAG is found in either the
+# upstream repo (wayland/weston) or the user's downstream repo, it is
+# reused for the build. This gives us predictability of build and far
+# quicker runtimes, however it means that any changes to the base container
+# must also change $FDO_DISTRIBUTION_TAG. When changing this, please use
+# the current date as well as a unique build identifier.
+#
+# After the container is either rebuilt (tag mismatch) or reused (tag
+# previously used), the build stage executes within this container.
+#
+# The final stage is used to expose documentation and coverage information,
+# including publishing documentation to the public site when built on the
+# main branch.
+#
+# Apart from the 'variables', 'include', and 'stages' top-level anchors,
+# everything not beginning with a dot ('.') is the name of a job which will
+# be executed as part of CI, unless the rules specify that it should not be
+# run.
+#
+# Variables prefixed with CI_ are generally provided by GitLab itself;
+# variables prefixed with FDO_ and templates prefixed by .fdo are provided
+# by the ci-templates.
+#
+# For more information on GitLab CI, including the YAML syntax, see:
+#   https://docs.gitlab.com/ee/ci/yaml/README.html
+#
+# Note that freedesktop.org uses the 'Community Edition' of GitLab, so features
+# marked as 'premium' or 'ultimate' are not available to us.
+#
+# For more information on ci-templates, see:
+#   - documentation at https://freedesktop.pages.freedesktop.org/ci-templates/
+#   - repo at https://gitlab.freedesktop.org/freedesktop/ci-templates/
+
+include:
+  - project: 'freedesktop/ci-templates'
+    # Here we use a fixed ref in order to isolate ourselves from ci-templates
+    # API changes. If you need new features from ci-templates you must bump
+    # this to the current SHA you require from the ci-templates repo, however
+    # be aware that you may need to account for API changes when doing so.
+    ref: b791bd48996e3ced9ca13f1c5ee82be8540b8adb
+    file:
+      - '/templates/debian.yml'
+      - '/templates/freebsd.yml'
+      - '/templates/ci-fairy.yml'
+
+variables:
+  FDO_UPSTREAM_REPO: wayland/wayland
+  FDO_REPO_SUFFIX: "$BUILD_OS/$BUILD_ARCH"
+
+
+# Define the build stages. These are used for UI grouping as well as
+# dependencies.
+stages:
+  - "Merge request checks"
+  - "Base container"
+  - "Build and test"
+  - "Other build configurations"
+
+.ci-rules:
+  rules:
+    - when: on_success
+
+# Base variables used for anything using a Debian environment
+.os-debian:
+  variables:
+    BUILD_OS: debian
+    FDO_DISTRIBUTION_VERSION: bookworm
+    FDO_DISTRIBUTION_PACKAGES: 'build-essential pkg-config libexpat1-dev libffi-dev libxml2-dev doxygen graphviz xmlto xsltproc docbook-xsl python3-pip python3-setuptools ninja-build'
+    FDO_DISTRIBUTION_EXEC: 'pip3 install --break-system-packages meson~=0.57.2'
+    # bump this tag every time you change something which requires rebuilding the
+    # base image
+    FDO_DISTRIBUTION_TAG: "2024-03-28.2"
+
+.debian-x86_64:
+  extends:
+    - .os-debian
+  variables:
+    BUILD_ARCH: "x86-64"
+
+.debian-aarch64:
+  extends:
+    - .os-debian
+  variables:
+    BUILD_ARCH: "aarch64"
+
+.debian-armv7:
+  extends:
+    - .os-debian
+  variables:
+    BUILD_ARCH: "armv7"
+
+
+# Does not inherit .ci-rules as we only want it to run in MR context.
+check-commit:
+  extends:
+    - .fdo.ci-fairy
+  stage: "Merge request checks"
+  rules:
+    - if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
+      when: always
+    - when: never
+  script:
+    - ci-fairy check-commits --signed-off-by --junit-xml=results.xml
+  variables:
+    GIT_DEPTH: 100
+  artifacts:
+    reports:
+      junit: results.xml
+
+
+# Build our base container image, which contains the core distribution, the
+# toolchain, and all our build dependencies. This will be reused in the build
+# stage.
+x86_64-debian-container_prep:
+  extends:
+    - .ci-rules
+    - .debian-x86_64
+    - .fdo.container-build@debian
+  stage: "Base container"
+  variables:
+    GIT_STRATEGY: none
+
+aarch64-debian-container_prep:
+  extends:
+    - .ci-rules
+    - .debian-aarch64
+    - .fdo.container-build@debian
+  tags:
+    - aarch64
+  stage: "Base container"
+  variables:
+    GIT_STRATEGY: none
+
+armv7-debian-container_prep:
+  extends:
+    - .ci-rules
+    - .debian-armv7
+    - .fdo.container-build@debian
+  tags:
+    - aarch64
+  stage: "Base container"
+  variables:
+    GIT_STRATEGY: none
+    FDO_BASE_IMAGE: "arm32v7/debian:$FDO_DISTRIBUTION_VERSION"
+
+
+# Core build environment.
+.build-env:
+  variables:
+    MESON_BUILD_TYPE: "-Dbuildtype=debug -Doptimization=0 -Db_sanitize=address,undefined"
+    # See https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/154
+    ASAN_OPTIONS: "detect_odr_violation=0"
+  before_script:
+    - export BUILD_ID="wayland-$CI_JOB_NAME"
+    - export PREFIX="${CI_PROJECT_DIR}/prefix-${BUILD_ID}"
+    - export BUILDDIR="${CI_PROJECT_DIR}/build-${BUILD_ID}"
+    - mkdir "$BUILDDIR" "$PREFIX"
+
+
+# Build variants to be stacked on as required.
+.build-release:
+  stage: "Other build configurations"
+  variables:
+    MESON_BUILD_TYPE: "-Dbuildtype=release"
+
+
+# OS/architecture-specific variants
+.build-env-debian-x86_64:
+  extends:
+    - .fdo.suffixed-image@debian
+    - .debian-x86_64
+    - .build-env
+  needs:
+    - job: x86_64-debian-container_prep
+      artifacts: false
+
+.build-env-debian-aarch64:
+  extends:
+    - .fdo.suffixed-image@debian
+    - .debian-aarch64
+    - .build-env
+  variables:
+    # At least with the versions we have, the LSan runtime makes fork unusably
+    # slow on AArch64, which is bad news since the test suite decides to fork
+    # for every single subtest. For now, in order to get AArch64 builds and
+    # tests into CI, just assume that we're not going to leak any more on
+    # AArch64 than we would on ARMv7 or x86-64.
+    ASAN_OPTIONS: "detect_leaks=0,detect_odr_violation=0"
+  tags:
+    - aarch64
+  needs:
+    - job: aarch64-debian-container_prep
+      artifacts: false
+
+.build-env-debian-armv7:
+  extends:
+    - .fdo.suffixed-image@debian
+    - .debian-armv7
+    - .build-env
+  tags:
+    - aarch64
+  needs:
+    - job: armv7-debian-container_prep
+      artifacts: false
+
+
+# Full build and test.
+.do-build:
+  extends:
+    - .ci-rules
+  stage: "Build and test"
+  script:
+    - cd "$BUILDDIR"
+    - meson --prefix="$PREFIX" -Dicon_directory=/usr/share/X11/icons --fatal-meson-warnings -Dwerror=true ${MESON_BUILD_TYPE} ..
+    - ninja -k0 -j${FDO_CI_CONCURRENT:-4}
+    - meson test --num-processes ${FDO_CI_CONCURRENT:-4}
+    - ninja clean
+  artifacts:
+    name: wayland-$CI_JOB_NAME
+    when: always
+    paths:
+      - build-*/meson-logs
+      - prefix-*
+    reports:
+      junit: build-*/meson-logs/testlog.junit.xml
+
+# Full build and test.
+.do-build-qemu:
+  extends:
+    - .ci-rules
+  stage: "Build and test"
+  script:
+    # Start the VM and copy our workspace to the VM
+    - /app/vmctl start
+    - scp -r $PWD "vm:"
+    # The `set +e is needed to ensure that we always copy the meson logs back to
+    # the workspace to see details about the failed tests.
+    - |
+      set +e
+      /app/vmctl exec "pkg info; cd $CI_PROJECT_NAME ; meson $BUILDDIR --prefix=$PREFIX $MESON_BUILD_TYPE $MESON_ARGS && ninja -C $BUILDDIR -j${FDO_CI_CONCURRENT:-4}"
+      /app/vmctl exec "meson test --print-errorlogs -C $BUILDDIR --num-processes ${FDO_CI_CONCURRENT:-4}" && touch .tests-successful
+      set -ex
+      scp -r vm:$BUILDDIR/meson-logs .
+      /app/vmctl exec "ninja -C $BUILDDIR install"
+      mkdir -p $PREFIX && scp -r vm:$PREFIX/ $PREFIX/
+    # Finally, shut down the VM.
+    - /app/vmctl stop
+    - test -f .tests-successful || exit 1
+  artifacts:
+    name: wayland-$CI_JOB_NAME
+    when: always
+    paths:
+      - meson-logs
+      - prefix-*
+    reports:
+      junit: meson-logs/testlog.junit.xml
+
+# Full build and test.
+x86_64-debian-build:
+  extends:
+    - .build-env-debian-x86_64
+    - .do-build
+
+x86_64-release-debian-build:
+  extends:
+    - .build-env-debian-x86_64
+    - .do-build
+    - .build-release
+
+aarch64-debian-build:
+  extends:
+    - .build-env-debian-aarch64
+    - .do-build
+
+aarch64-release-debian-build:
+  extends:
+    - .build-env-debian-aarch64
+    - .do-build
+    - .build-release
+
+armv7-debian-build:
+  extends:
+    - .build-env-debian-armv7
+    - .do-build
+
+armv7-release-debian-build:
+  extends:
+    - .build-env-debian-armv7
+    - .do-build
+    - .build-release
+
+# Base variables used for anything using a FreeBSD environment
+.os-freebsd:
+  variables:
+    BUILD_OS: freebsd
+    FDO_DISTRIBUTION_VERSION: "13.2"
+    FDO_DISTRIBUTION_PACKAGES: 'libxslt meson ninja pkgconf expat libffi libepoll-shim libxml2'
+    # bump this tag every time you change something which requires rebuilding the
+    # base image
+    FDO_DISTRIBUTION_TAG: "2023-08-02.0"
+    # Don't build documentation since installing the required tools massively
+    # increases the VM image (and therefore container) size.
+    MESON_ARGS: "--fatal-meson-warnings -Dwerror=true -Ddocumentation=false"
+
+.freebsd-x86_64:
+  extends:
+    - .os-freebsd
+  variables:
+    BUILD_ARCH: "x86_64"
+
+x86_64-freebsd-container_prep:
+  extends:
+    - .ci-rules
+    - .freebsd-x86_64
+    - .fdo.qemu-build@freebsd@x86_64
+  stage: "Base container"
+  variables:
+    GIT_STRATEGY: none
+
+.build-env-freebsd-x86_64:
+  variables:
+    # Compiling with ASan+UBSan appears to trigger an infinite loop in the
+    # compiler shipped with FreeBSD 13.0, so we only use UBSan here.
+    # Additionally, sanitizers can't be used with b_lundef on FreeBSD.
+    MESON_BUILD_TYPE: "-Dbuildtype=debug -Db_sanitize=undefined -Db_lundef=false"
+  extends:
+    - .fdo.suffixed-image@freebsd
+    - .freebsd-x86_64
+    - .build-env
+  needs:
+    - job: x86_64-freebsd-container_prep
+      artifacts: false
+
+# Full build and test.
+x86_64-freebsd-build:
+  extends:
+    - .build-env-freebsd-x86_64
+    - .do-build-qemu
+
+x86_64-release-freebsd-build:
+  extends:
+    - .build-env-freebsd-x86_64
+    - .do-build-qemu
+    - .build-release
diff --git a/subprojects/wayland/.gitlab/issue_templates/default.md b/subprojects/wayland/.gitlab/issue_templates/default.md
new file mode 100644
index 0000000000000000000000000000000000000000..f8149ceedf897398e6d8de37e9f3cebe1ec9e6fb
--- /dev/null
+++ b/subprojects/wayland/.gitlab/issue_templates/default.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 issue.
+-->
diff --git a/subprojects/wayland/.mailmap b/subprojects/wayland/.mailmap
new file mode 100644
index 0000000000000000000000000000000000000000..bdb791e72a11b2715f0b02257e505e9e57ba3115
--- /dev/null
+++ b/subprojects/wayland/.mailmap
@@ -0,0 +1,3 @@
+Faith Ekstrand <faith@gfxstrand.net> <jason@jlekstrand.net>
+Faith Ekstrand <faith@gfxstrand.net> <jason.ekstrand@intel.com>
+Faith Ekstrand <faith@gfxstrand.net> <jason.ekstrand@collabora.com>
diff --git a/subprojects/wayland/.triage-policies.yml b/subprojects/wayland/.triage-policies.yml
new file mode 100644
index 0000000000000000000000000000000000000000..580bead433d49cb2e230bb7dee961c43c80d24fa
--- /dev/null
+++ b/subprojects/wayland/.triage-policies.yml
@@ -0,0 +1,33 @@
+# This is a set of bugbot commands for issues and merge requests - setting any of the
+# bugbot::foo labels will trigger gitlab-triage to run with this ruleset (well, the
+# one we have on the main branch at the time)
+#
+# Note that for adding labels, the label must first created in the project.
+resource_rules:
+  issues:
+    rules:
+      - name: "Close bugs that aren't Wayland bugs"
+        conditions:
+          labels:
+            - "bugbot::not-wayland"
+        actions:
+          remove_labels:
+            - "bugbot::not-wayland"
+          comment: |
+            Thank you for the report, but your issue does not look like it would belong here. Sorry.
+
+            This repository is for the Wayland protocol specification and the
+            low-level C library that deals with the protocol.
+
+            This issue here is a bug not with the protocol itself but with either
+            - your compositor or desktop environment's implementation of the Wayland protocol and surrounding functionality,
+            - the individual application that triggers this issue, or
+            - the kernel driver used by your hardware
+
+            Please file the issue against your compositor/desktop environment, the application
+            or the kernel drivers instead, whichever seems more likely to you. If you are not sure,
+            file an issue against the application.
+          status: "close"
+  merge_requests:
+    rules:
+      []
diff --git a/subprojects/wayland/CONTRIBUTING.md b/subprojects/wayland/CONTRIBUTING.md
new file mode 100644
index 0000000000000000000000000000000000000000..1ea351f053c14e046133225d6f6d41f294235973
--- /dev/null
+++ b/subprojects/wayland/CONTRIBUTING.md
@@ -0,0 +1,344 @@
+Contributing to Wayland
+=======================
+
+Sending patches
+---------------
+
+Patches should be sent via
+[GitLab merge requests](https://docs.gitlab.com/ce/gitlab-basics/add-merge-request.html).
+Wayland is
+[hosted on freedesktop.org's GitLab](https://gitlab.freedesktop.org/wayland/wayland/):
+in order to submit code, you should create an account on this GitLab instance,
+fork the core Wayland repository, push your changes to a branch in your new
+repository, and then submit these patches for review through a merge request.
+
+Wayland formerly accepted patches via `git-send-email`, sent to
+**wayland-devel@lists.freedesktop.org**; these were
+[tracked using Patchwork](https://patchwork.freedesktop.org/project/wayland/).
+Some old patches continue to be sent this way, and we may accept small new
+patches sent to the list, but please send all new patches through GitLab merge
+requests.
+
+
+Formatting and separating commits
+---------------------------------
+
+Unlike many projects using GitHub and GitLab, Wayland has a
+[linear, 'recipe' style history](http://www.bitsnbites.eu/git-history-work-log-vs-recipe/).
+This means that every commit should be small, digestible, stand-alone, and
+functional. Rather than a purely chronological commit history like this:
+
+    connection: plug a fd leak
+    plug another fd leak
+    connection: init fds to -1
+    close all fds
+    refactor checks into a new function
+    don't close fds we handed out
+
+we aim to have a clean history which only reflects the final state, broken up
+into functional groupings:
+
+    connection: Refactor out closure allocation
+    connection: Clear fds we shouldn't close to -1
+    connection: Make wl_closure_destroy() close fds of undispatched closures
+
+This ensures that the final patch series only contains the final state,
+without the changes and missteps taken along the development process.
+
+The first line of a commit message should contain a prefix indicating
+what part is affected by the patch followed by one sentence that
+describes the change. For examples:
+
+    protocol: Support scaled outputs and surfaces
+
+and
+
+    doc: generate server documentation from XML too
+
+If in doubt what prefix to use, look at other commits that change the
+same file(s) as the patch being sent.
+
+The body of the commit message should describe what the patch changes
+and why, and also note any particular side effects. This shouldn't be
+empty on most of the cases. It shouldn't take a lot of effort to write
+a commit message for an obvious change, so an empty commit message
+body is only acceptable if the questions "What?" and "Why?" are already
+answered on the one-line summary.
+
+The lines of the commit message should have at most 76 characters, to
+cope with the way git log presents them.
+
+See [notes on commit messages] for a recommended reading on writing commit
+messages.
+
+Your patches should also include a Signed-off-by line with your name and
+email address.  If you're not the patch's original author, you should
+also gather S-o-b's by them (and/or whomever gave the patch to you.) The
+significance of this is that it certifies that you created the patch,
+that it was created under an appropriate open source license, or
+provided to you under those terms.  This lets us indicate a chain of
+responsibility for the copyright status of the code.
+
+We won't reject patches that lack S-o-b, but it is strongly recommended.
+
+When you re-send patches, revised or not, it would be very good to document the
+changes compared to the previous revision in the commit message and/or the
+merge request. If you have already received Reviewed-by or Acked-by tags, you
+should evaluate whether they still apply and include them in the respective
+commit messages. Otherwise the tags may be lost, reviewers miss the credit they
+deserve, and the patches may cause redundant review effort.
+
+
+Tracking patches and following up
+---------------------------------
+
+Once submitted to GitLab, your patches will be reviewed by the Wayland
+development team on GitLab. Review may be entirely positive and result in your
+code landing instantly, in which case, great! You're done. However, we may ask
+you to make some revisions: fixing some bugs we've noticed, working to a
+slightly different design, or adding documentation and tests.
+
+If you do get asked to revise the patches, please bear in mind the notes above.
+You should use `git rebase -i` to make revisions, so that your patches follow
+the clear linear split documented above. Following that split makes it easier
+for reviewers to understand your work, and to verify that the code you're
+submitting is correct.
+
+A common request is to split single large patch into multiple patches. This can
+happen, for example, if when adding a new feature you notice a bug elsewhere
+which you need to fix to progress. Separating these changes into separate
+commits will allow us to verify and land the bugfix quickly, pushing part of
+your work for the good of everyone, whilst revision and discussion continues on
+the larger feature part. It also allows us to direct you towards reviewers who
+best understand the different areas you are working on.
+
+When you have made any requested changes, please rebase the commits, verify
+that they still individually look good, then force-push your new branch to
+GitLab. This will update the merge request and notify everyone subscribed to
+your merge request, so they can review it again.
+
+There are also
+[many GitLab CLI clients](https://about.gitlab.com/applications/#cli-clients),
+if you prefer to avoid the web interface. It may be difficult to follow review
+comments without using the web interface though, so we do recommend using this
+to go through the review process, even if you use other clients to track the
+list of available patches.
+
+
+Coding style
+------------
+
+You should follow the style of the file you're editing. In general, we
+try to follow the rules below.
+
+**Note: this file uses spaces due to markdown rendering issues for tabs.
+  Code must be implemented using tabs.**
+
+- indent with tabs, and a tab is always 8 characters wide
+- opening braces are on the same line as the if statement;
+- no braces in an if-body with just one statement;
+- if one of the branches of an if-else condition has braces, then the
+  other branch should also have braces;
+- there is always an empty line between variable declarations and the
+  code;
+
+```c
+static int
+my_function(void)
+{
+        int a = 0;
+
+        if (a)
+                b();
+        else
+                c();
+
+        if (a) {
+                b();
+                c();
+        } else {
+                d();
+        }
+}
+```
+
+- lines should be less than 80 characters wide;
+- when breaking lines with functions calls, the parameters are aligned
+  with the opening parentheses;
+- when assigning a variable with the result of a function call, if the
+  line would be longer we break it around the equal '=' sign if it makes
+  sense;
+
+```c
+        long_variable_name =
+                function_with_a_really_long_name(parameter1, parameter2,
+                                                 parameter3, parameter4);
+
+        x = function_with_a_really_long_name(parameter1, parameter2,
+                                             parameter3, parameter4);
+```
+
+Conduct
+=======
+
+As a freedesktop.org project, Wayland follows the Contributor Covenant,
+found at:
+https://www.freedesktop.org/wiki/CodeOfConduct
+
+Please conduct yourself in a respectful and civilised manner when
+interacting with community members on mailing lists, IRC, or bug
+trackers. The community represents the project as a whole, and abusive
+or bullying behaviour is not tolerated by the project.
+
+
+Licensing
+=========
+
+Wayland is licensed with the intention to be usable anywhere X.org is.
+Originally, X.org was covered under the MIT X11 license, but changed to
+the MIT Expat license.  Similarly, Wayland was covered initially as MIT
+X11 licensed, but changed to the MIT Expat license, following in X.org's
+footsteps.  Other than wording, the two licenses are substantially the
+same, with the exception of a no-advertising clause in X11 not included
+in Expat.
+
+New source code files should specify the MIT Expat license in their
+boilerplate, as part of the copyright statement.
+
+
+Review
+======
+
+All patches, even trivial ones, require at least one positive review
+(Reviewed-by). Additionally, if no Reviewed-by's have been given by
+people with commit access, there needs to be at least one Acked-by from
+someone with commit access. A person with commit access is expected to be
+able to evaluate the patch with respect to the project scope and architecture.
+
+The below review guidelines are intended to be interpreted in spirit, not by
+the letter. There may be circumstances where some guidelines are better
+ignored. We rely very much on the judgement of reviewers and commit rights
+holders.
+
+During review, the following matters should be checked:
+
+- The commit message explains why the change is being made.
+
+- The code fits the project's scope.
+
+- The code license is the same MIT licence the project generally uses.
+
+- Stable ABI or API is not broken.
+
+- 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 exercising the additions in the test suite.
+
+- The code fits the existing software architecture, e.g. no layering
+violations.
+
+- The code is correct and does not introduce new failures for existing users,
+does not add new corner-case bugs, and does not introduce new compiler
+warnings.
+
+- The patch does what it says in the commit message and changes nothing else.
+
+- The patch is a single logical change. If the commit message addresses
+multiple points, it is a hint that the commit might need splitting up.
+
+- A bug fix should target the underlying root cause instead of hiding symptoms.
+If a complete fix is not practical, partial fixes are acceptable if they come
+with code comments and filed Gitlab issues for the remaining bugs.
+
+- The bug root cause rule applies to external software components as well, e.g.
+do not work around kernel driver issues in userspace.
+
+- The test suite passes.
+
+- The code does not depend on API or ABI which has no working free open source
+implementation.
+
+- The code is not dead or untestable. E.g. if there are no free open source
+software users for it then it is effectively dead code.
+
+- The code is written to be easy to understand, or if code cannot be clear
+enough on its own there are code comments to explain it.
+
+- The code is minimal, i.e. prefer refactor and re-use when possible unless
+clarity suffers.
+
+- The code adheres to the style guidelines.
+
+- In a patch series, every intermediate step adheres to the above guidelines.
+
+
+Commit rights
+=============
+
+Commit rights will be granted to anyone who requests them and fulfills the
+below criteria:
+
+- Submitted some (10 as a rule of thumb) non-trivial (not just simple
+  spelling fixes and whitespace adjustment) patches that have been merged
+  already.
+
+- Are actively participating in public discussions about their work (on the
+  mailing list or IRC). This should not be interpreted as a requirement to
+  review other peoples patches but just make sure that patch submission isn't
+  one-way communication. Cross-review is still highly encouraged.
+
+- Will be regularly contributing further patches. This includes regular
+  contributors to other parts of the open source graphics stack who only
+  do the occasional development in this project.
+
+- Agrees to use their commit rights in accordance with the documented merge
+  criteria, tools, and processes.
+
+To apply for commit rights, create a new issue in gitlab for the respective
+project and give it the "accounts" label.
+
+Committers are encouraged to request their commit rights get removed when they
+no longer contribute to the project. Commit rights will be reinstated when they
+come back to the project.
+
+Maintainers and committers should encourage contributors to request commit
+rights, especially junior contributors tend to underestimate their skills.
+
+
+Stabilising for releases
+========================
+
+A release cycle ends with a stable release which also starts a new cycle and
+lifts any code freezes. Gradual code freezing towards a stable release starts
+with an alpha release. The release stages of a cycle are:
+
+- **Alpha release**:
+    Signified by version number #.#.91.
+    Major features must have landed before this. Major features include
+    invasive code motion and refactoring, high risk changes, and new stable
+    library ABI.
+
+- **Beta release**:
+    Signified by version number #.#.92.
+    Minor features must have landed before this. Minor features include all
+    new features that are not major, low risk changes, clean-ups, and
+    documentation. Stable ABI that was new in the alpha release can be removed
+    before a beta release if necessary.
+
+- **Release candidates (RC)**:
+    Signified by version number #.#.93 and up to #.#.99.
+    Bug fixes that are not release critical must have landed before this.
+    Release critical bug fixes can still be landed after this, but they may
+    call for another RC.
+
+- **Stable release**:
+    Signified by version number #.#.0.
+    Ideally no changes since the last RC.
+
+Mind that version #.#.90 is never released. It is used during development when
+no code freeze is in effect. Stable branches and point releases are not covered
+by the above.
+
+
+[git documentation]: http://git-scm.com/documentation
+[notes on commit messages]: http://who-t.blogspot.de/2009/12/on-commit-messages.html
diff --git a/subprojects/wayland/COPYING b/subprojects/wayland/COPYING
new file mode 100644
index 0000000000000000000000000000000000000000..eb25a4e2b3d1582fb47f189c07f96227777c8e09
--- /dev/null
+++ b/subprojects/wayland/COPYING
@@ -0,0 +1,29 @@
+Copyright © 2008-2012 Kristian Høgsberg
+Copyright © 2010-2012 Intel Corporation
+Copyright © 2011 Benjamin Franzke
+Copyright © 2012 Collabora, Ltd.
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the
+Software is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice (including the next
+paragraph) shall be included in all copies or substantial portions of the
+Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+
+---
+
+The above is the version of the MIT "Expat" License used by X.org:
+
+    http://cgit.freedesktop.org/xorg/xserver/tree/COPYING
diff --git a/subprojects/wayland/README.md b/subprojects/wayland/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..437b39da2db75c3d16bfed8cf50ed4bcf554f60d
--- /dev/null
+++ b/subprojects/wayland/README.md
@@ -0,0 +1,30 @@
+# Wayland
+
+Wayland is a project to define a protocol for a compositor to talk to
+its clients as well as a library implementation of the protocol.  The
+compositor can be a standalone display server running on Linux kernel
+modesetting and evdev input devices, an X application, or a wayland
+client itself.  The clients can be traditional applications, X servers
+(rootless or fullscreen) or other display servers.
+
+The wayland protocol is essentially only about input handling and
+buffer management.  The compositor receives input events and forwards
+them to the relevant client.  The clients creates buffers and renders
+into them and notifies the compositor when it needs to redraw.  The
+protocol also handles drag and drop, selections, window management and
+other interactions that must go through the compositor.  However, the
+protocol does not handle rendering, which is one of the features that
+makes wayland so simple.  All clients are expected to handle rendering
+themselves, typically through cairo or OpenGL.
+
+Building the wayland libraries is fairly simple, aside from libffi,
+they don't have many dependencies:
+
+    $ git clone https://gitlab.freedesktop.org/wayland/wayland
+    $ cd wayland
+    $ meson build/ --prefix=PREFIX
+    $ ninja -C build/ install
+
+where PREFIX is where you want to install the libraries.
+
+See https://wayland.freedesktop.org for documentation.
diff --git a/subprojects/wayland/cursor/convert_font.c b/subprojects/wayland/cursor/convert_font.c
new file mode 100644
index 0000000000000000000000000000000000000000..74e45fbcafc1539c42fe005257103af6c949acfc
--- /dev/null
+++ b/subprojects/wayland/cursor/convert_font.c
@@ -0,0 +1,547 @@
+/*
+ * Copyright © 2012 Philipp Brüschweiler
+ *
+ * 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.
+ */
+
+/*
+ * This is a small, hacky tool to extract cursors from a .pcf file.
+ * The information about the file format has been gathered from
+ * http://fontforge.org/pcf-format.html
+ */
+
+#include <assert.h>
+#include <fcntl.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#define min(a, b) ((a) < (b) ? (a) : (b))
+#define max(a, b) ((a) > (b) ? (a) : (b))
+
+struct glyph {
+	char *name;
+	int16_t left_bearing, right_bearing, ascent, descent;
+
+	int16_t width, height;
+	int16_t hotx, hoty;
+
+	int32_t data_format;
+	char *data;
+};
+
+static struct {
+	int count;
+	struct glyph *glyphs;
+} extracted_font = {0, NULL};
+
+#define PCF_PROPERTIES		    (1<<0)
+#define PCF_ACCELERATORS	    (1<<1)
+#define PCF_METRICS		    (1<<2)
+#define PCF_BITMAPS		    (1<<3)
+#define PCF_INK_METRICS		    (1<<4)
+#define	PCF_BDF_ENCODINGS	    (1<<5)
+#define PCF_SWIDTHS		    (1<<6)
+#define PCF_GLYPH_NAMES		    (1<<7)
+#define PCF_BDF_ACCELERATORS	    (1<<8)
+
+#define PCF_DEFAULT_FORMAT	0x00000000
+#define PCF_INKBOUNDS		0x00000200
+#define PCF_ACCEL_W_INKBOUNDS	0x00000100
+#define PCF_COMPRESSED_METRICS	0x00000100
+
+#define	PCF_FORMAT_MASK		0xffffff00
+
+struct pcf_header {
+	char header[4];
+	int32_t table_count;
+	struct toc_entry {
+		int32_t type;
+		int32_t format;
+		int32_t size;
+		int32_t offset;
+	} tables[0];
+};
+
+struct compressed_metrics {
+	uint8_t left_sided_bearing;
+	uint8_t right_side_bearing;
+	uint8_t character_width;
+	uint8_t character_ascent;
+	uint8_t character_descent;
+};
+
+struct uncompressed_metrics {
+	int16_t left_sided_bearing;
+	int16_t right_side_bearing;
+	int16_t character_width;
+	int16_t character_ascent;
+	int16_t character_descent;
+	uint16_t character_attributes;
+};
+
+struct metrics {
+	int32_t format;
+	union {
+		struct {
+			int16_t count;
+			struct compressed_metrics compressed_metrics[0];
+		} compressed;
+		struct {
+			int32_t count;
+			struct uncompressed_metrics uncompressed_metrics[0];
+		} uncompressed;
+	};
+};
+
+struct glyph_names {
+	int32_t format;
+	int32_t glyph_count;
+	int32_t offsets[0];
+};
+
+struct bitmaps {
+	int32_t format;
+	int32_t glyph_count;
+	int32_t offsets[0];
+};
+
+static void
+handle_compressed_metrics(int32_t count, struct compressed_metrics *m)
+{
+	printf("metrics count: %d\n", count);
+	extracted_font.count = count;
+	extracted_font.glyphs = calloc(count, sizeof(struct glyph));
+
+	int i;
+	for (i = 0; i < count; ++i) {
+		struct glyph *glyph = &extracted_font.glyphs[i];
+		glyph->left_bearing =
+			((int16_t) m[i].left_sided_bearing) - 0x80;
+		glyph->right_bearing =
+			((int16_t) m[i].right_side_bearing) - 0x80;
+		glyph->width = ((int16_t) m[i].character_width) - 0x80;
+		glyph->ascent = ((int16_t) m[i].character_ascent) - 0x80;
+		glyph->descent = ((int16_t) m[i].character_descent) - 0x80;
+
+		/* computed stuff */
+		glyph->height = glyph->ascent + glyph->descent;
+
+		glyph->hotx = -glyph->left_bearing;
+		glyph->hoty = glyph->ascent;
+	}
+}
+
+static void
+handle_metrics(void *metricbuf)
+{
+	struct metrics *metrics = metricbuf;
+	printf("metric format: %x\n", metrics->format);
+
+	if ((metrics->format & PCF_FORMAT_MASK) == PCF_DEFAULT_FORMAT) {
+		printf("todo...\n");
+	} else if ((metrics->format & PCF_FORMAT_MASK) ==
+		   PCF_COMPRESSED_METRICS) {
+		handle_compressed_metrics(
+		    metrics->compressed.count,
+		    &metrics->compressed.compressed_metrics[0]);
+	} else {
+		printf("incompatible format\n");
+		abort();
+	}
+}
+
+static void
+handle_glyph_names(struct glyph_names *names)
+{
+	printf("glyph count %d\n", names->glyph_count);
+
+	if (names->glyph_count != extracted_font.count) {
+		abort();
+	}
+
+	printf("glyph names format %x\n", names->format);
+
+	void *names_start = ((void*) names) + sizeof(struct glyph_names)
+		+ (names->glyph_count + 1) * sizeof(int32_t);
+
+	int i;
+	for (i = 0; i < names->glyph_count; ++i) {
+		int32_t start = names->offsets[i];
+		int32_t end = names->offsets[i+1];
+		char *name = names_start + start;
+		extracted_font.glyphs[i].name = calloc(1, end - start + 1);
+		memcpy(extracted_font.glyphs[i].name, name, end - start);
+	}
+}
+
+static void
+handle_bitmaps(struct bitmaps *bitmaps)
+{
+	printf("bitmaps count %d\n", bitmaps->glyph_count);
+
+	if (bitmaps->glyph_count != extracted_font.count) {
+		abort();
+	}
+
+	printf("format %x\n", bitmaps->format);
+
+	if (bitmaps->format != 2) {
+		printf("format not yet supported\n");
+		abort();
+	}
+
+	void *bitmaps_start = ((void*) bitmaps) + sizeof(struct bitmaps)
+		+ (bitmaps->glyph_count + 4) * sizeof(int32_t);
+
+	int i;
+	for (i = 0; i < bitmaps->glyph_count; ++i) {
+		int32_t offset = bitmaps->offsets[i];
+		struct glyph *glyph = &extracted_font.glyphs[i];
+		glyph->data_format = bitmaps->format;
+
+		glyph->data = bitmaps_start + offset;
+	}
+}
+
+static void
+handle_pcf(void *fontbuf)
+{
+	struct pcf_header *header = fontbuf;
+	printf("tablecount %d\n", header->table_count);
+
+	int i;
+	for (i = 0; i < header->table_count; ++i) {
+		struct toc_entry *entry = &header->tables[i];
+		printf("type: %d\n", entry->type);
+		if (entry->type == PCF_METRICS) {
+			handle_metrics(fontbuf + entry->offset);
+		} else if (entry->type == PCF_GLYPH_NAMES) {
+			handle_glyph_names(fontbuf + entry->offset);
+		} else if (entry->type == PCF_BITMAPS) {
+			handle_bitmaps(fontbuf + entry->offset);
+		}
+	}
+}
+
+static char
+get_glyph_pixel(struct glyph *glyph, int x, int y)
+{
+	int absx = glyph->hotx + x;
+	int absy = glyph->hoty + y;
+
+	if (absx < 0 || absx >= glyph->width ||
+	    absy < 0 || absy >= glyph->height)
+		return 0;
+
+	int stride = (glyph->width + 31) / 32 * 4;
+	unsigned char block = glyph->data[absy * stride + (absx/8)];
+	int idx = absx % 8;
+	return (block >> idx) & 1;
+}
+
+static struct {
+	uint32_t *data;
+	size_t capacity, size;
+} data_buffer;
+
+static void
+init_data_buffer()
+{
+	data_buffer.data = malloc(sizeof(uint32_t) * 10);
+	data_buffer.capacity = 10;
+	data_buffer.size = 0;
+}
+
+static void
+add_pixel(uint32_t pixel)
+{
+	if (data_buffer.size == data_buffer.capacity) {
+		data_buffer.capacity *= 2;
+		data_buffer.data =
+			realloc(data_buffer.data,
+				sizeof(uint32_t) * data_buffer.capacity);
+	}
+	data_buffer.data[data_buffer.size++] = pixel;
+}
+
+struct reconstructed_glyph {
+	int32_t width, height;
+	int32_t hotspot_x, hotspot_y;
+	size_t offset;
+	char *name;
+};
+
+static void
+reconstruct_glyph(struct glyph *cursor, struct glyph *mask, char *name,
+		  struct reconstructed_glyph *glyph)
+{
+	int minx = min(-cursor->hotx, -mask->hotx);
+	int maxx = max(cursor->right_bearing, mask->right_bearing);
+
+	int miny = min(-cursor->hoty, -mask->hoty);
+	int maxy = max(cursor->height - cursor->hoty,
+		       mask->height - mask->hoty);
+
+	int width = maxx - minx;
+	int height = maxy - miny;
+
+	glyph->name = strdup(name);
+	glyph->width = width;
+	glyph->height = height;
+	glyph->hotspot_x = -minx;
+	glyph->hotspot_y = -miny;
+	glyph->offset = data_buffer.size;
+
+	int x, y;
+	for (y = miny; y < maxy; ++y) {
+		for (x = minx; x < maxx; ++x) {
+			char alpha = get_glyph_pixel(mask, x, y);
+			if (alpha) {
+				char color = get_glyph_pixel(cursor, x, y);
+				if (color)
+					add_pixel(0xff000000);
+				else
+					add_pixel(0xffffffff);
+			} else {
+				add_pixel(0);
+			}
+		}
+	}
+}
+
+/* 
+ * Originally from
+ * http://cgit.freedesktop.org/xorg/lib/libXfont/tree/src/builtins/fonts.c
+ * Changed to the MIT "Expat" style license for Wayland..
+ */
+static const char cursor_licence[] =
+	"/*\n"
+	"* Copyright 1999 SuSE, Inc.\n"
+	"*\n"
+	"* Permission is hereby granted, free of charge, to any person obtaining\n"
+	"* a copy of this software and associated documentation files (the\n"
+	"* \"Software\"), to deal in the Software without restriction, including\n"
+	"* without limitation the rights to use, copy, modify, merge, publish,\n"
+	"* distribute, sublicense, and/or sell copies of the Software, and to\n"
+	"* permit persons to whom the Software is furnished to do so, subject to\n"
+	"* the following conditions:\n"
+	"*\n"
+	"* The above copyright notice and this permission notice (including the\n"
+	"* next paragraph) shall be included in all copies or substantial\n"
+	"* portions of the Software.\n"
+	"*\n"
+	"* THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND,\n"
+	"* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\n"
+	"* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND\n"
+	"* NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS\n"
+	"* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN\n"
+	"* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN\n"
+	"* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\n"
+	"* SOFTWARE.\n"
+	"*\n"
+	"* Author:  Keith Packard, SuSE, Inc.\n"
+	"*/\n";
+
+static void
+write_output_file(struct reconstructed_glyph *glyphs, int n)
+{
+	int i, j, counter, size;
+	FILE *file = fopen("cursor-data.h", "w");
+	uint32_t *data;
+
+	fprintf(file, "%s\n", cursor_licence);
+
+	fprintf(file, "static uint32_t cursor_data[] = {\n\t");
+
+	counter = 0;
+	for (i = 0; i < n; ++i) {
+		data = data_buffer.data + glyphs[i].offset;
+		size = glyphs[i].width * glyphs[i].height;
+
+		for (j = 0; j < size; ++j) {
+			fprintf(file, "0x%08x, ", data[j]);
+			if (++counter % 6 == 0)
+				fprintf(file, "\n\t");
+		}
+	}
+	fprintf(file, "\n};\n\n");
+
+	fprintf(file,
+		"static struct {\n"
+		"\tchar *name;\n"
+		"\tint width, height;\n"
+		"\tint hotspot_x, hotspot_y;\n"
+		"\tsize_t offset;\n"
+		"} cursor_metadata[] = {\n");
+
+	for (i = 0; i < n; ++i)
+		fprintf(file, "\t{ \"%s\", %d, %d, %d, %d, %zu },\n",
+			glyphs[i].name,
+			glyphs[i].width, glyphs[i].height,
+			glyphs[i].hotspot_x, glyphs[i].hotspot_y,
+			glyphs[i].offset);
+
+	fprintf(file, "};");
+
+	fclose(file);
+}
+
+struct glyph *
+find_mask_glyph(char *name)
+{
+	const char mask[] = "_mask";
+	const int masklen = strlen(mask);
+
+	int len = strlen(name);
+	int i;
+	for (i = 0; i < extracted_font.count; ++i) {
+		struct glyph *g = &extracted_font.glyphs[i];
+		int l2 = strlen(g->name);
+		if ((l2 == len + masklen) &&
+		    (memcmp(g->name, name, len) == 0) &&
+		    (memcmp(g->name + len, mask, masklen) == 0)) {
+			return g;
+		}
+	}
+	return NULL;
+}
+
+static void
+output_all_cursors()
+{
+	int i, j;
+	struct reconstructed_glyph *glyphs =
+		malloc(sizeof(struct reconstructed_glyph) *
+		       extracted_font.count/2);
+	j = 0;
+
+	for (i = 0; i < extracted_font.count; ++i) {
+		struct glyph *g = &extracted_font.glyphs[i];
+		if (strstr(g->name, "_mask"))
+			continue;
+
+		struct glyph *mask = find_mask_glyph(g->name);
+
+		reconstruct_glyph(g, mask, g->name, &glyphs[j]);
+		j++;
+	}
+
+	write_output_file(glyphs, extracted_font.count/2);
+}
+
+static void
+find_cursor_and_mask(const char *name,
+		     struct glyph **cursor,
+		     struct glyph **mask)
+{
+	int i;
+	char mask_name[100];
+	sprintf(mask_name, "%s_mask", name);
+
+	*cursor = *mask = NULL;
+
+	for (i = 0; i < extracted_font.count && (!*mask || !*cursor); ++i) {
+		struct glyph *g = &extracted_font.glyphs[i];
+		if (!strcmp(name, g->name))
+			*cursor = g;
+		else if (!strcmp(mask_name, g->name))
+			*mask = g;
+	}
+}
+
+static struct {
+	char *target_name, *source_name;
+} interesting_cursors[] = {
+	{ "bottom_left_corner", "bottom_left_corner" },
+	{ "bottom_right_corner", "bottom_right_corner" },
+	{ "bottom_side", "bottom_side" },
+	{ "grabbing", "fleur" },
+	{ "left_ptr", "left_ptr" },
+	{ "left_side", "left_side" },
+	{ "right_side", "right_side" },
+	{ "top_left_corner", "top_left_corner" },
+	{ "top_right_corner", "top_right_corner" },
+	{ "top_side", "top_side" },
+	{ "xterm", "xterm" },
+	{ "hand1", "hand1" },
+	{ "watch", "watch" }
+};
+
+static void
+output_interesting_cursors()
+{
+	int i;
+	int n = sizeof(interesting_cursors) / sizeof(interesting_cursors[0]);
+	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,
+				     &cursor, &mask);
+		if (!cursor) {
+			printf("no cursor for %s\n",
+			       interesting_cursors[i].source_name);
+			abort();
+		}
+		if (!mask) {
+			printf("no mask for %s\n",
+			       interesting_cursors[i].source_name);
+			abort();
+		}
+		reconstruct_glyph(cursor, mask,
+				  interesting_cursors[i].target_name,
+				  &glyphs[i]);
+	}
+
+	write_output_file(glyphs, n);
+}
+
+int main()
+{
+	const char filename[] = "cursor.pcf";
+
+	int fd = open(filename, O_RDONLY);
+	struct stat filestat;
+
+	fstat(fd, &filestat);
+
+	void *fontbuf = mmap(NULL, filestat.st_size, PROT_READ,
+			     MAP_PRIVATE, fd, 0);
+
+	handle_pcf(fontbuf);
+
+	init_data_buffer();
+
+	//output_all_cursors();
+	output_interesting_cursors();
+}
diff --git a/subprojects/wayland/cursor/cursor-data.h b/subprojects/wayland/cursor/cursor-data.h
new file mode 100644
index 0000000000000000000000000000000000000000..2ee2f8a779431020a3ded7480e5730ad0835b792
--- /dev/null
+++ b/subprojects/wayland/cursor/cursor-data.h
@@ -0,0 +1,569 @@
+/*
+* Copyright 1999 SuSE, 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.
+*
+* Author:  Keith Packard, SuSE, Inc.
+*/
+
+#include <stdint.h>
+
+static uint32_t cursor_data[] = {
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000,
+	0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000,
+	0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff,
+	0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff,
+	0xffffffff, 0x00000000, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0x00000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0x00000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0xff000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xff000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xff000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff,
+	0xff000000, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xff000000, 0xff000000, 0xffffffff, 0xffffffff, 0xffffffff,
+	0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0xffffffff,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0xffffffff, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xffffffff, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000, 0xffffffff, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xffffffff,
+	0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000,
+	0xffffffff, 0xff000000, 0xff000000, 0xff000000, 0xff000000, 0xff000000,
+	0xff000000, 0xff000000, 0xff000000, 0xffffffff, 0x00000000, 0x00000000,
+	0x00000000, 0x00000000,
+};
+
+static struct cursor_metadata {
+	char *name;
+	int width, height;
+	int hotspot_x, hotspot_y;
+	size_t offset;
+} cursor_metadata[] = {
+	{ "bottom_left_corner", 16, 16, 1, 14, 0 },
+	{ "bottom_right_corner", 16, 16, 14, 14, 256 },
+	{ "bottom_side", 15, 16, 7, 14, 512 },
+	{ "grabbing", 16, 16, 8, 8, 752 },
+	{ "left_ptr", 10, 16, 1, 1, 1008 },
+	{ "left_side", 16, 15, 1, 7, 1168 },
+	{ "right_side", 16, 15, 14, 7, 1408 },
+	{ "top_left_corner", 16, 16, 1, 1, 1648 },
+	{ "top_right_corner", 16, 16, 14, 1, 1904 },
+	{ "top_side", 15, 16, 7, 1, 2160 },
+	{ "xterm", 9, 16, 4, 8, 2400 },
+	{ "hand1", 13, 16, 12, 0, 2544 },
+	{ "watch", 16, 16, 15, 9, 2752 },
+
+	/* https://www.freedesktop.org/wiki/Specifications/cursor-spec/ */
+	{ "sw-resize", 16, 16, 1, 14, 0 },
+	{ "se-resize", 16, 16, 14, 14, 256 },
+	{ "s-resize", 15, 16, 7, 14, 512 },
+	{ "all-scroll", 16, 16, 8, 8, 752 },
+	{ "default", 10, 16, 1, 1, 1008 },
+	{ "w-resize", 16, 15, 1, 7, 1168 },
+	{ "e-resize", 16, 15, 14, 7, 1408 },
+	{ "nw-resize", 16, 16, 1, 1, 1648 },
+	{ "ne-resize", 16, 16, 14, 1, 1904 },
+	{ "n-resize", 15, 16, 7, 1, 2160 },
+	{ "text", 9, 16, 4, 8, 2400 },
+	{ "pointer", 13, 16, 12, 0, 2544 },
+	{ "wait", 16, 16, 15, 9, 2752 },
+};
diff --git a/subprojects/wayland/cursor/cursor.pcf b/subprojects/wayland/cursor/cursor.pcf
new file mode 100644
index 0000000000000000000000000000000000000000..812fcc54fdf1ad92f7016e69fe6c2dd9f7437b62
Binary files /dev/null and b/subprojects/wayland/cursor/cursor.pcf differ
diff --git a/subprojects/wayland/cursor/meson.build b/subprojects/wayland/cursor/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..f7d82e4ee0872b449b2411e273b589ae7db060f9
--- /dev/null
+++ b/subprojects/wayland/cursor/meson.build
@@ -0,0 +1,47 @@
+icondir = get_option('icon_directory')
+if icondir == ''
+	icondir = join_paths(get_option('prefix'), get_option('datadir'), 'icons')
+endif
+
+if wayland_version[0] != '1'
+	# The versioning used for the shared libraries assumes that the major
+	# version of Wayland as a whole will increase to 2 if and only if there
+	# is an ABI break, at which point we should probably bump the SONAME of
+	# all libraries to .so.2. For more details see
+	# https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/177
+	error('We probably need to bump the SONAME of libwayland-cursor')
+endif
+
+wayland_cursor = library(
+	'wayland-cursor',
+	sources: [
+		'wayland-cursor.c',
+		'os-compatibility.c',
+		'xcursor.c',
+	],
+	# To avoid an unnecessary SONAME bump, wayland 1.x.y produces
+	# libwayland-cursor.so.0.x.y.
+	version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
+	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',
+)
+
+wayland_cursor_dep = declare_dependency(
+	link_with: wayland_cursor,
+	include_directories: [ root_inc, include_directories('.') ],
+)
+
+if meson.version().version_compare('>= 0.54.0')
+	meson.override_dependency('wayland-cursor', wayland_cursor_dep)
+endif
diff --git a/subprojects/wayland/cursor/os-compatibility.c b/subprojects/wayland/cursor/os-compatibility.c
new file mode 100644
index 0000000000000000000000000000000000000000..2b54bae2e137aa3dee8a3a307a91ea6a7331780e
--- /dev/null
+++ b/subprojects/wayland/cursor/os-compatibility.c
@@ -0,0 +1,222 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#ifdef HAVE_MEMFD_CREATE
+#include <sys/mman.h>
+#endif
+
+/* Fallback to no flag when missing the definition */
+#ifndef MFD_NOEXEC_SEAL
+#define MFD_NOEXEC_SEAL 0
+#endif
+
+#include "os-compatibility.h"
+
+#ifndef HAVE_MKOSTEMP
+static int
+set_cloexec_or_close(int fd)
+{
+	long flags;
+
+	if (fd == -1)
+		return -1;
+
+	flags = fcntl(fd, F_GETFD);
+	if (flags == -1)
+		goto err;
+
+	if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+		goto err;
+
+	return fd;
+
+err:
+	close(fd);
+	return -1;
+}
+#endif
+
+static int
+create_tmpfile_cloexec(char *tmpname)
+{
+	int fd;
+
+#ifdef HAVE_MKOSTEMP
+	fd = mkostemp(tmpname, O_CLOEXEC);
+	if (fd >= 0)
+		unlink(tmpname);
+#else
+	fd = mkstemp(tmpname);
+	if (fd >= 0) {
+		fd = set_cloexec_or_close(fd);
+		unlink(tmpname);
+	}
+#endif
+
+	return fd;
+}
+
+/*
+ * Create a new, unique, anonymous file of the given size, and
+ * return the file descriptor for it. The file descriptor is set
+ * CLOEXEC. The file is immediately suitable for mmap()'ing
+ * the given size at offset zero.
+ *
+ * The file should not have a permanent backing store like a disk,
+ * but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
+ *
+ * The file name is deleted from the file system.
+ *
+ * The file is suitable for buffer sharing between processes by
+ * transmitting the file descriptor over Unix sockets using the
+ * SCM_RIGHTS methods.
+ *
+ * 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 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)
+{
+	static const char template[] = "/wayland-cursor-shared-XXXXXX";
+	const char *path;
+	char *name;
+	size_t name_size;
+	int fd;
+
+#ifdef HAVE_MEMFD_CREATE
+	/*
+	* Linux kernels older than 6.3 reject MFD_NOEXEC_SEAL with EINVAL.
+	* Try first *with* it, and if that fails, try again *without* it.
+	*/
+	errno = 0;
+	fd = memfd_create(
+		"wayland-cursor",
+		MFD_CLOEXEC | MFD_ALLOW_SEALING | MFD_NOEXEC_SEAL);
+
+	if (fd < 0 && errno == EINVAL && MFD_NOEXEC_SEAL != 0) {
+		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 || path[0] != '/') {
+			errno = ENOENT;
+			return -1;
+		}
+
+		name_size = strlen(path) + sizeof(template);
+		name = malloc(name_size);
+		if (!name)
+			return -1;
+
+		snprintf(name, name_size, "%s%s", path, 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
+	sigset_t mask;
+	sigset_t old_mask;
+
+	/*
+	 * posix_fallocate() might be interrupted, so we need to check
+	 * for EINTR and retry in that case.
+	 * However, in the presence of an alarm, the interrupt may trigger
+	 * repeatedly and prevent a large posix_fallocate() to ever complete
+	 * successfully, so we need to first block SIGALRM to prevent
+	 * this.
+	 */
+	sigemptyset(&mask);
+	sigaddset(&mask, SIGALRM);
+	sigprocmask(SIG_BLOCK, &mask, &old_mask);
+	/*
+	 * Filesystems that do not support fallocate will return EINVAL or
+	 * EOPNOTSUPP. In this case we need to fall back to ftruncate
+	 */
+	do {
+		errno = posix_fallocate(fd, 0, size);
+	} while (errno == EINTR);
+	sigprocmask(SIG_SETMASK, &old_mask, NULL);
+	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/subprojects/wayland/cursor/os-compatibility.h b/subprojects/wayland/cursor/os-compatibility.h
new file mode 100644
index 0000000000000000000000000000000000000000..fdfeb78b143309915956de3ea92303776a3743b0
--- /dev/null
+++ b/subprojects/wayland/cursor/os-compatibility.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef OS_COMPATIBILITY_H
+#define OS_COMPATIBILITY_H
+
+#include <sys/types.h>
+
+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/subprojects/wayland/cursor/wayland-cursor.c b/subprojects/wayland/cursor/wayland-cursor.c
new file mode 100644
index 0000000000000000000000000000000000000000..156f0a80c288623d4801046c973aee55f9aedaa9
--- /dev/null
+++ b/subprojects/wayland/cursor/wayland-cursor.c
@@ -0,0 +1,516 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+#include "xcursor.h"
+#include "wayland-cursor.h"
+#include "wayland-client.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include "os-compatibility.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+struct shm_pool {
+	struct wl_shm_pool *pool;
+	int fd;
+	unsigned int size;
+	unsigned int used;
+	char *data;
+};
+
+static struct shm_pool *
+shm_pool_create(struct wl_shm *shm, int size)
+{
+	struct shm_pool *pool;
+
+	pool = malloc(sizeof *pool);
+	if (!pool)
+		return NULL;
+
+	pool->fd = os_create_anonymous_file(size);
+	if (pool->fd < 0)
+		goto err_free;
+
+	pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
+			  pool->fd, 0);
+
+	if (pool->data == MAP_FAILED)
+		goto err_close;
+
+	pool->pool = wl_shm_create_pool(shm, pool->fd, size);
+	pool->size = size;
+	pool->used = 0;
+
+	return pool;
+
+err_close:
+	close(pool->fd);
+err_free:
+	free(pool);
+	return NULL;
+}
+
+static int
+shm_pool_resize(struct shm_pool *pool, int size)
+{
+	if (os_resize_anonymous_file(pool->fd, size) < 0)
+		return 0;
+
+	wl_shm_pool_resize(pool->pool, size);
+
+	munmap(pool->data, pool->size);
+
+	pool->data = mmap(NULL, size, PROT_READ | PROT_WRITE, MAP_SHARED,
+			  pool->fd, 0);
+	if (pool->data == MAP_FAILED)
+		return 0;
+	pool->size = size;
+
+	return 1;
+}
+
+static int
+shm_pool_allocate(struct shm_pool *pool, int size)
+{
+	int offset;
+
+	if (pool->used + size > pool->size)
+		if (!shm_pool_resize(pool, 2 * pool->size + size))
+			return -1;
+
+	offset = pool->used;
+	pool->used += size;
+
+	return offset;
+}
+
+static void
+shm_pool_destroy(struct shm_pool *pool)
+{
+	munmap(pool->data, pool->size);
+	wl_shm_pool_destroy(pool->pool);
+	close(pool->fd);
+	free(pool);
+}
+
+
+struct wl_cursor_theme {
+	unsigned int cursor_count;
+	struct wl_cursor **cursors;
+	struct wl_shm *shm;
+	struct shm_pool *pool;
+	int size;
+};
+
+struct cursor_image {
+	struct wl_cursor_image image;
+	struct wl_cursor_theme *theme;
+	struct wl_buffer *buffer;
+	int offset; /* data offset of this image in the shm pool */
+};
+
+struct cursor {
+	struct wl_cursor cursor;
+	uint32_t total_delay; /* length of the animation in ms */
+};
+
+/** Get an shm buffer for a cursor image
+ *
+ * \param image The cursor image
+ * \return An shm buffer for the cursor image. The user should not destroy
+ * the returned buffer.
+ */
+WL_EXPORT struct wl_buffer *
+wl_cursor_image_get_buffer(struct wl_cursor_image *image)
+{
+	struct cursor_image *img = (struct cursor_image *) image;
+	struct wl_cursor_theme *theme = img->theme;
+
+	if (!img->buffer) {
+		img->buffer =
+			wl_shm_pool_create_buffer(theme->pool->pool,
+						  img->offset,
+						  image->width, image->height,
+						  image->width * 4,
+						  WL_SHM_FORMAT_ARGB8888);
+	};
+
+	return img->buffer;
+}
+
+static void
+wl_cursor_image_destroy(struct wl_cursor_image *image)
+{
+	struct cursor_image *img = (struct cursor_image *) image;
+
+	if (img->buffer)
+		wl_buffer_destroy(img->buffer);
+
+	free(img);
+}
+
+static void
+wl_cursor_destroy(struct wl_cursor *cursor)
+{
+	unsigned int i;
+
+	for (i = 0; i < cursor->image_count; i++)
+		wl_cursor_image_destroy(cursor->images[i]);
+
+	free(cursor->images);
+	free(cursor->name);
+	free(cursor);
+}
+
+#include "cursor-data.h"
+
+static struct wl_cursor *
+wl_cursor_create_from_data(struct cursor_metadata *metadata,
+			   struct wl_cursor_theme *theme)
+{
+	struct cursor *cursor;
+	struct cursor_image *image;
+	int size;
+
+	cursor = malloc(sizeof *cursor);
+	if (!cursor)
+		return NULL;
+
+	cursor->cursor.image_count = 1;
+	cursor->cursor.images = malloc(sizeof *cursor->cursor.images);
+	if (!cursor->cursor.images)
+		goto err_free_cursor;
+
+	cursor->cursor.name = strdup(metadata->name);
+	cursor->total_delay = 0;
+
+	image = malloc(sizeof *image);
+	if (!image)
+		goto err_free_images;
+
+	cursor->cursor.images[0] = (struct wl_cursor_image *) image;
+	image->theme = theme;
+	image->buffer = NULL;
+	image->image.width = metadata->width;
+	image->image.height = metadata->height;
+	image->image.hotspot_x = metadata->hotspot_x;
+	image->image.hotspot_y = metadata->hotspot_y;
+	image->image.delay = 0;
+
+	size = metadata->width * metadata->height * sizeof(uint32_t);
+	image->offset = shm_pool_allocate(theme->pool, size);
+
+	if (image->offset < 0)
+		goto err_free_image;
+
+	memcpy(theme->pool->data + image->offset,
+	       cursor_data + metadata->offset, size);
+
+	return &cursor->cursor;
+
+err_free_image:
+	free(image);
+
+err_free_images:
+	free(cursor->cursor.name);
+	free(cursor->cursor.images);
+
+err_free_cursor:
+	free(cursor);
+	return NULL;
+}
+
+static void
+load_fallback_theme(struct wl_cursor_theme *theme)
+{
+	uint32_t i;
+
+	theme->cursor_count = ARRAY_LENGTH(cursor_metadata);
+	theme->cursors = malloc(theme->cursor_count * sizeof(*theme->cursors));
+
+	if (theme->cursors == NULL) {
+		theme->cursor_count = 0;
+		return;
+	}
+
+	for (i = 0; i < theme->cursor_count; ++i) {
+		theme->cursors[i] =
+			wl_cursor_create_from_data(&cursor_metadata[i], theme);
+
+		if (theme->cursors[i] == NULL)
+			break;
+	}
+	theme->cursor_count = i;
+}
+
+static struct wl_cursor *
+wl_cursor_create_from_xcursor_images(struct xcursor_images *images,
+				     struct wl_cursor_theme *theme)
+{
+	struct cursor *cursor;
+	struct cursor_image *image;
+	int i, size;
+
+	cursor = malloc(sizeof *cursor);
+	if (!cursor)
+		return NULL;
+
+	cursor->cursor.images =
+		malloc(images->nimage * sizeof cursor->cursor.images[0]);
+	if (!cursor->cursor.images) {
+		free(cursor);
+		return NULL;
+	}
+
+	cursor->cursor.name = strdup(images->name);
+	cursor->total_delay = 0;
+
+	for (i = 0; i < images->nimage; i++) {
+		image = malloc(sizeof *image);
+		if (image == NULL)
+			break;
+
+		image->theme = theme;
+		image->buffer = NULL;
+
+		image->image.width = images->images[i]->width;
+		image->image.height = images->images[i]->height;
+		image->image.hotspot_x = images->images[i]->xhot;
+		image->image.hotspot_y = images->images[i]->yhot;
+		image->image.delay = images->images[i]->delay;
+
+		size = image->image.width * image->image.height * 4;
+		image->offset = shm_pool_allocate(theme->pool, size);
+		if (image->offset < 0) {
+			free(image);
+			break;
+		}
+
+		/* copy pixels to shm pool */
+		memcpy(theme->pool->data + image->offset,
+		       images->images[i]->pixels, size);
+		cursor->total_delay += image->image.delay;
+		cursor->cursor.images[i] = (struct wl_cursor_image *) image;
+	}
+	cursor->cursor.image_count = i;
+
+	if (cursor->cursor.image_count == 0) {
+		free(cursor->cursor.name);
+		free(cursor->cursor.images);
+		free(cursor);
+		return NULL;
+	}
+
+	return &cursor->cursor;
+}
+
+static void
+load_callback(struct xcursor_images *images, void *data)
+{
+	struct wl_cursor_theme *theme = data;
+	struct wl_cursor *cursor;
+
+	if (wl_cursor_theme_get_cursor(theme, images->name)) {
+		xcursor_images_destroy(images);
+		return;
+	}
+
+	cursor = wl_cursor_create_from_xcursor_images(images, theme);
+
+	if (cursor) {
+		theme->cursor_count++;
+		theme->cursors =
+			realloc(theme->cursors,
+				theme->cursor_count * sizeof theme->cursors[0]);
+
+		if (theme->cursors == NULL) {
+			theme->cursor_count--;
+			free(cursor);
+		} else {
+			theme->cursors[theme->cursor_count - 1] = cursor;
+		}
+	}
+
+	xcursor_images_destroy(images);
+}
+
+/** Load a cursor theme to memory shared with the compositor
+ *
+ * \param name The name of the cursor theme to load. If %NULL, the default
+ * theme will be loaded.
+ * \param size Desired size of the cursor images.
+ * \param shm The compositor's shm interface.
+ *
+ * \return An object representing the theme that should be destroyed with
+ * wl_cursor_theme_destroy() or %NULL on error. If no theme with the given
+ * name exists, a default theme will be loaded.
+ */
+WL_EXPORT struct wl_cursor_theme *
+wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm)
+{
+	struct wl_cursor_theme *theme;
+
+	theme = malloc(sizeof *theme);
+	if (!theme)
+		return NULL;
+
+	if (!name)
+		name = "default";
+
+	theme->size = size;
+	theme->cursor_count = 0;
+	theme->cursors = NULL;
+
+	theme->pool = shm_pool_create(shm, size * size * 4);
+	if (!theme->pool)
+		goto out_error_pool;
+
+	xcursor_load_theme(name, size, load_callback, theme);
+
+	if (theme->cursor_count == 0)
+		xcursor_load_theme(NULL, size, load_callback, theme);
+
+	if (theme->cursor_count == 0)
+		load_fallback_theme(theme);
+
+	return theme;
+
+out_error_pool:
+	free(theme);
+	return NULL;
+}
+
+/** Destroys a cursor theme object
+ *
+ * \param theme The cursor theme to be destroyed
+ */
+WL_EXPORT void
+wl_cursor_theme_destroy(struct wl_cursor_theme *theme)
+{
+	unsigned int i;
+
+	for (i = 0; i < theme->cursor_count; i++)
+		wl_cursor_destroy(theme->cursors[i]);
+
+	shm_pool_destroy(theme->pool);
+
+	free(theme->cursors);
+	free(theme);
+}
+
+/** Get the cursor for a given name from a cursor theme
+ *
+ * \param theme The cursor theme
+ * \param name Name of the desired cursor
+ * \return The theme's cursor of the given name or %NULL if there is no
+ * such cursor
+ */
+WL_EXPORT struct wl_cursor *
+wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
+			   const char *name)
+{
+	unsigned int i;
+
+	for (i = 0; i < theme->cursor_count; i++) {
+		if (strcmp(name, theme->cursors[i]->name) == 0)
+			return theme->cursors[i];
+	}
+
+	return NULL;
+}
+
+/** Find the frame for a given elapsed time in a cursor animation
+ *  as well as the time left until next cursor change.
+ *
+ * \param cursor The cursor
+ * \param time Elapsed time in ms since the beginning of the animation
+ * \param duration pointer to uint32_t to store time left for this image or
+ *                 zero if the cursor won't change.
+ *
+ * \return The index of the image that should be displayed for the
+ * given time in the cursor animation.
+ */
+WL_EXPORT int
+wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time,
+			     uint32_t *duration)
+{
+	struct cursor *cur = (struct cursor *) cursor;
+	uint32_t t;
+	int i;
+
+	if (cur->cursor.image_count == 1 || cur->total_delay == 0) {
+		if (duration)
+			*duration = 0;
+		return 0;
+	}
+
+	i = 0;
+	t = time % cur->total_delay;
+
+	/* If there is a 0 delay in the image set then this
+	 * loop breaks on it and we display that cursor until
+	 * time % cursor->total_delay wraps again.
+	 * Since a 0 delay is silly, and we've never actually
+	 * seen one in a cursor file, we haven't bothered to
+	 * "fix" this.
+	 */
+	while (t - cur->cursor.images[i]->delay < t)
+		t -= cur->cursor.images[i++]->delay;
+
+	if (!duration)
+		return i;
+
+	/* Make sure we don't accidentally tell the caller this is
+	 * a static cursor image.
+	 */
+	if (t >= cur->cursor.images[i]->delay)
+		*duration = 1;
+	else
+		*duration = cur->cursor.images[i]->delay - t;
+
+	return i;
+}
+
+/** Find the frame for a given elapsed time in a cursor animation
+ *
+ * \param cursor The cursor
+ * \param time Elapsed time in ms since the beginning of the animation
+ *
+ * \return The index of the image that should be displayed for the
+ * given time in the cursor animation.
+ */
+WL_EXPORT int
+wl_cursor_frame(struct wl_cursor *cursor, uint32_t time)
+{
+	return wl_cursor_frame_and_duration(cursor, time, NULL);
+}
diff --git a/subprojects/wayland/cursor/wayland-cursor.h b/subprojects/wayland/cursor/wayland-cursor.h
new file mode 100644
index 0000000000000000000000000000000000000000..915a1100c108e98169087364265bee6126d4b3fd
--- /dev/null
+++ b/subprojects/wayland/cursor/wayland-cursor.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_CURSOR_H
+#define WAYLAND_CURSOR_H
+
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct wl_cursor_theme;
+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 {
+	/** 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;
+};
+
+struct wl_cursor_theme *
+wl_cursor_theme_load(const char *name, int size, struct wl_shm *shm);
+
+void
+wl_cursor_theme_destroy(struct wl_cursor_theme *theme);
+
+struct wl_cursor *
+wl_cursor_theme_get_cursor(struct wl_cursor_theme *theme,
+			   const char *name);
+
+struct wl_buffer *
+wl_cursor_image_get_buffer(struct wl_cursor_image *image);
+
+int
+wl_cursor_frame(struct wl_cursor *cursor, uint32_t time);
+
+int
+wl_cursor_frame_and_duration(struct wl_cursor *cursor, uint32_t time,
+			     uint32_t *duration);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/cursor/xcursor.c b/subprojects/wayland/cursor/xcursor.c
new file mode 100644
index 0000000000000000000000000000000000000000..0d5761f215ed0943ddb1a489f03b66f54b5f69b5
--- /dev/null
+++ b/subprojects/wayland/cursor/xcursor.c
@@ -0,0 +1,830 @@
+/*
+ * Copyright © 2002 Keith Packard
+ *
+ * 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.
+ */
+
+#define _GNU_SOURCE
+#include "xcursor.h"
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+
+/*
+ * Cursor files start with a header.  The header
+ * contains a magic number, a version number and a
+ * table of contents which has type and offset information
+ * for the remaining tables in the file.
+ *
+ * File minor versions increment for compatible changes
+ * File major versions increment for incompatible changes (never, we hope)
+ *
+ * Chunks of the same type are always upward compatible.  Incompatible
+ * changes are made with new chunk types; the old data can remain under
+ * the old type.  Upward compatible changes can add header data as the
+ * header lengths are specified in the file.
+ *
+ *  File:
+ *	FileHeader
+ *	LISTofChunk
+ *
+ *  FileHeader:
+ *	CARD32		magic	    magic number
+ *	CARD32		header	    bytes in file header
+ *	CARD32		version	    file version
+ *	CARD32		ntoc	    number of toc entries
+ *	LISTofFileToc   toc	    table of contents
+ *
+ *  FileToc:
+ *	CARD32		type	    entry type
+ *	CARD32		subtype	    entry subtype (size for images)
+ *	CARD32		position    absolute file position
+ */
+
+#define XCURSOR_MAGIC 0x72756358 /* "Xcur" LSBFirst */
+
+/*
+ * This version number is stored in cursor files; changes to the
+ * file format require updating this version number
+ */
+#define XCURSOR_FILE_MAJOR 1
+#define XCURSOR_FILE_MINOR 0
+#define XCURSOR_FILE_VERSION ((XCURSOR_FILE_MAJOR << 16) | (XCURSOR_FILE_MINOR))
+#define XCURSOR_FILE_HEADER_LEN (4 * 4)
+#define XCURSOR_FILE_TOC_LEN (3 * 4)
+
+struct xcursor_file_toc {
+	uint32_t type; /* chunk type */
+	uint32_t subtype; /* subtype (size for images) */
+	uint32_t position; /* absolute position in file */
+};
+
+struct xcursor_file_header {
+	uint32_t magic; /* magic number */
+	uint32_t header; /* byte length of header */
+	uint32_t version; /* file version number */
+	uint32_t ntoc; /* number of toc entries */
+	struct xcursor_file_toc *tocs; /* table of contents */
+};
+
+/*
+ * The rest of the file is a list of chunks, each tagged by type
+ * and version.
+ *
+ *  Chunk:
+ *	ChunkHeader
+ *	<extra type-specific header fields>
+ *	<type-specific data>
+ *
+ *  ChunkHeader:
+ *	CARD32	    header	bytes in chunk header + type header
+ *	CARD32	    type	chunk type
+ *	CARD32	    subtype	chunk subtype
+ *	CARD32	    version	chunk type version
+ */
+
+#define XCURSOR_CHUNK_HEADER_LEN (4 * 4)
+
+struct xcursor_chunk_header {
+	uint32_t header; /* bytes in chunk header */
+	uint32_t type; /* chunk type */
+	uint32_t subtype; /* chunk subtype (size for images) */
+	uint32_t version; /* version of this type */
+};
+
+/*
+ * Each cursor image occupies a separate image chunk.
+ * The length of the image header follows the chunk header
+ * so that future versions can extend the header without
+ * breaking older applications
+ *
+ *  Image:
+ *	ChunkHeader	header	chunk header
+ *	CARD32		width	actual width
+ *	CARD32		height	actual height
+ *	CARD32		xhot	hot spot x
+ *	CARD32		yhot	hot spot y
+ *	CARD32		delay	animation delay
+ *	LISTofCARD32	pixels	ARGB pixels
+ */
+
+#define XCURSOR_IMAGE_TYPE 0xfffd0002
+#define XCURSOR_IMAGE_VERSION 1
+#define XCURSOR_IMAGE_HEADER_LEN (XCURSOR_CHUNK_HEADER_LEN + (5*4))
+#define XCURSOR_IMAGE_MAX_SIZE 0x7fff /* 32767x32767 max cursor size */
+
+/*
+ * From libXcursor/src/file.c
+ */
+
+static struct xcursor_image *
+xcursor_image_create(int width, int height)
+{
+	struct xcursor_image *image;
+
+	if (width < 0 || height < 0)
+		return NULL;
+	if (width > XCURSOR_IMAGE_MAX_SIZE || height > XCURSOR_IMAGE_MAX_SIZE)
+		return NULL;
+
+	image = malloc(sizeof(struct xcursor_image) +
+		       width * height * sizeof(uint32_t));
+	if (!image)
+		return NULL;
+	image->version = XCURSOR_IMAGE_VERSION;
+	image->pixels = (uint32_t *) (image + 1);
+	image->size = width > height ? width : height;
+	image->width = width;
+	image->height = height;
+	image->delay = 0;
+	return image;
+}
+
+static void
+xcursor_image_destroy(struct xcursor_image *image)
+{
+	free(image);
+}
+
+static struct xcursor_images *
+xcursor_images_create(int size)
+{
+	struct xcursor_images *images;
+
+	images = malloc(sizeof(struct xcursor_images) +
+			size * sizeof(struct xcursor_image *));
+	if (!images)
+		return NULL;
+	images->nimage = 0;
+	images->images = (struct xcursor_image **) (images + 1);
+	images->name = NULL;
+	return images;
+}
+
+void
+xcursor_images_destroy(struct xcursor_images *images)
+{
+	int n;
+
+	if (!images)
+		return;
+
+	for (n = 0; n < images->nimage; n++)
+		xcursor_image_destroy(images->images[n]);
+	free(images->name);
+	free(images);
+}
+
+static bool
+xcursor_read_uint(FILE *file, uint32_t *u)
+{
+	unsigned char bytes[4];
+
+	if (!file || !u)
+		return false;
+
+	if (fread(bytes, 1, 4, file) != 4)
+		return false;
+
+	*u = ((uint32_t)(bytes[0]) << 0) |
+		 ((uint32_t)(bytes[1]) << 8) |
+		 ((uint32_t)(bytes[2]) << 16) |
+		 ((uint32_t)(bytes[3]) << 24);
+	return true;
+}
+
+static void
+xcursor_file_header_destroy(struct xcursor_file_header *file_header)
+{
+	free(file_header);
+}
+
+static struct xcursor_file_header *
+xcursor_file_header_create(uint32_t ntoc)
+{
+	struct xcursor_file_header *file_header;
+
+	if (ntoc > 0x10000)
+		return NULL;
+	file_header = malloc(sizeof(struct xcursor_file_header) +
+			    ntoc * sizeof(struct xcursor_file_toc));
+	if (!file_header)
+		return NULL;
+	file_header->magic = XCURSOR_MAGIC;
+	file_header->header = XCURSOR_FILE_HEADER_LEN;
+	file_header->version = XCURSOR_FILE_VERSION;
+	file_header->ntoc = ntoc;
+	file_header->tocs = (struct xcursor_file_toc *) (file_header + 1);
+	return file_header;
+}
+
+static struct xcursor_file_header *
+xcursor_read_file_header(FILE *file)
+{
+	struct xcursor_file_header head, *file_header;
+	uint32_t skip;
+	unsigned int n;
+
+	if (!file)
+		return NULL;
+
+	if (!xcursor_read_uint(file, &head.magic))
+		return NULL;
+	if (head.magic != XCURSOR_MAGIC)
+		return NULL;
+	if (!xcursor_read_uint(file, &head.header))
+		return NULL;
+	if (!xcursor_read_uint(file, &head.version))
+		return NULL;
+	if (!xcursor_read_uint(file, &head.ntoc))
+		return NULL;
+	skip = head.header - XCURSOR_FILE_HEADER_LEN;
+	if (skip)
+		if (fseek(file, skip, SEEK_CUR) == EOF)
+			return NULL;
+	file_header = xcursor_file_header_create(head.ntoc);
+	if (!file_header)
+		return NULL;
+	file_header->magic = head.magic;
+	file_header->header = head.header;
+	file_header->version = head.version;
+	file_header->ntoc = head.ntoc;
+	for (n = 0; n < file_header->ntoc; n++) {
+		if (!xcursor_read_uint(file, &file_header->tocs[n].type))
+			break;
+		if (!xcursor_read_uint(file, &file_header->tocs[n].subtype))
+			break;
+		if (!xcursor_read_uint(file, &file_header->tocs[n].position))
+			break;
+	}
+	if (n != file_header->ntoc) {
+		xcursor_file_header_destroy(file_header);
+		return NULL;
+	}
+	return file_header;
+}
+
+static bool
+xcursor_seek_to_toc(FILE *file,
+		    struct xcursor_file_header *file_header,
+		    int toc)
+{
+	if (!file || !file_header ||
+	    fseek(file, file_header->tocs[toc].position, SEEK_SET) == EOF)
+		return false;
+	return true;
+}
+
+static bool
+xcursor_file_read_chunk_header(FILE *file,
+			       struct xcursor_file_header *file_header,
+			       int toc,
+			       struct xcursor_chunk_header *chunk_header)
+{
+	if (!file || !file_header || !chunk_header)
+		return false;
+	if (!xcursor_seek_to_toc(file, file_header, toc))
+		return false;
+	if (!xcursor_read_uint(file, &chunk_header->header))
+		return false;
+	if (!xcursor_read_uint(file, &chunk_header->type))
+		return false;
+	if (!xcursor_read_uint(file, &chunk_header->subtype))
+		return false;
+	if (!xcursor_read_uint(file, &chunk_header->version))
+		return false;
+	/* sanity check */
+	if (chunk_header->type != file_header->tocs[toc].type ||
+	    chunk_header->subtype != file_header->tocs[toc].subtype)
+		return false;
+	return true;
+}
+
+static uint32_t
+dist(uint32_t a, uint32_t b)
+{
+	return a > b ? a - b : b - a;
+}
+
+static uint32_t
+xcursor_file_best_size(struct xcursor_file_header *file_header,
+		       uint32_t size, int *nsizesp)
+{
+	unsigned int n;
+	int nsizes = 0;
+	uint32_t best_size = 0;
+	uint32_t this_size;
+
+	if (!file_header || !nsizesp)
+		return 0;
+
+	for (n = 0; n < file_header->ntoc; n++) {
+		if (file_header->tocs[n].type != XCURSOR_IMAGE_TYPE)
+			continue;
+		this_size = file_header->tocs[n].subtype;
+		if (!best_size || dist(this_size, size) < dist(best_size, size)) {
+			best_size = this_size;
+			nsizes = 1;
+		} else if (this_size == best_size) {
+			nsizes++;
+		}
+	}
+	*nsizesp = nsizes;
+	return best_size;
+}
+
+static int
+xcursor_find_image_toc(struct xcursor_file_header *file_header,
+		       uint32_t size, int count)
+{
+	unsigned int toc;
+	uint32_t this_size;
+
+	if (!file_header)
+		return 0;
+
+	for (toc = 0; toc < file_header->ntoc; toc++) {
+		if (file_header->tocs[toc].type != XCURSOR_IMAGE_TYPE)
+			continue;
+		this_size = file_header->tocs[toc].subtype;
+		if (this_size != size)
+			continue;
+		if (!count)
+			break;
+		count--;
+	}
+	if (toc == file_header->ntoc)
+		return -1;
+	return toc;
+}
+
+static struct xcursor_image *
+xcursor_read_image(FILE *file,
+		   struct xcursor_file_header *file_header,
+		   int toc)
+{
+	struct xcursor_chunk_header chunk_header;
+	struct xcursor_image head;
+	struct xcursor_image *image;
+	int n;
+	uint32_t *p;
+
+	if (!file || !file_header)
+		return NULL;
+
+	if (!xcursor_file_read_chunk_header(file, file_header, toc, &chunk_header))
+		return NULL;
+	if (!xcursor_read_uint(file, &head.width))
+		return NULL;
+	if (!xcursor_read_uint(file, &head.height))
+		return NULL;
+	if (!xcursor_read_uint(file, &head.xhot))
+		return NULL;
+	if (!xcursor_read_uint(file, &head.yhot))
+		return NULL;
+	if (!xcursor_read_uint(file, &head.delay))
+		return NULL;
+	/* sanity check data */
+	if (head.width > XCURSOR_IMAGE_MAX_SIZE ||
+	    head.height > XCURSOR_IMAGE_MAX_SIZE)
+		return NULL;
+	if (head.width == 0 || head.height == 0)
+		return NULL;
+	if (head.xhot > head.width || head.yhot > head.height)
+		return NULL;
+
+	/* Create the image and initialize it */
+	image = xcursor_image_create(head.width, head.height);
+	if (image == NULL)
+		return NULL;
+	if (chunk_header.version < image->version)
+		image->version = chunk_header.version;
+	image->size = chunk_header.subtype;
+	image->xhot = head.xhot;
+	image->yhot = head.yhot;
+	image->delay = head.delay;
+	n = image->width * image->height;
+	p = image->pixels;
+	while (n--) {
+		if (!xcursor_read_uint(file, p)) {
+			xcursor_image_destroy(image);
+			return NULL;
+		}
+		p++;
+	}
+	return image;
+}
+
+static struct xcursor_images *
+xcursor_xc_file_load_images(FILE *file, int size)
+{
+	struct xcursor_file_header *file_header;
+	uint32_t best_size;
+	int nsize;
+	struct xcursor_images *images;
+	int n;
+	int toc;
+
+	if (!file || size < 0)
+		return NULL;
+	file_header = xcursor_read_file_header(file);
+	if (!file_header)
+		return NULL;
+	best_size = xcursor_file_best_size(file_header, (uint32_t) size, &nsize);
+	if (!best_size) {
+		xcursor_file_header_destroy(file_header);
+		return NULL;
+	}
+	images = xcursor_images_create(nsize);
+	if (!images) {
+		xcursor_file_header_destroy(file_header);
+		return NULL;
+	}
+	for (n = 0; n < nsize; n++) {
+		toc = xcursor_find_image_toc(file_header, best_size, n);
+		if (toc < 0)
+			break;
+		images->images[images->nimage] = xcursor_read_image(file, file_header,
+								    toc);
+		if (!images->images[images->nimage])
+			break;
+		images->nimage++;
+	}
+	xcursor_file_header_destroy(file_header);
+	if (images->nimage != nsize) {
+		xcursor_images_destroy(images);
+		images = NULL;
+	}
+	return images;
+}
+
+/*
+ * From libXcursor/src/library.c
+ */
+
+#ifndef ICONDIR
+#define ICONDIR "/usr/X11R6/lib/X11/icons"
+#endif
+
+#ifndef XCURSORPATH
+#define XCURSORPATH "~/.icons:/usr/share/icons:/usr/share/pixmaps:~/.cursors:/usr/share/cursors/xorg-x11:"ICONDIR
+#endif
+
+#define XDG_DATA_HOME_FALLBACK "~/.local/share"
+#define CURSORDIR "/icons"
+
+/** Get search path for cursor themes
+ *
+ * This function builds the list of directories to look for cursor
+ * themes in.  The format is PATH-like: directories are separated by
+ * colons.
+ *
+ * The memory block returned by this function is allocated on the heap
+ * and must be freed by the caller.
+ */
+static char *
+xcursor_library_path(void)
+{
+	const char *env_var, *suffix;
+	char *path;
+	size_t path_size;
+
+	env_var = getenv("XCURSOR_PATH");
+	if (env_var)
+		return strdup(env_var);
+
+	env_var = getenv("XDG_DATA_HOME");
+	if (!env_var || env_var[0] != '/')
+		env_var = XDG_DATA_HOME_FALLBACK;
+
+	suffix = CURSORDIR ":" XCURSORPATH;
+	path_size = strlen(env_var) + strlen(suffix) + 1;
+	path = malloc(path_size);
+	if (!path)
+		return NULL;
+	snprintf(path, path_size, "%s%s", env_var, suffix);
+	return path;
+}
+
+static char *
+xcursor_build_theme_dir(const char *dir, const char *theme)
+{
+	const char *colon;
+	const char *tcolon;
+	char *full;
+	const char *home, *homesep;
+	int dirlen;
+	int homelen;
+	int themelen;
+	size_t full_size;
+
+	if (!dir || !theme)
+		return NULL;
+
+	colon = strchr(dir, ':');
+	if (!colon)
+		colon = dir + strlen(dir);
+
+	dirlen = colon - dir;
+
+	tcolon = strchr(theme, ':');
+	if (!tcolon)
+		tcolon = theme + strlen(theme);
+
+	themelen = tcolon - theme;
+
+	home = "";
+	homelen = 0;
+	homesep = "";
+	if (*dir == '~') {
+		home = getenv("HOME");
+		if (!home)
+			return NULL;
+		homelen = strlen(home);
+		homesep = "/";
+		dir++;
+		dirlen--;
+	}
+
+	/*
+	 * add space for any needed directory separators, one per component,
+	 * and one for the trailing null
+	 */
+	full_size = 1 + homelen + 1 + dirlen + 1 + themelen + 1;
+	full = malloc(full_size);
+	if (!full)
+		return NULL;
+	snprintf(full, full_size, "%s%s%.*s/%.*s", home, homesep,
+		 dirlen, dir, themelen, theme);
+	return full;
+}
+
+static char *
+xcursor_build_fullname(const char *dir, const char *subdir, const char *file)
+{
+	char *full;
+	size_t full_size;
+	int ret;
+
+	if (!dir || !subdir || !file)
+		return NULL;
+
+	full_size = strlen(dir) + 1 + strlen(subdir) + 1 + strlen(file) + 1;
+	full = malloc(full_size);
+	if (!full)
+		return NULL;
+	ret = snprintf(full, full_size, "%s/%s/%s", dir, subdir, file);
+	if (ret < 0) {
+		free(full);
+		return NULL;
+	}
+	return full;
+}
+
+static const char *
+xcursor_next_path(const char *path)
+{
+	char *colon = strchr(path, ':');
+
+	if (!colon)
+		return NULL;
+	return colon + 1;
+}
+
+static bool
+xcursor_white(char c)
+{
+	return c == ' ' || c == '\t' || c == '\n';
+}
+
+static bool
+xcursor_sep(char c)
+{
+	return c == ';' || c == ',';
+}
+
+static char *
+xcursor_theme_inherits(const char *full)
+{
+	char *line = NULL;
+	size_t line_size = 0;
+	char *result = NULL;
+	FILE *f;
+
+	if (!full)
+		return NULL;
+
+	f = fopen(full, "r");
+	if (!f)
+		return NULL;
+
+	while (getline(&line, &line_size, f) >= 0) {
+		const char *l;
+		char *r;
+
+		if (strncmp(line, "Inherits", 8))
+			continue;
+
+		l = line + 8;
+		while (*l == ' ')
+			l++;
+		if (*l != '=')
+			continue;
+		l++;
+		while (*l == ' ')
+			l++;
+		result = malloc(strlen(l) + 1);
+		if (!result)
+			break;
+
+		r = result;
+		while (*l) {
+			while (xcursor_sep(*l) || xcursor_white(*l))
+				l++;
+			if (!*l)
+				break;
+			if (r != result)
+				*r++ = ':';
+			while (*l && !xcursor_white(*l) && !xcursor_sep(*l))
+				*r++ = *l++;
+		}
+		*r++ = '\0';
+
+		break;
+	}
+
+	fclose(f);
+	free(line);
+
+	return result;
+}
+
+static void
+load_all_cursors_from_dir(const char *path, int size,
+			  void (*load_callback)(struct xcursor_images *, void *),
+			  void *user_data)
+{
+	FILE *f;
+	DIR *dir = opendir(path);
+	struct dirent *ent;
+	char *full;
+	struct xcursor_images *images;
+
+	if (!dir)
+		return;
+
+	for (ent = readdir(dir); ent; ent = readdir(dir)) {
+#ifdef _DIRENT_HAVE_D_TYPE
+		if (ent->d_type != DT_UNKNOWN &&
+		    ent->d_type != DT_REG &&
+		    ent->d_type != DT_LNK)
+			continue;
+#endif
+
+		full = xcursor_build_fullname(path, "", ent->d_name);
+		if (!full)
+			continue;
+
+		f = fopen(full, "r");
+		if (!f) {
+			free(full);
+			continue;
+		}
+
+		images = xcursor_xc_file_load_images(f, size);
+
+		if (images) {
+			images->name = strdup(ent->d_name);
+			load_callback(images, user_data);
+		}
+
+		fclose(f);
+		free(full);
+	}
+
+	closedir(dir);
+}
+
+struct xcursor_nodelist {
+	size_t nodelen;
+	const char *node;
+	struct xcursor_nodelist *next;
+};
+
+static bool
+nodelist_contains(struct xcursor_nodelist *nodelist, const char *s, size_t ss)
+{
+	struct xcursor_nodelist *vi;
+
+	for (vi = nodelist; vi && vi->node; vi = vi->next) {
+		if (vi->nodelen == ss && !strncmp(s, vi->node, vi->nodelen))
+			return true;
+	}
+	return false;
+}
+
+static void
+xcursor_load_theme_protected(const char *theme, int size,
+		   void (*load_callback)(struct xcursor_images *, void *),
+		   void *user_data,
+		   struct xcursor_nodelist *visited_nodes)
+{
+	char *full, *dir;
+	char *inherits = NULL;
+	const char *path, *i;
+	char *xcursor_path;
+	size_t si;
+	struct xcursor_nodelist current_node;
+
+	if (!theme)
+		theme = "default";
+
+	current_node.next = visited_nodes;
+	current_node.node = theme;
+	current_node.nodelen = strlen(theme);
+	visited_nodes = &current_node;
+
+	xcursor_path = xcursor_library_path();
+	for (path = xcursor_path;
+	     path;
+	     path = xcursor_next_path(path)) {
+		dir = xcursor_build_theme_dir(path, theme);
+		if (!dir)
+			continue;
+
+		full = xcursor_build_fullname(dir, "cursors", "");
+		load_all_cursors_from_dir(full, size, load_callback,
+					  user_data);
+		free(full);
+
+		if (!inherits) {
+			full = xcursor_build_fullname(dir, "", "index.theme");
+			inherits = xcursor_theme_inherits(full);
+			free(full);
+		}
+
+		free(dir);
+	}
+
+	for (i = inherits; i; i = xcursor_next_path(i)) {
+		si = strlen(i);
+		if (nodelist_contains(visited_nodes, i, si))
+			continue;
+		xcursor_load_theme_protected(i, size, load_callback, user_data, visited_nodes);
+	}
+
+	free(inherits);
+	free(xcursor_path);
+}
+
+/** Load all the cursor of a theme
+ *
+ * This function loads all the cursor images of a given theme and its
+ * inherited themes. Each cursor is loaded into an struct xcursor_images object
+ * which is passed to the caller's load callback. If a cursor appears
+ * more than once across all the inherited themes, the load callback
+ * will be called multiple times, with possibly different struct xcursor_images
+ * object which have the same name. The user is expected to destroy the
+ * struct xcursor_images objects passed to the callback with
+ * xcursor_images_destroy().
+ *
+ * \param theme The name of theme that should be loaded
+ * \param size The desired size of the cursor images
+ * \param load_callback A callback function that will be called
+ * for each cursor loaded. The first parameter is the struct xcursor_images
+ * object representing the loaded cursor and the second is a pointer
+ * to data provided by the user.
+ * \param user_data The data that should be passed to the load callback
+ */
+void
+xcursor_load_theme(const char *theme, int size,
+		   void (*load_callback)(struct xcursor_images *, void *),
+		   void *user_data)
+{
+	xcursor_load_theme_protected(theme,
+				     size,
+				     load_callback,
+				     user_data,
+				     NULL);
+}
diff --git a/subprojects/wayland/cursor/xcursor.h b/subprojects/wayland/cursor/xcursor.h
new file mode 100644
index 0000000000000000000000000000000000000000..459f8166869e420c1225006a5d7156709a7f81a0
--- /dev/null
+++ b/subprojects/wayland/cursor/xcursor.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright © 2002 Keith Packard
+ *
+ * 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 XCURSOR_H
+#define XCURSOR_H
+
+#include <stdint.h>
+
+struct xcursor_image {
+	uint32_t version; /* version of the image data */
+	uint32_t size; /* nominal size for matching */
+	uint32_t width; /* actual width */
+	uint32_t height; /* actual height */
+	uint32_t xhot; /* hot spot x (must be inside image) */
+	uint32_t yhot; /* hot spot y (must be inside image) */
+	uint32_t delay; /* animation delay to next frame (ms) */
+	uint32_t *pixels; /* pointer to pixels */
+};
+
+/*
+ * Other data structures exposed by the library API
+ */
+struct xcursor_images {
+	int nimage; /* number of images */
+	struct xcursor_image **images; /* array of XcursorImage pointers */
+	char *name; /* name used to load images */
+};
+
+void
+xcursor_images_destroy(struct xcursor_images *images);
+
+void
+xcursor_load_theme(const char *theme, int size,
+		   void (*load_callback)(struct xcursor_images *, void *),
+		   void *user_data);
+#endif
diff --git a/subprojects/wayland/doc/doxygen/.gitignore b/subprojects/wayland/doc/doxygen/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..d68d6fce7035af61ff79ff44383f54405202db88
--- /dev/null
+++ b/subprojects/wayland/doc/doxygen/.gitignore
@@ -0,0 +1,3 @@
+doxygen_sqlite3.db
+html/
+wayland.doxygen
diff --git a/subprojects/wayland/doc/doxygen/dot/wayland-architecture.gv b/subprojects/wayland/doc/doxygen/dot/wayland-architecture.gv
new file mode 100644
index 0000000000000000000000000000000000000000..f2c35075e73839a46df7f58ff6edda5fd0bf0651
--- /dev/null
+++ b/subprojects/wayland/doc/doxygen/dot/wayland-architecture.gv
@@ -0,0 +1,36 @@
+digraph arch_wayland {
+    edge[
+        fontname="DejaVu Sans",
+        dir="both",
+        arrowtail="dot",
+        arrowsize=.5,
+        fontname="DejaVu Sans",
+        fontsize="18",
+    ]
+
+    node[
+        color=none,
+        margin=0,
+        fontname="DejaVu Sans",
+        fontsize="18",
+   ]
+
+    c1 [label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD>Wayland Client</TD></TR></TABLE>>, URL="#c1"]
+    c2 [label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD>Wayland Client</TD></TR></TABLE>>, URL="#c2"]
+
+    comp [tooltip="Wayland Compositor", label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD><BR/>Wayland<BR/>Compositor<BR/><BR/></TD></TR></TABLE>>, URL="#comp"]
+
+    impl [tooltip="KMS evdev Kernel", label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD>KMS</TD><TD>evdev</TD></TR><TR><TD COLSPAN="2">Kernel</TD></TR></TABLE>>, URL="#impl"]
+
+    c1 -> comp [taillabel="â‘¢", labeldistance=2.5, URL="#step_3"];
+    c2 -> comp;
+
+    comp -> c1 [label="â‘¡", URL="#step_2"];
+    comp -> c2;
+
+    comp -> impl [xlabel = "â‘£", URL="#step_4"];
+    comp -> impl [style = invis, label="    "];
+    impl -> comp [xlabel = "â‘ ", URL="#step_1"];
+
+    c1 -> c2 [style=invis];
+}
diff --git a/subprojects/wayland/doc/doxygen/dot/x-architecture.gv b/subprojects/wayland/doc/doxygen/dot/x-architecture.gv
new file mode 100644
index 0000000000000000000000000000000000000000..b223d1dcad44ff3578d09e8fd548dbda32e265d7
--- /dev/null
+++ b/subprojects/wayland/doc/doxygen/dot/x-architecture.gv
@@ -0,0 +1,53 @@
+digraph arch_x {
+    edge[
+        fontname="DejaVu Sans",
+        dir="both",
+        arrowtail="dot",
+        arrowsize=.5,
+        fontname="DejaVu Sans",
+        fontsize="18",
+    ]
+
+    node[
+        shape="none",
+        color=none,
+        margin=0,
+        fontname="DejaVu Sans",
+        fontsize="18",
+    ]
+
+    {
+        rank=same;
+        c1 [label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD>X Client</TD></TR></TABLE>>, URL="#c1"]
+        c3 [label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD>X Client</TD></TR></TABLE>>, URL="#c3"]
+    }
+    c2 [label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD>X Client</TD></TR></TABLE>>, URL="#c2"]
+
+    {
+        rank=same;
+        xserver [tooltip="X Server", label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD><BR/>X Server<BR/><BR/></TD></TR></TABLE>>, URL="#xserver"]
+        comp [tooltip="Compositor", label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD><BR/>Compositor<BR/><BR/></TD></TR></TABLE>>, URL="#comp"]
+    }
+
+    impl [tooltip="KMS evdev Kernel", label=<<TABLE STYLE="rounded" BGCOLOR="#ffbc00"><TR><TD>KMS</TD><TD>evdev</TD></TR><TR><TD COLSPAN="2">Kernel</TD></TR></TABLE>>, URL="#impl"]
+
+    c1 -> xserver [taillabel="â‘¢", labeldistance=2, URL="#step_3"];
+    c2 -> xserver;
+    c3 -> xserver;
+
+    xserver -> c1 [taillabel="â‘¡", labeldistance=2, URL="#step_2"];
+    xserver -> c2;
+    xserver -> c3;
+
+    xserver -> impl [taillabel="â‘¥", labeldistance=1.75, URL="#step_6"];
+    xserver -> impl [style=invis, label="    "];
+    impl -> xserver [taillabel="â‘ ", labeldistance=1.75, URL="#step_1"];
+
+    xserver -> comp [style=invis];
+    xserver -> comp [taillabel="â‘£", labeldistance=1.75, labelangle=-45, URL="#step_4"];
+    comp -> xserver [taillabel="⑤", URL="#step_5"];
+    comp -> xserver [style=invis]
+
+    c1 -> c2 [style=invis];
+    c3 -> c2 [style=invis];
+ }
diff --git a/subprojects/wayland/doc/doxygen/gen-doxygen.py b/subprojects/wayland/doc/doxygen/gen-doxygen.py
new file mode 100755
index 0000000000000000000000000000000000000000..1bb07e571f123c720317799a53dd9f9a770b7353
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/doc/doxygen/mainpage.dox b/subprojects/wayland/doc/doxygen/mainpage.dox
new file mode 100644
index 0000000000000000000000000000000000000000..352f69beae5001833383eda0d1deea7df838c84c
--- /dev/null
+++ b/subprojects/wayland/doc/doxygen/mainpage.dox
@@ -0,0 +1,23 @@
+/**
+ * @mainpage
+ * Wayland protocol API documentation.
+ *
+ * This documentation is available for the Server- and the Client-side APIs.
+ *
+ * - <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
+ * <a href="https://wayland.freedesktop.org/docs/html">Wayland Book</a>
+ *
+ * @section ifaces Interfaces
+ * For the list of available interfaces, please see the
+ * <a href="modules.html">modules</a> list.
+ *
+ * @section protocols Protocols
+ * For the list of protocols, please see the
+ * <a href="pages.html">Related Pages</a>.
+ *
+ */
diff --git a/subprojects/wayland/doc/doxygen/meson.build b/subprojects/wayland/doc/doxygen/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..611262064a46e28662f39e59d3bde90aa683b090
--- /dev/null
+++ b/subprojects/wayland/doc/doxygen/meson.build
@@ -0,0 +1,117 @@
+# 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.project_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
+		stamp = join_paths(meson.current_build_dir(), '@0@.stamp'.format(t_name))
+		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=@0@'.format(stamp),
+				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
+stamp = join_paths(meson.current_build_dir(), 'man3.stamp')
+custom_target(
+	'man-pages-3',
+	command: [
+		gen_doxygen,
+		'--builddir=@OUTDIR@',
+		'--output-format=man3',
+		'--stamp=@0@'.format(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/subprojects/wayland/doc/doxygen/wayland.doxygen.in b/subprojects/wayland/doc/doxygen/wayland.doxygen.in
new file mode 100644
index 0000000000000000000000000000000000000000..60c5fbbb8e8a2003e553cf5157c0b73d0e990248
--- /dev/null
+++ b/subprojects/wayland/doc/doxygen/wayland.doxygen.in
@@ -0,0 +1,23 @@
+# Wayland-specific overrides
+PROJECT_NAME           = "Wayland"
+PROJECT_NUMBER         = @VERSION@
+OUTPUT_DIRECTORY       = @top_builddir@/doc/doxygen
+JAVADOC_AUTOBRIEF      = YES
+TAB_SIZE               = 8
+QUIET                  = YES
+HTML_TIMESTAMP         = YES
+GENERATE_LATEX         = NO
+MAN_LINKS              = NO
+PREDEFINED             = WL_EXPORT=              \
+                         WL_PRINTF(x,y)=
+MACRO_EXPANSION        = YES
+EXPAND_ONLY_PREDEF     = YES
+DOT_MULTI_TARGETS      = YES
+ALIASES                += comment{1}="/* \1 *<!-- -->/"
+OPTIMIZE_OUTPUT_FOR_C  = YES
+EXTRACT_ALL            = YES
+EXTRACT_STATIC         = YES
+# These must be set in the Makefile
+GENERATE_HTML          = NO
+GENERATE_XML           = NO
+GENERATE_MAN           = NO
diff --git a/subprojects/wayland/doc/doxygen/xml/Client/meson.build b/subprojects/wayland/doc/doxygen/xml/Client/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..849c30da68192b27239755084e56852b6c0e1f29
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/doc/doxygen/xml/Server/meson.build b/subprojects/wayland/doc/doxygen/xml/Server/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..4792c1bcdfc42151ff2e0d516ec64e7bf039ea87
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/doc/doxygen/xml/meson.build b/subprojects/wayland/doc/doxygen/xml/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..6d55c53afef2819be5097887e9c8e426e242afe0
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/doc/meson.build b/subprojects/wayland/doc/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..44fda2abf868235faa8fe67150e474f063710598
--- /dev/null
+++ b/subprojects/wayland/doc/meson.build
@@ -0,0 +1,41 @@
+if not get_option('libraries')
+	error('-Ddocumentation=true requires -Dlibraries=true')
+endif
+
+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, check: false)
+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/subprojects/wayland/doc/publican/.gitignore b/subprojects/wayland/doc/publican/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..c1656e70da7a8cf6b48cac76a29ef92276dfa91f
--- /dev/null
+++ b/subprojects/wayland/doc/publican/.gitignore
@@ -0,0 +1,3 @@
+Wayland
+en-US/
+publican-copy.cfg
diff --git a/subprojects/wayland/doc/publican/doxygen-to-publican.xsl b/subprojects/wayland/doc/publican/doxygen-to-publican.xsl
new file mode 100644
index 0000000000000000000000000000000000000000..e13dcd7684fe3a0352745c54355befda0d48f942
--- /dev/null
+++ b/subprojects/wayland/doc/publican/doxygen-to-publican.xsl
@@ -0,0 +1,147 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" encoding="UTF-8" indent="yes" />
+<xsl:param name="which" />
+
+<xsl:template match="/">
+  <xsl:apply-templates select="/doxygen/compounddef[@kind!='file' and @kind!='dir']" />
+
+  <section id="{$which}-Functions">
+    <title>Functions</title>
+    <para />
+    <variablelist>
+      <xsl:apply-templates select="/doxygen/compounddef[@kind='file']/sectiondef/memberdef" />
+    </variablelist>
+  </section>
+
+</xsl:template>
+
+<xsl:template match="parameteritem">
+    <varlistentry>
+        <term>
+          <xsl:apply-templates select="parameternamelist/parametername"/>
+        </term>
+      <listitem>
+        <simpara><xsl:apply-templates select="parameterdescription"/></simpara>
+      </listitem>
+    </varlistentry>
+</xsl:template>
+
+<xsl:template match="parameterlist">
+  <xsl:if test="parameteritem">
+      <variablelist>
+        <xsl:apply-templates select="parameteritem" />
+      </variablelist>
+  </xsl:if>
+</xsl:template>
+
+<xsl:template match="ref">
+  <link linkend="{$which}-{@refid}"><xsl:value-of select="." /></link>
+</xsl:template>
+
+<xsl:template match="simplesect[@kind='return']">
+  <variablelist>
+    <varlistentry>
+      <term>Returns:</term>
+      <listitem>
+        <simpara><xsl:apply-templates /></simpara>
+      </listitem>
+    </varlistentry>
+  </variablelist>
+</xsl:template>
+
+<xsl:template match="simplesect[@kind='see']">
+  See also: <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="simplesect[@kind='since']">
+  Since: <xsl:apply-templates />
+</xsl:template>
+
+<xsl:template match="simplesect[@kind='note']">
+  <emphasis>Note: <xsl:apply-templates /></emphasis>
+</xsl:template>
+
+<xsl:template match="sp">
+  <xsl:text> </xsl:text>
+</xsl:template>
+
+<xsl:template match="programlisting">
+  <programlisting><xsl:apply-templates /></programlisting>
+</xsl:template>
+
+<xsl:template match="itemizedlist">
+  <itemizedlist><xsl:apply-templates select="listitem" /></itemizedlist>
+</xsl:template>
+
+<xsl:template match="listitem">
+  <listitem><simpara><xsl:apply-templates /></simpara></listitem>
+</xsl:template>
+
+<!-- stops cross-references in the section titles -->
+<xsl:template match="briefdescription">
+  <xsl:value-of select="." />
+</xsl:template>
+
+<!-- this opens a para for each detaileddescription/para. I could not find a
+     way to extract the right text for the description from the
+     source otherwise. Downside: we can't use para for return value, "see
+     also", etc.  because they're already inside a para. So they're lists.
+
+     It also means we don't control the order of when something is added to
+     the output, it matches the input file
+     -->
+<xsl:template match="detaileddescription/para">
+  <para><xsl:apply-templates /></para>
+</xsl:template>
+
+<xsl:template match="detaileddescription">
+  <xsl:apply-templates select="para" />
+</xsl:template>
+
+<!-- methods -->
+<xsl:template match="memberdef" >
+  <xsl:if test="@kind = 'function' and @static = 'no' and @prot = 'public' or
+                @kind !='function' and normalize-space(briefdescription) != ''">
+    <varlistentry id="{$which}-{@id}">
+        <term>
+          <xsl:value-of select="name"/>
+          <xsl:if test="normalize-space(briefdescription) != ''">
+            - <xsl:apply-templates select="briefdescription" />
+          </xsl:if>
+        </term>
+        <listitem>
+          <synopsis>
+            <xsl:apply-templates select="definition"/><xsl:apply-templates select="argsstring"/>
+          </synopsis>
+          <xsl:apply-templates select="detaileddescription" />
+        </listitem>
+    </varlistentry>
+  </xsl:if>
+</xsl:template>
+
+<!-- classes -->
+<xsl:template match="compounddef" >
+    <section id="{$which}-{@id}">
+        <title>
+            <xsl:value-of select="compoundname" />
+            <xsl:if test="normalize-space(briefdescription) != ''">
+                - <xsl:apply-templates select="briefdescription" />
+            </xsl:if>
+        </title>
+        <xsl:choose>
+          <xsl:when test="normalize-space(detaileddescription) != ''">
+            <xsl:apply-templates select="detaileddescription" />
+          </xsl:when>
+          <xsl:otherwise>
+            <para />
+          </xsl:otherwise>
+        </xsl:choose>
+        <xsl:if test="sectiondef/memberdef[@kind='function' and @static='no']">
+          <variablelist>
+            <xsl:apply-templates select="sectiondef/memberdef" />
+          </variablelist>
+        </xsl:if>
+    </section>
+</xsl:template>
+</xsl:stylesheet>
diff --git a/subprojects/wayland/doc/publican/merge-mapcoords.xsl b/subprojects/wayland/doc/publican/merge-mapcoords.xsl
new file mode 100644
index 0000000000000000000000000000000000000000..7adaca3665bbf93f0c8d6616ce734abebf48b68f
--- /dev/null
+++ b/subprojects/wayland/doc/publican/merge-mapcoords.xsl
@@ -0,0 +1,64 @@
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+  <xsl:param name="basedir"/>
+  <xsl:output method="xml" encoding="utf-8" indent="yes"/>
+  <!-- -->
+  <!-- Template for the root so we can add a DOCTYPE -->
+  <xsl:template match="/">
+    <xsl:text disable-output-escaping="yes"><![CDATA[<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+]]></xsl:text>
+    <xsl:apply-templates select="@*|node()"/>
+  </xsl:template>
+  <!-- -->
+  <xsl:template match="@*|node()">
+    <xsl:copy>
+      <xsl:apply-templates select="@*|node()"/>
+    </xsl:copy>
+  </xsl:template>
+  <!-- -->
+  <!-- suppress existing image map areas -->
+  <xsl:template match="area"/>
+  <!-- -->
+  <xsl:template match="areaspec[area][name(..)='imageobjectco']">
+    <xsl:element name="areaspec">
+      <xsl:apply-templates select="@*"/>
+      <xsl:text>&#xa;</xsl:text>
+      <xsl:variable name="pngfile" select="../imageobject/imagedata/@fileref"/>
+      <xsl:variable name="mapfile" select="concat(substring($pngfile, 1, string-length($pngfile)-3), 'map')"/>
+      <xsl:variable name="maproot" select="document(concat($basedir, '/', $mapfile))"/>
+      <!-- -->
+      <!-- now emit the needed areas -->
+      <xsl:for-each select="area">
+	<xsl:variable name="anchor" select="."/>
+	<xsl:variable name="other" select="($maproot)//area[@href=($anchor)/@x_steal]"/>
+	<xsl:choose>
+	  <xsl:when test="$other">
+	    <xsl:text>&#x9;    </xsl:text>
+	    <xsl:element name="area">
+	      <xsl:attribute name="id">
+		<xsl:value-of select="@id"/>
+	      </xsl:attribute>
+	      <xsl:attribute name="linkends">
+		<xsl:value-of select="@linkends"/>
+	      </xsl:attribute>
+	      <xsl:attribute name="coords">
+		<xsl:value-of select="($other)/@coords"/>
+	      </xsl:attribute>
+	    </xsl:element>
+	  </xsl:when>
+	  <xsl:otherwise>
+	    <xsl:text>&#x9;    </xsl:text>
+	    <xsl:comment>
+	      <xsl:value-of select="concat('Warning: unable to locate area tagged ', ($anchor)/@x_steal)"/>
+	    </xsl:comment>
+	  </xsl:otherwise>
+	</xsl:choose>
+	<xsl:text>&#xa;</xsl:text>
+      </xsl:for-each>
+      <!-- -->
+      <xsl:text>&#x9;  </xsl:text>
+    </xsl:element>
+  </xsl:template>
+</xsl:stylesheet>
diff --git a/subprojects/wayland/doc/publican/meson.build b/subprojects/wayland/doc/publican/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..eac3e9b2931df50401d0e33fd02dbf953b279034
--- /dev/null
+++ b/subprojects/wayland/doc/publican/meson.build
@@ -0,0 +1,32 @@
+merge_mapcoords_xsl = files('merge-mapcoords.xsl')
+
+subdir('sources')
+
+custom_target(
+	'Wayland-docbook-html',
+	command: [
+		xmlto,
+		'--skip-validation',
+		'--stringparam', 'chunker.output.encoding=UTF-8',
+		'--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/subprojects/wayland/doc/publican/protocol-interfaces-to-docbook.xsl b/subprojects/wayland/doc/publican/protocol-interfaces-to-docbook.xsl
new file mode 100644
index 0000000000000000000000000000000000000000..f68216d57e2d86dcde15fe5f9156294625e1bb3e
--- /dev/null
+++ b/subprojects/wayland/doc/publican/protocol-interfaces-to-docbook.xsl
@@ -0,0 +1,51 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" encoding="UTF-8" indent="yes" />
+
+<xsl:template match="/">
+  <!-- insert docbook's DOCTYPE blurb -->
+    <xsl:text disable-output-escaping = "yes"><![CDATA[
+<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+  <!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+]]></xsl:text>
+
+  <section id="sect-Protocol-Interfaces">
+    <title>Interfaces</title>
+    <para>
+      The protocol includes several interfaces which are used for
+      interacting with the server.  Each interface provides requests,
+      events, and errors (which are really just special events) as described
+      above.  Specific compositor implementations may have their own
+      interfaces provided as extensions, but there are several which are
+      always expected to be present.
+    </para>
+
+    <para>
+      Core interfaces:
+      <variablelist>
+        <xsl:apply-templates select="protocol/interface" />
+      </variablelist>
+    </para>
+  </section>
+</xsl:template>
+
+<!-- Interfaces summary -->
+<xsl:template match="interface" >
+<varlistentry>
+  <term>
+    <link linkend="protocol-spec-{@name}">
+      <xsl:value-of select="@name" />
+    </link>
+  </term>
+  <listitem>
+    <simpara>
+      <xsl:value-of select="description/@summary" />
+    </simpara>
+  </listitem>
+</varlistentry>
+</xsl:template>
+
+</xsl:stylesheet>
+<!-- vim: set expandtab shiftwidth=2: -->
diff --git a/subprojects/wayland/doc/publican/protocol-to-docbook.xsl b/subprojects/wayland/doc/publican/protocol-to-docbook.xsl
new file mode 100644
index 0000000000000000000000000000000000000000..79c938bb3a1c6c184feca68654b9da5f8446526a
--- /dev/null
+++ b/subprojects/wayland/doc/publican/protocol-to-docbook.xsl
@@ -0,0 +1,223 @@
+<?xml version="1.0" ?>
+<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
+<xsl:output method="xml" encoding="UTF-8" indent="yes" />
+
+<xsl:template match="/">
+  <!-- insert docbook's DOCTYPE blurb -->
+    <xsl:text disable-output-escaping = "yes"><![CDATA[
+<!DOCTYPE appendix PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+  <!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+]]></xsl:text>
+
+  <appendix id="appe-Wayland-Protocol">
+    <title>Wayland Protocol Specification</title>
+    <xsl:apply-templates select="protocol/copyright" />
+
+    <xsl:apply-templates select="protocol/interface" />
+  </appendix>
+</xsl:template>
+
+<!-- Break text blocks separated by two new lines into paragraphs -->
+<xsl:template name="break">
+     <xsl:param name="text" />
+     <xsl:param name="linebreak" select="'&#10;&#10;'" />
+     <xsl:choose>
+       <xsl:when test="contains($text,$linebreak)">
+         <para>
+           <xsl:value-of select="substring-before($text,$linebreak)" />
+         </para>
+         <xsl:call-template name="break">
+           <xsl:with-param name="text" select="substring-after($text,$linebreak)" />
+         </xsl:call-template>
+       </xsl:when>
+       <xsl:otherwise>
+         <para><xsl:value-of select="$text" /></para>
+       </xsl:otherwise>
+     </xsl:choose>
+</xsl:template>
+
+<!-- Copyright blurb -->
+<xsl:template match="copyright">
+  <para>
+    <literallayout>
+      <xsl:value-of select="." disable-output-escaping="yes"/>
+    </literallayout>
+  </para>
+</xsl:template>
+
+<!-- Interface descriptions -->
+<xsl:template match="interface" >
+  <section id="protocol-spec-{@name}">
+    <title>
+      <xsl:value-of select="@name" />
+      <!-- only show summary if it exists -->
+      <xsl:if test="description/@summary">
+	- <xsl:value-of select="description/@summary" />
+      </xsl:if>
+    </title>
+    <xsl:call-template name="break">
+      <xsl:with-param name="text" select="description" />
+    </xsl:call-template>
+    <xsl:if test="request">
+      <section>
+        <title>Requests provided by <xsl:value-of select="@name" /></title>
+        <xsl:apply-templates select="request" />
+      </section>
+    </xsl:if>
+    <xsl:if test="event">
+      <section>
+        <title>Events provided by <xsl:value-of select="@name" /></title>
+        <xsl:apply-templates select="event" />
+      </section>
+    </xsl:if>
+    <xsl:if test="enum">
+      <section>
+        <title>Enums provided by <xsl:value-of select="@name" /></title>
+      <xsl:apply-templates select="enum" />
+      </section>
+    </xsl:if>
+  </section>
+</xsl:template>
+
+<!-- table contents for enum values -->
+<xsl:template match="entry">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+      <simpara>
+        <xsl:value-of select="@value"/>
+        <xsl:if test="@summary" >
+          - <xsl:value-of select="@summary"/>
+        </xsl:if>
+      </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- table contents for request/event arguments -->
+<xsl:template match="arg">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+        <simpara>
+          <xsl:value-of select="@type"/>
+          <xsl:if test="@summary" >
+            - <xsl:value-of select="@summary"/>
+          </xsl:if>
+        </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- id arguments -->
+<xsl:template match="arg[@type='object' and @interface]">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+        <simpara>
+          <link linkend="protocol-spec-{@interface}">
+            <xsl:value-of select="@interface"/>
+          </link>
+          <xsl:if test="@summary" >
+            - <xsl:value-of select="@summary"/>
+          </xsl:if>
+        </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- new_id arguments -->
+<xsl:template match="arg[@type='new_id' and @interface]">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+        <simpara>
+          id for the new
+          <link linkend="protocol-spec-{@interface}">
+            <xsl:value-of select="@interface"/>
+          </link>
+          <xsl:if test="@summary" >
+            - <xsl:value-of select="@summary"/>
+          </xsl:if>
+        </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- enum and bitfield arguments -->
+<xsl:template match="arg[@enum]">
+  <varlistentry>
+    <term><xsl:value-of select="@name"/></term>
+    <listitem>
+        <simpara>
+          <xsl:choose>
+            <xsl:when test="contains(@enum, '.')">
+              <link linkend="protocol-spec-{substring-before(@enum, '.')}-enum-{substring-after(@enum, '.')}">
+                <xsl:value-of select="substring-before(@enum, '.')"/>
+                <xsl:text>::</xsl:text>
+                <xsl:value-of select="substring-after(@enum, '.')"/>
+              </link>
+            </xsl:when>
+            <xsl:otherwise>
+              <link linkend="protocol-spec-{../../@name}-enum-{@enum}">
+                <xsl:value-of select="../../@name"/>
+                <xsl:text>::</xsl:text>
+                <xsl:value-of select="@enum"/>
+              </link>
+            </xsl:otherwise>
+          </xsl:choose>
+          (<xsl:value-of select="@type"/>)
+          <xsl:if test="@summary" >
+            - <xsl:value-of select="@summary"/>
+          </xsl:if>
+        </simpara>
+    </listitem>
+  </varlistentry>
+</xsl:template>
+
+<!-- Request/event list -->
+<xsl:template match="request|event">
+  <section id="protocol-spec-{../@name}-{name()}-{@name}">
+    <title>
+      <xsl:value-of select="../@name"/>::<xsl:value-of select="@name" />
+      <xsl:if test="description/@summary">
+        - <xsl:value-of select="description/@summary" />
+      </xsl:if>
+    </title>
+    <para>
+      <variablelist>
+        <xsl:apply-templates select="arg"/>
+      </variablelist>
+    </para>
+    <xsl:call-template name="break">
+      <xsl:with-param name="text" select="description" />
+    </xsl:call-template>
+  </section>
+</xsl:template>
+
+<!-- Enumeration -->
+<xsl:template match="enum">
+  <section id="protocol-spec-{../@name}-enum-{@name}">
+    <title>
+      <xsl:value-of select="../@name"/>::<xsl:value-of select="@name" />
+      <xsl:if test="@bitfield">
+        - bitfield
+      </xsl:if>
+      <xsl:if test="description/@summary">
+        - <xsl:value-of select="description/@summary" />
+      </xsl:if>
+    </title>
+    <xsl:call-template name="break">
+      <xsl:with-param name="text" select="description" />
+    </xsl:call-template>
+    <variablelist>
+      <xsl:apply-templates select="entry"/>
+    </variablelist>
+  </section>
+</xsl:template>
+
+</xsl:stylesheet>
+
+<!-- vim: set expandtab shiftwidth=2: -->
diff --git a/subprojects/wayland/doc/publican/sources/Architecture.xml b/subprojects/wayland/doc/publican/sources/Architecture.xml
new file mode 100644
index 0000000000000000000000000000000000000000..b8a104cfb4c0a2d589157c162e45c7f098118cf0
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Architecture.xml
@@ -0,0 +1,344 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-Wayland-Architecture">
+  <title>Wayland Architecture</title>
+  <section id="sect-Wayland-Architecture-wayland_architecture">
+    <title>X vs. Wayland Architecture</title>
+    <para>
+      A good way to understand the Wayland architecture
+      and how it is different from X is to follow an event
+      from the input device to the point where the change
+      it affects appears on screen.
+    </para>
+    <para>
+      This is where we are now with X:
+    </para>
+    <figure>
+      <title>X architecture diagram</title>
+      <mediaobjectco>
+	<imageobjectco>
+	  <areaspec id="map1" units="other" otherunits="imagemap">
+	    <area id="area1_1" linkends="x_flow_1" x_steal="#step_1"/>
+	    <area id="area1_2" linkends="x_flow_2" x_steal="#step_2"/>
+	    <area id="area1_3" linkends="x_flow_3" x_steal="#step_3"/>
+	    <area id="area1_4" linkends="x_flow_4" x_steal="#step_4"/>
+	    <area id="area1_5" linkends="x_flow_5" x_steal="#step_5"/>
+	    <area id="area1_6" linkends="x_flow_6" x_steal="#step_6"/>
+	  </areaspec>
+	  <imageobject>
+	    <imagedata fileref="images/x-architecture.png" format="PNG" />
+	  </imageobject>
+	</imageobjectco>
+      </mediaobjectco>
+    </figure>
+    <para>
+      <orderedlist>
+	<listitem id="x_flow_1">
+	  <para>
+	    The kernel gets an event from an input
+	    device and sends it to X through the evdev
+	    input driver. The kernel does all the hard
+	    work here by driving the device and
+	    translating the different device specific
+	    event protocols to the linux evdev input
+	    event standard.
+	  </para>
+	</listitem>
+	<listitem id="x_flow_2">
+	  <para>
+	    The X server determines which window the
+	    event affects and sends it to the clients
+	    that have selected for the event in question
+	    on that window. The X server doesn't
+	    actually know how to do this right, since
+	    the window location on screen is controlled
+	    by the compositor and may be transformed in
+	    a number of ways that the X server doesn't
+	    understand (scaled down, rotated, wobbling,
+	    etc).
+	  </para>
+	</listitem>
+	<listitem id="x_flow_3">
+	  <para>
+	    The client looks at the event and decides
+	    what to do. Often the UI will have to change
+	    in response to the event - perhaps a check
+	    box was clicked or the pointer entered a
+	    button that must be highlighted. Thus the
+	    client sends a rendering request back to the
+	    X server.
+	  </para>
+	</listitem>
+	<listitem id="x_flow_4">
+	  <para>
+	    When the X server receives the rendering
+	    request, it sends it to the driver to let it
+	    program the hardware to do the rendering.
+	    The X server also calculates the bounding
+	    region of the rendering, and sends that to
+	    the compositor as a damage event.
+	  </para>
+	</listitem>
+	<listitem id="x_flow_5">
+	  <para>
+	    The damage event tells the compositor that
+	    something changed in the window and that it
+	    has to recomposite the part of the screen
+	    where that window is visible. The compositor
+	    is responsible for rendering the entire
+	    screen contents based on its scenegraph and
+	    the contents of the X windows. Yet, it has
+	    to go through the X server to render this.
+	  </para>
+	</listitem>
+	<listitem id="x_flow_6">
+	  <para>
+	    The X server receives the rendering requests
+	    from the compositor and either copies the
+	    compositor back buffer to the front buffer
+	    or does a pageflip. In the general case, the
+	    X server has to do this step so it can
+	    account for overlapping windows, which may
+	    require clipping and determine whether or
+	    not it can page flip. However, for a
+	    compositor, which is always fullscreen, this
+	    is another unnecessary context switch.
+	  </para>
+	</listitem>
+      </orderedlist>
+    </para>
+    <para>
+      As suggested above, there are a few problems with this
+      approach. The X server doesn't have the information to
+      decide which window should receive the event, nor can it
+      transform the screen coordinates to window-local
+      coordinates. And even though X has handed responsibility for
+      the final painting of the screen to the compositing manager,
+      X still controls the front buffer and modesetting. Most of
+      the complexity that the X server used to handle is now
+      available in the kernel or self contained libraries (KMS,
+      evdev, mesa, fontconfig, freetype, cairo, Qt etc). In
+      general, the X server is now just a middle man that
+      introduces an extra step between applications and the
+      compositor and an extra step between the compositor and the
+      hardware.
+    </para>
+    <para>
+      In Wayland the compositor is the display server. We transfer
+      the control of KMS and evdev to the compositor. The Wayland
+      protocol lets the compositor send the input events directly
+      to the clients and lets the client send the damage event
+      directly to the compositor:
+    </para>
+    <figure>
+      <title>Wayland architecture diagram</title>
+      <mediaobjectco>
+	<imageobjectco>
+	  <areaspec id="mapB" units="other" otherunits="imagemap">
+	    <area id="areaB_1" linkends="wayland_flow_1" x_steal="#step_1"/>
+	    <area id="areaB_2" linkends="wayland_flow_2" x_steal="#step_2"/>
+	    <area id="areaB_3" linkends="wayland_flow_3" x_steal="#step_3"/>
+	    <area id="areaB_4" linkends="wayland_flow_4" x_steal="#step_4"/>
+	  </areaspec>
+	  <imageobject>
+	    <imagedata fileref="images/wayland-architecture.png" format="PNG" />
+	  </imageobject>
+	</imageobjectco>
+      </mediaobjectco>
+    </figure>
+    <para>
+      <orderedlist>
+	<listitem id="wayland_flow_1">
+	  <para>
+	    The kernel gets an event and sends
+	    it to the compositor. This
+	    is similar to the X case, which is
+	    great, since we get to reuse all the
+	    input drivers in the kernel.
+	  </para>
+	</listitem>
+	<listitem id="wayland_flow_2">
+	  <para>
+	    The compositor looks through its
+	    scenegraph to determine which window
+	    should receive the event. The
+	    scenegraph corresponds to what's on
+	    screen and the compositor
+	    understands the transformations that
+	    it may have applied to the elements
+	    in the scenegraph. Thus, the
+	    compositor can pick the right window
+	    and transform the screen coordinates
+	    to window-local coordinates, by
+	    applying the inverse
+	    transformations. The types of
+	    transformation that can be applied
+	    to a window is only restricted to
+	    what the compositor can do, as long
+	    as it can compute the inverse
+	    transformation for the input events.
+	  </para>
+	</listitem>
+	<listitem id="wayland_flow_3">
+	  <para>
+	    As in the X case, when the client
+	    receives the event, it updates the
+	    UI in response. But in the Wayland
+	    case, the rendering happens in the
+	    client, and the client just sends a
+	    request to the compositor to
+	    indicate the region that was
+	    updated.
+	  </para>
+	</listitem>
+	<listitem id="wayland_flow_4">
+	  <para>
+	    The compositor collects damage
+	    requests from its clients and then
+	    recomposites the screen. The
+	    compositor can then directly issue
+	    an ioctl to schedule a pageflip with
+	    KMS.
+	  </para>
+	</listitem>
+
+
+      </orderedlist>
+    </para>
+  </section>
+  <section id="sect-Wayland-Architecture-wayland_rendering">
+    <title>Wayland Rendering</title>
+    <para>
+      One of the details I left out in the above overview
+      is how clients actually render under Wayland. By
+      removing the X server from the picture we also
+      removed the mechanism by which X clients typically
+      render. But there's another mechanism that we're
+      already using with DRI2 under X: direct rendering.
+      With direct rendering, the client and the server
+      share a video memory buffer. The client links to a
+      rendering library such as OpenGL that knows how to
+      program the hardware and renders directly into the
+      buffer. The compositor in turn can take the buffer
+      and use it as a texture when it composites the
+      desktop. After the initial setup, the client only
+      needs to tell the compositor which buffer to use and
+      when and where it has rendered new content into it.
+    </para>
+
+    <para>
+      This leaves an application with two ways to update its window contents:
+    </para>
+    <para>
+      <orderedlist>
+	<listitem>
+	  <para>
+	    Render the new content into a new buffer and tell the compositor
+	    to use that instead of the old buffer. The application can
+	    allocate a new buffer every time it needs to update the window
+	    contents or it can keep two (or more) buffers around and cycle
+	    between them. The buffer management is entirely under
+	    application control.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Render the new content into the buffer that it previously
+	    told the compositor to to use. While it's possible to just
+	    render directly into the buffer shared with the compositor,
+	    this might race with the compositor. What can happen is that
+	    repainting the window contents could be interrupted by the
+	    compositor repainting the desktop. If the application gets
+	    interrupted just after clearing the window but before
+	    rendering the contents, the compositor will texture from a
+	    blank buffer. The result is that the application window will
+	    flicker between a blank window or half-rendered content. The
+	    traditional way to avoid this is to render the new content
+	    into a back buffer and then copy from there into the
+	    compositor surface. The back buffer can be allocated on the
+	    fly and just big enough to hold the new content, or the
+	    application can keep a buffer around. Again, this is under
+	    application control.
+	  </para>
+	</listitem>
+      </orderedlist>
+    </para>
+    <para>
+      In either case, the application must tell the compositor
+      which area of the surface holds new contents. When the
+      application renders directly to the shared buffer, the
+      compositor needs to be noticed that there is new content.
+      But also when exchanging buffers, the compositor doesn't
+      assume anything changed, and needs a request from the
+      application before it will repaint the desktop. The idea
+      that even if an application passes a new buffer to the
+      compositor, only a small part of the buffer may be
+      different, like a blinking cursor or a spinner.
+    </para>
+  </section>
+  <section id="sect-Wayland-Architecture-wayland_hw_enabling">
+    <title>Hardware Enabling for Wayland</title>
+    <para>
+      Typically, hardware enabling includes modesetting/display
+      and EGL/GLES2. On top of that Wayland needs a way to share
+      buffers efficiently between processes. There are two sides
+      to that, the client side and the server side.
+    </para>
+    <para>
+      On the client side we've defined a Wayland EGL platform. In
+      the EGL model, that consists of the native types
+      (EGLNativeDisplayType, EGLNativeWindowType and
+      EGLNativePixmapType) and a way to create those types. In
+      other words, it's the glue code that binds the EGL stack and
+      its buffer sharing mechanism to the generic Wayland API. The
+      EGL stack is expected to provide an implementation of the
+      Wayland EGL platform. The full API is in the wayland-egl.h
+      header. The open source implementation in the mesa EGL stack
+      is in wayland-egl.c and platform_wayland.c.
+    </para>
+    <para>
+      Under the hood, the EGL stack is expected to define a
+      vendor-specific protocol extension that lets the client side
+      EGL stack communicate buffer details with the compositor in
+      order to share buffers. The point of the wayland-egl.h API
+      is to abstract that away and just let the client create an
+      EGLSurface for a Wayland surface and start rendering. The
+      open source stack uses the drm Wayland extension, which lets
+      the client discover the drm device to use and authenticate
+      and then share drm (GEM) buffers with the compositor.
+    </para>
+    <para>
+      The server side of Wayland is the compositor and core UX for
+      the vertical, typically integrating task switcher, app
+      launcher, lock screen in one monolithic application. The
+      server runs on top of a modesetting API (kernel modesetting,
+      OpenWF Display or similar) and composites the final UI using
+      a mix of EGL/GLES2 compositor and hardware overlays if
+      available. Enabling modesetting, EGL/GLES2 and overlays is
+      something that should be part of standard hardware bringup.
+      The extra requirement for Wayland enabling is the
+      EGL_WL_bind_wayland_display extension that lets the
+      compositor create an EGLImage from a generic Wayland shared
+      buffer. It's similar to the EGL_KHR_image_pixmap extension
+      to create an EGLImage from an X pixmap.
+    </para>
+    <para>
+      The extension has a setup step where you have to bind the
+      EGL display to a Wayland display. Then as the compositor
+      receives generic Wayland buffers from the clients (typically
+      when the client calls eglSwapBuffers), it will be able to
+      pass the struct wl_buffer pointer to eglCreateImageKHR as
+      the EGLClientBuffer argument and with EGL_WAYLAND_BUFFER_WL
+      as the target. This will create an EGLImage, which can then
+      be used by the compositor as a texture or passed to the
+      modesetting code to use as an overlay plane. Again, this is
+      implemented by the vendor specific protocol extension, which
+      on the server side will receive the driver specific details
+      about the shared buffer and turn that into an EGL image when
+      the user calls eglCreateImageKHR.
+    </para>
+  </section>
+</chapter>
diff --git a/subprojects/wayland/doc/publican/sources/Author_Group.xml b/subprojects/wayland/doc/publican/sources/Author_Group.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2bdde62b38c85cc8dbebe36491ff59c71f295a25
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Author_Group.xml
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE authorgroup PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<authorgroup>
+  <author>
+    <firstname>Kristian</firstname>
+    <surname>Høgsberg</surname>
+    <affiliation>
+      <orgname>Intel Corporation</orgname>
+    </affiliation>
+    <email>krh@bitplanet.net</email>
+  </author>
+</authorgroup>
+
diff --git a/subprojects/wayland/doc/publican/sources/Book_Info.xml b/subprojects/wayland/doc/publican/sources/Book_Info.xml
new file mode 100644
index 0000000000000000000000000000000000000000..897673a0a5df3a8353f19857beeb5c61de9293bf
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Book_Info.xml
@@ -0,0 +1,71 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE bookinfo PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<bookinfo id="book-Wayland-Wayland">
+  <title>Wayland</title>
+  <subtitle>The Wayland Protocol</subtitle>
+  <productname>Documentation</productname>
+  <productnumber>0.1</productnumber>
+  <edition>1</edition>
+  <pubsnumber>0</pubsnumber>
+  <abstract>
+    <para>
+      Wayland is a protocol for a compositor to talk to
+      its clients as well as a C library implementation of
+      that protocol. The compositor can be a standalone
+      display server running on Linux kernel modesetting
+      and evdev input devices, an X application, or a
+      Wayland client itself. The clients can be
+      traditional applications, X servers (rootless or
+      fullscreen) or other display servers.
+    </para>
+  </abstract>
+  <corpauthor>
+    <inlinemediaobject>
+      <imageobject>
+	<imagedata fileref="images/wayland.png" format="PNG" />
+      </imageobject>
+      <textobject>
+	<phrase>
+	  Wayland logo
+	</phrase>
+      </textobject>
+    </inlinemediaobject>
+  </corpauthor>
+
+  <legalnotice lang="en-US">
+    <para>
+      Copyright <trademark class="copyright"></trademark> &YEAR; &HOLDER;
+    </para>
+
+	<para>
+	  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:
+	</para>
+
+	<para>
+	  The above copyright notice and this permission notice (including the next
+	  paragraph) shall be included in all copies or substantial portions of the
+	  Software.
+	</para>
+
+	<para>
+	  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.
+	</para>
+  </legalnotice>
+
+
+  <xi:include href="Author_Group.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+</bookinfo>
diff --git a/subprojects/wayland/doc/publican/sources/Client.xml b/subprojects/wayland/doc/publican/sources/Client.xml
new file mode 100644
index 0000000000000000000000000000000000000000..19bf3e9572a34cc3634c32ba8ca4ea4b253c4b8b
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Client.xml
@@ -0,0 +1,92 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+  <!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+  <!ENTITY doxygen SYSTEM "ClientAPI.xml">
+%BOOK_ENTITIES;
+]>
+<appendix id="sect-Library-Client">
+  <title>Client API</title>
+  <section><title>Introduction</title>
+  <para>
+    The open-source reference implementation of Wayland protocol is
+    split in two C libraries, libwayland-client and <link
+    linkend="sect-Library-Server">libwayland-server</link>. Their main
+    responsibility is to handle the Inter-process communication
+    (<emphasis>IPC</emphasis>) with each other, therefore guaranteeing
+    the protocol objects marshaling and messages synchronization.
+  </para>
+  <para>
+    A client uses libwayland-client to communicate with one or more
+    wayland servers. A <link
+    linkend="Client-classwl__display">wl_display</link> object is
+    created and manages each open connection to a server. At least one
+    <link linkend="Client-classwl__event__queue">wl_event_queue</link>
+    object is created for each wl_display, this holds events as they
+    are received from the server until they can be
+    processed. Multi-threading is supported by creating an additional
+    wl_event_queue for each additional thread, each object can have
+    it's events placed in a particular queue, so potentially a
+    different thread could be made to handle the events for each
+    object created.
+  </para>
+  <para>
+    Though some convenience functions are provided, libwayland-client
+    is designed to allow the calling code to wait for events, so that
+    different polling mechanisms can be used. A file descriptor is
+    provided, when it becomes ready for reading the calling code can
+    ask libwayland-client to read the available events from it into
+    the wl_event_queue objects.
+  </para>
+  <para>
+    The library only provides low-level access to the wayland objects.
+    Each object created by the client is represented by a <link
+    linkend="Client-classwl__proxy">wl_proxy</link> object that this
+    library creates. This includes the id that is actually
+    communicated over the socket to the server, a void* data pointer
+    that is intended to point at a client's representation of the
+    object, and a pointer to a static <link
+    linkend="Client-structwl__interface">wl_interface</link> object,
+    which is generated from the xml and identifies the object's class
+    and can be used for introspection into the messages and events.
+  </para>
+  <para>
+    Messages are sent by calling wl_proxy_marshal. This will write a
+    message to the socket, by using the message id and the
+    wl_interface to identify the types of each argument and convert
+    them into stream format.  Most software will call type-safe
+    wrappers generated from the xml description of the <link
+    linkend="appe-Wayland-Protocol">Wayland protocols</link>. For
+    instance the C header file generated from the xml defines the
+    following inline function to transmit the <link
+    linkend="protocol-spec-wl_surface-request-attach">wl_surface::attach</link>
+    message:
+  </para>
+  <programlisting>static inline void
+wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y)
+{
+  wl_proxy_marshal((struct wl_proxy *) wl_surface, WL_SURFACE_ATTACH, buffer, x, y);
+}</programlisting>
+  <para>
+    Events (messages from the server) are handled by calling a
+    "dispatcher" callback the client stores in the wl_proxy for each
+    event. A language binding for a string-based interpreter, such as
+    CPython, might have a dispatcher that uses the event name from the
+    wl_interface to identify the function to call. The default
+    dispatcher uses the message id number to index an array of
+    functions pointers, called a wl_listener, and the wl_interface to
+    convert data from the stream into arguments to the function. The
+    C header file generated from the xml defines a per-class structure
+    that forces the function pointers to be of the correct type, for
+    instance the <link
+    linkend="protocol-spec-wl_surface-event-enter">wl_surface::enter</link>
+    event defines this pointer in the wl_surface_listener object:
+  </para>
+  <programlisting>struct wl_surface_listener {
+  void (*enter)(void *data, struct wl_surface *, struct wl_output *);
+  ...
+}</programlisting>
+  <para>
+  </para>
+  </section>
+  &doxygen;
+</appendix>
diff --git a/subprojects/wayland/doc/publican/sources/Compositors.xml b/subprojects/wayland/doc/publican/sources/Compositors.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7a7bdaa06c57b1373b05f15ceafffdf3b4ee12f9
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Compositors.xml
@@ -0,0 +1,128 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-Compositors">
+  <title>Types of Compositors</title>
+
+  <para>
+    Compositors come in different types, depending on which
+    role they play in the overall architecture of the OS.
+    For instance, a
+    <link linkend="sect-Compositors-System-Compositor">system compositor</link>
+    can be used for booting the system, handling multiple user switching, a
+    possible console terminal emulator and so forth. A different compositor, a
+    <link linkend="sect-Compositors-Session-Compositor">session compositor</link>
+    would provide the actual desktop environment. There are many ways for
+    different types of compositors to co-exist.
+  </para>
+  <para>
+    In this section, we introduce three types of Wayland compositors relying
+    on <link linkend="sect-Library-Server">libwayland-server</link>.
+  </para>
+
+  <section id="sect-Compositors-System-Compositor">
+    <title>System Compositor</title>
+    <para>
+      A system compositor can run from early boot until shutdown.
+      It effectively replaces the kernel vt system, and can tie in
+      with the systems graphical boot setup and multiseat support.
+    </para>
+    <para>
+      A system compositor can host different types of session
+      compositors, and let us switch between multiple sessions
+      (fast user switching, or secure/personal desktop switching).
+    </para>
+    <para>
+      A linux implementation of a system compositor will typically
+      use libudev, egl, kms, evdev and cairo.
+    </para>
+    <para>
+      For fullscreen clients, the system compositor can reprogram the
+      video scanout address to read directly from the client provided
+      buffer.
+    </para>
+  </section>
+  <section id="sect-Compositors-Session-Compositor">
+    <title>Session Compositor</title>
+    <para>
+      A session compositor is responsible for a single user session.
+      If a system compositor is present, the session compositor will
+      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 hardware.
+     </para>
+     <para>
+      X applications can continue working under a session compositor
+      by means of a root-less X server that is activated on demand.
+     </para>
+    <para>
+       Possible examples for session compositors include
+      <itemizedlist>
+	<listitem>
+	  <para>
+	    gnome-shell
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    moblin
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    kwin
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    kmscon
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    rdp session
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    Weston with X11 or Wayland backend is a session compositor nested
+	    in another session compositor.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    fullscreen X session under Wayland
+	  </para>
+	</listitem>
+      </itemizedlist>
+    </para>
+  </section>
+  <section id="sect-Compositors-Embedding-Compositor">
+    <title>Embedding Compositor</title>
+    <para>
+      X11 lets clients embed windows from other clients, or lets clients
+      copy pixmap contents rendered by another client into their window.
+      This is often used for applets in a panel, browser plugins and similar.
+      Wayland doesn't directly allow this, but clients can communicate GEM
+      buffer names out-of-band, for example, using D-Bus, or command line
+      arguments when the panel launches the applet.  Another option is to
+      use a nested Wayland instance.  For this, the Wayland server will have
+      to be a library that the host application links to.  The host
+      application will then pass the Wayland server socket name to the
+      embedded application, and will need to implement the Wayland
+      compositor interface.  The host application composites the client
+      surfaces as part of it's window, that is, in the web page or in the
+      panel.  The benefit of nesting the Wayland server is that it provides
+      the requests the embedded client needs to inform the host about buffer
+      updates and a mechanism for forwarding input events from the host
+      application.
+    </para>
+    <para>
+      An example for this kind of setup is firefox embedding the flash
+      player as a kind of special-purpose compositor.
+    </para>
+  </section>
+</chapter>
diff --git a/subprojects/wayland/doc/publican/sources/Foreword.xml b/subprojects/wayland/doc/publican/sources/Foreword.xml
new file mode 100644
index 0000000000000000000000000000000000000000..46fda2becd8a50c259ce0ab06e6a62f74c162380
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Foreword.xml
@@ -0,0 +1,28 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+
+<preface>
+  <title>Preface</title>
+
+  <para>
+  This document describes the (i) Wayland architecture, (ii) Wayland model of
+  operation and (iii) its library API. Also, the Wayland protocol specification is shown
+  in the Appendix. This document is aimed primarily at Wayland developers and
+  those looking to program with it; it does not cover application development.
+  </para>
+  <para>
+  There have been many contributors to this document and since this is only the
+  first edition many errors are expected to be found. We appreciate
+  corrections.
+  </para>
+  <literallayout>
+Yours,
+
+	the Wayland open-source community
+	November 2012
+  </literallayout>
+</preface>
diff --git a/subprojects/wayland/doc/publican/sources/Introduction.xml b/subprojects/wayland/doc/publican/sources/Introduction.xml
new file mode 100644
index 0000000000000000000000000000000000000000..276db2daca8ae5265eb5a8cc6d827325c74d5938
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Introduction.xml
@@ -0,0 +1,116 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-Introduction">
+  <title>Introduction</title>
+  <section id="sect-Motivation">
+    <title>Motivation</title>
+    <para>
+      Most Linux and Unix-based systems rely on the X Window System (or
+      simply <emphasis>X</emphasis>) as the low-level protocol for building
+      bitmap graphics interfaces. On these systems, the X stack has grown to
+      encompass functionality arguably belonging in client libraries,
+      helper libraries, or the host operating system kernel.  Support for
+      things like PCI resource management, display configuration management,
+      direct rendering, and memory management has been integrated into the X
+      stack, imposing limitations like limited support for standalone
+      applications, duplication in other projects (e.g. the Linux fb layer
+      or the DirectFB project), and high levels of complexity for systems
+      combining multiple elements (for example radeon memory map handling
+      between the fb driver and X driver, or VT switching).
+    </para>
+    <para>
+      Moreover, X has grown to incorporate modern features like offscreen
+      rendering and scene composition, but subject to the limitations of the
+      X architecture.  For example, the X implementation of composition adds
+      additional context switches and makes things like input redirection
+      difficult.
+    </para>
+    <mediaobject>
+      <imageobject>
+	<imagedata fileref="images/x-architecture.png" format="PNG" />
+      </imageobject>
+      <textobject>
+	<phrase>
+	  X architecture diagram
+	</phrase>
+      </textobject>
+    </mediaobject>
+    <para>
+      The diagram above illustrates the central role of the X server and
+      compositor in operations, and the steps required to get contents on to
+      the screen.
+    </para>
+    <para>
+      Over time, X developers came to understand the shortcomings of this
+      approach and worked to split things up.  Over the past several years,
+      a lot of functionality has moved out of the X server and into
+      client-side libraries or kernel drivers. One of the first components
+      to move out was font rendering, with freetype and fontconfig providing
+      an alternative to the core X fonts.  Direct rendering OpenGL as a
+      graphics driver in a client side library went through some iterations,
+      ending up as DRI2, which abstracted most of the direct rendering
+      buffer management from client code. Then cairo came along and provided
+      a modern 2D rendering library independent of X, and compositing
+      managers took over control of the rendering of the desktop as toolkits
+      like GTK+ and Qt moved away from using X APIs for rendering. Recently,
+      memory and display management have moved to the Linux kernel, further
+      reducing the scope of X and its driver stack.  The end result is a
+      highly modular graphics stack.
+    </para>
+
+  </section>
+
+  <section id="sect-Compositing-manager-display-server">
+    <title>The compositing manager as the display server</title>
+    <para>
+      Wayland is a new display server and compositing protocol, and Weston
+      is the implementation of this protocol which builds on top of all the
+      components above. We are trying to distill out the functionality in
+      the X server that is still used by the modern Linux desktop. This
+      turns out to be not a whole lot. Applications can allocate their own
+      off-screen buffers and render their window contents directly, using
+      hardware accelerated libraries like libGL, or high quality software
+      implementations like those found in Cairo. In the end, what’s needed
+      is a way to present the resulting window surface for display, and a
+      way to receive and arbitrate input among multiple clients. This is
+      what Wayland provides, by piecing together the components already in
+      the eco-system in a slightly different way.
+    </para>
+    <para>
+      X will always be relevant, in the same way Fortran compilers and VRML
+      browsers are, but it’s time that we think about moving it out of the
+      critical path and provide it as an optional component for legacy
+      applications.
+    </para>
+    <para>
+      Overall, the philosophy of Wayland is to provide clients with a way to
+      manage windows and how their contents is displayed.  Rendering is left
+      to clients, and system wide memory management interfaces are used to
+      pass buffer handles between clients and the compositing manager.
+    </para>
+    <mediaobject>
+      <imageobject>
+	<imagedata fileref="images/wayland-architecture.png" format="PNG" />
+      </imageobject>
+      <textobject>
+	<phrase>
+	  Wayland architecture diagram
+	</phrase>
+      </textobject>
+    </mediaobject>
+    <para>
+      The figure above illustrates how Wayland clients interact with a
+      Wayland server.  Note that window management and composition are
+      handled entirely in the server, significantly reducing complexity
+      while marginally improving performance through reduced context
+      switching.  The resulting system is easier to build and extend than a
+      similar X system, because often changes need only be made in one
+      place.  Or in the case of protocol extensions, two (rather than 3 or 4
+      in the X case where window management and/or composition handling may
+      also need to be updated).
+    </para>
+  </section>
+</chapter>
diff --git a/subprojects/wayland/doc/publican/sources/Preface.xml b/subprojects/wayland/doc/publican/sources/Preface.xml
new file mode 100644
index 0000000000000000000000000000000000000000..17c6ebffa2710c1e1dfa582b386fc7bc659356ad
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Preface.xml
@@ -0,0 +1,20 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
+"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+
+<preface>
+  <title>Acknowledgments</title>
+
+  <para>
+  TODO: Kristian has to fill up this with one or two paragraphs and a small
+  "thank you": http://en.wikipedia.org/wiki/Preface
+  </para>
+  <literallayout>
+Best,
+
+	Kristian Høgsberg
+  </literallayout>
+</preface>
diff --git a/subprojects/wayland/doc/publican/sources/Protocol.xml b/subprojects/wayland/doc/publican/sources/Protocol.xml
new file mode 100644
index 0000000000000000000000000000000000000000..89d76d8e7d45404080b2736a2f83dd89d7d2759b
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Protocol.xml
@@ -0,0 +1,589 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-Protocol">
+  <title>Wayland Protocol and Model of Operation</title>
+  <section id="sect-Protocol-Basic-Principles">
+    <title>Basic Principles</title>
+    <para>
+      The Wayland protocol is an asynchronous object oriented protocol.  All
+      requests are method invocations on some object.  The requests include
+      an object ID that uniquely identifies an object on the server.  Each
+      object implements an interface and the requests include an opcode that
+      identifies which method in the interface to invoke.
+    </para>
+    <para>
+      The protocol is message-based.  A message sent by a client to the server
+      is called request.  A message from the server to a client is called event.
+      A message has a number of arguments, each of which has a certain type (see
+      <xref linkend="sect-Protocol-Wire-Format"/> for a list of argument types).
+    </para>
+    <para>
+      Additionally, the protocol can specify <type>enum</type>s which associate
+      names to specific numeric enumeration values.  These are primarily just
+      descriptive in nature: at the wire format level enums are just integers.
+      But they also serve a secondary purpose to enhance type safety or
+      otherwise add context for use in language bindings or other such code.
+      This latter usage is only supported so long as code written before these
+      attributes were introduced still works after; in other words, adding an
+      enum should not break API, otherwise it puts backwards compatibility at
+      risk.
+    </para>
+    <para>
+      <type>enum</type>s can be defined as just a set of integers, or as
+      bitfields.  This is specified via the <type>bitfield</type> boolean
+      attribute in the <type>enum</type> definition.  If this attribute is true,
+      the enum is intended to be accessed primarily using bitwise operations,
+      for example when arbitrarily many choices of the enum can be ORed
+      together; if it is false, or the attribute is omitted, then the enum
+      arguments are a just a sequence of numerical values.
+    </para>
+    <para>
+      The <type>enum</type> attribute can be used on either <type>uint</type>
+      or <type>int</type> arguments, however if the <type>enum</type> is
+      defined as a <type>bitfield</type>, it can only be used on
+      <type>uint</type> args.
+    </para>
+    <para>
+      The server sends back events to the client, each event is emitted from
+      an object.  Events can be error conditions.  The event includes the
+      object ID and the event opcode, from which the client can determine
+      the type of event.  Events are generated both in response to requests
+      (in which case the request and the event constitutes a round trip) or
+      spontaneously when the server state changes.
+    </para>
+    <para>
+      <itemizedlist>
+	<listitem>
+	  <para>
+	    State is broadcast on connect, events are sent
+	    out when state changes. Clients must listen for
+	    these changes and cache the state.
+	    There is no need (or mechanism) to query server state.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    The server will broadcast the presence of a number of global objects,
+	    which in turn will broadcast their current state.
+	  </para>
+	</listitem>
+      </itemizedlist>
+    </para>
+  </section>
+  <section id="sect-Protocol-Code-Generation">
+    <title>Code Generation</title>
+    <para>
+      The interfaces, requests and events are defined in
+      <filename>protocol/wayland.xml</filename>.
+      This xml is used to generate the function prototypes that can be used by
+      clients and compositors.
+    </para>
+    <para>
+      The protocol entry points are generated as inline functions which just
+      wrap the <function>wl_proxy_*</function> functions.  The inline functions aren't
+      part of the library ABI and language bindings should generate their
+      own stubs for the protocol entry points from the xml.
+    </para>
+  </section>
+  <section id="sect-Protocol-Wire-Format">
+    <title>Wire Format</title>
+    <para>
+      The protocol is sent over a UNIX domain stream socket, where the endpoint
+      usually is named <systemitem class="service">wayland-0</systemitem>
+      (although it can be changed via <emphasis>WAYLAND_DISPLAY</emphasis>
+      in the environment). Beginning in Wayland 1.15, implementations can
+      optionally support server socket endpoints located at arbitrary
+      locations in the filesystem by setting <emphasis>WAYLAND_DISPLAY</emphasis>
+      to the absolute path at which the server endpoint listens.
+    </para>
+    <para>
+      Every message is structured as 32-bit words; values are represented in the
+      host's byte-order.  The message header has 2 words in it:
+      <itemizedlist>
+	<listitem>
+	  <para>
+	    The first word is the sender's object ID (32-bit).
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    The second has 2 parts of 16-bit.  The upper 16-bits are the message
+	    size in bytes, starting at the header (i.e. it has a minimum value of 8).The lower is the request/event opcode.
+	  </para>
+	</listitem>
+      </itemizedlist>
+      The payload describes the request/event arguments.  Every argument is always
+      aligned to 32-bits. Where padding is required, the value of padding bytes is
+      undefined. There is no prefix that describes the type, but it is
+      inferred implicitly from the xml specification.
+    </para>
+    <para>
+
+      The representation of argument types are as follows:
+      <variablelist>
+	<varlistentry>
+	  <term>int</term>
+	  <term>uint</term>
+	  <listitem>
+	    <para>
+	      The value is the 32-bit value of the signed/unsigned
+	      int.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	<varlistentry>
+	  <term>fixed</term>
+	  <listitem>
+	    <para>
+	      Signed 24.8 decimal numbers. It is a signed decimal type which
+	      offers a sign bit, 23 bits of integer precision and 8 bits of
+	      decimal precision. This is exposed as an opaque struct with
+	      conversion helpers to and from double and int on the C API side.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	<varlistentry>
+	  <term>string</term>
+	  <listitem>
+	    <para>
+	      Starts with an unsigned 32-bit length (including null terminator),
+	      followed by the string contents, including terminating null byte,
+	      then padding to a 32-bit boundary. A null value is represented
+	      with a length of 0.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	<varlistentry>
+	  <term>object</term>
+	  <listitem>
+	    <para>
+	      32-bit object ID. A null value is represented with an ID of 0.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	<varlistentry>
+	  <term>new_id</term>
+	  <listitem>
+	    <para>
+	      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>
+	<varlistentry>
+	  <term>array</term>
+	  <listitem>
+	    <para>
+	      Starts with 32-bit array size in bytes, followed by the array
+	      contents verbatim, and finally padding to a 32-bit boundary.
+	    </para>
+	  </listitem>
+	</varlistentry>
+	<varlistentry>
+	  <term>fd</term>
+	  <listitem>
+	    <para>
+	      The file descriptor is not stored in the message buffer, but in
+	      the ancillary data of the UNIX domain socket message (msg_control).
+	    </para>
+	  </listitem>
+	</varlistentry>
+      </variablelist>
+    </para>
+    <para>
+      The protocol does not specify the exact position of the ancillary data
+      in the stream, except that the order of file descriptors is the same as
+      the order of messages and <code>fd</code> arguments within messages on
+      the wire.
+    </para>
+    <para>
+      In particular, it means that any byte of the stream, even the message
+      header, may carry the ancillary data with file descriptors.
+    </para>
+    <para>
+      Clients and compositors should queue incoming data until they have
+      whole messages to process, as file descriptors may arrive earlier
+      or later than the corresponding data bytes.
+    </para>
+  </section>
+  <xi:include href="ProtocolInterfaces.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+  <section id="sect-Protocol-Versioning">
+    <title>Versioning</title>
+    <para>
+      Every interface is versioned and every protocol object implements a
+      particular version of its interface.  For global objects, the maximum
+      version supported by the server is advertised with the global and the
+      actual version of the created protocol object is determined by the
+      version argument passed to wl_registry.bind().  For objects that are
+      not globals, their version is inferred from the object that created
+      them.
+    </para>
+    <para>
+      In order to keep things sane, this has a few implications for
+      interface versions:
+      <itemizedlist>
+	<listitem>
+	  <para>
+	    The object creation hierarchy must be a tree.  Otherwise,
+	    inferring object versions from the parent object becomes a much
+	    more difficult to properly track.
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    When the version of an interface increases, so does the version
+	    of its parent (recursively until you get to a global interface)
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    A global interface's version number acts like a counter for all
+	    of its child interfaces.  Whenever a child interface gets
+	    modified, the global parent's interface version number also
+	    increases (see above).  The child interface then takes on the
+	    same version number as the new version of its parent global
+	    interface.
+	  </para>
+	</listitem>
+      </itemizedlist>
+    </para>
+    <para>
+      To illustrate the above, consider the wl_compositor interface.  It
+      has two children, wl_surface and wl_region.  As of wayland version
+      1.2, wl_surface and wl_compositor are both at version 3.  If
+      something is added to the wl_region interface, both wl_region and
+      wl_compositor will get bumpped to version 4.  If, afterwards,
+      wl_surface is changed, both wl_compositor and wl_surface will be at
+      version 5.  In this way the global interface version is used as a
+      sort of "counter" for all of its child interfaces.  This makes it
+      very simple to know the version of the child given the version of its
+      parent.  The child is at the highest possible interface version that
+      is less than or equal to its parent's version.
+    </para>
+    <para>
+      It is worth noting a particular exception to the above versioning
+      scheme.  The wl_display (and, by extension, wl_registry) interface
+      cannot change because it is the core protocol object and its version
+      is never advertised nor is there a mechanism to request a different
+      version.
+    </para>
+  </section>
+  <section id="sect-Protocol-Connect-Time">
+    <title>Connect Time</title>
+    <para>
+      There is no fixed connection setup information, the server emits
+      multiple events at connect time, to indicate the presence and
+      properties of global objects: outputs, compositor, input devices.
+    </para>
+  </section>
+  <section id="sect-Protocol-Security-and-Authentication">
+    <title>Security and Authentication</title>
+    <para>
+      <itemizedlist>
+	<listitem>
+	  <para>
+	    mostly about access to underlying buffers, need new drm auth
+	    mechanism (the grant-to ioctl idea), need to check the cmd stream?
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    getting the server socket depends on the compositor type, could
+	    be a system wide name, through fd passing on the session dbus.
+	    or the client is forked by the compositor and the fd is
+	    already opened.
+	  </para>
+	</listitem>
+      </itemizedlist>
+    </para>
+  </section>
+  <section id="sect-Protocol-Creating-Objects">
+    <title>Creating Objects</title>
+    <para>
+      Each object has a unique ID.  The IDs are allocated by the entity
+      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-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. This ordering is
+      not merely a guideline, but a strict requirement, and there are
+      implementations of the protocol that rigorously enforce this rule,
+      including the ubiquitous libwayland.
+    </para>
+  </section>
+  <section id="sect-Protocol-Compositor">
+    <title>Compositor</title>
+    <para>
+      The compositor is a global object, advertised at connect time.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_compositor"/> for the
+      protocol description.
+    </para>
+  </section>
+  <section id="sect-Protocol-Surface">
+    <title>Surfaces</title>
+    <para>
+      A surface manages a rectangular grid of pixels that clients create
+      for displaying their content to the screen.  Clients don't know
+      the global position of their surfaces, and cannot access other
+      clients' surfaces.
+    </para>
+    <para>
+      Once the client has finished writing pixels, it 'commits' the
+      buffer; this permits the compositor to access the buffer and read
+      the pixels.  When the compositor is finished, it releases the
+      buffer back to the client.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_surface"/> for the protocol
+      description.
+    </para>
+  </section>
+  <section id="sect-Protocol-Input">
+    <title>Input</title>
+    <para>
+      A seat represents a group of input devices including mice,
+      keyboards and touchscreens. It has a keyboard and pointer
+      focus. Seats are global objects. Pointer events are delivered
+      in surface-local coordinates.
+    </para>
+    <para>
+      The compositor maintains an implicit grab when a button is
+      pressed, to ensure that the corresponding button release
+      event gets delivered to the same surface. But there is no way
+      for clients to take an explicit grab. Instead, surfaces can
+      be mapped as 'popup', which combines transient window semantics
+      with a pointer grab.
+    </para>
+    <para>
+      To avoid race conditions, input events that are likely to
+      trigger further requests (such as button presses, key events,
+      pointer motions) carry serial numbers, and requests such as
+      wl_surface.set_popup require that the serial number of the
+      triggering event is specified. The server maintains a
+      monotonically increasing counter for these serial numbers.
+    </para>
+    <para>
+      Input events also carry timestamps with millisecond granularity.
+      Their base is undefined, so they can't be compared against
+      system time (as obtained with clock_gettime or gettimeofday).
+      They can be compared with each other though, and for instance
+      be used to identify sequences of button presses as double
+      or triple clicks.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_seat"/> for the
+      protocol description.
+    </para>
+    <para>
+      Talk about:
+
+      <itemizedlist>
+	<listitem>
+	  <para>
+	    keyboard map, change events
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    xkb on Wayland
+	  </para>
+	</listitem>
+	<listitem>
+	  <para>
+	    multi pointer Wayland
+	  </para>
+	</listitem>
+      </itemizedlist>
+    </para>
+    <para>
+      A surface can change the pointer image when the surface is the pointer
+      focus of the input device.  Wayland doesn't automatically change the
+      pointer image when a pointer enters a surface, but expects the
+      application to set the cursor it wants in response to the pointer
+      focus and motion events.  The rationale is that a client has to manage
+      changing pointer images for UI elements within the surface in response
+      to motion events anyway, so we'll make that the only mechanism for
+      setting or changing the pointer image.  If the server receives a request
+      to set the pointer image after the surface loses pointer focus, the
+      request is ignored.  To the client this will look like it successfully
+      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.
+    </para>
+    <para>
+      What if the pointer moves from one window which has set a special
+      pointer image to a surface that doesn't set an image in response to
+      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.  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">
+    <title>Output</title>
+    <para>
+      An output is a global object, advertised at connect time or as it
+      comes and goes.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_output"/> for the protocol
+      description.
+    </para>
+    <para>
+    </para>
+    <itemizedlist>
+      <listitem>
+	<para>
+	  laid out in a big (compositor) coordinate system
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  basically xrandr over Wayland
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  geometry needs position in compositor coordinate system
+	</para>
+      </listitem>
+      <listitem>
+	<para>
+	  events to advertise available modes, requests to move and change
+	  modes
+	</para>
+      </listitem>
+    </itemizedlist>
+  </section>
+  <section id="sect-Protocol-data-sharing">
+    <title>Data sharing between clients</title>
+    <para>
+      The Wayland protocol provides clients a mechanism for sharing
+      data that allows the implementation of copy-paste and
+      drag-and-drop. The client providing the data creates a
+      <function>wl_data_source</function> object and the clients
+      obtaining the data will see it as <function>wl_data_offer</function>
+      object. This interface allows the clients to agree on a mutually
+      supported mime type and transfer the data via a file descriptor
+      that is passed through the protocol.
+    </para>
+    <para>
+      The next section explains the negotiation between data source and
+      data offer objects. <xref linkend="sect-Protocol-data-sharing-devices"/>
+      explains how these objects are created and passed to different
+      clients using the <function>wl_data_device</function> interface
+      that implements copy-paste and drag-and-drop support.
+    </para>
+    <para>
+      See <xref linkend="protocol-spec-wl_data_offer"/>,
+      <xref linkend="protocol-spec-wl_data_source"/>,
+      <xref linkend="protocol-spec-wl_data_device"/> and
+      <xref linkend="protocol-spec-wl_data_device_manager"/> for
+      protocol descriptions.
+    </para>
+    <para>
+      MIME is defined in RFC's 2045-2049. A
+      <ulink url="https://www.iana.org/assignments/media-types/media-types.xhtml">
+      registry of MIME types</ulink> is maintained by the Internet Assigned
+      Numbers Authority (IANA).
+    </para>
+    <section>
+      <title>Data negotiation</title>
+      <para>
+	A client providing data to other clients will create a <function>wl_data_source</function>
+	object and advertise the mime types for the formats it supports for
+	that data through the <function>wl_data_source.offer</function>
+	request. On the receiving end, the data offer object will generate one
+	<function>wl_data_offer.offer</function> event for each supported mime
+	type.
+      </para>
+      <para>
+	The actual data transfer happens when the receiving client sends a
+	<function>wl_data_offer.receive</function> request. This request takes
+	a mime type and a file descriptor as arguments. This request will generate a
+	<function>wl_data_source.send</function> event on the sending client
+	with the same arguments, and the latter client is expected to write its
+	data to the given file descriptor using the chosen mime type.
+      </para>
+    </section>
+    <section id="sect-Protocol-data-sharing-devices">
+      <title>Data devices</title>
+      <para>
+	Data devices glue data sources and offers together. A data device is
+	associated with a <function>wl_seat</function> and is obtained by the clients using the
+	<function>wl_data_device_manager</function> factory object, which is also responsible for
+	creating data sources.
+      </para>
+      <para>
+	Clients are informed of new data offers through the
+	<function>wl_data_device.data_offer</function> event. After this
+	event is generated the data offer will advertise the available mime
+	types. New data offers are introduced prior to their use for
+	copy-paste or drag-and-drop.
+      </para>
+      <section>
+	<title>Selection</title>
+	<para>
+	  Each data device has a selection data source. Clients create a data
+	  source object using the device manager and may set it as the
+	  current selection for a given data device. Whenever the current
+	  selection changes, the client with keyboard focus receives a
+	  <function>wl_data_device.selection</function> event. This event is
+	  also generated on a client immediately before it receives keyboard
+	  focus.
+	</para>
+	<para>
+	  The data offer is introduced with
+	  <function>wl_data_device.data_offer</function> event before the
+	  selection event.
+	</para>
+      </section>
+      <section>
+	<title>Drag and Drop</title>
+	<para>
+	  A drag-and-drop operation is started using the
+	  <function>wl_data_device.start_drag</function> request. This
+	  requests causes a pointer grab that will generate enter, motion and
+	  leave events on the data device. A data source is supplied as
+	  argument to start_drag, and data offers associated with it are
+	  supplied to clients surfaces under the pointer in the
+	  <function>wl_data_device.enter</function> event. The data offer
+	  is introduced to the client prior to the enter event with the
+	  <function>wl_data_device.data_offer</function> event.
+	</para>
+	<para>
+	  Clients are expected to provide feedback to the data sending client
+	  by calling the <function>wl_data_offer.accept</function> request with
+	  a mime type it accepts. If none of the advertised mime types is
+	  supported by the receiving client, it should supply NULL to the
+	  accept request. The accept request causes the sending client to
+	  receive a <function>wl_data_source.target</function> event with the
+	  chosen mime type.
+	</para>
+	<para>
+	  When the drag ends, the receiving client receives a
+	  <function>wl_data_device.drop</function> event at which it is expected
+	  to transfer the data using the
+	  <function>wl_data_offer.receive</function> request.
+	</para>
+      </section>
+    </section>
+  </section>
+</chapter>
diff --git a/subprojects/wayland/doc/publican/sources/Revision_History.xml b/subprojects/wayland/doc/publican/sources/Revision_History.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2c540fecf23f39c3db7d76fc62440b9a2a3383c2
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Revision_History.xml
@@ -0,0 +1,7 @@
+<revhistory>
+  <revision>
+    <revnumber>1-0</revnumber>
+    <authorinitials>krh</authorinitials>
+    <revremark>Initial version</revremark>
+  </revision>
+</revhistory>
diff --git a/subprojects/wayland/doc/publican/sources/Server.xml b/subprojects/wayland/doc/publican/sources/Server.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2333b1a4fba61d145a0db34c73db2a799847f672
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Server.xml
@@ -0,0 +1,49 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+  <!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+  <!ENTITY doxygen SYSTEM "ServerAPI.xml">
+%BOOK_ENTITIES;
+]>
+<appendix id="sect-Library-Server">
+  <title>Server API</title>
+  <section><title>Introduction</title>
+  <para>
+    The open-source reference implementation of Wayland protocol is
+    split in two C libraries, <link
+    linkend="sect-Library-Client">libwayland-client</link> and
+    libwayland-server. Their main responsibility is to handle the
+    Inter-process communication (<emphasis>IPC</emphasis>) with each
+    other, therefore guaranteeing the protocol objects marshaling and
+    messages synchronization.
+  </para>
+  <para>
+    The server library is designed to work much like libwayland-client,
+    although it is considerably complicated due to the server needing
+    to support multiple versions of the protocol. It is best to learn
+    libwayland-client first.
+  </para>
+  <para>
+    Each open socket to a client is represented by a <link
+    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
+    client-created objects, and <link
+    linkend="Server-structwl__global">wl_global</link> for objects
+    created by the server.
+  </para>
+  <para>
+    Often a server is also a client for another Wayland server, and
+    thus must link with both libwayland-client and libwayland-server.
+    This produces some type name conflicts (such as the <link
+    linkend="Client-classwl__display">client wl_display</link> and
+    <link linkend="Server-structwl__display">server wl_display</link>,
+    but the duplicate-but-not-the-same types are opaque, and accessed
+    only inside the correct library where it came from. Naturally that
+    means that the program writer needs to always know if a pointer to
+    a wl_display is for the server or client side and use the
+    corresponding functions.
+  </para>
+  </section>
+  &doxygen;
+</appendix>
diff --git a/subprojects/wayland/doc/publican/sources/Wayland.ent b/subprojects/wayland/doc/publican/sources/Wayland.ent
new file mode 100644
index 0000000000000000000000000000000000000000..da18a952e9848065095ce5dc87b0dc3c5b00de6d
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Wayland.ent
@@ -0,0 +1,4 @@
+<!ENTITY PRODUCT "Documentation">
+<!ENTITY BOOKID "Wayland">
+<!ENTITY YEAR "2012">
+<!ENTITY HOLDER "Kristian Høgsberg, Intel Corporation">
diff --git a/subprojects/wayland/doc/publican/sources/Wayland.xml b/subprojects/wayland/doc/publican/sources/Wayland.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0457c15cba145aae438695d3a884b3758d87b721
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Wayland.xml
@@ -0,0 +1,18 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<book>
+  <xi:include href="Book_Info.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Foreword.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Preface.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Introduction.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Compositors.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Architecture.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Protocol.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Xwayland.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="ProtocolSpec.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
+  <xi:include href="Client.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+  <xi:include href="Server.xml" xmlns:xi="http://www.w3.org/2001/XInclude"/>
+</book>
diff --git a/subprojects/wayland/doc/publican/sources/Xwayland.xml b/subprojects/wayland/doc/publican/sources/Xwayland.xml
new file mode 100644
index 0000000000000000000000000000000000000000..79155598722d9699a8de5bf3cb7feb22ea890891
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/Xwayland.xml
@@ -0,0 +1,170 @@
+<?xml version='1.0' encoding='utf-8' ?>
+<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
+<!ENTITY % BOOK_ENTITIES SYSTEM "Wayland.ent">
+%BOOK_ENTITIES;
+]>
+<chapter id="chap-X11-Application-Support">
+  <title>X11 Application Support</title>
+  <section id="sect-X11-Application-Support-introduction">
+    <title>Introduction</title>
+    <para>
+      Being able to run existing X11 applications is crucial for the adoption
+      of Wayland, especially on desktops, as there will always be X11
+      applications that have not been or cannot be converted into Wayland
+      applications, and throwing them all away would be prohibitive.
+      Therefore a Wayland compositor often needs to support running X11
+      applications.
+    </para>
+    <para>
+      X11 and Wayland are different enough that there is no "simple" way to
+      translate between them. Most of X11 is uninteresting to a Wayland
+      compositor. That, combined with the gigantic implementation effort needed
+      to support X11, makes it intractable to just write X11 support directly in
+      a Wayland compositor. The implementation would be nothing short of a
+      real X11 server.
+    </para>
+    <para>
+      Therefore, Wayland compositors should use Xwayland, the X11 server that
+      lives in the Xorg server source code repository and shares most of the
+      implementation with the Xorg server. Xwayland is a complete X11 server,
+      just like Xorg is, but instead of driving the displays and opening input
+      devices, it acts as a Wayland client. The rest of this chapter talks
+      about how Xwayland works.
+    </para>
+    <para>
+      For integration and architecture reasons, while Xwayland is a Wayland
+      client of the Wayland compositor, the Wayland compositor is an X11 client
+      of Xwayland. This circular dependency requires special care from the
+      Wayland compositor.
+    </para>
+  </section>
+  <section id="sect-X11-Application-Support-two-modes">
+    <title>Two Modes for Foreign Windows</title>
+    <para>
+      In general, windows from a foreign window system can be presented in one
+      of two ways: rootless and rootful (not rootless).
+    </para>
+    <para>
+      In rootful mode, the foreign window system as a whole is represented as a
+      window (or more) of its own. You have a native window, inside which all
+      the foreign windows are. The advantage of this approach in Xwayland's
+      case is that you can run your favourite X11 window manager to manage your
+      X11 applications. The disadvantage is that the foreign windows do not
+      integrate with the native desktop. Therefore this mode is not usually
+      used.
+    </para>
+    <para>
+      In rootless mode, each foreign window is a first-class resident among the
+      native windows. Foreign windows are not confined inside a native window
+      but act as if they were native windows. The advantage is that one can
+      freely stack and mix native and foreign windows, which is not possible in
+      rootful mode. The disadvantage is that this mode is harder to implement
+      and fundamental differences in window systems may prevent some things
+      from working. With rootless Xwayland, the Wayland compositor must take
+      the role as the X11 window manager, and one cannot use any other X11
+      window manager in its place.
+    </para>
+    <para>
+      This chapter concentrates on the rootless mode, and ignores the rootful
+      mode.
+    </para>
+  </section>
+  <section id="sect-X11-Application-Support-architecture">
+    <title>Architecture</title>
+    <para>
+      A Wayland compositor usually takes care of launching Xwayland.
+      Xwayland works in cooperation with a Wayland compositor as follows:
+    </para>
+    <figure>
+      <title>Xwayland architecture diagram</title>
+      <mediaobjectco>
+	<imageobjectco>
+	  <imageobject>
+	    <imagedata fileref="images/xwayland-architecture.png" format="PNG" />
+	  </imageobject>
+	</imageobjectco>
+      </mediaobjectco>
+    </figure>
+    <para>
+      An X11 application connects to Xwayland just like it would connect to any
+      X server. Xwayland processes all the X11 requests. On the other end,
+      Xwayland is a Wayland client that connects to the Wayland compositor.
+    </para>
+    <para>
+      The X11 window manager (XWM) is an integral part of the Wayland
+      compositor. XWM uses the usual X11 window management protocol to manage
+      all X11 windows in Xwayland. Most importantly, XWM acts as a bridge
+      between Xwayland window state and the Wayland compositor's window manager
+      (WWM). This way WWM can manage all windows, both native Wayland and X11
+      (Xwayland) windows. This is very important for a coherent user
+      experience.
+    </para>
+    <para>
+      Since Xwayland uses Wayland for input and output, it does not have any
+      use for the device drivers that Xorg uses. None of the xf86-video-* or
+      xf86-input-* modules are used. There also is no configuration file for
+      the Xwayland server. For optional hardware accelerated rendering,
+      Xwayland uses GLAMOR.
+    </para>
+    <para>
+      A Wayland compositor usually spawns only one Xwayland instance. This is
+      because many X11 applications assume they can communicate with other X11
+      applications through the X server, and this requires a shared X server
+      instance. This also means that Xwayland does not protect nor isolate X11
+      clients from each other, unless the Wayland compositor specifically
+      chooses to break the X11 client intercommunications by spawning
+      application specific Xwayland instances. X11 clients are naturally
+      isolated from Wayland clients.
+    </para>
+    <para>
+      Xwayland compatibility compared to a native X server will probably never
+      reach 100%. Desktop environment (DE) components, specifically X11 window
+      managers, are practically never supported. An X11 window manager would
+      not know about native Wayland windows, so it could manage only X11
+      windows. On the other hand, there must be an XWM that reserves the
+      exclusive window manager role so that the Wayland compositor could show
+      the X11 windows appropriately. For other DE components, like pagers and
+      panels, adding the necessary interfaces to support them in WWM through XWM
+      is often considered not worthwhile.
+    </para>
+  </section>
+  <section id="sect-X11-Application-Support-xwm">
+    <title>X Window Manager (XWM)</title>
+    <para>
+      From the X11 point of view, the X window manager (XWM) living inside a
+      Wayland compositor is just like any other window manager. The difference
+      is mostly in which process it resides in, and the few extra conventions
+      in the X11 protocol to support Wayland window management (WWM)
+      specifically.
+    </para>
+    <para>
+      There are two separate asynchronous communication channels between
+      Xwayland and a Wayland compositor: one uses the Wayland protocol, and the
+      other one, solely for XWM, uses X11 protocol. This setting demands great
+      care from the XWM implementation to avoid (random) deadlocks with
+      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 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.
+      </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.
+      </para>
+    </section>
+  </section>
+</chapter>
diff --git a/subprojects/wayland/doc/publican/sources/css/brand.css b/subprojects/wayland/doc/publican/sources/css/brand.css
new file mode 100644
index 0000000000000000000000000000000000000000..d86cba937909435f5cf731e075fef4994cf0dae8
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/css/brand.css
@@ -0,0 +1,14 @@
+/*headings*/
+h1, h2, h3, h4, h5, h6,
+div.producttitle,
+div.subtitle,
+div.author div.author,
+div.translator div.translator,
+div.othercredit div.othercredit,
+div.editor div.editor,
+div.contrib div.contrib,
+.title,
+.titlepage .edition,
+.titlepage .releaseinfo {
+	color: #336699;
+}
diff --git a/subprojects/wayland/doc/publican/sources/css/common.css b/subprojects/wayland/doc/publican/sources/css/common.css
new file mode 100644
index 0000000000000000000000000000000000000000..a05648ef59481afe827e9c1c6fbf95567dc45c35
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/css/common.css
@@ -0,0 +1,1769 @@
+* {
+	widows: 4 !important;
+	orphans: 4 !important;
+}
+
+body, h1, h2, h3, h4, h5, h6, pre, li, div {
+	line-height: 1.29em;
+}
+
+body {
+	background-color: white;
+	margin:0 auto;
+	font-family: "liberation sans", "Myriad ", "Bitstream Vera Sans", "Lucida Grande", "Luxi Sans", "Trebuchet MS", helvetica, verdana, arial, sans-serif;
+	font-size: 14px;
+	max-width: 770px;
+	color: black;
+}
+
+body.toc_embeded {
+	/*for web hosting system only*/
+	margin-left: 300px;
+}
+
+object.toc, iframe.toc {
+	/*for web hosting system only*/
+	border-style: none;
+	position: fixed;
+	width: 290px;
+	height: 99.99%;
+	top: 0;
+	left: 0;
+	z-index: 100;
+	border-style: none;
+	border-right:1px solid #999;
+}
+
+/* Hide web menu */
+
+body.notoc {
+	margin-left: 3em;
+}
+
+iframe.notoc {
+	border-style:none;
+	border: none;
+	padding: 0px;
+	position:fixed;
+	width: 21px;
+	height: 29px;
+	top: 0px;
+	left:0;
+	overflow: hidden;
+	margin: 0px;
+	margin-left: -3px;
+}
+/* End hide web menu */
+
+/* desktop styles */
+body.desktop {
+	margin-left: 26em;
+}
+
+body.desktop .book > .toc {
+	display:block;
+	width:24em;
+	height:99.99%;
+	position:fixed;
+	overflow:auto;
+	top:0px;
+	left:0px;
+/*	padding-left:1em; */
+	background-color:#EEEEEE;
+	font-size: 12px;
+}
+
+body.pdf {
+	max-width: 100%;
+}
+
+.toc {
+	line-height:1.35em;
+}
+
+.toc .glossary,
+.toc .chapter, .toc .appendix {
+	margin-top:1em;
+}
+
+.toc .part {
+	margin-top:1em;
+	display:block;
+}
+
+span.glossary,
+span.appendix {
+	display:block;
+	margin-top:0.5em;
+}
+
+div {
+	padding-top:0px;
+}
+
+div.section {
+	page-break-inside: avoid;
+}
+
+p, div.para {
+	padding-top: 0px;
+	margin-top: 1em;
+	padding-bottom: 0px;
+	margin-bottom: 1em;
+}
+
+div.formalpara {
+	padding-top: 0px;
+	margin-top: 1em;
+	padding-bottom: 0px;
+	margin-bottom: 1em;
+}
+
+.varlistentry div.para {
+	page-break-before: avoid;
+
+}
+
+/*Links*/
+a {
+	outline: none;
+}
+
+a:link {
+	text-decoration: none;
+	border-bottom: 1px dotted ;
+	color:#3366cc;
+}
+
+body.pdf a:link {
+	word-wrap: break-word;
+}
+
+a:visited {
+	text-decoration:none;
+	border-bottom: 1px dotted ;
+	color:#003366;
+}
+
+div.longdesc-link {
+	float:right;
+	color:#999;
+}
+
+.toc a, .qandaset a {
+	font-weight:normal;
+	border:none;
+}
+
+.toc a:hover, .qandaset a:hover
+{
+	border-bottom: 1px dotted;
+}
+
+/*headings*/
+h1, h2, h3, h4, h5, h6 {
+	color: #336699;
+	margin-top: 0px;
+	margin-bottom: 0px;
+	background-color: transparent;
+	margin-bottom: 0px;
+	margin-top: 20px;
+	page-break-inside: avoid;
+	page-break-after: avoid;
+	word-wrap: break-word;
+}
+
+h1 {
+	font-size: 22px;
+}
+
+.titlepage h1.title {
+	text-align:left;
+}
+
+.book > .titlepage h1.title {
+	text-align: center;
+}
+
+.article > .titlepage h1.title,
+.article > .titlepage h2.title {
+	text-align: center;
+}
+
+.set .titlepage > div > div > h1.title {
+	text-align: center;
+}
+
+.part > .titlepage h1.title {
+	text-align: center;
+	font-size: 24px;
+}
+
+div.producttitle {
+	margin-top: 0px;
+	margin-bottom: 20px;
+	font-size: 48px;
+	font-weight: bold;
+/* 	background: #003d6e url(../images/h1-bg.png) top left repeat-x; */
+	color:  #336699;
+	text-align: center;
+	padding-top: 12px;
+}
+
+.titlepage .corpauthor {
+	margin-top: 1em;
+	text-align: center;
+}
+
+.section h1.title {
+	font-size: 18px;
+	padding: 0px;
+	color: #336699;
+	text-align: left;
+	background: white;
+}
+
+h2 {
+	font-size: 20px;
+	margin-top: 30px;
+}
+
+
+.book div.subtitle, .book h2.subtitle, .book h3.subtitle {
+	margin-top: 1em;
+	margin-bottom: 1em;
+	font-size: 18px;
+	text-align: center;
+}
+
+div.subtitle {
+	color:  #336699;
+	font-weight: bold;
+}
+
+h1.legalnotice {
+	font-size: 24px;
+}
+
+.preface > div > div > div > h2.title,
+.preface > div > div > div > h1.title {
+	margin-top: 1em;
+	font-size: 24px;
+}
+
+.appendix h2 {
+	font-size: 24px;
+}
+
+
+
+h3 {
+	font-size: 14px;
+	padding-top:0px;
+	padding-bottom: 0px;
+	margin-bottom: 0px;
+}
+h4 {
+	font-size: 14px;
+	padding-top:0px;
+	padding-bottom:0px;
+}
+
+h5 {
+	font-size: 14px;
+}
+
+h6 {
+	font-size: 14px;
+	margin-bottom: 0px;
+}
+
+.abstract h6 {
+	margin-top:1em;
+	margin-bottom:.5em;
+	font-size: 24px;
+}
+
+.index > div > div > div > h2.title {
+	font-size: 24px;
+}
+
+.chapter > div > div > div > h2.title {
+	font-size: 24px;
+}
+
+.section > div > div > div > h2.title {
+	font-size: 21px;
+	page-break-inside: avoid;
+	page-break-before: avoid;
+	page-break-after: avoid;
+}
+
+.section > div > div > div > h3.title {
+	font-size: 17px;
+}
+
+/*element rules*/
+hr {
+	border-collapse: collapse;
+	border-style:none;
+	border-top: 1px dotted #ccc;
+	width:100%;
+}
+
+/* web site rules */
+ul.languages, .languages li {
+	display:inline;
+	padding:0px;
+}
+
+.languages li a {
+	padding:0px .5em;
+	text-decoration: none;
+}
+
+.languages li p, .languages li div.para {
+	display:inline;
+}
+
+.languages li a:link, .languages li a:visited {
+	color:#444;
+}
+
+.languages li a:hover, .languages li a:focus, .languages li a:active {
+	color:black;
+}
+
+ul.languages {
+	display:block;
+	background-color:#eee;
+	padding:.5em;
+}
+
+/*supporting stylesheets*/
+
+/*unique to the webpage only*/
+.books {
+	position:relative;
+}
+
+.versions li {
+	width:100%;
+	clear:both;
+	display:block;
+}
+
+a.version {
+	font-size: 20px;
+	text-decoration:none;
+	width:100%;
+	display:block;
+	padding:1em 0px .2em 0px;
+	clear:both;
+}
+
+a.version:before {
+	content:"Version";
+	font-size: smaller;
+}
+
+a.version:visited, a.version:link {
+	color:#666;
+}
+
+a.version:focus, a.version:hover {
+	color:black;
+}
+
+.books {
+	display:block;
+	position:relative;
+	clear:both;
+	width:100%;
+}
+
+.books li {
+	display:block;
+	width:200px;
+	float:left;
+	position:relative;
+	clear: none ;
+}
+
+.books .html {
+	width:170px;
+	display:block;
+}
+
+.books .pdf {
+	position:absolute;
+	left:170px;
+	top:0px;
+	font-size: smaller;
+}
+
+.books .pdf:link, .books .pdf:visited {
+	color:#555;
+}
+
+.books .pdf:hover, .books .pdf:focus {
+	color:#000;
+}
+
+.books li a {
+	text-decoration:none;
+}
+
+.books li a:hover {
+	color:black;
+}
+
+/*products*/
+.products li {
+	display: block;
+	width:300px;
+	float:left;
+}
+
+.products li a {
+	width:300px;
+	padding:.5em 0px;
+}
+
+.products ul {
+	clear:both;
+}
+
+/*revision history*/
+.revhistory {
+	display:block;
+}
+
+.revhistory table {
+	background-color:transparent;
+	border-color:#fff;
+	padding:0px;
+	margin: 0;
+	border-collapse:collapse;
+	border-style:none;
+}
+
+.revhistory td {
+	text-align :left;
+	padding:0px;
+	border: none;
+	border-top: 1px solid #fff;
+	font-weight: bold;
+}
+
+.revhistory .simplelist td {
+	font-weight: normal;
+}
+
+.revhistory .simplelist {
+	margin-bottom: 1.5em;
+	margin-left: 1em;
+}
+
+.revhistory table th {
+	display: none;
+}
+
+
+/*credits*/
+.authorgroup div {
+	clear:both;
+	text-align: center;
+}
+
+div.author div.author,
+div.translator div.translator,
+div.othercredit div.othercredit,
+div.editor div.editor,
+div.contrib div.contrib {
+	margin: 0px;
+	padding: 0px;
+	margin-top: 12px;
+	font-size: 14px;
+	font-weight: bold;
+	color: #336699;
+}
+
+div.editedby {
+	margin-top: 15px;
+	margin-bottom: -0.8em;
+}
+
+div.authorgroup .author,
+div.authorgroup.editor,
+div.authorgroup.translator,
+div.authorgroup.othercredit,
+div.authorgroup.contrib {
+	display: block;
+	font-size: 14px;
+	page-break-inside: avoid;
+}
+
+.revhistory .author {
+	display: inline;
+}
+
+.othercredit h3 {
+	padding-top: 1em;
+}
+
+
+.othercredit {
+	margin:0px;
+	padding:0px;
+}
+
+.releaseinfo {
+	clear: both;
+}
+
+.copyright {
+	margin-top: 1em;
+}
+
+/* qanda sets */
+.answer {
+	margin-bottom:1em;
+	border-bottom:1px dotted #ccc;
+}
+
+.qandaset .toc {
+	border-bottom:1px dotted #ccc;
+}
+
+.question {
+	font-weight:bold;
+}
+
+.answer .data, .question .data {
+	padding-left: 2.6em;
+}
+
+.answer .label, .question .label {
+	float:left;
+	font-weight:bold;
+}
+
+/* inline syntax highlighting */
+.perl_Alert {
+	color: #0000ff;
+}
+
+.perl_BaseN {
+	color: #007f00;
+}
+
+.perl_BString {
+	color: #5C3566;
+}
+
+.perl_Char {
+	color: #ff00ff;
+}
+
+.perl_Comment {
+	color: #888888;
+}
+
+
+.perl_DataType {
+	color: #0000ff;
+}
+
+
+.perl_DecVal {
+	color: #00007f;
+}
+
+
+.perl_Error {
+	color: #ff0000;
+}
+
+
+.perl_Float {
+	color: #00007f;
+}
+
+
+.perl_Function {
+	color: #007f00;
+}
+
+
+.perl_IString {
+	color: #5C3566;
+}
+
+
+.perl_Keyword {
+	color: #002F5D;
+}
+
+
+.perl_Operator {
+	color: #ffa500;
+}
+
+
+.perl_Others {
+	color: #b03060;
+}
+
+
+.perl_RegionMarker {
+	color: #96b9ff;
+}
+
+
+.perl_Reserved {
+	color: #9b30ff;
+}
+
+
+.perl_String {
+	color: #5C3566;
+}
+
+
+.perl_Variable {
+	color: #0000ff;
+}
+
+
+.perl_Warning {
+	color: #0000ff;
+}
+
+/*Lists*/
+ul {
+    list-style-image: url("../images/dot.png");
+    list-style-type: circle;
+    padding-left: 1.6em;
+}
+
+ul ul {
+    list-style-image: url("../images/dot2.png");
+    list-style-type: circle;
+}
+
+ol.1 {
+	list-style-type: decimal;
+}
+
+ol.a,
+ol ol {
+	list-style-type: lower-alpha;
+}
+
+ol.i {
+	list-style-type: lower-roman;
+}
+ol.A {
+	list-style-type: upper-alpha;
+}
+
+ol.I {
+	list-style-type: upper-roman;
+}
+
+dt {
+	font-weight:bold;
+	margin-bottom:0px;
+	padding-bottom:0px;
+}
+
+dd {
+	margin:0px;
+	margin-left:2em;
+	padding-top:0px;
+}
+
+li {
+	padding-top: 0px;
+	margin-top: 0px;
+	padding-bottom: 0px;
+/*	margin-bottom: 16px; */
+}
+
+/*images*/
+img {
+	display:block;
+	margin: 2em 0;
+	max-width: 100%;
+}
+
+.inlinemediaobject,
+.inlinemediaobject img,
+.inlinemediaobject object {
+	display:inline;
+	margin:0px;
+	overflow: hidden;
+}
+
+.figure {
+    margin-top: 1em;
+    width: 100%;
+}
+
+.figure img,
+.mediaobject img {
+	display:block;
+	margin: 0em;
+	page-break-inside: avoid;
+}
+
+.figure .title {
+	margin-bottom:2em;
+	padding:0px;
+}
+
+/*document modes*/
+.confidential {
+	background-color:#900;
+	color:White;
+	padding:.5em .5em;
+	text-transform:uppercase;
+	text-align:center;
+}
+
+.longdesc-link {
+	display:none;
+}
+
+.longdesc {
+	display:none;
+}
+
+.prompt {
+	padding:0px .3em;
+}
+
+/*user interface styles*/
+.screen .replaceable {
+}
+
+.guibutton, .guilabel {
+	font-family: "liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+	font-weight: bold;
+}
+
+.example {
+	background-color: #ffffff;
+	border-left: 3px solid #aaaaaa;
+	padding-top: 1px;
+	padding-bottom: 0.1em;
+	padding-left: 1em;
+}
+
+.equation {
+	border-left: 3px solid #aaaaaa;
+	background-color: #ffffff;
+	padding-top: 1px;
+	padding-bottom: 0.1em;
+	padding-left: 1em;
+}
+
+.equation-contents {
+	margin-left: 4em;
+}
+
+div.title {
+	margin-bottom: 1em;
+	font-weight: 14px;
+	font-weight: bold;
+	color: #336699;
+	page-break-inside: avoid;
+	page-break-after: avoid;
+	word-wrap: break-word;
+}
+
+.example-contents {
+	background-color: #ffffff;
+}
+
+.example-contents .para {
+/*	 padding: 10px;*/
+}
+
+/*terminal/console text*/
+.computeroutput,
+.option {
+	font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+	font-weight:bold;
+}
+
+.replaceable {
+	font-style: italic;
+}
+
+.command, .filename, .keycap, .classname, .literal {
+	font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+	font-weight:bold;
+}
+
+/* no bold in toc */
+.toc * {
+	font-weight: inherit;
+}
+
+.toc H1 {
+	font-weight: bold;
+}
+
+
+div.programlisting {
+	white-space: pre-wrap; /* css-3 */
+	white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+	white-space: -pre-wrap; /* Opera 4-6 */
+	white-space: -o-pre-wrap; /* Opera 7 */
+	word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+pre {
+	font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+	display:block;
+	background-color: #f5f5f5;
+	color: #000000;
+/*	border: 1px solid #aaaaaa; */
+	margin-bottom: 1em;
+	padding:.5em 1em;
+	white-space: pre-wrap; /* css-3 */
+	white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+	white-space: -pre-wrap; /* Opera 4-6 */
+	white-space: -o-pre-wrap; /* Opera 7 */
+	word-wrap: break-word; /* Internet Explorer 5.5+ */
+	font-size: 0.9em;
+	border-style:none;
+	box-shadow: 0 2px 5px #AAAAAA inset;
+	-moz-box-shadow:  0 2px 5px #AAAAAA inset;
+	-webkit-box-shadow: 0 2px 5px #AAAAAA inset;
+	-o-box-shadow: 0 2px 5px #AAAAAA inset;
+}
+
+body.pdf pre {
+	border: 1px solid #AAAAAA;
+	box-shadow: none;
+	-moz-box-shadow: none;
+	-webkit-box-shadow: none;
+	-o-box-shadow: none;
+}
+
+
+pre .replaceable,
+pre .keycap {
+}
+
+code {
+	font-family:"liberation mono", "bitstream vera mono", "dejavu mono", monospace;
+	white-space: pre-wrap;
+	word-wrap: break-word;
+	font-weight:bold;
+}
+
+.parameter code {
+	display: inline;
+	white-space: pre-wrap; /* css-3 */
+	white-space: -moz-pre-wrap !important; /* Mozilla, since 1999 */
+	white-space: -pre-wrap; /* Opera 4-6 */
+	white-space: -o-pre-wrap; /* Opera 7 */
+	word-wrap: break-word; /* Internet Explorer 5.5+ */
+}
+
+code.email {
+	font-weight: normal;
+	font-family: "liberation sans", "Myriad ", "Bitstream Vera Sans", "Lucida Grande", "Luxi Sans", "Trebuchet MS", helvetica, verdana, arial, sans-serif;
+
+}
+
+/*Notifications*/
+div.warning:before {
+	content:url(../images/warning.png);
+	padding-left: 5px;
+}
+
+div.note:before {
+	content:url(../images/note.png);
+	padding-left: 5px;
+}
+
+div.important:before {
+	content:url(../images/important.png);
+	padding-left: 5px;
+}
+
+div.warning, div.note, div.important {
+	color: black;
+	margin: 0px;
+	padding: 0px;
+	background: none;
+	background-color: white;
+	margin-bottom: 1em;
+	border-bottom: 1px solid #aaaaaa;
+	page-break-inside: avoid;
+}
+
+div.admonition_header p {
+	margin: 0px;
+	padding: 0px;
+	color: #eeeeec;
+	padding-top: 0px;
+	padding-bottom: 0px;
+	height: 1.4em;
+	line-height: 1.4em;
+	font-size: 17px;
+	display:inline;
+}
+
+div.admonition_header {
+	background-origin:content-box;
+	clear: both;
+	margin: 0px;
+	padding: 0px;
+	margin-top: -40px;
+	padding-left: 58px;
+	line-height: 1.0px;
+	font-size: 1.0px;
+}
+
+div.warning div.admonition_header {
+	background: url(../images/red.png) top left repeat-x;
+	background-color: #590000;
+	background: -webkit-linear-gradient(#a40000,#590000);
+	background: linear-gradient(#a40000,#590000);
+}
+
+div.note div.admonition_header {
+	background: url(../images/green.png) top right repeat-x;
+	background-color: #597800;
+	background: -webkit-linear-gradient(#769f00,#597800);
+	background: linear-gradient(#769f00,#597800);
+}
+
+div.important div.admonition_header {
+	background: url(../images/yellow.png) top right repeat-x;
+	background-color: #a6710f;
+	background: -webkit-linear-gradient(#d08e13,#a6710f);
+	background: linear-gradient(#d08e13,#a6710f);
+}
+
+div.warning p:first-child,
+div.warning div.para:first-child,
+div.note p:first-child,
+div.note div.para:first-child,
+div.important p:first-child,
+div.important div.para:first-child {
+	padding: 0px;
+	margin: 0px;
+}
+
+div.admonition {
+	border: none;
+	border-left: 1px solid #aaaaaa;
+	border-right: 1px solid #aaaaaa;
+	padding:0px;
+	margin:0px;
+	padding-top: 1.5em;
+	padding-bottom: 1em;
+	padding-left: 2em;
+	padding-right: 1em;
+	background-color: #eeeeec;
+	-moz-border-radius: 0px;
+	-webkit-border-radius: 0px;
+	border-radius: 0px;
+}
+
+/*Page Title*/
+#title  {
+	display:block;
+	height:45px;
+	padding-bottom:1em;
+	margin:0px;
+}
+
+#title a.left{
+	display:inline;
+	border:none;
+}
+
+#title a.left img{
+	border:none;
+	float:left;
+	margin:0px;
+	margin-top:.7em;
+}
+
+#title a.right {
+	padding-bottom:1em;
+}
+
+#title a.right img {
+	border:none;
+	float:right;
+	margin:0px;
+	margin-top:.7em;
+}
+
+/*Table*/
+div.table {
+/*	page-break-inside: avoid; */
+}
+
+table {
+	border: 1px solid #444;
+	width:100%;
+	border-collapse:collapse;
+	table-layout: fixed;
+	word-wrap: break-word;
+}
+
+table.blockquote,
+table.simplelist,
+.calloutlist table {
+	border-style: none;
+}
+
+table th {
+	text-align:left;
+	background-color:#6699cc;
+	padding:.3em .5em;
+	color:white;
+}
+
+table td {
+	padding:.15em .5em;
+}
+
+table tr.even td {
+	background-color:#f5f5f5;
+}
+
+tr:nth-child(even) {
+	background-color: #eeeeee;
+
+}
+
+
+table th p:first-child, table td p:first-child, table  li p:first-child,
+table th div.para:first-child, table td div.para:first-child, table  li div.para:first-child {
+	margin-top:0px;
+	padding-top:0px;
+	display:inline;
+}
+
+th, td {
+	border-style:none;
+	vertical-align: top;
+/* 	border: 1px solid #000; */
+}
+
+.blockquote td,
+.simplelist th,
+.simplelist td {
+	border: none;
+}
+
+table table td {
+	border-bottom:1px dotted #aaa;
+	background-color:white;
+	padding:.6em 0px;
+}
+
+table table {
+	border:1px solid white;
+}
+
+td.remarkval {
+	color:#444;
+}
+
+td.fieldval {
+	font-weight:bold;
+}
+
+.lbname, .lbtype, .lbdescr, .lbdriver, .lbhost {
+	color:white;
+	font-weight:bold;
+	background-color:#999;
+	width:120px;
+}
+
+td.remarkval {
+	width:230px;
+}
+
+td.tname {
+	font-weight:bold;
+}
+
+th.dbfield {
+	width:120px;
+}
+
+th.dbtype {
+	width:70px;
+}
+
+th.dbdefault {
+	width:70px;
+}
+
+th.dbnul {
+	width:70px;
+}
+
+th.dbkey {
+	width:70px;
+}
+
+span.book {
+	margin-top:4em;
+	display:block;
+	font-size: 11pt;
+}
+
+span.book a{
+	font-weight:bold;
+}
+span.chapter {
+	display:block;
+}
+
+table.simplelist td, .calloutlist table td {
+	border-style: none;
+}
+
+
+table.lt-4-cols.lt-7-rows td {
+	border: none;
+}
+/*to simplify layout*/
+
+
+table.lt-4-cols.gt-14-rows tr:nth-child(odd) {
+	background-color: #fafafa;
+}
+/* to keep simple but stripe rows */
+
+
+.gt-8-cols td {
+	border-left: 1px solid #ccc;
+}
+
+.gt-8-cols td:first-child {
+	border-left: 0;
+}
+/* to apply vertical lines to differentiate columns*/
+
+/*Breadcrumbs*/
+#breadcrumbs ul li.first:before {
+	content:" ";
+}
+
+#breadcrumbs {
+	color:#900;
+	padding:3px;
+	margin-bottom:25px;
+}
+
+#breadcrumbs ul {
+	margin-left:0;
+	padding-left:0;
+	display:inline;
+	border:none;
+}
+
+#breadcrumbs ul li {
+	margin-left:0;
+	padding-left:2px;
+	border:none;
+	list-style:none;
+	display:inline;
+}
+
+#breadcrumbs ul li:before {
+	content:"\0020 \0020 \0020 \00BB \0020";
+	color:#333;
+}
+
+dl {
+	margin-top: 0px;
+	margin-left: 28px;
+}
+
+.toc dl {
+	margin-left: 10px;
+}
+
+/*index*/
+.glossary h3,
+.index h3 {
+	font-size: 20px;
+	color:#aaa;
+	margin:0px;
+}
+
+.indexdiv {
+	margin-bottom:1em;
+}
+
+.glossary dt,
+.index dt {
+	color:#444;
+	padding-top:.5em;
+}
+
+.glossary dl dl dt,
+.index dl dl dt {
+	color:#777;
+	font-weight:normal;
+	padding-top:0px;
+}
+
+.index dl dl dt:before {
+	content:"- ";
+	color:#ccc;
+}
+
+/*changes*/
+.footnote {
+	font-size: 10px;
+	margin: 0px;
+	color: #222;
+}
+
+.footnotes {
+	margin-bottom: 60px;
+}
+
+table .footnote {
+}
+
+sup {
+	margin:0px;
+	padding:0px;
+	font-size: 10px;
+	padding-left:0px;
+}
+
+.footnote {
+	position:relative;
+}
+
+.footnote sup  {
+	color: black;
+	left: .4em;
+}
+
+.footnote a:link,
+.footnote a:visited {
+	text-decoration:none;
+	border: none;
+}
+
+.footnote .para sup  {
+/*	position:absolute; */
+	vertical-align:text-bottom;
+}
+
+a.footnote {
+	padding-right: 0.5em;
+	text-decoration:none;
+	border: none;
+}
+
+.footnote sup a:link,
+.footnote sup a:visited {
+	color:#92917d;
+	text-decoration:none;
+}
+
+.footnote:hover sup a {
+	text-decoration:none;
+}
+
+.footnote p,.footnote div.para {
+	padding-left:1em;
+}
+
+.footnote a:link,
+.footnote a:visited before{
+	color:#00537c;
+}
+
+.footnote a:hover {
+}
+
+/**/
+.pdf-break {
+	page-break-before: always;
+}
+
+div.legalnotice {
+	page-break-before: always;
+}
+
+div.abstract {
+	page-break-before: always;
+/*	page-break-after: always;*/
+}
+
+div.chapter {
+	page-break-before: always;
+}
+
+
+div.titlepage, div.titlepage > div, div.titlepage > div > div {
+	page-break-inside: avoid;
+	page-break-after: avoid;
+}
+
+div.preface, div.part {
+	page-break-before: always;
+}
+
+div.appendix {
+	page-break-before: always;
+}
+
+div.section {
+	page-break-inside: auto;
+	page-break-before: auto;
+	page-break-after: auto;
+}
+
+
+dt.varlistentry {
+	page-break-inside: avoid;
+	page-break-after: avoid;
+}
+
+dd {
+	page-break-before: avoid;
+}
+
+div.note .replaceable,
+div.important .replaceable,
+div.warning .replaceable,
+div.note .keycap,
+div.important .keycap,
+div.warning .keycap
+{
+}
+
+ul li p:last-child, ul li para:last-child {
+	margin-bottom:0px;
+	padding-bottom:0px;
+}
+
+/*document navigation*/
+.docnav a, .docnav strong {
+	border:none;
+	text-decoration:none;
+	font-weight:normal;
+}
+
+.docnav {
+	list-style:none;
+	margin:0px;
+	padding:0px;
+	position:relative;
+	width:100%;
+	padding-bottom:2em;
+	padding-top:1em;
+        height:2.5em;
+        line-height:2.5em;
+/*
+	border-top:1px dotted #ccc;
+        background-color: rgba(240, 240, 240, 0.9);
+-webkitbox-shadow: 0px .15em .5em rgba(0,0,0,0.2);
+  -moz-box-shadow: 0px .15em .5em rgba(0,0,0,0.2);
+       box-shadow: 0px .15em .5em rgba(0,0,0,0.2);
+*/
+}
+
+.docnav li {
+	list-style:none;
+	margin:0px;
+	padding:0px;
+	display:inline;
+	font-size: 14px;
+}
+
+.docnav li:before {
+	content:" ";
+}
+
+.docnav li.previous, .docnav li.next {
+	position:absolute;
+	top:1.5em;
+}
+
+.docnav li.up, .docnav li.home {
+	margin:0px 1.5em;
+}
+
+.docnav.top li.home {
+	color: #336699;
+	font-size: 22pt;
+	font-weight: bold;
+}
+
+
+.docnav li.previous {
+	left:0px;
+	text-align:left;
+}
+
+.docnav li.next {
+	right:0px;
+	text-align:right;
+}
+
+.docnav li.previous strong, .docnav li.next strong {
+	height: 17px;
+	display: block;
+}
+
+.docnav {
+	margin:0 auto;
+	text-align:center;
+}
+
+.docnav li.next a strong {
+	background:  url(../images/stock-go-forward.png) right 120% no-repeat;
+	padding-top:3px;
+	padding-bottom:4px;
+	padding-right:28px;
+}
+
+.docnav li.previous a strong {
+	background: url(../images/stock-go-back.png) left 120% no-repeat;
+	padding-top:3px;
+	padding-bottom:4px;
+	padding-left:28px;
+	padding-right:0.5em;
+}
+
+.docnav li.home a strong {
+	background: url(../images/stock-home.png) top left no-repeat;
+	padding:5px;
+	padding-left:28px;
+}
+
+.docnav li.up a strong {
+	background: url(../images/stock-go-up.png) top left no-repeat;
+	padding:5px;
+	padding-left:28px;
+}
+
+.docnav a:link, .docnav a:visited {
+	color:#666;
+}
+
+.docnav a:hover, .docnav a:focus, .docnav a:active {
+	color:black;
+}
+
+.docnav a {
+	max-width: 10px;
+	overflow:hidden;
+}
+
+.docnav a:link strong {
+	text-decoration:none;
+}
+
+.docnav {
+	margin:0 auto;
+	text-align:center;
+}
+
+ul.docnav {
+	margin-bottom: 1em;
+}
+/* Reports */
+.reports ul {
+	list-style:none;
+	margin:0px;
+	padding:0px;
+}
+
+.reports li{
+	margin:0px;
+	padding:0px;
+}
+
+.reports li.odd {
+	background-color: #eeeeee;
+	margin:0px;
+	padding:0px;
+}
+
+.reports dl {
+	display:inline;
+	margin:0px;
+	padding:0px;
+	float:right;
+	margin-right: 17em;
+	margin-top:-1.3em;
+}
+
+.reports dt {
+	display:inline;
+	margin:0px;
+	padding:0px;
+}
+
+.reports dd {
+	display:inline;
+	margin:0px;
+	padding:0px;
+	padding-right:.5em;
+}
+
+.reports h2, .reports h3{
+	display:inline;
+	padding-right:.5em;
+	font-size: 14px;
+	font-weight:normal;
+}
+
+.reports div.progress {
+	display:inline;
+	float:right;
+	width:16em;
+	background:#c00 url(../images/shine.png) top left repeat-x;
+	margin:0px;
+	margin-top:-1.3em;
+	padding:0px;
+	border:none;
+}
+
+/*uniform*/
+body.results, body.reports {
+	max-width:57em ;
+	padding:0px;
+}
+
+/*Progress Bar*/
+div.progress {
+	display:block;
+	float:left;
+	width:16em;
+	background:#c00 url(../images/shine.png) top left repeat-x;
+	height:1em;
+}
+
+div.progress span {
+	height:1em;
+	float:left;
+}
+
+div.progress span.translated {
+	background:#6c3 url(../images/shine.png) top left repeat-x;
+}
+
+div.progress span.fuzzy {
+	background:#ff9f00 url(../images/shine.png) top left repeat-x;
+}
+
+
+/*Results*/
+
+.results ul {
+	list-style:none;
+	margin:0px;
+	padding:0px;
+}
+
+.results li{
+	margin:0px;
+	padding:0px;
+}
+
+.results li.odd {
+	background-color: #eeeeee;
+	margin:0px;
+	padding:0px;
+}
+
+.results dl {
+	display:inline;
+	margin:0px;
+	padding:0px;
+	float:right;
+	margin-right: 17em;
+	margin-top:-1.3em;
+}
+
+.results dt {
+	display:inline;
+	margin:0px;
+	padding:0px;
+}
+
+.results dd {
+	display:inline;
+	margin:0px;
+	padding:0px;
+	padding-right:.5em;
+}
+
+.results h2, .results h3 {
+	display:inline;
+	padding-right:.5em;
+	font-size: 14px;
+	font-weight:normal;
+}
+
+.results div.progress {
+	display:inline;
+	float:right;
+	width:16em;
+	background:#c00 url(../images/shine.png) top left repeat-x;
+	margin:0px;
+	margin-top:-1.3em;
+	padding:0px;
+	border:none;
+}
+
+/* Dirty EVIL Mozilla hack for round corners */
+pre {
+	-moz-border-radius:11px;
+	-webkit-border-radius:11px;
+	border-radius: 11px;
+/*	page-break-inside: avoid; */
+}
+
+.example {
+	-moz-border-radius:0px;
+	-webkit-border-radius:0px;
+	border-radius: 0px;
+	page-break-inside: avoid;
+}
+
+/* move these invisible fields out of the flow */
+.example > a:first-child,
+.table > a:first-child {
+    float: left;
+}
+
+.package, .citetitle {
+	font-style: italic;
+}
+
+.titlepage .edition,
+.titlepage .releaseinfo {
+	color: #336699;
+	background-color: transparent;
+	margin-top: 1em;
+	margin-bottom: 1em;
+	font-size: 20px;
+	font-weight: bold;
+	text-align: center;
+}
+
+span.remark {
+	background-color: #ff00ff;
+}
+
+.draft {
+	background-image: url(../images/watermark-draft.png);
+	background-repeat: repeat-y;
+        background-position: center;
+}
+
+.foreignphrase {
+	font-style: inherit;
+}
+
+dt {
+	clear:both;
+	page-break-inside: avoid;
+	page-break-after: avoid;
+}
+
+dt img {
+	border-style: none;
+	max-width: 112px;
+}
+
+dt object {
+	max-width: 112px;
+}
+
+dt .inlinemediaobject, dt object {
+	display: inline;
+	float: left;
+	margin-bottom: 1em;
+	padding-right: 1em;
+	width: 112px;
+}
+
+dl:after {
+	display: block;
+	clear: both;
+	content: "";
+}
+
+.toc dd {
+	padding-bottom: 0px;
+	margin-bottom: 1em;
+	padding-left: 1.3em;
+	margin-left: 0px;
+}
+
+div.toc > dl > dt {
+	padding-bottom: 0px;
+	margin-bottom: 0px;
+	margin-top: 1em;
+}
+
+
+.strikethrough {
+	text-decoration: line-through;
+}
+
+.underline {
+	text-decoration: underline;
+}
+
+.calloutlist img, .callout {
+	padding: 0px;
+	margin: 0px;
+	width: 12pt;
+	display: inline;
+	vertical-align: middle;
+}
+
+li.step > a:first-child {
+	display: block;
+}
+
+.stepalternatives {
+	list-style-image: none;
+	list-style-type: upper-alpha;
+}
+.task {
+/*	page-break-inside: avoid; */
+}
+
+
+.added {
+	background-color: #99ff99;
+}
+
+.changed {
+	background-color: #ffff77;
+}
+
+.deleted {
+	background-color: #ff4455;
+	text-decoration: line-through;
+}
diff --git a/subprojects/wayland/doc/publican/sources/css/default.css b/subprojects/wayland/doc/publican/sources/css/default.css
new file mode 100644
index 0000000000000000000000000000000000000000..bf38ebb59311a770914945ae9f98979a48506a7a
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/css/default.css
@@ -0,0 +1,3 @@
+@import url("common.css");
+@import url("overrides.css");
+@import url("lang.css");
diff --git a/subprojects/wayland/doc/publican/sources/css/epub.css b/subprojects/wayland/doc/publican/sources/css/epub.css
new file mode 100644
index 0000000000000000000000000000000000000000..b0ffd43cb791141b05f6d51c5a92179f5f07c012
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/css/epub.css
@@ -0,0 +1,115 @@
+/*headings*/
+h1, h2, h3, h4, h5, h6,
+div.producttitle,
+div.subtitle,
+div.author div.author,
+div.translator div.translator,
+div.othercredit div.othercredit,
+div.editor div.editor,
+div.contrib div.contrib,
+.title,
+.titlepage .edition {
+}
+
+div.para {
+	margin-top: 1em;
+}
+/* inline syntax highlighting */
+.perl_Alert {
+	color: #0000ff;
+}
+
+.perl_BaseN {
+	color: #007f00;
+}
+
+.perl_BString {
+	color: #5C3566;
+}
+
+.perl_Char {
+	color: #ff00ff;
+}
+
+.perl_Comment {
+	color: #888888;
+}
+
+
+.perl_DataType {
+	color: #0000ff;
+}
+
+
+.perl_DecVal {
+	color: #00007f;
+}
+
+
+.perl_Error {
+	color: #ff0000;
+}
+
+
+.perl_Float {
+	color: #00007f;
+}
+
+
+.perl_Function {
+	color: #007f00;
+}
+
+
+.perl_IString {
+	color: #5C3566;
+}
+
+
+.perl_Keyword {
+	color: #002F5D;
+}
+
+
+.perl_Operator {
+	color: #ffa500;
+}
+
+
+.perl_Others {
+	color: #b03060;
+}
+
+
+.perl_RegionMarker {
+	color: #96b9ff;
+}
+
+
+.perl_Reserved {
+	color: #9b30ff;
+}
+
+
+.perl_String {
+	color: #5C3566;
+}
+
+
+.perl_Variable {
+	color: #0000ff;
+}
+
+
+.perl_Warning {
+	color: #0000ff;
+}
+
+b, strong {
+	font-weight: bolder;
+}
+
+code.command {
+	font-family: monospace;
+	font-weight: bolder;
+}
diff --git a/subprojects/wayland/doc/publican/sources/css/print.css b/subprojects/wayland/doc/publican/sources/css/print.css
new file mode 100644
index 0000000000000000000000000000000000000000..54088f48d6d5010601dd88b34ce1e533f81cba95
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/css/print.css
@@ -0,0 +1,15 @@
+@import url("common.css");
+@import url("overrides.css");
+@import url("lang.css");
+
+#tocframe {
+	display: none;
+}
+
+body.toc_embeded {
+	margin-left: 30px;
+}
+
+.producttitle {
+	color: #336699;
+}
diff --git a/subprojects/wayland/doc/publican/sources/images/icon.svg b/subprojects/wayland/doc/publican/sources/images/icon.svg
new file mode 100644
index 0000000000000000000000000000000000000000..b2f16d0f61d039f7e50c344cdcdd544210cc418c
--- /dev/null
+++ b/subprojects/wayland/doc/publican/sources/images/icon.svg
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.0" width="32" height="32" id="svg3017">
+  <defs id="defs3019">
+    <linearGradient id="linearGradient2381">
+      <stop id="stop2383" style="stop-color:#ffffff;stop-opacity:1" offset="0"/>
+      <stop id="stop2385" style="stop-color:#ffffff;stop-opacity:0" offset="1"/>
+    </linearGradient>
+    <linearGradient x1="296.4996" y1="188.81061" x2="317.32471" y2="209.69398" id="linearGradient2371" xlink:href="#linearGradient2381" gradientUnits="userSpaceOnUse" gradientTransform="matrix(0.90776,0,0,0.90776,24.35648,49.24131)"/>
+  </defs>
+  <g transform="matrix(0.437808,-0.437808,0.437808,0.437808,-220.8237,43.55311)" id="g5089">
+    <path d="m 8.4382985,-6.28125 c -0.6073916,0 -4.3132985,5.94886271 -4.3132985,8.25 l 0,26.71875 c 0,0.846384 0.5818159,1.125 1.15625,1.125 l 25.5625,0 c 0.632342,0 1.125001,-0.492658 1.125,-1.125 l 0,-5.21875 0.28125,0 c 0.49684,0 0.906249,-0.409411 0.90625,-0.90625 l 0,-27.9375 c 0,-0.4968398 -0.40941,-0.90625 -0.90625,-0.90625 l -23.8117015,0 z" transform="translate(282.8327,227.1903)" id="path5091" style="fill:#5c5c4f;stroke:#000000;stroke-width:3.23021388;stroke-miterlimit:4;stroke-dasharray:none"/>
+    <rect width="27.85074" height="29.369793" rx="1.1414107" ry="1.1414107" x="286.96509" y="227.63805" id="rect5093" style="fill:#032c87"/>
+    <path d="m 288.43262,225.43675 25.2418,0 0,29.3698 -26.37615,0.0241 1.13435,-29.39394 z" id="rect5095" style="fill:#ffffff"/>
+    <path d="m 302.44536,251.73726 c 1.38691,7.85917 -0.69311,11.28365 -0.69311,11.28365 2.24384,-1.60762 3.96426,-3.47694 4.90522,-5.736 0.96708,2.19264 1.83294,4.42866 4.27443,5.98941 0,0 -1.59504,-7.2004 -1.71143,-11.53706 l -6.77511,0 z" id="path5097" style="fill:#a70000;fill-opacity:1;stroke-width:2"/>
+    <rect width="25.241802" height="29.736675" rx="0.89682275" ry="0.89682275" x="290.73544" y="220.92249" id="rect5099" style="fill:#809cc9"/>
+    <path d="m 576.47347,725.93939 6.37084,0.41502 0.4069,29.51809 c -1.89202,-1.31785 -6.85427,-3.7608 -8.26232,-1.68101 l 0,-26.76752 c 0,-0.82246 0.66212,-1.48458 1.48458,-1.48458 z" transform="matrix(0.499065,-0.866565,0,1,0,0)" id="rect5101" style="fill:#4573b3;fill-opacity:1"/>
+    <path d="m 293.2599,221.89363 20.73918,0 c 0.45101,0 0.8141,0.3631 0.8141,0.81411 0.21547,6.32836 -19.36824,21.7635 -22.36739,17.59717 l 0,-17.59717 c 0,-0.45101 0.3631,-0.81411 0.81411,-0.81411 z" id="path5103" style="opacity:0.65536726;fill:url(#linearGradient2371);fill-opacity:1"/>
+  </g>
+</svg>
diff --git a/subprojects/wayland/doc/publican/sources/images/wayland.png b/subprojects/wayland/doc/publican/sources/images/wayland.png
new file mode 100644
index 0000000000000000000000000000000000000000..c9937928ce9584a660ee10f7092eed2033f6eab8
Binary files /dev/null and b/subprojects/wayland/doc/publican/sources/images/wayland.png differ
diff --git a/subprojects/wayland/doc/publican/sources/images/xwayland-architecture.png b/subprojects/wayland/doc/publican/sources/images/xwayland-architecture.png
new file mode 100644
index 0000000000000000000000000000000000000000..f24dc1837f2e190c9d38719420a844aeb5997efa
Binary files /dev/null and b/subprojects/wayland/doc/publican/sources/images/xwayland-architecture.png differ
diff --git a/subprojects/wayland/doc/publican/sources/meson.build b/subprojects/wayland/doc/publican/sources/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..52f3a681310606527954fb5e2271977ece8165ce
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/egl/meson.build b/subprojects/wayland/egl/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..5363e80856764fac49b29a3cb4fdce3b0d4f4a7e
--- /dev/null
+++ b/subprojects/wayland/egl/meson.build
@@ -0,0 +1,60 @@
+wayland_egl = library(
+	'wayland-egl',
+	sources: [
+		'wayland-egl.c',
+		wayland_client_protocol_h
+	],
+	include_directories: src_inc,
+	version: meson.project_version(),
+	install: true
+)
+
+if get_option('tests')
+	wayland_egl_abi_check = executable('wayland-egl-abi-check', 'wayland-egl-abi-check.c')
+	test('wayland-egl abi check', wayland_egl_abi_check)
+
+	if get_option('default_library') != 'static'
+		nm_path = find_program(['llvm-nm', 'nm']).full_path()
+		wayland_egl_shared = wayland_egl
+		if get_option('default_library') == 'both'
+			wayland_egl_shared = wayland_egl.get_shared_lib()
+		endif
+		test(
+			'wayland-egl symbols check',
+			find_program('wayland-egl-symbols-check'),
+			env: [
+				'WAYLAND_EGL_LIB=@0@'.format(wayland_egl_shared.full_path()),
+				'NM=@0@'.format(nm_path)
+			]
+		)
+	endif
+endif
+
+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'
+)
+
+wayland_egl_dep = declare_dependency(
+	link_with: wayland_egl,
+	include_directories: [ root_inc, include_directories('.') ],
+)
+
+if meson.version().version_compare('>= 0.54.0')
+	meson.override_dependency('wayland-egl', wayland_egl_dep)
+endif
diff --git a/subprojects/wayland/egl/wayland-egl-abi-check.c b/subprojects/wayland/egl/wayland-egl-abi-check.c
new file mode 100644
index 0000000000000000000000000000000000000000..ea877d0e5428f451a7f9aa376c95b7d8c6decc74
--- /dev/null
+++ b/subprojects/wayland/egl/wayland-egl-abi-check.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice 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 <stddef.h> /* offsetof */
+#include <stdio.h>  /* printf */
+
+#include "wayland-egl-backend.h" /* Current struct wl_egl_window implementation */
+
+/*
+ * Following are previous implementations of wl_egl_window.
+ *
+ * DO NOT EVER CHANGE!
+ */
+
+/* From: 214fc6e850 - Benjamin Franzke : egl: Implement libwayland-egl */
+struct wl_egl_window_v0 {
+    struct wl_surface *surface;
+
+    int width;
+    int height;
+    int dx;
+    int dy;
+
+    int attached_width;
+    int attached_height;
+};
+
+/* From: ca3ed3e024 - Ander Conselvan de Oliveira : egl/wayland: Don't invalidate drawable on swap buffers */
+struct wl_egl_window_v1 {
+    struct wl_surface *surface;
+
+    int width;
+    int height;
+    int dx;
+    int dy;
+
+    int attached_width;
+    int attached_height;
+
+    void *private;
+    void (*resize_callback)(struct wl_egl_window *, void *);
+};
+
+/* From: 690ead4a13 - Stencel, Joanna : egl/wayland-egl: Fix for segfault in dri2_wl_destroy_surface. */
+#define WL_EGL_WINDOW_VERSION_v2 2
+struct wl_egl_window_v2 {
+    struct wl_surface *surface;
+
+    int width;
+    int height;
+    int dx;
+    int dy;
+
+    int attached_width;
+    int attached_height;
+
+    void *private;
+    void (*resize_callback)(struct wl_egl_window *, void *);
+    void (*destroy_window_callback)(void *);
+};
+
+/* From: 2d5d61bc49 - Miguel A. Vico : wayland-egl: Make wl_egl_window a versioned struct */
+#define WL_EGL_WINDOW_VERSION_v3 3
+struct wl_egl_window_v3 {
+    const intptr_t version;
+
+    int width;
+    int height;
+    int dx;
+    int dy;
+
+    int attached_width;
+    int attached_height;
+
+    void *driver_private;
+    void (*resize_callback)(struct wl_egl_window *, void *);
+    void (*destroy_window_callback)(void *);
+
+    struct wl_surface *surface;
+};
+
+
+/* This program checks we keep a backwards-compatible struct wl_egl_window
+ * definition whenever it is modified in wayland-egl-backend.h.
+ *
+ * The previous definition should be added above as a new struct
+ * wl_egl_window_vN, and the appropriate checks should be added below
+ */
+
+#define MEMBER_SIZE(type, member) sizeof(((type *)0)->member)
+
+#define CHECK_RENAMED_MEMBER(a_ver, b_ver, a_member, b_member)                      \
+    do {                                                                            \
+        if (offsetof(struct wl_egl_window ## a_ver, a_member) !=                    \
+            offsetof(struct wl_egl_window ## b_ver, b_member)) {                    \
+            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;                                                               \
+        }                                                                           \
+                                                                                    \
+        if (MEMBER_SIZE(struct wl_egl_window ## a_ver, a_member) !=                 \
+            MEMBER_SIZE(struct wl_egl_window ## b_ver, b_member)) {                 \
+            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;                                                               \
+        }                                                                           \
+    } while (0)
+
+#define CHECK_MEMBER(a_ver, b_ver, member) CHECK_RENAMED_MEMBER(a_ver, b_ver, member, member)
+#define CHECK_MEMBER_CURRENT(a_ver, member) CHECK_MEMBER(a_ver,, member)
+
+#define CHECK_SIZE(a_ver, b_ver)                                                    \
+    do {                                                                            \
+        if (sizeof(struct wl_egl_window ## a_ver) >                                 \
+            sizeof(struct wl_egl_window ## b_ver)) {                                \
+            printf("Backwards incompatible change detected!\n   "                    \
+                   "sizeof(struct wl_egl_window" #a_ver ") > "                      \
+                   "sizeof(struct wl_egl_window" #b_ver ")\n");                     \
+            return 1;                                                               \
+        }                                                                           \
+    } while (0)
+
+#define CHECK_SIZE_CURRENT(a_ver)                                                   \
+    do {                                                                            \
+        if (sizeof(struct wl_egl_window ## a_ver) !=                                \
+            sizeof(struct wl_egl_window)) {                                         \
+            printf("Backwards incompatible change detected!\n   "                    \
+                   "sizeof(struct wl_egl_window" #a_ver ") != "                     \
+                   "sizeof(struct wl_egl_window)\n");                               \
+            return 1;                                                               \
+        }                                                                           \
+    } while (0)
+
+#define CHECK_VERSION(a_ver, b_ver)                                                 \
+    do {                                                                            \
+        if ((WL_EGL_WINDOW_VERSION ## a_ver) >=                                     \
+            (WL_EGL_WINDOW_VERSION ## b_ver)) {                                     \
+            printf("Backwards incompatible change detected!\n   "                    \
+                   "WL_EGL_WINDOW_VERSION" #a_ver " >= "                            \
+                   "WL_EGL_WINDOW_VERSION" #b_ver "\n");                            \
+            return 1;                                                               \
+        }                                                                           \
+    } while (0)
+
+#define CHECK_VERSION_CURRENT(a_ver)                                                \
+    do {                                                                            \
+        if ((WL_EGL_WINDOW_VERSION ## a_ver) !=                                     \
+            (WL_EGL_WINDOW_VERSION)) {                                              \
+            printf("Backwards incompatible change detected!\n   "                    \
+                   "WL_EGL_WINDOW_VERSION" #a_ver " != "                            \
+                   "WL_EGL_WINDOW_VERSION\n");                                      \
+            return 1;                                                               \
+        }                                                                           \
+    } while (0)
+
+int main(int argc, char **argv)
+{
+    /* Check wl_egl_window_v1 ABI against wl_egl_window_v0 */
+    CHECK_MEMBER(_v0, _v1, surface);
+    CHECK_MEMBER(_v0, _v1, width);
+    CHECK_MEMBER(_v0, _v1, height);
+    CHECK_MEMBER(_v0, _v1, dx);
+    CHECK_MEMBER(_v0, _v1, dy);
+    CHECK_MEMBER(_v0, _v1, attached_width);
+    CHECK_MEMBER(_v0, _v1, attached_height);
+
+    CHECK_SIZE(_v0, _v1);
+
+    /* Check wl_egl_window_v2 ABI against wl_egl_window_v1 */
+    CHECK_MEMBER(_v1, _v2, surface);
+    CHECK_MEMBER(_v1, _v2, width);
+    CHECK_MEMBER(_v1, _v2, height);
+    CHECK_MEMBER(_v1, _v2, dx);
+    CHECK_MEMBER(_v1, _v2, dy);
+    CHECK_MEMBER(_v1, _v2, attached_width);
+    CHECK_MEMBER(_v1, _v2, attached_height);
+    CHECK_MEMBER(_v1, _v2, private);
+    CHECK_MEMBER(_v1, _v2, resize_callback);
+
+    CHECK_SIZE(_v1, _v2);
+
+    /* Check wl_egl_window_v3 ABI against wl_egl_window_v2 */
+    CHECK_RENAMED_MEMBER(_v2, _v3, surface, version);
+    CHECK_MEMBER        (_v2, _v3, width);
+    CHECK_MEMBER        (_v2, _v3, height);
+    CHECK_MEMBER        (_v2, _v3, dx);
+    CHECK_MEMBER        (_v2, _v3, dy);
+    CHECK_MEMBER        (_v2, _v3, attached_width);
+    CHECK_MEMBER        (_v2, _v3, attached_height);
+    CHECK_RENAMED_MEMBER(_v2, _v3, private, driver_private);
+    CHECK_MEMBER        (_v2, _v3, resize_callback);
+    CHECK_MEMBER        (_v2, _v3, destroy_window_callback);
+
+    CHECK_SIZE   (_v2, _v3);
+    CHECK_VERSION(_v2, _v3);
+
+    /* Check current wl_egl_window ABI against wl_egl_window_v3 */
+    CHECK_MEMBER_CURRENT(_v3, version);
+    CHECK_MEMBER_CURRENT(_v3, width);
+    CHECK_MEMBER_CURRENT(_v3, height);
+    CHECK_MEMBER_CURRENT(_v3, dx);
+    CHECK_MEMBER_CURRENT(_v3, dy);
+    CHECK_MEMBER_CURRENT(_v3, attached_width);
+    CHECK_MEMBER_CURRENT(_v3, attached_height);
+    CHECK_MEMBER_CURRENT(_v3, driver_private);
+    CHECK_MEMBER_CURRENT(_v3, resize_callback);
+    CHECK_MEMBER_CURRENT(_v3, destroy_window_callback);
+    CHECK_MEMBER_CURRENT(_v3, surface);
+
+    CHECK_SIZE_CURRENT   (_v3);
+    CHECK_VERSION_CURRENT(_v3);
+
+    return 0;
+}
diff --git a/subprojects/wayland/egl/wayland-egl-backend.h b/subprojects/wayland/egl/wayland-egl-backend.h
new file mode 100644
index 0000000000000000000000000000000000000000..e5287b766ba7a06ec3ed33b4bae5da418ad5934d
--- /dev/null
+++ b/subprojects/wayland/egl/wayland-egl-backend.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright © 2011 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Benjamin Franzke <benjaminfranzke@googlemail.com>
+ */
+
+#ifndef _WAYLAND_EGL_PRIV_H
+#define _WAYLAND_EGL_PRIV_H
+
+#include <stdint.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * NOTE: This version must be kept in sync with the version field in the
+ * wayland-egl-backend pkgconfig file generated in meson.build.
+ */
+#define WL_EGL_WINDOW_VERSION 3
+
+struct wl_surface;
+
+struct wl_egl_window {
+	const intptr_t version;
+
+	int width;
+	int height;
+	int dx;
+	int dy;
+
+	int attached_width;
+	int attached_height;
+
+	void *driver_private;
+	void (*resize_callback)(struct wl_egl_window *, void *);
+	void (*destroy_window_callback)(void *);
+
+	struct wl_surface *surface;
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/egl/wayland-egl-core.h b/subprojects/wayland/egl/wayland-egl-core.h
new file mode 100644
index 0000000000000000000000000000000000000000..b3ab5124de547b7004895ea1d89c27726f93ac65
--- /dev/null
+++ b/subprojects/wayland/egl/wayland-egl-core.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright © 2011 Kristian Høgsberg
+ * Copyright © 2011 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_EGL_CORE_H
+#define WAYLAND_EGL_CORE_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#define WL_EGL_PLATFORM 1
+
+struct wl_egl_window;
+struct wl_surface;
+
+struct wl_egl_window *
+wl_egl_window_create(struct wl_surface *surface,
+		     int width, int height);
+
+void
+wl_egl_window_destroy(struct wl_egl_window *egl_window);
+
+void
+wl_egl_window_resize(struct wl_egl_window *egl_window,
+		     int width, int height,
+		     int dx, int dy);
+
+void
+wl_egl_window_get_attached_size(struct wl_egl_window *egl_window,
+				int *width, int *height);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/egl/wayland-egl-symbols-check b/subprojects/wayland/egl/wayland-egl-symbols-check
new file mode 100755
index 0000000000000000000000000000000000000000..d04fd042f43aabd4ac99a82c526531c817599965
--- /dev/null
+++ b/subprojects/wayland/egl/wayland-egl-symbols-check
@@ -0,0 +1,51 @@
+#!/bin/sh
+set -eu
+
+RET=0
+LIB=${WAYLAND_EGL_LIB}
+
+if ! test -f "$LIB"; then
+	echo "Test binary \"$LIB\" does not exist"
+	exit 99
+fi
+
+if ! test -n "$NM"; then
+	echo "nm environment variable not set"
+	exit 99
+fi
+
+AVAIL_FUNCS="$($NM -D --format=bsd --defined-only $LIB | awk '{print $3}')"
+
+# Official ABI, taken from the header.
+REQ_FUNCS="wl_egl_window_resize
+wl_egl_window_create
+wl_egl_window_destroy
+wl_egl_window_get_attached_size
+"
+
+NEW_ABI=$(echo "$AVAIL_FUNCS" | while read func; do
+    echo "$func" | grep -q "^_" && continue
+    echo "$REQ_FUNCS" | grep -q "^$func$" && continue
+
+    echo $func
+done)
+
+if test -n "$NEW_ABI"; then
+	echo "New ABI detected - If intentional, update the test."
+	echo "$NEW_ABI"
+	RET=1
+fi
+
+REMOVED_ABI=$(echo "$REQ_FUNCS" | while read func; do
+    echo "$AVAIL_FUNCS" | grep -q "^$func$" && continue
+
+    echo $func
+done)
+
+if test -n "$REMOVED_ABI"; then
+	echo "ABI break detected - Required symbol(s) no longer exported!"
+	echo "$REMOVED_ABI"
+	RET=1
+fi
+
+exit $RET
diff --git a/subprojects/wayland/egl/wayland-egl.c b/subprojects/wayland/egl/wayland-egl.c
new file mode 100644
index 0000000000000000000000000000000000000000..36a347128b8f9662ffe0162c442a5c6aedf8ac86
--- /dev/null
+++ b/subprojects/wayland/egl/wayland-egl.c
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2011 Kristian Høgsberg
+ * Copyright © 2011 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Authors:
+ *    Kristian Høgsberg <krh@bitplanet.net>
+ *    Benjamin Franzke <benjaminfranzke@googlemail.com>
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "wayland-egl.h"
+#include "wayland-egl-backend.h"
+#include "wayland-util.h"
+
+
+/** Resize the EGL window
+ *
+ * \param egl_window A pointer to a struct wl_egl_window
+ * \param width The new width
+ * \param height The new height
+ * \param dx Offset on the X axis
+ * \param dy Offset on the Y axis
+ *
+ * Note that applications should prefer using the wl_surface.offset request if
+ * the associated wl_surface has the interface version 5 or higher.
+ *
+ * If the wl_surface.offset request is used, applications MUST pass 0 to both
+ * dx and dy.
+ */
+WL_EXPORT void
+wl_egl_window_resize(struct wl_egl_window *egl_window,
+		     int width, int height,
+		     int dx, int dy)
+{
+	if (width <= 0 || height <= 0)
+		return;
+
+	egl_window->width  = width;
+	egl_window->height = height;
+	egl_window->dx     = dx;
+	egl_window->dy     = dy;
+
+	if (egl_window->resize_callback)
+		egl_window->resize_callback(egl_window, egl_window->driver_private);
+}
+
+WL_EXPORT struct wl_egl_window *
+wl_egl_window_create(struct wl_surface *surface,
+		     int width, int height)
+{
+	struct wl_egl_window *egl_window;
+
+	if (width <= 0 || height <= 0)
+		return NULL;
+
+	egl_window = calloc(1, sizeof *egl_window);
+	if (!egl_window)
+		return NULL;
+
+	/* Cast away the constness to set the version number.
+	 *
+	 * We want the const notation since it gives an explicit
+	 * feedback to the backend implementation, should it try to
+	 * change it.
+	 *
+	 * The latter in itself is not too surprising as these days APIs
+	 * tend to provide bidirectional version field.
+	 */
+	intptr_t *version = (intptr_t *)&egl_window->version;
+	*version = WL_EGL_WINDOW_VERSION;
+
+	egl_window->surface = surface;
+
+	egl_window->width  = width;
+	egl_window->height = height;
+
+	return egl_window;
+}
+
+WL_EXPORT void
+wl_egl_window_destroy(struct wl_egl_window *egl_window)
+{
+	if (egl_window->destroy_window_callback)
+		egl_window->destroy_window_callback(egl_window->driver_private);
+	free(egl_window);
+}
+
+WL_EXPORT void
+wl_egl_window_get_attached_size(struct wl_egl_window *egl_window,
+				int *width, int *height)
+{
+	if (width)
+		*width = egl_window->attached_width;
+	if (height)
+		*height = egl_window->attached_height;
+}
diff --git a/subprojects/wayland/egl/wayland-egl.h b/subprojects/wayland/egl/wayland-egl.h
new file mode 100644
index 0000000000000000000000000000000000000000..279dcb8bb8d2d13a1783445ea152799ca690270a
--- /dev/null
+++ b/subprojects/wayland/egl/wayland-egl.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2011 Kristian Høgsberg
+ * Copyright © 2011 Benjamin Franzke
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_EGL_H
+#define WAYLAND_EGL_H
+
+#include <wayland-client.h>
+#include "wayland-egl-core.h"
+
+#endif
diff --git a/subprojects/wayland/meson.build b/subprojects/wayland/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..8e28f2a2f7103d7e3718755e8e13e8a9923adfbc
--- /dev/null
+++ b/subprojects/wayland/meson.build
@@ -0,0 +1,140 @@
+project(
+	'wayland', 'c',
+	version: '1.23.0',
+	license: 'MIT',
+	meson_version: '>= 0.57.0',
+	default_options: [
+		'warning_level=2',
+		'buildtype=debugoptimized',
+		'c_std=c99',
+	]
+)
+wayland_version = meson.project_version().split('.')
+
+config_h = configuration_data()
+config_h.set_quoted('PACKAGE', meson.project_name())
+config_h.set_quoted('PACKAGE_VERSION', meson.project_version())
+
+cc_args = []
+if host_machine.system() not in ['freebsd', 'openbsd']
+	cc_args += ['-D_POSIX_C_SOURCE=200809L']
+endif
+add_project_arguments(cc_args, language: 'c')
+
+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', 'sys/procctl.h', 'sys/ucred.h' ]
+	config_h.set('HAVE_' + h.underscorify().to_upper(), cc.has_header(h))
+endforeach
+
+have_funcs = [
+	'accept4',
+	'mkostemp',
+	'posix_fallocate',
+	'prctl',
+	'memfd_create',
+	'mremap',
+	'strndup',
+]
+foreach f: have_funcs
+	config_h.set('HAVE_' + f.underscorify().to_upper(), cc.has_function(f))
+endforeach
+config_h.set10('HAVE_XUCRED_CR_PID', cc.has_member('struct xucred', 'cr_pid', prefix : '#include <sys/ucred.h>'))
+have_broken_msg_cmsg_cloexec = false
+if host_machine.system() == 'freebsd'
+	have_broken_msg_cmsg_cloexec = not cc.compiles('''
+#include <sys/param.h> /* To get __FreeBSD_version. */
+#if __FreeBSD_version < 1300502 || \
+    (__FreeBSD_version >= 1400000 && __FreeBSD_version < 1400006)
+/*
+ * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015 and
+ * 2021. Check if we are compiling against a version that includes the fix
+ * (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211).
+ */
+#error "Broken MSG_CMSG_CLOEXEC"
+#endif
+''', name : 'MSG_CMSG_CLOEXEC works correctly')
+endif
+config_h.set10('HAVE_BROKEN_MSG_CMSG_CLOEXEC', have_broken_msg_cmsg_cloexec)
+
+if get_option('libraries')
+	if host_machine.system() in ['freebsd', 'openbsd']
+		# When building for FreeBSD, epoll(7) is provided by a userspace
+		# wrapper around kqueue(2).
+		epoll_dep = dependency('epoll-shim')
+	else
+		# Otherwise, assume that epoll(7) is supported natively.
+		epoll_dep = []
+	endif
+	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'], dependencies: epoll_dep, args: cc_args)
+			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, args: cc_args)
+			error('clock_gettime not found')
+		endif
+	endif
+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')
+endif
+if get_option('tests')
+	subdir('tests')
+endif
+if get_option('documentation')
+	subdir('doc')
+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/subprojects/wayland/meson_options.txt b/subprojects/wayland/meson_options.txt
new file mode 100644
index 0000000000000000000000000000000000000000..b8e2ec60bdc82ba41bd7ce3d1c8f76d271166b8d
--- /dev/null
+++ b/subprojects/wayland/meson_options.txt
@@ -0,0 +1,24 @@
+option('libraries',
+  description: 'Compile Wayland libraries',
+  type: 'boolean',
+  value: true)
+option('scanner',
+  description: 'Compile wayland-scanner binary',
+  type: 'boolean',
+  value: true)
+option('tests',
+  description: 'Compile Wayland tests',
+  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/subprojects/wayland/protocol/.gitignore b/subprojects/wayland/protocol/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..78f49d269391764b3f3a620fd1ae5e4553e41921
--- /dev/null
+++ b/subprojects/wayland/protocol/.gitignore
@@ -0,0 +1,2 @@
+wayland.html
+.wayland.xml.valid
diff --git a/subprojects/wayland/protocol/generate-shm-formats.py b/subprojects/wayland/protocol/generate-shm-formats.py
new file mode 100755
index 0000000000000000000000000000000000000000..c56642e198b6e0e3eed5d555eee3187605ae7fea
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/protocol/tests.xml b/subprojects/wayland/protocol/tests.xml
new file mode 100644
index 0000000000000000000000000000000000000000..22d80a10ef98fb8ad5934d41302f94725af11132
--- /dev/null
+++ b/subprojects/wayland/protocol/tests.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="build_time_wayland_tests">
+
+  <copyright>
+    Copyright © 2017 Samsung Electronics Co., Ltd
+
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation files
+    (the "Software"), to deal in the Software without restriction,
+    including without limitation the rights to use, copy, modify, merge,
+    publish, distribute, sublicense, and/or sell copies of the Software,
+    and to permit persons to whom the Software is furnished to do so,
+    subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the
+    next paragraph) shall be included in all copies or substantial
+    portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+    SOFTWARE.
+  </copyright>
+
+  <interface name="fd_passer" version="2">
+    <description summary="Sends an event with an fd">
+      A trivial interface for fd passing tests.
+    </description>
+
+    <request name="destroy" type="destructor"/>
+
+    <event name="pre_fd"/>
+
+    <event name="fd">
+      <description summary="passes a file descriptor"/>
+      <arg name="fd" type="fd" summary="file descriptor"/>
+    </event>
+
+    <!-- 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.
+      </description>
+      <arg name="passer" type="object" interface="fd_passer"/>
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland/protocol/wayland.dtd b/subprojects/wayland/protocol/wayland.dtd
new file mode 100644
index 0000000000000000000000000000000000000000..b97372c55469fee9d26e8c86905e4052bbdd059c
--- /dev/null
+++ b/subprojects/wayland/protocol/wayland.dtd
@@ -0,0 +1,35 @@
+<!ELEMENT protocol (copyright?, description?, interface+)>
+  <!ATTLIST protocol name CDATA #REQUIRED>
+<!ELEMENT copyright (#PCDATA)>
+<!ELEMENT interface (description?,(request|event|enum)+)>
+  <!ATTLIST interface name CDATA #REQUIRED>
+  <!ATTLIST interface version CDATA #REQUIRED>
+<!ELEMENT request (description?,arg*)>
+  <!ATTLIST request name CDATA #REQUIRED>
+  <!ATTLIST request type CDATA #IMPLIED>
+  <!ATTLIST request since CDATA #IMPLIED>
+  <!ATTLIST request deprecated-since CDATA #IMPLIED>
+<!ELEMENT event (description?,arg*)>
+  <!ATTLIST event name CDATA #REQUIRED>
+  <!ATTLIST event type CDATA #IMPLIED>
+  <!ATTLIST event since CDATA #IMPLIED>
+  <!ATTLIST event deprecated-since CDATA #IMPLIED>
+<!ELEMENT enum (description?,entry*)>
+  <!ATTLIST enum name CDATA #REQUIRED>
+  <!ATTLIST enum since CDATA #IMPLIED>
+  <!ATTLIST enum bitfield CDATA #IMPLIED>
+<!ELEMENT entry (description?)>
+  <!ATTLIST entry name CDATA #REQUIRED>
+  <!ATTLIST entry value CDATA #REQUIRED>
+  <!ATTLIST entry summary CDATA #IMPLIED>
+  <!ATTLIST entry since CDATA #IMPLIED>
+  <!ATTLIST entry deprecated-since CDATA #IMPLIED>
+<!ELEMENT arg (description?)>
+  <!ATTLIST arg name CDATA #REQUIRED>
+  <!ATTLIST arg type CDATA #REQUIRED>
+  <!ATTLIST arg summary CDATA #IMPLIED>
+  <!ATTLIST arg interface CDATA #IMPLIED>
+  <!ATTLIST arg allow-null CDATA #IMPLIED>
+  <!ATTLIST arg enum CDATA #IMPLIED>
+<!ELEMENT description (#PCDATA)>
+  <!ATTLIST description summary CDATA #REQUIRED>
diff --git a/subprojects/wayland/protocol/wayland.xml b/subprojects/wayland/protocol/wayland.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9418c62f3f6a4852e06a4ecc97949b0f55301da0
--- /dev/null
+++ b/subprojects/wayland/protocol/wayland.xml
@@ -0,0 +1,3248 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland">
+
+  <copyright>
+    Copyright © 2008-2011 Kristian Høgsberg
+    Copyright © 2010-2011 Intel Corporation
+    Copyright © 2012-2013 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation files
+    (the "Software"), to deal in the Software without restriction,
+    including without limitation the rights to use, copy, modify, merge,
+    publish, distribute, sublicense, and/or sell copies of the Software,
+    and to permit persons to whom the Software is furnished to do so,
+    subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the
+    next paragraph) shall be included in all copies or substantial
+    portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+    SOFTWARE.
+  </copyright>
+
+  <interface name="wl_display" version="1">
+    <description summary="core global object">
+      The core global object.  This is a special singleton object.  It
+      is used for internal Wayland protocol features.
+    </description>
+
+    <request name="sync">
+      <description summary="asynchronous roundtrip">
+	The sync request asks the server to emit the 'done' event
+	on the returned wl_callback object.  Since requests are
+	handled in-order and events are delivered in-order, this can
+	be used as a barrier to ensure all previous requests and the
+	resulting events have been handled.
+
+	The object returned by this request will be destroyed by the
+	compositor after the callback is fired and as such the client must not
+	attempt to use it after that point.
+
+	The callback_data passed in the callback is undefined and should be ignored.
+      </description>
+      <arg name="callback" type="new_id" interface="wl_callback"
+	   summary="callback object for the sync request"/>
+    </request>
+
+    <request name="get_registry">
+      <description summary="get global registry object">
+	This request creates a registry object that allows the client
+	to list and bind the global objects available from the
+	compositor.
+
+	It should be noted that the server side resources consumed in
+	response to a get_registry request can only be released when the
+	client disconnects, not when the client side proxy is destroyed.
+	Therefore, clients should invoke get_registry as infrequently as
+	possible to avoid wasting memory.
+      </description>
+      <arg name="registry" type="new_id" interface="wl_registry"
+	   summary="global registry object"/>
+    </request>
+
+    <event name="error">
+      <description summary="fatal error event">
+	The error event is sent out when a fatal (non-recoverable)
+	error has occurred.  The object_id argument is the object
+	where the error occurred, most often in response to a request
+	to that object.  The code identifies the error and is defined
+	by the object interface.  As such, each interface defines its
+	own set of error codes.  The message is a brief description
+	of the error, for (debugging) convenience.
+      </description>
+      <arg name="object_id" type="object" summary="object where the error occurred"/>
+      <arg name="code" type="uint" summary="error code"/>
+      <arg name="message" type="string" summary="error description"/>
+    </event>
+
+    <enum name="error">
+      <description summary="global error values">
+	These errors are global and can be emitted in response to any
+	server request.
+      </description>
+      <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 or malformed request"/>
+      <entry name="no_memory" value="2"
+	     summary="server is out of memory"/>
+      <entry name="implementation" value="3"
+	     summary="implementation error in compositor"/>
+    </enum>
+
+    <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 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>
+  </interface>
+
+  <interface name="wl_registry" version="1">
+    <description summary="global registry object">
+      The singleton global registry object.  The server has a number of
+      global objects that are available to all clients.  These objects
+      typically represent an actual object in the server (for example,
+      an input device) or they are singleton objects that provide
+      extension functionality.
+
+      When a client creates a registry object, the registry object
+      will emit a global event for each global currently in the
+      registry.  Globals come and go as a result of device or
+      monitor hotplugs, reconfiguration or other events, and the
+      registry will send out global and global_remove events to
+      keep the client up to date with the changes.  To mark the end
+      of the initial burst of events, the client can use the
+      wl_display.sync request immediately after calling
+      wl_display.get_registry.
+
+      A client can bind to a global object by using the bind
+      request.  This creates a client-side handle that lets the object
+      emit events to the client and lets the client invoke requests on
+      the object.
+    </description>
+
+    <request name="bind">
+      <description summary="bind an object to the display">
+	Binds a new, client-created object to the server using the
+	specified name as the identifier.
+      </description>
+      <arg name="name" type="uint" summary="unique numeric name of the object"/>
+      <arg name="id" type="new_id" summary="bounded object"/>
+    </request>
+
+    <event name="global">
+      <description summary="announce global object">
+	Notify the client of global objects.
+
+	The event notifies the client that a global object with
+	the given name is now available, and it implements the
+	given version of the given interface.
+      </description>
+      <arg name="name" type="uint" summary="numeric name of the global object"/>
+      <arg name="interface" type="string" summary="interface implemented by the object"/>
+      <arg name="version" type="uint" summary="interface version"/>
+    </event>
+
+    <event name="global_remove">
+      <description summary="announce removal of global object">
+	Notify the client of removed global objects.
+
+	This event notifies the client that the global identified
+	by name is no longer available.  If the client bound to
+	the global using the bind request, the client should now
+	destroy that object.
+
+	The object remains valid and requests to the object will be
+	ignored until the client destroys it, to avoid races between
+	the global going away and a client sending a request to it.
+      </description>
+      <arg name="name" type="uint" summary="numeric name of the global object"/>
+    </event>
+  </interface>
+
+  <interface name="wl_callback" version="1">
+    <description summary="callback object">
+      Clients can handle the 'done' event to get notified when
+      the related request is done.
+
+      Note, because wl_callback objects are created from multiple independent
+      factory interfaces, the wl_callback interface is frozen at version 1.
+    </description>
+
+    <event name="done" type="destructor">
+      <description summary="done event">
+	Notify the client when the related request is done.
+      </description>
+      <arg name="callback_data" type="uint" summary="request-specific data for the callback"/>
+    </event>
+  </interface>
+
+  <interface name="wl_compositor" version="6">
+    <description summary="the compositor singleton">
+      A compositor.  This object is a singleton global.  The
+      compositor is in charge of combining the contents of multiple
+      surfaces into one displayable output.
+    </description>
+
+    <request name="create_surface">
+      <description summary="create new surface">
+	Ask the compositor to create a new surface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_surface" summary="the new surface"/>
+    </request>
+
+    <request name="create_region">
+      <description summary="create new region">
+	Ask the compositor to create a new region.
+      </description>
+      <arg name="id" type="new_id" interface="wl_region" summary="the new region"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shm_pool" version="2">
+    <description summary="a shared memory pool">
+      The wl_shm_pool object encapsulates a piece of memory shared
+      between the compositor and client.  Through the wl_shm_pool
+      object, the client can allocate shared memory wl_buffer objects.
+      All objects created through the same pool share the same
+      underlying mapped memory. Reusing the mapped memory avoids the
+      setup/teardown overhead and is useful when interactively resizing
+      a surface or for many small buffers.
+    </description>
+
+    <request name="create_buffer">
+      <description summary="create a buffer from the pool">
+	Create a wl_buffer object from the pool.
+
+	The buffer is created offset bytes into the pool and has
+	width and height as specified.  The stride argument specifies
+	the number of bytes from the beginning of one row to the beginning
+	of the next.  The format is the pixel format of the buffer and
+	must be one of those advertised through the wl_shm.format event.
+
+	A buffer will keep a reference to the pool it was created from
+	so it is valid to destroy the pool immediately after creating
+	a buffer from it.
+      </description>
+      <arg name="id" type="new_id" interface="wl_buffer" summary="buffer to create"/>
+      <arg name="offset" type="int" summary="buffer byte offset within the pool"/>
+      <arg name="width" type="int" summary="buffer width, in pixels"/>
+      <arg name="height" type="int" summary="buffer height, in pixels"/>
+      <arg name="stride" type="int" summary="number of bytes from the beginning of one row to the beginning of the next row"/>
+      <arg name="format" type="uint" enum="wl_shm.format" summary="buffer pixel format"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pool">
+	Destroy the shared memory pool.
+
+	The mmapped memory will be released when all
+	buffers that have been created from this pool
+	are gone.
+      </description>
+    </request>
+
+    <request name="resize">
+      <description summary="change the size of the pool mapping">
+	This request will cause the server to remap the backing memory
+	for the pool from the file descriptor passed when the pool was
+	created, but using the new size.  This request can only be
+	used to make the pool bigger.
+
+	This request only changes the amount of bytes that are mmapped
+	by the server and does not touch the file corresponding to the
+	file descriptor passed at creation time. It is the client's
+	responsibility to ensure that the file is at least as big as
+	the new pool size.
+      </description>
+      <arg name="size" type="int" summary="new size of the pool, in bytes"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shm" version="2">
+    <description summary="shared memory support">
+      A singleton global object that provides support for shared
+      memory.
+
+      Clients can create wl_shm_pool objects using the create_pool
+      request.
+
+      On binding the wl_shm object one or more format events
+      are emitted to inform clients about the valid pixel formats
+      that can be used for buffers.
+    </description>
+
+    <enum name="error">
+      <description summary="wl_shm error values">
+	These errors can be emitted in response to wl_shm requests.
+      </description>
+      <entry name="invalid_format" value="0" summary="buffer format is not known"/>
+      <entry name="invalid_stride" value="1" summary="invalid size or stride during pool or buffer creation"/>
+      <entry name="invalid_fd" value="2" summary="mmapping the file descriptor failed"/>
+    </enum>
+
+    <enum name="format">
+      <description summary="pixel formats">
+	This describes the memory layout of an individual pixel.
+
+	All renderers should support argb8888 and xrgb8888 but any other
+	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, except
+	argb8888 and xrgb8888. The formats actually supported by the compositor
+	will be reported by the format event.
+
+	For all wl_shm formats and unless specified in another protocol
+	extension, pre-multiplied alpha is used for pixel values.
+      </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"/>
+      <entry name="rgb332" value="0x38424752" summary="8-bit RGB format, [7:0] R:G:B 3:3:2"/>
+      <entry name="bgr233" value="0x38524742" summary="8-bit BGR format, [7:0] B:G:R 2:3:3"/>
+      <entry name="xrgb4444" value="0x32315258" summary="16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian"/>
+      <entry name="xbgr4444" value="0x32314258" summary="16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian"/>
+      <entry name="rgbx4444" value="0x32315852" summary="16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian"/>
+      <entry name="bgrx4444" value="0x32315842" summary="16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian"/>
+      <entry name="argb4444" value="0x32315241" summary="16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian"/>
+      <entry name="abgr4444" value="0x32314241" summary="16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian"/>
+      <entry name="rgba4444" value="0x32314152" summary="16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian"/>
+      <entry name="bgra4444" value="0x32314142" summary="16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian"/>
+      <entry name="xrgb1555" value="0x35315258" summary="16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian"/>
+      <entry name="xbgr1555" value="0x35314258" summary="16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian"/>
+      <entry name="rgbx5551" value="0x35315852" summary="16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian"/>
+      <entry name="bgrx5551" value="0x35315842" summary="16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian"/>
+      <entry name="argb1555" value="0x35315241" summary="16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian"/>
+      <entry name="abgr1555" value="0x35314241" summary="16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian"/>
+      <entry name="rgba5551" value="0x35314152" summary="16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian"/>
+      <entry name="bgra5551" value="0x35314142" summary="16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian"/>
+      <entry name="rgb565" value="0x36314752" summary="16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian"/>
+      <entry name="bgr565" value="0x36314742" summary="16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian"/>
+      <entry name="rgb888" value="0x34324752" summary="24-bit RGB format, [23:0] R:G:B little endian"/>
+      <entry name="bgr888" value="0x34324742" summary="24-bit BGR format, [23:0] B:G:R little endian"/>
+      <entry name="xbgr8888" value="0x34324258" summary="32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian"/>
+      <entry name="rgbx8888" value="0x34325852" summary="32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian"/>
+      <entry name="bgrx8888" value="0x34325842" summary="32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian"/>
+      <entry name="abgr8888" value="0x34324241" summary="32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian"/>
+      <entry name="rgba8888" value="0x34324152" summary="32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian"/>
+      <entry name="bgra8888" value="0x34324142" summary="32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian"/>
+      <entry name="xrgb2101010" value="0x30335258" summary="32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian"/>
+      <entry name="xbgr2101010" value="0x30334258" summary="32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian"/>
+      <entry name="rgbx1010102" value="0x30335852" summary="32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian"/>
+      <entry name="bgrx1010102" value="0x30335842" summary="32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian"/>
+      <entry name="argb2101010" value="0x30335241" summary="32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian"/>
+      <entry name="abgr2101010" value="0x30334241" summary="32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian"/>
+      <entry name="rgba1010102" value="0x30334152" summary="32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian"/>
+      <entry name="bgra1010102" value="0x30334142" summary="32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian"/>
+      <entry name="yuyv" value="0x56595559" summary="packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian"/>
+      <entry name="yvyu" value="0x55595659" summary="packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian"/>
+      <entry name="uyvy" value="0x59565955" summary="packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian"/>
+      <entry name="vyuy" value="0x59555956" summary="packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian"/>
+      <entry name="ayuv" value="0x56555941" summary="packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian"/>
+      <entry name="nv12" value="0x3231564e" summary="2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane"/>
+      <entry name="nv21" value="0x3132564e" summary="2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane"/>
+      <entry name="nv16" value="0x3631564e" summary="2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane"/>
+      <entry name="nv61" value="0x3136564e" summary="2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane"/>
+      <entry name="yuv410" value="0x39565559" summary="3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes"/>
+      <entry name="yvu410" value="0x39555659" summary="3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes"/>
+      <entry name="yuv411" value="0x31315559" summary="3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes"/>
+      <entry name="yvu411" value="0x31315659" summary="3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes"/>
+      <entry name="yuv420" value="0x32315559" summary="3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes"/>
+      <entry name="yvu420" value="0x32315659" summary="3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes"/>
+      <entry name="yuv422" value="0x36315559" summary="3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes"/>
+      <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"/>
+      <entry name="xrgb16161616" value="0x38345258" summary="[63:0] x:R:G:B 16:16:16:16 little endian"/>
+      <entry name="xbgr16161616" value="0x38344258" summary="[63:0] x:B:G:R 16:16:16:16 little endian"/>
+      <entry name="argb16161616" value="0x38345241" summary="[63:0] A:R:G:B 16:16:16:16 little endian"/>
+      <entry name="abgr16161616" value="0x38344241" summary="[63:0] A:B:G:R 16:16:16:16 little endian"/>
+      <entry name="c1" value="0x20203143" summary="[7:0] C0:C1:C2:C3:C4:C5:C6:C7 1:1:1:1:1:1:1:1 eight pixels/byte"/>
+      <entry name="c2" value="0x20203243" summary="[7:0] C0:C1:C2:C3 2:2:2:2 four pixels/byte"/>
+      <entry name="c4" value="0x20203443" summary="[7:0] C0:C1 4:4 two pixels/byte"/>
+      <entry name="d1" value="0x20203144" summary="[7:0] D0:D1:D2:D3:D4:D5:D6:D7 1:1:1:1:1:1:1:1 eight pixels/byte"/>
+      <entry name="d2" value="0x20203244" summary="[7:0] D0:D1:D2:D3 2:2:2:2 four pixels/byte"/>
+      <entry name="d4" value="0x20203444" summary="[7:0] D0:D1 4:4 two pixels/byte"/>
+      <entry name="d8" value="0x20203844" summary="[7:0] D"/>
+      <entry name="r1" value="0x20203152" summary="[7:0] R0:R1:R2:R3:R4:R5:R6:R7 1:1:1:1:1:1:1:1 eight pixels/byte"/>
+      <entry name="r2" value="0x20203252" summary="[7:0] R0:R1:R2:R3 2:2:2:2 four pixels/byte"/>
+      <entry name="r4" value="0x20203452" summary="[7:0] R0:R1 4:4 two pixels/byte"/>
+      <entry name="r10" value="0x20303152" summary="[15:0] x:R 6:10 little endian"/>
+      <entry name="r12" value="0x20323152" summary="[15:0] x:R 4:12 little endian"/>
+      <entry name="avuy8888" value="0x59555641" summary="[31:0] A:Cr:Cb:Y 8:8:8:8 little endian"/>
+      <entry name="xvuy8888" value="0x59555658" summary="[31:0] X:Cr:Cb:Y 8:8:8:8 little endian"/>
+      <entry name="p030" value="0x30333050" summary="2x2 subsampled Cr:Cb plane 10 bits per channel packed"/>
+    </enum>
+
+    <request name="create_pool">
+      <description summary="create a shm pool">
+	Create a new wl_shm_pool object.
+
+	The pool can be used to create shared memory based buffer
+	objects.  The server will mmap size bytes of the passed file
+	descriptor, to use as backing memory for the pool.
+      </description>
+      <arg name="id" type="new_id" interface="wl_shm_pool" summary="pool to create"/>
+      <arg name="fd" type="fd" summary="file descriptor for the pool"/>
+      <arg name="size" type="int" summary="pool size, in bytes"/>
+    </request>
+
+    <event name="format">
+      <description summary="pixel format description">
+	Informs the client about a valid pixel format that
+	can be used for buffers. Known formats include
+	argb8888 and xrgb8888.
+      </description>
+      <arg name="format" type="uint" enum="format" summary="buffer pixel format"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <request name="release" type="destructor" since="2">
+      <description summary="release the shm object">
+	Using this request a client can tell the server that it is not going to
+	use the shm object anymore.
+
+	Objects created via this interface remain unaffected.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="wl_buffer" version="1">
+    <description summary="content for a wl_surface">
+      A buffer provides the content for a wl_surface. Buffers are
+      created through factory interfaces such as wl_shm, wp_linux_buffer_params
+      (from the linux-dmabuf protocol extension) or similar. It has a width and
+      a height and can be attached to a wl_surface, but the mechanism by which a
+      client provides and updates the contents is defined by the buffer factory
+      interface.
+
+      Color channels are assumed to be electrical rather than optical (in other
+      words, encoded with a transfer function) unless otherwise specified. If
+      the buffer uses a format that has an alpha channel, the alpha channel is
+      assumed to be premultiplied into the electrical color channel values
+      (after transfer function encoding) unless otherwise specified.
+
+      Note, because wl_buffer objects are created from multiple independent
+      factory interfaces, the wl_buffer interface is frozen at version 1.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy a buffer">
+	Destroy a buffer. If and how you need to release the backing
+	storage is defined by the buffer factory interface.
+
+	For possible side-effects to a surface, see wl_surface.attach.
+      </description>
+    </request>
+
+    <event name="release">
+      <description summary="compositor releases buffer">
+	Sent when this wl_buffer is no longer used by the compositor.
+	The client is now free to reuse or destroy this buffer and its
+	backing storage.
+
+	If a client receives a release event before the frame callback
+	requested in the same wl_surface.commit that attaches this
+	wl_buffer to a surface, then the client is immediately free to
+	reuse the buffer and its backing storage, and does not need a
+	second buffer for the next surface content update. Typically
+	this is possible, when the compositor maintains a copy of the
+	wl_surface contents, e.g. as a GL texture. This is an important
+	optimization for GL(ES) compositors with wl_shm clients.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="wl_data_offer" version="3">
+    <description summary="offer to transfer data">
+      A wl_data_offer represents a piece of data offered for transfer
+      by another client (the source client).  It is used by the
+      copy-and-paste and drag-and-drop mechanisms.  The offer
+      describes the different mime types that the data can be
+      converted to and provides the mechanism for transferring the
+      data directly from the source client.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_finish" value="0"
+	     summary="finish request was called untimely"/>
+      <entry name="invalid_action_mask" value="1"
+	     summary="action mask contains invalid values"/>
+      <entry name="invalid_action" value="2"
+	     summary="action argument has an invalid value"/>
+      <entry name="invalid_offer" value="3"
+	     summary="offer doesn't accept this request"/>
+    </enum>
+
+    <request name="accept">
+      <description summary="accept one of the offered mime types">
+	Indicate that the client can accept the given mime type, or
+	NULL for not accepted.
+
+	For objects of version 2 or older, this request is used by the
+	client to give feedback whether the client can receive the given
+	mime type, or NULL if none is accepted; the feedback does not
+	determine whether the drag-and-drop operation succeeds or not.
+
+	For objects of version 3 or newer, this request determines the
+	final result of the drag-and-drop operation. If the end result
+	is that no mime types were accepted, the drag-and-drop operation
+	will be cancelled and the corresponding drag source will receive
+	wl_data_source.cancelled. Clients may still use this event in
+	conjunction with wl_data_source.action for feedback.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the accept request"/>
+      <arg name="mime_type" type="string" allow-null="true" summary="mime type accepted by the client"/>
+    </request>
+
+    <request name="receive">
+      <description summary="request that the data is transferred">
+	To transfer the offered data, the client issues this request
+	and indicates the mime type it wants to receive.  The transfer
+	happens through the passed file descriptor (typically created
+	with the pipe system call).  The source client writes the data
+	in the mime type representation requested and then closes the
+	file descriptor.
+
+	The receiving client reads from the read end of the pipe until
+	EOF and then closes its end, at which point the transfer is
+	complete.
+
+	This request may happen multiple times for different mime types,
+	both before and after wl_data_device.drop. Drag-and-drop destination
+	clients may preemptively fetch data or examine it more closely to
+	determine acceptance.
+      </description>
+      <arg name="mime_type" type="string" summary="mime type desired by receiver"/>
+      <arg name="fd" type="fd" summary="file descriptor for data transfer"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy data offer">
+	Destroy the data offer.
+      </description>
+    </request>
+
+    <event name="offer">
+      <description summary="advertise offered mime type">
+	Sent immediately after creating the wl_data_offer object.  One
+	event per offered mime type.
+      </description>
+      <arg name="mime_type" type="string" summary="offered mime type"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="finish" since="3">
+      <description summary="the offer will no longer be used">
+	Notifies the compositor that the drag destination successfully
+	finished the drag-and-drop operation.
+
+	Upon receiving this request, the compositor will emit
+	wl_data_source.dnd_finished on the drag source client.
+
+	It is a client error to perform other requests than
+	wl_data_offer.destroy after this one. It is also an error to perform
+	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>
+
+    <request name="set_actions" since="3">
+      <description summary="set the available/preferred drag-and-drop actions">
+	Sets the actions that the destination side client supports for
+	this operation. This request may trigger the emission of
+	wl_data_source.action and wl_data_offer.action events if the compositor
+	needs to change the selected action.
+
+	This request can be called multiple times throughout the
+	drag-and-drop operation, typically in response to wl_data_device.enter
+	or wl_data_device.motion events.
+
+	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_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
+	argument must only contain one of those values set, otherwise it
+	will result in a protocol error.
+
+	While managing an "ask" action, the destination drag-and-drop client
+	may perform further wl_data_offer.receive requests, and is expected
+	to perform one last wl_data_offer.set_actions request with a preferred
+	action other than "ask" (and optionally wl_data_offer.accept) before
+	requesting wl_data_offer.finish, in order to convey the action selected
+	by the user. If the preferred action is not in the
+	wl_data_offer.source_actions mask, an error will be raised.
+
+	If the "ask" action is dismissed (e.g. user cancellation), the client
+	is expected to perform wl_data_offer.destroy right away.
+
+	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"
+	   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">
+      <description summary="notify the source-side available actions">
+	This event indicates the actions offered by the data source. It
+	will be sent immediately after creating the wl_data_offer object,
+	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"
+	   enum="wl_data_device_manager.dnd_action"/>
+    </event>
+
+    <event name="action" since="3">
+      <description summary="notify the selected action">
+	This event indicates the action selected by the compositor after
+	matching the source/destination side actions. Only one action (or
+	none) will be offered here.
+
+	This event can be emitted multiple times during the drag-and-drop
+	operation in response to destination side action changes through
+	wl_data_offer.set_actions.
+
+	This event will no longer be emitted after wl_data_device.drop
+	happened on the drag-and-drop destination, the client must
+	honor the last action received, or the last preferred one set
+	through wl_data_offer.set_actions when handling an "ask" action.
+
+	Compositors may also change the selected action on the fly, mainly
+	in response to keyboard modifier changes during the drag-and-drop
+	operation.
+
+	The most recent action received is always the valid one. Prior to
+	receiving wl_data_device.drop, the chosen action may change (e.g.
+	due to keyboard modifiers being pressed). At the time of receiving
+	wl_data_device.drop the drag-and-drop destination must honor the
+	last action received.
+
+	Action changes may still happen after wl_data_device.drop,
+	especially on "ask" actions, where the drag-and-drop destination
+	may choose another action afterwards. Action changes happening
+	at this stage are always the result of inter-client negotiation, the
+	compositor shall no longer be able to induce a different action.
+
+	Upon "ask" actions, it is expected that the drag-and-drop destination
+	may potentially choose a different action and/or mime type,
+	based on wl_data_offer.source_actions and finally chosen by the
+	user (e.g. popping up a menu with the available options). The
+	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"
+	   enum="wl_data_device_manager.dnd_action"/>
+    </event>
+  </interface>
+
+  <interface name="wl_data_source" version="3">
+    <description summary="offer to transfer data">
+      The wl_data_source object is the source side of a wl_data_offer.
+      It is created by the source client in a data transfer and
+      provides a way to describe the offered data and a way to respond
+      to requests to transfer the data.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_action_mask" value="0"
+	     summary="action mask contains invalid values"/>
+      <entry name="invalid_source" value="1"
+	     summary="source doesn't accept this request"/>
+    </enum>
+
+    <request name="offer">
+      <description summary="add an offered mime type">
+	This request adds a mime type to the set of mime types
+	advertised to targets.  Can be called several times to offer
+	multiple types.
+      </description>
+      <arg name="mime_type" type="string" summary="mime type offered by the data source"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the data source">
+	Destroy the data source.
+      </description>
+    </request>
+
+    <event name="target">
+      <description summary="a target accepts an offered mime type">
+	Sent when a target accepts pointer_focus or motion events.  If
+	a target does not accept any of the offered types, type is NULL.
+
+	Used for feedback during drag-and-drop.
+      </description>
+      <arg name="mime_type" type="string" allow-null="true" summary="mime type accepted by the target"/>
+    </event>
+
+    <event name="send">
+      <description summary="send the data">
+	Request for data from the client.  Send the data as the
+	specified mime type over the passed file descriptor, then
+	close it.
+      </description>
+      <arg name="mime_type" type="string" summary="mime type for the data"/>
+      <arg name="fd" type="fd" summary="file descriptor for the data"/>
+    </event>
+
+    <event name="cancelled">
+      <description summary="selection was cancelled">
+	This data source is no longer valid. There are several reasons why
+	this could happen:
+
+	- The data source has been replaced by another data source.
+	- The drag-and-drop operation was performed, but the drop destination
+	  did not accept any of the mime types offered through
+	  wl_data_source.target.
+	- The drag-and-drop operation was performed, but the drop destination
+	  did not select any of the actions present in the mask offered through
+	  wl_data_source.action.
+	- The drag-and-drop operation was performed but didn't happen over a
+	  surface.
+	- The compositor cancelled the drag-and-drop operation (e.g. compositor
+	  dependent timeouts to avoid stale drag-and-drop transfers).
+
+	The client should clean up and destroy this data source.
+
+	For objects of version 2 or older, wl_data_source.cancelled will
+	only be emitted if the data source was replaced by another data
+	source.
+      </description>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="set_actions" since="3">
+      <description summary="set the available drag-and-drop actions">
+	Sets the actions that the source side client supports for this
+	operation. This request may trigger wl_data_source.action and
+	wl_data_offer.action events if the compositor needs to change the
+	selected action.
+
+	The dnd_actions argument must contain only values expressed in the
+	wl_data_device_manager.dnd_actions enum, otherwise it will result
+	in a protocol error.
+
+	This request must be made once only, and can only be made on sources
+	used in drag-and-drop, so it must be performed before
+	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"
+	   enum="wl_data_device_manager.dnd_action"/>
+    </request>
+
+    <event name="dnd_drop_performed" since="3">
+      <description summary="the drag-and-drop operation physically finished">
+	The user performed the drop action. This event does not indicate
+	acceptance, wl_data_source.cancelled may still be emitted afterwards
+	if the drop destination does not accept any mime type.
+
+	However, this event might however not be received if the compositor
+	cancelled the drag-and-drop operation before this event could happen.
+
+	Note that the data_source may still be used in the future and should
+	not be destroyed here.
+      </description>
+    </event>
+
+    <event name="dnd_finished" since="3">
+      <description summary="the drag-and-drop operation concluded">
+	The drop destination finished interoperating with this data
+	source, so the client is now free to destroy this data source and
+	free all associated data.
+
+	If the action used to perform the operation was "move", the
+	source can now delete the transferred data.
+      </description>
+    </event>
+
+    <event name="action" since="3">
+      <description summary="notify the selected action">
+	This event indicates the action selected by the compositor after
+	matching the source/destination side actions. Only one action (or
+	none) will be offered here.
+
+	This event can be emitted multiple times during the drag-and-drop
+	operation, mainly in response to destination side changes through
+	wl_data_offer.set_actions, and as the data device enters/leaves
+	surfaces.
+
+	It is only possible to receive this event after
+	wl_data_source.dnd_drop_performed if the drag-and-drop operation
+	ended in an "ask" action, in which case the final wl_data_source.action
+	event will happen immediately before wl_data_source.dnd_finished.
+
+	Compositors may also change the selected action on the fly, mainly
+	in response to keyboard modifier changes during the drag-and-drop
+	operation.
+
+	The most recent action received is always the valid one. The chosen
+	action may change alongside negotiation (e.g. an "ask" action can turn
+	into a "move" operation), so the effects of the final action must
+	always be applied in wl_data_offer.dnd_finished.
+
+	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"
+	   enum="wl_data_device_manager.dnd_action"/>
+    </event>
+  </interface>
+
+  <interface name="wl_data_device" version="3">
+    <description summary="data transfer device">
+      There is one wl_data_device per seat which can be obtained
+      from the global wl_data_device_manager singleton.
+
+      A wl_data_device provides access to inter-client data transfer
+      mechanisms such as copy-and-paste and drag-and-drop.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+      <entry name="used_source" value="1" summary="source has already been used"/>
+    </enum>
+
+    <request name="start_drag">
+      <description summary="start drag-and-drop operation">
+	This request asks the compositor to start a drag-and-drop
+	operation on behalf of the client.
+
+	The source argument is the data source that provides the data
+	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. 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
+	serial.
+
+	The icon surface is an optional (can be NULL) surface that
+	provides an icon to be moved around with the cursor.  Initially,
+	the top-left corner of the icon surface is placed at the cursor
+	hotspot, but subsequent wl_surface.offset requests can move the
+	relative position. Attach requests must be confirmed with
+	wl_surface.commit as usual. The icon surface is given the role of
+	a drag-and-drop icon. If the icon surface already has another role,
+	it raises a protocol error.
+
+	The input region is ignored for wl_surfaces with the role of a
+	drag-and-drop icon.
+
+	The given source may not be used in any further set_selection or
+	start_drag requests. Attempting to reuse a previously-used source
+	may send a used_source error.
+      </description>
+      <arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the eventual transfer"/>
+      <arg name="origin" type="object" interface="wl_surface" summary="surface where the drag originates"/>
+      <arg name="icon" type="object" interface="wl_surface" allow-null="true" summary="drag-and-drop icon surface"/>
+      <arg name="serial" type="uint" summary="serial number of the implicit grab on the origin"/>
+    </request>
+
+    <request name="set_selection">
+      <description summary="copy data to the selection">
+	This request asks the compositor to set the selection
+	to the data from the source on behalf of the client.
+
+	To unset the selection, set the source to NULL.
+
+	The given source may not be used in any further set_selection or
+	start_drag requests. Attempting to reuse a previously-used source
+	may send a used_source error.
+      </description>
+      <arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the selection"/>
+      <arg name="serial" type="uint" summary="serial number of the event that triggered this request"/>
+    </request>
+
+    <event name="data_offer">
+      <description summary="introduce a new wl_data_offer">
+	The data_offer event introduces a new wl_data_offer object,
+	which will subsequently be used in either the
+	data_device.enter event (for drag-and-drop) or the
+	data_device.selection event (for selections).  Immediately
+	following the data_device.data_offer event, the new data_offer
+	object will send out data_offer.offer events to describe the
+	mime types it offers.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_offer" summary="the new data_offer object"/>
+    </event>
+
+    <event name="enter">
+      <description summary="initiate drag-and-drop session">
+	This event is sent when an active drag-and-drop pointer enters
+	a surface owned by the client.  The position of the pointer at
+	enter time is provided by the x and y arguments, in surface-local
+	coordinates.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="client surface entered"/>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+      <arg name="id" type="object" interface="wl_data_offer" allow-null="true"
+	   summary="source data_offer object"/>
+    </event>
+
+    <event name="leave">
+      <description summary="end drag-and-drop session">
+	This event is sent when the drag-and-drop pointer leaves the
+	surface and the session ends.  The client must destroy the
+	wl_data_offer introduced at enter time at this point.
+      </description>
+    </event>
+
+    <event name="motion">
+      <description summary="drag-and-drop session motion">
+	This event is sent when the drag-and-drop pointer moves within
+	the currently focused surface. The new position of the pointer
+	is provided by the x and y arguments, in surface-local
+	coordinates.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="drop">
+      <description summary="end drag-and-drop session successfully">
+	The event is sent when a drag-and-drop operation is ended
+	because the implicit grab is removed.
+
+	The drag-and-drop destination is expected to honor the last action
+	received through wl_data_offer.action, if the resulting action is
+	"copy" or "move", the destination can still perform
+	wl_data_offer.receive requests, and is expected to end all
+	transfers with a wl_data_offer.finish request.
+
+	If the resulting action is "ask", the action will not be considered
+	final. The drag-and-drop destination is expected to perform one last
+	wl_data_offer.set_actions request, or wl_data_offer.destroy in order
+	to cancel the operation.
+      </description>
+    </event>
+
+    <event name="selection">
+      <description summary="advertise new selection">
+	The selection event is sent out to notify the client of a new
+	wl_data_offer for the selection for this device.  The
+	data_device.data_offer and the data_offer.offer events are
+	sent out immediately before this event to introduce the data
+	offer object.  The selection event is sent to a client
+	immediately before receiving keyboard focus and when a new
+	selection is set while the client has keyboard focus.  The
+	data_offer is valid until a new data_offer or NULL is received
+	or until the client loses keyboard focus.  Switching surface with
+	keyboard focus within the same client doesn't mean a new selection
+	will be sent.  The client must destroy the previous selection
+	data_offer, if any, upon receiving this event.
+      </description>
+      <arg name="id" type="object" interface="wl_data_offer" allow-null="true"
+	   summary="selection data_offer object"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <request name="release" type="destructor" since="2">
+      <description summary="destroy data device">
+	This request destroys the data device.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="wl_data_device_manager" version="3">
+    <description summary="data transfer interface">
+      The wl_data_device_manager is a singleton global object that
+      provides access to inter-client data transfer mechanisms such as
+      copy-and-paste and drag-and-drop.  These mechanisms are tied to
+      a wl_seat and this interface lets a client get a wl_data_device
+      corresponding to a wl_seat.
+
+      Depending on the version bound, the objects created from the bound
+      wl_data_device_manager object will have different requirements for
+      functioning properly. See wl_data_source.set_actions,
+      wl_data_offer.accept and wl_data_offer.finish for details.
+    </description>
+
+    <request name="create_data_source">
+      <description summary="create a new data source">
+	Create a new data source.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_source" summary="data source to create"/>
+    </request>
+
+    <request name="get_data_device">
+      <description summary="create a new data device">
+	Create a new data device for a given seat.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_device" summary="data device to create"/>
+      <arg name="seat" type="object" interface="wl_seat" summary="seat associated with the data device"/>
+    </request>
+
+    <!-- Version 3 additions -->
+
+    <enum name="dnd_action" bitfield="true" since="3">
+      <description summary="drag and drop actions">
+	This is a bitmask of the available/preferred actions in a
+	drag-and-drop operation.
+
+	In the compositor, the selected action is a result of matching the
+	actions offered by the source and destination sides.  "action" events
+	with a "none" action will be sent to both source and destination if
+	there is no match. All further checks will effectively happen on
+	(source actions ∩ destination actions).
+
+	In addition, compositors may also pick different actions in
+	reaction to key modifiers being pressed. One common design that
+	is used in major toolkits (and the behavior recommended for
+	compositors) is:
+
+	- If no modifiers are pressed, the first match (in bit order)
+	  will be used.
+	- Pressing Shift selects "move", if enabled in the mask.
+	- Pressing Control selects "copy", if enabled in the mask.
+
+	Behavior beyond that is considered implementation-dependent.
+	Compositors may for example bind other modifiers (like Alt/Meta)
+	or drags initiated with other buttons than BTN_LEFT to specific
+	actions (e.g. "ask").
+      </description>
+      <entry name="none" value="0" summary="no action"/>
+      <entry name="copy" value="1" summary="copy action"/>
+      <entry name="move" value="2" summary="move action"/>
+      <entry name="ask" value="4" summary="ask action"/>
+    </enum>
+  </interface>
+
+  <interface name="wl_shell" version="1">
+    <description summary="create desktop-style surfaces">
+      This interface is implemented by servers that provide
+      desktop-style user interfaces.
+
+      It allows clients to associate a wl_shell_surface with
+      a basic surface.
+
+      Note! This protocol is deprecated and not intended for production use.
+      For desktop-style user interfaces, use xdg_shell. Compositors and clients
+      should not implement this interface.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="get_shell_surface">
+      <description summary="create a shell surface from a surface">
+	Create a shell surface for an existing surface. This gives
+	the wl_surface the role of a shell surface. If the wl_surface
+	already has another role, it raises a protocol error.
+
+	Only one shell surface can be associated with a given surface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_shell_surface" summary="shell surface to create"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface to be given the shell surface role"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shell_surface" version="1">
+    <description summary="desktop-style metadata interface">
+      An interface that may be implemented by a wl_surface, for
+      implementations that provide a desktop-style user interface.
+
+      It provides requests to treat surfaces like toplevel, fullscreen
+      or popup windows, move, resize or maximize them, associate
+      metadata like title and class, etc.
+
+      On the server side the object is automatically destroyed when
+      the related wl_surface is destroyed. On the client side,
+      wl_shell_surface_destroy() must be called before destroying
+      the wl_surface object.
+    </description>
+
+    <request name="pong">
+      <description summary="respond to a ping event">
+	A client must respond to a ping event with a pong request or
+	the client may be deemed unresponsive.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the ping event"/>
+    </request>
+
+    <request name="move">
+      <description summary="start an interactive move">
+	Start a pointer-driven move of the surface.
+
+	This request must be used in response to a button press event.
+	The server may ignore move requests depending on the state of
+	the surface (e.g. fullscreen or maximized).
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/>
+    </request>
+
+    <enum name="resize" bitfield="true">
+      <description summary="edge values for resizing">
+	These values are used to indicate which edge of a surface
+	is being dragged in a resize operation. The server may
+	use this information to adapt its behavior, e.g. choose
+	an appropriate cursor image.
+      </description>
+      <entry name="none" value="0" summary="no edge"/>
+      <entry name="top" value="1" summary="top edge"/>
+      <entry name="bottom" value="2" summary="bottom edge"/>
+      <entry name="left" value="4" summary="left edge"/>
+      <entry name="top_left" value="5" summary="top and left edges"/>
+      <entry name="bottom_left" value="6" summary="bottom and left edges"/>
+      <entry name="right" value="8" summary="right edge"/>
+      <entry name="top_right" value="9" summary="top and right edges"/>
+      <entry name="bottom_right" value="10" summary="bottom and right edges"/>
+    </enum>
+
+    <request name="resize">
+      <description summary="start an interactive resize">
+	Start a pointer-driven resizing of the surface.
+
+	This request must be used in response to a button press event.
+	The server may ignore resize requests depending on the state of
+	the surface (e.g. fullscreen or maximized).
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/>
+      <arg name="edges" type="uint" enum="resize" summary="which edge or corner is being dragged"/>
+    </request>
+
+    <request name="set_toplevel">
+      <description summary="make the surface a toplevel surface">
+	Map the surface as a toplevel surface.
+
+	A toplevel surface is not fullscreen, maximized or transient.
+      </description>
+    </request>
+
+    <enum name="transient" bitfield="true">
+      <description summary="details of transient behaviour">
+	These flags specify details of the expected behaviour
+	of transient surfaces. Used in the set_transient request.
+      </description>
+      <entry name="inactive" value="0x1" summary="do not set keyboard focus"/>
+    </enum>
+
+    <request name="set_transient">
+      <description summary="make the surface a transient surface">
+	Map the surface relative to an existing surface.
+
+	The x and y arguments specify the location of the upper left
+	corner of the surface relative to the upper left corner of the
+	parent surface, in surface-local coordinates.
+
+	The flags argument controls details of the transient behaviour.
+      </description>
+      <arg name="parent" type="object" interface="wl_surface" summary="parent surface"/>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+      <arg name="flags" type="uint" enum="transient" summary="transient surface behavior"/>
+    </request>
+
+    <enum name="fullscreen_method">
+      <description summary="different method to set the surface fullscreen">
+	Hints to indicate to the compositor how to deal with a conflict
+	between the dimensions of the surface and the dimensions of the
+	output. The compositor is free to ignore this parameter.
+      </description>
+      <entry name="default" value="0" summary="no preference, apply default policy"/>
+      <entry name="scale" value="1" summary="scale, preserve the surface's aspect ratio and center on output"/>
+      <entry name="driver" value="2" summary="switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch"/>
+      <entry name="fill" value="3" summary="no upscaling, center on output and add black borders to compensate size mismatch"/>
+    </enum>
+
+    <request name="set_fullscreen">
+      <description summary="make the surface a fullscreen surface">
+	Map the surface as a fullscreen surface.
+
+	If an output parameter is given then the surface will be made
+	fullscreen on that output. If the client does not specify the
+	output then the compositor will apply its policy - usually
+	choosing the output on which the surface has the biggest surface
+	area.
+
+	The client may specify a method to resolve a size conflict
+	between the output size and the surface size - this is provided
+	through the method parameter.
+
+	The framerate parameter is used only when the method is set
+	to "driver", to indicate the preferred framerate. A value of 0
+	indicates that the client does not care about framerate.  The
+	framerate is specified in mHz, that is framerate of 60000 is 60Hz.
+
+	A method of "scale" or "driver" implies a scaling operation of
+	the surface, either via a direct scaling operation or a change of
+	the output mode. This will override any kind of output scaling, so
+	that mapping a surface with a buffer size equal to the mode can
+	fill the screen independent of buffer_scale.
+
+	A method of "fill" means we don't scale up the buffer, however
+	any output scale is applied. This means that you may run into
+	an edge case where the application maps a buffer with the same
+	size of the output mode but buffer_scale 1 (thus making a
+	surface larger than the output). In this case it is allowed to
+	downscale the results to fit the screen.
+
+	The compositor must reply to this request with a configure event
+	with the dimensions for the output on which the surface will
+	be made fullscreen.
+      </description>
+      <arg name="method" type="uint" enum="fullscreen_method" summary="method for resolving size conflict"/>
+      <arg name="framerate" type="uint" summary="framerate in mHz"/>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"
+	   summary="output on which the surface is to be fullscreen"/>
+    </request>
+
+    <request name="set_popup">
+      <description summary="make the surface a popup surface">
+	Map the surface as a popup.
+
+	A popup surface is a transient surface with an added pointer
+	grab.
+
+	An existing implicit grab will be changed to owner-events mode,
+	and the popup grab will continue after the implicit grab ends
+	(i.e. releasing the mouse button does not cause the popup to
+	be unmapped).
+
+	The popup grab continues until the window is destroyed or a
+	mouse button is pressed in any other client's window. A click
+	in any of the client's surfaces is reported as normal, however,
+	clicks in other clients' surfaces will be discarded and trigger
+	the callback.
+
+	The x and y arguments specify the location of the upper left
+	corner of the surface relative to the upper left corner of the
+	parent surface, in surface-local coordinates.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/>
+      <arg name="parent" type="object" interface="wl_surface" summary="parent surface"/>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+      <arg name="flags" type="uint" enum="transient" summary="transient surface behavior"/>
+    </request>
+
+    <request name="set_maximized">
+      <description summary="make the surface a maximized surface">
+	Map the surface as a maximized surface.
+
+	If an output parameter is given then the surface will be
+	maximized on that output. If the client does not specify the
+	output then the compositor will apply its policy - usually
+	choosing the output on which the surface has the biggest surface
+	area.
+
+	The compositor will reply with a configure event telling
+	the expected new surface size. The operation is completed
+	on the next buffer attach to this surface.
+
+	A maximized surface typically fills the entire output it is
+	bound to, except for desktop elements such as panels. This is
+	the main difference between a maximized shell surface and a
+	fullscreen shell surface.
+
+	The details depend on the compositor implementation.
+      </description>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"
+	   summary="output on which the surface is to be maximized"/>
+    </request>
+
+    <request name="set_title">
+      <description summary="set surface title">
+	Set a short title for the surface.
+
+	This string may be used to identify the surface in a task bar,
+	window list, or other user interface elements provided by the
+	compositor.
+
+	The string must be encoded in UTF-8.
+      </description>
+      <arg name="title" type="string" summary="surface title"/>
+    </request>
+
+    <request name="set_class">
+      <description summary="set surface class">
+	Set a class for the surface.
+
+	The surface class identifies the general class of applications
+	to which the surface belongs. A common convention is to use the
+	file name (or the full path if it is a non-standard location) of
+	the application's .desktop file as the class.
+      </description>
+      <arg name="class_" type="string" summary="surface class"/>
+    </request>
+
+    <event name="ping">
+      <description summary="ping client">
+	Ping a client to check if it is receiving events and sending
+	requests. A client is expected to reply with a pong request.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the ping"/>
+    </event>
+
+    <event name="configure">
+      <description summary="suggest resize">
+	The configure event asks the client to resize its surface.
+
+	The size is a hint, in the sense that the client is free to
+	ignore it if it doesn't resize, pick a smaller size (to
+	satisfy aspect ratio or resize in steps of NxM pixels).
+
+	The edges parameter provides a hint about how the surface
+	was resized. The client may use this information to decide
+	how to adjust its content to the new size (e.g. a scrolling
+	area might adjust its content position to leave the viewable
+	content unmoved).
+
+	The client is free to dismiss all but the last configure
+	event it received.
+
+	The width and height arguments specify the size of the window
+	in surface-local coordinates.
+      </description>
+      <arg name="edges" type="uint" enum="resize" summary="how the surface was resized"/>
+      <arg name="width" type="int" summary="new width of the surface"/>
+      <arg name="height" type="int" summary="new height of the surface"/>
+    </event>
+
+    <event name="popup_done">
+      <description summary="popup interaction is done">
+	The popup_done event is sent out when a popup grab is broken,
+	that is, when the user clicks a surface that doesn't belong
+	to the client owning the popup surface.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="wl_surface" version="6">
+    <description summary="an onscreen surface">
+      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
+      coordinates of the pixel content, in case a buffer_transform
+      or a buffer_scale is used.
+
+      A surface without a "role" is fairly useless: a compositor does
+      not know where, when or how to present it. The role is the
+      purpose of a wl_surface. Examples of roles are a cursor for a
+      pointer (as set by wl_pointer.set_cursor), a drag icon
+      (wl_data_device.start_drag), a sub-surface
+      (wl_subcompositor.get_subsurface), and a window as defined by a
+      shell protocol (e.g. wl_shell.get_shell_surface).
+
+      A surface can have only one role at a time. Initially a
+      wl_surface does not have a role. Once a wl_surface is given a
+      role, it is set permanently for the whole lifetime of the
+      wl_surface object. Giving the current role again is allowed,
+      unless explicitly forbidden by the relevant interface
+      specification.
+
+      Surface roles are given by requests in other interfaces such as
+      wl_pointer.set_cursor. The request should explicitly mention
+      that this request gives a role to a wl_surface. Often, this
+      request also creates a new protocol object that represents the
+      role and adds additional functionality to wl_surface. When a
+      client wants to destroy a wl_surface, they must destroy this role
+      object before the wl_surface, otherwise a defunct_role_object error is
+      sent.
+
+      Destroying the role object does not remove the role from the
+      wl_surface, but it may stop the wl_surface from "playing the role".
+      For instance, if a wl_subsurface object is destroyed, the wl_surface
+      it was created for will be unmapped and forget its position and
+      z-order. It is allowed to create a wl_subsurface for the same
+      wl_surface again, but it is not allowed to use the wl_surface as
+      a cursor (cursor is a different role than sub-surface, and role
+      switching is not allowed).
+    </description>
+
+    <enum name="error">
+      <description summary="wl_surface error values">
+	These errors can be emitted in response to wl_surface requests.
+      </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"/>
+      <entry name="invalid_offset" value="3" summary="buffer offset is invalid"/>
+      <entry name="defunct_role_object" value="4"
+	     summary="surface was destroyed before its role object"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete surface">
+	Deletes the surface and invalidates its object ID.
+      </description>
+    </request>
+
+    <request name="attach">
+      <description summary="set the surface contents">
+	Set a buffer as the content of this surface.
+
+	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 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
+	left corner, in surface-local coordinates. In other words, the
+	x and y, combined with the new surface size define in which
+	directions the surface's size changes. Setting anything other than 0
+	as x and y arguments is discouraged, and should instead be replaced
+	with using the separate wl_surface.offset request.
+
+	When the bound wl_surface version is 5 or higher, passing any
+	non-zero x or y is a protocol violation, and will result in an
+	'invalid_offset' error being raised. The x and y arguments are ignored
+	and do not change the pending state. To achieve equivalent semantics,
+	use wl_surface.offset.
+
+	Surface contents are double-buffered state, see wl_surface.commit.
+
+	The initial surface contents are void; there is no content.
+	wl_surface.attach assigns the given wl_buffer as the pending
+	wl_buffer. wl_surface.commit makes the pending wl_buffer the new
+	surface contents, and the size of the surface becomes the size
+	calculated from the wl_buffer, as described above. After commit,
+	there is no pending buffer until the next attach.
+
+	Committing a pending wl_buffer allows the compositor to read the
+	pixels in the wl_buffer. The compositor may access the pixels at
+	any time after the wl_surface.commit request. When the compositor
+	will not access the pixels anymore, it will send the
+	wl_buffer.release event. Only after receiving wl_buffer.release,
+	the client may reuse the wl_buffer. A wl_buffer that has been
+	attached and then replaced by another attach instead of committed
+	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. Destroying the wl_buffer before wl_buffer.release
+	is allowed as long as the underlying buffer storage isn't re-used (this
+	can happen e.g. on client process termination). However, if the client
+	destroys the wl_buffer before receiving the wl_buffer.release event and
+	mutates the underlying buffer storage, the surface contents become
+	undefined immediately.
+
+	If wl_surface.attach is sent with a NULL wl_buffer, the
+	following wl_surface.commit will remove the surface content.
+
+	If a pending wl_buffer has been destroyed, the result is not specified.
+	Many compositors are known to remove the surface content on the following
+	wl_surface.commit, but this behaviour is not universal. Clients seeking to
+	maximise compatibility should not destroy pending buffers and should
+	ensure that they explicitly remove content from surfaces, even after
+	destroying buffers.
+      </description>
+      <arg name="buffer" type="object" interface="wl_buffer" allow-null="true"
+	   summary="buffer of surface contents"/>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+    </request>
+
+    <request name="damage">
+      <description summary="mark part of the surface damaged">
+	This request is used to describe the regions where the pending
+	buffer is different from the current surface contents, and where
+	the surface therefore needs to be repainted. The compositor
+	ignores the parts of the damage that fall outside of the surface.
+
+	Damage is double-buffered state, see wl_surface.commit.
+
+	The damage rectangle is specified in surface-local coordinates,
+	where x and y specify the upper left corner of the damage rectangle.
+
+	The initial value for pending damage is empty: no damage.
+	wl_surface.damage adds pending damage: the new pending damage
+	is the union of old pending damage and the given rectangle.
+
+	wl_surface.commit assigns pending damage as the current damage,
+	and clears pending damage. The server will clear the current
+	damage as it repaints the surface.
+
+	Note! New clients should not use this request. Instead damage can be
+	posted with wl_surface.damage_buffer which uses buffer coordinates
+	instead of surface coordinates.
+      </description>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+      <arg name="width" type="int" summary="width of damage rectangle"/>
+      <arg name="height" type="int" summary="height of damage rectangle"/>
+    </request>
+
+    <request name="frame">
+      <description summary="request a frame throttling hint">
+	Request a notification when it is a good time to start drawing a new
+	frame, by creating a frame callback. This is useful for throttling
+	redrawing operations, and driving animations.
+
+	When a client is animating on a wl_surface, it can use the 'frame'
+	request to get notified when it is a good time to draw and commit the
+	next frame of animation. If the client commits an update earlier than
+	that, it is likely that some updates will not make it to the display,
+	and the client is wasting resources by drawing too often.
+
+	The frame request will take effect on the next wl_surface.commit.
+	The notification will only be posted for one frame unless
+	requested again. For a wl_surface, the notifications are posted in
+	the order the frame requests were committed.
+
+	The server must send the notifications so that a client
+	will not send excessive updates, while still allowing
+	the highest possible update rate for clients that wait for the reply
+	before drawing again. The server should give some time for the client
+	to draw and commit after sending the frame callback events to let it
+	hit the next output refresh.
+
+	A server should avoid signaling the frame callbacks if the
+	surface is not visible in any way, e.g. the surface is off-screen,
+	or completely obscured by other opaque surfaces.
+
+	The object returned by this request will be destroyed by the
+	compositor after the callback is fired and as such the client must not
+	attempt to use it after that point.
+
+	The callback_data passed in the callback is the current time, in
+	milliseconds, with an undefined base.
+      </description>
+      <arg name="callback" type="new_id" interface="wl_callback" summary="callback object for the frame request"/>
+    </request>
+
+    <request name="set_opaque_region">
+      <description summary="set opaque region">
+	This request sets the region of the surface that contains
+	opaque content.
+
+	The opaque region is an optimization hint for the compositor
+	that lets it optimize the redrawing of content behind opaque
+	regions.  Setting an opaque region is not required for correct
+	behaviour, but marking transparent content as opaque will result
+	in repaint artifacts.
+
+	The opaque region is specified in surface-local coordinates.
+
+	The compositor ignores the parts of the opaque region that fall
+	outside of the surface.
+
+	Opaque region is double-buffered state, see wl_surface.commit.
+
+	wl_surface.set_opaque_region changes the pending opaque region.
+	wl_surface.commit copies the pending region to the current region.
+	Otherwise, the pending and current regions are never changed.
+
+	The initial value for an opaque region is empty. Setting the pending
+	opaque region has copy semantics, and the wl_region object can be
+	destroyed immediately. A NULL wl_region causes the pending opaque
+	region to be set to empty.
+      </description>
+      <arg name="region" type="object" interface="wl_region" allow-null="true"
+	   summary="opaque region of the surface"/>
+    </request>
+
+    <request name="set_input_region">
+      <description summary="set input region">
+	This request sets the region of the surface that can receive
+	pointer and touch events.
+
+	Input events happening outside of this region will try the next
+	surface in the server surface stack. The compositor ignores the
+	parts of the input region that fall outside of the surface.
+
+	The input region is specified in surface-local coordinates.
+
+	Input region is double-buffered state, see wl_surface.commit.
+
+	wl_surface.set_input_region changes the pending input region.
+	wl_surface.commit copies the pending region to the current region.
+	Otherwise the pending and current regions are never changed,
+	except cursor and icon surfaces are special cases, see
+	wl_pointer.set_cursor and wl_data_device.start_drag.
+
+	The initial value for an input region is infinite. That means the
+	whole surface will accept input. Setting the pending input region
+	has copy semantics, and the wl_region object can be destroyed
+	immediately. A NULL wl_region causes the input region to be set
+	to infinite.
+      </description>
+      <arg name="region" type="object" interface="wl_region" allow-null="true"
+	   summary="input region of the surface"/>
+    </request>
+
+    <request name="commit">
+      <description summary="commit pending surface state">
+	Surface state (input, opaque, and damage regions, attached buffers,
+	etc.) is double-buffered. Protocol requests modify the pending state,
+	as opposed to the active state in use by the compositor.
+
+	A commit request atomically creates a content update from the pending
+	state, even if the pending state has not been touched. The content
+	update is placed in a queue until it becomes active. After commit, the
+	new pending state is as documented for each related request.
+
+	When the content update is applied, the wl_buffer is applied before all
+	other state. This means that all coordinates in double-buffered state
+	are relative to the newly attached wl_buffers, except for
+	wl_surface.attach itself. If there is no newly attached wl_buffer, the
+	coordinates are relative to the previous content update.
+
+	All requests that need a commit to become effective are documented
+	to affect double-buffered state.
+
+	Other interfaces may add further double-buffered surface state.
+      </description>
+    </request>
+
+    <event name="enter">
+      <description summary="surface enters an output">
+	This is emitted whenever a surface's creation, movement, or resizing
+	results in some part of it being within the scanout region of an
+	output.
+
+	Note that a surface may be overlapping with zero or more outputs.
+      </description>
+      <arg name="output" type="object" interface="wl_output" summary="output entered by the surface"/>
+    </event>
+
+    <event name="leave">
+      <description summary="surface leaves an output">
+	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>
+
+    <!-- Version 2 additions -->
+
+    <request name="set_buffer_transform" since="2">
+      <description summary="sets the buffer transformation">
+	This request sets the transformation that the client has already applied
+	to the content of the buffer. The accepted values for the transform
+	parameter are the values for wl_output.transform.
+
+	The compositor applies the inverse of this transformation whenever it
+	uses the buffer contents.
+
+	Buffer transform is double-buffered state, see wl_surface.commit.
+
+	A newly created surface has its buffer transformation set to normal.
+
+	wl_surface.set_buffer_transform changes the pending buffer
+	transformation. wl_surface.commit copies the pending buffer
+	transformation to the current one. Otherwise, the pending and current
+	values are never changed.
+
+	The purpose of this request is to allow clients to render content
+	according to the output transform, thus permitting the compositor to
+	use certain optimizations even if the display is rotated. Using
+	hardware overlays and scanning out a client buffer for fullscreen
+	surfaces are examples of such optimizations. Those optimizations are
+	highly dependent on the compositor implementation, so the use of this
+	request should be considered on a case-by-case basis.
+
+	Note that if the transform value includes 90 or 270 degree rotation,
+	the width of the buffer will become the surface height and the height
+	of the buffer will become the surface width.
+
+	If transform is not one of the values from the
+	wl_output.transform enum the invalid_transform protocol error
+	is raised.
+      </description>
+      <arg name="transform" type="int" enum="wl_output.transform"
+	   summary="transform for interpreting buffer contents"/>
+    </request>
+
+    <!-- Version 3 additions -->
+
+    <request name="set_buffer_scale" since="3">
+      <description summary="sets the buffer scaling factor">
+	This request sets an optional scaling factor on how the compositor
+	interprets the contents of the buffer attached to the window.
+
+	Buffer scale is double-buffered state, see wl_surface.commit.
+
+	A newly created surface has its buffer scale set to 1.
+
+	wl_surface.set_buffer_scale changes the pending buffer scale.
+	wl_surface.commit copies the pending buffer scale to the current one.
+	Otherwise, the pending and current values are never changed.
+
+	The purpose of this request is to allow clients to supply higher
+	resolution buffer data for use on high resolution outputs. It is
+	intended that you pick the same buffer scale as the scale of the
+	output that the surface is displayed on. This means the compositor
+	can avoid scaling when rendering the surface on that output.
+
+	Note that if the scale is larger than 1, then you have to attach
+	a buffer that is larger (by a factor of scale in each dimension)
+	than the desired surface size.
+
+	If scale is not greater than 0 the invalid_scale protocol error is
+	raised.
+      </description>
+      <arg name="scale" type="int"
+	   summary="scale for interpreting buffer contents"/>
+    </request>
+
+    <!-- Version 4 additions -->
+    <request name="damage_buffer" since="4">
+      <description summary="mark part of the surface damaged using buffer coordinates">
+	This request is used to describe the regions where the pending
+	buffer is different from the current surface contents, and where
+	the surface therefore needs to be repainted. The compositor
+	ignores the parts of the damage that fall outside of the surface.
+
+	Damage is double-buffered state, see wl_surface.commit.
+
+	The damage rectangle is specified in buffer coordinates,
+	where x and y specify the upper left corner of the damage rectangle.
+
+	The initial value for pending damage is empty: no damage.
+	wl_surface.damage_buffer adds pending damage: the new pending
+	damage is the union of old pending damage and the given rectangle.
+
+	wl_surface.commit assigns pending damage as the current damage,
+	and clears pending damage. The server will clear the current
+	damage as it repaints the surface.
+
+	This request differs from wl_surface.damage in only one way - it
+	takes damage in buffer coordinates instead of surface-local
+	coordinates. While this generally is more intuitive than surface
+	coordinates, it is especially desirable when using wp_viewport
+	or when a drawing library (like EGL) is unaware of buffer scale
+	and buffer transform.
+
+	Note: Because buffer transformation changes and damage requests may
+	be interleaved in the protocol stream, it is impossible to determine
+	the actual mapping between surface and buffer damage until
+	wl_surface.commit time. Therefore, compositors wishing to take both
+	kinds of damage into account will have to accumulate damage from the
+	two requests separately and only transform from one to the other
+	after receiving the wl_surface.commit.
+      </description>
+      <arg name="x" type="int" summary="buffer-local x coordinate"/>
+      <arg name="y" type="int" summary="buffer-local y coordinate"/>
+      <arg name="width" type="int" summary="width of damage rectangle"/>
+      <arg name="height" type="int" summary="height of damage rectangle"/>
+    </request>
+
+    <!-- Version 5 additions -->
+
+    <request name="offset" since="5">
+      <description summary="set the surface contents offset">
+	The x and y arguments specify the location of the new pending
+	buffer's upper left corner, relative to the current buffer's upper
+	left corner, in surface-local coordinates. In other words, the
+	x and y, combined with the new surface size define in which
+	directions the surface's size changes.
+
+	Surface location offset is double-buffered state, see
+	wl_surface.commit.
+
+	This request is semantically equivalent to and the replaces the x and y
+	arguments in the wl_surface.attach request in wl_surface versions prior
+	to 5. See wl_surface.attach for details.
+      </description>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+    </request>
+
+    <!-- Version 6 additions -->
+
+    <event name="preferred_buffer_scale" since="6">
+      <description summary="preferred buffer scale for the surface">
+	This event indicates the preferred buffer scale for this surface. It is
+	sent whenever the compositor's preference changes.
+
+	Before receiving this event the preferred buffer scale for this surface
+	is 1.
+
+	It is intended that scaling aware clients use this event to scale their
+	content and use wl_surface.set_buffer_scale to indicate the scale they
+	have rendered with. This allows clients to supply a higher detail
+	buffer.
+
+	The compositor shall emit a scale value greater than 0.
+      </description>
+      <arg name="factor" type="int" summary="preferred scaling factor"/>
+    </event>
+
+    <event name="preferred_buffer_transform" since="6">
+      <description summary="preferred buffer transform for the surface">
+	This event indicates the preferred buffer transform for this surface.
+	It is sent whenever the compositor's preference changes.
+
+	Before receiving this event the preferred buffer transform for this
+	surface is normal.
+
+	Applying this transformation to the surface buffer contents and using
+	wl_surface.set_buffer_transform might allow the compositor to use the
+	surface buffer more efficiently.
+      </description>
+      <arg name="transform" type="uint" enum="wl_output.transform"
+	   summary="preferred transform"/>
+    </event>
+   </interface>
+
+  <interface name="wl_seat" version="9">
+    <description summary="group of input devices">
+      A seat is a group of keyboards, pointer and touch devices. This
+      object is published as a global during start up, or when such a
+      device is hot plugged.  A seat typically has a pointer and
+      maintains a keyboard focus and a pointer focus.
+    </description>
+
+    <enum name="capability" bitfield="true">
+      <description summary="seat capability bitmask">
+	This is a bitmask of capabilities this seat has; if a member is
+	set, then it is present on the seat.
+      </description>
+      <entry name="pointer" value="1" summary="the seat has pointer devices"/>
+      <entry name="keyboard" value="2" summary="the seat has one or more keyboards"/>
+      <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,
+	keyboard or touch capabilities.  The argument is a capability
+	enum containing the complete set of capabilities this seat has.
+
+	When the pointer capability is added, a client may create a
+	wl_pointer object using the wl_seat.get_pointer request. This object
+	will receive pointer events until the capability is removed in the
+	future.
+
+	When the pointer capability is removed, a client should destroy the
+	wl_pointer objects associated with the seat where the capability was
+	removed, using the wl_pointer.release request. No further pointer
+	events will be received on these objects.
+
+	In some compositors, if a seat regains the pointer capability and a
+	client has a previously obtained wl_pointer object of version 4 or
+	less, that object may start sending pointer events again. This
+	behavior is considered a misinterpretation of the intended behavior
+	and must not be relied upon by the client. wl_pointer objects of
+	version 5 or later must not send events if created before the most
+	recent event notifying the client of an added pointer capability.
+
+	The above behavior also applies to wl_keyboard and wl_touch with the
+	keyboard and touch capabilities, respectively.
+      </description>
+      <arg name="capabilities" type="uint" enum="capability" summary="capabilities of the seat"/>
+    </event>
+
+    <request name="get_pointer">
+      <description summary="return pointer object">
+	The ID provided will be initialized to the wl_pointer interface
+	for this seat.
+
+	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. The missing_capability error will
+	be sent in this case.
+      </description>
+      <arg name="id" type="new_id" interface="wl_pointer" summary="seat pointer"/>
+    </request>
+
+    <request name="get_keyboard">
+      <description summary="return keyboard object">
+	The ID provided will be initialized to the wl_keyboard interface
+	for this seat.
+
+	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. The missing_capability error will
+	be sent in this case.
+      </description>
+      <arg name="id" type="new_id" interface="wl_keyboard" summary="seat keyboard"/>
+    </request>
+
+    <request name="get_touch">
+      <description summary="return touch object">
+	The ID provided will be initialized to the wl_touch interface
+	for this seat.
+
+	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. 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>
+
+    <!-- Version 2 additions -->
+
+    <event name="name" since="2">
+      <description summary="unique identifier for this seat">
+	In a multi-seat configuration the seat name can be used by clients to
+	help identify which physical devices the seat represents.
+
+	The seat name is a UTF-8 string with no convention defined for its
+	contents. Each name is unique among all wl_seat globals. The name is
+	only guaranteed to be unique for the current compositor instance.
+
+	The same seat names are used for all clients. Thus, the name can be
+	shared across processes to refer to a specific wl_seat global.
+
+	The name event is sent after binding to the seat global. This event is
+	only sent once per seat object, and the name does not change over the
+	lifetime of the wl_seat global.
+
+	Compositors may re-use the same seat name if the wl_seat global is
+	destroyed and re-created later.
+      </description>
+      <arg name="name" type="string" summary="seat identifier"/>
+    </event>
+
+    <!-- Version 5 additions -->
+
+    <request name="release" type="destructor" since="5">
+      <description summary="release the seat object">
+	Using this request a client can tell the server that it is not going to
+	use the seat object anymore.
+      </description>
+    </request>
+
+  </interface>
+
+  <interface name="wl_pointer" version="9">
+    <description summary="pointer input device">
+      The wl_pointer interface represents one or more input devices,
+      such as mice, which control the pointer location and pointer_focus
+      of a seat.
+
+      The wl_pointer interface generates motion, enter and leave
+      events for the surfaces that the pointer is located over,
+      and button and axis events for button presses, button releases
+      and scrolling.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="set_cursor">
+      <description summary="set the pointer surface">
+	Set the pointer surface, i.e., the surface that contains the
+	pointer image (cursor). This request gives the surface the role
+	of a cursor. If the surface already has another role, it raises
+	a protocol error.
+
+	The cursor actually changes only if the pointer
+	focus for this device is one of the requesting client's surfaces
+	or the surface parameter is the current pointer surface. If
+	there was a previous surface set with this request it is
+	replaced. If surface is NULL, the pointer image is hidden.
+
+	The parameters hotspot_x and hotspot_y define the position of
+	the pointer surface relative to the pointer location. Its
+	top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
+	where (x, y) are the coordinates of the pointer location, in
+	surface-local coordinates.
+
+	On wl_surface.offset requests to the pointer surface, hotspot_x
+	and hotspot_y are decremented by the x and y parameters
+	passed to the request. The offset must be applied by
+	wl_surface.commit as usual.
+
+	The hotspot can also be updated by passing the currently set
+	pointer surface to this request with new values for hotspot_x
+	and hotspot_y.
+
+	The input region is ignored for wl_surfaces with the role of
+	a cursor. When the use as a cursor ends, the wl_surface is
+	unmapped.
+
+	The serial parameter must match the latest wl_pointer.enter
+	serial number sent to the client. Otherwise the request will be
+	ignored.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" allow-null="true"
+	   summary="pointer surface"/>
+      <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/>
+      <arg name="hotspot_y" type="int" summary="surface-local y coordinate"/>
+    </request>
+
+    <event name="enter">
+      <description summary="enter event">
+	Notification that this seat's pointer is focused on a certain
+	surface.
+
+	When a seat's focus enters a surface, the pointer image
+	is undefined and a client should respond to this event by setting
+	an appropriate pointer image with the set_cursor request.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface entered by the pointer"/>
+      <arg name="surface_x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="surface_y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+	Notification that this seat's pointer is no longer focused on
+	a certain surface.
+
+	The leave notification is sent before the enter notification
+	for the new focus.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the leave event"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface left by the pointer"/>
+    </event>
+
+    <event name="motion">
+      <description summary="pointer motion event">
+	Notification of pointer location change. The arguments
+	surface_x and surface_y are the location relative to the
+	focused surface.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface_x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="surface_y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+	Describes the physical state of a button that produced the button
+	event.
+      </description>
+      <entry name="released" value="0" summary="the button is not pressed"/>
+      <entry name="pressed" value="1" summary="the button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="pointer button event">
+	Mouse button click and release notifications.
+
+	The location of the click is given by the last motion or
+	enter event.
+	The time argument is a timestamp with millisecond
+	granularity, with an undefined base.
+
+	The button is a button code as defined in the Linux kernel's
+	linux/input-event-codes.h header file, e.g. BTN_LEFT.
+
+	Any 16-bit button code value is reserved for future additions to the
+	kernel's event code list. All other button codes above 0xFFFF are
+	currently undefined but may be used in future versions of this
+	protocol.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the button event"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="button" type="uint" summary="button that produced the event"/>
+      <arg name="state" type="uint" enum="button_state" summary="physical state of the button"/>
+    </event>
+
+    <enum name="axis">
+      <description summary="axis types">
+	Describes the axis types of scroll events.
+      </description>
+      <entry name="vertical_scroll" value="0" summary="vertical axis"/>
+      <entry name="horizontal_scroll" value="1" summary="horizontal axis"/>
+    </enum>
+
+    <event name="axis">
+      <description summary="axis event">
+	Scroll and other axis notifications.
+
+	For scroll events (vertical and horizontal scroll axes), the
+	value parameter is the length of a vector along the specified
+	axis in a coordinate space identical to those of motion events,
+	representing a relative movement along the specified axis.
+
+	For devices that support movements non-parallel to axes multiple
+	axis events will be emitted.
+
+	When applicable, for example for touch pads, the server can
+	choose to emit scroll events where the motion vector is
+	equivalent to a motion event vector.
+
+	When applicable, a client can transform its content relative to the
+	scroll distance.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+      <arg name="value" type="fixed" summary="length of vector in surface-local coordinate space"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the pointer object">
+	Using this request a client can tell the server that it is not going to
+	use the pointer object anymore.
+
+	This request destroys the pointer proxy object, so clients must not call
+	wl_pointer_destroy() after using this request.
+      </description>
+    </request>
+
+    <!-- Version 5 additions -->
+
+    <event name="frame" since="5">
+      <description summary="end of a pointer event sequence">
+	Indicates the end of a set of events that logically belong together.
+	A client is expected to accumulate the data in all events within the
+	frame before proceeding.
+
+	All wl_pointer events before a wl_pointer.frame event belong
+	logically together. For example, in a diagonal scroll motion the
+	compositor will send an optional wl_pointer.axis_source event, two
+	wl_pointer.axis events (horizontal and vertical) and finally a
+	wl_pointer.frame event. The client may use this information to
+	calculate a diagonal vector for scrolling.
+
+	When multiple wl_pointer.axis events occur within the same frame,
+	the motion vector is the combined motion of all events.
+	When a wl_pointer.axis and a wl_pointer.axis_stop event occur within
+	the same frame, this indicates that axis movement in one axis has
+	stopped but continues in the other axis.
+	When multiple wl_pointer.axis_stop events occur within the same
+	frame, this indicates that these axes stopped in the same instance.
+
+	A wl_pointer.frame event is sent for every logical event group,
+	even if the group only contains a single wl_pointer event.
+	Specifically, a client may get a sequence: motion, frame, button,
+	frame, axis, frame, axis_stop, frame.
+
+	The wl_pointer.enter and wl_pointer.leave events are logical events
+	generated by the compositor and not the hardware. These events are
+	also grouped by a wl_pointer.frame. When a pointer moves from one
+	surface to another, a compositor should group the
+	wl_pointer.leave event within the same wl_pointer.frame.
+	However, a client must not rely on wl_pointer.leave and
+	wl_pointer.enter being in the same wl_pointer.frame.
+	Compositor-specific policies may require the wl_pointer.leave and
+	wl_pointer.enter event being split across multiple wl_pointer.frame
+	groups.
+      </description>
+    </event>
+
+    <enum name="axis_source">
+      <description summary="axis source types">
+	Describes the source types for axis events. This indicates to the
+	client how an axis event was physically generated; a client may
+	adjust the user interface accordingly. For example, scroll events
+	from a "finger" source may be in a smooth coordinate space with
+	kinetic scrolling whereas a "wheel" source may be in discrete steps
+	of a number of lines.
+
+	The "continuous" axis source is a device generating events in a
+	continuous coordinate space, but using something other than a
+	finger. One example for this source is button-based scrolling where
+	the vertical motion of a device is converted to scroll events while
+	a button is held down.
+
+	The "wheel tilt" axis source indicates that the actual device is a
+	wheel but the scroll event is not caused by a rotation but a
+	(usually sideways) tilt of the wheel.
+      </description>
+      <entry name="wheel" value="0" summary="a physical wheel rotation" />
+      <entry name="finger" value="1" summary="finger on a touch surface" />
+      <entry name="continuous" value="2" summary="continuous coordinate space"/>
+      <entry name="wheel_tilt" value="3" summary="a physical wheel tilt" since="6"/>
+    </enum>
+
+    <event name="axis_source" since="5">
+      <description summary="axis source event">
+	Source information for scroll and other axes.
+
+	This event does not occur on its own. It is sent before a
+	wl_pointer.frame event and carries the source information for
+	all events within that frame.
+
+	The source specifies how this event was generated. If the source is
+	wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be
+	sent when the user lifts the finger off the device.
+
+	If the source is wl_pointer.axis_source.wheel,
+	wl_pointer.axis_source.wheel_tilt or
+	wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may
+	or may not be sent. Whether a compositor sends an axis_stop event
+	for these sources is hardware-specific and implementation-dependent;
+	clients must not rely on receiving an axis_stop event for these
+	scroll sources and should treat scroll sequences from these scroll
+	sources as unterminated by default.
+
+	This event is optional. If the source is unknown for a particular
+	axis event sequence, no event is sent.
+	Only one wl_pointer.axis_source event is permitted per frame.
+
+	The order of wl_pointer.axis_discrete and wl_pointer.axis_source is
+	not guaranteed.
+      </description>
+      <arg name="axis_source" type="uint" enum="axis_source" summary="source of the axis event"/>
+    </event>
+
+    <event name="axis_stop" since="5">
+      <description summary="axis stop event">
+	Stop notification for scroll and other axes.
+
+	For some wl_pointer.axis_source types, a wl_pointer.axis_stop event
+	is sent to notify a client that the axis sequence has terminated.
+	This enables the client to implement kinetic scrolling.
+	See the wl_pointer.axis_source documentation for information on when
+	this event may be generated.
+
+	Any wl_pointer.axis events with the same axis_source after this
+	event should be considered as the start of a new axis motion.
+
+	The timestamp is to be interpreted identical to the timestamp in the
+	wl_pointer.axis event. The timestamp value may be the same as a
+	preceding wl_pointer.axis event.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="axis" type="uint" enum="axis" summary="the axis stopped with this event"/>
+    </event>
+
+    <event name="axis_discrete" since="5" deprecated-since="8">
+      <description summary="axis click event">
+	Discrete step information for scroll and other axes.
+
+	This event carries the axis value of the wl_pointer.axis event in
+	discrete steps (e.g. mouse wheel clicks).
+
+	This event is deprecated with wl_pointer version 8 - this event is not
+	sent to clients supporting version 8 or later.
+
+	This event does not occur on its own, it is coupled with a
+	wl_pointer.axis event that represents this axis value on a
+	continuous scale. The protocol guarantees that each axis_discrete
+	event is always followed by exactly one axis event with the same
+	axis number within the same wl_pointer.frame. Note that the protocol
+	allows for other events to occur between the axis_discrete and
+	its coupled axis event, including other axis_discrete or axis
+	events. A wl_pointer.frame must not contain more than one axis_discrete
+	event per axis type.
+
+	This event is optional; continuous scrolling devices
+	like two-finger scrolling on touchpads do not have discrete
+	steps and do not generate this event.
+
+	The discrete value carries the directional information. e.g. a value
+	of -2 is two steps towards the negative direction of this axis.
+
+	The axis number is identical to the axis number in the associated
+	axis event.
+
+	The order of wl_pointer.axis_discrete and wl_pointer.axis_source is
+	not guaranteed.
+      </description>
+      <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+      <arg name="discrete" type="int" summary="number of steps"/>
+    </event>
+
+    <event name="axis_value120" since="8">
+      <description summary="axis high-resolution scroll event">
+	Discrete high-resolution scroll information.
+
+	This event carries high-resolution wheel scroll information,
+	with each multiple of 120 representing one logical scroll step
+	(a wheel detent). For example, an axis_value120 of 30 is one quarter of
+	a logical scroll step in the positive direction, a value120 of
+	-240 are two logical scroll steps in the negative direction within the
+	same hardware event.
+	Clients that rely on discrete scrolling should accumulate the
+	value120 to multiples of 120 before processing the event.
+
+	The value120 must not be zero.
+
+	This event replaces the wl_pointer.axis_discrete event in clients
+	supporting wl_pointer version 8 or later.
+
+	Where a wl_pointer.axis_source event occurs in the same
+	wl_pointer.frame, the axis source applies to this event.
+
+	The order of wl_pointer.axis_value120 and wl_pointer.axis_source is
+	not guaranteed.
+      </description>
+      <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+      <arg name="value120" type="int" summary="scroll distance as fraction of 120"/>
+    </event>
+
+    <!-- Version 9 additions -->
+
+    <enum name="axis_relative_direction">
+      <description summary="axis relative direction">
+	This specifies the direction of the physical motion that caused a
+	wl_pointer.axis event, relative to the wl_pointer.axis direction.
+      </description>
+      <entry name="identical" value="0"
+	  summary="physical motion matches axis direction"/>
+      <entry name="inverted" value="1"
+	  summary="physical motion is the inverse of the axis direction"/>
+    </enum>
+
+    <event name="axis_relative_direction" since="9">
+      <description summary="axis relative physical direction event">
+	Relative directional information of the entity causing the axis
+	motion.
+
+	For a wl_pointer.axis event, the wl_pointer.axis_relative_direction
+	event specifies the movement direction of the entity causing the
+	wl_pointer.axis event. For example:
+	- if a user's fingers on a touchpad move down and this
+	  causes a wl_pointer.axis vertical_scroll down event, the physical
+	  direction is 'identical'
+	- if a user's fingers on a touchpad move down and this causes a
+	  wl_pointer.axis vertical_scroll up scroll up event ('natural
+	  scrolling'), the physical direction is 'inverted'.
+
+	A client may use this information to adjust scroll motion of
+	components. Specifically, enabling natural scrolling causes the
+	content to change direction compared to traditional scrolling.
+	Some widgets like volume control sliders should usually match the
+	physical direction regardless of whether natural scrolling is
+	active. This event enables clients to match the scroll direction of
+	a widget to the physical direction.
+
+	This event does not occur on its own, it is coupled with a
+	wl_pointer.axis event that represents this axis value.
+	The protocol guarantees that each axis_relative_direction event is
+	always followed by exactly one axis event with the same
+	axis number within the same wl_pointer.frame. Note that the protocol
+	allows for other events to occur between the axis_relative_direction
+	and its coupled axis event.
+
+	The axis number is identical to the axis number in the associated
+	axis event.
+
+	The order of wl_pointer.axis_relative_direction,
+	wl_pointer.axis_discrete and wl_pointer.axis_source is not
+	guaranteed.
+      </description>
+      <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+      <arg name="direction" type="uint" enum="axis_relative_direction"
+	  summary="physical direction relative to axis motion"/>
+    </event>
+  </interface>
+
+  <interface name="wl_keyboard" version="9">
+    <description summary="keyboard input device">
+      The wl_keyboard interface represents one or more keyboards
+      associated with a seat.
+
+      Each wl_keyboard has the following logical state:
+
+      - an active surface (possibly null),
+      - the keys currently logically down,
+      - the active modifiers,
+      - the active group.
+
+      By default, the active surface is null, the keys currently logically down
+      are empty, the active modifiers and the active group are 0.
+    </description>
+
+    <enum name="keymap_format">
+      <description summary="keyboard mapping format">
+	This specifies the format of the keymap provided to the
+	client with the wl_keyboard.keymap event.
+      </description>
+      <entry name="no_keymap" value="0"
+	     summary="no keymap; client must understand how to interpret the raw keycode"/>
+      <entry name="xkb_v1" value="1"
+	     summary="libxkbcommon compatible, null-terminated string; to determine the xkb keycode, clients must add 8 to the key event keycode"/>
+    </enum>
+
+    <event name="keymap">
+      <description summary="keyboard mapping">
+	This event provides a file descriptor to the client which can be
+	memory-mapped in read-only mode to provide a keyboard mapping
+	description.
+
+	From version 7 onwards, the fd must be mapped with MAP_PRIVATE by
+	the recipient, as MAP_SHARED may fail.
+      </description>
+      <arg name="format" type="uint" enum="keymap_format" summary="keymap format"/>
+      <arg name="fd" type="fd" summary="keymap file descriptor"/>
+      <arg name="size" type="uint" summary="keymap size, in bytes"/>
+    </event>
+
+    <event name="enter">
+      <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.
+
+	In the wl_keyboard logical state, this event sets the active surface to
+	the surface argument and the keys currently logically down to the keys
+	in the keys argument. The compositor must not send this event if the
+	wl_keyboard already had an active surface immediately before 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"/>
+      <arg name="keys" type="array" summary="the keys currently logically down"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+	Notification that this seat's keyboard focus is no longer on
+	a certain surface.
+
+	The leave notification is sent before the enter notification
+	for the new focus.
+
+	In the wl_keyboard logical state, this event resets all values to their
+	defaults. The compositor must not send this event if the active surface
+	of the wl_keyboard was not equal to the surface argument immediately
+	before this event.
+      </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"/>
+    </event>
+
+    <enum name="key_state">
+      <description summary="physical key state">
+	Describes the physical state of a key that produced the key event.
+      </description>
+      <entry name="released" value="0" summary="key is not pressed"/>
+      <entry name="pressed" value="1" summary="key is pressed"/>
+    </enum>
+
+    <event name="key">
+      <description summary="key event">
+	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.
+
+	In the wl_keyboard logical state, this event adds the key to the keys
+	currently logically down (if the state argument is pressed) or removes
+	the key from the keys currently logically down (if the state argument is
+	released). The compositor must not send this event if the wl_keyboard
+	did not have an active surface immediately before this event. The
+	compositor must not send this event if state is pressed (resp. released)
+	and the key was already logically down (resp. was not logically down)
+	immediately before 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"/>
+      <arg name="key" type="uint" summary="key that produced the event"/>
+      <arg name="state" type="uint" enum="key_state" summary="physical state of the key"/>
+    </event>
+
+    <event name="modifiers">
+      <description summary="modifier and group state">
+	Notifies clients that the modifier and/or group state has
+	changed, and it should update its local state.
+
+	The compositor may send this event without a surface of the client
+	having keyboard focus, for example to tie modifier information to
+	pointer focus instead. If a modifier event with pressed modifiers is sent
+	without a prior enter event, the client can assume the modifier state is
+	valid until it receives the next wl_keyboard.modifiers event. In order to
+	reset the modifier state again, the compositor can send a
+	wl_keyboard.modifiers event with no pressed modifiers.
+
+	In the wl_keyboard logical state, this event updates the modifiers and
+	group.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the modifiers event"/>
+      <arg name="mods_depressed" type="uint" summary="depressed modifiers"/>
+      <arg name="mods_latched" type="uint" summary="latched modifiers"/>
+      <arg name="mods_locked" type="uint" summary="locked modifiers"/>
+      <arg name="group" type="uint" summary="keyboard layout"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the keyboard object"/>
+    </request>
+
+    <!-- Version 4 additions -->
+
+    <event name="repeat_info" since="4">
+      <description summary="repeat rate and delay">
+	Informs the client about the keyboard's repeat rate and delay.
+
+	This event is sent as soon as the wl_keyboard object has been created,
+	and is guaranteed to be received by the client before any key press
+	event.
+
+	Negative values for either rate or delay are illegal. A rate of zero
+	will disable any repeating (regardless of the value of delay).
+
+	This event can be sent later on as well with a new value if necessary,
+	so clients should continue listening for the event past the creation
+	of wl_keyboard.
+      </description>
+      <arg name="rate" type="int"
+	   summary="the rate of repeating keys in characters per second"/>
+      <arg name="delay" type="int"
+	   summary="delay in milliseconds since key down until repeating starts"/>
+    </event>
+  </interface>
+
+  <interface name="wl_touch" version="9">
+    <description summary="touchscreen input device">
+      The wl_touch interface represents a touchscreen
+      associated with a seat.
+
+      Touch interactions can consist of one or more contacts.
+      For each contact, a series of events is generated, starting
+      with a down event, followed by zero or more motion events,
+      and ending with an up event. Events relating to the same
+      contact point can be identified by the ID of the sequence.
+    </description>
+
+    <event name="down">
+      <description summary="touch down event and beginning of a touch sequence">
+	A new touch point has appeared on the surface. This touch point is
+	assigned a unique ID. Future events from this touch point reference
+	this ID. The ID ceases to be valid after a touch up event and may be
+	reused in the future.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the touch down event"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface touched"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="up">
+      <description summary="end of a touch event sequence">
+	The touch point has disappeared. No further events will be sent for
+	this touch point and the touch point's ID is released and may be
+	reused in a future touch down event.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the touch up event"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+    </event>
+
+    <event name="motion">
+      <description summary="update of touch point coordinates">
+	A touch point has changed coordinates.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="frame">
+      <description summary="end of touch frame event">
+	Indicates the end of a set of events that logically belong together.
+	A client is expected to accumulate the data in all events within the
+	frame before proceeding.
+
+	A wl_touch.frame terminates at least one event but otherwise no
+	guarantee is provided about the set of events within a frame. A client
+	must assume that any state not updated in a frame is unchanged from the
+	previously known state.
+      </description>
+    </event>
+
+    <event name="cancel">
+      <description summary="touch session cancelled">
+	Sent if the compositor decides the touch stream is a global
+	gesture. No further events are sent to the clients from that
+	particular gesture. Touch cancellation applies to all touch points
+	currently active on this client's surface. The client is
+	responsible for finalizing the touch points, future touch points on
+	this surface may reuse the touch point ID.
+
+	No frame event is required after the cancel event.
+      </description>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the touch object"/>
+    </request>
+
+    <!-- Version 6 additions -->
+
+    <event name="shape" since="6">
+      <description summary="update shape of touch point">
+	Sent when a touchpoint has changed its shape.
+
+	This event does not occur on its own. It is sent before a
+	wl_touch.frame event and carries the new shape information for
+	any previously reported, or new touch points of that frame.
+
+	Other events describing the touch point such as wl_touch.down,
+	wl_touch.motion or wl_touch.orientation may be sent within the
+	same wl_touch.frame. A client should treat these events as a single
+	logical touch point update. The order of wl_touch.shape,
+	wl_touch.orientation and wl_touch.motion is not guaranteed.
+	A wl_touch.down event is guaranteed to occur before the first
+	wl_touch.shape event for this touch ID but both events may occur within
+	the same wl_touch.frame.
+
+	A touchpoint shape is approximated by an ellipse through the major and
+	minor axis length. The major axis length describes the longer diameter
+	of the ellipse, while the minor axis length describes the shorter
+	diameter. Major and minor are orthogonal and both are specified in
+	surface-local coordinates. The center of the ellipse is always at the
+	touchpoint location as reported by wl_touch.down or wl_touch.move.
+
+	This event is only sent by the compositor if the touch device supports
+	shape reports. The client has to make reasonable assumptions about the
+	shape if it did not receive this event.
+      </description>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="major" type="fixed" summary="length of the major axis in surface-local coordinates"/>
+      <arg name="minor" type="fixed" summary="length of the minor axis in surface-local coordinates"/>
+    </event>
+
+    <event name="orientation" since="6">
+      <description summary="update orientation of touch point">
+	Sent when a touchpoint has changed its orientation.
+
+	This event does not occur on its own. It is sent before a
+	wl_touch.frame event and carries the new shape information for
+	any previously reported, or new touch points of that frame.
+
+	Other events describing the touch point such as wl_touch.down,
+	wl_touch.motion or wl_touch.shape may be sent within the
+	same wl_touch.frame. A client should treat these events as a single
+	logical touch point update. The order of wl_touch.shape,
+	wl_touch.orientation and wl_touch.motion is not guaranteed.
+	A wl_touch.down event is guaranteed to occur before the first
+	wl_touch.orientation event for this touch ID but both events may occur
+	within the same wl_touch.frame.
+
+	The orientation describes the clockwise angle of a touchpoint's major
+	axis to the positive surface y-axis and is normalized to the -180 to
+	+180 degree range. The granularity of orientation depends on the touch
+	device, some devices only support binary rotation values between 0 and
+	90 degrees.
+
+	This event is only sent by the compositor if the touch device supports
+	orientation reports.
+      </description>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="orientation" type="fixed" summary="angle between major axis and positive surface y-axis in degrees"/>
+    </event>
+  </interface>
+
+  <interface name="wl_output" version="4">
+    <description summary="compositor output region">
+      An output describes part of the compositor geometry.  The
+      compositor works in the 'compositor coordinate system' and an
+      output corresponds to a rectangular area in that space that is
+      actually visible.  This typically corresponds to a monitor that
+      displays part of the compositor space.  This object is published
+      as global during start up, or when a monitor is hotplugged.
+    </description>
+
+    <enum name="subpixel">
+      <description summary="subpixel geometry information">
+	This enumeration describes how the physical
+	pixels on an output are laid out.
+      </description>
+      <entry name="unknown" value="0" summary="unknown geometry"/>
+      <entry name="none" value="1" summary="no geometry"/>
+      <entry name="horizontal_rgb" value="2" summary="horizontal RGB"/>
+      <entry name="horizontal_bgr" value="3" summary="horizontal BGR"/>
+      <entry name="vertical_rgb" value="4" summary="vertical RGB"/>
+      <entry name="vertical_bgr" value="5" summary="vertical BGR"/>
+    </enum>
+
+    <enum name="transform">
+      <description summary="transformation applied to buffer contents">
+	This describes transformations that clients and compositors apply to
+	buffer contents.
+
+	The flipped values correspond to an initial flip around a
+	vertical axis followed by rotation.
+
+	The purpose is mainly to allow clients to render accordingly and
+	tell the compositor, so that for fullscreen surfaces, the
+	compositor will still be able to scan out directly from client
+	surfaces.
+      </description>
+      <entry name="normal" value="0" summary="no transform"/>
+      <entry name="90" value="1" summary="90 degrees counter-clockwise"/>
+      <entry name="180" value="2" summary="180 degrees counter-clockwise"/>
+      <entry name="270" value="3" summary="270 degrees counter-clockwise"/>
+      <entry name="flipped" value="4" summary="180 degree flip around a vertical axis"/>
+      <entry name="flipped_90" value="5" summary="flip and rotate 90 degrees counter-clockwise"/>
+      <entry name="flipped_180" value="6" summary="flip and rotate 180 degrees counter-clockwise"/>
+      <entry name="flipped_270" value="7" summary="flip and rotate 270 degrees counter-clockwise"/>
+    </enum>
+
+    <event name="geometry">
+      <description summary="properties of the output">
+	The geometry event describes geometric properties of the output.
+	The event is sent when binding to the output object and whenever
+	any of the properties change.
+
+	The physical size can be set to zero if it doesn't make sense for this
+	output (e.g. for projectors or virtual outputs).
+
+	The geometry event will be followed by a done event (starting from
+	version 2).
+
+	Clients should use wl_surface.preferred_buffer_transform instead of the
+	transform advertised by this event to find the preferred buffer
+	transform to use for a surface.
+
+	Note: wl_output only advertises partial information about the output
+	position and identification. Some compositors, for instance those not
+	implementing a desktop-style output layout or those exposing virtual
+	outputs, might fake this information. Instead of using x and y, clients
+	should use xdg_output.logical_position. Instead of using make and model,
+	clients should use name and description.
+      </description>
+      <arg name="x" type="int"
+	   summary="x position within the global compositor space"/>
+      <arg name="y" type="int"
+	   summary="y position within the global compositor space"/>
+      <arg name="physical_width" type="int"
+	   summary="width in millimeters of the output"/>
+      <arg name="physical_height" type="int"
+	   summary="height in millimeters of the output"/>
+      <arg name="subpixel" type="int" enum="subpixel"
+	   summary="subpixel orientation of the output"/>
+      <arg name="make" type="string"
+	   summary="textual description of the manufacturer"/>
+      <arg name="model" type="string"
+	   summary="textual description of the model"/>
+      <arg name="transform" type="int" enum="transform"
+	   summary="additional transformation applied to buffer contents during presentation"/>
+    </event>
+
+    <enum name="mode" bitfield="true">
+      <description summary="mode information">
+	These flags describe properties of an output mode.
+	They are used in the flags bitfield of the mode event.
+      </description>
+      <entry name="current" value="0x1"
+	     summary="indicates this is the current mode"/>
+      <entry name="preferred" value="0x2"
+	     summary="indicates this is the preferred mode"/>
+    </enum>
+
+    <event name="mode">
+      <description summary="advertise available modes for the output">
+	The mode event describes an available mode for the output.
+
+	The event is sent when binding to the output object and there
+	will always be one mode, the current mode.  The event is sent
+	again if an output changes mode, for the mode that is now
+	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,
+	the output may be scaled, as described in wl_output.scale,
+	or transformed, as described in wl_output.transform. Clients
+	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).
+
+	The mode event will be followed by a done event (starting from
+	version 2).
+
+	Clients should not use the refresh rate to schedule frames. Instead,
+	they should use the wl_surface.frame event or the presentation-time
+	protocol.
+
+	Note: this information is not always meaningful for all outputs. Some
+	compositors, such as those exposing virtual outputs, might fake the
+	refresh rate or the size.
+      </description>
+      <arg name="flags" type="uint" enum="mode" summary="bitfield of mode flags"/>
+      <arg name="width" type="int" summary="width of the mode in hardware units"/>
+      <arg name="height" type="int" summary="height of the mode in hardware units"/>
+      <arg name="refresh" type="int" summary="vertical refresh rate in mHz"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <event name="done" since="2">
+      <description summary="sent all information about output">
+	This event is sent after all other properties have been
+	sent after binding to the output object and after any
+	other property changes done after that. This allows
+	changes to the output properties to be seen as
+	atomic, even if they happen via multiple events.
+      </description>
+    </event>
+
+    <event name="scale" since="2">
+      <description summary="output scaling properties">
+	This event contains scaling geometry information
+	that is not in the geometry event. It may be sent after
+	binding the output object or if the output scale changes
+	later. The compositor will emit a non-zero, positive
+	value for scale. If it is not sent, the client should
+	assume a scale of 1.
+
+	A scale larger than 1 means that the compositor will
+	automatically scale surface buffers by this amount
+	when rendering. This is used for very high resolution
+	displays where applications rendering at the native
+	resolution would be too small to be legible.
+
+	Clients should use wl_surface.preferred_buffer_scale
+	instead of this event to find the preferred buffer
+	scale to use for a surface.
+
+	The scale event will be followed by a done event.
+      </description>
+      <arg name="factor" type="int" summary="scaling factor of output"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the output object">
+	Using this request a client can tell the server that it is not going to
+	use the output object anymore.
+      </description>
+    </request>
+
+    <!-- Version 4 additions -->
+
+    <event name="name" since="4">
+      <description summary="name of this output">
+	Many compositors will assign user-friendly names to their outputs, show
+	them to the user, allow the user to refer to an output, etc. The client
+	may wish to know this name as well to offer the user similar behaviors.
+
+	The name is a UTF-8 string with no convention defined for its contents.
+	Each name is unique among all wl_output globals. The name is only
+	guaranteed to be unique for the compositor instance.
+
+	The same output name is used for all clients for a given wl_output
+	global. Thus, the name can be shared across processes to refer to a
+	specific wl_output global.
+
+	The name is not guaranteed to be persistent across sessions, thus cannot
+	be used to reliably identify an output in e.g. configuration files.
+
+	Examples of names include 'HDMI-A-1', 'WL-1', 'X11-1', etc. However, do
+	not assume that the name is a reflection of an underlying DRM connector,
+	X11 connection, etc.
+
+	The name event is sent after binding the output object. This event is
+	only sent once per output object, and the name does not change over the
+	lifetime of the wl_output global.
+
+	Compositors may re-use the same output name if the wl_output global is
+	destroyed and re-created later. Compositors should avoid re-using the
+	same name if possible.
+
+	The name event will be followed by a done event.
+      </description>
+      <arg name="name" type="string" summary="output name"/>
+    </event>
+
+    <event name="description" since="4">
+      <description summary="human-readable description of this output">
+	Many compositors can produce human-readable descriptions of their
+	outputs. The client may wish to know this description as well, e.g. for
+	output selection purposes.
+
+	The description is a UTF-8 string with no convention defined for its
+	contents. The description is not guaranteed to be unique among all
+	wl_output globals. Examples might include 'Foocorp 11" Display' or
+	'Virtual X11 output via :1'.
+
+	The description event is sent after binding the output object and
+	whenever the description changes. The description is optional, and may
+	not be sent at all.
+
+	The description event will be followed by a done event.
+      </description>
+      <arg name="description" type="string" summary="output description"/>
+    </event>
+  </interface>
+
+  <interface name="wl_region" version="1">
+    <description summary="region interface">
+      A region object describes an area.
+
+      Region objects are used to describe the opaque and input
+      regions of a surface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy region">
+	Destroy the region.  This will invalidate the object ID.
+      </description>
+    </request>
+
+    <request name="add">
+      <description summary="add rectangle to region">
+	Add the specified rectangle to the region.
+      </description>
+      <arg name="x" type="int" summary="region-local x coordinate"/>
+      <arg name="y" type="int" summary="region-local y coordinate"/>
+      <arg name="width" type="int" summary="rectangle width"/>
+      <arg name="height" type="int" summary="rectangle height"/>
+    </request>
+
+    <request name="subtract">
+      <description summary="subtract rectangle from region">
+	Subtract the specified rectangle from the region.
+      </description>
+      <arg name="x" type="int" summary="region-local x coordinate"/>
+      <arg name="y" type="int" summary="region-local y coordinate"/>
+      <arg name="width" type="int" summary="rectangle width"/>
+      <arg name="height" type="int" summary="rectangle height"/>
+    </request>
+  </interface>
+
+  <interface name="wl_subcompositor" version="1">
+    <description summary="sub-surface compositing">
+      The global interface exposing sub-surface compositing capabilities.
+      A wl_surface, that has sub-surfaces associated, is called the
+      parent surface. Sub-surfaces can be arbitrarily nested and create
+      a tree of sub-surfaces.
+
+      The root surface in a tree of sub-surfaces is the main
+      surface. The main surface cannot be a sub-surface, because
+      sub-surfaces must always have a parent.
+
+      A main surface with its sub-surfaces forms a (compound) window.
+      For window management purposes, this set of wl_surface objects is
+      to be considered as a single window, and it should also behave as
+      such.
+
+      The aim of sub-surfaces is to offload some of the compositing work
+      within a window from clients to the compositor. A prime example is
+      a video player with decorations and video in separate wl_surface
+      objects. This should allow the compositor to pass YUV video buffer
+      processing to dedicated overlay hardware when possible.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the subcompositor interface">
+	Informs the server that the client will not be using this
+	protocol object anymore. This does not affect any other
+	objects, wl_subsurface objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_surface" value="0"
+	     summary="the to-be sub-surface is invalid"/>
+      <entry name="bad_parent" value="1"
+	     summary="the to-be sub-surface parent is invalid"/>
+    </enum>
+
+    <request name="get_subsurface">
+      <description summary="give a surface the role sub-surface">
+	Create a sub-surface interface for the given surface, and
+	associate it with the given parent surface. This turns a
+	plain wl_surface into a sub-surface.
+
+	The to-be sub-surface must not already have another role, and it
+	must not have an existing wl_subsurface object. Otherwise the
+	bad_surface protocol error is raised.
+
+	Adding sub-surfaces to a parent is a double-buffered operation on the
+	parent (see wl_surface.commit). The effect of adding a sub-surface
+	becomes visible on the next time the state of the parent surface is
+	applied.
+
+	The parent surface must not be one of the child surface's descendants,
+	and the parent must be different from the child surface, otherwise the
+	bad_parent protocol error is raised.
+
+	This request modifies the behaviour of wl_surface.commit request on
+	the sub-surface, see the documentation on wl_subsurface interface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_subsurface"
+	   summary="the new sub-surface object ID"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the surface to be turned into a sub-surface"/>
+      <arg name="parent" type="object" interface="wl_surface"
+	   summary="the parent surface"/>
+    </request>
+  </interface>
+
+  <interface name="wl_subsurface" version="1">
+    <description summary="sub-surface interface to a wl_surface">
+      An additional interface to a wl_surface object, which has been
+      made a sub-surface. A sub-surface has one parent surface. A
+      sub-surface's size and position are not limited to that of the parent.
+      Particularly, a sub-surface is not automatically clipped to its
+      parent's area.
+
+      A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+      and the parent surface is mapped. The order of which one happens
+      first is irrelevant. A sub-surface is hidden if the parent becomes
+      hidden, or if a NULL wl_buffer is applied. These rules apply
+      recursively through the tree of surfaces.
+
+      The behaviour of a wl_surface.commit request on a sub-surface
+      depends on the sub-surface's mode. The possible modes are
+      synchronized and desynchronized, see methods
+      wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
+      mode caches the wl_surface state to be applied when the parent's
+      state gets applied, and desynchronized mode applies the pending
+      wl_surface state directly. A sub-surface is initially in the
+      synchronized mode.
+
+      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
+      the parent and its sub-surfaces (wl_subsurface.place_above and
+      .place_below). This state is applied when the parent surface's
+      wl_surface state is applied, regardless of the sub-surface's mode.
+      As the exception, set_sync and set_desync are effective immediately.
+
+      The main surface can be thought to be always in desynchronized mode,
+      since it does not have a parent in the sub-surfaces sense.
+
+      Even if a sub-surface is in desynchronized mode, it will behave as
+      in synchronized mode, if its parent surface behaves as in
+      synchronized mode. This rule is applied recursively throughout the
+      tree of surfaces. This means, that one can set a sub-surface into
+      synchronized mode, and then assume that all its child and grand-child
+      sub-surfaces are synchronized, too, without explicitly setting them.
+
+      Destroying a sub-surface takes effect immediately. If you need to
+      synchronize the removal of a sub-surface to the parent surface update,
+      unmap the sub-surface first by attaching a NULL wl_buffer, update parent,
+      and then destroy the sub-surface.
+
+      If the parent wl_surface object is destroyed, the sub-surface is
+      unmapped.
+
+      A sub-surface never has the keyboard focus of any seat.
+
+      The wl_surface.offset request is ignored: clients must use set_position
+      instead to move the sub-surface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove sub-surface interface">
+	The sub-surface interface is removed from the wl_surface object
+	that was turned into a sub-surface with a
+	wl_subcompositor.get_subsurface request. The wl_surface's association
+	to the parent is deleted. The wl_surface is unmapped immediately.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_surface" value="0"
+	     summary="wl_surface is not a sibling or the parent"/>
+    </enum>
+
+    <request name="set_position">
+      <description summary="reposition the sub-surface">
+	This schedules a sub-surface position change.
+	The sub-surface will be moved so that its origin (top left
+	corner pixel) will be at the location x, y of the parent surface
+	coordinate system. The coordinates are not restricted to the parent
+	surface area. Negative values are allowed.
+
+	The scheduled coordinates will take effect whenever the state of the
+	parent surface is applied.
+
+	If more than one set_position request is invoked by the client before
+	the commit of the parent surface, the position of a new request always
+	replaces the scheduled position from any previous request.
+
+	The initial position is 0, 0.
+      </description>
+      <arg name="x" type="int" summary="x coordinate in the parent surface"/>
+      <arg name="y" type="int" summary="y coordinate in the parent surface"/>
+    </request>
+
+    <request name="place_above">
+      <description summary="restack the sub-surface">
+	This sub-surface is taken from the stack, and put back just
+	above the reference surface, changing the z-order of the sub-surfaces.
+	The reference surface must be one of the sibling surfaces, or the
+	parent surface. Using any other surface, including this sub-surface,
+	will cause a protocol error.
+
+	The z-order is double-buffered. Requests are handled in order and
+	applied immediately to a pending state. The final pending state is
+	copied to the active state the next time the state of the parent
+	surface is applied.
+
+	A new sub-surface is initially added as the top-most in the stack
+	of its siblings and parent.
+      </description>
+      <arg name="sibling" type="object" interface="wl_surface"
+	   summary="the reference surface"/>
+    </request>
+
+    <request name="place_below">
+      <description summary="restack the sub-surface">
+	The sub-surface is placed just below the reference surface.
+	See wl_subsurface.place_above.
+      </description>
+      <arg name="sibling" type="object" interface="wl_surface"
+	   summary="the reference surface"/>
+    </request>
+
+    <request name="set_sync">
+      <description summary="set sub-surface to synchronized mode">
+	Change the commit behaviour of the sub-surface to synchronized
+	mode, also described as the parent dependent mode.
+
+	In synchronized mode, wl_surface.commit on a sub-surface will
+	accumulate the committed state in a cache, but the state will
+	not be applied and hence will not change the compositor output.
+	The cached state is applied to the sub-surface immediately after
+	the parent surface's state is applied. This ensures atomic
+	updates of the parent and all its synchronized sub-surfaces.
+	Applying the cached state will invalidate the cache, so further
+	parent surface commits do not (re-)apply old state.
+
+	See wl_subsurface for the recursive effect of this mode.
+      </description>
+    </request>
+
+    <request name="set_desync">
+      <description summary="set sub-surface to desynchronized mode">
+	Change the commit behaviour of the sub-surface to desynchronized
+	mode, also described as independent or freely running mode.
+
+	In desynchronized mode, wl_surface.commit on a sub-surface will
+	apply the pending state directly, without caching, as happens
+	normally with a wl_surface. Calling wl_surface.commit on the
+	parent surface has no effect on the sub-surface's wl_surface
+	state. This mode allows a sub-surface to be updated on its own.
+
+	If cached state exists when wl_surface.commit is called in
+	desynchronized mode, the pending state is added to the cached
+	state, and applied as a whole. This invalidates the cache.
+
+	Note: even if a sub-surface is set to desynchronized, a parent
+	sub-surface may override it to behave as synchronized. For details,
+	see wl_subsurface.
+
+	If a surface's parent surface behaves as desynchronized, then
+	the cached state is applied on set_desync.
+      </description>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland/release.sh b/subprojects/wayland/release.sh
new file mode 100755
index 0000000000000000000000000000000000000000..8e843f56c31ac40011ae1e21747d5c951a6a48ff
--- /dev/null
+++ b/subprojects/wayland/release.sh
@@ -0,0 +1,79 @@
+#!/bin/sh -eu
+
+build_dir=build-release
+
+if ! type glab >/dev/null; then
+	echo "glab is needed to create a release"
+	exit 1
+fi
+
+case "$(git rev-parse --abbrev-ref HEAD)" in
+main | [0-9]*.[0-9]*)
+	;;
+*)
+	echo "Not on the main or a stable branch"
+	exit 1
+esac
+
+if [ -n "$(git log @{upstream}..)" ]; then
+	echo "The main branch has unpushed commits"
+	exit 1
+fi
+
+meson_options=""
+if [ -e "$build_dir" ]; then
+	meson_options="$meson_options --wipe"
+fi
+meson setup "$build_dir" $meson_options
+
+prev_version="$(git describe --tags --abbrev=0)"
+version="$(meson introspect "$build_dir" --projectinfo | jq -r .version)"
+if [ "$version" = "$prev_version" ]; then
+	echo "Version not bumped"
+	exit 1
+fi
+
+name="$(meson introspect "$build_dir" --projectinfo | jq -r .descriptive_name)"
+if [ "$name" = "" ]; then
+	echo "Cannot determine project name"
+	exit 1
+fi
+
+ninja -C "$build_dir" dist
+
+archive_name="$name-$version.tar.xz"
+archive_path="$build_dir/meson-dist/$archive_name"
+gpg --detach-sig "$archive_path"
+
+sha256="$(cd $build_dir/meson-dist && sha256sum $archive_name)"
+sha512="$(cd $build_dir/meson-dist && sha512sum $archive_name)"
+archive_url="https://gitlab.freedesktop.org/wayland/$name/-/releases/$version/downloads/$archive_name"
+announce_path="$build_dir/meson-dist/$name-$version-announce.eml"
+current_branch=$(git branch --show-current)
+remote_name=$(git config --get branch.${current_branch}.remote)
+
+cat >"$announce_path" <<EOF
+To: <wayland-devel@lists.freedesktop.org>
+Subject: [ANNOUNCE] $name $version
+
+`git shortlog --no-merges "$prev_version.."`
+
+git tag: $version
+
+$archive_url
+SHA256: $sha256
+SHA512: $sha512
+PGP:    $archive_url.sig
+EOF
+
+echo "Release announcement written to $announce_path"
+
+echo -n "Release $name $version? [y/N] "
+read answer
+if [ "$answer" != "y" ]; then
+	exit 1
+fi
+
+git tag -s -m "$version" "$version"
+git push "$remote_name" "$version"
+glab release create "$version" "$archive_path"* --notes ""
diff --git a/subprojects/wayland/releasing.txt b/subprojects/wayland/releasing.txt
new file mode 100644
index 0000000000000000000000000000000000000000..e93f53dda79b2684afd4a588c95885fc61f8b14f
--- /dev/null
+++ b/subprojects/wayland/releasing.txt
@@ -0,0 +1,62 @@
+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.
+
+      $ ninja -C build/ test
+
+  1.  Update the first stanza of meson.build 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 meson.build -m "build: 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.
+
+  3.  Compose the release announcements.  The script will generate a
+      wayland-x.y.z-announce.eml file 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 meson.build version should always be (at least)
+x.y.90, with x.y being the most recent stable branch.  The stable
+branch's meson.build 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/subprojects/wayland/src/.gitignore b/subprojects/wayland/src/.gitignore
new file mode 100644
index 0000000000000000000000000000000000000000..128e4f7ce7294b1ab21061580a5962b78594bafa
--- /dev/null
+++ b/subprojects/wayland/src/.gitignore
@@ -0,0 +1,2 @@
+*.dtd.embed
+/wayland-version.h
diff --git a/subprojects/wayland/src/connection.c b/subprojects/wayland/src/connection.c
new file mode 100644
index 0000000000000000000000000000000000000000..8870fd2da88b4af35966aabb083e2ed06ea2ccda
--- /dev/null
+++ b/subprojects/wayland/src/connection.c
@@ -0,0 +1,1610 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ * 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.
+ */
+
+#define _GNU_SOURCE
+
+#include <assert.h>
+#include <math.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <ffi.h>
+
+#include "wayland-util.h"
+#include "wayland-private.h"
+#include "wayland-os.h"
+
+static inline uint32_t
+div_roundup(uint32_t n, size_t a)
+{
+	/* The cast to uint64_t is necessary to prevent overflow when rounding
+	 * values close to UINT32_MAX. After the division it is again safe to
+	 * cast back to uint32_t.
+	 */
+	return (uint32_t) (((uint64_t) n + (a - 1)) / a);
+}
+
+struct wl_ring_buffer {
+	char *data;
+	size_t head, tail;
+	uint32_t size_bits;
+	uint32_t max_size_bits;  /* 0 for unlimited */
+};
+
+#define MAX_FDS_OUT	28
+#define CLEN		(CMSG_LEN(MAX_FDS_OUT * sizeof(int32_t)))
+
+struct wl_connection {
+	struct wl_ring_buffer in, out;
+	struct wl_ring_buffer fds_in, fds_out;
+	int fd;
+	int want_flush;
+};
+
+static inline size_t
+size_pot(uint32_t size_bits)
+{
+	assert(size_bits < 8 * sizeof(size_t));
+
+	return ((size_t)1) << size_bits;
+}
+
+static size_t
+ring_buffer_capacity(const struct wl_ring_buffer *b) {
+	return size_pot(b->size_bits);
+}
+
+static size_t
+ring_buffer_mask(const struct wl_ring_buffer *b, size_t i) {
+	size_t m = ring_buffer_capacity(b) - 1;
+	return i & m;
+}
+
+static int
+ring_buffer_put(struct wl_ring_buffer *b, const void *data, size_t count)
+{
+	size_t head, size;
+
+	if (count == 0)
+		return 0;
+
+	head = ring_buffer_mask(b, b->head);
+	if (head + count <= ring_buffer_capacity(b)) {
+		memcpy(b->data + head, data, count);
+	} else {
+		size = ring_buffer_capacity(b) - head;
+		memcpy(b->data + head, data, size);
+		memcpy(b->data, (const char *) data + size, count - size);
+	}
+
+	b->head += count;
+
+	return 0;
+}
+
+static void
+ring_buffer_put_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
+{
+	size_t head, tail;
+
+	head = ring_buffer_mask(b, b->head);
+	tail = ring_buffer_mask(b, b->tail);
+	if (head < tail) {
+		iov[0].iov_base = b->data + head;
+		iov[0].iov_len = tail - head;
+		*count = 1;
+	} else if (tail == 0) {
+		iov[0].iov_base = b->data + head;
+		iov[0].iov_len = ring_buffer_capacity(b) - head;
+		*count = 1;
+	} else {
+		iov[0].iov_base = b->data + head;
+		iov[0].iov_len = ring_buffer_capacity(b) - head;
+		iov[1].iov_base = b->data;
+		iov[1].iov_len = tail;
+		*count = 2;
+	}
+}
+
+static void
+ring_buffer_get_iov(struct wl_ring_buffer *b, struct iovec *iov, int *count)
+{
+	size_t head, tail;
+
+	head = ring_buffer_mask(b, b->head);
+	tail = ring_buffer_mask(b, b->tail);
+	if (tail < head) {
+		iov[0].iov_base = b->data + tail;
+		iov[0].iov_len = head - tail;
+		*count = 1;
+	} else if (head == 0) {
+		iov[0].iov_base = b->data + tail;
+		iov[0].iov_len = ring_buffer_capacity(b) - tail;
+		*count = 1;
+	} else {
+		iov[0].iov_base = b->data + tail;
+		iov[0].iov_len = ring_buffer_capacity(b) - tail;
+		iov[1].iov_base = b->data;
+		iov[1].iov_len = head;
+		*count = 2;
+	}
+}
+
+static void
+ring_buffer_copy(struct wl_ring_buffer *b, void *data, size_t count)
+{
+	size_t tail, size;
+
+	if (count == 0)
+		return;
+
+	tail = ring_buffer_mask(b, b->tail);
+	if (tail + count <= ring_buffer_capacity(b)) {
+		memcpy(data, b->data + tail, count);
+	} else {
+		size = ring_buffer_capacity(b) - tail;
+		memcpy(data, b->data + tail, size);
+		memcpy((char *) data + size, b->data, count - size);
+	}
+}
+
+static size_t
+ring_buffer_size(struct wl_ring_buffer *b)
+{
+	return b->head - b->tail;
+}
+
+static char *
+ring_buffer_tail(const struct wl_ring_buffer *b)
+{
+	return b->data + ring_buffer_mask(b, b->tail);
+}
+
+static uint32_t
+get_max_size_bits_for_size(size_t buffer_size)
+{
+	uint32_t max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
+
+	/* buffer_size == 0 means unbound buffer size */
+	if (buffer_size == 0)
+		return 0;
+
+	while (max_size_bits < 8 * sizeof(size_t) && size_pot(max_size_bits) < buffer_size)
+		max_size_bits++;
+
+	return max_size_bits;
+}
+
+static int
+ring_buffer_allocate(struct wl_ring_buffer *b, size_t size_bits)
+{
+	char *new_data;
+
+	new_data = calloc(size_pot(size_bits), 1);
+	if (!new_data)
+		return -1;
+
+	ring_buffer_copy(b, new_data, ring_buffer_size(b));
+	free(b->data);
+	b->data = new_data;
+	b->size_bits = size_bits;
+	b->head = ring_buffer_size(b);
+	b->tail = 0;
+
+	return 0;
+}
+
+static size_t
+ring_buffer_get_bits_for_size(struct wl_ring_buffer *b, size_t net_size)
+{
+	size_t max_size_bits = get_max_size_bits_for_size(net_size);
+
+	if (max_size_bits < WL_BUFFER_DEFAULT_SIZE_POT)
+		max_size_bits = WL_BUFFER_DEFAULT_SIZE_POT;
+
+	if (b->max_size_bits > 0 && max_size_bits > b->max_size_bits)
+		max_size_bits = b->max_size_bits;
+
+	return max_size_bits;
+}
+
+static bool
+ring_buffer_is_max_size_reached(struct wl_ring_buffer *b)
+{
+	size_t net_size = ring_buffer_size(b) + 1;
+	size_t size_bits = ring_buffer_get_bits_for_size(b, net_size);
+
+	return net_size >= size_pot(size_bits);
+}
+
+static int
+ring_buffer_ensure_space(struct wl_ring_buffer *b, size_t count)
+{
+	size_t net_size = ring_buffer_size(b) + count;
+	size_t size_bits = ring_buffer_get_bits_for_size(b, net_size);
+
+	/* The 'size_bits' value represents the required size (in POT) to store
+	 * 'net_size', which depending whether the buffers are bounded or not
+	 * might not be sufficient (i.e. we might have reached the maximum size
+	 * allowed).
+	 */
+	if (net_size > size_pot(size_bits)) {
+		wl_log("Data too big for buffer (%d + %zd > %zd).\n",
+		       ring_buffer_size(b), count, size_pot(size_bits));
+		errno = E2BIG;
+		return -1;
+	}
+
+	/* The following test here is a short-cut to avoid reallocating a buffer
+	 * of the same size.
+	 */
+	if (size_bits == b->size_bits)
+		return 0;
+
+	/* Otherwise, we (re)allocate the buffer to match the required size */
+	return ring_buffer_allocate(b, size_bits);
+}
+
+static void
+ring_buffer_close_fds(struct wl_ring_buffer *buffer, int32_t count)
+{
+	int32_t i, *p;
+	size_t size, tail;
+
+	size = ring_buffer_capacity(buffer);
+	tail = ring_buffer_mask(buffer, buffer->tail);
+	p = (int32_t *) (buffer->data + tail);
+
+	for (i = 0; i < count; i++) {
+		if (p >= (int32_t *) (buffer->data + size))
+			p = (int32_t *) buffer->data;
+		close(*p++);
+	}
+}
+
+void
+wl_connection_set_max_buffer_size(struct wl_connection *connection,
+				  size_t max_buffer_size)
+{
+	uint32_t max_size_bits;
+
+	max_size_bits = get_max_size_bits_for_size(max_buffer_size);
+
+	connection->fds_in.max_size_bits = max_size_bits;
+	ring_buffer_ensure_space(&connection->fds_in, 0);
+
+	connection->fds_out.max_size_bits = max_size_bits;
+	ring_buffer_ensure_space(&connection->fds_out, 0);
+
+	connection->in.max_size_bits = max_size_bits;
+	ring_buffer_ensure_space(&connection->in, 0);
+
+	connection->out.max_size_bits = max_size_bits;
+	ring_buffer_ensure_space(&connection->out, 0);
+}
+
+struct wl_connection *
+wl_connection_create(int fd, size_t max_buffer_size)
+{
+	struct wl_connection *connection;
+
+	connection = zalloc(sizeof *connection);
+	if (connection == NULL)
+		return NULL;
+
+	wl_connection_set_max_buffer_size(connection, max_buffer_size);
+
+	connection->fd = fd;
+
+	return connection;
+}
+
+static void
+close_fds(struct wl_ring_buffer *buffer, int max)
+{
+	size_t size;
+	int32_t count;
+
+	size = ring_buffer_size(buffer);
+	if (size == 0)
+		return;
+
+	count = size / sizeof(int32_t);
+	if (max > 0 && max < count)
+		count = max;
+
+	ring_buffer_close_fds(buffer, count);
+
+	size = count * sizeof(int32_t);
+	buffer->tail += size;
+}
+
+void
+wl_connection_close_fds_in(struct wl_connection *connection, int max)
+{
+	close_fds(&connection->fds_in, max);
+}
+
+int
+wl_connection_destroy(struct wl_connection *connection)
+{
+	int fd = connection->fd;
+
+	close_fds(&connection->fds_out, -1);
+	free(connection->fds_out.data);
+	free(connection->out.data);
+
+	close_fds(&connection->fds_in, -1);
+	free(connection->fds_in.data);
+	free(connection->in.data);
+
+	free(connection);
+
+	return fd;
+}
+
+void
+wl_connection_copy(struct wl_connection *connection, void *data, size_t size)
+{
+	ring_buffer_copy(&connection->in, data, size);
+}
+
+void
+wl_connection_consume(struct wl_connection *connection, size_t size)
+{
+	connection->in.tail += size;
+}
+
+static void
+build_cmsg(struct wl_ring_buffer *buffer, char *data, size_t *clen)
+{
+	struct cmsghdr *cmsg;
+	size_t size;
+
+	size = ring_buffer_size(buffer);
+	if (size > MAX_FDS_OUT * sizeof(int32_t))
+		size = MAX_FDS_OUT * sizeof(int32_t);
+
+	if (size > 0) {
+		cmsg = (struct cmsghdr *) data;
+		cmsg->cmsg_level = SOL_SOCKET;
+		cmsg->cmsg_type = SCM_RIGHTS;
+		cmsg->cmsg_len = CMSG_LEN(size);
+		ring_buffer_copy(buffer, CMSG_DATA(cmsg), size);
+		*clen = cmsg->cmsg_len;
+	} else {
+		*clen = 0;
+	}
+}
+
+static int
+decode_cmsg(struct wl_ring_buffer *buffer, struct msghdr *msg)
+{
+	struct cmsghdr *cmsg;
+	size_t size, i;
+	int overflow = 0;
+
+	for (cmsg = CMSG_FIRSTHDR(msg); cmsg != NULL;
+	     cmsg = CMSG_NXTHDR(msg, cmsg)) {
+		if (cmsg->cmsg_level != SOL_SOCKET ||
+		    cmsg->cmsg_type != SCM_RIGHTS)
+			continue;
+
+		size = cmsg->cmsg_len - CMSG_LEN(0);
+
+		if (ring_buffer_ensure_space(buffer, size) < 0 || overflow) {
+			overflow = 1;
+			size /= sizeof(int32_t);
+			for (i = 0; i < size; i++)
+				close(((int*)CMSG_DATA(cmsg))[i]);
+		} else if (ring_buffer_put(buffer, CMSG_DATA(cmsg), size) < 0) {
+				return -1;
+		}
+	}
+
+	if (overflow) {
+		errno = EOVERFLOW;
+		return -1;
+	}
+
+	return 0;
+}
+
+int
+wl_connection_flush(struct wl_connection *connection)
+{
+	struct iovec iov[2];
+	struct msghdr msg = {0};
+	char cmsg[CLEN];
+	int len = 0, count;
+	size_t clen;
+	size_t tail;
+
+	if (!connection->want_flush)
+		return 0;
+
+	tail = connection->out.tail;
+	while (ring_buffer_size(&connection->out) > 0) {
+		build_cmsg(&connection->fds_out, cmsg, &clen);
+
+		if (clen >= CLEN) {
+			/* UNIX domain sockets allows to send file descriptors
+			 * using ancillary data.
+			 *
+			 * As per the UNIX domain sockets man page (man 7 unix),
+			 * "at least one byte of real data should be sent when
+			 * sending ancillary data".
+			 *
+			 * This is why we send only a single byte here, to ensure
+			 * all file descriptors are sent before the bytes are
+			 * cleared out.
+			 *
+			 * Otherwise This can fail to clear the file descriptors
+			 * first if individual messages are allowed to have 224
+			 * (8 bytes * MAX_FDS_OUT = 224) file descriptors .
+			 */
+			iov[0].iov_base = ring_buffer_tail(&connection->out);
+			iov[0].iov_len = 1;
+			count = 1;
+		} else {
+			ring_buffer_get_iov(&connection->out, iov, &count);
+		}
+
+		msg.msg_name = NULL;
+		msg.msg_namelen = 0;
+		msg.msg_iov = iov;
+		msg.msg_iovlen = count;
+		msg.msg_control = (clen > 0) ? cmsg : NULL;
+		msg.msg_controllen = clen;
+
+		do {
+			len = sendmsg(connection->fd, &msg,
+				      MSG_NOSIGNAL | MSG_DONTWAIT);
+		} while (len == -1 && errno == EINTR);
+
+		if (len == -1)
+			return -1;
+
+		close_fds(&connection->fds_out, MAX_FDS_OUT);
+
+		connection->out.tail += len;
+	}
+
+	connection->want_flush = 0;
+
+	return connection->out.head - tail;
+}
+
+uint32_t
+wl_connection_pending_input(struct wl_connection *connection)
+{
+	return ring_buffer_size(&connection->in);
+}
+
+int
+wl_connection_read(struct wl_connection *connection)
+{
+	struct iovec iov[2];
+	struct msghdr msg;
+	char cmsg[CLEN];
+	int len, count, ret;
+
+	while (1) {
+		int data_size = ring_buffer_size(&connection->in);
+
+		/* Stop once we've read the max buffer size. */
+		if (ring_buffer_is_max_size_reached(&connection->in))
+			return data_size;
+
+		if (ring_buffer_ensure_space(&connection->in, 1) < 0)
+			return -1;
+
+		ring_buffer_put_iov(&connection->in, iov, &count);
+
+		msg.msg_name = NULL;
+		msg.msg_namelen = 0;
+		msg.msg_iov = iov;
+		msg.msg_iovlen = count;
+		msg.msg_control = cmsg;
+		msg.msg_controllen = sizeof cmsg;
+		msg.msg_flags = 0;
+
+		do {
+			len = wl_os_recvmsg_cloexec(connection->fd, &msg, MSG_DONTWAIT);
+		} while (len < 0 && errno == EINTR);
+
+		if (len == 0) {
+		    /* EOF, return previously read data first */
+		    return data_size;
+		}
+		if (len < 0) {
+		    if (errno == EAGAIN && data_size > 0) {
+			/* nothing new read, return previously read data */
+			return data_size;
+		    }
+		    return len;
+		}
+
+		ret = decode_cmsg(&connection->fds_in, &msg);
+		if (ret)
+			return -1;
+
+		connection->in.head += len;
+	}
+}
+
+int
+wl_connection_write(struct wl_connection *connection,
+		    const void *data, size_t count)
+{
+	if (wl_connection_queue(connection, data, count) < 0)
+		return -1;
+
+	connection->want_flush = 1;
+
+	return 0;
+}
+
+int
+wl_connection_queue(struct wl_connection *connection,
+		    const void *data, size_t count)
+{
+	/* We want to try to flush when the buffer reaches the default maximum
+	 * size even if the buffer has been previously expanded.
+	 *
+	 * Otherwise the larger buffer will cause us to flush less frequently,
+	 * which could increase lag.
+	 *
+	 * We'd like to flush often and get the buffer size back down if possible.
+	 */
+	if (ring_buffer_size(&connection->out) + count > WL_BUFFER_DEFAULT_MAX_SIZE) {
+		connection->want_flush = 1;
+		if (wl_connection_flush(connection) < 0 && errno != EAGAIN)
+			return -1;
+	}
+
+	if (ring_buffer_ensure_space(&connection->out, count) < 0)
+		return -1;
+
+	return ring_buffer_put(&connection->out, data, count);
+}
+
+int
+wl_message_count_arrays(const struct wl_message *message)
+{
+	int i, arrays;
+
+	for (i = 0, arrays = 0; message->signature[i]; i++) {
+		if (message->signature[i] == WL_ARG_ARRAY)
+			arrays++;
+	}
+
+	return arrays;
+}
+
+int
+wl_connection_get_fd(struct wl_connection *connection)
+{
+	return connection->fd;
+}
+
+static int
+wl_connection_put_fd(struct wl_connection *connection, int32_t fd)
+{
+	if (ring_buffer_size(&connection->fds_out) >= MAX_FDS_OUT * sizeof fd) {
+		connection->want_flush = 1;
+		if (wl_connection_flush(connection) < 0 && errno != EAGAIN)
+			return -1;
+	}
+
+	if (ring_buffer_ensure_space(&connection->fds_out, sizeof fd) < 0)
+		return -1;
+
+	return ring_buffer_put(&connection->fds_out, &fd, sizeof fd);
+}
+
+const char *
+get_next_argument(const char *signature, struct argument_details *details)
+{
+	details->nullable = 0;
+	for(; *signature; ++signature) {
+		switch(*signature) {
+		case WL_ARG_INT:
+		case WL_ARG_UINT:
+		case WL_ARG_FIXED:
+		case WL_ARG_STRING:
+		case WL_ARG_OBJECT:
+		case WL_ARG_NEW_ID:
+		case WL_ARG_ARRAY:
+		case WL_ARG_FD:
+			details->type = *signature;
+			return signature + 1;
+		case '?':
+			details->nullable = 1;
+		}
+	}
+	details->type = '\0';
+	return signature;
+}
+
+int
+arg_count_for_signature(const char *signature)
+{
+	int count = 0;
+	for(; *signature; ++signature) {
+		switch(*signature) {
+		case WL_ARG_INT:
+		case WL_ARG_UINT:
+		case WL_ARG_FIXED:
+		case WL_ARG_STRING:
+		case WL_ARG_OBJECT:
+		case WL_ARG_NEW_ID:
+		case WL_ARG_ARRAY:
+		case WL_ARG_FD:
+			++count;
+		}
+	}
+	return count;
+}
+
+int
+wl_message_get_since(const struct wl_message *message)
+{
+	int since;
+
+	since = atoi(message->signature);
+
+	if (since == 0)
+		since = 1;
+
+	return since;
+}
+
+void
+wl_argument_from_va_list(const char *signature, union wl_argument *args,
+			 int count, va_list ap)
+{
+	int i;
+	const char *sig_iter;
+	struct argument_details arg;
+
+	sig_iter = signature;
+	for (i = 0; i < count; i++) {
+		sig_iter = get_next_argument(sig_iter, &arg);
+
+		switch(arg.type) {
+		case WL_ARG_INT:
+			args[i].i = va_arg(ap, int32_t);
+			break;
+		case WL_ARG_UINT:
+			args[i].u = va_arg(ap, uint32_t);
+			break;
+		case WL_ARG_FIXED:
+			args[i].f = va_arg(ap, wl_fixed_t);
+			break;
+		case WL_ARG_STRING:
+			args[i].s = va_arg(ap, const char *);
+			break;
+		case WL_ARG_OBJECT:
+			args[i].o = va_arg(ap, struct wl_object *);
+			break;
+		case WL_ARG_NEW_ID:
+			args[i].o = va_arg(ap, struct wl_object *);
+			break;
+		case WL_ARG_ARRAY:
+			args[i].a = va_arg(ap, struct wl_array *);
+			break;
+		case WL_ARG_FD:
+			args[i].h = va_arg(ap, int32_t);
+			break;
+		}
+	}
+}
+
+static void
+wl_closure_clear_fds(struct wl_closure *closure)
+{
+	const char *signature = closure->message->signature;
+	struct argument_details arg;
+	int i;
+
+	for (i = 0; i < closure->count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (arg.type == WL_ARG_FD)
+			closure->args[i].h = -1;
+	}
+}
+
+static struct wl_closure *
+wl_closure_init(const struct wl_message *message, uint32_t size,
+                int *num_arrays, union wl_argument *args)
+{
+	struct wl_closure *closure;
+	int count;
+
+	count = arg_count_for_signature(message->signature);
+	if (count > WL_CLOSURE_MAX_ARGS) {
+		wl_log("too many args (%d) for %s (signature %s)\n", count,
+		       message->name, message->signature);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	int size_to_allocate;
+
+	if (size) {
+		*num_arrays = wl_message_count_arrays(message);
+		size_to_allocate = sizeof *closure + size +
+				   *num_arrays * sizeof(struct wl_array);
+	} else {
+		size_to_allocate = sizeof *closure;
+	}
+	closure = zalloc(size_to_allocate);
+
+	if (!closure) {
+		wl_log("could not allocate closure of size (%d) for "
+		       "%s (signature %s)\n", size_to_allocate, message->name,
+		       message->signature);
+		errno = ENOMEM;
+		return NULL;
+	}
+
+	if (args)
+		memcpy(closure->args, args, count * sizeof *args);
+
+	closure->message = message;
+	closure->count = count;
+
+	/* Set these all to -1 so we can close any that have been
+	 * set to a real value during wl_closure_destroy().
+	 * We may have copied a bunch of fds into the closure with
+	 * memcpy previously, but those are undup()d client fds
+	 * that we would have replaced anyway.
+	 */
+	wl_closure_clear_fds(closure);
+
+	return closure;
+}
+
+struct wl_closure *
+wl_closure_marshal(struct wl_object *sender, uint32_t opcode,
+		   union wl_argument *args,
+		   const struct wl_message *message)
+{
+	struct wl_closure *closure;
+	struct wl_object *object;
+	int i, count, fd, dup_fd;
+	const char *signature;
+	struct argument_details arg;
+
+	closure = wl_closure_init(message, 0, NULL, args);
+	if (closure == NULL)
+		return NULL;
+
+	count = closure->count;
+
+	signature = message->signature;
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+
+		switch (arg.type) {
+		case WL_ARG_FIXED:
+		case WL_ARG_UINT:
+		case WL_ARG_INT:
+			break;
+		case WL_ARG_STRING:
+			if (!arg.nullable && args[i].s == NULL)
+				goto err_null;
+			break;
+		case WL_ARG_OBJECT:
+			if (!arg.nullable && args[i].o == NULL)
+				goto err_null;
+			break;
+		case WL_ARG_NEW_ID:
+			object = args[i].o;
+			if (object == NULL)
+				goto err_null;
+
+			closure->args[i].n = object ? object->id : 0;
+			break;
+		case WL_ARG_ARRAY:
+			if (args[i].a == NULL)
+				goto err_null;
+			break;
+		case WL_ARG_FD:
+			fd = args[i].h;
+			dup_fd = wl_os_dupfd_cloexec(fd, 0);
+			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:
+			wl_abort("unhandled format code: '%c'\n", arg.type);
+			break;
+		}
+	}
+
+	closure->sender_id = sender->id;
+	closure->opcode = opcode;
+
+	return closure;
+
+err_null:
+	wl_closure_destroy(closure);
+	wl_log("error marshalling arguments for %s (signature %s): "
+	       "null value passed for arg %i\n", message->name,
+	       message->signature, i);
+	errno = EINVAL;
+	return NULL;
+}
+
+struct wl_closure *
+wl_closure_vmarshal(struct wl_object *sender, uint32_t opcode, va_list ap,
+		    const struct wl_message *message)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+
+	wl_argument_from_va_list(message->signature, args,
+				 WL_CLOSURE_MAX_ARGS, ap);
+
+	return wl_closure_marshal(sender, opcode, args, message);
+}
+
+struct wl_closure *
+wl_connection_demarshal(struct wl_connection *connection,
+			uint32_t size,
+			struct wl_map *objects,
+			const struct wl_message *message)
+{
+	uint32_t *p, *next, *end, length, length_in_u32, id;
+	int fd;
+	char *s;
+	int i, count, num_arrays;
+	const char *signature;
+	struct argument_details arg;
+	struct wl_closure *closure;
+	struct wl_array *array_extra;
+
+	/* Space for sender_id and opcode */
+	if (size < 2 * sizeof *p) {
+		wl_log("message too short, invalid header\n");
+		wl_connection_consume(connection, size);
+		errno = EINVAL;
+		return NULL;
+	}
+
+	closure = wl_closure_init(message, size, &num_arrays, NULL);
+	if (closure == NULL) {
+		wl_connection_consume(connection, size);
+		return NULL;
+	}
+
+	count = closure->count;
+
+	array_extra = closure->extra;
+	p = (uint32_t *)(closure->extra + num_arrays);
+	end = p + size / sizeof *p;
+
+	wl_connection_copy(connection, p, size);
+	closure->sender_id = *p++;
+	closure->opcode = *p++ & 0x0000ffff;
+
+	signature = message->signature;
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+
+		if (arg.type != WL_ARG_FD && p + 1 > end) {
+			wl_log("message too short, "
+			       "object (%d), message %s(%s)\n",
+			       closure->sender_id, message->name,
+			       message->signature);
+			errno = EINVAL;
+			goto err;
+		}
+
+		switch (arg.type) {
+		case WL_ARG_UINT:
+			closure->args[i].u = *p++;
+			break;
+		case WL_ARG_INT:
+			closure->args[i].i = *p++;
+			break;
+		case WL_ARG_FIXED:
+			closure->args[i].f = *p++;
+			break;
+		case WL_ARG_STRING:
+			length = *p++;
+
+			if (length == 0 && !arg.nullable) {
+				wl_log("NULL string received on non-nullable "
+				       "type, message %s(%s)\n", message->name,
+				       message->signature);
+				errno = EINVAL;
+				goto err;
+			}
+			if (length == 0) {
+				closure->args[i].s = NULL;
+				break;
+			}
+
+			length_in_u32 = div_roundup(length, sizeof *p);
+			if ((uint32_t) (end - p) < length_in_u32) {
+				wl_log("message too short, "
+				       "object (%d), message %s(%s)\n",
+				       closure->sender_id, message->name,
+				       message->signature);
+				errno = EINVAL;
+				goto err;
+			}
+			next = p + length_in_u32;
+
+			s = (char *) p;
+
+			if (length > 0 && s[length - 1] != '\0') {
+				wl_log("string not nul-terminated, "
+				       "message %s(%s)\n",
+				       message->name, message->signature);
+				errno = EINVAL;
+				goto err;
+			}
+
+			closure->args[i].s = s;
+			p = next;
+			break;
+		case WL_ARG_OBJECT:
+			id = *p++;
+			closure->args[i].n = id;
+
+			if (id == 0 && !arg.nullable) {
+				wl_log("NULL object received on non-nullable "
+				       "type, message %s(%s)\n", message->name,
+				       message->signature);
+				errno = EINVAL;
+				goto err;
+			}
+			break;
+		case WL_ARG_NEW_ID:
+			id = *p++;
+			closure->args[i].n = id;
+
+			if (id == 0) {
+				wl_log("NULL new ID received on non-nullable "
+				       "type, message %s(%s)\n", message->name,
+				       message->signature);
+				errno = EINVAL;
+				goto err;
+			}
+
+			if (wl_map_reserve_new(objects, id) < 0) {
+				if (errno == EINVAL) {
+					wl_log("not a valid new object id (%u), "
+					       "message %s(%s)\n", id,
+					       message->name,
+					       message->signature);
+				}
+				goto err;
+			}
+
+			break;
+		case WL_ARG_ARRAY:
+			length = *p++;
+
+			length_in_u32 = div_roundup(length, sizeof *p);
+			if ((uint32_t) (end - p) < length_in_u32) {
+				wl_log("message too short, "
+				       "object (%d), message %s(%s)\n",
+				       closure->sender_id, message->name,
+				       message->signature);
+				errno = EINVAL;
+				goto err;
+			}
+			next = p + length_in_u32;
+
+			array_extra->size = length;
+			array_extra->alloc = 0;
+			array_extra->data = p;
+
+			closure->args[i].a = array_extra++;
+			p = next;
+			break;
+		case WL_ARG_FD:
+			if (connection->fds_in.tail == connection->fds_in.head) {
+				wl_log("file descriptor expected, "
+				       "object (%d), message %s(%s)\n",
+				       closure->sender_id, message->name,
+				       message->signature);
+				errno = EINVAL;
+				goto err;
+			}
+
+			ring_buffer_copy(&connection->fds_in, &fd, sizeof fd);
+			connection->fds_in.tail += sizeof fd;
+			closure->args[i].h = fd;
+			break;
+		default:
+			wl_abort("unknown type\n");
+			break;
+		}
+	}
+
+	wl_connection_consume(connection, size);
+
+	return closure;
+
+ err:
+	wl_closure_destroy(closure);
+	wl_connection_consume(connection, size);
+
+	return NULL;
+}
+
+bool
+wl_object_is_zombie(struct wl_map *map, uint32_t id)
+{
+	uint32_t flags;
+
+	/* Zombie objects only exist on the client side. */
+	if (map->side == WL_MAP_SERVER_SIDE)
+		return false;
+
+	/* Zombie objects can only have been created by the client. */
+	if (id >= WL_SERVER_ID_START)
+		return false;
+
+	flags = wl_map_lookup_flags(map, id);
+	return !!(flags & WL_MAP_ENTRY_ZOMBIE);
+}
+
+int
+wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects)
+{
+	struct wl_object *object;
+	const struct wl_message *message;
+	const char *signature;
+	struct argument_details arg;
+	int i, count;
+	uint32_t id;
+
+	message = closure->message;
+	signature = message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (arg.type != WL_ARG_OBJECT)
+			continue;
+
+		id = closure->args[i].n;
+		closure->args[i].o = NULL;
+
+		object = wl_map_lookup(objects, id);
+		if (wl_object_is_zombie(objects, id)) {
+			/* references object we've already
+			 * destroyed client side */
+			object = NULL;
+		} else if (object == NULL && id != 0) {
+			wl_log("unknown object (%u), message %s(%s)\n",
+			       id, message->name, message->signature);
+			errno = EINVAL;
+			return -1;
+		}
+
+		if (object != NULL && message->types[i] != NULL &&
+		    !wl_interface_equal((object)->interface,
+					message->types[i])) {
+			wl_log("invalid object (%u), type (%s), "
+			       "message %s(%s)\n",
+			       id, (object)->interface->name,
+			       message->name, message->signature);
+			errno = EINVAL;
+			return -1;
+		}
+		closure->args[i].o = object;
+	}
+
+	return 0;
+}
+
+static void
+convert_arguments_to_ffi(const char *signature, uint32_t flags,
+			 union wl_argument *args,
+			 int count, ffi_type **ffi_types, void** ffi_args)
+{
+	int i;
+	const char *sig_iter;
+	struct argument_details arg;
+
+	sig_iter = signature;
+	for (i = 0; i < count; i++) {
+		sig_iter = get_next_argument(sig_iter, &arg);
+
+		switch(arg.type) {
+		case WL_ARG_INT:
+			ffi_types[i] = &ffi_type_sint32;
+			ffi_args[i] = &args[i].i;
+			break;
+		case WL_ARG_UINT:
+			ffi_types[i] = &ffi_type_uint32;
+			ffi_args[i] = &args[i].u;
+			break;
+		case WL_ARG_FIXED:
+			ffi_types[i] = &ffi_type_sint32;
+			ffi_args[i] = &args[i].f;
+			break;
+		case WL_ARG_STRING:
+			ffi_types[i] = &ffi_type_pointer;
+			ffi_args[i] = &args[i].s;
+			break;
+		case WL_ARG_OBJECT:
+			ffi_types[i] = &ffi_type_pointer;
+			ffi_args[i] = &args[i].o;
+			break;
+		case WL_ARG_NEW_ID:
+			if (flags & WL_CLOSURE_INVOKE_CLIENT) {
+				ffi_types[i] = &ffi_type_pointer;
+				ffi_args[i] = &args[i].o;
+			} else {
+				ffi_types[i] = &ffi_type_uint32;
+				ffi_args[i] = &args[i].n;
+			}
+			break;
+		case WL_ARG_ARRAY:
+			ffi_types[i] = &ffi_type_pointer;
+			ffi_args[i] = &args[i].a;
+			break;
+		case WL_ARG_FD:
+			ffi_types[i] = &ffi_type_sint32;
+			ffi_args[i] = &args[i].h;
+			break;
+		default:
+			wl_abort("unknown type\n");
+			break;
+		}
+	}
+}
+
+void
+wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
+		  struct wl_object *target, uint32_t opcode, void *data)
+{
+	int count;
+	ffi_cif cif;
+	ffi_type *ffi_types[WL_CLOSURE_MAX_ARGS + 2];
+	void * ffi_args[WL_CLOSURE_MAX_ARGS + 2];
+	void (* const *implementation)(void);
+
+	count = arg_count_for_signature(closure->message->signature);
+
+	ffi_types[0] = &ffi_type_pointer;
+	ffi_args[0] = &data;
+	ffi_types[1] = &ffi_type_pointer;
+	ffi_args[1] = &target;
+
+	convert_arguments_to_ffi(closure->message->signature, flags, closure->args,
+				 count, ffi_types + 2, ffi_args + 2);
+
+	ffi_prep_cif(&cif, FFI_DEFAULT_ABI,
+		     count + 2, &ffi_type_void, ffi_types);
+
+	implementation = target->implementation;
+	if (!implementation[opcode]) {
+		wl_abort("listener function for opcode %u of %s is NULL\n",
+			 opcode, target->interface->name);
+	}
+	ffi_call(&cif, implementation[opcode], NULL, ffi_args);
+
+	wl_closure_clear_fds(closure);
+}
+
+void
+wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher,
+		    struct wl_object *target, uint32_t opcode)
+{
+	dispatcher(target->implementation, target, opcode, closure->message,
+		   closure->args);
+
+	wl_closure_clear_fds(closure);
+}
+
+static int
+copy_fds_to_connection(struct wl_closure *closure,
+		       struct wl_connection *connection)
+{
+	const struct wl_message *message = closure->message;
+	uint32_t i, count;
+	struct argument_details arg;
+	const char *signature = message->signature;
+	int fd;
+
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (arg.type != WL_ARG_FD)
+			continue;
+
+		fd = closure->args[i].h;
+		if (wl_connection_put_fd(connection, fd)) {
+			wl_log("request could not be marshaled: "
+			       "can't send file descriptor\n");
+			return -1;
+		}
+		closure->args[i].h = -1;
+	}
+
+	return 0;
+}
+
+
+static uint32_t
+buffer_size_for_closure(struct wl_closure *closure)
+{
+	const struct wl_message *message = closure->message;
+	int i, count;
+	struct argument_details arg;
+	const char *signature;
+	uint32_t size, buffer_size = 0;
+
+	signature = message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+
+		switch (arg.type) {
+		case WL_ARG_FD:
+			break;
+		case WL_ARG_UINT:
+		case WL_ARG_INT:
+		case WL_ARG_FIXED:
+		case WL_ARG_OBJECT:
+		case WL_ARG_NEW_ID:
+			buffer_size++;
+			break;
+		case WL_ARG_STRING:
+			if (closure->args[i].s == NULL) {
+				buffer_size++;
+				break;
+			}
+
+			size = strlen(closure->args[i].s) + 1;
+			buffer_size += 1 + div_roundup(size, sizeof(uint32_t));
+			break;
+		case WL_ARG_ARRAY:
+			if (closure->args[i].a == NULL) {
+				buffer_size++;
+				break;
+			}
+
+			size = closure->args[i].a->size;
+			buffer_size += (1 + div_roundup(size, sizeof(uint32_t)));
+			break;
+		default:
+			break;
+		}
+	}
+
+	return buffer_size + 2;
+}
+
+static int
+serialize_closure(struct wl_closure *closure, uint32_t *buffer,
+		  size_t buffer_count)
+{
+	const struct wl_message *message = closure->message;
+	unsigned int i, count, size;
+	uint32_t *p, *end;
+	struct argument_details arg;
+	const char *signature;
+
+	if (buffer_count < 2)
+		goto overflow;
+
+	p = buffer + 2;
+	end = buffer + buffer_count;
+
+	signature = message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+
+		if (arg.type == WL_ARG_FD)
+			continue;
+
+		if (p + 1 > end)
+			goto overflow;
+
+		switch (arg.type) {
+		case WL_ARG_UINT:
+			*p++ = closure->args[i].u;
+			break;
+		case WL_ARG_INT:
+			*p++ = closure->args[i].i;
+			break;
+		case WL_ARG_FIXED:
+			*p++ = closure->args[i].f;
+			break;
+		case WL_ARG_OBJECT:
+			*p++ = closure->args[i].o ? closure->args[i].o->id : 0;
+			break;
+		case WL_ARG_NEW_ID:
+			*p++ = closure->args[i].n;
+			break;
+		case WL_ARG_STRING:
+			if (closure->args[i].s == NULL) {
+				*p++ = 0;
+				break;
+			}
+
+			size = strlen(closure->args[i].s) + 1;
+			*p++ = size;
+
+			if (p + div_roundup(size, sizeof *p) > end)
+				goto overflow;
+
+			memcpy(p, closure->args[i].s, size);
+			p += div_roundup(size, sizeof *p);
+			break;
+		case WL_ARG_ARRAY:
+			if (closure->args[i].a == NULL) {
+				*p++ = 0;
+				break;
+			}
+
+			size = closure->args[i].a->size;
+			*p++ = size;
+
+			if (p + div_roundup(size, sizeof *p) > end)
+				goto overflow;
+
+			if (size != 0)
+				memcpy(p, closure->args[i].a->data, size);
+			p += div_roundup(size, sizeof *p);
+			break;
+		case WL_ARG_FD:
+			break;
+		}
+	}
+
+	size = (p - buffer) * sizeof *p;
+
+	buffer[0] = closure->sender_id;
+	buffer[1] = size << 16 | (closure->opcode & 0x0000ffff);
+
+	return size;
+
+overflow:
+	wl_log("serialize_closure overflow for %s (signature %s)\n",
+	       message->name, message->signature);
+	errno = ERANGE;
+	return -1;
+}
+
+int
+wl_closure_send(struct wl_closure *closure, struct wl_connection *connection)
+{
+	int size;
+	uint32_t buffer_size;
+	uint32_t *buffer;
+	int result;
+
+	if (copy_fds_to_connection(closure, connection))
+		return -1;
+
+	buffer_size = buffer_size_for_closure(closure);
+	buffer = zalloc(buffer_size * sizeof buffer[0]);
+	if (buffer == NULL) {
+		wl_log("wl_closure_send error: buffer allocation failure of "
+		       "size %d\n for %s (signature %s)",
+		       buffer_size * sizeof buffer[0], closure->message->name,
+		       closure->message->signature);
+		return -1;
+	}
+
+	size = serialize_closure(closure, buffer, buffer_size);
+	if (size < 0) {
+		free(buffer);
+		return -1;
+	}
+
+	result = wl_connection_write(connection, buffer, size);
+	free(buffer);
+
+	return result;
+}
+
+int
+wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection)
+{
+	int size;
+	uint32_t buffer_size;
+	uint32_t *buffer;
+	int result;
+
+	if (copy_fds_to_connection(closure, connection))
+		return -1;
+
+	buffer_size = buffer_size_for_closure(closure);
+	buffer = malloc(buffer_size * sizeof buffer[0]);
+	if (buffer == NULL) {
+		wl_log("wl_closure_queue error: buffer allocation failure of "
+		       "size %d\n for %s (signature %s)",
+		       buffer_size * sizeof buffer[0], closure->message->name,
+		       closure->message->signature);
+		return -1;
+	}
+
+	size = serialize_closure(closure, buffer, buffer_size);
+	if (size < 0) {
+		free(buffer);
+		return -1;
+	}
+
+	result = wl_connection_queue(connection, buffer, size);
+	free(buffer);
+
+	return result;
+}
+
+void
+wl_closure_print(struct wl_closure *closure, struct wl_object *target,
+		 int send, int discarded, uint32_t (*n_parse)(union wl_argument *arg),
+		 const char *queue_name)
+{
+	int i;
+	struct argument_details arg;
+	const char *signature = closure->message->signature;
+	struct timespec tp;
+	unsigned int time;
+	uint32_t nval;
+	FILE *f;
+	char *buffer;
+	size_t buffer_length;
+
+	f = open_memstream(&buffer, &buffer_length);
+	if (f == NULL)
+		return;
+
+	clock_gettime(CLOCK_REALTIME, &tp);
+	time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+	fprintf(f, "[%7u.%03u] ", time / 1000, time % 1000);
+
+	if (queue_name)
+		fprintf(f, "{%s} ", queue_name);
+
+	fprintf(f, "%s%s%s#%u.%s(",
+		discarded ? "discarded " : "",
+		send ? " -> " : "",
+		target->interface->name, target->id,
+		closure->message->name);
+
+	for (i = 0; i < closure->count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (i > 0)
+			fprintf(f, ", ");
+
+		switch (arg.type) {
+		case WL_ARG_UINT:
+			fprintf(f, "%u", closure->args[i].u);
+			break;
+		case WL_ARG_INT:
+			fprintf(f, "%d", closure->args[i].i);
+			break;
+		case WL_ARG_FIXED:
+			/* The magic number 390625 is 1e8 / 256 */
+			if (closure->args[i].f >= 0) {
+				fprintf(f, "%d.%08d",
+					closure->args[i].f / 256,
+					390625 * (closure->args[i].f % 256));
+			} else {
+
+				fprintf(f, "-%d.%08d",
+					closure->args[i].f / -256,
+					-390625 * (closure->args[i].f % 256));
+			}
+			break;
+		case WL_ARG_STRING:
+			if (closure->args[i].s)
+				fprintf(f, "\"%s\"", closure->args[i].s);
+			else
+				fprintf(f, "nil");
+			break;
+		case WL_ARG_OBJECT:
+			if (closure->args[i].o)
+				fprintf(f, "%s#%u",
+					closure->args[i].o->interface->name,
+					closure->args[i].o->id);
+			else
+				fprintf(f, "nil");
+			break;
+		case WL_ARG_NEW_ID:
+			if (n_parse)
+				nval = n_parse(&closure->args[i]);
+			else
+				nval = closure->args[i].n;
+
+			fprintf(f, "new id %s#",
+				(closure->message->types[i]) ?
+				 closure->message->types[i]->name :
+				  "[unknown]");
+			if (nval != 0)
+				fprintf(f, "%u", nval);
+			else
+				fprintf(f, "nil");
+			break;
+		case WL_ARG_ARRAY:
+			fprintf(f, "array[%zu]", closure->args[i].a->size);
+			break;
+		case WL_ARG_FD:
+			fprintf(f, "fd %d", closure->args[i].h);
+			break;
+		}
+	}
+
+	fprintf(f, ")\n");
+
+	if (fclose(f) == 0) {
+		fprintf(stderr, "%s", buffer);
+		free(buffer);
+	}
+}
+
+static int
+wl_closure_close_fds(struct wl_closure *closure)
+{
+	int i;
+	struct argument_details arg;
+	const char *signature = closure->message->signature;
+
+	for (i = 0; i < closure->count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (arg.type == WL_ARG_FD && closure->args[i].h != -1)
+			close(closure->args[i].h);
+	}
+
+	return 0;
+}
+
+void
+wl_closure_destroy(struct wl_closure *closure)
+{
+	/* wl_closure_destroy has free() semantics */
+	if (!closure)
+		return;
+
+	wl_closure_close_fds(closure);
+	free(closure);
+}
diff --git a/subprojects/wayland/src/embed.py b/subprojects/wayland/src/embed.py
new file mode 100644
index 0000000000000000000000000000000000000000..abebb157fce94b6766c803b6990f7352380ac79c
--- /dev/null
+++ b/subprojects/wayland/src/embed.py
@@ -0,0 +1,45 @@
+#!/usr/bin/env python3
+
+"""
+Simple C data embedder
+
+License: MIT
+
+Copyright (c) 2020 Simon Ser
+
+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 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.
+"""
+
+import sys
+
+if len(sys.argv) != 3:
+    print('usage: ' + sys.argv[0] + ' <filename> <ident>', file=sys.stderr)
+    sys.exit(1)
+
+filename = sys.argv[1]
+ident = sys.argv[2]
+
+with open(filename, 'rb') as f:
+    buf = f.read()
+
+print('static const char ' + ident + '[] = {\n\t', end='')
+for i in range(len(buf)):
+    ch = buf[i:i+1]
+    print('0x' + ch.hex() + ', ', end='')
+print('\n};')
diff --git a/subprojects/wayland/src/event-loop.c b/subprojects/wayland/src/event-loop.c
new file mode 100644
index 0000000000000000000000000000000000000000..45222f71d0e97918102e2e4f5de18c2eee4c150b
--- /dev/null
+++ b/subprojects/wayland/src/event-loop.c
@@ -0,0 +1,1168 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <sys/epoll.h>
+#include <sys/signalfd.h>
+#include <sys/timerfd.h>
+#include <unistd.h>
+#include "wayland-util.h"
+#include "wayland-private.h"
+#include "wayland-server-core.h"
+#include "wayland-server-private.h"
+#include "wayland-os.h"
+
+/** \cond INTERNAL */
+
+#define TIMER_REMOVED -2
+
+struct wl_event_loop;
+struct wl_event_source_interface;
+struct wl_event_source_timer;
+
+struct wl_event_source {
+	struct wl_event_source_interface *interface;
+	struct wl_event_loop *loop;
+	struct wl_list link;
+	void *data;
+	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_priv_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;
+	int fd;
+};
+
+/** \endcond */
+
+static int
+wl_event_source_fd_dispatch(struct wl_event_source *source,
+			    struct epoll_event *ep)
+{
+	struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
+	uint32_t mask;
+
+	mask = 0;
+	if (ep->events & EPOLLIN)
+		mask |= WL_EVENT_READABLE;
+	if (ep->events & EPOLLOUT)
+		mask |= WL_EVENT_WRITABLE;
+	if (ep->events & EPOLLHUP)
+		mask |= WL_EVENT_HANGUP;
+	if (ep->events & EPOLLERR)
+		mask |= WL_EVENT_ERROR;
+
+	return fd_source->func(fd_source->fd, mask, source->data);
+}
+
+struct wl_event_source_interface fd_source_interface = {
+	wl_event_source_fd_dispatch,
+};
+
+static struct wl_event_source *
+add_source(struct wl_event_loop *loop,
+	   struct wl_event_source *source, uint32_t mask, void *data)
+{
+	struct epoll_event ep;
+
+	if (source->fd < 0) {
+		free(source);
+		return NULL;
+	}
+
+	source->loop = loop;
+	source->data = data;
+	wl_list_init(&source->link);
+
+	memset(&ep, 0, sizeof ep);
+	if (mask & WL_EVENT_READABLE)
+		ep.events |= EPOLLIN;
+	if (mask & WL_EVENT_WRITABLE)
+		ep.events |= EPOLLOUT;
+	ep.data.ptr = source;
+
+	if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
+		close(source->fd);
+		free(source);
+		return NULL;
+	}
+
+	return source;
+}
+
+/** Create a file descriptor event source
+ *
+ * \param loop The event loop that will process the new source.
+ * \param fd The file descriptor to watch.
+ * \param mask A bitwise-or of which events to watch for: \c WL_EVENT_READABLE,
+ * \c WL_EVENT_WRITABLE.
+ * \param func The file descriptor dispatch function.
+ * \param data User data.
+ * \return A new file descriptor event source.
+ *
+ * The given file descriptor is initially watched for the events given in
+ * \c mask. This can be changed as needed with wl_event_source_fd_update().
+ *
+ * If it is possible that program execution causes the file descriptor to be
+ * read while leaving the data in a buffer without actually processing it,
+ * it may be necessary to register the file descriptor source to be re-checked,
+ * see wl_event_source_check(). This will ensure that the dispatch function
+ * gets called even if the file descriptor is not readable or writable
+ * anymore. This is especially useful with IPC libraries that automatically
+ * buffer incoming data, possibly as a side-effect of other operations.
+ *
+ * \sa wl_event_loop_fd_func_t
+ * \memberof wl_event_source
+ */
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_fd(struct wl_event_loop *loop,
+		     int fd, uint32_t mask,
+		     wl_event_loop_fd_func_t func,
+		     void *data)
+{
+	struct wl_event_source_fd *source;
+
+	source = zalloc(sizeof *source);
+	if (source == NULL)
+		return NULL;
+
+	source->base.interface = &fd_source_interface;
+	source->base.fd = wl_os_dupfd_cloexec(fd, 0);
+	source->func = func;
+	source->fd = fd;
+
+	return add_source(loop, &source->base, mask, data);
+}
+
+/** Update a file descriptor source's event mask
+ *
+ * \param source The file descriptor event source to update.
+ * \param mask The new mask, a bitwise-or of: \c WL_EVENT_READABLE,
+ * \c WL_EVENT_WRITABLE.
+ * \return 0 on success, -1 on failure.
+ *
+ * This changes which events, readable and/or writable, cause the dispatch
+ * callback to be called on.
+ *
+ * File descriptors are usually writable to begin with, so they do not need to
+ * be polled for writable until a write actually fails. When a write fails,
+ * the event mask can be changed to poll for readable and writable, delivering
+ * a dispatch callback when it is possible to write more. Once all data has
+ * been written, the mask can be changed to poll only for readable to avoid
+ * busy-looping on dispatch.
+ *
+ * \sa wl_event_loop_add_fd()
+ * \memberof wl_event_source
+ */
+WL_EXPORT int
+wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
+{
+	struct wl_event_loop *loop = source->loop;
+	struct epoll_event ep;
+
+	memset(&ep, 0, sizeof ep);
+	if (mask & WL_EVENT_READABLE)
+		ep.events |= EPOLLIN;
+	if (mask & WL_EVENT_WRITABLE)
+		ep.events |= EPOLLOUT;
+	ep.data.ptr = source;
+
+	return epoll_ctl(loop->epoll_fd, EPOLL_CTL_MOD, source->fd, &ep);
+}
+
+/** \cond INTERNAL */
+
+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;
+};
+
+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\n");
+			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\n");
+			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;
+
+	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.
+ * \param func The timer dispatch function.
+ * \param data User data.
+ * \return A new timer event source.
+ *
+ * The timer is initially disarmed. It needs to be armed with a call to
+ * wl_event_source_timer_update() before it can trigger a dispatch call.
+ *
+ * \sa wl_event_loop_timer_func_t
+ * \memberof wl_event_source
+ */
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_timer(struct wl_event_loop *loop,
+			wl_event_loop_timer_func_t func,
+			void *data)
+{
+	struct wl_event_source_timer *source;
+
+	if (wl_timer_heap_ensure_timerfd(&loop->timers) < 0)
+		return NULL;
+
+	source = zalloc(sizeof *source);
+	if (source == NULL)
+		return NULL;
+
+	source->base.interface = &timer_source_interface;
+	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;
+
+	if (wl_timer_heap_reserve(&loop->timers) < 0) {
+		free(source);
+		return NULL;
+	}
+
+	return &source->base;
+}
+
+/** Arm or disarm a timer
+ *
+ * \param source The timer event source to modify.
+ * \param ms_delay The timeout in milliseconds.
+ * \return 0 on success, -1 on failure.
+ *
+ * If the timeout is zero, the timer is disarmed.
+ *
+ * If the timeout is non-zero, the timer is set to expire after the given
+ * timeout in milliseconds. When the timer expires, the dispatch function
+ * set with wl_event_loop_add_timer() is called once from
+ * wl_event_loop_dispatch(). If another dispatch is desired after another
+ * expiry, wl_event_source_timer_update() needs to be called again.
+ *
+ * \memberof wl_event_source
+ */
+WL_EXPORT int
+wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
+{
+	struct wl_event_source_timer *tsource =
+		wl_container_of(source, tsource, base);
+	struct wl_timer_heap *timers = &tsource->base.loop->timers;
+
+	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;
+}
+
+/** \cond INTERNAL */
+
+struct wl_event_source_signal {
+	struct wl_event_source base;
+	int signal_number;
+	wl_event_loop_signal_func_t func;
+};
+
+/** \endcond */
+
+static int
+wl_event_source_signal_dispatch(struct wl_event_source *source,
+				struct epoll_event *ep)
+{
+	struct wl_event_source_signal *signal_source =
+		(struct wl_event_source_signal *) source;
+	struct signalfd_siginfo signal_info;
+	int len;
+
+	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: %s\n", strerror(errno));
+
+	return signal_source->func(signal_source->signal_number,
+				   signal_source->base.data);
+}
+
+struct wl_event_source_interface signal_source_interface = {
+	wl_event_source_signal_dispatch,
+};
+
+/** Create a POSIX signal event source
+ *
+ * \param loop The event loop that will process the new source.
+ * \param signal_number Number of the signal to watch for.
+ * \param func The signal dispatch function.
+ * \param data User data.
+ * \return A new signal event source.
+ *
+ * This function blocks the normal delivery of the given signal in the calling
+ * thread, and creates a "watch" for it. Signal delivery no longer happens
+ * asynchronously, but by wl_event_loop_dispatch() calling the dispatch
+ * callback function \c func.
+ *
+ * It is the caller's responsibility to ensure that all other threads have
+ * also blocked the signal.
+ *
+ * \sa wl_event_loop_signal_func_t
+ * \memberof wl_event_source
+ */
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_signal(struct wl_event_loop *loop,
+			 int signal_number,
+			 wl_event_loop_signal_func_t func,
+			 void *data)
+{
+	struct wl_event_source_signal *source;
+	sigset_t mask;
+
+	source = zalloc(sizeof *source);
+	if (source == NULL)
+		return NULL;
+
+	source->base.interface = &signal_source_interface;
+	source->signal_number = signal_number;
+
+	sigemptyset(&mask);
+	sigaddset(&mask, signal_number);
+	source->base.fd = signalfd(-1, &mask, SFD_CLOEXEC | SFD_NONBLOCK);
+	sigprocmask(SIG_BLOCK, &mask, NULL);
+
+	source->func = func;
+
+	return add_source(loop, &source->base, WL_EVENT_READABLE, data);
+}
+
+/** \cond INTERNAL */
+
+struct wl_event_source_idle {
+	struct wl_event_source base;
+	wl_event_loop_idle_func_t func;
+};
+
+/** \endcond */
+
+struct wl_event_source_interface idle_source_interface = {
+	NULL,
+};
+
+/** Create an idle task
+ *
+ * \param loop The event loop that will process the new task.
+ * \param func The idle task dispatch function.
+ * \param data User data.
+ * \return A new idle task (an event source).
+ *
+ * Idle tasks are dispatched before wl_event_loop_dispatch() goes to sleep.
+ * See wl_event_loop_dispatch() for more details.
+ *
+ * Idle tasks fire once, and are automatically destroyed right after the
+ * callback function has been called.
+ *
+ * An idle task can be cancelled before the callback has been called by
+ * wl_event_source_remove(). Calling wl_event_source_remove() after or from
+ * within the callback results in undefined behaviour.
+ *
+ * \sa wl_event_loop_idle_func_t
+ * \memberof wl_event_source
+ */
+WL_EXPORT struct wl_event_source *
+wl_event_loop_add_idle(struct wl_event_loop *loop,
+		       wl_event_loop_idle_func_t func,
+		       void *data)
+{
+	struct wl_event_source_idle *source;
+
+	source = zalloc(sizeof *source);
+	if (source == NULL)
+		return NULL;
+
+	source->base.interface = &idle_source_interface;
+	source->base.loop = loop;
+	source->base.fd = -1;
+
+	source->func = func;
+	source->base.data = data;
+
+	wl_list_insert(loop->idle_list.prev, &source->base.link);
+
+	return &source->base;
+}
+
+/** Mark event source to be re-checked
+ *
+ * \param source The event source to be re-checked.
+ *
+ * This function permanently marks the event source to be re-checked after
+ * the normal dispatch of sources in wl_event_loop_dispatch(). Re-checking
+ * will keep iterating over all such event sources until the dispatch
+ * function for them all returns zero.
+ *
+ * Re-checking is used on sources that may become ready to dispatch as a
+ * side-effect of dispatching themselves or other event sources, including idle
+ * sources. Re-checking ensures all the incoming events have been fully drained
+ * before wl_event_loop_dispatch() returns.
+ *
+ * \memberof wl_event_source
+ */
+WL_EXPORT void
+wl_event_source_check(struct wl_event_source *source)
+{
+	wl_list_insert(source->loop->check_list.prev, &source->link);
+}
+
+/** Remove an event source from its event loop
+ *
+ * \param source The event source to be removed.
+ * \return Zero.
+ *
+ * The event source is removed from the event loop it was created for,
+ * and is effectively destroyed. This invalidates \c source .
+ * The dispatch function of the source will no longer be called through this
+ * source.
+ *
+ * \memberof wl_event_source
+ */
+WL_EXPORT int
+wl_event_source_remove(struct wl_event_source *source)
+{
+	struct wl_event_loop *loop = source->loop;
+
+	/* We need to explicitly remove the fd, since closing the fd
+	 * isn't enough in case we've dup'ed the fd. */
+	if (source->fd >= 0) {
+		epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, source->fd, NULL);
+		close(source->fd);
+		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);
+
+	return 0;
+}
+
+static void
+wl_event_loop_process_destroy_list(struct wl_event_loop *loop)
+{
+	struct wl_event_source *source, *next;
+
+	wl_list_for_each_safe(source, next, &loop->destroy_list, link)
+		free(source);
+
+	wl_list_init(&loop->destroy_list);
+}
+
+/** Create a new event loop context
+ *
+ * \return A new event loop context object.
+ *
+ * This creates a new event loop context. Initially this context is empty.
+ * Event sources need to be explicitly added to it.
+ *
+ * Normally the event loop is run by calling wl_event_loop_dispatch() in
+ * a loop until the program terminates. Alternatively, an event loop can be
+ * embedded in another event loop by its file descriptor, see
+ * wl_event_loop_get_fd().
+ *
+ * \memberof wl_event_loop
+ */
+WL_EXPORT struct wl_event_loop *
+wl_event_loop_create(void)
+{
+	struct wl_event_loop *loop;
+
+	loop = zalloc(sizeof *loop);
+	if (loop == NULL)
+		return NULL;
+
+	loop->epoll_fd = wl_os_epoll_create_cloexec();
+	if (loop->epoll_fd < 0) {
+		free(loop);
+		return NULL;
+	}
+	wl_list_init(&loop->check_list);
+	wl_list_init(&loop->idle_list);
+	wl_list_init(&loop->destroy_list);
+
+	wl_priv_signal_init(&loop->destroy_signal);
+
+	wl_timer_heap_init(&loop->timers, loop);
+
+	return loop;
+}
+
+/** Destroy an event loop context
+ *
+ * \param loop The event loop to be destroyed.
+ *
+ * This emits the event loop destroy signal, closes the event loop file
+ * descriptor, and frees \c loop.
+ *
+ * If the event loop has existing sources, those cannot be safely removed
+ * afterwards. Therefore one must call wl_event_source_remove() on all
+ * event sources before destroying the event loop context.
+ *
+ * \memberof wl_event_loop
+ */
+WL_EXPORT void
+wl_event_loop_destroy(struct wl_event_loop *loop)
+{
+	wl_priv_signal_final_emit(&loop->destroy_signal, loop);
+
+	wl_event_loop_process_destroy_list(loop);
+	wl_timer_heap_release(&loop->timers);
+	close(loop->epoll_fd);
+	free(loop);
+}
+
+static bool
+post_dispatch_check(struct wl_event_loop *loop)
+{
+	struct epoll_event ep;
+	struct wl_event_source *source, *next;
+	bool needs_recheck = false;
+
+	ep.events = 0;
+	wl_list_for_each_safe(source, next, &loop->check_list, link) {
+		int dispatch_result;
+
+		dispatch_result = source->interface->dispatch(source, &ep);
+		if (dispatch_result < 0) {
+			wl_log("Source dispatch function returned negative value!\n");
+			wl_log("This would previously accidentally suppress a follow-up dispatch\n");
+		}
+		needs_recheck |= dispatch_result != 0;
+	}
+
+	return needs_recheck;
+}
+
+/** Dispatch the idle sources
+ *
+ * \param loop The event loop whose idle sources are dispatched.
+ *
+ * \sa wl_event_loop_add_idle()
+ * \memberof wl_event_loop
+ */
+WL_EXPORT void
+wl_event_loop_dispatch_idle(struct wl_event_loop *loop)
+{
+	struct wl_event_source_idle *source;
+
+	while (!wl_list_empty(&loop->idle_list)) {
+		source = wl_container_of(loop->idle_list.next,
+					 source, base.link);
+		source->func(source->base.data);
+		wl_event_source_remove(&source->base);
+	}
+}
+
+static int
+timespec_to_ms(struct timespec value)
+{
+	return (value.tv_sec * 1000) + (value.tv_nsec / 1000000);
+}
+
+static struct timespec
+ms_to_timespec(int ms)
+{
+	struct timespec val;
+	val.tv_sec = ms / 1000;
+	val.tv_nsec = (ms % 1000) * 1000000;
+	return val;
+}
+
+static struct timespec
+timespec_normalize(struct timespec value)
+{
+	struct timespec result = value;
+
+	while (result.tv_nsec >= 1000000000) {
+		result.tv_nsec -= 1000000000;
+		result.tv_sec++;
+	}
+
+	while (result.tv_nsec < 0) {
+		result.tv_nsec += 1000000000;
+		result.tv_sec--;
+	}
+
+	return result;
+}
+
+static struct timespec
+timespec_add(struct timespec a, struct timespec b)
+{
+	struct timespec result;
+	result.tv_sec = a.tv_sec + b.tv_sec;
+	result.tv_nsec = a.tv_nsec + b.tv_nsec;
+	return timespec_normalize(result);
+}
+
+static struct timespec
+timespec_sub(struct timespec a, struct timespec b)
+{
+	struct timespec result;
+	result.tv_sec = a.tv_sec - b.tv_sec;
+	result.tv_nsec = a.tv_nsec - b.tv_nsec;
+	return timespec_normalize(result);
+}
+
+/** Wait for events and dispatch them
+ *
+ * \param loop The event loop whose sources to wait for.
+ * \param timeout The polling timeout in milliseconds.
+ * \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
+ * expires. A timeout of -1 disables the timeout, causing the function to block
+ * indefinitely. A timeout of zero causes the poll to always return immediately.
+ *
+ * All idle sources are dispatched before blocking. An idle source is destroyed
+ * when it is dispatched. After blocking, all other ready sources are
+ * dispatched. Then, idle sources are dispatched again, in case the dispatched
+ * events created idle sources. Finally, all sources marked with
+ * wl_event_source_check() are dispatched in a loop until their dispatch
+ * functions all return zero.
+ *
+ * \memberof wl_event_loop
+ */
+WL_EXPORT int
+wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout)
+{
+	struct epoll_event ep[32];
+	struct wl_event_source *source;
+	int i, count;
+	bool has_timers = false;
+	bool use_timeout = timeout > 0;
+	struct timespec now, end;
+
+	wl_event_loop_dispatch_idle(loop);
+
+	if (use_timeout) {
+		clock_gettime(CLOCK_MONOTONIC, &now);
+		end = timespec_add(now, ms_to_timespec(timeout));
+	}
+
+	while (true) {
+		count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
+		if (count >= 0)
+			break; /* have events or timeout */
+		else if (count < 0 && errno != EINTR && errno != EAGAIN)
+			break; /* have error */
+
+		if (use_timeout) {
+			clock_gettime(CLOCK_MONOTONIC, &now);
+			timeout = timespec_to_ms(timespec_sub(end, now));
+			if (timeout <= 0) {
+				/* too late */
+				count = 0;
+				break;
+			}
+		}
+	}
+
+	if (count < 0)
+		return -1;
+
+	for (i = 0; i < count; i++) {
+		source = ep[i].data.ptr;
+		if (source == &loop->timers.base) {
+			has_timers = true;
+			break;
+		}
+	}
+
+	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]);
+	}
+
+	wl_event_loop_process_destroy_list(loop);
+
+	wl_event_loop_dispatch_idle(loop);
+
+	while (post_dispatch_check(loop));
+
+	return 0;
+}
+
+/** Get the event loop file descriptor
+ *
+ * \param loop The event loop context.
+ * \return The aggregate file descriptor.
+ *
+ * This function returns the aggregate file descriptor, that represents all
+ * the event sources (idle sources excluded) associated with the given event
+ * loop context. When any event source makes an event available, it will be
+ * reflected in the aggregate file descriptor.
+ *
+ * When the aggregate file descriptor delivers an event, one can call
+ * wl_event_loop_dispatch() on the event loop context to dispatch all the
+ * available events.
+ *
+ * \memberof wl_event_loop
+ */
+WL_EXPORT int
+wl_event_loop_get_fd(struct wl_event_loop *loop)
+{
+	return loop->epoll_fd;
+}
+
+/** Register a destroy listener for an event loop context
+ *
+ * \param loop The event loop context whose destruction to listen for.
+ * \param listener The listener with the callback to be called.
+ *
+ * \sa wl_listener
+ * \memberof wl_event_loop
+ */
+WL_EXPORT void
+wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
+				   struct wl_listener *listener)
+{
+	wl_priv_signal_add(&loop->destroy_signal, listener);
+}
+
+/** Get the listener struct for the specified callback
+ *
+ * \param loop The event loop context to inspect.
+ * \param notify The destroy callback to find.
+ * \return The wl_listener registered to the event loop context with
+ * the given callback pointer.
+ *
+ * \memberof wl_event_loop
+ */
+WL_EXPORT struct wl_listener *
+wl_event_loop_get_destroy_listener(struct wl_event_loop *loop,
+				   wl_notify_func_t notify)
+{
+	return wl_priv_signal_get(&loop->destroy_signal, notify);
+}
diff --git a/subprojects/wayland/src/meson.build b/subprojects/wayland/src/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..5d04334e6b95fb3c8d5f241f5e5c392add44d54a
--- /dev/null
+++ b/subprojects/wayland/src/meson.build
@@ -0,0 +1,280 @@
+if not (get_option('scanner') or get_option('libraries'))
+	error('Either -Dscanner=true or -Dlibraries=true is required')
+endif
+
+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
+
+	scanner_deps = [ dependency('expat') ]
+	scanner_args = [ '-include', 'config.h' ]
+
+	if get_option('dtd_validation')
+		scanner_deps += dependency('libxml-2.0')
+		scanner_args += '-DHAVE_LIBXML=1'
+	endif
+
+	prog_embed = find_program('embed.py', native: true)
+
+	embed_dtd = custom_target(
+		'wayland.dtd.h',
+		input: '../protocol/wayland.dtd',
+		output: 'wayland.dtd.h',
+		command: [ prog_embed, '@INPUT@', 'wayland_dtd' ],
+		capture: true
+	)
+
+	wayland_scanner_sources = [ 'scanner.c', embed_dtd ]
+	wayland_scanner_includes = [ root_inc, protocol_inc ]
+
+	wayland_scanner = executable(
+		'wayland-scanner',
+		wayland_scanner_sources,
+		c_args: scanner_args,
+		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('${pc_sysrootdir}${datarootdir}', meson.project_name()),
+			'bindir=' + join_paths('${prefix}', get_option('bindir')),
+			'wayland_scanner=${bindir}/wayland-scanner'
+		],
+		filebase: 'wayland-scanner'
+	)
+
+	if meson.can_run_host_binaries()
+		meson.override_find_program('wayland-scanner', wayland_scanner)
+		meson.override_dependency('wayland-scanner', declare_dependency(
+			variables: { 'wayland_scanner': 'wayland-scanner' },
+		))
+	endif
+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_variable(pkgconfig: '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: [ epoll_dep, 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'
+	)
+
+	if wayland_version[0] != '1'
+		# The versioning used for the shared libraries assumes that the major
+		# version of Wayland as a whole will increase to 2 if and only if there
+		# is an ABI break, at which point we should probably bump the SONAME of
+		# all libraries to .so.2. For more details see
+		# https://gitlab.freedesktop.org/wayland/wayland/-/merge_requests/177
+		error('We probably need to bump the SONAME of libwayland-server and -client')
+	endif
+
+	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'
+		],
+		# To avoid an unnecessary SONAME bump, wayland 1.x.y produces
+		# libwayland-server.so.0.x.y.
+		version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
+		dependencies: [
+			epoll_dep,
+			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: [ epoll_dep, 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('${pc_sysrootdir}${datarootdir}', meson.project_name())
+		]
+	)
+
+	if meson.version().version_compare('>= 0.54.0')
+		meson.override_dependency('wayland-server', wayland_server_dep)
+	endif
+
+	wayland_client = library(
+		'wayland-client',
+		sources: [
+			wayland_client_protocol_core_h,
+			wayland_client_protocol_h,
+			wayland_protocol_c,
+			'wayland-client.c'
+		],
+		# To avoid an unnecessary SONAME bump, wayland 1.x.y produces
+		# libwayland-client.so.0.x.y.
+		version: '.'.join(['0', wayland_version[1], wayland_version[2]]),
+		dependencies: [
+			epoll_dep,
+			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('${pc_sysrootdir}${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
+		]
+	)
+
+	if meson.version().version_compare('>= 0.54.0')
+		meson.override_dependency('wayland-client', wayland_client_dep)
+	endif
+
+	install_headers([
+		'wayland-util.h',
+		'wayland-server.h',
+		'wayland-server-core.h',
+		'wayland-client.h',
+		'wayland-client-core.h',
+	])
+endif
diff --git a/subprojects/wayland/src/scanner.c b/subprojects/wayland/src/scanner.c
new file mode 100644
index 0000000000000000000000000000000000000000..955245135868ed80e54505c11ecb69c708d9dca9
--- /dev/null
+++ b/subprojects/wayland/src/scanner.c
@@ -0,0 +1,2191 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ * Copyright © 2015 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 "wayland-version.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <limits.h>
+#include <unistd.h>
+
+#if HAVE_LIBXML
+#include <libxml/parser.h>
+
+/* Embedded wayland.dtd file */
+/* static const char wayland_dtd[]; wayland.dtd */
+#include "wayland.dtd.h"
+#endif
+
+/* Expat must be included after libxml as both want to declare XMLCALL; see
+ * the Git commit that 'git blame' for this comment points to for more. */
+#include <expat.h>
+
+#include "wayland-util.h"
+
+#define PROGRAM_NAME "wayland-scanner"
+
+enum side {
+	CLIENT,
+	SERVER,
+};
+
+enum visibility {
+	PRIVATE,
+	PUBLIC,
+};
+
+static int
+usage(int ret)
+{
+	fprintf(stderr, "usage: %s [OPTION] [client-header|server-header|enum-header|private-code|public-code]"
+		" [input_file output_file]\n", PROGRAM_NAME);
+	fprintf(stderr, "\n");
+	fprintf(stderr, "Converts XML protocol descriptions supplied on "
+			"stdin or input file to client\n"
+			"headers, server headers, or protocol marshalling code.\n\n"
+			"Use \"public-code\" only if the marshalling code will be public - "
+			"aka DSO will export it while other components will be using it.\n"
+			"Using \"private-code\" is strongly recommended.\n\n");
+	fprintf(stderr, "options:\n");
+	fprintf(stderr, "    -h,  --help                  display this help and exit.\n"
+			"    -v,  --version               print the wayland library version that\n"
+			"                                 the scanner was built against.\n"
+			"    -c,  --include-core-only     include the core version of the headers,\n"
+			"                                 that is e.g. wayland-client-core.h instead\n"
+			"                                 of wayland-client.h.\n"
+			"    -s,  --strict                exit immediately with an error if DTD\n"
+			"                                 verification fails.\n");
+	exit(ret);
+}
+
+static int
+scanner_version(int ret)
+{
+	fprintf(stderr, "%s %s\n", PROGRAM_NAME, WAYLAND_VERSION);
+	exit(ret);
+}
+
+static bool
+is_dtd_valid(FILE *input, const char *filename)
+{
+	bool rc = true;
+#if HAVE_LIBXML
+	xmlParserCtxtPtr ctx = NULL;
+	xmlDocPtr doc = NULL;
+	xmlDtdPtr dtd = NULL;
+	xmlValidCtxtPtr	dtdctx;
+	xmlParserInputBufferPtr	buffer;
+	int fd = fileno(input);
+
+	dtdctx = xmlNewValidCtxt();
+	ctx = xmlNewParserCtxt();
+	if (!ctx || !dtdctx)
+		abort();
+
+	buffer = xmlParserInputBufferCreateMem(wayland_dtd,
+					       sizeof(wayland_dtd),
+					       XML_CHAR_ENCODING_UTF8);
+	if (!buffer) {
+		fprintf(stderr, "Failed to init buffer for DTD.\n");
+		abort();
+	}
+
+	dtd = xmlIOParseDTD(NULL, buffer, XML_CHAR_ENCODING_UTF8);
+	if (!dtd) {
+		fprintf(stderr, "Failed to parse DTD.\n");
+		abort();
+	}
+
+	doc = xmlCtxtReadFd(ctx, fd, filename, NULL, 0);
+	if (!doc) {
+		fprintf(stderr, "Failed to read XML\n");
+		abort();
+	}
+
+	rc = xmlValidateDtd(dtdctx, doc, dtd);
+	xmlFreeDoc(doc);
+	xmlFreeParserCtxt(ctx);
+	xmlFreeDtd(dtd);
+	xmlFreeValidCtxt(dtdctx);
+	/* xmlIOParseDTD consumes buffer */
+
+	if (lseek(fd, 0, SEEK_SET) != 0) {
+		fprintf(stderr, "Failed to reset fd, output would be garbage.\n");
+		abort();
+	}
+#endif
+	return rc;
+}
+
+#define XML_BUFFER_SIZE 4096
+
+struct location {
+	const char *filename;
+	int line_number;
+};
+
+struct description {
+	char *summary;
+	char *text;
+};
+
+struct protocol {
+	char *name;
+	char *uppercase_name;
+	struct wl_list interface_list;
+	int type_index;
+	int null_run_length;
+	char *copyright;
+	struct description *description;
+	bool core_headers;
+};
+
+struct interface {
+	struct location loc;
+	char *name;
+	char *uppercase_name;
+	int version;
+	int since, deprecated_since;
+	struct wl_list request_list;
+	struct wl_list event_list;
+	struct wl_list enumeration_list;
+	struct wl_list link;
+	struct description *description;
+};
+
+struct message {
+	struct location loc;
+	char *name;
+	char *uppercase_name;
+	struct wl_list arg_list;
+	struct wl_list link;
+	int arg_count;
+	int new_id_count;
+	int type_index;
+	int all_null;
+	int destructor;
+	int since, deprecated_since;
+	struct description *description;
+};
+
+enum arg_type {
+	NEW_ID,
+	INT,
+	UNSIGNED,
+	FIXED,
+	STRING,
+	OBJECT,
+	ARRAY,
+	FD
+};
+
+struct arg {
+	char *name;
+	enum arg_type type;
+	int nullable;
+	char *interface_name;
+	struct wl_list link;
+	char *summary;
+	char *enumeration_name;
+};
+
+struct enumeration {
+	char *name;
+	char *uppercase_name;
+	struct wl_list entry_list;
+	struct wl_list link;
+	struct description *description;
+	bool bitfield;
+	int since;
+};
+
+struct entry {
+	char *name;
+	char *uppercase_name;
+	char *value;
+	char *summary;
+	int since, deprecated_since;
+	struct wl_list link;
+	struct description *description;
+};
+
+struct parse_context {
+	struct location loc;
+	XML_Parser parser;
+	struct protocol *protocol;
+	struct interface *interface;
+	struct message *message;
+	struct enumeration *enumeration;
+	struct entry *entry;
+	struct description *description;
+	char character_data[8192];
+	unsigned int character_data_length;
+};
+
+enum identifier_role {
+	STANDALONE_IDENT,
+	TRAILING_IDENT
+};
+
+static void *
+fail_on_null(void *p)
+{
+	if (p == NULL) {
+		fprintf(stderr, "%s: out of memory\n", PROGRAM_NAME);
+		exit(EXIT_FAILURE);
+	}
+
+	return p;
+}
+
+static void *
+zalloc(size_t s)
+{
+	return calloc(s, 1);
+}
+
+static void *
+xzalloc(size_t s)
+{
+	return fail_on_null(zalloc(s));
+}
+
+static char *
+xstrdup(const char *s)
+{
+	return fail_on_null(strdup(s));
+}
+
+static char *
+uppercase_dup(const char *src)
+{
+	char *u;
+	int i;
+
+	u = xstrdup(src);
+	for (i = 0; u[i]; i++)
+		u[i] = toupper(u[i]);
+	u[i] = '\0';
+
+	return u;
+}
+
+static const char *indent(int n)
+{
+	const char *whitespace[] = {
+		"\t\t\t\t\t\t\t\t\t\t\t\t",
+		"\t\t\t\t\t\t\t\t\t\t\t\t ",
+		"\t\t\t\t\t\t\t\t\t\t\t\t  ",
+		"\t\t\t\t\t\t\t\t\t\t\t\t   ",
+		"\t\t\t\t\t\t\t\t\t\t\t\t    ",
+		"\t\t\t\t\t\t\t\t\t\t\t\t     ",
+		"\t\t\t\t\t\t\t\t\t\t\t\t      ",
+		"\t\t\t\t\t\t\t\t\t\t\t\t       "
+	};
+
+	return whitespace[n % 8] + 12 - n / 8;
+}
+
+static void
+desc_dump(char *desc, const char *fmt, ...) WL_PRINTF(2, 3);
+
+static void
+desc_dump(char *desc, const char *fmt, ...)
+{
+	va_list ap;
+	char buf[128], hang;
+	int col, i, j, k, startcol, newlines;
+
+	va_start(ap, fmt);
+	vsnprintf(buf, sizeof buf, fmt, ap);
+	va_end(ap);
+
+	for (i = 0, col = 0; buf[i] != '*'; i++) {
+		if (buf[i] == '\t')
+			col = (col + 8) & ~7;
+		else
+			col++;
+	}
+
+	printf("%s", buf);
+
+	if (!desc) {
+		printf("(none)\n");
+		return;
+	}
+
+	startcol = col;
+	col += strlen(&buf[i]);
+	if (col - startcol > 2)
+		hang = '\t';
+	else
+		hang = ' ';
+
+	for (i = 0; desc[i]; ) {
+		k = i;
+		newlines = 0;
+		while (desc[i] && isspace(desc[i])) {
+			if (desc[i] == '\n')
+				newlines++;
+			i++;
+		}
+		if (!desc[i])
+			break;
+
+		j = i;
+		while (desc[i] && !isspace(desc[i]))
+			i++;
+
+		if (newlines > 1)
+			printf("\n%s*", indent(startcol));
+		if (newlines > 1 || col + i - j > 72) {
+			printf("\n%s*%c", indent(startcol), hang);
+			col = startcol;
+		}
+
+		if (col > startcol && k > 0)
+			col += printf(" ");
+		col += printf("%.*s", i - j, &desc[j]);
+	}
+	putchar('\n');
+}
+
+static void __attribute__ ((noreturn))
+fail(struct location *loc, const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	fprintf(stderr, "%s:%d: error: ",
+		loc->filename, loc->line_number);
+	vfprintf(stderr, msg, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+	exit(EXIT_FAILURE);
+}
+
+static void
+warn(struct location *loc, const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	fprintf(stderr, "%s:%d: warning: ",
+		loc->filename, loc->line_number);
+	vfprintf(stderr, msg, ap);
+	fprintf(stderr, "\n");
+	va_end(ap);
+}
+
+static bool
+is_nullable_type(struct arg *arg)
+{
+	switch (arg->type) {
+	/* Strings and objects are possibly nullable */
+	case STRING:
+	case OBJECT:
+		return true;
+	default:
+		return false;
+	}
+}
+
+static struct message *
+create_message(struct location loc, const char *name)
+{
+	struct message *message;
+
+	message = xzalloc(sizeof *message);
+	message->loc = loc;
+	message->name = xstrdup(name);
+	message->uppercase_name = uppercase_dup(name);
+	wl_list_init(&message->arg_list);
+
+	return message;
+}
+
+static void
+free_arg(struct arg *arg)
+{
+	free(arg->name);
+	free(arg->interface_name);
+	free(arg->summary);
+	free(arg->enumeration_name);
+	free(arg);
+}
+
+static struct arg *
+create_arg(const char *name)
+{
+	struct arg *arg;
+
+	arg = xzalloc(sizeof *arg);
+	arg->name = xstrdup(name);
+
+	return arg;
+}
+
+static bool
+set_arg_type(struct arg *arg, const char *type)
+{
+	if (strcmp(type, "int") == 0)
+		arg->type = INT;
+	else if (strcmp(type, "uint") == 0)
+		arg->type = UNSIGNED;
+	else if (strcmp(type, "fixed") == 0)
+		arg->type = FIXED;
+	else if (strcmp(type, "string") == 0)
+		arg->type = STRING;
+	else if (strcmp(type, "array") == 0)
+		arg->type = ARRAY;
+	else if (strcmp(type, "fd") == 0)
+		arg->type = FD;
+	else if (strcmp(type, "new_id") == 0)
+		arg->type = NEW_ID;
+	else if (strcmp(type, "object") == 0)
+		arg->type = OBJECT;
+	else
+		return false;
+
+	return true;
+}
+
+static void
+free_description(struct description *desc)
+{
+	if (!desc)
+		return;
+
+	free(desc->summary);
+	free(desc->text);
+
+	free(desc);
+}
+
+static void
+free_message(struct message *message)
+{
+	struct arg *a, *a_next;
+
+	free(message->name);
+	free(message->uppercase_name);
+	free_description(message->description);
+
+	wl_list_for_each_safe(a, a_next, &message->arg_list, link)
+		free_arg(a);
+
+	free(message);
+}
+
+static struct enumeration *
+create_enumeration(const char *name)
+{
+	struct enumeration *enumeration;
+
+	enumeration = xzalloc(sizeof *enumeration);
+	enumeration->name = xstrdup(name);
+	enumeration->uppercase_name = uppercase_dup(name);
+	enumeration->since = 1;
+
+	wl_list_init(&enumeration->entry_list);
+
+	return enumeration;
+}
+
+static struct entry *
+create_entry(const char *name, const char *value)
+{
+	struct entry *entry;
+
+	entry = xzalloc(sizeof *entry);
+	entry->name = xstrdup(name);
+	entry->uppercase_name = uppercase_dup(name);
+	entry->value = xstrdup(value);
+
+	return entry;
+}
+
+static void
+free_entry(struct entry *entry)
+{
+	free(entry->name);
+	free(entry->uppercase_name);
+	free(entry->value);
+	free(entry->summary);
+	free_description(entry->description);
+
+	free(entry);
+}
+
+static void
+free_enumeration(struct enumeration *enumeration)
+{
+	struct entry *e, *e_next;
+
+	free(enumeration->name);
+	free(enumeration->uppercase_name);
+	free_description(enumeration->description);
+
+	wl_list_for_each_safe(e, e_next, &enumeration->entry_list, link)
+		free_entry(e);
+
+	free(enumeration);
+}
+
+static struct interface *
+create_interface(struct location loc, const char *name, int version)
+{
+	struct interface *interface;
+
+	interface = xzalloc(sizeof *interface);
+	interface->loc = loc;
+	interface->name = xstrdup(name);
+	interface->uppercase_name = uppercase_dup(name);
+	interface->version = version;
+	interface->since = 1;
+	wl_list_init(&interface->request_list);
+	wl_list_init(&interface->event_list);
+	wl_list_init(&interface->enumeration_list);
+
+	return interface;
+}
+
+static void
+free_interface(struct interface *interface)
+{
+	struct message *m, *next_m;
+	struct enumeration *e, *next_e;
+
+	free(interface->name);
+	free(interface->uppercase_name);
+	free_description(interface->description);
+
+	wl_list_for_each_safe(m, next_m, &interface->request_list, link)
+		free_message(m);
+	wl_list_for_each_safe(m, next_m, &interface->event_list, link)
+		free_message(m);
+	wl_list_for_each_safe(e, next_e, &interface->enumeration_list, link)
+		free_enumeration(e);
+
+	free(interface);
+}
+
+/* Convert string to unsigned integer
+ *
+ * Parses a non-negative base-10 number from the given string.  If the
+ * specified string is blank, contains non-numerical characters, is out
+ * of range, or results in a negative number, -1 is returned to indicate
+ * an error.
+ *
+ * Upon error, this routine does not modify or set errno.
+ *
+ * Returns -1 on error, or a non-negative integer on success
+ */
+static int
+strtouint(const char *str)
+{
+	long int ret;
+	char *end;
+	int prev_errno = errno;
+
+	errno = 0;
+	ret = strtol(str, &end, 10);
+	if (errno != 0 || end == str || *end != '\0')
+		return -1;
+
+	/* check range */
+	if (ret < 0 || ret > INT_MAX) {
+		return -1;
+	}
+
+	errno = prev_errno;
+	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)
+{
+	int version;
+
+	if (since != NULL) {
+		version = strtouint(since);
+		if (version == -1) {
+			fail(&ctx->loc, "invalid integer (%s)\n", since);
+		} else if (version > ctx->interface->version) {
+			fail(&ctx->loc, "since (%u) larger than version (%u)\n",
+			     version, ctx->interface->version);
+		}
+	} else {
+		version = 1;
+	}
+
+
+	return version;
+}
+
+static int
+version_from_deprecated_since(struct parse_context *ctx, const char *deprecated_since)
+{
+	int version;
+
+	if (deprecated_since == NULL)
+		return 0;
+
+	version = strtouint(deprecated_since);
+	if (version == -1) {
+		fail(&ctx->loc, "invalid integer (%s)\n", deprecated_since);
+	} else if (version > ctx->interface->version) {
+		fail(&ctx->loc, "deprecated-since (%u) larger than version (%u)\n",
+		     version, ctx->interface->version);
+	}
+
+	return version;
+}
+
+static void
+start_element(void *data, const char *element_name, const char **atts)
+{
+	struct parse_context *ctx = data;
+	struct interface *interface;
+	struct message *message;
+	struct arg *arg;
+	struct enumeration *enumeration;
+	struct entry *entry;
+	struct description *description = NULL;
+	const char *name = NULL;
+	const char *type = NULL;
+	const char *interface_name = NULL;
+	const char *value = NULL;
+	const char *summary = NULL;
+	const char *since = NULL;
+	const char *deprecated_since = NULL;
+	const char *allow_null = NULL;
+	const char *enumeration_name = NULL;
+	const char *bitfield = NULL;
+	int i, version = 0;
+
+	ctx->loc.line_number = XML_GetCurrentLineNumber(ctx->parser);
+	for (i = 0; atts[i]; i += 2) {
+		if (strcmp(atts[i], "name") == 0)
+			name = atts[i + 1];
+		if (strcmp(atts[i], "version") == 0) {
+			version = strtouint(atts[i + 1]);
+			if (version == -1)
+				fail(&ctx->loc, "wrong version (%s)", atts[i + 1]);
+		}
+		if (strcmp(atts[i], "type") == 0)
+			type = atts[i + 1];
+		if (strcmp(atts[i], "value") == 0)
+			value = atts[i + 1];
+		if (strcmp(atts[i], "interface") == 0)
+			interface_name = atts[i + 1];
+		if (strcmp(atts[i], "summary") == 0)
+			summary = atts[i + 1];
+		if (strcmp(atts[i], "since") == 0)
+			since = atts[i + 1];
+		if (strcmp(atts[i], "deprecated-since") == 0)
+			deprecated_since = atts[i + 1];
+		if (strcmp(atts[i], "allow-null") == 0)
+			allow_null = atts[i + 1];
+		if (strcmp(atts[i], "enum") == 0)
+			enumeration_name = atts[i + 1];
+		if (strcmp(atts[i], "bitfield") == 0)
+			bitfield = atts[i + 1];
+	}
+
+	ctx->character_data_length = 0;
+	if (strcmp(element_name, "protocol") == 0) {
+		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) {
+
+	} else if (strcmp(element_name, "interface") == 0) {
+		if (name == NULL)
+			fail(&ctx->loc, "no interface name given");
+
+		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,
+			       &interface->link);
+	} else if (strcmp(element_name, "request") == 0 ||
+		   strcmp(element_name, "event") == 0) {
+		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)
+			wl_list_insert(ctx->interface->request_list.prev,
+				       &message->link);
+		else
+			wl_list_insert(ctx->interface->event_list.prev,
+				       &message->link);
+
+		if (type != NULL && strcmp(type, "destructor") == 0)
+			message->destructor = 1;
+
+		version = version_from_since(ctx, since);
+		if (version < ctx->interface->since)
+			warn(&ctx->loc, "since version not increasing\n");
+		ctx->interface->since = version;
+		message->since = version;
+
+		version = version_from_deprecated_since(ctx, deprecated_since);
+		if (version > 0 && version <= message->since)
+			fail(&ctx->loc, "deprecated-since version (%d) smaller "
+			     "or equal to since version (%u)\n",
+			     version, message->since);
+		message->deprecated_since = version;
+
+		if (strcmp(name, "destroy") == 0 && !message->destructor)
+			fail(&ctx->loc, "destroy request should be destructor type");
+
+		ctx->message = message;
+	} else if (strcmp(element_name, "arg") == 0) {
+		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);
+
+		switch (arg->type) {
+		case NEW_ID:
+			ctx->message->new_id_count++;
+			/* fallthrough */
+		case OBJECT:
+			if (interface_name) {
+				validate_identifier(&ctx->loc,
+						    interface_name,
+						    STANDALONE_IDENT);
+				arg->interface_name = xstrdup(interface_name);
+			}
+			break;
+		default:
+			if (interface_name != NULL)
+				fail(&ctx->loc, "interface attribute not allowed for type %s", type);
+			break;
+		}
+
+		if (allow_null) {
+			if (strcmp(allow_null, "true") == 0)
+				arg->nullable = 1;
+			else if (strcmp(allow_null, "false") != 0)
+				fail(&ctx->loc,
+				     "invalid value for allow-null attribute (%s)",
+				     allow_null);
+
+			if (!is_nullable_type(arg))
+				fail(&ctx->loc,
+				     "allow-null is only valid for objects, strings, and arrays");
+		}
+
+		if (enumeration_name == NULL || strcmp(enumeration_name, "") == 0)
+			arg->enumeration_name = NULL;
+		else
+			arg->enumeration_name = xstrdup(enumeration_name);
+
+		if (summary)
+			arg->summary = xstrdup(summary);
+
+		wl_list_insert(ctx->message->arg_list.prev, &arg->link);
+		ctx->message->arg_count++;
+	} else if (strcmp(element_name, "enum") == 0) {
+		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)
+			enumeration->bitfield = false;
+		else if (strcmp(bitfield, "true") == 0)
+			enumeration->bitfield = true;
+		else
+			fail(&ctx->loc,
+			     "invalid value (%s) for bitfield attribute (only true/false are accepted)",
+			     bitfield);
+
+		wl_list_insert(ctx->interface->enumeration_list.prev,
+			       &enumeration->link);
+
+		ctx->enumeration = enumeration;
+	} else if (strcmp(element_name, "entry") == 0) {
+		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);
+		if (version < ctx->enumeration->since)
+			warn(&ctx->loc, "since version not increasing\n");
+		ctx->enumeration->since = version;
+		entry->since = version;
+
+		version = version_from_deprecated_since(ctx, deprecated_since);
+		if (version > 0 && version <= entry->since)
+			fail(&ctx->loc, "deprecated-since version (%d) smaller "
+			     "or equal to since version (%u)\n",
+			     version, entry->since);
+		entry->deprecated_since = version;
+
+		if (summary)
+			entry->summary = xstrdup(summary);
+		else
+			entry->summary = NULL;
+		wl_list_insert(ctx->enumeration->entry_list.prev,
+			       &entry->link);
+		ctx->entry = entry;
+	} else if (strcmp(element_name, "description") == 0) {
+		if (summary == NULL)
+			fail(&ctx->loc, "description without summary");
+
+		description = xzalloc(sizeof *description);
+		description->summary = xstrdup(summary);
+
+		if (ctx->message)
+			ctx->message->description = description;
+		else if (ctx->entry)
+			ctx->entry->description = description;
+		else if (ctx->enumeration)
+			ctx->enumeration->description = description;
+		else if (ctx->interface)
+			ctx->interface->description = description;
+		else
+			ctx->protocol->description = description;
+		ctx->description = description;
+	}
+}
+
+static struct enumeration *
+find_enumeration(struct protocol *protocol,
+		 struct interface *interface,
+		 char *enum_attribute)
+{
+	struct interface *i;
+	struct enumeration *e;
+	char *enum_name;
+	uint32_t idx = 0, j;
+
+	for (j = 0; j + 1 < strlen(enum_attribute); j++) {
+		if (enum_attribute[j] == '.') {
+			idx = j;
+		}
+	}
+
+	if (idx > 0) {
+		enum_name = enum_attribute + idx + 1;
+
+		wl_list_for_each(i, &protocol->interface_list, link)
+			if (strncmp(i->name, enum_attribute, idx) == 0)
+				wl_list_for_each(e, &i->enumeration_list, link)
+					if (strcmp(e->name, enum_name) == 0)
+						return e;
+	} else if (interface) {
+		enum_name = enum_attribute;
+
+		wl_list_for_each(e, &interface->enumeration_list, link)
+			if (strcmp(e->name, enum_name) == 0)
+				return e;
+	}
+
+	return NULL;
+}
+
+static void
+verify_arguments(struct parse_context *ctx,
+		 struct interface *interface,
+		 struct wl_list *messages,
+		 struct wl_list *enumerations)
+{
+	struct message *m;
+	wl_list_for_each(m, messages, link) {
+		struct arg *a;
+		wl_list_for_each(a, &m->arg_list, link) {
+			struct enumeration *e;
+
+			if (!a->enumeration_name)
+				continue;
+
+
+			e = find_enumeration(ctx->protocol, interface,
+					     a->enumeration_name);
+
+			switch (a->type) {
+			case INT:
+				if (e && e->bitfield)
+					fail(&ctx->loc,
+					     "bitfield-style enum must only be referenced by uint");
+				break;
+			case UNSIGNED:
+				break;
+			default:
+				fail(&ctx->loc,
+				     "enumeration-style argument has wrong type");
+			}
+		}
+	}
+
+}
+
+#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)
+{
+	struct parse_context *ctx = data;
+
+	if (strcmp(name, "copyright") == 0) {
+		ctx->protocol->copyright =
+			strndup(ctx->character_data,
+				ctx->character_data_length);
+	} else if (strcmp(name, "description") == 0) {
+		ctx->description->text =
+			strndup(ctx->character_data,
+				ctx->character_data_length);
+		ctx->description = NULL;
+	} else if (strcmp(name, "request") == 0 ||
+		   strcmp(name, "event") == 0) {
+		ctx->message = NULL;
+	} else if (strcmp(name, "enum") == 0) {
+		if (wl_list_empty(&ctx->enumeration->entry_list)) {
+			fail(&ctx->loc, "enumeration %s was empty",
+			     ctx->enumeration->name);
+		}
+		ctx->enumeration = NULL;
+	} else if (strcmp(name, "entry") == 0) {
+		ctx->entry = NULL;
+	} else if (strcmp(name, "protocol") == 0) {
+		struct interface *i;
+
+		wl_list_for_each(i, &ctx->protocol->interface_list, link) {
+			verify_arguments(ctx, i, &i->request_list, &i->enumeration_list);
+			verify_arguments(ctx, i, &i->event_list, &i->enumeration_list);
+		}
+	}
+}
+
+static void
+character_data(void *data, const XML_Char *s, int len)
+{
+	struct parse_context *ctx = data;
+
+	if (ctx->character_data_length + len > sizeof (ctx->character_data)) {
+		fprintf(stderr, "too much character data");
+		exit(EXIT_FAILURE);
+	    }
+
+	memcpy(ctx->character_data + ctx->character_data_length, s, len);
+	ctx->character_data_length += len;
+}
+
+static void
+format_text_to_comment(const char *text, bool standalone_comment)
+{
+	int bol = 1, start = 0, i, length;
+	bool comment_started = !standalone_comment;
+
+	length = strlen(text);
+	for (i = 0; i <= length; i++) {
+		if (bol && (text[i] == ' ' || text[i] == '\t')) {
+			continue;
+		} else if (bol) {
+			bol = 0;
+			start = i;
+		}
+		if (text[i] == '\n' ||
+		    (text[i] == '\0' && !(start == i))) {
+			printf("%s%s%.*s\n",
+			       comment_started ? " *" : "/*",
+			       i > start ? " " : "",
+			       i - start, text + start);
+			bol = 1;
+			comment_started = true;
+		}
+	}
+	if (comment_started && standalone_comment)
+		printf(" */\n\n");
+}
+
+static void
+emit_opcodes(struct wl_list *message_list, struct interface *interface)
+{
+	struct message *m;
+	int opcode;
+
+	if (wl_list_empty(message_list))
+		return;
+
+	opcode = 0;
+	wl_list_for_each(m, message_list, link)
+		printf("#define %s_%s %d\n",
+		       interface->uppercase_name, m->uppercase_name, opcode++);
+
+	printf("\n");
+}
+
+static void
+emit_opcode_versions(struct wl_list *message_list, struct interface *interface)
+{
+	struct message *m;
+
+	wl_list_for_each(m, message_list, link) {
+		printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
+		printf("#define %s_%s_SINCE_VERSION %d\n",
+		       interface->uppercase_name, m->uppercase_name, m->since);
+	}
+
+	printf("\n");
+}
+
+static void
+emit_type(struct arg *a)
+{
+	switch (a->type) {
+	default:
+	case INT:
+	case FD:
+		printf("int32_t ");
+		break;
+	case NEW_ID:
+	case UNSIGNED:
+		printf("uint32_t ");
+		break;
+	case FIXED:
+		printf("wl_fixed_t ");
+		break;
+	case STRING:
+		printf("const char *");
+		break;
+	case OBJECT:
+		printf("struct %s *", a->interface_name);
+		break;
+	case ARRAY:
+		printf("struct wl_array *");
+		break;
+	}
+}
+
+static void
+emit_stubs(struct wl_list *message_list, struct interface *interface)
+{
+	struct message *m;
+	struct arg *a, *ret;
+	int has_destructor, has_destroy;
+
+	printf("/** @ingroup iface_%s */\n", interface->name);
+	printf("static inline void\n"
+	       "%s_set_user_data(struct %s *%s, void *user_data)\n"
+	       "{\n"
+	       "\twl_proxy_set_user_data((struct wl_proxy *) %s, user_data);\n"
+	       "}\n\n",
+	       interface->name, interface->name, interface->name,
+	       interface->name);
+
+	printf("/** @ingroup iface_%s */\n", interface->name);
+	printf("static inline void *\n"
+	       "%s_get_user_data(struct %s *%s)\n"
+	       "{\n"
+	       "\treturn wl_proxy_get_user_data((struct wl_proxy *) %s);\n"
+	       "}\n\n",
+	       interface->name, interface->name, interface->name,
+	       interface->name);
+
+	printf("static inline uint32_t\n"
+	       "%s_get_version(struct %s *%s)\n"
+	       "{\n"
+	       "\treturn wl_proxy_get_version((struct wl_proxy *) %s);\n"
+	       "}\n\n",
+	       interface->name, interface->name, interface->name,
+	       interface->name);
+
+	has_destructor = 0;
+	has_destroy = 0;
+	wl_list_for_each(m, message_list, link) {
+		if (m->destructor)
+			has_destructor = 1;
+		if (strcmp(m->name, "destroy") == 0)
+			has_destroy = 1;
+	}
+
+	if (!has_destructor && has_destroy) {
+		fail(&interface->loc,
+		     "interface '%s' has method named destroy "
+		     "but no destructor",
+		     interface->name);
+		exit(EXIT_FAILURE);
+	}
+
+	if (!has_destroy && strcmp(interface->name, "wl_display") != 0) {
+		printf("/** @ingroup iface_%s */\n", interface->name);
+		printf("static inline void\n"
+		       "%s_destroy(struct %s *%s)\n"
+		       "{\n"
+		       "\twl_proxy_destroy("
+		       "(struct wl_proxy *) %s);\n"
+		       "}\n\n",
+		       interface->name, interface->name, interface->name,
+		       interface->name);
+	}
+
+	if (wl_list_empty(message_list))
+		return;
+
+	wl_list_for_each(m, message_list, link) {
+		if (m->new_id_count > 1) {
+			warn(&m->loc,
+			     "request '%s::%s' has more than "
+			     "one new_id arg, not emitting stub\n",
+			     interface->name, m->name);
+			continue;
+		}
+
+		ret = NULL;
+		wl_list_for_each(a, &m->arg_list, link) {
+			if (a->type == NEW_ID)
+				ret = a;
+		}
+
+		printf("/**\n"
+		       " * @ingroup iface_%s\n", interface->name);
+		if (m->description && m->description->text)
+			format_text_to_comment(m->description->text, false);
+		printf(" */\n");
+		if (ret && ret->interface_name == NULL)
+			printf("static inline void *\n");
+		else if (ret)
+			printf("static inline struct %s *\n",
+			       ret->interface_name);
+		else
+			printf("static inline void\n");
+
+		printf("%s_%s(struct %s *%s",
+		       interface->name, m->name,
+		       interface->name, interface->name);
+
+		wl_list_for_each(a, &m->arg_list, link) {
+			if (a->type == NEW_ID && a->interface_name == NULL) {
+				printf(", const struct wl_interface *interface"
+				       ", uint32_t version");
+				continue;
+			} else if (a->type == NEW_ID)
+				continue;
+			printf(", ");
+			emit_type(a);
+			printf("%s", a->name);
+		}
+
+		printf(")\n"
+		       "{\n");
+		printf("\t");
+		if (ret) {
+			printf("struct wl_proxy *%s;\n\n"
+			       "\t%s = ", ret->name, ret->name);
+		}
+		printf("wl_proxy_marshal_flags("
+		       "(struct wl_proxy *) %s,\n"
+		       "\t\t\t %s_%s",
+		       interface->name,
+		       interface->uppercase_name,
+		       m->uppercase_name);
+
+		if (ret) {
+			if (ret->interface_name) {
+				/* Normal factory case, an arg has type="new_id" and
+				 * an interface is provided */
+				printf(", &%s_interface", ret->interface_name);
+			} else {
+				/* an arg has type ="new_id" but interface is not
+				 * provided, such as in wl_registry.bind */
+				printf(", interface");
+			}
+		} else {
+			/* No args have type="new_id" */
+			printf(", NULL");
+		}
+
+		if (ret && ret->interface_name == NULL)
+			printf(", version");
+		else
+			printf(", wl_proxy_get_version((struct wl_proxy *) %s)",
+			       interface->name);
+		printf(", %s", m->destructor ? "WL_MARSHAL_FLAG_DESTROY" : "0");
+
+		wl_list_for_each(a, &m->arg_list, link) {
+			if (a->type == NEW_ID) {
+				if (a->interface_name == NULL)
+					printf(", interface->name, version");
+				printf(", NULL");
+			} else {
+				printf(", %s", a->name);
+			}
+		}
+		printf(");\n");
+
+		if (ret && ret->interface_name == NULL)
+			printf("\n\treturn (void *) %s;\n", ret->name);
+		else if (ret)
+			printf("\n\treturn (struct %s *) %s;\n",
+			       ret->interface_name, ret->name);
+
+		printf("}\n\n");
+	}
+}
+
+static void
+emit_event_wrappers(struct wl_list *message_list, struct interface *interface)
+{
+	struct message *m;
+	struct arg *a;
+
+	/* We provide hand written functions for the display object */
+	if (strcmp(interface->name, "wl_display") == 0)
+		return;
+
+	wl_list_for_each(m, message_list, link) {
+		printf("/**\n"
+		       " * @ingroup iface_%s\n"
+		       " * Sends an %s event to the client owning the resource.\n",
+		       interface->name,
+		       m->name);
+		printf(" * @param resource_ The client's resource\n");
+		wl_list_for_each(a, &m->arg_list, link) {
+			if (a->summary)
+				printf(" * @param %s %s\n", a->name, a->summary);
+		}
+		printf(" */\n");
+		printf("static inline void\n"
+		       "%s_send_%s(struct wl_resource *resource_",
+		       interface->name, m->name);
+
+		wl_list_for_each(a, &m->arg_list, link) {
+			printf(", ");
+			switch (a->type) {
+			case NEW_ID:
+			case OBJECT:
+				printf("struct wl_resource *");
+				break;
+			default:
+				emit_type(a);
+			}
+			printf("%s", a->name);
+		}
+
+		printf(")\n"
+		       "{\n"
+		       "\twl_resource_post_event(resource_, %s_%s",
+		       interface->uppercase_name, m->uppercase_name);
+
+		wl_list_for_each(a, &m->arg_list, link)
+			printf(", %s", a->name);
+
+		printf(");\n");
+		printf("}\n\n");
+	}
+}
+
+static void
+emit_enumerations(struct interface *interface, bool with_validators)
+{
+	struct enumeration *e;
+	struct entry *entry;
+
+	wl_list_for_each(e, &interface->enumeration_list, link) {
+		struct description *desc = e->description;
+
+		printf("#ifndef %s_%s_ENUM\n",
+		       interface->uppercase_name, e->uppercase_name);
+		printf("#define %s_%s_ENUM\n",
+		       interface->uppercase_name, e->uppercase_name);
+
+		if (desc) {
+			printf("/**\n");
+			printf(" * @ingroup iface_%s\n", interface->name);
+			format_text_to_comment(desc->summary, false);
+			if (desc->text)
+				format_text_to_comment(desc->text, false);
+			printf(" */\n");
+		}
+		printf("enum %s_%s {\n", interface->name, e->name);
+		wl_list_for_each(entry, &e->entry_list, link) {
+			desc = entry->description;
+			if (entry->summary || entry->since > 1 || desc) {
+				printf("\t/**\n");
+				if (entry->summary)
+					printf("\t * %s\n", entry->summary);
+				if (desc) {
+					printf("\t * %s\n", desc->summary);
+					printf("\t *\n");
+					if (desc->text)
+						desc_dump(desc->text, "\t * ");
+				}
+				if (entry->since > 1)
+					printf("\t * @since %d\n", entry->since);
+				if (entry->deprecated_since > 0)
+					printf("\t * @deprecated Deprecated since version %d\n",
+					       entry->deprecated_since);
+				printf("\t */\n");
+			}
+			printf("\t%s_%s_%s = %s,\n",
+			       interface->uppercase_name,
+			       e->uppercase_name,
+			       entry->uppercase_name, entry->value);
+		}
+		printf("};\n");
+
+		wl_list_for_each(entry, &e->entry_list, link) {
+			if (entry->since == 1)
+                            continue;
+
+                        printf("/**\n * @ingroup iface_%s\n */\n", interface->name);
+                        printf("#define %s_%s_%s_SINCE_VERSION %d\n",
+                               interface->uppercase_name,
+                               e->uppercase_name, entry->uppercase_name,
+                               entry->since);
+
+		}
+
+		if (with_validators) {
+			printf("/**\n"
+			       " * @ingroup iface_%s\n"
+			       " * Validate a %s %s value.\n"
+			       " *\n"
+			       " * @return true on success, false on error.\n"
+			       " * @ref %s_%s\n"
+			       " */\n"
+			       "static inline bool\n"
+			       "%s_%s_is_valid(uint32_t value, uint32_t version) {\n"
+			       "	switch (value) {\n",
+			       interface->name, interface->name, e->name,
+			       interface->name, e->name,
+			       interface->name, e->name);
+			wl_list_for_each(entry, &e->entry_list, link) {
+				printf("	case %s%s_%s_%s:\n"
+				       "		return version >= %d;\n",
+				       entry->value[0] == '-' ? "(uint32_t)" : "",
+				       interface->uppercase_name, e->uppercase_name,
+				       entry->uppercase_name, entry->since);
+			}
+			printf("	default:\n"
+			       "		return false;\n"
+			       "	}\n"
+			       "}\n");
+		}
+
+		printf("#endif /* %s_%s_ENUM */\n\n",
+		       interface->uppercase_name, e->uppercase_name);
+	}
+}
+
+static void
+emit_structs(struct wl_list *message_list, struct interface *interface, enum side side)
+{
+	struct message *m;
+	struct arg *a;
+	int n;
+
+	if (wl_list_empty(message_list))
+		return;
+
+	printf("/**\n");
+	printf(" * @ingroup iface_%s\n", interface->name);
+	printf(" * @struct %s_%s\n", interface->name,
+	       (side == SERVER) ? "interface" : "listener");
+	printf(" */\n");
+	printf("struct %s_%s {\n", interface->name,
+	       (side == SERVER) ? "interface" : "listener");
+
+	wl_list_for_each(m, message_list, link) {
+		struct description *mdesc = m->description;
+
+		printf("\t/**\n");
+		if (mdesc) {
+			if (mdesc->summary)
+				printf("\t * %s\n", mdesc->summary);
+			printf("\t *\n");
+			desc_dump(mdesc->text, "\t * ");
+		}
+		wl_list_for_each(a, &m->arg_list, link) {
+			if (side == SERVER && a->type == NEW_ID &&
+			    a->interface_name == NULL)
+				printf("\t * @param interface name of the objects interface\n"
+				       "\t * @param version version of the objects interface\n");
+
+			if (a->summary)
+				printf("\t * @param %s %s\n", a->name,
+				       a->summary);
+		}
+		if (m->since > 1)
+			printf("\t * @since %d\n", m->since);
+		if (m->deprecated_since > 0)
+			printf("\t * @deprecated Deprecated since version %d\n",
+			       m->deprecated_since);
+		printf("\t */\n");
+		printf("\tvoid (*%s)(", m->name);
+
+		n = strlen(m->name) + 17;
+		if (side == SERVER) {
+			printf("struct wl_client *client,\n"
+			       "%sstruct wl_resource *resource",
+			       indent(n));
+		} else {
+			printf("void *data,\n"),
+			printf("%sstruct %s *%s",
+			       indent(n), interface->name, interface->name);
+		}
+
+		wl_list_for_each(a, &m->arg_list, link) {
+			printf(",\n%s", indent(n));
+
+			if (side == SERVER && a->type == OBJECT)
+				printf("struct wl_resource *");
+			else if (side == SERVER && a->type == NEW_ID && a->interface_name == NULL)
+				printf("const char *interface, uint32_t version, uint32_t ");
+			else if (side == CLIENT && a->type == OBJECT && a->interface_name == NULL)
+				printf("void *");
+
+			else if (side == CLIENT && a->type == NEW_ID)
+				printf("struct %s *", a->interface_name);
+			else
+				emit_type(a);
+
+			printf("%s", a->name);
+		}
+
+		printf(");\n");
+	}
+
+	printf("};\n\n");
+
+	if (side == CLIENT) {
+	    printf("/**\n"
+		   " * @ingroup iface_%s\n"
+		   " */\n", interface->name);
+	    printf("static inline int\n"
+		   "%s_add_listener(struct %s *%s,\n"
+		   "%sconst struct %s_listener *listener, void *data)\n"
+		   "{\n"
+		   "\treturn wl_proxy_add_listener((struct wl_proxy *) %s,\n"
+		   "%s(void (**)(void)) listener, data);\n"
+		   "}\n\n",
+		   interface->name, interface->name, interface->name,
+		   indent(14 + strlen(interface->name)),
+		   interface->name,
+		   interface->name,
+		   indent(37));
+	}
+}
+
+static void
+emit_types_forward_declarations(struct protocol *protocol,
+				struct wl_list *message_list,
+				struct wl_array *types)
+{
+	struct message *m;
+	struct arg *a;
+	int length;
+	char **p;
+
+	wl_list_for_each(m, message_list, link) {
+		length = 0;
+		m->all_null = 1;
+		wl_list_for_each(a, &m->arg_list, link) {
+			length++;
+			switch (a->type) {
+			case NEW_ID:
+			case OBJECT:
+				if (!a->interface_name)
+					continue;
+
+				m->all_null = 0;
+				p = fail_on_null(wl_array_add(types, sizeof *p));
+				*p = a->interface_name;
+				break;
+			default:
+				break;
+			}
+		}
+
+		if (m->all_null && length > protocol->null_run_length)
+			protocol->null_run_length = length;
+	}
+}
+
+static int
+cmp_names(const void *p1, const void *p2)
+{
+	const char * const *s1 = p1, * const *s2 = p2;
+
+	return strcmp(*s1, *s2);
+}
+
+static const char *
+get_include_name(bool core, enum side side)
+{
+	if (side == SERVER)
+		return core ? "wayland-server-core.h" : "wayland-server.h";
+	else
+		return core ? "wayland-client-core.h" : "wayland-client.h";
+}
+
+static void
+emit_mainpage_blurb(const struct protocol *protocol, enum side side)
+{
+	struct interface *i;
+
+	printf("/**\n"
+	       " * @page page_%s The %s protocol\n",
+	       protocol->name, protocol->name);
+
+	if (protocol->description) {
+		if (protocol->description->summary) {
+			printf(" * %s\n"
+			       " *\n", protocol->description->summary);
+		}
+
+		if (protocol->description->text) {
+			printf(" * @section page_desc_%s Description\n", protocol->name);
+			format_text_to_comment(protocol->description->text, false);
+			printf(" *\n");
+		}
+	}
+
+	printf(" * @section page_ifaces_%s Interfaces\n", protocol->name);
+	wl_list_for_each(i, &protocol->interface_list, link) {
+		printf(" * - @subpage page_iface_%s - %s\n",
+		       i->name,
+		       i->description && i->description->summary ?  i->description->summary : "");
+	}
+
+	if (protocol->copyright) {
+		printf(" * @section page_copyright_%s Copyright\n",
+		       protocol->name);
+		printf(" * <pre>\n");
+		format_text_to_comment(protocol->copyright, false);
+		printf(" * </pre>\n");
+	}
+
+	printf(" */\n");
+}
+
+static void
+emit_header(struct protocol *protocol, enum side side)
+{
+	struct interface *i, *i_next;
+	struct wl_array types;
+	const char *s = (side == SERVER) ? "SERVER" : "CLIENT";
+	char **p, *prev;
+
+	printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
+
+	printf("#ifndef %s_%s_PROTOCOL_H\n"
+	       "#define %s_%s_PROTOCOL_H\n"
+	       "\n"
+	       "#include <stdint.h>\n"
+	       "#include <stddef.h>\n"
+	       "#include \"%s\"\n\n"
+	       "#ifdef  __cplusplus\n"
+	       "extern \"C\" {\n"
+	       "#endif\n\n",
+	       protocol->uppercase_name, s,
+	       protocol->uppercase_name, s,
+	       get_include_name(protocol->core_headers, side));
+	if (side == SERVER)
+		printf("struct wl_client;\n"
+		       "struct wl_resource;\n\n");
+
+	emit_mainpage_blurb(protocol, side);
+
+	wl_array_init(&types);
+	wl_list_for_each(i, &protocol->interface_list, link) {
+		emit_types_forward_declarations(protocol, &i->request_list, &types);
+		emit_types_forward_declarations(protocol, &i->event_list, &types);
+	}
+
+	wl_list_for_each(i, &protocol->interface_list, link) {
+		p = fail_on_null(wl_array_add(&types, sizeof *p));
+		*p = i->name;
+	}
+
+	if (types.size > 0)
+		qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
+
+	prev = NULL;
+	wl_array_for_each(p, &types) {
+		if (prev && strcmp(*p, prev) == 0)
+			continue;
+		printf("struct %s;\n", *p);
+		prev = *p;
+	}
+	wl_array_release(&types);
+	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);
+		if (i->description && i->description->text) {
+			printf(" * @section page_iface_%s_desc Description\n",
+			       i->name);
+			format_text_to_comment(i->description->text, false);
+		}
+		printf(" * @section page_iface_%s_api API\n"
+		       " * See @ref iface_%s.\n"
+		       " */\n",
+		       i->name, i->name);
+		printf("/**\n"
+		       " * @defgroup iface_%s The %s interface\n",
+		       i->name, i->name);
+		if (i->description && i->description->text)
+			format_text_to_comment(i->description->text, false);
+		printf(" */\n");
+		printf("extern const struct wl_interface "
+		       "%s_interface;\n", i->name);
+		printf("#endif\n");
+	}
+
+	printf("\n");
+
+	wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
+
+		emit_enumerations(i, side == SERVER);
+
+		if (side == SERVER) {
+			emit_structs(&i->request_list, i, side);
+			emit_opcodes(&i->event_list, i);
+			emit_opcode_versions(&i->event_list, i);
+			emit_opcode_versions(&i->request_list, i);
+			emit_event_wrappers(&i->event_list, i);
+		} else {
+			emit_structs(&i->event_list, i, side);
+			emit_opcodes(&i->request_list, i);
+			emit_opcode_versions(&i->event_list, i);
+			emit_opcode_versions(&i->request_list, i);
+			emit_stubs(&i->request_list, i);
+		}
+
+		free_interface(i);
+	}
+
+	printf("#ifdef  __cplusplus\n"
+	       "}\n"
+	       "#endif\n"
+	       "\n"
+	       "#endif\n");
+}
+
+static void
+emit_enum_header(struct protocol *protocol)
+{
+	struct interface *i, *i_next;
+
+	printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
+
+	printf("#ifndef %s_ENUM_PROTOCOL_H\n"
+	       "#define %s_ENUM_PROTOCOL_H\n"
+	       "\n"
+	       "#ifdef  __cplusplus\n"
+	       "extern \"C\" {\n"
+	       "#endif\n\n",
+	       protocol->uppercase_name,
+	       protocol->uppercase_name);
+
+	wl_list_for_each_safe(i, i_next, &protocol->interface_list, link) {
+		emit_enumerations(i, false);
+
+		free_interface(i);
+	}
+
+	printf("#ifdef  __cplusplus\n"
+	       "}\n"
+	       "#endif\n"
+	       "\n"
+	       "#endif\n");
+}
+
+static void
+emit_null_run(struct protocol *protocol)
+{
+	int i;
+
+	for (i = 0; i < protocol->null_run_length; i++)
+		printf("\tNULL,\n");
+}
+
+static void
+emit_types(struct protocol *protocol, struct wl_list *message_list)
+{
+	struct message *m;
+	struct arg *a;
+
+	wl_list_for_each(m, message_list, link) {
+		if (m->all_null) {
+			m->type_index = 0;
+			continue;
+		}
+
+		m->type_index =
+			protocol->null_run_length + protocol->type_index;
+		protocol->type_index += m->arg_count;
+
+		wl_list_for_each(a, &m->arg_list, link) {
+			switch (a->type) {
+			case NEW_ID:
+			case OBJECT:
+				if (a->interface_name)
+					printf("\t&%s_interface,\n",
+					       a->interface_name);
+				else
+					printf("\tNULL,\n");
+				break;
+			default:
+				printf("\tNULL,\n");
+				break;
+			}
+		}
+	}
+}
+
+static void
+emit_messages(const char *name, struct wl_list *message_list,
+	      struct interface *interface, const char *suffix)
+{
+	struct message *m;
+	struct arg *a;
+
+	if (wl_list_empty(message_list))
+		return;
+
+	printf("static const struct wl_message "
+	       "%s_%s[] = {\n",
+	       interface->name, suffix);
+
+	wl_list_for_each(m, message_list, link) {
+		printf("\t{ \"%s\", \"", m->name);
+
+		if (m->since > 1)
+			printf("%d", m->since);
+
+		wl_list_for_each(a, &m->arg_list, link) {
+			if (is_nullable_type(a) && a->nullable)
+				printf("?");
+
+			switch (a->type) {
+			default:
+			case INT:
+				printf("i");
+				break;
+			case NEW_ID:
+				if (a->interface_name == NULL)
+					printf("su");
+				printf("n");
+				break;
+			case UNSIGNED:
+				printf("u");
+				break;
+			case FIXED:
+				printf("f");
+				break;
+			case STRING:
+				printf("s");
+				break;
+			case OBJECT:
+				printf("o");
+				break;
+			case ARRAY:
+				printf("a");
+				break;
+			case FD:
+				printf("h");
+				break;
+			}
+		}
+		printf("\", %s_types + %d },\n", name, m->type_index);
+	}
+
+	printf("};\n\n");
+}
+
+
+static void
+emit_code(struct protocol *protocol, enum visibility vis)
+{
+	const char *symbol_visibility;
+	struct interface *i, *next;
+	struct wl_array types;
+	char **p, *prev;
+
+	printf("/* Generated by %s %s */\n\n", PROGRAM_NAME, WAYLAND_VERSION);
+
+	if (protocol->copyright)
+		format_text_to_comment(protocol->copyright, true);
+
+	printf("#include <stdbool.h>\n"
+	       "#include <stdlib.h>\n"
+	       "#include <stdint.h>\n"
+	       "#include \"wayland-util.h\"\n\n");
+
+	/* When building a shared library symbols must be exported, otherwise
+	 * we want to have the symbols hidden. */
+	if (vis == PRIVATE) {
+		symbol_visibility = "WL_PRIVATE";
+		printf("#ifndef __has_attribute\n"
+		       "# define __has_attribute(x) 0  /* Compatibility with non-clang compilers. */\n"
+		       "#endif\n\n");
+
+		printf("#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)\n"
+		       "#define WL_PRIVATE __attribute__ ((visibility(\"hidden\")))\n"
+		       "#else\n"
+		       "#define WL_PRIVATE\n"
+		       "#endif\n\n");
+	} else {
+		symbol_visibility = "WL_EXPORT";
+	}
+
+	wl_array_init(&types);
+	wl_list_for_each(i, &protocol->interface_list, link) {
+		emit_types_forward_declarations(protocol, &i->request_list, &types);
+		emit_types_forward_declarations(protocol, &i->event_list, &types);
+	}
+
+	if (types.size > 0)
+		qsort(types.data, types.size / sizeof *p, sizeof *p, cmp_names);
+
+	prev = NULL;
+	wl_array_for_each(p, &types) {
+		if (prev && strcmp(*p, prev) == 0)
+			continue;
+		printf("extern const struct wl_interface %s_interface;\n", *p);
+		prev = *p;
+	}
+	wl_array_release(&types);
+	printf("\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);
+		emit_types(protocol, &i->event_list);
+	}
+	printf("};\n\n");
+
+	wl_list_for_each_safe(i, next, &protocol->interface_list, link) {
+
+		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"
+		       "\t\"%s\", %d,\n",
+		       symbol_visibility, i->name, i->name, i->version);
+
+		if (!wl_list_empty(&i->request_list))
+			printf("\t%d, %s_requests,\n",
+			       wl_list_length(&i->request_list), i->name);
+		else
+			printf("\t0, NULL,\n");
+
+		if (!wl_list_empty(&i->event_list))
+			printf("\t%d, %s_events,\n",
+			       wl_list_length(&i->event_list), i->name);
+		else
+			printf("\t0, NULL,\n");
+
+		printf("};\n\n");
+
+		/* we won't need it any further */
+		free_interface(i);
+	}
+}
+
+static void
+free_protocol(struct protocol *protocol)
+{
+	free(protocol->name);
+	free(protocol->uppercase_name);
+	free(protocol->copyright);
+	free_description(protocol->description);
+}
+
+int main(int argc, char *argv[])
+{
+	struct parse_context ctx;
+	struct protocol protocol;
+	FILE *input = stdin;
+	char *input_filename = NULL;
+	int len;
+	void *buf;
+	bool help = false;
+	bool core_headers = false;
+	bool version = false;
+	bool strict = false;
+	bool fail = false;
+	int opt;
+	enum {
+		CLIENT_HEADER,
+		SERVER_HEADER,
+		ENUM_HEADER,
+		PRIVATE_CODE,
+		PUBLIC_CODE,
+		CODE,
+	} mode;
+
+	static const struct option options[] = {
+		{ "help",              no_argument, NULL, 'h' },
+		{ "version",           no_argument, NULL, 'v' },
+		{ "include-core-only", no_argument, NULL, 'c' },
+		{ "strict",            no_argument, NULL, 's' },
+		{ 0,                   0,           NULL, 0 }
+	};
+
+	while (1) {
+		opt = getopt_long(argc, argv, "hvcs", options, NULL);
+
+		if (opt == -1)
+			break;
+
+		switch (opt) {
+		case 'h':
+			help = true;
+			break;
+		case 'v':
+			version = true;
+			break;
+		case 'c':
+			core_headers = true;
+			break;
+		case 's':
+			strict = true;
+			break;
+		default:
+			fail = true;
+			break;
+		}
+	}
+
+	argv += optind;
+	argc -= optind;
+
+	if (help)
+		usage(EXIT_SUCCESS);
+	else if (version)
+		scanner_version(EXIT_SUCCESS);
+	else if ((argc != 1 && argc != 3) || fail)
+		usage(EXIT_FAILURE);
+	else if (strcmp(argv[0], "help") == 0)
+		usage(EXIT_SUCCESS);
+	else if (strcmp(argv[0], "client-header") == 0)
+		mode = CLIENT_HEADER;
+	else if (strcmp(argv[0], "server-header") == 0)
+		mode = SERVER_HEADER;
+	else if (strcmp(argv[0], "enum-header") == 0)
+		mode = ENUM_HEADER;
+	else if (strcmp(argv[0], "private-code") == 0)
+		mode = PRIVATE_CODE;
+	else if (strcmp(argv[0], "public-code") == 0)
+		mode = PUBLIC_CODE;
+	else if (strcmp(argv[0], "code") == 0)
+		mode = CODE;
+	else
+		usage(EXIT_FAILURE);
+
+	if (argc == 3) {
+		input_filename = argv[1];
+		input = fopen(input_filename, "r");
+		if (input == NULL) {
+			fprintf(stderr, "Could not open input file: %s\n",
+				strerror(errno));
+			exit(EXIT_FAILURE);
+		}
+		if (freopen(argv[2], "w", stdout) == NULL) {
+			fprintf(stderr, "Could not open output file: %s\n",
+				strerror(errno));
+			fclose(input);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	/* initialize protocol structure */
+	memset(&protocol, 0, sizeof protocol);
+	wl_list_init(&protocol.interface_list);
+	protocol.core_headers = core_headers;
+
+	/* initialize context */
+	memset(&ctx, 0, sizeof ctx);
+	ctx.protocol = &protocol;
+	if (input == stdin)
+		ctx.loc.filename = "<stdin>";
+	else
+		ctx.loc.filename = input_filename;
+
+	if (!is_dtd_valid(input, ctx.loc.filename)) {
+		fprintf(stderr,
+		"*******************************************************\n"
+		"*                                                     *\n"
+		"* WARNING: XML failed validation against built-in DTD *\n"
+		"*                                                     *\n"
+		"*******************************************************\n");
+		if (strict) {
+			fclose(input);
+			exit(EXIT_FAILURE);
+		}
+	}
+
+	/* create XML parser */
+	ctx.parser = XML_ParserCreate(NULL);
+	XML_SetUserData(ctx.parser, &ctx);
+	if (ctx.parser == NULL) {
+		fprintf(stderr, "failed to create parser\n");
+		fclose(input);
+		exit(EXIT_FAILURE);
+	}
+
+	XML_SetElementHandler(ctx.parser, start_element, end_element);
+	XML_SetCharacterDataHandler(ctx.parser, character_data);
+
+	do {
+		buf = XML_GetBuffer(ctx.parser, XML_BUFFER_SIZE);
+		len = fread(buf, 1, XML_BUFFER_SIZE, input);
+		if (len < 0) {
+			fprintf(stderr, "fread: %s\n", strerror(errno));
+			fclose(input);
+			exit(EXIT_FAILURE);
+		}
+		if (XML_ParseBuffer(ctx.parser, len, len == 0) == 0) {
+			fprintf(stderr,
+				"Error parsing XML at line %ld col %ld: %s\n",
+				XML_GetCurrentLineNumber(ctx.parser),
+				XML_GetCurrentColumnNumber(ctx.parser),
+				XML_ErrorString(XML_GetErrorCode(ctx.parser)));
+			fclose(input);
+			exit(EXIT_FAILURE);
+		}
+	} while (len > 0);
+
+	XML_ParserFree(ctx.parser);
+
+	switch (mode) {
+		case CLIENT_HEADER:
+			emit_header(&protocol, CLIENT);
+			break;
+		case SERVER_HEADER:
+			emit_header(&protocol, SERVER);
+			break;
+		case ENUM_HEADER:
+			emit_enum_header(&protocol);
+			break;
+		case PRIVATE_CODE:
+			emit_code(&protocol, PRIVATE);
+			break;
+		case CODE:
+			fprintf(stderr,
+				"Using \"code\" is deprecated - use "
+				"private-code or public-code.\n"
+				"See the help page for details.\n");
+			/* fallthrough */
+		case PUBLIC_CODE:
+			emit_code(&protocol, PUBLIC);
+			break;
+	}
+
+	free_protocol(&protocol);
+	fclose(input);
+
+	return 0;
+}
diff --git a/subprojects/wayland/src/wayland-client-core.h b/subprojects/wayland/src/wayland-client-core.h
new file mode 100644
index 0000000000000000000000000000000000000000..a4ca4e5de1f18f15ceb66d80b7d48f25c7ce989c
--- /dev/null
+++ b/subprojects/wayland/src/wayland-client-core.h
@@ -0,0 +1,309 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_CLIENT_CORE_H
+#define WAYLAND_CLIENT_CORE_H
+
+#include <stdint.h>
+#include "wayland-util.h"
+#include "wayland-version.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/** \class wl_proxy
+ *
+ * \brief Represents a protocol object on the client side.
+ *
+ * A wl_proxy acts as a client side proxy to an object existing in the
+ * compositor. The proxy is responsible for converting requests made by the
+ * clients with \ref wl_proxy_marshal() into Wayland's wire format. Events
+ * coming from the compositor are also handled by the proxy, which will in
+ * turn call the handler set with \ref wl_proxy_add_listener().
+ *
+ * \note With the exception of function \ref wl_proxy_set_queue(), functions
+ * accessing a wl_proxy are not normally used by client code. Clients
+ * should normally use the higher level interface generated by the scanner to
+ * interact with compositor objects.
+ *
+ */
+struct wl_proxy;
+
+/** \class wl_display
+ *
+ * \brief Represents a connection to the compositor and acts as a proxy to
+ * the wl_display singleton object.
+ *
+ * A wl_display object represents a client connection to a Wayland
+ * compositor. It is created with either \ref wl_display_connect() or
+ * \ref wl_display_connect_to_fd(). A connection is terminated using
+ * \ref wl_display_disconnect().
+ *
+ * A wl_display is also used as the \ref wl_proxy for the wl_display
+ * singleton object on the compositor side.
+ *
+ * A wl_display object handles all the data sent from and to the
+ * compositor. When a \ref wl_proxy marshals a request, it will write its wire
+ * representation to the display's write buffer. The data is sent to the
+ * compositor when the client calls \ref wl_display_flush().
+ *
+ * Incoming data is handled in two steps: queueing and dispatching. In the
+ * queue step, the data coming from the display fd is interpreted and
+ * added to a queue. On the dispatch step, the handler for the incoming
+ * event set by the client on the corresponding \ref wl_proxy is called.
+ *
+ * A wl_display has at least one event queue, called the <em>default
+ * queue</em>. Clients can create additional event queues with \ref
+ * wl_display_create_queue() and assign \ref wl_proxy's to it. Events
+ * occurring in a particular proxy are always queued in its assigned queue.
+ * A client can ensure that a certain assumption, such as holding a lock
+ * or running from a given thread, is true when a proxy event handler is
+ * called by assigning that proxy to an event queue and making sure that
+ * this queue is only dispatched when the assumption holds.
+ *
+ * The default queue is dispatched by calling \ref wl_display_dispatch().
+ * This will dispatch any events queued on the default queue and attempt
+ * to read from the display fd if it's empty. Events read are then queued
+ * on the appropriate queues according to the proxy assignment.
+ *
+ * A user created queue is dispatched with \ref wl_display_dispatch_queue().
+ * This function behaves exactly the same as wl_display_dispatch()
+ * but it dispatches given queue instead of the default queue.
+ *
+ * A real world example of event queue usage is Mesa's implementation of
+ * eglSwapBuffers() for the Wayland platform. This function might need
+ * to block until a frame callback is received, but dispatching the default
+ * queue could cause an event handler on the client to start drawing
+ * again. This problem is solved using another event queue, so that only
+ * the events handled by the EGL code are dispatched during the block.
+ *
+ * This creates a problem where a thread dispatches a non-default
+ * queue, reading all the data from the display fd. If the application
+ * would call \em poll(2) after that it would block, even though there
+ * might be events queued on the default queue. Those events should be
+ * dispatched with \ref wl_display_dispatch_pending() or \ref
+ * wl_display_dispatch_queue_pending() before flushing and blocking.
+ */
+struct wl_display;
+
+/** \class wl_event_queue
+ *
+ * \brief A queue for \ref wl_proxy object events.
+ *
+ * Event queues allows the events on a display to be handled in a thread-safe
+ * manner. See \ref wl_display for details.
+ *
+ */
+struct wl_event_queue;
+
+/** Destroy proxy after marshalling
+ * \relates wl_proxy
+ */
+#define WL_MARSHAL_FLAG_DESTROY (1 << 0)
+
+void
+wl_event_queue_destroy(struct wl_event_queue *queue);
+
+struct wl_proxy *
+wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode,
+		       const struct wl_interface *interface,
+		       uint32_t version,
+		       uint32_t flags, ...);
+
+struct wl_proxy *
+wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
+			     const struct wl_interface *interface,
+			     uint32_t version,
+			     uint32_t flags,
+			     union wl_argument *args);
+
+void
+wl_proxy_marshal(struct wl_proxy *p, uint32_t opcode, ...);
+
+void
+wl_proxy_marshal_array(struct wl_proxy *p, uint32_t opcode,
+		       union wl_argument *args);
+
+struct wl_proxy *
+wl_proxy_create(struct wl_proxy *factory,
+		const struct wl_interface *interface);
+
+void *
+wl_proxy_create_wrapper(void *proxy);
+
+void
+wl_proxy_wrapper_destroy(void *proxy_wrapper);
+
+struct wl_proxy *
+wl_proxy_marshal_constructor(struct wl_proxy *proxy,
+			     uint32_t opcode,
+			     const struct wl_interface *interface,
+			     ...);
+
+struct wl_proxy *
+wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy,
+				       uint32_t opcode,
+				       const struct wl_interface *interface,
+				       uint32_t version,
+				       ...);
+
+struct wl_proxy *
+wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,
+				   uint32_t opcode, union wl_argument *args,
+				   const struct wl_interface *interface);
+
+struct wl_proxy *
+wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
+					     uint32_t opcode,
+					     union wl_argument *args,
+					     const struct wl_interface *interface,
+					     uint32_t version);
+
+void
+wl_proxy_destroy(struct wl_proxy *proxy);
+
+int
+wl_proxy_add_listener(struct wl_proxy *proxy,
+		      void (**implementation)(void), void *data);
+
+const void *
+wl_proxy_get_listener(struct wl_proxy *proxy);
+
+int
+wl_proxy_add_dispatcher(struct wl_proxy *proxy,
+			wl_dispatcher_func_t dispatcher_func,
+			const void * dispatcher_data, void *data);
+
+void
+wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data);
+
+void *
+wl_proxy_get_user_data(struct wl_proxy *proxy);
+
+uint32_t
+wl_proxy_get_version(struct wl_proxy *proxy);
+
+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);
+
+struct wl_display *
+wl_proxy_get_display(struct wl_proxy *proxy);
+
+void
+wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue);
+
+struct wl_event_queue *
+wl_proxy_get_queue(const struct wl_proxy *proxy);
+
+const char *
+wl_event_queue_get_name(const struct wl_event_queue *queue);
+
+struct wl_display *
+wl_display_connect(const char *name);
+
+struct wl_display *
+wl_display_connect_to_fd(int fd);
+
+void
+wl_display_disconnect(struct wl_display *display);
+
+int
+wl_display_get_fd(struct wl_display *display);
+
+int
+wl_display_dispatch(struct wl_display *display);
+
+int
+wl_display_dispatch_queue(struct wl_display *display,
+			  struct wl_event_queue *queue);
+
+int
+wl_display_dispatch_queue_pending(struct wl_display *display,
+				  struct wl_event_queue *queue);
+
+int
+wl_display_dispatch_pending(struct wl_display *display);
+
+int
+wl_display_get_error(struct wl_display *display);
+
+uint32_t
+wl_display_get_protocol_error(struct wl_display *display,
+			      const struct wl_interface **interface,
+			      uint32_t *id);
+
+int
+wl_display_flush(struct wl_display *display);
+
+int
+wl_display_roundtrip_queue(struct wl_display *display,
+			   struct wl_event_queue *queue);
+
+int
+wl_display_roundtrip(struct wl_display *display);
+
+struct wl_event_queue *
+wl_display_create_queue(struct wl_display *display);
+
+struct wl_event_queue *
+wl_display_create_queue_with_name(struct wl_display *display,
+				  const char *name);
+
+int
+wl_display_prepare_read_queue(struct wl_display *display,
+			      struct wl_event_queue *queue);
+
+int
+wl_display_prepare_read(struct wl_display *display);
+
+void
+wl_display_cancel_read(struct wl_display *display);
+
+int
+wl_display_read_events(struct wl_display *display);
+
+void
+wl_log_set_handler_client(wl_log_func_t handler);
+
+void
+wl_display_set_max_buffer_size(struct wl_display *display,
+                               size_t max_buffer_size);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/src/wayland-client.c b/subprojects/wayland/src/wayland-client.c
new file mode 100644
index 0000000000000000000000000000000000000000..9cf279394da09f72c1beea6dfc9442776595f203
--- /dev/null
+++ b/subprojects/wayland/src/wayland-client.c
@@ -0,0 +1,2599 @@
+/*
+ * Copyright © 2008-2012 Kristian Høgsberg
+ * Copyright © 2010-2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <ctype.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <poll.h>
+#include <pthread.h>
+
+#include "wayland-util.h"
+#include "wayland-os.h"
+#include "wayland-client.h"
+#include "wayland-private.h"
+
+/** \cond */
+
+enum wl_proxy_flag {
+	WL_PROXY_FLAG_ID_DELETED = (1 << 0),
+	WL_PROXY_FLAG_DESTROYED = (1 << 1),
+	WL_PROXY_FLAG_WRAPPER = (1 << 2),
+};
+
+struct wl_zombie {
+	int event_count;
+	int *fd_count;
+};
+
+struct wl_proxy {
+	struct wl_object object;
+	struct wl_display *display;
+	struct wl_event_queue *queue;
+	uint32_t flags;
+	int refcount;
+	void *user_data;
+	wl_dispatcher_func_t dispatcher;
+	uint32_t version;
+	const char * const *tag;
+	struct wl_list queue_link; /**< in struct wl_event_queue::proxy_list */
+};
+
+struct wl_event_queue {
+	struct wl_list event_list;
+	struct wl_list proxy_list; /**< struct wl_proxy::queue_link */
+	struct wl_display *display;
+	char *name;
+};
+
+struct wl_display {
+	struct wl_proxy proxy;
+	struct wl_connection *connection;
+
+	/* errno of the last wl_display error */
+	int last_error;
+
+	/* When display gets an error event from some object, it stores
+	 * information about it here, so that client can get this
+	 * information afterwards */
+	struct {
+		/* Code of the error. It can be compared to
+		 * the interface's errors enumeration. */
+		uint32_t code;
+		/* interface (protocol) in which the error occurred */
+		const struct wl_interface *interface;
+		/* id of the proxy that caused the error. There's no warranty
+		 * that the proxy is still valid. It's up to client how it will
+		 * use it */
+		uint32_t id;
+	} protocol_error;
+	int fd;
+	struct wl_map objects;
+	struct wl_event_queue display_queue;
+	struct wl_event_queue default_queue;
+	pthread_mutex_t mutex;
+
+	int reader_count;
+	uint32_t read_serial;
+	pthread_cond_t reader_cond;
+};
+
+/** \endcond */
+
+static int debug_client = 0;
+
+/**
+ * This helper function wakes up all threads that are
+ * waiting for display->reader_cond (i. e. when reading is done,
+ * canceled, or an error occurred)
+ *
+ * NOTE: must be called with display->mutex locked
+ */
+static void
+display_wakeup_threads(struct wl_display *display)
+{
+	/* Thread can get sleeping only in read_events(). If we're
+	 * waking it up, it means that the read completed or was
+	 * canceled, so we must increase the read_serial.
+	 * This prevents from indefinite sleeping in read_events().
+	 */
+	++display->read_serial;
+
+	pthread_cond_broadcast(&display->reader_cond);
+}
+
+/**
+ * This function is called for local errors (no memory, server hung up)
+ *
+ * \param display
+ * \param error    error value (EINVAL, EFAULT, ...)
+ *
+ * \note this function is called with display mutex locked
+ */
+static void
+display_fatal_error(struct wl_display *display, int error)
+{
+	if (display->last_error)
+		return;
+
+	if (!error)
+		error = EFAULT;
+
+	display->last_error = error;
+
+	display_wakeup_threads(display);
+}
+
+/**
+ * This function is called for error events
+ * and indicates that in some object an error occurred.
+ * The difference between this function and display_fatal_error()
+ * is that this one handles errors that will come by wire,
+ * whereas display_fatal_error() is called for local errors.
+ *
+ * \param display
+ * \param code    error code
+ * \param id      id of the object that generated the error
+ * \param intf    protocol interface
+ */
+static void
+display_protocol_error(struct wl_display *display, uint32_t code,
+		       uint32_t id, const struct wl_interface *intf)
+{
+	int err;
+
+	if (display->last_error)
+		return;
+
+	/* set correct errno */
+	if (intf && wl_interface_equal(intf, &wl_display_interface)) {
+		switch (code) {
+		case WL_DISPLAY_ERROR_INVALID_OBJECT:
+		case WL_DISPLAY_ERROR_INVALID_METHOD:
+			err = EINVAL;
+			break;
+		case WL_DISPLAY_ERROR_NO_MEMORY:
+			err = ENOMEM;
+			break;
+		case WL_DISPLAY_ERROR_IMPLEMENTATION:
+			err = EPROTO;
+			break;
+		default:
+			err = EFAULT;
+		}
+	} else {
+		err = EPROTO;
+	}
+
+	pthread_mutex_lock(&display->mutex);
+
+	display->last_error = err;
+
+	display->protocol_error.code = code;
+	display->protocol_error.id = id;
+	display->protocol_error.interface = intf;
+
+	/*
+	 * here it is not necessary to wake up threads like in
+	 * display_fatal_error, because this function is called from
+	 * an event handler and that means that read_events() is done
+	 * and woke up all threads. Since wl_display_prepare_read()
+	 * fails when there are events in the queue, no threads
+	 * can sleep in read_events() during dispatching
+	 * (and therefore during calling this function), so this is safe.
+	 */
+
+	pthread_mutex_unlock(&display->mutex);
+}
+
+static void
+wl_event_queue_init(struct wl_event_queue *queue,
+		    struct wl_display *display,
+		    const char *name)
+{
+	wl_list_init(&queue->event_list);
+	wl_list_init(&queue->proxy_list);
+	queue->display = display;
+	if (name)
+		queue->name = strdup(name);
+}
+
+static void
+wl_proxy_unref(struct wl_proxy *proxy)
+{
+	assert(proxy->refcount > 0);
+	if (--proxy->refcount > 0)
+		return;
+
+	/* If we get here, the client must have explicitly requested
+	 * deletion. */
+	assert(proxy->flags & WL_PROXY_FLAG_DESTROYED);
+	free(proxy);
+}
+
+static void
+validate_closure_objects(struct wl_closure *closure)
+{
+	const char *signature;
+	struct argument_details arg;
+	int i, count;
+	struct wl_proxy *proxy;
+
+	signature = closure->message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		switch (arg.type) {
+		case WL_ARG_NEW_ID:
+		case WL_ARG_OBJECT:
+			proxy = (struct wl_proxy *) closure->args[i].o;
+			if (proxy && proxy->flags & WL_PROXY_FLAG_DESTROYED)
+				closure->args[i].o = NULL;
+			break;
+		default:
+			break;
+		}
+	}
+}
+
+/* Destroys a closure which was demarshaled for dispatch; unrefs all the
+ * proxies in its arguments, as well as its own proxy, and destroys the
+ * closure itself. */
+static void
+destroy_queued_closure(struct wl_closure *closure)
+{
+	const char *signature;
+	struct argument_details arg;
+	struct wl_proxy *proxy;
+	int i, count;
+
+	signature = closure->message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		switch (arg.type) {
+		case WL_ARG_NEW_ID:
+		case WL_ARG_OBJECT:
+			proxy = (struct wl_proxy *) closure->args[i].o;
+			if (proxy)
+				wl_proxy_unref(proxy);
+			break;
+		default:
+			break;
+		}
+	}
+
+	wl_proxy_unref(closure->proxy);
+	wl_closure_destroy(closure);
+}
+
+static void
+wl_event_queue_release(struct wl_event_queue *queue)
+{
+	struct wl_closure *closure;
+
+	if (!wl_list_empty(&queue->proxy_list)) {
+		struct wl_proxy *proxy, *tmp;
+
+		if (queue != &queue->display->default_queue) {
+			if (queue->name) {
+				wl_log("warning: queue \"%s\" "
+				       "%p destroyed while proxies "
+				       "still attached:\n", queue->name, queue);
+			} else {
+				wl_log("warning: queue "
+				       "%p destroyed while proxies "
+				       "still attached:\n", queue);
+			}
+		}
+
+		wl_list_for_each_safe(proxy, tmp, &queue->proxy_list,
+				      queue_link) {
+			if (queue != &queue->display->default_queue) {
+				wl_log("  %s#%u still attached\n",
+				       proxy->object.interface->name,
+				       proxy->object.id);
+			}
+			proxy->queue = NULL;
+			wl_list_remove(&proxy->queue_link);
+			wl_list_init(&proxy->queue_link);
+		}
+	}
+
+	while (!wl_list_empty(&queue->event_list)) {
+		closure = wl_container_of(queue->event_list.next,
+					  closure, link);
+		wl_list_remove(&closure->link);
+		destroy_queued_closure(closure);
+	}
+}
+
+/** Destroy an event queue
+ *
+ * \param queue The event queue to be destroyed
+ *
+ * Destroy the given event queue. Any pending event on that queue is
+ * discarded.
+ *
+ * The \ref wl_display object used to create the queue should not be
+ * destroyed until all event queues created with it are destroyed with
+ * this function.
+ *
+ * \memberof wl_event_queue
+ */
+WL_EXPORT void
+wl_event_queue_destroy(struct wl_event_queue *queue)
+{
+	struct wl_display *display = queue->display;
+
+	pthread_mutex_lock(&display->mutex);
+	wl_event_queue_release(queue);
+	free(queue->name);
+	free(queue);
+	pthread_mutex_unlock(&display->mutex);
+}
+
+/** Create a new event queue for this display
+ *
+ * \param display The display context object
+ * \return A new event queue associated with this display or NULL on
+ * failure.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_event_queue *
+wl_display_create_queue(struct wl_display *display)
+{
+	struct wl_event_queue *queue;
+
+	queue = zalloc(sizeof *queue);
+	if (queue == NULL)
+		return NULL;
+
+	wl_event_queue_init(queue, display, NULL);
+
+	return queue;
+}
+
+/** Create a new event queue for this display and give it a name
+ *
+ * \param display The display context object
+ * \param name A human readable queue name
+ * \return A new event queue associated with this display or NULL on
+ * failure.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_event_queue *
+wl_display_create_queue_with_name(struct wl_display *display, const char *name)
+{
+	struct wl_event_queue *queue;
+
+	queue = zalloc(sizeof *queue);
+	if (queue == NULL)
+		return NULL;
+
+	wl_event_queue_init(queue, display, name);
+
+	return queue;
+}
+
+static int
+message_count_fds(const char *signature)
+{
+	unsigned int count, i, fds = 0;
+	struct argument_details arg;
+
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (arg.type == WL_ARG_FD)
+			fds++;
+	}
+
+	return fds;
+}
+
+static struct wl_zombie *
+prepare_zombie(struct wl_proxy *proxy)
+{
+	const struct wl_interface *interface = proxy->object.interface;
+	const struct wl_message *message;
+	int i, count;
+	struct wl_zombie *zombie = NULL;
+
+	/* If we hit an event with an FD, ensure we have a zombie object and
+	 * fill the fd_count slot for that event with the number of FDs for
+	 * that event. Interfaces with no events containing FDs will not have
+	 * zombie objects created. */
+	for (i = 0; i < interface->event_count; i++) {
+		message = &interface->events[i];
+		count = message_count_fds(message->signature);
+
+		if (!count)
+			continue;
+
+		if (!zombie) {
+			zombie = zalloc(sizeof(*zombie) +
+				        (interface->event_count * sizeof(int)));
+			if (!zombie)
+				return NULL;
+
+			zombie->event_count = interface->event_count;
+			zombie->fd_count = (int *) &zombie[1];
+		}
+
+		zombie->fd_count[i] = count;
+	}
+
+	return zombie;
+}
+
+static enum wl_iterator_result
+free_zombies(void *element, void *data, uint32_t flags)
+{
+	if (flags & WL_MAP_ENTRY_ZOMBIE)
+		free(element);
+
+	return WL_ITERATOR_CONTINUE;
+}
+
+static struct wl_proxy *
+proxy_create(struct wl_proxy *factory, const struct wl_interface *interface,
+	     uint32_t version)
+{
+	struct wl_proxy *proxy;
+	struct wl_display *display = factory->display;
+
+	proxy = zalloc(sizeof *proxy);
+	if (proxy == NULL)
+		return NULL;
+
+	proxy->object.interface = interface;
+	proxy->display = display;
+	proxy->queue = factory->queue;
+	proxy->refcount = 1;
+	proxy->version = version;
+
+	proxy->object.id = wl_map_insert_new(&display->objects, 0, proxy);
+	if (proxy->object.id == 0) {
+		free(proxy);
+		return NULL;
+	}
+
+	wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
+
+	return proxy;
+}
+
+/** Create a proxy object with a given interface
+ *
+ * \param factory Factory proxy object
+ * \param interface Interface the proxy object should use
+ * \return A newly allocated proxy object or NULL on failure
+ *
+ * This function creates a new proxy object with the supplied interface. The
+ * proxy object will have an id assigned from the client id space. The id
+ * should be created on the compositor side by sending an appropriate request
+ * with \ref wl_proxy_marshal().
+ *
+ * The proxy will inherit the display and event queue of the factory object.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \sa wl_display, wl_event_queue, wl_proxy_marshal()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_create(struct wl_proxy *factory, const struct wl_interface *interface)
+{
+	struct wl_display *display = factory->display;
+	struct wl_proxy *proxy;
+
+	pthread_mutex_lock(&display->mutex);
+	proxy = proxy_create(factory, interface, factory->version);
+	pthread_mutex_unlock(&display->mutex);
+
+	return proxy;
+}
+
+/* The caller should hold the display lock */
+static struct wl_proxy *
+wl_proxy_create_for_id(struct wl_proxy *factory,
+		       uint32_t id, const struct wl_interface *interface)
+{
+	struct wl_proxy *proxy;
+	struct wl_display *display = factory->display;
+
+	proxy = zalloc(sizeof *proxy);
+	if (proxy == NULL)
+		return NULL;
+
+	proxy->object.interface = interface;
+	proxy->object.id = id;
+	proxy->display = display;
+	proxy->queue = factory->queue;
+	proxy->refcount = 1;
+	proxy->version = factory->version;
+
+	if (wl_map_insert_at(&display->objects, 0, id, proxy) == -1) {
+		free(proxy);
+		return NULL;
+	}
+
+	wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
+
+	return proxy;
+}
+
+static void
+proxy_destroy(struct wl_proxy *proxy)
+{
+	if (proxy->flags & WL_PROXY_FLAG_ID_DELETED) {
+		wl_map_remove(&proxy->display->objects, proxy->object.id);
+	} else if (proxy->object.id < WL_SERVER_ID_START) {
+		struct wl_zombie *zombie = prepare_zombie(proxy);
+
+		/* The map now contains the zombie entry, until the delete_id
+		 * event arrives. */
+		wl_map_insert_at(&proxy->display->objects,
+				 WL_MAP_ENTRY_ZOMBIE,
+				 proxy->object.id,
+				 zombie);
+	} else {
+		wl_map_insert_at(&proxy->display->objects, 0,
+				 proxy->object.id, NULL);
+	}
+
+	proxy->flags |= WL_PROXY_FLAG_DESTROYED;
+
+	proxy->queue = NULL;
+	wl_list_remove(&proxy->queue_link);
+	wl_list_init(&proxy->queue_link);
+
+	wl_proxy_unref(proxy);
+}
+
+static void
+wl_proxy_destroy_caller_locks(struct wl_proxy *proxy)
+{
+	if (proxy->flags & WL_PROXY_FLAG_WRAPPER)
+		wl_abort("Tried to destroy wrapper with wl_proxy_destroy()\n");
+
+	proxy_destroy(proxy);
+}
+
+/** Destroy a proxy object
+ *
+ * \param proxy The proxy to be destroyed
+ *
+ * \c proxy must not be a proxy wrapper.
+ *
+ * \note This function will abort in response to egregious
+ * errors, and will do so with the display lock held. This means
+ * SIGABRT handlers must not perform any actions that would
+ * attempt to take that lock, or a deadlock would occur.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_destroy(struct wl_proxy *proxy)
+{
+	struct wl_display *display = proxy->display;
+
+	pthread_mutex_lock(&display->mutex);
+
+	wl_proxy_destroy_caller_locks(proxy);
+
+	pthread_mutex_unlock(&display->mutex);
+}
+
+/** Set a proxy's listener
+ *
+ * \param proxy The proxy object
+ * \param implementation The listener to be added to proxy
+ * \param data User data to be associated with the proxy
+ * \return 0 on success or -1 on failure
+ *
+ * Set proxy's listener to \c implementation and its user data to
+ * \c data. If a listener has already been set, this function
+ * fails and nothing is changed.
+ *
+ * \c implementation is a vector of function pointers. For an opcode
+ * \c n, \c implementation[n] should point to the handler of \c n for
+ * the given object.
+ *
+ * \c proxy must not be a proxy wrapper.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT int
+wl_proxy_add_listener(struct wl_proxy *proxy,
+		      void (**implementation)(void), void *data)
+{
+	if (proxy->flags & WL_PROXY_FLAG_WRAPPER)
+		wl_abort("Proxy %p is a wrapper\n", proxy);
+
+	if (proxy->object.implementation || proxy->dispatcher) {
+		wl_log("proxy %p already has listener\n", proxy);
+		return -1;
+	}
+
+	proxy->object.implementation = implementation;
+	proxy->user_data = data;
+
+	return 0;
+}
+
+/** Get a proxy's listener
+ *
+ * \param proxy The proxy object
+ * \return The address of the proxy's listener or NULL if no listener is set
+ *
+ * Gets the address to the proxy's listener; which is the listener set with
+ * \ref wl_proxy_add_listener.
+ *
+ * This function is useful in clients with multiple listeners on the same
+ * interface to allow the identification of which code to execute.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT const void *
+wl_proxy_get_listener(struct wl_proxy *proxy)
+{
+	return proxy->object.implementation;
+}
+
+/** Set a proxy's listener (with dispatcher)
+ *
+ * \param proxy The proxy object
+ * \param dispatcher The dispatcher to be used for this proxy
+ * \param implementation The dispatcher-specific listener implementation
+ * \param data User data to be associated with the proxy
+ * \return 0 on success or -1 on failure
+ *
+ * Set proxy's listener to use \c dispatcher_func as its dispatcher and \c
+ * dispatcher_data as its dispatcher-specific implementation and its user data
+ * to \c data. If a listener has already been set, this function
+ * fails and nothing is changed.
+ *
+ * The exact details of dispatcher_data depend on the dispatcher used.  This
+ * function is intended to be used by language bindings, not user code.
+ *
+ * \c proxy must not be a proxy wrapper.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT int
+wl_proxy_add_dispatcher(struct wl_proxy *proxy,
+			wl_dispatcher_func_t dispatcher,
+			const void *implementation, void *data)
+{
+	if (proxy->flags & WL_PROXY_FLAG_WRAPPER)
+		wl_abort("Proxy %p is a wrapper\n", proxy);
+
+	if (proxy->object.implementation || proxy->dispatcher) {
+		wl_log("proxy %p already has listener\n", proxy);
+		return -1;
+	}
+
+	proxy->object.implementation = implementation;
+	proxy->dispatcher = dispatcher;
+	proxy->user_data = data;
+
+	return 0;
+}
+
+static struct wl_proxy *
+create_outgoing_proxy(struct wl_proxy *proxy, const struct wl_message *message,
+		      union wl_argument *args,
+		      const struct wl_interface *interface, uint32_t version)
+{
+	int i, count;
+	const char *signature;
+	struct argument_details arg;
+	struct wl_proxy *new_proxy = NULL;
+
+	signature = message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (arg.type != WL_ARG_NEW_ID)
+			continue;
+
+		new_proxy = proxy_create(proxy, interface, version);
+		if (new_proxy == NULL)
+			return NULL;
+
+		args[i].o = &new_proxy->object;
+	}
+
+	return new_proxy;
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param args Extra arguments for the given request
+ * \param interface The interface to use for the new proxy
+ *
+ * This function translates a request given an opcode, an interface and a
+ * wl_argument array to the wire format and writes it to the connection
+ * buffer.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server.  The new wl_proxy will be returned
+ * on success or NULL on error with errno set accordingly.  The newly
+ * created proxy will inherit their version from their parent.
+ *
+ * \note This is intended to be used by language bindings and not in
+ * non-generated code.
+ *
+ * \sa wl_proxy_marshal()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_array_constructor(struct wl_proxy *proxy,
+				   uint32_t opcode, union wl_argument *args,
+				   const struct wl_interface *interface)
+{
+	return wl_proxy_marshal_array_constructor_versioned(proxy, opcode,
+							    args, interface,
+							    proxy->version);
+}
+
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param args Extra arguments for the given request
+ * \param interface The interface to use for the new proxy
+ * \param version The protocol object version for the new proxy
+ *
+ * Translates the request given by opcode and the extra arguments into the
+ * wire format and write it to the connection buffer.  This version takes an
+ * array of the union type wl_argument.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server.  The new wl_proxy will be returned
+ * on success or NULL on error with errno set accordingly.  The newly
+ * created proxy will have the version specified.
+ *
+ * \note This is intended to be used by language bindings and not in
+ * non-generated code.
+ *
+ * \sa wl_proxy_marshal()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_array_constructor_versioned(struct wl_proxy *proxy,
+					     uint32_t opcode,
+					     union wl_argument *args,
+					     const struct wl_interface *interface,
+					     uint32_t version)
+{
+	return wl_proxy_marshal_array_flags(proxy, opcode, interface, version, 0, args);
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param interface The interface to use for the new proxy
+ * \param version The protocol object version of the new proxy
+ * \param flags Flags that modify marshalling behaviour
+ * \param ... Extra arguments for the given request
+ * \return A new wl_proxy for the new_id argument or NULL on error
+ *
+ * Translates the request given by opcode and the extra arguments into the
+ * wire format and write it to the connection buffer.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server.  The new wl_proxy will be returned
+ * on success or NULL on error with errno set accordingly.  The newly
+ * created proxy will have the version specified.
+ *
+ * The flag WL_MARSHAL_FLAG_DESTROY may be passed to ensure the proxy
+ * is destroyed atomically with the marshalling in order to prevent
+ * races that can occur if the display lock is dropped between the
+ * marshal and destroy operations.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_flags(struct wl_proxy *proxy, uint32_t opcode,
+		       const struct wl_interface *interface, uint32_t version,
+		       uint32_t flags, ...)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	va_list ap;
+
+	va_start(ap, flags);
+	wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
+				 args, WL_CLOSURE_MAX_ARGS, ap);
+	va_end(ap);
+
+	return wl_proxy_marshal_array_flags(proxy, opcode, interface, version, flags, args);
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param interface The interface to use for the new proxy
+ * \param version The protocol object version for the new proxy
+ * \param flags Flags that modify marshalling behaviour
+ * \param args Extra arguments for the given request
+ *
+ * Translates the request given by opcode and the extra arguments into the
+ * wire format and write it to the connection buffer.  This version takes an
+ * array of the union type wl_argument.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server.  The new wl_proxy will be returned
+ * on success or NULL on error with errno set accordingly.  The newly
+ * created proxy will have the version specified.
+ *
+ * The flag WL_MARSHAL_FLAG_DESTROY may be passed to ensure the proxy
+ * is destroyed atomically with the marshalling in order to prevent
+ * races that can occur if the display lock is dropped between the
+ * marshal and destroy operations.
+ *
+ * \note This is intended to be used by language bindings and not in
+ * non-generated code.
+ *
+ * \sa wl_proxy_marshal_flags()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_array_flags(struct wl_proxy *proxy, uint32_t opcode,
+			     const struct wl_interface *interface, uint32_t version,
+			     uint32_t flags, union wl_argument *args)
+{
+	struct wl_closure *closure;
+	struct wl_proxy *new_proxy = NULL;
+	const struct wl_message *message;
+	struct wl_display *disp = proxy->display;
+
+	pthread_mutex_lock(&disp->mutex);
+
+	message = &proxy->object.interface->methods[opcode];
+	if (interface) {
+		new_proxy = create_outgoing_proxy(proxy, message,
+						  args, interface,
+						  version);
+		if (new_proxy == NULL)
+			goto err_unlock;
+	}
+
+	if (proxy->display->last_error) {
+		goto err_unlock;
+	}
+
+	closure = wl_closure_marshal(&proxy->object, opcode, args, message);
+	if (closure == NULL) {
+		wl_log("Error marshalling request: %s\n", strerror(errno));
+		display_fatal_error(proxy->display, errno);
+		goto err_unlock;
+	}
+
+	if (debug_client) {
+		struct wl_event_queue *queue;
+
+		queue = wl_proxy_get_queue(proxy);
+		wl_closure_print(closure, &proxy->object, true, false, NULL,
+				 wl_event_queue_get_name(queue));
+	}
+
+	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);
+
+ err_unlock:
+	if (flags & WL_MARSHAL_FLAG_DESTROY)
+		wl_proxy_destroy_caller_locks(proxy);
+
+	pthread_mutex_unlock(&disp->mutex);
+
+	return new_proxy;
+}
+
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param ... Extra arguments for the given request
+ *
+ * This function is similar to wl_proxy_marshal_constructor(), except
+ * it doesn't create proxies for new-id arguments.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \sa wl_proxy_create()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_marshal(struct wl_proxy *proxy, uint32_t opcode, ...)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	va_list ap;
+
+	va_start(ap, opcode);
+	wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
+				 args, WL_CLOSURE_MAX_ARGS, ap);
+	va_end(ap);
+
+	wl_proxy_marshal_array_constructor(proxy, opcode, args, NULL);
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param interface The interface to use for the new proxy
+ * \param ... Extra arguments for the given request
+ * \return A new wl_proxy for the new_id argument or NULL on error
+ *
+ * This function translates a request given an opcode, an interface and extra
+ * arguments to the wire format and writes it to the connection buffer. The
+ * types of the extra arguments must correspond to the argument types of the
+ * method associated with the opcode in the interface.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server.  The new wl_proxy will be returned
+ * on success or NULL on error with errno set accordingly.  The newly
+ * created proxy will inherit their version from their parent.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_constructor(struct wl_proxy *proxy, uint32_t opcode,
+			     const struct wl_interface *interface, ...)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	va_list ap;
+
+	va_start(ap, interface);
+	wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
+				 args, WL_CLOSURE_MAX_ARGS, ap);
+	va_end(ap);
+
+	return wl_proxy_marshal_array_constructor(proxy, opcode,
+						  args, interface);
+}
+
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param interface The interface to use for the new proxy
+ * \param version The protocol object version of the new proxy
+ * \param ... Extra arguments for the given request
+ * \return A new wl_proxy for the new_id argument or NULL on error
+ *
+ * Translates the request given by opcode and the extra arguments into the
+ * wire format and write it to the connection buffer.
+ *
+ * For new-id arguments, this function will allocate a new wl_proxy
+ * and send the ID to the server.  The new wl_proxy will be returned
+ * on success or NULL on error with errno set accordingly.  The newly
+ * created proxy will have the version specified.
+ *
+ * \note This should not normally be used by non-generated code.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT struct wl_proxy *
+wl_proxy_marshal_constructor_versioned(struct wl_proxy *proxy, uint32_t opcode,
+				       const struct wl_interface *interface,
+				       uint32_t version, ...)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	va_list ap;
+
+	va_start(ap, version);
+	wl_argument_from_va_list(proxy->object.interface->methods[opcode].signature,
+				 args, WL_CLOSURE_MAX_ARGS, ap);
+	va_end(ap);
+
+	return wl_proxy_marshal_array_constructor_versioned(proxy, opcode,
+							    args, interface,
+							    version);
+}
+
+/** Prepare a request to be sent to the compositor
+ *
+ * \param proxy The proxy object
+ * \param opcode Opcode of the request to be sent
+ * \param args Extra arguments for the given request
+ *
+ * This function is similar to wl_proxy_marshal_array_constructor(), except
+ * it doesn't create proxies for new-id arguments.
+ *
+ * \note This is intended to be used by language bindings and not in
+ * non-generated code.
+ *
+ * \sa wl_proxy_marshal()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_marshal_array(struct wl_proxy *proxy, uint32_t opcode,
+		       union wl_argument *args)
+{
+	wl_proxy_marshal_array_constructor(proxy, opcode, args, NULL);
+}
+
+static void
+display_handle_error(void *data,
+		     struct wl_display *display, void *object,
+		     uint32_t code, const char *message)
+{
+	struct wl_proxy *proxy = object;
+	uint32_t object_id;
+	const struct wl_interface *interface;
+
+	if (proxy) {
+		wl_log("%s#%u: error %d: %s\n",
+		       proxy->object.interface->name,
+		       proxy->object.id,
+		       code, message);
+
+		object_id = proxy->object.id;
+		interface = proxy->object.interface;
+	} else {
+		wl_log("[destroyed object]: error %d: %s\n",
+		       code, message);
+
+		object_id = 0;
+		interface = NULL;
+	}
+
+	display_protocol_error(display, code, object_id, interface);
+}
+
+static void
+display_handle_delete_id(void *data, struct wl_display *display, uint32_t id)
+{
+	struct wl_proxy *proxy;
+
+	pthread_mutex_lock(&display->mutex);
+
+	proxy = wl_map_lookup(&display->objects, id);
+
+	if (wl_object_is_zombie(&display->objects, id)) {
+		/* For zombie objects, the 'proxy' is actually the zombie
+		 * event-information structure, which we can free. */
+		free(proxy);
+		wl_map_remove(&display->objects, id);
+	} else if (proxy) {
+		proxy->flags |= WL_PROXY_FLAG_ID_DELETED;
+	} else {
+		wl_log("error: received delete_id for unknown id (%u)\n", id);
+	}
+
+	pthread_mutex_unlock(&display->mutex);
+}
+
+static const struct wl_display_listener display_listener = {
+	display_handle_error,
+	display_handle_delete_id
+};
+
+static int
+connect_to_socket(const char *name)
+{
+	struct sockaddr_un addr;
+	socklen_t size;
+	const char *runtime_dir;
+	int name_size, fd;
+	bool path_is_absolute;
+
+	if (name == NULL)
+		name = getenv("WAYLAND_DISPLAY");
+	if (name == NULL)
+		name = "wayland-0";
+
+	path_is_absolute = name[0] == '/';
+
+	runtime_dir = getenv("XDG_RUNTIME_DIR");
+	if (((!runtime_dir || runtime_dir[0] != '/') && !path_is_absolute)) {
+		wl_log("error: XDG_RUNTIME_DIR is invalid or not set in the environment.\n");
+		/* to prevent programs reporting
+		 * "failed to create display: Success" */
+		errno = ENOENT;
+		return -1;
+	}
+
+	fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
+	if (fd < 0)
+		return -1;
+
+	memset(&addr, 0, sizeof addr);
+	addr.sun_family = AF_LOCAL;
+	if (!path_is_absolute) {
+		name_size =
+			snprintf(addr.sun_path, sizeof addr.sun_path,
+			         "%s/%s", runtime_dir, name) + 1;
+	} else {
+		/* absolute path */
+		name_size =
+			snprintf(addr.sun_path, sizeof addr.sun_path,
+			         "%s", name) + 1;
+	}
+
+	assert(name_size > 0);
+	if (name_size > (int)sizeof addr.sun_path) {
+		if (!path_is_absolute) {
+			wl_log("error: socket path \"%s/%s\" plus null terminator"
+			       " exceeds %i bytes\n", runtime_dir, name, (int) sizeof(addr.sun_path));
+		} else {
+			wl_log("error: socket path \"%s\" plus null terminator"
+			       " exceeds %i bytes\n", name, (int) sizeof(addr.sun_path));
+		}
+		close(fd);
+		/* to prevent programs reporting
+		 * "failed to add socket: Success" */
+		errno = ENAMETOOLONG;
+		return -1;
+	};
+
+	size = offsetof (struct sockaddr_un, sun_path) + name_size;
+
+	if (connect(fd, (struct sockaddr *) &addr, size) < 0) {
+		close(fd);
+		return -1;
+	}
+
+	return fd;
+}
+
+/** Connect to Wayland display on an already open fd
+ *
+ * \param fd The fd to use for the connection
+ * \return A \ref wl_display object or \c NULL on failure
+ *
+ * The wl_display takes ownership of the fd and will close it when the
+ * display is destroyed.  The fd will also be closed in case of
+ * failure.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_display *
+wl_display_connect_to_fd(int fd)
+{
+	struct wl_display *display;
+	const char *debug;
+
+	debug = getenv("WAYLAND_DEBUG");
+	if (debug && (strstr(debug, "client") || strstr(debug, "1")))
+		debug_client = 1;
+
+	display = zalloc(sizeof *display);
+	if (display == NULL) {
+		close(fd);
+		return NULL;
+	}
+
+	display->fd = fd;
+	wl_map_init(&display->objects, WL_MAP_CLIENT_SIDE);
+	wl_event_queue_init(&display->default_queue, display, "Default Queue");
+	wl_event_queue_init(&display->display_queue, display, "Display Queue");
+	pthread_mutex_init(&display->mutex, NULL);
+	pthread_cond_init(&display->reader_cond, NULL);
+	display->reader_count = 0;
+
+	if (wl_map_insert_at(&display->objects, 0, 0, NULL) == -1)
+		goto err_connection;
+
+	display->proxy.object.id =
+		wl_map_insert_new(&display->objects, 0, display);
+
+	if (display->proxy.object.id == 0)
+		goto err_connection;
+
+	display->proxy.object.interface = &wl_display_interface;
+	display->proxy.display = display;
+	display->proxy.object.implementation = (void(**)(void)) &display_listener;
+	display->proxy.user_data = display;
+	display->proxy.queue = &display->default_queue;
+	display->proxy.flags = 0;
+	display->proxy.refcount = 1;
+
+	/* We set this version to 0 for backwards compatibility.
+	 *
+	 * If a client is using old versions of protocol headers,
+	 * it will use unversioned API to create proxies.  Those
+	 * proxies will inherit this 0.
+	 *
+	 * A client could be passing these proxies into library
+	 * code newer than the headers that checks proxy
+	 * versions.  When the proxy version is reported as 0
+	 * the library will know that it can't reliably determine
+	 * the proxy version, and should do whatever fallback is
+	 * required.
+	 *
+	 * This trick forces wl_display to always report 0, but
+	 * since it's a special object that we can't bind
+	 * specific versions of anyway, this should be fine.
+	 */
+	display->proxy.version = 0;
+
+	display->connection = wl_connection_create(display->fd, 0);
+	if (display->connection == NULL)
+		goto err_connection;
+
+	return display;
+
+ err_connection:
+	pthread_mutex_destroy(&display->mutex);
+	pthread_cond_destroy(&display->reader_cond);
+	wl_map_release(&display->objects);
+	close(display->fd);
+	free(display);
+
+	return NULL;
+}
+
+/** Connect to a Wayland display
+ *
+ * \param name Name of the Wayland display to connect to
+ * \return A \ref wl_display object or \c NULL on failure
+ *
+ * Connect to the Wayland display named \c name. If \c name is \c NULL,
+ * 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.
+ *
+ * If \c name is \c NULL and the WAYLAND_DISPLAY environment variable
+ * is set to an absolute pathname, then that pathname is used as-is
+ * for the socket in the same manner as if \c name held an absolute
+ * path. Support for absolute paths in \c name and WAYLAND_DISPLAY
+ * is present since Wayland version 1.15.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_display *
+wl_display_connect(const char *name)
+{
+	char *connection, *end;
+	int flags, fd;
+
+	connection = getenv("WAYLAND_SOCKET");
+	if (connection) {
+		int prev_errno = errno;
+		errno = 0;
+		fd = strtol(connection, &end, 10);
+		if (errno != 0 || connection == end || *end != '\0')
+			return NULL;
+		errno = prev_errno;
+
+		flags = fcntl(fd, F_GETFD);
+		if (flags == -1 && errno == EBADF)
+			return NULL;
+		else if (flags != -1)
+			fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+		unsetenv("WAYLAND_SOCKET");
+	} else {
+		fd = connect_to_socket(name);
+		if (fd < 0)
+			return NULL;
+	}
+
+	return wl_display_connect_to_fd(fd);
+}
+
+/** Close a connection to a Wayland display
+ *
+ * \param display The display context object
+ *
+ * Close the connection to \c display. The \ref wl_proxy and
+ * \ref wl_event_queue objects need to be manually destroyed by the caller
+ * before disconnecting.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_disconnect(struct wl_display *display)
+{
+	wl_connection_destroy(display->connection);
+	wl_map_for_each(&display->objects, free_zombies, NULL);
+	wl_map_release(&display->objects);
+	wl_event_queue_release(&display->default_queue);
+	free(display->default_queue.name);
+	wl_event_queue_release(&display->display_queue);
+	free(display->display_queue.name);
+	pthread_mutex_destroy(&display->mutex);
+	pthread_cond_destroy(&display->reader_cond);
+	close(display->fd);
+
+	free(display);
+}
+
+/** Get a display context's file descriptor
+ *
+ * \param display The display context object
+ * \return Display object file descriptor
+ *
+ * Return the file descriptor associated with a display so it can be
+ * integrated into the client's main loop.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_get_fd(struct wl_display *display)
+{
+	return display->fd;
+}
+
+static void
+sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
+{
+	int *done = data;
+
+	*done = 1;
+	wl_callback_destroy(callback);
+}
+
+static const struct wl_callback_listener sync_listener = {
+	sync_callback
+};
+
+/** Block until all pending request are processed by the server
+ *
+ * \param display The display context object
+ * \param queue The queue on which to run the roundtrip
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * This function blocks until the server has processed all currently issued
+ * requests by sending a request to the display server and waiting for a
+ * reply before returning.
+ *
+ * This function uses wl_display_dispatch_queue() internally. It is not allowed
+ * to call this function while the thread is being prepared for reading events,
+ * and doing so will cause a dead lock.
+ *
+ * \note This function may dispatch other events being received on the given
+ * queue.
+ *
+ * \sa wl_display_roundtrip()
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_roundtrip_queue(struct wl_display *display, struct wl_event_queue *queue)
+{
+	struct wl_display *display_wrapper;
+	struct wl_callback *callback;
+	int done, ret = 0;
+
+	done = 0;
+
+	display_wrapper = wl_proxy_create_wrapper(display);
+	if (!display_wrapper)
+		return -1;
+
+	wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
+	callback = wl_display_sync(display_wrapper);
+	wl_proxy_wrapper_destroy(display_wrapper);
+
+	if (callback == NULL)
+		return -1;
+
+	wl_callback_add_listener(callback, &sync_listener, &done);
+	while (!done && ret >= 0)
+		ret = wl_display_dispatch_queue(display, queue);
+
+	if (ret == -1 && !done)
+		wl_callback_destroy(callback);
+
+	return ret;
+}
+
+/** Block until all pending request are processed by the server
+ *
+ * \param display The display context object
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * This function blocks until the server has processed all currently issued
+ * requests by sending a request to the display server and waiting for a reply
+ * before returning.
+ *
+ * This function uses wl_display_dispatch_queue() internally. It is not allowed
+ * to call this function while the thread is being prepared for reading events,
+ * and doing so will cause a dead lock.
+ *
+ * \note This function may dispatch other events being received on the default
+ * queue.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_roundtrip(struct wl_display *display)
+{
+	return wl_display_roundtrip_queue(display, &display->default_queue);
+}
+
+static int
+create_proxies(struct wl_proxy *sender, struct wl_closure *closure)
+{
+	struct wl_proxy *proxy;
+	const char *signature;
+	struct argument_details arg;
+	uint32_t id;
+	int i;
+	int count;
+
+	signature = closure->message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		if (arg.type != WL_ARG_NEW_ID)
+			continue;
+
+		id = closure->args[i].n;
+		if (id == 0) {
+			closure->args[i].o = NULL;
+			continue;
+		}
+		proxy = wl_proxy_create_for_id(sender, id,
+					       closure->message->types[i]);
+		if (proxy == NULL)
+			return -1;
+		closure->args[i].o = (struct wl_object *)proxy;
+	}
+
+	return 0;
+}
+
+static void
+increase_closure_args_refcount(struct wl_closure *closure)
+{
+	const char *signature;
+	struct argument_details arg;
+	int i, count;
+	struct wl_proxy *proxy;
+
+	signature = closure->message->signature;
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		switch (arg.type) {
+		case WL_ARG_NEW_ID:
+		case WL_ARG_OBJECT:
+			proxy = (struct wl_proxy *) closure->args[i].o;
+			if (proxy)
+				proxy->refcount++;
+			break;
+		default:
+			break;
+		}
+	}
+
+	closure->proxy->refcount++;
+}
+
+static int
+queue_event(struct wl_display *display, int len)
+{
+	uint32_t p[2], id;
+	int opcode, size;
+	struct wl_proxy *proxy;
+	struct wl_closure *closure;
+	const struct wl_message *message;
+	struct wl_event_queue *queue;
+	struct timespec tp;
+	unsigned int time;
+	int num_zombie_fds;
+
+	wl_connection_copy(display->connection, p, sizeof p);
+	id = p[0];
+	opcode = p[1] & 0xffff;
+	size = p[1] >> 16;
+	if (len < size)
+		return 0;
+
+	/* If our proxy is gone or a zombie, just eat the event (and any FDs,
+	 * if applicable). */
+	proxy = wl_map_lookup(&display->objects, id);
+	if (!proxy || wl_object_is_zombie(&display->objects, id)) {
+		struct wl_zombie *zombie = wl_map_lookup(&display->objects, id);
+		num_zombie_fds = (zombie && opcode < zombie->event_count) ?
+			zombie->fd_count[opcode] : 0;
+
+		if (debug_client) {
+			clock_gettime(CLOCK_REALTIME, &tp);
+			time = (tp.tv_sec * 1000000L) + (tp.tv_nsec / 1000);
+
+			fprintf(stderr, "[%7u.%03u] discarded [%s]#%d.[event %d]"
+				"(%d fd, %d byte)\n",
+				time / 1000, time % 1000,
+				zombie ? "zombie" : "unknown",
+				id, opcode,
+				num_zombie_fds, size);
+		}
+		if (num_zombie_fds > 0)
+			wl_connection_close_fds_in(display->connection,
+						   num_zombie_fds);
+
+		wl_connection_consume(display->connection, size);
+		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);
+	if (!closure)
+		return -1;
+
+	if (create_proxies(proxy, closure) < 0) {
+		wl_closure_destroy(closure);
+		return -1;
+	}
+
+	if (wl_closure_lookup_objects(closure, &display->objects) != 0) {
+		wl_closure_destroy(closure);
+		return -1;
+	}
+
+	closure->proxy = proxy;
+	increase_closure_args_refcount(closure);
+
+	if (proxy == &display->proxy)
+		queue = &display->display_queue;
+	else
+		queue = proxy->queue;
+
+	if (!queue)
+		wl_abort("Tried to add event to destroyed queue\n");
+
+	wl_list_insert(queue->event_list.prev, &closure->link);
+
+	return size;
+}
+
+static uint32_t
+id_from_object(union wl_argument *arg)
+{
+	struct wl_proxy *proxy;
+
+	if (arg->o) {
+		proxy = (struct wl_proxy *)arg->o;
+		return proxy->object.id;
+	}
+
+	return 0;
+}
+
+static void
+dispatch_event(struct wl_display *display, struct wl_event_queue *queue)
+{
+	struct wl_closure *closure;
+	struct wl_proxy *proxy;
+	int opcode;
+	bool proxy_destroyed;
+
+	closure = wl_container_of(queue->event_list.next, closure, link);
+	wl_list_remove(&closure->link);
+	opcode = closure->opcode;
+
+	/* Verify that the receiving object is still valid by checking if has
+	 * been destroyed by the application. */
+	validate_closure_objects(closure);
+	proxy = closure->proxy;
+	proxy_destroyed = !!(proxy->flags & WL_PROXY_FLAG_DESTROYED);
+
+	if (debug_client) {
+		bool discarded = proxy_destroyed ||
+				 !(proxy->dispatcher || proxy->object.implementation);
+
+		wl_closure_print(closure, &proxy->object, false, discarded,
+				 id_from_object, queue->name);
+	}
+
+	if (proxy_destroyed) {
+		destroy_queued_closure(closure);
+		return;
+	}
+
+	pthread_mutex_unlock(&display->mutex);
+
+	if (proxy->dispatcher) {
+		wl_closure_dispatch(closure, proxy->dispatcher,
+				    &proxy->object, opcode);
+	} else if (proxy->object.implementation) {
+		wl_closure_invoke(closure, WL_CLOSURE_INVOKE_CLIENT,
+				  &proxy->object, opcode, proxy->user_data);
+	}
+
+	pthread_mutex_lock(&display->mutex);
+
+	destroy_queued_closure(closure);
+}
+
+static int
+read_events(struct wl_display *display)
+{
+	int total, rem, size;
+	uint32_t serial;
+
+	display->reader_count--;
+	if (display->reader_count == 0) {
+		total = wl_connection_read(display->connection);
+		if (total == -1) {
+			if (errno == EAGAIN) {
+				/* we must wake up threads whenever
+				 * the reader_count dropped to 0 */
+				display_wakeup_threads(display);
+
+				return 0;
+			}
+
+			display_fatal_error(display, errno);
+			return -1;
+		} else if (total == 0) {
+			/* The compositor has closed the socket. This
+			 * should be considered an error so we'll fake
+			 * an errno */
+			errno = EPIPE;
+			display_fatal_error(display, errno);
+			return -1;
+		}
+
+		for (rem = total; rem >= 8; rem -= size) {
+			size = queue_event(display, rem);
+			if (size == -1) {
+				display_fatal_error(display, errno);
+				return -1;
+			} else if (size == 0) {
+				break;
+			}
+		}
+
+		display_wakeup_threads(display);
+	} else {
+		serial = display->read_serial;
+		while (display->read_serial == serial)
+			pthread_cond_wait(&display->reader_cond,
+					  &display->mutex);
+
+		if (display->last_error) {
+			errno = display->last_error;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+static void
+cancel_read(struct wl_display *display)
+{
+	display->reader_count--;
+	if (display->reader_count == 0)
+		display_wakeup_threads(display);
+}
+
+/** Read events from display file descriptor
+ *
+ * \param display The display context object
+ * \return 0 on success or -1 on error.  In case of error errno will
+ * be set accordingly
+ *
+ * Calling this function will result in data available on the display file
+ * descriptor being read and read events will be queued on their corresponding
+ * event queues.
+ *
+ * Before calling this function, depending on what thread it is to be called
+ * from, wl_display_prepare_read_queue() or wl_display_prepare_read() needs to
+ * be called. See wl_display_prepare_read_queue() for more details.
+ *
+ * When being called at a point where other threads have been prepared to read
+ * (using wl_display_prepare_read_queue() or wl_display_prepare_read()) this
+ * function will sleep until all other prepared threads have either been
+ * cancelled (using wl_display_cancel_read()) or them self entered this
+ * function. The last thread that calls this function will then read and queue
+ * events on their corresponding event queues, and finally wake up all other
+ * wl_display_read_events() calls causing them to return.
+ *
+ * If a thread cancels a read preparation when all other threads that have
+ * prepared to read has either called wl_display_cancel_read() or
+ * wl_display_read_events(), all reader threads will return without having read
+ * any data.
+ *
+ * To dispatch events that may have been queued, call
+ * wl_display_dispatch_pending() or wl_display_dispatch_queue_pending().
+ *
+ * \sa wl_display_prepare_read(), wl_display_cancel_read(),
+ * wl_display_dispatch_pending(), wl_display_dispatch()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_read_events(struct wl_display *display)
+{
+	int ret;
+
+	pthread_mutex_lock(&display->mutex);
+
+	if (display->last_error) {
+		cancel_read(display);
+		pthread_mutex_unlock(&display->mutex);
+
+		errno = display->last_error;
+		return -1;
+	}
+
+	ret = read_events(display);
+
+	pthread_mutex_unlock(&display->mutex);
+
+	return ret;
+}
+
+static int
+dispatch_queue(struct wl_display *display, struct wl_event_queue *queue)
+{
+	int count;
+
+	if (display->last_error)
+		goto err;
+
+	count = 0;
+	while (!wl_list_empty(&display->display_queue.event_list)) {
+		dispatch_event(display, &display->display_queue);
+		if (display->last_error)
+			goto err;
+		count++;
+	}
+
+	while (!wl_list_empty(&queue->event_list)) {
+		dispatch_event(display, queue);
+		if (display->last_error)
+			goto err;
+		count++;
+	}
+
+	return count;
+
+err:
+	errno = display->last_error;
+
+	return -1;
+}
+
+/** Prepare to read events from the display's file descriptor to a queue
+ *
+ * \param display The display context object
+ * \param queue The event queue to use
+ * \return 0 on success or -1 if event queue was not empty
+ *
+ * This function (or wl_display_prepare_read()) must be called before reading
+ * from the file descriptor using wl_display_read_events(). Calling
+ * wl_display_prepare_read_queue() announces the calling thread's intention to
+ * read and ensures that until the thread is ready to read and calls
+ * wl_display_read_events(), no other thread will read from the file descriptor.
+ * This only succeeds if the event queue is empty, and if not -1 is returned and
+ * errno set to EAGAIN.
+ *
+ * If a thread successfully calls wl_display_prepare_read_queue(), it must
+ * either call wl_display_read_events() when it's ready or cancel the read
+ * intention by calling wl_display_cancel_read().
+ *
+ * Use this function before polling on the display fd or integrate the fd into a
+ * toolkit event loop in a race-free way. A correct usage would be (with most
+ * error checking left out):
+ *
+ * \code
+ * while (wl_display_prepare_read_queue(display, queue) != 0)
+ *         wl_display_dispatch_queue_pending(display, queue);
+ * wl_display_flush(display);
+ *
+ * ret = poll(fds, nfds, -1);
+ * if (has_error(ret))
+ *         wl_display_cancel_read(display);
+ * else
+ *         wl_display_read_events(display);
+ *
+ * wl_display_dispatch_queue_pending(display, queue);
+ * \endcode
+ *
+ * Here we call wl_display_prepare_read_queue(), which ensures that between
+ * returning from that call and eventually calling wl_display_read_events(), no
+ * other thread will read from the fd and queue events in our queue. If the call
+ * to wl_display_prepare_read_queue() fails, we dispatch the pending events and
+ * try again until we're successful.
+ *
+ * The wl_display_prepare_read_queue() function doesn't acquire exclusive access
+ * to the display's fd. It only registers that the thread calling this function
+ * has intention to read from fd. When all registered readers call
+ * wl_display_read_events(), only one (at random) eventually reads and queues
+ * the events and the others are sleeping meanwhile. This way we avoid races and
+ * still can read from more threads.
+ *
+ * \sa wl_display_cancel_read(), wl_display_read_events(),
+ * wl_display_prepare_read()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_prepare_read_queue(struct wl_display *display,
+			      struct wl_event_queue *queue)
+{
+	int ret;
+
+	pthread_mutex_lock(&display->mutex);
+
+	if (!wl_list_empty(&queue->event_list)) {
+		errno = EAGAIN;
+		ret = -1;
+	} else {
+		display->reader_count++;
+		ret = 0;
+	}
+
+	pthread_mutex_unlock(&display->mutex);
+
+	return ret;
+}
+
+/** Prepare to read events from the display's file descriptor
+ *
+ * \param display The display context object
+ * \return 0 on success or -1 if event queue was not empty
+ *
+ * This function does the same thing as wl_display_prepare_read_queue()
+ * with the default queue passed as the queue.
+ *
+ * \sa wl_display_prepare_read_queue
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_prepare_read(struct wl_display *display)
+{
+	return wl_display_prepare_read_queue(display, &display->default_queue);
+}
+
+/** Cancel read intention on display's fd
+ *
+ * \param display The display context object
+ *
+ * After a thread successfully called wl_display_prepare_read() it must
+ * either call wl_display_read_events() or wl_display_cancel_read().
+ * If the threads do not follow this rule it will lead to deadlock.
+ *
+ * \sa wl_display_prepare_read(), wl_display_read_events()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_cancel_read(struct wl_display *display)
+{
+	pthread_mutex_lock(&display->mutex);
+
+	cancel_read(display);
+
+	pthread_mutex_unlock(&display->mutex);
+}
+
+static int
+wl_display_poll(struct wl_display *display, short int events)
+{
+	int ret;
+	struct pollfd pfd[1];
+
+	pfd[0].fd = display->fd;
+	pfd[0].events = events;
+	do {
+		ret = poll(pfd, 1, -1);
+	} while (ret == -1 && errno == EINTR);
+
+	return ret;
+}
+
+/** Dispatch events in an event queue
+ *
+ * \param display The display context object
+ * \param queue The event queue to dispatch
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * Dispatch events on the given event queue.
+ *
+ * If the given event queue is empty, this function blocks until there are
+ * events to be read from the display fd. Events are read and queued on
+ * the appropriate event queues. Finally, events on given event queue are
+ * dispatched. On failure -1 is returned and errno set appropriately.
+ *
+ * In a multi threaded environment, do not manually wait using poll() (or
+ * equivalent) before calling this function, as doing so might cause a dead
+ * lock. If external reliance on poll() (or equivalent) is required, see
+ * wl_display_prepare_read_queue() of how to do so.
+ *
+ * This function is thread safe as long as it dispatches the right queue on the
+ * right thread. It is also compatible with the multi thread event reading
+ * preparation API (see wl_display_prepare_read_queue()), and uses the
+ * equivalent functionality internally. It is not allowed to call this function
+ * while the thread is being prepared for reading events, and doing so will
+ * cause a dead lock.
+ *
+ * It can be used as a helper function to ease the procedure of reading and
+ * dispatching events.
+ *
+ * \note Since Wayland 1.5 the display has an extra queue
+ * for its own events (i. e. delete_id). This queue is dispatched always,
+ * no matter what queue we passed as an argument to this function.
+ * That means that this function can return non-0 value even when it
+ * haven't dispatched any event for the given queue.
+ *
+ * \sa wl_display_dispatch(), wl_display_dispatch_pending(),
+ * wl_display_dispatch_queue_pending(), wl_display_prepare_read_queue()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_dispatch_queue(struct wl_display *display,
+			  struct wl_event_queue *queue)
+{
+	int ret;
+
+	if (wl_display_prepare_read_queue(display, queue) == -1)
+		return wl_display_dispatch_queue_pending(display, queue);
+
+	while (true) {
+		ret = wl_display_flush(display);
+
+		if (ret != -1 || errno != EAGAIN)
+			break;
+
+		if (wl_display_poll(display, POLLOUT) == -1) {
+			wl_display_cancel_read(display);
+			return -1;
+		}
+	}
+
+	/* Don't stop if flushing hits an EPIPE; continue so we can read any
+	 * protocol error that may have triggered it. */
+	if (ret < 0 && errno != EPIPE) {
+		wl_display_cancel_read(display);
+		return -1;
+	}
+
+	if (wl_display_poll(display, POLLIN) == -1) {
+		wl_display_cancel_read(display);
+		return -1;
+	}
+
+	if (wl_display_read_events(display) == -1)
+		return -1;
+
+	return wl_display_dispatch_queue_pending(display, queue);
+}
+
+/** Dispatch pending events in an event queue
+ *
+ * \param display The display context object
+ * \param queue The event queue to dispatch
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * Dispatch all incoming events for objects assigned to the given
+ * event queue. On failure -1 is returned and errno set appropriately.
+ * If there are no events queued, this function returns immediately.
+ *
+ * \memberof wl_display
+ * \since 1.0.2
+ */
+WL_EXPORT int
+wl_display_dispatch_queue_pending(struct wl_display *display,
+				  struct wl_event_queue *queue)
+{
+	int ret;
+
+	pthread_mutex_lock(&display->mutex);
+
+	ret = dispatch_queue(display, queue);
+
+	pthread_mutex_unlock(&display->mutex);
+
+	return ret;
+}
+
+/** Process incoming events
+ *
+ * \param display The display context object
+ * \return The number of dispatched events on success or -1 on failure
+ *
+ * Dispatch events on the default event queue.
+ *
+ * If the default event queue is empty, this function blocks until there are
+ * events to be read from the display fd. Events are read and queued on
+ * the appropriate event queues. Finally, events on the default event queue
+ * are dispatched. On failure -1 is returned and errno set appropriately.
+ *
+ * In a multi threaded environment, do not manually wait using poll() (or
+ * equivalent) before calling this function, as doing so might cause a dead
+ * lock. If external reliance on poll() (or equivalent) is required, see
+ * wl_display_prepare_read_queue() of how to do so.
+ *
+ * This function is thread safe as long as it dispatches the right queue on the
+ * right thread. It is also compatible with the multi thread event reading
+ * preparation API (see wl_display_prepare_read_queue()), and uses the
+ * equivalent functionality internally. It is not allowed to call this function
+ * while the thread is being prepared for reading events, and doing so will
+ * cause a dead lock.
+ *
+ * \note It is not possible to check if there are events on the queue
+ * or not. For dispatching default queue events without blocking, see \ref
+ * wl_display_dispatch_pending().
+ *
+ * \sa wl_display_dispatch_pending(), wl_display_dispatch_queue(),
+ * wl_display_read_events()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_dispatch(struct wl_display *display)
+{
+	return wl_display_dispatch_queue(display, &display->default_queue);
+}
+
+/** Dispatch default queue events without reading from the display fd
+ *
+ * \param display The display context object
+ * \return The number of dispatched events or -1 on failure
+ *
+ * This function dispatches events on the main event queue. It does not
+ * attempt to read the display fd and simply returns zero if the main
+ * queue is empty, i.e., it doesn't block.
+ *
+ * \sa wl_display_dispatch(), wl_display_dispatch_queue(),
+ * wl_display_flush()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_dispatch_pending(struct wl_display *display)
+{
+	return wl_display_dispatch_queue_pending(display,
+						 &display->default_queue);
+}
+
+/** Retrieve the last error that occurred on a display
+ *
+ * \param display The display context object
+ * \return The last error that occurred on \c display or 0 if no error occurred
+ *
+ * Return the last error that occurred on the display. This may be an error sent
+ * by the server or caused by the local client.
+ *
+ * \note Errors are \b fatal. If this function returns non-zero the display
+ * can no longer be used.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_get_error(struct wl_display *display)
+{
+	int ret;
+
+	pthread_mutex_lock(&display->mutex);
+
+	ret = display->last_error;
+
+	pthread_mutex_unlock(&display->mutex);
+
+	return ret;
+}
+
+/** Retrieves the information about a protocol error:
+ *
+ * \param display    The Wayland display
+ * \param interface  if not NULL, stores the interface where the error occurred,
+ *                   or NULL, if unknown.
+ * \param id         if not NULL, stores the object id that generated
+ *                   the error, or 0, if the object id is unknown. There's no
+ *                   guarantee the object is still valid; the client must know
+ *                   if it deleted the object.
+ * \return           The error code as defined in the interface specification.
+ *
+ * \code
+ * int err = wl_display_get_error(display);
+ *
+ * if (err == EPROTO) {
+ *        code = wl_display_get_protocol_error(display, &interface, &id);
+ *        handle_error(code, interface, id);
+ * }
+ *
+ * ...
+ * \endcode
+ * \memberof wl_display
+ */
+WL_EXPORT uint32_t
+wl_display_get_protocol_error(struct wl_display *display,
+			      const struct wl_interface **interface,
+			      uint32_t *id)
+{
+	uint32_t ret;
+
+	pthread_mutex_lock(&display->mutex);
+
+	ret = display->protocol_error.code;
+
+	if (interface)
+		*interface = display->protocol_error.interface;
+	if (id)
+		*id = display->protocol_error.id;
+
+	pthread_mutex_unlock(&display->mutex);
+
+	return ret;
+}
+
+
+/** Send all buffered requests on the display to the server
+ *
+ * \param display The display context object
+ * \return The number of bytes sent on success or -1 on failure
+ *
+ * Send all buffered data on the client side to the server. Clients should
+ * always call this function before blocking on input from the display fd.
+ * On success, the number of bytes sent to the server is returned. On
+ * failure, this function returns -1 and errno is set appropriately.
+ *
+ * wl_display_flush() never blocks.  It will write as much data as
+ * possible, but if all data could not be written, errno will be set
+ * to EAGAIN and -1 returned.  In that case, use poll on the display
+ * file descriptor to wait for it to become writable again.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_flush(struct wl_display *display)
+{
+	int ret;
+
+	pthread_mutex_lock(&display->mutex);
+
+	if (display->last_error) {
+		errno = display->last_error;
+		ret = -1;
+	} else {
+		/* We don't make EPIPE a fatal error here, so that we may try to
+		 * read events after the failed flush. When the compositor sends
+		 * an error it will close the socket, and if we make EPIPE fatal
+		 * here we don't get a chance to process the error. */
+		ret = wl_connection_flush(display->connection);
+		if (ret < 0 && errno != EAGAIN && errno != EPIPE)
+			display_fatal_error(display, errno);
+	}
+
+	pthread_mutex_unlock(&display->mutex);
+
+	return ret;
+}
+
+/** Adjust the maximum size of the client connection buffers
+ *
+ * \param display The display context object
+ * \param max_buffer_size The maximum size of the connection buffers
+ *
+ * Client buffers are unbounded by default. This function sets a limit to the
+ * size of the connection buffers.
+ *
+ * A value of 0 for \a max_buffer_size requests the buffers to be unbounded.
+ *
+ * The actual size of the connection buffers is a power of two, the requested
+ * \a max_buffer_size is therefore rounded up to the nearest power of two value.
+ *
+ * Lowering the maximum size may not take effect immediately if the current
+ * content of the buffer does not fit within the new size limit.
+ *
+ * \memberof wl_display
+ * \since 1.22.90
+ */
+WL_EXPORT void
+wl_display_set_max_buffer_size(struct wl_display *display,
+                               size_t max_buffer_size)
+{
+	wl_connection_set_max_buffer_size(display->connection, max_buffer_size);
+}
+
+/** Set the user data associated with a proxy
+ *
+ * \param proxy The proxy object
+ * \param user_data The data to be associated with proxy
+ *
+ * Set the user data associated with \c proxy. When events for this
+ * proxy are received, \c user_data will be supplied to its listener.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data)
+{
+	proxy->user_data = user_data;
+}
+
+/** Get the user data associated with a proxy
+ *
+ * \param proxy The proxy object
+ * \return The user data associated with proxy
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void *
+wl_proxy_get_user_data(struct wl_proxy *proxy)
+{
+	return proxy->user_data;
+}
+
+/** Get the protocol object version of a proxy object
+ *
+ * \param proxy The proxy object
+ * \return The protocol object version of the proxy or 0
+ *
+ * Gets the protocol object version of a proxy object, or 0
+ * if the proxy was created with unversioned API.
+ *
+ * A returned value of 0 means that no version information is
+ * available, so the caller must make safe assumptions about
+ * the object's real version.
+ *
+ * wl_display's version will always return 0.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT uint32_t
+wl_proxy_get_version(struct wl_proxy *proxy)
+{
+	return proxy->version;
+}
+
+/** Get the id of a proxy object
+ *
+ * \param proxy The proxy object
+ * \return The id the object associated with the proxy
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT uint32_t
+wl_proxy_get_id(struct wl_proxy *proxy)
+{
+	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
+ * \return The interface name of the object associated with the proxy
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT const char *
+wl_proxy_get_class(struct wl_proxy *proxy)
+{
+	return proxy->object.interface->name;
+}
+
+/** Get the display of a proxy object
+ *
+ * \param proxy The proxy object
+ * \return The wl_display the proxy is associated with
+ *
+ * \memberof wl_proxy
+ * \since 1.23
+ */
+WL_EXPORT struct wl_display *
+wl_proxy_get_display(struct wl_proxy *proxy)
+{
+	return proxy->display;
+}
+
+/** Assign a proxy to an event queue
+ *
+ * \param proxy The proxy object
+ * \param queue The event queue that will handle this proxy or NULL
+ *
+ * Assign proxy to event queue. Events coming from \c proxy will be
+ * queued in \c queue from now. If queue is NULL, then the display's
+ * default queue is set to the proxy.
+ *
+ * In order to guarantee proper handing of all events which were queued
+ * before the queue change takes effect, it is required to dispatch the
+ * proxy's old event queue after setting a new event queue.
+ *
+ * This is particularly important for multi-threaded setups, where it is
+ * possible for events to be queued to the proxy's old queue from a
+ * different thread during the invocation of this function.
+ *
+ * To ensure that all events for a newly created proxy are dispatched
+ * on a particular queue, it is necessary to use a proxy wrapper if
+ * events are read and dispatched on more than one thread. See
+ * wl_proxy_create_wrapper() for more details.
+ *
+ * \note By default, the queue set in proxy is the one inherited from parent.
+ *
+ * \sa wl_display_dispatch_queue()
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_set_queue(struct wl_proxy *proxy, struct wl_event_queue *queue)
+{
+	pthread_mutex_lock(&proxy->display->mutex);
+
+	wl_list_remove(&proxy->queue_link);
+
+	if (queue) {
+		assert(proxy->display == queue->display);
+		proxy->queue = queue;
+	} else {
+		proxy->queue = &proxy->display->default_queue;
+	}
+
+	wl_list_insert(&proxy->queue->proxy_list, &proxy->queue_link);
+
+	pthread_mutex_unlock(&proxy->display->mutex);
+}
+
+/** Get a proxy's event queue
+ *
+ * \param proxy The proxy to query
+ *
+ * Return the event queue
+ */
+WL_EXPORT struct wl_event_queue *
+wl_proxy_get_queue(const struct wl_proxy *proxy)
+{
+	return proxy->queue;
+
+}
+/** Get the name of an event queue
+ *
+ * \param queue The queue to query
+ *
+ * Return the human readable name for the event queue
+ *
+ * This may be NULL if no name has been set.
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT const char *
+wl_event_queue_get_name(const struct wl_event_queue *queue)
+{
+	return queue->name;
+}
+
+/** Create a proxy wrapper for making queue assignments thread-safe
+ *
+ * \param proxy The proxy object to be wrapped
+ * \return A proxy wrapper for the given proxy or NULL on failure
+ *
+ * A proxy wrapper is type of 'struct wl_proxy' instance that can be used when
+ * sending requests instead of using the original proxy. A proxy wrapper does
+ * not have an implementation or dispatcher, and events received on the
+ * object is still emitted on the original proxy. Trying to set an
+ * implementation or dispatcher will have no effect but result in a warning
+ * being logged.
+ *
+ * Setting the proxy queue of the proxy wrapper will make new objects created
+ * using the proxy wrapper use the set proxy queue.
+ * Even though there is no implementation nor dispatcher, the proxy queue can
+ * be changed. This will affect the default queue of new objects created by
+ * requests sent via the proxy wrapper.
+ *
+ * A proxy wrapper can only be destroyed using wl_proxy_wrapper_destroy().
+ *
+ * A proxy wrapper must be destroyed before the proxy it was created from.
+ *
+ * If a user reads and dispatches events on more than one thread, it is
+ * necessary to use a proxy wrapper when sending requests on objects when the
+ * intention is that a newly created proxy is to use a proxy queue different
+ * from the proxy the request was sent on, as creating the new proxy and then
+ * setting the queue is not thread safe.
+ *
+ * For example, a module that runs using its own proxy queue that needs to
+ * do display roundtrip must wrap the wl_display proxy object before sending
+ * the wl_display.sync request. For example:
+ *
+ * \code
+ *
+ *   struct wl_event_queue *queue = ...;
+ *   struct wl_display *wrapped_display;
+ *   struct wl_callback *callback;
+ *
+ *   wrapped_display = wl_proxy_create_wrapper(display);
+ *   wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue);
+ *   callback = wl_display_sync(wrapped_display);
+ *   wl_proxy_wrapper_destroy(wrapped_display);
+ *   wl_callback_add_listener(callback, ...);
+ *
+ * \endcode
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void *
+wl_proxy_create_wrapper(void *proxy)
+{
+	struct wl_proxy *wrapped_proxy = proxy;
+	struct wl_proxy *wrapper;
+
+	wrapper = zalloc(sizeof *wrapper);
+	if (!wrapper)
+		return NULL;
+
+	pthread_mutex_lock(&wrapped_proxy->display->mutex);
+
+	wrapper->object.interface = wrapped_proxy->object.interface;
+	wrapper->object.id = wrapped_proxy->object.id;
+	wrapper->version = wrapped_proxy->version;
+	wrapper->display = wrapped_proxy->display;
+	wrapper->queue = wrapped_proxy->queue;
+	wrapper->flags = WL_PROXY_FLAG_WRAPPER;
+	wrapper->refcount = 1;
+
+	wl_list_insert(&wrapper->queue->proxy_list, &wrapper->queue_link);
+
+	pthread_mutex_unlock(&wrapped_proxy->display->mutex);
+
+	return wrapper;
+}
+
+/** Destroy a proxy wrapper
+ * \param proxy_wrapper The proxy wrapper to be destroyed
+ *
+ * \memberof wl_proxy
+ */
+WL_EXPORT void
+wl_proxy_wrapper_destroy(void *proxy_wrapper)
+{
+	struct wl_proxy *wrapper = proxy_wrapper;
+
+	if (!(wrapper->flags & WL_PROXY_FLAG_WRAPPER))
+		wl_abort("Tried to destroy non-wrapper proxy with "
+			 "wl_proxy_wrapper_destroy\n");
+
+	assert(wrapper->refcount == 1);
+
+	pthread_mutex_lock(&wrapper->display->mutex);
+
+	wl_list_remove(&wrapper->queue_link);
+
+	pthread_mutex_unlock(&wrapper->display->mutex);
+
+	free(wrapper);
+}
+
+WL_EXPORT void
+wl_log_set_handler_client(wl_log_func_t handler)
+{
+	wl_log_handler = handler;
+}
diff --git a/subprojects/wayland/src/wayland-client.h b/subprojects/wayland/src/wayland-client.h
new file mode 100644
index 0000000000000000000000000000000000000000..9f70fa3fbb1fc01d5603d851e3413e83e112b994
--- /dev/null
+++ b/subprojects/wayland/src/wayland-client.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/** \file
+ *
+ *  \brief Include the client API and protocol C API.
+ *
+ *  \warning Use of this header file is discouraged. Prefer including
+ *  wayland-client-core.h instead, which does not include the
+ *  client protocol header and as such only defines the library
+ *  API.
+ */
+
+#ifndef WAYLAND_CLIENT_H
+#define WAYLAND_CLIENT_H
+
+#include "wayland-client-core.h"
+#include "wayland-client-protocol.h"
+
+#endif
diff --git a/subprojects/wayland/src/wayland-os.c b/subprojects/wayland/src/wayland-os.c
new file mode 100644
index 0000000000000000000000000000000000000000..f00ead4b95e6e207002a665b813d84b6135213dc
--- /dev/null
+++ b/subprojects/wayland/src/wayland-os.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include "../config.h"
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/epoll.h>
+#include <sys/mman.h>
+#include <sys/un.h>
+#ifdef HAVE_SYS_UCRED_H
+#include <sys/ucred.h>
+#endif
+
+#include "wayland-os.h"
+
+/* used by tests */
+int (*wl_fcntl)(int fildes, int cmd, ...) = fcntl;
+int (*wl_socket)(int domain, int type, int protocol) = socket;
+ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags) = recvmsg;
+int (*wl_epoll_create1)(int flags) = epoll_create1;
+
+static int
+set_cloexec_or_close(int fd)
+{
+	long flags;
+
+	if (fd == -1)
+		return -1;
+
+	flags = wl_fcntl(fd, F_GETFD);
+	if (flags == -1)
+		goto err;
+
+	if (wl_fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
+		goto err;
+
+	return fd;
+
+err:
+	close(fd);
+	return -1;
+}
+
+int
+wl_os_socket_cloexec(int domain, int type, int protocol)
+{
+	int fd;
+
+	fd = wl_socket(domain, type | SOCK_CLOEXEC, protocol);
+	if (fd >= 0)
+		return fd;
+	if (errno != EINVAL)
+		return -1;
+
+	fd = wl_socket(domain, type, protocol);
+	return set_cloexec_or_close(fd);
+}
+
+#if defined(__FreeBSD__)
+int
+wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
+{
+	socklen_t len;
+	struct xucred ucred;
+
+	len = sizeof(ucred);
+	if (getsockopt(sockfd, SOL_LOCAL, LOCAL_PEERCRED, &ucred, &len) < 0 ||
+	    ucred.cr_version != XUCRED_VERSION)
+		return -1;
+	*uid = ucred.cr_uid;
+	*gid = ucred.cr_gid;
+#if HAVE_XUCRED_CR_PID
+	/* Since https://cgit.freebsd.org/src/commit/?id=c5afec6e895a */
+	*pid = ucred.cr_pid;
+#else
+	*pid = 0;
+#endif
+	return 0;
+}
+#elif defined(SO_PEERCRED)
+int
+wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid)
+{
+	socklen_t len;
+#if defined(__OpenBSD__)
+	struct sockpeercred ucred;
+#else
+	struct ucred ucred;
+#endif
+
+	len = sizeof(ucred);
+	if (getsockopt(sockfd, SOL_SOCKET, SO_PEERCRED, &ucred, &len) < 0)
+		return -1;
+	*uid = ucred.uid;
+	*gid = ucred.gid;
+	*pid = ucred.pid;
+	return 0;
+}
+#else
+#error "Don't know how to read ucred on this platform"
+#endif
+
+int
+wl_os_dupfd_cloexec(int fd, int minfd)
+{
+	int newfd;
+
+	newfd = wl_fcntl(fd, F_DUPFD_CLOEXEC, minfd);
+	if (newfd >= 0)
+		return newfd;
+	if (errno != EINVAL)
+		return -1;
+
+	newfd = wl_fcntl(fd, F_DUPFD, minfd);
+	return set_cloexec_or_close(newfd);
+}
+
+static ssize_t
+recvmsg_cloexec_fallback(int sockfd, struct msghdr *msg, int flags)
+{
+	ssize_t len;
+	struct cmsghdr *cmsg;
+	unsigned char *data;
+	int *fd;
+	int *end;
+
+	len = wl_recvmsg(sockfd, msg, flags);
+	if (len == -1)
+		return -1;
+
+	if (!msg->msg_control || msg->msg_controllen == 0)
+		return len;
+
+	cmsg = CMSG_FIRSTHDR(msg);
+	for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+		if (cmsg->cmsg_level != SOL_SOCKET ||
+		    cmsg->cmsg_type != SCM_RIGHTS)
+			continue;
+
+		data = CMSG_DATA(cmsg);
+		end = (int *)(data + cmsg->cmsg_len - CMSG_LEN(0));
+		for (fd = (int *)data; fd < end; ++fd)
+			*fd = set_cloexec_or_close(*fd);
+	}
+
+	return len;
+}
+
+ssize_t
+wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags)
+{
+#if HAVE_BROKEN_MSG_CMSG_CLOEXEC
+	/*
+	 * FreeBSD had a broken implementation of MSG_CMSG_CLOEXEC between 2015
+	 * and 2021, so we have to use the non-MSG_CMSG_CLOEXEC fallback
+	 * directly when compiling against a version that does not include the
+	 * fix (https://cgit.freebsd.org/src/commit/?id=6ceacebdf52211).
+	 */
+#pragma message("Using fallback directly since MSG_CMSG_CLOEXEC is broken.")
+#else
+	ssize_t len;
+
+	len = wl_recvmsg(sockfd, msg, flags | MSG_CMSG_CLOEXEC);
+	if (len >= 0)
+		return len;
+	if (errno != EINVAL)
+		return -1;
+#endif
+	return recvmsg_cloexec_fallback(sockfd, msg, flags);
+}
+
+int
+wl_os_epoll_create_cloexec(void)
+{
+	int fd;
+
+#ifdef EPOLL_CLOEXEC
+	fd = wl_epoll_create1(EPOLL_CLOEXEC);
+	if (fd >= 0)
+		return fd;
+	if (errno != EINVAL)
+		return -1;
+#endif
+
+	fd = epoll_create(1);
+	return set_cloexec_or_close(fd);
+}
+
+int
+wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen)
+{
+	int fd;
+
+#ifdef HAVE_ACCEPT4
+	fd = accept4(sockfd, addr, addrlen, SOCK_CLOEXEC);
+	if (fd >= 0)
+		return fd;
+	if (errno != ENOSYS)
+		return -1;
+#endif
+
+	fd = accept(sockfd, addr, addrlen);
+	return set_cloexec_or_close(fd);
+}
+
+/*
+ * Fallback function for operating systems that don't implement
+ * mremap(MREMAP_MAYMOVE).
+ */
+void *
+wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size,
+		     ssize_t new_size, int prot, int flags)
+{
+	void *result;
+
+	/* Make sure any pending write is flushed. */
+	if (msync(old_data, *old_size, MS_SYNC) != 0)
+		return MAP_FAILED;
+
+	/* We could try mapping a new block immediately after the current one
+	 * with MAP_FIXED, however that is not guaranteed to work and breaks
+	 * on CHERI-enabled architectures since the data pointer will still
+	 * have the bounds of the previous allocation.
+	 */
+	result = mmap(NULL, new_size, prot, flags, fd, 0);
+	if (result == MAP_FAILED)
+		return MAP_FAILED;
+
+	if (munmap(old_data, *old_size) == 0)
+		*old_size = 0;
+
+	return result;
+}
diff --git a/subprojects/wayland/src/wayland-os.h b/subprojects/wayland/src/wayland-os.h
new file mode 100644
index 0000000000000000000000000000000000000000..068fd2fea3da8e0a13a3ab993fcc7d4c609a366d
--- /dev/null
+++ b/subprojects/wayland/src/wayland-os.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_OS_H
+#define WAYLAND_OS_H
+
+#include <sys/types.h>
+#include <sys/socket.h>
+
+int
+wl_os_socket_cloexec(int domain, int type, int protocol);
+
+int
+wl_os_socket_peercred(int sockfd, uid_t *uid, gid_t *gid, pid_t *pid);
+
+int
+wl_os_dupfd_cloexec(int fd, int minfd);
+
+ssize_t
+wl_os_recvmsg_cloexec(int sockfd, struct msghdr *msg, int flags);
+
+int
+wl_os_epoll_create_cloexec(void);
+
+int
+wl_os_accept_cloexec(int sockfd, struct sockaddr *addr, socklen_t *addrlen);
+
+void *
+wl_os_mremap_maymove(int fd, void *old_data, ssize_t *old_size,
+		     ssize_t new_size, int prot, int flags);
+
+
+/*
+ * The following are for wayland-os.c and the unit tests.
+ * Do not use them elsewhere.
+ */
+
+#ifdef __linux__
+
+#ifndef SOCK_CLOEXEC
+#define SOCK_CLOEXEC 02000000
+#endif
+
+#ifndef F_DUPFD_CLOEXEC
+#define F_DUPFD_CLOEXEC 1030
+#endif
+
+#ifndef MSG_CMSG_CLOEXEC
+#define MSG_CMSG_CLOEXEC 0x40000000
+#endif
+
+#endif /* __linux__ */
+
+#endif
diff --git a/subprojects/wayland/src/wayland-private.h b/subprojects/wayland/src/wayland-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..fe9120afd7efa5d550c6a2a83021d06e27619c12
--- /dev/null
+++ b/subprojects/wayland/src/wayland-private.h
@@ -0,0 +1,261 @@
+/*
+ * 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_PRIVATE_H
+#define WAYLAND_PRIVATE_H
+
+#include <stdarg.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+
+#define WL_HIDE_DEPRECATED 1
+
+#include "wayland-util.h"
+
+/* Invalid memory address */
+#define WL_ARRAY_POISON_PTR (void *) 4
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+#define WL_MAP_SERVER_SIDE 0
+#define WL_MAP_CLIENT_SIDE 1
+#define WL_SERVER_ID_START 0xff000000
+#define WL_MAP_MAX_OBJECTS 0x00f00000
+#define WL_CLOSURE_MAX_ARGS 20
+#define WL_BUFFER_DEFAULT_SIZE_POT 12
+#define WL_BUFFER_DEFAULT_MAX_SIZE (1 << WL_BUFFER_DEFAULT_SIZE_POT)
+
+/**
+ * Argument types used in signatures.
+ */
+enum wl_arg_type {
+	WL_ARG_INT = 'i',
+	WL_ARG_UINT = 'u',
+	WL_ARG_FIXED = 'f',
+	WL_ARG_STRING = 's',
+	WL_ARG_OBJECT = 'o',
+	WL_ARG_NEW_ID = 'n',
+	WL_ARG_ARRAY = 'a',
+	WL_ARG_FD = 'h',
+};
+
+struct wl_object {
+	const struct wl_interface *interface;
+	const void *implementation;
+	uint32_t id;
+};
+
+int
+wl_interface_equal(const struct wl_interface *iface1,
+		   const struct wl_interface *iface2);
+
+/* Flags for wl_map_insert_new and wl_map_insert_at.  Flags can be queried with
+ * wl_map_lookup_flags.  The current implementation has room for 1 bit worth of
+ * flags.  If more flags are ever added, the implementation of wl_map will have
+ * to change to allow for new flags */
+enum wl_map_entry_flags {
+	WL_MAP_ENTRY_LEGACY = (1 << 0), /* Server side only */
+	WL_MAP_ENTRY_ZOMBIE = (1 << 0) /* Client side only */
+};
+
+struct wl_map {
+	struct wl_array client_entries;
+	struct wl_array server_entries;
+	uint32_t side;
+	uint32_t free_list;
+};
+
+typedef enum wl_iterator_result (*wl_iterator_func_t)(void *element,
+						      void *data,
+						      uint32_t flags);
+
+void
+wl_map_init(struct wl_map *map, uint32_t side);
+
+void
+wl_map_release(struct wl_map *map);
+
+uint32_t
+wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data);
+
+int
+wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data);
+
+int
+wl_map_reserve_new(struct wl_map *map, uint32_t i);
+
+void
+wl_map_remove(struct wl_map *map, uint32_t i);
+
+void *
+wl_map_lookup(struct wl_map *map, uint32_t i);
+
+uint32_t
+wl_map_lookup_flags(struct wl_map *map, uint32_t i);
+
+void
+wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data);
+
+struct wl_connection *
+wl_connection_create(int fd, size_t max_buffer_size);
+
+int
+wl_connection_destroy(struct wl_connection *connection);
+
+void
+wl_connection_copy(struct wl_connection *connection, void *data, size_t size);
+
+void
+wl_connection_consume(struct wl_connection *connection, size_t size);
+
+int
+wl_connection_flush(struct wl_connection *connection);
+
+uint32_t
+wl_connection_pending_input(struct wl_connection *connection);
+
+int
+wl_connection_read(struct wl_connection *connection);
+
+int
+wl_connection_write(struct wl_connection *connection,
+		    const void *data, size_t count);
+
+int
+wl_connection_queue(struct wl_connection *connection,
+		    const void *data, size_t count);
+
+int
+wl_connection_get_fd(struct wl_connection *connection);
+
+struct wl_closure {
+	int count;
+	const struct wl_message *message;
+	uint32_t opcode;
+	uint32_t sender_id;
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	struct wl_list link;
+	struct wl_proxy *proxy;
+	struct wl_array extra[0];
+};
+
+struct argument_details {
+	enum wl_arg_type type;
+	int nullable;
+};
+
+const char *
+get_next_argument(const char *signature, struct argument_details *details);
+
+int
+arg_count_for_signature(const char *signature);
+
+int
+wl_message_count_arrays(const struct wl_message *message);
+
+int
+wl_message_get_since(const struct wl_message *message);
+
+void
+wl_argument_from_va_list(const char *signature, union wl_argument *args,
+			 int count, va_list ap);
+
+struct wl_closure *
+wl_closure_marshal(struct wl_object *sender,
+		    uint32_t opcode, union wl_argument *args,
+		    const struct wl_message *message);
+
+struct wl_closure *
+wl_closure_vmarshal(struct wl_object *sender,
+		    uint32_t opcode, va_list ap,
+		    const struct wl_message *message);
+
+struct wl_closure *
+wl_connection_demarshal(struct wl_connection *connection,
+			uint32_t size,
+			struct wl_map *objects,
+			const struct wl_message *message);
+
+bool
+wl_object_is_zombie(struct wl_map *map, uint32_t id);
+
+int
+wl_closure_lookup_objects(struct wl_closure *closure, struct wl_map *objects);
+
+enum wl_closure_invoke_flag {
+	WL_CLOSURE_INVOKE_CLIENT = (1 << 0),
+	WL_CLOSURE_INVOKE_SERVER = (1 << 1)
+};
+
+void
+wl_closure_invoke(struct wl_closure *closure, uint32_t flags,
+		  struct wl_object *target, uint32_t opcode, void *data);
+
+void
+wl_closure_dispatch(struct wl_closure *closure, wl_dispatcher_func_t dispatcher,
+		    struct wl_object *target, uint32_t opcode);
+
+int
+wl_closure_send(struct wl_closure *closure, struct wl_connection *connection);
+
+int
+wl_closure_queue(struct wl_closure *closure, struct wl_connection *connection);
+
+void
+wl_closure_print(struct wl_closure *closure,
+		 struct wl_object *target, int send, int discarded,
+		 uint32_t (*n_parse)(union wl_argument *arg),
+		 const char *queue_name);
+
+void
+wl_closure_destroy(struct wl_closure *closure);
+
+extern wl_log_func_t wl_log_handler;
+
+void wl_log(const char *fmt, ...);
+void wl_abort(const char *fmt, ...);
+
+struct wl_display;
+
+struct wl_array *
+wl_display_get_additional_shm_formats(struct wl_display *display);
+
+static inline void *
+zalloc(size_t s)
+{
+	return calloc(1, s);
+}
+
+void
+wl_connection_close_fds_in(struct wl_connection *connection, int max);
+
+void
+wl_connection_set_max_buffer_size(struct wl_connection *connection,
+				  size_t max_buffer_size);
+
+#endif
diff --git a/subprojects/wayland/src/wayland-server-core.h b/subprojects/wayland/src/wayland-server-core.h
new file mode 100644
index 0000000000000000000000000000000000000000..63d0f02d3e67325735dfa23385483904f3ffbecd
--- /dev/null
+++ b/subprojects/wayland/src/wayland-server-core.h
@@ -0,0 +1,713 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_SERVER_CORE_H
+#define WAYLAND_SERVER_CORE_H
+
+#include <sys/types.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include "wayland-util.h"
+#include "wayland-version.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+enum {
+	WL_EVENT_READABLE = 0x01,
+	WL_EVENT_WRITABLE = 0x02,
+	WL_EVENT_HANGUP   = 0x04,
+	WL_EVENT_ERROR    = 0x08
+};
+
+/** File descriptor dispatch function type
+ *
+ * Functions of this type are used as callbacks for file descriptor events.
+ *
+ * \param fd The file descriptor delivering the event.
+ * \param mask Describes the kind of the event as a bitwise-or of:
+ * \c WL_EVENT_READABLE, \c WL_EVENT_WRITABLE, \c WL_EVENT_HANGUP,
+ * \c WL_EVENT_ERROR.
+ * \param data The user data argument of the related wl_event_loop_add_fd()
+ * call.
+ * \return If the event source is registered for re-check with
+ * wl_event_source_check(): 0 for all done, 1 for needing a re-check.
+ * If not registered, the return value is ignored and should be zero.
+ *
+ * \sa wl_event_loop_add_fd()
+ * \memberof wl_event_source
+ */
+typedef int (*wl_event_loop_fd_func_t)(int fd, uint32_t mask, void *data);
+
+/** Timer dispatch function type
+ *
+ * Functions of this type are used as callbacks for timer expiry.
+ *
+ * \param data The user data argument of the related wl_event_loop_add_timer()
+ * call.
+ * \return If the event source is registered for re-check with
+ * wl_event_source_check(): 0 for all done, 1 for needing a re-check.
+ * If not registered, the return value is ignored and should be zero.
+ *
+ * \sa wl_event_loop_add_timer()
+ * \memberof wl_event_source
+ */
+typedef int (*wl_event_loop_timer_func_t)(void *data);
+
+/** Signal dispatch function type
+ *
+ * Functions of this type are used as callbacks for (POSIX) signals.
+ *
+ * \param signal_number
+ * \param data The user data argument of the related wl_event_loop_add_signal()
+ * call.
+ * \return If the event source is registered for re-check with
+ * wl_event_source_check(): 0 for all done, 1 for needing a re-check.
+ * If not registered, the return value is ignored and should be zero.
+ *
+ * \sa wl_event_loop_add_signal()
+ * \memberof wl_event_source
+ */
+typedef int (*wl_event_loop_signal_func_t)(int signal_number, void *data);
+
+/** Idle task function type
+ *
+ * Functions of this type are used as callbacks before blocking in
+ * wl_event_loop_dispatch().
+ *
+ * \param data The user data argument of the related wl_event_loop_add_idle()
+ * call.
+ *
+ * \sa wl_event_loop_add_idle() wl_event_loop_dispatch()
+ * \memberof wl_event_source
+ */
+typedef void (*wl_event_loop_idle_func_t)(void *data);
+
+/** \struct wl_event_loop
+ *
+ * \brief An event loop context
+ *
+ * Usually you create an event loop context, add sources to it, and call
+ * wl_event_loop_dispatch() in a loop to process events.
+ *
+ * \sa wl_event_source
+ */
+
+/** \struct wl_event_source
+ *
+ * \brief An abstract event source
+ *
+ * This is the generic type for fd, timer, signal, and idle sources.
+ * Functions that operate on specific source types must not be used with
+ * a different type, even if the function signature allows it.
+ */
+
+struct wl_event_loop *
+wl_event_loop_create(void);
+
+void
+wl_event_loop_destroy(struct wl_event_loop *loop);
+
+struct wl_event_source *
+wl_event_loop_add_fd(struct wl_event_loop *loop,
+		     int fd, uint32_t mask,
+		     wl_event_loop_fd_func_t func,
+		     void *data);
+
+int
+wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask);
+
+struct wl_event_source *
+wl_event_loop_add_timer(struct wl_event_loop *loop,
+			wl_event_loop_timer_func_t func,
+			void *data);
+
+struct wl_event_source *
+wl_event_loop_add_signal(struct wl_event_loop *loop,
+			 int signal_number,
+			 wl_event_loop_signal_func_t func,
+			 void *data);
+
+int
+wl_event_source_timer_update(struct wl_event_source *source,
+			     int ms_delay);
+
+int
+wl_event_source_remove(struct wl_event_source *source);
+
+void
+wl_event_source_check(struct wl_event_source *source);
+
+int
+wl_event_loop_dispatch(struct wl_event_loop *loop, int timeout);
+
+void
+wl_event_loop_dispatch_idle(struct wl_event_loop *loop);
+
+struct wl_event_source *
+wl_event_loop_add_idle(struct wl_event_loop *loop,
+		       wl_event_loop_idle_func_t func,
+		       void *data);
+
+int
+wl_event_loop_get_fd(struct wl_event_loop *loop);
+
+struct wl_listener;
+
+typedef void (*wl_notify_func_t)(struct wl_listener *listener, void *data);
+
+void
+wl_event_loop_add_destroy_listener(struct wl_event_loop *loop,
+				   struct wl_listener *listener);
+
+struct wl_listener *
+wl_event_loop_get_destroy_listener(struct wl_event_loop *loop,
+				   wl_notify_func_t notify);
+
+struct wl_display *
+wl_display_create(void);
+
+void
+wl_display_destroy(struct wl_display *display);
+
+struct wl_event_loop *
+wl_display_get_event_loop(struct wl_display *display);
+
+int
+wl_display_add_socket(struct wl_display *display, const char *name);
+
+const char *
+wl_display_add_socket_auto(struct wl_display *display);
+
+int
+wl_display_add_socket_fd(struct wl_display *display, int sock_fd);
+
+void
+wl_display_terminate(struct wl_display *display);
+
+void
+wl_display_run(struct wl_display *display);
+
+void
+wl_display_flush_clients(struct wl_display *display);
+
+void
+wl_display_destroy_clients(struct wl_display *display);
+
+void
+wl_display_set_default_max_buffer_size(struct wl_display *display,
+				       size_t max_buffer_size);
+
+struct wl_client;
+
+typedef void (*wl_global_bind_func_t)(struct wl_client *client, void *data,
+				      uint32_t version, uint32_t id);
+
+uint32_t
+wl_display_get_serial(struct wl_display *display);
+
+uint32_t
+wl_display_next_serial(struct wl_display *display);
+
+void
+wl_display_add_destroy_listener(struct wl_display *display,
+				struct wl_listener *listener);
+
+void
+wl_display_add_client_created_listener(struct wl_display *display,
+					struct wl_listener *listener);
+
+struct wl_listener *
+wl_display_get_destroy_listener(struct wl_display *display,
+				wl_notify_func_t notify);
+
+struct wl_global *
+wl_global_create(struct wl_display *display,
+		 const struct wl_interface *interface,
+		 int version,
+		 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
+ *
+ * \param client The client object
+ * \param global The global object to show or hide
+ * \param data   The user data pointer
+ *
+ * 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 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.
+ */
+typedef bool (*wl_display_global_filter_func_t)(const struct wl_client *client,
+						const struct wl_global *global,
+						void *data);
+
+void
+wl_display_set_global_filter(struct wl_display *display,
+			     wl_display_global_filter_func_t filter,
+			     void *data);
+
+const struct wl_interface *
+wl_global_get_interface(const struct wl_global *global);
+
+uint32_t
+wl_global_get_name(const struct wl_global *global,
+                   const struct wl_client *client);
+
+uint32_t
+wl_global_get_version(const struct wl_global *global);
+
+struct wl_display *
+wl_global_get_display(const struct wl_global *global);
+
+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);
+
+struct wl_list *
+wl_display_get_client_list(struct wl_display *display);
+
+struct wl_list *
+wl_client_get_link(struct wl_client *client);
+
+struct wl_client *
+wl_client_from_link(struct wl_list *link);
+
+/** Iterate over a list of clients. */
+#define wl_client_for_each(client, list)				\
+	for (client = wl_client_from_link((list)->next);	\
+	     wl_client_get_link(client) != (list);			\
+	     client = wl_client_from_link(wl_client_get_link(client)->next))
+
+void
+wl_client_destroy(struct wl_client *client);
+
+void
+wl_client_flush(struct wl_client *client);
+
+void
+wl_client_get_credentials(struct wl_client *client,
+			  pid_t *pid, uid_t *uid, gid_t *gid);
+
+int
+wl_client_get_fd(struct wl_client *client);
+
+void
+wl_client_add_destroy_listener(struct wl_client *client,
+			       struct wl_listener *listener);
+
+struct wl_listener *
+wl_client_get_destroy_listener(struct wl_client *client,
+			       wl_notify_func_t notify);
+
+void
+wl_client_add_destroy_late_listener(struct wl_client *client,
+				    struct wl_listener *listener);
+
+struct wl_listener *
+wl_client_get_destroy_late_listener(struct wl_client *client,
+				    wl_notify_func_t notify);
+
+struct wl_resource *
+wl_client_get_object(struct wl_client *client, uint32_t id);
+
+void
+wl_client_post_no_memory(struct wl_client *client);
+
+void
+wl_client_post_implementation_error(struct wl_client *client,
+                                    const char* msg, ...) WL_PRINTF(2,3);
+
+void
+wl_client_add_resource_created_listener(struct wl_client *client,
+                                        struct wl_listener *listener);
+
+typedef enum wl_iterator_result (*wl_client_for_each_resource_iterator_func_t)(
+						struct wl_resource *resource,
+						void *user_data);
+
+void
+wl_client_for_each_resource(struct wl_client *client,
+                            wl_client_for_each_resource_iterator_func_t iterator,
+                            void *user_data);
+
+typedef void (*wl_user_data_destroy_func_t)(void *data);
+
+void
+wl_client_set_user_data(struct wl_client *client,
+			void *data,
+			wl_user_data_destroy_func_t dtor);
+
+void *
+wl_client_get_user_data(struct wl_client *client);
+
+void
+wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size);
+
+/** \class wl_listener
+ *
+ * \brief A single listener for Wayland signals
+ *
+ * wl_listener provides the means to listen for wl_signal notifications. Many
+ * Wayland objects use wl_listener for notification of significant events like
+ * object destruction.
+ *
+ * Clients should create wl_listener objects manually and can register them as
+ * listeners to signals using #wl_signal_add, assuming the signal is
+ * directly accessible. For opaque structs like wl_event_loop, adding a
+ * listener should be done through provided accessor methods. A listener can
+ * only listen to one signal at a time.
+ *
+ * \code
+ * struct wl_listener your_listener;
+ *
+ * your_listener.notify = your_callback_method;
+ *
+ * // Direct access
+ * wl_signal_add(&some_object->destroy_signal, &your_listener);
+ *
+ * // Accessor access
+ * wl_event_loop *loop = ...;
+ * wl_event_loop_add_destroy_listener(loop, &your_listener);
+ * \endcode
+ *
+ * If the listener is part of a larger struct, #wl_container_of can be used
+ * to retrieve a pointer to it:
+ *
+ * \code
+ * void your_listener(struct wl_listener *listener, void *data)
+ * {
+ * 	struct your_data *data;
+ *
+ * 	your_data = wl_container_of(listener, data, your_member_name);
+ * }
+ * \endcode
+ *
+ * If you need to remove a listener from a signal, use wl_list_remove().
+ *
+ * \code
+ * wl_list_remove(&your_listener.link);
+ * \endcode
+ *
+ * \sa wl_signal
+ */
+struct wl_listener {
+	struct wl_list link;
+	wl_notify_func_t notify;
+};
+
+/** \class wl_signal
+ *
+ * \brief A source of a type of observable event
+ *
+ * Signals are recognized points where significant events can be observed.
+ * Compositors as well as the server can provide signals. Observers are
+ * wl_listener's that are added through #wl_signal_add. Signals are emitted
+ * using #wl_signal_emit, which will invoke all listeners until that
+ * listener is removed by wl_list_remove() (or whenever the signal is
+ * destroyed).
+ *
+ * \sa wl_listener for more information on using wl_signal
+ */
+struct wl_signal {
+	struct wl_list listener_list;
+};
+
+/** Initialize a new \ref wl_signal for use.
+ *
+ * \param signal The signal that will be initialized
+ *
+ * \memberof wl_signal
+ */
+static inline void
+wl_signal_init(struct wl_signal *signal)
+{
+	wl_list_init(&signal->listener_list);
+}
+
+/** Add the specified listener to this signal.
+ *
+ * \param signal The signal that will emit events to the listener
+ * \param listener The listener to add
+ *
+ * \memberof wl_signal
+ */
+static inline void
+wl_signal_add(struct wl_signal *signal, struct wl_listener *listener)
+{
+	wl_list_insert(signal->listener_list.prev, &listener->link);
+}
+
+/** Gets the listener struct for the specified callback.
+ *
+ * \param signal The signal that contains the specified listener
+ * \param notify The listener that is the target of this search
+ * \return the list item that corresponds to the specified listener, or NULL
+ * if none was found
+ *
+ * \memberof wl_signal
+ */
+static inline struct wl_listener *
+wl_signal_get(struct wl_signal *signal, wl_notify_func_t notify)
+{
+	struct wl_listener *l;
+
+	wl_list_for_each(l, &signal->listener_list, link)
+		if (l->notify == notify)
+			return l;
+
+	return NULL;
+}
+
+/** Emits this signal, notifying all registered listeners.
+ *
+ * \param signal The signal object that will emit the signal
+ * \param data The data that will be emitted with the signal
+ *
+ * \memberof wl_signal
+ */
+static inline void
+wl_signal_emit(struct wl_signal *signal, void *data)
+{
+	struct wl_listener *l, *next;
+
+	wl_list_for_each_safe(l, next, &signal->listener_list, link)
+		l->notify(l, data);
+}
+
+void
+wl_signal_emit_mutable(struct wl_signal *signal, void *data);
+
+typedef void (*wl_resource_destroy_func_t)(struct wl_resource *resource);
+
+/*
+ * Post an event to the client's object referred to by 'resource'.
+ * 'opcode' is the event number generated from the protocol XML
+ * description (the event name). The variable arguments are the event
+ * parameters, in the order they appear in the protocol XML specification.
+ *
+ * The variable arguments' types are:
+ * - type=uint:	uint32_t
+ * - type=int:		int32_t
+ * - type=fixed:	wl_fixed_t
+ * - type=string:	(const char *) to a nil-terminated string
+ * - type=array:	(struct wl_array *)
+ * - type=fd:		int, that is an open file descriptor
+ * - type=new_id:	(struct wl_object *) or (struct wl_resource *)
+ * - type=object:	(struct wl_object *) or (struct wl_resource *)
+ */
+void
+wl_resource_post_event(struct wl_resource *resource,
+		       uint32_t opcode, ...);
+
+void
+wl_resource_post_event_array(struct wl_resource *resource,
+			     uint32_t opcode, union wl_argument *args);
+
+void
+wl_resource_queue_event(struct wl_resource *resource,
+			uint32_t opcode, ...);
+
+void
+wl_resource_queue_event_array(struct wl_resource *resource,
+			      uint32_t opcode, union wl_argument *args);
+
+/* msg is a printf format string, variable args are its args. */
+void
+wl_resource_post_error(struct wl_resource *resource,
+		       uint32_t code, const char *msg, ...) WL_PRINTF(3, 4);
+
+void
+wl_resource_post_no_memory(struct wl_resource *resource);
+
+struct wl_display *
+wl_client_get_display(struct wl_client *client);
+
+struct wl_resource *
+wl_resource_create(struct wl_client *client,
+		   const struct wl_interface *interface,
+		   int version, uint32_t id);
+
+void
+wl_resource_set_implementation(struct wl_resource *resource,
+			       const void *implementation,
+			       void *data,
+			       wl_resource_destroy_func_t destroy);
+
+void
+wl_resource_set_dispatcher(struct wl_resource *resource,
+			   wl_dispatcher_func_t dispatcher,
+			   const void *implementation,
+			   void *data,
+			   wl_resource_destroy_func_t destroy);
+
+void
+wl_resource_destroy(struct wl_resource *resource);
+
+uint32_t
+wl_resource_get_id(struct wl_resource *resource);
+
+struct wl_list *
+wl_resource_get_link(struct wl_resource *resource);
+
+struct wl_resource *
+wl_resource_from_link(struct wl_list *resource);
+
+struct wl_resource *
+wl_resource_find_for_client(struct wl_list *list, struct wl_client *client);
+
+struct wl_client *
+wl_resource_get_client(struct wl_resource *resource);
+
+void
+wl_resource_set_user_data(struct wl_resource *resource, void *data);
+
+void *
+wl_resource_get_user_data(struct wl_resource *resource);
+
+int
+wl_resource_get_version(struct wl_resource *resource);
+
+void
+wl_resource_set_destructor(struct wl_resource *resource,
+			   wl_resource_destroy_func_t destroy);
+
+int
+wl_resource_instance_of(struct wl_resource *resource,
+			const struct wl_interface *interface,
+			const void *implementation);
+const char *
+wl_resource_get_class(struct wl_resource *resource);
+
+void
+wl_resource_add_destroy_listener(struct wl_resource *resource,
+				 struct wl_listener *listener);
+
+struct wl_listener *
+wl_resource_get_destroy_listener(struct wl_resource *resource,
+				 wl_notify_func_t notify);
+
+#define wl_resource_for_each(resource, list)					\
+	for (resource = 0, resource = wl_resource_from_link((list)->next);	\
+	     wl_resource_get_link(resource) != (list);				\
+	     resource = wl_resource_from_link(wl_resource_get_link(resource)->next))
+
+#define wl_resource_for_each_safe(resource, tmp, list)					\
+	for (resource = 0, tmp = 0,							\
+	     resource = wl_resource_from_link((list)->next),	\
+	     tmp = wl_resource_from_link((list)->next->next);	\
+	     wl_resource_get_link(resource) != (list);				\
+	     resource = tmp,							\
+	     tmp = wl_resource_from_link(wl_resource_get_link(resource)->next))
+
+struct wl_shm_buffer *
+wl_shm_buffer_get(struct wl_resource *resource);
+
+void
+wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer);
+
+void
+wl_shm_buffer_end_access(struct wl_shm_buffer *buffer);
+
+void *
+wl_shm_buffer_get_data(struct wl_shm_buffer *buffer);
+
+int32_t
+wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer);
+
+uint32_t
+wl_shm_buffer_get_format(struct wl_shm_buffer *buffer);
+
+int32_t
+wl_shm_buffer_get_width(struct wl_shm_buffer *buffer);
+
+int32_t
+wl_shm_buffer_get_height(struct wl_shm_buffer *buffer);
+
+struct wl_shm_pool *
+wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer);
+
+void
+wl_shm_pool_unref(struct wl_shm_pool *pool);
+
+int
+wl_display_init_shm(struct wl_display *display);
+
+uint32_t *
+wl_display_add_shm_format(struct wl_display *display, uint32_t format);
+
+struct wl_shm_buffer *
+wl_shm_buffer_create(struct wl_client *client,
+		     uint32_t id, int32_t width, int32_t height,
+		     int32_t stride, uint32_t format) WL_DEPRECATED;
+
+void
+wl_log_set_handler_server(wl_log_func_t handler);
+
+enum wl_protocol_logger_type {
+	WL_PROTOCOL_LOGGER_REQUEST,
+	WL_PROTOCOL_LOGGER_EVENT,
+};
+
+struct wl_protocol_logger_message {
+	struct wl_resource *resource;
+	int message_opcode;
+	const struct wl_message *message;
+	int arguments_count;
+	const union wl_argument *arguments;
+};
+
+typedef void (*wl_protocol_logger_func_t)(void *user_data,
+					  enum wl_protocol_logger_type direction,
+					  const struct wl_protocol_logger_message *message);
+
+struct wl_protocol_logger *
+wl_display_add_protocol_logger(struct wl_display *display,
+			       wl_protocol_logger_func_t, void *user_data);
+
+void
+wl_protocol_logger_destroy(struct wl_protocol_logger *logger);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/src/wayland-server-private.h b/subprojects/wayland/src/wayland-server-private.h
new file mode 100644
index 0000000000000000000000000000000000000000..23fa4587689822d4c07dd95b75b1cf30f5e510a5
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/src/wayland-server.c b/subprojects/wayland/src/wayland-server.c
new file mode 100644
index 0000000000000000000000000000000000000000..2e18563487ce312b27bdf9006bd2a3d625807bac
--- /dev/null
+++ b/subprojects/wayland/src/wayland-server.c
@@ -0,0 +1,2630 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+#include <dlfcn.h>
+#include <assert.h>
+#include <sys/time.h>
+#include <fcntl.h>
+#include <sys/eventfd.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+
+#include "wayland-util.h"
+#include "wayland-private.h"
+#include "wayland-server-private.h"
+#include "wayland-server.h"
+#include "wayland-os.h"
+
+/* This is the size of the char array in struct sock_addr_un.
+ * No Wayland socket can be created with a path longer than this,
+ * including the null terminator.
+ */
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX	108
+#endif
+
+#define LOCK_SUFFIX	".lock"
+#define LOCK_SUFFIXLEN	5
+
+struct wl_socket {
+	int fd;
+	int fd_lock;
+	struct sockaddr_un addr;
+	char lock_addr[UNIX_PATH_MAX + LOCK_SUFFIXLEN];
+	struct wl_list link;
+	struct wl_event_source *source;
+	char *display_name;
+};
+
+struct wl_client {
+	struct wl_connection *connection;
+	struct wl_event_source *source;
+	struct wl_display *display;
+	struct wl_resource *display_resource;
+	struct wl_list link;
+	struct wl_map objects;
+	struct wl_priv_signal destroy_signal;
+	struct wl_priv_signal destroy_late_signal;
+	pid_t pid;
+	uid_t uid;
+	gid_t gid;
+	bool error;
+	struct wl_priv_signal resource_created_signal;
+	void *data;
+	wl_user_data_destroy_func_t data_dtor;
+};
+
+struct wl_display {
+	struct wl_event_loop *loop;
+	bool run;
+
+	uint32_t next_global_name;
+	uint32_t serial;
+
+	struct wl_list registry_resource_list;
+	struct wl_list global_list;
+	struct wl_list socket_list;
+	struct wl_list client_list;
+	struct wl_list protocol_loggers;
+
+	struct wl_priv_signal destroy_signal;
+	struct wl_priv_signal create_client_signal;
+
+	struct wl_array additional_shm_formats;
+
+	wl_display_global_filter_func_t global_filter;
+	void *global_filter_data;
+
+	int terminate_efd;
+	struct wl_event_source *term_source;
+
+	size_t max_buffer_size;
+};
+
+struct wl_global {
+	struct wl_display *display;
+	const struct wl_interface *interface;
+	uint32_t name;
+	uint32_t version;
+	void *data;
+	wl_global_bind_func_t bind;
+	struct wl_list link;
+	bool removed;
+};
+
+struct wl_resource {
+	struct wl_object object;
+	wl_resource_destroy_func_t destroy;
+	struct wl_list link;
+	/* Unfortunately some users of libwayland (e.g. mesa) still use the
+	 * deprecated wl_resource struct, even if creating it with the new
+	 * wl_resource_create(). So we cannot change the layout of the struct
+	 * unless after the data field. */
+	struct wl_signal deprecated_destroy_signal;
+	struct wl_client *client;
+	void *data;
+	int version;
+	wl_dispatcher_func_t dispatcher;
+	struct wl_priv_signal destroy_signal;
+};
+
+struct wl_protocol_logger {
+	struct wl_list link;
+	wl_protocol_logger_func_t func;
+	void *user_data;
+};
+
+static int debug_server = 0;
+
+static void
+log_closure(struct wl_resource *resource,
+	    struct wl_closure *closure, int send)
+{
+	struct wl_object *object = &resource->object;
+	struct wl_display *display = resource->client->display;
+	struct wl_protocol_logger *protocol_logger;
+	struct wl_protocol_logger_message message;
+
+	if (debug_server)
+		wl_closure_print(closure, object, send, false, NULL, NULL);
+
+	if (!wl_list_empty(&display->protocol_loggers)) {
+		message.resource = resource;
+		message.message_opcode = closure->opcode;
+		message.message = closure->message;
+		message.arguments_count = closure->count;
+		message.arguments = closure->args;
+		wl_list_for_each(protocol_logger,
+				 &display->protocol_loggers, link) {
+			protocol_logger->func(protocol_logger->user_data,
+					      send ? WL_PROTOCOL_LOGGER_EVENT :
+						     WL_PROTOCOL_LOGGER_REQUEST,
+					      &message);
+		}
+	}
+}
+
+static bool
+verify_objects(struct wl_resource *resource, uint32_t opcode,
+	       union wl_argument *args)
+{
+	struct wl_object *object = &resource->object;
+	const char *signature = object->interface->events[opcode].signature;
+	struct argument_details arg;
+	struct wl_resource *res;
+	int count, i;
+
+	count = arg_count_for_signature(signature);
+	for (i = 0; i < count; i++) {
+		signature = get_next_argument(signature, &arg);
+		switch (arg.type) {
+		case WL_ARG_NEW_ID:
+		case WL_ARG_OBJECT:
+			res = (struct wl_resource *) (args[i].o);
+			if (res && res->client != resource->client) {
+				wl_log("compositor bug: The compositor "
+				       "tried to use an object from one "
+				       "client in a '%s.%s' for a different "
+				       "client.\n", object->interface->name,
+				       object->interface->events[opcode].name);
+				return false;
+			}
+		default:
+			break;
+		}
+	}
+	return true;
+}
+
+static void
+handle_array(struct wl_resource *resource, uint32_t opcode,
+	     union wl_argument *args,
+	     int (*send_func)(struct wl_closure *, struct wl_connection *))
+{
+	struct wl_closure *closure;
+	struct wl_object *object = &resource->object;
+
+	if (resource->client->error)
+		return;
+
+	if (!verify_objects(resource, opcode, args)) {
+		resource->client->error = true;
+		return;
+	}
+
+	closure = wl_closure_marshal(object, opcode, args,
+				     &object->interface->events[opcode]);
+
+	if (closure == NULL) {
+		resource->client->error = true;
+		return;
+	}
+
+	log_closure(resource, closure, true);
+
+	if (send_func(closure, resource->client->connection))
+		resource->client->error = true;
+
+	wl_closure_destroy(closure);
+}
+
+WL_EXPORT void
+wl_resource_post_event_array(struct wl_resource *resource, uint32_t opcode,
+			     union wl_argument *args)
+{
+	handle_array(resource, opcode, args, wl_closure_send);
+}
+
+WL_EXPORT void
+wl_resource_post_event(struct wl_resource *resource, uint32_t opcode, ...)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	struct wl_object *object = &resource->object;
+	va_list ap;
+
+	va_start(ap, opcode);
+	wl_argument_from_va_list(object->interface->events[opcode].signature,
+				 args, WL_CLOSURE_MAX_ARGS, ap);
+	va_end(ap);
+
+	wl_resource_post_event_array(resource, opcode, args);
+}
+
+
+WL_EXPORT void
+wl_resource_queue_event_array(struct wl_resource *resource, uint32_t opcode,
+			      union wl_argument *args)
+{
+	handle_array(resource, opcode, args, wl_closure_queue);
+}
+
+WL_EXPORT void
+wl_resource_queue_event(struct wl_resource *resource, uint32_t opcode, ...)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	struct wl_object *object = &resource->object;
+	va_list ap;
+
+	va_start(ap, opcode);
+	wl_argument_from_va_list(object->interface->events[opcode].signature,
+				 args, WL_CLOSURE_MAX_ARGS, ap);
+	va_end(ap);
+
+	wl_resource_queue_event_array(resource, opcode, args);
+}
+
+static void
+wl_resource_post_error_vargs(struct wl_resource *resource,
+			     uint32_t code, const char *msg, va_list argp)
+{
+	struct wl_client *client = resource->client;
+	char buffer[128];
+
+	vsnprintf(buffer, sizeof buffer, msg, argp);
+
+	/*
+	 * When a client aborts, its resources are destroyed in id order,
+	 * which means the display resource is destroyed first. If destruction
+	 * of any later resources results in a protocol error, we end up here
+	 * with a NULL display_resource. Do not try to send errors to an
+	 * already dead client.
+	 */
+	if (client->error || !client->display_resource)
+		return;
+
+	wl_resource_post_event(client->display_resource,
+			       WL_DISPLAY_ERROR, resource, code, buffer);
+	client->error = true;
+
+}
+
+WL_EXPORT void
+wl_resource_post_error(struct wl_resource *resource,
+		       uint32_t code, const char *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	wl_resource_post_error_vargs(resource, code, msg, ap);
+	va_end(ap);
+}
+
+static void
+destroy_client_with_error(struct wl_client *client, const char *reason)
+{
+	wl_log("%s (pid %u)\n", reason, client->pid);
+	wl_client_destroy(client);
+}
+
+static int
+wl_client_connection_data(int fd, uint32_t mask, void *data)
+{
+	struct wl_client *client = data;
+	struct wl_connection *connection = client->connection;
+	struct wl_resource *resource;
+	struct wl_object *object;
+	struct wl_closure *closure;
+	const struct wl_message *message;
+	uint32_t p[2];
+	uint32_t resource_flags;
+	int opcode, size, since;
+	int len;
+
+	if (mask & WL_EVENT_HANGUP) {
+		wl_client_destroy(client);
+		return 1;
+	}
+
+	if (mask & WL_EVENT_ERROR) {
+		destroy_client_with_error(client, "socket error");
+		return 1;
+	}
+
+	if (mask & WL_EVENT_WRITABLE) {
+		len = wl_connection_flush(connection);
+		if (len < 0 && errno != EAGAIN) {
+			destroy_client_with_error(
+			    client, "failed to flush client connection");
+			return 1;
+		} else if (len >= 0) {
+			wl_event_source_fd_update(client->source,
+						  WL_EVENT_READABLE);
+		}
+	}
+
+	len = 0;
+	if (mask & WL_EVENT_READABLE) {
+		len = wl_connection_read(connection);
+		if (len == 0 || (len < 0 && errno != EAGAIN)) {
+			destroy_client_with_error(
+			    client, "failed to read client connection");
+			return 1;
+		}
+	}
+
+	while (len >= 0 && (size_t) len >= sizeof p) {
+		wl_connection_copy(connection, p, sizeof p);
+		opcode = p[1] & 0xffff;
+		size = p[1] >> 16;
+		if (len < size)
+			break;
+
+		resource = wl_map_lookup(&client->objects, p[0]);
+		resource_flags = wl_map_lookup_flags(&client->objects, p[0]);
+		if (resource == NULL) {
+			wl_resource_post_error(client->display_resource,
+					       WL_DISPLAY_ERROR_INVALID_OBJECT,
+					       "invalid object %u", p[0]);
+			break;
+		}
+
+		object = &resource->object;
+		if (opcode >= object->interface->method_count) {
+			wl_resource_post_error(client->display_resource,
+					       WL_DISPLAY_ERROR_INVALID_METHOD,
+					       "invalid method %d, object %s#%u",
+					       opcode,
+					       object->interface->name,
+					       object->id);
+			break;
+		}
+
+		message = &object->interface->methods[opcode];
+		since = wl_message_get_since(message);
+		if (!(resource_flags & WL_MAP_ENTRY_LEGACY) &&
+		    resource->version > 0 && resource->version < since) {
+			wl_resource_post_error(client->display_resource,
+					       WL_DISPLAY_ERROR_INVALID_METHOD,
+					       "invalid method %d (since %d < %d)"
+					       ", object %s#%u",
+					       opcode, resource->version, since,
+					       object->interface->name,
+					       object->id);
+			break;
+		}
+
+
+		closure = wl_connection_demarshal(client->connection, size,
+						  &client->objects, message);
+
+		if (closure == NULL && errno == ENOMEM) {
+			wl_resource_post_no_memory(resource);
+			break;
+		} else if (closure == NULL ||
+			   wl_closure_lookup_objects(closure, &client->objects) < 0) {
+			wl_resource_post_error(client->display_resource,
+					       WL_DISPLAY_ERROR_INVALID_METHOD,
+					       "invalid arguments for %s#%u.%s",
+					       object->interface->name,
+					       object->id,
+					       message->name);
+			wl_closure_destroy(closure);
+			break;
+		}
+
+		log_closure(resource, closure, false);
+
+		if ((resource_flags & WL_MAP_ENTRY_LEGACY) ||
+		    resource->dispatcher == NULL) {
+			wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER,
+					  object, opcode, client);
+		} else {
+			wl_closure_dispatch(closure, resource->dispatcher,
+					    object, opcode);
+		}
+
+		wl_closure_destroy(closure);
+
+		if (client->error)
+			break;
+
+		len = wl_connection_pending_input(connection);
+	}
+
+	if (client->error) {
+		destroy_client_with_error(client,
+					  "error in client communication");
+	}
+
+	return 1;
+}
+
+/** Flush pending events to the client
+ *
+ * \param client The client object
+ *
+ * Events sent to clients are queued in a buffer and written to the
+ * socket later - typically when the compositor has handled all
+ * requests and goes back to block in the event loop.  This function
+ * flushes all queued up events for a client immediately.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_flush(struct wl_client *client)
+{
+	wl_connection_flush(client->connection);
+}
+
+/** Get the display object for the given client
+ *
+ * \param client The client object
+ * \return The display object the client is associated with.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT struct wl_display *
+wl_client_get_display(struct wl_client *client)
+{
+	return client->display;
+}
+
+static int
+bind_display(struct wl_client *client, struct wl_display *display);
+
+/** Create a client for the given file descriptor
+ *
+ * \param display The display object
+ * \param fd The file descriptor for the socket to the client
+ * \return The new client object or NULL on failure.
+ *
+ * Given a file descriptor corresponding to one end of a socket, this
+ * function will create a wl_client struct and add the new client to
+ * the compositors client list.  At that point, the client is
+ * initialized and ready to run, as if the client had connected to the
+ * servers listening socket.  When the client eventually sends
+ * requests to the compositor, the wl_client argument to the request
+ * handler will be the wl_client returned from this function.
+ *
+ * The other end of the socket can be passed to
+ * wl_display_connect_to_fd() on the client side or used with the
+ * WAYLAND_SOCKET environment variable on the client side.
+ *
+ * Listeners added with wl_display_add_client_created_listener() will
+ * be notified by this function after the client is fully constructed.
+ *
+ * On failure this function sets errno accordingly and returns NULL.
+ *
+ * On success, the new client object takes the ownership of the file
+ * descriptor. On failure, the ownership of the socket endpoint file
+ * descriptor is unchanged, it is the responsibility of the caller to
+ * perform cleanup, e.g. call close().
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_client *
+wl_client_create(struct wl_display *display, int fd)
+{
+	struct wl_client *client;
+
+	client = zalloc(sizeof *client);
+	if (client == NULL)
+		return NULL;
+
+	wl_priv_signal_init(&client->resource_created_signal);
+	client->display = display;
+	client->source = wl_event_loop_add_fd(display->loop, fd,
+					      WL_EVENT_READABLE,
+					      wl_client_connection_data, client);
+
+	if (!client->source)
+		goto err_client;
+
+	if (wl_os_socket_peercred(fd, &client->uid, &client->gid,
+				  &client->pid) != 0)
+		goto err_source;
+
+	client->connection = wl_connection_create(fd, display->max_buffer_size);
+
+	if (client->connection == NULL)
+		goto err_source;
+
+	wl_map_init(&client->objects, WL_MAP_SERVER_SIDE);
+
+	if (wl_map_insert_at(&client->objects, 0, 0, NULL) < 0)
+		goto err_map;
+
+	wl_priv_signal_init(&client->destroy_signal);
+	wl_priv_signal_init(&client->destroy_late_signal);
+	if (bind_display(client, display) < 0)
+		goto err_map;
+
+	wl_list_insert(display->client_list.prev, &client->link);
+
+	wl_priv_signal_emit(&display->create_client_signal, client);
+
+	return client;
+
+err_map:
+	wl_map_release(&client->objects);
+	wl_connection_destroy(client->connection);
+err_source:
+	wl_event_source_remove(client->source);
+err_client:
+	free(client);
+	return NULL;
+}
+
+/** Return Unix credentials for the client
+ *
+ * \param client The display object
+ * \param pid Returns the process ID
+ * \param uid Returns the user ID
+ * \param gid Returns the group ID
+ *
+ * This function returns the process ID, the user ID and the group ID
+ * for the given client.  The credentials come from getsockopt() with
+ * SO_PEERCRED, on the client socket fd.  All the pointers can be
+ * NULL, if the caller is not interested in a particular ID.
+ *
+ * Note, process IDs are subject to race conditions and are not a reliable way
+ * to identify a client.
+ *
+ * Be aware that for clients that a compositor forks and execs and
+ * then connects using socketpair(), this function will return the
+ * credentials for the compositor.  The credentials for the socketpair
+ * are set at creation time in the compositor.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_get_credentials(struct wl_client *client,
+			  pid_t *pid, uid_t *uid, gid_t *gid)
+{
+	if (pid)
+		*pid = client->pid;
+	if (uid)
+		*uid = client->uid;
+	if (gid)
+		*gid = client->gid;
+}
+
+/** Get the file descriptor for the client
+ *
+ * \param client The display object
+ * \return The file descriptor to use for the connection
+ *
+ * This function returns the file descriptor for the given client.
+ *
+ * Be sure to use the file descriptor from the client for inspection only.
+ * If the caller does anything to the file descriptor that changes its state,
+ * it will likely cause problems.
+ *
+ * See also wl_client_get_credentials().
+ * It is recommended that you evaluate whether wl_client_get_credentials()
+ * can be applied to your use case instead of this function.
+ *
+ * If you would like to distinguish just between the client and the compositor
+ * itself from the client's request, it can be done by getting the client
+ * credentials and by checking the PID of the client and the compositor's PID.
+ * Regarding the case in which the socketpair() is being used, you need to be
+ * careful. Please note the documentation for wl_client_get_credentials().
+ *
+ * This function can be used for a compositor to validate a request from
+ * a client if there are additional information provided from the client's
+ * file descriptor. For instance, suppose you can get the security contexts
+ * from the client's file descriptor. The compositor can validate the client's
+ * request with the contexts and make a decision whether it permits or deny it.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT int
+wl_client_get_fd(struct wl_client *client)
+{
+	return wl_connection_get_fd(client->connection);
+}
+
+/** Look up an object in the client name space
+ *
+ * \param client The client object
+ * \param id The object id
+ * \return The object or NULL if there is not object for the given ID
+ *
+ * This looks up an object in the client object name space by its
+ * object ID.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT struct wl_resource *
+wl_client_get_object(struct wl_client *client, uint32_t id)
+{
+	return wl_map_lookup(&client->objects, id);
+}
+
+WL_EXPORT void
+wl_client_post_no_memory(struct wl_client *client)
+{
+	wl_resource_post_error(client->display_resource,
+			       WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
+}
+
+/** Report an internal server error
+ *
+ * \param client The client object
+ * \param msg A printf-style format string
+ * \param ... Format string arguments
+ *
+ * Report an unspecified internal implementation error and disconnect
+ * the client.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_post_implementation_error(struct wl_client *client,
+				    char const *msg, ...)
+{
+	va_list ap;
+
+	va_start(ap, msg);
+	wl_resource_post_error_vargs(client->display_resource,
+				     WL_DISPLAY_ERROR_IMPLEMENTATION,
+				     msg, ap);
+	va_end(ap);
+}
+
+WL_EXPORT void
+wl_resource_post_no_memory(struct wl_resource *resource)
+{
+	wl_resource_post_error(resource->client->display_resource,
+			       WL_DISPLAY_ERROR_NO_MEMORY, "no memory");
+}
+
+/** Detect if a wl_resource uses the deprecated public definition.
+ *
+ * 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
+ * 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 compatibility.
+ */
+static bool
+resource_is_deprecated(struct wl_resource *resource)
+{
+	struct wl_map *map = &resource->client->objects;
+	int id = resource->object.id;
+
+	/* wl_client_add_resource() marks deprecated resources with the flag. */
+	if (wl_map_lookup_flags(map, id) & WL_MAP_ENTRY_LEGACY)
+		return true;
+
+	return false;
+}
+
+/** Removes the wl_resource from the client's object map and deletes it.
+ *
+ * Triggers the destroy signal and destructor for the resource before
+ * removing it from the client's object map and releasing the resource's
+ * memory.
+ *
+ * This order is important to ensure listeners and destruction code can
+ * find the resource before it has been destroyed whilst ensuring the
+ * resource is not accessible via the object map after memory has been
+ * freed.
+ */
+static enum wl_iterator_result
+remove_and_destroy_resource(void *element, void *data, uint32_t flags)
+{
+	struct wl_resource *resource = element;
+	struct wl_client *client = resource->client;
+	uint32_t id = resource->object.id;;
+
+	wl_signal_emit(&resource->deprecated_destroy_signal, resource);
+	/* Don't emit the new signal for deprecated resources, as that would
+	 * access memory outside the bounds of the deprecated struct */
+	if (!resource_is_deprecated(resource))
+		wl_priv_signal_final_emit(&resource->destroy_signal, resource);
+
+	if (resource->destroy)
+		resource->destroy(resource);
+
+	/* The resource should be cleared from the map before memory is freed. */
+	if (id < WL_SERVER_ID_START) {
+		if (client->display_resource) {
+			wl_resource_queue_event(client->display_resource,
+						WL_DISPLAY_DELETE_ID, id);
+		}
+		wl_map_insert_at(&client->objects, 0, id, NULL);
+	} else {
+		wl_map_remove(&client->objects, id);
+	}
+
+	if (!(flags & WL_MAP_ENTRY_LEGACY))
+		free(resource);
+
+	return WL_ITERATOR_CONTINUE;
+}
+
+WL_EXPORT void
+wl_resource_destroy(struct wl_resource *resource)
+{
+	struct wl_client *client = resource->client;
+	uint32_t flags = wl_map_lookup_flags(&client->objects, resource->object.id);
+
+	remove_and_destroy_resource(resource, NULL, flags);
+}
+
+WL_EXPORT uint32_t
+wl_resource_get_id(struct wl_resource *resource)
+{
+	return resource->object.id;
+}
+
+WL_EXPORT struct wl_list *
+wl_resource_get_link(struct wl_resource *resource)
+{
+	return &resource->link;
+}
+
+WL_EXPORT struct wl_resource *
+wl_resource_from_link(struct wl_list *link)
+{
+	struct wl_resource *resource;
+
+	return wl_container_of(link, resource, link);
+}
+
+WL_EXPORT struct wl_resource *
+wl_resource_find_for_client(struct wl_list *list, struct wl_client *client)
+{
+	struct wl_resource *resource;
+
+	if (client == NULL)
+		return NULL;
+
+	wl_list_for_each(resource, list, link) {
+		if (resource->client == client)
+			return resource;
+	}
+
+	return NULL;
+}
+
+WL_EXPORT struct wl_client *
+wl_resource_get_client(struct wl_resource *resource)
+{
+	return resource->client;
+}
+
+WL_EXPORT void
+wl_resource_set_user_data(struct wl_resource *resource, void *data)
+{
+	resource->data = data;
+}
+
+WL_EXPORT void *
+wl_resource_get_user_data(struct wl_resource *resource)
+{
+	return resource->data;
+}
+
+WL_EXPORT int
+wl_resource_get_version(struct wl_resource *resource)
+{
+	return resource->version;
+}
+
+WL_EXPORT void
+wl_resource_set_destructor(struct wl_resource *resource,
+			   wl_resource_destroy_func_t destroy)
+{
+	resource->destroy = destroy;
+}
+
+WL_EXPORT int
+wl_resource_instance_of(struct wl_resource *resource,
+			const struct wl_interface *interface,
+			const void *implementation)
+{
+	return wl_interface_equal(resource->object.interface, interface) &&
+		resource->object.implementation == implementation;
+}
+
+WL_EXPORT void
+wl_resource_add_destroy_listener(struct wl_resource *resource,
+				 struct wl_listener * listener)
+{
+	if (resource_is_deprecated(resource))
+		wl_signal_add(&resource->deprecated_destroy_signal, listener);
+	else
+		wl_priv_signal_add(&resource->destroy_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_resource_get_destroy_listener(struct wl_resource *resource,
+				 wl_notify_func_t notify)
+{
+	if (resource_is_deprecated(resource))
+		return wl_signal_get(&resource->deprecated_destroy_signal, notify);
+	return wl_priv_signal_get(&resource->destroy_signal, notify);
+}
+
+/** Retrieve the interface name (class) of a resource object.
+ *
+ * \param resource The resource object
+ *
+ * \memberof wl_resource
+ */
+WL_EXPORT const char *
+wl_resource_get_class(struct wl_resource *resource)
+{
+	return resource->object.interface->name;
+}
+
+/**
+ * Add a listener to be called at the beginning of wl_client destruction
+ *
+ * The listener provided will be called when wl_client destroy has begun,
+ * before any of that client's resources have been destroyed.
+ *
+ * There is no requirement to remove the link of the wl_listener when the
+ * signal is emitted.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_add_destroy_listener(struct wl_client *client,
+			       struct wl_listener *listener)
+{
+	wl_priv_signal_add(&client->destroy_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_client_get_destroy_listener(struct wl_client *client,
+			       wl_notify_func_t notify)
+{
+	return wl_priv_signal_get(&client->destroy_signal, notify);
+}
+
+/**
+ * Add a listener to be called at the end of wl_client destruction
+ *
+ * The listener provided will be called when wl_client destroy is nearly
+ * complete, after all of that client's resources have been destroyed.
+ *
+ * There is no requirement to remove the link of the wl_listener when the
+ * signal is emitted.
+ *
+ * \memberof wl_client
+ * \since 1.22.0
+ */
+WL_EXPORT void
+wl_client_add_destroy_late_listener(struct wl_client *client,
+				    struct wl_listener *listener)
+{
+	wl_priv_signal_add(&client->destroy_late_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_client_get_destroy_late_listener(struct wl_client *client,
+				    wl_notify_func_t notify)
+{
+	return wl_priv_signal_get(&client->destroy_late_signal, notify);
+}
+
+WL_EXPORT void
+wl_client_destroy(struct wl_client *client)
+{
+
+	/* wl_client_destroy() should not be called twice for the same client. */
+	if (wl_list_empty(&client->link)) {
+		client->error = 1;
+		wl_log("wl_client_destroy: encountered re-entrant client destruction.\n");
+		return;
+	}
+
+	wl_list_remove(&client->link);
+	/* Keep the client link safe to inspect. */
+	wl_list_init(&client->link);
+
+	wl_priv_signal_final_emit(&client->destroy_signal, client);
+
+	wl_client_flush(client);
+	wl_map_for_each(&client->objects, remove_and_destroy_resource, NULL);
+	wl_map_release(&client->objects);
+	wl_event_source_remove(client->source);
+	close(wl_connection_destroy(client->connection));
+
+	wl_priv_signal_final_emit(&client->destroy_late_signal, client);
+
+	wl_list_remove(&client->resource_created_signal.listener_list);
+
+	if (client->data_dtor)
+		client->data_dtor(client->data);
+
+	free(client);
+}
+
+/* Check if a global filter is registered and use it if any.
+ *
+ * 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
+wl_global_is_visible(const struct wl_client *client,
+	      const struct wl_global *global)
+{
+	struct wl_display *display = client->display;
+
+	return (display->global_filter == NULL ||
+		display->global_filter(client, global, display->global_filter_data));
+}
+
+static void
+registry_bind(struct wl_client *client,
+	      struct wl_resource *resource, uint32_t name,
+	      const char *interface, uint32_t version, uint32_t id)
+{
+	struct wl_global *global;
+	struct wl_display *display = resource->data;
+
+	wl_list_for_each(global, &display->global_list, link)
+		if (global->name == name)
+			break;
+
+	if (&global->link == &display->global_list)
+		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,
+				       "invalid version for global %s (%d): 0 is not a valid version",
+				       interface, name);
+	else if (global->version < version)
+		wl_resource_post_error(resource,
+				       WL_DISPLAY_ERROR_INVALID_OBJECT,
+				       "invalid version for global %s (%d): have %d, wanted %d",
+				       interface, name, global->version, version);
+	else if (!wl_global_is_visible(client, global))
+		wl_resource_post_error(resource,
+				       WL_DISPLAY_ERROR_INVALID_OBJECT,
+				       "invalid global %s (%d)", interface, name);
+	else
+		global->bind(client, global->data, version, id);
+}
+
+static const struct wl_registry_interface registry_interface = {
+	registry_bind
+};
+
+static void
+display_sync(struct wl_client *client,
+	     struct wl_resource *resource, uint32_t id)
+{
+	struct wl_resource *callback;
+	uint32_t serial;
+
+	callback = wl_resource_create(client, &wl_callback_interface, 1, id);
+	if (callback == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	serial = wl_display_get_serial(client->display);
+	wl_callback_send_done(callback, serial);
+	wl_resource_destroy(callback);
+}
+
+static void
+unbind_resource(struct wl_resource *resource)
+{
+	wl_list_remove(&resource->link);
+}
+
+static void
+display_get_registry(struct wl_client *client,
+		     struct wl_resource *resource, uint32_t id)
+{
+	struct wl_display *display = resource->data;
+	struct wl_resource *registry_resource;
+	struct wl_global *global;
+
+	registry_resource =
+		wl_resource_create(client, &wl_registry_interface, 1, id);
+	if (registry_resource == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	wl_resource_set_implementation(registry_resource,
+				       &registry_interface,
+				       display, unbind_resource);
+
+	wl_list_insert(&display->registry_resource_list,
+		       &registry_resource->link);
+
+	wl_list_for_each(global, &display->global_list, link)
+		if (wl_global_is_visible(client, global) && !global->removed)
+			wl_resource_post_event(registry_resource,
+					       WL_REGISTRY_GLOBAL,
+					       global->name,
+					       global->interface->name,
+					       global->version);
+}
+
+static const struct wl_display_interface display_interface = {
+	display_sync,
+	display_get_registry
+};
+
+static void
+destroy_client_display_resource(struct wl_resource *resource)
+{
+	resource->client->display_resource = NULL;
+}
+
+static int
+bind_display(struct wl_client *client, struct wl_display *display)
+{
+	client->display_resource =
+		wl_resource_create(client, &wl_display_interface, 1, 1);
+	if (client->display_resource == NULL) {
+		/* DON'T send no-memory error to client - it has no
+		 * resource to which it could post the event */
+		return -1;
+	}
+
+	wl_resource_set_implementation(client->display_resource,
+				       &display_interface, display,
+				       destroy_client_display_resource);
+	return 0;
+}
+
+static int
+handle_display_terminate(int fd, uint32_t mask, void *data) {
+	uint64_t term_event;
+
+	if (read(fd, &term_event, sizeof(term_event)) < 0 && errno != EAGAIN)
+		return -1;
+
+	return 0;
+}
+
+/** Create Wayland display object.
+ *
+ * \return The Wayland display object. Null if failed to create
+ *
+ * This creates the wl_display object.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_display *
+wl_display_create(void)
+{
+	struct wl_display *display;
+	const char *debug;
+
+	debug = getenv("WAYLAND_DEBUG");
+	if (debug && (strstr(debug, "server") || strstr(debug, "1")))
+		debug_server = 1;
+
+	display = zalloc(sizeof *display);
+	if (display == NULL)
+		return NULL;
+
+	display->loop = wl_event_loop_create();
+	if (display->loop == NULL) {
+		free(display);
+		return NULL;
+	}
+
+	display->terminate_efd = eventfd(0, EFD_CLOEXEC | EFD_NONBLOCK);
+	if (display->terminate_efd < 0)
+		goto err_eventfd;
+
+	display->term_source = wl_event_loop_add_fd(display->loop,
+						    display->terminate_efd,
+						    WL_EVENT_READABLE,
+						    handle_display_terminate,
+						    NULL);
+
+	if (display->term_source == NULL)
+		goto err_term_source;
+
+	wl_list_init(&display->global_list);
+	wl_list_init(&display->socket_list);
+	wl_list_init(&display->client_list);
+	wl_list_init(&display->registry_resource_list);
+	wl_list_init(&display->protocol_loggers);
+
+	wl_priv_signal_init(&display->destroy_signal);
+	wl_priv_signal_init(&display->create_client_signal);
+
+	display->next_global_name = 1;
+	display->serial = 0;
+
+	display->global_filter = NULL;
+	display->global_filter_data = NULL;
+	display->max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
+
+	wl_array_init(&display->additional_shm_formats);
+
+	return display;
+
+err_term_source:
+	close(display->terminate_efd);
+err_eventfd:
+	wl_event_loop_destroy(display->loop);
+	free(display);
+	return NULL;
+}
+
+static void
+wl_socket_destroy(struct wl_socket *s)
+{
+	if (s->source)
+		wl_event_source_remove(s->source);
+	if (s->addr.sun_path[0])
+		unlink(s->addr.sun_path);
+	if (s->fd >= 0)
+		close(s->fd);
+	if (s->lock_addr[0])
+		unlink(s->lock_addr);
+	if (s->fd_lock >= 0)
+		close(s->fd_lock);
+
+	free(s);
+}
+
+static struct wl_socket *
+wl_socket_alloc(void)
+{
+	struct wl_socket *s;
+
+	s = zalloc(sizeof *s);
+	if (!s)
+		return NULL;
+
+	s->fd = -1;
+	s->fd_lock = -1;
+
+	return s;
+}
+
+/** Destroy Wayland display object.
+ *
+ * \param display The Wayland display object which should be destroyed.
+ *
+ * This function emits the wl_display destroy signal, releases
+ * all the sockets added to this display, free's all the globals associated
+ * with this display, free's memory of additional shared memory formats and
+ * destroy the display object.
+ *
+ * \sa wl_display_add_destroy_listener
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_destroy(struct wl_display *display)
+{
+	struct wl_socket *s, *next;
+	struct wl_global *global, *gnext;
+
+	wl_priv_signal_final_emit(&display->destroy_signal, display);
+
+	wl_list_for_each_safe(s, next, &display->socket_list, link) {
+		wl_socket_destroy(s);
+	}
+
+	close(display->terminate_efd);
+	wl_event_source_remove(display->term_source);
+
+	wl_event_loop_destroy(display->loop);
+
+	wl_list_for_each_safe(global, gnext, &display->global_list, link)
+		free(global);
+
+	wl_array_release(&display->additional_shm_formats);
+
+	wl_list_remove(&display->protocol_loggers);
+
+	free(display);
+}
+
+/** Set a filter function for global objects
+ *
+ * \param display The Wayland display object.
+ * \param filter  The global filter function.
+ * \param data User data to be associated with the global filter.
+ *
+ * Set a filter for the wl_display to advertise or hide global objects
+ * to clients.
+ * 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.
+ *
+ * Clients that try to bind to a global that was filtered out will
+ * have an error raised.
+ *
+ * Setting the filter NULL will result in all globals being
+ * advertised to all clients. The default is no filter.
+ *
+ * The filter should be installed before any client connects and should always
+ * take the same decision given a client and a global. Not doing so will result
+ * in inconsistent filtering and broken wl_registry event sequences.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_set_global_filter(struct wl_display *display,
+			     wl_display_global_filter_func_t filter,
+			     void *data)
+{
+	display->global_filter = filter;
+	display->global_filter_data = data;
+}
+
+WL_EXPORT struct wl_global *
+wl_global_create(struct wl_display *display,
+		 const struct wl_interface *interface, int version,
+		 void *data, wl_global_bind_func_t bind)
+{
+	struct wl_global *global;
+	struct wl_resource *resource;
+
+	if (version < 1) {
+		wl_log("wl_global_create: failing to create interface "
+		       "'%s' with version %d because it is less than 1\n",
+			interface->name, version);
+		return NULL;
+	}
+
+	if (version > interface->version) {
+		wl_log("wl_global_create: implemented version for '%s' "
+		       "higher than interface version (%d > %d)\n",
+		       interface->name, version, interface->version);
+		return NULL;
+	}
+
+	if (display->next_global_name >= UINT32_MAX) {
+		wl_log("wl_global_create: ran out of global names\n");
+		return NULL;
+	}
+
+	global = zalloc(sizeof *global);
+	if (global == NULL)
+		return NULL;
+
+	global->display = display;
+	global->name = display->next_global_name++;
+	global->interface = interface;
+	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)
+		if (wl_global_is_visible(resource->client, global))
+			wl_resource_post_event(resource,
+					       WL_REGISTRY_GLOBAL,
+					       global->name,
+					       global->interface->name,
+					       global->version);
+
+	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_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)
+		if (wl_global_is_visible(resource->client, global))
+			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);
+}
+
+WL_EXPORT const struct wl_interface *
+wl_global_get_interface(const struct wl_global *global)
+{
+	return global->interface;
+}
+
+/** Get the name of the global.
+ *
+ * \param global The global object.
+ * \param client Client for which to look up the global.
+ * \return The name of the global, or 0 if the global is not visible to the
+ *         client.
+ *
+ * \memberof wl_global
+ * \since 1.22
+ */
+WL_EXPORT uint32_t
+wl_global_get_name(const struct wl_global *global,
+		   const struct wl_client *client)
+{
+	return wl_global_is_visible(client, global) ? global->name : 0;
+}
+
+/** Get the version of the given global.
+ *
+ * \param global The global object.
+ * \return The version advertised by the global.
+ *
+ * \memberof wl_global
+ * \since 1.21
+ */
+WL_EXPORT uint32_t
+wl_global_get_version(const struct wl_global *global)
+{
+	return global->version;
+}
+
+/** Get the display object for the given global
+ *
+ * \param global The global object
+ * \return The display object the global is associated with.
+ *
+ * \memberof wl_global
+ * \since 1.20
+ */
+WL_EXPORT struct wl_display *
+wl_global_get_display(const struct wl_global *global)
+{
+	return global->display;
+}
+
+WL_EXPORT void *
+wl_global_get_user_data(const struct wl_global *global)
+{
+	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
+ *
+ * This function returns the most recent serial number, but does not
+ * increment it.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT uint32_t
+wl_display_get_serial(struct wl_display *display)
+{
+	return display->serial;
+}
+
+/** Get the next serial number
+ *
+ * \param display The display object
+ *
+ * This function increments the display serial number and returns the
+ * new value.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT uint32_t
+wl_display_next_serial(struct wl_display *display)
+{
+	display->serial++;
+
+	return display->serial;
+}
+
+WL_EXPORT struct wl_event_loop *
+wl_display_get_event_loop(struct wl_display *display)
+{
+	return display->loop;
+}
+
+WL_EXPORT void
+wl_display_terminate(struct wl_display *display)
+{
+	int ret;
+	uint64_t terminate = 1;
+
+	display->run = false;
+
+	ret = write(display->terminate_efd, &terminate, sizeof(terminate));
+	assert (ret >= 0 || errno == EAGAIN);
+}
+
+WL_EXPORT void
+wl_display_run(struct wl_display *display)
+{
+	display->run = true;
+
+	while (display->run) {
+		wl_display_flush_clients(display);
+		if (wl_event_loop_dispatch(display->loop, -1) < 0) {
+			break;
+		}
+	}
+}
+
+WL_EXPORT void
+wl_display_flush_clients(struct wl_display *display)
+{
+	struct wl_client *client, *next;
+	int ret;
+
+	wl_list_for_each_safe(client, next, &display->client_list, link) {
+		ret = wl_connection_flush(client->connection);
+		if (ret < 0 && errno == EAGAIN) {
+			wl_event_source_fd_update(client->source,
+						  WL_EVENT_WRITABLE |
+						  WL_EVENT_READABLE);
+		} else if (ret < 0) {
+			wl_client_destroy(client);
+		}
+	}
+}
+
+/** Destroy all clients connected to the display
+ *
+ * \param display The display object
+ *
+ * This function should be called right before wl_display_destroy() to ensure
+ * all client resources are closed properly. Destroying a client from within
+ * wl_display_destroy_clients() is safe, but creating one will leak resources
+ * and raise a warning.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT void
+wl_display_destroy_clients(struct wl_display *display)
+{
+	struct wl_list tmp_client_list, *pos;
+	struct wl_client *client;
+
+	/* Move the whole client list to a temporary head because some new clients
+	 * might be added to the original head. */
+	wl_list_init(&tmp_client_list);
+	wl_list_insert_list(&tmp_client_list, &display->client_list);
+	wl_list_init(&display->client_list);
+
+	/* wl_list_for_each_safe isn't enough here: it fails if the next client is
+	 * destroyed by the destroy handler of the current one. */
+	while (!wl_list_empty(&tmp_client_list)) {
+		pos = tmp_client_list.next;
+		client = wl_container_of(pos, client, link);
+
+		wl_client_destroy(client);
+	}
+
+	if (!wl_list_empty(&display->client_list)) {
+		wl_log("wl_display_destroy_clients: cannot destroy all clients because "
+			   "new ones were created by destroy callbacks\n");
+	}
+}
+
+/** Sets the default maximum size for connection buffers of new clients
+ *
+ * \param display The display object
+ * \param max_buffer_size The default maximum size of the connection buffers
+ *
+ * This function sets the default size of the internal connection buffers for
+ * new clients. It doesn't change the buffer size for existing wl_client.
+ *
+ * The connection buffer size of an existing wl_client can be adjusted using
+ * wl_client_set_max_buffer_size().
+ *
+ * The actual size of the connection buffers is a power of two, the requested
+ * \a max_buffer_size is therefore rounded up to the nearest power of two value.
+ *
+ * The minimum buffer size is 4096.
+ *
+ * \sa wl_client_set_max_buffer_size
+ *
+ * \memberof wl_display
+ * \since 1.22.90
+ */
+WL_EXPORT void
+wl_display_set_default_max_buffer_size(struct wl_display *display,
+			               size_t max_buffer_size)
+{
+	if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE)
+		max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
+
+	display->max_buffer_size = max_buffer_size;
+}
+
+static int
+socket_data(int fd, uint32_t mask, void *data)
+{
+	struct wl_display *display = data;
+	struct sockaddr_un name;
+	socklen_t length;
+	int client_fd;
+
+	length = sizeof name;
+	client_fd = wl_os_accept_cloexec(fd, (struct sockaddr *) &name,
+					 &length);
+	if (client_fd < 0)
+		wl_log("failed to accept: %s\n", strerror(errno));
+	else
+		if (!wl_client_create(display, client_fd))
+			close(client_fd);
+
+	return 1;
+}
+
+static int
+wl_socket_lock(struct wl_socket *socket)
+{
+	struct stat socket_stat;
+
+	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 | O_RDWR,
+			       (S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP));
+
+	if (socket->fd_lock < 0) {
+		wl_log("unable to open lockfile %s check permissions\n",
+			socket->lock_addr);
+		goto err;
+	}
+
+	if (flock(socket->fd_lock, LOCK_EX | LOCK_NB) < 0) {
+		wl_log("unable to lock lockfile %s, maybe another compositor is running\n",
+			socket->lock_addr);
+		goto err_fd;
+	}
+
+	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);
+			goto err_fd;
+		}
+	} else if (socket_stat.st_mode & S_IWUSR ||
+		   socket_stat.st_mode & S_IWGRP) {
+		unlink(socket->addr.sun_path);
+	}
+
+	return 0;
+err_fd:
+	close(socket->fd_lock);
+	socket->fd_lock = -1;
+err:
+	*socket->lock_addr = 0;
+	/* we did not set this value here, but without lock the
+	 * socket won't be created anyway. This prevents the
+	 * wl_socket_destroy from unlinking already existing socket
+	 * created by other compositor */
+	*socket->addr.sun_path = 0;
+
+	return -1;
+}
+
+static int
+wl_socket_init_for_display_name(struct wl_socket *s, const char *name)
+{
+	int name_size;
+	const char *runtime_dir = "";
+	const char *separator = "";
+
+	if (name[0] != '/') {
+		runtime_dir = getenv("XDG_RUNTIME_DIR");
+		if (!runtime_dir || runtime_dir[0] != '/') {
+			wl_log("error: XDG_RUNTIME_DIR is invalid or not set in"
+			       " the environment\n");
+
+			/* 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%s", runtime_dir, separator, name) + 1;
+
+	assert(name_size > 0);
+	if (name_size > (int)sizeof s->addr.sun_path) {
+		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" */
+		errno = ENAMETOOLONG;
+		return -1;
+	}
+
+	s->display_name = (s->addr.sun_path + name_size - 1) - strlen(name);
+
+	return 0;
+}
+
+static int
+_wl_display_add_socket(struct wl_display *display, struct wl_socket *s)
+{
+	socklen_t size;
+
+	s->fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
+	if (s->fd < 0) {
+		return -1;
+	}
+
+	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: %s\n", strerror(errno));
+		return -1;
+	}
+
+	if (listen(s->fd, 128) < 0) {
+		wl_log("listen() failed with error: %s\n", strerror(errno));
+		return -1;
+	}
+
+	s->source = wl_event_loop_add_fd(display->loop, s->fd,
+					 WL_EVENT_READABLE,
+					 socket_data, display);
+	if (s->source == NULL) {
+		return -1;
+	}
+
+	wl_list_insert(display->socket_list.prev, &s->link);
+	return 0;
+}
+
+WL_EXPORT const char *
+wl_display_add_socket_auto(struct wl_display *display)
+{
+	struct wl_socket *s;
+	int displayno = 0;
+	char display_name[20] = "";
+
+	/* A reasonable number of maximum default sockets. If
+	 * you need more than this, use the explicit add_socket API. */
+	const int MAX_DISPLAYNO = 32;
+
+	s = wl_socket_alloc();
+	if (s == NULL)
+		return NULL;
+
+	do {
+		snprintf(display_name, sizeof display_name, "wayland-%d", displayno);
+		if (wl_socket_init_for_display_name(s, display_name) < 0) {
+			wl_socket_destroy(s);
+			return NULL;
+		}
+
+		if (wl_socket_lock(s) < 0)
+			continue;
+
+		if (_wl_display_add_socket(display, s) < 0) {
+			wl_socket_destroy(s);
+			return NULL;
+		}
+
+		return s->display_name;
+	} while (displayno++ < MAX_DISPLAYNO);
+
+	/* Ran out of display names. */
+	wl_socket_destroy(s);
+	errno = EINVAL;
+	return NULL;
+}
+
+/**  Add a socket with an existing fd to Wayland display for the clients to connect.
+ *
+ * \param display Wayland display to which the socket should be added.
+ * \param sock_fd The existing socket file descriptor to be used
+ * \return 0 if success. -1 if failed.
+ *
+ * The existing socket fd must already be created, opened, and locked.
+ * The fd must be properly set to CLOEXEC and bound to a socket file
+ * with both bind() and listen() already called.
+ *
+ * On success, the socket fd ownership is transferred to libwayland:
+ * libwayland will close the socket when the display is destroyed.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT int
+wl_display_add_socket_fd(struct wl_display *display, int sock_fd)
+{
+	struct wl_socket *s;
+	struct stat buf;
+
+	/* Require a valid fd or fail */
+	if (sock_fd < 0 || fstat(sock_fd, &buf) < 0 || !S_ISSOCK(buf.st_mode)) {
+		return -1;
+	}
+
+	s = wl_socket_alloc();
+	if (s == NULL)
+		return -1;
+
+	s->source = wl_event_loop_add_fd(display->loop, sock_fd,
+					 WL_EVENT_READABLE,
+					 socket_data, display);
+	if (s->source == NULL) {
+		wl_log("failed to establish event source\n");
+		wl_socket_destroy(s);
+		return -1;
+	}
+
+	/* Reuse the existing fd */
+	s->fd = sock_fd;
+
+	wl_list_insert(display->socket_list.prev, &s->link);
+
+	return 0;
+}
+
+/** Add a socket to Wayland display for the clients to connect.
+ *
+ * \param display Wayland display to which the socket should be added.
+ * \param name Name of the Unix socket.
+ * \return 0 if success. -1 if failed.
+ *
+ * This adds a Unix socket to Wayland display which can be used by clients to
+ * connect to Wayland display.
+ *
+ * If NULL is passed as name, then it would look for WAYLAND_DISPLAY env
+ * variable for the socket name. If WAYLAND_DISPLAY is not set, then default
+ * wayland-0 is used.
+ *
+ * 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 invalid or not set, then this function fails and returns -1.
+ *
+ * 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
+ */
+WL_EXPORT int
+wl_display_add_socket(struct wl_display *display, const char *name)
+{
+	struct wl_socket *s;
+
+	s = wl_socket_alloc();
+	if (s == NULL)
+		return -1;
+
+	if (name == NULL)
+		name = getenv("WAYLAND_DISPLAY");
+	if (name == NULL)
+		name = "wayland-0";
+
+	if (wl_socket_init_for_display_name(s, name) < 0) {
+		wl_socket_destroy(s);
+		return -1;
+	}
+
+	if (wl_socket_lock(s) < 0) {
+		wl_socket_destroy(s);
+		return -1;
+	}
+
+	if (_wl_display_add_socket(display, s) < 0) {
+		wl_socket_destroy(s);
+		return -1;
+	}
+
+	return 0;
+}
+
+WL_EXPORT void
+wl_display_add_destroy_listener(struct wl_display *display,
+				struct wl_listener *listener)
+{
+	wl_priv_signal_add(&display->destroy_signal, listener);
+}
+
+/** Registers a listener for the client connection signal.
+ *  When a new client object is created, \a listener will be notified, carrying
+ *  a pointer to the new wl_client object.
+ *
+ *  \ref wl_client_create
+ *  \ref wl_display
+ *  \ref wl_listener
+ *
+ * \param display The display object
+ * \param listener Signal handler object
+ */
+WL_EXPORT void
+wl_display_add_client_created_listener(struct wl_display *display,
+					struct wl_listener *listener)
+{
+	wl_priv_signal_add(&display->create_client_signal, listener);
+}
+
+WL_EXPORT struct wl_listener *
+wl_display_get_destroy_listener(struct wl_display *display,
+				wl_notify_func_t notify)
+{
+	return wl_priv_signal_get(&display->destroy_signal, notify);
+}
+
+WL_EXPORT void
+wl_resource_set_implementation(struct wl_resource *resource,
+			       const void *implementation,
+			       void *data, wl_resource_destroy_func_t destroy)
+{
+	resource->object.implementation = implementation;
+	resource->data = data;
+	resource->destroy = destroy;
+	resource->dispatcher = NULL;
+}
+
+WL_EXPORT void
+wl_resource_set_dispatcher(struct wl_resource *resource,
+			   wl_dispatcher_func_t dispatcher,
+			   const void *implementation,
+			   void *data, wl_resource_destroy_func_t destroy)
+{
+	resource->dispatcher = dispatcher;
+	resource->object.implementation = implementation;
+	resource->data = data;
+	resource->destroy = destroy;
+}
+
+/** Create a new resource object
+ *
+ * \param client The client owner of the new resource.
+ * \param interface The interface of the new resource.
+ * \param version The version of the new resource.
+ * \param id The id of the new resource. If 0, an available id will be used.
+ *
+ * Listeners added with \a wl_client_add_resource_created_listener will be
+ * notified at the end of this function.
+ *
+ * \memberof wl_resource
+ */
+WL_EXPORT struct wl_resource *
+wl_resource_create(struct wl_client *client,
+		   const struct wl_interface *interface,
+		   int version, uint32_t id)
+{
+	struct wl_resource *resource;
+
+	resource = zalloc(sizeof *resource);
+	if (resource == NULL)
+		return NULL;
+
+	if (id == 0) {
+		id = wl_map_insert_new(&client->objects, 0, NULL);
+		if (id == 0) {
+			free(resource);
+			return NULL;
+		}
+	}
+
+	resource->object.id = id;
+	resource->object.interface = interface;
+	resource->object.implementation = NULL;
+
+	wl_signal_init(&resource->deprecated_destroy_signal);
+	wl_priv_signal_init(&resource->destroy_signal);
+
+	resource->destroy = NULL;
+	resource->client = client;
+	resource->data = NULL;
+	resource->version = version;
+	resource->dispatcher = NULL;
+
+	if (wl_map_insert_at(&client->objects, 0, id, resource) < 0) {
+		if (errno == EINVAL) {
+			wl_resource_post_error(client->display_resource,
+					       WL_DISPLAY_ERROR_INVALID_OBJECT,
+					       "invalid new id %d", id);
+		}
+		free(resource);
+		return NULL;
+	}
+
+	wl_priv_signal_emit(&client->resource_created_signal, resource);
+	return resource;
+}
+
+WL_EXPORT void
+wl_log_set_handler_server(wl_log_func_t handler)
+{
+	wl_log_handler = handler;
+}
+
+/** Adds a new protocol logger.
+ *
+ * When a new protocol message arrives or is sent from the server
+ * all the protocol logger functions will be called, carrying the
+ * \a user_data pointer, the type of the message (request or
+ * event) and the actual message.
+ * The lifetime of the messages passed to the logger function ends
+ * when they return so the messages cannot be stored and accessed
+ * later.
+ *
+ * \a errno is set on error.
+ *
+ * \param display The display object
+ * \param func The function to call to log a new protocol message
+ * \param user_data The user data pointer to pass to \a func
+ *
+ * \return The protol logger object on success, NULL on failure.
+ *
+ * \sa wl_protocol_logger_destroy
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_protocol_logger *
+wl_display_add_protocol_logger(struct wl_display *display,
+			       wl_protocol_logger_func_t func, void *user_data)
+{
+	struct wl_protocol_logger *logger;
+
+	logger = zalloc(sizeof *logger);
+	if (!logger)
+		return NULL;
+
+	logger->func = func;
+	logger->user_data = user_data;
+	wl_list_insert(&display->protocol_loggers, &logger->link);
+
+	return logger;
+}
+
+/** Destroys a protocol logger.
+ *
+ * This function destroys a protocol logger and removes it from the display
+ * it was added to with \a wl_display_add_protocol_logger.
+ * The \a logger object becomes invalid after calling this function.
+ *
+ * \sa wl_display_add_protocol_logger
+ *
+ * \memberof wl_protocol_logger
+ */
+WL_EXPORT void
+wl_protocol_logger_destroy(struct wl_protocol_logger *logger)
+{
+	wl_list_remove(&logger->link);
+	free(logger);
+}
+
+/** Add support for a wl_shm pixel format
+ *
+ * \param display The display object
+ * \param format The wl_shm pixel format to advertise
+ * \return A pointer to the wl_shm format that was added to the list
+ * or NULL if adding it to the list failed.
+ *
+ * Add the specified wl_shm format to the list of formats the wl_shm
+ * object advertises when a client binds to it.  Adding a format to
+ * the list means that clients will know that the compositor supports
+ * this format and may use it for creating wl_shm buffers.  The
+ * compositor must be able to handle the pixel format when a client
+ * requests it.
+ *
+ * The compositor by default supports WL_SHM_FORMAT_ARGB8888 and
+ * WL_SHM_FORMAT_XRGB8888.
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT uint32_t *
+wl_display_add_shm_format(struct wl_display *display, uint32_t format)
+{
+	uint32_t *p = NULL;
+
+	p = wl_array_add(&display->additional_shm_formats, sizeof *p);
+
+	if (p != NULL)
+		*p = format;
+	return p;
+}
+
+/**
+ * Get list of additional wl_shm pixel formats
+ *
+ * \param display The display object
+ *
+ * This function returns the list of addition wl_shm pixel formats
+ * that the compositor supports.  WL_SHM_FORMAT_ARGB8888 and
+ * WL_SHM_FORMAT_XRGB8888 are always supported and not included in the
+ * array, but all formats added through wl_display_add_shm_format()
+ * will be in the array.
+ *
+ * \sa wl_display_add_shm_format()
+ *
+ * \private
+ *
+ * \memberof wl_display
+ */
+struct wl_array *
+wl_display_get_additional_shm_formats(struct wl_display *display)
+{
+	return &display->additional_shm_formats;
+}
+
+/** Get the list of currently connected clients
+ *
+ * \param display The display object
+ *
+ * This function returns a pointer to the list of clients currently
+ * connected to the display. You can iterate on the list by using
+ * the \a wl_client_for_each macro.
+ * The returned value is valid for the lifetime of the \a display.
+ * You must not modify the returned list, but only access it.
+ *
+ * \sa wl_client_for_each()
+ * \sa wl_client_get_link()
+ * \sa wl_client_from_link()
+ *
+ * \memberof wl_display
+ */
+WL_EXPORT struct wl_list *
+wl_display_get_client_list(struct wl_display *display)
+{
+	return &display->client_list;
+}
+
+/** Get the link by which a client is inserted in the client list
+ *
+ * \param client The client object
+ *
+ * \sa wl_client_for_each()
+ * \sa wl_display_get_client_list()
+ * \sa wl_client_from_link()
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT struct wl_list *
+wl_client_get_link(struct wl_client *client)
+{
+	return &client->link;
+}
+
+/** Get a wl_client by its link
+ *
+ * \param link The link of a wl_client
+ *
+ * \sa wl_client_for_each()
+ * \sa wl_display_get_client_list()
+ * \sa wl_client_get_link()
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT struct wl_client *
+wl_client_from_link(struct wl_list *link)
+{
+	struct wl_client *client;
+
+	return wl_container_of(link, client, link);
+}
+
+/** Add a listener for the client's resource creation signal
+ *
+ * \param client The client object
+ * \param listener The listener to be added
+ *
+ * When a new resource is created for this client the listener
+ * will be notified, carrying the new resource as the data argument.
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_add_resource_created_listener(struct wl_client *client,
+					struct wl_listener *listener)
+{
+	wl_priv_signal_add(&client->resource_created_signal, listener);
+}
+
+struct wl_resource_iterator_context {
+	void *user_data;
+	wl_client_for_each_resource_iterator_func_t it;
+};
+
+static enum wl_iterator_result
+resource_iterator_helper(void *res, void *user_data, uint32_t flags)
+{
+	struct wl_resource_iterator_context *context = user_data;
+	struct wl_resource *resource = res;
+
+	return context->it(resource, context->user_data);
+}
+
+/** Iterate over all the resources of a client
+ *
+ * \param client The client object
+ * \param iterator The iterator function
+ * \param user_data The user data pointer
+ *
+ * The function pointed by \a iterator will be called for each
+ * resource owned by the client. The \a user_data will be passed
+ * as the second argument of the iterator function.
+ * If the \a iterator function returns \a WL_ITERATOR_CONTINUE the iteration
+ * will continue, if it returns \a WL_ITERATOR_STOP it will stop.
+ *
+ * Creating and destroying resources while iterating is safe, but new
+ * resources may or may not be picked up by the iterator.
+ *
+ * \sa wl_iterator_result
+ *
+ * \memberof wl_client
+ */
+WL_EXPORT void
+wl_client_for_each_resource(struct wl_client *client,
+			    wl_client_for_each_resource_iterator_func_t iterator,
+			    void *user_data)
+{
+	struct wl_resource_iterator_context context = {
+		.user_data = user_data,
+		.it = iterator,
+	};
+
+	wl_map_for_each(&client->objects, resource_iterator_helper, &context);
+}
+
+static void
+handle_noop(struct wl_listener *listener, void *data)
+{
+	/* Do nothing */
+}
+
+/** Emits this signal, notifying all registered listeners.
+ *
+ * A safer version of wl_signal_emit() which can gracefully handle additions
+ * and deletions of any signal listener from within listener notification
+ * callbacks.
+ *
+ * Listeners deleted during a signal emission and which have not already been
+ * notified at the time of deletion are not notified by that emission.
+ *
+ * Listeners added (or readded) during signal emission are ignored by that
+ * emission.
+ *
+ * Note that repurposing a listener without explicitly removing it and readding
+ * it is not supported and can lead to unexpected behavior.
+ *
+ * \param signal The signal object that will emit the signal
+ * \param data The data that will be emitted with the signal
+ *
+ * \memberof wl_signal
+ * \since 1.20.90
+ */
+WL_EXPORT void
+wl_signal_emit_mutable(struct wl_signal *signal, void *data)
+{
+	struct wl_listener cursor;
+	struct wl_listener end;
+
+	/* Add two special markers: one cursor and one end marker. This way, we
+	 * know that we've already called listeners on the left of the cursor
+	 * and that we don't want to call listeners on the right of the end
+	 * marker. The 'it' function can remove any element it wants from the
+	 * list without troubles.
+	 *
+	 * There was a previous attempt that used to steal the whole list of
+	 * listeners but then that broke wl_signal_get().
+	 *
+	 * wl_list_for_each_safe tries to be safe but it fails: it works fine
+	 * if the current item is removed, but not if the next one is. */
+	wl_list_insert(&signal->listener_list, &cursor.link);
+	cursor.notify = handle_noop;
+	wl_list_insert(signal->listener_list.prev, &end.link);
+	end.notify = handle_noop;
+
+	while (cursor.link.next != &end.link) {
+		struct wl_list *pos = cursor.link.next;
+		struct wl_listener *l = wl_container_of(pos, l, link);
+
+		wl_list_remove(&cursor.link);
+		wl_list_insert(pos, &cursor.link);
+
+		l->notify(l, data);
+	}
+
+	wl_list_remove(&cursor.link);
+	wl_list_remove(&end.link);
+}
+
+/** Adjust the maximum size of the client connection buffers
+ *
+ * \param client The client object
+ * \param max_buffer_size The maximum size of the connection buffers
+ *
+ * The actual size of the connection buffers is a power of two, the requested
+ * \a max_buffer_size is therefore rounded up to the nearest power of two value.
+ *
+ * Lowering the maximum size may not take effect immediately if the current content
+ * of the buffer does not fit within the new size limit.
+ *
+ * The minimum buffer size is 4096. The default buffers size can be set using
+ * wl_display_set_default_max_buffer_size().
+ *
+ * \sa wl_display_set_default_max_buffer_size()
+ *
+ * \memberof wl_client
+ * \since 1.22.90
+ */
+WL_EXPORT void
+wl_client_set_max_buffer_size(struct wl_client *client, size_t max_buffer_size)
+{
+	if (max_buffer_size < WL_BUFFER_DEFAULT_MAX_SIZE)
+		max_buffer_size = WL_BUFFER_DEFAULT_MAX_SIZE;
+
+	wl_connection_set_max_buffer_size(client->connection, max_buffer_size);
+}
+
+/** \cond INTERNAL */
+
+/** Initialize a wl_priv_signal object
+ *
+ * wl_priv_signal is a safer implementation of a signal type, with the same API
+ * as wl_signal, but kept as a private utility of libwayland-server.
+ * It is safer because listeners can be removed from within wl_priv_signal_emit()
+ * without corrupting the signal's list.
+ *
+ * Before passing a wl_priv_signal object to any other function it must be
+ * initialized by using wl_priv_signal_init().
+ *
+ * \memberof wl_priv_signal
+ */
+void
+wl_priv_signal_init(struct wl_priv_signal *signal)
+{
+	wl_list_init(&signal->listener_list);
+	wl_list_init(&signal->emit_list);
+}
+
+/** Add a listener to a signal
+ *
+ * The new listener will be called when calling wl_signal_emit(). If a listener is
+ * added to the signal while wl_signal_emit() is running it will be called from
+ * the next time wl_priv_signal_emit() is called.
+ * To remove a listener call wl_list_remove() on its link member.
+ *
+ * \memberof wl_priv_signal
+ */
+void
+wl_priv_signal_add(struct wl_priv_signal *signal, struct wl_listener *listener)
+{
+	wl_list_insert(signal->listener_list.prev, &listener->link);
+}
+
+/** Get a listener added to a signal
+ *
+ * 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 within wl_priv_signal_emit() is safe and will
+ * return the correct value.
+ *
+ * \memberof wl_priv_signal
+ */
+struct wl_listener *
+wl_priv_signal_get(struct wl_priv_signal *signal, wl_notify_func_t notify)
+{
+	struct wl_listener *l;
+
+	wl_list_for_each(l, &signal->listener_list, link)
+		if (l->notify == notify)
+			return l;
+	wl_list_for_each(l, &signal->emit_list, link)
+		if (l->notify == notify)
+			return l;
+
+	return NULL;
+}
+
+/** Emit the signal, calling all the installed listeners
+ *
+ * Iterate over all the listeners added to this \a signal and call
+ * their \a notify function pointer, passing on the given \a data.
+ * Removing or adding a listener from within wl_priv_signal_emit()
+ * is safe.
+ */
+void
+wl_priv_signal_emit(struct wl_priv_signal *signal, void *data)
+{
+	struct wl_listener *l;
+	struct wl_list *pos;
+
+	wl_list_insert_list(&signal->emit_list, &signal->listener_list);
+	wl_list_init(&signal->listener_list);
+
+	/* Take every element out of the list and put them in a temporary list.
+	 * This way, the 'it' func can remove any element it wants from the list
+	 * without troubles, because we always get the first element, not the
+	 * one after the current, which may be invalid.
+	 * wl_list_for_each_safe tries to be safe but it fails: it works fine
+	 * if the current item is removed, but not if the next one is. */
+	while (!wl_list_empty(&signal->emit_list)) {
+		pos = signal->emit_list.next;
+		l = wl_container_of(pos, l, link);
+
+		wl_list_remove(pos);
+		wl_list_insert(&signal->listener_list, pos);
+
+		l->notify(l, data);
+	}
+}
+
+/** Emit the signal for the last time, calling all the installed listeners
+ *
+ * Iterate over all the listeners added to this \a signal and call
+ * their \a notify function pointer, passing on the given \a data.
+ * Removing or adding a listener from within wl_priv_signal_emit()
+ * is safe, as is freeing the structure containing the listener.
+ *
+ * A large body of external code assumes it's ok to free a destruction
+ * listener without removing that listener from the list.  Mixing code
+ * that acts like this and code that doesn't will result in list
+ * corruption.
+ *
+ * We resolve this by removing each item from the list and isolating it
+ * in another list.  We discard it completely after firing the notifier.
+ * This should allow interoperability between code that unlinks its
+ * destruction listeners and code that just frees structures they're in.
+ *
+ */
+void
+wl_priv_signal_final_emit(struct wl_priv_signal *signal, void *data)
+{
+	struct wl_listener *l;
+	struct wl_list *pos;
+
+	/* During a destructor notifier isolate every list item before
+	 * notifying.  This renders harmless the long standing misuse
+	 * of freeing listeners without removing them, but allows
+	 * callers that do choose to remove them to interoperate with
+	 * ones that don't. */
+	while (!wl_list_empty(&signal->listener_list)) {
+		pos = signal->listener_list.next;
+		l = wl_container_of(pos, l, link);
+
+		wl_list_remove(pos);
+		wl_list_init(pos);
+
+		l->notify(l, data);
+	}
+}
+
+/** \endcond INTERNAL */
+
+/** \cond */ /* Deprecated functions below. */
+
+uint32_t
+wl_client_add_resource(struct wl_client *client,
+		       struct wl_resource *resource) WL_DEPRECATED;
+
+WL_EXPORT uint32_t
+wl_client_add_resource(struct wl_client *client,
+		       struct wl_resource *resource)
+{
+	if (resource->object.id == 0) {
+		resource->object.id =
+			wl_map_insert_new(&client->objects,
+					  WL_MAP_ENTRY_LEGACY, resource);
+		if (resource->object.id == 0)
+			return 0;
+	} else if (wl_map_insert_at(&client->objects, WL_MAP_ENTRY_LEGACY,
+				  resource->object.id, resource) < 0) {
+		if (errno == EINVAL) {
+			wl_resource_post_error(client->display_resource,
+					       WL_DISPLAY_ERROR_INVALID_OBJECT,
+					       "invalid new id %d",
+					       resource->object.id);
+		}
+		return 0;
+	}
+
+	resource->client = client;
+	wl_signal_init(&resource->deprecated_destroy_signal);
+
+	return resource->object.id;
+}
+
+struct wl_resource *
+wl_client_add_object(struct wl_client *client,
+		     const struct wl_interface *interface,
+		     const void *implementation,
+		     uint32_t id, void *data) WL_DEPRECATED;
+
+WL_EXPORT struct wl_resource *
+wl_client_add_object(struct wl_client *client,
+		     const struct wl_interface *interface,
+		     const void *implementation, uint32_t id, void *data)
+{
+	struct wl_resource *resource;
+
+	resource = wl_resource_create(client, interface, -1, id);
+	if (resource == NULL)
+		wl_client_post_no_memory(client);
+	else
+		wl_resource_set_implementation(resource,
+					       implementation, data, NULL);
+
+	return resource;
+}
+
+struct wl_resource *
+wl_client_new_object(struct wl_client *client,
+		     const struct wl_interface *interface,
+		     const void *implementation, void *data) WL_DEPRECATED;
+
+WL_EXPORT struct wl_resource *
+wl_client_new_object(struct wl_client *client,
+		     const struct wl_interface *interface,
+		     const void *implementation, void *data)
+{
+	struct wl_resource *resource;
+
+	resource = wl_resource_create(client, interface, -1, 0);
+	if (resource == NULL)
+		wl_client_post_no_memory(client);
+	else
+		wl_resource_set_implementation(resource,
+					       implementation, data, NULL);
+
+	return resource;
+}
+
+/** Set the client's user data
+ *
+ * User data is whatever the caller wants to store. Use dtor if
+ * the user data needs freeing as the very last step of destroying
+ * the client.
+ *
+ * \param client The client object
+ * \param data The user data pointer
+ * \param dtor Destroy function to be called after all resources have been
+ * destroyed and all destroy listeners have been called. Can be NULL.
+ *
+ * The argument to the destroy function is the user data pointer. If the
+ * destroy function is not NULL, it will be called even if user data is NULL.
+ *
+ * \since 1.22.90
+ * \sa wl_client_get_user_data
+ */
+WL_EXPORT void
+wl_client_set_user_data(struct wl_client *client,
+			void *data,
+			wl_user_data_destroy_func_t dtor)
+{
+	client->data = data;
+	client->data_dtor = dtor;
+}
+
+/** Get the client's user data
+ *
+ * \param client The client object
+ * \return The user data pointer
+ *
+ * \since 1.22.90
+ * \sa wl_client_set_user_data
+ */
+WL_EXPORT void *
+wl_client_get_user_data(struct wl_client *client)
+{
+	return client->data;
+}
+
+struct wl_global *
+wl_display_add_global(struct wl_display *display,
+		      const struct wl_interface *interface,
+		      void *data, wl_global_bind_func_t bind) WL_DEPRECATED;
+
+WL_EXPORT struct wl_global *
+wl_display_add_global(struct wl_display *display,
+		      const struct wl_interface *interface,
+		      void *data, wl_global_bind_func_t bind)
+{
+	return wl_global_create(display, interface, interface->version, data, bind);
+}
+
+void
+wl_display_remove_global(struct wl_display *display,
+			 struct wl_global *global) WL_DEPRECATED;
+
+WL_EXPORT void
+wl_display_remove_global(struct wl_display *display, struct wl_global *global)
+{
+	wl_global_destroy(global);
+}
+
+/** \endcond */
+
+/* Functions at the end of this file are deprecated.  Instead of adding new
+ * code here, add it before the comment above that states:
+ * Deprecated functions below.
+ */
diff --git a/subprojects/wayland/src/wayland-server.h b/subprojects/wayland/src/wayland-server.h
new file mode 100644
index 0000000000000000000000000000000000000000..1be565f23f7bf57b853893576fdd8cd702d6121b
--- /dev/null
+++ b/subprojects/wayland/src/wayland-server.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/** \file
+ *
+ *  \brief Include the server API, deprecations and protocol C API.
+ *
+ *  \warning Use of this header file is discouraged. Prefer including
+ *  wayland-server-core.h instead, which does not include the
+ *  server protocol header and as such only defines the library
+ *  API, excluding the deprecated API below.
+ */
+
+#ifndef WAYLAND_SERVER_H
+#define WAYLAND_SERVER_H
+
+#include <stdint.h>
+#include "wayland-server-core.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * The user can set this macro to hide the wl_object, wl_resource and wl_buffer
+ * objects alongside the associated API.
+ *
+ * The structs were meant to be opaque, although we missed that in the early days.
+ *
+ * NOTE: the list of structs, functions, etc in this section MUST NEVER GROW.
+ * Otherwise we will break forward compatibility and applications that used to
+ * build fine will no longer be able to do so.
+ */
+#ifndef WL_HIDE_DEPRECATED
+
+struct wl_object {
+	const struct wl_interface *interface;
+	const void *implementation;
+	uint32_t id;
+};
+
+struct wl_resource {
+	struct wl_object object;
+	wl_resource_destroy_func_t destroy;
+	struct wl_list link;
+	struct wl_signal destroy_signal;
+	struct wl_client *client;
+	void *data;
+};
+
+uint32_t
+wl_client_add_resource(struct wl_client *client,
+		       struct wl_resource *resource) WL_DEPRECATED;
+
+struct wl_resource *
+wl_client_add_object(struct wl_client *client,
+		     const struct wl_interface *interface,
+		     const void *implementation,
+		     uint32_t id, void *data) WL_DEPRECATED;
+
+struct wl_resource *
+wl_client_new_object(struct wl_client *client,
+		     const struct wl_interface *interface,
+		     const void *implementation, void *data) WL_DEPRECATED;
+
+struct wl_global *
+wl_display_add_global(struct wl_display *display,
+		      const struct wl_interface *interface,
+		      void *data,
+		      wl_global_bind_func_t bind) WL_DEPRECATED;
+
+void
+wl_display_remove_global(struct wl_display *display,
+			 struct wl_global *global) WL_DEPRECATED;
+
+#endif
+
+#ifdef  __cplusplus
+}
+#endif
+
+#include "wayland-server-protocol.h"
+
+#endif
diff --git a/subprojects/wayland/src/wayland-shm.c b/subprojects/wayland/src/wayland-shm.c
new file mode 100644
index 0000000000000000000000000000000000000000..0a11736a6da01fdcd1a6c5067dcc814563a498aa
--- /dev/null
+++ b/subprojects/wayland/src/wayland-shm.c
@@ -0,0 +1,718 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ * Authors:
+ *    Kristian Høgsberg <krh@bitplanet.net>
+ *    Benjamin Franzke <benjaminfranzke@googlemail.com>
+ *
+ */
+
+#define _GNU_SOURCE
+
+#include "config.h"
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <pthread.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "wayland-os.h"
+#include "wayland-util.h"
+#include "wayland-private.h"
+#include "wayland-server.h"
+
+/* This once_t is used to synchronize installing the SIGBUS handler
+ * and creating the TLS key. This will be done in the first call
+ * wl_shm_buffer_begin_access which can happen from any thread */
+static pthread_once_t wl_shm_sigbus_once = PTHREAD_ONCE_INIT;
+static pthread_key_t wl_shm_sigbus_data_key;
+static struct sigaction wl_shm_old_sigbus_action;
+
+struct wl_shm_pool {
+	struct wl_resource *resource;
+	int internal_refcount;
+	int external_refcount;
+	char *data;
+	ssize_t size;
+	ssize_t new_size;
+#ifndef MREMAP_MAYMOVE
+	/* The following three fields are needed for mremap() emulation. */
+	int mmap_fd;
+	int mmap_flags;
+	int mmap_prot;
+#endif
+	bool sigbus_is_impossible;
+};
+
+/** \class wl_shm_buffer
+ *
+ * \brief A SHM buffer
+ *
+ * wl_shm_buffer provides a helper for accessing the contents of a wl_buffer
+ * resource created via the wl_shm interface.
+ *
+ * A wl_shm_buffer becomes invalid as soon as its #wl_resource is destroyed.
+ */
+struct wl_shm_buffer {
+	struct wl_resource *resource;
+	int32_t width, height;
+	int32_t stride;
+	uint32_t format;
+	int offset;
+	struct wl_shm_pool *pool;
+};
+
+struct wl_shm_sigbus_data {
+	struct wl_shm_pool *current_pool;
+	int access_count;
+	int fallback_mapping_used;
+};
+
+static void *
+shm_pool_grow_mapping(struct wl_shm_pool *pool)
+{
+	void *data;
+
+#ifdef MREMAP_MAYMOVE
+	data = mremap(pool->data, pool->size, pool->new_size, MREMAP_MAYMOVE);
+#else
+	data = wl_os_mremap_maymove(pool->mmap_fd, pool->data, &pool->size,
+				    pool->new_size, pool->mmap_prot,
+				    pool->mmap_flags);
+	if (pool->size != 0 && pool->resource != NULL) {
+		wl_resource_post_error(pool->resource,
+				       WL_SHM_ERROR_INVALID_FD,
+				       "leaked old mapping");
+	}
+#endif
+	return data;
+}
+
+static void
+shm_pool_finish_resize(struct wl_shm_pool *pool)
+{
+	void *data;
+
+	if (pool->size == pool->new_size)
+		return;
+
+	data = shm_pool_grow_mapping(pool);
+	if (data == MAP_FAILED) {
+		if (pool->resource != NULL)
+			wl_resource_post_error(pool->resource,
+					       WL_SHM_ERROR_INVALID_FD,
+					       "failed mremap");
+		return;
+	}
+
+	pool->data = data;
+	pool->size = pool->new_size;
+}
+
+static void
+shm_pool_unref(struct wl_shm_pool *pool, bool external)
+{
+	if (external) {
+		pool->external_refcount--;
+		assert(pool->external_refcount >= 0);
+		if (pool->external_refcount == 0)
+			shm_pool_finish_resize(pool);
+	} else {
+		pool->internal_refcount--;
+		assert(pool->internal_refcount >= 0);
+	}
+
+	if (pool->internal_refcount + pool->external_refcount > 0)
+		return;
+
+	munmap(pool->data, pool->size);
+#ifndef MREMAP_MAYMOVE
+	close(pool->mmap_fd);
+#endif
+	free(pool);
+}
+
+static void
+destroy_buffer(struct wl_resource *resource)
+{
+	struct wl_shm_buffer *buffer = wl_resource_get_user_data(resource);
+
+	shm_pool_unref(buffer->pool, false);
+	free(buffer);
+}
+
+static void
+shm_buffer_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct wl_buffer_interface shm_buffer_interface = {
+	shm_buffer_destroy
+};
+
+static bool
+format_is_supported(struct wl_client *client, uint32_t format)
+{
+	struct wl_display *display = wl_client_get_display(client);
+	struct wl_array *formats;
+	uint32_t *p;
+
+	switch (format) {
+	case WL_SHM_FORMAT_ARGB8888:
+	case WL_SHM_FORMAT_XRGB8888:
+		return true;
+	default:
+		formats = wl_display_get_additional_shm_formats(display);
+		wl_array_for_each(p, formats)
+			if (*p == format)
+				return true;
+	}
+
+	return false;
+}
+
+static void
+shm_pool_create_buffer(struct wl_client *client, struct wl_resource *resource,
+		       uint32_t id, int32_t offset,
+		       int32_t width, int32_t height,
+		       int32_t stride, uint32_t format)
+{
+	struct wl_shm_pool *pool = wl_resource_get_user_data(resource);
+	struct wl_shm_buffer *buffer;
+
+	if (!format_is_supported(client, format)) {
+		wl_resource_post_error(resource,
+				       WL_SHM_ERROR_INVALID_FORMAT,
+				       "invalid format 0x%x", format);
+		return;
+	}
+
+	if (offset < 0 || width <= 0 || height <= 0 || stride < width ||
+	    INT32_MAX / stride < height ||
+	    offset > pool->size - stride * height) {
+		wl_resource_post_error(resource,
+				       WL_SHM_ERROR_INVALID_STRIDE,
+				       "invalid width, height or stride (%dx%d, %u)",
+				       width, height, stride);
+		return;
+	}
+
+	buffer = zalloc(sizeof *buffer);
+	if (buffer == NULL) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	buffer->width = width;
+	buffer->height = height;
+	buffer->format = format;
+	buffer->stride = stride;
+	buffer->offset = offset;
+	buffer->pool = pool;
+	pool->internal_refcount++;
+
+	buffer->resource =
+		wl_resource_create(client, &wl_buffer_interface, 1, id);
+	if (buffer->resource == NULL) {
+		wl_client_post_no_memory(client);
+		shm_pool_unref(pool, false);
+		free(buffer);
+		return;
+	}
+
+	wl_resource_set_implementation(buffer->resource,
+				       &shm_buffer_interface,
+				       buffer, destroy_buffer);
+}
+
+static void
+destroy_pool(struct wl_resource *resource)
+{
+	struct wl_shm_pool *pool = wl_resource_get_user_data(resource);
+
+	pool->resource = NULL;
+	shm_pool_unref(pool, false);
+}
+
+static void
+shm_pool_destroy(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static void
+shm_pool_resize(struct wl_client *client, struct wl_resource *resource,
+		int32_t size)
+{
+	struct wl_shm_pool *pool = wl_resource_get_user_data(resource);
+
+	if (size < pool->size) {
+		wl_resource_post_error(resource,
+				       WL_SHM_ERROR_INVALID_FD,
+				       "shrinking pool invalid");
+		return;
+	}
+
+	pool->new_size = size;
+
+	/* If the compositor has taken references on this pool it
+	 * may be caching pointers into it. In that case we
+	 * defer the resize (which may move the entire mapping)
+	 * until the compositor finishes dereferencing the pool.
+	 */
+	if (pool->external_refcount == 0)
+		shm_pool_finish_resize(pool);
+}
+
+static const struct wl_shm_pool_interface shm_pool_interface = {
+	shm_pool_create_buffer,
+	shm_pool_destroy,
+	shm_pool_resize
+};
+
+static void
+shm_create_pool(struct wl_client *client, struct wl_resource *resource,
+		uint32_t id, int fd, int32_t size)
+{
+	struct wl_shm_pool *pool;
+	struct stat statbuf;
+	int seals;
+	int prot;
+	int flags;
+	uint32_t version;
+
+	if (size <= 0) {
+		wl_resource_post_error(resource,
+				       WL_SHM_ERROR_INVALID_STRIDE,
+				       "invalid size (%d)", size);
+		goto err_close;
+	}
+
+	pool = zalloc(sizeof *pool);
+	if (pool == NULL) {
+		wl_client_post_no_memory(client);
+		goto err_close;
+	}
+
+#ifdef HAVE_MEMFD_CREATE
+	seals = fcntl(fd, F_GET_SEALS);
+	if (seals == -1)
+		seals = 0;
+
+	if ((seals & F_SEAL_SHRINK) && fstat(fd, &statbuf) >= 0)
+		pool->sigbus_is_impossible = statbuf.st_size >= size;
+	else
+		pool->sigbus_is_impossible = false;
+#else
+	pool->sigbus_is_impossible = false;
+#endif
+
+	pool->internal_refcount = 1;
+	pool->external_refcount = 0;
+	pool->size = size;
+	pool->new_size = size;
+	prot = PROT_READ | PROT_WRITE;
+	flags = MAP_SHARED;
+	pool->data = mmap(NULL, size, prot, flags, fd, 0);
+	if (pool->data == MAP_FAILED) {
+		wl_resource_post_error(resource, WL_SHM_ERROR_INVALID_FD,
+				       "failed mmap fd %d: %s", fd,
+				       strerror(errno));
+		goto err_free;
+	}
+#ifndef MREMAP_MAYMOVE
+	/* We may need to keep the fd, prot and flags to emulate mremap(). */
+	pool->mmap_fd = fd;
+	pool->mmap_prot = prot;
+	pool->mmap_flags = flags;
+#else
+	close(fd);
+#endif
+
+	version = wl_resource_get_version(resource);
+	pool->resource =
+		wl_resource_create(client, &wl_shm_pool_interface, version, id);
+	if (!pool->resource) {
+		wl_client_post_no_memory(client);
+		munmap(pool->data, pool->size);
+		free(pool);
+		return;
+	}
+
+	wl_resource_set_implementation(pool->resource,
+				       &shm_pool_interface,
+				       pool, destroy_pool);
+
+	return;
+
+err_free:
+	free(pool);
+err_close:
+	close(fd);
+}
+
+static void
+shm_release(struct wl_client *client, struct wl_resource *resource)
+{
+	wl_resource_destroy(resource);
+}
+
+static const struct wl_shm_interface shm_interface = {
+	shm_create_pool,
+	shm_release,
+};
+
+static void
+bind_shm(struct wl_client *client,
+	 void *data, uint32_t version, uint32_t id)
+{
+	struct wl_resource *resource;
+	struct wl_display *display = wl_client_get_display(client);
+	struct wl_array *additional_formats;
+	uint32_t *p;
+
+	resource = wl_resource_create(client, &wl_shm_interface, version, id);
+	if (!resource) {
+		wl_client_post_no_memory(client);
+		return;
+	}
+
+	wl_resource_set_implementation(resource, &shm_interface, data, NULL);
+
+	wl_shm_send_format(resource, WL_SHM_FORMAT_ARGB8888);
+	wl_shm_send_format(resource, WL_SHM_FORMAT_XRGB8888);
+
+	additional_formats = wl_display_get_additional_shm_formats(display);
+	wl_array_for_each(p, additional_formats)
+		wl_shm_send_format(resource, *p);
+}
+
+WL_EXPORT int
+wl_display_init_shm(struct wl_display *display)
+{
+	if (!wl_global_create(display, &wl_shm_interface, 2, NULL, bind_shm))
+		return -1;
+
+	return 0;
+}
+
+WL_EXPORT struct wl_shm_buffer *
+wl_shm_buffer_get(struct wl_resource *resource)
+{
+	if (resource == NULL)
+		return NULL;
+
+	if (wl_resource_instance_of(resource, &wl_buffer_interface,
+				    &shm_buffer_interface))
+		return wl_resource_get_user_data(resource);
+	else
+		return NULL;
+}
+
+WL_EXPORT int32_t
+wl_shm_buffer_get_stride(struct wl_shm_buffer *buffer)
+{
+	return buffer->stride;
+}
+
+
+/** Get a pointer to the memory for the SHM buffer
+ *
+ * \param buffer The buffer object
+ *
+ * Returns a pointer which can be used to read the data contained in
+ * the given SHM buffer.
+ *
+ * As this buffer is memory-mapped, reading from it may generate
+ * SIGBUS signals. This can happen if the client claims that the
+ * buffer is larger than it is or if something truncates the
+ * underlying file. To prevent this signal from causing the compositor
+ * to crash you should call wl_shm_buffer_begin_access and
+ * wl_shm_buffer_end_access around code that reads from the memory.
+ *
+ * \memberof wl_shm_buffer
+ */
+WL_EXPORT void *
+wl_shm_buffer_get_data(struct wl_shm_buffer *buffer)
+{
+	if (buffer->pool->external_refcount &&
+	    (buffer->pool->size != buffer->pool->new_size))
+		wl_log("Buffer address requested when its parent pool "
+		       "has an external reference and a deferred resize "
+		       "pending.\n");
+	return buffer->pool->data + buffer->offset;
+}
+
+WL_EXPORT uint32_t
+wl_shm_buffer_get_format(struct wl_shm_buffer *buffer)
+{
+	return buffer->format;
+}
+
+WL_EXPORT int32_t
+wl_shm_buffer_get_width(struct wl_shm_buffer *buffer)
+{
+	return buffer->width;
+}
+
+WL_EXPORT int32_t
+wl_shm_buffer_get_height(struct wl_shm_buffer *buffer)
+{
+	return buffer->height;
+}
+
+/** Get a reference to a shm_buffer's shm_pool
+ *
+ * \param buffer The buffer object
+ *
+ * Returns a pointer to a buffer's shm_pool and increases the
+ * shm_pool refcount.
+ *
+ * The compositor must remember to call wl_shm_pool_unref when
+ * it no longer needs the reference to ensure proper destruction
+ * of the pool.
+ *
+ * \memberof wl_shm_buffer
+ * \sa wl_shm_pool_unref
+ */
+WL_EXPORT struct wl_shm_pool *
+wl_shm_buffer_ref_pool(struct wl_shm_buffer *buffer)
+{
+	assert(buffer->pool->internal_refcount +
+	       buffer->pool->external_refcount);
+
+	buffer->pool->external_refcount++;
+	return buffer->pool;
+}
+
+/** Unreference a shm_pool
+ *
+ * \param pool The pool object
+ *
+ * Drops a reference to a wl_shm_pool object.
+ *
+ * This is only necessary if the compositor has explicitly
+ * taken a reference with wl_shm_buffer_ref_pool(), otherwise
+ * the pool will be automatically destroyed when appropriate.
+ *
+ * \memberof wl_shm_pool
+ * \sa wl_shm_buffer_ref_pool
+ */
+WL_EXPORT void
+wl_shm_pool_unref(struct wl_shm_pool *pool)
+{
+	shm_pool_unref(pool, true);
+}
+
+static void
+reraise_sigbus(void)
+{
+	/* If SIGBUS is raised for some other reason than accessing
+	 * the pool then we'll uninstall the signal handler so we can
+	 * reraise it. This would presumably kill the process */
+	sigaction(SIGBUS, &wl_shm_old_sigbus_action, NULL);
+	raise(SIGBUS);
+}
+
+static void
+sigbus_handler(int signum, siginfo_t *info, void *context)
+{
+	struct wl_shm_sigbus_data *sigbus_data =
+		pthread_getspecific(wl_shm_sigbus_data_key);
+	struct wl_shm_pool *pool;
+
+	if (sigbus_data == NULL) {
+		reraise_sigbus();
+		return;
+	}
+
+	pool = sigbus_data->current_pool;
+
+	/* If the offending address is outside the mapped space for
+	 * the pool then the error is a real problem so we'll reraise
+	 * the signal */
+	if (pool == NULL ||
+	    (char *) info->si_addr < pool->data ||
+	    (char *) info->si_addr >= pool->data + pool->size) {
+		reraise_sigbus();
+		return;
+	}
+
+	sigbus_data->fallback_mapping_used = 1;
+
+	/* This should replace the previous mapping */
+	if (mmap(pool->data, pool->size, PROT_READ | PROT_WRITE,
+		 MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, 0, 0) == MAP_FAILED) {
+		reraise_sigbus();
+		return;
+	}
+}
+
+static void
+destroy_sigbus_data(void *data)
+{
+	struct wl_shm_sigbus_data *sigbus_data = data;
+
+	free(sigbus_data);
+}
+
+static void
+init_sigbus_data_key(void)
+{
+	struct sigaction new_action = {
+		.sa_sigaction = sigbus_handler,
+		.sa_flags = SA_SIGINFO | SA_NODEFER
+	};
+
+	sigemptyset(&new_action.sa_mask);
+
+	sigaction(SIGBUS, &new_action, &wl_shm_old_sigbus_action);
+
+	pthread_key_create(&wl_shm_sigbus_data_key, destroy_sigbus_data);
+}
+
+/** Mark that the given SHM buffer is about to be accessed
+ *
+ * \param buffer The SHM buffer
+ *
+ * An SHM buffer is a memory-mapped file given by the client.
+ * According to POSIX, reading from a memory-mapped region that
+ * extends off the end of the file will cause a SIGBUS signal to be
+ * generated. Normally this would cause the compositor to terminate.
+ * In order to make the compositor robust against clients that change
+ * the size of the underlying file or lie about its size, you should
+ * protect access to the buffer by calling this function before
+ * reading from the memory and call wl_shm_buffer_end_access
+ * afterwards. This will install a signal handler for SIGBUS which
+ * will prevent the compositor from crashing.
+ *
+ * After calling this function the signal handler will remain
+ * installed for the lifetime of the compositor process. Note that
+ * this function will not work properly if the compositor is also
+ * installing its own handler for SIGBUS.
+ *
+ * If a SIGBUS signal is received for an address within the range of
+ * the SHM pool of the given buffer then the client will be sent an
+ * error event when wl_shm_buffer_end_access is called. If the signal
+ * is for an address outside that range then the signal handler will
+ * reraise the signal which would will likely cause the compositor to
+ * terminate.
+ *
+ * It is safe to nest calls to these functions as long as the nested
+ * calls are all accessing the same buffer. The number of calls to
+ * wl_shm_buffer_end_access must match the number of calls to
+ * wl_shm_buffer_begin_access. These functions are thread-safe and it
+ * is allowed to simultaneously access different buffers or the same
+ * buffer from multiple threads.
+ *
+ * \memberof wl_shm_buffer
+ */
+WL_EXPORT void
+wl_shm_buffer_begin_access(struct wl_shm_buffer *buffer)
+{
+	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);
+	if (sigbus_data == NULL) {
+		sigbus_data = zalloc(sizeof *sigbus_data);
+		if (sigbus_data == NULL)
+			return;
+
+		pthread_setspecific(wl_shm_sigbus_data_key, sigbus_data);
+	}
+
+	assert(sigbus_data->current_pool == NULL ||
+	       sigbus_data->current_pool == pool);
+
+	sigbus_data->current_pool = pool;
+	sigbus_data->access_count++;
+}
+
+/** Ends the access to a buffer started by wl_shm_buffer_begin_access
+ *
+ * \param buffer The SHM buffer
+ *
+ * This should be called after wl_shm_buffer_begin_access once the
+ * buffer is no longer being accessed. If a SIGBUS signal was
+ * generated in-between these two calls then the resource for the
+ * given buffer will be sent an error.
+ *
+ * \memberof wl_shm_buffer
+ */
+WL_EXPORT void
+wl_shm_buffer_end_access(struct wl_shm_buffer *buffer)
+{
+	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) {
+		if (sigbus_data->fallback_mapping_used) {
+			wl_resource_post_error(buffer->resource,
+					       WL_SHM_ERROR_INVALID_FD,
+					       "error accessing SHM buffer");
+			sigbus_data->fallback_mapping_used = 0;
+		}
+
+		sigbus_data->current_pool = NULL;
+	}
+}
+
+/** \cond */ /* Deprecated functions below. */
+
+WL_EXPORT struct wl_shm_buffer *
+wl_shm_buffer_create(struct wl_client *client,
+		     uint32_t id, int32_t width, int32_t height,
+		     int32_t stride, uint32_t format)
+{
+	return NULL;
+}
+
+/** \endcond */
+
+/* Functions at the end of this file are deprecated.  Instead of adding new
+ * code here, add it before the comment above that states:
+ * Deprecated functions below.
+ */
diff --git a/subprojects/wayland/src/wayland-util.c b/subprojects/wayland/src/wayland-util.c
new file mode 100644
index 0000000000000000000000000000000000000000..7231346b197aaf3718bb5d6fc18dfe506abb2361
--- /dev/null
+++ b/subprojects/wayland/src/wayland-util.c
@@ -0,0 +1,479 @@
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2011 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+
+#include "wayland-util.h"
+#include "wayland-private.h"
+
+WL_EXPORT void
+wl_list_init(struct wl_list *list)
+{
+	list->prev = list;
+	list->next = list;
+}
+
+WL_EXPORT void
+wl_list_insert(struct wl_list *list, struct wl_list *elm)
+{
+	elm->prev = list;
+	elm->next = list->next;
+	list->next = elm;
+	elm->next->prev = elm;
+}
+
+WL_EXPORT void
+wl_list_remove(struct wl_list *elm)
+{
+	elm->prev->next = elm->next;
+	elm->next->prev = elm->prev;
+	elm->next = NULL;
+	elm->prev = NULL;
+}
+
+WL_EXPORT int
+wl_list_length(const struct wl_list *list)
+{
+	struct wl_list *e;
+	int count;
+
+	count = 0;
+	e = list->next;
+	while (e != list) {
+		e = e->next;
+		count++;
+	}
+
+	return count;
+}
+
+WL_EXPORT int
+wl_list_empty(const struct wl_list *list)
+{
+	return list->next == list;
+}
+
+WL_EXPORT void
+wl_list_insert_list(struct wl_list *list, struct wl_list *other)
+{
+	if (wl_list_empty(other))
+		return;
+
+	other->next->prev = list;
+	other->prev->next = list->next;
+	list->next->prev = other->prev;
+	list->next = other->next;
+}
+
+WL_EXPORT void
+wl_array_init(struct wl_array *array)
+{
+	memset(array, 0, sizeof *array);
+}
+
+WL_EXPORT void
+wl_array_release(struct wl_array *array)
+{
+	free(array->data);
+	array->data = WL_ARRAY_POISON_PTR;
+}
+
+WL_EXPORT void *
+wl_array_add(struct wl_array *array, size_t size)
+{
+	size_t alloc;
+	void *data, *p;
+
+	if (array->alloc > 0)
+		alloc = array->alloc;
+	else
+		alloc = 16;
+
+	while (alloc < array->size + size)
+		alloc *= 2;
+
+	if (array->alloc < alloc) {
+		if (array->alloc > 0)
+			data = realloc(array->data, alloc);
+		else
+			data = malloc(alloc);
+
+		if (data == NULL)
+			return NULL;
+		array->data = data;
+		array->alloc = alloc;
+	}
+
+	p = (char *)array->data + array->size;
+	array->size += size;
+
+	return p;
+}
+
+WL_EXPORT int
+wl_array_copy(struct wl_array *array, struct wl_array *source)
+{
+	if (array->size < source->size) {
+		if (!wl_array_add(array, source->size - array->size))
+			return -1;
+	} else {
+		array->size = source->size;
+	}
+
+	if (source->size > 0)
+		memcpy(array->data, source->data, source->size);
+
+	return 0;
+}
+
+/** \cond */
+
+int
+wl_interface_equal(const struct wl_interface *a, const struct wl_interface *b)
+{
+	/* In most cases the pointer equality test is sufficient.
+	 * However, in some cases, depending on how things are split
+	 * across shared objects, we can end up with multiple
+	 * instances of the interface metadata constants.  So if the
+	 * pointers match, the interfaces are equal, if they don't
+	 * match we have to compare the interface names.
+	 */
+	return a == b || strcmp(a->name, b->name) == 0;
+}
+
+union map_entry {
+	uintptr_t next;
+	void *data;
+};
+
+static inline bool
+map_entry_is_free(union map_entry entry)
+{
+	return entry.next & 0x1;
+}
+
+static inline void *
+map_entry_get_data(union map_entry entry)
+{
+	return (void *)(entry.next & ~(uintptr_t)0x3);
+}
+
+static inline uint32_t
+map_entry_get_flags(union map_entry entry)
+{
+	return (entry.next >> 1) & 0x1;
+}
+
+void
+wl_map_init(struct wl_map *map, uint32_t side)
+{
+	memset(map, 0, sizeof *map);
+	map->side = side;
+}
+
+void
+wl_map_release(struct wl_map *map)
+{
+	wl_array_release(&map->client_entries);
+	wl_array_release(&map->server_entries);
+}
+
+uint32_t
+wl_map_insert_new(struct wl_map *map, uint32_t flags, void *data)
+{
+	union map_entry *start, *entry;
+	struct wl_array *entries;
+	uint32_t base;
+	uint32_t count;
+
+	if (map->side == WL_MAP_CLIENT_SIDE) {
+		entries = &map->client_entries;
+		base = 0;
+	} else {
+		entries = &map->server_entries;
+		base = WL_SERVER_ID_START;
+	}
+
+	if (map->free_list) {
+		start = entries->data;
+		entry = &start[map->free_list >> 1];
+		map->free_list = entry->next;
+	} else {
+		entry = wl_array_add(entries, sizeof *entry);
+		if (!entry)
+			return 0;
+		start = entries->data;
+	}
+
+	/* wl_array only grows, so if we have too many objects at
+	 * this point there's no way to clean up. We could be more
+	 * pro-active about trying to avoid this allocation, but
+	 * it doesn't really matter because at this point there is
+	 * nothing to be done but disconnect the client and delete
+	 * the whole array either way.
+	 */
+	count = entry - start;
+	if (count > WL_MAP_MAX_OBJECTS) {
+		/* entry->data is freshly malloced garbage, so we'd
+		 * better make it a NULL so wl_map_for_each doesn't
+		 * dereference it later. */
+		entry->data = NULL;
+		errno = ENOSPC;
+		return 0;
+	}
+	entry->data = data;
+	entry->next |= (flags & 0x1) << 1;
+
+	return count + base;
+}
+
+int
+wl_map_insert_at(struct wl_map *map, uint32_t flags, uint32_t i, void *data)
+{
+	union map_entry *start;
+	uint32_t count;
+	struct wl_array *entries;
+
+	if (i < WL_SERVER_ID_START) {
+		entries = &map->client_entries;
+	} else {
+		entries = &map->server_entries;
+		i -= WL_SERVER_ID_START;
+	}
+
+	if (i > WL_MAP_MAX_OBJECTS) {
+		errno = ENOSPC;
+		return -1;
+	}
+
+	count = entries->size / sizeof *start;
+	if (count < i) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (count == i) {
+		if (!wl_array_add(entries, sizeof *start))
+			return -1;
+	}
+
+	start = entries->data;
+	start[i].data = data;
+	start[i].next |= (flags & 0x1) << 1;
+
+	return 0;
+}
+
+int
+wl_map_reserve_new(struct wl_map *map, uint32_t i)
+{
+	union map_entry *start;
+	uint32_t count;
+	struct wl_array *entries;
+
+	if (i < WL_SERVER_ID_START) {
+		if (map->side == WL_MAP_CLIENT_SIDE) {
+			errno = EINVAL;
+			return -1;
+		}
+
+		entries = &map->client_entries;
+	} else {
+		if (map->side == WL_MAP_SERVER_SIDE) {
+			errno = EINVAL;
+			return -1;
+		}
+
+		entries = &map->server_entries;
+		i -= WL_SERVER_ID_START;
+	}
+
+	if (i > WL_MAP_MAX_OBJECTS) {
+		errno = ENOSPC;
+		return -1;
+	}
+
+	count = entries->size / sizeof *start;
+	if (count < i) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	if (count == i) {
+		if (!wl_array_add(entries, sizeof *start))
+			return -1;
+
+		start = entries->data;
+		start[i].data = NULL;
+	} else {
+		start = entries->data;
+		if (start[i].data != NULL) {
+			errno = EINVAL;
+			return -1;
+		}
+	}
+
+	return 0;
+}
+
+void
+wl_map_remove(struct wl_map *map, uint32_t i)
+{
+	union map_entry *start;
+	struct wl_array *entries;
+
+	if (i < WL_SERVER_ID_START) {
+		if (map->side == WL_MAP_SERVER_SIDE)
+			return;
+
+		entries = &map->client_entries;
+	} else {
+		if (map->side == WL_MAP_CLIENT_SIDE)
+			return;
+
+		entries = &map->server_entries;
+		i -= WL_SERVER_ID_START;
+	}
+
+	start = entries->data;
+	start[i].next = map->free_list;
+	map->free_list = (i << 1) | 1;
+}
+
+void *
+wl_map_lookup(struct wl_map *map, uint32_t i)
+{
+	union map_entry *start;
+	uint32_t count;
+	struct wl_array *entries;
+
+	if (i < WL_SERVER_ID_START) {
+		entries = &map->client_entries;
+	} else {
+		entries = &map->server_entries;
+		i -= WL_SERVER_ID_START;
+	}
+
+	start = entries->data;
+	count = entries->size / sizeof *start;
+
+	if (i < count && !map_entry_is_free(start[i]))
+		return map_entry_get_data(start[i]);
+
+	return NULL;
+}
+
+uint32_t
+wl_map_lookup_flags(struct wl_map *map, uint32_t i)
+{
+	union map_entry *start;
+	uint32_t count;
+	struct wl_array *entries;
+
+	if (i < WL_SERVER_ID_START) {
+		entries = &map->client_entries;
+	} else {
+		entries = &map->server_entries;
+		i -= WL_SERVER_ID_START;
+	}
+
+	start = entries->data;
+	count = entries->size / sizeof *start;
+
+	if (i < count && !map_entry_is_free(start[i]))
+		return map_entry_get_flags(start[i]);
+
+	return 0;
+}
+
+static enum wl_iterator_result
+for_each_helper(struct wl_array *entries, wl_iterator_func_t func, void *data)
+{
+	enum wl_iterator_result ret = WL_ITERATOR_CONTINUE;
+	union map_entry entry, *start;
+	size_t count;
+
+	start = (union map_entry *) entries->data;
+	count = entries->size / sizeof(union map_entry);
+
+	for (size_t idx = 0; idx < count; idx++) {
+		entry = start[idx];
+		if (entry.data && !map_entry_is_free(entry)) {
+			ret = func(map_entry_get_data(entry), data, map_entry_get_flags(entry));
+			if (ret != WL_ITERATOR_CONTINUE)
+				break;
+		}
+	}
+
+	return ret;
+}
+
+void
+wl_map_for_each(struct wl_map *map, wl_iterator_func_t func, void *data)
+{
+	enum wl_iterator_result ret;
+
+	ret = for_each_helper(&map->client_entries, func, data);
+	if (ret == WL_ITERATOR_CONTINUE)
+		for_each_helper(&map->server_entries, func, data);
+}
+
+static void
+wl_log_stderr_handler(const char *fmt, va_list arg)
+{
+	vfprintf(stderr, fmt, arg);
+}
+
+wl_log_func_t wl_log_handler = wl_log_stderr_handler;
+
+void
+wl_log(const char *fmt, ...)
+{
+	va_list argp;
+
+	va_start(argp, fmt);
+	wl_log_handler(fmt, argp);
+	va_end(argp);
+}
+
+void
+wl_abort(const char *fmt, ...)
+{
+	va_list argp;
+
+	va_start(argp, fmt);
+	wl_log_handler(fmt, argp);
+	va_end(argp);
+
+	abort();
+}
+
+/** \endcond */
diff --git a/subprojects/wayland/src/wayland-util.h b/subprojects/wayland/src/wayland-util.h
new file mode 100644
index 0000000000000000000000000000000000000000..929a34f3ec0a87f342464edf1eb3cee648507f0a
--- /dev/null
+++ b/subprojects/wayland/src/wayland-util.h
@@ -0,0 +1,760 @@
+/*
+ * Copyright © 2008 Kristian Høgsberg
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+/** \file wayland-util.h
+ *
+ * \brief Utility classes, functions, and macros.
+ */
+
+#ifndef WAYLAND_UTIL_H
+#define WAYLAND_UTIL_H
+
+#include <math.h>
+#include <stddef.h>
+#include <inttypes.h>
+#include <stdarg.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/** Visibility attribute */
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define WL_EXPORT __attribute__ ((visibility("default")))
+#else
+#define WL_EXPORT
+#endif
+
+/** Deprecated attribute */
+#if __STDC_VERSION__ >= 202311L
+#define WL_DEPRECATED [[deprecated]]
+#elif defined(__GNUC__) && __GNUC__ >= 4
+#define WL_DEPRECATED __attribute__ ((deprecated))
+#else
+#define WL_DEPRECATED
+#endif
+
+/**
+ * Printf-style argument attribute
+ *
+ * \param x Ordinality of the format string argument
+ * \param y Ordinality of the argument to check against the format string
+ *
+ * \sa https://gcc.gnu.org/onlinedocs/gcc-3.2.1/gcc/Function-Attributes.html
+ */
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define WL_PRINTF(x, y) __attribute__((__format__(__printf__, x, y)))
+#else
+#define WL_PRINTF(x, y)
+#endif
+
+#if __STDC_VERSION__ >= 202311L
+#define WL_TYPEOF(expr) typeof(expr)
+#else
+#define WL_TYPEOF(expr) __typeof__(expr)
+#endif
+
+/** \class wl_object
+ *
+ * \brief A protocol object.
+ *
+ * A `wl_object` is an opaque struct identifying the protocol object
+ * underlying a `wl_proxy` or `wl_resource`.
+ *
+ * \note Functions accessing a `wl_object` are not normally used by client code.
+ * Clients should normally use the higher level interface generated by the
+ * scanner to interact with compositor objects.
+ *
+ */
+struct wl_object;
+
+/**
+ * Protocol message signature
+ *
+ * A wl_message describes the signature of an actual protocol message, such as a
+ * request or event, that adheres to the Wayland protocol wire format. The
+ * protocol implementation uses a wl_message within its demarshal machinery for
+ * decoding messages between a compositor and its clients. In a sense, a
+ * wl_message is to a protocol message like a class is to an object.
+ *
+ * The `name` of a wl_message is the name of the corresponding protocol message.
+ *
+ * The `signature` is an ordered list of symbols representing the data types
+ * of message arguments and, optionally, a protocol version and indicators for
+ * nullability. A leading integer in the `signature` indicates the _since_
+ * version of the protocol message. A `?` preceding a data type symbol indicates
+ * that the following argument type is nullable. While it is a protocol violation
+ * to send messages with non-nullable arguments set to `NULL`, event handlers in
+ * clients might still get called with non-nullable object arguments set to
+ * `NULL`. This can happen when the client destroyed the object being used as
+ * argument on its side and an event referencing that object was sent before the
+ * server knew about its destruction. As this race cannot be prevented, clients
+ * should - as a general rule - program their event handlers such that they can
+ * handle object arguments declared non-nullable being `NULL` gracefully.
+ *
+ * When no arguments accompany a message, `signature` is an empty string.
+ *
+ * Symbols:
+ *
+ * * `i`: int
+ * * `u`: uint
+ * * `f`: fixed
+ * * `s`: string
+ * * `o`: object
+ * * `n`: new_id
+ * * `a`: array
+ * * `h`: fd
+ * * `?`: following argument (`o` or `s`) is nullable
+ *
+ * While demarshaling primitive arguments is straightforward, when demarshaling
+ * messages containing `object` or `new_id` arguments, the protocol
+ * implementation often must determine the type of the object. The `types` of a
+ * wl_message is an array of wl_interface references that correspond to `o` and
+ * `n` arguments in `signature`, with `NULL` placeholders for arguments with
+ * non-object types.
+ *
+ * Consider the protocol event wl_display `delete_id` that has a single `uint`
+ * argument. The wl_message is:
+ *
+ * \code
+ * { "delete_id", "u", [NULL] }
+ * \endcode
+ *
+ * Here, the message `name` is `"delete_id"`, the `signature` is `"u"`, and the
+ * argument `types` is `[NULL]`, indicating that the `uint` argument has no
+ * corresponding wl_interface since it is a primitive argument.
+ *
+ * In contrast, consider a `wl_foo` interface supporting protocol request `bar`
+ * that has existed since version 2, and has two arguments: a `uint` and an
+ * object of type `wl_baz_interface` that may be `NULL`. Such a `wl_message`
+ * might be:
+ *
+ * \code
+ * { "bar", "2u?o", [NULL, &wl_baz_interface] }
+ * \endcode
+ *
+ * Here, the message `name` is `"bar"`, and the `signature` is `"2u?o"`. Notice
+ * how the `2` indicates the protocol version, the `u` indicates the first
+ * argument type is `uint`, and the `?o` indicates that the second argument
+ * is an object that may be `NULL`. Lastly, the argument `types` array indicates
+ * that no wl_interface corresponds to the first argument, while the type
+ * `wl_baz_interface` corresponds to the second argument.
+ *
+ * \sa wl_argument
+ * \sa wl_interface
+ * \sa <a href="https://wayland.freedesktop.org/docs/html/ch04.html#sect-Protocol-Wire-Format">Wire Format</a>
+ */
+struct wl_message {
+	/** Message name */
+	const char *name;
+	/** Message signature */
+	const char *signature;
+	/** Object argument interfaces */
+	const struct wl_interface **types;
+};
+
+/**
+ * Protocol object interface
+ *
+ * A wl_interface describes the API of a protocol object defined in the Wayland
+ * protocol specification. The protocol implementation uses a wl_interface
+ * within its marshalling machinery for encoding client requests.
+ *
+ * The `name` of a wl_interface is the name of the corresponding protocol
+ * interface, and `version` represents the version of the interface. The members
+ * `method_count` and `event_count` represent the number of `methods` (requests)
+ * and `events` in the respective wl_message members.
+ *
+ * For example, consider a protocol interface `foo`, marked as version `1`, with
+ * two requests and one event.
+ *
+ * \code{.xml}
+ * <interface name="foo" version="1">
+ *   <request name="a"></request>
+ *   <request name="b"></request>
+ *   <event name="c"></event>
+ * </interface>
+ * \endcode
+ *
+ * Given two wl_message arrays `foo_requests` and `foo_events`, a wl_interface
+ * for `foo` might be:
+ *
+ * \code
+ * struct wl_interface foo_interface = {
+ *         "foo", 1,
+ *         2, foo_requests,
+ *         1, foo_events
+ * };
+ * \endcode
+ *
+ * \note The server side of the protocol may define interface <em>implementation
+ *       types</em> that incorporate the term `interface` in their name. Take
+ *       care to not confuse these server-side `struct`s with a wl_interface
+ *       variable whose name also ends in `interface`. For example, while the
+ *       server may define a type `struct wl_foo_interface`, the client may
+ *       define a `struct wl_interface wl_foo_interface`.
+ *
+ * \sa wl_message
+ * \sa wl_proxy
+ * \sa <a href="https://wayland.freedesktop.org/docs/html/ch04.html#sect-Protocol-Interfaces">Interfaces</a>
+ * \sa <a href="https://wayland.freedesktop.org/docs/html/ch04.html#sect-Protocol-Versioning">Versioning</a>
+ */
+struct wl_interface {
+	/** Interface name */
+	const char *name;
+	/** Interface version */
+	int version;
+	/** Number of methods (requests) */
+	int method_count;
+	/** Method (request) signatures */
+	const struct wl_message *methods;
+	/** Number of events */
+	int event_count;
+	/** Event signatures */
+	const struct wl_message *events;
+};
+
+/** \class wl_list
+ *
+ * \brief Doubly-linked list
+ *
+ * On its own, an instance of `struct wl_list` represents the sentinel head of
+ * a doubly-linked list, and must be initialized using wl_list_init().
+ * When empty, the list head's `next` and `prev` members point to the list head
+ * itself, otherwise `next` references the first element in the list, and `prev`
+ * refers to the last element in the list.
+ *
+ * Use the `struct wl_list` type to represent both the list head and the links
+ * between elements within the list. Use wl_list_empty() to determine if the
+ * list is empty in O(1).
+ *
+ * All elements in the list must be of the same type. The element type must have
+ * a `struct wl_list` member, often named `link` by convention. Prior to
+ * insertion, there is no need to initialize an element's `link` - invoking
+ * wl_list_init() on an individual list element's `struct wl_list` member is
+ * unnecessary if the very next operation is wl_list_insert(). However, a
+ * common idiom is to initialize an element's `link` prior to removal - ensure
+ * safety by invoking wl_list_init() before wl_list_remove().
+ *
+ * Consider a list reference `struct wl_list foo_list`, an element type as
+ * `struct element`, and an element's link member as `struct wl_list link`.
+ *
+ * The following code initializes a list and adds three elements to it.
+ *
+ * \code
+ * struct wl_list foo_list;
+ *
+ * struct element {
+ *         int foo;
+ *         struct wl_list link;
+ * };
+ * struct element e1, e2, e3;
+ *
+ * wl_list_init(&foo_list);
+ * wl_list_insert(&foo_list, &e1.link);   // e1 is the first element
+ * wl_list_insert(&foo_list, &e2.link);   // e2 is now the first element
+ * wl_list_insert(&e2.link, &e3.link); // insert e3 after e2
+ * \endcode
+ *
+ * The list now looks like <em>[e2, e3, e1]</em>.
+ *
+ * The `wl_list` API provides some iterator macros. For example, to iterate
+ * a list in ascending order:
+ *
+ * \code
+ * struct element *e;
+ * wl_list_for_each(e, foo_list, link) {
+ *         do_something_with_element(e);
+ * }
+ * \endcode
+ *
+ * See the documentation of each iterator for details.
+ * \sa http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/linux/list.h
+ */
+struct wl_list {
+	/** Previous list element */
+	struct wl_list *prev;
+	/** Next list element */
+	struct wl_list *next;
+};
+
+/**
+ * Initializes the list.
+ *
+ * \param list List to initialize
+ *
+ * \memberof wl_list
+ */
+void
+wl_list_init(struct wl_list *list);
+
+/**
+ * Inserts an element into the list, after the element represented by \p list.
+ * When \p list is a reference to the list itself (the head), set the containing
+ * struct of \p elm as the first element in the list.
+ *
+ * \note If \p elm is already part of a list, inserting it again will lead to
+ *       list corruption.
+ *
+ * \param list List element after which the new element is inserted
+ * \param elm Link of the containing struct to insert into the list
+ *
+ * \memberof wl_list
+ */
+void
+wl_list_insert(struct wl_list *list, struct wl_list *elm);
+
+/**
+ * Removes an element from the list.
+ *
+ * \note This operation leaves \p elm in an invalid state.
+ *
+ * \param elm Link of the containing struct to remove from the list
+ *
+ * \memberof wl_list
+ */
+void
+wl_list_remove(struct wl_list *elm);
+
+/**
+ * Determines the length of the list.
+ *
+ * \note This is an O(n) operation.
+ *
+ * \param list List whose length is to be determined
+ *
+ * \return Number of elements in the list
+ *
+ * \memberof wl_list
+ */
+int
+wl_list_length(const struct wl_list *list);
+
+/**
+ * Determines if the list is empty.
+ *
+ * \param list List whose emptiness is to be determined
+ *
+ * \return 1 if empty, or 0 if not empty
+ *
+ * \memberof wl_list
+ */
+int
+wl_list_empty(const struct wl_list *list);
+
+/**
+ * Inserts all of the elements of one list into another, after the element
+ * represented by \p list.
+ *
+ * \note This leaves \p other in an invalid state.
+ *
+ * \param list List element after which the other list elements will be inserted
+ * \param other List of elements to insert
+ *
+ * \memberof wl_list
+ */
+void
+wl_list_insert_list(struct wl_list *list, struct wl_list *other);
+
+/**
+ * Retrieves a pointer to a containing struct, given a member name.
+ *
+ * This macro allows "conversion" from a pointer to a member to its containing
+ * struct. This is useful if you have a contained item like a wl_list,
+ * wl_listener, or wl_signal, provided via a callback or other means, and would
+ * like to retrieve the struct that contains it.
+ *
+ * To demonstrate, the following example retrieves a pointer to
+ * `example_container` given only its `destroy_listener` member:
+ *
+ * \code
+ * struct example_container {
+ *         struct wl_listener destroy_listener;
+ *         // other members...
+ * };
+ *
+ * void example_container_destroy(struct wl_listener *listener, void *data)
+ * {
+ *         struct example_container *ctr;
+ *
+ *         ctr = wl_container_of(listener, ctr, destroy_listener);
+ *         // destroy ctr...
+ * }
+ * \endcode
+ *
+ * \note `sample` need not be a valid pointer. A null or uninitialised pointer
+ *       is sufficient.
+ *
+ * \param ptr Valid pointer to the contained member
+ * \param sample Pointer to a struct whose type contains \p ptr
+ * \param member Named location of \p ptr within the \p sample type
+ *
+ * \return The container for the specified pointer
+ */
+#define wl_container_of(ptr, sample, member)				\
+	(WL_TYPEOF(sample))((char *)(ptr) -				\
+			     offsetof(WL_TYPEOF(*sample), member))
+
+/**
+ * Iterates over a list.
+ *
+ * This macro expresses a for-each iterator for wl_list. Given a list and
+ * wl_list link member name (often named `link` by convention), this macro
+ * assigns each element in the list to \p pos, which can then be referenced in
+ * a trailing code block. For example, given a wl_list of `struct message`
+ * elements:
+ *
+ * \code
+ * struct message {
+ *         char *contents;
+ *         wl_list link;
+ * };
+ *
+ * struct wl_list *message_list;
+ * // Assume message_list now "contains" many messages
+ *
+ * struct message *m;
+ * wl_list_for_each(m, message_list, link) {
+ *         do_something_with_message(m);
+ * }
+ * \endcode
+ *
+ * \param pos Cursor that each list element will be assigned to
+ * \param head Head of the list to iterate over
+ * \param member Name of the link member within the element struct
+ *
+ * \relates wl_list
+ */
+#define wl_list_for_each(pos, head, member)				\
+	for (pos = wl_container_of((head)->next, pos, member);	\
+	     &pos->member != (head);					\
+	     pos = wl_container_of(pos->member.next, pos, member))
+
+/**
+ * Iterates over a list, safe against removal of the list element.
+ *
+ * \note Only removal of the current element, \p pos, is safe. Removing
+ *       any other element during traversal may lead to a loop malfunction.
+ *
+ * \sa wl_list_for_each()
+ *
+ * \param pos Cursor that each list element will be assigned to
+ * \param tmp Temporary pointer of the same type as \p pos
+ * \param head Head of the list to iterate over
+ * \param member Name of the link member within the element struct
+ *
+ * \relates wl_list
+ */
+#define wl_list_for_each_safe(pos, tmp, head, member)			\
+	for (pos = wl_container_of((head)->next, pos, member),		\
+	     tmp = wl_container_of((pos)->member.next, tmp, member);	\
+	     &pos->member != (head);					\
+	     pos = tmp,							\
+	     tmp = wl_container_of(pos->member.next, tmp, member))
+
+/**
+ * Iterates backwards over a list.
+ *
+ * \sa wl_list_for_each()
+ *
+ * \param pos Cursor that each list element will be assigned to
+ * \param head Head of the list to iterate over
+ * \param member Name of the link member within the element struct
+ *
+ * \relates wl_list
+ */
+#define wl_list_for_each_reverse(pos, head, member)			\
+	for (pos = wl_container_of((head)->prev, pos, member);	\
+	     &pos->member != (head);					\
+	     pos = wl_container_of(pos->member.prev, pos, member))
+
+/**
+ * Iterates backwards over a list, safe against removal of the list element.
+ *
+ * \note Only removal of the current element, \p pos, is safe. Removing
+ *       any other element during traversal may lead to a loop malfunction.
+ *
+ * \sa wl_list_for_each()
+ *
+ * \param pos Cursor that each list element will be assigned to
+ * \param tmp Temporary pointer of the same type as \p pos
+ * \param head Head of the list to iterate over
+ * \param member Name of the link member within the element struct
+ *
+ * \relates wl_list
+ */
+#define wl_list_for_each_reverse_safe(pos, tmp, head, member)		\
+	for (pos = wl_container_of((head)->prev, pos, member),	\
+	     tmp = wl_container_of((pos)->member.prev, tmp, member);	\
+	     &pos->member != (head);					\
+	     pos = tmp,							\
+	     tmp = wl_container_of(pos->member.prev, tmp, member))
+
+/**
+ * \class wl_array
+ *
+ * Dynamic array
+ *
+ * A wl_array is a dynamic array that can only grow until released. It is
+ * intended for relatively small allocations whose size is variable or not known
+ * in advance. While construction of a wl_array does not require all elements to
+ * be of the same size, wl_array_for_each() does require all elements to have
+ * the same type and size.
+ *
+ */
+struct wl_array {
+	/** Array size */
+	size_t size;
+	/** Allocated space */
+	size_t alloc;
+	/** Array data */
+	void *data;
+};
+
+/**
+ * Initializes the array.
+ *
+ * \param array Array to initialize
+ *
+ * \memberof wl_array
+ */
+void
+wl_array_init(struct wl_array *array);
+
+/**
+ * Releases the array data.
+ *
+ * \note Leaves the array in an invalid state.
+ *
+ * \param array Array whose data is to be released
+ *
+ * \memberof wl_array
+ */
+void
+wl_array_release(struct wl_array *array);
+
+/**
+ * Increases the size of the array by \p size bytes.
+ *
+ * \param array Array whose size is to be increased
+ * \param size Number of bytes to increase the size of the array by
+ *
+ * \return A pointer to the beginning of the newly appended space, or NULL when
+ *         resizing fails.
+ *
+ * \memberof wl_array
+ */
+void *
+wl_array_add(struct wl_array *array, size_t size);
+
+/**
+ * Copies the contents of \p source to \p array.
+ *
+ * \param array Destination array to copy to
+ * \param source Source array to copy from
+ *
+ * \return 0 on success, or -1 on failure
+ *
+ * \memberof wl_array
+ */
+int
+wl_array_copy(struct wl_array *array, struct wl_array *source);
+
+/**
+ * Iterates over an array.
+ *
+ * This macro expresses a for-each iterator for wl_array. It assigns each
+ * element in the array to \p pos, which can then be referenced in a trailing
+ * code block. \p pos must be a pointer to the array element type, and all
+ * array elements must be of the same type and size.
+ *
+ * \param pos Cursor that each array element will be assigned to
+ * \param array Array to iterate over
+ *
+ * \relates wl_array
+ * \sa wl_list_for_each()
+ */
+#define wl_array_for_each(pos, array)					\
+	for (pos = (array)->data;					\
+	     (array)->size != 0 &&					\
+	     (const char *) pos < ((const char *) (array)->data + (array)->size); \
+	     (pos)++)
+
+/**
+ * Fixed-point number
+ *
+ * A `wl_fixed_t` is a 24.8 signed fixed-point number with a sign bit, 23 bits
+ * of integer precision and 8 bits of decimal precision. Consider `wl_fixed_t`
+ * as an opaque struct with methods that facilitate conversion to and from
+ * `double` and `int` types.
+ */
+typedef int32_t wl_fixed_t;
+
+/**
+ * Converts a fixed-point number to a floating-point number.
+ *
+ * \param f Fixed-point number to convert
+ *
+ * \return Floating-point representation of the fixed-point argument
+ */
+static inline double
+wl_fixed_to_double(wl_fixed_t f)
+{
+	return f / 256.0;
+}
+
+/**
+ * Converts a floating-point number to a fixed-point number.
+ *
+ * \param d Floating-point number to convert
+ *
+ * \return Fixed-point representation of the floating-point argument
+ */
+static inline wl_fixed_t
+wl_fixed_from_double(double d)
+{
+	return (wl_fixed_t) (d * 256.0);
+}
+
+/**
+ * Converts a fixed-point number to an integer.
+ *
+ * \param f Fixed-point number to convert
+ *
+ * \return Integer component of the fixed-point argument
+ */
+static inline int
+wl_fixed_to_int(wl_fixed_t f)
+{
+	return f / 256;
+}
+
+/**
+ * Converts an integer to a fixed-point number.
+ *
+ * \param i Integer to convert
+ *
+ * \return Fixed-point representation of the integer argument
+ */
+static inline wl_fixed_t
+wl_fixed_from_int(int i)
+{
+	return i * 256;
+}
+
+/**
+ * Protocol message argument data types
+ *
+ * This union represents all of the argument types in the Wayland protocol wire
+ * format. The protocol implementation uses wl_argument within its marshalling
+ * machinery for dispatching messages between a client and a compositor.
+ *
+ * \sa wl_message
+ * \sa wl_interface
+ * \sa <a href="https://wayland.freedesktop.org/docs/html/ch04.html#sect-Protocol-wire-Format">Wire Format</a>
+ */
+union wl_argument {
+	int32_t i;           /**< `int`    */
+	uint32_t u;          /**< `uint`   */
+	wl_fixed_t f;        /**< `fixed`  */
+	const char *s;       /**< `string` */
+	struct wl_object *o; /**< `object` */
+	uint32_t n;          /**< `new_id` */
+	struct wl_array *a;  /**< `array`  */
+	int32_t h;           /**< `fd`     */
+};
+
+/**
+ * Dispatcher function type alias
+ *
+ * A dispatcher is a function that handles the emitting of callbacks in client
+ * code. For programs directly using the C library, this is done by using
+ * libffi to call function pointers. When binding to languages other than C,
+ * dispatchers provide a way to abstract the function calling process to be
+ * friendlier to other function calling systems.
+ *
+ * A dispatcher takes five arguments: The first is the dispatcher-specific
+ * implementation associated with the target object. The second is the object
+ * upon which the callback is being invoked (either wl_proxy or wl_resource).
+ * The third and fourth arguments are the opcode and the wl_message
+ * corresponding to the callback. The final argument is an array of arguments
+ * received from the other process via the wire protocol.
+ *
+ * \param user_data Dispatcher-specific implementation data
+ * \param target Callback invocation target (wl_proxy or `wl_resource`)
+ * \param opcode Callback opcode
+ * \param msg Callback message signature
+ * \param args Array of received arguments
+ *
+ * \return 0 on success, or -1 on failure
+ */
+typedef int (*wl_dispatcher_func_t)(const void *user_data, void *target,
+				    uint32_t opcode, const struct wl_message *msg,
+				    union wl_argument *args);
+
+/**
+ * Log function type alias
+ *
+ * The C implementation of the Wayland protocol abstracts the details of
+ * logging. Users may customize the logging behavior, with a function conforming
+ * to the `wl_log_func_t` type, via `wl_log_set_handler_client` and
+ * `wl_log_set_handler_server`.
+ *
+ * A `wl_log_func_t` must conform to the expectations of `vprintf`, and
+ * expects two arguments: a string to write and a corresponding variable
+ * argument list. While the string to write may contain format specifiers and
+ * use values in the variable argument list, the behavior of any `wl_log_func_t`
+ * depends on the implementation.
+ *
+ * \note Take care to not confuse this with `wl_protocol_logger_func_t`, which
+ *       is a specific server-side logger for requests and events.
+ *
+ * \param fmt String to write to the log, containing optional format
+ *            specifiers
+ * \param args Variable argument list
+ *
+ * \sa wl_log_set_handler_client
+ * \sa wl_log_set_handler_server
+ */
+typedef void (*wl_log_func_t)(const char *fmt, va_list args) WL_PRINTF(1, 0);
+
+/**
+ * Return value of an iterator function
+ *
+ * \sa wl_client_for_each_resource_iterator_func_t
+ * \sa wl_client_for_each_resource
+ */
+enum wl_iterator_result {
+	/** Stop the iteration */
+	WL_ITERATOR_STOP,
+	/** Continue the iteration */
+	WL_ITERATOR_CONTINUE
+};
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/src/wayland-version.h.in b/subprojects/wayland/src/wayland-version.h.in
new file mode 100644
index 0000000000000000000000000000000000000000..c5d786e25b951a18ed77e80de505543110e9b761
--- /dev/null
+++ b/subprojects/wayland/src/wayland-version.h.in
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef WAYLAND_VERSION_H
+#define WAYLAND_VERSION_H
+
+#define WAYLAND_VERSION_MAJOR @WAYLAND_VERSION_MAJOR@
+#define WAYLAND_VERSION_MINOR @WAYLAND_VERSION_MINOR@
+#define WAYLAND_VERSION_MICRO @WAYLAND_VERSION_MICRO@
+#define WAYLAND_VERSION "@WAYLAND_VERSION@"
+
+#endif
diff --git a/subprojects/wayland/tests/array-test.c b/subprojects/wayland/tests/array-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..78dfbb0a80b2f49f26cd4346c503cdfa3dd6ef07
--- /dev/null
+++ b/subprojects/wayland/tests/array-test.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include "wayland-util.h"
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(array_init)
+{
+	struct wl_array array;
+
+	/* fill with garbage to emulate uninitialized memory */
+	memset(&array, 0x57, sizeof array);
+
+	wl_array_init(&array);
+	assert(array.size == 0);
+	assert(array.alloc == 0);
+	assert(array.data == 0);
+}
+
+TEST(array_release)
+{
+	struct wl_array array;
+	void *ptr;
+
+	wl_array_init(&array);
+	ptr = wl_array_add(&array, 1);
+	assert(ptr != NULL);
+	assert(array.data != NULL);
+
+	wl_array_release(&array);
+	assert(array.data == WL_ARRAY_POISON_PTR);
+}
+
+TEST(array_add)
+{
+	struct mydata {
+		unsigned int a;
+		unsigned int b;
+		double c;
+		double d;
+	};
+
+	const unsigned int iterations = 1321; /* this is arbitrary */
+	const int datasize = sizeof(struct mydata);
+	struct wl_array array;
+	size_t i;
+
+	wl_array_init(&array);
+
+	/* add some data */
+	for (i = 0; i < iterations; i++) {
+		struct mydata* ptr = wl_array_add(&array, datasize);
+		assert(ptr);
+		assert((i + 1) * datasize == array.size);
+
+		ptr->a = i * 3;
+		ptr->b = 20000 - i;
+		ptr->c = (double)(i);
+		ptr->d = (double)(i / 2.);
+	}
+
+	/* verify the data */
+	for (i = 0; i < iterations; ++i) {
+		struct mydata* check = (struct mydata*)array.data + i;
+
+		assert(check->a == i * 3);
+		assert(check->b == 20000 - i);
+		assert(check->c == (double)(i));
+		assert(check->d == (double)(i/2.));
+	}
+
+	wl_array_release(&array);
+}
+
+TEST(array_copy)
+{
+	const int iterations = 1529; /* this is arbitrary */
+	struct wl_array source;
+	struct wl_array copy;
+	int i;
+
+	wl_array_init(&source);
+
+	/* add some data */
+	for (i = 0; i < iterations; i++) {
+		int *p = wl_array_add(&source, sizeof(int));
+		assert(p);
+		*p = i * 2 + i;
+	}
+
+	/* copy the array */
+	wl_array_init(&copy);
+	wl_array_copy(&copy, &source);
+
+	/* check the copy */
+	for (i = 0; i < iterations; i++) {
+		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 */
+		assert(*s == i * 2 + i); /* sanity check */
+	}
+
+	wl_array_release(&source);
+	wl_array_release(&copy);
+}
+
+TEST(array_for_each)
+{
+	static const int elements[] = { 77, 12, 45192, 53280, 334455 };
+	struct wl_array array;
+	int *p;
+	int i;
+
+	wl_array_init(&array);
+	for (i = 0; i < 5; i++) {
+		p = wl_array_add(&array, sizeof *p);
+		assert(p);
+		*p = elements[i];
+	}
+
+	i = 0;
+	wl_array_for_each(p, &array) {
+		assert(*p == elements[i]);
+		i++;
+	}
+	assert(i == 5);
+
+	wl_array_release(&array);
+}
diff --git a/subprojects/wayland/tests/client-test.c b/subprojects/wayland/tests/client-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..5585c0cd01ffdad6af9f8a79fd6ded0143c51deb
--- /dev/null
+++ b/subprojects/wayland/tests/client-test.c
@@ -0,0 +1,207 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+struct client_destroy_listener {
+	struct wl_listener listener;
+	bool done;
+	struct wl_listener late_listener;
+	bool late_done;
+	struct wl_listener resource_listener;
+	bool resource_done;
+};
+
+static void
+client_destroy_notify(struct wl_listener *l, void *data)
+{
+	struct client_destroy_listener *listener =
+		wl_container_of(l, listener, listener);
+
+	listener->done = true;
+	assert(!listener->resource_done);
+	assert(!listener->late_done);
+}
+
+static void
+client_resource_destroy_notify(struct wl_listener *l, void *data)
+{
+	struct client_destroy_listener *listener =
+		wl_container_of(l, listener, resource_listener);
+
+	assert(listener->done);
+	listener->resource_done = true;
+	assert(!listener->late_done);
+}
+
+static void
+client_late_destroy_notify(struct wl_listener *l, void *data)
+{
+	struct client_destroy_listener *listener =
+		wl_container_of(l, listener, late_listener);
+
+	assert(listener->done);
+	assert(listener->resource_done);
+	listener->late_done = true;
+}
+
+static void
+client_user_data_destroy(void *data)
+{
+	bool *user_data_destroyed = data;
+
+	*user_data_destroyed = true;
+}
+
+TEST(client_destroy_listener)
+{
+	struct wl_display *display;
+	struct wl_client *client;
+	struct wl_resource *resource;
+	struct client_destroy_listener a, b;
+	bool user_data_destroyed = false;
+	int s[2];
+
+	assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+	display = wl_display_create();
+	assert(display);
+	client = wl_client_create(display, s[0]);
+	assert(client);
+
+	wl_client_set_user_data(client, &user_data_destroyed, client_user_data_destroy);
+	assert(wl_client_get_user_data(client) == &user_data_destroyed);
+
+	resource = wl_resource_create(client, &wl_callback_interface, 1, 0);
+	assert(resource);
+
+	a.listener.notify = client_destroy_notify;
+	a.done = false;
+	a.resource_listener.notify = client_resource_destroy_notify;
+	a.resource_done = false;
+	a.late_listener.notify = client_late_destroy_notify;
+	a.late_done = false;
+	wl_client_add_destroy_listener(client, &a.listener);
+	wl_resource_add_destroy_listener(resource, &a.resource_listener);
+	wl_client_add_destroy_late_listener(client, &a.late_listener);
+
+	assert(wl_client_get_destroy_listener(client, client_destroy_notify) ==
+	       &a.listener);
+	assert(wl_resource_get_destroy_listener(resource, client_resource_destroy_notify) ==
+	       &a.resource_listener);
+	assert(wl_client_get_destroy_late_listener(client, client_late_destroy_notify) ==
+	       &a.late_listener);
+
+	b.listener.notify = client_destroy_notify;
+	b.done = false;
+	b.resource_listener.notify = client_resource_destroy_notify;
+	b.resource_done = false;
+	b.late_listener.notify = client_late_destroy_notify;
+	b.late_done = false;
+	wl_client_add_destroy_listener(client, &b.listener);
+	wl_resource_add_destroy_listener(resource, &b.resource_listener);
+	wl_client_add_destroy_late_listener(client, &b.late_listener);
+
+	wl_list_remove(&a.listener.link);
+	wl_list_remove(&a.resource_listener.link);
+	wl_list_remove(&a.late_listener.link);
+
+	assert(!user_data_destroyed);
+
+	wl_client_destroy(client);
+
+	assert(!a.done);
+	assert(!a.resource_done);
+	assert(!a.late_done);
+	assert(b.done);
+	assert(b.resource_done);
+	assert(b.late_done);
+	assert(user_data_destroyed);
+
+	close(s[0]);
+	close(s[1]);
+
+	wl_display_destroy(display);
+}
+
+static void
+client_destroy_remove_link_notify(struct wl_listener *l, void *data)
+{
+	struct wl_client *client = data;
+	struct client_destroy_listener *listener =
+		wl_container_of(l, listener, listener);
+
+	/* The client destruction signal should not be emitted more than once. */
+	assert(!listener->done);
+	listener->done = true;
+
+	/* The client should have been removed from the display's list. */
+	assert(wl_list_empty(wl_client_get_link(client)));
+}
+
+/*
+ * Tests that wl_client_destroy() will remove the client from the display's
+ * client list to prevent client access during destruction.
+ */
+TEST(client_destroy_removes_link)
+{
+	struct wl_display *display;
+	struct wl_client *client;
+	struct client_destroy_listener destroy_listener;
+	int s[2];
+
+	assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+	display = wl_display_create();
+	assert(display);
+	client = wl_client_create(display, s[0]);
+	assert(client);
+
+	destroy_listener.listener.notify = client_destroy_remove_link_notify;
+	destroy_listener.done = false;
+	wl_client_add_destroy_listener(client, &destroy_listener.listener);
+
+	assert(wl_client_get_destroy_listener(client,
+		client_destroy_remove_link_notify) == &destroy_listener.listener);
+
+	wl_client_destroy(client);
+	assert(destroy_listener.done);
+
+	close(s[0]);
+	close(s[1]);
+
+	wl_display_destroy(display);
+}
diff --git a/subprojects/wayland/tests/compositor-introspection-test.c b/subprojects/wayland/tests/compositor-introspection-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..064d25307152a804c98eee49106ad7eac1b8f16d
--- /dev/null
+++ b/subprojects/wayland/tests/compositor-introspection-test.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright © 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "wayland-client.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+/* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */
+static const char *
+require_xdg_runtime_dir(void)
+{
+	char *val = getenv("XDG_RUNTIME_DIR");
+	assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test");
+
+	return val;
+}
+
+struct compositor {
+	struct wl_display *display;
+	struct wl_listener listener;
+	struct wl_client *client;
+};
+
+static void
+client_created(struct wl_listener *listener, void *data)
+{
+	struct compositor *c = wl_container_of(listener, c, listener);
+	c->client = data;
+}
+
+static void
+check_client_list(struct compositor *compositor)
+{
+	struct wl_list *client_list;
+	struct wl_client *client, *client_it;
+	int num_clients = 0;
+
+	client_list = wl_display_get_client_list(compositor->display);
+	wl_client_for_each(client_it, client_list) {
+		num_clients++;
+		client = client_it;
+	}
+	assert(num_clients == 1);
+	/* 'client_it' is not valid here, so we took a copy of the client in the loop.
+	 * We could also do this assert in the loop directly, but in case it fails it is
+	 * easier to understand the problem when we know that the previous assert passed,
+	 * so that there is only one client but the wrong one. */
+	assert(compositor->client == client);
+}
+
+static const char *
+setup_compositor(struct compositor *compositor)
+{
+	const char *socket;
+
+	require_xdg_runtime_dir();
+
+	compositor->display = wl_display_create();
+	socket = wl_display_add_socket_auto(compositor->display);
+
+	compositor->listener.notify = client_created;
+	wl_display_add_client_created_listener(compositor->display, &compositor->listener);
+
+	return socket;
+}
+
+static void
+cleanup_compositor(struct compositor *compositor)
+{
+	wl_client_destroy(compositor->client);
+	wl_display_destroy(compositor->display);
+}
+
+TEST(new_client_connect)
+{
+	const char *socket;
+	struct compositor compositor = { 0 };
+	struct {
+		struct wl_display *display;
+	} client;
+
+	socket = setup_compositor(&compositor);
+
+	client.display = wl_display_connect(socket);
+
+	wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100);
+
+	assert(compositor.client != NULL);
+
+	check_client_list(&compositor);
+
+
+
+	wl_display_disconnect(client.display);
+	cleanup_compositor(&compositor);
+}
+
+struct resource_listener {
+	struct wl_listener listener;
+	int count;
+};
+
+static void
+resource_created(struct wl_listener *listener, void *data)
+{
+	struct resource_listener *l;
+	l = wl_container_of(listener, l, listener);
+	l->count++;
+}
+
+TEST(new_resource)
+{
+	const char *socket;
+	struct compositor compositor = { 0 };
+	struct {
+		struct wl_display *display;
+		struct wl_callback *cb;
+	} client;
+	struct resource_listener resource_listener;
+
+	socket = setup_compositor(&compositor);
+	client.display = wl_display_connect(socket);
+	wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100);
+
+	resource_listener.count = 0;
+	resource_listener.listener.notify = resource_created;
+	wl_client_add_resource_created_listener(compositor.client,
+						&resource_listener.listener);
+
+	client.cb = wl_display_sync(client.display);
+	wl_display_flush(client.display);
+	wl_event_loop_dispatch(wl_display_get_event_loop(compositor.display), 100);
+
+	assert(resource_listener.count == 1);
+
+	wl_callback_destroy(client.cb);
+	wl_display_disconnect(client.display);
+	cleanup_compositor(&compositor);
+
+	/* This is defined to be safe also after client destruction */
+	wl_list_remove(&resource_listener.listener.link);
+}
diff --git a/subprojects/wayland/tests/connection-test.c b/subprojects/wayland/tests/connection-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..dde5d89ca1f4dad8431e682aeb921d8c6b1631f9
--- /dev/null
+++ b/subprojects/wayland/tests/connection-test.c
@@ -0,0 +1,909 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <poll.h>
+
+#include "wayland-private.h"
+#include "test-runner.h"
+#include "test-compositor.h"
+
+static const char message[] = "Hello, world";
+
+static struct wl_connection *
+setup(int *s)
+{
+	struct wl_connection *connection;
+
+	assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+
+	connection = wl_connection_create(s[0], WL_BUFFER_DEFAULT_MAX_SIZE);
+	assert(connection);
+
+	return connection;
+}
+
+TEST(connection_create)
+{
+	struct wl_connection *connection;
+	int s[2];
+
+	connection = setup(s);
+	wl_connection_destroy(connection);
+	close(s[0]);
+	close(s[1]);
+}
+
+TEST(connection_write)
+{
+	struct wl_connection *connection;
+	int s[2];
+	char buffer[64];
+
+	connection = setup(s);
+
+	assert(wl_connection_write(connection, message, sizeof message) == 0);
+	assert(wl_connection_flush(connection) == sizeof message);
+	assert(read(s[1], buffer, sizeof buffer) == sizeof message);
+	assert(memcmp(message, buffer, sizeof message) == 0);
+
+	wl_connection_destroy(connection);
+	close(s[0]);
+	close(s[1]);
+}
+
+TEST(connection_data)
+{
+	struct wl_connection *connection;
+	int s[2];
+	char buffer[64];
+
+	connection = setup(s);
+
+	assert(write(s[1], message, sizeof message) == sizeof message);
+	assert(wl_connection_read(connection) == sizeof message);
+	wl_connection_copy(connection, buffer, sizeof message);
+	assert(memcmp(message, buffer, sizeof message) == 0);
+	wl_connection_consume(connection, sizeof message);
+
+	wl_connection_destroy(connection);
+	close(s[0]);
+	close(s[1]);
+}
+
+TEST(connection_queue)
+{
+	struct wl_connection *connection;
+	int s[2];
+	char buffer[64];
+
+	connection = setup(s);
+
+	/* Test that wl_connection_queue() puts data in the output
+	 * buffer without flush it.  Verify that the data did get in
+	 * the buffer by writing another message and making sure that
+	 * we receive the two messages on the other fd. */
+
+	assert(wl_connection_queue(connection, message, sizeof message) == 0);
+	assert(wl_connection_flush(connection) == 0);
+	assert(wl_connection_write(connection, message, sizeof message) == 0);
+	assert(wl_connection_flush(connection) == 2 * sizeof message);
+	assert(read(s[1], buffer, sizeof buffer) == 2 * sizeof message);
+	assert(memcmp(message, buffer, sizeof message) == 0);
+	assert(memcmp(message, buffer + sizeof message, sizeof message) == 0);
+
+	wl_connection_destroy(connection);
+	close(s[0]);
+	close(s[1]);
+}
+
+static void
+va_list_wrapper(const char *signature, union wl_argument *args, int count, ...)
+{
+	va_list ap;
+	va_start(ap, count);
+	wl_argument_from_va_list(signature, args, count, ap);
+	va_end(ap);
+}
+
+TEST(argument_from_va_list)
+{
+	union wl_argument args[WL_CLOSURE_MAX_ARGS];
+	struct wl_object fake_object, fake_new_object;
+	struct wl_array fake_array;
+
+	va_list_wrapper("i", args, 1, 100);
+	assert(args[0].i == 100);
+
+	va_list_wrapper("is", args, 2, 101, "value");
+	assert(args[0].i == 101);
+	assert(strcmp(args[1].s, "value") == 0);
+
+	va_list_wrapper("?iuf?sonah", args, 8,
+			102, 103, wl_fixed_from_int(104), "value",
+			&fake_object, &fake_new_object, &fake_array, 106);
+	assert(args[0].i == 102);
+	assert(args[1].u == 103);
+	assert(args[2].f == wl_fixed_from_int(104));
+	assert(strcmp(args[3].s, "value") == 0);
+	assert(args[4].o == &fake_object);
+	assert(args[5].o == &fake_new_object);
+	assert(args[6].a == &fake_array);
+	assert(args[7].h == 106);
+}
+
+struct marshal_data {
+	struct wl_connection *read_connection;
+	struct wl_connection *write_connection;
+	int s[2];
+	uint32_t buffer[10];
+	union {
+		uint32_t u;
+		int32_t i;
+		const char *s;
+		int h;
+	} value;
+};
+
+static void
+setup_marshal_data(struct marshal_data *data)
+{
+	assert(socketpair(AF_UNIX,
+			  SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
+	data->read_connection = wl_connection_create(data->s[0],
+						     WL_BUFFER_DEFAULT_MAX_SIZE);
+	assert(data->read_connection);
+	data->write_connection = wl_connection_create(data->s[1],
+						      WL_BUFFER_DEFAULT_MAX_SIZE);
+	assert(data->write_connection);
+}
+
+static void
+release_marshal_data(struct marshal_data *data)
+{
+	close(wl_connection_destroy(data->read_connection));
+	close(wl_connection_destroy(data->write_connection));
+}
+
+static void
+marshal(struct marshal_data *data, const char *format, int size, ...)
+{
+	struct wl_closure *closure;
+	static const uint32_t opcode = 4444;
+	static struct wl_object sender = { NULL, NULL, 1234 };
+	struct wl_message message = { "test", format, NULL };
+	va_list ap;
+
+	va_start(ap, size);
+	closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+	va_end(ap);
+
+	assert(closure);
+	assert(wl_closure_send(closure, data->write_connection) == 0);
+	wl_closure_destroy(closure);
+	assert(wl_connection_flush(data->write_connection) == size);
+	assert(read(data->s[0], data->buffer, sizeof data->buffer) == size);
+
+	assert(data->buffer[0] == sender.id);
+	assert(data->buffer[1] == (opcode | (size << 16)));
+}
+
+TEST(connection_marshal)
+{
+	struct marshal_data data;
+	struct wl_object object;
+	struct wl_array array;
+	static const char text[] = "curry";
+
+	setup_marshal_data(&data);
+
+	marshal(&data, "i", 12, 42);
+	assert(data.buffer[2] == 42);
+
+	marshal(&data, "u", 12, 55);
+	assert(data.buffer[2] == 55);
+
+	marshal(&data, "s", 20, "frappo");
+	assert(data.buffer[2] == 7);
+	assert(strcmp((char *) &data.buffer[3], "frappo") == 0);
+
+	object.id = 557799;
+	marshal(&data, "o", 12, &object);
+	assert(data.buffer[2] == object.id);
+
+	marshal(&data, "n", 12, &object);
+	assert(data.buffer[2] == object.id);
+
+	array.data = (void *) text;
+	array.size = sizeof text;
+	marshal(&data, "a", 20, &array);
+	assert(data.buffer[2] == array.size);
+	assert(memcmp(&data.buffer[3], text, array.size) == 0);
+
+	release_marshal_data(&data);
+}
+
+static void
+expected_fail_marshal(int expected_error, const char *format, ...)
+{
+	struct wl_closure *closure;
+	static const uint32_t opcode = 4444;
+	static const struct wl_interface test_interface = {
+		.name = "test_object"
+	};
+	static struct wl_object sender = { 0 };
+	struct wl_message message = { "test", format, NULL };
+
+	sender.interface = &test_interface;
+	sender.id = 1234;
+	va_list ap;
+
+	va_start(ap, format);
+	closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+	va_end(ap);
+
+	assert(closure == NULL);
+	assert(errno == expected_error);
+}
+
+static void
+marshal_send(struct marshal_data *data, const char *format, ...)
+{
+	struct wl_closure *closure;
+	static const uint32_t opcode = 4444;
+	static struct wl_object sender = { NULL, NULL, 1234 };
+	struct wl_message message = { "test", format, NULL };
+	va_list ap;
+
+	va_start(ap, format);
+	closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+	va_end(ap);
+
+	assert(closure);
+	assert(wl_closure_send(closure, data->write_connection) == 0);
+
+	wl_closure_destroy(closure);
+}
+
+static void
+expected_fail_marshal_send(struct marshal_data *data, int expected_error,
+			   const char *format, ...)
+{
+	struct wl_closure *closure;
+	static const uint32_t opcode = 4444;
+	static struct wl_object sender = { NULL, NULL, 1234 };
+	struct wl_message message = { "test", format, NULL };
+	va_list ap;
+
+	va_start(ap, format);
+	closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+	va_end(ap);
+
+	assert(closure);
+	assert(wl_closure_send(closure, data->write_connection) < 0);
+	assert(errno == expected_error);
+
+	wl_closure_destroy(closure);
+}
+
+TEST(connection_marshal_nullables)
+{
+	struct marshal_data data;
+	struct wl_object object;
+	const char text[] = "curry";
+
+	setup_marshal_data(&data);
+
+	expected_fail_marshal(EINVAL, "o", NULL);
+	expected_fail_marshal(EINVAL, "s", NULL);
+	expected_fail_marshal(EINVAL, "a", NULL);
+
+	marshal(&data, "?o", 12, NULL);
+	assert(data.buffer[2] == 0);
+
+	marshal(&data, "?s", 12, NULL);
+	assert(data.buffer[2] == 0);
+
+	object.id = 55293;
+	marshal(&data, "?o", 12, &object);
+	assert(data.buffer[2] == object.id);
+
+	marshal(&data, "?s", 20, text);
+	assert(data.buffer[2] == sizeof text);
+	assert(strcmp((char *) &data.buffer[3], text) == 0);
+
+	release_marshal_data(&data);
+}
+
+static void
+validate_demarshal_u(struct marshal_data *data,
+		     struct wl_object *object, uint32_t u)
+{
+	assert(data->value.u == u);
+}
+
+static void
+validate_demarshal_i(struct marshal_data *data,
+		     struct wl_object *object, int32_t i)
+{
+	assert(data->value.i == i);
+}
+
+static void
+validate_demarshal_s(struct marshal_data *data,
+		     struct wl_object *object, const char *s)
+{
+	if (data->value.s != NULL)
+		assert(strcmp(data->value.s, s) == 0);
+	else
+		assert(s == NULL);
+}
+
+static void
+validate_demarshal_h(struct marshal_data *data,
+		     struct wl_object *object, int fd)
+{
+	struct stat buf1, buf2;
+
+	assert(fd != data->value.h);
+	fstat(fd, &buf1);
+	fstat(data->value.h, &buf2);
+	assert(buf1.st_dev == buf2.st_dev);
+	assert(buf1.st_ino == buf2.st_ino);
+	close(fd);
+	close(data->value.h);
+}
+
+static void
+validate_demarshal_f(struct marshal_data *data,
+		     struct wl_object *object, wl_fixed_t f)
+{
+	assert(data->value.i == f);
+}
+
+static void
+demarshal(struct marshal_data *data, const char *format,
+	  uint32_t *msg, void (*func)(void))
+{
+	struct wl_message message = { "test", format, NULL };
+	struct wl_closure *closure;
+	struct wl_map objects;
+	struct wl_object object = { NULL, &func, 0 };
+	int size = msg[1] >> 16;
+
+	assert(write(data->s[1], msg, size) == size);
+	assert(wl_connection_read(data->read_connection) == size);
+
+	wl_map_init(&objects, WL_MAP_SERVER_SIDE);
+	object.id = msg[0];
+	closure = wl_connection_demarshal(data->read_connection,
+					  size, &objects, &message);
+	assert(closure);
+	wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
+	wl_closure_destroy(closure);
+}
+
+TEST(connection_demarshal)
+{
+	struct marshal_data data;
+	uint32_t msg[10];
+
+	setup_marshal_data(&data);
+
+	data.value.u = 8000;
+	msg[0] = 400200;	/* object id */
+	msg[1] = 12 << 16;		/* size = 12, opcode = 0 */
+	msg[2] = data.value.u;
+	demarshal(&data, "u", msg, (void *) validate_demarshal_u);
+
+	data.value.i = -557799;
+	msg[0] = 400200;
+	msg[1] = 12 << 16;
+	msg[2] = data.value.i;
+	demarshal(&data, "i", msg, (void *) validate_demarshal_i);
+
+	data.value.s = "superdude";
+	msg[0] = 400200;
+	msg[1] = 24 << 16;
+	msg[2] = 10;
+	msg[3 + msg[2]/4] = 0;
+	memcpy(&msg[3], data.value.s, msg[2]);
+	demarshal(&data, "s", msg, (void *) validate_demarshal_s);
+
+	data.value.s = "superdude";
+	msg[0] = 400200;
+	msg[1] = 24 << 16;
+	msg[2] = 10;
+	msg[3 + msg[2]/4] = 0;
+	memcpy(&msg[3], data.value.s, msg[2]);
+	demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
+
+	data.value.i = wl_fixed_from_double(-90000.2390);
+	msg[0] = 400200;
+	msg[1] = 12 << 16;
+	msg[2] = data.value.i;
+	demarshal(&data, "f", msg, (void *) validate_demarshal_f);
+
+	data.value.s = NULL;
+	msg[0] = 400200;
+	msg[1] = 12 << 16;
+	msg[2] = 0;
+	demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
+
+	release_marshal_data(&data);
+}
+
+static void
+marshal_demarshal(struct marshal_data *data,
+		  void (*func)(void), int size, const char *format, ...)
+{
+	struct wl_closure *closure;
+	static const int opcode = 4444;
+	static struct wl_object sender = { NULL, NULL, 1234 };
+	struct wl_message message = { "test", format, NULL };
+	struct wl_map objects;
+	struct wl_object object = { NULL, &func, 0 };
+	va_list ap;
+	uint32_t msg[1] = { 1234 };
+
+	va_start(ap, format);
+	closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+	va_end(ap);
+
+	assert(closure);
+	assert(wl_closure_send(closure, data->write_connection) == 0);
+	wl_closure_destroy(closure);
+	assert(wl_connection_flush(data->write_connection) == size);
+
+	assert(wl_connection_read(data->read_connection) == size);
+
+	wl_map_init(&objects, WL_MAP_SERVER_SIDE);
+	object.id = msg[0];
+	closure = wl_connection_demarshal(data->read_connection,
+					  size, &objects, &message);
+	assert(closure);
+	wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
+	wl_closure_destroy(closure);
+}
+
+TEST(connection_marshal_demarshal)
+{
+	struct marshal_data data;
+	char f[] = "/tmp/wayland-tests-XXXXXX";
+
+	setup_marshal_data(&data);
+
+	data.value.u = 889911;
+	marshal_demarshal(&data, (void *) validate_demarshal_u,
+			  12, "u", data.value.u);
+
+	data.value.i = -13;
+	marshal_demarshal(&data, (void *) validate_demarshal_i,
+			  12, "i", data.value.i);
+
+	data.value.s = "cookie robots";
+	marshal_demarshal(&data, (void *) validate_demarshal_s,
+			  28, "s", data.value.s);
+
+	data.value.s = "cookie robots";
+	marshal_demarshal(&data, (void *) validate_demarshal_s,
+			  28, "?s", data.value.s);
+
+	data.value.h = mkstemp(f);
+	assert(data.value.h >= 0);
+	unlink(f);
+	marshal_demarshal(&data, (void *) validate_demarshal_h,
+			  8, "h", data.value.h);
+
+	data.value.i = wl_fixed_from_double(1234.5678);
+	marshal_demarshal(&data, (void *) validate_demarshal_f,
+	                  12, "f", data.value.i);
+
+	data.value.i = wl_fixed_from_double(-90000.2390);
+	marshal_demarshal(&data, (void *) validate_demarshal_f,
+	                  12, "f", data.value.i);
+
+	data.value.i = wl_fixed_from_double((1 << 23) - 1 + 0.0941);
+	marshal_demarshal(&data, (void *) validate_demarshal_f,
+	                  12, "f", data.value.i);
+
+	release_marshal_data(&data);
+}
+
+static void
+expected_fail_demarshal(struct marshal_data *data, const char *format,
+                        const uint32_t *msg, int expected_error)
+{
+	struct wl_message message = { "test", format, NULL };
+	struct wl_closure *closure;
+	struct wl_map objects;
+	int size = (msg[1] >> 16);
+
+	assert(write(data->s[1], msg, size) == size);
+	assert(wl_connection_read(data->read_connection) == size);
+
+	wl_map_init(&objects, WL_MAP_SERVER_SIDE);
+	closure = wl_connection_demarshal(data->read_connection,
+					    size, &objects, &message);
+
+	assert(closure == NULL);
+	assert(errno == expected_error);
+}
+
+TEST(connection_demarshal_null_strings)
+{
+	struct marshal_data data;
+	uint32_t msg[3];
+
+	setup_marshal_data(&data);
+
+	data.value.s = NULL;
+	msg[0] = 400200;	/* object id */
+	msg[1] = 12 << 16;	/* size = 12, opcode = 0 */
+	msg[2] = 0;		/* string length = 0 */
+	demarshal(&data, "?s", msg, (void *) validate_demarshal_s);
+
+	expected_fail_demarshal(&data, "s", msg, EINVAL);
+
+	release_marshal_data(&data);
+}
+
+/* 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.
+ */
+TEST(connection_demarshal_failures)
+{
+	struct marshal_data data;
+	unsigned int i;
+	uint32_t msg[3];
+
+	const uint32_t overflowing_values[] = {
+		/* Values very close to UINT32_MAX. Before f5b9e3b9 these
+		 * would cause integer overflow in DIV_ROUNDUP. */
+		0xffffffff, 0xfffffffe, 0xfffffffd, 0xfffffffc,
+
+		/* Values at various offsets from UINT32_MAX. Before f7fdface
+		 * these would overflow the "p" pointer on 32bit systems,
+		 * effectively subtracting the offset from it. It had good
+		 * chance to cause crash depending on what was stored at that
+		 * offset before "p". */
+		0xfffff000, 0xffffd000, 0xffffc000, 0xffffb000
+	};
+
+	setup_marshal_data(&data);
+
+	/* sender_id, does not matter */
+	msg[0] = 0;
+
+	/* (size << 16 | opcode), opcode is 0, does not matter */
+	msg[1] = sizeof(msg) << 16;
+
+	for (i = 0; i < ARRAY_LENGTH(overflowing_values); i++) {
+		/* length of the string or array */
+		msg[2] = overflowing_values[i];
+
+		expected_fail_demarshal(&data, "s", msg, EINVAL);
+		expected_fail_demarshal(&data, "a", msg, EINVAL);
+	}
+
+	release_marshal_data(&data);
+}
+
+TEST(connection_marshal_alot)
+{
+	struct marshal_data data;
+	char f[64];
+	int i;
+
+	setup_marshal_data(&data);
+
+	/* We iterate enough to make sure we wrap the circular buffers
+	 * for both regular data an fds. */
+
+	for (i = 0; i < 2000; i++) {
+		strcpy(f, "/tmp/wayland-tests-XXXXXX");
+		data.value.h = mkstemp(f);
+		assert(data.value.h >= 0);
+		unlink(f);
+		marshal_demarshal(&data, (void *) validate_demarshal_h,
+				  8, "h", data.value.h);
+	}
+
+	release_marshal_data(&data);
+}
+
+TEST(connection_marshal_too_big)
+{
+	struct marshal_data data;
+	char *big_string = malloc(5000);
+
+	assert(big_string);
+
+	memset(big_string, ' ', 4999);
+	big_string[4999] = '\0';
+
+	setup_marshal_data(&data);
+
+	expected_fail_marshal_send(&data, E2BIG, "s", big_string);
+
+	release_marshal_data(&data);
+	free(big_string);
+}
+
+TEST(connection_marshal_big_enough)
+{
+	struct marshal_data data;
+	char *big_string = malloc(5000);
+
+	assert(big_string);
+
+	memset(big_string, ' ', 4999);
+	big_string[4999] = '\0';
+
+	setup_marshal_data(&data);
+	wl_connection_set_max_buffer_size(data.write_connection, 5120);
+
+	marshal_send(&data, "s", big_string);
+
+	release_marshal_data(&data);
+	free(big_string);
+}
+
+TEST(connection_marshal_unbounded_boundary_size)
+{
+	/* A string of lenth 8178 requires a buffer size of exactly 2^13. */
+	struct marshal_data data;
+	char *big_string = malloc(8178);
+	assert(big_string);
+
+	memset(big_string, ' ', 8177);
+	big_string[8177] = '\0';
+
+	setup_marshal_data(&data);
+
+	/* Set the max size to 0 (unbounded). */
+	wl_connection_set_max_buffer_size(data.write_connection, 0);
+
+	marshal_send(&data, "s", big_string);
+
+	release_marshal_data(&data);
+	free(big_string);
+}
+
+static void
+marshal_helper(const char *format, void *handler, ...)
+{
+	struct wl_closure *closure;
+	static struct wl_object sender = { NULL, NULL, 1234 };
+	struct wl_object object = { NULL, &handler, 0 };
+	static const int opcode = 4444;
+	struct wl_message message = { "test", format, NULL };
+	va_list ap;
+	int done;
+
+	va_start(ap, handler);
+	closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+	va_end(ap);
+
+	assert(closure);
+	done = 0;
+	wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, &done);
+	wl_closure_destroy(closure);
+	assert(done);
+}
+
+static void
+suu_handler(void *data, struct wl_object *object,
+	    const char *s, uint32_t u1, uint32_t u2)
+{
+	int *done = data;
+
+	assert(strcmp(s, "foo") == 0);
+	assert(u1 == 500);
+	assert(u2 == 404040);
+	*done = 1;
+}
+
+TEST(invoke_closure)
+{
+	marshal_helper("suu", suu_handler, "foo", 500, 404040);
+}
+
+static void
+leak_closure(void)
+{
+	struct wl_callback *cb;
+	struct pollfd pfd;
+	struct client *c = client_connect();
+
+	cb = wl_display_sync(c->wl_display);
+	assert(cb);
+	assert(wl_display_flush(c->wl_display) > 0);
+
+	/* we don't need it, it is referenced */
+	wl_callback_destroy(cb);
+
+	pfd.fd = wl_display_get_fd(c->wl_display);
+	pfd.events = POLLIN;
+
+	test_set_timeout(2);
+	assert(poll(&pfd, 1, -1) == 1);
+
+	/* read events, but do not dispatch them */
+	assert(wl_display_prepare_read(c->wl_display) == 0);
+	assert(wl_display_read_events(c->wl_display) == 0);
+
+	/*
+	 * now we have wl_callback.done and wl_display.delete_id queued;
+	 * if we now release the queue (in wl_display_disconnect())
+	 * we should not leak memory
+	 */
+
+	client_disconnect(c);
+}
+
+TEST(closure_leaks)
+{
+	struct display *d = display_create();
+
+	client_create_noarg(d, leak_closure);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+static void
+leak_after_error(void)
+{
+	struct client *c = client_connect();
+
+	/* this should return -1, because we'll send error
+	 * from server. */
+	assert(stop_display(c, 1) == -1);
+	assert(wl_display_dispatch_pending(c->wl_display) == -1);
+	assert(wl_display_get_error(c->wl_display) == ENOMEM);
+
+	/* after we got error, we have display_resume event
+	 * in the queue. It should be freed in wl_display_disconnect().
+	 * Let's see! */
+
+	wl_proxy_destroy((struct wl_proxy *) c->tc);
+	wl_display_disconnect(c->wl_display);
+	free(c);
+}
+
+TEST(closure_leaks_after_error)
+{
+	struct display *d = display_create();
+	struct client_info *cl;
+
+	cl = client_create_noarg(d, leak_after_error);
+	display_run(d);
+
+	wl_client_post_no_memory(cl->wl_client);
+	display_resume(d);
+
+	display_destroy(d);
+}
+
+/** Raw read from socket expecting wl_display.error
+ *
+ * \param sockfd The socket to read from.
+ * \param expected_error The expected wl_display error code.
+ *
+ * Reads the socket and manually parses one message, expecting it to be a
+ * wl_display.error with the wl_display as the originating object.
+ * Asserts that the received error code is expected_error.
+ */
+static void
+expect_error_recv(int sockfd, uint32_t expected_error)
+{
+	uint32_t buf[1024];
+	ssize_t slen;
+	uint32_t opcode;
+	int str_len;
+
+	slen = recv(sockfd, buf, sizeof buf, 0);
+	assert(slen >= 2 * (ssize_t)sizeof (uint32_t));
+	opcode = buf[1] & 0xffff;
+	fprintf(stderr, "Received %zd bytes, object %u, opcode %u\n",
+		slen, buf[0], opcode);
+
+	/* check error event */
+	assert(buf[0] == 1);
+	assert(opcode == WL_DISPLAY_ERROR);
+
+	str_len = buf[4];
+	assert(str_len > 0);
+	assert(str_len <= slen - 5 * (ssize_t)sizeof (uint32_t));
+	fprintf(stderr, "Error event on object %u, code %u, message \"%*s\"\n",
+		buf[2], buf[3], str_len, (const char *)&buf[5]);
+
+	assert(buf[3] == expected_error);
+}
+
+/* A test for https://gitlab.freedesktop.org/wayland/wayland/issues/52
+ * trying to provoke a read from uninitialized memory in
+ * wl_connection_demarshal() for sender_id and opcode.
+ *
+ * This test might not fail as is even with #52 unfixed, since there is no way
+ * to detect what happens and the crash with zero size depends on stack content.
+ * However, running under Valgrind would point out invalid reads and use of
+ * uninitialized values.
+ */
+TEST(request_bogus_size)
+{
+	struct wl_display *display;
+	struct wl_client *client;
+	int s[2];
+	uint32_t msg[3];
+	int bogus_size;
+
+	test_set_timeout(1);
+
+	/*
+	 * The manufactured message has real size 12. Test all bogus sizes
+	 * smaller than that, and zero as the last one since wl_closure_init
+	 * handles zero specially and having garbage in the stack makes it more
+	 * likely to crash in wl_connection_demarshal.
+	 */
+	for (bogus_size = 11; bogus_size >= 0; bogus_size--) {
+		fprintf(stderr, "* bogus size %d\n", bogus_size);
+
+		assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+		display = wl_display_create();
+		assert(display);
+		client = wl_client_create(display, s[0]);
+		assert(client);
+
+		/* manufacture a request that lies about its size */
+		msg[0] = 1; /* sender id: wl_display */
+		msg[1] = (bogus_size << 16) | WL_DISPLAY_SYNC; /* size and opcode */
+		msg[2] = 2; /* sync argument: new_id for wl_callback */
+
+		assert(send(s[1], msg, sizeof msg, 0) == sizeof msg);
+
+		wl_event_loop_dispatch(wl_display_get_event_loop(display), 0);
+
+		expect_error_recv(s[1], WL_DISPLAY_ERROR_INVALID_METHOD);
+
+		/* Do not wl_client_destroy, the error already caused it. */
+		close(s[1]);
+		wl_display_destroy(display);
+	}
+}
diff --git a/subprojects/wayland/tests/cpp-compile-test.cpp b/subprojects/wayland/tests/cpp-compile-test.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..1e84e6376e651ad1d89d3ffb95e4e5c61c996959
--- /dev/null
+++ b/subprojects/wayland/tests/cpp-compile-test.cpp
@@ -0,0 +1,5 @@
+/* This source should compile fine with C++ compiler */
+#include "wayland-server-protocol.h"
+
+int main() { return 0; }
+
diff --git a/subprojects/wayland/tests/data/README.md b/subprojects/wayland/tests/data/README.md
new file mode 100644
index 0000000000000000000000000000000000000000..148134539b3d3dc2fecf69aeb7268175b7b06f08
--- /dev/null
+++ b/subprojects/wayland/tests/data/README.md
@@ -0,0 +1,3 @@
+To re-generate the test data, run:
+
+    ninja -C build/ gen-scanner-test
diff --git a/subprojects/wayland/tests/data/bad-identifier-arg.xml b/subprojects/wayland/tests/data/bad-identifier-arg.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ac2a6b76b695d64553c84e91ee637868ecd914e9
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/tests/data/bad-identifier-entry.xml b/subprojects/wayland/tests/data/bad-identifier-entry.xml
new file mode 100644
index 0000000000000000000000000000000000000000..6ea2fae08a9ba632489ac89d22b020a213f04e88
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/tests/data/bad-identifier-enum.xml b/subprojects/wayland/tests/data/bad-identifier-enum.xml
new file mode 100644
index 0000000000000000000000000000000000000000..3225384e5eca0ae6de23db0cf4ea0d3eb96145e4
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/tests/data/bad-identifier-event.xml b/subprojects/wayland/tests/data/bad-identifier-event.xml
new file mode 100644
index 0000000000000000000000000000000000000000..9708e3bc54c1305a061532a75d05da26330704f6
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/tests/data/bad-identifier-interface.xml b/subprojects/wayland/tests/data/bad-identifier-interface.xml
new file mode 100644
index 0000000000000000000000000000000000000000..17404c5e4cbe8f4e6df2771190f68a87d597d269
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/tests/data/bad-identifier-protocol.xml b/subprojects/wayland/tests/data/bad-identifier-protocol.xml
new file mode 100644
index 0000000000000000000000000000000000000000..7a172045115a16aa7954bdeaf7aae5716ea79495
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/tests/data/bad-identifier-request.xml b/subprojects/wayland/tests/data/bad-identifier-request.xml
new file mode 100644
index 0000000000000000000000000000000000000000..a68c8aac402ae0971c82cf0bef2f693d8ee5b878
--- /dev/null
+++ b/subprojects/wayland/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/subprojects/wayland/tests/data/empty-client.h b/subprojects/wayland/tests/data/empty-client.h
new file mode 100644
index 0000000000000000000000000000000000000000..bf1264a42b4dd2bd8fe67ae6627b899534d7ec8a
--- /dev/null
+++ b/subprojects/wayland/tests/data/empty-client.h
@@ -0,0 +1,83 @@
+/* SCANNER TEST */
+
+#ifndef EMPTY_CLIENT_PROTOCOL_H
+#define EMPTY_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_empty The empty protocol
+ * @section page_ifaces_empty Interfaces
+ * - @subpage page_iface_empty - 
+ */
+struct empty;
+
+#ifndef EMPTY_INTERFACE
+#define EMPTY_INTERFACE
+/**
+ * @page page_iface_empty empty
+ * @section page_iface_empty_api API
+ * See @ref iface_empty.
+ */
+/**
+ * @defgroup iface_empty The empty interface
+ */
+extern const struct wl_interface empty_interface;
+#endif
+
+#define EMPTY_EMPTY 0
+
+
+/**
+ * @ingroup iface_empty
+ */
+#define EMPTY_EMPTY_SINCE_VERSION 1
+
+/** @ingroup iface_empty */
+static inline void
+empty_set_user_data(struct empty *empty, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) empty, user_data);
+}
+
+/** @ingroup iface_empty */
+static inline void *
+empty_get_user_data(struct empty *empty)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) empty);
+}
+
+static inline uint32_t
+empty_get_version(struct empty *empty)
+{
+	return wl_proxy_get_version((struct wl_proxy *) empty);
+}
+
+/** @ingroup iface_empty */
+static inline void
+empty_destroy(struct empty *empty)
+{
+	wl_proxy_destroy((struct wl_proxy *) empty);
+}
+
+/**
+ * @ingroup iface_empty
+ */
+static inline void
+empty_empty(struct empty *empty)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) empty,
+			 EMPTY_EMPTY, NULL, wl_proxy_get_version((struct wl_proxy *) empty), 0);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/empty-code.c b/subprojects/wayland/tests/data/empty-code.c
new file mode 100644
index 0000000000000000000000000000000000000000..67382d20da7e3b0eb8a7abdf0228e92a8c0fa2ad
--- /dev/null
+++ b/subprojects/wayland/tests/data/empty-code.c
@@ -0,0 +1,21 @@
+/* SCANNER TEST */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+
+static const struct wl_interface *empty_types[] = {
+};
+
+static const struct wl_message empty_requests[] = {
+	{ "empty", "", empty_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface empty_interface = {
+	"empty", 1,
+	1, empty_requests,
+	0, NULL,
+};
+
diff --git a/subprojects/wayland/tests/data/empty-server.h b/subprojects/wayland/tests/data/empty-server.h
new file mode 100644
index 0000000000000000000000000000000000000000..4baf6d6bcf8158c43502d6795590df2e61ebac52
--- /dev/null
+++ b/subprojects/wayland/tests/data/empty-server.h
@@ -0,0 +1,58 @@
+/* SCANNER TEST */
+
+#ifndef EMPTY_SERVER_PROTOCOL_H
+#define EMPTY_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_empty The empty protocol
+ * @section page_ifaces_empty Interfaces
+ * - @subpage page_iface_empty - 
+ */
+struct empty;
+
+#ifndef EMPTY_INTERFACE
+#define EMPTY_INTERFACE
+/**
+ * @page page_iface_empty empty
+ * @section page_iface_empty_api API
+ * See @ref iface_empty.
+ */
+/**
+ * @defgroup iface_empty The empty interface
+ */
+extern const struct wl_interface empty_interface;
+#endif
+
+/**
+ * @ingroup iface_empty
+ * @struct empty_interface
+ */
+struct empty_interface {
+	/**
+	 */
+	void (*empty)(struct wl_client *client,
+		      struct wl_resource *resource);
+};
+
+
+/**
+ * @ingroup iface_empty
+ */
+#define EMPTY_EMPTY_SINCE_VERSION 1
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/empty.xml b/subprojects/wayland/tests/data/empty.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2549d8fcef6fc6b6ed44863ed4d0e9dccee01865
--- /dev/null
+++ b/subprojects/wayland/tests/data/empty.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="empty">
+  <interface name="empty" version="1">
+    <request name="empty">
+    </request>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland/tests/data/example-client.h b/subprojects/wayland/tests/data/example-client.h
new file mode 100644
index 0000000000000000000000000000000000000000..a14b5e0033689e13be68079265b83c701e578ca8
--- /dev/null
+++ b/subprojects/wayland/tests/data/example-client.h
@@ -0,0 +1,5625 @@
+/* SCANNER TEST */
+
+#ifndef WAYLAND_CLIENT_PROTOCOL_H
+#define WAYLAND_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_wayland The wayland protocol
+ * @section page_ifaces_wayland Interfaces
+ * - @subpage page_iface_wl_display - core global object
+ * - @subpage page_iface_wl_registry - global registry object
+ * - @subpage page_iface_wl_callback - callback object
+ * - @subpage page_iface_wl_compositor - the compositor singleton
+ * - @subpage page_iface_wl_shm_pool - a shared memory pool
+ * - @subpage page_iface_wl_shm - shared memory support
+ * - @subpage page_iface_wl_buffer - content for a wl_surface
+ * - @subpage page_iface_wl_data_offer - offer to transfer data
+ * - @subpage page_iface_wl_data_source - offer to transfer data
+ * - @subpage page_iface_wl_data_device - data transfer device
+ * - @subpage page_iface_wl_data_device_manager - data transfer interface
+ * - @subpage page_iface_wl_shell - create desktop-style surfaces
+ * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface
+ * - @subpage page_iface_wl_surface - an onscreen surface
+ * - @subpage page_iface_wl_seat - group of input devices
+ * - @subpage page_iface_wl_pointer - pointer input device
+ * - @subpage page_iface_wl_keyboard - keyboard input device
+ * - @subpage page_iface_wl_touch - touchscreen input device
+ * - @subpage page_iface_wl_output - compositor output region
+ * - @subpage page_iface_wl_region - region interface
+ * - @subpage page_iface_wl_subcompositor - sub-surface compositing
+ * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface
+ * @section page_copyright_wayland Copyright
+ * <pre>
+ *
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * </pre>
+ */
+struct wl_buffer;
+struct wl_callback;
+struct wl_compositor;
+struct wl_data_device;
+struct wl_data_device_manager;
+struct wl_data_offer;
+struct wl_data_source;
+struct wl_display;
+struct wl_keyboard;
+struct wl_output;
+struct wl_pointer;
+struct wl_region;
+struct wl_registry;
+struct wl_seat;
+struct wl_shell;
+struct wl_shell_surface;
+struct wl_shm;
+struct wl_shm_pool;
+struct wl_subcompositor;
+struct wl_subsurface;
+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
+ *
+ * The core global object.  This is a special singleton object.  It
+ * is used for internal Wayland protocol features.
+ * @section page_iface_wl_display_api API
+ * See @ref iface_wl_display.
+ */
+/**
+ * @defgroup iface_wl_display The wl_display interface
+ *
+ * The core global object.  This is a special singleton object.  It
+ * 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
+ *
+ * The singleton global registry object.  The server has a number of
+ * global objects that are available to all clients.  These objects
+ * typically represent an actual object in the server (for example,
+ * an input device) or they are singleton objects that provide
+ * extension functionality.
+ *
+ * When a client creates a registry object, the registry object
+ * will emit a global event for each global currently in the
+ * registry.  Globals come and go as a result of device or
+ * monitor hotplugs, reconfiguration or other events, and the
+ * registry will send out global and global_remove events to
+ * keep the client up to date with the changes.  To mark the end
+ * of the initial burst of events, the client can use the
+ * wl_display.sync request immediately after calling
+ * wl_display.get_registry.
+ *
+ * A client can bind to a global object by using the bind
+ * request.  This creates a client-side handle that lets the object
+ * emit events to the client and lets the client invoke requests on
+ * the object.
+ * @section page_iface_wl_registry_api API
+ * See @ref iface_wl_registry.
+ */
+/**
+ * @defgroup iface_wl_registry The wl_registry interface
+ *
+ * The singleton global registry object.  The server has a number of
+ * global objects that are available to all clients.  These objects
+ * typically represent an actual object in the server (for example,
+ * an input device) or they are singleton objects that provide
+ * extension functionality.
+ *
+ * When a client creates a registry object, the registry object
+ * will emit a global event for each global currently in the
+ * registry.  Globals come and go as a result of device or
+ * monitor hotplugs, reconfiguration or other events, and the
+ * registry will send out global and global_remove events to
+ * keep the client up to date with the changes.  To mark the end
+ * of the initial burst of events, the client can use the
+ * wl_display.sync request immediately after calling
+ * wl_display.get_registry.
+ *
+ * A client can bind to a global object by using the bind
+ * request.  This creates a client-side handle that lets the object
+ * emit events to the client and lets the client invoke requests on
+ * 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
+ *
+ * Clients can handle the 'done' event to get notified when
+ * the related request is done.
+ * @section page_iface_wl_callback_api API
+ * See @ref iface_wl_callback.
+ */
+/**
+ * @defgroup iface_wl_callback The wl_callback interface
+ *
+ * Clients can handle the 'done' event to get notified when
+ * 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
+ *
+ * A compositor.  This object is a singleton global.  The
+ * compositor is in charge of combining the contents of multiple
+ * surfaces into one displayable output.
+ * @section page_iface_wl_compositor_api API
+ * See @ref iface_wl_compositor.
+ */
+/**
+ * @defgroup iface_wl_compositor The wl_compositor interface
+ *
+ * A compositor.  This object is a singleton global.  The
+ * compositor is in charge of combining the contents of multiple
+ * 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
+ *
+ * The wl_shm_pool object encapsulates a piece of memory shared
+ * between the compositor and client.  Through the wl_shm_pool
+ * object, the client can allocate shared memory wl_buffer objects.
+ * All objects created through the same pool share the same
+ * underlying mapped memory. Reusing the mapped memory avoids the
+ * setup/teardown overhead and is useful when interactively resizing
+ * a surface or for many small buffers.
+ * @section page_iface_wl_shm_pool_api API
+ * See @ref iface_wl_shm_pool.
+ */
+/**
+ * @defgroup iface_wl_shm_pool The wl_shm_pool interface
+ *
+ * The wl_shm_pool object encapsulates a piece of memory shared
+ * between the compositor and client.  Through the wl_shm_pool
+ * object, the client can allocate shared memory wl_buffer objects.
+ * All objects created through the same pool share the same
+ * underlying mapped memory. Reusing the mapped memory avoids the
+ * setup/teardown overhead and is useful when interactively resizing
+ * 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
+ *
+ * A singleton global object that provides support for shared
+ * memory.
+ *
+ * Clients can create wl_shm_pool objects using the create_pool
+ * request.
+ *
+ * At connection setup time, the wl_shm object emits one or more
+ * format events to inform clients about the valid pixel formats
+ * that can be used for buffers.
+ * @section page_iface_wl_shm_api API
+ * See @ref iface_wl_shm.
+ */
+/**
+ * @defgroup iface_wl_shm The wl_shm interface
+ *
+ * A singleton global object that provides support for shared
+ * memory.
+ *
+ * Clients can create wl_shm_pool objects using the create_pool
+ * request.
+ *
+ * At connection setup time, the wl_shm object emits one or more
+ * format events to inform clients about the valid pixel formats
+ * 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
+ *
+ * A buffer provides the content for a wl_surface. Buffers are
+ * created through factory interfaces such as wl_drm, wl_shm or
+ * similar. It has a width and a height and can be attached to a
+ * wl_surface, but the mechanism by which a client provides and
+ * updates the contents is defined by the buffer factory interface.
+ * @section page_iface_wl_buffer_api API
+ * See @ref iface_wl_buffer.
+ */
+/**
+ * @defgroup iface_wl_buffer The wl_buffer interface
+ *
+ * A buffer provides the content for a wl_surface. Buffers are
+ * created through factory interfaces such as wl_drm, wl_shm or
+ * similar. It has a width and a height and can be attached to a
+ * wl_surface, but the mechanism by which a client provides and
+ * 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
+ *
+ * A wl_data_offer represents a piece of data offered for transfer
+ * by another client (the source client).  It is used by the
+ * copy-and-paste and drag-and-drop mechanisms.  The offer
+ * describes the different mime types that the data can be
+ * converted to and provides the mechanism for transferring the
+ * data directly from the source client.
+ * @section page_iface_wl_data_offer_api API
+ * See @ref iface_wl_data_offer.
+ */
+/**
+ * @defgroup iface_wl_data_offer The wl_data_offer interface
+ *
+ * A wl_data_offer represents a piece of data offered for transfer
+ * by another client (the source client).  It is used by the
+ * copy-and-paste and drag-and-drop mechanisms.  The offer
+ * describes the different mime types that the data can be
+ * converted to and provides the mechanism for transferring the
+ * 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
+ *
+ * The wl_data_source object is the source side of a wl_data_offer.
+ * It is created by the source client in a data transfer and
+ * provides a way to describe the offered data and a way to respond
+ * to requests to transfer the data.
+ * @section page_iface_wl_data_source_api API
+ * See @ref iface_wl_data_source.
+ */
+/**
+ * @defgroup iface_wl_data_source The wl_data_source interface
+ *
+ * The wl_data_source object is the source side of a wl_data_offer.
+ * It is created by the source client in a data transfer and
+ * provides a way to describe the offered data and a way to respond
+ * 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
+ *
+ * There is one wl_data_device per seat which can be obtained
+ * from the global wl_data_device_manager singleton.
+ *
+ * A wl_data_device provides access to inter-client data transfer
+ * mechanisms such as copy-and-paste and drag-and-drop.
+ * @section page_iface_wl_data_device_api API
+ * See @ref iface_wl_data_device.
+ */
+/**
+ * @defgroup iface_wl_data_device The wl_data_device interface
+ *
+ * There is one wl_data_device per seat which can be obtained
+ * from the global wl_data_device_manager singleton.
+ *
+ * A wl_data_device provides access to inter-client data transfer
+ * 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
+ *
+ * The wl_data_device_manager is a singleton global object that
+ * provides access to inter-client data transfer mechanisms such as
+ * copy-and-paste and drag-and-drop.  These mechanisms are tied to
+ * a wl_seat and this interface lets a client get a wl_data_device
+ * corresponding to a wl_seat.
+ *
+ * Depending on the version bound, the objects created from the bound
+ * wl_data_device_manager object will have different requirements for
+ * functioning properly. See wl_data_source.set_actions,
+ * wl_data_offer.accept and wl_data_offer.finish for details.
+ * @section page_iface_wl_data_device_manager_api API
+ * See @ref iface_wl_data_device_manager.
+ */
+/**
+ * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface
+ *
+ * The wl_data_device_manager is a singleton global object that
+ * provides access to inter-client data transfer mechanisms such as
+ * copy-and-paste and drag-and-drop.  These mechanisms are tied to
+ * a wl_seat and this interface lets a client get a wl_data_device
+ * corresponding to a wl_seat.
+ *
+ * Depending on the version bound, the objects created from the bound
+ * wl_data_device_manager object will have different requirements for
+ * functioning properly. See wl_data_source.set_actions,
+ * 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
+ *
+ * This interface is implemented by servers that provide
+ * desktop-style user interfaces.
+ *
+ * It allows clients to associate a wl_shell_surface with
+ * a basic surface.
+ * @section page_iface_wl_shell_api API
+ * See @ref iface_wl_shell.
+ */
+/**
+ * @defgroup iface_wl_shell The wl_shell interface
+ *
+ * This interface is implemented by servers that provide
+ * desktop-style user interfaces.
+ *
+ * It allows clients to associate a wl_shell_surface with
+ * 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
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like toplevel, fullscreen
+ * or popup windows, move, resize or maximize them, associate
+ * metadata like title and class, etc.
+ *
+ * On the server side the object is automatically destroyed when
+ * the related wl_surface is destroyed. On the client side,
+ * wl_shell_surface_destroy() must be called before destroying
+ * the wl_surface object.
+ * @section page_iface_wl_shell_surface_api API
+ * See @ref iface_wl_shell_surface.
+ */
+/**
+ * @defgroup iface_wl_shell_surface The wl_shell_surface interface
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like toplevel, fullscreen
+ * or popup windows, move, resize or maximize them, associate
+ * metadata like title and class, etc.
+ *
+ * On the server side the object is automatically destroyed when
+ * the related wl_surface is destroyed. On the client side,
+ * wl_shell_surface_destroy() must be called before destroying
+ * 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
+ *
+ * A surface is a rectangular area that is displayed on the screen.
+ * It has a location, size and pixel contents.
+ *
+ * The size of a surface (and relative positions on it) is described
+ * in surface-local coordinates, which may differ from the buffer
+ * coordinates of the pixel content, in case a buffer_transform
+ * or a buffer_scale is used.
+ *
+ * A surface without a "role" is fairly useless: a compositor does
+ * not know where, when or how to present it. The role is the
+ * purpose of a wl_surface. Examples of roles are a cursor for a
+ * pointer (as set by wl_pointer.set_cursor), a drag icon
+ * (wl_data_device.start_drag), a sub-surface
+ * (wl_subcompositor.get_subsurface), and a window as defined by a
+ * shell protocol (e.g. wl_shell.get_shell_surface).
+ *
+ * A surface can have only one role at a time. Initially a
+ * wl_surface does not have a role. Once a wl_surface is given a
+ * role, it is set permanently for the whole lifetime of the
+ * wl_surface object. Giving the current role again is allowed,
+ * unless explicitly forbidden by the relevant interface
+ * specification.
+ *
+ * Surface roles are given by requests in other interfaces such as
+ * wl_pointer.set_cursor. The request should explicitly mention
+ * that this request gives a role to a wl_surface. Often, this
+ * request also creates a new protocol object that represents the
+ * role and adds additional functionality to wl_surface. When a
+ * client wants to destroy a wl_surface, they must destroy this 'role
+ * object' before the wl_surface.
+ *
+ * Destroying the role object does not remove the role from the
+ * wl_surface, but it may stop the wl_surface from "playing the role".
+ * For instance, if a wl_subsurface object is destroyed, the wl_surface
+ * it was created for will be unmapped and forget its position and
+ * z-order. It is allowed to create a wl_subsurface for the same
+ * wl_surface again, but it is not allowed to use the wl_surface as
+ * a cursor (cursor is a different role than sub-surface, and role
+ * switching is not allowed).
+ * @section page_iface_wl_surface_api API
+ * See @ref iface_wl_surface.
+ */
+/**
+ * @defgroup iface_wl_surface The wl_surface interface
+ *
+ * A surface is a rectangular area that is displayed on the screen.
+ * It has a location, size and pixel contents.
+ *
+ * The size of a surface (and relative positions on it) is described
+ * in surface-local coordinates, which may differ from the buffer
+ * coordinates of the pixel content, in case a buffer_transform
+ * or a buffer_scale is used.
+ *
+ * A surface without a "role" is fairly useless: a compositor does
+ * not know where, when or how to present it. The role is the
+ * purpose of a wl_surface. Examples of roles are a cursor for a
+ * pointer (as set by wl_pointer.set_cursor), a drag icon
+ * (wl_data_device.start_drag), a sub-surface
+ * (wl_subcompositor.get_subsurface), and a window as defined by a
+ * shell protocol (e.g. wl_shell.get_shell_surface).
+ *
+ * A surface can have only one role at a time. Initially a
+ * wl_surface does not have a role. Once a wl_surface is given a
+ * role, it is set permanently for the whole lifetime of the
+ * wl_surface object. Giving the current role again is allowed,
+ * unless explicitly forbidden by the relevant interface
+ * specification.
+ *
+ * Surface roles are given by requests in other interfaces such as
+ * wl_pointer.set_cursor. The request should explicitly mention
+ * that this request gives a role to a wl_surface. Often, this
+ * request also creates a new protocol object that represents the
+ * role and adds additional functionality to wl_surface. When a
+ * client wants to destroy a wl_surface, they must destroy this 'role
+ * object' before the wl_surface.
+ *
+ * Destroying the role object does not remove the role from the
+ * wl_surface, but it may stop the wl_surface from "playing the role".
+ * For instance, if a wl_subsurface object is destroyed, the wl_surface
+ * it was created for will be unmapped and forget its position and
+ * z-order. It is allowed to create a wl_subsurface for the same
+ * wl_surface again, but it is not allowed to use the wl_surface as
+ * a cursor (cursor is a different role than sub-surface, and role
+ * 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
+ *
+ * A seat is a group of keyboards, pointer and touch devices. This
+ * object is published as a global during start up, or when such a
+ * device is hot plugged.  A seat typically has a pointer and
+ * maintains a keyboard focus and a pointer focus.
+ * @section page_iface_wl_seat_api API
+ * See @ref iface_wl_seat.
+ */
+/**
+ * @defgroup iface_wl_seat The wl_seat interface
+ *
+ * A seat is a group of keyboards, pointer and touch devices. This
+ * object is published as a global during start up, or when such a
+ * device is hot plugged.  A seat typically has a pointer and
+ * 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
+ *
+ * The wl_pointer interface represents one or more input devices,
+ * such as mice, which control the pointer location and pointer_focus
+ * of a seat.
+ *
+ * The wl_pointer interface generates motion, enter and leave
+ * events for the surfaces that the pointer is located over,
+ * and button and axis events for button presses, button releases
+ * and scrolling.
+ * @section page_iface_wl_pointer_api API
+ * See @ref iface_wl_pointer.
+ */
+/**
+ * @defgroup iface_wl_pointer The wl_pointer interface
+ *
+ * The wl_pointer interface represents one or more input devices,
+ * such as mice, which control the pointer location and pointer_focus
+ * of a seat.
+ *
+ * The wl_pointer interface generates motion, enter and leave
+ * events for the surfaces that the pointer is located over,
+ * and button and axis events for button presses, button releases
+ * 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
+ *
+ * The wl_keyboard interface represents one or more keyboards
+ * associated with a seat.
+ * @section page_iface_wl_keyboard_api API
+ * See @ref iface_wl_keyboard.
+ */
+/**
+ * @defgroup iface_wl_keyboard The wl_keyboard interface
+ *
+ * The wl_keyboard interface represents one or more keyboards
+ * 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
+ *
+ * The wl_touch interface represents a touchscreen
+ * associated with a seat.
+ *
+ * Touch interactions can consist of one or more contacts.
+ * For each contact, a series of events is generated, starting
+ * with a down event, followed by zero or more motion events,
+ * and ending with an up event. Events relating to the same
+ * contact point can be identified by the ID of the sequence.
+ * @section page_iface_wl_touch_api API
+ * See @ref iface_wl_touch.
+ */
+/**
+ * @defgroup iface_wl_touch The wl_touch interface
+ *
+ * The wl_touch interface represents a touchscreen
+ * associated with a seat.
+ *
+ * Touch interactions can consist of one or more contacts.
+ * For each contact, a series of events is generated, starting
+ * with a down event, followed by zero or more motion events,
+ * and ending with an up event. Events relating to the same
+ * 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
+ *
+ * An output describes part of the compositor geometry.  The
+ * compositor works in the 'compositor coordinate system' and an
+ * output corresponds to a rectangular area in that space that is
+ * actually visible.  This typically corresponds to a monitor that
+ * displays part of the compositor space.  This object is published
+ * as global during start up, or when a monitor is hotplugged.
+ * @section page_iface_wl_output_api API
+ * See @ref iface_wl_output.
+ */
+/**
+ * @defgroup iface_wl_output The wl_output interface
+ *
+ * An output describes part of the compositor geometry.  The
+ * compositor works in the 'compositor coordinate system' and an
+ * output corresponds to a rectangular area in that space that is
+ * actually visible.  This typically corresponds to a monitor that
+ * displays part of the compositor space.  This object is published
+ * 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
+ *
+ * A region object describes an area.
+ *
+ * Region objects are used to describe the opaque and input
+ * regions of a surface.
+ * @section page_iface_wl_region_api API
+ * See @ref iface_wl_region.
+ */
+/**
+ * @defgroup iface_wl_region The wl_region interface
+ *
+ * A region object describes an area.
+ *
+ * Region objects are used to describe the opaque and input
+ * 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
+ *
+ * The global interface exposing sub-surface compositing capabilities.
+ * A wl_surface, that has sub-surfaces associated, is called the
+ * parent surface. Sub-surfaces can be arbitrarily nested and create
+ * a tree of sub-surfaces.
+ *
+ * The root surface in a tree of sub-surfaces is the main
+ * surface. The main surface cannot be a sub-surface, because
+ * sub-surfaces must always have a parent.
+ *
+ * A main surface with its sub-surfaces forms a (compound) window.
+ * For window management purposes, this set of wl_surface objects is
+ * to be considered as a single window, and it should also behave as
+ * such.
+ *
+ * The aim of sub-surfaces is to offload some of the compositing work
+ * within a window from clients to the compositor. A prime example is
+ * a video player with decorations and video in separate wl_surface
+ * objects. This should allow the compositor to pass YUV video buffer
+ * processing to dedicated overlay hardware when possible.
+ * @section page_iface_wl_subcompositor_api API
+ * See @ref iface_wl_subcompositor.
+ */
+/**
+ * @defgroup iface_wl_subcompositor The wl_subcompositor interface
+ *
+ * The global interface exposing sub-surface compositing capabilities.
+ * A wl_surface, that has sub-surfaces associated, is called the
+ * parent surface. Sub-surfaces can be arbitrarily nested and create
+ * a tree of sub-surfaces.
+ *
+ * The root surface in a tree of sub-surfaces is the main
+ * surface. The main surface cannot be a sub-surface, because
+ * sub-surfaces must always have a parent.
+ *
+ * A main surface with its sub-surfaces forms a (compound) window.
+ * For window management purposes, this set of wl_surface objects is
+ * to be considered as a single window, and it should also behave as
+ * such.
+ *
+ * The aim of sub-surfaces is to offload some of the compositing work
+ * within a window from clients to the compositor. A prime example is
+ * a video player with decorations and video in separate wl_surface
+ * objects. This should allow the compositor to pass YUV video buffer
+ * 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
+ *
+ * An additional interface to a wl_surface object, which has been
+ * made a sub-surface. A sub-surface has one parent surface. A
+ * sub-surface's size and position are not limited to that of the parent.
+ * Particularly, a sub-surface is not automatically clipped to its
+ * parent's area.
+ *
+ * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+ * and the parent surface is mapped. The order of which one happens
+ * first is irrelevant. A sub-surface is hidden if the parent becomes
+ * hidden, or if a NULL wl_buffer is applied. These rules apply
+ * recursively through the tree of surfaces.
+ *
+ * The behaviour of a wl_surface.commit request on a sub-surface
+ * depends on the sub-surface's mode. The possible modes are
+ * synchronized and desynchronized, see methods
+ * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
+ * mode caches the wl_surface state to be applied when the parent's
+ * state gets applied, and desynchronized mode applies the pending
+ * 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
+ * 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
+ * the parent and its sub-surfaces (wl_subsurface.place_above and
+ * .place_below). This state is applied when the parent surface's
+ * wl_surface state is applied, regardless of the sub-surface's mode.
+ * As the exception, set_sync and set_desync are effective immediately.
+ *
+ * The main surface can be thought to be always in desynchronized mode,
+ * since it does not have a parent in the sub-surfaces sense.
+ *
+ * Even if a sub-surface is in desynchronized mode, it will behave as
+ * in synchronized mode, if its parent surface behaves as in
+ * synchronized mode. This rule is applied recursively throughout the
+ * tree of surfaces. This means, that one can set a sub-surface into
+ * synchronized mode, and then assume that all its child and grand-child
+ * sub-surfaces are synchronized, too, without explicitly setting them.
+ *
+ * If the wl_surface associated with the wl_subsurface is destroyed, the
+ * wl_subsurface object becomes inert. Note, that destroying either object
+ * takes effect immediately. If you need to synchronize the removal
+ * of a sub-surface to the parent surface update, unmap the sub-surface
+ * first by attaching a NULL wl_buffer, update parent, and then destroy
+ * the sub-surface.
+ *
+ * If the parent wl_surface object is destroyed, the sub-surface is
+ * unmapped.
+ * @section page_iface_wl_subsurface_api API
+ * See @ref iface_wl_subsurface.
+ */
+/**
+ * @defgroup iface_wl_subsurface The wl_subsurface interface
+ *
+ * An additional interface to a wl_surface object, which has been
+ * made a sub-surface. A sub-surface has one parent surface. A
+ * sub-surface's size and position are not limited to that of the parent.
+ * Particularly, a sub-surface is not automatically clipped to its
+ * parent's area.
+ *
+ * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+ * and the parent surface is mapped. The order of which one happens
+ * first is irrelevant. A sub-surface is hidden if the parent becomes
+ * hidden, or if a NULL wl_buffer is applied. These rules apply
+ * recursively through the tree of surfaces.
+ *
+ * The behaviour of a wl_surface.commit request on a sub-surface
+ * depends on the sub-surface's mode. The possible modes are
+ * synchronized and desynchronized, see methods
+ * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
+ * mode caches the wl_surface state to be applied when the parent's
+ * state gets applied, and desynchronized mode applies the pending
+ * 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
+ * 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
+ * the parent and its sub-surfaces (wl_subsurface.place_above and
+ * .place_below). This state is applied when the parent surface's
+ * wl_surface state is applied, regardless of the sub-surface's mode.
+ * As the exception, set_sync and set_desync are effective immediately.
+ *
+ * The main surface can be thought to be always in desynchronized mode,
+ * since it does not have a parent in the sub-surfaces sense.
+ *
+ * Even if a sub-surface is in desynchronized mode, it will behave as
+ * in synchronized mode, if its parent surface behaves as in
+ * synchronized mode. This rule is applied recursively throughout the
+ * tree of surfaces. This means, that one can set a sub-surface into
+ * synchronized mode, and then assume that all its child and grand-child
+ * sub-surfaces are synchronized, too, without explicitly setting them.
+ *
+ * If the wl_surface associated with the wl_subsurface is destroyed, the
+ * wl_subsurface object becomes inert. Note, that destroying either object
+ * takes effect immediately. If you need to synchronize the removal
+ * of a sub-surface to the parent surface update, unmap the sub-surface
+ * first by attaching a NULL wl_buffer, update parent, and then destroy
+ * the sub-surface.
+ *
+ * If the parent wl_surface object is destroyed, the sub-surface is
+ * unmapped.
+ */
+extern const struct wl_interface wl_subsurface_interface;
+#endif
+
+#ifndef WL_DISPLAY_ERROR_ENUM
+#define WL_DISPLAY_ERROR_ENUM
+/**
+ * @ingroup iface_wl_display
+ * global error values
+ *
+ * These errors are global and can be emitted in response to any
+ * server request.
+ */
+enum wl_display_error {
+	/**
+	 * server couldn't find object
+	 */
+	WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
+	/**
+	 * method doesn't exist on the specified interface
+	 */
+	WL_DISPLAY_ERROR_INVALID_METHOD = 1,
+	/**
+	 * server is out of memory
+	 */
+	WL_DISPLAY_ERROR_NO_MEMORY = 2,
+};
+#endif /* WL_DISPLAY_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_display
+ * @struct wl_display_listener
+ */
+struct wl_display_listener {
+	/**
+	 * fatal error event
+	 *
+	 * The error event is sent out when a fatal (non-recoverable)
+	 * error has occurred. The object_id argument is the object where
+	 * the error occurred, most often in response to a request to that
+	 * object. The code identifies the error and is defined by the
+	 * object interface. As such, each interface defines its own set of
+	 * error codes. The message is a brief description of the error,
+	 * for (debugging) convenience.
+	 * @param object_id object where the error occurred
+	 * @param code error code
+	 * @param message error description
+	 */
+	void (*error)(void *data,
+		      struct wl_display *wl_display,
+		      void *object_id,
+		      uint32_t code,
+		      const char *message);
+	/**
+	 * 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.
+	 * @param id deleted object ID
+	 */
+	void (*delete_id)(void *data,
+			  struct wl_display *wl_display,
+			  uint32_t id);
+};
+
+/**
+ * @ingroup iface_wl_display
+ */
+static inline int
+wl_display_add_listener(struct wl_display *wl_display,
+			const struct wl_display_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_display,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DISPLAY_SYNC 0
+#define WL_DISPLAY_GET_REGISTRY 1
+
+/**
+ * @ingroup iface_wl_display
+ */
+#define WL_DISPLAY_ERROR_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_display
+ */
+#define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_display
+ */
+#define WL_DISPLAY_SYNC_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_display
+ */
+#define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1
+
+/** @ingroup iface_wl_display */
+static inline void
+wl_display_set_user_data(struct wl_display *wl_display, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_display, user_data);
+}
+
+/** @ingroup iface_wl_display */
+static inline void *
+wl_display_get_user_data(struct wl_display *wl_display)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_display);
+}
+
+static inline uint32_t
+wl_display_get_version(struct wl_display *wl_display)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_display);
+}
+
+/**
+ * @ingroup iface_wl_display
+ *
+ * The sync request asks the server to emit the 'done' event
+ * on the returned wl_callback object.  Since requests are
+ * handled in-order and events are delivered in-order, this can
+ * be used as a barrier to ensure all previous requests and the
+ * resulting events have been handled.
+ *
+ * The object returned by this request will be destroyed by the
+ * compositor after the callback is fired and as such the client must not
+ * attempt to use it after that point.
+ *
+ * The callback_data passed in the callback is the event serial.
+ */
+static inline struct wl_callback *
+wl_display_sync(struct wl_display *wl_display)
+{
+	struct wl_proxy *callback;
+
+	callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_display,
+			 WL_DISPLAY_SYNC, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL);
+
+	return (struct wl_callback *) callback;
+}
+
+/**
+ * @ingroup iface_wl_display
+ *
+ * This request creates a registry object that allows the client
+ * to list and bind the global objects available from the
+ * compositor.
+ */
+static inline struct wl_registry *
+wl_display_get_registry(struct wl_display *wl_display)
+{
+	struct wl_proxy *registry;
+
+	registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display,
+			 WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, wl_proxy_get_version((struct wl_proxy *) wl_display), 0, NULL);
+
+	return (struct wl_registry *) registry;
+}
+
+/**
+ * @ingroup iface_wl_registry
+ * @struct wl_registry_listener
+ */
+struct wl_registry_listener {
+	/**
+	 * announce global object
+	 *
+	 * Notify the client of global objects.
+	 *
+	 * The event notifies the client that a global object with the
+	 * given name is now available, and it implements the given version
+	 * of the given interface.
+	 * @param name numeric name of the global object
+	 * @param interface interface implemented by the object
+	 * @param version interface version
+	 */
+	void (*global)(void *data,
+		       struct wl_registry *wl_registry,
+		       uint32_t name,
+		       const char *interface,
+		       uint32_t version);
+	/**
+	 * announce removal of global object
+	 *
+	 * Notify the client of removed global objects.
+	 *
+	 * This event notifies the client that the global identified by
+	 * name is no longer available. If the client bound to the global
+	 * using the bind request, the client should now destroy that
+	 * object.
+	 *
+	 * The object remains valid and requests to the object will be
+	 * ignored until the client destroys it, to avoid races between the
+	 * global going away and a client sending a request to it.
+	 * @param name numeric name of the global object
+	 */
+	void (*global_remove)(void *data,
+			      struct wl_registry *wl_registry,
+			      uint32_t name);
+};
+
+/**
+ * @ingroup iface_wl_registry
+ */
+static inline int
+wl_registry_add_listener(struct wl_registry *wl_registry,
+			 const struct wl_registry_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_registry,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_REGISTRY_BIND 0
+
+/**
+ * @ingroup iface_wl_registry
+ */
+#define WL_REGISTRY_GLOBAL_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_registry
+ */
+#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_registry
+ */
+#define WL_REGISTRY_BIND_SINCE_VERSION 1
+
+/** @ingroup iface_wl_registry */
+static inline void
+wl_registry_set_user_data(struct wl_registry *wl_registry, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_registry, user_data);
+}
+
+/** @ingroup iface_wl_registry */
+static inline void *
+wl_registry_get_user_data(struct wl_registry *wl_registry)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_registry);
+}
+
+static inline uint32_t
+wl_registry_get_version(struct wl_registry *wl_registry)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_registry);
+}
+
+/** @ingroup iface_wl_registry */
+static inline void
+wl_registry_destroy(struct wl_registry *wl_registry)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_registry);
+}
+
+/**
+ * @ingroup iface_wl_registry
+ *
+ * Binds a new, client-created object to the server using the
+ * specified name as the identifier.
+ */
+static inline void *
+wl_registry_bind(struct wl_registry *wl_registry, uint32_t name, const struct wl_interface *interface, uint32_t version)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_registry,
+			 WL_REGISTRY_BIND, interface, version, 0, name, interface->name, version, NULL);
+
+	return (void *) id;
+}
+
+/**
+ * @ingroup iface_wl_callback
+ * @struct wl_callback_listener
+ */
+struct wl_callback_listener {
+	/**
+	 * done event
+	 *
+	 * Notify the client when the related request is done.
+	 * @param callback_data request-specific data for the callback
+	 */
+	void (*done)(void *data,
+		     struct wl_callback *wl_callback,
+		     uint32_t callback_data);
+};
+
+/**
+ * @ingroup iface_wl_callback
+ */
+static inline int
+wl_callback_add_listener(struct wl_callback *wl_callback,
+			 const struct wl_callback_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_callback,
+				     (void (**)(void)) listener, data);
+}
+
+/**
+ * @ingroup iface_wl_callback
+ */
+#define WL_CALLBACK_DONE_SINCE_VERSION 1
+
+
+/** @ingroup iface_wl_callback */
+static inline void
+wl_callback_set_user_data(struct wl_callback *wl_callback, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_callback, user_data);
+}
+
+/** @ingroup iface_wl_callback */
+static inline void *
+wl_callback_get_user_data(struct wl_callback *wl_callback)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_callback);
+}
+
+static inline uint32_t
+wl_callback_get_version(struct wl_callback *wl_callback)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_callback);
+}
+
+/** @ingroup iface_wl_callback */
+static inline void
+wl_callback_destroy(struct wl_callback *wl_callback)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_callback);
+}
+
+#define WL_COMPOSITOR_CREATE_SURFACE 0
+#define WL_COMPOSITOR_CREATE_REGION 1
+
+
+/**
+ * @ingroup iface_wl_compositor
+ */
+#define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_compositor
+ */
+#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1
+
+/** @ingroup iface_wl_compositor */
+static inline void
+wl_compositor_set_user_data(struct wl_compositor *wl_compositor, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_compositor, user_data);
+}
+
+/** @ingroup iface_wl_compositor */
+static inline void *
+wl_compositor_get_user_data(struct wl_compositor *wl_compositor)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_compositor);
+}
+
+static inline uint32_t
+wl_compositor_get_version(struct wl_compositor *wl_compositor)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_compositor);
+}
+
+/** @ingroup iface_wl_compositor */
+static inline void
+wl_compositor_destroy(struct wl_compositor *wl_compositor)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_compositor);
+}
+
+/**
+ * @ingroup iface_wl_compositor
+ *
+ * Ask the compositor to create a new surface.
+ */
+static inline struct wl_surface *
+wl_compositor_create_surface(struct wl_compositor *wl_compositor)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor,
+			 WL_COMPOSITOR_CREATE_SURFACE, &wl_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL);
+
+	return (struct wl_surface *) id;
+}
+
+/**
+ * @ingroup iface_wl_compositor
+ *
+ * Ask the compositor to create a new region.
+ */
+static inline struct wl_region *
+wl_compositor_create_region(struct wl_compositor *wl_compositor)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_compositor,
+			 WL_COMPOSITOR_CREATE_REGION, &wl_region_interface, wl_proxy_get_version((struct wl_proxy *) wl_compositor), 0, NULL);
+
+	return (struct wl_region *) id;
+}
+
+#define WL_SHM_POOL_CREATE_BUFFER 0
+#define WL_SHM_POOL_DESTROY 1
+#define WL_SHM_POOL_RESIZE 2
+
+
+/**
+ * @ingroup iface_wl_shm_pool
+ */
+#define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shm_pool
+ */
+#define WL_SHM_POOL_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shm_pool
+ */
+#define WL_SHM_POOL_RESIZE_SINCE_VERSION 1
+
+/** @ingroup iface_wl_shm_pool */
+static inline void
+wl_shm_pool_set_user_data(struct wl_shm_pool *wl_shm_pool, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shm_pool, user_data);
+}
+
+/** @ingroup iface_wl_shm_pool */
+static inline void *
+wl_shm_pool_get_user_data(struct wl_shm_pool *wl_shm_pool)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shm_pool);
+}
+
+static inline uint32_t
+wl_shm_pool_get_version(struct wl_shm_pool *wl_shm_pool)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_shm_pool);
+}
+
+/**
+ * @ingroup iface_wl_shm_pool
+ *
+ * Create a wl_buffer object from the pool.
+ *
+ * The buffer is created offset bytes into the pool and has
+ * width and height as specified.  The stride argument specifies
+ * the number of bytes from the beginning of one row to the beginning
+ * of the next.  The format is the pixel format of the buffer and
+ * must be one of those advertised through the wl_shm.format event.
+ *
+ * A buffer will keep a reference to the pool it was created from
+ * so it is valid to destroy the pool immediately after creating
+ * a buffer from it.
+ */
+static inline struct wl_buffer *
+wl_shm_pool_create_buffer(struct wl_shm_pool *wl_shm_pool, int32_t offset, int32_t width, int32_t height, int32_t stride, uint32_t format)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_CREATE_BUFFER, &wl_buffer_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, NULL, offset, width, height, stride, format);
+
+	return (struct wl_buffer *) id;
+}
+
+/**
+ * @ingroup iface_wl_shm_pool
+ *
+ * Destroy the shared memory pool.
+ *
+ * The mmapped memory will be released when all
+ * buffers that have been created from this pool
+ * are gone.
+ */
+static inline void
+wl_shm_pool_destroy(struct wl_shm_pool *wl_shm_pool)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wl_shm_pool
+ *
+ * This request will cause the server to remap the backing memory
+ * for the pool from the file descriptor passed when the pool was
+ * created, but using the new size.  This request can only be
+ * used to make the pool bigger.
+ */
+static inline void
+wl_shm_pool_resize(struct wl_shm_pool *wl_shm_pool, int32_t size)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shm_pool,
+			 WL_SHM_POOL_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shm_pool), 0, size);
+}
+
+#ifndef WL_SHM_ERROR_ENUM
+#define WL_SHM_ERROR_ENUM
+/**
+ * @ingroup iface_wl_shm
+ * wl_shm error values
+ *
+ * These errors can be emitted in response to wl_shm requests.
+ */
+enum wl_shm_error {
+	/**
+	 * buffer format is not known
+	 */
+	WL_SHM_ERROR_INVALID_FORMAT = 0,
+	/**
+	 * invalid size or stride during pool or buffer creation
+	 */
+	WL_SHM_ERROR_INVALID_STRIDE = 1,
+	/**
+	 * mmapping the file descriptor failed
+	 */
+	WL_SHM_ERROR_INVALID_FD = 2,
+};
+#endif /* WL_SHM_ERROR_ENUM */
+
+#ifndef WL_SHM_FORMAT_ENUM
+#define WL_SHM_FORMAT_ENUM
+/**
+ * @ingroup iface_wl_shm
+ * pixel formats
+ *
+ * This describes the memory layout of an individual pixel.
+ *
+ * All renderers should support argb8888 and xrgb8888 but any other
+ * 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.
+ */
+enum wl_shm_format {
+	/**
+	 * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_ARGB8888 = 0,
+	/**
+	 * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_XRGB8888 = 1,
+	/**
+	 * 8-bit color index format, [7:0] C
+	 */
+	WL_SHM_FORMAT_C8 = 0x20203843,
+	/**
+	 * 8-bit RGB format, [7:0] R:G:B 3:3:2
+	 */
+	WL_SHM_FORMAT_RGB332 = 0x38424752,
+	/**
+	 * 8-bit BGR format, [7:0] B:G:R 2:3:3
+	 */
+	WL_SHM_FORMAT_BGR233 = 0x38524742,
+	/**
+	 * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_XRGB4444 = 0x32315258,
+	/**
+	 * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_XBGR4444 = 0x32314258,
+	/**
+	 * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_RGBX4444 = 0x32315852,
+	/**
+	 * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_BGRX4444 = 0x32315842,
+	/**
+	 * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_ARGB4444 = 0x32315241,
+	/**
+	 * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_ABGR4444 = 0x32314241,
+	/**
+	 * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_RGBA4444 = 0x32314152,
+	/**
+	 * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_BGRA4444 = 0x32314142,
+	/**
+	 * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_XRGB1555 = 0x35315258,
+	/**
+	 * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_XBGR1555 = 0x35314258,
+	/**
+	 * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_RGBX5551 = 0x35315852,
+	/**
+	 * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_BGRX5551 = 0x35315842,
+	/**
+	 * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_ARGB1555 = 0x35315241,
+	/**
+	 * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_ABGR1555 = 0x35314241,
+	/**
+	 * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_RGBA5551 = 0x35314152,
+	/**
+	 * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_BGRA5551 = 0x35314142,
+	/**
+	 * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian
+	 */
+	WL_SHM_FORMAT_RGB565 = 0x36314752,
+	/**
+	 * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian
+	 */
+	WL_SHM_FORMAT_BGR565 = 0x36314742,
+	/**
+	 * 24-bit RGB format, [23:0] R:G:B little endian
+	 */
+	WL_SHM_FORMAT_RGB888 = 0x34324752,
+	/**
+	 * 24-bit BGR format, [23:0] B:G:R little endian
+	 */
+	WL_SHM_FORMAT_BGR888 = 0x34324742,
+	/**
+	 * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_XBGR8888 = 0x34324258,
+	/**
+	 * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_RGBX8888 = 0x34325852,
+	/**
+	 * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_BGRX8888 = 0x34325842,
+	/**
+	 * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_ABGR8888 = 0x34324241,
+	/**
+	 * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_RGBA8888 = 0x34324152,
+	/**
+	 * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_BGRA8888 = 0x34324142,
+	/**
+	 * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
+	/**
+	 * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
+	/**
+	 * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
+	/**
+	 * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
+	/**
+	 * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
+	/**
+	 * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
+	/**
+	 * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
+	/**
+	 * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
+	/**
+	 * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_YUYV = 0x56595559,
+	/**
+	 * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_YVYU = 0x55595659,
+	/**
+	 * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_UYVY = 0x59565955,
+	/**
+	 * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_VYUY = 0x59555956,
+	/**
+	 * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_AYUV = 0x56555941,
+	/**
+	 * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane
+	 */
+	WL_SHM_FORMAT_NV12 = 0x3231564e,
+	/**
+	 * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane
+	 */
+	WL_SHM_FORMAT_NV21 = 0x3132564e,
+	/**
+	 * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane
+	 */
+	WL_SHM_FORMAT_NV16 = 0x3631564e,
+	/**
+	 * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane
+	 */
+	WL_SHM_FORMAT_NV61 = 0x3136564e,
+	/**
+	 * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV410 = 0x39565559,
+	/**
+	 * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU410 = 0x39555659,
+	/**
+	 * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV411 = 0x31315559,
+	/**
+	 * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU411 = 0x31315659,
+	/**
+	 * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV420 = 0x32315559,
+	/**
+	 * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU420 = 0x32315659,
+	/**
+	 * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV422 = 0x36315559,
+	/**
+	 * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU422 = 0x36315659,
+	/**
+	 * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV444 = 0x34325559,
+	/**
+	 * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU444 = 0x34325659,
+};
+#endif /* WL_SHM_FORMAT_ENUM */
+
+/**
+ * @ingroup iface_wl_shm
+ * @struct wl_shm_listener
+ */
+struct wl_shm_listener {
+	/**
+	 * pixel format description
+	 *
+	 * Informs the client about a valid pixel format that can be used
+	 * for buffers. Known formats include argb8888 and xrgb8888.
+	 * @param format buffer pixel format
+	 */
+	void (*format)(void *data,
+		       struct wl_shm *wl_shm,
+		       uint32_t format);
+};
+
+/**
+ * @ingroup iface_wl_shm
+ */
+static inline int
+wl_shm_add_listener(struct wl_shm *wl_shm,
+		    const struct wl_shm_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_shm,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SHM_CREATE_POOL 0
+
+/**
+ * @ingroup iface_wl_shm
+ */
+#define WL_SHM_FORMAT_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_shm
+ */
+#define WL_SHM_CREATE_POOL_SINCE_VERSION 1
+
+/** @ingroup iface_wl_shm */
+static inline void
+wl_shm_set_user_data(struct wl_shm *wl_shm, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shm, user_data);
+}
+
+/** @ingroup iface_wl_shm */
+static inline void *
+wl_shm_get_user_data(struct wl_shm *wl_shm)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shm);
+}
+
+static inline uint32_t
+wl_shm_get_version(struct wl_shm *wl_shm)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_shm);
+}
+
+/** @ingroup iface_wl_shm */
+static inline void
+wl_shm_destroy(struct wl_shm *wl_shm)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shm);
+}
+
+/**
+ * @ingroup iface_wl_shm
+ *
+ * Create a new wl_shm_pool object.
+ *
+ * The pool can be used to create shared memory based buffer
+ * objects.  The server will mmap size bytes of the passed file
+ * descriptor, to use as backing memory for the pool.
+ */
+static inline struct wl_shm_pool *
+wl_shm_create_pool(struct wl_shm *wl_shm, int32_t fd, int32_t size)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shm,
+			 WL_SHM_CREATE_POOL, &wl_shm_pool_interface, wl_proxy_get_version((struct wl_proxy *) wl_shm), 0, NULL, fd, size);
+
+	return (struct wl_shm_pool *) id;
+}
+
+/**
+ * @ingroup iface_wl_buffer
+ * @struct wl_buffer_listener
+ */
+struct wl_buffer_listener {
+	/**
+	 * compositor releases buffer
+	 *
+	 * Sent when this wl_buffer is no longer used by the compositor.
+	 * The client is now free to reuse or destroy this buffer and its
+	 * backing storage.
+	 *
+	 * If a client receives a release event before the frame callback
+	 * requested in the same wl_surface.commit that attaches this
+	 * wl_buffer to a surface, then the client is immediately free to
+	 * reuse the buffer and its backing storage, and does not need a
+	 * second buffer for the next surface content update. Typically
+	 * this is possible, when the compositor maintains a copy of the
+	 * wl_surface contents, e.g. as a GL texture. This is an important
+	 * optimization for GL(ES) compositors with wl_shm clients.
+	 */
+	void (*release)(void *data,
+			struct wl_buffer *wl_buffer);
+};
+
+/**
+ * @ingroup iface_wl_buffer
+ */
+static inline int
+wl_buffer_add_listener(struct wl_buffer *wl_buffer,
+		       const struct wl_buffer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_buffer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_BUFFER_DESTROY 0
+
+/**
+ * @ingroup iface_wl_buffer
+ */
+#define WL_BUFFER_RELEASE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_buffer
+ */
+#define WL_BUFFER_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_wl_buffer */
+static inline void
+wl_buffer_set_user_data(struct wl_buffer *wl_buffer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_buffer, user_data);
+}
+
+/** @ingroup iface_wl_buffer */
+static inline void *
+wl_buffer_get_user_data(struct wl_buffer *wl_buffer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_buffer);
+}
+
+static inline uint32_t
+wl_buffer_get_version(struct wl_buffer *wl_buffer)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_buffer);
+}
+
+/**
+ * @ingroup iface_wl_buffer
+ *
+ * Destroy a buffer. If and how you need to release the backing
+ * storage is defined by the buffer factory interface.
+ *
+ * For possible side-effects to a surface, see wl_surface.attach.
+ */
+static inline void
+wl_buffer_destroy(struct wl_buffer *wl_buffer)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_buffer,
+			 WL_BUFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_buffer), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifndef WL_DATA_OFFER_ERROR_ENUM
+#define WL_DATA_OFFER_ERROR_ENUM
+enum wl_data_offer_error {
+	/**
+	 * finish request was called untimely
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_FINISH = 0,
+	/**
+	 * action mask contains invalid values
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1,
+	/**
+	 * action argument has an invalid value
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_ACTION = 2,
+	/**
+	 * offer doesn't accept this request
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_OFFER = 3,
+};
+#endif /* WL_DATA_OFFER_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_data_offer
+ * @struct wl_data_offer_listener
+ */
+struct wl_data_offer_listener {
+	/**
+	 * advertise offered mime type
+	 *
+	 * Sent immediately after creating the wl_data_offer object. One
+	 * event per offered mime type.
+	 * @param mime_type offered mime type
+	 */
+	void (*offer)(void *data,
+		      struct wl_data_offer *wl_data_offer,
+		      const char *mime_type);
+	/**
+	 * notify the source-side available actions
+	 *
+	 * This event indicates the actions offered by the data source.
+	 * It will be sent right after wl_data_device.enter, or anytime the
+	 * source side changes its offered actions through
+	 * wl_data_source.set_actions.
+	 * @param source_actions actions offered by the data source
+	 * @since 3
+	 */
+	void (*source_actions)(void *data,
+			       struct wl_data_offer *wl_data_offer,
+			       uint32_t source_actions);
+	/**
+	 * notify the selected action
+	 *
+	 * This event indicates the action selected by the compositor
+	 * after matching the source/destination side actions. Only one
+	 * action (or none) will be offered here.
+	 *
+	 * This event can be emitted multiple times during the
+	 * drag-and-drop operation in response to destination side action
+	 * changes through wl_data_offer.set_actions.
+	 *
+	 * This event will no longer be emitted after wl_data_device.drop
+	 * happened on the drag-and-drop destination, the client must honor
+	 * the last action received, or the last preferred one set through
+	 * wl_data_offer.set_actions when handling an "ask" action.
+	 *
+	 * Compositors may also change the selected action on the fly,
+	 * mainly in response to keyboard modifier changes during the
+	 * drag-and-drop operation.
+	 *
+	 * The most recent action received is always the valid one. Prior
+	 * to receiving wl_data_device.drop, the chosen action may change
+	 * (e.g. due to keyboard modifiers being pressed). At the time of
+	 * receiving wl_data_device.drop the drag-and-drop destination must
+	 * honor the last action received.
+	 *
+	 * Action changes may still happen after wl_data_device.drop,
+	 * especially on "ask" actions, where the drag-and-drop destination
+	 * may choose another action afterwards. Action changes happening
+	 * at this stage are always the result of inter-client negotiation,
+	 * the compositor shall no longer be able to induce a different
+	 * action.
+	 *
+	 * Upon "ask" actions, it is expected that the drag-and-drop
+	 * destination may potentially choose a different action and/or
+	 * mime type, based on wl_data_offer.source_actions and finally
+	 * chosen by the user (e.g. popping up a menu with the available
+	 * options). The final wl_data_offer.set_actions and
+	 * wl_data_offer.accept requests must happen before the call to
+	 * wl_data_offer.finish.
+	 * @param dnd_action action selected by the compositor
+	 * @since 3
+	 */
+	void (*action)(void *data,
+		       struct wl_data_offer *wl_data_offer,
+		       uint32_t dnd_action);
+};
+
+/**
+ * @ingroup iface_wl_data_offer
+ */
+static inline int
+wl_data_offer_add_listener(struct wl_data_offer *wl_data_offer,
+			   const struct wl_data_offer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_offer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_OFFER_ACCEPT 0
+#define WL_DATA_OFFER_RECEIVE 1
+#define WL_DATA_OFFER_DESTROY 2
+#define WL_DATA_OFFER_FINISH 3
+#define WL_DATA_OFFER_SET_ACTIONS 4
+
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_OFFER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_ACTION_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_FINISH_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3
+
+/** @ingroup iface_wl_data_offer */
+static inline void
+wl_data_offer_set_user_data(struct wl_data_offer *wl_data_offer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_offer, user_data);
+}
+
+/** @ingroup iface_wl_data_offer */
+static inline void *
+wl_data_offer_get_user_data(struct wl_data_offer *wl_data_offer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_offer);
+}
+
+static inline uint32_t
+wl_data_offer_get_version(struct wl_data_offer *wl_data_offer)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_data_offer);
+}
+
+/**
+ * @ingroup iface_wl_data_offer
+ *
+ * Indicate that the client can accept the given mime type, or
+ * NULL for not accepted.
+ *
+ * For objects of version 2 or older, this request is used by the
+ * client to give feedback whether the client can receive the given
+ * mime type, or NULL if none is accepted; the feedback does not
+ * determine whether the drag-and-drop operation succeeds or not.
+ *
+ * For objects of version 3 or newer, this request determines the
+ * final result of the drag-and-drop operation. If the end result
+ * is that no mime types were accepted, the drag-and-drop operation
+ * will be cancelled and the corresponding drag source will receive
+ * wl_data_source.cancelled. Clients may still use this event in
+ * conjunction with wl_data_source.action for feedback.
+ */
+static inline void
+wl_data_offer_accept(struct wl_data_offer *wl_data_offer, uint32_t serial, const char *mime_type)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_ACCEPT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, serial, mime_type);
+}
+
+/**
+ * @ingroup iface_wl_data_offer
+ *
+ * To transfer the offered data, the client issues this request
+ * and indicates the mime type it wants to receive.  The transfer
+ * happens through the passed file descriptor (typically created
+ * with the pipe system call).  The source client writes the data
+ * in the mime type representation requested and then closes the
+ * file descriptor.
+ *
+ * The receiving client reads from the read end of the pipe until
+ * EOF and then closes its end, at which point the transfer is
+ * complete.
+ *
+ * This request may happen multiple times for different mime types,
+ * both before and after wl_data_device.drop. Drag-and-drop destination
+ * clients may preemptively fetch data or examine it more closely to
+ * determine acceptance.
+ */
+static inline void
+wl_data_offer_receive(struct wl_data_offer *wl_data_offer, const char *mime_type, int32_t fd)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_RECEIVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, mime_type, fd);
+}
+
+/**
+ * @ingroup iface_wl_data_offer
+ *
+ * Destroy the data offer.
+ */
+static inline void
+wl_data_offer_destroy(struct wl_data_offer *wl_data_offer)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wl_data_offer
+ *
+ * Notifies the compositor that the drag destination successfully
+ * finished the drag-and-drop operation.
+ *
+ * Upon receiving this request, the compositor will emit
+ * wl_data_source.dnd_finished on the drag source client.
+ *
+ * It is a client error to perform other requests than
+ * wl_data_offer.destroy after this one. It is also an error to perform
+ * 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.
+ */
+static inline void
+wl_data_offer_finish(struct wl_data_offer *wl_data_offer)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_FINISH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0);
+}
+
+/**
+ * @ingroup iface_wl_data_offer
+ *
+ * Sets the actions that the destination side client supports for
+ * this operation. This request may trigger the emission of
+ * wl_data_source.action and wl_data_offer.action events if the compositor
+ * needs to change the selected action.
+ *
+ * This request can be called multiple times throughout the
+ * drag-and-drop operation, typically in response to wl_data_device.enter
+ * or wl_data_device.motion events.
+ *
+ * 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 dnd_actions argument must contain only values expressed in the
+ * wl_data_device_manager.dnd_actions enum, and the preferred_action
+ * argument must only contain one of those values set, otherwise it
+ * will result in a protocol error.
+ *
+ * While managing an "ask" action, the destination drag-and-drop client
+ * may perform further wl_data_offer.receive requests, and is expected
+ * to perform one last wl_data_offer.set_actions request with a preferred
+ * action other than "ask" (and optionally wl_data_offer.accept) before
+ * requesting wl_data_offer.finish, in order to convey the action selected
+ * by the user. If the preferred action is not in the
+ * wl_data_offer.source_actions mask, an error will be raised.
+ *
+ * If the "ask" action is dismissed (e.g. user cancellation), the client
+ * is expected to perform wl_data_offer.destroy right away.
+ *
+ * This request can only be made on drag-and-drop offers, a protocol error
+ * will be raised otherwise.
+ */
+static inline void
+wl_data_offer_set_actions(struct wl_data_offer *wl_data_offer, uint32_t dnd_actions, uint32_t preferred_action)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_offer,
+			 WL_DATA_OFFER_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_offer), 0, dnd_actions, preferred_action);
+}
+
+#ifndef WL_DATA_SOURCE_ERROR_ENUM
+#define WL_DATA_SOURCE_ERROR_ENUM
+enum wl_data_source_error {
+	/**
+	 * action mask contains invalid values
+	 */
+	WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0,
+	/**
+	 * source doesn't accept this request
+	 */
+	WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1,
+};
+#endif /* WL_DATA_SOURCE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_data_source
+ * @struct wl_data_source_listener
+ */
+struct wl_data_source_listener {
+	/**
+	 * a target accepts an offered mime type
+	 *
+	 * Sent when a target accepts pointer_focus or motion events. If
+	 * a target does not accept any of the offered types, type is NULL.
+	 *
+	 * Used for feedback during drag-and-drop.
+	 * @param mime_type mime type accepted by the target
+	 */
+	void (*target)(void *data,
+		       struct wl_data_source *wl_data_source,
+		       const char *mime_type);
+	/**
+	 * send the data
+	 *
+	 * Request for data from the client. Send the data as the
+	 * specified mime type over the passed file descriptor, then close
+	 * it.
+	 * @param mime_type mime type for the data
+	 * @param fd file descriptor for the data
+	 */
+	void (*send)(void *data,
+		     struct wl_data_source *wl_data_source,
+		     const char *mime_type,
+		     int32_t fd);
+	/**
+	 * selection was cancelled
+	 *
+	 * This data source is no longer valid. There are several reasons
+	 * why this could happen:
+	 *
+	 * - The data source has been replaced by another data source. -
+	 * The drag-and-drop operation was performed, but the drop
+	 * destination did not accept any of the mime types offered through
+	 * wl_data_source.target. - The drag-and-drop operation was
+	 * performed, but the drop destination did not select any of the
+	 * actions present in the mask offered through
+	 * wl_data_source.action. - The drag-and-drop operation was
+	 * performed but didn't happen over a surface. - The compositor
+	 * cancelled the drag-and-drop operation (e.g. compositor dependent
+	 * timeouts to avoid stale drag-and-drop transfers).
+	 *
+	 * The client should clean up and destroy this data source.
+	 *
+	 * For objects of version 2 or older, wl_data_source.cancelled will
+	 * only be emitted if the data source was replaced by another data
+	 * source.
+	 */
+	void (*cancelled)(void *data,
+			  struct wl_data_source *wl_data_source);
+	/**
+	 * the drag-and-drop operation physically finished
+	 *
+	 * The user performed the drop action. This event does not
+	 * indicate acceptance, wl_data_source.cancelled may still be
+	 * emitted afterwards if the drop destination does not accept any
+	 * mime type.
+	 *
+	 * However, this event might however not be received if the
+	 * compositor cancelled the drag-and-drop operation before this
+	 * event could happen.
+	 *
+	 * Note that the data_source may still be used in the future and
+	 * should not be destroyed here.
+	 * @since 3
+	 */
+	void (*dnd_drop_performed)(void *data,
+				   struct wl_data_source *wl_data_source);
+	/**
+	 * the drag-and-drop operation concluded
+	 *
+	 * The drop destination finished interoperating with this data
+	 * source, so the client is now free to destroy this data source
+	 * and free all associated data.
+	 *
+	 * If the action used to perform the operation was "move", the
+	 * source can now delete the transferred data.
+	 * @since 3
+	 */
+	void (*dnd_finished)(void *data,
+			     struct wl_data_source *wl_data_source);
+	/**
+	 * notify the selected action
+	 *
+	 * This event indicates the action selected by the compositor
+	 * after matching the source/destination side actions. Only one
+	 * action (or none) will be offered here.
+	 *
+	 * This event can be emitted multiple times during the
+	 * drag-and-drop operation, mainly in response to destination side
+	 * changes through wl_data_offer.set_actions, and as the data
+	 * device enters/leaves surfaces.
+	 *
+	 * It is only possible to receive this event after
+	 * wl_data_source.dnd_drop_performed if the drag-and-drop operation
+	 * ended in an "ask" action, in which case the final
+	 * wl_data_source.action event will happen immediately before
+	 * wl_data_source.dnd_finished.
+	 *
+	 * Compositors may also change the selected action on the fly,
+	 * mainly in response to keyboard modifier changes during the
+	 * drag-and-drop operation.
+	 *
+	 * The most recent action received is always the valid one. The
+	 * chosen action may change alongside negotiation (e.g. an "ask"
+	 * action can turn into a "move" operation), so the effects of the
+	 * final action must always be applied in
+	 * wl_data_offer.dnd_finished.
+	 *
+	 * Clients can trigger cursor surface changes from this point, so
+	 * they reflect the current action.
+	 * @param dnd_action action selected by the compositor
+	 * @since 3
+	 */
+	void (*action)(void *data,
+		       struct wl_data_source *wl_data_source,
+		       uint32_t dnd_action);
+};
+
+/**
+ * @ingroup iface_wl_data_source
+ */
+static inline int
+wl_data_source_add_listener(struct wl_data_source *wl_data_source,
+			    const struct wl_data_source_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_source,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_SOURCE_OFFER 0
+#define WL_DATA_SOURCE_DESTROY 1
+#define WL_DATA_SOURCE_SET_ACTIONS 2
+
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_SEND_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3
+
+/** @ingroup iface_wl_data_source */
+static inline void
+wl_data_source_set_user_data(struct wl_data_source *wl_data_source, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_source, user_data);
+}
+
+/** @ingroup iface_wl_data_source */
+static inline void *
+wl_data_source_get_user_data(struct wl_data_source *wl_data_source)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_source);
+}
+
+static inline uint32_t
+wl_data_source_get_version(struct wl_data_source *wl_data_source)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_data_source);
+}
+
+/**
+ * @ingroup iface_wl_data_source
+ *
+ * This request adds a mime type to the set of mime types
+ * advertised to targets.  Can be called several times to offer
+ * multiple types.
+ */
+static inline void
+wl_data_source_offer(struct wl_data_source *wl_data_source, const char *mime_type)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
+			 WL_DATA_SOURCE_OFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, mime_type);
+}
+
+/**
+ * @ingroup iface_wl_data_source
+ *
+ * Destroy the data source.
+ */
+static inline void
+wl_data_source_destroy(struct wl_data_source *wl_data_source)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
+			 WL_DATA_SOURCE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wl_data_source
+ *
+ * Sets the actions that the source side client supports for this
+ * operation. This request may trigger wl_data_source.action and
+ * wl_data_offer.action events if the compositor needs to change the
+ * selected action.
+ *
+ * The dnd_actions argument must contain only values expressed in the
+ * wl_data_device_manager.dnd_actions enum, otherwise it will result
+ * in a protocol error.
+ *
+ * This request must be made once only, and can only be made on sources
+ * used in drag-and-drop, so it must be performed before
+ * wl_data_device.start_drag. Attempting to use the source other than
+ * for drag-and-drop will raise a protocol error.
+ */
+static inline void
+wl_data_source_set_actions(struct wl_data_source *wl_data_source, uint32_t dnd_actions)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_source,
+			 WL_DATA_SOURCE_SET_ACTIONS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_source), 0, dnd_actions);
+}
+
+#ifndef WL_DATA_DEVICE_ERROR_ENUM
+#define WL_DATA_DEVICE_ERROR_ENUM
+enum wl_data_device_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_DATA_DEVICE_ERROR_ROLE = 0,
+};
+#endif /* WL_DATA_DEVICE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_data_device
+ * @struct wl_data_device_listener
+ */
+struct wl_data_device_listener {
+	/**
+	 * introduce a new wl_data_offer
+	 *
+	 * The data_offer event introduces a new wl_data_offer object,
+	 * which will subsequently be used in either the data_device.enter
+	 * event (for drag-and-drop) or the data_device.selection event
+	 * (for selections). Immediately following the
+	 * data_device.data_offer event, the new data_offer object will
+	 * send out data_offer.offer events to describe the mime types it
+	 * offers.
+	 * @param id the new data_offer object
+	 */
+	void (*data_offer)(void *data,
+			   struct wl_data_device *wl_data_device,
+			   struct wl_data_offer *id);
+	/**
+	 * initiate drag-and-drop session
+	 *
+	 * This event is sent when an active drag-and-drop pointer enters
+	 * a surface owned by the client. The position of the pointer at
+	 * enter time is provided by the x and y arguments, in
+	 * surface-local coordinates.
+	 * @param serial serial number of the enter event
+	 * @param surface client surface entered
+	 * @param x surface-local x coordinate
+	 * @param y surface-local y coordinate
+	 * @param id source data_offer object
+	 */
+	void (*enter)(void *data,
+		      struct wl_data_device *wl_data_device,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      wl_fixed_t x,
+		      wl_fixed_t y,
+		      struct wl_data_offer *id);
+	/**
+	 * end drag-and-drop session
+	 *
+	 * This event is sent when the drag-and-drop pointer leaves the
+	 * surface and the session ends. The client must destroy the
+	 * wl_data_offer introduced at enter time at this point.
+	 */
+	void (*leave)(void *data,
+		      struct wl_data_device *wl_data_device);
+	/**
+	 * drag-and-drop session motion
+	 *
+	 * This event is sent when the drag-and-drop pointer moves within
+	 * the currently focused surface. The new position of the pointer
+	 * is provided by the x and y arguments, in surface-local
+	 * coordinates.
+	 * @param time timestamp with millisecond granularity
+	 * @param x surface-local x coordinate
+	 * @param y surface-local y coordinate
+	 */
+	void (*motion)(void *data,
+		       struct wl_data_device *wl_data_device,
+		       uint32_t time,
+		       wl_fixed_t x,
+		       wl_fixed_t y);
+	/**
+	 * end drag-and-drop session successfully
+	 *
+	 * The event is sent when a drag-and-drop operation is ended
+	 * because the implicit grab is removed.
+	 *
+	 * The drag-and-drop destination is expected to honor the last
+	 * action received through wl_data_offer.action, if the resulting
+	 * action is "copy" or "move", the destination can still perform
+	 * wl_data_offer.receive requests, and is expected to end all
+	 * transfers with a wl_data_offer.finish request.
+	 *
+	 * If the resulting action is "ask", the action will not be
+	 * considered final. The drag-and-drop destination is expected to
+	 * perform one last wl_data_offer.set_actions request, or
+	 * wl_data_offer.destroy in order to cancel the operation.
+	 */
+	void (*drop)(void *data,
+		     struct wl_data_device *wl_data_device);
+	/**
+	 * advertise new selection
+	 *
+	 * The selection event is sent out to notify the client of a new
+	 * wl_data_offer for the selection for this device. The
+	 * data_device.data_offer and the data_offer.offer events are sent
+	 * out immediately before this event to introduce the data offer
+	 * object. The selection event is sent to a client immediately
+	 * before receiving keyboard focus and when a new selection is set
+	 * while the client has keyboard focus. The data_offer is valid
+	 * until a new data_offer or NULL is received or until the client
+	 * loses keyboard focus. The client must destroy the previous
+	 * selection data_offer, if any, upon receiving this event.
+	 * @param id selection data_offer object
+	 */
+	void (*selection)(void *data,
+			  struct wl_data_device *wl_data_device,
+			  struct wl_data_offer *id);
+};
+
+/**
+ * @ingroup iface_wl_data_device
+ */
+static inline int
+wl_data_device_add_listener(struct wl_data_device *wl_data_device,
+			    const struct wl_data_device_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_data_device,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_DATA_DEVICE_START_DRAG 0
+#define WL_DATA_DEVICE_SET_SELECTION 1
+#define WL_DATA_DEVICE_RELEASE 2
+
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_DROP_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2
+
+/** @ingroup iface_wl_data_device */
+static inline void
+wl_data_device_set_user_data(struct wl_data_device *wl_data_device, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_device, user_data);
+}
+
+/** @ingroup iface_wl_data_device */
+static inline void *
+wl_data_device_get_user_data(struct wl_data_device *wl_data_device)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device);
+}
+
+static inline uint32_t
+wl_data_device_get_version(struct wl_data_device *wl_data_device)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_data_device);
+}
+
+/** @ingroup iface_wl_data_device */
+static inline void
+wl_data_device_destroy(struct wl_data_device *wl_data_device)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_data_device);
+}
+
+/**
+ * @ingroup iface_wl_data_device
+ *
+ * This request asks the compositor to start a drag-and-drop
+ * operation on behalf of the client.
+ *
+ * The source argument is the data source that provides the data
+ * 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.
+ *
+ * The origin surface is the surface where the drag originates and
+ * the client must have an active implicit grab that matches the
+ * serial.
+ *
+ * The icon surface is an optional (can be NULL) surface that
+ * provides an icon to be moved around with the cursor.  Initially,
+ * the top-left corner of the icon surface is placed at the cursor
+ * hotspot, but subsequent wl_surface.attach request can move the
+ * relative position. Attach requests must be confirmed with
+ * wl_surface.commit as usual. The icon surface is given the role of
+ * a drag-and-drop icon. If the icon surface already has another role,
+ * it raises a protocol error.
+ *
+ * The current and pending input regions of the icon wl_surface are
+ * cleared, and wl_surface.set_input_region is ignored until the
+ * wl_surface is no longer used as the icon surface. When the use
+ * as an icon ends, the current and pending input regions become
+ * undefined, and the wl_surface is unmapped.
+ */
+static inline void
+wl_data_device_start_drag(struct wl_data_device *wl_data_device, struct wl_data_source *source, struct wl_surface *origin, struct wl_surface *icon, uint32_t serial)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_START_DRAG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, origin, icon, serial);
+}
+
+/**
+ * @ingroup iface_wl_data_device
+ *
+ * This request asks the compositor to set the selection
+ * to the data from the source on behalf of the client.
+ *
+ * To unset the selection, set the source to NULL.
+ */
+static inline void
+wl_data_device_set_selection(struct wl_data_device *wl_data_device, struct wl_data_source *source, uint32_t serial)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_SET_SELECTION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), 0, source, serial);
+}
+
+/**
+ * @ingroup iface_wl_data_device
+ *
+ * This request destroys the data device.
+ */
+static inline void
+wl_data_device_release(struct wl_data_device *wl_data_device)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device,
+			 WL_DATA_DEVICE_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_data_device), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
+#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
+/**
+ * @ingroup iface_wl_data_device_manager
+ * drag and drop actions
+ *
+ * This is a bitmask of the available/preferred actions in a
+ * drag-and-drop operation.
+ *
+ * In the compositor, the selected action is a result of matching the
+ * actions offered by the source and destination sides.  "action" events
+ * with a "none" action will be sent to both source and destination if
+ * there is no match. All further checks will effectively happen on
+ * (source actions ∩ destination actions).
+ *
+ * In addition, compositors may also pick different actions in
+ * reaction to key modifiers being pressed. One common design that
+ * is used in major toolkits (and the behavior recommended for
+ * compositors) is:
+ *
+ * - If no modifiers are pressed, the first match (in bit order)
+ * will be used.
+ * - Pressing Shift selects "move", if enabled in the mask.
+ * - Pressing Control selects "copy", if enabled in the mask.
+ *
+ * Behavior beyond that is considered implementation-dependent.
+ * Compositors may for example bind other modifiers (like Alt/Meta)
+ * or drags initiated with other buttons than BTN_LEFT to specific
+ * actions (e.g. "ask").
+ */
+enum wl_data_device_manager_dnd_action {
+	/**
+	 * no action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0,
+	/**
+	 * copy action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1,
+	/**
+	 * move action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2,
+	/**
+	 * ask action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4,
+};
+#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */
+
+#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE 0
+#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE 1
+
+
+/**
+ * @ingroup iface_wl_data_device_manager
+ */
+#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device_manager
+ */
+#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1
+
+/** @ingroup iface_wl_data_device_manager */
+static inline void
+wl_data_device_manager_set_user_data(struct wl_data_device_manager *wl_data_device_manager, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_data_device_manager, user_data);
+}
+
+/** @ingroup iface_wl_data_device_manager */
+static inline void *
+wl_data_device_manager_get_user_data(struct wl_data_device_manager *wl_data_device_manager)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_data_device_manager);
+}
+
+static inline uint32_t
+wl_data_device_manager_get_version(struct wl_data_device_manager *wl_data_device_manager)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager);
+}
+
+/** @ingroup iface_wl_data_device_manager */
+static inline void
+wl_data_device_manager_destroy(struct wl_data_device_manager *wl_data_device_manager)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_data_device_manager);
+}
+
+/**
+ * @ingroup iface_wl_data_device_manager
+ *
+ * Create a new data source.
+ */
+static inline struct wl_data_source *
+wl_data_device_manager_create_data_source(struct wl_data_device_manager *wl_data_device_manager)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager,
+			 WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE, &wl_data_source_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL);
+
+	return (struct wl_data_source *) id;
+}
+
+/**
+ * @ingroup iface_wl_data_device_manager
+ *
+ * Create a new data device for a given seat.
+ */
+static inline struct wl_data_device *
+wl_data_device_manager_get_data_device(struct wl_data_device_manager *wl_data_device_manager, struct wl_seat *seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_data_device_manager,
+			 WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE, &wl_data_device_interface, wl_proxy_get_version((struct wl_proxy *) wl_data_device_manager), 0, NULL, seat);
+
+	return (struct wl_data_device *) id;
+}
+
+#ifndef WL_SHELL_ERROR_ENUM
+#define WL_SHELL_ERROR_ENUM
+enum wl_shell_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_SHELL_ERROR_ROLE = 0,
+};
+#endif /* WL_SHELL_ERROR_ENUM */
+
+#define WL_SHELL_GET_SHELL_SURFACE 0
+
+
+/**
+ * @ingroup iface_wl_shell
+ */
+#define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1
+
+/** @ingroup iface_wl_shell */
+static inline void
+wl_shell_set_user_data(struct wl_shell *wl_shell, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shell, user_data);
+}
+
+/** @ingroup iface_wl_shell */
+static inline void *
+wl_shell_get_user_data(struct wl_shell *wl_shell)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shell);
+}
+
+static inline uint32_t
+wl_shell_get_version(struct wl_shell *wl_shell)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_shell);
+}
+
+/** @ingroup iface_wl_shell */
+static inline void
+wl_shell_destroy(struct wl_shell *wl_shell)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shell);
+}
+
+/**
+ * @ingroup iface_wl_shell
+ *
+ * Create a shell surface for an existing surface. This gives
+ * the wl_surface the role of a shell surface. If the wl_surface
+ * already has another role, it raises a protocol error.
+ *
+ * Only one shell surface can be associated with a given surface.
+ */
+static inline struct wl_shell_surface *
+wl_shell_get_shell_surface(struct wl_shell *wl_shell, struct wl_surface *surface)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_shell,
+			 WL_SHELL_GET_SHELL_SURFACE, &wl_shell_surface_interface, wl_proxy_get_version((struct wl_proxy *) wl_shell), 0, NULL, surface);
+
+	return (struct wl_shell_surface *) id;
+}
+
+#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
+#define WL_SHELL_SURFACE_RESIZE_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * edge values for resizing
+ *
+ * These values are used to indicate which edge of a surface
+ * is being dragged in a resize operation. The server may
+ * use this information to adapt its behavior, e.g. choose
+ * an appropriate cursor image.
+ */
+enum wl_shell_surface_resize {
+	/**
+	 * no edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_NONE = 0,
+	/**
+	 * top edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP = 1,
+	/**
+	 * bottom edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
+	/**
+	 * left edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_LEFT = 4,
+	/**
+	 * top and left edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
+	/**
+	 * bottom and left edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
+	/**
+	 * right edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
+	/**
+	 * top and right edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
+	/**
+	 * bottom and right edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
+};
+#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
+
+#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
+#define WL_SHELL_SURFACE_TRANSIENT_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * details of transient behaviour
+ *
+ * These flags specify details of the expected behaviour
+ * of transient surfaces. Used in the set_transient request.
+ */
+enum wl_shell_surface_transient {
+	/**
+	 * do not set keyboard focus
+	 */
+	WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
+};
+#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
+
+#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * different method to set the surface fullscreen
+ *
+ * Hints to indicate to the compositor how to deal with a conflict
+ * between the dimensions of the surface and the dimensions of the
+ * output. The compositor is free to ignore this parameter.
+ */
+enum wl_shell_surface_fullscreen_method {
+	/**
+	 * no preference, apply default policy
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
+	/**
+	 * scale, preserve the surface's aspect ratio and center on output
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
+	/**
+	 * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
+	/**
+	 * no upscaling, center on output and add black borders to compensate size mismatch
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
+};
+#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
+
+/**
+ * @ingroup iface_wl_shell_surface
+ * @struct wl_shell_surface_listener
+ */
+struct wl_shell_surface_listener {
+	/**
+	 * ping client
+	 *
+	 * Ping a client to check if it is receiving events and sending
+	 * requests. A client is expected to reply with a pong request.
+	 * @param serial serial number of the ping
+	 */
+	void (*ping)(void *data,
+		     struct wl_shell_surface *wl_shell_surface,
+		     uint32_t serial);
+	/**
+	 * suggest resize
+	 *
+	 * The configure event asks the client to resize its surface.
+	 *
+	 * The size is a hint, in the sense that the client is free to
+	 * ignore it if it doesn't resize, pick a smaller size (to satisfy
+	 * aspect ratio or resize in steps of NxM pixels).
+	 *
+	 * The edges parameter provides a hint about how the surface was
+	 * resized. The client may use this information to decide how to
+	 * adjust its content to the new size (e.g. a scrolling area might
+	 * adjust its content position to leave the viewable content
+	 * unmoved).
+	 *
+	 * The client is free to dismiss all but the last configure event
+	 * it received.
+	 *
+	 * The width and height arguments specify the size of the window in
+	 * surface-local coordinates.
+	 * @param edges how the surface was resized
+	 * @param width new width of the surface
+	 * @param height new height of the surface
+	 */
+	void (*configure)(void *data,
+			  struct wl_shell_surface *wl_shell_surface,
+			  uint32_t edges,
+			  int32_t width,
+			  int32_t height);
+	/**
+	 * popup interaction is done
+	 *
+	 * The popup_done event is sent out when a popup grab is broken,
+	 * that is, when the user clicks a surface that doesn't belong to
+	 * the client owning the popup surface.
+	 */
+	void (*popup_done)(void *data,
+			   struct wl_shell_surface *wl_shell_surface);
+};
+
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+static inline int
+wl_shell_surface_add_listener(struct wl_shell_surface *wl_shell_surface,
+			      const struct wl_shell_surface_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_shell_surface,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SHELL_SURFACE_PONG 0
+#define WL_SHELL_SURFACE_MOVE 1
+#define WL_SHELL_SURFACE_RESIZE 2
+#define WL_SHELL_SURFACE_SET_TOPLEVEL 3
+#define WL_SHELL_SURFACE_SET_TRANSIENT 4
+#define WL_SHELL_SURFACE_SET_FULLSCREEN 5
+#define WL_SHELL_SURFACE_SET_POPUP 6
+#define WL_SHELL_SURFACE_SET_MAXIMIZED 7
+#define WL_SHELL_SURFACE_SET_TITLE 8
+#define WL_SHELL_SURFACE_SET_CLASS 9
+
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_PING_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1
+
+/** @ingroup iface_wl_shell_surface */
+static inline void
+wl_shell_surface_set_user_data(struct wl_shell_surface *wl_shell_surface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_shell_surface, user_data);
+}
+
+/** @ingroup iface_wl_shell_surface */
+static inline void *
+wl_shell_surface_get_user_data(struct wl_shell_surface *wl_shell_surface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_shell_surface);
+}
+
+static inline uint32_t
+wl_shell_surface_get_version(struct wl_shell_surface *wl_shell_surface)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_shell_surface);
+}
+
+/** @ingroup iface_wl_shell_surface */
+static inline void
+wl_shell_surface_destroy(struct wl_shell_surface *wl_shell_surface)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_shell_surface);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * A client must respond to a ping event with a pong request or
+ * the client may be deemed unresponsive.
+ */
+static inline void
+wl_shell_surface_pong(struct wl_shell_surface *wl_shell_surface, uint32_t serial)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_PONG, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, serial);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Start a pointer-driven move of the surface.
+ *
+ * This request must be used in response to a button press event.
+ * The server may ignore move requests depending on the state of
+ * the surface (e.g. fullscreen or maximized).
+ */
+static inline void
+wl_shell_surface_move(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_MOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Start a pointer-driven resizing of the surface.
+ *
+ * This request must be used in response to a button press event.
+ * The server may ignore resize requests depending on the state of
+ * the surface (e.g. fullscreen or maximized).
+ */
+static inline void
+wl_shell_surface_resize(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, uint32_t edges)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_RESIZE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, edges);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Map the surface as a toplevel surface.
+ *
+ * A toplevel surface is not fullscreen, maximized or transient.
+ */
+static inline void
+wl_shell_surface_set_toplevel(struct wl_shell_surface *wl_shell_surface)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TOPLEVEL, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Map the surface relative to an existing surface.
+ *
+ * The x and y arguments specify the location of the upper left
+ * corner of the surface relative to the upper left corner of the
+ * parent surface, in surface-local coordinates.
+ *
+ * The flags argument controls details of the transient behaviour.
+ */
+static inline void
+wl_shell_surface_set_transient(struct wl_shell_surface *wl_shell_surface, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TRANSIENT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, parent, x, y, flags);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Map the surface as a fullscreen surface.
+ *
+ * If an output parameter is given then the surface will be made
+ * fullscreen on that output. If the client does not specify the
+ * output then the compositor will apply its policy - usually
+ * choosing the output on which the surface has the biggest surface
+ * area.
+ *
+ * The client may specify a method to resolve a size conflict
+ * between the output size and the surface size - this is provided
+ * through the method parameter.
+ *
+ * The framerate parameter is used only when the method is set
+ * to "driver", to indicate the preferred framerate. A value of 0
+ * indicates that the client does not care about framerate.  The
+ * framerate is specified in mHz, that is framerate of 60000 is 60Hz.
+ *
+ * A method of "scale" or "driver" implies a scaling operation of
+ * the surface, either via a direct scaling operation or a change of
+ * the output mode. This will override any kind of output scaling, so
+ * that mapping a surface with a buffer size equal to the mode can
+ * fill the screen independent of buffer_scale.
+ *
+ * A method of "fill" means we don't scale up the buffer, however
+ * any output scale is applied. This means that you may run into
+ * an edge case where the application maps a buffer with the same
+ * size of the output mode but buffer_scale 1 (thus making a
+ * surface larger than the output). In this case it is allowed to
+ * downscale the results to fit the screen.
+ *
+ * The compositor must reply to this request with a configure event
+ * with the dimensions for the output on which the surface will
+ * be made fullscreen.
+ */
+static inline void
+wl_shell_surface_set_fullscreen(struct wl_shell_surface *wl_shell_surface, uint32_t method, uint32_t framerate, struct wl_output *output)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_FULLSCREEN, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, method, framerate, output);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Map the surface as a popup.
+ *
+ * A popup surface is a transient surface with an added pointer
+ * grab.
+ *
+ * An existing implicit grab will be changed to owner-events mode,
+ * and the popup grab will continue after the implicit grab ends
+ * (i.e. releasing the mouse button does not cause the popup to
+ * be unmapped).
+ *
+ * The popup grab continues until the window is destroyed or a
+ * mouse button is pressed in any other client's window. A click
+ * in any of the client's surfaces is reported as normal, however,
+ * clicks in other clients' surfaces will be discarded and trigger
+ * the callback.
+ *
+ * The x and y arguments specify the location of the upper left
+ * corner of the surface relative to the upper left corner of the
+ * parent surface, in surface-local coordinates.
+ */
+static inline void
+wl_shell_surface_set_popup(struct wl_shell_surface *wl_shell_surface, struct wl_seat *seat, uint32_t serial, struct wl_surface *parent, int32_t x, int32_t y, uint32_t flags)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_POPUP, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, seat, serial, parent, x, y, flags);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Map the surface as a maximized surface.
+ *
+ * If an output parameter is given then the surface will be
+ * maximized on that output. If the client does not specify the
+ * output then the compositor will apply its policy - usually
+ * choosing the output on which the surface has the biggest surface
+ * area.
+ *
+ * The compositor will reply with a configure event telling
+ * the expected new surface size. The operation is completed
+ * on the next buffer attach to this surface.
+ *
+ * A maximized surface typically fills the entire output it is
+ * bound to, except for desktop elements such as panels. This is
+ * the main difference between a maximized shell surface and a
+ * fullscreen shell surface.
+ *
+ * The details depend on the compositor implementation.
+ */
+static inline void
+wl_shell_surface_set_maximized(struct wl_shell_surface *wl_shell_surface, struct wl_output *output)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_MAXIMIZED, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, output);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Set a short title for the surface.
+ *
+ * This string may be used to identify the surface in a task bar,
+ * window list, or other user interface elements provided by the
+ * compositor.
+ *
+ * The string must be encoded in UTF-8.
+ */
+static inline void
+wl_shell_surface_set_title(struct wl_shell_surface *wl_shell_surface, const char *title)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_TITLE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, title);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ *
+ * Set a class for the surface.
+ *
+ * The surface class identifies the general class of applications
+ * to which the surface belongs. A common convention is to use the
+ * file name (or the full path if it is a non-standard location) of
+ * the application's .desktop file as the class.
+ */
+static inline void
+wl_shell_surface_set_class(struct wl_shell_surface *wl_shell_surface, const char *class_)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_shell_surface,
+			 WL_SHELL_SURFACE_SET_CLASS, NULL, wl_proxy_get_version((struct wl_proxy *) wl_shell_surface), 0, class_);
+}
+
+#ifndef WL_SURFACE_ERROR_ENUM
+#define WL_SURFACE_ERROR_ENUM
+/**
+ * @ingroup iface_wl_surface
+ * wl_surface error values
+ *
+ * These errors can be emitted in response to wl_surface requests.
+ */
+enum wl_surface_error {
+	/**
+	 * buffer scale value is invalid
+	 */
+	WL_SURFACE_ERROR_INVALID_SCALE = 0,
+	/**
+	 * buffer transform value is invalid
+	 */
+	WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
+};
+#endif /* WL_SURFACE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_surface
+ * @struct wl_surface_listener
+ */
+struct wl_surface_listener {
+	/**
+	 * surface enters an output
+	 *
+	 * This is emitted whenever a surface's creation, movement, or
+	 * resizing results in some part of it being within the scanout
+	 * region of an output.
+	 *
+	 * Note that a surface may be overlapping with zero or more
+	 * outputs.
+	 * @param output output entered by the surface
+	 */
+	void (*enter)(void *data,
+		      struct wl_surface *wl_surface,
+		      struct wl_output *output);
+	/**
+	 * surface leaves an output
+	 *
+	 * 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.
+	 * @param output output left by the surface
+	 */
+	void (*leave)(void *data,
+		      struct wl_surface *wl_surface,
+		      struct wl_output *output);
+};
+
+/**
+ * @ingroup iface_wl_surface
+ */
+static inline int
+wl_surface_add_listener(struct wl_surface *wl_surface,
+			const struct wl_surface_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_surface,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SURFACE_DESTROY 0
+#define WL_SURFACE_ATTACH 1
+#define WL_SURFACE_DAMAGE 2
+#define WL_SURFACE_FRAME 3
+#define WL_SURFACE_SET_OPAQUE_REGION 4
+#define WL_SURFACE_SET_INPUT_REGION 5
+#define WL_SURFACE_COMMIT 6
+#define WL_SURFACE_SET_BUFFER_TRANSFORM 7
+#define WL_SURFACE_SET_BUFFER_SCALE 8
+#define WL_SURFACE_DAMAGE_BUFFER 9
+
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_ENTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_LEAVE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_ATTACH_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_DAMAGE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_FRAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_COMMIT_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4
+
+/** @ingroup iface_wl_surface */
+static inline void
+wl_surface_set_user_data(struct wl_surface *wl_surface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_surface, user_data);
+}
+
+/** @ingroup iface_wl_surface */
+static inline void *
+wl_surface_get_user_data(struct wl_surface *wl_surface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_surface);
+}
+
+static inline uint32_t
+wl_surface_get_version(struct wl_surface *wl_surface)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_surface);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * Deletes the surface and invalidates its object ID.
+ */
+static inline void
+wl_surface_destroy(struct wl_surface *wl_surface)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * Set a buffer as the content of this surface.
+ *
+ * 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.
+ *
+ * The x and y arguments specify the location of the new pending
+ * buffer's upper left corner, relative to the current buffer's upper
+ * left corner, in surface-local coordinates. In other words, the
+ * x and y, combined with the new surface size define in which
+ * directions the surface's size changes.
+ *
+ * Surface contents are double-buffered state, see wl_surface.commit.
+ *
+ * The initial surface contents are void; there is no content.
+ * wl_surface.attach assigns the given wl_buffer as the pending
+ * wl_buffer. wl_surface.commit makes the pending wl_buffer the new
+ * surface contents, and the size of the surface becomes the size
+ * calculated from the wl_buffer, as described above. After commit,
+ * there is no pending buffer until the next attach.
+ *
+ * Committing a pending wl_buffer allows the compositor to read the
+ * pixels in the wl_buffer. The compositor may access the pixels at
+ * any time after the wl_surface.commit request. When the compositor
+ * will not access the pixels anymore, it will send the
+ * wl_buffer.release event. Only after receiving wl_buffer.release,
+ * the client may reuse the wl_buffer. A wl_buffer that has been
+ * attached and then replaced by another attach instead of committed
+ * will not receive a release event, and is not used by the
+ * compositor.
+ *
+ * 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
+ * contents become undefined immediately.
+ *
+ * If wl_surface.attach is sent with a NULL wl_buffer, the
+ * following wl_surface.commit will remove the surface content.
+ */
+static inline void
+wl_surface_attach(struct wl_surface *wl_surface, struct wl_buffer *buffer, int32_t x, int32_t y)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_ATTACH, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, buffer, x, y);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * This request is used to describe the regions where the pending
+ * buffer is different from the current surface contents, and where
+ * the surface therefore needs to be repainted. The compositor
+ * ignores the parts of the damage that fall outside of the surface.
+ *
+ * Damage is double-buffered state, see wl_surface.commit.
+ *
+ * The damage rectangle is specified in surface-local coordinates,
+ * where x and y specify the upper left corner of the damage rectangle.
+ *
+ * The initial value for pending damage is empty: no damage.
+ * wl_surface.damage adds pending damage: the new pending damage
+ * is the union of old pending damage and the given rectangle.
+ *
+ * wl_surface.commit assigns pending damage as the current damage,
+ * and clears pending damage. The server will clear the current
+ * damage as it repaints the surface.
+ *
+ * Alternatively, damage can be posted with wl_surface.damage_buffer
+ * which uses buffer coordinates instead of surface coordinates,
+ * and is probably the preferred and intuitive way of doing this.
+ */
+static inline void
+wl_surface_damage(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_DAMAGE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * Request a notification when it is a good time to start drawing a new
+ * frame, by creating a frame callback. This is useful for throttling
+ * redrawing operations, and driving animations.
+ *
+ * When a client is animating on a wl_surface, it can use the 'frame'
+ * request to get notified when it is a good time to draw and commit the
+ * next frame of animation. If the client commits an update earlier than
+ * that, it is likely that some updates will not make it to the display,
+ * and the client is wasting resources by drawing too often.
+ *
+ * The frame request will take effect on the next wl_surface.commit.
+ * The notification will only be posted for one frame unless
+ * requested again. For a wl_surface, the notifications are posted in
+ * the order the frame requests were committed.
+ *
+ * The server must send the notifications so that a client
+ * will not send excessive updates, while still allowing
+ * the highest possible update rate for clients that wait for the reply
+ * before drawing again. The server should give some time for the client
+ * to draw and commit after sending the frame callback events to let it
+ * hit the next output refresh.
+ *
+ * A server should avoid signaling the frame callbacks if the
+ * surface is not visible in any way, e.g. the surface is off-screen,
+ * or completely obscured by other opaque surfaces.
+ *
+ * The object returned by this request will be destroyed by the
+ * compositor after the callback is fired and as such the client must not
+ * attempt to use it after that point.
+ *
+ * The callback_data passed in the callback is the current time, in
+ * milliseconds, with an undefined base.
+ */
+static inline struct wl_callback *
+wl_surface_frame(struct wl_surface *wl_surface)
+{
+	struct wl_proxy *callback;
+
+	callback = wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_FRAME, &wl_callback_interface, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, NULL);
+
+	return (struct wl_callback *) callback;
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * This request sets the region of the surface that contains
+ * opaque content.
+ *
+ * The opaque region is an optimization hint for the compositor
+ * that lets it optimize the redrawing of content behind opaque
+ * regions.  Setting an opaque region is not required for correct
+ * behaviour, but marking transparent content as opaque will result
+ * in repaint artifacts.
+ *
+ * The opaque region is specified in surface-local coordinates.
+ *
+ * The compositor ignores the parts of the opaque region that fall
+ * outside of the surface.
+ *
+ * Opaque region is double-buffered state, see wl_surface.commit.
+ *
+ * wl_surface.set_opaque_region changes the pending opaque region.
+ * wl_surface.commit copies the pending region to the current region.
+ * Otherwise, the pending and current regions are never changed.
+ *
+ * The initial value for an opaque region is empty. Setting the pending
+ * opaque region has copy semantics, and the wl_region object can be
+ * destroyed immediately. A NULL wl_region causes the pending opaque
+ * region to be set to empty.
+ */
+static inline void
+wl_surface_set_opaque_region(struct wl_surface *wl_surface, struct wl_region *region)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_OPAQUE_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * This request sets the region of the surface that can receive
+ * pointer and touch events.
+ *
+ * Input events happening outside of this region will try the next
+ * surface in the server surface stack. The compositor ignores the
+ * parts of the input region that fall outside of the surface.
+ *
+ * The input region is specified in surface-local coordinates.
+ *
+ * Input region is double-buffered state, see wl_surface.commit.
+ *
+ * wl_surface.set_input_region changes the pending input region.
+ * wl_surface.commit copies the pending region to the current region.
+ * Otherwise the pending and current regions are never changed,
+ * except cursor and icon surfaces are special cases, see
+ * wl_pointer.set_cursor and wl_data_device.start_drag.
+ *
+ * The initial value for an input region is infinite. That means the
+ * whole surface will accept input. Setting the pending input region
+ * has copy semantics, and the wl_region object can be destroyed
+ * immediately. A NULL wl_region causes the input region to be set
+ * to infinite.
+ */
+static inline void
+wl_surface_set_input_region(struct wl_surface *wl_surface, struct wl_region *region)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_INPUT_REGION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, region);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * Surface state (input, opaque, and damage regions, attached buffers,
+ * etc.) is double-buffered. Protocol requests modify the pending state,
+ * as opposed to the current state in use by the compositor. A commit
+ * request atomically applies all pending state, replacing the current
+ * state. After commit, the new pending state is as documented for each
+ * related request.
+ *
+ * On commit, a pending wl_buffer is applied first, and all other state
+ * second. This means that all coordinates in double-buffered state are
+ * relative to the new wl_buffer coming into use, except for
+ * wl_surface.attach itself. If there is no pending wl_buffer, the
+ * coordinates are relative to the current surface contents.
+ *
+ * All requests that need a commit to become effective are documented
+ * to affect double-buffered state.
+ *
+ * Other interfaces may add further double-buffered surface state.
+ */
+static inline void
+wl_surface_commit(struct wl_surface *wl_surface)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_COMMIT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * This request sets an optional transformation on how the compositor
+ * interprets the contents of the buffer attached to the surface. The
+ * accepted values for the transform parameter are the values for
+ * wl_output.transform.
+ *
+ * Buffer transform is double-buffered state, see wl_surface.commit.
+ *
+ * A newly created surface has its buffer transformation set to normal.
+ *
+ * wl_surface.set_buffer_transform changes the pending buffer
+ * transformation. wl_surface.commit copies the pending buffer
+ * transformation to the current one. Otherwise, the pending and current
+ * values are never changed.
+ *
+ * The purpose of this request is to allow clients to render content
+ * according to the output transform, thus permitting the compositor to
+ * use certain optimizations even if the display is rotated. Using
+ * hardware overlays and scanning out a client buffer for fullscreen
+ * surfaces are examples of such optimizations. Those optimizations are
+ * highly dependent on the compositor implementation, so the use of this
+ * request should be considered on a case-by-case basis.
+ *
+ * Note that if the transform value includes 90 or 270 degree rotation,
+ * the width of the buffer will become the surface height and the height
+ * of the buffer will become the surface width.
+ *
+ * If transform is not one of the values from the
+ * wl_output.transform enum the invalid_transform protocol error
+ * is raised.
+ */
+static inline void
+wl_surface_set_buffer_transform(struct wl_surface *wl_surface, int32_t transform)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_BUFFER_TRANSFORM, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, transform);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * This request sets an optional scaling factor on how the compositor
+ * interprets the contents of the buffer attached to the window.
+ *
+ * Buffer scale is double-buffered state, see wl_surface.commit.
+ *
+ * A newly created surface has its buffer scale set to 1.
+ *
+ * wl_surface.set_buffer_scale changes the pending buffer scale.
+ * wl_surface.commit copies the pending buffer scale to the current one.
+ * Otherwise, the pending and current values are never changed.
+ *
+ * The purpose of this request is to allow clients to supply higher
+ * resolution buffer data for use on high resolution outputs. It is
+ * intended that you pick the same buffer scale as the scale of the
+ * output that the surface is displayed on. This means the compositor
+ * can avoid scaling when rendering the surface on that output.
+ *
+ * Note that if the scale is larger than 1, then you have to attach
+ * a buffer that is larger (by a factor of scale in each dimension)
+ * than the desired surface size.
+ *
+ * If scale is not positive the invalid_scale protocol error is
+ * raised.
+ */
+static inline void
+wl_surface_set_buffer_scale(struct wl_surface *wl_surface, int32_t scale)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_SET_BUFFER_SCALE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, scale);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ *
+ * This request is used to describe the regions where the pending
+ * buffer is different from the current surface contents, and where
+ * the surface therefore needs to be repainted. The compositor
+ * ignores the parts of the damage that fall outside of the surface.
+ *
+ * Damage is double-buffered state, see wl_surface.commit.
+ *
+ * The damage rectangle is specified in buffer coordinates,
+ * where x and y specify the upper left corner of the damage rectangle.
+ *
+ * The initial value for pending damage is empty: no damage.
+ * wl_surface.damage_buffer adds pending damage: the new pending
+ * damage is the union of old pending damage and the given rectangle.
+ *
+ * wl_surface.commit assigns pending damage as the current damage,
+ * and clears pending damage. The server will clear the current
+ * damage as it repaints the surface.
+ *
+ * This request differs from wl_surface.damage in only one way - it
+ * takes damage in buffer coordinates instead of surface-local
+ * coordinates. While this generally is more intuitive than surface
+ * coordinates, it is especially desirable when using wp_viewport
+ * or when a drawing library (like EGL) is unaware of buffer scale
+ * and buffer transform.
+ *
+ * Note: Because buffer transformation changes and damage requests may
+ * be interleaved in the protocol stream, it is impossible to determine
+ * the actual mapping between surface and buffer damage until
+ * wl_surface.commit time. Therefore, compositors wishing to take both
+ * kinds of damage into account will have to accumulate damage from the
+ * two requests separately and only transform from one to the other
+ * after receiving the wl_surface.commit.
+ */
+static inline void
+wl_surface_damage_buffer(struct wl_surface *wl_surface, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_surface,
+			 WL_SURFACE_DAMAGE_BUFFER, NULL, wl_proxy_get_version((struct wl_proxy *) wl_surface), 0, x, y, width, height);
+}
+
+#ifndef WL_SEAT_CAPABILITY_ENUM
+#define WL_SEAT_CAPABILITY_ENUM
+/**
+ * @ingroup iface_wl_seat
+ * seat capability bitmask
+ *
+ * This is a bitmask of capabilities this seat has; if a member is
+ * set, then it is present on the seat.
+ */
+enum wl_seat_capability {
+	/**
+	 * the seat has pointer devices
+	 */
+	WL_SEAT_CAPABILITY_POINTER = 1,
+	/**
+	 * the seat has one or more keyboards
+	 */
+	WL_SEAT_CAPABILITY_KEYBOARD = 2,
+	/**
+	 * the seat has touch devices
+	 */
+	WL_SEAT_CAPABILITY_TOUCH = 4,
+};
+#endif /* WL_SEAT_CAPABILITY_ENUM */
+
+/**
+ * @ingroup iface_wl_seat
+ * @struct wl_seat_listener
+ */
+struct wl_seat_listener {
+	/**
+	 * seat capabilities changed
+	 *
+	 * This is emitted whenever a seat gains or loses the pointer,
+	 * keyboard or touch capabilities. The argument is a capability
+	 * enum containing the complete set of capabilities this seat has.
+	 *
+	 * When the pointer capability is added, a client may create a
+	 * wl_pointer object using the wl_seat.get_pointer request. This
+	 * object will receive pointer events until the capability is
+	 * removed in the future.
+	 *
+	 * When the pointer capability is removed, a client should destroy
+	 * the wl_pointer objects associated with the seat where the
+	 * capability was removed, using the wl_pointer.release request. No
+	 * further pointer events will be received on these objects.
+	 *
+	 * In some compositors, if a seat regains the pointer capability
+	 * and a client has a previously obtained wl_pointer object of
+	 * version 4 or less, that object may start sending pointer events
+	 * again. This behavior is considered a misinterpretation of the
+	 * intended behavior and must not be relied upon by the client.
+	 * wl_pointer objects of version 5 or later must not send events if
+	 * created before the most recent event notifying the client of an
+	 * added pointer capability.
+	 *
+	 * The above behavior also applies to wl_keyboard and wl_touch with
+	 * the keyboard and touch capabilities, respectively.
+	 * @param capabilities capabilities of the seat
+	 */
+	void (*capabilities)(void *data,
+			     struct wl_seat *wl_seat,
+			     uint32_t capabilities);
+	/**
+	 * unique identifier for this seat
+	 *
+	 * In a multiseat configuration this can be used by the client to
+	 * help identify which physical devices the seat represents. Based
+	 * on the seat configuration used by the compositor.
+	 * @param name seat identifier
+	 * @since 2
+	 */
+	void (*name)(void *data,
+		     struct wl_seat *wl_seat,
+		     const char *name);
+};
+
+/**
+ * @ingroup iface_wl_seat
+ */
+static inline int
+wl_seat_add_listener(struct wl_seat *wl_seat,
+		     const struct wl_seat_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_seat,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_SEAT_GET_POINTER 0
+#define WL_SEAT_GET_KEYBOARD 1
+#define WL_SEAT_GET_TOUCH 2
+#define WL_SEAT_RELEASE 3
+
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_CAPABILITIES_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_NAME_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_GET_POINTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_GET_TOUCH_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_RELEASE_SINCE_VERSION 5
+
+/** @ingroup iface_wl_seat */
+static inline void
+wl_seat_set_user_data(struct wl_seat *wl_seat, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_seat, user_data);
+}
+
+/** @ingroup iface_wl_seat */
+static inline void *
+wl_seat_get_user_data(struct wl_seat *wl_seat)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_seat);
+}
+
+static inline uint32_t
+wl_seat_get_version(struct wl_seat *wl_seat)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_seat);
+}
+
+/** @ingroup iface_wl_seat */
+static inline void
+wl_seat_destroy(struct wl_seat *wl_seat)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_seat);
+}
+
+/**
+ * @ingroup iface_wl_seat
+ *
+ * The ID provided will be initialized to the wl_pointer interface
+ * for this seat.
+ *
+ * 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.
+ */
+static inline struct wl_pointer *
+wl_seat_get_pointer(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_POINTER, &wl_pointer_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
+
+	return (struct wl_pointer *) id;
+}
+
+/**
+ * @ingroup iface_wl_seat
+ *
+ * The ID provided will be initialized to the wl_keyboard interface
+ * for this seat.
+ *
+ * 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.
+ */
+static inline struct wl_keyboard *
+wl_seat_get_keyboard(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_KEYBOARD, &wl_keyboard_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
+
+	return (struct wl_keyboard *) id;
+}
+
+/**
+ * @ingroup iface_wl_seat
+ *
+ * The ID provided will be initialized to the wl_touch interface
+ * for this seat.
+ *
+ * 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.
+ */
+static inline struct wl_touch *
+wl_seat_get_touch(struct wl_seat *wl_seat)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
+			 WL_SEAT_GET_TOUCH, &wl_touch_interface, wl_proxy_get_version((struct wl_proxy *) wl_seat), 0, NULL);
+
+	return (struct wl_touch *) id;
+}
+
+/**
+ * @ingroup iface_wl_seat
+ *
+ * Using this request a client can tell the server that it is not going to
+ * use the seat object anymore.
+ */
+static inline void
+wl_seat_release(struct wl_seat *wl_seat)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_seat,
+			 WL_SEAT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_seat), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifndef WL_POINTER_ERROR_ENUM
+#define WL_POINTER_ERROR_ENUM
+enum wl_pointer_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_POINTER_ERROR_ROLE = 0,
+};
+#endif /* WL_POINTER_ERROR_ENUM */
+
+#ifndef WL_POINTER_BUTTON_STATE_ENUM
+#define WL_POINTER_BUTTON_STATE_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * physical button state
+ *
+ * Describes the physical state of a button that produced the button
+ * event.
+ */
+enum wl_pointer_button_state {
+	/**
+	 * the button is not pressed
+	 */
+	WL_POINTER_BUTTON_STATE_RELEASED = 0,
+	/**
+	 * the button is pressed
+	 */
+	WL_POINTER_BUTTON_STATE_PRESSED = 1,
+};
+#endif /* WL_POINTER_BUTTON_STATE_ENUM */
+
+#ifndef WL_POINTER_AXIS_ENUM
+#define WL_POINTER_AXIS_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * axis types
+ *
+ * Describes the axis types of scroll events.
+ */
+enum wl_pointer_axis {
+	/**
+	 * vertical axis
+	 */
+	WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
+	/**
+	 * horizontal axis
+	 */
+	WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
+};
+#endif /* WL_POINTER_AXIS_ENUM */
+
+#ifndef WL_POINTER_AXIS_SOURCE_ENUM
+#define WL_POINTER_AXIS_SOURCE_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * axis source types
+ *
+ * Describes the source types for axis events. This indicates to the
+ * client how an axis event was physically generated; a client may
+ * adjust the user interface accordingly. For example, scroll events
+ * from a "finger" source may be in a smooth coordinate space with
+ * kinetic scrolling whereas a "wheel" source may be in discrete steps
+ * of a number of lines.
+ */
+enum wl_pointer_axis_source {
+	/**
+	 * a physical wheel rotation
+	 */
+	WL_POINTER_AXIS_SOURCE_WHEEL = 0,
+	/**
+	 * finger on a touch surface
+	 */
+	WL_POINTER_AXIS_SOURCE_FINGER = 1,
+	/**
+	 * continuous coordinate space
+	 *
+	 * A device generating events in a continuous coordinate space,
+	 * but using something other than a finger. One example for this
+	 * source is button-based scrolling where the vertical motion of a
+	 * device is converted to scroll events while a button is held
+	 * down.
+	 */
+	WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2,
+	/**
+	 * a physical wheel tilt
+	 *
+	 * Indicates that the actual device is a wheel but the scroll
+	 * event is not caused by a rotation but a (usually sideways) tilt
+	 * of the wheel.
+	 * @since 6
+	 */
+	WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3,
+};
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6
+#endif /* WL_POINTER_AXIS_SOURCE_ENUM */
+
+/**
+ * @ingroup iface_wl_pointer
+ * @struct wl_pointer_listener
+ */
+struct wl_pointer_listener {
+	/**
+	 * enter event
+	 *
+	 * Notification that this seat's pointer is focused on a certain
+	 * surface.
+	 *
+	 * When a seat's focus enters a surface, the pointer image is
+	 * undefined and a client should respond to this event by setting
+	 * an appropriate pointer image with the set_cursor request.
+	 * @param serial serial number of the enter event
+	 * @param surface surface entered by the pointer
+	 * @param surface_x surface-local x coordinate
+	 * @param surface_y surface-local y coordinate
+	 */
+	void (*enter)(void *data,
+		      struct wl_pointer *wl_pointer,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      wl_fixed_t surface_x,
+		      wl_fixed_t surface_y);
+	/**
+	 * leave event
+	 *
+	 * Notification that this seat's pointer is no longer focused on
+	 * a certain surface.
+	 *
+	 * The leave notification is sent before the enter notification for
+	 * the new focus.
+	 * @param serial serial number of the leave event
+	 * @param surface surface left by the pointer
+	 */
+	void (*leave)(void *data,
+		      struct wl_pointer *wl_pointer,
+		      uint32_t serial,
+		      struct wl_surface *surface);
+	/**
+	 * pointer motion event
+	 *
+	 * Notification of pointer location change. The arguments
+	 * surface_x and surface_y are the location relative to the focused
+	 * surface.
+	 * @param time timestamp with millisecond granularity
+	 * @param surface_x surface-local x coordinate
+	 * @param surface_y surface-local y coordinate
+	 */
+	void (*motion)(void *data,
+		       struct wl_pointer *wl_pointer,
+		       uint32_t time,
+		       wl_fixed_t surface_x,
+		       wl_fixed_t surface_y);
+	/**
+	 * pointer button event
+	 *
+	 * Mouse button click and release notifications.
+	 *
+	 * The location of the click is given by the last motion or enter
+	 * event. The time argument is a timestamp with millisecond
+	 * granularity, with an undefined base.
+	 *
+	 * The button is a button code as defined in the Linux kernel's
+	 * linux/input-event-codes.h header file, e.g. BTN_LEFT.
+	 *
+	 * Any 16-bit button code value is reserved for future additions to
+	 * the kernel's event code list. All other button codes above
+	 * 0xFFFF are currently undefined but may be used in future
+	 * versions of this protocol.
+	 * @param serial serial number of the button event
+	 * @param time timestamp with millisecond granularity
+	 * @param button button that produced the event
+	 * @param state physical state of the button
+	 */
+	void (*button)(void *data,
+		       struct wl_pointer *wl_pointer,
+		       uint32_t serial,
+		       uint32_t time,
+		       uint32_t button,
+		       uint32_t state);
+	/**
+	 * axis event
+	 *
+	 * Scroll and other axis notifications.
+	 *
+	 * For scroll events (vertical and horizontal scroll axes), the
+	 * value parameter is the length of a vector along the specified
+	 * axis in a coordinate space identical to those of motion events,
+	 * representing a relative movement along the specified axis.
+	 *
+	 * For devices that support movements non-parallel to axes multiple
+	 * axis events will be emitted.
+	 *
+	 * When applicable, for example for touch pads, the server can
+	 * choose to emit scroll events where the motion vector is
+	 * equivalent to a motion event vector.
+	 *
+	 * When applicable, a client can transform its content relative to
+	 * the scroll distance.
+	 * @param time timestamp with millisecond granularity
+	 * @param axis axis type
+	 * @param value length of vector in surface-local coordinate space
+	 */
+	void (*axis)(void *data,
+		     struct wl_pointer *wl_pointer,
+		     uint32_t time,
+		     uint32_t axis,
+		     wl_fixed_t value);
+	/**
+	 * end of a pointer event sequence
+	 *
+	 * Indicates the end of a set of events that logically belong
+	 * together. A client is expected to accumulate the data in all
+	 * events within the frame before proceeding.
+	 *
+	 * All wl_pointer events before a wl_pointer.frame event belong
+	 * logically together. For example, in a diagonal scroll motion the
+	 * compositor will send an optional wl_pointer.axis_source event,
+	 * two wl_pointer.axis events (horizontal and vertical) and finally
+	 * a wl_pointer.frame event. The client may use this information to
+	 * calculate a diagonal vector for scrolling.
+	 *
+	 * When multiple wl_pointer.axis events occur within the same
+	 * frame, the motion vector is the combined motion of all events.
+	 * When a wl_pointer.axis and a wl_pointer.axis_stop event occur
+	 * within the same frame, this indicates that axis movement in one
+	 * axis has stopped but continues in the other axis. When multiple
+	 * wl_pointer.axis_stop events occur within the same frame, this
+	 * indicates that these axes stopped in the same instance.
+	 *
+	 * A wl_pointer.frame event is sent for every logical event group,
+	 * even if the group only contains a single wl_pointer event.
+	 * Specifically, a client may get a sequence: motion, frame,
+	 * button, frame, axis, frame, axis_stop, frame.
+	 *
+	 * The wl_pointer.enter and wl_pointer.leave events are logical
+	 * events generated by the compositor and not the hardware. These
+	 * events are also grouped by a wl_pointer.frame. When a pointer
+	 * moves from one surface to another, a compositor should group the
+	 * wl_pointer.leave event within the same wl_pointer.frame.
+	 * However, a client must not rely on wl_pointer.leave and
+	 * wl_pointer.enter being in the same wl_pointer.frame.
+	 * Compositor-specific policies may require the wl_pointer.leave
+	 * and wl_pointer.enter event being split across multiple
+	 * wl_pointer.frame groups.
+	 * @since 5
+	 */
+	void (*frame)(void *data,
+		      struct wl_pointer *wl_pointer);
+	/**
+	 * axis source event
+	 *
+	 * Source information for scroll and other axes.
+	 *
+	 * This event does not occur on its own. It is sent before a
+	 * wl_pointer.frame event and carries the source information for
+	 * all events within that frame.
+	 *
+	 * The source specifies how this event was generated. If the source
+	 * is wl_pointer.axis_source.finger, a wl_pointer.axis_stop event
+	 * will be sent when the user lifts the finger off the device.
+	 *
+	 * If the source is wl_pointer.axis_source.wheel,
+	 * wl_pointer.axis_source.wheel_tilt or
+	 * wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event
+	 * may or may not be sent. Whether a compositor sends an axis_stop
+	 * event for these sources is hardware-specific and
+	 * implementation-dependent; clients must not rely on receiving an
+	 * axis_stop event for these scroll sources and should treat scroll
+	 * sequences from these scroll sources as unterminated by default.
+	 *
+	 * This event is optional. If the source is unknown for a
+	 * particular axis event sequence, no event is sent. Only one
+	 * wl_pointer.axis_source event is permitted per frame.
+	 *
+	 * The order of wl_pointer.axis_discrete and wl_pointer.axis_source
+	 * is not guaranteed.
+	 * @param axis_source source of the axis event
+	 * @since 5
+	 */
+	void (*axis_source)(void *data,
+			    struct wl_pointer *wl_pointer,
+			    uint32_t axis_source);
+	/**
+	 * axis stop event
+	 *
+	 * Stop notification for scroll and other axes.
+	 *
+	 * For some wl_pointer.axis_source types, a wl_pointer.axis_stop
+	 * event is sent to notify a client that the axis sequence has
+	 * terminated. This enables the client to implement kinetic
+	 * scrolling. See the wl_pointer.axis_source documentation for
+	 * information on when this event may be generated.
+	 *
+	 * Any wl_pointer.axis events with the same axis_source after this
+	 * event should be considered as the start of a new axis motion.
+	 *
+	 * The timestamp is to be interpreted identical to the timestamp in
+	 * the wl_pointer.axis event. The timestamp value may be the same
+	 * as a preceding wl_pointer.axis event.
+	 * @param time timestamp with millisecond granularity
+	 * @param axis the axis stopped with this event
+	 * @since 5
+	 */
+	void (*axis_stop)(void *data,
+			  struct wl_pointer *wl_pointer,
+			  uint32_t time,
+			  uint32_t axis);
+	/**
+	 * axis click event
+	 *
+	 * Discrete step information for scroll and other axes.
+	 *
+	 * This event carries the axis value of the wl_pointer.axis event
+	 * in discrete steps (e.g. mouse wheel clicks).
+	 *
+	 * This event does not occur on its own, it is coupled with a
+	 * wl_pointer.axis event that represents this axis value on a
+	 * continuous scale. The protocol guarantees that each
+	 * axis_discrete event is always followed by exactly one axis event
+	 * with the same axis number within the same wl_pointer.frame. Note
+	 * that the protocol allows for other events to occur between the
+	 * axis_discrete and its coupled axis event, including other
+	 * axis_discrete or axis events.
+	 *
+	 * This event is optional; continuous scrolling devices like
+	 * two-finger scrolling on touchpads do not have discrete steps and
+	 * do not generate this event.
+	 *
+	 * The discrete value carries the directional information. e.g. a
+	 * value of -2 is two steps towards the negative direction of this
+	 * axis.
+	 *
+	 * The axis number is identical to the axis number in the
+	 * associated axis event.
+	 *
+	 * The order of wl_pointer.axis_discrete and wl_pointer.axis_source
+	 * is not guaranteed.
+	 * @param axis axis type
+	 * @param discrete number of steps
+	 * @since 5
+	 */
+	void (*axis_discrete)(void *data,
+			      struct wl_pointer *wl_pointer,
+			      uint32_t axis,
+			      int32_t discrete);
+};
+
+/**
+ * @ingroup iface_wl_pointer
+ */
+static inline int
+wl_pointer_add_listener(struct wl_pointer *wl_pointer,
+			const struct wl_pointer_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_pointer,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_POINTER_SET_CURSOR 0
+#define WL_POINTER_RELEASE 1
+
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_ENTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_LEAVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_MOTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_BUTTON_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_FRAME_SINCE_VERSION 5
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_STOP_SINCE_VERSION 5
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5
+
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_SET_CURSOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_RELEASE_SINCE_VERSION 3
+
+/** @ingroup iface_wl_pointer */
+static inline void
+wl_pointer_set_user_data(struct wl_pointer *wl_pointer, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_pointer, user_data);
+}
+
+/** @ingroup iface_wl_pointer */
+static inline void *
+wl_pointer_get_user_data(struct wl_pointer *wl_pointer)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_pointer);
+}
+
+static inline uint32_t
+wl_pointer_get_version(struct wl_pointer *wl_pointer)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_pointer);
+}
+
+/** @ingroup iface_wl_pointer */
+static inline void
+wl_pointer_destroy(struct wl_pointer *wl_pointer)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_pointer);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ *
+ * Set the pointer surface, i.e., the surface that contains the
+ * pointer image (cursor). This request gives the surface the role
+ * of a cursor. If the surface already has another role, it raises
+ * a protocol error.
+ *
+ * The cursor actually changes only if the pointer
+ * focus for this device is one of the requesting client's surfaces
+ * or the surface parameter is the current pointer surface. If
+ * there was a previous surface set with this request it is
+ * replaced. If surface is NULL, the pointer image is hidden.
+ *
+ * The parameters hotspot_x and hotspot_y define the position of
+ * the pointer surface relative to the pointer location. Its
+ * top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
+ * where (x, y) are the coordinates of the pointer location, in
+ * surface-local coordinates.
+ *
+ * On surface.attach requests to the pointer surface, hotspot_x
+ * and hotspot_y are decremented by the x and y parameters
+ * passed to the request. Attach must be confirmed by
+ * wl_surface.commit as usual.
+ *
+ * The hotspot can also be updated by passing the currently set
+ * pointer surface to this request with new values for hotspot_x
+ * and hotspot_y.
+ *
+ * The current and pending input regions of the wl_surface are
+ * cleared, and wl_surface.set_input_region is ignored until the
+ * wl_surface is no longer used as the cursor. When the use as a
+ * cursor ends, the current and pending input regions become
+ * undefined, and the wl_surface is unmapped.
+ */
+static inline void
+wl_pointer_set_cursor(struct wl_pointer *wl_pointer, uint32_t serial, struct wl_surface *surface, int32_t hotspot_x, int32_t hotspot_y)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer,
+			 WL_POINTER_SET_CURSOR, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), 0, serial, surface, hotspot_x, hotspot_y);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ *
+ * Using this request a client can tell the server that it is not going to
+ * use the pointer object anymore.
+ *
+ * This request destroys the pointer proxy object, so clients must not call
+ * wl_pointer_destroy() after using this request.
+ */
+static inline void
+wl_pointer_release(struct wl_pointer *wl_pointer)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_pointer,
+			 WL_POINTER_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_pointer), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+/**
+ * @ingroup iface_wl_keyboard
+ * keyboard mapping format
+ *
+ * This specifies the format of the keymap provided to the
+ * client with the wl_keyboard.keymap event.
+ */
+enum wl_keyboard_keymap_format {
+	/**
+	 * no keymap; client must understand how to interpret the raw keycode
+	 */
+	WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
+	/**
+	 * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode
+	 */
+	WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
+};
+#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
+
+#ifndef WL_KEYBOARD_KEY_STATE_ENUM
+#define WL_KEYBOARD_KEY_STATE_ENUM
+/**
+ * @ingroup iface_wl_keyboard
+ * physical key state
+ *
+ * Describes the physical state of a key that produced the key event.
+ */
+enum wl_keyboard_key_state {
+	/**
+	 * key is not pressed
+	 */
+	WL_KEYBOARD_KEY_STATE_RELEASED = 0,
+	/**
+	 * key is pressed
+	 */
+	WL_KEYBOARD_KEY_STATE_PRESSED = 1,
+};
+#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
+
+/**
+ * @ingroup iface_wl_keyboard
+ * @struct wl_keyboard_listener
+ */
+struct wl_keyboard_listener {
+	/**
+	 * keyboard mapping
+	 *
+	 * This event provides a file descriptor to the client which can
+	 * be memory-mapped to provide a keyboard mapping description.
+	 * @param format keymap format
+	 * @param fd keymap file descriptor
+	 * @param size keymap size, in bytes
+	 */
+	void (*keymap)(void *data,
+		       struct wl_keyboard *wl_keyboard,
+		       uint32_t format,
+		       int32_t fd,
+		       uint32_t size);
+	/**
+	 * enter event
+	 *
+	 * Notification that this seat's keyboard focus is on a certain
+	 * surface.
+	 * @param serial serial number of the enter event
+	 * @param surface surface gaining keyboard focus
+	 * @param keys the currently pressed keys
+	 */
+	void (*enter)(void *data,
+		      struct wl_keyboard *wl_keyboard,
+		      uint32_t serial,
+		      struct wl_surface *surface,
+		      struct wl_array *keys);
+	/**
+	 * leave event
+	 *
+	 * Notification that this seat's keyboard focus is no longer on a
+	 * certain surface.
+	 *
+	 * The leave notification is sent before the enter notification for
+	 * the new focus.
+	 * @param serial serial number of the leave event
+	 * @param surface surface that lost keyboard focus
+	 */
+	void (*leave)(void *data,
+		      struct wl_keyboard *wl_keyboard,
+		      uint32_t serial,
+		      struct wl_surface *surface);
+	/**
+	 * key event
+	 *
+	 * A key was pressed or released. The time argument is a
+	 * timestamp with millisecond granularity, with an undefined base.
+	 * @param serial serial number of the key event
+	 * @param time timestamp with millisecond granularity
+	 * @param key key that produced the event
+	 * @param state physical state of the key
+	 */
+	void (*key)(void *data,
+		    struct wl_keyboard *wl_keyboard,
+		    uint32_t serial,
+		    uint32_t time,
+		    uint32_t key,
+		    uint32_t state);
+	/**
+	 * modifier and group state
+	 *
+	 * Notifies clients that the modifier and/or group state has
+	 * changed, and it should update its local state.
+	 * @param serial serial number of the modifiers event
+	 * @param mods_depressed depressed modifiers
+	 * @param mods_latched latched modifiers
+	 * @param mods_locked locked modifiers
+	 * @param group keyboard layout
+	 */
+	void (*modifiers)(void *data,
+			  struct wl_keyboard *wl_keyboard,
+			  uint32_t serial,
+			  uint32_t mods_depressed,
+			  uint32_t mods_latched,
+			  uint32_t mods_locked,
+			  uint32_t group);
+	/**
+	 * repeat rate and delay
+	 *
+	 * Informs the client about the keyboard's repeat rate and delay.
+	 *
+	 * This event is sent as soon as the wl_keyboard object has been
+	 * created, and is guaranteed to be received by the client before
+	 * any key press event.
+	 *
+	 * Negative values for either rate or delay are illegal. A rate of
+	 * zero will disable any repeating (regardless of the value of
+	 * delay).
+	 *
+	 * This event can be sent later on as well with a new value if
+	 * necessary, so clients should continue listening for the event
+	 * past the creation of wl_keyboard.
+	 * @param rate the rate of repeating keys in characters per second
+	 * @param delay delay in milliseconds since key down until repeating starts
+	 * @since 4
+	 */
+	void (*repeat_info)(void *data,
+			    struct wl_keyboard *wl_keyboard,
+			    int32_t rate,
+			    int32_t delay);
+};
+
+/**
+ * @ingroup iface_wl_keyboard
+ */
+static inline int
+wl_keyboard_add_listener(struct wl_keyboard *wl_keyboard,
+			 const struct wl_keyboard_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_keyboard,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_KEYBOARD_RELEASE 0
+
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_ENTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_LEAVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_KEY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4
+
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_RELEASE_SINCE_VERSION 3
+
+/** @ingroup iface_wl_keyboard */
+static inline void
+wl_keyboard_set_user_data(struct wl_keyboard *wl_keyboard, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_keyboard, user_data);
+}
+
+/** @ingroup iface_wl_keyboard */
+static inline void *
+wl_keyboard_get_user_data(struct wl_keyboard *wl_keyboard)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_keyboard);
+}
+
+static inline uint32_t
+wl_keyboard_get_version(struct wl_keyboard *wl_keyboard)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_keyboard);
+}
+
+/** @ingroup iface_wl_keyboard */
+static inline void
+wl_keyboard_destroy(struct wl_keyboard *wl_keyboard)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_keyboard);
+}
+
+/**
+ * @ingroup iface_wl_keyboard
+ */
+static inline void
+wl_keyboard_release(struct wl_keyboard *wl_keyboard)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_keyboard,
+			 WL_KEYBOARD_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_keyboard), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ * @struct wl_touch_listener
+ */
+struct wl_touch_listener {
+	/**
+	 * touch down event and beginning of a touch sequence
+	 *
+	 * A new touch point has appeared on the surface. This touch
+	 * point is assigned a unique ID. Future events from this touch
+	 * point reference this ID. The ID ceases to be valid after a touch
+	 * up event and may be reused in the future.
+	 * @param serial serial number of the touch down event
+	 * @param time timestamp with millisecond granularity
+	 * @param surface surface touched
+	 * @param id the unique ID of this touch point
+	 * @param x surface-local x coordinate
+	 * @param y surface-local y coordinate
+	 */
+	void (*down)(void *data,
+		     struct wl_touch *wl_touch,
+		     uint32_t serial,
+		     uint32_t time,
+		     struct wl_surface *surface,
+		     int32_t id,
+		     wl_fixed_t x,
+		     wl_fixed_t y);
+	/**
+	 * end of a touch event sequence
+	 *
+	 * The touch point has disappeared. No further events will be
+	 * sent for this touch point and the touch point's ID is released
+	 * and may be reused in a future touch down event.
+	 * @param serial serial number of the touch up event
+	 * @param time timestamp with millisecond granularity
+	 * @param id the unique ID of this touch point
+	 */
+	void (*up)(void *data,
+		   struct wl_touch *wl_touch,
+		   uint32_t serial,
+		   uint32_t time,
+		   int32_t id);
+	/**
+	 * update of touch point coordinates
+	 *
+	 * A touch point has changed coordinates.
+	 * @param time timestamp with millisecond granularity
+	 * @param id the unique ID of this touch point
+	 * @param x surface-local x coordinate
+	 * @param y surface-local y coordinate
+	 */
+	void (*motion)(void *data,
+		       struct wl_touch *wl_touch,
+		       uint32_t time,
+		       int32_t id,
+		       wl_fixed_t x,
+		       wl_fixed_t y);
+	/**
+	 * end of touch frame event
+	 *
+	 * Indicates the end of a set of events that logically belong
+	 * together. A client is expected to accumulate the data in all
+	 * events within the frame before proceeding.
+	 *
+	 * A wl_touch.frame terminates at least one event but otherwise no
+	 * guarantee is provided about the set of events within a frame. A
+	 * client must assume that any state not updated in a frame is
+	 * unchanged from the previously known state.
+	 */
+	void (*frame)(void *data,
+		      struct wl_touch *wl_touch);
+	/**
+	 * touch session cancelled
+	 *
+	 * Sent if the compositor decides the touch stream is a global
+	 * gesture. No further events are sent to the clients from that
+	 * particular gesture. Touch cancellation applies to all touch
+	 * points currently active on this client's surface. The client is
+	 * responsible for finalizing the touch points, future touch points
+	 * on this surface may reuse the touch point ID.
+	 */
+	void (*cancel)(void *data,
+		       struct wl_touch *wl_touch);
+	/**
+	 * update shape of touch point
+	 *
+	 * Sent when a touchpoint has changed its shape.
+	 *
+	 * This event does not occur on its own. It is sent before a
+	 * wl_touch.frame event and carries the new shape information for
+	 * any previously reported, or new touch points of that frame.
+	 *
+	 * Other events describing the touch point such as wl_touch.down,
+	 * wl_touch.motion or wl_touch.orientation may be sent within the
+	 * same wl_touch.frame. A client should treat these events as a
+	 * single logical touch point update. The order of wl_touch.shape,
+	 * wl_touch.orientation and wl_touch.motion is not guaranteed. A
+	 * wl_touch.down event is guaranteed to occur before the first
+	 * wl_touch.shape event for this touch ID but both events may occur
+	 * within the same wl_touch.frame.
+	 *
+	 * A touchpoint shape is approximated by an ellipse through the
+	 * major and minor axis length. The major axis length describes the
+	 * longer diameter of the ellipse, while the minor axis length
+	 * describes the shorter diameter. Major and minor are orthogonal
+	 * and both are specified in surface-local coordinates. The center
+	 * of the ellipse is always at the touchpoint location as reported
+	 * by wl_touch.down or wl_touch.move.
+	 *
+	 * This event is only sent by the compositor if the touch device
+	 * supports shape reports. The client has to make reasonable
+	 * assumptions about the shape if it did not receive this event.
+	 * @param id the unique ID of this touch point
+	 * @param major length of the major axis in surface-local coordinates
+	 * @param minor length of the minor axis in surface-local coordinates
+	 * @since 6
+	 */
+	void (*shape)(void *data,
+		      struct wl_touch *wl_touch,
+		      int32_t id,
+		      wl_fixed_t major,
+		      wl_fixed_t minor);
+	/**
+	 * update orientation of touch point
+	 *
+	 * Sent when a touchpoint has changed its orientation.
+	 *
+	 * This event does not occur on its own. It is sent before a
+	 * wl_touch.frame event and carries the new shape information for
+	 * any previously reported, or new touch points of that frame.
+	 *
+	 * Other events describing the touch point such as wl_touch.down,
+	 * wl_touch.motion or wl_touch.shape may be sent within the same
+	 * wl_touch.frame. A client should treat these events as a single
+	 * logical touch point update. The order of wl_touch.shape,
+	 * wl_touch.orientation and wl_touch.motion is not guaranteed. A
+	 * wl_touch.down event is guaranteed to occur before the first
+	 * wl_touch.orientation event for this touch ID but both events may
+	 * occur within the same wl_touch.frame.
+	 *
+	 * The orientation describes the clockwise angle of a touchpoint's
+	 * major axis to the positive surface y-axis and is normalized to
+	 * the -180 to +180 degree range. The granularity of orientation
+	 * depends on the touch device, some devices only support binary
+	 * rotation values between 0 and 90 degrees.
+	 *
+	 * This event is only sent by the compositor if the touch device
+	 * supports orientation reports.
+	 * @param id the unique ID of this touch point
+	 * @param orientation angle between major axis and positive surface y-axis in degrees
+	 * @since 6
+	 */
+	void (*orientation)(void *data,
+			    struct wl_touch *wl_touch,
+			    int32_t id,
+			    wl_fixed_t orientation);
+};
+
+/**
+ * @ingroup iface_wl_touch
+ */
+static inline int
+wl_touch_add_listener(struct wl_touch *wl_touch,
+		      const struct wl_touch_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_touch,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_TOUCH_RELEASE 0
+
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_DOWN_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_UP_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_MOTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_FRAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_CANCEL_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_SHAPE_SINCE_VERSION 6
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_ORIENTATION_SINCE_VERSION 6
+
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_RELEASE_SINCE_VERSION 3
+
+/** @ingroup iface_wl_touch */
+static inline void
+wl_touch_set_user_data(struct wl_touch *wl_touch, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_touch, user_data);
+}
+
+/** @ingroup iface_wl_touch */
+static inline void *
+wl_touch_get_user_data(struct wl_touch *wl_touch)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_touch);
+}
+
+static inline uint32_t
+wl_touch_get_version(struct wl_touch *wl_touch)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_touch);
+}
+
+/** @ingroup iface_wl_touch */
+static inline void
+wl_touch_destroy(struct wl_touch *wl_touch)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_touch);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ */
+static inline void
+wl_touch_release(struct wl_touch *wl_touch)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_touch,
+			 WL_TOUCH_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_touch), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifndef WL_OUTPUT_SUBPIXEL_ENUM
+#define WL_OUTPUT_SUBPIXEL_ENUM
+/**
+ * @ingroup iface_wl_output
+ * subpixel geometry information
+ *
+ * This enumeration describes how the physical
+ * pixels on an output are laid out.
+ */
+enum wl_output_subpixel {
+	/**
+	 * unknown geometry
+	 */
+	WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
+	/**
+	 * no geometry
+	 */
+	WL_OUTPUT_SUBPIXEL_NONE = 1,
+	/**
+	 * horizontal RGB
+	 */
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
+	/**
+	 * horizontal BGR
+	 */
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
+	/**
+	 * vertical RGB
+	 */
+	WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
+	/**
+	 * vertical BGR
+	 */
+	WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
+};
+#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
+
+#ifndef WL_OUTPUT_TRANSFORM_ENUM
+#define WL_OUTPUT_TRANSFORM_ENUM
+/**
+ * @ingroup iface_wl_output
+ * transform from framebuffer to output
+ *
+ * This describes the transform that a compositor will apply to a
+ * surface to compensate for the rotation or mirroring of an
+ * output device.
+ *
+ * The flipped values correspond to an initial flip around a
+ * vertical axis followed by rotation.
+ *
+ * The purpose is mainly to allow clients to render accordingly and
+ * tell the compositor, so that for fullscreen surfaces, the
+ * compositor will still be able to scan out directly from client
+ * surfaces.
+ */
+enum wl_output_transform {
+	/**
+	 * no transform
+	 */
+	WL_OUTPUT_TRANSFORM_NORMAL = 0,
+	/**
+	 * 90 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_90 = 1,
+	/**
+	 * 180 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_180 = 2,
+	/**
+	 * 270 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_270 = 3,
+	/**
+	 * 180 degree flip around a vertical axis
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED = 4,
+	/**
+	 * flip and rotate 90 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
+	/**
+	 * flip and rotate 180 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
+	/**
+	 * flip and rotate 270 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
+};
+#endif /* WL_OUTPUT_TRANSFORM_ENUM */
+
+#ifndef WL_OUTPUT_MODE_ENUM
+#define WL_OUTPUT_MODE_ENUM
+/**
+ * @ingroup iface_wl_output
+ * mode information
+ *
+ * These flags describe properties of an output mode.
+ * They are used in the flags bitfield of the mode event.
+ */
+enum wl_output_mode {
+	/**
+	 * indicates this is the current mode
+	 */
+	WL_OUTPUT_MODE_CURRENT = 0x1,
+	/**
+	 * indicates this is the preferred mode
+	 */
+	WL_OUTPUT_MODE_PREFERRED = 0x2,
+};
+#endif /* WL_OUTPUT_MODE_ENUM */
+
+/**
+ * @ingroup iface_wl_output
+ * @struct wl_output_listener
+ */
+struct wl_output_listener {
+	/**
+	 * properties of the output
+	 *
+	 * The geometry event describes geometric properties of the
+	 * output. The event is sent when binding to the output object and
+	 * whenever any of the properties change.
+	 * @param x x position within the global compositor space
+	 * @param y y position within the global compositor space
+	 * @param physical_width width in millimeters of the output
+	 * @param physical_height height in millimeters of the output
+	 * @param subpixel subpixel orientation of the output
+	 * @param make textual description of the manufacturer
+	 * @param model textual description of the model
+	 * @param transform transform that maps framebuffer to output
+	 */
+	void (*geometry)(void *data,
+			 struct wl_output *wl_output,
+			 int32_t x,
+			 int32_t y,
+			 int32_t physical_width,
+			 int32_t physical_height,
+			 int32_t subpixel,
+			 const char *make,
+			 const char *model,
+			 int32_t transform);
+	/**
+	 * advertise available modes for the output
+	 *
+	 * The mode event describes an available mode for the output.
+	 *
+	 * The event is sent when binding to the output object and there
+	 * will always be one mode, the current mode. The event is sent
+	 * again if an output changes mode, for the mode that is now
+	 * current. In other words, the current mode is always the last
+	 * mode that was received with the current flag set.
+	 *
+	 * 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, the output
+	 * may be scaled, as described in wl_output.scale, or transformed,
+	 * as described in wl_output.transform.
+	 * @param flags bitfield of mode flags
+	 * @param width width of the mode in hardware units
+	 * @param height height of the mode in hardware units
+	 * @param refresh vertical refresh rate in mHz
+	 */
+	void (*mode)(void *data,
+		     struct wl_output *wl_output,
+		     uint32_t flags,
+		     int32_t width,
+		     int32_t height,
+		     int32_t refresh);
+	/**
+	 * sent all information about output
+	 *
+	 * This event is sent after all other properties have been sent
+	 * after binding to the output object and after any other property
+	 * changes done after that. This allows changes to the output
+	 * properties to be seen as atomic, even if they happen via
+	 * multiple events.
+	 * @since 2
+	 */
+	void (*done)(void *data,
+		     struct wl_output *wl_output);
+	/**
+	 * output scaling properties
+	 *
+	 * This event contains scaling geometry information that is not
+	 * in the geometry event. It may be sent after binding the output
+	 * object or if the output scale changes later. If it is not sent,
+	 * the client should assume a scale of 1.
+	 *
+	 * A scale larger than 1 means that the compositor will
+	 * automatically scale surface buffers by this amount when
+	 * rendering. This is used for very high resolution displays where
+	 * applications rendering at the native resolution would be too
+	 * small to be legible.
+	 *
+	 * It is intended that scaling aware clients track the current
+	 * output of a surface, and if it is on a scaled output it should
+	 * use wl_surface.set_buffer_scale with the scale of the output.
+	 * That way the compositor can avoid scaling the surface, and the
+	 * client can supply a higher detail image.
+	 * @param factor scaling factor of output
+	 * @since 2
+	 */
+	void (*scale)(void *data,
+		      struct wl_output *wl_output,
+		      int32_t factor);
+};
+
+/**
+ * @ingroup iface_wl_output
+ */
+static inline int
+wl_output_add_listener(struct wl_output *wl_output,
+		       const struct wl_output_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) wl_output,
+				     (void (**)(void)) listener, data);
+}
+
+#define WL_OUTPUT_RELEASE 0
+
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_MODE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_DONE_SINCE_VERSION 2
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_SCALE_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_RELEASE_SINCE_VERSION 3
+
+/** @ingroup iface_wl_output */
+static inline void
+wl_output_set_user_data(struct wl_output *wl_output, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_output, user_data);
+}
+
+/** @ingroup iface_wl_output */
+static inline void *
+wl_output_get_user_data(struct wl_output *wl_output)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_output);
+}
+
+static inline uint32_t
+wl_output_get_version(struct wl_output *wl_output)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_output);
+}
+
+/** @ingroup iface_wl_output */
+static inline void
+wl_output_destroy(struct wl_output *wl_output)
+{
+	wl_proxy_destroy((struct wl_proxy *) wl_output);
+}
+
+/**
+ * @ingroup iface_wl_output
+ *
+ * Using this request a client can tell the server that it is not going to
+ * use the output object anymore.
+ */
+static inline void
+wl_output_release(struct wl_output *wl_output)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_output,
+			 WL_OUTPUT_RELEASE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_output), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#define WL_REGION_DESTROY 0
+#define WL_REGION_ADD 1
+#define WL_REGION_SUBTRACT 2
+
+
+/**
+ * @ingroup iface_wl_region
+ */
+#define WL_REGION_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_region
+ */
+#define WL_REGION_ADD_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_region
+ */
+#define WL_REGION_SUBTRACT_SINCE_VERSION 1
+
+/** @ingroup iface_wl_region */
+static inline void
+wl_region_set_user_data(struct wl_region *wl_region, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_region, user_data);
+}
+
+/** @ingroup iface_wl_region */
+static inline void *
+wl_region_get_user_data(struct wl_region *wl_region)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_region);
+}
+
+static inline uint32_t
+wl_region_get_version(struct wl_region *wl_region)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_region);
+}
+
+/**
+ * @ingroup iface_wl_region
+ *
+ * Destroy the region.  This will invalidate the object ID.
+ */
+static inline void
+wl_region_destroy(struct wl_region *wl_region)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
+			 WL_REGION_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wl_region
+ *
+ * Add the specified rectangle to the region.
+ */
+static inline void
+wl_region_add(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
+			 WL_REGION_ADD, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height);
+}
+
+/**
+ * @ingroup iface_wl_region
+ *
+ * Subtract the specified rectangle from the region.
+ */
+static inline void
+wl_region_subtract(struct wl_region *wl_region, int32_t x, int32_t y, int32_t width, int32_t height)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_region,
+			 WL_REGION_SUBTRACT, NULL, wl_proxy_get_version((struct wl_proxy *) wl_region), 0, x, y, width, height);
+}
+
+#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
+#define WL_SUBCOMPOSITOR_ERROR_ENUM
+enum wl_subcompositor_error {
+	/**
+	 * the to-be sub-surface is invalid
+	 */
+	WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
+
+#define WL_SUBCOMPOSITOR_DESTROY 0
+#define WL_SUBCOMPOSITOR_GET_SUBSURFACE 1
+
+
+/**
+ * @ingroup iface_wl_subcompositor
+ */
+#define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subcompositor
+ */
+#define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1
+
+/** @ingroup iface_wl_subcompositor */
+static inline void
+wl_subcompositor_set_user_data(struct wl_subcompositor *wl_subcompositor, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_subcompositor, user_data);
+}
+
+/** @ingroup iface_wl_subcompositor */
+static inline void *
+wl_subcompositor_get_user_data(struct wl_subcompositor *wl_subcompositor)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_subcompositor);
+}
+
+static inline uint32_t
+wl_subcompositor_get_version(struct wl_subcompositor *wl_subcompositor)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_subcompositor);
+}
+
+/**
+ * @ingroup iface_wl_subcompositor
+ *
+ * Informs the server that the client will not be using this
+ * protocol object anymore. This does not affect any other
+ * objects, wl_subsurface objects included.
+ */
+static inline void
+wl_subcompositor_destroy(struct wl_subcompositor *wl_subcompositor)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor,
+			 WL_SUBCOMPOSITOR_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wl_subcompositor
+ *
+ * Create a sub-surface interface for the given surface, and
+ * associate it with the given parent surface. This turns a
+ * plain wl_surface into a sub-surface.
+ *
+ * The to-be sub-surface must not already have another role, and it
+ * must not have an existing wl_subsurface object. Otherwise a protocol
+ * error is raised.
+ */
+static inline struct wl_subsurface *
+wl_subcompositor_get_subsurface(struct wl_subcompositor *wl_subcompositor, struct wl_surface *surface, struct wl_surface *parent)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_flags((struct wl_proxy *) wl_subcompositor,
+			 WL_SUBCOMPOSITOR_GET_SUBSURFACE, &wl_subsurface_interface, wl_proxy_get_version((struct wl_proxy *) wl_subcompositor), 0, NULL, surface, parent);
+
+	return (struct wl_subsurface *) id;
+}
+
+#ifndef WL_SUBSURFACE_ERROR_ENUM
+#define WL_SUBSURFACE_ERROR_ENUM
+enum wl_subsurface_error {
+	/**
+	 * wl_surface is not a sibling or the parent
+	 */
+	WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBSURFACE_ERROR_ENUM */
+
+#define WL_SUBSURFACE_DESTROY 0
+#define WL_SUBSURFACE_SET_POSITION 1
+#define WL_SUBSURFACE_PLACE_ABOVE 2
+#define WL_SUBSURFACE_PLACE_BELOW 3
+#define WL_SUBSURFACE_SET_SYNC 4
+#define WL_SUBSURFACE_SET_DESYNC 5
+
+
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1
+
+/** @ingroup iface_wl_subsurface */
+static inline void
+wl_subsurface_set_user_data(struct wl_subsurface *wl_subsurface, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) wl_subsurface, user_data);
+}
+
+/** @ingroup iface_wl_subsurface */
+static inline void *
+wl_subsurface_get_user_data(struct wl_subsurface *wl_subsurface)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) wl_subsurface);
+}
+
+static inline uint32_t
+wl_subsurface_get_version(struct wl_subsurface *wl_subsurface)
+{
+	return wl_proxy_get_version((struct wl_proxy *) wl_subsurface);
+}
+
+/**
+ * @ingroup iface_wl_subsurface
+ *
+ * The sub-surface interface is removed from the wl_surface object
+ * that was turned into a sub-surface with a
+ * wl_subcompositor.get_subsurface request. The wl_surface's association
+ * to the parent is deleted, and the wl_surface loses its role as
+ * a sub-surface. The wl_surface is unmapped.
+ */
+static inline void
+wl_subsurface_destroy(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), WL_MARSHAL_FLAG_DESTROY);
+}
+
+/**
+ * @ingroup iface_wl_subsurface
+ *
+ * This schedules a sub-surface position change.
+ * The sub-surface will be moved so that its origin (top left
+ * corner pixel) will be at the location x, y of the parent surface
+ * coordinate system. The coordinates are not restricted to the parent
+ * surface area. Negative values are allowed.
+ *
+ * The scheduled coordinates will take effect whenever the state of the
+ * parent surface is applied. When this happens depends on whether the
+ * parent surface is in synchronized mode or not. See
+ * wl_subsurface.set_sync and wl_subsurface.set_desync for details.
+ *
+ * If more than one set_position request is invoked by the client before
+ * the commit of the parent surface, the position of a new request always
+ * replaces the scheduled position from any previous request.
+ *
+ * The initial position is 0, 0.
+ */
+static inline void
+wl_subsurface_set_position(struct wl_subsurface *wl_subsurface, int32_t x, int32_t y)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_POSITION, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, x, y);
+}
+
+/**
+ * @ingroup iface_wl_subsurface
+ *
+ * This sub-surface is taken from the stack, and put back just
+ * above the reference surface, changing the z-order of the sub-surfaces.
+ * The reference surface must be one of the sibling surfaces, or the
+ * parent surface. Using any other surface, including this sub-surface,
+ * will cause a protocol error.
+ *
+ * The z-order is double-buffered. Requests are handled in order and
+ * applied immediately to a pending state. The final pending state is
+ * copied to the active state the next time the state of the parent
+ * surface is applied. When this happens depends on whether the parent
+ * surface is in synchronized mode or not. See wl_subsurface.set_sync and
+ * wl_subsurface.set_desync for details.
+ *
+ * A new sub-surface is initially added as the top-most in the stack
+ * of its siblings and parent.
+ */
+static inline void
+wl_subsurface_place_above(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_PLACE_ABOVE, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling);
+}
+
+/**
+ * @ingroup iface_wl_subsurface
+ *
+ * The sub-surface is placed just below the reference surface.
+ * See wl_subsurface.place_above.
+ */
+static inline void
+wl_subsurface_place_below(struct wl_subsurface *wl_subsurface, struct wl_surface *sibling)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_PLACE_BELOW, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0, sibling);
+}
+
+/**
+ * @ingroup iface_wl_subsurface
+ *
+ * Change the commit behaviour of the sub-surface to synchronized
+ * mode, also described as the parent dependent mode.
+ *
+ * In synchronized mode, wl_surface.commit on a sub-surface will
+ * accumulate the committed state in a cache, but the state will
+ * not be applied and hence will not change the compositor output.
+ * The cached state is applied to the sub-surface immediately after
+ * the parent surface's state is applied. This ensures atomic
+ * updates of the parent and all its synchronized sub-surfaces.
+ * Applying the cached state will invalidate the cache, so further
+ * parent surface commits do not (re-)apply old state.
+ *
+ * See wl_subsurface for the recursive effect of this mode.
+ */
+static inline void
+wl_subsurface_set_sync(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_SYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0);
+}
+
+/**
+ * @ingroup iface_wl_subsurface
+ *
+ * Change the commit behaviour of the sub-surface to desynchronized
+ * mode, also described as independent or freely running mode.
+ *
+ * In desynchronized mode, wl_surface.commit on a sub-surface will
+ * apply the pending state directly, without caching, as happens
+ * normally with a wl_surface. Calling wl_surface.commit on the
+ * parent surface has no effect on the sub-surface's wl_surface
+ * state. This mode allows a sub-surface to be updated on its own.
+ *
+ * If cached state exists when wl_surface.commit is called in
+ * desynchronized mode, the pending state is added to the cached
+ * state, and applied as a whole. This invalidates the cache.
+ *
+ * Note: even if a sub-surface is set to desynchronized, a parent
+ * sub-surface may override it to behave as synchronized. For details,
+ * see wl_subsurface.
+ *
+ * If a surface's parent surface behaves as desynchronized, then
+ * the cached state is applied on set_desync.
+ */
+static inline void
+wl_subsurface_set_desync(struct wl_subsurface *wl_subsurface)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) wl_subsurface,
+			 WL_SUBSURFACE_SET_DESYNC, NULL, wl_proxy_get_version((struct wl_proxy *) wl_subsurface), 0);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/example-code.c b/subprojects/wayland/tests/data/example-code.c
new file mode 100644
index 0000000000000000000000000000000000000000..37feed78c389cdafce6fc65f240929be473d4264
--- /dev/null
+++ b/subprojects/wayland/tests/data/example-code.c
@@ -0,0 +1,508 @@
+/* SCANNER TEST */
+
+/*
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+extern const struct wl_interface wl_buffer_interface;
+extern const struct wl_interface wl_callback_interface;
+extern const struct wl_interface wl_data_device_interface;
+extern const struct wl_interface wl_data_offer_interface;
+extern const struct wl_interface wl_data_source_interface;
+extern const struct wl_interface wl_keyboard_interface;
+extern const struct wl_interface wl_output_interface;
+extern const struct wl_interface wl_pointer_interface;
+extern const struct wl_interface wl_region_interface;
+extern const struct wl_interface wl_registry_interface;
+extern const struct wl_interface wl_seat_interface;
+extern const struct wl_interface wl_shell_surface_interface;
+extern const struct wl_interface wl_shm_pool_interface;
+extern const struct wl_interface wl_subsurface_interface;
+extern const struct wl_interface wl_surface_interface;
+extern const struct wl_interface wl_touch_interface;
+
+static const struct wl_interface *wayland_types[] = {
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&wl_callback_interface,
+	&wl_registry_interface,
+	&wl_surface_interface,
+	&wl_region_interface,
+	&wl_buffer_interface,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&wl_shm_pool_interface,
+	NULL,
+	NULL,
+	&wl_data_source_interface,
+	&wl_surface_interface,
+	&wl_surface_interface,
+	NULL,
+	&wl_data_source_interface,
+	NULL,
+	&wl_data_offer_interface,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	&wl_data_offer_interface,
+	&wl_data_offer_interface,
+	&wl_data_source_interface,
+	&wl_data_device_interface,
+	&wl_seat_interface,
+	&wl_shell_surface_interface,
+	&wl_surface_interface,
+	&wl_seat_interface,
+	NULL,
+	&wl_seat_interface,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&wl_output_interface,
+	&wl_seat_interface,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	&wl_output_interface,
+	&wl_buffer_interface,
+	NULL,
+	NULL,
+	&wl_callback_interface,
+	&wl_region_interface,
+	&wl_region_interface,
+	&wl_output_interface,
+	&wl_output_interface,
+	&wl_pointer_interface,
+	&wl_keyboard_interface,
+	&wl_touch_interface,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	&wl_surface_interface,
+	NULL,
+	NULL,
+	NULL,
+	&wl_subsurface_interface,
+	&wl_surface_interface,
+	&wl_surface_interface,
+	&wl_surface_interface,
+	&wl_surface_interface,
+};
+
+static const struct wl_message wl_display_requests[] = {
+	{ "sync", "n", wayland_types + 8 },
+	{ "get_registry", "n", wayland_types + 9 },
+};
+
+static const struct wl_message wl_display_events[] = {
+	{ "error", "ous", wayland_types + 0 },
+	{ "delete_id", "u", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_display_interface = {
+	"wl_display", 1,
+	2, wl_display_requests,
+	2, wl_display_events,
+};
+
+static const struct wl_message wl_registry_requests[] = {
+	{ "bind", "usun", wayland_types + 0 },
+};
+
+static const struct wl_message wl_registry_events[] = {
+	{ "global", "usu", wayland_types + 0 },
+	{ "global_remove", "u", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_registry_interface = {
+	"wl_registry", 1,
+	1, wl_registry_requests,
+	2, wl_registry_events,
+};
+
+static const struct wl_message wl_callback_events[] = {
+	{ "done", "u", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_callback_interface = {
+	"wl_callback", 1,
+	0, NULL,
+	1, wl_callback_events,
+};
+
+static const struct wl_message wl_compositor_requests[] = {
+	{ "create_surface", "n", wayland_types + 10 },
+	{ "create_region", "n", wayland_types + 11 },
+};
+
+WL_EXPORT const struct wl_interface wl_compositor_interface = {
+	"wl_compositor", 4,
+	2, wl_compositor_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_shm_pool_requests[] = {
+	{ "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 = {
+	"wl_shm_pool", 1,
+	3, wl_shm_pool_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_shm_requests[] = {
+	{ "create_pool", "nhi", wayland_types + 18 },
+};
+
+static const struct wl_message wl_shm_events[] = {
+	{ "format", "u", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_shm_interface = {
+	"wl_shm", 1,
+	1, wl_shm_requests,
+	1, wl_shm_events,
+};
+
+static const struct wl_message wl_buffer_requests[] = {
+	{ "destroy", "", wayland_types + 0 },
+};
+
+static const struct wl_message wl_buffer_events[] = {
+	{ "release", "", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_buffer_interface = {
+	"wl_buffer", 1,
+	1, wl_buffer_requests,
+	1, wl_buffer_events,
+};
+
+static const struct wl_message wl_data_offer_requests[] = {
+	{ "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", wayland_types + 0 },
+	{ "source_actions", "3u", wayland_types + 0 },
+	{ "action", "3u", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_data_offer_interface = {
+	"wl_data_offer", 3,
+	5, wl_data_offer_requests,
+	3, wl_data_offer_events,
+};
+
+static const struct wl_message wl_data_source_requests[] = {
+	{ "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", 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 = {
+	"wl_data_source", 3,
+	3, wl_data_source_requests,
+	6, wl_data_source_events,
+};
+
+static const struct wl_message wl_data_device_requests[] = {
+	{ "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", 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 = {
+	"wl_data_device", 3,
+	3, wl_data_device_requests,
+	6, wl_data_device_events,
+};
+
+static const struct wl_message wl_data_device_manager_requests[] = {
+	{ "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 = {
+	"wl_data_device_manager", 3,
+	2, wl_data_device_manager_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_shell_requests[] = {
+	{ "get_shell_surface", "no", wayland_types + 37 },
+};
+
+WL_EXPORT const struct wl_interface wl_shell_interface = {
+	"wl_shell", 1,
+	1, wl_shell_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_shell_surface_requests[] = {
+	{ "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", wayland_types + 0 },
+	{ "configure", "uii", wayland_types + 0 },
+	{ "popup_done", "", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_shell_surface_interface = {
+	"wl_shell_surface", 1,
+	10, wl_shell_surface_requests,
+	3, wl_shell_surface_events,
+};
+
+static const struct wl_message wl_surface_requests[] = {
+	{ "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", wayland_types + 64 },
+	{ "leave", "o", wayland_types + 65 },
+};
+
+WL_EXPORT const struct wl_interface wl_surface_interface = {
+	"wl_surface", 4,
+	10, wl_surface_requests,
+	2, wl_surface_events,
+};
+
+static const struct wl_message wl_seat_requests[] = {
+	{ "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", wayland_types + 0 },
+	{ "name", "2s", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_seat_interface = {
+	"wl_seat", 6,
+	4, wl_seat_requests,
+	2, wl_seat_events,
+};
+
+static const struct wl_message wl_pointer_requests[] = {
+	{ "set_cursor", "u?oii", wayland_types + 69 },
+	{ "release", "3", wayland_types + 0 },
+};
+
+static const struct wl_message wl_pointer_events[] = {
+	{ "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 = {
+	"wl_pointer", 6,
+	2, wl_pointer_requests,
+	9, wl_pointer_events,
+};
+
+static const struct wl_message wl_keyboard_requests[] = {
+	{ "release", "3", wayland_types + 0 },
+};
+
+static const struct wl_message wl_keyboard_events[] = {
+	{ "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 = {
+	"wl_keyboard", 6,
+	1, wl_keyboard_requests,
+	6, wl_keyboard_events,
+};
+
+static const struct wl_message wl_touch_requests[] = {
+	{ "release", "3", wayland_types + 0 },
+};
+
+static const struct wl_message wl_touch_events[] = {
+	{ "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 = {
+	"wl_touch", 6,
+	1, wl_touch_requests,
+	7, wl_touch_events,
+};
+
+static const struct wl_message wl_output_requests[] = {
+	{ "release", "3", wayland_types + 0 },
+};
+
+static const struct wl_message wl_output_events[] = {
+	{ "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 = {
+	"wl_output", 3,
+	1, wl_output_requests,
+	4, wl_output_events,
+};
+
+static const struct wl_message wl_region_requests[] = {
+	{ "destroy", "", wayland_types + 0 },
+	{ "add", "iiii", wayland_types + 0 },
+	{ "subtract", "iiii", wayland_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface wl_region_interface = {
+	"wl_region", 1,
+	3, wl_region_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_subcompositor_requests[] = {
+	{ "destroy", "", wayland_types + 0 },
+	{ "get_subsurface", "noo", wayland_types + 90 },
+};
+
+WL_EXPORT const struct wl_interface wl_subcompositor_interface = {
+	"wl_subcompositor", 1,
+	2, wl_subcompositor_requests,
+	0, NULL,
+};
+
+static const struct wl_message wl_subsurface_requests[] = {
+	{ "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 = {
+	"wl_subsurface", 1,
+	6, wl_subsurface_requests,
+	0, NULL,
+};
+
diff --git a/subprojects/wayland/tests/data/example-enum.h b/subprojects/wayland/tests/data/example-enum.h
new file mode 100644
index 0000000000000000000000000000000000000000..9aec40354bba3a93de1d3304fa1a493d10abd67a
--- /dev/null
+++ b/subprojects/wayland/tests/data/example-enum.h
@@ -0,0 +1,836 @@
+/* SCANNER TEST */
+
+#ifndef WAYLAND_ENUM_PROTOCOL_H
+#define WAYLAND_ENUM_PROTOCOL_H
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+#ifndef WL_DISPLAY_ERROR_ENUM
+#define WL_DISPLAY_ERROR_ENUM
+/**
+ * @ingroup iface_wl_display
+ * global error values
+ *
+ * These errors are global and can be emitted in response to any
+ * server request.
+ */
+enum wl_display_error {
+	/**
+	 * server couldn't find object
+	 */
+	WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
+	/**
+	 * method doesn't exist on the specified interface
+	 */
+	WL_DISPLAY_ERROR_INVALID_METHOD = 1,
+	/**
+	 * server is out of memory
+	 */
+	WL_DISPLAY_ERROR_NO_MEMORY = 2,
+};
+#endif /* WL_DISPLAY_ERROR_ENUM */
+
+#ifndef WL_SHM_ERROR_ENUM
+#define WL_SHM_ERROR_ENUM
+/**
+ * @ingroup iface_wl_shm
+ * wl_shm error values
+ *
+ * These errors can be emitted in response to wl_shm requests.
+ */
+enum wl_shm_error {
+	/**
+	 * buffer format is not known
+	 */
+	WL_SHM_ERROR_INVALID_FORMAT = 0,
+	/**
+	 * invalid size or stride during pool or buffer creation
+	 */
+	WL_SHM_ERROR_INVALID_STRIDE = 1,
+	/**
+	 * mmapping the file descriptor failed
+	 */
+	WL_SHM_ERROR_INVALID_FD = 2,
+};
+#endif /* WL_SHM_ERROR_ENUM */
+
+#ifndef WL_SHM_FORMAT_ENUM
+#define WL_SHM_FORMAT_ENUM
+/**
+ * @ingroup iface_wl_shm
+ * pixel formats
+ *
+ * This describes the memory layout of an individual pixel.
+ *
+ * All renderers should support argb8888 and xrgb8888 but any other
+ * 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.
+ */
+enum wl_shm_format {
+	/**
+	 * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_ARGB8888 = 0,
+	/**
+	 * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_XRGB8888 = 1,
+	/**
+	 * 8-bit color index format, [7:0] C
+	 */
+	WL_SHM_FORMAT_C8 = 0x20203843,
+	/**
+	 * 8-bit RGB format, [7:0] R:G:B 3:3:2
+	 */
+	WL_SHM_FORMAT_RGB332 = 0x38424752,
+	/**
+	 * 8-bit BGR format, [7:0] B:G:R 2:3:3
+	 */
+	WL_SHM_FORMAT_BGR233 = 0x38524742,
+	/**
+	 * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_XRGB4444 = 0x32315258,
+	/**
+	 * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_XBGR4444 = 0x32314258,
+	/**
+	 * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_RGBX4444 = 0x32315852,
+	/**
+	 * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_BGRX4444 = 0x32315842,
+	/**
+	 * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_ARGB4444 = 0x32315241,
+	/**
+	 * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_ABGR4444 = 0x32314241,
+	/**
+	 * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_RGBA4444 = 0x32314152,
+	/**
+	 * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_BGRA4444 = 0x32314142,
+	/**
+	 * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_XRGB1555 = 0x35315258,
+	/**
+	 * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_XBGR1555 = 0x35314258,
+	/**
+	 * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_RGBX5551 = 0x35315852,
+	/**
+	 * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_BGRX5551 = 0x35315842,
+	/**
+	 * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_ARGB1555 = 0x35315241,
+	/**
+	 * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_ABGR1555 = 0x35314241,
+	/**
+	 * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_RGBA5551 = 0x35314152,
+	/**
+	 * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_BGRA5551 = 0x35314142,
+	/**
+	 * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian
+	 */
+	WL_SHM_FORMAT_RGB565 = 0x36314752,
+	/**
+	 * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian
+	 */
+	WL_SHM_FORMAT_BGR565 = 0x36314742,
+	/**
+	 * 24-bit RGB format, [23:0] R:G:B little endian
+	 */
+	WL_SHM_FORMAT_RGB888 = 0x34324752,
+	/**
+	 * 24-bit BGR format, [23:0] B:G:R little endian
+	 */
+	WL_SHM_FORMAT_BGR888 = 0x34324742,
+	/**
+	 * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_XBGR8888 = 0x34324258,
+	/**
+	 * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_RGBX8888 = 0x34325852,
+	/**
+	 * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_BGRX8888 = 0x34325842,
+	/**
+	 * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_ABGR8888 = 0x34324241,
+	/**
+	 * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_RGBA8888 = 0x34324152,
+	/**
+	 * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_BGRA8888 = 0x34324142,
+	/**
+	 * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
+	/**
+	 * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
+	/**
+	 * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
+	/**
+	 * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
+	/**
+	 * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
+	/**
+	 * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
+	/**
+	 * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
+	/**
+	 * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
+	/**
+	 * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_YUYV = 0x56595559,
+	/**
+	 * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_YVYU = 0x55595659,
+	/**
+	 * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_UYVY = 0x59565955,
+	/**
+	 * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_VYUY = 0x59555956,
+	/**
+	 * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_AYUV = 0x56555941,
+	/**
+	 * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane
+	 */
+	WL_SHM_FORMAT_NV12 = 0x3231564e,
+	/**
+	 * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane
+	 */
+	WL_SHM_FORMAT_NV21 = 0x3132564e,
+	/**
+	 * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane
+	 */
+	WL_SHM_FORMAT_NV16 = 0x3631564e,
+	/**
+	 * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane
+	 */
+	WL_SHM_FORMAT_NV61 = 0x3136564e,
+	/**
+	 * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV410 = 0x39565559,
+	/**
+	 * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU410 = 0x39555659,
+	/**
+	 * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV411 = 0x31315559,
+	/**
+	 * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU411 = 0x31315659,
+	/**
+	 * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV420 = 0x32315559,
+	/**
+	 * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU420 = 0x32315659,
+	/**
+	 * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV422 = 0x36315559,
+	/**
+	 * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU422 = 0x36315659,
+	/**
+	 * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV444 = 0x34325559,
+	/**
+	 * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU444 = 0x34325659,
+};
+#endif /* WL_SHM_FORMAT_ENUM */
+
+#ifndef WL_DATA_OFFER_ERROR_ENUM
+#define WL_DATA_OFFER_ERROR_ENUM
+enum wl_data_offer_error {
+	/**
+	 * finish request was called untimely
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_FINISH = 0,
+	/**
+	 * action mask contains invalid values
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1,
+	/**
+	 * action argument has an invalid value
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_ACTION = 2,
+	/**
+	 * offer doesn't accept this request
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_OFFER = 3,
+};
+#endif /* WL_DATA_OFFER_ERROR_ENUM */
+
+#ifndef WL_DATA_SOURCE_ERROR_ENUM
+#define WL_DATA_SOURCE_ERROR_ENUM
+enum wl_data_source_error {
+	/**
+	 * action mask contains invalid values
+	 */
+	WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0,
+	/**
+	 * source doesn't accept this request
+	 */
+	WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1,
+};
+#endif /* WL_DATA_SOURCE_ERROR_ENUM */
+
+#ifndef WL_DATA_DEVICE_ERROR_ENUM
+#define WL_DATA_DEVICE_ERROR_ENUM
+enum wl_data_device_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_DATA_DEVICE_ERROR_ROLE = 0,
+};
+#endif /* WL_DATA_DEVICE_ERROR_ENUM */
+
+#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
+#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
+/**
+ * @ingroup iface_wl_data_device_manager
+ * drag and drop actions
+ *
+ * This is a bitmask of the available/preferred actions in a
+ * drag-and-drop operation.
+ *
+ * In the compositor, the selected action is a result of matching the
+ * actions offered by the source and destination sides.  "action" events
+ * with a "none" action will be sent to both source and destination if
+ * there is no match. All further checks will effectively happen on
+ * (source actions ∩ destination actions).
+ *
+ * In addition, compositors may also pick different actions in
+ * reaction to key modifiers being pressed. One common design that
+ * is used in major toolkits (and the behavior recommended for
+ * compositors) is:
+ *
+ * - If no modifiers are pressed, the first match (in bit order)
+ * will be used.
+ * - Pressing Shift selects "move", if enabled in the mask.
+ * - Pressing Control selects "copy", if enabled in the mask.
+ *
+ * Behavior beyond that is considered implementation-dependent.
+ * Compositors may for example bind other modifiers (like Alt/Meta)
+ * or drags initiated with other buttons than BTN_LEFT to specific
+ * actions (e.g. "ask").
+ */
+enum wl_data_device_manager_dnd_action {
+	/**
+	 * no action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0,
+	/**
+	 * copy action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1,
+	/**
+	 * move action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2,
+	/**
+	 * ask action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4,
+};
+#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */
+
+#ifndef WL_SHELL_ERROR_ENUM
+#define WL_SHELL_ERROR_ENUM
+enum wl_shell_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_SHELL_ERROR_ROLE = 0,
+};
+#endif /* WL_SHELL_ERROR_ENUM */
+
+#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
+#define WL_SHELL_SURFACE_RESIZE_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * edge values for resizing
+ *
+ * These values are used to indicate which edge of a surface
+ * is being dragged in a resize operation. The server may
+ * use this information to adapt its behavior, e.g. choose
+ * an appropriate cursor image.
+ */
+enum wl_shell_surface_resize {
+	/**
+	 * no edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_NONE = 0,
+	/**
+	 * top edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP = 1,
+	/**
+	 * bottom edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
+	/**
+	 * left edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_LEFT = 4,
+	/**
+	 * top and left edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
+	/**
+	 * bottom and left edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
+	/**
+	 * right edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
+	/**
+	 * top and right edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
+	/**
+	 * bottom and right edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
+};
+#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
+
+#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
+#define WL_SHELL_SURFACE_TRANSIENT_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * details of transient behaviour
+ *
+ * These flags specify details of the expected behaviour
+ * of transient surfaces. Used in the set_transient request.
+ */
+enum wl_shell_surface_transient {
+	/**
+	 * do not set keyboard focus
+	 */
+	WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
+};
+#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
+
+#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * different method to set the surface fullscreen
+ *
+ * Hints to indicate to the compositor how to deal with a conflict
+ * between the dimensions of the surface and the dimensions of the
+ * output. The compositor is free to ignore this parameter.
+ */
+enum wl_shell_surface_fullscreen_method {
+	/**
+	 * no preference, apply default policy
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
+	/**
+	 * scale, preserve the surface's aspect ratio and center on output
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
+	/**
+	 * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
+	/**
+	 * no upscaling, center on output and add black borders to compensate size mismatch
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
+};
+#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
+
+#ifndef WL_SURFACE_ERROR_ENUM
+#define WL_SURFACE_ERROR_ENUM
+/**
+ * @ingroup iface_wl_surface
+ * wl_surface error values
+ *
+ * These errors can be emitted in response to wl_surface requests.
+ */
+enum wl_surface_error {
+	/**
+	 * buffer scale value is invalid
+	 */
+	WL_SURFACE_ERROR_INVALID_SCALE = 0,
+	/**
+	 * buffer transform value is invalid
+	 */
+	WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
+};
+#endif /* WL_SURFACE_ERROR_ENUM */
+
+#ifndef WL_SEAT_CAPABILITY_ENUM
+#define WL_SEAT_CAPABILITY_ENUM
+/**
+ * @ingroup iface_wl_seat
+ * seat capability bitmask
+ *
+ * This is a bitmask of capabilities this seat has; if a member is
+ * set, then it is present on the seat.
+ */
+enum wl_seat_capability {
+	/**
+	 * the seat has pointer devices
+	 */
+	WL_SEAT_CAPABILITY_POINTER = 1,
+	/**
+	 * the seat has one or more keyboards
+	 */
+	WL_SEAT_CAPABILITY_KEYBOARD = 2,
+	/**
+	 * the seat has touch devices
+	 */
+	WL_SEAT_CAPABILITY_TOUCH = 4,
+};
+#endif /* WL_SEAT_CAPABILITY_ENUM */
+
+#ifndef WL_POINTER_ERROR_ENUM
+#define WL_POINTER_ERROR_ENUM
+enum wl_pointer_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_POINTER_ERROR_ROLE = 0,
+};
+#endif /* WL_POINTER_ERROR_ENUM */
+
+#ifndef WL_POINTER_BUTTON_STATE_ENUM
+#define WL_POINTER_BUTTON_STATE_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * physical button state
+ *
+ * Describes the physical state of a button that produced the button
+ * event.
+ */
+enum wl_pointer_button_state {
+	/**
+	 * the button is not pressed
+	 */
+	WL_POINTER_BUTTON_STATE_RELEASED = 0,
+	/**
+	 * the button is pressed
+	 */
+	WL_POINTER_BUTTON_STATE_PRESSED = 1,
+};
+#endif /* WL_POINTER_BUTTON_STATE_ENUM */
+
+#ifndef WL_POINTER_AXIS_ENUM
+#define WL_POINTER_AXIS_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * axis types
+ *
+ * Describes the axis types of scroll events.
+ */
+enum wl_pointer_axis {
+	/**
+	 * vertical axis
+	 */
+	WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
+	/**
+	 * horizontal axis
+	 */
+	WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
+};
+#endif /* WL_POINTER_AXIS_ENUM */
+
+#ifndef WL_POINTER_AXIS_SOURCE_ENUM
+#define WL_POINTER_AXIS_SOURCE_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * axis source types
+ *
+ * Describes the source types for axis events. This indicates to the
+ * client how an axis event was physically generated; a client may
+ * adjust the user interface accordingly. For example, scroll events
+ * from a "finger" source may be in a smooth coordinate space with
+ * kinetic scrolling whereas a "wheel" source may be in discrete steps
+ * of a number of lines.
+ */
+enum wl_pointer_axis_source {
+	/**
+	 * a physical wheel rotation
+	 */
+	WL_POINTER_AXIS_SOURCE_WHEEL = 0,
+	/**
+	 * finger on a touch surface
+	 */
+	WL_POINTER_AXIS_SOURCE_FINGER = 1,
+	/**
+	 * continuous coordinate space
+	 *
+	 * A device generating events in a continuous coordinate space,
+	 * but using something other than a finger. One example for this
+	 * source is button-based scrolling where the vertical motion of a
+	 * device is converted to scroll events while a button is held
+	 * down.
+	 */
+	WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2,
+	/**
+	 * a physical wheel tilt
+	 *
+	 * Indicates that the actual device is a wheel but the scroll
+	 * event is not caused by a rotation but a (usually sideways) tilt
+	 * of the wheel.
+	 * @since 6
+	 */
+	WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3,
+};
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6
+#endif /* WL_POINTER_AXIS_SOURCE_ENUM */
+
+#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+/**
+ * @ingroup iface_wl_keyboard
+ * keyboard mapping format
+ *
+ * This specifies the format of the keymap provided to the
+ * client with the wl_keyboard.keymap event.
+ */
+enum wl_keyboard_keymap_format {
+	/**
+	 * no keymap; client must understand how to interpret the raw keycode
+	 */
+	WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
+	/**
+	 * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode
+	 */
+	WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
+};
+#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
+
+#ifndef WL_KEYBOARD_KEY_STATE_ENUM
+#define WL_KEYBOARD_KEY_STATE_ENUM
+/**
+ * @ingroup iface_wl_keyboard
+ * physical key state
+ *
+ * Describes the physical state of a key that produced the key event.
+ */
+enum wl_keyboard_key_state {
+	/**
+	 * key is not pressed
+	 */
+	WL_KEYBOARD_KEY_STATE_RELEASED = 0,
+	/**
+	 * key is pressed
+	 */
+	WL_KEYBOARD_KEY_STATE_PRESSED = 1,
+};
+#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
+
+#ifndef WL_OUTPUT_SUBPIXEL_ENUM
+#define WL_OUTPUT_SUBPIXEL_ENUM
+/**
+ * @ingroup iface_wl_output
+ * subpixel geometry information
+ *
+ * This enumeration describes how the physical
+ * pixels on an output are laid out.
+ */
+enum wl_output_subpixel {
+	/**
+	 * unknown geometry
+	 */
+	WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
+	/**
+	 * no geometry
+	 */
+	WL_OUTPUT_SUBPIXEL_NONE = 1,
+	/**
+	 * horizontal RGB
+	 */
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
+	/**
+	 * horizontal BGR
+	 */
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
+	/**
+	 * vertical RGB
+	 */
+	WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
+	/**
+	 * vertical BGR
+	 */
+	WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
+};
+#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
+
+#ifndef WL_OUTPUT_TRANSFORM_ENUM
+#define WL_OUTPUT_TRANSFORM_ENUM
+/**
+ * @ingroup iface_wl_output
+ * transform from framebuffer to output
+ *
+ * This describes the transform that a compositor will apply to a
+ * surface to compensate for the rotation or mirroring of an
+ * output device.
+ *
+ * The flipped values correspond to an initial flip around a
+ * vertical axis followed by rotation.
+ *
+ * The purpose is mainly to allow clients to render accordingly and
+ * tell the compositor, so that for fullscreen surfaces, the
+ * compositor will still be able to scan out directly from client
+ * surfaces.
+ */
+enum wl_output_transform {
+	/**
+	 * no transform
+	 */
+	WL_OUTPUT_TRANSFORM_NORMAL = 0,
+	/**
+	 * 90 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_90 = 1,
+	/**
+	 * 180 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_180 = 2,
+	/**
+	 * 270 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_270 = 3,
+	/**
+	 * 180 degree flip around a vertical axis
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED = 4,
+	/**
+	 * flip and rotate 90 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
+	/**
+	 * flip and rotate 180 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
+	/**
+	 * flip and rotate 270 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
+};
+#endif /* WL_OUTPUT_TRANSFORM_ENUM */
+
+#ifndef WL_OUTPUT_MODE_ENUM
+#define WL_OUTPUT_MODE_ENUM
+/**
+ * @ingroup iface_wl_output
+ * mode information
+ *
+ * These flags describe properties of an output mode.
+ * They are used in the flags bitfield of the mode event.
+ */
+enum wl_output_mode {
+	/**
+	 * indicates this is the current mode
+	 */
+	WL_OUTPUT_MODE_CURRENT = 0x1,
+	/**
+	 * indicates this is the preferred mode
+	 */
+	WL_OUTPUT_MODE_PREFERRED = 0x2,
+};
+#endif /* WL_OUTPUT_MODE_ENUM */
+
+#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
+#define WL_SUBCOMPOSITOR_ERROR_ENUM
+enum wl_subcompositor_error {
+	/**
+	 * the to-be sub-surface is invalid
+	 */
+	WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
+
+#ifndef WL_SUBSURFACE_ERROR_ENUM
+#define WL_SUBSURFACE_ERROR_ENUM
+enum wl_subsurface_error {
+	/**
+	 * wl_surface is not a sibling or the parent
+	 */
+	WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
+};
+#endif /* WL_SUBSURFACE_ERROR_ENUM */
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/example-server.h b/subprojects/wayland/tests/data/example-server.h
new file mode 100644
index 0000000000000000000000000000000000000000..b0d9226d7f14a3490eb5fcd66c4d033d07a1399d
--- /dev/null
+++ b/subprojects/wayland/tests/data/example-server.h
@@ -0,0 +1,4989 @@
+/* SCANNER TEST */
+
+#ifndef WAYLAND_SERVER_PROTOCOL_H
+#define WAYLAND_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_wayland The wayland protocol
+ * @section page_ifaces_wayland Interfaces
+ * - @subpage page_iface_wl_display - core global object
+ * - @subpage page_iface_wl_registry - global registry object
+ * - @subpage page_iface_wl_callback - callback object
+ * - @subpage page_iface_wl_compositor - the compositor singleton
+ * - @subpage page_iface_wl_shm_pool - a shared memory pool
+ * - @subpage page_iface_wl_shm - shared memory support
+ * - @subpage page_iface_wl_buffer - content for a wl_surface
+ * - @subpage page_iface_wl_data_offer - offer to transfer data
+ * - @subpage page_iface_wl_data_source - offer to transfer data
+ * - @subpage page_iface_wl_data_device - data transfer device
+ * - @subpage page_iface_wl_data_device_manager - data transfer interface
+ * - @subpage page_iface_wl_shell - create desktop-style surfaces
+ * - @subpage page_iface_wl_shell_surface - desktop-style metadata interface
+ * - @subpage page_iface_wl_surface - an onscreen surface
+ * - @subpage page_iface_wl_seat - group of input devices
+ * - @subpage page_iface_wl_pointer - pointer input device
+ * - @subpage page_iface_wl_keyboard - keyboard input device
+ * - @subpage page_iface_wl_touch - touchscreen input device
+ * - @subpage page_iface_wl_output - compositor output region
+ * - @subpage page_iface_wl_region - region interface
+ * - @subpage page_iface_wl_subcompositor - sub-surface compositing
+ * - @subpage page_iface_wl_subsurface - sub-surface interface to a wl_surface
+ * @section page_copyright_wayland Copyright
+ * <pre>
+ *
+ * Copyright © 2008-2011 Kristian Høgsberg
+ * Copyright © 2010-2011 Intel Corporation
+ * Copyright © 2012-2013 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * </pre>
+ */
+struct wl_buffer;
+struct wl_callback;
+struct wl_compositor;
+struct wl_data_device;
+struct wl_data_device_manager;
+struct wl_data_offer;
+struct wl_data_source;
+struct wl_display;
+struct wl_keyboard;
+struct wl_output;
+struct wl_pointer;
+struct wl_region;
+struct wl_registry;
+struct wl_seat;
+struct wl_shell;
+struct wl_shell_surface;
+struct wl_shm;
+struct wl_shm_pool;
+struct wl_subcompositor;
+struct wl_subsurface;
+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
+ *
+ * The core global object.  This is a special singleton object.  It
+ * is used for internal Wayland protocol features.
+ * @section page_iface_wl_display_api API
+ * See @ref iface_wl_display.
+ */
+/**
+ * @defgroup iface_wl_display The wl_display interface
+ *
+ * The core global object.  This is a special singleton object.  It
+ * 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
+ *
+ * The singleton global registry object.  The server has a number of
+ * global objects that are available to all clients.  These objects
+ * typically represent an actual object in the server (for example,
+ * an input device) or they are singleton objects that provide
+ * extension functionality.
+ *
+ * When a client creates a registry object, the registry object
+ * will emit a global event for each global currently in the
+ * registry.  Globals come and go as a result of device or
+ * monitor hotplugs, reconfiguration or other events, and the
+ * registry will send out global and global_remove events to
+ * keep the client up to date with the changes.  To mark the end
+ * of the initial burst of events, the client can use the
+ * wl_display.sync request immediately after calling
+ * wl_display.get_registry.
+ *
+ * A client can bind to a global object by using the bind
+ * request.  This creates a client-side handle that lets the object
+ * emit events to the client and lets the client invoke requests on
+ * the object.
+ * @section page_iface_wl_registry_api API
+ * See @ref iface_wl_registry.
+ */
+/**
+ * @defgroup iface_wl_registry The wl_registry interface
+ *
+ * The singleton global registry object.  The server has a number of
+ * global objects that are available to all clients.  These objects
+ * typically represent an actual object in the server (for example,
+ * an input device) or they are singleton objects that provide
+ * extension functionality.
+ *
+ * When a client creates a registry object, the registry object
+ * will emit a global event for each global currently in the
+ * registry.  Globals come and go as a result of device or
+ * monitor hotplugs, reconfiguration or other events, and the
+ * registry will send out global and global_remove events to
+ * keep the client up to date with the changes.  To mark the end
+ * of the initial burst of events, the client can use the
+ * wl_display.sync request immediately after calling
+ * wl_display.get_registry.
+ *
+ * A client can bind to a global object by using the bind
+ * request.  This creates a client-side handle that lets the object
+ * emit events to the client and lets the client invoke requests on
+ * 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
+ *
+ * Clients can handle the 'done' event to get notified when
+ * the related request is done.
+ * @section page_iface_wl_callback_api API
+ * See @ref iface_wl_callback.
+ */
+/**
+ * @defgroup iface_wl_callback The wl_callback interface
+ *
+ * Clients can handle the 'done' event to get notified when
+ * 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
+ *
+ * A compositor.  This object is a singleton global.  The
+ * compositor is in charge of combining the contents of multiple
+ * surfaces into one displayable output.
+ * @section page_iface_wl_compositor_api API
+ * See @ref iface_wl_compositor.
+ */
+/**
+ * @defgroup iface_wl_compositor The wl_compositor interface
+ *
+ * A compositor.  This object is a singleton global.  The
+ * compositor is in charge of combining the contents of multiple
+ * 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
+ *
+ * The wl_shm_pool object encapsulates a piece of memory shared
+ * between the compositor and client.  Through the wl_shm_pool
+ * object, the client can allocate shared memory wl_buffer objects.
+ * All objects created through the same pool share the same
+ * underlying mapped memory. Reusing the mapped memory avoids the
+ * setup/teardown overhead and is useful when interactively resizing
+ * a surface or for many small buffers.
+ * @section page_iface_wl_shm_pool_api API
+ * See @ref iface_wl_shm_pool.
+ */
+/**
+ * @defgroup iface_wl_shm_pool The wl_shm_pool interface
+ *
+ * The wl_shm_pool object encapsulates a piece of memory shared
+ * between the compositor and client.  Through the wl_shm_pool
+ * object, the client can allocate shared memory wl_buffer objects.
+ * All objects created through the same pool share the same
+ * underlying mapped memory. Reusing the mapped memory avoids the
+ * setup/teardown overhead and is useful when interactively resizing
+ * 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
+ *
+ * A singleton global object that provides support for shared
+ * memory.
+ *
+ * Clients can create wl_shm_pool objects using the create_pool
+ * request.
+ *
+ * At connection setup time, the wl_shm object emits one or more
+ * format events to inform clients about the valid pixel formats
+ * that can be used for buffers.
+ * @section page_iface_wl_shm_api API
+ * See @ref iface_wl_shm.
+ */
+/**
+ * @defgroup iface_wl_shm The wl_shm interface
+ *
+ * A singleton global object that provides support for shared
+ * memory.
+ *
+ * Clients can create wl_shm_pool objects using the create_pool
+ * request.
+ *
+ * At connection setup time, the wl_shm object emits one or more
+ * format events to inform clients about the valid pixel formats
+ * 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
+ *
+ * A buffer provides the content for a wl_surface. Buffers are
+ * created through factory interfaces such as wl_drm, wl_shm or
+ * similar. It has a width and a height and can be attached to a
+ * wl_surface, but the mechanism by which a client provides and
+ * updates the contents is defined by the buffer factory interface.
+ * @section page_iface_wl_buffer_api API
+ * See @ref iface_wl_buffer.
+ */
+/**
+ * @defgroup iface_wl_buffer The wl_buffer interface
+ *
+ * A buffer provides the content for a wl_surface. Buffers are
+ * created through factory interfaces such as wl_drm, wl_shm or
+ * similar. It has a width and a height and can be attached to a
+ * wl_surface, but the mechanism by which a client provides and
+ * 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
+ *
+ * A wl_data_offer represents a piece of data offered for transfer
+ * by another client (the source client).  It is used by the
+ * copy-and-paste and drag-and-drop mechanisms.  The offer
+ * describes the different mime types that the data can be
+ * converted to and provides the mechanism for transferring the
+ * data directly from the source client.
+ * @section page_iface_wl_data_offer_api API
+ * See @ref iface_wl_data_offer.
+ */
+/**
+ * @defgroup iface_wl_data_offer The wl_data_offer interface
+ *
+ * A wl_data_offer represents a piece of data offered for transfer
+ * by another client (the source client).  It is used by the
+ * copy-and-paste and drag-and-drop mechanisms.  The offer
+ * describes the different mime types that the data can be
+ * converted to and provides the mechanism for transferring the
+ * 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
+ *
+ * The wl_data_source object is the source side of a wl_data_offer.
+ * It is created by the source client in a data transfer and
+ * provides a way to describe the offered data and a way to respond
+ * to requests to transfer the data.
+ * @section page_iface_wl_data_source_api API
+ * See @ref iface_wl_data_source.
+ */
+/**
+ * @defgroup iface_wl_data_source The wl_data_source interface
+ *
+ * The wl_data_source object is the source side of a wl_data_offer.
+ * It is created by the source client in a data transfer and
+ * provides a way to describe the offered data and a way to respond
+ * 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
+ *
+ * There is one wl_data_device per seat which can be obtained
+ * from the global wl_data_device_manager singleton.
+ *
+ * A wl_data_device provides access to inter-client data transfer
+ * mechanisms such as copy-and-paste and drag-and-drop.
+ * @section page_iface_wl_data_device_api API
+ * See @ref iface_wl_data_device.
+ */
+/**
+ * @defgroup iface_wl_data_device The wl_data_device interface
+ *
+ * There is one wl_data_device per seat which can be obtained
+ * from the global wl_data_device_manager singleton.
+ *
+ * A wl_data_device provides access to inter-client data transfer
+ * 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
+ *
+ * The wl_data_device_manager is a singleton global object that
+ * provides access to inter-client data transfer mechanisms such as
+ * copy-and-paste and drag-and-drop.  These mechanisms are tied to
+ * a wl_seat and this interface lets a client get a wl_data_device
+ * corresponding to a wl_seat.
+ *
+ * Depending on the version bound, the objects created from the bound
+ * wl_data_device_manager object will have different requirements for
+ * functioning properly. See wl_data_source.set_actions,
+ * wl_data_offer.accept and wl_data_offer.finish for details.
+ * @section page_iface_wl_data_device_manager_api API
+ * See @ref iface_wl_data_device_manager.
+ */
+/**
+ * @defgroup iface_wl_data_device_manager The wl_data_device_manager interface
+ *
+ * The wl_data_device_manager is a singleton global object that
+ * provides access to inter-client data transfer mechanisms such as
+ * copy-and-paste and drag-and-drop.  These mechanisms are tied to
+ * a wl_seat and this interface lets a client get a wl_data_device
+ * corresponding to a wl_seat.
+ *
+ * Depending on the version bound, the objects created from the bound
+ * wl_data_device_manager object will have different requirements for
+ * functioning properly. See wl_data_source.set_actions,
+ * 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
+ *
+ * This interface is implemented by servers that provide
+ * desktop-style user interfaces.
+ *
+ * It allows clients to associate a wl_shell_surface with
+ * a basic surface.
+ * @section page_iface_wl_shell_api API
+ * See @ref iface_wl_shell.
+ */
+/**
+ * @defgroup iface_wl_shell The wl_shell interface
+ *
+ * This interface is implemented by servers that provide
+ * desktop-style user interfaces.
+ *
+ * It allows clients to associate a wl_shell_surface with
+ * 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
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like toplevel, fullscreen
+ * or popup windows, move, resize or maximize them, associate
+ * metadata like title and class, etc.
+ *
+ * On the server side the object is automatically destroyed when
+ * the related wl_surface is destroyed. On the client side,
+ * wl_shell_surface_destroy() must be called before destroying
+ * the wl_surface object.
+ * @section page_iface_wl_shell_surface_api API
+ * See @ref iface_wl_shell_surface.
+ */
+/**
+ * @defgroup iface_wl_shell_surface The wl_shell_surface interface
+ *
+ * An interface that may be implemented by a wl_surface, for
+ * implementations that provide a desktop-style user interface.
+ *
+ * It provides requests to treat surfaces like toplevel, fullscreen
+ * or popup windows, move, resize or maximize them, associate
+ * metadata like title and class, etc.
+ *
+ * On the server side the object is automatically destroyed when
+ * the related wl_surface is destroyed. On the client side,
+ * wl_shell_surface_destroy() must be called before destroying
+ * 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
+ *
+ * A surface is a rectangular area that is displayed on the screen.
+ * It has a location, size and pixel contents.
+ *
+ * The size of a surface (and relative positions on it) is described
+ * in surface-local coordinates, which may differ from the buffer
+ * coordinates of the pixel content, in case a buffer_transform
+ * or a buffer_scale is used.
+ *
+ * A surface without a "role" is fairly useless: a compositor does
+ * not know where, when or how to present it. The role is the
+ * purpose of a wl_surface. Examples of roles are a cursor for a
+ * pointer (as set by wl_pointer.set_cursor), a drag icon
+ * (wl_data_device.start_drag), a sub-surface
+ * (wl_subcompositor.get_subsurface), and a window as defined by a
+ * shell protocol (e.g. wl_shell.get_shell_surface).
+ *
+ * A surface can have only one role at a time. Initially a
+ * wl_surface does not have a role. Once a wl_surface is given a
+ * role, it is set permanently for the whole lifetime of the
+ * wl_surface object. Giving the current role again is allowed,
+ * unless explicitly forbidden by the relevant interface
+ * specification.
+ *
+ * Surface roles are given by requests in other interfaces such as
+ * wl_pointer.set_cursor. The request should explicitly mention
+ * that this request gives a role to a wl_surface. Often, this
+ * request also creates a new protocol object that represents the
+ * role and adds additional functionality to wl_surface. When a
+ * client wants to destroy a wl_surface, they must destroy this 'role
+ * object' before the wl_surface.
+ *
+ * Destroying the role object does not remove the role from the
+ * wl_surface, but it may stop the wl_surface from "playing the role".
+ * For instance, if a wl_subsurface object is destroyed, the wl_surface
+ * it was created for will be unmapped and forget its position and
+ * z-order. It is allowed to create a wl_subsurface for the same
+ * wl_surface again, but it is not allowed to use the wl_surface as
+ * a cursor (cursor is a different role than sub-surface, and role
+ * switching is not allowed).
+ * @section page_iface_wl_surface_api API
+ * See @ref iface_wl_surface.
+ */
+/**
+ * @defgroup iface_wl_surface The wl_surface interface
+ *
+ * A surface is a rectangular area that is displayed on the screen.
+ * It has a location, size and pixel contents.
+ *
+ * The size of a surface (and relative positions on it) is described
+ * in surface-local coordinates, which may differ from the buffer
+ * coordinates of the pixel content, in case a buffer_transform
+ * or a buffer_scale is used.
+ *
+ * A surface without a "role" is fairly useless: a compositor does
+ * not know where, when or how to present it. The role is the
+ * purpose of a wl_surface. Examples of roles are a cursor for a
+ * pointer (as set by wl_pointer.set_cursor), a drag icon
+ * (wl_data_device.start_drag), a sub-surface
+ * (wl_subcompositor.get_subsurface), and a window as defined by a
+ * shell protocol (e.g. wl_shell.get_shell_surface).
+ *
+ * A surface can have only one role at a time. Initially a
+ * wl_surface does not have a role. Once a wl_surface is given a
+ * role, it is set permanently for the whole lifetime of the
+ * wl_surface object. Giving the current role again is allowed,
+ * unless explicitly forbidden by the relevant interface
+ * specification.
+ *
+ * Surface roles are given by requests in other interfaces such as
+ * wl_pointer.set_cursor. The request should explicitly mention
+ * that this request gives a role to a wl_surface. Often, this
+ * request also creates a new protocol object that represents the
+ * role and adds additional functionality to wl_surface. When a
+ * client wants to destroy a wl_surface, they must destroy this 'role
+ * object' before the wl_surface.
+ *
+ * Destroying the role object does not remove the role from the
+ * wl_surface, but it may stop the wl_surface from "playing the role".
+ * For instance, if a wl_subsurface object is destroyed, the wl_surface
+ * it was created for will be unmapped and forget its position and
+ * z-order. It is allowed to create a wl_subsurface for the same
+ * wl_surface again, but it is not allowed to use the wl_surface as
+ * a cursor (cursor is a different role than sub-surface, and role
+ * 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
+ *
+ * A seat is a group of keyboards, pointer and touch devices. This
+ * object is published as a global during start up, or when such a
+ * device is hot plugged.  A seat typically has a pointer and
+ * maintains a keyboard focus and a pointer focus.
+ * @section page_iface_wl_seat_api API
+ * See @ref iface_wl_seat.
+ */
+/**
+ * @defgroup iface_wl_seat The wl_seat interface
+ *
+ * A seat is a group of keyboards, pointer and touch devices. This
+ * object is published as a global during start up, or when such a
+ * device is hot plugged.  A seat typically has a pointer and
+ * 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
+ *
+ * The wl_pointer interface represents one or more input devices,
+ * such as mice, which control the pointer location and pointer_focus
+ * of a seat.
+ *
+ * The wl_pointer interface generates motion, enter and leave
+ * events for the surfaces that the pointer is located over,
+ * and button and axis events for button presses, button releases
+ * and scrolling.
+ * @section page_iface_wl_pointer_api API
+ * See @ref iface_wl_pointer.
+ */
+/**
+ * @defgroup iface_wl_pointer The wl_pointer interface
+ *
+ * The wl_pointer interface represents one or more input devices,
+ * such as mice, which control the pointer location and pointer_focus
+ * of a seat.
+ *
+ * The wl_pointer interface generates motion, enter and leave
+ * events for the surfaces that the pointer is located over,
+ * and button and axis events for button presses, button releases
+ * 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
+ *
+ * The wl_keyboard interface represents one or more keyboards
+ * associated with a seat.
+ * @section page_iface_wl_keyboard_api API
+ * See @ref iface_wl_keyboard.
+ */
+/**
+ * @defgroup iface_wl_keyboard The wl_keyboard interface
+ *
+ * The wl_keyboard interface represents one or more keyboards
+ * 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
+ *
+ * The wl_touch interface represents a touchscreen
+ * associated with a seat.
+ *
+ * Touch interactions can consist of one or more contacts.
+ * For each contact, a series of events is generated, starting
+ * with a down event, followed by zero or more motion events,
+ * and ending with an up event. Events relating to the same
+ * contact point can be identified by the ID of the sequence.
+ * @section page_iface_wl_touch_api API
+ * See @ref iface_wl_touch.
+ */
+/**
+ * @defgroup iface_wl_touch The wl_touch interface
+ *
+ * The wl_touch interface represents a touchscreen
+ * associated with a seat.
+ *
+ * Touch interactions can consist of one or more contacts.
+ * For each contact, a series of events is generated, starting
+ * with a down event, followed by zero or more motion events,
+ * and ending with an up event. Events relating to the same
+ * 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
+ *
+ * An output describes part of the compositor geometry.  The
+ * compositor works in the 'compositor coordinate system' and an
+ * output corresponds to a rectangular area in that space that is
+ * actually visible.  This typically corresponds to a monitor that
+ * displays part of the compositor space.  This object is published
+ * as global during start up, or when a monitor is hotplugged.
+ * @section page_iface_wl_output_api API
+ * See @ref iface_wl_output.
+ */
+/**
+ * @defgroup iface_wl_output The wl_output interface
+ *
+ * An output describes part of the compositor geometry.  The
+ * compositor works in the 'compositor coordinate system' and an
+ * output corresponds to a rectangular area in that space that is
+ * actually visible.  This typically corresponds to a monitor that
+ * displays part of the compositor space.  This object is published
+ * 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
+ *
+ * A region object describes an area.
+ *
+ * Region objects are used to describe the opaque and input
+ * regions of a surface.
+ * @section page_iface_wl_region_api API
+ * See @ref iface_wl_region.
+ */
+/**
+ * @defgroup iface_wl_region The wl_region interface
+ *
+ * A region object describes an area.
+ *
+ * Region objects are used to describe the opaque and input
+ * 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
+ *
+ * The global interface exposing sub-surface compositing capabilities.
+ * A wl_surface, that has sub-surfaces associated, is called the
+ * parent surface. Sub-surfaces can be arbitrarily nested and create
+ * a tree of sub-surfaces.
+ *
+ * The root surface in a tree of sub-surfaces is the main
+ * surface. The main surface cannot be a sub-surface, because
+ * sub-surfaces must always have a parent.
+ *
+ * A main surface with its sub-surfaces forms a (compound) window.
+ * For window management purposes, this set of wl_surface objects is
+ * to be considered as a single window, and it should also behave as
+ * such.
+ *
+ * The aim of sub-surfaces is to offload some of the compositing work
+ * within a window from clients to the compositor. A prime example is
+ * a video player with decorations and video in separate wl_surface
+ * objects. This should allow the compositor to pass YUV video buffer
+ * processing to dedicated overlay hardware when possible.
+ * @section page_iface_wl_subcompositor_api API
+ * See @ref iface_wl_subcompositor.
+ */
+/**
+ * @defgroup iface_wl_subcompositor The wl_subcompositor interface
+ *
+ * The global interface exposing sub-surface compositing capabilities.
+ * A wl_surface, that has sub-surfaces associated, is called the
+ * parent surface. Sub-surfaces can be arbitrarily nested and create
+ * a tree of sub-surfaces.
+ *
+ * The root surface in a tree of sub-surfaces is the main
+ * surface. The main surface cannot be a sub-surface, because
+ * sub-surfaces must always have a parent.
+ *
+ * A main surface with its sub-surfaces forms a (compound) window.
+ * For window management purposes, this set of wl_surface objects is
+ * to be considered as a single window, and it should also behave as
+ * such.
+ *
+ * The aim of sub-surfaces is to offload some of the compositing work
+ * within a window from clients to the compositor. A prime example is
+ * a video player with decorations and video in separate wl_surface
+ * objects. This should allow the compositor to pass YUV video buffer
+ * 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
+ *
+ * An additional interface to a wl_surface object, which has been
+ * made a sub-surface. A sub-surface has one parent surface. A
+ * sub-surface's size and position are not limited to that of the parent.
+ * Particularly, a sub-surface is not automatically clipped to its
+ * parent's area.
+ *
+ * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+ * and the parent surface is mapped. The order of which one happens
+ * first is irrelevant. A sub-surface is hidden if the parent becomes
+ * hidden, or if a NULL wl_buffer is applied. These rules apply
+ * recursively through the tree of surfaces.
+ *
+ * The behaviour of a wl_surface.commit request on a sub-surface
+ * depends on the sub-surface's mode. The possible modes are
+ * synchronized and desynchronized, see methods
+ * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
+ * mode caches the wl_surface state to be applied when the parent's
+ * state gets applied, and desynchronized mode applies the pending
+ * 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
+ * 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
+ * the parent and its sub-surfaces (wl_subsurface.place_above and
+ * .place_below). This state is applied when the parent surface's
+ * wl_surface state is applied, regardless of the sub-surface's mode.
+ * As the exception, set_sync and set_desync are effective immediately.
+ *
+ * The main surface can be thought to be always in desynchronized mode,
+ * since it does not have a parent in the sub-surfaces sense.
+ *
+ * Even if a sub-surface is in desynchronized mode, it will behave as
+ * in synchronized mode, if its parent surface behaves as in
+ * synchronized mode. This rule is applied recursively throughout the
+ * tree of surfaces. This means, that one can set a sub-surface into
+ * synchronized mode, and then assume that all its child and grand-child
+ * sub-surfaces are synchronized, too, without explicitly setting them.
+ *
+ * If the wl_surface associated with the wl_subsurface is destroyed, the
+ * wl_subsurface object becomes inert. Note, that destroying either object
+ * takes effect immediately. If you need to synchronize the removal
+ * of a sub-surface to the parent surface update, unmap the sub-surface
+ * first by attaching a NULL wl_buffer, update parent, and then destroy
+ * the sub-surface.
+ *
+ * If the parent wl_surface object is destroyed, the sub-surface is
+ * unmapped.
+ * @section page_iface_wl_subsurface_api API
+ * See @ref iface_wl_subsurface.
+ */
+/**
+ * @defgroup iface_wl_subsurface The wl_subsurface interface
+ *
+ * An additional interface to a wl_surface object, which has been
+ * made a sub-surface. A sub-surface has one parent surface. A
+ * sub-surface's size and position are not limited to that of the parent.
+ * Particularly, a sub-surface is not automatically clipped to its
+ * parent's area.
+ *
+ * A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+ * and the parent surface is mapped. The order of which one happens
+ * first is irrelevant. A sub-surface is hidden if the parent becomes
+ * hidden, or if a NULL wl_buffer is applied. These rules apply
+ * recursively through the tree of surfaces.
+ *
+ * The behaviour of a wl_surface.commit request on a sub-surface
+ * depends on the sub-surface's mode. The possible modes are
+ * synchronized and desynchronized, see methods
+ * wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
+ * mode caches the wl_surface state to be applied when the parent's
+ * state gets applied, and desynchronized mode applies the pending
+ * 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
+ * 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
+ * the parent and its sub-surfaces (wl_subsurface.place_above and
+ * .place_below). This state is applied when the parent surface's
+ * wl_surface state is applied, regardless of the sub-surface's mode.
+ * As the exception, set_sync and set_desync are effective immediately.
+ *
+ * The main surface can be thought to be always in desynchronized mode,
+ * since it does not have a parent in the sub-surfaces sense.
+ *
+ * Even if a sub-surface is in desynchronized mode, it will behave as
+ * in synchronized mode, if its parent surface behaves as in
+ * synchronized mode. This rule is applied recursively throughout the
+ * tree of surfaces. This means, that one can set a sub-surface into
+ * synchronized mode, and then assume that all its child and grand-child
+ * sub-surfaces are synchronized, too, without explicitly setting them.
+ *
+ * If the wl_surface associated with the wl_subsurface is destroyed, the
+ * wl_subsurface object becomes inert. Note, that destroying either object
+ * takes effect immediately. If you need to synchronize the removal
+ * of a sub-surface to the parent surface update, unmap the sub-surface
+ * first by attaching a NULL wl_buffer, update parent, and then destroy
+ * the sub-surface.
+ *
+ * If the parent wl_surface object is destroyed, the sub-surface is
+ * unmapped.
+ */
+extern const struct wl_interface wl_subsurface_interface;
+#endif
+
+#ifndef WL_DISPLAY_ERROR_ENUM
+#define WL_DISPLAY_ERROR_ENUM
+/**
+ * @ingroup iface_wl_display
+ * global error values
+ *
+ * These errors are global and can be emitted in response to any
+ * server request.
+ */
+enum wl_display_error {
+	/**
+	 * server couldn't find object
+	 */
+	WL_DISPLAY_ERROR_INVALID_OBJECT = 0,
+	/**
+	 * method doesn't exist on the specified interface
+	 */
+	WL_DISPLAY_ERROR_INVALID_METHOD = 1,
+	/**
+	 * server is out of memory
+	 */
+	WL_DISPLAY_ERROR_NO_MEMORY = 2,
+};
+/**
+ * @ingroup iface_wl_display
+ * Validate a wl_display error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_display_error
+ */
+static inline bool
+wl_display_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_DISPLAY_ERROR_INVALID_OBJECT:
+		return version >= 1;
+	case WL_DISPLAY_ERROR_INVALID_METHOD:
+		return version >= 1;
+	case WL_DISPLAY_ERROR_NO_MEMORY:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_DISPLAY_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_display
+ * @struct wl_display_interface
+ */
+struct wl_display_interface {
+	/**
+	 * asynchronous roundtrip
+	 *
+	 * The sync request asks the server to emit the 'done' event on
+	 * the returned wl_callback object. Since requests are handled
+	 * in-order and events are delivered in-order, this can be used as
+	 * a barrier to ensure all previous requests and the resulting
+	 * events have been handled.
+	 *
+	 * The object returned by this request will be destroyed by the
+	 * compositor after the callback is fired and as such the client
+	 * must not attempt to use it after that point.
+	 *
+	 * The callback_data passed in the callback is the event serial.
+	 * @param callback callback object for the sync request
+	 */
+	void (*sync)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t callback);
+	/**
+	 * get global registry object
+	 *
+	 * This request creates a registry object that allows the client
+	 * to list and bind the global objects available from the
+	 * compositor.
+	 * @param registry global registry object
+	 */
+	void (*get_registry)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t registry);
+};
+
+#define WL_DISPLAY_ERROR 0
+#define WL_DISPLAY_DELETE_ID 1
+
+/**
+ * @ingroup iface_wl_display
+ */
+#define WL_DISPLAY_ERROR_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_display
+ */
+#define WL_DISPLAY_DELETE_ID_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_display
+ */
+#define WL_DISPLAY_SYNC_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_display
+ */
+#define WL_DISPLAY_GET_REGISTRY_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_registry
+ * @struct wl_registry_interface
+ */
+struct wl_registry_interface {
+	/**
+	 * bind an object to the display
+	 *
+	 * Binds a new, client-created object to the server using the
+	 * specified name as the identifier.
+	 * @param name unique numeric name of the object
+	 * @param interface name of the objects interface
+	 * @param version version of the objects interface
+	 * @param id bounded object
+	 */
+	void (*bind)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t name,
+		     const char *interface, uint32_t version, uint32_t id);
+};
+
+#define WL_REGISTRY_GLOBAL 0
+#define WL_REGISTRY_GLOBAL_REMOVE 1
+
+/**
+ * @ingroup iface_wl_registry
+ */
+#define WL_REGISTRY_GLOBAL_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_registry
+ */
+#define WL_REGISTRY_GLOBAL_REMOVE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_registry
+ */
+#define WL_REGISTRY_BIND_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_registry
+ * Sends an global event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param name numeric name of the global object
+ * @param interface interface implemented by the object
+ * @param version interface version
+ */
+static inline void
+wl_registry_send_global(struct wl_resource *resource_, uint32_t name, const char *interface, uint32_t version)
+{
+	wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL, name, interface, version);
+}
+
+/**
+ * @ingroup iface_wl_registry
+ * Sends an global_remove event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param name numeric name of the global object
+ */
+static inline void
+wl_registry_send_global_remove(struct wl_resource *resource_, uint32_t name)
+{
+	wl_resource_post_event(resource_, WL_REGISTRY_GLOBAL_REMOVE, name);
+}
+
+#define WL_CALLBACK_DONE 0
+
+/**
+ * @ingroup iface_wl_callback
+ */
+#define WL_CALLBACK_DONE_SINCE_VERSION 1
+
+
+/**
+ * @ingroup iface_wl_callback
+ * Sends an done event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param callback_data request-specific data for the callback
+ */
+static inline void
+wl_callback_send_done(struct wl_resource *resource_, uint32_t callback_data)
+{
+	wl_resource_post_event(resource_, WL_CALLBACK_DONE, callback_data);
+}
+
+/**
+ * @ingroup iface_wl_compositor
+ * @struct wl_compositor_interface
+ */
+struct wl_compositor_interface {
+	/**
+	 * create new surface
+	 *
+	 * Ask the compositor to create a new surface.
+	 * @param id the new surface
+	 */
+	void (*create_surface)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t id);
+	/**
+	 * create new region
+	 *
+	 * Ask the compositor to create a new region.
+	 * @param id the new region
+	 */
+	void (*create_region)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      uint32_t id);
+};
+
+
+/**
+ * @ingroup iface_wl_compositor
+ */
+#define WL_COMPOSITOR_CREATE_SURFACE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_compositor
+ */
+#define WL_COMPOSITOR_CREATE_REGION_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_shm_pool
+ * @struct wl_shm_pool_interface
+ */
+struct wl_shm_pool_interface {
+	/**
+	 * create a buffer from the pool
+	 *
+	 * Create a wl_buffer object from the pool.
+	 *
+	 * The buffer is created offset bytes into the pool and has width
+	 * and height as specified. The stride argument specifies the
+	 * number of bytes from the beginning of one row to the beginning
+	 * of the next. The format is the pixel format of the buffer and
+	 * must be one of those advertised through the wl_shm.format event.
+	 *
+	 * A buffer will keep a reference to the pool it was created from
+	 * so it is valid to destroy the pool immediately after creating a
+	 * buffer from it.
+	 * @param id buffer to create
+	 * @param offset buffer byte offset within the pool
+	 * @param width buffer width, in pixels
+	 * @param height buffer height, in pixels
+	 * @param stride number of bytes from the beginning of one row to the beginning of the next row
+	 * @param format buffer pixel format
+	 */
+	void (*create_buffer)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      uint32_t id,
+			      int32_t offset,
+			      int32_t width,
+			      int32_t height,
+			      int32_t stride,
+			      uint32_t format);
+	/**
+	 * destroy the pool
+	 *
+	 * Destroy the shared memory pool.
+	 *
+	 * The mmapped memory will be released when all buffers that have
+	 * been created from this pool are gone.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * change the size of the pool mapping
+	 *
+	 * This request will cause the server to remap the backing memory
+	 * for the pool from the file descriptor passed when the pool was
+	 * created, but using the new size. This request can only be used
+	 * to make the pool bigger.
+	 * @param size new size of the pool, in bytes
+	 */
+	void (*resize)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       int32_t size);
+};
+
+
+/**
+ * @ingroup iface_wl_shm_pool
+ */
+#define WL_SHM_POOL_CREATE_BUFFER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shm_pool
+ */
+#define WL_SHM_POOL_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shm_pool
+ */
+#define WL_SHM_POOL_RESIZE_SINCE_VERSION 1
+
+#ifndef WL_SHM_ERROR_ENUM
+#define WL_SHM_ERROR_ENUM
+/**
+ * @ingroup iface_wl_shm
+ * wl_shm error values
+ *
+ * These errors can be emitted in response to wl_shm requests.
+ */
+enum wl_shm_error {
+	/**
+	 * buffer format is not known
+	 */
+	WL_SHM_ERROR_INVALID_FORMAT = 0,
+	/**
+	 * invalid size or stride during pool or buffer creation
+	 */
+	WL_SHM_ERROR_INVALID_STRIDE = 1,
+	/**
+	 * mmapping the file descriptor failed
+	 */
+	WL_SHM_ERROR_INVALID_FD = 2,
+};
+/**
+ * @ingroup iface_wl_shm
+ * Validate a wl_shm error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_shm_error
+ */
+static inline bool
+wl_shm_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SHM_ERROR_INVALID_FORMAT:
+		return version >= 1;
+	case WL_SHM_ERROR_INVALID_STRIDE:
+		return version >= 1;
+	case WL_SHM_ERROR_INVALID_FD:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SHM_ERROR_ENUM */
+
+#ifndef WL_SHM_FORMAT_ENUM
+#define WL_SHM_FORMAT_ENUM
+/**
+ * @ingroup iface_wl_shm
+ * pixel formats
+ *
+ * This describes the memory layout of an individual pixel.
+ *
+ * All renderers should support argb8888 and xrgb8888 but any other
+ * 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.
+ */
+enum wl_shm_format {
+	/**
+	 * 32-bit ARGB format, [31:0] A:R:G:B 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_ARGB8888 = 0,
+	/**
+	 * 32-bit RGB format, [31:0] x:R:G:B 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_XRGB8888 = 1,
+	/**
+	 * 8-bit color index format, [7:0] C
+	 */
+	WL_SHM_FORMAT_C8 = 0x20203843,
+	/**
+	 * 8-bit RGB format, [7:0] R:G:B 3:3:2
+	 */
+	WL_SHM_FORMAT_RGB332 = 0x38424752,
+	/**
+	 * 8-bit BGR format, [7:0] B:G:R 2:3:3
+	 */
+	WL_SHM_FORMAT_BGR233 = 0x38524742,
+	/**
+	 * 16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_XRGB4444 = 0x32315258,
+	/**
+	 * 16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_XBGR4444 = 0x32314258,
+	/**
+	 * 16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_RGBX4444 = 0x32315852,
+	/**
+	 * 16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_BGRX4444 = 0x32315842,
+	/**
+	 * 16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_ARGB4444 = 0x32315241,
+	/**
+	 * 16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_ABGR4444 = 0x32314241,
+	/**
+	 * 16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_RGBA4444 = 0x32314152,
+	/**
+	 * 16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian
+	 */
+	WL_SHM_FORMAT_BGRA4444 = 0x32314142,
+	/**
+	 * 16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_XRGB1555 = 0x35315258,
+	/**
+	 * 16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_XBGR1555 = 0x35314258,
+	/**
+	 * 16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_RGBX5551 = 0x35315852,
+	/**
+	 * 16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_BGRX5551 = 0x35315842,
+	/**
+	 * 16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_ARGB1555 = 0x35315241,
+	/**
+	 * 16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian
+	 */
+	WL_SHM_FORMAT_ABGR1555 = 0x35314241,
+	/**
+	 * 16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_RGBA5551 = 0x35314152,
+	/**
+	 * 16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian
+	 */
+	WL_SHM_FORMAT_BGRA5551 = 0x35314142,
+	/**
+	 * 16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian
+	 */
+	WL_SHM_FORMAT_RGB565 = 0x36314752,
+	/**
+	 * 16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian
+	 */
+	WL_SHM_FORMAT_BGR565 = 0x36314742,
+	/**
+	 * 24-bit RGB format, [23:0] R:G:B little endian
+	 */
+	WL_SHM_FORMAT_RGB888 = 0x34324752,
+	/**
+	 * 24-bit BGR format, [23:0] B:G:R little endian
+	 */
+	WL_SHM_FORMAT_BGR888 = 0x34324742,
+	/**
+	 * 32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_XBGR8888 = 0x34324258,
+	/**
+	 * 32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_RGBX8888 = 0x34325852,
+	/**
+	 * 32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_BGRX8888 = 0x34325842,
+	/**
+	 * 32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_ABGR8888 = 0x34324241,
+	/**
+	 * 32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_RGBA8888 = 0x34324152,
+	/**
+	 * 32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_BGRA8888 = 0x34324142,
+	/**
+	 * 32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_XRGB2101010 = 0x30335258,
+	/**
+	 * 32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_XBGR2101010 = 0x30334258,
+	/**
+	 * 32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_RGBX1010102 = 0x30335852,
+	/**
+	 * 32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_BGRX1010102 = 0x30335842,
+	/**
+	 * 32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_ARGB2101010 = 0x30335241,
+	/**
+	 * 32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian
+	 */
+	WL_SHM_FORMAT_ABGR2101010 = 0x30334241,
+	/**
+	 * 32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_RGBA1010102 = 0x30334152,
+	/**
+	 * 32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian
+	 */
+	WL_SHM_FORMAT_BGRA1010102 = 0x30334142,
+	/**
+	 * packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_YUYV = 0x56595559,
+	/**
+	 * packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_YVYU = 0x55595659,
+	/**
+	 * packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_UYVY = 0x59565955,
+	/**
+	 * packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_VYUY = 0x59555956,
+	/**
+	 * packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian
+	 */
+	WL_SHM_FORMAT_AYUV = 0x56555941,
+	/**
+	 * 2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane
+	 */
+	WL_SHM_FORMAT_NV12 = 0x3231564e,
+	/**
+	 * 2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane
+	 */
+	WL_SHM_FORMAT_NV21 = 0x3132564e,
+	/**
+	 * 2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane
+	 */
+	WL_SHM_FORMAT_NV16 = 0x3631564e,
+	/**
+	 * 2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane
+	 */
+	WL_SHM_FORMAT_NV61 = 0x3136564e,
+	/**
+	 * 3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV410 = 0x39565559,
+	/**
+	 * 3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU410 = 0x39555659,
+	/**
+	 * 3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV411 = 0x31315559,
+	/**
+	 * 3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU411 = 0x31315659,
+	/**
+	 * 3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV420 = 0x32315559,
+	/**
+	 * 3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU420 = 0x32315659,
+	/**
+	 * 3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV422 = 0x36315559,
+	/**
+	 * 3 plane YCbCr format, 2x1 subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU422 = 0x36315659,
+	/**
+	 * 3 plane YCbCr format, non-subsampled Cb (1) and Cr (2) planes
+	 */
+	WL_SHM_FORMAT_YUV444 = 0x34325559,
+	/**
+	 * 3 plane YCbCr format, non-subsampled Cr (1) and Cb (2) planes
+	 */
+	WL_SHM_FORMAT_YVU444 = 0x34325659,
+};
+/**
+ * @ingroup iface_wl_shm
+ * Validate a wl_shm format value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_shm_format
+ */
+static inline bool
+wl_shm_format_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SHM_FORMAT_ARGB8888:
+		return version >= 1;
+	case WL_SHM_FORMAT_XRGB8888:
+		return version >= 1;
+	case WL_SHM_FORMAT_C8:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGB332:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGR233:
+		return version >= 1;
+	case WL_SHM_FORMAT_XRGB4444:
+		return version >= 1;
+	case WL_SHM_FORMAT_XBGR4444:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGBX4444:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGRX4444:
+		return version >= 1;
+	case WL_SHM_FORMAT_ARGB4444:
+		return version >= 1;
+	case WL_SHM_FORMAT_ABGR4444:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGBA4444:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGRA4444:
+		return version >= 1;
+	case WL_SHM_FORMAT_XRGB1555:
+		return version >= 1;
+	case WL_SHM_FORMAT_XBGR1555:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGBX5551:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGRX5551:
+		return version >= 1;
+	case WL_SHM_FORMAT_ARGB1555:
+		return version >= 1;
+	case WL_SHM_FORMAT_ABGR1555:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGBA5551:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGRA5551:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGB565:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGR565:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGB888:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGR888:
+		return version >= 1;
+	case WL_SHM_FORMAT_XBGR8888:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGBX8888:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGRX8888:
+		return version >= 1;
+	case WL_SHM_FORMAT_ABGR8888:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGBA8888:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGRA8888:
+		return version >= 1;
+	case WL_SHM_FORMAT_XRGB2101010:
+		return version >= 1;
+	case WL_SHM_FORMAT_XBGR2101010:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGBX1010102:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGRX1010102:
+		return version >= 1;
+	case WL_SHM_FORMAT_ARGB2101010:
+		return version >= 1;
+	case WL_SHM_FORMAT_ABGR2101010:
+		return version >= 1;
+	case WL_SHM_FORMAT_RGBA1010102:
+		return version >= 1;
+	case WL_SHM_FORMAT_BGRA1010102:
+		return version >= 1;
+	case WL_SHM_FORMAT_YUYV:
+		return version >= 1;
+	case WL_SHM_FORMAT_YVYU:
+		return version >= 1;
+	case WL_SHM_FORMAT_UYVY:
+		return version >= 1;
+	case WL_SHM_FORMAT_VYUY:
+		return version >= 1;
+	case WL_SHM_FORMAT_AYUV:
+		return version >= 1;
+	case WL_SHM_FORMAT_NV12:
+		return version >= 1;
+	case WL_SHM_FORMAT_NV21:
+		return version >= 1;
+	case WL_SHM_FORMAT_NV16:
+		return version >= 1;
+	case WL_SHM_FORMAT_NV61:
+		return version >= 1;
+	case WL_SHM_FORMAT_YUV410:
+		return version >= 1;
+	case WL_SHM_FORMAT_YVU410:
+		return version >= 1;
+	case WL_SHM_FORMAT_YUV411:
+		return version >= 1;
+	case WL_SHM_FORMAT_YVU411:
+		return version >= 1;
+	case WL_SHM_FORMAT_YUV420:
+		return version >= 1;
+	case WL_SHM_FORMAT_YVU420:
+		return version >= 1;
+	case WL_SHM_FORMAT_YUV422:
+		return version >= 1;
+	case WL_SHM_FORMAT_YVU422:
+		return version >= 1;
+	case WL_SHM_FORMAT_YUV444:
+		return version >= 1;
+	case WL_SHM_FORMAT_YVU444:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SHM_FORMAT_ENUM */
+
+/**
+ * @ingroup iface_wl_shm
+ * @struct wl_shm_interface
+ */
+struct wl_shm_interface {
+	/**
+	 * create a shm pool
+	 *
+	 * Create a new wl_shm_pool object.
+	 *
+	 * The pool can be used to create shared memory based buffer
+	 * objects. The server will mmap size bytes of the passed file
+	 * descriptor, to use as backing memory for the pool.
+	 * @param id pool to create
+	 * @param fd file descriptor for the pool
+	 * @param size pool size, in bytes
+	 */
+	void (*create_pool)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    uint32_t id,
+			    int32_t fd,
+			    int32_t size);
+};
+
+#define WL_SHM_FORMAT 0
+
+/**
+ * @ingroup iface_wl_shm
+ */
+#define WL_SHM_FORMAT_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_shm
+ */
+#define WL_SHM_CREATE_POOL_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_shm
+ * Sends an format event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param format buffer pixel format
+ */
+static inline void
+wl_shm_send_format(struct wl_resource *resource_, uint32_t format)
+{
+	wl_resource_post_event(resource_, WL_SHM_FORMAT, format);
+}
+
+/**
+ * @ingroup iface_wl_buffer
+ * @struct wl_buffer_interface
+ */
+struct wl_buffer_interface {
+	/**
+	 * destroy a buffer
+	 *
+	 * Destroy a buffer. If and how you need to release the backing
+	 * storage is defined by the buffer factory interface.
+	 *
+	 * For possible side-effects to a surface, see wl_surface.attach.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_BUFFER_RELEASE 0
+
+/**
+ * @ingroup iface_wl_buffer
+ */
+#define WL_BUFFER_RELEASE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_buffer
+ */
+#define WL_BUFFER_DESTROY_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_buffer
+ * Sends an release event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_buffer_send_release(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_BUFFER_RELEASE);
+}
+
+#ifndef WL_DATA_OFFER_ERROR_ENUM
+#define WL_DATA_OFFER_ERROR_ENUM
+enum wl_data_offer_error {
+	/**
+	 * finish request was called untimely
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_FINISH = 0,
+	/**
+	 * action mask contains invalid values
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK = 1,
+	/**
+	 * action argument has an invalid value
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_ACTION = 2,
+	/**
+	 * offer doesn't accept this request
+	 */
+	WL_DATA_OFFER_ERROR_INVALID_OFFER = 3,
+};
+/**
+ * @ingroup iface_wl_data_offer
+ * Validate a wl_data_offer error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_data_offer_error
+ */
+static inline bool
+wl_data_offer_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_DATA_OFFER_ERROR_INVALID_FINISH:
+		return version >= 1;
+	case WL_DATA_OFFER_ERROR_INVALID_ACTION_MASK:
+		return version >= 1;
+	case WL_DATA_OFFER_ERROR_INVALID_ACTION:
+		return version >= 1;
+	case WL_DATA_OFFER_ERROR_INVALID_OFFER:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_DATA_OFFER_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_data_offer
+ * @struct wl_data_offer_interface
+ */
+struct wl_data_offer_interface {
+	/**
+	 * accept one of the offered mime types
+	 *
+	 * Indicate that the client can accept the given mime type, or
+	 * NULL for not accepted.
+	 *
+	 * For objects of version 2 or older, this request is used by the
+	 * client to give feedback whether the client can receive the given
+	 * mime type, or NULL if none is accepted; the feedback does not
+	 * determine whether the drag-and-drop operation succeeds or not.
+	 *
+	 * For objects of version 3 or newer, this request determines the
+	 * final result of the drag-and-drop operation. If the end result
+	 * is that no mime types were accepted, the drag-and-drop operation
+	 * will be cancelled and the corresponding drag source will receive
+	 * wl_data_source.cancelled. Clients may still use this event in
+	 * conjunction with wl_data_source.action for feedback.
+	 * @param serial serial number of the accept request
+	 * @param mime_type mime type accepted by the client
+	 */
+	void (*accept)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       uint32_t serial,
+		       const char *mime_type);
+	/**
+	 * request that the data is transferred
+	 *
+	 * To transfer the offered data, the client issues this request
+	 * and indicates the mime type it wants to receive. The transfer
+	 * happens through the passed file descriptor (typically created
+	 * with the pipe system call). The source client writes the data in
+	 * the mime type representation requested and then closes the file
+	 * descriptor.
+	 *
+	 * The receiving client reads from the read end of the pipe until
+	 * EOF and then closes its end, at which point the transfer is
+	 * complete.
+	 *
+	 * This request may happen multiple times for different mime types,
+	 * both before and after wl_data_device.drop. Drag-and-drop
+	 * destination clients may preemptively fetch data or examine it
+	 * more closely to determine acceptance.
+	 * @param mime_type mime type desired by receiver
+	 * @param fd file descriptor for data transfer
+	 */
+	void (*receive)(struct wl_client *client,
+			struct wl_resource *resource,
+			const char *mime_type,
+			int32_t fd);
+	/**
+	 * destroy data offer
+	 *
+	 * Destroy the data offer.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * the offer will no longer be used
+	 *
+	 * Notifies the compositor that the drag destination successfully
+	 * finished the drag-and-drop operation.
+	 *
+	 * Upon receiving this request, the compositor will emit
+	 * wl_data_source.dnd_finished on the drag source client.
+	 *
+	 * It is a client error to perform other requests than
+	 * wl_data_offer.destroy after this one. It is also an error to
+	 * perform 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.
+	 * @since 3
+	 */
+	void (*finish)(struct wl_client *client,
+		       struct wl_resource *resource);
+	/**
+	 * set the available/preferred drag-and-drop actions
+	 *
+	 * Sets the actions that the destination side client supports for
+	 * this operation. This request may trigger the emission of
+	 * wl_data_source.action and wl_data_offer.action events if the
+	 * compositor needs to change the selected action.
+	 *
+	 * This request can be called multiple times throughout the
+	 * drag-and-drop operation, typically in response to
+	 * wl_data_device.enter or wl_data_device.motion events.
+	 *
+	 * 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 dnd_actions argument must contain only values expressed in
+	 * the wl_data_device_manager.dnd_actions enum, and the
+	 * preferred_action argument must only contain one of those values
+	 * set, otherwise it will result in a protocol error.
+	 *
+	 * While managing an "ask" action, the destination drag-and-drop
+	 * client may perform further wl_data_offer.receive requests, and
+	 * is expected to perform one last wl_data_offer.set_actions
+	 * request with a preferred action other than "ask" (and optionally
+	 * wl_data_offer.accept) before requesting wl_data_offer.finish, in
+	 * order to convey the action selected by the user. If the
+	 * preferred action is not in the wl_data_offer.source_actions
+	 * mask, an error will be raised.
+	 *
+	 * If the "ask" action is dismissed (e.g. user cancellation), the
+	 * client is expected to perform wl_data_offer.destroy right away.
+	 *
+	 * This request can only be made on drag-and-drop offers, a
+	 * protocol error will be raised otherwise.
+	 * @param dnd_actions actions supported by the destination client
+	 * @param preferred_action action preferred by the destination client
+	 * @since 3
+	 */
+	void (*set_actions)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    uint32_t dnd_actions,
+			    uint32_t preferred_action);
+};
+
+#define WL_DATA_OFFER_OFFER 0
+#define WL_DATA_OFFER_SOURCE_ACTIONS 1
+#define WL_DATA_OFFER_ACTION 2
+
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_OFFER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_SOURCE_ACTIONS_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_ACTION_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_ACCEPT_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_RECEIVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_FINISH_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_data_offer
+ */
+#define WL_DATA_OFFER_SET_ACTIONS_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_data_offer
+ * Sends an offer event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param mime_type offered mime type
+ */
+static inline void
+wl_data_offer_send_offer(struct wl_resource *resource_, const char *mime_type)
+{
+	wl_resource_post_event(resource_, WL_DATA_OFFER_OFFER, mime_type);
+}
+
+/**
+ * @ingroup iface_wl_data_offer
+ * Sends an source_actions event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param source_actions actions offered by the data source
+ */
+static inline void
+wl_data_offer_send_source_actions(struct wl_resource *resource_, uint32_t source_actions)
+{
+	wl_resource_post_event(resource_, WL_DATA_OFFER_SOURCE_ACTIONS, source_actions);
+}
+
+/**
+ * @ingroup iface_wl_data_offer
+ * Sends an action event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param dnd_action action selected by the compositor
+ */
+static inline void
+wl_data_offer_send_action(struct wl_resource *resource_, uint32_t dnd_action)
+{
+	wl_resource_post_event(resource_, WL_DATA_OFFER_ACTION, dnd_action);
+}
+
+#ifndef WL_DATA_SOURCE_ERROR_ENUM
+#define WL_DATA_SOURCE_ERROR_ENUM
+enum wl_data_source_error {
+	/**
+	 * action mask contains invalid values
+	 */
+	WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK = 0,
+	/**
+	 * source doesn't accept this request
+	 */
+	WL_DATA_SOURCE_ERROR_INVALID_SOURCE = 1,
+};
+/**
+ * @ingroup iface_wl_data_source
+ * Validate a wl_data_source error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_data_source_error
+ */
+static inline bool
+wl_data_source_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_DATA_SOURCE_ERROR_INVALID_ACTION_MASK:
+		return version >= 1;
+	case WL_DATA_SOURCE_ERROR_INVALID_SOURCE:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_DATA_SOURCE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_data_source
+ * @struct wl_data_source_interface
+ */
+struct wl_data_source_interface {
+	/**
+	 * add an offered mime type
+	 *
+	 * This request adds a mime type to the set of mime types
+	 * advertised to targets. Can be called several times to offer
+	 * multiple types.
+	 * @param mime_type mime type offered by the data source
+	 */
+	void (*offer)(struct wl_client *client,
+		      struct wl_resource *resource,
+		      const char *mime_type);
+	/**
+	 * destroy the data source
+	 *
+	 * Destroy the data source.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * set the available drag-and-drop actions
+	 *
+	 * Sets the actions that the source side client supports for this
+	 * operation. This request may trigger wl_data_source.action and
+	 * wl_data_offer.action events if the compositor needs to change
+	 * the selected action.
+	 *
+	 * The dnd_actions argument must contain only values expressed in
+	 * the wl_data_device_manager.dnd_actions enum, otherwise it will
+	 * result in a protocol error.
+	 *
+	 * This request must be made once only, and can only be made on
+	 * sources used in drag-and-drop, so it must be performed before
+	 * wl_data_device.start_drag. Attempting to use the source other
+	 * than for drag-and-drop will raise a protocol error.
+	 * @param dnd_actions actions supported by the data source
+	 * @since 3
+	 */
+	void (*set_actions)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    uint32_t dnd_actions);
+};
+
+#define WL_DATA_SOURCE_TARGET 0
+#define WL_DATA_SOURCE_SEND 1
+#define WL_DATA_SOURCE_CANCELLED 2
+#define WL_DATA_SOURCE_DND_DROP_PERFORMED 3
+#define WL_DATA_SOURCE_DND_FINISHED 4
+#define WL_DATA_SOURCE_ACTION 5
+
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_TARGET_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_SEND_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_CANCELLED_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_DND_DROP_PERFORMED_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_DND_FINISHED_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_ACTION_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_OFFER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_source
+ */
+#define WL_DATA_SOURCE_SET_ACTIONS_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_data_source
+ * Sends an target event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param mime_type mime type accepted by the target
+ */
+static inline void
+wl_data_source_send_target(struct wl_resource *resource_, const char *mime_type)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_TARGET, mime_type);
+}
+
+/**
+ * @ingroup iface_wl_data_source
+ * Sends an send event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param mime_type mime type for the data
+ * @param fd file descriptor for the data
+ */
+static inline void
+wl_data_source_send_send(struct wl_resource *resource_, const char *mime_type, int32_t fd)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_SEND, mime_type, fd);
+}
+
+/**
+ * @ingroup iface_wl_data_source
+ * Sends an cancelled event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_data_source_send_cancelled(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_CANCELLED);
+}
+
+/**
+ * @ingroup iface_wl_data_source
+ * Sends an dnd_drop_performed event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_data_source_send_dnd_drop_performed(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_DND_DROP_PERFORMED);
+}
+
+/**
+ * @ingroup iface_wl_data_source
+ * Sends an dnd_finished event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_data_source_send_dnd_finished(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_DND_FINISHED);
+}
+
+/**
+ * @ingroup iface_wl_data_source
+ * Sends an action event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param dnd_action action selected by the compositor
+ */
+static inline void
+wl_data_source_send_action(struct wl_resource *resource_, uint32_t dnd_action)
+{
+	wl_resource_post_event(resource_, WL_DATA_SOURCE_ACTION, dnd_action);
+}
+
+#ifndef WL_DATA_DEVICE_ERROR_ENUM
+#define WL_DATA_DEVICE_ERROR_ENUM
+enum wl_data_device_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_DATA_DEVICE_ERROR_ROLE = 0,
+};
+/**
+ * @ingroup iface_wl_data_device
+ * Validate a wl_data_device error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_data_device_error
+ */
+static inline bool
+wl_data_device_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_DATA_DEVICE_ERROR_ROLE:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_DATA_DEVICE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_data_device
+ * @struct wl_data_device_interface
+ */
+struct wl_data_device_interface {
+	/**
+	 * start drag-and-drop operation
+	 *
+	 * This request asks the compositor to start a drag-and-drop
+	 * operation on behalf of the client.
+	 *
+	 * The source argument is the data source that provides the data
+	 * 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.
+	 *
+	 * The origin surface is the surface where the drag originates and
+	 * the client must have an active implicit grab that matches the
+	 * serial.
+	 *
+	 * The icon surface is an optional (can be NULL) surface that
+	 * provides an icon to be moved around with the cursor. Initially,
+	 * the top-left corner of the icon surface is placed at the cursor
+	 * hotspot, but subsequent wl_surface.attach request can move the
+	 * relative position. Attach requests must be confirmed with
+	 * wl_surface.commit as usual. The icon surface is given the role
+	 * of a drag-and-drop icon. If the icon surface already has another
+	 * role, it raises a protocol error.
+	 *
+	 * The current and pending input regions of the icon wl_surface are
+	 * cleared, and wl_surface.set_input_region is ignored until the
+	 * wl_surface is no longer used as the icon surface. When the use
+	 * as an icon ends, the current and pending input regions become
+	 * undefined, and the wl_surface is unmapped.
+	 * @param source data source for the eventual transfer
+	 * @param origin surface where the drag originates
+	 * @param icon drag-and-drop icon surface
+	 * @param serial serial number of the implicit grab on the origin
+	 */
+	void (*start_drag)(struct wl_client *client,
+			   struct wl_resource *resource,
+			   struct wl_resource *source,
+			   struct wl_resource *origin,
+			   struct wl_resource *icon,
+			   uint32_t serial);
+	/**
+	 * copy data to the selection
+	 *
+	 * This request asks the compositor to set the selection to the
+	 * data from the source on behalf of the client.
+	 *
+	 * To unset the selection, set the source to NULL.
+	 * @param source data source for the selection
+	 * @param serial serial number of the event that triggered this request
+	 */
+	void (*set_selection)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *source,
+			      uint32_t serial);
+	/**
+	 * destroy data device
+	 *
+	 * This request destroys the data device.
+	 * @since 2
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_DATA_DEVICE_DATA_OFFER 0
+#define WL_DATA_DEVICE_ENTER 1
+#define WL_DATA_DEVICE_LEAVE 2
+#define WL_DATA_DEVICE_MOTION 3
+#define WL_DATA_DEVICE_DROP 4
+#define WL_DATA_DEVICE_SELECTION 5
+
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_DATA_OFFER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_ENTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_LEAVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_MOTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_DROP_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_SELECTION_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_START_DRAG_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_SET_SELECTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device
+ */
+#define WL_DATA_DEVICE_RELEASE_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_wl_data_device
+ * Sends an data_offer event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param id the new data_offer object
+ */
+static inline void
+wl_data_device_send_data_offer(struct wl_resource *resource_, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_DATA_OFFER, id);
+}
+
+/**
+ * @ingroup iface_wl_data_device
+ * Sends an enter event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the enter event
+ * @param surface client surface entered
+ * @param x surface-local x coordinate
+ * @param y surface-local y coordinate
+ * @param id source data_offer object
+ */
+static inline void
+wl_data_device_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t x, wl_fixed_t y, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_ENTER, serial, surface, x, y, id);
+}
+
+/**
+ * @ingroup iface_wl_data_device
+ * Sends an leave event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_data_device_send_leave(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_LEAVE);
+}
+
+/**
+ * @ingroup iface_wl_data_device
+ * Sends an motion event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param x surface-local x coordinate
+ * @param y surface-local y coordinate
+ */
+static inline void
+wl_data_device_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_MOTION, time, x, y);
+}
+
+/**
+ * @ingroup iface_wl_data_device
+ * Sends an drop event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_data_device_send_drop(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_DROP);
+}
+
+/**
+ * @ingroup iface_wl_data_device
+ * Sends an selection event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param id selection data_offer object
+ */
+static inline void
+wl_data_device_send_selection(struct wl_resource *resource_, struct wl_resource *id)
+{
+	wl_resource_post_event(resource_, WL_DATA_DEVICE_SELECTION, id);
+}
+
+#ifndef WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
+#define WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM
+/**
+ * @ingroup iface_wl_data_device_manager
+ * drag and drop actions
+ *
+ * This is a bitmask of the available/preferred actions in a
+ * drag-and-drop operation.
+ *
+ * In the compositor, the selected action is a result of matching the
+ * actions offered by the source and destination sides.  "action" events
+ * with a "none" action will be sent to both source and destination if
+ * there is no match. All further checks will effectively happen on
+ * (source actions ∩ destination actions).
+ *
+ * In addition, compositors may also pick different actions in
+ * reaction to key modifiers being pressed. One common design that
+ * is used in major toolkits (and the behavior recommended for
+ * compositors) is:
+ *
+ * - If no modifiers are pressed, the first match (in bit order)
+ * will be used.
+ * - Pressing Shift selects "move", if enabled in the mask.
+ * - Pressing Control selects "copy", if enabled in the mask.
+ *
+ * Behavior beyond that is considered implementation-dependent.
+ * Compositors may for example bind other modifiers (like Alt/Meta)
+ * or drags initiated with other buttons than BTN_LEFT to specific
+ * actions (e.g. "ask").
+ */
+enum wl_data_device_manager_dnd_action {
+	/**
+	 * no action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE = 0,
+	/**
+	 * copy action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY = 1,
+	/**
+	 * move action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE = 2,
+	/**
+	 * ask action
+	 */
+	WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK = 4,
+};
+/**
+ * @ingroup iface_wl_data_device_manager
+ * Validate a wl_data_device_manager dnd_action value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_data_device_manager_dnd_action
+ */
+static inline bool
+wl_data_device_manager_dnd_action_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
+		return version >= 1;
+	case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
+		return version >= 1;
+	case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
+		return version >= 1;
+	case WL_DATA_DEVICE_MANAGER_DND_ACTION_ASK:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_DATA_DEVICE_MANAGER_DND_ACTION_ENUM */
+
+/**
+ * @ingroup iface_wl_data_device_manager
+ * @struct wl_data_device_manager_interface
+ */
+struct wl_data_device_manager_interface {
+	/**
+	 * create a new data source
+	 *
+	 * Create a new data source.
+	 * @param id data source to create
+	 */
+	void (*create_data_source)(struct wl_client *client,
+				   struct wl_resource *resource,
+				   uint32_t id);
+	/**
+	 * create a new data device
+	 *
+	 * Create a new data device for a given seat.
+	 * @param id data device to create
+	 * @param seat seat associated with the data device
+	 */
+	void (*get_data_device)(struct wl_client *client,
+				struct wl_resource *resource,
+				uint32_t id,
+				struct wl_resource *seat);
+};
+
+
+/**
+ * @ingroup iface_wl_data_device_manager
+ */
+#define WL_DATA_DEVICE_MANAGER_CREATE_DATA_SOURCE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_data_device_manager
+ */
+#define WL_DATA_DEVICE_MANAGER_GET_DATA_DEVICE_SINCE_VERSION 1
+
+#ifndef WL_SHELL_ERROR_ENUM
+#define WL_SHELL_ERROR_ENUM
+enum wl_shell_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_SHELL_ERROR_ROLE = 0,
+};
+/**
+ * @ingroup iface_wl_shell
+ * Validate a wl_shell error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_shell_error
+ */
+static inline bool
+wl_shell_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SHELL_ERROR_ROLE:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SHELL_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_shell
+ * @struct wl_shell_interface
+ */
+struct wl_shell_interface {
+	/**
+	 * create a shell surface from a surface
+	 *
+	 * Create a shell surface for an existing surface. This gives the
+	 * wl_surface the role of a shell surface. If the wl_surface
+	 * already has another role, it raises a protocol error.
+	 *
+	 * Only one shell surface can be associated with a given surface.
+	 * @param id shell surface to create
+	 * @param surface surface to be given the shell surface role
+	 */
+	void (*get_shell_surface)(struct wl_client *client,
+				  struct wl_resource *resource,
+				  uint32_t id,
+				  struct wl_resource *surface);
+};
+
+
+/**
+ * @ingroup iface_wl_shell
+ */
+#define WL_SHELL_GET_SHELL_SURFACE_SINCE_VERSION 1
+
+#ifndef WL_SHELL_SURFACE_RESIZE_ENUM
+#define WL_SHELL_SURFACE_RESIZE_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * edge values for resizing
+ *
+ * These values are used to indicate which edge of a surface
+ * is being dragged in a resize operation. The server may
+ * use this information to adapt its behavior, e.g. choose
+ * an appropriate cursor image.
+ */
+enum wl_shell_surface_resize {
+	/**
+	 * no edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_NONE = 0,
+	/**
+	 * top edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP = 1,
+	/**
+	 * bottom edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM = 2,
+	/**
+	 * left edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_LEFT = 4,
+	/**
+	 * top and left edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP_LEFT = 5,
+	/**
+	 * bottom and left edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT = 6,
+	/**
+	 * right edge
+	 */
+	WL_SHELL_SURFACE_RESIZE_RIGHT = 8,
+	/**
+	 * top and right edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_TOP_RIGHT = 9,
+	/**
+	 * bottom and right edges
+	 */
+	WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT = 10,
+};
+/**
+ * @ingroup iface_wl_shell_surface
+ * Validate a wl_shell_surface resize value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_shell_surface_resize
+ */
+static inline bool
+wl_shell_surface_resize_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SHELL_SURFACE_RESIZE_NONE:
+		return version >= 1;
+	case WL_SHELL_SURFACE_RESIZE_TOP:
+		return version >= 1;
+	case WL_SHELL_SURFACE_RESIZE_BOTTOM:
+		return version >= 1;
+	case WL_SHELL_SURFACE_RESIZE_LEFT:
+		return version >= 1;
+	case WL_SHELL_SURFACE_RESIZE_TOP_LEFT:
+		return version >= 1;
+	case WL_SHELL_SURFACE_RESIZE_BOTTOM_LEFT:
+		return version >= 1;
+	case WL_SHELL_SURFACE_RESIZE_RIGHT:
+		return version >= 1;
+	case WL_SHELL_SURFACE_RESIZE_TOP_RIGHT:
+		return version >= 1;
+	case WL_SHELL_SURFACE_RESIZE_BOTTOM_RIGHT:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SHELL_SURFACE_RESIZE_ENUM */
+
+#ifndef WL_SHELL_SURFACE_TRANSIENT_ENUM
+#define WL_SHELL_SURFACE_TRANSIENT_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * details of transient behaviour
+ *
+ * These flags specify details of the expected behaviour
+ * of transient surfaces. Used in the set_transient request.
+ */
+enum wl_shell_surface_transient {
+	/**
+	 * do not set keyboard focus
+	 */
+	WL_SHELL_SURFACE_TRANSIENT_INACTIVE = 0x1,
+};
+/**
+ * @ingroup iface_wl_shell_surface
+ * Validate a wl_shell_surface transient value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_shell_surface_transient
+ */
+static inline bool
+wl_shell_surface_transient_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SHELL_SURFACE_TRANSIENT_INACTIVE:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SHELL_SURFACE_TRANSIENT_ENUM */
+
+#ifndef WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+#define WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM
+/**
+ * @ingroup iface_wl_shell_surface
+ * different method to set the surface fullscreen
+ *
+ * Hints to indicate to the compositor how to deal with a conflict
+ * between the dimensions of the surface and the dimensions of the
+ * output. The compositor is free to ignore this parameter.
+ */
+enum wl_shell_surface_fullscreen_method {
+	/**
+	 * no preference, apply default policy
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT = 0,
+	/**
+	 * scale, preserve the surface's aspect ratio and center on output
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE = 1,
+	/**
+	 * switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER = 2,
+	/**
+	 * no upscaling, center on output and add black borders to compensate size mismatch
+	 */
+	WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL = 3,
+};
+/**
+ * @ingroup iface_wl_shell_surface
+ * Validate a wl_shell_surface fullscreen_method value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_shell_surface_fullscreen_method
+ */
+static inline bool
+wl_shell_surface_fullscreen_method_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DEFAULT:
+		return version >= 1;
+	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_SCALE:
+		return version >= 1;
+	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_DRIVER:
+		return version >= 1;
+	case WL_SHELL_SURFACE_FULLSCREEN_METHOD_FILL:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SHELL_SURFACE_FULLSCREEN_METHOD_ENUM */
+
+/**
+ * @ingroup iface_wl_shell_surface
+ * @struct wl_shell_surface_interface
+ */
+struct wl_shell_surface_interface {
+	/**
+	 * respond to a ping event
+	 *
+	 * A client must respond to a ping event with a pong request or
+	 * the client may be deemed unresponsive.
+	 * @param serial serial number of the ping event
+	 */
+	void (*pong)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     uint32_t serial);
+	/**
+	 * start an interactive move
+	 *
+	 * Start a pointer-driven move of the surface.
+	 *
+	 * This request must be used in response to a button press event.
+	 * The server may ignore move requests depending on the state of
+	 * the surface (e.g. fullscreen or maximized).
+	 * @param seat seat whose pointer is used
+	 * @param serial serial number of the implicit grab on the pointer
+	 */
+	void (*move)(struct wl_client *client,
+		     struct wl_resource *resource,
+		     struct wl_resource *seat,
+		     uint32_t serial);
+	/**
+	 * start an interactive resize
+	 *
+	 * Start a pointer-driven resizing of the surface.
+	 *
+	 * This request must be used in response to a button press event.
+	 * The server may ignore resize requests depending on the state of
+	 * the surface (e.g. fullscreen or maximized).
+	 * @param seat seat whose pointer is used
+	 * @param serial serial number of the implicit grab on the pointer
+	 * @param edges which edge or corner is being dragged
+	 */
+	void (*resize)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       struct wl_resource *seat,
+		       uint32_t serial,
+		       uint32_t edges);
+	/**
+	 * make the surface a toplevel surface
+	 *
+	 * Map the surface as a toplevel surface.
+	 *
+	 * A toplevel surface is not fullscreen, maximized or transient.
+	 */
+	void (*set_toplevel)(struct wl_client *client,
+			     struct wl_resource *resource);
+	/**
+	 * make the surface a transient surface
+	 *
+	 * Map the surface relative to an existing surface.
+	 *
+	 * The x and y arguments specify the location of the upper left
+	 * corner of the surface relative to the upper left corner of the
+	 * parent surface, in surface-local coordinates.
+	 *
+	 * The flags argument controls details of the transient behaviour.
+	 * @param parent parent surface
+	 * @param x surface-local x coordinate
+	 * @param y surface-local y coordinate
+	 * @param flags transient surface behavior
+	 */
+	void (*set_transient)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *parent,
+			      int32_t x,
+			      int32_t y,
+			      uint32_t flags);
+	/**
+	 * make the surface a fullscreen surface
+	 *
+	 * Map the surface as a fullscreen surface.
+	 *
+	 * If an output parameter is given then the surface will be made
+	 * fullscreen on that output. If the client does not specify the
+	 * output then the compositor will apply its policy - usually
+	 * choosing the output on which the surface has the biggest surface
+	 * area.
+	 *
+	 * The client may specify a method to resolve a size conflict
+	 * between the output size and the surface size - this is provided
+	 * through the method parameter.
+	 *
+	 * The framerate parameter is used only when the method is set to
+	 * "driver", to indicate the preferred framerate. A value of 0
+	 * indicates that the client does not care about framerate. The
+	 * framerate is specified in mHz, that is framerate of 60000 is
+	 * 60Hz.
+	 *
+	 * A method of "scale" or "driver" implies a scaling operation of
+	 * the surface, either via a direct scaling operation or a change
+	 * of the output mode. This will override any kind of output
+	 * scaling, so that mapping a surface with a buffer size equal to
+	 * the mode can fill the screen independent of buffer_scale.
+	 *
+	 * A method of "fill" means we don't scale up the buffer, however
+	 * any output scale is applied. This means that you may run into an
+	 * edge case where the application maps a buffer with the same size
+	 * of the output mode but buffer_scale 1 (thus making a surface
+	 * larger than the output). In this case it is allowed to downscale
+	 * the results to fit the screen.
+	 *
+	 * The compositor must reply to this request with a configure event
+	 * with the dimensions for the output on which the surface will be
+	 * made fullscreen.
+	 * @param method method for resolving size conflict
+	 * @param framerate framerate in mHz
+	 * @param output output on which the surface is to be fullscreen
+	 */
+	void (*set_fullscreen)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t method,
+			       uint32_t framerate,
+			       struct wl_resource *output);
+	/**
+	 * make the surface a popup surface
+	 *
+	 * Map the surface as a popup.
+	 *
+	 * A popup surface is a transient surface with an added pointer
+	 * grab.
+	 *
+	 * An existing implicit grab will be changed to owner-events mode,
+	 * and the popup grab will continue after the implicit grab ends
+	 * (i.e. releasing the mouse button does not cause the popup to be
+	 * unmapped).
+	 *
+	 * The popup grab continues until the window is destroyed or a
+	 * mouse button is pressed in any other client's window. A click in
+	 * any of the client's surfaces is reported as normal, however,
+	 * clicks in other clients' surfaces will be discarded and trigger
+	 * the callback.
+	 *
+	 * The x and y arguments specify the location of the upper left
+	 * corner of the surface relative to the upper left corner of the
+	 * parent surface, in surface-local coordinates.
+	 * @param seat seat whose pointer is used
+	 * @param serial serial number of the implicit grab on the pointer
+	 * @param parent parent surface
+	 * @param x surface-local x coordinate
+	 * @param y surface-local y coordinate
+	 * @param flags transient surface behavior
+	 */
+	void (*set_popup)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  struct wl_resource *seat,
+			  uint32_t serial,
+			  struct wl_resource *parent,
+			  int32_t x,
+			  int32_t y,
+			  uint32_t flags);
+	/**
+	 * make the surface a maximized surface
+	 *
+	 * Map the surface as a maximized surface.
+	 *
+	 * If an output parameter is given then the surface will be
+	 * maximized on that output. If the client does not specify the
+	 * output then the compositor will apply its policy - usually
+	 * choosing the output on which the surface has the biggest surface
+	 * area.
+	 *
+	 * The compositor will reply with a configure event telling the
+	 * expected new surface size. The operation is completed on the
+	 * next buffer attach to this surface.
+	 *
+	 * A maximized surface typically fills the entire output it is
+	 * bound to, except for desktop elements such as panels. This is
+	 * the main difference between a maximized shell surface and a
+	 * fullscreen shell surface.
+	 *
+	 * The details depend on the compositor implementation.
+	 * @param output output on which the surface is to be maximized
+	 */
+	void (*set_maximized)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      struct wl_resource *output);
+	/**
+	 * set surface title
+	 *
+	 * Set a short title for the surface.
+	 *
+	 * This string may be used to identify the surface in a task bar,
+	 * window list, or other user interface elements provided by the
+	 * compositor.
+	 *
+	 * The string must be encoded in UTF-8.
+	 * @param title surface title
+	 */
+	void (*set_title)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  const char *title);
+	/**
+	 * set surface class
+	 *
+	 * Set a class for the surface.
+	 *
+	 * The surface class identifies the general class of applications
+	 * to which the surface belongs. A common convention is to use the
+	 * file name (or the full path if it is a non-standard location) of
+	 * the application's .desktop file as the class.
+	 * @param class_ surface class
+	 */
+	void (*set_class)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  const char *class_);
+};
+
+#define WL_SHELL_SURFACE_PING 0
+#define WL_SHELL_SURFACE_CONFIGURE 1
+#define WL_SHELL_SURFACE_POPUP_DONE 2
+
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_PING_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_CONFIGURE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_POPUP_DONE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_PONG_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_MOVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_RESIZE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_TOPLEVEL_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_TRANSIENT_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_FULLSCREEN_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_POPUP_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_MAXIMIZED_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_TITLE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_shell_surface
+ */
+#define WL_SHELL_SURFACE_SET_CLASS_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_shell_surface
+ * Sends an ping event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the ping
+ */
+static inline void
+wl_shell_surface_send_ping(struct wl_resource *resource_, uint32_t serial)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_PING, serial);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ * Sends an configure event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param edges how the surface was resized
+ * @param width new width of the surface
+ * @param height new height of the surface
+ */
+static inline void
+wl_shell_surface_send_configure(struct wl_resource *resource_, uint32_t edges, int32_t width, int32_t height)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_CONFIGURE, edges, width, height);
+}
+
+/**
+ * @ingroup iface_wl_shell_surface
+ * Sends an popup_done event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_shell_surface_send_popup_done(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_SHELL_SURFACE_POPUP_DONE);
+}
+
+#ifndef WL_SURFACE_ERROR_ENUM
+#define WL_SURFACE_ERROR_ENUM
+/**
+ * @ingroup iface_wl_surface
+ * wl_surface error values
+ *
+ * These errors can be emitted in response to wl_surface requests.
+ */
+enum wl_surface_error {
+	/**
+	 * buffer scale value is invalid
+	 */
+	WL_SURFACE_ERROR_INVALID_SCALE = 0,
+	/**
+	 * buffer transform value is invalid
+	 */
+	WL_SURFACE_ERROR_INVALID_TRANSFORM = 1,
+};
+/**
+ * @ingroup iface_wl_surface
+ * Validate a wl_surface error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_surface_error
+ */
+static inline bool
+wl_surface_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SURFACE_ERROR_INVALID_SCALE:
+		return version >= 1;
+	case WL_SURFACE_ERROR_INVALID_TRANSFORM:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SURFACE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_surface
+ * @struct wl_surface_interface
+ */
+struct wl_surface_interface {
+	/**
+	 * delete surface
+	 *
+	 * Deletes the surface and invalidates its object ID.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * set the surface contents
+	 *
+	 * Set a buffer as the content of this surface.
+	 *
+	 * 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.
+	 *
+	 * The x and y arguments specify the location of the new pending
+	 * buffer's upper left corner, relative to the current buffer's
+	 * upper left corner, in surface-local coordinates. In other words,
+	 * the x and y, combined with the new surface size define in which
+	 * directions the surface's size changes.
+	 *
+	 * Surface contents are double-buffered state, see
+	 * wl_surface.commit.
+	 *
+	 * The initial surface contents are void; there is no content.
+	 * wl_surface.attach assigns the given wl_buffer as the pending
+	 * wl_buffer. wl_surface.commit makes the pending wl_buffer the new
+	 * surface contents, and the size of the surface becomes the size
+	 * calculated from the wl_buffer, as described above. After commit,
+	 * there is no pending buffer until the next attach.
+	 *
+	 * Committing a pending wl_buffer allows the compositor to read the
+	 * pixels in the wl_buffer. The compositor may access the pixels at
+	 * any time after the wl_surface.commit request. When the
+	 * compositor will not access the pixels anymore, it will send the
+	 * wl_buffer.release event. Only after receiving wl_buffer.release,
+	 * the client may reuse the wl_buffer. A wl_buffer that has been
+	 * attached and then replaced by another attach instead of
+	 * committed will not receive a release event, and is not used by
+	 * the compositor.
+	 *
+	 * 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 contents become undefined immediately.
+	 *
+	 * If wl_surface.attach is sent with a NULL wl_buffer, the
+	 * following wl_surface.commit will remove the surface content.
+	 * @param buffer buffer of surface contents
+	 * @param x surface-local x coordinate
+	 * @param y surface-local y coordinate
+	 */
+	void (*attach)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       struct wl_resource *buffer,
+		       int32_t x,
+		       int32_t y);
+	/**
+	 * mark part of the surface damaged
+	 *
+	 * This request is used to describe the regions where the pending
+	 * buffer is different from the current surface contents, and where
+	 * the surface therefore needs to be repainted. The compositor
+	 * ignores the parts of the damage that fall outside of the
+	 * surface.
+	 *
+	 * Damage is double-buffered state, see wl_surface.commit.
+	 *
+	 * The damage rectangle is specified in surface-local coordinates,
+	 * where x and y specify the upper left corner of the damage
+	 * rectangle.
+	 *
+	 * The initial value for pending damage is empty: no damage.
+	 * wl_surface.damage adds pending damage: the new pending damage is
+	 * the union of old pending damage and the given rectangle.
+	 *
+	 * wl_surface.commit assigns pending damage as the current damage,
+	 * and clears pending damage. The server will clear the current
+	 * damage as it repaints the surface.
+	 *
+	 * Alternatively, damage can be posted with
+	 * wl_surface.damage_buffer which uses buffer coordinates instead
+	 * of surface coordinates, and is probably the preferred and
+	 * intuitive way of doing this.
+	 * @param x surface-local x coordinate
+	 * @param y surface-local y coordinate
+	 * @param width width of damage rectangle
+	 * @param height height of damage rectangle
+	 */
+	void (*damage)(struct wl_client *client,
+		       struct wl_resource *resource,
+		       int32_t x,
+		       int32_t y,
+		       int32_t width,
+		       int32_t height);
+	/**
+	 * request a frame throttling hint
+	 *
+	 * Request a notification when it is a good time to start drawing
+	 * a new frame, by creating a frame callback. This is useful for
+	 * throttling redrawing operations, and driving animations.
+	 *
+	 * When a client is animating on a wl_surface, it can use the
+	 * 'frame' request to get notified when it is a good time to draw
+	 * and commit the next frame of animation. If the client commits an
+	 * update earlier than that, it is likely that some updates will
+	 * not make it to the display, and the client is wasting resources
+	 * by drawing too often.
+	 *
+	 * The frame request will take effect on the next
+	 * wl_surface.commit. The notification will only be posted for one
+	 * frame unless requested again. For a wl_surface, the
+	 * notifications are posted in the order the frame requests were
+	 * committed.
+	 *
+	 * The server must send the notifications so that a client will not
+	 * send excessive updates, while still allowing the highest
+	 * possible update rate for clients that wait for the reply before
+	 * drawing again. The server should give some time for the client
+	 * to draw and commit after sending the frame callback events to
+	 * let it hit the next output refresh.
+	 *
+	 * A server should avoid signaling the frame callbacks if the
+	 * surface is not visible in any way, e.g. the surface is
+	 * off-screen, or completely obscured by other opaque surfaces.
+	 *
+	 * The object returned by this request will be destroyed by the
+	 * compositor after the callback is fired and as such the client
+	 * must not attempt to use it after that point.
+	 *
+	 * The callback_data passed in the callback is the current time, in
+	 * milliseconds, with an undefined base.
+	 * @param callback callback object for the frame request
+	 */
+	void (*frame)(struct wl_client *client,
+		      struct wl_resource *resource,
+		      uint32_t callback);
+	/**
+	 * set opaque region
+	 *
+	 * This request sets the region of the surface that contains
+	 * opaque content.
+	 *
+	 * The opaque region is an optimization hint for the compositor
+	 * that lets it optimize the redrawing of content behind opaque
+	 * regions. Setting an opaque region is not required for correct
+	 * behaviour, but marking transparent content as opaque will result
+	 * in repaint artifacts.
+	 *
+	 * The opaque region is specified in surface-local coordinates.
+	 *
+	 * The compositor ignores the parts of the opaque region that fall
+	 * outside of the surface.
+	 *
+	 * Opaque region is double-buffered state, see wl_surface.commit.
+	 *
+	 * wl_surface.set_opaque_region changes the pending opaque region.
+	 * wl_surface.commit copies the pending region to the current
+	 * region. Otherwise, the pending and current regions are never
+	 * changed.
+	 *
+	 * The initial value for an opaque region is empty. Setting the
+	 * pending opaque region has copy semantics, and the wl_region
+	 * object can be destroyed immediately. A NULL wl_region causes the
+	 * pending opaque region to be set to empty.
+	 * @param region opaque region of the surface
+	 */
+	void (*set_opaque_region)(struct wl_client *client,
+				  struct wl_resource *resource,
+				  struct wl_resource *region);
+	/**
+	 * set input region
+	 *
+	 * This request sets the region of the surface that can receive
+	 * pointer and touch events.
+	 *
+	 * Input events happening outside of this region will try the next
+	 * surface in the server surface stack. The compositor ignores the
+	 * parts of the input region that fall outside of the surface.
+	 *
+	 * The input region is specified in surface-local coordinates.
+	 *
+	 * Input region is double-buffered state, see wl_surface.commit.
+	 *
+	 * wl_surface.set_input_region changes the pending input region.
+	 * wl_surface.commit copies the pending region to the current
+	 * region. Otherwise the pending and current regions are never
+	 * changed, except cursor and icon surfaces are special cases, see
+	 * wl_pointer.set_cursor and wl_data_device.start_drag.
+	 *
+	 * The initial value for an input region is infinite. That means
+	 * the whole surface will accept input. Setting the pending input
+	 * region has copy semantics, and the wl_region object can be
+	 * destroyed immediately. A NULL wl_region causes the input region
+	 * to be set to infinite.
+	 * @param region input region of the surface
+	 */
+	void (*set_input_region)(struct wl_client *client,
+				 struct wl_resource *resource,
+				 struct wl_resource *region);
+	/**
+	 * commit pending surface state
+	 *
+	 * Surface state (input, opaque, and damage regions, attached
+	 * buffers, etc.) is double-buffered. Protocol requests modify the
+	 * pending state, as opposed to the current state in use by the
+	 * compositor. A commit request atomically applies all pending
+	 * state, replacing the current state. After commit, the new
+	 * pending state is as documented for each related request.
+	 *
+	 * On commit, a pending wl_buffer is applied first, and all other
+	 * state second. This means that all coordinates in double-buffered
+	 * state are relative to the new wl_buffer coming into use, except
+	 * for wl_surface.attach itself. If there is no pending wl_buffer,
+	 * the coordinates are relative to the current surface contents.
+	 *
+	 * All requests that need a commit to become effective are
+	 * documented to affect double-buffered state.
+	 *
+	 * Other interfaces may add further double-buffered surface state.
+	 */
+	void (*commit)(struct wl_client *client,
+		       struct wl_resource *resource);
+	/**
+	 * sets the buffer transformation
+	 *
+	 * This request sets an optional transformation on how the
+	 * compositor interprets the contents of the buffer attached to the
+	 * surface. The accepted values for the transform parameter are the
+	 * values for wl_output.transform.
+	 *
+	 * Buffer transform is double-buffered state, see
+	 * wl_surface.commit.
+	 *
+	 * A newly created surface has its buffer transformation set to
+	 * normal.
+	 *
+	 * wl_surface.set_buffer_transform changes the pending buffer
+	 * transformation. wl_surface.commit copies the pending buffer
+	 * transformation to the current one. Otherwise, the pending and
+	 * current values are never changed.
+	 *
+	 * The purpose of this request is to allow clients to render
+	 * content according to the output transform, thus permitting the
+	 * compositor to use certain optimizations even if the display is
+	 * rotated. Using hardware overlays and scanning out a client
+	 * buffer for fullscreen surfaces are examples of such
+	 * optimizations. Those optimizations are highly dependent on the
+	 * compositor implementation, so the use of this request should be
+	 * considered on a case-by-case basis.
+	 *
+	 * Note that if the transform value includes 90 or 270 degree
+	 * rotation, the width of the buffer will become the surface height
+	 * and the height of the buffer will become the surface width.
+	 *
+	 * If transform is not one of the values from the
+	 * wl_output.transform enum the invalid_transform protocol error is
+	 * raised.
+	 * @param transform transform for interpreting buffer contents
+	 * @since 2
+	 */
+	void (*set_buffer_transform)(struct wl_client *client,
+				     struct wl_resource *resource,
+				     int32_t transform);
+	/**
+	 * sets the buffer scaling factor
+	 *
+	 * This request sets an optional scaling factor on how the
+	 * compositor interprets the contents of the buffer attached to the
+	 * window.
+	 *
+	 * Buffer scale is double-buffered state, see wl_surface.commit.
+	 *
+	 * A newly created surface has its buffer scale set to 1.
+	 *
+	 * wl_surface.set_buffer_scale changes the pending buffer scale.
+	 * wl_surface.commit copies the pending buffer scale to the current
+	 * one. Otherwise, the pending and current values are never
+	 * changed.
+	 *
+	 * The purpose of this request is to allow clients to supply higher
+	 * resolution buffer data for use on high resolution outputs. It is
+	 * intended that you pick the same buffer scale as the scale of the
+	 * output that the surface is displayed on. This means the
+	 * compositor can avoid scaling when rendering the surface on that
+	 * output.
+	 *
+	 * Note that if the scale is larger than 1, then you have to attach
+	 * a buffer that is larger (by a factor of scale in each dimension)
+	 * than the desired surface size.
+	 *
+	 * If scale is not positive the invalid_scale protocol error is
+	 * raised.
+	 * @param scale positive scale for interpreting buffer contents
+	 * @since 3
+	 */
+	void (*set_buffer_scale)(struct wl_client *client,
+				 struct wl_resource *resource,
+				 int32_t scale);
+	/**
+	 * mark part of the surface damaged using buffer coordinates
+	 *
+	 * This request is used to describe the regions where the pending
+	 * buffer is different from the current surface contents, and where
+	 * the surface therefore needs to be repainted. The compositor
+	 * ignores the parts of the damage that fall outside of the
+	 * surface.
+	 *
+	 * Damage is double-buffered state, see wl_surface.commit.
+	 *
+	 * The damage rectangle is specified in buffer coordinates, where x
+	 * and y specify the upper left corner of the damage rectangle.
+	 *
+	 * The initial value for pending damage is empty: no damage.
+	 * wl_surface.damage_buffer adds pending damage: the new pending
+	 * damage is the union of old pending damage and the given
+	 * rectangle.
+	 *
+	 * wl_surface.commit assigns pending damage as the current damage,
+	 * and clears pending damage. The server will clear the current
+	 * damage as it repaints the surface.
+	 *
+	 * This request differs from wl_surface.damage in only one way - it
+	 * takes damage in buffer coordinates instead of surface-local
+	 * coordinates. While this generally is more intuitive than surface
+	 * coordinates, it is especially desirable when using wp_viewport
+	 * or when a drawing library (like EGL) is unaware of buffer scale
+	 * and buffer transform.
+	 *
+	 * Note: Because buffer transformation changes and damage requests
+	 * may be interleaved in the protocol stream, it is impossible to
+	 * determine the actual mapping between surface and buffer damage
+	 * until wl_surface.commit time. Therefore, compositors wishing to
+	 * take both kinds of damage into account will have to accumulate
+	 * damage from the two requests separately and only transform from
+	 * one to the other after receiving the wl_surface.commit.
+	 * @param x buffer-local x coordinate
+	 * @param y buffer-local y coordinate
+	 * @param width width of damage rectangle
+	 * @param height height of damage rectangle
+	 * @since 4
+	 */
+	void (*damage_buffer)(struct wl_client *client,
+			      struct wl_resource *resource,
+			      int32_t x,
+			      int32_t y,
+			      int32_t width,
+			      int32_t height);
+};
+
+#define WL_SURFACE_ENTER 0
+#define WL_SURFACE_LEAVE 1
+
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_ENTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_LEAVE_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_ATTACH_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_DAMAGE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_FRAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_SET_OPAQUE_REGION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_SET_INPUT_REGION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_COMMIT_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_SET_BUFFER_TRANSFORM_SINCE_VERSION 2
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_SET_BUFFER_SCALE_SINCE_VERSION 3
+/**
+ * @ingroup iface_wl_surface
+ */
+#define WL_SURFACE_DAMAGE_BUFFER_SINCE_VERSION 4
+
+/**
+ * @ingroup iface_wl_surface
+ * Sends an enter event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param output output entered by the surface
+ */
+static inline void
+wl_surface_send_enter(struct wl_resource *resource_, struct wl_resource *output)
+{
+	wl_resource_post_event(resource_, WL_SURFACE_ENTER, output);
+}
+
+/**
+ * @ingroup iface_wl_surface
+ * Sends an leave event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param output output left by the surface
+ */
+static inline void
+wl_surface_send_leave(struct wl_resource *resource_, struct wl_resource *output)
+{
+	wl_resource_post_event(resource_, WL_SURFACE_LEAVE, output);
+}
+
+#ifndef WL_SEAT_CAPABILITY_ENUM
+#define WL_SEAT_CAPABILITY_ENUM
+/**
+ * @ingroup iface_wl_seat
+ * seat capability bitmask
+ *
+ * This is a bitmask of capabilities this seat has; if a member is
+ * set, then it is present on the seat.
+ */
+enum wl_seat_capability {
+	/**
+	 * the seat has pointer devices
+	 */
+	WL_SEAT_CAPABILITY_POINTER = 1,
+	/**
+	 * the seat has one or more keyboards
+	 */
+	WL_SEAT_CAPABILITY_KEYBOARD = 2,
+	/**
+	 * the seat has touch devices
+	 */
+	WL_SEAT_CAPABILITY_TOUCH = 4,
+};
+/**
+ * @ingroup iface_wl_seat
+ * Validate a wl_seat capability value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_seat_capability
+ */
+static inline bool
+wl_seat_capability_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SEAT_CAPABILITY_POINTER:
+		return version >= 1;
+	case WL_SEAT_CAPABILITY_KEYBOARD:
+		return version >= 1;
+	case WL_SEAT_CAPABILITY_TOUCH:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SEAT_CAPABILITY_ENUM */
+
+/**
+ * @ingroup iface_wl_seat
+ * @struct wl_seat_interface
+ */
+struct wl_seat_interface {
+	/**
+	 * return pointer object
+	 *
+	 * The ID provided will be initialized to the wl_pointer
+	 * interface for this seat.
+	 *
+	 * 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.
+	 * @param id seat pointer
+	 */
+	void (*get_pointer)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    uint32_t id);
+	/**
+	 * return keyboard object
+	 *
+	 * The ID provided will be initialized to the wl_keyboard
+	 * interface for this seat.
+	 *
+	 * 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.
+	 * @param id seat keyboard
+	 */
+	void (*get_keyboard)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     uint32_t id);
+	/**
+	 * return touch object
+	 *
+	 * The ID provided will be initialized to the wl_touch interface
+	 * for this seat.
+	 *
+	 * 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.
+	 * @param id seat touch interface
+	 */
+	void (*get_touch)(struct wl_client *client,
+			  struct wl_resource *resource,
+			  uint32_t id);
+	/**
+	 * release the seat object
+	 *
+	 * Using this request a client can tell the server that it is not
+	 * going to use the seat object anymore.
+	 * @since 5
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_SEAT_CAPABILITIES 0
+#define WL_SEAT_NAME 1
+
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_CAPABILITIES_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_NAME_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_GET_POINTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_GET_KEYBOARD_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_GET_TOUCH_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_seat
+ */
+#define WL_SEAT_RELEASE_SINCE_VERSION 5
+
+/**
+ * @ingroup iface_wl_seat
+ * Sends an capabilities event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param capabilities capabilities of the seat
+ */
+static inline void
+wl_seat_send_capabilities(struct wl_resource *resource_, uint32_t capabilities)
+{
+	wl_resource_post_event(resource_, WL_SEAT_CAPABILITIES, capabilities);
+}
+
+/**
+ * @ingroup iface_wl_seat
+ * Sends an name event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param name seat identifier
+ */
+static inline void
+wl_seat_send_name(struct wl_resource *resource_, const char *name)
+{
+	wl_resource_post_event(resource_, WL_SEAT_NAME, name);
+}
+
+#ifndef WL_POINTER_ERROR_ENUM
+#define WL_POINTER_ERROR_ENUM
+enum wl_pointer_error {
+	/**
+	 * given wl_surface has another role
+	 */
+	WL_POINTER_ERROR_ROLE = 0,
+};
+/**
+ * @ingroup iface_wl_pointer
+ * Validate a wl_pointer error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_pointer_error
+ */
+static inline bool
+wl_pointer_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_POINTER_ERROR_ROLE:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_POINTER_ERROR_ENUM */
+
+#ifndef WL_POINTER_BUTTON_STATE_ENUM
+#define WL_POINTER_BUTTON_STATE_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * physical button state
+ *
+ * Describes the physical state of a button that produced the button
+ * event.
+ */
+enum wl_pointer_button_state {
+	/**
+	 * the button is not pressed
+	 */
+	WL_POINTER_BUTTON_STATE_RELEASED = 0,
+	/**
+	 * the button is pressed
+	 */
+	WL_POINTER_BUTTON_STATE_PRESSED = 1,
+};
+/**
+ * @ingroup iface_wl_pointer
+ * Validate a wl_pointer button_state value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_pointer_button_state
+ */
+static inline bool
+wl_pointer_button_state_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_POINTER_BUTTON_STATE_RELEASED:
+		return version >= 1;
+	case WL_POINTER_BUTTON_STATE_PRESSED:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_POINTER_BUTTON_STATE_ENUM */
+
+#ifndef WL_POINTER_AXIS_ENUM
+#define WL_POINTER_AXIS_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * axis types
+ *
+ * Describes the axis types of scroll events.
+ */
+enum wl_pointer_axis {
+	/**
+	 * vertical axis
+	 */
+	WL_POINTER_AXIS_VERTICAL_SCROLL = 0,
+	/**
+	 * horizontal axis
+	 */
+	WL_POINTER_AXIS_HORIZONTAL_SCROLL = 1,
+};
+/**
+ * @ingroup iface_wl_pointer
+ * Validate a wl_pointer axis value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_pointer_axis
+ */
+static inline bool
+wl_pointer_axis_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_POINTER_AXIS_VERTICAL_SCROLL:
+		return version >= 1;
+	case WL_POINTER_AXIS_HORIZONTAL_SCROLL:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_POINTER_AXIS_ENUM */
+
+#ifndef WL_POINTER_AXIS_SOURCE_ENUM
+#define WL_POINTER_AXIS_SOURCE_ENUM
+/**
+ * @ingroup iface_wl_pointer
+ * axis source types
+ *
+ * Describes the source types for axis events. This indicates to the
+ * client how an axis event was physically generated; a client may
+ * adjust the user interface accordingly. For example, scroll events
+ * from a "finger" source may be in a smooth coordinate space with
+ * kinetic scrolling whereas a "wheel" source may be in discrete steps
+ * of a number of lines.
+ */
+enum wl_pointer_axis_source {
+	/**
+	 * a physical wheel rotation
+	 */
+	WL_POINTER_AXIS_SOURCE_WHEEL = 0,
+	/**
+	 * finger on a touch surface
+	 */
+	WL_POINTER_AXIS_SOURCE_FINGER = 1,
+	/**
+	 * continuous coordinate space
+	 *
+	 * A device generating events in a continuous coordinate space,
+	 * but using something other than a finger. One example for this
+	 * source is button-based scrolling where the vertical motion of a
+	 * device is converted to scroll events while a button is held
+	 * down.
+	 */
+	WL_POINTER_AXIS_SOURCE_CONTINUOUS = 2,
+	/**
+	 * a physical wheel tilt
+	 *
+	 * Indicates that the actual device is a wheel but the scroll
+	 * event is not caused by a rotation but a (usually sideways) tilt
+	 * of the wheel.
+	 * @since 6
+	 */
+	WL_POINTER_AXIS_SOURCE_WHEEL_TILT = 3,
+};
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_SOURCE_WHEEL_TILT_SINCE_VERSION 6
+/**
+ * @ingroup iface_wl_pointer
+ * Validate a wl_pointer axis_source value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_pointer_axis_source
+ */
+static inline bool
+wl_pointer_axis_source_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_POINTER_AXIS_SOURCE_WHEEL:
+		return version >= 1;
+	case WL_POINTER_AXIS_SOURCE_FINGER:
+		return version >= 1;
+	case WL_POINTER_AXIS_SOURCE_CONTINUOUS:
+		return version >= 1;
+	case WL_POINTER_AXIS_SOURCE_WHEEL_TILT:
+		return version >= 6;
+	default:
+		return false;
+	}
+}
+#endif /* WL_POINTER_AXIS_SOURCE_ENUM */
+
+/**
+ * @ingroup iface_wl_pointer
+ * @struct wl_pointer_interface
+ */
+struct wl_pointer_interface {
+	/**
+	 * set the pointer surface
+	 *
+	 * Set the pointer surface, i.e., the surface that contains the
+	 * pointer image (cursor). This request gives the surface the role
+	 * of a cursor. If the surface already has another role, it raises
+	 * a protocol error.
+	 *
+	 * The cursor actually changes only if the pointer focus for this
+	 * device is one of the requesting client's surfaces or the surface
+	 * parameter is the current pointer surface. If there was a
+	 * previous surface set with this request it is replaced. If
+	 * surface is NULL, the pointer image is hidden.
+	 *
+	 * The parameters hotspot_x and hotspot_y define the position of
+	 * the pointer surface relative to the pointer location. Its
+	 * top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
+	 * where (x, y) are the coordinates of the pointer location, in
+	 * surface-local coordinates.
+	 *
+	 * On surface.attach requests to the pointer surface, hotspot_x and
+	 * hotspot_y are decremented by the x and y parameters passed to
+	 * the request. Attach must be confirmed by wl_surface.commit as
+	 * usual.
+	 *
+	 * The hotspot can also be updated by passing the currently set
+	 * pointer surface to this request with new values for hotspot_x
+	 * and hotspot_y.
+	 *
+	 * The current and pending input regions of the wl_surface are
+	 * cleared, and wl_surface.set_input_region is ignored until the
+	 * wl_surface is no longer used as the cursor. When the use as a
+	 * cursor ends, the current and pending input regions become
+	 * undefined, and the wl_surface is unmapped.
+	 * @param serial serial number of the enter event
+	 * @param surface pointer surface
+	 * @param hotspot_x surface-local x coordinate
+	 * @param hotspot_y surface-local y coordinate
+	 */
+	void (*set_cursor)(struct wl_client *client,
+			   struct wl_resource *resource,
+			   uint32_t serial,
+			   struct wl_resource *surface,
+			   int32_t hotspot_x,
+			   int32_t hotspot_y);
+	/**
+	 * release the pointer object
+	 *
+	 * Using this request a client can tell the server that it is not
+	 * going to use the pointer object anymore.
+	 *
+	 * This request destroys the pointer proxy object, so clients must
+	 * not call wl_pointer_destroy() after using this request.
+	 * @since 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_POINTER_ENTER 0
+#define WL_POINTER_LEAVE 1
+#define WL_POINTER_MOTION 2
+#define WL_POINTER_BUTTON 3
+#define WL_POINTER_AXIS 4
+#define WL_POINTER_FRAME 5
+#define WL_POINTER_AXIS_SOURCE 6
+#define WL_POINTER_AXIS_STOP 7
+#define WL_POINTER_AXIS_DISCRETE 8
+
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_ENTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_LEAVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_MOTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_BUTTON_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_FRAME_SINCE_VERSION 5
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_SOURCE_SINCE_VERSION 5
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_STOP_SINCE_VERSION 5
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_AXIS_DISCRETE_SINCE_VERSION 5
+
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_SET_CURSOR_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_pointer
+ */
+#define WL_POINTER_RELEASE_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an enter event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the enter event
+ * @param surface surface entered by the pointer
+ * @param surface_x surface-local x coordinate
+ * @param surface_y surface-local y coordinate
+ */
+static inline void
+wl_pointer_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+	wl_resource_post_event(resource_, WL_POINTER_ENTER, serial, surface, surface_x, surface_y);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an leave event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the leave event
+ * @param surface surface left by the pointer
+ */
+static inline void
+wl_pointer_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface)
+{
+	wl_resource_post_event(resource_, WL_POINTER_LEAVE, serial, surface);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an motion event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param surface_x surface-local x coordinate
+ * @param surface_y surface-local y coordinate
+ */
+static inline void
+wl_pointer_send_motion(struct wl_resource *resource_, uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y)
+{
+	wl_resource_post_event(resource_, WL_POINTER_MOTION, time, surface_x, surface_y);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an button event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the button event
+ * @param time timestamp with millisecond granularity
+ * @param button button that produced the event
+ * @param state physical state of the button
+ */
+static inline void
+wl_pointer_send_button(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t button, uint32_t state)
+{
+	wl_resource_post_event(resource_, WL_POINTER_BUTTON, serial, time, button, state);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an axis event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param axis axis type
+ * @param value length of vector in surface-local coordinate space
+ */
+static inline void
+wl_pointer_send_axis(struct wl_resource *resource_, uint32_t time, uint32_t axis, wl_fixed_t value)
+{
+	wl_resource_post_event(resource_, WL_POINTER_AXIS, time, axis, value);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an frame event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_pointer_send_frame(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_POINTER_FRAME);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an axis_source event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param axis_source source of the axis event
+ */
+static inline void
+wl_pointer_send_axis_source(struct wl_resource *resource_, uint32_t axis_source)
+{
+	wl_resource_post_event(resource_, WL_POINTER_AXIS_SOURCE, axis_source);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an axis_stop event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param axis the axis stopped with this event
+ */
+static inline void
+wl_pointer_send_axis_stop(struct wl_resource *resource_, uint32_t time, uint32_t axis)
+{
+	wl_resource_post_event(resource_, WL_POINTER_AXIS_STOP, time, axis);
+}
+
+/**
+ * @ingroup iface_wl_pointer
+ * Sends an axis_discrete event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param axis axis type
+ * @param discrete number of steps
+ */
+static inline void
+wl_pointer_send_axis_discrete(struct wl_resource *resource_, uint32_t axis, int32_t discrete)
+{
+	wl_resource_post_event(resource_, WL_POINTER_AXIS_DISCRETE, axis, discrete);
+}
+
+#ifndef WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+#define WL_KEYBOARD_KEYMAP_FORMAT_ENUM
+/**
+ * @ingroup iface_wl_keyboard
+ * keyboard mapping format
+ *
+ * This specifies the format of the keymap provided to the
+ * client with the wl_keyboard.keymap event.
+ */
+enum wl_keyboard_keymap_format {
+	/**
+	 * no keymap; client must understand how to interpret the raw keycode
+	 */
+	WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP = 0,
+	/**
+	 * libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode
+	 */
+	WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1 = 1,
+};
+/**
+ * @ingroup iface_wl_keyboard
+ * Validate a wl_keyboard keymap_format value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_keyboard_keymap_format
+ */
+static inline bool
+wl_keyboard_keymap_format_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_KEYBOARD_KEYMAP_FORMAT_NO_KEYMAP:
+		return version >= 1;
+	case WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_KEYBOARD_KEYMAP_FORMAT_ENUM */
+
+#ifndef WL_KEYBOARD_KEY_STATE_ENUM
+#define WL_KEYBOARD_KEY_STATE_ENUM
+/**
+ * @ingroup iface_wl_keyboard
+ * physical key state
+ *
+ * Describes the physical state of a key that produced the key event.
+ */
+enum wl_keyboard_key_state {
+	/**
+	 * key is not pressed
+	 */
+	WL_KEYBOARD_KEY_STATE_RELEASED = 0,
+	/**
+	 * key is pressed
+	 */
+	WL_KEYBOARD_KEY_STATE_PRESSED = 1,
+};
+/**
+ * @ingroup iface_wl_keyboard
+ * Validate a wl_keyboard key_state value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_keyboard_key_state
+ */
+static inline bool
+wl_keyboard_key_state_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_KEYBOARD_KEY_STATE_RELEASED:
+		return version >= 1;
+	case WL_KEYBOARD_KEY_STATE_PRESSED:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_KEYBOARD_KEY_STATE_ENUM */
+
+/**
+ * @ingroup iface_wl_keyboard
+ * @struct wl_keyboard_interface
+ */
+struct wl_keyboard_interface {
+	/**
+	 * release the keyboard object
+	 *
+	 * 
+	 * @since 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_KEYBOARD_KEYMAP 0
+#define WL_KEYBOARD_ENTER 1
+#define WL_KEYBOARD_LEAVE 2
+#define WL_KEYBOARD_KEY 3
+#define WL_KEYBOARD_MODIFIERS 4
+#define WL_KEYBOARD_REPEAT_INFO 5
+
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_KEYMAP_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_ENTER_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_LEAVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_KEY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_MODIFIERS_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_REPEAT_INFO_SINCE_VERSION 4
+
+/**
+ * @ingroup iface_wl_keyboard
+ */
+#define WL_KEYBOARD_RELEASE_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_keyboard
+ * Sends an keymap event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param format keymap format
+ * @param fd keymap file descriptor
+ * @param size keymap size, in bytes
+ */
+static inline void
+wl_keyboard_send_keymap(struct wl_resource *resource_, uint32_t format, int32_t fd, uint32_t size)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_KEYMAP, format, fd, size);
+}
+
+/**
+ * @ingroup iface_wl_keyboard
+ * Sends an enter event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the enter event
+ * @param surface surface gaining keyboard focus
+ * @param keys the currently pressed keys
+ */
+static inline void
+wl_keyboard_send_enter(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface, struct wl_array *keys)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_ENTER, serial, surface, keys);
+}
+
+/**
+ * @ingroup iface_wl_keyboard
+ * Sends an leave event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the leave event
+ * @param surface surface that lost keyboard focus
+ */
+static inline void
+wl_keyboard_send_leave(struct wl_resource *resource_, uint32_t serial, struct wl_resource *surface)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_LEAVE, serial, surface);
+}
+
+/**
+ * @ingroup iface_wl_keyboard
+ * Sends an key event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the key event
+ * @param time timestamp with millisecond granularity
+ * @param key key that produced the event
+ * @param state physical state of the key
+ */
+static inline void
+wl_keyboard_send_key(struct wl_resource *resource_, uint32_t serial, uint32_t time, uint32_t key, uint32_t state)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_KEY, serial, time, key, state);
+}
+
+/**
+ * @ingroup iface_wl_keyboard
+ * Sends an modifiers event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the modifiers event
+ * @param mods_depressed depressed modifiers
+ * @param mods_latched latched modifiers
+ * @param mods_locked locked modifiers
+ * @param group keyboard layout
+ */
+static inline void
+wl_keyboard_send_modifiers(struct wl_resource *resource_, uint32_t serial, uint32_t mods_depressed, uint32_t mods_latched, uint32_t mods_locked, uint32_t group)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_MODIFIERS, serial, mods_depressed, mods_latched, mods_locked, group);
+}
+
+/**
+ * @ingroup iface_wl_keyboard
+ * Sends an repeat_info event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param rate the rate of repeating keys in characters per second
+ * @param delay delay in milliseconds since key down until repeating starts
+ */
+static inline void
+wl_keyboard_send_repeat_info(struct wl_resource *resource_, int32_t rate, int32_t delay)
+{
+	wl_resource_post_event(resource_, WL_KEYBOARD_REPEAT_INFO, rate, delay);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ * @struct wl_touch_interface
+ */
+struct wl_touch_interface {
+	/**
+	 * release the touch object
+	 *
+	 * 
+	 * @since 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_TOUCH_DOWN 0
+#define WL_TOUCH_UP 1
+#define WL_TOUCH_MOTION 2
+#define WL_TOUCH_FRAME 3
+#define WL_TOUCH_CANCEL 4
+#define WL_TOUCH_SHAPE 5
+#define WL_TOUCH_ORIENTATION 6
+
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_DOWN_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_UP_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_MOTION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_FRAME_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_CANCEL_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_SHAPE_SINCE_VERSION 6
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_ORIENTATION_SINCE_VERSION 6
+
+/**
+ * @ingroup iface_wl_touch
+ */
+#define WL_TOUCH_RELEASE_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_touch
+ * Sends an down event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the touch down event
+ * @param time timestamp with millisecond granularity
+ * @param surface surface touched
+ * @param id the unique ID of this touch point
+ * @param x surface-local x coordinate
+ * @param y surface-local y coordinate
+ */
+static inline void
+wl_touch_send_down(struct wl_resource *resource_, uint32_t serial, uint32_t time, struct wl_resource *surface, int32_t id, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_DOWN, serial, time, surface, id, x, y);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ * Sends an up event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param serial serial number of the touch up event
+ * @param time timestamp with millisecond granularity
+ * @param id the unique ID of this touch point
+ */
+static inline void
+wl_touch_send_up(struct wl_resource *resource_, uint32_t serial, uint32_t time, int32_t id)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_UP, serial, time, id);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ * Sends an motion event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param time timestamp with millisecond granularity
+ * @param id the unique ID of this touch point
+ * @param x surface-local x coordinate
+ * @param y surface-local y coordinate
+ */
+static inline void
+wl_touch_send_motion(struct wl_resource *resource_, uint32_t time, int32_t id, wl_fixed_t x, wl_fixed_t y)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_MOTION, time, id, x, y);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ * Sends an frame event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_touch_send_frame(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_FRAME);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ * Sends an cancel event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_touch_send_cancel(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_CANCEL);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ * Sends an shape event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param id the unique ID of this touch point
+ * @param major length of the major axis in surface-local coordinates
+ * @param minor length of the minor axis in surface-local coordinates
+ */
+static inline void
+wl_touch_send_shape(struct wl_resource *resource_, int32_t id, wl_fixed_t major, wl_fixed_t minor)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_SHAPE, id, major, minor);
+}
+
+/**
+ * @ingroup iface_wl_touch
+ * Sends an orientation event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param id the unique ID of this touch point
+ * @param orientation angle between major axis and positive surface y-axis in degrees
+ */
+static inline void
+wl_touch_send_orientation(struct wl_resource *resource_, int32_t id, wl_fixed_t orientation)
+{
+	wl_resource_post_event(resource_, WL_TOUCH_ORIENTATION, id, orientation);
+}
+
+#ifndef WL_OUTPUT_SUBPIXEL_ENUM
+#define WL_OUTPUT_SUBPIXEL_ENUM
+/**
+ * @ingroup iface_wl_output
+ * subpixel geometry information
+ *
+ * This enumeration describes how the physical
+ * pixels on an output are laid out.
+ */
+enum wl_output_subpixel {
+	/**
+	 * unknown geometry
+	 */
+	WL_OUTPUT_SUBPIXEL_UNKNOWN = 0,
+	/**
+	 * no geometry
+	 */
+	WL_OUTPUT_SUBPIXEL_NONE = 1,
+	/**
+	 * horizontal RGB
+	 */
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB = 2,
+	/**
+	 * horizontal BGR
+	 */
+	WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR = 3,
+	/**
+	 * vertical RGB
+	 */
+	WL_OUTPUT_SUBPIXEL_VERTICAL_RGB = 4,
+	/**
+	 * vertical BGR
+	 */
+	WL_OUTPUT_SUBPIXEL_VERTICAL_BGR = 5,
+};
+/**
+ * @ingroup iface_wl_output
+ * Validate a wl_output subpixel value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_output_subpixel
+ */
+static inline bool
+wl_output_subpixel_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_OUTPUT_SUBPIXEL_UNKNOWN:
+		return version >= 1;
+	case WL_OUTPUT_SUBPIXEL_NONE:
+		return version >= 1;
+	case WL_OUTPUT_SUBPIXEL_HORIZONTAL_RGB:
+		return version >= 1;
+	case WL_OUTPUT_SUBPIXEL_HORIZONTAL_BGR:
+		return version >= 1;
+	case WL_OUTPUT_SUBPIXEL_VERTICAL_RGB:
+		return version >= 1;
+	case WL_OUTPUT_SUBPIXEL_VERTICAL_BGR:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_OUTPUT_SUBPIXEL_ENUM */
+
+#ifndef WL_OUTPUT_TRANSFORM_ENUM
+#define WL_OUTPUT_TRANSFORM_ENUM
+/**
+ * @ingroup iface_wl_output
+ * transform from framebuffer to output
+ *
+ * This describes the transform that a compositor will apply to a
+ * surface to compensate for the rotation or mirroring of an
+ * output device.
+ *
+ * The flipped values correspond to an initial flip around a
+ * vertical axis followed by rotation.
+ *
+ * The purpose is mainly to allow clients to render accordingly and
+ * tell the compositor, so that for fullscreen surfaces, the
+ * compositor will still be able to scan out directly from client
+ * surfaces.
+ */
+enum wl_output_transform {
+	/**
+	 * no transform
+	 */
+	WL_OUTPUT_TRANSFORM_NORMAL = 0,
+	/**
+	 * 90 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_90 = 1,
+	/**
+	 * 180 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_180 = 2,
+	/**
+	 * 270 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_270 = 3,
+	/**
+	 * 180 degree flip around a vertical axis
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED = 4,
+	/**
+	 * flip and rotate 90 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_90 = 5,
+	/**
+	 * flip and rotate 180 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_180 = 6,
+	/**
+	 * flip and rotate 270 degrees counter-clockwise
+	 */
+	WL_OUTPUT_TRANSFORM_FLIPPED_270 = 7,
+};
+/**
+ * @ingroup iface_wl_output
+ * Validate a wl_output transform value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_output_transform
+ */
+static inline bool
+wl_output_transform_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_OUTPUT_TRANSFORM_NORMAL:
+		return version >= 1;
+	case WL_OUTPUT_TRANSFORM_90:
+		return version >= 1;
+	case WL_OUTPUT_TRANSFORM_180:
+		return version >= 1;
+	case WL_OUTPUT_TRANSFORM_270:
+		return version >= 1;
+	case WL_OUTPUT_TRANSFORM_FLIPPED:
+		return version >= 1;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_90:
+		return version >= 1;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_180:
+		return version >= 1;
+	case WL_OUTPUT_TRANSFORM_FLIPPED_270:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_OUTPUT_TRANSFORM_ENUM */
+
+#ifndef WL_OUTPUT_MODE_ENUM
+#define WL_OUTPUT_MODE_ENUM
+/**
+ * @ingroup iface_wl_output
+ * mode information
+ *
+ * These flags describe properties of an output mode.
+ * They are used in the flags bitfield of the mode event.
+ */
+enum wl_output_mode {
+	/**
+	 * indicates this is the current mode
+	 */
+	WL_OUTPUT_MODE_CURRENT = 0x1,
+	/**
+	 * indicates this is the preferred mode
+	 */
+	WL_OUTPUT_MODE_PREFERRED = 0x2,
+};
+/**
+ * @ingroup iface_wl_output
+ * Validate a wl_output mode value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_output_mode
+ */
+static inline bool
+wl_output_mode_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_OUTPUT_MODE_CURRENT:
+		return version >= 1;
+	case WL_OUTPUT_MODE_PREFERRED:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_OUTPUT_MODE_ENUM */
+
+/**
+ * @ingroup iface_wl_output
+ * @struct wl_output_interface
+ */
+struct wl_output_interface {
+	/**
+	 * release the output object
+	 *
+	 * Using this request a client can tell the server that it is not
+	 * going to use the output object anymore.
+	 * @since 3
+	 */
+	void (*release)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define WL_OUTPUT_GEOMETRY 0
+#define WL_OUTPUT_MODE 1
+#define WL_OUTPUT_DONE 2
+#define WL_OUTPUT_SCALE 3
+
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_GEOMETRY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_MODE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_DONE_SINCE_VERSION 2
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_SCALE_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_wl_output
+ */
+#define WL_OUTPUT_RELEASE_SINCE_VERSION 3
+
+/**
+ * @ingroup iface_wl_output
+ * Sends an geometry event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param x x position within the global compositor space
+ * @param y y position within the global compositor space
+ * @param physical_width width in millimeters of the output
+ * @param physical_height height in millimeters of the output
+ * @param subpixel subpixel orientation of the output
+ * @param make textual description of the manufacturer
+ * @param model textual description of the model
+ * @param transform transform that maps framebuffer to output
+ */
+static inline void
+wl_output_send_geometry(struct wl_resource *resource_, int32_t x, int32_t y, int32_t physical_width, int32_t physical_height, int32_t subpixel, const char *make, const char *model, int32_t transform)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_GEOMETRY, x, y, physical_width, physical_height, subpixel, make, model, transform);
+}
+
+/**
+ * @ingroup iface_wl_output
+ * Sends an mode event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param flags bitfield of mode flags
+ * @param width width of the mode in hardware units
+ * @param height height of the mode in hardware units
+ * @param refresh vertical refresh rate in mHz
+ */
+static inline void
+wl_output_send_mode(struct wl_resource *resource_, uint32_t flags, int32_t width, int32_t height, int32_t refresh)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_MODE, flags, width, height, refresh);
+}
+
+/**
+ * @ingroup iface_wl_output
+ * Sends an done event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+wl_output_send_done(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_DONE);
+}
+
+/**
+ * @ingroup iface_wl_output
+ * Sends an scale event to the client owning the resource.
+ * @param resource_ The client's resource
+ * @param factor scaling factor of output
+ */
+static inline void
+wl_output_send_scale(struct wl_resource *resource_, int32_t factor)
+{
+	wl_resource_post_event(resource_, WL_OUTPUT_SCALE, factor);
+}
+
+/**
+ * @ingroup iface_wl_region
+ * @struct wl_region_interface
+ */
+struct wl_region_interface {
+	/**
+	 * destroy region
+	 *
+	 * Destroy the region. This will invalidate the object ID.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * add rectangle to region
+	 *
+	 * Add the specified rectangle to the region.
+	 * @param x region-local x coordinate
+	 * @param y region-local y coordinate
+	 * @param width rectangle width
+	 * @param height rectangle height
+	 */
+	void (*add)(struct wl_client *client,
+		    struct wl_resource *resource,
+		    int32_t x,
+		    int32_t y,
+		    int32_t width,
+		    int32_t height);
+	/**
+	 * subtract rectangle from region
+	 *
+	 * Subtract the specified rectangle from the region.
+	 * @param x region-local x coordinate
+	 * @param y region-local y coordinate
+	 * @param width rectangle width
+	 * @param height rectangle height
+	 */
+	void (*subtract)(struct wl_client *client,
+			 struct wl_resource *resource,
+			 int32_t x,
+			 int32_t y,
+			 int32_t width,
+			 int32_t height);
+};
+
+
+/**
+ * @ingroup iface_wl_region
+ */
+#define WL_REGION_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_region
+ */
+#define WL_REGION_ADD_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_region
+ */
+#define WL_REGION_SUBTRACT_SINCE_VERSION 1
+
+#ifndef WL_SUBCOMPOSITOR_ERROR_ENUM
+#define WL_SUBCOMPOSITOR_ERROR_ENUM
+enum wl_subcompositor_error {
+	/**
+	 * the to-be sub-surface is invalid
+	 */
+	WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE = 0,
+};
+/**
+ * @ingroup iface_wl_subcompositor
+ * Validate a wl_subcompositor error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_subcompositor_error
+ */
+static inline bool
+wl_subcompositor_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SUBCOMPOSITOR_ERROR_BAD_SURFACE:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SUBCOMPOSITOR_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_subcompositor
+ * @struct wl_subcompositor_interface
+ */
+struct wl_subcompositor_interface {
+	/**
+	 * unbind from the subcompositor interface
+	 *
+	 * Informs the server that the client will not be using this
+	 * protocol object anymore. This does not affect any other objects,
+	 * wl_subsurface objects included.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * give a surface the role sub-surface
+	 *
+	 * Create a sub-surface interface for the given surface, and
+	 * associate it with the given parent surface. This turns a plain
+	 * wl_surface into a sub-surface.
+	 *
+	 * The to-be sub-surface must not already have another role, and it
+	 * must not have an existing wl_subsurface object. Otherwise a
+	 * protocol error is raised.
+	 * @param id the new sub-surface object ID
+	 * @param surface the surface to be turned into a sub-surface
+	 * @param parent the parent surface
+	 */
+	void (*get_subsurface)(struct wl_client *client,
+			       struct wl_resource *resource,
+			       uint32_t id,
+			       struct wl_resource *surface,
+			       struct wl_resource *parent);
+};
+
+
+/**
+ * @ingroup iface_wl_subcompositor
+ */
+#define WL_SUBCOMPOSITOR_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subcompositor
+ */
+#define WL_SUBCOMPOSITOR_GET_SUBSURFACE_SINCE_VERSION 1
+
+#ifndef WL_SUBSURFACE_ERROR_ENUM
+#define WL_SUBSURFACE_ERROR_ENUM
+enum wl_subsurface_error {
+	/**
+	 * wl_surface is not a sibling or the parent
+	 */
+	WL_SUBSURFACE_ERROR_BAD_SURFACE = 0,
+};
+/**
+ * @ingroup iface_wl_subsurface
+ * Validate a wl_subsurface error value.
+ *
+ * @return true on success, false on error.
+ * @ref wl_subsurface_error
+ */
+static inline bool
+wl_subsurface_error_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case WL_SUBSURFACE_ERROR_BAD_SURFACE:
+		return version >= 1;
+	default:
+		return false;
+	}
+}
+#endif /* WL_SUBSURFACE_ERROR_ENUM */
+
+/**
+ * @ingroup iface_wl_subsurface
+ * @struct wl_subsurface_interface
+ */
+struct wl_subsurface_interface {
+	/**
+	 * remove sub-surface interface
+	 *
+	 * The sub-surface interface is removed from the wl_surface
+	 * object that was turned into a sub-surface with a
+	 * wl_subcompositor.get_subsurface request. The wl_surface's
+	 * association to the parent is deleted, and the wl_surface loses
+	 * its role as a sub-surface. The wl_surface is unmapped.
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+	/**
+	 * reposition the sub-surface
+	 *
+	 * This schedules a sub-surface position change. The sub-surface
+	 * will be moved so that its origin (top left corner pixel) will be
+	 * at the location x, y of the parent surface coordinate system.
+	 * The coordinates are not restricted to the parent surface area.
+	 * Negative values are allowed.
+	 *
+	 * The scheduled coordinates will take effect whenever the state of
+	 * the parent surface is applied. When this happens depends on
+	 * whether the parent surface is in synchronized mode or not. See
+	 * wl_subsurface.set_sync and wl_subsurface.set_desync for details.
+	 *
+	 * If more than one set_position request is invoked by the client
+	 * before the commit of the parent surface, the position of a new
+	 * request always replaces the scheduled position from any previous
+	 * request.
+	 *
+	 * The initial position is 0, 0.
+	 * @param x x coordinate in the parent surface
+	 * @param y y coordinate in the parent surface
+	 */
+	void (*set_position)(struct wl_client *client,
+			     struct wl_resource *resource,
+			     int32_t x,
+			     int32_t y);
+	/**
+	 * restack the sub-surface
+	 *
+	 * This sub-surface is taken from the stack, and put back just
+	 * above the reference surface, changing the z-order of the
+	 * sub-surfaces. The reference surface must be one of the sibling
+	 * surfaces, or the parent surface. Using any other surface,
+	 * including this sub-surface, will cause a protocol error.
+	 *
+	 * The z-order is double-buffered. Requests are handled in order
+	 * and applied immediately to a pending state. The final pending
+	 * state is copied to the active state the next time the state of
+	 * the parent surface is applied. When this happens depends on
+	 * whether the parent surface is in synchronized mode or not. See
+	 * wl_subsurface.set_sync and wl_subsurface.set_desync for details.
+	 *
+	 * A new sub-surface is initially added as the top-most in the
+	 * stack of its siblings and parent.
+	 * @param sibling the reference surface
+	 */
+	void (*place_above)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    struct wl_resource *sibling);
+	/**
+	 * restack the sub-surface
+	 *
+	 * The sub-surface is placed just below the reference surface.
+	 * See wl_subsurface.place_above.
+	 * @param sibling the reference surface
+	 */
+	void (*place_below)(struct wl_client *client,
+			    struct wl_resource *resource,
+			    struct wl_resource *sibling);
+	/**
+	 * set sub-surface to synchronized mode
+	 *
+	 * Change the commit behaviour of the sub-surface to synchronized
+	 * mode, also described as the parent dependent mode.
+	 *
+	 * In synchronized mode, wl_surface.commit on a sub-surface will
+	 * accumulate the committed state in a cache, but the state will
+	 * not be applied and hence will not change the compositor output.
+	 * The cached state is applied to the sub-surface immediately after
+	 * the parent surface's state is applied. This ensures atomic
+	 * updates of the parent and all its synchronized sub-surfaces.
+	 * Applying the cached state will invalidate the cache, so further
+	 * parent surface commits do not (re-)apply old state.
+	 *
+	 * See wl_subsurface for the recursive effect of this mode.
+	 */
+	void (*set_sync)(struct wl_client *client,
+			 struct wl_resource *resource);
+	/**
+	 * set sub-surface to desynchronized mode
+	 *
+	 * Change the commit behaviour of the sub-surface to
+	 * desynchronized mode, also described as independent or freely
+	 * running mode.
+	 *
+	 * In desynchronized mode, wl_surface.commit on a sub-surface will
+	 * apply the pending state directly, without caching, as happens
+	 * normally with a wl_surface. Calling wl_surface.commit on the
+	 * parent surface has no effect on the sub-surface's wl_surface
+	 * state. This mode allows a sub-surface to be updated on its own.
+	 *
+	 * If cached state exists when wl_surface.commit is called in
+	 * desynchronized mode, the pending state is added to the cached
+	 * state, and applied as a whole. This invalidates the cache.
+	 *
+	 * Note: even if a sub-surface is set to desynchronized, a parent
+	 * sub-surface may override it to behave as synchronized. For
+	 * details, see wl_subsurface.
+	 *
+	 * If a surface's parent surface behaves as desynchronized, then
+	 * the cached state is applied on set_desync.
+	 */
+	void (*set_desync)(struct wl_client *client,
+			   struct wl_resource *resource);
+};
+
+
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_DESTROY_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_SET_POSITION_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_PLACE_ABOVE_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_PLACE_BELOW_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_SET_SYNC_SINCE_VERSION 1
+/**
+ * @ingroup iface_wl_subsurface
+ */
+#define WL_SUBSURFACE_SET_DESYNC_SINCE_VERSION 1
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/example.xml b/subprojects/wayland/tests/data/example.xml
new file mode 100644
index 0000000000000000000000000000000000000000..2d769408803460415708a84c814b5a396eaf8bc6
--- /dev/null
+++ b/subprojects/wayland/tests/data/example.xml
@@ -0,0 +1,2748 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="wayland">
+
+  <copyright>
+    Copyright © 2008-2011 Kristian Høgsberg
+    Copyright © 2010-2011 Intel Corporation
+    Copyright © 2012-2013 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation files
+    (the "Software"), to deal in the Software without restriction,
+    including without limitation the rights to use, copy, modify, merge,
+    publish, distribute, sublicense, and/or sell copies of the Software,
+    and to permit persons to whom the Software is furnished to do so,
+    subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the
+    next paragraph) shall be included in all copies or substantial
+    portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+    SOFTWARE.
+  </copyright>
+
+  <interface name="wl_display" version="1">
+    <description summary="core global object">
+      The core global object.  This is a special singleton object.  It
+      is used for internal Wayland protocol features.
+    </description>
+
+    <request name="sync">
+      <description summary="asynchronous roundtrip">
+	The sync request asks the server to emit the 'done' event
+	on the returned wl_callback object.  Since requests are
+	handled in-order and events are delivered in-order, this can
+	be used as a barrier to ensure all previous requests and the
+	resulting events have been handled.
+
+	The object returned by this request will be destroyed by the
+	compositor after the callback is fired and as such the client must not
+	attempt to use it after that point.
+
+	The callback_data passed in the callback is the event serial.
+      </description>
+      <arg name="callback" type="new_id" interface="wl_callback"
+	   summary="callback object for the sync request"/>
+    </request>
+
+    <request name="get_registry">
+      <description summary="get global registry object">
+	This request creates a registry object that allows the client
+	to list and bind the global objects available from the
+	compositor.
+      </description>
+      <arg name="registry" type="new_id" interface="wl_registry"
+	   summary="global registry object"/>
+    </request>
+
+    <event name="error">
+      <description summary="fatal error event">
+	The error event is sent out when a fatal (non-recoverable)
+	error has occurred.  The object_id argument is the object
+	where the error occurred, most often in response to a request
+	to that object.  The code identifies the error and is defined
+	by the object interface.  As such, each interface defines its
+	own set of error codes.  The message is a brief description
+	of the error, for (debugging) convenience.
+      </description>
+      <arg name="object_id" type="object" summary="object where the error occurred"/>
+      <arg name="code" type="uint" summary="error code"/>
+      <arg name="message" type="string" summary="error description"/>
+    </event>
+
+    <enum name="error">
+      <description summary="global error values">
+	These errors are global and can be emitted in response to any
+	server request.
+      </description>
+      <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"/>
+      <entry name="no_memory" value="2"
+	     summary="server is out of memory"/>
+    </enum>
+
+    <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.
+      </description>
+      <arg name="id" type="uint" summary="deleted object ID"/>
+    </event>
+  </interface>
+
+  <interface name="wl_registry" version="1">
+    <description summary="global registry object">
+      The singleton global registry object.  The server has a number of
+      global objects that are available to all clients.  These objects
+      typically represent an actual object in the server (for example,
+      an input device) or they are singleton objects that provide
+      extension functionality.
+
+      When a client creates a registry object, the registry object
+      will emit a global event for each global currently in the
+      registry.  Globals come and go as a result of device or
+      monitor hotplugs, reconfiguration or other events, and the
+      registry will send out global and global_remove events to
+      keep the client up to date with the changes.  To mark the end
+      of the initial burst of events, the client can use the
+      wl_display.sync request immediately after calling
+      wl_display.get_registry.
+
+      A client can bind to a global object by using the bind
+      request.  This creates a client-side handle that lets the object
+      emit events to the client and lets the client invoke requests on
+      the object.
+    </description>
+
+    <request name="bind">
+      <description summary="bind an object to the display">
+	Binds a new, client-created object to the server using the
+	specified name as the identifier.
+      </description>
+      <arg name="name" type="uint" summary="unique numeric name of the object"/>
+      <arg name="id" type="new_id" summary="bounded object"/>
+    </request>
+
+    <event name="global">
+      <description summary="announce global object">
+	Notify the client of global objects.
+
+	The event notifies the client that a global object with
+	the given name is now available, and it implements the
+	given version of the given interface.
+      </description>
+      <arg name="name" type="uint" summary="numeric name of the global object"/>
+      <arg name="interface" type="string" summary="interface implemented by the object"/>
+      <arg name="version" type="uint" summary="interface version"/>
+    </event>
+
+    <event name="global_remove">
+      <description summary="announce removal of global object">
+	Notify the client of removed global objects.
+
+	This event notifies the client that the global identified
+	by name is no longer available.  If the client bound to
+	the global using the bind request, the client should now
+	destroy that object.
+
+	The object remains valid and requests to the object will be
+	ignored until the client destroys it, to avoid races between
+	the global going away and a client sending a request to it.
+      </description>
+      <arg name="name" type="uint" summary="numeric name of the global object"/>
+    </event>
+  </interface>
+
+  <interface name="wl_callback" version="1">
+    <description summary="callback object">
+      Clients can handle the 'done' event to get notified when
+      the related request is done.
+    </description>
+
+    <event name="done">
+      <description summary="done event">
+	Notify the client when the related request is done.
+      </description>
+      <arg name="callback_data" type="uint" summary="request-specific data for the callback"/>
+    </event>
+  </interface>
+
+  <interface name="wl_compositor" version="4">
+    <description summary="the compositor singleton">
+      A compositor.  This object is a singleton global.  The
+      compositor is in charge of combining the contents of multiple
+      surfaces into one displayable output.
+    </description>
+
+    <request name="create_surface">
+      <description summary="create new surface">
+	Ask the compositor to create a new surface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_surface" summary="the new surface"/>
+    </request>
+
+    <request name="create_region">
+      <description summary="create new region">
+	Ask the compositor to create a new region.
+      </description>
+      <arg name="id" type="new_id" interface="wl_region" summary="the new region"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shm_pool" version="1">
+    <description summary="a shared memory pool">
+      The wl_shm_pool object encapsulates a piece of memory shared
+      between the compositor and client.  Through the wl_shm_pool
+      object, the client can allocate shared memory wl_buffer objects.
+      All objects created through the same pool share the same
+      underlying mapped memory. Reusing the mapped memory avoids the
+      setup/teardown overhead and is useful when interactively resizing
+      a surface or for many small buffers.
+    </description>
+
+    <request name="create_buffer">
+      <description summary="create a buffer from the pool">
+	Create a wl_buffer object from the pool.
+
+	The buffer is created offset bytes into the pool and has
+	width and height as specified.  The stride argument specifies
+	the number of bytes from the beginning of one row to the beginning
+	of the next.  The format is the pixel format of the buffer and
+	must be one of those advertised through the wl_shm.format event.
+
+	A buffer will keep a reference to the pool it was created from
+	so it is valid to destroy the pool immediately after creating
+	a buffer from it.
+      </description>
+      <arg name="id" type="new_id" interface="wl_buffer" summary="buffer to create"/>
+      <arg name="offset" type="int" summary="buffer byte offset within the pool"/>
+      <arg name="width" type="int" summary="buffer width, in pixels"/>
+      <arg name="height" type="int" summary="buffer height, in pixels"/>
+      <arg name="stride" type="int" summary="number of bytes from the beginning of one row to the beginning of the next row"/>
+      <arg name="format" type="uint" enum="wl_shm.format" summary="buffer pixel format"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the pool">
+	Destroy the shared memory pool.
+
+	The mmapped memory will be released when all
+	buffers that have been created from this pool
+	are gone.
+      </description>
+    </request>
+
+    <request name="resize">
+      <description summary="change the size of the pool mapping">
+	This request will cause the server to remap the backing memory
+	for the pool from the file descriptor passed when the pool was
+	created, but using the new size.  This request can only be
+	used to make the pool bigger.
+      </description>
+      <arg name="size" type="int" summary="new size of the pool, in bytes"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shm" version="1">
+    <description summary="shared memory support">
+      A singleton global object that provides support for shared
+      memory.
+
+      Clients can create wl_shm_pool objects using the create_pool
+      request.
+
+      At connection setup time, the wl_shm object emits one or more
+      format events to inform clients about the valid pixel formats
+      that can be used for buffers.
+    </description>
+
+    <enum name="error">
+      <description summary="wl_shm error values">
+	These errors can be emitted in response to wl_shm requests.
+      </description>
+      <entry name="invalid_format" value="0" summary="buffer format is not known"/>
+      <entry name="invalid_stride" value="1" summary="invalid size or stride during pool or buffer creation"/>
+      <entry name="invalid_fd" value="2" summary="mmapping the file descriptor failed"/>
+    </enum>
+
+    <enum name="format">
+      <description summary="pixel formats">
+	This describes the memory layout of an individual pixel.
+
+	All renderers should support argb8888 and xrgb8888 but any other
+	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.
+      </description>
+      <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"/>
+      <entry name="rgb332" value="0x38424752" summary="8-bit RGB format, [7:0] R:G:B 3:3:2"/>
+      <entry name="bgr233" value="0x38524742" summary="8-bit BGR format, [7:0] B:G:R 2:3:3"/>
+      <entry name="xrgb4444" value="0x32315258" summary="16-bit xRGB format, [15:0] x:R:G:B 4:4:4:4 little endian"/>
+      <entry name="xbgr4444" value="0x32314258" summary="16-bit xBGR format, [15:0] x:B:G:R 4:4:4:4 little endian"/>
+      <entry name="rgbx4444" value="0x32315852" summary="16-bit RGBx format, [15:0] R:G:B:x 4:4:4:4 little endian"/>
+      <entry name="bgrx4444" value="0x32315842" summary="16-bit BGRx format, [15:0] B:G:R:x 4:4:4:4 little endian"/>
+      <entry name="argb4444" value="0x32315241" summary="16-bit ARGB format, [15:0] A:R:G:B 4:4:4:4 little endian"/>
+      <entry name="abgr4444" value="0x32314241" summary="16-bit ABGR format, [15:0] A:B:G:R 4:4:4:4 little endian"/>
+      <entry name="rgba4444" value="0x32314152" summary="16-bit RBGA format, [15:0] R:G:B:A 4:4:4:4 little endian"/>
+      <entry name="bgra4444" value="0x32314142" summary="16-bit BGRA format, [15:0] B:G:R:A 4:4:4:4 little endian"/>
+      <entry name="xrgb1555" value="0x35315258" summary="16-bit xRGB format, [15:0] x:R:G:B 1:5:5:5 little endian"/>
+      <entry name="xbgr1555" value="0x35314258" summary="16-bit xBGR 1555 format, [15:0] x:B:G:R 1:5:5:5 little endian"/>
+      <entry name="rgbx5551" value="0x35315852" summary="16-bit RGBx 5551 format, [15:0] R:G:B:x 5:5:5:1 little endian"/>
+      <entry name="bgrx5551" value="0x35315842" summary="16-bit BGRx 5551 format, [15:0] B:G:R:x 5:5:5:1 little endian"/>
+      <entry name="argb1555" value="0x35315241" summary="16-bit ARGB 1555 format, [15:0] A:R:G:B 1:5:5:5 little endian"/>
+      <entry name="abgr1555" value="0x35314241" summary="16-bit ABGR 1555 format, [15:0] A:B:G:R 1:5:5:5 little endian"/>
+      <entry name="rgba5551" value="0x35314152" summary="16-bit RGBA 5551 format, [15:0] R:G:B:A 5:5:5:1 little endian"/>
+      <entry name="bgra5551" value="0x35314142" summary="16-bit BGRA 5551 format, [15:0] B:G:R:A 5:5:5:1 little endian"/>
+      <entry name="rgb565" value="0x36314752" summary="16-bit RGB 565 format, [15:0] R:G:B 5:6:5 little endian"/>
+      <entry name="bgr565" value="0x36314742" summary="16-bit BGR 565 format, [15:0] B:G:R 5:6:5 little endian"/>
+      <entry name="rgb888" value="0x34324752" summary="24-bit RGB format, [23:0] R:G:B little endian"/>
+      <entry name="bgr888" value="0x34324742" summary="24-bit BGR format, [23:0] B:G:R little endian"/>
+      <entry name="xbgr8888" value="0x34324258" summary="32-bit xBGR format, [31:0] x:B:G:R 8:8:8:8 little endian"/>
+      <entry name="rgbx8888" value="0x34325852" summary="32-bit RGBx format, [31:0] R:G:B:x 8:8:8:8 little endian"/>
+      <entry name="bgrx8888" value="0x34325842" summary="32-bit BGRx format, [31:0] B:G:R:x 8:8:8:8 little endian"/>
+      <entry name="abgr8888" value="0x34324241" summary="32-bit ABGR format, [31:0] A:B:G:R 8:8:8:8 little endian"/>
+      <entry name="rgba8888" value="0x34324152" summary="32-bit RGBA format, [31:0] R:G:B:A 8:8:8:8 little endian"/>
+      <entry name="bgra8888" value="0x34324142" summary="32-bit BGRA format, [31:0] B:G:R:A 8:8:8:8 little endian"/>
+      <entry name="xrgb2101010" value="0x30335258" summary="32-bit xRGB format, [31:0] x:R:G:B 2:10:10:10 little endian"/>
+      <entry name="xbgr2101010" value="0x30334258" summary="32-bit xBGR format, [31:0] x:B:G:R 2:10:10:10 little endian"/>
+      <entry name="rgbx1010102" value="0x30335852" summary="32-bit RGBx format, [31:0] R:G:B:x 10:10:10:2 little endian"/>
+      <entry name="bgrx1010102" value="0x30335842" summary="32-bit BGRx format, [31:0] B:G:R:x 10:10:10:2 little endian"/>
+      <entry name="argb2101010" value="0x30335241" summary="32-bit ARGB format, [31:0] A:R:G:B 2:10:10:10 little endian"/>
+      <entry name="abgr2101010" value="0x30334241" summary="32-bit ABGR format, [31:0] A:B:G:R 2:10:10:10 little endian"/>
+      <entry name="rgba1010102" value="0x30334152" summary="32-bit RGBA format, [31:0] R:G:B:A 10:10:10:2 little endian"/>
+      <entry name="bgra1010102" value="0x30334142" summary="32-bit BGRA format, [31:0] B:G:R:A 10:10:10:2 little endian"/>
+      <entry name="yuyv" value="0x56595559" summary="packed YCbCr format, [31:0] Cr0:Y1:Cb0:Y0 8:8:8:8 little endian"/>
+      <entry name="yvyu" value="0x55595659" summary="packed YCbCr format, [31:0] Cb0:Y1:Cr0:Y0 8:8:8:8 little endian"/>
+      <entry name="uyvy" value="0x59565955" summary="packed YCbCr format, [31:0] Y1:Cr0:Y0:Cb0 8:8:8:8 little endian"/>
+      <entry name="vyuy" value="0x59555956" summary="packed YCbCr format, [31:0] Y1:Cb0:Y0:Cr0 8:8:8:8 little endian"/>
+      <entry name="ayuv" value="0x56555941" summary="packed AYCbCr format, [31:0] A:Y:Cb:Cr 8:8:8:8 little endian"/>
+      <entry name="nv12" value="0x3231564e" summary="2 plane YCbCr Cr:Cb format, 2x2 subsampled Cr:Cb plane"/>
+      <entry name="nv21" value="0x3132564e" summary="2 plane YCbCr Cb:Cr format, 2x2 subsampled Cb:Cr plane"/>
+      <entry name="nv16" value="0x3631564e" summary="2 plane YCbCr Cr:Cb format, 2x1 subsampled Cr:Cb plane"/>
+      <entry name="nv61" value="0x3136564e" summary="2 plane YCbCr Cb:Cr format, 2x1 subsampled Cb:Cr plane"/>
+      <entry name="yuv410" value="0x39565559" summary="3 plane YCbCr format, 4x4 subsampled Cb (1) and Cr (2) planes"/>
+      <entry name="yvu410" value="0x39555659" summary="3 plane YCbCr format, 4x4 subsampled Cr (1) and Cb (2) planes"/>
+      <entry name="yuv411" value="0x31315559" summary="3 plane YCbCr format, 4x1 subsampled Cb (1) and Cr (2) planes"/>
+      <entry name="yvu411" value="0x31315659" summary="3 plane YCbCr format, 4x1 subsampled Cr (1) and Cb (2) planes"/>
+      <entry name="yuv420" value="0x32315559" summary="3 plane YCbCr format, 2x2 subsampled Cb (1) and Cr (2) planes"/>
+      <entry name="yvu420" value="0x32315659" summary="3 plane YCbCr format, 2x2 subsampled Cr (1) and Cb (2) planes"/>
+      <entry name="yuv422" value="0x36315559" summary="3 plane YCbCr format, 2x1 subsampled Cb (1) and Cr (2) planes"/>
+      <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"/>
+    </enum>
+
+    <request name="create_pool">
+      <description summary="create a shm pool">
+	Create a new wl_shm_pool object.
+
+	The pool can be used to create shared memory based buffer
+	objects.  The server will mmap size bytes of the passed file
+	descriptor, to use as backing memory for the pool.
+      </description>
+      <arg name="id" type="new_id" interface="wl_shm_pool" summary="pool to create"/>
+      <arg name="fd" type="fd" summary="file descriptor for the pool"/>
+      <arg name="size" type="int" summary="pool size, in bytes"/>
+    </request>
+
+    <event name="format">
+      <description summary="pixel format description">
+	Informs the client about a valid pixel format that
+	can be used for buffers. Known formats include
+	argb8888 and xrgb8888.
+      </description>
+      <arg name="format" type="uint" enum="format" summary="buffer pixel format"/>
+    </event>
+  </interface>
+
+  <interface name="wl_buffer" version="1">
+    <description summary="content for a wl_surface">
+      A buffer provides the content for a wl_surface. Buffers are
+      created through factory interfaces such as wl_drm, wl_shm or
+      similar. It has a width and a height and can be attached to a
+      wl_surface, but the mechanism by which a client provides and
+      updates the contents is defined by the buffer factory interface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy a buffer">
+	Destroy a buffer. If and how you need to release the backing
+	storage is defined by the buffer factory interface.
+
+	For possible side-effects to a surface, see wl_surface.attach.
+      </description>
+    </request>
+
+    <event name="release">
+      <description summary="compositor releases buffer">
+	Sent when this wl_buffer is no longer used by the compositor.
+	The client is now free to reuse or destroy this buffer and its
+	backing storage.
+
+	If a client receives a release event before the frame callback
+	requested in the same wl_surface.commit that attaches this
+	wl_buffer to a surface, then the client is immediately free to
+	reuse the buffer and its backing storage, and does not need a
+	second buffer for the next surface content update. Typically
+	this is possible, when the compositor maintains a copy of the
+	wl_surface contents, e.g. as a GL texture. This is an important
+	optimization for GL(ES) compositors with wl_shm clients.
+      </description>
+    </event>
+  </interface>
+
+  <interface name="wl_data_offer" version="3">
+    <description summary="offer to transfer data">
+      A wl_data_offer represents a piece of data offered for transfer
+      by another client (the source client).  It is used by the
+      copy-and-paste and drag-and-drop mechanisms.  The offer
+      describes the different mime types that the data can be
+      converted to and provides the mechanism for transferring the
+      data directly from the source client.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_finish" value="0"
+	     summary="finish request was called untimely"/>
+      <entry name="invalid_action_mask" value="1"
+	     summary="action mask contains invalid values"/>
+      <entry name="invalid_action" value="2"
+	     summary="action argument has an invalid value"/>
+      <entry name="invalid_offer" value="3"
+	     summary="offer doesn't accept this request"/>
+    </enum>
+
+    <request name="accept">
+      <description summary="accept one of the offered mime types">
+	Indicate that the client can accept the given mime type, or
+	NULL for not accepted.
+
+	For objects of version 2 or older, this request is used by the
+	client to give feedback whether the client can receive the given
+	mime type, or NULL if none is accepted; the feedback does not
+	determine whether the drag-and-drop operation succeeds or not.
+
+	For objects of version 3 or newer, this request determines the
+	final result of the drag-and-drop operation. If the end result
+	is that no mime types were accepted, the drag-and-drop operation
+	will be cancelled and the corresponding drag source will receive
+	wl_data_source.cancelled. Clients may still use this event in
+	conjunction with wl_data_source.action for feedback.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the accept request"/>
+      <arg name="mime_type" type="string" allow-null="true" summary="mime type accepted by the client"/>
+    </request>
+
+    <request name="receive">
+      <description summary="request that the data is transferred">
+	To transfer the offered data, the client issues this request
+	and indicates the mime type it wants to receive.  The transfer
+	happens through the passed file descriptor (typically created
+	with the pipe system call).  The source client writes the data
+	in the mime type representation requested and then closes the
+	file descriptor.
+
+	The receiving client reads from the read end of the pipe until
+	EOF and then closes its end, at which point the transfer is
+	complete.
+
+	This request may happen multiple times for different mime types,
+	both before and after wl_data_device.drop. Drag-and-drop destination
+	clients may preemptively fetch data or examine it more closely to
+	determine acceptance.
+      </description>
+      <arg name="mime_type" type="string" summary="mime type desired by receiver"/>
+      <arg name="fd" type="fd" summary="file descriptor for data transfer"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy data offer">
+	Destroy the data offer.
+      </description>
+    </request>
+
+    <event name="offer">
+      <description summary="advertise offered mime type">
+	Sent immediately after creating the wl_data_offer object.  One
+	event per offered mime type.
+      </description>
+      <arg name="mime_type" type="string" summary="offered mime type"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="finish" since="3">
+      <description summary="the offer will no longer be used">
+	Notifies the compositor that the drag destination successfully
+	finished the drag-and-drop operation.
+
+	Upon receiving this request, the compositor will emit
+	wl_data_source.dnd_finished on the drag source client.
+
+	It is a client error to perform other requests than
+	wl_data_offer.destroy after this one. It is also an error to perform
+	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.
+      </description>
+    </request>
+
+    <request name="set_actions" since="3">
+      <description summary="set the available/preferred drag-and-drop actions">
+	Sets the actions that the destination side client supports for
+	this operation. This request may trigger the emission of
+	wl_data_source.action and wl_data_offer.action events if the compositor
+	needs to change the selected action.
+
+	This request can be called multiple times throughout the
+	drag-and-drop operation, typically in response to wl_data_device.enter
+	or wl_data_device.motion events.
+
+	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 dnd_actions argument must contain only values expressed in the
+	wl_data_device_manager.dnd_actions enum, and the preferred_action
+	argument must only contain one of those values set, otherwise it
+	will result in a protocol error.
+
+	While managing an "ask" action, the destination drag-and-drop client
+	may perform further wl_data_offer.receive requests, and is expected
+	to perform one last wl_data_offer.set_actions request with a preferred
+	action other than "ask" (and optionally wl_data_offer.accept) before
+	requesting wl_data_offer.finish, in order to convey the action selected
+	by the user. If the preferred action is not in the
+	wl_data_offer.source_actions mask, an error will be raised.
+
+	If the "ask" action is dismissed (e.g. user cancellation), the client
+	is expected to perform wl_data_offer.destroy right away.
+
+	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"/>
+    </request>
+
+    <event name="source_actions" since="3">
+      <description summary="notify the source-side available actions">
+	This event indicates the actions offered by the data source. It
+	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"/>
+    </event>
+
+    <event name="action" since="3">
+      <description summary="notify the selected action">
+	This event indicates the action selected by the compositor after
+	matching the source/destination side actions. Only one action (or
+	none) will be offered here.
+
+	This event can be emitted multiple times during the drag-and-drop
+	operation in response to destination side action changes through
+	wl_data_offer.set_actions.
+
+	This event will no longer be emitted after wl_data_device.drop
+	happened on the drag-and-drop destination, the client must
+	honor the last action received, or the last preferred one set
+	through wl_data_offer.set_actions when handling an "ask" action.
+
+	Compositors may also change the selected action on the fly, mainly
+	in response to keyboard modifier changes during the drag-and-drop
+	operation.
+
+	The most recent action received is always the valid one. Prior to
+	receiving wl_data_device.drop, the chosen action may change (e.g.
+	due to keyboard modifiers being pressed). At the time of receiving
+	wl_data_device.drop the drag-and-drop destination must honor the
+	last action received.
+
+	Action changes may still happen after wl_data_device.drop,
+	especially on "ask" actions, where the drag-and-drop destination
+	may choose another action afterwards. Action changes happening
+	at this stage are always the result of inter-client negotiation, the
+	compositor shall no longer be able to induce a different action.
+
+	Upon "ask" actions, it is expected that the drag-and-drop destination
+	may potentially choose a different action and/or mime type,
+	based on wl_data_offer.source_actions and finally chosen by the
+	user (e.g. popping up a menu with the available options). The
+	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"/>
+    </event>
+  </interface>
+
+  <interface name="wl_data_source" version="3">
+    <description summary="offer to transfer data">
+      The wl_data_source object is the source side of a wl_data_offer.
+      It is created by the source client in a data transfer and
+      provides a way to describe the offered data and a way to respond
+      to requests to transfer the data.
+    </description>
+
+    <enum name="error">
+      <entry name="invalid_action_mask" value="0"
+	     summary="action mask contains invalid values"/>
+      <entry name="invalid_source" value="1"
+	     summary="source doesn't accept this request"/>
+    </enum>
+
+    <request name="offer">
+      <description summary="add an offered mime type">
+	This request adds a mime type to the set of mime types
+	advertised to targets.  Can be called several times to offer
+	multiple types.
+      </description>
+      <arg name="mime_type" type="string" summary="mime type offered by the data source"/>
+    </request>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy the data source">
+	Destroy the data source.
+      </description>
+    </request>
+
+    <event name="target">
+      <description summary="a target accepts an offered mime type">
+	Sent when a target accepts pointer_focus or motion events.  If
+	a target does not accept any of the offered types, type is NULL.
+
+	Used for feedback during drag-and-drop.
+      </description>
+      <arg name="mime_type" type="string" allow-null="true" summary="mime type accepted by the target"/>
+    </event>
+
+    <event name="send">
+      <description summary="send the data">
+	Request for data from the client.  Send the data as the
+	specified mime type over the passed file descriptor, then
+	close it.
+      </description>
+      <arg name="mime_type" type="string" summary="mime type for the data"/>
+      <arg name="fd" type="fd" summary="file descriptor for the data"/>
+    </event>
+
+    <event name="cancelled">
+      <description summary="selection was cancelled">
+	This data source is no longer valid. There are several reasons why
+	this could happen:
+
+	- The data source has been replaced by another data source.
+	- The drag-and-drop operation was performed, but the drop destination
+	  did not accept any of the mime types offered through
+	  wl_data_source.target.
+	- The drag-and-drop operation was performed, but the drop destination
+	  did not select any of the actions present in the mask offered through
+	  wl_data_source.action.
+	- The drag-and-drop operation was performed but didn't happen over a
+	  surface.
+	- The compositor cancelled the drag-and-drop operation (e.g. compositor
+	  dependent timeouts to avoid stale drag-and-drop transfers).
+
+	The client should clean up and destroy this data source.
+
+	For objects of version 2 or older, wl_data_source.cancelled will
+	only be emitted if the data source was replaced by another data
+	source.
+      </description>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="set_actions" since="3">
+      <description summary="set the available drag-and-drop actions">
+	Sets the actions that the source side client supports for this
+	operation. This request may trigger wl_data_source.action and
+	wl_data_offer.action events if the compositor needs to change the
+	selected action.
+
+	The dnd_actions argument must contain only values expressed in the
+	wl_data_device_manager.dnd_actions enum, otherwise it will result
+	in a protocol error.
+
+	This request must be made once only, and can only be made on sources
+	used in drag-and-drop, so it must be performed before
+	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"/>
+    </request>
+
+    <event name="dnd_drop_performed" since="3">
+      <description summary="the drag-and-drop operation physically finished">
+	The user performed the drop action. This event does not indicate
+	acceptance, wl_data_source.cancelled may still be emitted afterwards
+	if the drop destination does not accept any mime type.
+
+	However, this event might however not be received if the compositor
+	cancelled the drag-and-drop operation before this event could happen.
+
+	Note that the data_source may still be used in the future and should
+	not be destroyed here.
+      </description>
+    </event>
+
+    <event name="dnd_finished" since="3">
+      <description summary="the drag-and-drop operation concluded">
+	The drop destination finished interoperating with this data
+	source, so the client is now free to destroy this data source and
+	free all associated data.
+
+	If the action used to perform the operation was "move", the
+	source can now delete the transferred data.
+      </description>
+    </event>
+
+    <event name="action" since="3">
+      <description summary="notify the selected action">
+	This event indicates the action selected by the compositor after
+	matching the source/destination side actions. Only one action (or
+	none) will be offered here.
+
+	This event can be emitted multiple times during the drag-and-drop
+	operation, mainly in response to destination side changes through
+	wl_data_offer.set_actions, and as the data device enters/leaves
+	surfaces.
+
+	It is only possible to receive this event after
+	wl_data_source.dnd_drop_performed if the drag-and-drop operation
+	ended in an "ask" action, in which case the final wl_data_source.action
+	event will happen immediately before wl_data_source.dnd_finished.
+
+	Compositors may also change the selected action on the fly, mainly
+	in response to keyboard modifier changes during the drag-and-drop
+	operation.
+
+	The most recent action received is always the valid one. The chosen
+	action may change alongside negotiation (e.g. an "ask" action can turn
+	into a "move" operation), so the effects of the final action must
+	always be applied in wl_data_offer.dnd_finished.
+
+	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"/>
+    </event>
+  </interface>
+
+  <interface name="wl_data_device" version="3">
+    <description summary="data transfer device">
+      There is one wl_data_device per seat which can be obtained
+      from the global wl_data_device_manager singleton.
+
+      A wl_data_device provides access to inter-client data transfer
+      mechanisms such as copy-and-paste and drag-and-drop.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="start_drag">
+      <description summary="start drag-and-drop operation">
+	This request asks the compositor to start a drag-and-drop
+	operation on behalf of the client.
+
+	The source argument is the data source that provides the data
+	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.
+
+	The origin surface is the surface where the drag originates and
+	the client must have an active implicit grab that matches the
+	serial.
+
+	The icon surface is an optional (can be NULL) surface that
+	provides an icon to be moved around with the cursor.  Initially,
+	the top-left corner of the icon surface is placed at the cursor
+	hotspot, but subsequent wl_surface.attach request can move the
+	relative position. Attach requests must be confirmed with
+	wl_surface.commit as usual. The icon surface is given the role of
+	a drag-and-drop icon. If the icon surface already has another role,
+	it raises a protocol error.
+
+	The current and pending input regions of the icon wl_surface are
+	cleared, and wl_surface.set_input_region is ignored until the
+	wl_surface is no longer used as the icon surface. When the use
+	as an icon ends, the current and pending input regions become
+	undefined, and the wl_surface is unmapped.
+      </description>
+      <arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the eventual transfer"/>
+      <arg name="origin" type="object" interface="wl_surface" summary="surface where the drag originates"/>
+      <arg name="icon" type="object" interface="wl_surface" allow-null="true" summary="drag-and-drop icon surface"/>
+      <arg name="serial" type="uint" summary="serial number of the implicit grab on the origin"/>
+    </request>
+
+    <request name="set_selection">
+      <description summary="copy data to the selection">
+	This request asks the compositor to set the selection
+	to the data from the source on behalf of the client.
+
+	To unset the selection, set the source to NULL.
+      </description>
+      <arg name="source" type="object" interface="wl_data_source" allow-null="true" summary="data source for the selection"/>
+      <arg name="serial" type="uint" summary="serial number of the event that triggered this request"/>
+    </request>
+
+    <event name="data_offer">
+      <description summary="introduce a new wl_data_offer">
+	The data_offer event introduces a new wl_data_offer object,
+	which will subsequently be used in either the
+	data_device.enter event (for drag-and-drop) or the
+	data_device.selection event (for selections).  Immediately
+	following the data_device.data_offer event, the new data_offer
+	object will send out data_offer.offer events to describe the
+	mime types it offers.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_offer" summary="the new data_offer object"/>
+    </event>
+
+    <event name="enter">
+      <description summary="initiate drag-and-drop session">
+	This event is sent when an active drag-and-drop pointer enters
+	a surface owned by the client.  The position of the pointer at
+	enter time is provided by the x and y arguments, in surface-local
+	coordinates.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="client surface entered"/>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+      <arg name="id" type="object" interface="wl_data_offer" allow-null="true"
+	   summary="source data_offer object"/>
+    </event>
+
+    <event name="leave">
+      <description summary="end drag-and-drop session">
+	This event is sent when the drag-and-drop pointer leaves the
+	surface and the session ends.  The client must destroy the
+	wl_data_offer introduced at enter time at this point.
+      </description>
+    </event>
+
+    <event name="motion">
+      <description summary="drag-and-drop session motion">
+	This event is sent when the drag-and-drop pointer moves within
+	the currently focused surface. The new position of the pointer
+	is provided by the x and y arguments, in surface-local
+	coordinates.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="drop">
+      <description summary="end drag-and-drop session successfully">
+	The event is sent when a drag-and-drop operation is ended
+	because the implicit grab is removed.
+
+	The drag-and-drop destination is expected to honor the last action
+	received through wl_data_offer.action, if the resulting action is
+	"copy" or "move", the destination can still perform
+	wl_data_offer.receive requests, and is expected to end all
+	transfers with a wl_data_offer.finish request.
+
+	If the resulting action is "ask", the action will not be considered
+	final. The drag-and-drop destination is expected to perform one last
+	wl_data_offer.set_actions request, or wl_data_offer.destroy in order
+	to cancel the operation.
+      </description>
+    </event>
+
+    <event name="selection">
+      <description summary="advertise new selection">
+	The selection event is sent out to notify the client of a new
+	wl_data_offer for the selection for this device.  The
+	data_device.data_offer and the data_offer.offer events are
+	sent out immediately before this event to introduce the data
+	offer object.  The selection event is sent to a client
+	immediately before receiving keyboard focus and when a new
+	selection is set while the client has keyboard focus.  The
+	data_offer is valid until a new data_offer or NULL is received
+	or until the client loses keyboard focus.  The client must
+	destroy the previous selection data_offer, if any, upon receiving
+	this event.
+      </description>
+      <arg name="id" type="object" interface="wl_data_offer" allow-null="true"
+	   summary="selection data_offer object"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <request name="release" type="destructor" since="2">
+      <description summary="destroy data device">
+	This request destroys the data device.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="wl_data_device_manager" version="3">
+    <description summary="data transfer interface">
+      The wl_data_device_manager is a singleton global object that
+      provides access to inter-client data transfer mechanisms such as
+      copy-and-paste and drag-and-drop.  These mechanisms are tied to
+      a wl_seat and this interface lets a client get a wl_data_device
+      corresponding to a wl_seat.
+
+      Depending on the version bound, the objects created from the bound
+      wl_data_device_manager object will have different requirements for
+      functioning properly. See wl_data_source.set_actions,
+      wl_data_offer.accept and wl_data_offer.finish for details.
+    </description>
+
+    <request name="create_data_source">
+      <description summary="create a new data source">
+	Create a new data source.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_source" summary="data source to create"/>
+    </request>
+
+    <request name="get_data_device">
+      <description summary="create a new data device">
+	Create a new data device for a given seat.
+      </description>
+      <arg name="id" type="new_id" interface="wl_data_device" summary="data device to create"/>
+      <arg name="seat" type="object" interface="wl_seat" summary="seat associated with the data device"/>
+    </request>
+
+    <!-- Version 3 additions -->
+
+    <enum name="dnd_action" bitfield="true" since="3">
+      <description summary="drag and drop actions">
+	This is a bitmask of the available/preferred actions in a
+	drag-and-drop operation.
+
+	In the compositor, the selected action is a result of matching the
+	actions offered by the source and destination sides.  "action" events
+	with a "none" action will be sent to both source and destination if
+	there is no match. All further checks will effectively happen on
+	(source actions ∩ destination actions).
+
+	In addition, compositors may also pick different actions in
+	reaction to key modifiers being pressed. One common design that
+	is used in major toolkits (and the behavior recommended for
+	compositors) is:
+
+	- If no modifiers are pressed, the first match (in bit order)
+	  will be used.
+	- Pressing Shift selects "move", if enabled in the mask.
+	- Pressing Control selects "copy", if enabled in the mask.
+
+	Behavior beyond that is considered implementation-dependent.
+	Compositors may for example bind other modifiers (like Alt/Meta)
+	or drags initiated with other buttons than BTN_LEFT to specific
+	actions (e.g. "ask").
+      </description>
+      <entry name="none" value="0" summary="no action"/>
+      <entry name="copy" value="1" summary="copy action"/>
+      <entry name="move" value="2" summary="move action"/>
+      <entry name="ask" value="4" summary="ask action"/>
+    </enum>
+  </interface>
+
+  <interface name="wl_shell" version="1">
+    <description summary="create desktop-style surfaces">
+      This interface is implemented by servers that provide
+      desktop-style user interfaces.
+
+      It allows clients to associate a wl_shell_surface with
+      a basic surface.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="get_shell_surface">
+      <description summary="create a shell surface from a surface">
+	Create a shell surface for an existing surface. This gives
+	the wl_surface the role of a shell surface. If the wl_surface
+	already has another role, it raises a protocol error.
+
+	Only one shell surface can be associated with a given surface.
+      </description>
+      <arg name="id" type="new_id" interface="wl_shell_surface" summary="shell surface to create"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface to be given the shell surface role"/>
+    </request>
+  </interface>
+
+  <interface name="wl_shell_surface" version="1">
+    <description summary="desktop-style metadata interface">
+      An interface that may be implemented by a wl_surface, for
+      implementations that provide a desktop-style user interface.
+
+      It provides requests to treat surfaces like toplevel, fullscreen
+      or popup windows, move, resize or maximize them, associate
+      metadata like title and class, etc.
+
+      On the server side the object is automatically destroyed when
+      the related wl_surface is destroyed. On the client side,
+      wl_shell_surface_destroy() must be called before destroying
+      the wl_surface object.
+    </description>
+
+    <request name="pong">
+      <description summary="respond to a ping event">
+	A client must respond to a ping event with a pong request or
+	the client may be deemed unresponsive.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the ping event"/>
+    </request>
+
+    <request name="move">
+      <description summary="start an interactive move">
+	Start a pointer-driven move of the surface.
+
+	This request must be used in response to a button press event.
+	The server may ignore move requests depending on the state of
+	the surface (e.g. fullscreen or maximized).
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/>
+    </request>
+
+    <enum name="resize" bitfield="true">
+      <description summary="edge values for resizing">
+	These values are used to indicate which edge of a surface
+	is being dragged in a resize operation. The server may
+	use this information to adapt its behavior, e.g. choose
+	an appropriate cursor image.
+      </description>
+      <entry name="none" value="0" summary="no edge"/>
+      <entry name="top" value="1" summary="top edge"/>
+      <entry name="bottom" value="2" summary="bottom edge"/>
+      <entry name="left" value="4" summary="left edge"/>
+      <entry name="top_left" value="5" summary="top and left edges"/>
+      <entry name="bottom_left" value="6" summary="bottom and left edges"/>
+      <entry name="right" value="8" summary="right edge"/>
+      <entry name="top_right" value="9" summary="top and right edges"/>
+      <entry name="bottom_right" value="10" summary="bottom and right edges"/>
+    </enum>
+
+    <request name="resize">
+      <description summary="start an interactive resize">
+	Start a pointer-driven resizing of the surface.
+
+	This request must be used in response to a button press event.
+	The server may ignore resize requests depending on the state of
+	the surface (e.g. fullscreen or maximized).
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/>
+      <arg name="edges" type="uint" enum="resize" summary="which edge or corner is being dragged"/>
+    </request>
+
+    <request name="set_toplevel">
+      <description summary="make the surface a toplevel surface">
+	Map the surface as a toplevel surface.
+
+	A toplevel surface is not fullscreen, maximized or transient.
+      </description>
+    </request>
+
+    <enum name="transient" bitfield="true">
+      <description summary="details of transient behaviour">
+	These flags specify details of the expected behaviour
+	of transient surfaces. Used in the set_transient request.
+      </description>
+      <entry name="inactive" value="0x1" summary="do not set keyboard focus"/>
+    </enum>
+
+    <request name="set_transient">
+      <description summary="make the surface a transient surface">
+	Map the surface relative to an existing surface.
+
+	The x and y arguments specify the location of the upper left
+	corner of the surface relative to the upper left corner of the
+	parent surface, in surface-local coordinates.
+
+	The flags argument controls details of the transient behaviour.
+      </description>
+      <arg name="parent" type="object" interface="wl_surface" summary="parent surface"/>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+      <arg name="flags" type="uint" enum="transient" summary="transient surface behavior"/>
+    </request>
+
+    <enum name="fullscreen_method">
+      <description summary="different method to set the surface fullscreen">
+	Hints to indicate to the compositor how to deal with a conflict
+	between the dimensions of the surface and the dimensions of the
+	output. The compositor is free to ignore this parameter.
+      </description>
+      <entry name="default" value="0" summary="no preference, apply default policy"/>
+      <entry name="scale" value="1" summary="scale, preserve the surface's aspect ratio and center on output"/>
+      <entry name="driver" value="2" summary="switch output mode to the smallest mode that can fit the surface, add black borders to compensate size mismatch"/>
+      <entry name="fill" value="3" summary="no upscaling, center on output and add black borders to compensate size mismatch"/>
+    </enum>
+
+    <request name="set_fullscreen">
+      <description summary="make the surface a fullscreen surface">
+	Map the surface as a fullscreen surface.
+
+	If an output parameter is given then the surface will be made
+	fullscreen on that output. If the client does not specify the
+	output then the compositor will apply its policy - usually
+	choosing the output on which the surface has the biggest surface
+	area.
+
+	The client may specify a method to resolve a size conflict
+	between the output size and the surface size - this is provided
+	through the method parameter.
+
+	The framerate parameter is used only when the method is set
+	to "driver", to indicate the preferred framerate. A value of 0
+	indicates that the client does not care about framerate.  The
+	framerate is specified in mHz, that is framerate of 60000 is 60Hz.
+
+	A method of "scale" or "driver" implies a scaling operation of
+	the surface, either via a direct scaling operation or a change of
+	the output mode. This will override any kind of output scaling, so
+	that mapping a surface with a buffer size equal to the mode can
+	fill the screen independent of buffer_scale.
+
+	A method of "fill" means we don't scale up the buffer, however
+	any output scale is applied. This means that you may run into
+	an edge case where the application maps a buffer with the same
+	size of the output mode but buffer_scale 1 (thus making a
+	surface larger than the output). In this case it is allowed to
+	downscale the results to fit the screen.
+
+	The compositor must reply to this request with a configure event
+	with the dimensions for the output on which the surface will
+	be made fullscreen.
+      </description>
+      <arg name="method" type="uint" enum="fullscreen_method" summary="method for resolving size conflict"/>
+      <arg name="framerate" type="uint" summary="framerate in mHz"/>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"
+	   summary="output on which the surface is to be fullscreen"/>
+    </request>
+
+    <request name="set_popup">
+      <description summary="make the surface a popup surface">
+	Map the surface as a popup.
+
+	A popup surface is a transient surface with an added pointer
+	grab.
+
+	An existing implicit grab will be changed to owner-events mode,
+	and the popup grab will continue after the implicit grab ends
+	(i.e. releasing the mouse button does not cause the popup to
+	be unmapped).
+
+	The popup grab continues until the window is destroyed or a
+	mouse button is pressed in any other client's window. A click
+	in any of the client's surfaces is reported as normal, however,
+	clicks in other clients' surfaces will be discarded and trigger
+	the callback.
+
+	The x and y arguments specify the location of the upper left
+	corner of the surface relative to the upper left corner of the
+	parent surface, in surface-local coordinates.
+      </description>
+      <arg name="seat" type="object" interface="wl_seat" summary="seat whose pointer is used"/>
+      <arg name="serial" type="uint" summary="serial number of the implicit grab on the pointer"/>
+      <arg name="parent" type="object" interface="wl_surface" summary="parent surface"/>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+      <arg name="flags" type="uint" enum="transient" summary="transient surface behavior"/>
+    </request>
+
+    <request name="set_maximized">
+      <description summary="make the surface a maximized surface">
+	Map the surface as a maximized surface.
+
+	If an output parameter is given then the surface will be
+	maximized on that output. If the client does not specify the
+	output then the compositor will apply its policy - usually
+	choosing the output on which the surface has the biggest surface
+	area.
+
+	The compositor will reply with a configure event telling
+	the expected new surface size. The operation is completed
+	on the next buffer attach to this surface.
+
+	A maximized surface typically fills the entire output it is
+	bound to, except for desktop elements such as panels. This is
+	the main difference between a maximized shell surface and a
+	fullscreen shell surface.
+
+	The details depend on the compositor implementation.
+      </description>
+      <arg name="output" type="object" interface="wl_output" allow-null="true"
+	   summary="output on which the surface is to be maximized"/>
+    </request>
+
+    <request name="set_title">
+      <description summary="set surface title">
+	Set a short title for the surface.
+
+	This string may be used to identify the surface in a task bar,
+	window list, or other user interface elements provided by the
+	compositor.
+
+	The string must be encoded in UTF-8.
+      </description>
+      <arg name="title" type="string" summary="surface title"/>
+    </request>
+
+    <request name="set_class">
+      <description summary="set surface class">
+	Set a class for the surface.
+
+	The surface class identifies the general class of applications
+	to which the surface belongs. A common convention is to use the
+	file name (or the full path if it is a non-standard location) of
+	the application's .desktop file as the class.
+      </description>
+      <arg name="class_" type="string" summary="surface class"/>
+    </request>
+
+    <event name="ping">
+      <description summary="ping client">
+	Ping a client to check if it is receiving events and sending
+	requests. A client is expected to reply with a pong request.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the ping"/>
+    </event>
+
+    <event name="configure">
+      <description summary="suggest resize">
+	The configure event asks the client to resize its surface.
+
+	The size is a hint, in the sense that the client is free to
+	ignore it if it doesn't resize, pick a smaller size (to
+	satisfy aspect ratio or resize in steps of NxM pixels).
+
+	The edges parameter provides a hint about how the surface
+	was resized. The client may use this information to decide
+	how to adjust its content to the new size (e.g. a scrolling
+	area might adjust its content position to leave the viewable
+	content unmoved).
+
+	The client is free to dismiss all but the last configure
+	event it received.
+
+	The width and height arguments specify the size of the window
+	in surface-local coordinates.
+      </description>
+      <arg name="edges" type="uint" enum="resize" summary="how the surface was resized"/>
+      <arg name="width" type="int" summary="new width of the surface"/>
+      <arg name="height" type="int" summary="new height of the surface"/>
+    </event>
+
+    <event name="popup_done">
+      <description summary="popup interaction is done">
+	The popup_done event is sent out when a popup grab is broken,
+	that is, when the user clicks a surface that doesn't belong
+	to the client owning the popup surface.
+      </description>
+    </event>
+  </interface>
+
+  <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.
+
+      The size of a surface (and relative positions on it) is described
+      in surface-local coordinates, which may differ from the buffer
+      coordinates of the pixel content, in case a buffer_transform
+      or a buffer_scale is used.
+
+      A surface without a "role" is fairly useless: a compositor does
+      not know where, when or how to present it. The role is the
+      purpose of a wl_surface. Examples of roles are a cursor for a
+      pointer (as set by wl_pointer.set_cursor), a drag icon
+      (wl_data_device.start_drag), a sub-surface
+      (wl_subcompositor.get_subsurface), and a window as defined by a
+      shell protocol (e.g. wl_shell.get_shell_surface).
+
+      A surface can have only one role at a time. Initially a
+      wl_surface does not have a role. Once a wl_surface is given a
+      role, it is set permanently for the whole lifetime of the
+      wl_surface object. Giving the current role again is allowed,
+      unless explicitly forbidden by the relevant interface
+      specification.
+
+      Surface roles are given by requests in other interfaces such as
+      wl_pointer.set_cursor. The request should explicitly mention
+      that this request gives a role to a wl_surface. Often, this
+      request also creates a new protocol object that represents the
+      role and adds additional functionality to wl_surface. When a
+      client wants to destroy a wl_surface, they must destroy this 'role
+      object' before the wl_surface.
+
+      Destroying the role object does not remove the role from the
+      wl_surface, but it may stop the wl_surface from "playing the role".
+      For instance, if a wl_subsurface object is destroyed, the wl_surface
+      it was created for will be unmapped and forget its position and
+      z-order. It is allowed to create a wl_subsurface for the same
+      wl_surface again, but it is not allowed to use the wl_surface as
+      a cursor (cursor is a different role than sub-surface, and role
+      switching is not allowed).
+    </description>
+
+    <enum name="error">
+      <description summary="wl_surface error values">
+	These errors can be emitted in response to wl_surface requests.
+      </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"/>
+    </enum>
+
+    <request name="destroy" type="destructor">
+      <description summary="delete surface">
+	Deletes the surface and invalidates its object ID.
+      </description>
+    </request>
+
+    <request name="attach">
+      <description summary="set the surface contents">
+	Set a buffer as the content of this surface.
+
+	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.
+
+	The x and y arguments specify the location of the new pending
+	buffer's upper left corner, relative to the current buffer's upper
+	left corner, in surface-local coordinates. In other words, the
+	x and y, combined with the new surface size define in which
+	directions the surface's size changes.
+
+	Surface contents are double-buffered state, see wl_surface.commit.
+
+	The initial surface contents are void; there is no content.
+	wl_surface.attach assigns the given wl_buffer as the pending
+	wl_buffer. wl_surface.commit makes the pending wl_buffer the new
+	surface contents, and the size of the surface becomes the size
+	calculated from the wl_buffer, as described above. After commit,
+	there is no pending buffer until the next attach.
+
+	Committing a pending wl_buffer allows the compositor to read the
+	pixels in the wl_buffer. The compositor may access the pixels at
+	any time after the wl_surface.commit request. When the compositor
+	will not access the pixels anymore, it will send the
+	wl_buffer.release event. Only after receiving wl_buffer.release,
+	the client may reuse the wl_buffer. A wl_buffer that has been
+	attached and then replaced by another attach instead of committed
+	will not receive a release event, and is not used by the
+	compositor.
+
+	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
+	contents become undefined immediately.
+
+	If wl_surface.attach is sent with a NULL wl_buffer, the
+	following wl_surface.commit will remove the surface content.
+      </description>
+      <arg name="buffer" type="object" interface="wl_buffer" allow-null="true"
+	   summary="buffer of surface contents"/>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+    </request>
+
+    <request name="damage">
+      <description summary="mark part of the surface damaged">
+	This request is used to describe the regions where the pending
+	buffer is different from the current surface contents, and where
+	the surface therefore needs to be repainted. The compositor
+	ignores the parts of the damage that fall outside of the surface.
+
+	Damage is double-buffered state, see wl_surface.commit.
+
+	The damage rectangle is specified in surface-local coordinates,
+	where x and y specify the upper left corner of the damage rectangle.
+
+	The initial value for pending damage is empty: no damage.
+	wl_surface.damage adds pending damage: the new pending damage
+	is the union of old pending damage and the given rectangle.
+
+	wl_surface.commit assigns pending damage as the current damage,
+	and clears pending damage. The server will clear the current
+	damage as it repaints the surface.
+
+	Alternatively, damage can be posted with wl_surface.damage_buffer
+	which uses buffer coordinates instead of surface coordinates,
+	and is probably the preferred and intuitive way of doing this.
+      </description>
+      <arg name="x" type="int" summary="surface-local x coordinate"/>
+      <arg name="y" type="int" summary="surface-local y coordinate"/>
+      <arg name="width" type="int" summary="width of damage rectangle"/>
+      <arg name="height" type="int" summary="height of damage rectangle"/>
+    </request>
+
+    <request name="frame">
+      <description summary="request a frame throttling hint">
+	Request a notification when it is a good time to start drawing a new
+	frame, by creating a frame callback. This is useful for throttling
+	redrawing operations, and driving animations.
+
+	When a client is animating on a wl_surface, it can use the 'frame'
+	request to get notified when it is a good time to draw and commit the
+	next frame of animation. If the client commits an update earlier than
+	that, it is likely that some updates will not make it to the display,
+	and the client is wasting resources by drawing too often.
+
+	The frame request will take effect on the next wl_surface.commit.
+	The notification will only be posted for one frame unless
+	requested again. For a wl_surface, the notifications are posted in
+	the order the frame requests were committed.
+
+	The server must send the notifications so that a client
+	will not send excessive updates, while still allowing
+	the highest possible update rate for clients that wait for the reply
+	before drawing again. The server should give some time for the client
+	to draw and commit after sending the frame callback events to let it
+	hit the next output refresh.
+
+	A server should avoid signaling the frame callbacks if the
+	surface is not visible in any way, e.g. the surface is off-screen,
+	or completely obscured by other opaque surfaces.
+
+	The object returned by this request will be destroyed by the
+	compositor after the callback is fired and as such the client must not
+	attempt to use it after that point.
+
+	The callback_data passed in the callback is the current time, in
+	milliseconds, with an undefined base.
+      </description>
+      <arg name="callback" type="new_id" interface="wl_callback" summary="callback object for the frame request"/>
+    </request>
+
+    <request name="set_opaque_region">
+      <description summary="set opaque region">
+	This request sets the region of the surface that contains
+	opaque content.
+
+	The opaque region is an optimization hint for the compositor
+	that lets it optimize the redrawing of content behind opaque
+	regions.  Setting an opaque region is not required for correct
+	behaviour, but marking transparent content as opaque will result
+	in repaint artifacts.
+
+	The opaque region is specified in surface-local coordinates.
+
+	The compositor ignores the parts of the opaque region that fall
+	outside of the surface.
+
+	Opaque region is double-buffered state, see wl_surface.commit.
+
+	wl_surface.set_opaque_region changes the pending opaque region.
+	wl_surface.commit copies the pending region to the current region.
+	Otherwise, the pending and current regions are never changed.
+
+	The initial value for an opaque region is empty. Setting the pending
+	opaque region has copy semantics, and the wl_region object can be
+	destroyed immediately. A NULL wl_region causes the pending opaque
+	region to be set to empty.
+      </description>
+      <arg name="region" type="object" interface="wl_region" allow-null="true"
+	   summary="opaque region of the surface"/>
+    </request>
+
+    <request name="set_input_region">
+      <description summary="set input region">
+	This request sets the region of the surface that can receive
+	pointer and touch events.
+
+	Input events happening outside of this region will try the next
+	surface in the server surface stack. The compositor ignores the
+	parts of the input region that fall outside of the surface.
+
+	The input region is specified in surface-local coordinates.
+
+	Input region is double-buffered state, see wl_surface.commit.
+
+	wl_surface.set_input_region changes the pending input region.
+	wl_surface.commit copies the pending region to the current region.
+	Otherwise the pending and current regions are never changed,
+	except cursor and icon surfaces are special cases, see
+	wl_pointer.set_cursor and wl_data_device.start_drag.
+
+	The initial value for an input region is infinite. That means the
+	whole surface will accept input. Setting the pending input region
+	has copy semantics, and the wl_region object can be destroyed
+	immediately. A NULL wl_region causes the input region to be set
+	to infinite.
+      </description>
+      <arg name="region" type="object" interface="wl_region" allow-null="true"
+	   summary="input region of the surface"/>
+    </request>
+
+    <request name="commit">
+      <description summary="commit pending surface state">
+	Surface state (input, opaque, and damage regions, attached buffers,
+	etc.) is double-buffered. Protocol requests modify the pending state,
+	as opposed to the current state in use by the compositor. A commit
+	request atomically applies all pending state, replacing the current
+	state. After commit, the new pending state is as documented for each
+	related request.
+
+	On commit, a pending wl_buffer is applied first, and all other state
+	second. This means that all coordinates in double-buffered state are
+	relative to the new wl_buffer coming into use, except for
+	wl_surface.attach itself. If there is no pending wl_buffer, the
+	coordinates are relative to the current surface contents.
+
+	All requests that need a commit to become effective are documented
+	to affect double-buffered state.
+
+	Other interfaces may add further double-buffered surface state.
+      </description>
+    </request>
+
+    <event name="enter">
+      <description summary="surface enters an output">
+	This is emitted whenever a surface's creation, movement, or resizing
+	results in some part of it being within the scanout region of an
+	output.
+
+	Note that a surface may be overlapping with zero or more outputs.
+      </description>
+      <arg name="output" type="object" interface="wl_output" summary="output entered by the surface"/>
+    </event>
+
+    <event name="leave">
+      <description summary="surface leaves an output">
+	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.
+      </description>
+      <arg name="output" type="object" interface="wl_output" summary="output left by the surface"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <request name="set_buffer_transform" since="2">
+      <description summary="sets the buffer transformation">
+	This request sets an optional transformation on how the compositor
+	interprets the contents of the buffer attached to the surface. The
+	accepted values for the transform parameter are the values for
+	wl_output.transform.
+
+	Buffer transform is double-buffered state, see wl_surface.commit.
+
+	A newly created surface has its buffer transformation set to normal.
+
+	wl_surface.set_buffer_transform changes the pending buffer
+	transformation. wl_surface.commit copies the pending buffer
+	transformation to the current one. Otherwise, the pending and current
+	values are never changed.
+
+	The purpose of this request is to allow clients to render content
+	according to the output transform, thus permitting the compositor to
+	use certain optimizations even if the display is rotated. Using
+	hardware overlays and scanning out a client buffer for fullscreen
+	surfaces are examples of such optimizations. Those optimizations are
+	highly dependent on the compositor implementation, so the use of this
+	request should be considered on a case-by-case basis.
+
+	Note that if the transform value includes 90 or 270 degree rotation,
+	the width of the buffer will become the surface height and the height
+	of the buffer will become the surface width.
+
+	If transform is not one of the values from the
+	wl_output.transform enum the invalid_transform protocol error
+	is raised.
+      </description>
+      <arg name="transform" type="int" enum="wl_output.transform"
+	   summary="transform for interpreting buffer contents"/>
+    </request>
+
+    <!-- Version 3 additions -->
+
+    <request name="set_buffer_scale" since="3">
+      <description summary="sets the buffer scaling factor">
+	This request sets an optional scaling factor on how the compositor
+	interprets the contents of the buffer attached to the window.
+
+	Buffer scale is double-buffered state, see wl_surface.commit.
+
+	A newly created surface has its buffer scale set to 1.
+
+	wl_surface.set_buffer_scale changes the pending buffer scale.
+	wl_surface.commit copies the pending buffer scale to the current one.
+	Otherwise, the pending and current values are never changed.
+
+	The purpose of this request is to allow clients to supply higher
+	resolution buffer data for use on high resolution outputs. It is
+	intended that you pick the same buffer scale as the scale of the
+	output that the surface is displayed on. This means the compositor
+	can avoid scaling when rendering the surface on that output.
+
+	Note that if the scale is larger than 1, then you have to attach
+	a buffer that is larger (by a factor of scale in each dimension)
+	than the desired surface size.
+
+	If scale is not positive the invalid_scale protocol error is
+	raised.
+      </description>
+      <arg name="scale" type="int"
+	   summary="positive scale for interpreting buffer contents"/>
+    </request>
+
+    <!-- Version 4 additions -->
+    <request name="damage_buffer" since="4">
+      <description summary="mark part of the surface damaged using buffer coordinates">
+	This request is used to describe the regions where the pending
+	buffer is different from the current surface contents, and where
+	the surface therefore needs to be repainted. The compositor
+	ignores the parts of the damage that fall outside of the surface.
+
+	Damage is double-buffered state, see wl_surface.commit.
+
+	The damage rectangle is specified in buffer coordinates,
+	where x and y specify the upper left corner of the damage rectangle.
+
+	The initial value for pending damage is empty: no damage.
+	wl_surface.damage_buffer adds pending damage: the new pending
+	damage is the union of old pending damage and the given rectangle.
+
+	wl_surface.commit assigns pending damage as the current damage,
+	and clears pending damage. The server will clear the current
+	damage as it repaints the surface.
+
+	This request differs from wl_surface.damage in only one way - it
+	takes damage in buffer coordinates instead of surface-local
+	coordinates. While this generally is more intuitive than surface
+	coordinates, it is especially desirable when using wp_viewport
+	or when a drawing library (like EGL) is unaware of buffer scale
+	and buffer transform.
+
+	Note: Because buffer transformation changes and damage requests may
+	be interleaved in the protocol stream, it is impossible to determine
+	the actual mapping between surface and buffer damage until
+	wl_surface.commit time. Therefore, compositors wishing to take both
+	kinds of damage into account will have to accumulate damage from the
+	two requests separately and only transform from one to the other
+	after receiving the wl_surface.commit.
+      </description>
+      <arg name="x" type="int" summary="buffer-local x coordinate"/>
+      <arg name="y" type="int" summary="buffer-local y coordinate"/>
+      <arg name="width" type="int" summary="width of damage rectangle"/>
+      <arg name="height" type="int" summary="height of damage rectangle"/>
+    </request>
+   </interface>
+
+  <interface name="wl_seat" version="6">
+    <description summary="group of input devices">
+      A seat is a group of keyboards, pointer and touch devices. This
+      object is published as a global during start up, or when such a
+      device is hot plugged.  A seat typically has a pointer and
+      maintains a keyboard focus and a pointer focus.
+    </description>
+
+    <enum name="capability" bitfield="true">
+      <description summary="seat capability bitmask">
+	This is a bitmask of capabilities this seat has; if a member is
+	set, then it is present on the seat.
+      </description>
+      <entry name="pointer" value="1" summary="the seat has pointer devices"/>
+      <entry name="keyboard" value="2" summary="the seat has one or more keyboards"/>
+      <entry name="touch" value="4" summary="the seat has touch devices"/>
+    </enum>
+
+    <event name="capabilities">
+      <description summary="seat capabilities changed">
+	This is emitted whenever a seat gains or loses the pointer,
+	keyboard or touch capabilities.  The argument is a capability
+	enum containing the complete set of capabilities this seat has.
+
+	When the pointer capability is added, a client may create a
+	wl_pointer object using the wl_seat.get_pointer request. This object
+	will receive pointer events until the capability is removed in the
+	future.
+
+	When the pointer capability is removed, a client should destroy the
+	wl_pointer objects associated with the seat where the capability was
+	removed, using the wl_pointer.release request. No further pointer
+	events will be received on these objects.
+
+	In some compositors, if a seat regains the pointer capability and a
+	client has a previously obtained wl_pointer object of version 4 or
+	less, that object may start sending pointer events again. This
+	behavior is considered a misinterpretation of the intended behavior
+	and must not be relied upon by the client. wl_pointer objects of
+	version 5 or later must not send events if created before the most
+	recent event notifying the client of an added pointer capability.
+
+	The above behavior also applies to wl_keyboard and wl_touch with the
+	keyboard and touch capabilities, respectively.
+      </description>
+      <arg name="capabilities" type="uint" enum="capability" summary="capabilities of the seat"/>
+    </event>
+
+    <request name="get_pointer">
+      <description summary="return pointer object">
+	The ID provided will be initialized to the wl_pointer interface
+	for this seat.
+
+	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.
+      </description>
+      <arg name="id" type="new_id" interface="wl_pointer" summary="seat pointer"/>
+    </request>
+
+    <request name="get_keyboard">
+      <description summary="return keyboard object">
+	The ID provided will be initialized to the wl_keyboard interface
+	for this seat.
+
+	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.
+      </description>
+      <arg name="id" type="new_id" interface="wl_keyboard" summary="seat keyboard"/>
+    </request>
+
+    <request name="get_touch">
+      <description summary="return touch object">
+	The ID provided will be initialized to the wl_touch interface
+	for this seat.
+
+	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.
+      </description>
+      <arg name="id" type="new_id" interface="wl_touch" summary="seat touch interface"/>
+    </request>
+
+    <!-- Version 2 additions -->
+
+    <event name="name" since="2">
+      <description summary="unique identifier for this seat">
+	In a multiseat configuration this can be used by the client to help
+	identify which physical devices the seat represents. Based on
+	the seat configuration used by the compositor.
+      </description>
+      <arg name="name" type="string" summary="seat identifier"/>
+    </event>
+
+    <!-- Version 5 additions -->
+
+    <request name="release" type="destructor" since="5">
+      <description summary="release the seat object">
+	Using this request a client can tell the server that it is not going to
+	use the seat object anymore.
+      </description>
+    </request>
+
+  </interface>
+
+  <interface name="wl_pointer" version="6">
+    <description summary="pointer input device">
+      The wl_pointer interface represents one or more input devices,
+      such as mice, which control the pointer location and pointer_focus
+      of a seat.
+
+      The wl_pointer interface generates motion, enter and leave
+      events for the surfaces that the pointer is located over,
+      and button and axis events for button presses, button releases
+      and scrolling.
+    </description>
+
+    <enum name="error">
+      <entry name="role" value="0" summary="given wl_surface has another role"/>
+    </enum>
+
+    <request name="set_cursor">
+      <description summary="set the pointer surface">
+	Set the pointer surface, i.e., the surface that contains the
+	pointer image (cursor). This request gives the surface the role
+	of a cursor. If the surface already has another role, it raises
+	a protocol error.
+
+	The cursor actually changes only if the pointer
+	focus for this device is one of the requesting client's surfaces
+	or the surface parameter is the current pointer surface. If
+	there was a previous surface set with this request it is
+	replaced. If surface is NULL, the pointer image is hidden.
+
+	The parameters hotspot_x and hotspot_y define the position of
+	the pointer surface relative to the pointer location. Its
+	top-left corner is always at (x, y) - (hotspot_x, hotspot_y),
+	where (x, y) are the coordinates of the pointer location, in
+	surface-local coordinates.
+
+	On surface.attach requests to the pointer surface, hotspot_x
+	and hotspot_y are decremented by the x and y parameters
+	passed to the request. Attach must be confirmed by
+	wl_surface.commit as usual.
+
+	The hotspot can also be updated by passing the currently set
+	pointer surface to this request with new values for hotspot_x
+	and hotspot_y.
+
+	The current and pending input regions of the wl_surface are
+	cleared, and wl_surface.set_input_region is ignored until the
+	wl_surface is no longer used as the cursor. When the use as a
+	cursor ends, the current and pending input regions become
+	undefined, and the wl_surface is unmapped.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" allow-null="true"
+	   summary="pointer surface"/>
+      <arg name="hotspot_x" type="int" summary="surface-local x coordinate"/>
+      <arg name="hotspot_y" type="int" summary="surface-local y coordinate"/>
+    </request>
+
+    <event name="enter">
+      <description summary="enter event">
+	Notification that this seat's pointer is focused on a certain
+	surface.
+
+	When a seat's focus enters a surface, the pointer image
+	is undefined and a client should respond to this event by setting
+	an appropriate pointer image with the set_cursor request.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the enter event"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface entered by the pointer"/>
+      <arg name="surface_x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="surface_y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+	Notification that this seat's pointer is no longer focused on
+	a certain surface.
+
+	The leave notification is sent before the enter notification
+	for the new focus.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the leave event"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface left by the pointer"/>
+    </event>
+
+    <event name="motion">
+      <description summary="pointer motion event">
+	Notification of pointer location change. The arguments
+	surface_x and surface_y are the location relative to the
+	focused surface.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface_x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="surface_y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <enum name="button_state">
+      <description summary="physical button state">
+	Describes the physical state of a button that produced the button
+	event.
+      </description>
+      <entry name="released" value="0" summary="the button is not pressed"/>
+      <entry name="pressed" value="1" summary="the button is pressed"/>
+    </enum>
+
+    <event name="button">
+      <description summary="pointer button event">
+	Mouse button click and release notifications.
+
+	The location of the click is given by the last motion or
+	enter event.
+	The time argument is a timestamp with millisecond
+	granularity, with an undefined base.
+
+	The button is a button code as defined in the Linux kernel's
+	linux/input-event-codes.h header file, e.g. BTN_LEFT.
+
+	Any 16-bit button code value is reserved for future additions to the
+	kernel's event code list. All other button codes above 0xFFFF are
+	currently undefined but may be used in future versions of this
+	protocol.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the button event"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="button" type="uint" summary="button that produced the event"/>
+      <arg name="state" type="uint" enum="button_state" summary="physical state of the button"/>
+    </event>
+
+    <enum name="axis">
+      <description summary="axis types">
+	Describes the axis types of scroll events.
+      </description>
+      <entry name="vertical_scroll" value="0" summary="vertical axis"/>
+      <entry name="horizontal_scroll" value="1" summary="horizontal axis"/>
+    </enum>
+
+    <event name="axis">
+      <description summary="axis event">
+	Scroll and other axis notifications.
+
+	For scroll events (vertical and horizontal scroll axes), the
+	value parameter is the length of a vector along the specified
+	axis in a coordinate space identical to those of motion events,
+	representing a relative movement along the specified axis.
+
+	For devices that support movements non-parallel to axes multiple
+	axis events will be emitted.
+
+	When applicable, for example for touch pads, the server can
+	choose to emit scroll events where the motion vector is
+	equivalent to a motion event vector.
+
+	When applicable, a client can transform its content relative to the
+	scroll distance.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+      <arg name="value" type="fixed" summary="length of vector in surface-local coordinate space"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the pointer object">
+	Using this request a client can tell the server that it is not going to
+	use the pointer object anymore.
+
+	This request destroys the pointer proxy object, so clients must not call
+	wl_pointer_destroy() after using this request.
+      </description>
+    </request>
+
+    <!-- Version 5 additions -->
+
+    <event name="frame" since="5">
+      <description summary="end of a pointer event sequence">
+	Indicates the end of a set of events that logically belong together.
+	A client is expected to accumulate the data in all events within the
+	frame before proceeding.
+
+	All wl_pointer events before a wl_pointer.frame event belong
+	logically together. For example, in a diagonal scroll motion the
+	compositor will send an optional wl_pointer.axis_source event, two
+	wl_pointer.axis events (horizontal and vertical) and finally a
+	wl_pointer.frame event. The client may use this information to
+	calculate a diagonal vector for scrolling.
+
+	When multiple wl_pointer.axis events occur within the same frame,
+	the motion vector is the combined motion of all events.
+	When a wl_pointer.axis and a wl_pointer.axis_stop event occur within
+	the same frame, this indicates that axis movement in one axis has
+	stopped but continues in the other axis.
+	When multiple wl_pointer.axis_stop events occur within the same
+	frame, this indicates that these axes stopped in the same instance.
+
+	A wl_pointer.frame event is sent for every logical event group,
+	even if the group only contains a single wl_pointer event.
+	Specifically, a client may get a sequence: motion, frame, button,
+	frame, axis, frame, axis_stop, frame.
+
+	The wl_pointer.enter and wl_pointer.leave events are logical events
+	generated by the compositor and not the hardware. These events are
+	also grouped by a wl_pointer.frame. When a pointer moves from one
+	surface to another, a compositor should group the
+	wl_pointer.leave event within the same wl_pointer.frame.
+	However, a client must not rely on wl_pointer.leave and
+	wl_pointer.enter being in the same wl_pointer.frame.
+	Compositor-specific policies may require the wl_pointer.leave and
+	wl_pointer.enter event being split across multiple wl_pointer.frame
+	groups.
+      </description>
+    </event>
+
+    <enum name="axis_source">
+      <description summary="axis source types">
+	Describes the source types for axis events. This indicates to the
+	client how an axis event was physically generated; a client may
+	adjust the user interface accordingly. For example, scroll events
+	from a "finger" source may be in a smooth coordinate space with
+	kinetic scrolling whereas a "wheel" source may be in discrete steps
+	of a number of lines.
+      </description>
+      <entry name="wheel" value="0" summary="a physical wheel rotation" />
+      <entry name="finger" value="1" summary="finger on a touch surface" />
+      <entry name="continuous" value="2">
+	<description summary="continuous coordinate space">
+	  A device generating events in a continuous coordinate space, but
+	  using something other than a finger. One example for this source
+	  is button-based scrolling where the vertical motion of a device
+	  is converted to scroll events while a button is held down.
+	</description>
+      </entry>
+      <entry name="wheel_tilt" value="3" since="6">
+	<description summary="a physical wheel tilt">
+	  Indicates that the actual device is a wheel but the scroll event is
+	  not caused by a rotation but a (usually sideways) tilt of the wheel.
+	</description>
+      </entry>
+    </enum>
+
+    <event name="axis_source" since="5">
+      <description summary="axis source event">
+	Source information for scroll and other axes.
+
+	This event does not occur on its own. It is sent before a
+	wl_pointer.frame event and carries the source information for
+	all events within that frame.
+
+	The source specifies how this event was generated. If the source is
+	wl_pointer.axis_source.finger, a wl_pointer.axis_stop event will be
+	sent when the user lifts the finger off the device.
+
+	If the source is wl_pointer.axis_source.wheel,
+	wl_pointer.axis_source.wheel_tilt or
+	wl_pointer.axis_source.continuous, a wl_pointer.axis_stop event may
+	or may not be sent. Whether a compositor sends an axis_stop event
+	for these sources is hardware-specific and implementation-dependent;
+	clients must not rely on receiving an axis_stop event for these
+	scroll sources and should treat scroll sequences from these scroll
+	sources as unterminated by default.
+
+	This event is optional. If the source is unknown for a particular
+	axis event sequence, no event is sent.
+	Only one wl_pointer.axis_source event is permitted per frame.
+
+	The order of wl_pointer.axis_discrete and wl_pointer.axis_source is
+	not guaranteed.
+      </description>
+      <arg name="axis_source" type="uint" enum="axis_source" summary="source of the axis event"/>
+    </event>
+
+    <event name="axis_stop" since="5">
+      <description summary="axis stop event">
+	Stop notification for scroll and other axes.
+
+	For some wl_pointer.axis_source types, a wl_pointer.axis_stop event
+	is sent to notify a client that the axis sequence has terminated.
+	This enables the client to implement kinetic scrolling.
+	See the wl_pointer.axis_source documentation for information on when
+	this event may be generated.
+
+	Any wl_pointer.axis events with the same axis_source after this
+	event should be considered as the start of a new axis motion.
+
+	The timestamp is to be interpreted identical to the timestamp in the
+	wl_pointer.axis event. The timestamp value may be the same as a
+	preceding wl_pointer.axis event.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="axis" type="uint" enum="axis" summary="the axis stopped with this event"/>
+    </event>
+
+    <event name="axis_discrete" since="5">
+      <description summary="axis click event">
+	Discrete step information for scroll and other axes.
+
+	This event carries the axis value of the wl_pointer.axis event in
+	discrete steps (e.g. mouse wheel clicks).
+
+	This event does not occur on its own, it is coupled with a
+	wl_pointer.axis event that represents this axis value on a
+	continuous scale. The protocol guarantees that each axis_discrete
+	event is always followed by exactly one axis event with the same
+	axis number within the same wl_pointer.frame. Note that the protocol
+	allows for other events to occur between the axis_discrete and
+	its coupled axis event, including other axis_discrete or axis
+	events.
+
+	This event is optional; continuous scrolling devices
+	like two-finger scrolling on touchpads do not have discrete
+	steps and do not generate this event.
+
+	The discrete value carries the directional information. e.g. a value
+	of -2 is two steps towards the negative direction of this axis.
+
+	The axis number is identical to the axis number in the associated
+	axis event.
+
+	The order of wl_pointer.axis_discrete and wl_pointer.axis_source is
+	not guaranteed.
+      </description>
+      <arg name="axis" type="uint" enum="axis" summary="axis type"/>
+      <arg name="discrete" type="int" summary="number of steps"/>
+    </event>
+  </interface>
+
+  <interface name="wl_keyboard" version="6">
+    <description summary="keyboard input device">
+      The wl_keyboard interface represents one or more keyboards
+      associated with a seat.
+    </description>
+
+    <enum name="keymap_format">
+      <description summary="keyboard mapping format">
+	This specifies the format of the keymap provided to the
+	client with the wl_keyboard.keymap event.
+      </description>
+      <entry name="no_keymap" value="0"
+	     summary="no keymap; client must understand how to interpret the raw keycode"/>
+      <entry name="xkb_v1" value="1"
+	     summary="libxkbcommon compatible; to determine the xkb keycode, clients must add 8 to the key event keycode"/>
+    </enum>
+
+    <event name="keymap">
+      <description summary="keyboard mapping">
+	This event provides a file descriptor to the client which can be
+	memory-mapped to provide a keyboard mapping description.
+      </description>
+      <arg name="format" type="uint" enum="keymap_format" summary="keymap format"/>
+      <arg name="fd" type="fd" summary="keymap file descriptor"/>
+      <arg name="size" type="uint" summary="keymap size, in bytes"/>
+    </event>
+
+    <event name="enter">
+      <description summary="enter event">
+	Notification that this seat's keyboard focus is on a certain
+	surface.
+      </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"/>
+      <arg name="keys" type="array" summary="the currently pressed keys"/>
+    </event>
+
+    <event name="leave">
+      <description summary="leave event">
+	Notification that this seat's keyboard focus is no longer on
+	a certain surface.
+
+	The leave notification is sent before the enter notification
+	for the new focus.
+      </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"/>
+    </event>
+
+    <enum name="key_state">
+      <description summary="physical key state">
+	Describes the physical state of a key that produced the key event.
+      </description>
+      <entry name="released" value="0" summary="key is not pressed"/>
+      <entry name="pressed" value="1" summary="key is pressed"/>
+    </enum>
+
+    <event name="key">
+      <description summary="key event">
+	A key was pressed or released.
+	The time argument is a timestamp with millisecond
+	granularity, with an undefined base.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the key event"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="key" type="uint" summary="key that produced the event"/>
+      <arg name="state" type="uint" enum="key_state" summary="physical state of the key"/>
+    </event>
+
+    <event name="modifiers">
+      <description summary="modifier and group state">
+	Notifies clients that the modifier and/or group state has
+	changed, and it should update its local state.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the modifiers event"/>
+      <arg name="mods_depressed" type="uint" summary="depressed modifiers"/>
+      <arg name="mods_latched" type="uint" summary="latched modifiers"/>
+      <arg name="mods_locked" type="uint" summary="locked modifiers"/>
+      <arg name="group" type="uint" summary="keyboard layout"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the keyboard object"/>
+    </request>
+
+    <!-- Version 4 additions -->
+
+    <event name="repeat_info" since="4">
+      <description summary="repeat rate and delay">
+	Informs the client about the keyboard's repeat rate and delay.
+
+	This event is sent as soon as the wl_keyboard object has been created,
+	and is guaranteed to be received by the client before any key press
+	event.
+
+	Negative values for either rate or delay are illegal. A rate of zero
+	will disable any repeating (regardless of the value of delay).
+
+	This event can be sent later on as well with a new value if necessary,
+	so clients should continue listening for the event past the creation
+	of wl_keyboard.
+      </description>
+      <arg name="rate" type="int"
+	   summary="the rate of repeating keys in characters per second"/>
+      <arg name="delay" type="int"
+	   summary="delay in milliseconds since key down until repeating starts"/>
+    </event>
+  </interface>
+
+  <interface name="wl_touch" version="6">
+    <description summary="touchscreen input device">
+      The wl_touch interface represents a touchscreen
+      associated with a seat.
+
+      Touch interactions can consist of one or more contacts.
+      For each contact, a series of events is generated, starting
+      with a down event, followed by zero or more motion events,
+      and ending with an up event. Events relating to the same
+      contact point can be identified by the ID of the sequence.
+    </description>
+
+    <event name="down">
+      <description summary="touch down event and beginning of a touch sequence">
+	A new touch point has appeared on the surface. This touch point is
+	assigned a unique ID. Future events from this touch point reference
+	this ID. The ID ceases to be valid after a touch up event and may be
+	reused in the future.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the touch down event"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="surface" type="object" interface="wl_surface" summary="surface touched"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="up">
+      <description summary="end of a touch event sequence">
+	The touch point has disappeared. No further events will be sent for
+	this touch point and the touch point's ID is released and may be
+	reused in a future touch down event.
+      </description>
+      <arg name="serial" type="uint" summary="serial number of the touch up event"/>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+    </event>
+
+    <event name="motion">
+      <description summary="update of touch point coordinates">
+	A touch point has changed coordinates.
+      </description>
+      <arg name="time" type="uint" summary="timestamp with millisecond granularity"/>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="x" type="fixed" summary="surface-local x coordinate"/>
+      <arg name="y" type="fixed" summary="surface-local y coordinate"/>
+    </event>
+
+    <event name="frame">
+      <description summary="end of touch frame event">
+	Indicates the end of a set of events that logically belong together.
+	A client is expected to accumulate the data in all events within the
+	frame before proceeding.
+
+	A wl_touch.frame terminates at least one event but otherwise no
+	guarantee is provided about the set of events within a frame. A client
+	must assume that any state not updated in a frame is unchanged from the
+	previously known state.
+      </description>
+    </event>
+
+    <event name="cancel">
+      <description summary="touch session cancelled">
+	Sent if the compositor decides the touch stream is a global
+	gesture. No further events are sent to the clients from that
+	particular gesture. Touch cancellation applies to all touch points
+	currently active on this client's surface. The client is
+	responsible for finalizing the touch points, future touch points on
+	this surface may reuse the touch point ID.
+      </description>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the touch object"/>
+    </request>
+
+    <!-- Version 6 additions -->
+
+    <event name="shape" since="6">
+      <description summary="update shape of touch point">
+	Sent when a touchpoint has changed its shape.
+
+	This event does not occur on its own. It is sent before a
+	wl_touch.frame event and carries the new shape information for
+	any previously reported, or new touch points of that frame.
+
+	Other events describing the touch point such as wl_touch.down,
+	wl_touch.motion or wl_touch.orientation may be sent within the
+	same wl_touch.frame. A client should treat these events as a single
+	logical touch point update. The order of wl_touch.shape,
+	wl_touch.orientation and wl_touch.motion is not guaranteed.
+	A wl_touch.down event is guaranteed to occur before the first
+	wl_touch.shape event for this touch ID but both events may occur within
+	the same wl_touch.frame.
+
+	A touchpoint shape is approximated by an ellipse through the major and
+	minor axis length. The major axis length describes the longer diameter
+	of the ellipse, while the minor axis length describes the shorter
+	diameter. Major and minor are orthogonal and both are specified in
+	surface-local coordinates. The center of the ellipse is always at the
+	touchpoint location as reported by wl_touch.down or wl_touch.move.
+
+	This event is only sent by the compositor if the touch device supports
+	shape reports. The client has to make reasonable assumptions about the
+	shape if it did not receive this event.
+      </description>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="major" type="fixed" summary="length of the major axis in surface-local coordinates"/>
+      <arg name="minor" type="fixed" summary="length of the minor axis in surface-local coordinates"/>
+    </event>
+
+    <event name="orientation" since="6">
+      <description summary="update orientation of touch point">
+	Sent when a touchpoint has changed its orientation.
+
+	This event does not occur on its own. It is sent before a
+	wl_touch.frame event and carries the new shape information for
+	any previously reported, or new touch points of that frame.
+
+	Other events describing the touch point such as wl_touch.down,
+	wl_touch.motion or wl_touch.shape may be sent within the
+	same wl_touch.frame. A client should treat these events as a single
+	logical touch point update. The order of wl_touch.shape,
+	wl_touch.orientation and wl_touch.motion is not guaranteed.
+	A wl_touch.down event is guaranteed to occur before the first
+	wl_touch.orientation event for this touch ID but both events may occur
+	within the same wl_touch.frame.
+
+	The orientation describes the clockwise angle of a touchpoint's major
+	axis to the positive surface y-axis and is normalized to the -180 to
+	+180 degree range. The granularity of orientation depends on the touch
+	device, some devices only support binary rotation values between 0 and
+	90 degrees.
+
+	This event is only sent by the compositor if the touch device supports
+	orientation reports.
+      </description>
+      <arg name="id" type="int" summary="the unique ID of this touch point"/>
+      <arg name="orientation" type="fixed" summary="angle between major axis and positive surface y-axis in degrees"/>
+    </event>
+  </interface>
+
+  <interface name="wl_output" version="3">
+    <description summary="compositor output region">
+      An output describes part of the compositor geometry.  The
+      compositor works in the 'compositor coordinate system' and an
+      output corresponds to a rectangular area in that space that is
+      actually visible.  This typically corresponds to a monitor that
+      displays part of the compositor space.  This object is published
+      as global during start up, or when a monitor is hotplugged.
+    </description>
+
+    <enum name="subpixel">
+      <description summary="subpixel geometry information">
+	This enumeration describes how the physical
+	pixels on an output are laid out.
+      </description>
+      <entry name="unknown" value="0" summary="unknown geometry"/>
+      <entry name="none" value="1" summary="no geometry"/>
+      <entry name="horizontal_rgb" value="2" summary="horizontal RGB"/>
+      <entry name="horizontal_bgr" value="3" summary="horizontal BGR"/>
+      <entry name="vertical_rgb" value="4" summary="vertical RGB"/>
+      <entry name="vertical_bgr" value="5" summary="vertical BGR"/>
+    </enum>
+
+    <enum name="transform">
+      <description summary="transform from framebuffer to output">
+	This describes the transform that a compositor will apply to a
+	surface to compensate for the rotation or mirroring of an
+	output device.
+
+	The flipped values correspond to an initial flip around a
+	vertical axis followed by rotation.
+
+	The purpose is mainly to allow clients to render accordingly and
+	tell the compositor, so that for fullscreen surfaces, the
+	compositor will still be able to scan out directly from client
+	surfaces.
+      </description>
+      <entry name="normal" value="0" summary="no transform"/>
+      <entry name="90" value="1" summary="90 degrees counter-clockwise"/>
+      <entry name="180" value="2" summary="180 degrees counter-clockwise"/>
+      <entry name="270" value="3" summary="270 degrees counter-clockwise"/>
+      <entry name="flipped" value="4" summary="180 degree flip around a vertical axis"/>
+      <entry name="flipped_90" value="5" summary="flip and rotate 90 degrees counter-clockwise"/>
+      <entry name="flipped_180" value="6" summary="flip and rotate 180 degrees counter-clockwise"/>
+      <entry name="flipped_270" value="7" summary="flip and rotate 270 degrees counter-clockwise"/>
+    </enum>
+
+    <event name="geometry">
+      <description summary="properties of the output">
+	The geometry event describes geometric properties of the output.
+	The event is sent when binding to the output object and whenever
+	any of the properties change.
+      </description>
+      <arg name="x" type="int"
+	   summary="x position within the global compositor space"/>
+      <arg name="y" type="int"
+	   summary="y position within the global compositor space"/>
+      <arg name="physical_width" type="int"
+	   summary="width in millimeters of the output"/>
+      <arg name="physical_height" type="int"
+	   summary="height in millimeters of the output"/>
+      <arg name="subpixel" type="int" enum="subpixel"
+	   summary="subpixel orientation of the output"/>
+      <arg name="make" type="string"
+	   summary="textual description of the manufacturer"/>
+      <arg name="model" type="string"
+	   summary="textual description of the model"/>
+      <arg name="transform" type="int" enum="transform"
+	   summary="transform that maps framebuffer to output"/>
+    </event>
+
+    <enum name="mode" bitfield="true">
+      <description summary="mode information">
+	These flags describe properties of an output mode.
+	They are used in the flags bitfield of the mode event.
+      </description>
+      <entry name="current" value="0x1"
+	     summary="indicates this is the current mode"/>
+      <entry name="preferred" value="0x2"
+	     summary="indicates this is the preferred mode"/>
+    </enum>
+
+    <event name="mode">
+      <description summary="advertise available modes for the output">
+	The mode event describes an available mode for the output.
+
+	The event is sent when binding to the output object and there
+	will always be one mode, the current mode.  The event is sent
+	again if an output changes mode, for the mode that is now
+	current.  In other words, the current mode is always the last
+	mode that was received with the current flag set.
+
+	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,
+	the output may be scaled, as described in wl_output.scale,
+	or transformed, as described in wl_output.transform.
+      </description>
+      <arg name="flags" type="uint" enum="mode" summary="bitfield of mode flags"/>
+      <arg name="width" type="int" summary="width of the mode in hardware units"/>
+      <arg name="height" type="int" summary="height of the mode in hardware units"/>
+      <arg name="refresh" type="int" summary="vertical refresh rate in mHz"/>
+    </event>
+
+    <!-- Version 2 additions -->
+
+    <event name="done" since="2">
+      <description summary="sent all information about output">
+	This event is sent after all other properties have been
+	sent after binding to the output object and after any
+	other property changes done after that. This allows
+	changes to the output properties to be seen as
+	atomic, even if they happen via multiple events.
+      </description>
+    </event>
+
+    <event name="scale" since="2">
+      <description summary="output scaling properties">
+	This event contains scaling geometry information
+	that is not in the geometry event. It may be sent after
+	binding the output object or if the output scale changes
+	later. If it is not sent, the client should assume a
+	scale of 1.
+
+	A scale larger than 1 means that the compositor will
+	automatically scale surface buffers by this amount
+	when rendering. This is used for very high resolution
+	displays where applications rendering at the native
+	resolution would be too small to be legible.
+
+	It is intended that scaling aware clients track the
+	current output of a surface, and if it is on a scaled
+	output it should use wl_surface.set_buffer_scale with
+	the scale of the output. That way the compositor can
+	avoid scaling the surface, and the client can supply
+	a higher detail image.
+      </description>
+      <arg name="factor" type="int" summary="scaling factor of output"/>
+    </event>
+
+    <!-- Version 3 additions -->
+
+    <request name="release" type="destructor" since="3">
+      <description summary="release the output object">
+	Using this request a client can tell the server that it is not going to
+	use the output object anymore.
+      </description>
+    </request>
+  </interface>
+
+  <interface name="wl_region" version="1">
+    <description summary="region interface">
+      A region object describes an area.
+
+      Region objects are used to describe the opaque and input
+      regions of a surface.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="destroy region">
+	Destroy the region.  This will invalidate the object ID.
+      </description>
+    </request>
+
+    <request name="add">
+      <description summary="add rectangle to region">
+	Add the specified rectangle to the region.
+      </description>
+      <arg name="x" type="int" summary="region-local x coordinate"/>
+      <arg name="y" type="int" summary="region-local y coordinate"/>
+      <arg name="width" type="int" summary="rectangle width"/>
+      <arg name="height" type="int" summary="rectangle height"/>
+    </request>
+
+    <request name="subtract">
+      <description summary="subtract rectangle from region">
+	Subtract the specified rectangle from the region.
+      </description>
+      <arg name="x" type="int" summary="region-local x coordinate"/>
+      <arg name="y" type="int" summary="region-local y coordinate"/>
+      <arg name="width" type="int" summary="rectangle width"/>
+      <arg name="height" type="int" summary="rectangle height"/>
+    </request>
+  </interface>
+
+  <interface name="wl_subcompositor" version="1">
+    <description summary="sub-surface compositing">
+      The global interface exposing sub-surface compositing capabilities.
+      A wl_surface, that has sub-surfaces associated, is called the
+      parent surface. Sub-surfaces can be arbitrarily nested and create
+      a tree of sub-surfaces.
+
+      The root surface in a tree of sub-surfaces is the main
+      surface. The main surface cannot be a sub-surface, because
+      sub-surfaces must always have a parent.
+
+      A main surface with its sub-surfaces forms a (compound) window.
+      For window management purposes, this set of wl_surface objects is
+      to be considered as a single window, and it should also behave as
+      such.
+
+      The aim of sub-surfaces is to offload some of the compositing work
+      within a window from clients to the compositor. A prime example is
+      a video player with decorations and video in separate wl_surface
+      objects. This should allow the compositor to pass YUV video buffer
+      processing to dedicated overlay hardware when possible.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="unbind from the subcompositor interface">
+	Informs the server that the client will not be using this
+	protocol object anymore. This does not affect any other
+	objects, wl_subsurface objects included.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_surface" value="0"
+	     summary="the to-be sub-surface is invalid"/>
+    </enum>
+
+    <request name="get_subsurface">
+      <description summary="give a surface the role sub-surface">
+	Create a sub-surface interface for the given surface, and
+	associate it with the given parent surface. This turns a
+	plain wl_surface into a sub-surface.
+
+	The to-be sub-surface must not already have another role, and it
+	must not have an existing wl_subsurface object. Otherwise a protocol
+	error is raised.
+      </description>
+      <arg name="id" type="new_id" interface="wl_subsurface"
+	   summary="the new sub-surface object ID"/>
+      <arg name="surface" type="object" interface="wl_surface"
+	   summary="the surface to be turned into a sub-surface"/>
+      <arg name="parent" type="object" interface="wl_surface"
+	   summary="the parent surface"/>
+    </request>
+  </interface>
+
+  <interface name="wl_subsurface" version="1">
+    <description summary="sub-surface interface to a wl_surface">
+      An additional interface to a wl_surface object, which has been
+      made a sub-surface. A sub-surface has one parent surface. A
+      sub-surface's size and position are not limited to that of the parent.
+      Particularly, a sub-surface is not automatically clipped to its
+      parent's area.
+
+      A sub-surface becomes mapped, when a non-NULL wl_buffer is applied
+      and the parent surface is mapped. The order of which one happens
+      first is irrelevant. A sub-surface is hidden if the parent becomes
+      hidden, or if a NULL wl_buffer is applied. These rules apply
+      recursively through the tree of surfaces.
+
+      The behaviour of a wl_surface.commit request on a sub-surface
+      depends on the sub-surface's mode. The possible modes are
+      synchronized and desynchronized, see methods
+      wl_subsurface.set_sync and wl_subsurface.set_desync. Synchronized
+      mode caches the wl_surface state to be applied when the parent's
+      state gets applied, and desynchronized mode applies the pending
+      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
+      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
+      the parent and its sub-surfaces (wl_subsurface.place_above and
+      .place_below). This state is applied when the parent surface's
+      wl_surface state is applied, regardless of the sub-surface's mode.
+      As the exception, set_sync and set_desync are effective immediately.
+
+      The main surface can be thought to be always in desynchronized mode,
+      since it does not have a parent in the sub-surfaces sense.
+
+      Even if a sub-surface is in desynchronized mode, it will behave as
+      in synchronized mode, if its parent surface behaves as in
+      synchronized mode. This rule is applied recursively throughout the
+      tree of surfaces. This means, that one can set a sub-surface into
+      synchronized mode, and then assume that all its child and grand-child
+      sub-surfaces are synchronized, too, without explicitly setting them.
+
+      If the wl_surface associated with the wl_subsurface is destroyed, the
+      wl_subsurface object becomes inert. Note, that destroying either object
+      takes effect immediately. If you need to synchronize the removal
+      of a sub-surface to the parent surface update, unmap the sub-surface
+      first by attaching a NULL wl_buffer, update parent, and then destroy
+      the sub-surface.
+
+      If the parent wl_surface object is destroyed, the sub-surface is
+      unmapped.
+    </description>
+
+    <request name="destroy" type="destructor">
+      <description summary="remove sub-surface interface">
+	The sub-surface interface is removed from the wl_surface object
+	that was turned into a sub-surface with a
+	wl_subcompositor.get_subsurface request. The wl_surface's association
+	to the parent is deleted, and the wl_surface loses its role as
+	a sub-surface. The wl_surface is unmapped.
+      </description>
+    </request>
+
+    <enum name="error">
+      <entry name="bad_surface" value="0"
+	     summary="wl_surface is not a sibling or the parent"/>
+    </enum>
+
+    <request name="set_position">
+      <description summary="reposition the sub-surface">
+	This schedules a sub-surface position change.
+	The sub-surface will be moved so that its origin (top left
+	corner pixel) will be at the location x, y of the parent surface
+	coordinate system. The coordinates are not restricted to the parent
+	surface area. Negative values are allowed.
+
+	The scheduled coordinates will take effect whenever the state of the
+	parent surface is applied. When this happens depends on whether the
+	parent surface is in synchronized mode or not. See
+	wl_subsurface.set_sync and wl_subsurface.set_desync for details.
+
+	If more than one set_position request is invoked by the client before
+	the commit of the parent surface, the position of a new request always
+	replaces the scheduled position from any previous request.
+
+	The initial position is 0, 0.
+      </description>
+      <arg name="x" type="int" summary="x coordinate in the parent surface"/>
+      <arg name="y" type="int" summary="y coordinate in the parent surface"/>
+    </request>
+
+    <request name="place_above">
+      <description summary="restack the sub-surface">
+	This sub-surface is taken from the stack, and put back just
+	above the reference surface, changing the z-order of the sub-surfaces.
+	The reference surface must be one of the sibling surfaces, or the
+	parent surface. Using any other surface, including this sub-surface,
+	will cause a protocol error.
+
+	The z-order is double-buffered. Requests are handled in order and
+	applied immediately to a pending state. The final pending state is
+	copied to the active state the next time the state of the parent
+	surface is applied. When this happens depends on whether the parent
+	surface is in synchronized mode or not. See wl_subsurface.set_sync and
+	wl_subsurface.set_desync for details.
+
+	A new sub-surface is initially added as the top-most in the stack
+	of its siblings and parent.
+      </description>
+      <arg name="sibling" type="object" interface="wl_surface"
+	   summary="the reference surface"/>
+    </request>
+
+    <request name="place_below">
+      <description summary="restack the sub-surface">
+	The sub-surface is placed just below the reference surface.
+	See wl_subsurface.place_above.
+      </description>
+      <arg name="sibling" type="object" interface="wl_surface"
+	   summary="the reference surface"/>
+    </request>
+
+    <request name="set_sync">
+      <description summary="set sub-surface to synchronized mode">
+	Change the commit behaviour of the sub-surface to synchronized
+	mode, also described as the parent dependent mode.
+
+	In synchronized mode, wl_surface.commit on a sub-surface will
+	accumulate the committed state in a cache, but the state will
+	not be applied and hence will not change the compositor output.
+	The cached state is applied to the sub-surface immediately after
+	the parent surface's state is applied. This ensures atomic
+	updates of the parent and all its synchronized sub-surfaces.
+	Applying the cached state will invalidate the cache, so further
+	parent surface commits do not (re-)apply old state.
+
+	See wl_subsurface for the recursive effect of this mode.
+      </description>
+    </request>
+
+    <request name="set_desync">
+      <description summary="set sub-surface to desynchronized mode">
+	Change the commit behaviour of the sub-surface to desynchronized
+	mode, also described as independent or freely running mode.
+
+	In desynchronized mode, wl_surface.commit on a sub-surface will
+	apply the pending state directly, without caching, as happens
+	normally with a wl_surface. Calling wl_surface.commit on the
+	parent surface has no effect on the sub-surface's wl_surface
+	state. This mode allows a sub-surface to be updated on its own.
+
+	If cached state exists when wl_surface.commit is called in
+	desynchronized mode, the pending state is added to the cached
+	state, and applied as a whole. This invalidates the cache.
+
+	Note: even if a sub-surface is set to desynchronized, a parent
+	sub-surface may override it to behave as synchronized. For details,
+	see wl_subsurface.
+
+	If a surface's parent surface behaves as desynchronized, then
+	the cached state is applied on set_desync.
+      </description>
+    </request>
+  </interface>
+
+</protocol>
diff --git a/subprojects/wayland/tests/data/small-client-core.h b/subprojects/wayland/tests/data/small-client-core.h
new file mode 100644
index 0000000000000000000000000000000000000000..0e722441457b70c6a32095e199362f63871cd964
--- /dev/null
+++ b/subprojects/wayland/tests/data/small-client-core.h
@@ -0,0 +1,225 @@
+/* SCANNER TEST */
+
+#ifndef SMALL_TEST_CLIENT_PROTOCOL_H
+#define SMALL_TEST_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client-core.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_small_test The small_test protocol
+ * @section page_ifaces_small_test Interfaces
+ * - @subpage page_iface_intf_A - the thing A
+ * @section page_copyright_small_test Copyright
+ * <pre>
+ *
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * </pre>
+ */
+struct another_intf;
+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
+ *
+ * A useless example trying to tickle the scanner.
+ * @section page_iface_intf_A_api API
+ * See @ref iface_intf_A.
+ */
+/**
+ * @defgroup iface_intf_A The intf_A interface
+ *
+ * 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
+enum intf_A_foo {
+	/**
+	 * this is the first
+	 */
+	INTF_A_FOO_FIRST = 0,
+	/**
+	 * this is the second
+	 */
+	INTF_A_FOO_SECOND = 1,
+	/**
+	 * this is the third
+	 * @since 2
+	 */
+	INTF_A_FOO_THIRD = 2,
+	/**
+	 * this is a negative value
+	 * @since 2
+	 */
+	INTF_A_FOO_NEGATIVE = -1,
+	/**
+	 * this is a deprecated value
+	 * @since 2
+	 * @deprecated Deprecated since version 3
+	 */
+	INTF_A_FOO_DEPRECATED = 3,
+};
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_THIRD_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2
+#endif /* INTF_A_FOO_ENUM */
+
+/**
+ * @ingroup iface_intf_A
+ * @struct intf_A_listener
+ */
+struct intf_A_listener {
+	/**
+	 */
+	void (*hey)(void *data,
+		    struct intf_A *intf_A);
+	/**
+	 * @since 2
+	 * @deprecated Deprecated since version 3
+	 */
+	void (*yo)(void *data,
+		   struct intf_A *intf_A);
+};
+
+/**
+ * @ingroup iface_intf_A
+ */
+static inline int
+intf_A_add_listener(struct intf_A *intf_A,
+		    const struct intf_A_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) intf_A,
+				     (void (**)(void)) listener, data);
+}
+
+#define INTF_A_RQ1 0
+#define INTF_A_RQ2 1
+#define INTF_A_DESTROY 2
+
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_HEY_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_YO_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_RQ1_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_RQ2_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_intf_A */
+static inline void
+intf_A_set_user_data(struct intf_A *intf_A, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) intf_A, user_data);
+}
+
+/** @ingroup iface_intf_A */
+static inline void *
+intf_A_get_user_data(struct intf_A *intf_A)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) intf_A);
+}
+
+static inline uint32_t
+intf_A_get_version(struct intf_A *intf_A)
+{
+	return wl_proxy_get_version((struct wl_proxy *) intf_A);
+}
+
+/**
+ * @ingroup iface_intf_A
+ */
+static inline void *
+intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t version)
+{
+	struct wl_proxy *untyped_new;
+
+	untyped_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+			 INTF_A_RQ1, interface, version, 0, interface->name, version, NULL);
+
+	return (void *) untyped_new;
+}
+
+/**
+ * @ingroup iface_intf_A
+ */
+static inline struct intf_not_here *
+intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fixed_t f, int32_t fd, struct another_intf *obj)
+{
+	struct wl_proxy *typed_new;
+
+	typed_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+			 INTF_A_RQ2, &intf_not_here_interface, wl_proxy_get_version((struct wl_proxy *) intf_A), 0, NULL, str, i, u, f, fd, obj);
+
+	return (struct intf_not_here *) typed_new;
+}
+
+/**
+ * @ingroup iface_intf_A
+ */
+static inline void
+intf_A_destroy(struct intf_A *intf_A)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+			 INTF_A_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) intf_A), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/small-client.h b/subprojects/wayland/tests/data/small-client.h
new file mode 100644
index 0000000000000000000000000000000000000000..ad43592365c46e1e0de5e4de05cbb57dcdac9f7b
--- /dev/null
+++ b/subprojects/wayland/tests/data/small-client.h
@@ -0,0 +1,225 @@
+/* SCANNER TEST */
+
+#ifndef SMALL_TEST_CLIENT_PROTOCOL_H
+#define SMALL_TEST_CLIENT_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-client.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @page page_small_test The small_test protocol
+ * @section page_ifaces_small_test Interfaces
+ * - @subpage page_iface_intf_A - the thing A
+ * @section page_copyright_small_test Copyright
+ * <pre>
+ *
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * </pre>
+ */
+struct another_intf;
+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
+ *
+ * A useless example trying to tickle the scanner.
+ * @section page_iface_intf_A_api API
+ * See @ref iface_intf_A.
+ */
+/**
+ * @defgroup iface_intf_A The intf_A interface
+ *
+ * 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
+enum intf_A_foo {
+	/**
+	 * this is the first
+	 */
+	INTF_A_FOO_FIRST = 0,
+	/**
+	 * this is the second
+	 */
+	INTF_A_FOO_SECOND = 1,
+	/**
+	 * this is the third
+	 * @since 2
+	 */
+	INTF_A_FOO_THIRD = 2,
+	/**
+	 * this is a negative value
+	 * @since 2
+	 */
+	INTF_A_FOO_NEGATIVE = -1,
+	/**
+	 * this is a deprecated value
+	 * @since 2
+	 * @deprecated Deprecated since version 3
+	 */
+	INTF_A_FOO_DEPRECATED = 3,
+};
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_THIRD_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2
+#endif /* INTF_A_FOO_ENUM */
+
+/**
+ * @ingroup iface_intf_A
+ * @struct intf_A_listener
+ */
+struct intf_A_listener {
+	/**
+	 */
+	void (*hey)(void *data,
+		    struct intf_A *intf_A);
+	/**
+	 * @since 2
+	 * @deprecated Deprecated since version 3
+	 */
+	void (*yo)(void *data,
+		   struct intf_A *intf_A);
+};
+
+/**
+ * @ingroup iface_intf_A
+ */
+static inline int
+intf_A_add_listener(struct intf_A *intf_A,
+		    const struct intf_A_listener *listener, void *data)
+{
+	return wl_proxy_add_listener((struct wl_proxy *) intf_A,
+				     (void (**)(void)) listener, data);
+}
+
+#define INTF_A_RQ1 0
+#define INTF_A_RQ2 1
+#define INTF_A_DESTROY 2
+
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_HEY_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_YO_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_RQ1_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_RQ2_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_DESTROY_SINCE_VERSION 1
+
+/** @ingroup iface_intf_A */
+static inline void
+intf_A_set_user_data(struct intf_A *intf_A, void *user_data)
+{
+	wl_proxy_set_user_data((struct wl_proxy *) intf_A, user_data);
+}
+
+/** @ingroup iface_intf_A */
+static inline void *
+intf_A_get_user_data(struct intf_A *intf_A)
+{
+	return wl_proxy_get_user_data((struct wl_proxy *) intf_A);
+}
+
+static inline uint32_t
+intf_A_get_version(struct intf_A *intf_A)
+{
+	return wl_proxy_get_version((struct wl_proxy *) intf_A);
+}
+
+/**
+ * @ingroup iface_intf_A
+ */
+static inline void *
+intf_A_rq1(struct intf_A *intf_A, const struct wl_interface *interface, uint32_t version)
+{
+	struct wl_proxy *untyped_new;
+
+	untyped_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+			 INTF_A_RQ1, interface, version, 0, interface->name, version, NULL);
+
+	return (void *) untyped_new;
+}
+
+/**
+ * @ingroup iface_intf_A
+ */
+static inline struct intf_not_here *
+intf_A_rq2(struct intf_A *intf_A, const char *str, int32_t i, uint32_t u, wl_fixed_t f, int32_t fd, struct another_intf *obj)
+{
+	struct wl_proxy *typed_new;
+
+	typed_new = wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+			 INTF_A_RQ2, &intf_not_here_interface, wl_proxy_get_version((struct wl_proxy *) intf_A), 0, NULL, str, i, u, f, fd, obj);
+
+	return (struct intf_not_here *) typed_new;
+}
+
+/**
+ * @ingroup iface_intf_A
+ */
+static inline void
+intf_A_destroy(struct intf_A *intf_A)
+{
+	wl_proxy_marshal_flags((struct wl_proxy *) intf_A,
+			 INTF_A_DESTROY, NULL, wl_proxy_get_version((struct wl_proxy *) intf_A), WL_MARSHAL_FLAG_DESTROY);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/small-code-core.c b/subprojects/wayland/tests/data/small-code-core.c
new file mode 100644
index 0000000000000000000000000000000000000000..b65454930d69d3283eba5109e67bd6ff3d70b616
--- /dev/null
+++ b/subprojects/wayland/tests/data/small-code-core.c
@@ -0,0 +1,63 @@
+/* SCANNER TEST */
+
+/*
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+extern const struct wl_interface another_intf_interface;
+extern const struct wl_interface intf_not_here_interface;
+
+static const struct wl_interface *small_test_types[] = {
+	NULL,
+	&intf_not_here_interface,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&another_intf_interface,
+};
+
+static const struct wl_message intf_A_requests[] = {
+	{ "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", "", small_test_types + 0 },
+	{ "yo", "2", small_test_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface intf_A_interface = {
+	"intf_A", 3,
+	3, intf_A_requests,
+	2, intf_A_events,
+};
+
diff --git a/subprojects/wayland/tests/data/small-code.c b/subprojects/wayland/tests/data/small-code.c
new file mode 100644
index 0000000000000000000000000000000000000000..b65454930d69d3283eba5109e67bd6ff3d70b616
--- /dev/null
+++ b/subprojects/wayland/tests/data/small-code.c
@@ -0,0 +1,63 @@
+/* SCANNER TEST */
+
+/*
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+extern const struct wl_interface another_intf_interface;
+extern const struct wl_interface intf_not_here_interface;
+
+static const struct wl_interface *small_test_types[] = {
+	NULL,
+	&intf_not_here_interface,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&another_intf_interface,
+};
+
+static const struct wl_message intf_A_requests[] = {
+	{ "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", "", small_test_types + 0 },
+	{ "yo", "2", small_test_types + 0 },
+};
+
+WL_EXPORT const struct wl_interface intf_A_interface = {
+	"intf_A", 3,
+	3, intf_A_requests,
+	2, intf_A_events,
+};
+
diff --git a/subprojects/wayland/tests/data/small-private-code.c b/subprojects/wayland/tests/data/small-private-code.c
new file mode 100644
index 0000000000000000000000000000000000000000..b2bbf0a387136adda7384a33398b82489451f721
--- /dev/null
+++ b/subprojects/wayland/tests/data/small-private-code.c
@@ -0,0 +1,73 @@
+/* SCANNER TEST */
+
+/*
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include "wayland-util.h"
+
+#ifndef __has_attribute
+# define __has_attribute(x) 0  /* Compatibility with non-clang compilers. */
+#endif
+
+#if (__has_attribute(visibility) || defined(__GNUC__) && __GNUC__ >= 4)
+#define WL_PRIVATE __attribute__ ((visibility("hidden")))
+#else
+#define WL_PRIVATE
+#endif
+
+extern const struct wl_interface another_intf_interface;
+extern const struct wl_interface intf_not_here_interface;
+
+static const struct wl_interface *small_test_types[] = {
+	NULL,
+	&intf_not_here_interface,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	NULL,
+	&another_intf_interface,
+};
+
+static const struct wl_message intf_A_requests[] = {
+	{ "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", "", small_test_types + 0 },
+	{ "yo", "2", small_test_types + 0 },
+};
+
+WL_PRIVATE const struct wl_interface intf_A_interface = {
+	"intf_A", 3,
+	3, intf_A_requests,
+	2, intf_A_events,
+};
+
diff --git a/subprojects/wayland/tests/data/small-server-core.h b/subprojects/wayland/tests/data/small-server-core.h
new file mode 100644
index 0000000000000000000000000000000000000000..e696cde7c4f14f9c8297d0c3653a1e37af95a89b
--- /dev/null
+++ b/subprojects/wayland/tests/data/small-server-core.h
@@ -0,0 +1,216 @@
+/* SCANNER TEST */
+
+#ifndef SMALL_TEST_SERVER_PROTOCOL_H
+#define SMALL_TEST_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server-core.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_small_test The small_test protocol
+ * @section page_ifaces_small_test Interfaces
+ * - @subpage page_iface_intf_A - the thing A
+ * @section page_copyright_small_test Copyright
+ * <pre>
+ *
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * </pre>
+ */
+struct another_intf;
+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
+ *
+ * A useless example trying to tickle the scanner.
+ * @section page_iface_intf_A_api API
+ * See @ref iface_intf_A.
+ */
+/**
+ * @defgroup iface_intf_A The intf_A interface
+ *
+ * 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
+enum intf_A_foo {
+	/**
+	 * this is the first
+	 */
+	INTF_A_FOO_FIRST = 0,
+	/**
+	 * this is the second
+	 */
+	INTF_A_FOO_SECOND = 1,
+	/**
+	 * this is the third
+	 * @since 2
+	 */
+	INTF_A_FOO_THIRD = 2,
+	/**
+	 * this is a negative value
+	 * @since 2
+	 */
+	INTF_A_FOO_NEGATIVE = -1,
+	/**
+	 * this is a deprecated value
+	 * @since 2
+	 * @deprecated Deprecated since version 3
+	 */
+	INTF_A_FOO_DEPRECATED = 3,
+};
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_THIRD_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ * Validate a intf_A foo value.
+ *
+ * @return true on success, false on error.
+ * @ref intf_A_foo
+ */
+static inline bool
+intf_A_foo_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case INTF_A_FOO_FIRST:
+		return version >= 1;
+	case INTF_A_FOO_SECOND:
+		return version >= 1;
+	case INTF_A_FOO_THIRD:
+		return version >= 2;
+	case (uint32_t)INTF_A_FOO_NEGATIVE:
+		return version >= 2;
+	case INTF_A_FOO_DEPRECATED:
+		return version >= 2;
+	default:
+		return false;
+	}
+}
+#endif /* INTF_A_FOO_ENUM */
+
+/**
+ * @ingroup iface_intf_A
+ * @struct intf_A_interface
+ */
+struct intf_A_interface {
+	/**
+	 * @param interface name of the objects interface
+	 * @param version version of the objects interface
+	 */
+	void (*rq1)(struct wl_client *client,
+		    struct wl_resource *resource,
+		    const char *interface, uint32_t version, uint32_t untyped_new);
+	/**
+	 */
+	void (*rq2)(struct wl_client *client,
+		    struct wl_resource *resource,
+		    uint32_t typed_new,
+		    const char *str,
+		    int32_t i,
+		    uint32_t u,
+		    wl_fixed_t f,
+		    int32_t fd,
+		    struct wl_resource *obj);
+	/**
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define INTF_A_HEY 0
+#define INTF_A_YO 1
+
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_HEY_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_YO_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_RQ1_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_RQ2_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_DESTROY_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_intf_A
+ * Sends an hey event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+intf_A_send_hey(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, INTF_A_HEY);
+}
+
+/**
+ * @ingroup iface_intf_A
+ * Sends an yo event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+intf_A_send_yo(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, INTF_A_YO);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/small-server.h b/subprojects/wayland/tests/data/small-server.h
new file mode 100644
index 0000000000000000000000000000000000000000..009d9cdd328e71c4f12fd983cf1e82974c2fdf15
--- /dev/null
+++ b/subprojects/wayland/tests/data/small-server.h
@@ -0,0 +1,216 @@
+/* SCANNER TEST */
+
+#ifndef SMALL_TEST_SERVER_PROTOCOL_H
+#define SMALL_TEST_SERVER_PROTOCOL_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include "wayland-server.h"
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+struct wl_client;
+struct wl_resource;
+
+/**
+ * @page page_small_test The small_test protocol
+ * @section page_ifaces_small_test Interfaces
+ * - @subpage page_iface_intf_A - the thing A
+ * @section page_copyright_small_test Copyright
+ * <pre>
+ *
+ * Copyright © 2016 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation files
+ * (the "Software"), to deal in the Software without restriction,
+ * including without limitation the rights to use, copy, modify, merge,
+ * publish, distribute, sublicense, and/or sell copies of the Software,
+ * and to permit persons to whom the Software is furnished to do so,
+ * subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ * </pre>
+ */
+struct another_intf;
+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
+ *
+ * A useless example trying to tickle the scanner.
+ * @section page_iface_intf_A_api API
+ * See @ref iface_intf_A.
+ */
+/**
+ * @defgroup iface_intf_A The intf_A interface
+ *
+ * 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
+enum intf_A_foo {
+	/**
+	 * this is the first
+	 */
+	INTF_A_FOO_FIRST = 0,
+	/**
+	 * this is the second
+	 */
+	INTF_A_FOO_SECOND = 1,
+	/**
+	 * this is the third
+	 * @since 2
+	 */
+	INTF_A_FOO_THIRD = 2,
+	/**
+	 * this is a negative value
+	 * @since 2
+	 */
+	INTF_A_FOO_NEGATIVE = -1,
+	/**
+	 * this is a deprecated value
+	 * @since 2
+	 * @deprecated Deprecated since version 3
+	 */
+	INTF_A_FOO_DEPRECATED = 3,
+};
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_THIRD_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_NEGATIVE_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_FOO_DEPRECATED_SINCE_VERSION 2
+/**
+ * @ingroup iface_intf_A
+ * Validate a intf_A foo value.
+ *
+ * @return true on success, false on error.
+ * @ref intf_A_foo
+ */
+static inline bool
+intf_A_foo_is_valid(uint32_t value, uint32_t version) {
+	switch (value) {
+	case INTF_A_FOO_FIRST:
+		return version >= 1;
+	case INTF_A_FOO_SECOND:
+		return version >= 1;
+	case INTF_A_FOO_THIRD:
+		return version >= 2;
+	case (uint32_t)INTF_A_FOO_NEGATIVE:
+		return version >= 2;
+	case INTF_A_FOO_DEPRECATED:
+		return version >= 2;
+	default:
+		return false;
+	}
+}
+#endif /* INTF_A_FOO_ENUM */
+
+/**
+ * @ingroup iface_intf_A
+ * @struct intf_A_interface
+ */
+struct intf_A_interface {
+	/**
+	 * @param interface name of the objects interface
+	 * @param version version of the objects interface
+	 */
+	void (*rq1)(struct wl_client *client,
+		    struct wl_resource *resource,
+		    const char *interface, uint32_t version, uint32_t untyped_new);
+	/**
+	 */
+	void (*rq2)(struct wl_client *client,
+		    struct wl_resource *resource,
+		    uint32_t typed_new,
+		    const char *str,
+		    int32_t i,
+		    uint32_t u,
+		    wl_fixed_t f,
+		    int32_t fd,
+		    struct wl_resource *obj);
+	/**
+	 */
+	void (*destroy)(struct wl_client *client,
+			struct wl_resource *resource);
+};
+
+#define INTF_A_HEY 0
+#define INTF_A_YO 1
+
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_HEY_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_YO_SINCE_VERSION 2
+
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_RQ1_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_RQ2_SINCE_VERSION 1
+/**
+ * @ingroup iface_intf_A
+ */
+#define INTF_A_DESTROY_SINCE_VERSION 1
+
+/**
+ * @ingroup iface_intf_A
+ * Sends an hey event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+intf_A_send_hey(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, INTF_A_HEY);
+}
+
+/**
+ * @ingroup iface_intf_A
+ * Sends an yo event to the client owning the resource.
+ * @param resource_ The client's resource
+ */
+static inline void
+intf_A_send_yo(struct wl_resource *resource_)
+{
+	wl_resource_post_event(resource_, INTF_A_YO);
+}
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif
diff --git a/subprojects/wayland/tests/data/small.xml b/subprojects/wayland/tests/data/small.xml
new file mode 100644
index 0000000000000000000000000000000000000000..ac527795e9d9cf0884dbd6422486fb9a2ae2e8fa
--- /dev/null
+++ b/subprojects/wayland/tests/data/small.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<protocol name="small_test">
+
+  <copyright>
+    Copyright © 2016 Collabora, Ltd.
+
+    Permission is hereby granted, free of charge, to any person
+    obtaining a copy of this software and associated documentation files
+    (the "Software"), to deal in the Software without restriction,
+    including without limitation the rights to use, copy, modify, merge,
+    publish, distribute, sublicense, and/or sell copies of the Software,
+    and to permit persons to whom the Software is furnished to do so,
+    subject to the following conditions:
+
+    The above copyright notice and this permission notice (including the
+    next paragraph) shall be included in all copies or substantial
+    portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+    BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+    ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+    CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+    SOFTWARE.
+  </copyright>
+
+  <interface name="intf_A" version="3">
+    <description summary="the thing A">
+      A useless example trying to tickle the scanner.
+    </description>
+
+    <request name="rq1">
+      <arg name="untyped_new" type="new_id"/>
+    </request>
+
+    <request name="rq2">
+      <arg name="typed_new" type="new_id" interface="intf_not_here"/>
+      <arg name="str" type="string"/>
+      <arg name="i" type="int"/>
+      <arg name="u" type="uint"/>
+      <arg name="f" type="fixed"/>
+      <arg name="fd" type="fd"/>
+      <arg name="obj" type="object" interface="another_intf"/>
+    </request>
+
+    <request name="destroy" type="destructor"/>
+
+    <event name="hey"/>
+
+    <event name="yo" since="2" deprecated-since="3"/>
+
+    <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="negative" value="-1" since="2" summary="this is a negative value"/>
+	<entry name="deprecated" value="3" since="2" deprecated-since="3" summary="this is a deprecated value"/>
+    </enum>
+  </interface>
+</protocol>
diff --git a/subprojects/wayland/tests/display-test.c b/subprojects/wayland/tests/display-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..c2def444d0e0114ec5ec6dabe4df9d7864496122
--- /dev/null
+++ b/subprojects/wayland/tests/display-test.c
@@ -0,0 +1,1717 @@
+/*
+ * Copyright © 2012 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <string.h>
+#include <assert.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+
+#include <pthread.h>
+#include <poll.h>
+
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "wayland-client.h"
+#include "test-runner.h"
+#include "test-compositor.h"
+
+#include "tests-server-protocol.h"
+#include "tests-client-protocol.h"
+
+struct display_destroy_listener {
+	struct wl_listener listener;
+	int done;
+};
+
+static void
+display_destroy_notify(struct wl_listener *l, void *data)
+{
+	struct display_destroy_listener *listener;
+
+	listener = wl_container_of(l, listener, listener);
+	listener->done = 1;
+}
+
+TEST(display_destroy_listener)
+{
+	struct wl_display *display;
+	struct display_destroy_listener a, b;
+
+	display = wl_display_create();
+	assert(display);
+
+	a.listener.notify = &display_destroy_notify;
+	a.done = 0;
+	wl_display_add_destroy_listener(display, &a.listener);
+
+	assert(wl_display_get_destroy_listener(display, display_destroy_notify) ==
+	       &a.listener);
+
+	b.listener.notify = display_destroy_notify;
+	b.done = 0;
+	wl_display_add_destroy_listener(display, &b.listener);
+
+	wl_list_remove(&a.listener.link);
+
+	wl_display_destroy(display);
+
+	assert(!a.done);
+	assert(b.done);
+}
+
+/* Fake 'client' which does not use wl_display_connect, and thus leaves the
+ * file descriptor passed through WAYLAND_SOCKET intact. This should not
+ * trigger an assertion in the leak check. */
+static void
+empty_client(void)
+{
+	return;
+}
+
+TEST(tc_leaks_tests)
+{
+	struct display *d = display_create();
+	client_create_noarg(d, empty_client);
+	display_run(d);
+	display_destroy(d);
+}
+
+/* This is how pre proxy-version registry binds worked,
+ * this should create a proxy that shares the display's
+ * version number: 0 */
+static void *
+old_registry_bind(struct wl_registry *wl_registry,
+		  uint32_t name,
+		  const struct wl_interface *interface,
+		  uint32_t version)
+{
+	struct wl_proxy *id;
+
+	id = wl_proxy_marshal_constructor(
+		(struct wl_proxy *) wl_registry, WL_REGISTRY_BIND,
+		interface, name, interface->name, version, NULL);
+
+	return (void *) id;
+}
+
+struct handler_info {
+	struct wl_seat *seat;
+	uint32_t bind_version;
+	bool use_unversioned;
+};
+
+static void
+registry_handle_globals(void *data, struct wl_registry *registry,
+			uint32_t id, const char *intf, uint32_t ver)
+{
+	struct handler_info *hi = data;
+
+	/* This is only for the proxy version test */
+	if (hi->bind_version)
+		ver = hi->bind_version;
+
+	if (strcmp(intf, "wl_seat") == 0) {
+		if (hi->use_unversioned)
+			hi->seat = old_registry_bind(registry, id,
+						     &wl_seat_interface, ver);
+		else
+			hi->seat = wl_registry_bind(registry, id,
+						    &wl_seat_interface, ver);
+		assert(hi->seat);
+	}
+}
+
+static const struct wl_registry_listener registry_listener = {
+	registry_handle_globals,
+	NULL
+};
+
+static struct wl_seat *
+client_get_seat_with_info(struct client *c, struct handler_info *hi)
+{
+	struct wl_registry *reg = wl_display_get_registry(c->wl_display);
+	assert(reg);
+
+	assert(hi);
+	hi->seat = NULL;
+	wl_registry_add_listener(reg, &registry_listener, hi);
+	wl_display_roundtrip(c->wl_display);
+	assert(hi->seat);
+
+	wl_registry_destroy(reg);
+
+	return hi->seat;
+}
+
+static struct wl_seat *
+client_get_seat(struct client *c)
+{
+	struct handler_info hi;
+
+	hi.use_unversioned = false;
+	hi.bind_version = 0;
+
+	return client_get_seat_with_info(c, &hi);
+}
+
+static void
+check_pending_error(struct client *c, struct wl_proxy *proxy)
+{
+	uint32_t ec, id;
+	int err;
+	const struct wl_interface *intf;
+
+	err = wl_display_get_error(c->wl_display);
+	assert(err == EPROTO);
+
+	ec = wl_display_get_protocol_error(c->wl_display, &intf, &id);
+	assert(ec == 23);
+	assert(intf == &wl_seat_interface);
+	assert(id == wl_proxy_get_id(proxy));
+}
+
+static void
+check_for_error(struct client *c, struct wl_proxy *proxy)
+{
+	/* client should be disconnected */
+	assert(wl_display_roundtrip(c->wl_display) == -1);
+
+	check_pending_error(c, proxy);
+}
+
+static struct client_info *
+find_client_info(struct display *d, struct wl_client *client)
+{
+	struct client_info *ci;
+
+	wl_list_for_each(ci, &d->clients, link) {
+		if (ci->wl_client == client)
+			return ci;
+	}
+
+	return NULL;
+}
+
+static void
+bind_seat(struct wl_client *client, void *data,
+	  uint32_t vers, uint32_t id)
+{
+	struct display *d = data;
+	struct client_info *ci;
+	struct wl_resource *res;
+
+	ci = find_client_info(d, client);
+	assert(ci);
+
+	res = wl_resource_create(client, &wl_seat_interface, vers, id);
+	assert(res);
+
+	/* save the resource as client's info data,
+	 * so that we can use it later */
+	ci->data = res;
+}
+
+static void
+client_disconnect_nocheck(struct client *c)
+{
+	wl_proxy_destroy((struct wl_proxy *) c->tc);
+	wl_display_disconnect(c->wl_display);
+	free(c);
+}
+
+static void
+post_error_main(void)
+{
+	struct client *c = client_connect();
+	struct wl_seat *seat = client_get_seat(c);
+
+	/* stop display so that it can post the error.
+	 * The function should return -1, because of the posted error */
+	assert(stop_display(c, 1) == -1);
+
+	/* display should have posted error, check it! */
+	check_for_error(c, (struct wl_proxy *) seat);
+
+	/* don't call client_disconnect(c), because then the test would be
+	 * aborted due to checks for error in this function */
+	wl_proxy_destroy((struct wl_proxy *) seat);
+	client_disconnect_nocheck(c);
+}
+
+TEST(post_error_to_one_client)
+{
+	struct display *d = display_create();
+	struct client_info *cl;
+
+	wl_global_create(d->wl_display, &wl_seat_interface,
+			 1, d, bind_seat);
+
+	cl = client_create_noarg(d, post_error_main);
+	display_run(d);
+
+	/* the display was stopped by client, so it can
+	 * proceed in the code and post an error */
+	assert(cl->data);
+	wl_resource_post_error((struct wl_resource *) cl->data,
+			       23, "Dummy error");
+
+	/* this one should be ignored */
+	wl_resource_post_error((struct wl_resource *) cl->data,
+			       21, "Dummy error (ignore)");
+
+	display_resume(d);
+	display_destroy(d);
+}
+
+static void
+post_error_main2(void)
+{
+	struct client *c = client_connect();
+	struct wl_seat *seat = client_get_seat(c);
+
+	/* the error should not be posted for this client */
+	assert(stop_display(c, 2) >= 0);
+
+	wl_proxy_destroy((struct wl_proxy *) seat);
+	client_disconnect(c);
+}
+
+static void
+post_error_main3(void)
+{
+	struct client *c = client_connect();
+	struct wl_seat *seat = client_get_seat(c);
+
+	assert(stop_display(c, 2) == -1);
+	check_for_error(c, (struct wl_proxy *) seat);
+
+	/* don't call client_disconnect(c), because then the test would be
+	 * aborted due to checks for error in this function */
+	wl_proxy_destroy((struct wl_proxy *) seat);
+	client_disconnect_nocheck(c);
+}
+
+/* all the testcases could be in one TEST, but splitting it
+ * apart is better for debugging when the test fails */
+TEST(post_error_to_one_from_two_clients)
+{
+	struct display *d = display_create();
+	struct client_info *cl;
+
+	wl_global_create(d->wl_display, &wl_seat_interface,
+			 1, d, bind_seat);
+
+	client_create_noarg(d, post_error_main2);
+	cl = client_create_noarg(d, post_error_main3);
+	display_run(d);
+
+	/* post error only to the second client */
+	assert(cl->data);
+	wl_resource_post_error((struct wl_resource *) cl->data,
+			       23, "Dummy error");
+	wl_resource_post_error((struct wl_resource *) cl->data,
+			       21, "Dummy error (ignore)");
+
+	display_resume(d);
+	display_destroy(d);
+}
+
+/* all the testcases could be in one TEST, but splitting it
+ * apart is better for debugging when the test fails */
+TEST(post_error_to_two_clients)
+{
+	struct display *d = display_create();
+	struct client_info *cl, *cl2;
+
+	wl_global_create(d->wl_display, &wl_seat_interface,
+			 1, d, bind_seat);
+
+	cl = client_create_noarg(d, post_error_main3);
+	cl2 = client_create_noarg(d, post_error_main3);
+
+	display_run(d);
+
+	/* Try to send the error to both clients */
+	assert(cl->data && cl2->data);
+	wl_resource_post_error((struct wl_resource *) cl->data,
+			       23, "Dummy error");
+	wl_resource_post_error((struct wl_resource *) cl->data,
+			       21, "Dummy error (ignore)");
+
+	wl_resource_post_error((struct wl_resource *) cl2->data,
+			       23, "Dummy error");
+	wl_resource_post_error((struct wl_resource *) cl2->data,
+			       21, "Dummy error (ignore)");
+
+	display_resume(d);
+	display_destroy(d);
+}
+
+static void
+post_nomem_main(void)
+{
+	struct client *c = client_connect();
+	struct wl_seat *seat = client_get_seat(c);
+
+	assert(stop_display(c, 1) == -1);
+	assert(wl_display_get_error(c->wl_display) == ENOMEM);
+
+	wl_proxy_destroy((struct wl_proxy *) seat);
+	client_disconnect_nocheck(c);
+}
+
+TEST(post_nomem_tst)
+{
+	struct display *d = display_create();
+	struct client_info *cl;
+
+	wl_global_create(d->wl_display, &wl_seat_interface,
+			 1, d, bind_seat);
+
+	cl = client_create_noarg(d, post_nomem_main);
+	display_run(d);
+
+	assert(cl->data);
+	wl_resource_post_no_memory((struct wl_resource *) cl->data);
+	display_resume(d);
+
+	/* first client terminated. Run it again,
+	 * but post no memory to client */
+	cl = client_create_noarg(d, post_nomem_main);
+	display_run(d);
+
+	assert(cl->data);
+	wl_client_post_no_memory(cl->wl_client);
+	display_resume(d);
+
+	display_destroy(d);
+}
+
+static void
+post_implementation_error_main(void)
+{
+	struct client *c = client_connect();
+	struct wl_seat *seat = client_get_seat(c);
+	uint32_t object_id, protocol_error;
+	const struct wl_interface *interface;
+
+	assert(stop_display(c, 1) == -1);
+	int err = wl_display_get_error(c->wl_display);
+	fprintf(stderr, "Err is %i\n", err);
+	assert(err == EPROTO);
+	protocol_error = wl_display_get_protocol_error(c->wl_display,
+						       &interface,
+						       &object_id);
+	assert(protocol_error == WL_DISPLAY_ERROR_IMPLEMENTATION);
+	assert(interface == &wl_display_interface);
+
+	wl_proxy_destroy((struct wl_proxy *) seat);
+	client_disconnect_nocheck(c);
+}
+
+TEST(post_internal_error_tst)
+{
+	struct display *d = display_create();
+	struct client_info *cl;
+
+	wl_global_create(d->wl_display, &wl_seat_interface,
+			 1, d, bind_seat);
+
+	cl = client_create_noarg(d, post_implementation_error_main);
+	display_run(d);
+
+	wl_client_post_implementation_error(cl->wl_client, "Error %i", 20);
+
+	display_resume(d);
+
+	display_destroy(d);
+}
+
+static void
+register_reading(struct wl_display *display)
+{
+	while(wl_display_prepare_read(display) != 0 && errno == EAGAIN)
+		assert(wl_display_dispatch_pending(display) >= 0);
+	assert(wl_display_flush(display) >= 0);
+}
+
+/* create thread that will call prepare+read so that
+ * it will block */
+static pthread_t
+create_thread(struct client *c, void *(*func)(void*))
+{
+	pthread_t thread;
+
+	c->display_stopped = 0;
+	/* func must set display->stopped to 1 before sleeping */
+	assert(pthread_create(&thread, NULL, func, c) == 0);
+
+	/* make sure the thread is sleeping. It's a little bit racy
+	 * (setting display_stopped to 1 and calling wl_display_read_events)
+	 * so call usleep once again after the loop ends - it should
+	 * be sufficient... */
+	while (c->display_stopped == 0)
+		test_usleep(500);
+	test_usleep(10000);
+
+	return thread;
+}
+
+static void *
+thread_read_error(void *data)
+{
+	struct client *c = data;
+
+	register_reading(c->wl_display);
+
+	/*
+	 * Calling the read right now will block this thread
+	 * until the other thread will read the data.
+	 * However, after invoking an error, this
+	 * thread should be woken up or it will block indefinitely.
+	 */
+	c->display_stopped = 1;
+	assert(wl_display_read_events(c->wl_display) == -1);
+
+	assert(wl_display_dispatch_pending(c->wl_display) == -1);
+	assert(wl_display_get_error(c->wl_display));
+
+	pthread_exit(NULL);
+}
+
+/* test posting an error in multi-threaded environment. */
+static void
+threading_post_err(void)
+{
+	DISABLE_LEAK_CHECKS;
+
+	struct client *c = client_connect();
+	pthread_t thread;
+
+	/* register read intention */
+	register_reading(c->wl_display);
+
+	/* use this var as an indicator that thread is sleeping */
+	c->display_stopped = 0;
+
+	/* create new thread that will register its intention too */
+	thread = create_thread(c, thread_read_error);
+
+	/* so now we have sleeping thread waiting for a pthread_cond signal.
+	 * The main thread must call wl_display_read_events().
+	 * If this call fails, then it won't call broadcast at the
+	 * end of the function and the sleeping thread will block indefinitely.
+	 * Make the call fail and watch if libwayland will unblock the thread! */
+
+	/* create error on fd, so that wl_display_read_events will fail.
+	 * The same can happen when server hangs up */
+	close(wl_display_get_fd(c->wl_display));
+	/* this read events will fail and will
+	 * post an error that should wake the sleeping thread
+	 * and dispatch the incoming events */
+	assert(wl_display_read_events(c->wl_display) == -1);
+
+	/* kill test in 3 seconds. This should be enough time for the
+	 * thread to exit if it's not blocking. If everything is OK, than
+	 * the thread was woken up and the test will end before the SIGALRM */
+	test_set_timeout(3);
+	pthread_join(thread, NULL);
+
+	client_disconnect_nocheck(c);
+}
+
+TEST(threading_errors_tst)
+{
+	struct display *d = display_create();
+
+	client_create_noarg(d, threading_post_err);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+static void *
+thread_prepare_and_read(void *data)
+{
+	struct client *c = data;
+
+	register_reading(c->wl_display);
+
+	c->display_stopped = 1;
+
+	assert(wl_display_read_events(c->wl_display) == 0);
+	assert(wl_display_dispatch_pending(c->wl_display) == 0);
+
+	pthread_exit(NULL);
+}
+
+/* test cancel read*/
+static void
+threading_cancel_read(void)
+{
+	DISABLE_LEAK_CHECKS;
+
+	struct client *c = client_connect();
+	pthread_t th1, th2, th3;
+
+	register_reading(c->wl_display);
+
+	th1 = create_thread(c, thread_prepare_and_read);
+	th2 = create_thread(c, thread_prepare_and_read);
+	th3 = create_thread(c, thread_prepare_and_read);
+
+	/* all the threads are sleeping, waiting until read or cancel
+	 * is called. Cancel the read and let the threads proceed */
+	wl_display_cancel_read(c->wl_display);
+
+	/* kill test in 3 seconds. This should be enough time for the
+	 * thread to exit if it's not blocking. If everything is OK, than
+	 * the thread was woken up and the test will end before the SIGALRM */
+	test_set_timeout(3);
+	pthread_join(th1, NULL);
+	pthread_join(th2, NULL);
+	pthread_join(th3, NULL);
+
+	client_disconnect(c);
+}
+
+TEST(threading_cancel_read_tst)
+{
+	struct display *d = display_create();
+
+	client_create_noarg(d, threading_cancel_read);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+static void
+threading_read_eagain(void)
+{
+	DISABLE_LEAK_CHECKS;
+
+	struct client *c = client_connect();
+	pthread_t th1, th2, th3;
+
+	register_reading(c->wl_display);
+
+	th1 = create_thread(c, thread_prepare_and_read);
+	th2 = create_thread(c, thread_prepare_and_read);
+	th3 = create_thread(c, thread_prepare_and_read);
+
+	/* All the threads are sleeping, waiting until read or cancel
+	 * is called. Since we have no data on socket waiting,
+	 * the wl_connection_read should end up with error and set errno
+	 * to EAGAIN. Check if the threads are woken up in this case. */
+	assert(wl_display_read_events(c->wl_display) == 0);
+	/* errno should be still set to EAGAIN if wl_connection_read
+	 * set it - check if we're testing the right case */
+	assert(errno == EAGAIN);
+
+	test_set_timeout(3);
+	pthread_join(th1, NULL);
+	pthread_join(th2, NULL);
+	pthread_join(th3, NULL);
+
+	client_disconnect(c);
+}
+
+TEST(threading_read_eagain_tst)
+{
+	struct display *d = display_create();
+	client_create_noarg(d, threading_read_eagain);
+
+	display_run(d);
+
+	display_destroy(d);
+}
+
+static void *
+thread_prepare_and_read2(void *data)
+{
+	struct client *c = data;
+
+	while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
+		assert(wl_display_dispatch_pending(c->wl_display) == -1);
+	assert(wl_display_flush(c->wl_display) == -1);
+
+	c->display_stopped = 1;
+
+	assert(wl_display_read_events(c->wl_display) == -1);
+	assert(wl_display_dispatch_pending(c->wl_display) == -1);
+
+	pthread_exit(NULL);
+}
+
+static void
+threading_read_after_error(void)
+{
+	DISABLE_LEAK_CHECKS;
+
+	struct client *c = client_connect();
+	pthread_t thread;
+
+	/* create an error */
+	close(wl_display_get_fd(c->wl_display));
+	assert(wl_display_dispatch(c->wl_display) == -1);
+
+	/* try to prepare for reading */
+	while(wl_display_prepare_read(c->wl_display) != 0 && errno == EAGAIN)
+		assert(wl_display_dispatch_pending(c->wl_display) == -1);
+	assert(wl_display_flush(c->wl_display) == -1);
+
+	assert(pthread_create(&thread, NULL,
+			      thread_prepare_and_read2, c) == 0);
+
+	/* make sure thread is sleeping */
+	while (c->display_stopped == 0)
+		test_usleep(500);
+	test_usleep(10000);
+
+	assert(wl_display_read_events(c->wl_display) == -1);
+
+	/* kill test in 3 seconds */
+	test_set_timeout(3);
+	pthread_join(thread, NULL);
+
+	client_disconnect_nocheck(c);
+}
+
+TEST(threading_read_after_error_tst)
+{
+	struct display *d = display_create();
+
+	client_create_noarg(d, threading_read_after_error);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+static void
+wait_for_error_using_dispatch(struct client *c, struct wl_proxy *proxy)
+{
+	int ret;
+
+	while (true) {
+		/* Dispatching should eventually hit the protocol error before
+		 * any other error. */
+		ret = wl_display_dispatch(c->wl_display);
+		if (ret == 0) {
+			continue;
+		} else {
+			assert(errno == EPROTO);
+			break;
+		}
+	}
+
+	check_pending_error(c, proxy);
+}
+
+static void
+wait_for_error_using_prepare_read(struct client *c, struct wl_proxy *proxy)
+{
+	int ret = 0;
+	struct pollfd pfd[2];
+
+	while (true) {
+		while (wl_display_prepare_read(c->wl_display) != 0 &&
+		      errno == EAGAIN) {
+			assert(wl_display_dispatch_pending(c->wl_display) >= 0);
+		}
+
+		/* Flush may fail due to EPIPE if the connection is broken, but
+		 * this must not set a fatal display error because that would
+		 * result in it being impossible to read a potential protocol
+		 * error. */
+		do {
+			ret = wl_display_flush(c->wl_display);
+		} while (ret == -1 && (errno == EINTR || errno == EAGAIN));
+		assert(ret >= 0 || errno == EPIPE);
+		assert(wl_display_get_error(c->wl_display) == 0);
+
+		pfd[0].fd = wl_display_get_fd(c->wl_display);
+		pfd[0].events = POLLIN;
+		do {
+			ret = poll(pfd, 1, -1);
+		} while (ret == -1 && errno == EINTR);
+		assert(ret != -1);
+
+		/* We should always manage to read the error before the EPIPE
+		 * comes this way. */
+		assert(wl_display_read_events(c->wl_display) == 0);
+
+		/* Dispatching should eventually hit the protocol error before
+		 * any other error. */
+		ret = wl_display_dispatch_pending(c->wl_display);
+		if (ret == 0) {
+			continue;
+		} else {
+			assert(errno == EPROTO);
+			break;
+		}
+	}
+
+	check_pending_error(c, proxy);
+}
+
+static void
+check_error_after_epipe(void *data)
+{
+	bool use_dispatch_helpers = *(bool *) data;
+	struct client *client;
+	struct wl_seat *seat;
+	struct wl_callback *callback;
+
+	client = client_connect();
+
+	/* This will, according to the implementation below, cause the server
+	 * to post an error. */
+	seat = client_get_seat(client);
+	wl_display_flush(client->wl_display);
+
+	/* The server will not actually destroy the client until it receives
+	 * input, so send something to trigger the client destruction. */
+	callback = wl_display_sync(client->wl_display);
+	wl_callback_destroy(callback);
+
+	/* Sleep some to give the server a chance to react and destroy the
+	 * client. */
+	test_usleep(200000);
+
+	/* Wait for the protocol error and check that we reached it before
+	 * EPIPE. */
+	if (use_dispatch_helpers) {
+		wait_for_error_using_dispatch(client, (struct wl_proxy *) seat);
+	} else {
+		wait_for_error_using_prepare_read(client,
+						  (struct wl_proxy *) seat);
+	}
+
+	wl_seat_destroy(seat);
+	client_disconnect_nocheck(client);
+}
+
+static void
+bind_seat_and_post_error(struct wl_client *client, void *data,
+			 uint32_t version, uint32_t id)
+{
+	struct display *d = data;
+	struct client_info *ci;
+	struct wl_resource *resource;
+
+	ci = find_client_info(d, client);
+	assert(ci);
+
+	resource = wl_resource_create(client, &wl_seat_interface, version, id);
+	assert(resource);
+	ci->data = resource;
+
+	wl_resource_post_error(ci->data, 23, "Dummy error");
+}
+
+TEST(error_code_after_epipe)
+{
+	struct display *d = display_create();
+	bool use_dispatch_helpers;
+
+	wl_global_create(d->wl_display, &wl_seat_interface,
+			 1, d, bind_seat_and_post_error);
+
+	use_dispatch_helpers = true;
+	client_create(d, check_error_after_epipe, &use_dispatch_helpers);
+	display_run(d);
+
+	use_dispatch_helpers = false;
+	client_create(d, check_error_after_epipe, &use_dispatch_helpers);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+static void
+check_seat_versions(struct wl_seat *seat, uint32_t ev)
+{
+	struct wl_pointer *pointer;
+
+	assert(wl_proxy_get_version((struct wl_proxy *) seat) == ev);
+	assert(wl_seat_get_version(seat) == ev);
+
+	pointer = wl_seat_get_pointer(seat);
+	assert(wl_pointer_get_version(pointer) == ev);
+	assert(wl_proxy_get_version((struct wl_proxy *) pointer) == ev);
+	wl_proxy_destroy((struct wl_proxy *) pointer);
+}
+
+/* Normal client with proxy versions available. */
+static void
+seat_version(void *data)
+{
+	struct handler_info *hi = data;
+	struct client *c = client_connect();
+	struct wl_seat *seat;
+
+	/* display proxy should always be version 0 */
+	assert(wl_proxy_get_version((struct wl_proxy *) c->wl_display) == 0);
+
+	seat = client_get_seat_with_info(c, hi);
+	if (hi->use_unversioned)
+		check_seat_versions(seat, 0);
+	else
+		check_seat_versions(seat, hi->bind_version);
+
+	wl_proxy_destroy((struct wl_proxy *) seat);
+
+	client_disconnect_nocheck(c);
+}
+
+TEST(versions)
+{
+	struct display *d = display_create();
+	struct wl_global *global;
+	int i;
+
+	global = wl_global_create(d->wl_display, &wl_seat_interface,
+				  5, d, bind_seat);
+
+	for (i = 1; i <= 5; i++) {
+		struct handler_info hi;
+
+		hi.bind_version = i;
+		hi.use_unversioned = false;
+		client_create(d, seat_version, &hi);
+		hi.use_unversioned = true;
+		client_create(d, seat_version, &hi);
+	}
+
+	display_run(d);
+
+	wl_global_destroy(global);
+
+	display_destroy(d);
+}
+
+static void
+check_error_on_destroyed_object(void *data)
+{
+	struct client *c;
+	struct wl_seat *seat;
+	uint32_t id;
+	const struct wl_interface *intf;
+
+	c = client_connect();
+	seat = client_get_seat(c);
+
+	/* destroy the seat proxy. The display won't know
+	 * about it yet, so it will post the error as usual */
+	wl_proxy_destroy((struct wl_proxy *) seat);
+
+	/* let display post the error. The error will
+	 * be caught in stop_display while dispatching */
+	assert(stop_display(c, 1) == -1);
+
+	/* check the returned error. Since the object was destroyed,
+	 * we don't know the interface and id */
+	assert(wl_display_get_error(c->wl_display) == EPROTO);
+	assert(wl_display_get_protocol_error(c->wl_display, &intf, &id) == 23);
+	assert(intf == NULL);
+	assert(id == 0);
+
+	client_disconnect_nocheck(c);
+}
+
+TEST(error_on_destroyed_object)
+{
+	struct client_info *cl;
+	struct display *d = display_create();
+
+	wl_global_create(d->wl_display, &wl_seat_interface,
+			 1, d, bind_seat);
+
+	cl = client_create_noarg(d, check_error_on_destroyed_object);
+	display_run(d);
+
+	/* did client bind to the seat? */
+	assert(cl->data);
+
+	/* post error on the destroyed object */
+	wl_resource_post_error((struct wl_resource *) cl->data,
+			       23, "Dummy error");
+	display_resume(d);
+	display_destroy(d);
+}
+
+static bool
+global_filter(const struct wl_client *client,
+	      const struct wl_global *global,
+	      void *data)
+{
+	/* Hide the wl_data_offer interface if no data was provided */
+	if (wl_global_get_interface(global) == &wl_data_offer_interface)
+		return data != NULL;
+
+	/* Show all the others */
+	return true;
+}
+
+static void
+bind_data_offer(struct wl_client *client, void *data,
+		uint32_t vers, uint32_t id)
+{
+	/* Client should not be able to bind to this interface! */
+	assert(false);
+}
+
+static void
+registry_handle_filtered(void *data, struct wl_registry *registry,
+			 uint32_t id, const char *intf, uint32_t ver)
+{
+	uint32_t *name = data;
+
+	if (strcmp (intf, "wl_data_offer") == 0) {
+		assert(name);
+		*name = id;
+	}
+}
+
+static void
+registry_handle_remove_filtered(void *data, struct wl_registry *registry,
+				uint32_t id)
+{
+	assert(false);
+}
+
+static const struct wl_registry_listener registry_listener_filtered = {
+	registry_handle_filtered,
+	registry_handle_remove_filtered,
+};
+
+static void
+get_globals(void *data)
+{
+	struct client *c = client_connect();
+	struct wl_registry *registry;
+
+	registry = wl_display_get_registry(c->wl_display);
+	wl_registry_add_listener(registry, &registry_listener_filtered, data);
+	wl_display_roundtrip(c->wl_display);
+
+	wl_registry_destroy(registry);
+	client_disconnect_nocheck(c);
+}
+
+TEST(filtered_global_is_hidden)
+{
+	struct display *d;
+	struct wl_global *g;
+
+	d = display_create();
+
+	g = wl_global_create(d->wl_display, &wl_data_offer_interface,
+		      1, d, bind_data_offer);
+	wl_display_set_global_filter(d->wl_display, global_filter, NULL);
+
+	client_create_noarg(d, get_globals);
+	display_run(d);
+
+	wl_global_destroy(g);
+
+	display_destroy(d);
+}
+
+static void
+get_dynamic_globals(void *data)
+{
+	struct client *c = client_connect();
+	struct wl_registry *registry;
+
+	registry = wl_display_get_registry(c->wl_display);
+	wl_registry_add_listener(registry, &registry_listener_filtered, data);
+	wl_display_roundtrip(c->wl_display);
+
+	/* Wait for the server to create a new global */
+	assert(stop_display(c, 1) >= 0);
+
+	/* Check that we don't see it */
+	wl_display_roundtrip(c->wl_display);
+
+	/* Wait for the server to remove that global */
+	assert(stop_display(c, 1) >= 0);
+
+	/* Check that we don't get a global_remove event */
+	wl_display_roundtrip(c->wl_display);
+
+	wl_registry_destroy(registry);
+	client_disconnect_nocheck(c);
+}
+
+TEST(filtered_dynamic_global_is_hidden)
+{
+	struct display *d;
+	struct wl_global *g;
+
+	d = display_create();
+	wl_display_set_global_filter(d->wl_display, global_filter, NULL);
+
+	/* Create a client and let it enumerate the globals */
+	client_create_noarg(d, get_dynamic_globals);
+	display_run(d);
+
+	/* Dynamically create a new global */
+	g = wl_global_create(d->wl_display, &wl_data_offer_interface,
+			     1, d, bind_data_offer);
+
+	display_resume(d);
+
+	/* Dynamically remove the global */
+	wl_global_destroy(g);
+
+	display_resume(d);
+
+	display_destroy(d);
+}
+
+static void
+check_bind_error(struct client *c)
+{
+	uint32_t errorcode, id;
+	int err;
+	const struct wl_interface *intf;
+
+	err = wl_display_get_error(c->wl_display);
+	assert(err == EPROTO);
+
+	errorcode = wl_display_get_protocol_error(c->wl_display, &intf, &id);
+	assert(errorcode == WL_DISPLAY_ERROR_INVALID_OBJECT);
+}
+
+static void
+force_bind(void *data)
+{
+	struct client *c = client_connect();
+	struct wl_registry *registry;
+	void *ptr;
+	uint32_t *name = data;
+
+	registry = wl_display_get_registry(c->wl_display);
+
+	ptr = wl_registry_bind (registry, *name, &wl_data_offer_interface, 1);
+	wl_display_roundtrip(c->wl_display);
+	check_bind_error(c);
+
+	wl_proxy_destroy((struct wl_proxy *) ptr);
+	wl_registry_destroy(registry);
+
+	client_disconnect_nocheck(c);
+}
+
+TEST(bind_fails_on_filtered_global)
+{
+	struct display *d;
+	struct wl_global *g;
+	uint32_t *name;
+
+	/* Create a anonymous shared memory to pass the interface name */
+	name = mmap(NULL, sizeof(uint32_t),
+		    PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
+
+	d = display_create();
+
+	g = wl_global_create(d->wl_display, &wl_data_offer_interface,
+			     1, d, bind_data_offer);
+	wl_display_set_global_filter(d->wl_display, global_filter, name);
+
+	client_create(d, get_globals, name);
+	*name = 0;
+
+	display_run(d);
+	/* wl_data_offer should be 2 */
+	assert(*name == 2);
+	wl_display_set_global_filter(d->wl_display, global_filter, NULL);
+
+	/* Try to bind to the interface name when a global filter is in place */
+	client_create(d, force_bind, name);
+	display_run(d);
+
+	wl_global_destroy(g);
+
+	display_destroy(d);
+}
+
+static void
+pre_fd(void *data, struct fd_passer *fdp)
+{
+	fd_passer_destroy(fdp);
+}
+
+static void
+fd(void *data, struct fd_passer *fdp, int32_t fd)
+{
+	/* We destroyed the resource before this event */
+	assert(false);
+}
+
+struct fd_passer_listener fd_passer_listener = {
+	pre_fd,
+	fd,
+};
+
+static void
+zombie_fd_handle_globals(void *data, struct wl_registry *registry,
+			 uint32_t id, const char *intf, uint32_t ver)
+{
+	struct fd_passer *fdp;
+
+	if (!strcmp(intf, "fd_passer")) {
+		fdp = wl_registry_bind(registry, id, &fd_passer_interface, 1);
+		fd_passer_add_listener(fdp, &fd_passer_listener, NULL);
+	}
+}
+
+static const struct wl_registry_listener zombie_fd_registry_listener = {
+	zombie_fd_handle_globals,
+	NULL
+};
+
+static void
+zombie_client(void *data)
+{
+	struct client *c = client_connect();
+	struct wl_registry *registry;
+
+	registry = wl_display_get_registry(c->wl_display);
+	wl_registry_add_listener(registry, &zombie_fd_registry_listener, NULL);
+
+	/* Gets the registry */
+	wl_display_roundtrip(c->wl_display);
+
+	/* push out the fd_passer bind */
+	wl_display_roundtrip(c->wl_display);
+
+	/* push out our fd_passer.destroy */
+	wl_display_roundtrip(c->wl_display);
+
+	wl_registry_destroy(registry);
+
+	client_disconnect_nocheck(c);
+}
+
+struct passer_data {
+	struct wl_resource *conjoined_passer;
+};
+
+static void
+feed_pipe(int fd, char tosend)
+{
+	int count;
+
+	do {
+		count = write(fd, &tosend, 1);
+	} while (count != 1 && errno == EAGAIN);
+	assert(count == 1);
+	close(fd);
+}
+
+static void
+fd_passer_clobber(struct wl_client *client, struct wl_resource *res)
+{
+	struct passer_data *pdata = wl_resource_get_user_data(res);
+	int pipes1[2], pipes2[2], ret;
+
+	if (pdata->conjoined_passer) {
+		ret = pipe(pipes1);
+		assert(ret == 0);
+		ret = pipe(pipes2);
+		assert(ret == 0);
+
+		wl_resource_queue_event(res, FD_PASSER_FD, pipes1[0]);
+		fd_passer_send_fd(pdata->conjoined_passer, pipes2[0]);
+		feed_pipe(pipes1[1], '1');
+		feed_pipe(pipes2[1], '2');
+		close(pipes1[0]);
+		close(pipes2[0]);
+	}
+	wl_resource_destroy(res);
+}
+
+static void
+fd_passer_twin(struct wl_client *client, struct wl_resource *res, struct wl_resource *passer)
+{
+	struct passer_data *pdata = wl_resource_get_user_data(res);
+
+	pdata->conjoined_passer = passer;
+}
+
+static const struct fd_passer_interface fdp_interface = {
+	fd_passer_clobber,
+	fd_passer_twin
+};
+
+static void
+pdata_destroy(struct wl_resource *res)
+{
+	struct passer_data *pdata = wl_resource_get_user_data(res);
+
+	free(pdata);
+}
+
+static void
+bind_fd_passer(struct wl_client *client, void *data,
+	       uint32_t vers, uint32_t id)
+{
+	struct wl_resource *res;
+	struct passer_data *pdata;
+
+	pdata = malloc(sizeof(*pdata));
+	assert(pdata);
+	pdata->conjoined_passer = NULL;
+
+	res = wl_resource_create(client, &fd_passer_interface, vers, id);
+	wl_resource_set_implementation(res, &fdp_interface, pdata, pdata_destroy);
+	assert(res);
+	if (vers == 1) {
+		fd_passer_send_pre_fd(res);
+		fd_passer_send_fd(res, fileno(stdin));
+	}
+}
+
+TEST(zombie_fd)
+{
+	struct display *d;
+	struct wl_global *g;
+
+	d = display_create();
+
+	g = wl_global_create(d->wl_display, &fd_passer_interface,
+			     1, d, bind_fd_passer);
+
+	client_create_noarg(d, zombie_client);
+	display_run(d);
+
+	wl_global_destroy(g);
+
+	display_destroy(d);
+}
+
+
+static void
+double_pre_fd(void *data, struct fd_passer *fdp)
+{
+	assert(false);
+}
+
+static void
+double_fd(void *data, struct fd_passer *fdp, int32_t fd)
+{
+	char buf;
+	int count;
+
+	do {
+		count = read(fd, &buf, 1);
+	} while (count != 1 && errno == EAGAIN);
+	assert(count == 1);
+
+	close(fd);
+	fd_passer_destroy(fdp);
+	assert(buf == '2');
+}
+
+struct fd_passer_listener double_fd_passer_listener = {
+	double_pre_fd,
+	double_fd,
+};
+
+
+static void
+double_zombie_fd_handle_globals(void *data, struct wl_registry *registry,
+			 uint32_t id, const char *intf, uint32_t ver)
+{
+	struct fd_passer *fdp1, *fdp2;
+
+	if (!strcmp(intf, "fd_passer")) {
+		fdp1 = wl_registry_bind(registry, id, &fd_passer_interface, 2);
+		fd_passer_add_listener(fdp1, &double_fd_passer_listener, NULL);
+		fdp2 = wl_registry_bind(registry, id, &fd_passer_interface, 2);
+		fd_passer_add_listener(fdp2, &double_fd_passer_listener, NULL);
+		fd_passer_conjoin(fdp1, fdp2);
+		fd_passer_destroy(fdp1);
+	}
+}
+
+static const struct wl_registry_listener double_zombie_fd_registry_listener = {
+	double_zombie_fd_handle_globals,
+	NULL
+};
+
+static void
+double_zombie_client(void *data)
+{
+	struct client *c = client_connect();
+	struct wl_registry *registry;
+
+	registry = wl_display_get_registry(c->wl_display);
+	wl_registry_add_listener(registry, &double_zombie_fd_registry_listener, NULL);
+
+	/* Gets the registry */
+	wl_display_roundtrip(c->wl_display);
+
+	/* One more so server can respond to conjoin+destroy */
+	wl_display_roundtrip(c->wl_display);
+
+	/* And finally push out our last fd_passer.destroy */
+	wl_display_roundtrip(c->wl_display);
+
+	wl_registry_destroy(registry);
+
+	client_disconnect_nocheck(c);
+}
+
+TEST(zombie_fd_errant_consumption)
+{
+	struct display *d;
+	struct wl_global *g;
+
+	d = display_create();
+
+	g = wl_global_create(d->wl_display, &fd_passer_interface,
+			     2, d, bind_fd_passer);
+
+	client_create_noarg(d, double_zombie_client);
+	display_run(d);
+
+	wl_global_destroy(g);
+
+	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;
+
+	/* By default, client buffers are now unbounded, set a limit to cause
+	 * an overflow, otherwise the client buffers will grow indefinitely. */
+	wl_display_set_max_buffer_size(c->wl_display, 4096);
+
+	/* 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);
+		fprintf(stderr, "Send loop %i\n", i);
+		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 - ring_buffer_ensure_space() returns E2BIG */
+	fprintf(stderr, "Send loop failed on try %d, err = %d, %s\n", i, err, strerror(err));
+	assert(err == EAGAIN || err == E2BIG);
+
+	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);
+}
+
+static void
+terminate_display(void *arg)
+{
+	struct wl_display *wl_display = arg;
+	wl_display_terminate(wl_display);
+}
+
+TEST(no_source_terminate)
+{
+	struct display *d;
+	struct wl_event_loop *loop;
+
+	d = display_create();
+	loop = wl_display_get_event_loop(d->wl_display);
+
+	wl_event_loop_add_idle(loop, terminate_display, d->wl_display);
+
+	display_run(d);
+	display_destroy(d);
+}
diff --git a/subprojects/wayland/tests/enum-validator-test.c b/subprojects/wayland/tests/enum-validator-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..92037cff26fc7b234db1b70b7149c26e8028d00f
--- /dev/null
+++ b/subprojects/wayland/tests/enum-validator-test.c
@@ -0,0 +1,13 @@
+#include <assert.h>
+#include "data/small-server-core.h"
+
+int
+main(int argc, char *argv[]) {
+	assert(intf_A_foo_is_valid(INTF_A_FOO_FIRST, 1));
+	assert(intf_A_foo_is_valid(INTF_A_FOO_FIRST, 2));
+
+	assert(!intf_A_foo_is_valid(INTF_A_FOO_THIRD, 1));
+	assert(intf_A_foo_is_valid(INTF_A_FOO_THIRD, 2));
+
+	assert(intf_A_foo_is_valid(INTF_A_FOO_NEGATIVE, 2));
+}
diff --git a/subprojects/wayland/tests/event-loop-test.c b/subprojects/wayland/tests/event-loop-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..a51ba8fb888ec534b52fb573b9eea5219dd968ee
--- /dev/null
+++ b/subprojects/wayland/tests/event-loop-test.c
@@ -0,0 +1,555 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ * Copyright © 2012 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.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/time.h>
+
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+static int
+fd_dispatch(int fd, uint32_t mask, void *data)
+{
+	int *p = data;
+
+	assert(mask == 0);
+	++(*p);
+
+	return 0;
+}
+
+TEST(event_loop_post_dispatch_check)
+{
+	struct wl_event_loop *loop = wl_event_loop_create();
+	struct wl_event_source *source;
+	int dispatch_ran = 0;
+	int p[2];
+
+	assert(loop);
+	assert(pipe(p) == 0);
+
+	source = wl_event_loop_add_fd(loop, p[0], WL_EVENT_READABLE,
+				      fd_dispatch, &dispatch_ran);
+	assert(source);
+	wl_event_source_check(source);
+
+	wl_event_loop_dispatch(loop, 0);
+	assert(dispatch_ran == 1);
+
+	assert(close(p[0]) == 0);
+	assert(close(p[1]) == 0);
+	wl_event_source_remove(source);
+	wl_event_loop_destroy(loop);
+}
+
+struct free_source_context {
+	struct wl_event_source *source1, *source2;
+	int p1[2], p2[2];
+	int count;
+};
+
+static int
+free_source_callback(int fd, uint32_t mask, void *data)
+{
+	struct free_source_context *context = data;
+
+	context->count++;
+
+	/* Remove other source */
+	if (fd == context->p1[0]) {
+		wl_event_source_remove(context->source2);
+		context->source2 = NULL;
+	} else if (fd == context->p2[0]) {
+		wl_event_source_remove(context->source1);
+		context->source1 = NULL;
+	} else {
+		assert(0);
+	}
+
+	return 1;
+}
+
+TEST(event_loop_free_source_with_data)
+{
+	struct wl_event_loop *loop = wl_event_loop_create();
+	struct free_source_context context;
+	int data;
+
+	/* This test is a little tricky to get right, since we don't
+	 * have any guarantee from the event loop (ie epoll) on the
+	 * order of which it reports events.  We want to have one
+	 * source free the other, but we don't know which one is going
+	 * to run first.  So we add two fd sources with a callback
+	 * that frees the other source and check that only one of them
+	 * run (and that we don't crash, of course).
+	 */
+
+	assert(loop);
+
+	context.count = 0;
+	assert(pipe(context.p1) == 0);
+	assert(pipe(context.p2) == 0);
+	context.source1 =
+		wl_event_loop_add_fd(loop, context.p1[0], WL_EVENT_READABLE,
+				     free_source_callback, &context);
+	assert(context.source1);
+	context.source2 =
+		wl_event_loop_add_fd(loop, context.p2[0], WL_EVENT_READABLE,
+				     free_source_callback, &context);
+	assert(context.source2);
+
+	data = 5;
+	assert(write(context.p1[1], &data, sizeof data) == sizeof data);
+	assert(write(context.p2[1], &data, sizeof data) == sizeof data);
+
+	wl_event_loop_dispatch(loop, 0);
+
+	assert(context.count == 1);
+
+	if (context.source1)
+		wl_event_source_remove(context.source1);
+	if (context.source2)
+		wl_event_source_remove(context.source2);
+	wl_event_loop_destroy(loop);
+
+	assert(close(context.p1[0]) == 0);
+	assert(close(context.p1[1]) == 0);
+	assert(close(context.p2[0]) == 0);
+	assert(close(context.p2[1]) == 0);
+}
+
+static int
+signal_callback(int signal_number, void *data)
+{
+	int *got_it = data;
+
+	assert(signal_number == SIGUSR1);
+	++(*got_it);
+
+	return 1;
+}
+
+TEST(event_loop_signal)
+{
+	struct wl_event_loop *loop = wl_event_loop_create();
+	struct wl_event_source *source;
+	int got_it = 0;
+
+	source = wl_event_loop_add_signal(loop, SIGUSR1,
+					  signal_callback, &got_it);
+	assert(source);
+
+	assert(wl_event_loop_dispatch(loop, 0) == 0);
+	assert(!got_it);
+	assert(kill(getpid(), SIGUSR1) == 0);
+	/*
+	 * On Linux the signal will be immediately visible in the epoll_wait()
+	 * call. However, on FreeBSD we may need a small delay between kill()
+	 * call and the signal being visible to the kevent() call. This
+	 * sometimes happens when the signal processing and kevent processing
+	 * runs on different CPUs, so becomes more likely when the system is
+	 * under load (e.g. running all tests in parallel).
+	 * See https://github.com/jiixyj/epoll-shim/pull/32
+	 * Passing 1ms as the timeout appears to avoid this race condition in
+	 * all cases tested so far, but to be safe we use 1000ms which should
+	 * be enough time even on a really slow (or emulated) system.
+	 */
+	assert(wl_event_loop_dispatch(loop, 1000) == 0);
+	assert(got_it == 1);
+
+	wl_event_source_remove(source);
+	wl_event_loop_destroy(loop);
+}
+
+TEST(event_loop_multiple_same_signals)
+{
+	struct wl_event_loop *loop = wl_event_loop_create();
+	struct wl_event_source *s1, *s2;
+	int calls_no = 0;
+	int i;
+
+	s1 = wl_event_loop_add_signal(loop, SIGUSR1,
+				      signal_callback, &calls_no);
+	assert(s1);
+
+	s2 = wl_event_loop_add_signal(loop, SIGUSR1,
+				      signal_callback, &calls_no);
+	assert(s2);
+
+	assert(wl_event_loop_dispatch(loop, 0) == 0);
+	assert(!calls_no);
+
+	/* Try it more times */
+	for (i = 0; i < 5; ++i) {
+		calls_no = 0;
+		assert(kill(getpid(), SIGUSR1) == 0);
+		/*
+		 * We need a non-zero timeout here to allow the test to pass
+		 * on non-Linux systems (see comment in event_loop_signal).
+		 */
+		assert(wl_event_loop_dispatch(loop, 1000) == 0);
+		assert(calls_no == 2);
+	}
+
+	wl_event_source_remove(s1);
+
+	/* Try it again  with one source */
+	calls_no = 0;
+	assert(kill(getpid(), SIGUSR1) == 0);
+	/*
+	 * We need a non-zero timeout here to allow the test to pass
+	 * on non-Linux systems (see comment in event_loop_signal).
+	 */
+	assert(wl_event_loop_dispatch(loop, 1000) == 0);
+	assert(calls_no == 1);
+
+	wl_event_source_remove(s2);
+
+	wl_event_loop_destroy(loop);
+}
+
+static int
+timer_callback(void *data)
+{
+	int *got_it = data;
+
+	++(*got_it);
+
+	return 1;
+}
+
+TEST(event_loop_timer)
+{
+	struct wl_event_loop *loop = wl_event_loop_create();
+	struct wl_event_source *source1, *source2;
+	int got_it = 0;
+
+	source1 = wl_event_loop_add_timer(loop, timer_callback, &got_it);
+	assert(source1);
+	wl_event_source_timer_update(source1, 20);
+
+	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);
+}
+
+#define MSEC_TO_USEC(msec) ((msec) * 1000)
+
+struct timer_update_context {
+	struct wl_event_source *source1, *source2;
+	int count;
+};
+
+static int
+timer_update_callback_1(void *data)
+{
+	struct timer_update_context *context = data;
+
+	context->count++;
+	wl_event_source_timer_update(context->source2, 1000);
+	return 1;
+}
+
+static int
+timer_update_callback_2(void *data)
+{
+	struct timer_update_context *context = data;
+
+	context->count++;
+	wl_event_source_timer_update(context->source1, 1000);
+	return 1;
+}
+
+TEST(event_loop_timer_updates)
+{
+	struct wl_event_loop *loop = wl_event_loop_create();
+	struct timer_update_context context;
+	struct timeval start_time, end_time, interval;
+
+	/* Create two timers that should expire at the same time (after 10ms).
+	 * The first timer to receive its expiry callback updates the other timer
+	 * with a much larger timeout (1s). This highlights a bug where
+	 * wl_event_source_timer_dispatch would block for this larger timeout
+	 * when reading from the timer fd, before calling the second timer's
+	 * callback.
+	 */
+
+	context.source1 = wl_event_loop_add_timer(loop, timer_update_callback_1,
+						  &context);
+	assert(context.source1);
+	assert(wl_event_source_timer_update(context.source1, 10) == 0);
+
+	context.source2 = wl_event_loop_add_timer(loop, timer_update_callback_2,
+						  &context);
+	assert(context.source2);
+	assert(wl_event_source_timer_update(context.source2, 10) == 0);
+
+	context.count = 0;
+
+	/* Since calling the functions between source2's update and
+	 * wl_event_loop_dispatch() takes some time, it may happen
+	 * that only one timer expires until we call epoll_wait.
+	 * This naturally means that only one source is dispatched
+	 * and the test fails. To fix that, sleep 15 ms before
+	 * calling wl_event_loop_dispatch(). That should be enough
+	 * for the second timer to expire.
+	 *
+	 * https://bugs.freedesktop.org/show_bug.cgi?id=80594
+	 */
+	usleep(MSEC_TO_USEC(15));
+
+	gettimeofday(&start_time, NULL);
+	wl_event_loop_dispatch(loop, 20);
+	gettimeofday(&end_time, NULL);
+
+	assert(context.count == 2);
+
+	/* Dispatching the events should not have taken much more than 20ms,
+	 * since this is the timeout passed to wl_event_loop_dispatch. If it
+	 * blocked, then it will have taken over 1s.
+	 * Of course, it could take over 1s anyway on a very slow or heavily
+	 * loaded system, so this test isn't 100% perfect.
+	 */
+
+	timersub(&end_time, &start_time, &interval);
+	assert(interval.tv_sec < 1);
+
+	wl_event_source_remove(context.source1);
+	wl_event_source_remove(context.source2);
+	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;
+};
+
+static void
+event_loop_destroy_notify(struct wl_listener *l, void *data)
+{
+	struct event_loop_destroy_listener *listener =
+		wl_container_of(l, listener, listener);
+
+	listener->done = 1;
+}
+
+TEST(event_loop_destroy)
+{
+	struct wl_event_loop *loop;
+	struct wl_display * display;
+	struct event_loop_destroy_listener a, b;
+
+	loop = wl_event_loop_create();
+	assert(loop);
+
+	a.listener.notify = &event_loop_destroy_notify;
+	a.done = 0;
+	wl_event_loop_add_destroy_listener(loop, &a.listener);
+
+	assert(wl_event_loop_get_destroy_listener(loop,
+	       event_loop_destroy_notify) == &a.listener);
+
+	b.listener.notify = &event_loop_destroy_notify;
+	b.done = 0;
+	wl_event_loop_add_destroy_listener(loop, &b.listener);
+
+	wl_list_remove(&a.listener.link);
+	wl_event_loop_destroy(loop);
+
+	assert(!a.done);
+	assert(b.done);
+
+	/* Test to make sure it gets fired on display destruction */
+	display = wl_display_create();
+	assert(display);
+	loop = wl_display_get_event_loop(display);
+	assert(loop);
+
+	a.done = 0;
+	wl_event_loop_add_destroy_listener(loop, &a.listener);
+
+	wl_display_destroy(display);
+
+	assert(a.done);
+}
+
diff --git a/subprojects/wayland/tests/exec-fd-leak-checker.c b/subprojects/wayland/tests/exec-fd-leak-checker.c
new file mode 100644
index 0000000000000000000000000000000000000000..5f3b3958b9f42a5638dc79d33a03afa140979806
--- /dev/null
+++ b/subprojects/wayland/tests/exec-fd-leak-checker.c
@@ -0,0 +1,78 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <limits.h>
+
+#include "test-runner.h"
+
+static int
+parse_count(const char *str, int *value)
+{
+	char *end;
+	long v;
+
+	errno = 0;
+	v = strtol(str, &end, 10);
+	if ((errno == ERANGE && (v == LONG_MAX || v == LONG_MIN)) ||
+	    (errno != 0 && v == 0) ||
+	    (end == str) ||
+	    (*end != '\0')) {
+		return -1;
+	}
+
+	if (v < 0 || v > INT_MAX) {
+		return -1;
+	}
+
+	*value = v;
+	return 0;
+}
+
+int main(int argc, char *argv[])
+{
+	int expected;
+
+	if (argc != 2)
+		goto help_out;
+
+	if (parse_count(argv[1], &expected) < 0)
+		goto help_out;
+
+	if (count_open_fds() == expected)
+		return EXIT_SUCCESS;
+	else
+		return EXIT_FAILURE;
+
+help_out:
+	fprintf(stderr, "Usage: %s N\n"
+		"where N is the expected number of open file descriptors.\n"
+		"This program exits with a failure if the number "
+		"does not match exactly.\n", argv[0]);
+
+	return EXIT_FAILURE;
+}
diff --git a/subprojects/wayland/tests/fixed-test.c b/subprojects/wayland/tests/fixed-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..0b587978ab26eae54fa0aa6dc54b66d897c60cc0
--- /dev/null
+++ b/subprojects/wayland/tests/fixed-test.c
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <assert.h>
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(fixed_double_conversions)
+{
+	wl_fixed_t f;
+	double d;
+
+	d = 62.125;
+	f = wl_fixed_from_double(d);
+	fprintf(stderr, "double %lf to fixed %x\n", d, f);
+	assert(f == 0x3e20);
+
+	d = -1200.625;
+	f = wl_fixed_from_double(d);
+	fprintf(stderr, "double %lf to fixed %x\n", d, f);
+	assert(f == -0x4b0a0);
+
+	f = random();
+	d = wl_fixed_to_double(f);
+	fprintf(stderr, "fixed %x to double %lf\n", f, d);
+	assert(d == f / 256.0);
+
+	f = 0x012030;
+	d = wl_fixed_to_double(f);
+	fprintf(stderr, "fixed %x to double %lf\n", f, d);
+	assert(d == 288.1875);
+
+	f = 0x70000000;
+	d = wl_fixed_to_double(f);
+	fprintf(stderr, "fixed %x to double %lf\n", f, d);
+	assert(d == f / 256);
+
+	f = -0x012030;
+	d = wl_fixed_to_double(f);
+	fprintf(stderr, "fixed %x to double %lf\n", f, d);
+	assert(d == -288.1875);
+
+	f = 0x80000000;
+	d = wl_fixed_to_double(f);
+	fprintf(stderr, "fixed %x to double %lf\n", f, d);
+	assert(d == f / 256);
+}
+
+TEST(fixed_int_conversions)
+{
+	wl_fixed_t f;
+	int i;
+
+	i = 62;
+	f = wl_fixed_from_int(i);
+	assert(f == 62 * 256);
+
+	i = -2080;
+	f = wl_fixed_from_int(i);
+	assert(f == -2080 * 256);
+
+	f = 0x277013;
+	i = wl_fixed_to_int(f);
+	assert(i == 0x2770);
+
+	f = -0x5044;
+	i = wl_fixed_to_int(f);
+	assert(i == -0x50);
+}
diff --git a/subprojects/wayland/tests/headers-protocol-core-test.c b/subprojects/wayland/tests/headers-protocol-core-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..5c2baf36c1d8c69d49aec33405d87a32f4645497
--- /dev/null
+++ b/subprojects/wayland/tests/headers-protocol-core-test.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright © 2015 Giulio Camuffo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wayland-client-protocol-core.h"
+#include "wayland-server-protocol-core.h"
+
+#ifndef WAYLAND_CLIENT_CORE_H
+#error including wayland-client-protocol-core.h did not include wayland-client-core.h!
+#endif
+#ifndef WAYLAND_SERVER_CORE_H
+#error including wayland-server-protocol-core.h did not include wayland-server-core.h!
+#endif
+
+#ifdef WAYLAND_CLIENT_H
+#error including wayland-client-protocol-core.h included wayland-client.h!
+#endif
+#ifdef WAYLAND_SERVER_H
+#error including wayland-server-protocol-core.h included wayland-server.h!
+#endif
diff --git a/subprojects/wayland/tests/headers-protocol-test.c b/subprojects/wayland/tests/headers-protocol-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..87952f7ed335ff24b5e0ee48fcc2f324b9c693df
--- /dev/null
+++ b/subprojects/wayland/tests/headers-protocol-test.c
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2015 Giulio Camuffo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wayland-client-protocol.h"
+#include "wayland-server-protocol.h"
+
+#ifndef WAYLAND_CLIENT_H
+#error including wayland-client-protocol.h did not include wayland-client.h!
+#endif
+#ifndef WAYLAND_SERVER_H
+#error including wayland-server-protocol.h did not include wayland-server.h!
+#endif
diff --git a/subprojects/wayland/tests/headers-test.c b/subprojects/wayland/tests/headers-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..51856f821e7aac216c6f9eb34f64c636d51c3fdd
--- /dev/null
+++ b/subprojects/wayland/tests/headers-test.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright © 2015 Giulio Camuffo
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "wayland-client-core.h"
+#include "wayland-server-core.h"
+
+#ifdef WL_DISPLAY_SYNC
+#error including wayland-client-core.h imported protocol symbols!
+#endif
+#ifdef WL_DISPLAY_ERROR
+#error including wayland-server-core.h imported protocol symbols!
+#endif
+
+#ifdef WAYLAND_CLIENT_H
+#error including wayland-client-core.h included the non-core header!
+#endif
+#ifdef WAYLAND_SERVER_H
+#error including wayland-server-core.h included the non-core header!
+#endif
+
+#include "wayland-client.h"
+#include "wayland-server.h"
+
+#ifndef WL_DISPLAY_SYNC
+#error including wayland-client.h did not import protocol symbols!
+#endif
+#ifndef WL_DISPLAY_ERROR
+#error including wayland-server.h did not import protocol symbols!
+#endif
+
+int main(int argc, char **argv) { return 0; }
diff --git a/subprojects/wayland/tests/interface-test.c b/subprojects/wayland/tests/interface-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..5290bb654ea78bcef3624faffadeef66101abdc3
--- /dev/null
+++ b/subprojects/wayland/tests/interface-test.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright © 2016 Yong Bakos
+ *
+ * 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 "wayland-client.h"
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(interface_equal)
+{
+	const struct wl_interface fake = {
+		"fake", 1, 0, NULL, 0, NULL
+	};
+	const struct wl_interface fake_registry = {
+		"wl_registry", 1, 0, NULL, 0, NULL
+	};
+	const struct wl_interface copy = wl_registry_interface;
+
+	assert(&wl_registry_interface != &copy);
+
+	assert(wl_interface_equal(&wl_registry_interface,
+				  &wl_registry_interface));
+	assert(wl_interface_equal(&wl_registry_interface, &copy));
+	assert(wl_interface_equal(&wl_registry_interface,
+				  &fake_registry));
+	assert(!wl_interface_equal(&wl_registry_interface, &fake));
+}
diff --git a/subprojects/wayland/tests/list-test.c b/subprojects/wayland/tests/list-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..075261817e81c46778557da2c15e7c2cb333e4fa
--- /dev/null
+++ b/subprojects/wayland/tests/list-test.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <assert.h>
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(list_init)
+{
+	struct wl_list list;
+
+	wl_list_init(&list);
+	assert(list.next == &list);
+	assert(list.prev == &list);
+	assert(wl_list_empty(&list));
+}
+
+struct element {
+	int i;
+	struct wl_list link;
+};
+
+TEST(list_insert)
+{
+	struct wl_list list;
+	struct element e;
+
+	wl_list_init(&list);
+	wl_list_insert(&list, &e.link);
+	assert(list.next == &e.link);
+	assert(list.prev == &e.link);
+	assert(e.link.next == &list);
+	assert(e.link.prev == &list);
+}
+
+TEST(list_length)
+{
+	struct wl_list list;
+	struct element e;
+
+	wl_list_init(&list);
+	assert(wl_list_length(&list) == 0);
+	wl_list_insert(&list, &e.link);
+	assert(wl_list_length(&list) == 1);
+	wl_list_remove(&e.link);
+	assert(wl_list_length(&list) == 0);
+}
+
+TEST(list_iterator)
+{
+	struct wl_list list;
+	struct element e1, e2, e3, e4, *e;
+	int reference[] = { 708090, 102030, 5588, 12 };
+	unsigned int i;
+
+	e1.i = 708090;
+	e2.i = 102030;
+	e3.i = 5588;
+	e4.i = 12;
+
+	wl_list_init(&list);
+	wl_list_insert(list.prev, &e1.link);
+	wl_list_insert(list.prev, &e2.link);
+	wl_list_insert(list.prev, &e3.link);
+	wl_list_insert(list.prev, &e4.link);
+
+	i = 0;
+	wl_list_for_each(e, &list, link) {
+		assert(i < ARRAY_LENGTH(reference));
+		assert(e->i == reference[i]);
+		i++;
+	}
+	assert(i == ARRAY_LENGTH(reference));
+
+	i = 0;
+	wl_list_for_each_reverse(e, &list, link) {
+		assert(i < ARRAY_LENGTH(reference));
+		assert(e->i == reference[ARRAY_LENGTH(reference) - i - 1]);
+		i++;
+	}
+	assert(i == ARRAY_LENGTH(reference));
+}
+
+static int
+validate_list(struct wl_list *list, int *reference, int length)
+{
+	struct element *e;
+	int i;
+
+	i = 0;
+	wl_list_for_each(e, list, link) {
+		if (i >= length)
+			return 0;
+		if (e->i != reference[i])
+			return 0;
+		i++;
+	}
+
+	if (i != length)
+		return 0;
+
+	return 1;
+}
+
+TEST(list_remove)
+{
+	struct wl_list list;
+	struct element e1, e2, e3;
+	int reference1[] = { 17, 8888, 1000 }, reference2[] = { 17, 1000 };
+
+	e1.i = 17;
+	e2.i = 8888;
+	e3.i = 1000;
+
+	wl_list_init(&list);
+	wl_list_insert(&list, &e1.link);
+	wl_list_insert(list.prev, &e2.link);
+	wl_list_insert(list.prev, &e3.link);
+	assert(validate_list(&list, reference1, ARRAY_LENGTH(reference1)));
+
+	wl_list_remove(&e2.link);
+	assert(validate_list(&list, reference2, ARRAY_LENGTH(reference2)));
+}
+
+TEST(list_insert_list)
+{
+	struct wl_list list, other;
+	struct element e1, e2, e3, e4, e5, e6;
+	int reference1[] = { 17, 8888, 1000 };
+	int reference2[] = { 76543, 1, -500 };
+	int reference3[] = { 17, 76543, 1, -500, 8888, 1000 };
+
+	e1.i = 17;
+	e2.i = 8888;
+	e3.i = 1000;
+
+	wl_list_init(&list);
+	wl_list_insert(&list, &e1.link);
+	wl_list_insert(list.prev, &e2.link);
+	wl_list_insert(list.prev, &e3.link);
+	assert(validate_list(&list, reference1, ARRAY_LENGTH(reference1)));
+
+	e4.i = 76543;
+	e5.i = 1;
+	e6.i = -500;
+
+	wl_list_init(&other);
+	wl_list_insert(&other, &e4.link);
+	wl_list_insert(other.prev, &e5.link);
+	wl_list_insert(other.prev, &e6.link);
+	assert(validate_list(&other, reference2, ARRAY_LENGTH(reference2)));
+
+	wl_list_insert_list(list.next, &other);
+	assert(validate_list(&list, reference3, ARRAY_LENGTH(reference3)));
+}
diff --git a/subprojects/wayland/tests/map-test.c b/subprojects/wayland/tests/map-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..03568ea7acbb76fb8ffb6d4a836c2475171356d8
--- /dev/null
+++ b/subprojects/wayland/tests/map-test.c
@@ -0,0 +1,137 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include "wayland-private.h"
+#include "test-runner.h"
+
+TEST(map_insert_new)
+{
+	struct wl_map map;
+	uint32_t i, j, k, a, b, c;
+
+	wl_map_init(&map, WL_MAP_SERVER_SIDE);
+	i = wl_map_insert_new(&map, 0, &a);
+	j = wl_map_insert_new(&map, 0, &b);
+	k = wl_map_insert_new(&map, 0, &c);
+	assert(i == WL_SERVER_ID_START);
+	assert(j == WL_SERVER_ID_START + 1);
+	assert(k == WL_SERVER_ID_START + 2);
+
+	assert(wl_map_lookup(&map, i) == &a);
+	assert(wl_map_lookup(&map, j) == &b);
+	assert(wl_map_lookup(&map, k) == &c);
+    wl_map_release(&map);
+
+	wl_map_init(&map, WL_MAP_CLIENT_SIDE);
+	i = wl_map_insert_new(&map, 0, &a);
+	assert(i == 0);
+	assert(wl_map_lookup(&map, i) == &a);
+
+	wl_map_release(&map);
+}
+
+TEST(map_insert_at)
+{
+	struct wl_map map;
+	uint32_t a, b, c;
+
+	wl_map_init(&map, WL_MAP_CLIENT_SIDE);
+	assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START, &a) == 0);
+	assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START + 3, &b) == -1);
+	assert(wl_map_insert_at(&map, 0, WL_SERVER_ID_START + 1, &c) == 0);
+
+	assert(wl_map_lookup(&map, WL_SERVER_ID_START) == &a);
+	assert(wl_map_lookup(&map, WL_SERVER_ID_START + 1) == &c);
+
+	wl_map_release(&map);
+}
+
+TEST(map_remove)
+{
+	struct wl_map map;
+	uint32_t i, j, k, l, a, b, c, d;
+
+	wl_map_init(&map, WL_MAP_SERVER_SIDE);
+	i = wl_map_insert_new(&map, 0, &a);
+	j = wl_map_insert_new(&map, 0, &b);
+	k = wl_map_insert_new(&map, 0, &c);
+	assert(i == WL_SERVER_ID_START);
+	assert(j == WL_SERVER_ID_START + 1);
+	assert(k == WL_SERVER_ID_START + 2);
+
+	assert(wl_map_lookup(&map, i) == &a);
+	assert(wl_map_lookup(&map, j) == &b);
+	assert(wl_map_lookup(&map, k) == &c);
+
+	wl_map_remove(&map, j);
+	assert(wl_map_lookup(&map, j) == NULL);
+
+	/* Verify that we insert d at the hole left by removing b */
+	l = wl_map_insert_new(&map, 0, &d);
+	assert(l == WL_SERVER_ID_START + 1);
+	assert(wl_map_lookup(&map, l) == &d);
+
+	wl_map_release(&map);
+}
+
+TEST(map_flags)
+{
+	struct wl_map map;
+	uint32_t i, j, a, b;
+
+	wl_map_init(&map, WL_MAP_SERVER_SIDE);
+	i = wl_map_insert_new(&map, 0, &a);
+	j = wl_map_insert_new(&map, 1, &b);
+	assert(i == WL_SERVER_ID_START);
+	assert(j == WL_SERVER_ID_START + 1);
+
+	assert(wl_map_lookup(&map, i) == &a);
+	assert(wl_map_lookup(&map, j) == &b);
+
+    assert(wl_map_lookup_flags(&map, i) == 0);
+    assert(wl_map_lookup_flags(&map, j) == 1);
+
+	wl_map_release(&map);
+}
+
+static enum wl_iterator_result never_run(void *element, void *data, uint32_t flags)
+{
+	assert(0);
+}
+
+TEST(map_iter_empty)
+{
+	struct wl_map map;
+
+	wl_map_init(&map, WL_MAP_SERVER_SIDE);
+
+	wl_map_for_each(&map, never_run, NULL);
+
+	wl_map_release(&map);
+}
diff --git a/subprojects/wayland/tests/meson.build b/subprojects/wayland/tests/meson.build
new file mode 100644
index 0000000000000000000000000000000000000000..2c22b82afe916cf5e542b491879c41a987480c13
--- /dev/null
+++ b/subprojects/wayland/tests/meson.build
@@ -0,0 +1,176 @@
+if not get_option('libraries')
+	error('-Dtests=true requires -Dlibraries=true')
+endif
+
+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'),
+		epoll_dep,
+		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'
+)
+
+executable(
+	'exec-fd-leak-checker',
+	'exec-fd-leak-checker.c',
+	dependencies: test_runner_dep
+)
+
+if add_languages('cpp', native: false)
+	test(
+		'cpp-compile-test',
+		executable(
+			'cpp-compile-test',
+			'cpp-compile-test.cpp',
+			wayland_server_protocol_h,
+			include_directories: src_inc
+		)
+	)
+endif
+
+sed_path = find_program('sed').full_path()
+
+if get_option('scanner')
+	scanner_test_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()),
+	]
+
+	test(
+		'scanner-test',
+		find_program('scanner-test.sh'),
+		env: scanner_test_env,
+	)
+
+	run_target(
+		'gen-scanner-test',
+		command: find_program('scanner-test-gen.sh'),
+		env: scanner_test_env,
+	)
+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': [],
+	'proxy-test': [
+		wayland_client_protocol_h,
+		wayland_server_protocol_h,
+	],
+	'enum-validator-test': [],
+}
+
+foreach test_name, test_extra_sources: tests
+	test_sources = [ test_name + '.c' ] + test_extra_sources
+	test_deps = [test_runner_dep, epoll_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/subprojects/wayland/tests/message-test.c b/subprojects/wayland/tests/message-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..86f387abcf8ac5f5abd86982c4f8d0c1a170f5c6
--- /dev/null
+++ b/subprojects/wayland/tests/message-test.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2014 Jonas Ådahl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <assert.h>
+
+#include "wayland-client.h"
+#include "wayland-private.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+TEST(message_version)
+{
+	unsigned int i;
+	const struct {
+		const struct wl_message *message;
+		int expected_version;
+	} messages[] = {
+		{ &wl_pointer_interface.events[WL_POINTER_ENTER], 1 },
+		{ &wl_surface_interface.events[WL_SURFACE_ENTER], 1 },
+		{ &wl_pointer_interface.methods[WL_POINTER_SET_CURSOR], 1 },
+		{ &wl_pointer_interface.methods[WL_POINTER_RELEASE], 3 },
+		{ &wl_surface_interface.methods[WL_SURFACE_DESTROY], 1 },
+		{ &wl_surface_interface.methods[WL_SURFACE_SET_BUFFER_TRANSFORM], 2 },
+		{ &wl_surface_interface.methods[WL_SURFACE_SET_BUFFER_SCALE], 3 },
+	};
+
+	for (i = 0; i < ARRAY_LENGTH(messages); ++i) {
+		assert(wl_message_get_since(messages[i].message) ==
+		       messages[i].expected_version);
+	}
+}
+
+TEST(message_count_arrays)
+{
+	unsigned int i;
+	struct wl_message fake_messages[] = {
+		{ "empty", "", NULL },
+		{ "non_present", "iufsonh", NULL },
+		{ "leading", "aiufsonh", NULL},
+		{ "trailing", "iufsonha", NULL },
+		{ "middle", "iufasonh", NULL },
+		{ "multiple", "aaiufaasonhaa", NULL },
+		{ "leading_version", "2aaiufaasonhaa", NULL },
+		{ "among_nullables", "iufsa?oa?sah", NULL },
+		{ "all_mixed", "2aiufas?oa?sa", NULL },
+	};
+	const struct {
+		const struct wl_message *message;
+		int expected_array_count;
+	} messages[] = {
+		{ &wl_pointer_interface.events[WL_POINTER_ENTER], 0 },
+		{ &wl_keyboard_interface.events[WL_KEYBOARD_ENTER], 1 },
+		{ &fake_messages[0], 0 },
+		{ &fake_messages[1], 0 },
+		{ &fake_messages[2], 1 },
+		{ &fake_messages[3], 1 },
+		{ &fake_messages[4], 1 },
+		{ &fake_messages[5], 6 },
+		{ &fake_messages[6], 6 },
+		{ &fake_messages[7], 3 },
+		{ &fake_messages[8], 4 },
+	};
+
+	for (i = 0; i < ARRAY_LENGTH(messages); ++i) {
+		assert(wl_message_count_arrays(messages[i].message) ==
+		       messages[i].expected_array_count);
+	}
+}
diff --git a/subprojects/wayland/tests/newsignal-test.c b/subprojects/wayland/tests/newsignal-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..051e10e8b70d213a27272c10b4f1f88bca332e7d
--- /dev/null
+++ b/subprojects/wayland/tests/newsignal-test.c
@@ -0,0 +1,337 @@
+/*
+ * Copyright © 2013 Marek Chalupa
+ *
+ * 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 "test-runner.h"
+#include "wayland-server-private.h"
+
+static void
+signal_notify(struct wl_listener *listener, void *data)
+{
+	/* only increase counter*/
+	++(*((int *) data));
+}
+
+TEST(signal_init)
+{
+	struct wl_priv_signal signal;
+
+	wl_priv_signal_init(&signal);
+
+	/* Test if listeners' list is initialized */
+	assert(&signal.listener_list == signal.listener_list.next
+		&& "Maybe wl_priv_signal implementation changed?");
+	assert(signal.listener_list.next == signal.listener_list.prev
+		&& "Maybe wl_priv_signal implementation changed?");
+}
+
+TEST(signal_add_get)
+{
+	struct wl_priv_signal signal;
+
+	/* we just need different values of notify */
+	struct wl_listener l1 = {.notify = (wl_notify_func_t) 0x1};
+	struct wl_listener l2 = {.notify = (wl_notify_func_t) 0x2};
+	struct wl_listener l3 = {.notify = (wl_notify_func_t) 0x3};
+	/* one real, why not */
+	struct wl_listener l4 = {.notify = signal_notify};
+
+	wl_priv_signal_init(&signal);
+
+	wl_priv_signal_add(&signal, &l1);
+	wl_priv_signal_add(&signal, &l2);
+	wl_priv_signal_add(&signal, &l3);
+	wl_priv_signal_add(&signal, &l4);
+
+	assert(wl_priv_signal_get(&signal, signal_notify) == &l4);
+	assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3);
+	assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2);
+	assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1);
+
+	/* get should not be destructive */
+	assert(wl_priv_signal_get(&signal, signal_notify) == &l4);
+	assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3);
+	assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2);
+	assert(wl_priv_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1);
+}
+
+TEST(signal_emit_to_one_listener)
+{
+	int count = 0;
+	int counter;
+
+	struct wl_priv_signal signal;
+	struct wl_listener l1 = {.notify = signal_notify};
+
+	wl_priv_signal_init(&signal);
+	wl_priv_signal_add(&signal, &l1);
+
+	for (counter = 0; counter < 100; counter++)
+		wl_priv_signal_emit(&signal, &count);
+
+	assert(counter == count);
+}
+
+TEST(signal_emit_to_more_listeners)
+{
+	int count = 0;
+	int counter;
+
+	struct wl_priv_signal signal;
+	struct wl_listener l1 = {.notify = signal_notify};
+	struct wl_listener l2 = {.notify = signal_notify};
+	struct wl_listener l3 = {.notify = signal_notify};
+
+	wl_priv_signal_init(&signal);
+	wl_priv_signal_add(&signal, &l1);
+	wl_priv_signal_add(&signal, &l2);
+	wl_priv_signal_add(&signal, &l3);
+
+	for (counter = 0; counter < 100; counter++)
+		wl_priv_signal_emit(&signal, &count);
+
+	assert(3 * counter == count);
+}
+
+struct signal
+{
+	struct wl_priv_signal signal;
+	struct wl_listener l1, l2, l3;
+	int count;
+	struct wl_listener *current;
+};
+
+static void notify_remove(struct wl_listener *l, void *data)
+{
+	struct signal *sig = data;
+	wl_list_remove(&sig->current->link);
+	wl_list_init(&sig->current->link);
+	sig->count++;
+}
+
+#define INIT \
+	wl_priv_signal_init(&signal.signal); \
+	wl_list_init(&signal.l1.link); \
+	wl_list_init(&signal.l2.link); \
+	wl_list_init(&signal.l3.link);
+#define CHECK_EMIT(expected) \
+	signal.count = 0; \
+	wl_priv_signal_emit(&signal.signal, &signal); \
+	assert(signal.count == expected);
+
+TEST(signal_remove_listener)
+{
+	test_set_timeout(4);
+
+	struct signal signal;
+
+	signal.l1.notify = notify_remove;
+	signal.l2.notify = notify_remove;
+	signal.l3.notify = notify_remove;
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+
+	signal.current = &signal.l1;
+	CHECK_EMIT(1)
+	CHECK_EMIT(0)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+
+	CHECK_EMIT(2)
+	CHECK_EMIT(1)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+
+	signal.current = &signal.l2;
+	CHECK_EMIT(1)
+	CHECK_EMIT(1)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+	wl_priv_signal_add(&signal.signal, &signal.l3);
+
+	signal.current = &signal.l1;
+	CHECK_EMIT(3)
+	CHECK_EMIT(2)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+	wl_priv_signal_add(&signal.signal, &signal.l3);
+
+	signal.current = &signal.l2;
+	CHECK_EMIT(2)
+	CHECK_EMIT(2)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+	wl_priv_signal_add(&signal.signal, &signal.l3);
+
+	signal.current = &signal.l3;
+	CHECK_EMIT(2)
+	CHECK_EMIT(2)
+}
+
+static void notify_readd(struct wl_listener *l, void *data)
+{
+	struct signal *signal = data;
+	if (signal->current) {
+		wl_list_remove(&signal->current->link);
+		wl_list_init(&signal->current->link);
+		wl_priv_signal_add(&signal->signal, signal->current);
+	}
+	signal->count++;
+}
+
+static void notify_empty(struct wl_listener *l, void *data)
+{
+	struct signal *signal = data;
+	signal->count++;
+}
+
+TEST(signal_readd_listener)
+{
+	/* Readding a listener is supported, that is it doesn't trigger an
+	 * infinite loop or other weird things, but if in a listener you
+	 * re-add another listener, that will not be fired in the current
+	 * signal emission. */
+
+	test_set_timeout(4);
+
+	struct signal signal;
+
+	signal.l1.notify = notify_readd;
+	signal.l2.notify = notify_readd;
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+
+	signal.current = &signal.l1;
+	CHECK_EMIT(1)
+	CHECK_EMIT(1)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+
+	signal.current = &signal.l2;
+	CHECK_EMIT(1)
+	signal.current = NULL;
+	CHECK_EMIT(2)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+
+	signal.current = &signal.l1;
+	CHECK_EMIT(1)
+	/* l2 was added before l1, so l2 is fired first, which by readding l1
+	 * removes it from the current list that is being fired, so 1 is correct */
+	CHECK_EMIT(1)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+
+	signal.l1.notify = notify_empty;
+	signal.current = &signal.l2;
+	CHECK_EMIT(2)
+	CHECK_EMIT(2)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+
+	signal.l1.notify = notify_empty;
+	signal.current = &signal.l1;
+	CHECK_EMIT(2)
+	/* same as before, by readding l1 in the first emit, it now is fired
+	 * after l2, so on the second emit it is not fired at all. */
+	CHECK_EMIT(1)
+}
+
+static void notify_addandget(struct wl_listener *l, void *data)
+{
+	struct signal *signal = data;
+	wl_list_remove(&signal->current->link);
+	wl_list_init(&signal->current->link);
+	wl_priv_signal_add(&signal->signal, signal->current);
+
+	assert(wl_priv_signal_get(&signal->signal, signal->current->notify) != NULL);
+
+	signal->count++;
+}
+
+static void notify_get(struct wl_listener *l, void *data)
+{
+	struct signal *signal = data;
+	assert(wl_priv_signal_get(&signal->signal, signal->current->notify) == signal->current);
+	signal->count++;
+}
+
+TEST(signal_get_listener)
+{
+	test_set_timeout(4);
+
+	struct signal signal;
+
+	signal.l1.notify = notify_addandget;
+	signal.l2.notify = notify_get;
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+
+	signal.current = &signal.l2;
+	CHECK_EMIT(1)
+
+	INIT
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+
+	signal.current = &signal.l2;
+	CHECK_EMIT(1)
+
+	INIT
+	signal.l1.notify = notify_get;
+	signal.l2.notify = notify_empty;
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+
+	CHECK_EMIT(2)
+
+	INIT
+	signal.l1.notify = notify_empty;
+	signal.l2.notify = notify_get;
+	wl_priv_signal_add(&signal.signal, &signal.l1);
+	wl_priv_signal_add(&signal.signal, &signal.l2);
+
+	signal.current = &signal.l1;
+	CHECK_EMIT(2)
+}
diff --git a/subprojects/wayland/tests/os-wrappers-test.c b/subprojects/wayland/tests/os-wrappers-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..061d29e6acb2272ed8d0efab1a73f05a5adc6f34
--- /dev/null
+++ b/subprojects/wayland/tests/os-wrappers-test.c
@@ -0,0 +1,391 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "../config.h"
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <sys/epoll.h>
+
+#include "wayland-private.h"
+#include "test-runner.h"
+#include "wayland-os.h"
+
+extern int (*wl_socket)(int domain, int type, int protocol);
+extern int (*wl_fcntl)(int fildes, int cmd, ...);
+extern ssize_t (*wl_recvmsg)(int socket, struct msghdr *message, int flags);
+extern int (*wl_epoll_create1)(int flags);
+
+static int fall_back;
+
+static int wrapped_calls_socket = 0;
+static int wrapped_calls_fcntl = 0;
+static int wrapped_calls_recvmsg = 0;
+static int wrapped_calls_epoll_create1 = 0;
+
+static int
+socket_wrapper(int domain, int type, int protocol)
+{
+	wrapped_calls_socket++;
+
+	if (fall_back && (type & SOCK_CLOEXEC)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	return socket(domain, type, protocol);
+}
+
+static int
+fcntl_wrapper(int fd, int cmd, ...)
+{
+	va_list ap;
+	int arg;
+	int has_arg;
+
+	wrapped_calls_fcntl++;
+
+	if (fall_back && (cmd == F_DUPFD_CLOEXEC)) {
+		errno = EINVAL;
+		return -1;
+	}
+	switch (cmd) {
+	case F_DUPFD_CLOEXEC:
+	case F_DUPFD:
+	case F_SETFD:
+		va_start(ap, cmd);
+		arg = va_arg(ap, int);
+		has_arg = 1;
+		va_end(ap);
+		break;
+	case F_GETFD:
+		has_arg = 0;
+		break;
+	default:
+		fprintf(stderr, "Unexpected fctnl cmd %d\n", cmd);
+		abort();
+	}
+
+	if (has_arg) {
+		return fcntl(fd, cmd, arg);
+	}
+	return fcntl(fd, cmd);
+}
+
+static ssize_t
+recvmsg_wrapper(int sockfd, struct msghdr *msg, int flags)
+{
+	wrapped_calls_recvmsg++;
+
+	if (fall_back && (flags & MSG_CMSG_CLOEXEC)) {
+		errno = EINVAL;
+		return -1;
+	}
+
+	return recvmsg(sockfd, msg, flags);
+}
+
+static int
+epoll_create1_wrapper(int flags)
+{
+	wrapped_calls_epoll_create1++;
+
+	if (fall_back) {
+		wrapped_calls_epoll_create1++; /* epoll_create() not wrapped */
+		errno = EINVAL;
+		return -1;
+	}
+
+	return epoll_create1(flags);
+}
+
+static void
+init_fallbacks(int do_fallbacks)
+{
+	fall_back = do_fallbacks;
+	wl_fcntl = fcntl_wrapper;
+	wl_socket = socket_wrapper;
+	wl_recvmsg = recvmsg_wrapper;
+	wl_epoll_create1 = epoll_create1_wrapper;
+}
+
+static void
+do_os_wrappers_socket_cloexec(int n)
+{
+	int fd;
+	int nr_fds;
+
+	nr_fds = count_open_fds();
+
+	/* simply create a socket that closes on exec */
+	fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
+	assert(fd >= 0);
+
+	/*
+	 * Must have 2 calls if falling back, but must also allow
+	 * falling back without a forced fallback.
+	 */
+	assert(wrapped_calls_socket > n);
+
+	exec_fd_leak_check(nr_fds);
+}
+
+TEST(os_wrappers_socket_cloexec)
+{
+	/* normal case */
+	init_fallbacks(0);
+	do_os_wrappers_socket_cloexec(0);
+}
+
+TEST(os_wrappers_socket_cloexec_fallback)
+{
+	/* forced fallback */
+	init_fallbacks(1);
+	do_os_wrappers_socket_cloexec(1);
+}
+
+static void
+do_os_wrappers_dupfd_cloexec(int n)
+{
+	int base_fd;
+	int fd;
+	int nr_fds;
+
+	nr_fds = count_open_fds();
+
+	base_fd = socket(PF_LOCAL, SOCK_STREAM, 0);
+	assert(base_fd >= 0);
+
+	fd = wl_os_dupfd_cloexec(base_fd, 13);
+	assert(fd >= 13);
+
+	close(base_fd);
+
+	/*
+	 * Must have 4 calls if falling back, but must also allow
+	 * falling back without a forced fallback.
+	 */
+	assert(wrapped_calls_fcntl > n);
+
+	exec_fd_leak_check(nr_fds);
+}
+
+TEST(os_wrappers_dupfd_cloexec)
+{
+	init_fallbacks(0);
+	do_os_wrappers_dupfd_cloexec(0);
+}
+
+TEST(os_wrappers_dupfd_cloexec_fallback)
+{
+	init_fallbacks(1);
+	do_os_wrappers_dupfd_cloexec(3);
+}
+
+struct marshal_data {
+	struct wl_connection *read_connection;
+	struct wl_connection *write_connection;
+	int s[2];
+	uint32_t read_mask;
+	uint32_t write_mask;
+	union {
+		int h[3];
+	} value;
+	int nr_fds_begin;
+	int nr_fds_conn;
+	int wrapped_calls;
+};
+
+static void
+setup_marshal_data(struct marshal_data *data)
+{
+	assert(socketpair(AF_UNIX,
+			  SOCK_STREAM | SOCK_CLOEXEC, 0, data->s) == 0);
+
+	data->read_connection = wl_connection_create(data->s[0],
+						     WL_BUFFER_DEFAULT_MAX_SIZE);
+	assert(data->read_connection);
+
+	data->write_connection = wl_connection_create(data->s[1],
+						      WL_BUFFER_DEFAULT_MAX_SIZE);
+	assert(data->write_connection);
+}
+
+static void
+marshal_demarshal(struct marshal_data *data,
+		  void (*func)(void), int size, const char *format, ...)
+{
+	struct wl_closure *closure;
+	static const int opcode = 4444;
+	static struct wl_object sender = { NULL, NULL, 1234 };
+	struct wl_message message = { "test", format, NULL };
+	struct wl_map objects;
+	struct wl_object object = { NULL, &func, 1234 };
+	va_list ap;
+	uint32_t msg[1] = { 1234 };
+
+	va_start(ap, format);
+	closure = wl_closure_vmarshal(&sender, opcode, ap, &message);
+	va_end(ap);
+
+	assert(closure);
+	assert(wl_closure_send(closure, data->write_connection) == 0);
+	wl_closure_destroy(closure);
+	assert(wl_connection_flush(data->write_connection) == size);
+
+	assert(wl_connection_read(data->read_connection) == size);
+
+	wl_map_init(&objects, WL_MAP_SERVER_SIDE);
+	object.id = msg[0];
+	closure = wl_connection_demarshal(data->read_connection,
+					  size, &objects, &message);
+	assert(closure);
+	wl_closure_invoke(closure, WL_CLOSURE_INVOKE_SERVER, &object, 0, data);
+	wl_closure_destroy(closure);
+}
+
+static void
+validate_recvmsg_h(struct marshal_data *data,
+		   struct wl_object *object, int fd1, int fd2, int fd3)
+{
+	struct stat buf1, buf2;
+
+	assert(fd1 >= 0);
+	assert(fd2 >= 0);
+	assert(fd3 >= 0);
+
+	assert(fd1 != data->value.h[0]);
+	assert(fd2 != data->value.h[1]);
+	assert(fd3 != data->value.h[2]);
+
+	assert(fstat(fd3, &buf1) == 0);
+	assert(fstat(data->value.h[2], &buf2) == 0);
+	assert(buf1.st_dev == buf2.st_dev);
+	assert(buf1.st_ino == buf2.st_ino);
+
+	/* close the original file descriptors */
+	close(data->value.h[0]);
+	close(data->value.h[1]);
+	close(data->value.h[2]);
+
+	/* the dup'd (received) fds should still be open */
+	assert(count_open_fds() == data->nr_fds_conn + 3);
+
+	/*
+	 * Must have 2 calls if falling back, but must also allow
+	 * falling back without a forced fallback.
+	 */
+	assert(wrapped_calls_recvmsg > data->wrapped_calls);
+
+	if (data->wrapped_calls == 0 && wrapped_calls_recvmsg > 1)
+		printf("recvmsg fell back unforced.\n");
+
+	/* all fds opened during the test in any way should be gone on exec */
+	exec_fd_leak_check(data->nr_fds_begin);
+}
+
+static void
+do_os_wrappers_recvmsg_cloexec(int n)
+{
+	struct marshal_data data;
+
+	data.nr_fds_begin = count_open_fds();
+#if HAVE_BROKEN_MSG_CMSG_CLOEXEC
+	/* We call the fallback directly on FreeBSD versions with a broken
+	 * MSG_CMSG_CLOEXEC, so we don't call the local recvmsg() wrapper. */
+	data.wrapped_calls = 0;
+#else
+	data.wrapped_calls = n;
+#endif
+
+	setup_marshal_data(&data);
+	data.nr_fds_conn = count_open_fds();
+
+	assert(pipe(data.value.h) >= 0);
+
+	data.value.h[2] = open("/dev/zero", O_RDONLY);
+	assert(data.value.h[2] >= 0);
+
+	marshal_demarshal(&data, (void *) validate_recvmsg_h,
+			  8, "hhh", data.value.h[0], data.value.h[1],
+			  data.value.h[2]);
+}
+
+TEST(os_wrappers_recvmsg_cloexec)
+{
+	init_fallbacks(0);
+	do_os_wrappers_recvmsg_cloexec(0);
+}
+
+TEST(os_wrappers_recvmsg_cloexec_fallback)
+{
+	init_fallbacks(1);
+	do_os_wrappers_recvmsg_cloexec(1);
+}
+
+static void
+do_os_wrappers_epoll_create_cloexec(int n)
+{
+	int fd;
+	int nr_fds;
+
+	nr_fds = count_open_fds();
+
+	fd = wl_os_epoll_create_cloexec();
+	assert(fd >= 0);
+
+#ifdef EPOLL_CLOEXEC
+	assert(wrapped_calls_epoll_create1 == n);
+#else
+	printf("No epoll_create1.\n");
+#endif
+
+	exec_fd_leak_check(nr_fds);
+}
+
+TEST(os_wrappers_epoll_create_cloexec)
+{
+	init_fallbacks(0);
+	do_os_wrappers_epoll_create_cloexec(1);
+}
+
+TEST(os_wrappers_epoll_create_cloexec_fallback)
+{
+	init_fallbacks(1);
+	do_os_wrappers_epoll_create_cloexec(2);
+}
+
+/* FIXME: add tests for wl_os_accept_cloexec() */
diff --git a/subprojects/wayland/tests/protocol-logger-test.c b/subprojects/wayland/tests/protocol-logger-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..a0ebd22a76d87005be42a98d0fb7e45f89edce01
--- /dev/null
+++ b/subprojects/wayland/tests/protocol-logger-test.c
@@ -0,0 +1,148 @@
+/*
+ * Copyright © 2016 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "wayland-client.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+/* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */
+static const char *
+require_xdg_runtime_dir(void)
+{
+	char *val = getenv("XDG_RUNTIME_DIR");
+	assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test");
+
+	return val;
+}
+
+struct compositor {
+	struct wl_display *display;
+	struct wl_event_loop *loop;
+	int message;
+	struct wl_client *client;
+};
+
+struct message {
+	enum wl_protocol_logger_type type;
+	const char *class;
+	int opcode;
+	const char *message_name;
+	int args_count;
+} messages[] = {
+	{
+		.type = WL_PROTOCOL_LOGGER_REQUEST,
+		.class = "wl_display",
+		.opcode = 0,
+		.message_name = "sync",
+		.args_count = 1,
+	},
+	{
+		.type = WL_PROTOCOL_LOGGER_EVENT,
+		.class = "wl_callback",
+		.opcode = 0,
+		.message_name = "done",
+		.args_count = 1,
+	},
+	{
+		.type = WL_PROTOCOL_LOGGER_EVENT,
+		.class = "wl_display",
+		.opcode = 1,
+		.message_name = "delete_id",
+		.args_count = 1,
+	},
+};
+
+static void
+logger_func(void *user_data, enum wl_protocol_logger_type type,
+	    const struct wl_protocol_logger_message *message)
+{
+	struct compositor *c = user_data;
+	struct message *msg = &messages[c->message++];
+
+	assert(msg->type == type);
+	assert(strcmp(msg->class, wl_resource_get_class(message->resource)) == 0);
+	assert(msg->opcode == message->message_opcode);
+	assert(strcmp(msg->message_name, message->message->name) == 0);
+	assert(msg->args_count == message->arguments_count);
+
+	c->client = wl_resource_get_client(message->resource);
+}
+
+static void
+callback_done(void *data, struct wl_callback *cb, uint32_t time)
+{
+	wl_callback_destroy(cb);
+}
+
+static const struct wl_callback_listener callback_listener = {
+	callback_done,
+};
+
+TEST(logger)
+{
+	test_set_timeout(1);
+
+	const char *socket;
+	struct compositor compositor = { 0 };
+	struct {
+		struct wl_display *display;
+		struct wl_callback *cb;
+	} client;
+	struct wl_protocol_logger *logger;
+
+	require_xdg_runtime_dir();
+
+	compositor.display = wl_display_create();
+	compositor.loop = wl_display_get_event_loop(compositor.display);
+	socket = wl_display_add_socket_auto(compositor.display);
+
+	logger = wl_display_add_protocol_logger(compositor.display,
+						logger_func, &compositor);
+
+	client.display = wl_display_connect(socket);
+	client.cb = wl_display_sync(client.display);
+	wl_callback_add_listener(client.cb, &callback_listener, NULL);
+	wl_display_flush(client.display);
+
+	while (compositor.message < 3) {
+		wl_event_loop_dispatch(compositor.loop, -1);
+		wl_display_flush_clients(compositor.display);
+	}
+
+	wl_display_dispatch(client.display);
+	wl_display_disconnect(client.display);
+
+	wl_client_destroy(compositor.client);
+	wl_protocol_logger_destroy(logger);
+	wl_display_destroy(compositor.display);
+}
diff --git a/subprojects/wayland/tests/proxy-test.c b/subprojects/wayland/tests/proxy-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..2a8f4254a75a54e5f4180c02f8b36c0728efba38
--- /dev/null
+++ b/subprojects/wayland/tests/proxy-test.c
@@ -0,0 +1,139 @@
+/*
+ * 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);
+
+	assert(wl_proxy_get_display((struct wl_proxy *) client.callback_b) == client.display);
+
+	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/subprojects/wayland/tests/queue-test.c b/subprojects/wayland/tests/queue-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..cb61a85b2252426926ea7fba7a15b7f0646628f0
--- /dev/null
+++ b/subprojects/wayland/tests/queue-test.c
@@ -0,0 +1,711 @@
+/*
+ * Copyright © 2012 Jonas Ådahl
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define _GNU_SOURCE /* For memrchr */
+#include <stdlib.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <signal.h>
+
+#include "wayland-client.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+#include "test-compositor.h"
+
+#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
+
+static void
+registry_handle_global(void *data, struct wl_registry *registry,
+		       uint32_t id, const char *interface, uint32_t version)
+{
+	int *pcounter = data;
+	(*pcounter)++;
+	assert(*pcounter == 1);
+	wl_registry_destroy(registry);
+}
+
+static const struct wl_registry_listener registry_listener = {
+	registry_handle_global,
+	NULL
+};
+
+/* Test that destroying a proxy object doesn't result in any more
+ * callback being invoked, even though were many queued. */
+static void
+client_test_proxy_destroy(void)
+{
+	struct wl_display *display;
+	struct wl_registry *registry;
+	int counter = 0;
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	registry = wl_display_get_registry(display);
+	assert(registry != NULL);
+	wl_registry_add_listener(registry, &registry_listener,
+				 &counter);
+	assert(wl_display_roundtrip(display) != -1);
+
+	assert(counter == 1);
+
+	/* don't destroy the registry, we have already destroyed them
+	 * in the global handler */
+	wl_display_disconnect(display);
+}
+
+struct multiple_queues_state {
+	struct wl_display *display;
+	struct wl_callback* callback2;
+	bool done;
+};
+
+static void
+sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
+{
+	struct multiple_queues_state *state = data;
+
+	state->done = true;
+	wl_callback_destroy(callback);
+
+	wl_display_dispatch_pending(state->display);
+
+	wl_callback_destroy(state->callback2);
+}
+
+static const struct wl_callback_listener sync_listener = {
+	sync_callback
+};
+
+/* Test that when receiving the first of two synchronization
+ * callback events, destroying the second one doesn't cause any
+ * errors even if the delete_id event is handled out of order. */
+static void
+client_test_multiple_queues(void)
+{
+	struct wl_event_queue *queue;
+	struct wl_callback *callback1;
+	struct multiple_queues_state state;
+	int ret = 0;
+
+	state.display = wl_display_connect(NULL);
+	assert(state.display);
+
+	queue = wl_display_create_queue(state.display);
+	assert(queue);
+
+	state.done = false;
+	callback1 = wl_display_sync(state.display);
+	assert(callback1 != NULL);
+	wl_callback_add_listener(callback1, &sync_listener, &state);
+	wl_proxy_set_queue((struct wl_proxy *) callback1, queue);
+
+	state.callback2 = wl_display_sync(state.display);
+	assert(state.callback2 != NULL);
+	wl_callback_add_listener(state.callback2, &sync_listener, NULL);
+	wl_proxy_set_queue((struct wl_proxy *) state.callback2, queue);
+
+	wl_display_flush(state.display);
+
+	while (!state.done && !ret)
+		ret = wl_display_dispatch_queue(state.display, queue);
+
+	wl_event_queue_destroy(queue);
+	wl_display_disconnect(state.display);
+
+	exit(ret == -1 ? -1 : 0);
+}
+
+static void
+sync_callback_roundtrip(void *data, struct wl_callback *callback, uint32_t serial)
+{
+	bool *done = data;
+	*done = true;
+}
+
+static const struct wl_callback_listener sync_listener_roundtrip = {
+	sync_callback_roundtrip
+};
+
+/* Test that doing a roundtrip on a queue only the events on that
+ * queue get dispatched. */
+static void
+client_test_queue_roundtrip(void)
+{
+	struct wl_event_queue *queue;
+	struct wl_callback *callback1;
+	struct wl_callback *callback2;
+	struct wl_display *display;
+	bool done1 = false;
+	bool done2 = false;
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	queue = wl_display_create_queue(display);
+	assert(queue);
+
+	/* arm a callback on the default queue */
+	callback1 = wl_display_sync(display);
+	assert(callback1 != NULL);
+	wl_callback_add_listener(callback1, &sync_listener_roundtrip, &done1);
+
+	/* arm a callback on the other queue */
+	callback2 = wl_display_sync(display);
+	assert(callback2 != NULL);
+	wl_callback_add_listener(callback2, &sync_listener_roundtrip, &done2);
+	wl_proxy_set_queue((struct wl_proxy *) callback2, queue);
+
+	/* roundtrip on default queue must not dispatch the other queue. */
+	wl_display_roundtrip(display);
+	assert(done1 == true);
+	assert(done2 == false);
+
+	/* re-arm the sync callback on the default queue, so we see that
+	 * wl_display_roundtrip_queue() does not dispatch the default queue. */
+	wl_callback_destroy(callback1);
+	done1 = false;
+	callback1 = wl_display_sync(display);
+	assert(callback1 != NULL);
+	wl_callback_add_listener(callback1, &sync_listener_roundtrip, &done1);
+
+	wl_display_roundtrip_queue(display, queue);
+	assert(done1 == false);
+	assert(done2 == true);
+
+	wl_callback_destroy(callback1);
+	wl_callback_destroy(callback2);
+	wl_event_queue_destroy(queue);
+
+	wl_display_disconnect(display);
+}
+
+static void
+client_test_queue_proxy_wrapper(void)
+{
+	struct wl_event_queue *queue;
+	struct wl_display *display;
+	struct wl_display *display_wrapper;
+	struct wl_callback *callback;
+	bool done = false;
+
+	/*
+	 * For an illustration of what usage would normally fail without using
+	 * proxy wrappers, see the `client_test_queue_set_queue_race' test case.
+	 */
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	/* Pretend we are in a separate thread where a thread-local queue is
+	 * used. */
+	queue = wl_display_create_queue(display);
+	assert(queue);
+
+	display_wrapper = wl_proxy_create_wrapper(display);
+	assert(display_wrapper);
+	wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
+	callback = wl_display_sync(display_wrapper);
+	wl_proxy_wrapper_destroy(display_wrapper);
+	assert(callback != NULL);
+
+	/* Pretend we are now another thread and dispatch the dispatch the main
+	 * queue while also knowing our callback is read and queued. */
+	wl_display_roundtrip(display);
+
+	/* Make sure that the pretend-to-be main thread didn't dispatch our
+	 * callback, behind our back. */
+	wl_callback_add_listener(callback, &sync_listener_roundtrip, &done);
+	wl_display_flush(display);
+
+	assert(!done);
+
+	/* Make sure that we eventually end up dispatching our callback. */
+	while (!done)
+		assert(wl_display_dispatch_queue(display, queue) != -1);
+
+	wl_callback_destroy(callback);
+	wl_event_queue_destroy(queue);
+
+	wl_display_disconnect(display);
+}
+
+static void
+client_test_queue_set_queue_race(void)
+{
+	struct wl_event_queue *queue;
+	struct wl_display *display;
+	struct wl_callback *callback;
+	bool done = false;
+
+	/*
+	 * This test illustrates the multi threading scenario which would fail
+	 * without doing what is done in the `client_test_queue_proxy_wrapper'
+	 * test.
+	 */
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	/* Pretend we are in a separate thread where a thread-local queue is
+	 * used. */
+	queue = wl_display_create_queue(display);
+	assert(queue);
+
+	callback = wl_display_sync(display);
+	assert(callback != NULL);
+
+	/* Pretend we are now another thread and dispatch the dispatch the main
+	 * queue while also knowing our callback is read, queued on the wrong
+	 * queue, and dispatched. */
+	wl_display_roundtrip(display);
+
+	/* Pretend we are back in the separate thread, and continue with setting
+	 * up our callback. */
+	wl_callback_add_listener(callback, &sync_listener_roundtrip, &done);
+	wl_proxy_set_queue((struct wl_proxy *) callback, queue);
+
+	/* Roundtrip our separate thread queue to make sure any events are
+	 * dispatched. */
+	wl_display_roundtrip_queue(display, queue);
+
+	/* Verify that the callback has indeed been dropped. */
+	assert(!done);
+
+	wl_callback_destroy(callback);
+	wl_event_queue_destroy(queue);
+
+	wl_display_disconnect(display);
+}
+
+static char *
+maybe_map_file(int fd, size_t *len)
+{
+	char *data;
+
+	*len = lseek(fd, 0, SEEK_END);
+	data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0);
+
+	return data;
+}
+
+static char *
+map_file(int fd, size_t *len)
+{
+	char *data;
+
+	data = maybe_map_file(fd, len);
+	assert(data != MAP_FAILED && "Failed to mmap file");
+
+	return data;
+}
+
+static char *
+last_line_of(char *s)
+{
+	size_t len = strlen(s);
+	char *last;
+
+	last = memrchr(s, '\n', len);
+	/* If we found a newline at end of string, find the previous one. */
+	if (last && last[1] == 0)
+		last = memrchr(s, '\n', len - 1);
+	/* If we have a newline, the last line starts after the newline.
+	 * Otherwise, the whole string is the last line. */
+	if (last)
+		last += 1;
+	else
+		last = s;
+
+	return last;
+}
+
+static void
+client_test_queue_destroy_with_attached_proxies(void)
+{
+	struct wl_event_queue *queue;
+	struct wl_display *display;
+	struct wl_display *display_wrapper;
+	struct wl_callback *callback;
+	char *log;
+	size_t log_len;
+	char callback_name[24];
+	int ret;
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	/* Pretend we are in a separate thread where a thread-local queue is
+	 * used. */
+	queue = wl_display_create_queue(display);
+	assert(queue);
+
+	/* Create a sync dispatching events on the thread-local queue. */
+	display_wrapper = wl_proxy_create_wrapper(display);
+	assert(display_wrapper);
+	wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
+	callback = wl_display_sync(display_wrapper);
+	wl_proxy_wrapper_destroy(display_wrapper);
+	assert(callback != NULL);
+
+	/* Destroy the queue before the attached object. */
+	wl_event_queue_destroy(queue);
+
+	/* Check that the log contains some information about the attached
+	 * wl_callback proxy. */
+	log = map_file(client_log_fd, &log_len);
+	ret = snprintf(callback_name, sizeof(callback_name), "wl_callback#%u",
+		       wl_proxy_get_id((struct wl_proxy *) callback));
+	assert(ret > 0 && ret < (int)sizeof(callback_name) &&
+	       "callback name creation failed (possibly truncated)");
+	assert(strstr(last_line_of(log), callback_name));
+	munmap(log, log_len);
+
+	wl_callback_destroy(callback);
+
+	wl_display_disconnect(display);
+}
+
+static void
+client_test_queue_proxy_event_to_destroyed_queue(void)
+{
+	struct wl_event_queue *queue;
+	struct wl_display *display;
+	struct wl_display *display_wrapper;
+	struct wl_callback *callback;
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	/* Pretend we are in a separate thread where a thread-local queue is
+	 * used. */
+	queue = wl_display_create_queue(display);
+	assert(queue);
+
+	/* Create a sync dispatching events on the thread-local queue. */
+	display_wrapper = wl_proxy_create_wrapper(display);
+	assert(display_wrapper);
+	wl_proxy_set_queue((struct wl_proxy *) display_wrapper, queue);
+	callback = wl_display_sync(display_wrapper);
+	wl_proxy_wrapper_destroy(display_wrapper);
+	assert(callback != NULL);
+	wl_display_flush(display);
+
+	/* Destroy the queue before the attached object. */
+	wl_event_queue_destroy(queue);
+
+	/* During this roundtrip we should receive the done event on 'callback',
+	 * try to queue it to the destroyed queue, and abort. */
+	wl_display_roundtrip(display);
+
+	wl_callback_destroy(callback);
+
+	wl_display_disconnect(display);
+}
+
+static void
+client_test_queue_destroy_default_with_attached_proxies(void)
+{
+	struct wl_display *display;
+	struct wl_callback *callback;
+	char *log;
+	size_t log_len;
+	char callback_name[24];
+	int ret;
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	/* Create a sync dispatching events on the default queue. */
+	callback = wl_display_sync(display);
+	assert(callback != NULL);
+
+	/* Destroy the default queue (by disconnecting) before the attached
+	 * object. */
+	wl_display_disconnect(display);
+
+	/* Check that the log does not contain any warning about the attached
+	 * wl_callback proxy. */
+	log = maybe_map_file(client_log_fd, &log_len);
+	ret = snprintf(callback_name, sizeof(callback_name), "wl_callback#%u",
+		       wl_proxy_get_id((struct wl_proxy *) callback));
+	assert(ret > 0 && ret < (int)sizeof(callback_name) &&
+	       "callback name creation failed (possibly truncated)");
+	assert(log == MAP_FAILED || strstr(log, callback_name) == NULL);
+	if (log != MAP_FAILED)
+		munmap(log, log_len);
+
+	/* HACK: Directly free the memory of the wl_callback proxy to appease
+	 * ASan. We would normally use wl_callback_destroy(), but since we have
+	 * destroyed the associated wl_display, using this function would lead
+	 * to memory errors. */
+	free(callback);
+}
+
+static void
+check_queue_name(struct wl_proxy *proxy, const char *name)
+{
+	struct wl_event_queue *queue;
+	const char *queue_name;
+
+	queue = wl_proxy_get_queue(proxy);
+	queue_name = wl_event_queue_get_name(queue);
+	if (!name)
+		assert(!queue_name);
+	else
+		assert(strcmp(queue_name, name) == 0);
+}
+
+static struct wl_callback *
+roundtrip_named_queue_nonblock(struct wl_display *display,
+			       struct wl_event_queue *queue,
+			       const char *name)
+{
+	struct wl_callback *callback;
+	struct wl_display *wrapped_display = NULL;
+
+	if (queue) {
+		wrapped_display = wl_proxy_create_wrapper(display);
+		assert(wrapped_display);
+		wl_proxy_set_queue((struct wl_proxy *) wrapped_display, queue);
+		check_queue_name((struct wl_proxy *) wrapped_display, name);
+
+		callback = wl_display_sync(wrapped_display);
+	} else
+		callback = wl_display_sync(display);
+
+	check_queue_name((struct wl_proxy *) callback, name);
+
+	if (wrapped_display)
+		wl_proxy_wrapper_destroy(wrapped_display);
+
+	assert(callback != NULL);
+
+	return callback;
+}
+
+static void
+client_test_queue_names(void)
+{
+	struct wl_event_queue *queue1, *queue2, *queue3;
+	struct wl_display *display;
+	struct wl_callback *callback1, *callback2, *callback3, *callback4;
+	struct wl_event_queue *default_queue;
+	char *log;
+	size_t log_len;
+	const char *default_queue_name;
+
+	display = wl_display_connect(NULL);
+	assert(display);
+
+	default_queue = wl_proxy_get_queue((struct wl_proxy *) display);
+	default_queue_name = wl_event_queue_get_name(default_queue);
+	assert(strcmp(default_queue_name, "Default Queue") == 0);
+
+	/* Create some event queues both with and without names. */
+	queue1 = wl_display_create_queue_with_name(display, "First");
+	assert(queue1);
+
+	queue2 = wl_display_create_queue_with_name(display, "Second");
+	assert(queue2);
+
+	queue3 = wl_display_create_queue(display);
+	assert(queue3);
+
+	/* Create some requests and ensure their queues have the expected
+	 * names.
+	 */
+	callback1 = roundtrip_named_queue_nonblock(display, queue1, "First");
+	callback2 = roundtrip_named_queue_nonblock(display, queue2, "Second");
+	callback3 = roundtrip_named_queue_nonblock(display, queue3, NULL);
+	callback4 = roundtrip_named_queue_nonblock(display, NULL, "Default Queue");
+
+	/* Destroy one queue with proxies still attached so we can verify
+         * that the queue name is in the log message. */
+	wl_event_queue_destroy(queue2);
+	log = map_file(client_log_fd, &log_len);
+	assert(strstr(log, "Second"));
+
+	/* There's no reason for the First queue name to be present. */
+	assert(!strstr(log, "First"));
+
+	munmap(log, log_len);
+
+	wl_callback_destroy(callback1);
+	wl_callback_destroy(callback2);
+	wl_callback_destroy(callback3);
+	wl_callback_destroy(callback4);
+
+	wl_event_queue_destroy(queue1);
+	wl_event_queue_destroy(queue3);
+
+	wl_display_disconnect(display);
+}
+
+static void
+dummy_bind(struct wl_client *client,
+	   void *data, uint32_t version, uint32_t id)
+{
+}
+
+TEST(queue_proxy_destroy)
+{
+	struct display *d;
+	const struct wl_interface *dummy_interfaces[] = {
+		&wl_seat_interface,
+		&wl_pointer_interface,
+		&wl_keyboard_interface,
+		&wl_surface_interface
+	};
+	unsigned int i;
+
+	d = display_create();
+
+	for (i = 0; i < ARRAY_LENGTH(dummy_interfaces); i++)
+		wl_global_create(d->wl_display, dummy_interfaces[i],
+				 dummy_interfaces[i]->version,
+				 NULL, dummy_bind);
+
+	test_set_timeout(2);
+
+	client_create_noarg(d, client_test_proxy_destroy);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+TEST(queue_multiple_queues)
+{
+	struct display *d = display_create();
+
+	test_set_timeout(2);
+
+	client_create_noarg(d, client_test_multiple_queues);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+TEST(queue_roundtrip)
+{
+	struct display *d = display_create();
+
+	test_set_timeout(2);
+
+	client_create_noarg(d, client_test_queue_roundtrip);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+TEST(queue_set_queue_proxy_wrapper)
+{
+	struct display *d = display_create();
+
+	test_set_timeout(2);
+
+	client_create_noarg(d, client_test_queue_proxy_wrapper);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+TEST(queue_set_queue_race)
+{
+	struct display *d = display_create();
+
+	test_set_timeout(2);
+
+	client_create_noarg(d, client_test_queue_set_queue_race);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+TEST(queue_destroy_with_attached_proxies)
+{
+	struct display *d = display_create();
+
+	test_set_timeout(2);
+
+	client_create_noarg(d, client_test_queue_destroy_with_attached_proxies);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+TEST(queue_proxy_event_to_destroyed_queue)
+{
+	struct display *d = display_create();
+	struct client_info *ci;
+	char *client_log;
+	size_t client_log_len;
+
+	test_set_timeout(2);
+
+	ci = client_create_noarg(d, client_test_queue_proxy_event_to_destroyed_queue);
+	display_run(d);
+
+	/* Check that the final line in the log mentions the expected reason
+	 * for the abort. */
+	client_log = map_file(ci->log_fd, &client_log_len);
+	assert(!strcmp(last_line_of(client_log),
+		       "Tried to add event to destroyed queue\n"));
+	munmap(client_log, client_log_len);
+
+	/* Check that the client aborted. */
+	display_destroy_expect_signal(d, SIGABRT);
+}
+
+TEST(queue_destroy_default_with_attached_proxies)
+{
+	struct display *d = display_create();
+
+	test_set_timeout(2);
+
+	client_create_noarg(d, client_test_queue_destroy_default_with_attached_proxies);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+TEST(queue_names)
+{
+	struct display *d = display_create();
+
+	test_set_timeout(2);
+
+	client_create_noarg(d, client_test_queue_names);
+	display_run(d);
+
+	display_destroy(d);
+}
diff --git a/subprojects/wayland/tests/resources-test.c b/subprojects/wayland/tests/resources-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..92707297b695faa151af610c2504800b2066ada5
--- /dev/null
+++ b/subprojects/wayland/tests/resources-test.c
@@ -0,0 +1,265 @@
+/*
+ * Copyright © 2013 Marek Chalupa
+ *
+ * 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 <sys/socket.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "wayland-server.h"
+#include "test-runner.h"
+
+TEST(create_resource_tst)
+{
+	struct wl_display *display;
+	struct wl_client *client;
+	struct wl_resource *res;
+	struct wl_list *link;
+	int s[2];
+	uint32_t id;
+
+	assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+	display = wl_display_create();
+	assert(display);
+	client = wl_client_create(display, s[0]);
+	assert(client);
+
+	res = wl_resource_create(client, &wl_seat_interface, 4, 0);
+	assert(res);
+
+	/* setters/getters */
+	assert(wl_resource_get_version(res) == 4);
+
+	assert(client == wl_resource_get_client(res));
+	id = wl_resource_get_id(res);
+	assert(wl_client_get_object(client, id) == res);
+
+	link = wl_resource_get_link(res);
+	assert(link);
+	assert(wl_resource_from_link(link) == res);
+
+	wl_resource_set_user_data(res, (void *) 0xbee);
+	assert(wl_resource_get_user_data(res) == (void *) 0xbee);
+
+	wl_resource_destroy(res);
+	wl_client_destroy(client);
+	wl_display_destroy(display);
+	close(s[1]);
+}
+
+static void
+res_destroy_func(struct wl_resource *res)
+{
+	assert(res);
+
+	_Bool *destr = wl_resource_get_user_data(res);
+	*destr = 1;
+}
+
+static _Bool notify_called = 0;
+static void
+destroy_notify(struct wl_listener *l, void *data)
+{
+	assert(l && data);
+	notify_called = 1;
+
+	/* In real code it's common to free the structure holding the
+	 * listener at this point, but not to remove it from the list.
+	 *
+	 * That's fine since this is a destruction notification and
+	 * it's the last time this signal can fire.  We set these
+	 * to NULL so we can check them later to ensure no write after
+	 * "free" occurred.
+	 */
+	l->link.prev = NULL;
+	l->link.next = NULL;
+}
+
+TEST(destroy_res_tst)
+{
+	struct wl_display *display;
+	struct wl_client *client;
+	struct wl_resource *res;
+	int s[2];
+	unsigned id;
+	struct wl_list *link;
+
+	_Bool destroyed = 0;
+	struct wl_listener destroy_listener = {
+		.notify = &destroy_notify
+	};
+
+	assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+	display = wl_display_create();
+	assert(display);
+	client = wl_client_create(display, s[0]);
+	assert(client);
+
+	res = wl_resource_create(client, &wl_seat_interface, 4, 0);
+	assert(res);
+	wl_resource_set_implementation(res, NULL, &destroyed, res_destroy_func);
+	wl_resource_add_destroy_listener(res, &destroy_listener);
+
+	id = wl_resource_get_id(res);
+	link = wl_resource_get_link(res);
+	assert(link);
+
+	wl_resource_destroy(res);
+	assert(destroyed);
+	assert(notify_called); /* check if signal was emitted */
+	assert(wl_client_get_object(client, id) == NULL);
+	assert(destroy_listener.link.prev == NULL);
+	assert(destroy_listener.link.next == NULL);
+
+	res = wl_resource_create(client, &wl_seat_interface, 2, 0);
+	assert(res);
+	destroyed = 0;
+	notify_called = 0;
+	wl_resource_set_destructor(res, res_destroy_func);
+	wl_resource_set_user_data(res, &destroyed);
+	wl_resource_add_destroy_listener(res, &destroy_listener);
+	/* client should destroy the resource upon its destruction */
+	wl_client_destroy(client);
+	assert(destroyed);
+	assert(notify_called);
+	assert(destroy_listener.link.prev == NULL);
+	assert(destroy_listener.link.next == NULL);
+
+	wl_display_destroy(display);
+	close(s[1]);
+}
+
+TEST(create_resource_with_same_id)
+{
+	struct wl_display *display;
+	struct wl_client *client;
+	struct wl_resource *res, *res2;
+	int s[2];
+	uint32_t id;
+
+	assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+	display = wl_display_create();
+	assert(display);
+	client = wl_client_create(display, s[0]);
+	assert(client);
+
+	res = wl_resource_create(client, &wl_seat_interface, 2, 0);
+	assert(res);
+	id = wl_resource_get_id(res);
+	assert(wl_client_get_object(client, id) == res);
+
+	/* this one should replace the old one */
+	res2 = wl_resource_create(client, &wl_seat_interface, 1, id);
+	assert(res2 != NULL);
+	assert(wl_client_get_object(client, id) == res2);
+
+	wl_resource_destroy(res2);
+	wl_resource_destroy(res);
+
+	wl_client_destroy(client);
+	wl_display_destroy(display);
+	close(s[1]);
+}
+
+static void
+display_destroy_notify(struct wl_listener *l, void *data)
+{
+	l->link.prev = l->link.next = NULL;
+}
+
+TEST(free_without_remove)
+{
+	struct wl_display *display;
+	struct wl_listener a, b;
+
+	display = wl_display_create();
+	a.notify = display_destroy_notify;
+	b.notify = display_destroy_notify;
+
+	wl_display_add_destroy_listener(display, &a);
+	wl_display_add_destroy_listener(display, &b);
+
+	wl_display_destroy(display);
+
+	assert(a.link.next == a.link.prev && a.link.next == NULL);
+	assert(b.link.next == b.link.prev && b.link.next == NULL);
+}
+
+static enum wl_iterator_result
+client_resource_check(struct wl_resource* resource, void* data)
+{
+	/* Ensure there is no iteration over already freed resources. */
+	assert(!wl_resource_get_user_data(resource));
+	return WL_ITERATOR_CONTINUE;
+}
+
+static void
+resource_destroy_notify(struct wl_listener *l, void *data)
+{
+	struct wl_resource* resource = data;
+	struct wl_client* client = resource->client;
+
+	wl_client_for_each_resource(client, client_resource_check, NULL);
+
+	/* Set user data to flag the resource has been deleted. The resource should
+	 * not be accessible from this point forward. */
+	wl_resource_set_user_data(resource, client);
+}
+
+TEST(resource_destroy_iteration)
+{
+	struct wl_display *display;
+	struct wl_client *client;
+	struct wl_resource *resource1;
+	struct wl_resource *resource2;
+	int s[2];
+
+	struct wl_listener destroy_listener1 = {
+		.notify = &resource_destroy_notify
+	};
+	struct wl_listener destroy_listener2 = {
+		.notify = &resource_destroy_notify
+	};
+
+	assert(socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, s) == 0);
+	display = wl_display_create();
+	assert(display);
+	client = wl_client_create(display, s[0]);
+	assert(client);
+	resource1 = wl_resource_create(client, &wl_callback_interface, 1, 0);
+	resource2 = wl_resource_create(client, &wl_callback_interface, 1, 0);
+	assert(resource1);
+	assert(resource2);
+
+	wl_resource_add_destroy_listener(resource1, &destroy_listener1);
+	wl_resource_add_destroy_listener(resource2, &destroy_listener2);
+
+	wl_client_destroy(client);
+
+	close(s[0]);
+	close(s[1]);
+
+	wl_display_destroy(display);
+}
diff --git a/subprojects/wayland/tests/sanity-test.c b/subprojects/wayland/tests/sanity-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..e614cfb3f6cfc52662d21e8b014f5c162f072609
--- /dev/null
+++ b/subprojects/wayland/tests/sanity-test.c
@@ -0,0 +1,311 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <signal.h>
+#include <unistd.h>
+
+#include "test-runner.h"
+#include "wayland-util.h"
+#include "wayland-private.h"
+
+#include "test-compositor.h"
+
+extern int fd_leak_check_enabled;
+
+TEST(empty)
+{
+}
+
+TEST(exit_success)
+{
+	exit(EXIT_SUCCESS);
+}
+
+FAIL_TEST(exit_failure)
+{
+	exit(EXIT_FAILURE);
+}
+
+FAIL_TEST(fail_abort)
+{
+	test_disable_coredumps();
+	abort();
+}
+
+FAIL_TEST(fail_wl_abort)
+{
+	test_disable_coredumps();
+	wl_abort("Abort the program\n");
+}
+
+FAIL_TEST(fail_kill)
+{
+	kill(getpid(), SIGTERM);
+}
+
+FAIL_TEST(fail_segv)
+{
+	char * volatile *null = 0;
+
+	test_disable_coredumps();
+	*null = "Goodbye, world";
+}
+
+FAIL_TEST(sanity_assert)
+{
+	test_disable_coredumps();
+	/* must fail */
+	assert(0);
+}
+
+FAIL_TEST(sanity_fd_leak)
+{
+	int fd[2];
+
+	assert(fd_leak_check_enabled);
+
+	/* leak 2 file descriptors */
+	if (pipe(fd) < 0)
+		exit(EXIT_SUCCESS); /* failed to fail */
+
+	test_disable_coredumps();
+}
+
+FAIL_TEST(sanity_fd_leak_exec)
+{
+	int fd[2];
+	int nr_fds = count_open_fds();
+
+	/* leak 2 file descriptors */
+	if (pipe(fd) < 0)
+		exit(EXIT_SUCCESS); /* failed to fail */
+
+	test_disable_coredumps();
+	exec_fd_leak_check(nr_fds);
+}
+
+TEST(sanity_fd_exec)
+{
+	int fd[2];
+	int nr_fds = count_open_fds();
+
+	/* create 2 file descriptors, that should pass over exec */
+	assert(pipe(fd) >= 0);
+
+	exec_fd_leak_check(nr_fds + 2);
+}
+
+static void
+sanity_fd_no_leak(void)
+{
+	int fd[2];
+
+	assert(fd_leak_check_enabled);
+
+	/* leak 2 file descriptors */
+	if (pipe(fd) < 0)
+		exit(EXIT_SUCCESS); /* failed to fail */
+
+	close(fd[0]);
+	close(fd[1]);
+}
+
+static void
+sanity_client_no_leak(void)
+{
+	struct wl_display *display = wl_display_connect(NULL);
+	assert(display);
+
+	wl_display_disconnect(display);
+}
+
+TEST(tc_client_no_fd_leaks)
+{
+	struct display *d = display_create();
+
+	/* Client which does not consume the WAYLAND_DISPLAY socket. */
+	client_create_noarg(d, sanity_fd_no_leak);
+	display_run(d);
+
+	/* Client which does consume the WAYLAND_DISPLAY socket. */
+	client_create_noarg(d, sanity_client_no_leak);
+	display_run(d);
+
+	display_destroy(d);
+}
+
+FAIL_TEST(tc_client_fd_leaks)
+{
+	struct display *d = display_create();
+
+	client_create_noarg(d, sanity_fd_leak);
+	display_run(d);
+
+	test_disable_coredumps();
+	display_destroy(d);
+}
+
+FAIL_TEST(tc_client_fd_leaks_exec)
+{
+	struct display *d = display_create();
+
+	client_create_noarg(d, sanity_fd_leak_exec);
+	display_run(d);
+
+	test_disable_coredumps();
+	display_destroy(d);
+}
+
+static char *
+map_file(int fd, size_t *len)
+{
+	char *data;
+
+	*len = lseek(fd, 0, SEEK_END);
+	data = mmap(0, *len, PROT_READ, MAP_PRIVATE, fd, 0);
+	assert(data != MAP_FAILED && "Failed to mmap file");
+
+	return data;
+}
+
+static void
+sanity_client_log(void)
+{
+	char *log;
+	size_t log_len;
+	char *wayland_socket = strdup(getenv("WAYLAND_SOCKET"));
+	char *xdg_runtime_dir = strdup(getenv("XDG_RUNTIME_DIR"));
+
+	unsetenv("WAYLAND_SOCKET");
+	unsetenv("XDG_RUNTIME_DIR");
+
+	/* Try to connect to the default wayland display, which should fail since
+	 * we have neither WAYLAND_SOCKET nor XDG_RUNTIME_DIR. */
+	assert(!wl_display_connect(NULL));
+
+	/* Check that the client log contains some mention of XDG_RUNTIME_DIR. */
+	log = map_file(client_log_fd, &log_len);
+	assert(strstr(log, "XDG_RUNTIME_DIR"));
+	munmap(log, log_len);
+
+	/* Reset the environment variables we unset for the test. The test harness
+	 * leak checker cares about the value of WAYLAND_SOCKET during teardown for
+	 * correct fd accounting. */
+	setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 0);
+	setenv("WAYLAND_SOCKET", wayland_socket, 0);
+	free(xdg_runtime_dir);
+	free(wayland_socket);
+}
+
+TEST(tc_client_log)
+{
+	struct display *d = display_create();
+	struct client_info *ci;
+	char *log;
+	size_t log_len;
+
+	ci = client_create_noarg(d, sanity_client_log);
+	display_run(d);
+
+	/* Check that the client log contains some mention of XDG_RUNTIME_DIR. */
+	log = map_file(ci->log_fd, &log_len);
+	assert(strstr(log, "XDG_RUNTIME_DIR"));
+	munmap(log, log_len);
+
+	display_destroy(d);
+}
+
+FAIL_TEST(timeout_tst)
+{
+	test_set_timeout(1);
+	test_disable_coredumps();
+	/* test should reach timeout */
+	test_sleep(2);
+}
+
+TEST(timeout2_tst)
+{
+	/* the test should end before reaching timeout,
+	 * thus it should pass */
+	test_set_timeout(1);
+	/* 200 000 microsec = 0.2 sec */
+	test_usleep(200000);
+}
+
+FAIL_TEST(timeout_reset_tst)
+{
+	test_set_timeout(5);
+	test_set_timeout(10);
+	test_set_timeout(1);
+
+	test_disable_coredumps();
+	/* test should fail on timeout */
+	test_sleep(2);
+}
+
+TEST(timeout_turnoff)
+{
+	test_set_timeout(1);
+	test_set_timeout(0);
+
+	test_usleep(2);
+}
+
+/* test timeouts with test-compositor */
+FAIL_TEST(tc_timeout_tst)
+{
+	struct display *d = display_create();
+	client_create_noarg(d, timeout_tst);
+	display_run(d);
+	test_disable_coredumps();
+	display_destroy(d);
+}
+
+FAIL_TEST(tc_timeout2_tst)
+{
+	struct display *d = display_create();
+	client_create_noarg(d, timeout_reset_tst);
+	display_run(d);
+	test_disable_coredumps();
+	display_destroy(d);
+}
+
+TEST(tc_timeout3_tst)
+{
+	struct display *d = display_create();
+
+	client_create_noarg(d, timeout2_tst);
+	display_run(d);
+
+	client_create_noarg(d, timeout_turnoff);
+	display_run(d);
+
+	display_destroy(d);
+}
diff --git a/subprojects/wayland/tests/scanner-test-gen.sh b/subprojects/wayland/tests/scanner-test-gen.sh
new file mode 100755
index 0000000000000000000000000000000000000000..b9c9294ded67c2b3d2229230d5659ff1efe95723
--- /dev/null
+++ b/subprojects/wayland/tests/scanner-test-gen.sh
@@ -0,0 +1,26 @@
+#!/bin/sh -eu
+
+generate() {
+	"$WAYLAND_SCANNER" $1 < "$TEST_DATA_DIR/$2" > "$TEST_DATA_DIR/$3"
+	"$SED" -i -e 's/Generated by wayland-scanner [0-9.]*/SCANNER TEST/' \
+		"$TEST_DATA_DIR/$3"
+}
+
+generate "code" "example.xml" "example-code.c"
+generate "client-header" "example.xml" "example-client.h"
+generate "server-header" "example.xml" "example-server.h"
+generate "enum-header" "example.xml" "example-enum.h"
+
+generate "code" "small.xml" "small-code.c"
+generate "client-header" "small.xml" "small-client.h"
+generate "server-header" "small.xml" "small-server.h"
+
+generate "-c code" "small.xml" "small-code-core.c"
+generate "-c client-header" "small.xml" "small-client-core.h"
+generate "-c server-header" "small.xml" "small-server-core.h"
+
+generate "private-code" "small.xml" "small-private-code.c"
+
+generate "code" "empty.xml" "empty-code.c"
+generate "client-header" "empty.xml" "empty-client.h"
+generate "server-header" "empty.xml" "empty-server.h"
diff --git a/subprojects/wayland/tests/scanner-test.sh b/subprojects/wayland/tests/scanner-test.sh
new file mode 100755
index 0000000000000000000000000000000000000000..d4cd19ba5b0f58ba90f7bffe1a268fffa097c500
--- /dev/null
+++ b/subprojects/wayland/tests/scanner-test.sh
@@ -0,0 +1,83 @@
+#!/bin/sh
+
+echo "srcdir: $srcdir"
+echo "scanner: $WAYLAND_SCANNER"
+echo "test_data_dir: $TEST_DATA_DIR"
+echo "test_output_dir: $TEST_OUTPUT_DIR"
+echo "pwd: $PWD"
+echo "sed: $SED"
+
+RETCODE=0
+
+hard_fail() {
+	echo "$@" "ERROR"
+	exit 99
+}
+
+fail() {
+	echo "$@" "FAIL"
+	RETCODE=1
+}
+
+mkdir -p "$TEST_OUTPUT_DIR" || hard_fail "setup"
+
+generate_and_compare() {
+	echo
+	echo "Testing $1 generation: $2 -> $3"
+
+	"$WAYLAND_SCANNER" $1 < "$TEST_DATA_DIR/$2" > "$TEST_OUTPUT_DIR/$3" || \
+		hard_fail "$2 -> $3"
+
+	"$SED" -i -e 's/Generated by wayland-scanner [0-9.]*/SCANNER TEST/' \
+		"$TEST_OUTPUT_DIR/$3" || hard_fail "$2 -> $3"
+
+	diff -q "$TEST_DATA_DIR/$3" "$TEST_OUTPUT_DIR/$3" && \
+		echo "$2 -> $3 PASS" || \
+		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"
+generate_and_compare "enum-header" "example.xml" "example-enum.h"
+
+generate_and_compare "code" "small.xml" "small-code.c"
+generate_and_compare "client-header" "small.xml" "small-client.h"
+generate_and_compare "server-header" "small.xml" "small-server.h"
+
+generate_and_compare "-c code" "small.xml" "small-code-core.c"
+generate_and_compare "-c client-header" "small.xml" "small-client-core.h"
+generate_and_compare "-c server-header" "small.xml" "small-server-core.h"
+
+# The existing "code" must produce result identical to "public-code"
+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"
+
+generate_and_compare "code" "empty.xml" "empty-code.c"
+generate_and_compare "client-header" "empty.xml" "empty-client.h"
+generate_and_compare "server-header" "empty.xml" "empty-server.h"
+
+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/subprojects/wayland/tests/signal-test.c b/subprojects/wayland/tests/signal-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..f7e1bd6fe1aad99774756932b28db2a464e1b228
--- /dev/null
+++ b/subprojects/wayland/tests/signal-test.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright © 2013 Marek Chalupa
+ *
+ * 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 "wayland-server.h"
+#include "test-runner.h"
+
+static void
+signal_notify(struct wl_listener *listener, void *data)
+{
+	/* only increase counter*/
+	++(*((int *) data));
+}
+
+TEST(signal_init)
+{
+	struct wl_signal signal;
+
+	wl_signal_init(&signal);
+
+	/* Test if listeners' list is initialized */
+	assert(&signal.listener_list == signal.listener_list.next
+		&& "Maybe wl_signal implementation changed?");
+	assert(signal.listener_list.next == signal.listener_list.prev
+		&& "Maybe wl_signal implementation changed?");
+}
+
+TEST(signal_add_get)
+{
+	struct wl_signal signal;
+
+	/* we just need different values of notify */
+	struct wl_listener l1 = {.notify = (wl_notify_func_t) 0x1};
+	struct wl_listener l2 = {.notify = (wl_notify_func_t) 0x2};
+	struct wl_listener l3 = {.notify = (wl_notify_func_t) 0x3};
+	/* one real, why not */
+	struct wl_listener l4 = {.notify = signal_notify};
+
+	wl_signal_init(&signal);
+
+	wl_signal_add(&signal, &l1);
+	wl_signal_add(&signal, &l2);
+	wl_signal_add(&signal, &l3);
+	wl_signal_add(&signal, &l4);
+
+	assert(wl_signal_get(&signal, signal_notify) == &l4);
+	assert(wl_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3);
+	assert(wl_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2);
+	assert(wl_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1);
+
+	/* get should not be destructive */
+	assert(wl_signal_get(&signal, signal_notify) == &l4);
+	assert(wl_signal_get(&signal, (wl_notify_func_t) 0x3) == &l3);
+	assert(wl_signal_get(&signal, (wl_notify_func_t) 0x2) == &l2);
+	assert(wl_signal_get(&signal, (wl_notify_func_t) 0x1) == &l1);
+}
+
+TEST(signal_emit_to_one_listener)
+{
+	int count = 0;
+	int counter;
+
+	struct wl_signal signal;
+	struct wl_listener l1 = {.notify = signal_notify};
+
+	wl_signal_init(&signal);
+	wl_signal_add(&signal, &l1);
+
+	for (counter = 0; counter < 100; counter++)
+		wl_signal_emit(&signal, &count);
+
+	assert(counter == count);
+}
+
+TEST(signal_emit_to_more_listeners)
+{
+	int count = 0;
+	int counter;
+
+	struct wl_signal signal;
+	struct wl_listener l1 = {.notify = signal_notify};
+	struct wl_listener l2 = {.notify = signal_notify};
+	struct wl_listener l3 = {.notify = signal_notify};
+
+	wl_signal_init(&signal);
+	wl_signal_add(&signal, &l1);
+	wl_signal_add(&signal, &l2);
+	wl_signal_add(&signal, &l3);
+
+	for (counter = 0; counter < 100; counter++)
+		wl_signal_emit(&signal, &count);
+
+	assert(3 * counter == count);
+}
+
+struct signal_emit_mutable_data {
+	int count;
+	struct wl_listener *remove_listener;
+};
+
+static void
+signal_notify_mutable(struct wl_listener *listener, void *data)
+{
+	struct signal_emit_mutable_data *test_data = data;
+	test_data->count++;
+}
+
+static void
+signal_notify_and_remove_mutable(struct wl_listener *listener, void *data)
+{
+	struct signal_emit_mutable_data *test_data = data;
+	signal_notify_mutable(listener, test_data);
+	wl_list_remove(&test_data->remove_listener->link);
+}
+
+TEST(signal_emit_mutable)
+{
+	struct signal_emit_mutable_data data = {0};
+
+	/* l2 will remove l3 before l3 is notified */
+	struct wl_signal signal;
+	struct wl_listener l1 = {.notify = signal_notify_mutable};
+	struct wl_listener l2 = {.notify = signal_notify_and_remove_mutable};
+	struct wl_listener l3 = {.notify = signal_notify_mutable};
+
+	wl_signal_init(&signal);
+	wl_signal_add(&signal, &l1);
+	wl_signal_add(&signal, &l2);
+	wl_signal_add(&signal, &l3);
+
+	data.remove_listener = &l3;
+	wl_signal_emit_mutable(&signal, &data);
+
+	assert(data.count == 2);
+}
diff --git a/subprojects/wayland/tests/socket-test.c b/subprojects/wayland/tests/socket-test.c
new file mode 100644
index 0000000000000000000000000000000000000000..78743dc3a20f24cf04b2cc3bf859db8f6d309b13
--- /dev/null
+++ b/subprojects/wayland/tests/socket-test.c
@@ -0,0 +1,289 @@
+/*
+ * 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 <stdlib.h>
+#include <assert.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <unistd.h>
+
+#include "wayland-client.h"
+#include "wayland-os.h"
+#include "wayland-server.h"
+#include "test-runner.h"
+
+/* Paths longer than what the .sun_path array can contain must be rejected.
+ * This is a hard limitation of assigning a name to AF_UNIX/AF_LOCAL sockets.
+ * See `man 7 unix`.
+ */
+
+static struct sockaddr_un example_sockaddr_un;
+
+#define TOO_LONG (1 + sizeof example_sockaddr_un.sun_path)
+
+/* Ensure the connection doesn't fail due to lack of XDG_RUNTIME_DIR. */
+static const char *
+require_xdg_runtime_dir(void)
+{
+	char *val = getenv("XDG_RUNTIME_DIR");
+	assert(val && val[0] == '/' && "set $XDG_RUNTIME_DIR to run this test");
+
+	return val;
+}
+
+TEST(socket_path_overflow_client_connect)
+{
+	char path[TOO_LONG];
+	struct wl_display *d;
+
+	require_xdg_runtime_dir();
+
+	memset(path, 'a', sizeof path);
+	path[sizeof path - 1] = '\0';
+
+	d = wl_display_connect(path);
+	assert(d == NULL);
+	assert(errno == ENAMETOOLONG);
+
+	/* This is useless, but prevents a warning about example_sockaddr_un
+	 * being discarded from the compilation unit. */
+	strcpy(example_sockaddr_un.sun_path, "happy now clang?");
+	assert(example_sockaddr_un.sun_path[0] != '\0');
+}
+
+TEST(socket_path_overflow_server_create)
+{
+	char path[TOO_LONG];
+	struct wl_display *d;
+	int ret;
+
+	require_xdg_runtime_dir();
+
+	memset(path, 'a', sizeof path);
+	path[sizeof path - 1] = '\0';
+
+	d = wl_display_create();
+	assert(d != NULL);
+
+	ret = wl_display_add_socket(d, path);
+	assert(ret < 0);
+	assert(errno == ENAMETOOLONG);
+
+	wl_display_destroy(d);
+}
+
+TEST(add_existing_socket)
+{
+	char path[sizeof example_sockaddr_un.sun_path];
+	const char *name = "wayland-test-0";
+	const char *xdg_runtime_dir;
+	struct wl_display *d;
+	int ret;
+	size_t len;
+
+	xdg_runtime_dir = require_xdg_runtime_dir();
+
+	d = wl_display_create();
+	assert(d != NULL);
+
+	/* this one should be OK */
+	ret = wl_display_add_socket(d, name);
+	assert(ret == 0);
+
+	/* this one should fail */
+	ret = wl_display_add_socket(d, name);
+	assert(ret < 0);
+
+	/* the original socket should still exist.
+	 * this was a bug introduced in e2c0d47b0c77f18cd90e9c6eabb358c4d89681c8 */
+	len = snprintf(path, sizeof example_sockaddr_un.sun_path, "%s/%s",
+		       xdg_runtime_dir, name);
+	assert(len < sizeof example_sockaddr_un.sun_path
+	       && "Bug in test. Path too long");
+
+	assert(access(path, F_OK) != -1);
+
+	/* the original socket should still exist */
+	ret = wl_display_add_socket(d, name);
+	assert(ret < 0);
+
+	wl_display_destroy(d);
+}
+
+TEST(add_socket_auto)
+{
+	/* the number of auto sockets is currently 32,
+	 * set in wayland-server.c.
+	 */
+	const int MAX_SOCKETS = 32;
+
+	char path[sizeof example_sockaddr_un.sun_path];
+	const char *name;
+	const char *xdg_runtime_dir;
+	struct wl_display *d;
+	int i;
+	size_t len;
+
+	xdg_runtime_dir = require_xdg_runtime_dir();
+
+	d = wl_display_create();
+	assert(d != NULL);
+
+	for (i = 0; i <= MAX_SOCKETS; ++i) {
+		name = wl_display_add_socket_auto(d);
+		assert(name != NULL);
+
+		len = snprintf(path, sizeof example_sockaddr_un.sun_path,
+			       "%s/%s", xdg_runtime_dir, name);
+		assert(len < sizeof example_sockaddr_un.sun_path
+		       && "Bug in test. Path too long");
+
+		/* was the socket created correctly? */
+		assert(access(path, F_OK) != -1);
+
+		/* is the name sequential? */
+		len = snprintf(path, sizeof example_sockaddr_un.sun_path,
+			       "wayland-%d", i);
+		assert(strcmp(name, path) == 0);
+	}
+
+	/* next addition should return NULL */
+	name = wl_display_add_socket_auto(d);
+	assert(name == NULL);
+
+	/* check if the socket was not deleted the last time */
+	name = wl_display_add_socket_auto(d);
+	assert(name == NULL);
+
+	wl_display_destroy(d);
+}
+
+struct client_create_listener {
+	struct wl_listener listener;
+	struct wl_display *display;
+};
+
+struct client_destroy_listener {
+	struct wl_listener listener;
+	struct wl_display *display;
+};
+
+static void
+client_destroy_notify(struct wl_listener *l, void *data)
+{
+	struct client_destroy_listener *listener =
+		wl_container_of(l, listener, listener);
+	wl_display_terminate(listener->display);
+	free(listener);
+}
+
+static void
+client_create_notify(struct wl_listener *l, void *data)
+{
+	struct wl_client *client = data;
+	struct client_create_listener *listener =
+		wl_container_of(l, listener, listener);
+	struct client_destroy_listener *destroy_listener = (struct client_destroy_listener *)malloc(sizeof *destroy_listener);
+	assert(destroy_listener != NULL);
+	destroy_listener->display = listener->display;
+	destroy_listener->listener.notify = client_destroy_notify;
+	wl_client_add_destroy_listener(client, &destroy_listener->listener);
+}
+
+TEST(absolute_socket_path)
+{
+	struct wl_display *display;
+	struct client_create_listener client_create_listener;
+	struct sockaddr_un addr;
+	int fd;
+	socklen_t size;
+	const char *xdg_runtime_dir;
+	size_t len;
+	int ret;
+	pid_t pid;
+
+	/* It's a little weird that this test about absolute socket paths
+	 * uses XDG_RUNTIME_DIR, but that's the only location guaranteed
+	 * by test-runner to be both writable and unique. This isn't
+	 * really a problem; we'll just take care that the leaf-level
+	 * filename used for the socket isn't anything that would
+	 * accidentally be generated by a default usage of wl_display_connect(). */
+	xdg_runtime_dir = require_xdg_runtime_dir();
+	memset(&addr, 0, sizeof addr);
+	len = snprintf(addr.sun_path, sizeof addr.sun_path,
+		       "%s/%s", xdg_runtime_dir, "wayland-absolute-0");
+	assert(len < sizeof addr.sun_path
+	       && "Bug in test. Path too long");
+
+	/* The path must not exist prior to binding. */
+	assert(access(addr.sun_path, F_OK) == -1);
+
+	size = offsetof (struct sockaddr_un, sun_path) + strlen(addr.sun_path);
+	addr.sun_family = AF_LOCAL;
+	fd = wl_os_socket_cloexec(PF_LOCAL, SOCK_STREAM, 0);
+	assert(fd >= 0 );
+	ret = bind(fd, (struct sockaddr *) &addr, size);
+	assert(ret >= 0);
+	ret = listen(fd, 128);
+	assert(ret >= 0);
+
+	/* Start server display. Be careful (by avoiding wl_display_add_socket_auto()
+	 * to offer only the absolutely qualified socket made above. */
+	display = wl_display_create();
+	assert(display != NULL);
+	client_create_listener.listener.notify = client_create_notify;
+	client_create_listener.display = display;
+	wl_display_add_client_created_listener(display, &client_create_listener.listener);
+	ret = wl_display_add_socket_fd(display, fd);
+	assert(ret == 0);
+
+	/* Execute client that connects to the absolutely qualified server socket path. */
+	pid = fork();
+	assert(pid != -1);
+
+	if (pid == 0) {
+		ret = setenv("WAYLAND_DISPLAY", addr.sun_path, 1);
+		assert(ret == 0);
+		struct wl_display *client_display = wl_display_connect(NULL);
+		assert(client_display != NULL);
+		ret = wl_display_roundtrip(client_display);
+		assert(ret != -1);
+		wl_display_disconnect(client_display);
+		exit(0);
+		assert(false);
+	}
+
+	wl_display_run(display);
+	ret = waitpid(pid, NULL, 0);
+	assert(ret == pid);
+
+	wl_display_destroy(display);
+
+	ret = unlink(addr.sun_path);
+	assert(ret == 0);
+}
diff --git a/subprojects/wayland/tests/test-compositor.c b/subprojects/wayland/tests/test-compositor.c
new file mode 100644
index 0000000000000000000000000000000000000000..8648fb69bfee9155c6537bfd71da7967d9f20073
--- /dev/null
+++ b/subprojects/wayland/tests/test-compositor.c
@@ -0,0 +1,585 @@
+/*
+ * Copyright (c) 2014 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 <errno.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <signal.h>
+
+#define WL_HIDE_DEPRECATED
+
+#include "test-runner.h"
+#include "test-compositor.h"
+
+int client_log_fd = -1;
+
+/* --- Protocol --- */
+struct test_compositor;
+
+static const struct wl_message tc_requests[] = {
+	/* this request serves as a barrier for synchronizing*/
+	{ "stop_display", "u", NULL },
+	{ "noop", "", NULL },
+};
+
+static const struct wl_message tc_events[] = {
+	{ "display_resumed", "", NULL }
+};
+
+const struct wl_interface test_compositor_interface = {
+	"test", 1,
+	2, tc_requests,
+	1, tc_events
+};
+
+struct test_compositor_interface {
+	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 {
+	void (*display_resumed)(void *data, struct test_compositor *tc);
+
+};
+
+enum {
+	STOP_DISPLAY = 0,
+	TEST_NOOP = 1
+};
+
+enum {
+	DISPLAY_RESUMED = 0
+};
+
+/* Since tests can run parallelly, we need unique socket names
+ * for each test, otherwise the test can fail on wl_display_add_socket. */
+static const char *
+get_socket_name(void)
+{
+	struct timeval tv;
+	static char retval[64];
+
+	gettimeofday(&tv, NULL);
+	snprintf(retval, sizeof retval, "wayland-test-%d-%ld%ld",
+		 getpid(), tv.tv_sec, tv.tv_usec);
+
+	return retval;
+}
+
+static void
+handle_client_destroy(void *data)
+{
+	struct client_info *ci = data;
+	struct display *d;
+	int status;
+
+	d = ci->display;
+
+	assert(waitpid(ci->pid, &status, 0) != -1);
+
+	if (WIFSIGNALED(status)) {
+		fprintf(stderr, "Client '%s' was killed by signal %d\n",
+			ci->name, WTERMSIG(status));
+		ci->kill_code = WTERMSIG(status);
+
+	} else if (WIFEXITED(status)) {
+		if (WEXITSTATUS(status) != EXIT_SUCCESS)
+			fprintf(stderr, "Client '%s' exited with code %d\n",
+				ci->name, WEXITSTATUS(status));
+
+		ci->exit_code = WEXITSTATUS(status);
+	}
+
+	++d->clients_terminated_no;
+	if (d->clients_no == d->clients_terminated_no) {
+		wl_display_terminate(d->wl_display);
+	}
+
+	/* the clients are not removed from the list, because
+	 * at the end of the test we check the exit codes of all
+	 * clients. In the case that the test would go through
+	 * the clients list manually, zero out the wl_client as a sign
+	 * that the client is not running anymore */
+}
+
+/**
+ * Check client's state and terminate display when all clients exited
+ */
+static void
+client_destroyed(struct wl_listener *listener, void *data)
+{
+	struct client_info *ci;
+	struct display *d;
+	struct wl_event_loop *loop;
+
+	/* Wait for client in an idle handler to avoid blocking the actual
+	 * client destruction (fd close etc. */
+	ci = wl_container_of(listener, ci, destroy_listener);
+	d = ci->display;
+	loop = wl_display_get_event_loop(d->wl_display);
+	wl_event_loop_add_idle(loop, handle_client_destroy, ci);
+
+	ci->wl_client = NULL;
+}
+
+static void
+client_log_handler(const char *fmt, va_list arg)
+{
+	va_list arg_copy;
+
+	va_copy(arg_copy, arg);
+	vdprintf(client_log_fd, fmt, arg_copy);
+	va_end(arg_copy);
+
+	vfprintf(stderr, fmt, arg);
+}
+
+static void
+run_client(void (*client_main)(void *data), void *data,
+	   int wayland_sock, int client_pipe, int log_fd)
+{
+	char s[8];
+	int cur_fds;
+	int can_continue = 0;
+
+	/* Wait until display signals that client can continue */
+	assert(read(client_pipe, &can_continue, sizeof(int)) == sizeof(int));
+
+	if (can_continue == 0)
+		abort(); /* error in parent */
+
+	/* for wl_display_connect() */
+	snprintf(s, sizeof s, "%d", wayland_sock);
+	setenv("WAYLAND_SOCKET", s, 0);
+
+	/* Capture the log to the specified file descriptor. */
+	client_log_fd = log_fd;
+	wl_log_set_handler_client(client_log_handler);
+
+	cur_fds = count_open_fds();
+
+	client_main(data);
+
+	/* Clients using wl_display_connect() will end up closing the socket
+	 * passed in through the WAYLAND_SOCKET environment variable. When
+	 * doing this, it clears the environment variable, so if it's been
+	 * unset, then we assume the client consumed the file descriptor and
+	 * do not count it towards leak checking. */
+	if (!getenv("WAYLAND_SOCKET"))
+		cur_fds--;
+
+	check_fd_leaks(cur_fds);
+}
+
+static int
+create_log_fd(void)
+{
+	char logname[] = "/tmp/wayland-tests-log-XXXXXX";
+	int log_fd = mkstemp(logname);
+
+	if (log_fd >= 0)
+		unlink(logname);
+
+	return log_fd;
+}
+
+static struct client_info *
+display_create_client(struct display *d,
+		      void (*client_main)(void *data),
+		      void *data,
+		      const char *name)
+{
+	int pipe_cli[2];
+	int sock_wayl[2];
+	pid_t pid;
+	int can_continue = 0;
+	struct client_info *cl;
+	int log_fd;
+
+	assert(pipe(pipe_cli) == 0 && "Failed creating pipe");
+	assert(socketpair(AF_UNIX, SOCK_STREAM, 0, sock_wayl) == 0
+	       && "Failed creating socket pair");
+
+	log_fd = create_log_fd();
+	assert(log_fd >= 0 && "Failed to create log fd");
+
+	pid = fork();
+	assert(pid != -1 && "Fork failed");
+
+	if (pid == 0) {
+		close(sock_wayl[1]);
+		close(pipe_cli[1]);
+
+		run_client(client_main, data, sock_wayl[0], pipe_cli[0], log_fd);
+
+		close(sock_wayl[0]);
+		close(pipe_cli[0]);
+		close(log_fd);
+
+		exit(0);
+	}
+
+	close(sock_wayl[0]);
+	close(pipe_cli[0]);
+
+	cl = calloc(1, sizeof(struct client_info));
+	assert(cl && "Out of memory");
+
+	wl_list_insert(&d->clients, &cl->link);
+
+	cl->display = d;
+	cl->name = name;
+	cl->pid = pid;
+	cl->pipe = pipe_cli[1];
+	cl->log_fd = log_fd;
+	cl->destroy_listener.notify = &client_destroyed;
+
+	cl->wl_client = wl_client_create(d->wl_display, sock_wayl[1]);
+	if (!cl->wl_client) {
+		int ret;
+
+		/* abort the client */
+		ret = write(cl->pipe, &can_continue, sizeof(int));
+		assert(ret == sizeof(int) && "aborting the client failed");
+		assert(0 && "Couldn't create wayland client");
+	}
+
+	wl_client_add_destroy_listener(cl->wl_client,
+				       &cl->destroy_listener);
+
+	++d->clients_no;
+
+	return cl;
+}
+
+struct client_info *
+client_create_with_name(struct display *d,
+			void (*client_main)(void *data), void *data,
+			const char *name)
+{
+	int can_continue = 1;
+	struct client_info *cl = display_create_client(d,
+						       client_main, data,
+						       name);
+
+	/* let the show begin! */
+	assert(write(cl->pipe, &can_continue, sizeof(int)) == sizeof(int));
+
+	return cl;
+}
+
+/* wfr = waiting for resume */
+struct wfr {
+	struct wl_resource *resource;
+	struct wl_list link;
+};
+
+static void
+handle_stop_display(struct wl_client *client,
+		    struct wl_resource *resource, uint32_t num)
+{
+	struct display *d = wl_resource_get_user_data(resource);
+	struct wfr *wfr;
+
+	assert(d->wfr_num < num
+	       && "test error: Too many clients sent stop_display request");
+
+	++d->wfr_num;
+
+	wfr = malloc(sizeof *wfr);
+	if (!wfr) {
+		wl_client_post_no_memory(client);
+		assert(0 && "Out of memory");
+	}
+
+	wfr->resource = resource;
+	wl_list_insert(&d->waiting_for_resume, &wfr->link);
+
+	if (d->wfr_num == num)
+		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_noop,
+};
+
+static void
+tc_bind(struct wl_client *client, void *data,
+	uint32_t ver, uint32_t id)
+{
+	struct wl_resource *res;
+
+	res = wl_resource_create(client, &test_compositor_interface, ver, id);
+	if (!res) {
+		wl_client_post_no_memory(client);
+		assert(0 && "Out of memory");
+	}
+
+	wl_resource_set_implementation(res, &tc_implementation, data, NULL);
+}
+
+struct display *
+display_create(void)
+{
+	struct display *d = NULL;
+	const char *socket_name;
+	int stat = 0;
+
+	d = calloc(1, sizeof *d);
+	assert(d && "Out of memory");
+
+	d->wl_display = wl_display_create();
+	assert(d->wl_display && "Creating display failed");
+
+	/* hope the path won't be longer than 108 ... */
+	socket_name = get_socket_name();
+	stat = wl_display_add_socket(d->wl_display, socket_name);
+	assert(stat == 0 && "Failed adding socket");
+
+	wl_list_init(&d->clients);
+	d->clients_no = d->clients_terminated_no = 0;
+
+	wl_list_init(&d->waiting_for_resume);
+	d->wfr_num = 0;
+
+	d->test_global = wl_global_create(d->wl_display,
+					  &test_compositor_interface,
+					  1, d, tc_bind);
+	assert(d->test_global && "Creating test global failed");
+
+	return d;
+}
+
+void
+display_run(struct display *d)
+{
+	assert(d->wfr_num == 0
+	       && "test error: Have waiting clients. Use display_resume.");
+	wl_display_run(d->wl_display);
+}
+
+void
+display_post_resume_events(struct display *d)
+{
+	struct wfr *wfr, *next;
+
+	assert(d->wfr_num > 0 && "test error: No clients waiting.");
+
+	wl_list_for_each_safe(wfr, next, &d->waiting_for_resume, link) {
+		wl_resource_post_event(wfr->resource, DISPLAY_RESUMED);
+		wl_list_remove(&wfr->link);
+		free(wfr);
+	}
+
+	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);
+}
+
+/* If signum is 0, expect a successful client exit, otherwise
+ * expect the client to have been killed by that signal. */
+void
+display_destroy_expect_signal(struct display *d, int signum)
+{
+	struct client_info *cl, *next;
+	int failed = 0;
+
+	assert(d->wfr_num == 0
+	       && "test error: Didn't you forget to call display_resume?");
+
+	wl_list_for_each_safe(cl, next, &d->clients, link) {
+		assert(cl->wl_client == NULL);
+
+		if (signum != 0 && cl->kill_code != signum) {
+			++failed;
+			fprintf(stderr,
+				"Client '%s' failed, expecting signal %d, "
+				"got %d\n",
+				cl->name, signum, cl->kill_code);
+		}
+		else if (signum == 0 &&
+			 (cl->kill_code != 0 || cl->exit_code != 0)) {
+			++failed;
+			fprintf(stderr, "Client '%s' failed\n", cl->name);
+		}
+
+		close(cl->pipe);
+		close(cl->log_fd);
+		free(cl);
+	}
+
+	wl_global_destroy(d->test_global);
+	wl_display_destroy(d->wl_display);
+	free(d);
+
+	if (failed) {
+		fprintf(stderr, "%d child(ren) failed\n", failed);
+		abort();
+	}
+}
+
+void
+display_destroy(struct display *d)
+{
+	display_destroy_expect_signal(d, 0);
+}
+
+/*
+ * --- Client helper functions ---
+ */
+static void
+handle_display_resumed(void *data, struct test_compositor *tc)
+{
+	struct client *c = data;
+
+	c->display_stopped = 0;
+}
+
+static const struct test_compositor_listener tc_listener = {
+	handle_display_resumed
+};
+
+static void
+registry_handle_globals(void *data, struct wl_registry *registry,
+			uint32_t id, const char *intf, uint32_t ver)
+{
+	struct client *c = data;
+
+	if (strcmp(intf, "test") != 0)
+		return;
+
+	c->tc = wl_registry_bind(registry, id, &test_compositor_interface, ver);
+	assert(c->tc && "Failed binding to registry");
+
+	wl_proxy_add_listener((struct wl_proxy *) c->tc,
+			      (void *) &tc_listener, c);
+}
+
+static const struct wl_registry_listener registry_listener =
+{
+	registry_handle_globals,
+	NULL
+};
+
+struct client *client_connect()
+{
+	struct wl_registry *reg;
+	struct client *c = calloc(1, sizeof *c);
+	assert(c && "Out of memory");
+
+	c->wl_display = wl_display_connect(NULL);
+	assert(c->wl_display && "Failed connecting to display");
+
+	/* create test_compositor proxy. Do it with temporary
+	 * registry so that client can define it's own listener later */
+	reg = wl_display_get_registry(c->wl_display);
+	assert(reg);
+	wl_registry_add_listener(reg, &registry_listener, c);
+	wl_display_roundtrip(c->wl_display);
+	assert(c->tc);
+
+	wl_registry_destroy(reg);
+
+	return c;
+}
+
+static void
+check_error(struct wl_display *display)
+{
+	uint32_t ec, id;
+	const struct wl_interface *intf;
+	int err;
+
+	err = wl_display_get_error(display);
+	/* write out message about protocol error */
+	if (err == EPROTO) {
+		ec = wl_display_get_protocol_error(display, &intf, &id);
+		fprintf(stderr, "Client: Got protocol error %u on interface %s"
+				" (object %u)\n", ec, intf->name, id);
+	}
+
+	if (err) {
+		fprintf(stderr, "Client error: %s\n", strerror(err));
+		abort();
+	}
+}
+
+void
+client_disconnect(struct client *c)
+{
+	/* check for errors */
+	check_error(c->wl_display);
+
+	wl_proxy_destroy((struct wl_proxy *) c->tc);
+	wl_display_disconnect(c->wl_display);
+	free(c);
+}
+
+/* num is number of clients that requests to stop display.
+ * Display is stopped after it receives num STOP_DISPLAY requests */
+int
+stop_display(struct client *c, int num)
+{
+	int n = 0;
+
+	c->display_stopped = 1;
+	wl_proxy_marshal((struct wl_proxy *) c->tc, STOP_DISPLAY, num);
+
+	while (c->display_stopped && n >= 0) {
+		n = wl_display_dispatch(c->wl_display);
+	}
+
+	return n;
+}
+
+void
+noop_request(struct client *c)
+{
+	wl_proxy_marshal((struct wl_proxy *) c->tc, TEST_NOOP);
+}
diff --git a/subprojects/wayland/tests/test-compositor.h b/subprojects/wayland/tests/test-compositor.h
new file mode 100644
index 0000000000000000000000000000000000000000..3fb390c28bdd9fb8155ee0c174194ce2d3a66f9a
--- /dev/null
+++ b/subprojects/wayland/tests/test-compositor.h
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014 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 <stdint.h>
+#include <unistd.h>
+#include <stdatomic.h>
+
+#include "wayland-server.h"
+#include "wayland-client.h"
+
+/* info about a client on server side */
+struct client_info {
+	struct display *display;
+	struct wl_client *wl_client;
+	struct wl_listener destroy_listener;
+	const char *name; /* for debugging */
+
+	int pipe;
+	pid_t pid;
+	int exit_code;
+	int kill_code;
+
+	struct wl_list link;
+	void *data; /* for arbitrary use */
+	int log_fd;
+};
+
+struct display {
+	struct wl_display *wl_display;
+	struct wl_global *test_global;
+
+	struct wl_list clients;
+	uint32_t clients_no;
+	uint32_t clients_terminated_no;
+
+	/* list of clients waiting for display_resumed event */
+	struct wl_list waiting_for_resume;
+	uint32_t wfr_num;
+};
+
+/* This is a helper structure for clients.
+ * Instead of calling wl_display_connect() and all the other stuff,
+ * client can use client_connect and it will return this structure
+ * filled. */
+struct client {
+	struct wl_display *wl_display;
+	struct test_compositor *tc;
+
+	atomic_bool display_stopped;
+};
+
+struct client *client_connect(void);
+void client_disconnect(struct client *);
+int stop_display(struct client *, int);
+void noop_request(struct client *);
+
+/**
+ * Usual workflow:
+ *
+ *    d = display_create();
+ *
+ *    wl_global_create(d->wl_display, ...);
+ *    ... other setups ...
+ *
+ *    client_create(d, client_main, data);
+ *    client_create(d, client_main2, data);
+ *
+ *    display_run(d);
+ *    display_destroy(d);
+ */
+struct display *display_create(void);
+void display_destroy(struct display *d);
+void display_destroy_expect_signal(struct display *d, int signum);
+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 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);
+
+/* The file descriptor containing the client log. This is only valid in the
+ * test client processes. */
+extern int client_log_fd;
+
+struct client_info *client_create_with_name(struct display *d,
+					    void (*client_main)(void *data),
+					    void *data,
+					    const char *name);
+#define client_create(d, c, data) client_create_with_name((d), (c), data, (#c))
+#define client_create_noarg(d, c) \
+	client_create_with_name((d), (void(*)(void *)) (c), NULL, (#c))
diff --git a/subprojects/wayland/tests/test-helpers.c b/subprojects/wayland/tests/test-helpers.c
new file mode 100644
index 0000000000000000000000000000000000000000..1af813bb4607b8208329c026e7c2331b50cbd357
--- /dev/null
+++ b/subprojects/wayland/tests/test-helpers.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright © 2012 Collabora, Ltd.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "config.h"
+
+#include <assert.h>
+#include <errno.h>
+#include <dirent.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/resource.h>
+
+#ifdef HAVE_SYS_PRCTL_H
+#include <sys/prctl.h>
+#endif
+
+#include "test-runner.h"
+
+#if defined(__FreeBSD__)
+#include <sys/sysctl.h>
+
+/*
+ * On FreeBSD, get file descriptor information using sysctl() since that does
+ * not depend on a mounted fdescfs (which provides /dev/fd/N for N > 2).
+ */
+int
+count_open_fds(void)
+{
+	int error;
+	int nfds;
+	int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_NFDS, 0 };
+	size_t len;
+
+	len = sizeof(nfds);
+	error = sysctl(mib, 4, &nfds, &len, NULL, 0);
+	assert(error == 0 && "sysctl KERN_PROC_NFDS failed.");
+	return nfds;
+}
+#elif defined(__OpenBSD__)
+#include <sys/sysctl.h>
+
+/*
+ * On OpenBSD, get file descriptor information using sysctl()
+ */
+int
+count_open_fds(void)
+{
+	int error;
+	int mib[6];
+	size_t size;
+
+	mib[0] = CTL_KERN;
+	mib[1] = KERN_FILE;
+	mib[2] = KERN_FILE_BYPID;
+	mib[3] = getpid();
+	mib[4] = sizeof(struct kinfo_file);
+	mib[5] = 0;
+
+	/* find the size required to store all the entries */
+	error = sysctl(mib, 6, NULL, &size, NULL, 0);
+	assert(error != -1 && "sysctl KERN_FILE_BYPID failed.");
+
+	/* return the current number of entries */
+	return size / sizeof(struct kinfo_file);
+}
+#else
+int
+count_open_fds(void)
+{
+	DIR *dir;
+	struct dirent *ent;
+	int count = 0;
+
+	/*
+	 * Using /dev/fd instead of /proc/self/fd should allow this code to
+	 * work on non-Linux operating systems.
+	 */
+	dir = opendir("/dev/fd");
+	assert(dir && "opening /dev/fd failed.");
+
+	errno = 0;
+	while ((ent = readdir(dir))) {
+		const char *s = ent->d_name;
+		if (s[0] == '.' && (s[1] == 0 || (s[1] == '.' && s[2] == 0)))
+			continue;
+		count++;
+	}
+	assert(errno == 0 && "reading /dev/fd failed.");
+
+	closedir(dir);
+
+	return count;
+}
+#endif
+
+void
+exec_fd_leak_check(int nr_expected_fds)
+{
+	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_path, exe, number, (char *)NULL);
+	assert(0 && "execing fd leak checker failed");
+}
+
+#define USEC_TO_NSEC(n) (1000 * (n))
+
+/* our implementation of usleep and sleep functions that are safe to use with
+ * timeouts (timeouts are implemented using alarm(), so it is not safe use
+ * usleep and sleep. See man pages of these functions)
+ */
+void
+test_usleep(useconds_t usec)
+{
+	struct timespec ts = {
+		.tv_sec = 0,
+		.tv_nsec = USEC_TO_NSEC(usec)
+	};
+
+	assert(nanosleep(&ts, NULL) == 0);
+}
+
+/* we must write the whole function instead of
+ * wrapping test_usleep, because useconds_t may not
+ * be able to contain such a big number of microseconds */
+void
+test_sleep(unsigned int sec)
+{
+	struct timespec ts = {
+		.tv_sec = sec,
+		.tv_nsec = 0
+	};
+
+	assert(nanosleep(&ts, NULL) == 0);
+}
+
+/** Try to disable coredumps
+ *
+ * Useful for tests that crash on purpose, to avoid creating a core file
+ * or launching an application crash handler service or cluttering coredumpctl.
+ *
+ * NOTE: Calling this may make the process undebuggable.
+ */
+void
+test_disable_coredumps(void)
+{
+	struct rlimit r;
+
+	if (getrlimit(RLIMIT_CORE, &r) == 0) {
+		r.rlim_cur = 0;
+		setrlimit(RLIMIT_CORE, &r);
+	}
+
+#if defined(HAVE_PRCTL) && defined(PR_SET_DUMPABLE)
+	prctl(PR_SET_DUMPABLE, 0, 0, 0, 0);
+#endif
+}
diff --git a/subprojects/wayland/tests/test-runner.c b/subprojects/wayland/tests/test-runner.c
new file mode 100644
index 0000000000000000000000000000000000000000..9a50d1dd19dccbf859a0fc1ce27575d16276d6c6
--- /dev/null
+++ b/subprojects/wayland/tests/test-runner.c
@@ -0,0 +1,416 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#include "../config.h"
+
+#define _GNU_SOURCE
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <assert.h>
+#include <dlfcn.h>
+#include <errno.h>
+#include <limits.h>
+#include <signal.h>
+#include <sys/ptrace.h>
+#ifdef HAVE_SYS_PROCCTL_H
+#include <sys/procctl.h>
+#elif defined(HAVE_SYS_PRCTL_H)
+#include <sys/prctl.h>
+#ifndef PR_SET_PTRACER
+# define PR_SET_PTRACER 0x59616d61
+#endif
+#endif
+
+#include "test-runner.h"
+
+/* when set to 1, check if tests are not leaking opened files.
+ * It is turned on by default. It can be turned off by
+ * WAYLAND_TEST_NO_LEAK_CHECK environment variable. */
+int fd_leak_check_enabled;
+
+/* when this var is set to 0, every call to test_set_timeout() is
+ * suppressed - handy when debugging the test. Can be set by
+ * WAYLAND_TEST_NO_TIMEOUTS environment variable. */
+static int timeouts_enabled = 1;
+
+/* set to one if the output goes to the terminal */
+static int is_atty = 0;
+
+extern const struct test __start_test_section, __stop_test_section;
+
+static const struct test *
+find_test(const char *name)
+{
+	const struct test *t;
+
+	for (t = &__start_test_section; t < &__stop_test_section; t++)
+		if (strcmp(t->name, name) == 0)
+			return t;
+
+	return NULL;
+}
+
+static void
+usage(const char *name, int status)
+{
+	const struct test *t;
+
+	fprintf(stderr, "Usage: %s [TEST]\n\n"
+		"With no arguments, run all test.  Specify test case to run\n"
+		"only that test without forking.  Available tests:\n\n",
+		name);
+
+	for (t = &__start_test_section; t < &__stop_test_section; t++)
+		fprintf(stderr, "  %s\n", t->name);
+
+	fprintf(stderr, "\n");
+
+	exit(status);
+}
+
+void
+test_set_timeout(unsigned int to)
+{
+	int re;
+
+	if (!timeouts_enabled) {
+		fprintf(stderr, "Timeouts suppressed.\n");
+		return;
+	}
+
+	re = alarm(to);
+	fprintf(stderr, "Timeout was %sset", re ? "re-" : "");
+
+	if (to != 0)
+		fprintf(stderr, " to %d second%s from now.\n",
+			to, to > 1 ? "s" : "");
+	else
+		fprintf(stderr, " off.\n");
+}
+
+static void
+sigalrm_handler(int signum)
+{
+	fprintf(stderr, "Test timed out.\n");
+	abort();
+}
+
+void
+check_fd_leaks(int supposed_fds)
+{
+	int num_fds;
+
+	if (fd_leak_check_enabled) {
+		num_fds = count_open_fds();
+		if (supposed_fds != num_fds) {
+			fprintf(stderr, "fd leak detected in test. "
+				"Opened %d files, unclosed %d\n", num_fds,
+				num_fds - supposed_fds);
+			abort();
+		}
+	} else {
+		fprintf(stderr, "FD leak checks disabled\n");
+	}
+}
+
+static void
+run_test(const struct test *t)
+{
+	int cur_fds;
+	struct sigaction sa;
+
+	if (timeouts_enabled) {
+		sa.sa_handler = sigalrm_handler;
+		sa.sa_flags = 0;
+		sigemptyset(&sa.sa_mask);
+		assert(sigaction(SIGALRM, &sa, NULL) == 0);
+	}
+
+	//cur_alloc = get_current_alloc_num();
+	cur_fds = count_open_fds();
+
+	t->run();
+
+	/* turn off timeout (if any) after test completion */
+	if (timeouts_enabled)
+		alarm(0);
+
+	check_fd_leaks(cur_fds);
+
+	exit(EXIT_SUCCESS);
+}
+
+#ifndef PATH_MAX
+#define PATH_MAX 256
+#endif
+
+static void
+set_xdg_runtime_dir(void)
+{
+	char xdg_runtime_dir[PATH_MAX];
+	const char *xrd_env;
+
+	xrd_env = getenv("XDG_RUNTIME_DIR");
+	/* if XDG_RUNTIME_DIR is not set in environ, fallback to /tmp */
+	assert((snprintf(xdg_runtime_dir, PATH_MAX, "%s/wayland-tests-XXXXXX",
+			 (xrd_env && xrd_env[0] == '/') ? xrd_env : "/tmp") < PATH_MAX)
+		&& "test error: XDG_RUNTIME_DIR too long");
+
+	assert(mkdtemp(xdg_runtime_dir) && "test error: mkdtemp failed");
+	if (mkdir(xdg_runtime_dir, 0700) == -1)
+		if (errno != EEXIST) {
+			perror("Creating XDG_RUNTIME_DIR");
+			abort();
+		}
+
+	if (setenv("XDG_RUNTIME_DIR", xdg_runtime_dir, 1) == -1) {
+		perror("Setting XDG_RUNTIME_DIR");
+		abort();
+	}
+}
+
+static void
+rmdir_xdg_runtime_dir(void)
+{
+	const char *xrd_env = getenv("XDG_RUNTIME_DIR");
+	assert(xrd_env && xrd_env[0] == '/' && "No XDG_RUNTIME_DIR set");
+
+	/* rmdir may fail if some test didn't do clean up */
+	if (rmdir(xrd_env) == -1)
+		perror("Cleaning XDG_RUNTIME_DIR");
+}
+
+#define RED	"\033[31m"
+#define GREEN	"\033[32m"
+
+static void
+stderr_set_color(const char *color)
+{
+	/* use colors only when the output is connected to
+	 * the terminal */
+	if (is_atty)
+		fprintf(stderr, "%s", color);
+}
+
+static void
+stderr_reset_color(void)
+{
+	if (is_atty)
+		fprintf(stderr, "\033[0m");
+}
+
+/* this function is taken from libinput/test/litest.c
+ * (rev 028513a0a723e97941c39)
+ *
+ * Returns: 1 if a debugger is confirmed present; 0 if no debugger is
+ * present or if it can't be determined.
+ */
+#if defined(HAVE_SYS_PROCCTL_H) && defined(PROC_TRACE_STATUS)
+static int
+is_debugger_attached(void)
+{
+	int rc;
+	int status;
+	rc = procctl(P_PID, getpid(), PROC_TRACE_STATUS, &status);
+	if (rc == -1) {
+		perror("procctl");
+		return 0;
+	}
+	/* -1=tracing disabled, 0=no debugger attached, >0=pid of debugger. */
+	return status > 0;
+}
+#elif defined(HAVE_SYS_PRCTL_H)
+static int
+is_debugger_attached(void)
+{
+	int status;
+	int rc;
+	pid_t pid;
+	int pipefd[2];
+
+	if (pipe(pipefd) == -1) {
+		perror("pipe");
+		return 0;
+	}
+
+	pid = fork();
+	if (pid == -1) {
+		perror("fork");
+		close(pipefd[0]);
+		close(pipefd[1]);
+		return 0;
+	} else if (pid == 0) {
+		char buf;
+		pid_t ppid = getppid();
+
+		/* Wait until parent is ready */
+		close(pipefd[1]);  /* Close unused write end */
+		read(pipefd[0], &buf, 1);
+		close(pipefd[0]);
+		if (buf == '-')
+			_exit(1);
+		if (ptrace(PTRACE_ATTACH, ppid, NULL, NULL) != 0)
+			_exit(1);
+		if (!waitpid(-1, NULL, 0))
+			_exit(1);
+		ptrace(PTRACE_CONT, NULL, NULL);
+		ptrace(PTRACE_DETACH, ppid, NULL, NULL);
+		_exit(0);
+	} else {
+		close(pipefd[0]);
+
+		/* Enable child to ptrace the parent process */
+		rc = prctl(PR_SET_PTRACER, pid);
+		if (rc != 0 && errno != EINVAL) {
+			/* An error prevents us from telling if a debugger is attached.
+			 * Instead of propagating the error, assume no debugger present.
+			 * But note the error to the log as a clue for troubleshooting.
+			 * Then flag the error state to the client by sending '-'.
+			 */
+			perror("prctl");
+			write(pipefd[1], "-", 1);
+		} else {
+			/* Signal to client that parent is ready by passing '+' */
+			write(pipefd[1], "+", 1);
+		}
+		close(pipefd[1]);
+
+		waitpid(pid, &status, 0);
+		rc = WEXITSTATUS(status);
+	}
+
+	return rc;
+}
+#else
+static int
+is_debugger_attached(void)
+{
+	/* 0=debugger can't be determined */
+	return 0;
+}
+#endif
+
+int main(int argc, char *argv[])
+{
+	const struct test *t;
+	pid_t pid;
+	int total, pass;
+	int info;
+
+	if (isatty(fileno(stderr)))
+		is_atty = 1;
+
+	if (is_debugger_attached()) {
+		fd_leak_check_enabled = 0;
+		timeouts_enabled = 0;
+	} else {
+		fd_leak_check_enabled = !getenv("WAYLAND_TEST_NO_LEAK_CHECK");
+		timeouts_enabled = !getenv("WAYLAND_TEST_NO_TIMEOUTS");
+	}
+
+	if (argc == 2 && strcmp(argv[1], "--help") == 0)
+		usage(argv[0], EXIT_SUCCESS);
+
+	if (argc == 2) {
+		t = find_test(argv[1]);
+		if (t == NULL) {
+			fprintf(stderr, "unknown test: \"%s\"\n", argv[1]);
+			usage(argv[0], EXIT_FAILURE);
+		}
+
+		set_xdg_runtime_dir();
+		/* run_test calls exit() */
+		assert(atexit(rmdir_xdg_runtime_dir) == 0);
+
+		run_test(t);
+	}
+
+	/* set our own XDG_RUNTIME_DIR */
+	set_xdg_runtime_dir();
+
+	pass = 0;
+	for (t = &__start_test_section; t < &__stop_test_section; t++) {
+		int success = 0;
+
+		pid = fork();
+		assert(pid >= 0);
+
+		if (pid == 0)
+			run_test(t); /* never returns */
+
+		if (waitpid(pid, &info, 0) == -1) {
+			stderr_set_color(RED);
+			fprintf(stderr, "waitpid failed: %s\n",
+				strerror(errno));
+			stderr_reset_color();
+
+			abort();
+		}
+
+		if (WIFEXITED(info)) {
+			if (WEXITSTATUS(info) == EXIT_SUCCESS)
+				success = !t->must_fail;
+			else
+				success = t->must_fail;
+
+			stderr_set_color(success ? GREEN : RED);
+			fprintf(stderr, "test \"%s\":\texit status %d",
+				t->name, WEXITSTATUS(info));
+
+		} else if (WIFSIGNALED(info)) {
+			if (t->must_fail)
+				success = 1;
+
+			stderr_set_color(success ? GREEN : RED);
+			fprintf(stderr, "test \"%s\":\tsignal %d",
+				t->name, WTERMSIG(info));
+		}
+
+		if (success) {
+			pass++;
+			fprintf(stderr, ", pass.\n");
+		} else
+			fprintf(stderr, ", fail.\n");
+
+		stderr_reset_color();
+
+		/* print separator line */
+		fprintf(stderr, "----------------------------------------\n");
+	}
+
+	total = &__stop_test_section - &__start_test_section;
+	fprintf(stderr, "%d tests, %d pass, %d fail\n",
+		total, pass, total - pass);
+
+	/* cleaning */
+	rmdir_xdg_runtime_dir();
+
+	return pass == total ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/subprojects/wayland/tests/test-runner.h b/subprojects/wayland/tests/test-runner.h
new file mode 100644
index 0000000000000000000000000000000000000000..d0734009601e8d7462e8b837996bda01a299ef6e
--- /dev/null
+++ b/subprojects/wayland/tests/test-runner.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2012 Intel Corporation
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the
+ * next paragraph) shall be included in all copies or substantial
+ * portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+#ifndef _TEST_RUNNER_H_
+#define _TEST_RUNNER_H_
+
+#ifdef NDEBUG
+#error "Tests must not be built with NDEBUG defined, they rely on assert()."
+#endif
+
+#include <unistd.h>
+
+struct test {
+	const char *name;
+	void (*run)(void);
+	int must_fail;
+} __attribute__ ((aligned (16)));
+
+#define TEST(name)							\
+	static void name(void);						\
+									\
+	const struct test test##name					\
+		 __attribute__ ((used, section ("test_section"))) = {	\
+		#name, name, 0						\
+	};								\
+									\
+	static void name(void)
+
+#define FAIL_TEST(name)							\
+	static void name(void);						\
+									\
+	const struct test test##name					\
+		 __attribute__ ((used, section ("test_section"))) = {	\
+		#name, name, 1						\
+	};								\
+									\
+	static void name(void)
+
+int
+count_open_fds(void);
+
+void
+exec_fd_leak_check(int nr_expected_fds); /* never returns */
+
+void
+check_fd_leaks(int supposed_fds);
+
+/*
+ * set/reset the timeout in seconds. The timeout starts
+ * at the point of invoking this function
+ */
+void
+test_set_timeout(unsigned int);
+
+/* test-runner uses alarm() and SIGALRM, so we can not
+ * use usleep and sleep functions in tests (see 'man usleep'
+ * or 'man sleep', respectively). Following functions are safe
+ * to use in tests */
+void
+test_usleep(useconds_t);
+
+void
+test_sleep(unsigned int);
+
+void
+test_disable_coredumps(void);
+
+#define DISABLE_LEAK_CHECKS				\
+	do {						\
+		extern int fd_leak_check_enabled;	\
+		fd_leak_check_enabled = 0;		\
+	} while (0);
+
+#endif
diff --git a/subprojects/wayland/wayland-scanner.m4 b/subprojects/wayland/wayland-scanner.m4
new file mode 100644
index 0000000000000000000000000000000000000000..2b222e8bd58b6584a4faed936df18e83ef11e9ae
--- /dev/null
+++ b/subprojects/wayland/wayland-scanner.m4
@@ -0,0 +1,13 @@
+AC_DEFUN([WAYLAND_SCANNER_RULES], [
+    PKG_PROG_PKG_CONFIG
+
+    PKG_CHECK_MODULES([WAYLAND_SCANNER], [wayland-scanner >= 1.14.0])
+
+    wayland_scanner=`$PKG_CONFIG --variable=wayland_scanner wayland-scanner`
+    AC_SUBST([wayland_scanner])
+
+    wayland_scanner_rules=`$PKG_CONFIG --variable=pkgdatadir wayland-scanner`/wayland-scanner.mk
+    AC_SUBST_FILE([wayland_scanner_rules])
+
+    AC_SUBST([wayland_protocoldir], [$1])
+])
diff --git a/subprojects/wayland/wayland-scanner.mk b/subprojects/wayland/wayland-scanner.mk
new file mode 100644
index 0000000000000000000000000000000000000000..c174e6bd726b524d95c38b46cbbfbded4a65c977
--- /dev/null
+++ b/subprojects/wayland/wayland-scanner.mk
@@ -0,0 +1,8 @@
+%-protocol.c : $(wayland_protocoldir)/%.xml
+	$(AM_V_GEN)$(wayland_scanner) code $< $@
+
+%-server-protocol.h : $(wayland_protocoldir)/%.xml
+	$(AM_V_GEN)$(wayland_scanner) server-header $< $@
+
+%-client-protocol.h : $(wayland_protocoldir)/%.xml
+	$(AM_V_GEN)$(wayland_scanner) client-header $< $@
diff --git a/tests/testlockbutton.c b/tests/testlockbutton.c
index 67bcb458533e57d5ab75eeaf7d960d4a2e40b1c4..caa4d67934ca0049808b1dbf435b6311ab88f27e 100644
--- a/tests/testlockbutton.c
+++ b/tests/testlockbutton.c
@@ -19,6 +19,13 @@
 #include <gtk/gtk.h>
 #include <gio/gio.h>
 
+/* This is used to take screenshots of GtkLockButton for the docs.
+ *
+ * Run it like: testlockbutton lockbutton.ui style.css
+ *
+ * with the ui and css from the images directory for the docs.
+ */
+
 G_GNUC_BEGIN_IGNORE_DEPRECATIONS
 
 /* a fake permission implementation */
@@ -190,8 +197,6 @@ update_clicked (GtkButton *button, GtkLockButton *lockbutton)
   g_test_permission_set_success (G_TEST_PERMISSION (permission), success);
 }
 
-static GtkWidget *content;
-
 static void
 permission_changed (GPermission *permission,
                     GParamSpec  *pspec)
@@ -207,8 +212,93 @@ permission_changed (GPermission *permission,
   gtk_check_button_set_active (GTK_CHECK_BUTTON (allowed_button), allowed);
   gtk_check_button_set_active (GTK_CHECK_BUTTON (can_acquire_button), can_acquire);
   gtk_check_button_set_active (GTK_CHECK_BUTTON (can_release_button), can_release);
+}
+
+static void
+draw_paintable (GdkPaintable *paintable)
+{
+  GtkSnapshot *snapshot;
+  GskRenderNode *node;
+  GdkTexture *texture;
+  GskRenderer *renderer;
+  graphene_rect_t bounds;
+  static int count = 0;
+  char *path;
+
+  snapshot = gtk_snapshot_new ();
+  gdk_paintable_snapshot (paintable,
+                          snapshot,
+                          gdk_paintable_get_intrinsic_width (paintable),
+                          gdk_paintable_get_intrinsic_height (paintable));
+  node = gtk_snapshot_free_to_node (snapshot);
+
+  /* If the window literally draws nothing, we assume it hasn't been mapped yet and as such
+   * the invalidations were only side effects of resizes.
+   */
+  if (node == NULL)
+    return;
+
+  if (gsk_render_node_get_node_type (node) == GSK_CLIP_NODE)
+    {
+      GskRenderNode *child;
+
+      child = gsk_render_node_ref (gsk_clip_node_get_child (node));
+      gsk_render_node_unref (node);
+      node = child;
+    }
+
+  renderer = gtk_native_get_renderer (
+                 gtk_widget_get_native (
+                     gtk_widget_paintable_get_widget (GTK_WIDGET_PAINTABLE (paintable))));
+
+  gsk_render_node_get_bounds (node, &bounds);
+  graphene_rect_union (&bounds,
+                       &GRAPHENE_RECT_INIT (
+                         0, 0,
+                         gdk_paintable_get_intrinsic_width (paintable),
+                         gdk_paintable_get_intrinsic_height (paintable)
+                       ),
+                       &bounds);
+
+  texture = gsk_renderer_render_texture (renderer, node, &bounds);
+  g_object_set_data_full (G_OBJECT (texture),
+                          "source-render-node",
+                          node,
+                          (GDestroyNotify) gsk_render_node_unref);
+
+  path = g_strdup_printf ("screenshot%d.png", count++);
+  gdk_texture_save_to_png (texture, path);
+  g_free (path);
+
+  g_object_unref (texture);
+
+  g_signal_handlers_disconnect_by_func (paintable, draw_paintable, NULL);
+  g_object_unref (paintable);
+}
+
+static gboolean
+do_snapshot (gpointer data)
+{
+  GtkWidget *widget = data;
+  GdkPaintable *paintable;
+
+  paintable = gtk_widget_paintable_new (widget);
+  g_signal_connect (paintable, "invalidate-contents", G_CALLBACK (draw_paintable), NULL);
+
+  gtk_widget_queue_draw (widget);
 
-  gtk_widget_set_sensitive (content, allowed);
+  return G_SOURCE_REMOVE;
+}
+
+static void
+screenshot_clicked (GtkButton *button,
+                    GtkWidget *widget)
+{
+  g_assert_true (gtk_widget_get_realized (widget));
+
+  gtk_widget_grab_focus (GTK_WIDGET (gtk_widget_get_root (widget)));
+
+  g_idle_add (do_snapshot, gtk_widget_get_root (widget));
 }
 
 int
@@ -219,7 +309,10 @@ main (int argc, char *argv[])
   GtkWidget *button;
   GtkWidget *box;
   GtkWidget *update;
+  GtkWidget *screenshot;
   GPermission *permission;
+  GtkBuilder *builder;
+  GtkCssProvider *provider;
 
   gtk_init ();
 
@@ -241,27 +334,28 @@ main (int argc, char *argv[])
   gtk_box_append (GTK_BOX (box), success_button);
   update = gtk_button_new_with_label ("Update");
   gtk_box_append (GTK_BOX (box), update);
+  screenshot = gtk_button_new_with_label ("Screenshot");
+  gtk_box_append (GTK_BOX (box), screenshot);
   g_signal_connect (permission, "notify",
                     G_CALLBACK (permission_changed), NULL);
 
-  button = gtk_lock_button_new (permission);
+  builder = gtk_builder_new_from_file (argv[1]);
 
-  g_signal_connect (update, "clicked",
-                    G_CALLBACK (update_clicked), button);
+  provider = gtk_css_provider_new ();
+  gtk_css_provider_load_from_path (provider, argv[2]);
 
-  dialog = gtk_dialog_new_with_buttons ("Dialog", NULL, 0,
-                                        "Close", GTK_RESPONSE_CLOSE,
-                                        "Some other action", GTK_RESPONSE_APPLY,
-                                        NULL);
-  gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+  gtk_style_context_add_provider_for_display (gdk_display_get_default (), GTK_STYLE_PROVIDER (provider), GTK_STYLE_PROVIDER_PRIORITY_USER);
 
-  content = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
-  gtk_box_append (GTK_BOX (content), gtk_check_button_new_with_label ("Control 1"));
-  gtk_box_append (GTK_BOX (content), gtk_check_button_new_with_label ("Control 2"));
-  gtk_widget_set_sensitive (content, FALSE);
+  button = GTK_WIDGET (gtk_builder_get_object (builder, "lockbutton"));
+  gtk_lock_button_set_permission (GTK_LOCK_BUTTON (button), permission);
 
-  gtk_box_append (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), content);
-  gtk_box_append (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), button);
+  dialog = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
+  gtk_widget_add_css_class (dialog, "nobackground");
+
+  g_signal_connect (update, "clicked",
+                    G_CALLBACK (update_clicked), button);
+  g_signal_connect (screenshot, "clicked",
+                    G_CALLBACK (screenshot_clicked), button);
 
   gtk_window_present (GTK_WINDOW (window));
   gtk_window_present (GTK_WINDOW (dialog));
diff --git a/testsuite/gtk/ui/test8.expected b/testsuite/gtk/ui/test8.expected
new file mode 100644
index 0000000000000000000000000000000000000000..ff43ca409150a5479415981803955ee1d40e4d16
--- /dev/null
+++ b/testsuite/gtk/ui/test8.expected
@@ -0,0 +1 @@
+SUCCESS
diff --git a/testsuite/gtk/ui/test8.ui b/testsuite/gtk/ui/test8.ui
new file mode 100644
index 0000000000000000000000000000000000000000..a704d80211201d176b6ed51f4315a822953e0d4e
--- /dev/null
+++ b/testsuite/gtk/ui/test8.ui
@@ -0,0 +1,35 @@
+<interface>
+  <menu id="menubar">
+    <submenu>
+      <attribute name="label" translatable="yes">_File</attribute>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_New</attribute>
+          <attribute name="action">app.new</attribute>
+          <attribute name="accel">&lt;Control&gt;n</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Open</attribute>
+          <attribute name="action">app.open</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">_Save</attribute>
+          <attribute name="action">app.save</attribute>
+          <attribute name="accel">&lt;Control&gt;s</attribute>
+        </item>
+        <item>
+          <attribute name="label" translatable="yes">Save _As...</attribute>
+          <attribute name="action">app.save-as</attribute>
+          <attribute name="accel">&lt;Control&gt;&lt;Shift&gt;s</attribute>
+        </item>
+      </section>
+      <section>
+        <item>
+          <attribute name="label" translatable="yes">_Quit</attribute>
+          <attribute name="action">app.quit</attribute>
+          <attribute name="accel">&lt;Control&gt;q</attribute>
+        </item>
+      </section>
+    </submenu>
+  </menu>
+</interface>
diff --git a/testsuite/gtk/ui/test9.expected b/testsuite/gtk/ui/test9.expected
new file mode 100644
index 0000000000000000000000000000000000000000..ff43ca409150a5479415981803955ee1d40e4d16
--- /dev/null
+++ b/testsuite/gtk/ui/test9.expected
@@ -0,0 +1 @@
+SUCCESS
diff --git a/testsuite/gtk/ui/test9.ui b/testsuite/gtk/ui/test9.ui
new file mode 100644
index 0000000000000000000000000000000000000000..404624aab55bf4d6f10f573accc9b4c1754c2eac
--- /dev/null
+++ b/testsuite/gtk/ui/test9.ui
@@ -0,0 +1,39 @@
+<interface>
+  <object class="GtkLabel">
+    <property name="extra-menu">
+      <menu id="menubar">
+        <submenu>
+          <attribute name="label" translatable="yes">_File</attribute>
+          <section>
+            <item>
+              <attribute name="label" translatable="yes">_New</attribute>
+              <attribute name="action">app.new</attribute>
+              <attribute name="accel">&lt;Control&gt;n</attribute>
+            </item>
+            <item>
+              <attribute name="label" translatable="yes">_Open</attribute>
+              <attribute name="action">app.open</attribute>
+            </item>
+            <item>
+              <attribute name="label" translatable="yes">_Save</attribute>
+              <attribute name="action">app.save</attribute>
+              <attribute name="accel">&lt;Control&gt;s</attribute>
+            </item>
+            <item>
+              <attribute name="label" translatable="yes">Save _As...</attribute>
+              <attribute name="action">app.save-as</attribute>
+              <attribute name="accel">&lt;Control&gt;&lt;Shift&gt;s</attribute>
+            </item>
+          </section>
+          <section>
+            <item>
+              <attribute name="label" translatable="yes">_Quit</attribute>
+              <attribute name="action">app.quit</attribute>
+              <attribute name="accel">&lt;Control&gt;q</attribute>
+            </item>
+          </section>
+        </submenu>
+      </menu>
+    </property>
+  </object>
+</interface>
diff --git a/tools/gtk4builder.rng b/tools/gtk4builder.rng
index 8e1973fc0aa59ef15e6d5d8a6101c4baf6408730..28a4b17290cdaead103248a2a7f2cf3a18324318 100644
--- a/tools/gtk4builder.rng
+++ b/tools/gtk4builder.rng
@@ -122,6 +122,7 @@
         <ref name="constant"/>
         <ref name="lookup"/>
         <ref name="closure"/>
+        <ref name="menu"/>
       </choice>
     </element>
   </define>
@@ -178,9 +179,11 @@
   </define>
   <define name="menu">
     <element name="menu">
-      <attribute name="id">
-        <data type="ID" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"/>
-      </attribute>
+      <optional>
+        <attribute name="id">
+          <data type="ID" datatypeLibrary="http://www.w3.org/2001/XMLSchema-datatypes"/>
+        </attribute>
+      </optional>
       <optional>
         <attribute name="domain">
           <text/>