SDL: wayland: Add the xdg-foreign-unstable-v2 protocol

From 19764ffcc811a498a508fe524a986455d25cf7e1 Mon Sep 17 00:00:00 2001
From: Frank Praznik <[EMAIL REDACTED]>
Date: Fri, 15 Mar 2024 11:36:05 -0400
Subject: [PATCH] wayland: Add the xdg-foreign-unstable-v2 protocol

Add the xdg-foreign-unstable-v2 protocol and use it to create export handles for toplevel windows, which will be used when an external component, such as the file chooser portal, requires it.
---
 include/SDL3/SDL_video.h                      |  57 ++---
 src/video/wayland/SDL_waylandvideo.c          |   8 +
 src/video/wayland/SDL_waylandvideo.h          |   1 +
 src/video/wayland/SDL_waylandwindow.c         |  39 +++-
 src/video/wayland/SDL_waylandwindow.h         |   2 +
 wayland-protocols/xdg-foreign-unstable-v2.xml | 200 ++++++++++++++++++
 6 files changed, 279 insertions(+), 28 deletions(-)
 create mode 100644 wayland-protocols/xdg-foreign-unstable-v2.xml

diff --git a/include/SDL3/SDL_video.h b/include/SDL3/SDL_video.h
index fde2f56b56efc..eff00923dc64d 100644
--- a/include/SDL3/SDL_video.h
+++ b/include/SDL3/SDL_video.h
@@ -1111,6 +1111,8 @@ extern DECLSPEC SDL_Window *SDLCALL SDL_GetWindowParent(SDL_Window *window);
  *   with the window
  * - `SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER`: the xdg_toplevel role
  *   associated with the window
+ * - 'SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_EXPORT_HANDLE_POINTER': the export
+ *   handle associated with the window
  * - `SDL_PROP_WINDOW_WAYLAND_XDG_POPUP_POINTER`: the xdg_popup role
  *   associated with the window
  * - `SDL_PROP_WINDOW_WAYLAND_XDG_POSITIONER_POINTER`: the xdg_positioner
@@ -1136,33 +1138,34 @@ extern DECLSPEC SDL_Window *SDLCALL SDL_GetWindowParent(SDL_Window *window);
  */
 extern DECLSPEC SDL_PropertiesID SDLCALL SDL_GetWindowProperties(SDL_Window *window);
 
-#define SDL_PROP_WINDOW_SHAPE_POINTER                   "SDL.window.shape"
-#define SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER          "SDL.window.android.window"
-#define SDL_PROP_WINDOW_ANDROID_SURFACE_POINTER         "SDL.window.android.surface"
-#define SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER            "SDL.window.uikit.window"
-#define SDL_PROP_WINDOW_UIKIT_METAL_VIEW_TAG_NUMBER     "SDL.window.uikit.metal_view_tag"
-#define SDL_PROP_WINDOW_KMSDRM_DEVICE_INDEX_NUMBER      "SDL.window.kmsdrm.dev_index"
-#define SDL_PROP_WINDOW_KMSDRM_DRM_FD_NUMBER            "SDL.window.kmsdrm.drm_fd"
-#define SDL_PROP_WINDOW_KMSDRM_GBM_DEVICE_POINTER       "SDL.window.kmsdrm.gbm_dev"
-#define SDL_PROP_WINDOW_COCOA_WINDOW_POINTER            "SDL.window.cocoa.window"
-#define SDL_PROP_WINDOW_COCOA_METAL_VIEW_TAG_NUMBER     "SDL.window.cocoa.metal_view_tag"
-#define SDL_PROP_WINDOW_VIVANTE_DISPLAY_POINTER         "SDL.window.vivante.display"
-#define SDL_PROP_WINDOW_VIVANTE_WINDOW_POINTER          "SDL.window.vivante.window"
-#define SDL_PROP_WINDOW_VIVANTE_SURFACE_POINTER         "SDL.window.vivante.surface"
-#define SDL_PROP_WINDOW_WINRT_WINDOW_POINTER            "SDL.window.winrt.window"
-#define SDL_PROP_WINDOW_WIN32_HWND_POINTER              "SDL.window.win32.hwnd"
-#define SDL_PROP_WINDOW_WIN32_HDC_POINTER               "SDL.window.win32.hdc"
-#define SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER          "SDL.window.win32.instance"
-#define SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER         "SDL.window.wayland.display"
-#define SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER         "SDL.window.wayland.surface"
-#define SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER      "SDL.window.wayland.egl_window"
-#define SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER     "SDL.window.wayland.xdg_surface"
-#define SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER    "SDL.window.wayland.xdg_toplevel"
-#define SDL_PROP_WINDOW_WAYLAND_XDG_POPUP_POINTER       "SDL.window.wayland.xdg_popup"
-#define SDL_PROP_WINDOW_WAYLAND_XDG_POSITIONER_POINTER  "SDL.window.wayland.xdg_positioner"
-#define SDL_PROP_WINDOW_X11_DISPLAY_POINTER             "SDL.window.x11.display"
-#define SDL_PROP_WINDOW_X11_SCREEN_NUMBER               "SDL.window.x11.screen"
-#define SDL_PROP_WINDOW_X11_WINDOW_NUMBER               "SDL.window.x11.window"
+#define SDL_PROP_WINDOW_SHAPE_POINTER                              "SDL.window.shape"
+#define SDL_PROP_WINDOW_ANDROID_WINDOW_POINTER                     "SDL.window.android.window"
+#define SDL_PROP_WINDOW_ANDROID_SURFACE_POINTER                    "SDL.window.android.surface"
+#define SDL_PROP_WINDOW_UIKIT_WINDOW_POINTER                       "SDL.window.uikit.window"
+#define SDL_PROP_WINDOW_UIKIT_METAL_VIEW_TAG_NUMBER                "SDL.window.uikit.metal_view_tag"
+#define SDL_PROP_WINDOW_KMSDRM_DEVICE_INDEX_NUMBER                 "SDL.window.kmsdrm.dev_index"
+#define SDL_PROP_WINDOW_KMSDRM_DRM_FD_NUMBER                       "SDL.window.kmsdrm.drm_fd"
+#define SDL_PROP_WINDOW_KMSDRM_GBM_DEVICE_POINTER                  "SDL.window.kmsdrm.gbm_dev"
+#define SDL_PROP_WINDOW_COCOA_WINDOW_POINTER                       "SDL.window.cocoa.window"
+#define SDL_PROP_WINDOW_COCOA_METAL_VIEW_TAG_NUMBER                "SDL.window.cocoa.metal_view_tag"
+#define SDL_PROP_WINDOW_VIVANTE_DISPLAY_POINTER                    "SDL.window.vivante.display"
+#define SDL_PROP_WINDOW_VIVANTE_WINDOW_POINTER                     "SDL.window.vivante.window"
+#define SDL_PROP_WINDOW_VIVANTE_SURFACE_POINTER                    "SDL.window.vivante.surface"
+#define SDL_PROP_WINDOW_WINRT_WINDOW_POINTER                       "SDL.window.winrt.window"
+#define SDL_PROP_WINDOW_WIN32_HWND_POINTER                         "SDL.window.win32.hwnd"
+#define SDL_PROP_WINDOW_WIN32_HDC_POINTER                          "SDL.window.win32.hdc"
+#define SDL_PROP_WINDOW_WIN32_INSTANCE_POINTER                     "SDL.window.win32.instance"
+#define SDL_PROP_WINDOW_WAYLAND_DISPLAY_POINTER                    "SDL.window.wayland.display"
+#define SDL_PROP_WINDOW_WAYLAND_SURFACE_POINTER                    "SDL.window.wayland.surface"
+#define SDL_PROP_WINDOW_WAYLAND_EGL_WINDOW_POINTER                 "SDL.window.wayland.egl_window"
+#define SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER                "SDL.window.wayland.xdg_surface"
+#define SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER               "SDL.window.wayland.xdg_toplevel"
+#define SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_EXPORT_HANDLE_POINTER "SDL.window.wayland.xdg_toplevel_export_handle"
+#define SDL_PROP_WINDOW_WAYLAND_XDG_POPUP_POINTER                  "SDL.window.wayland.xdg_popup"
+#define SDL_PROP_WINDOW_WAYLAND_XDG_POSITIONER_POINTER             "SDL.window.wayland.xdg_positioner"
+#define SDL_PROP_WINDOW_X11_DISPLAY_POINTER                        "SDL.window.x11.display"
+#define SDL_PROP_WINDOW_X11_SCREEN_NUMBER                          "SDL.window.x11.screen"
+#define SDL_PROP_WINDOW_X11_WINDOW_NUMBER                          "SDL.window.x11.window"
 
 /**
  * Get the window flags.
diff --git a/src/video/wayland/SDL_waylandvideo.c b/src/video/wayland/SDL_waylandvideo.c
index 2054471eb561c..4b372efecd6da 100644
--- a/src/video/wayland/SDL_waylandvideo.c
+++ b/src/video/wayland/SDL_waylandvideo.c
@@ -57,6 +57,7 @@
 #include "viewporter-client-protocol.h"
 #include "xdg-activation-v1-client-protocol.h"
 #include "xdg-decoration-unstable-v1-client-protocol.h"
+#include "xdg-foreign-unstable-v2-client-protocol.h"
 #include "xdg-output-unstable-v1-client-protocol.h"
 #include "xdg-shell-client-protocol.h"
 
@@ -1078,6 +1079,8 @@ static void display_handle_global(void *data, struct wl_registry *registry, uint
         if (d->input) {
             Wayland_CreateCursorShapeDevice(d->input);
         }
+    } else if (SDL_strcmp(interface, "zxdg_exporter_v2") == 0) {
+        d->zxdg_exporter_v2 = wl_registry_bind(d->registry, id, &zxdg_exporter_v2_interface, 1);
     } else if (SDL_strcmp(interface, "kde_output_order_v1") == 0) {
         d->kde_output_order = wl_registry_bind(d->registry, id, &kde_output_order_v1_interface, 1);
         kde_output_order_v1_add_listener(d->kde_output_order, &kde_output_order_listener, d);
@@ -1331,6 +1334,11 @@ static void Wayland_VideoCleanup(SDL_VideoDevice *_this)
         data->cursor_shape_manager = NULL;
     }
 
+    if (data->zxdg_exporter_v2) {
+        zxdg_exporter_v2_destroy(data->zxdg_exporter_v2);
+        data->zxdg_exporter_v2 = NULL;
+    }
+
     if (data->kde_output_order) {
         Wayland_FlushOutputOrder(data);
         kde_output_order_v1_destroy(data->kde_output_order);
diff --git a/src/video/wayland/SDL_waylandvideo.h b/src/video/wayland/SDL_waylandvideo.h
index 874a33ae80dc8..c6ee45788f7f6 100644
--- a/src/video/wayland/SDL_waylandvideo.h
+++ b/src/video/wayland/SDL_waylandvideo.h
@@ -79,6 +79,7 @@ struct SDL_VideoData
     struct wp_viewporter *viewporter;
     struct wp_fractional_scale_manager_v1 *fractional_scale_manager;
     struct zwp_input_timestamps_manager_v1 *input_timestamps_manager;
+    struct zxdg_exporter_v2 *zxdg_exporter_v2;
     struct kde_output_order_v1 *kde_output_order;
 
     struct xkb_context *xkb_context;
diff --git a/src/video/wayland/SDL_waylandwindow.c b/src/video/wayland/SDL_waylandwindow.c
index e211a7b1fa0c1..dfc203ffed004 100644
--- a/src/video/wayland/SDL_waylandwindow.c
+++ b/src/video/wayland/SDL_waylandwindow.c
@@ -38,6 +38,7 @@
 #include "xdg-activation-v1-client-protocol.h"
 #include "viewporter-client-protocol.h"
 #include "fractional-scale-v1-client-protocol.h"
+#include "xdg-foreign-unstable-v2-client-protocol.h"
 
 #ifdef HAVE_LIBDECOR_H
 #include <libdecor.h>
@@ -1484,6 +1485,21 @@ static struct wl_callback_listener show_hide_sync_listener = {
     show_hide_sync_handler
 };
 
+static void exported_handle_handler(void *data, struct zxdg_exported_v2 *zxdg_exported_v2, const char *handle)
+{
+    SDL_WindowData *wind = (SDL_WindowData*)data;
+    SDL_PropertiesID props = SDL_GetWindowProperties(wind->sdlwindow);
+
+    SDL_free(wind->export_handle);
+    wind->export_handle = SDL_strdup(handle);
+
+    SDL_SetProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_EXPORT_HANDLE_POINTER, wind->export_handle);
+}
+
+static struct zxdg_exported_v2_listener exported_v2_listener = {
+    exported_handle_handler
+};
+
 void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
 {
     SDL_VideoData *c = _this->driverdata;
@@ -1549,6 +1565,11 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
             libdecor_frame_set_app_id(data->shell_surface.libdecor.frame, data->app_id);
             libdecor_frame_map(data->shell_surface.libdecor.frame);
 
+            if (c->zxdg_exporter_v2) {
+                data->exported = zxdg_exporter_v2_export_toplevel(c->zxdg_exporter_v2, data->surface);
+                zxdg_exported_v2_add_listener(data->exported, &exported_v2_listener, data);
+            }
+
             SDL_SetProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_SURFACE_POINTER, libdecor_frame_get_xdg_surface(data->shell_surface.libdecor.frame));
             SDL_SetProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, libdecor_frame_get_xdg_toplevel(data->shell_surface.libdecor.frame));
         }
@@ -1623,6 +1644,12 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
             data->shell_surface.xdg.roleobj.toplevel = xdg_surface_get_toplevel(data->shell_surface.xdg.surface);
             xdg_toplevel_set_app_id(data->shell_surface.xdg.roleobj.toplevel, data->app_id);
             xdg_toplevel_add_listener(data->shell_surface.xdg.roleobj.toplevel, &toplevel_listener_xdg, data);
+
+            if (c->zxdg_exporter_v2) {
+                data->exported = zxdg_exporter_v2_export_toplevel(c->zxdg_exporter_v2, data->surface);
+                zxdg_exported_v2_add_listener(data->exported, &exported_v2_listener, data);
+            }
+
             SDL_SetProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_POINTER, data->shell_surface.xdg.roleobj.toplevel);
         }
     }
@@ -1699,7 +1726,6 @@ void Wayland_ShowWindow(SDL_VideoDevice *_this, SDL_Window *window)
     Wayland_SetWindowResizable(_this, window, !!(window->flags & SDL_WINDOW_RESIZABLE));
     Wayland_SetWindowBordered(_this, window, !(window->flags & SDL_WINDOW_BORDERLESS));
 
-
     /* We're finally done putting the window together, raise if possible */
     if (c->activation_manager) {
         /* Note that we don't check for empty strings, as that is still
@@ -1798,6 +1824,17 @@ void Wayland_HideWindow(SDL_VideoDevice *_this, SDL_Window *window)
         wl_surface_commit(wind->surface);
     }
 
+    /* Clean up the export handle. */
+    if (wind->exported) {
+        zxdg_exported_v2_destroy(wind->exported);
+        wind->exported = NULL;
+
+        SDL_free(wind->export_handle);
+        wind->export_handle = NULL;
+
+        SDL_SetProperty(props, SDL_PROP_WINDOW_WAYLAND_XDG_TOPLEVEL_EXPORT_HANDLE_POINTER, NULL);
+    }
+
 #ifdef HAVE_LIBDECOR_H
     if (wind->shell_surface_type == WAYLAND_SURFACE_LIBDECOR) {
         if (wind->shell_surface.libdecor.frame) {
diff --git a/src/video/wayland/SDL_waylandwindow.h b/src/video/wayland/SDL_waylandwindow.h
index afd348c2085d5..5900122b875bc 100644
--- a/src/video/wayland/SDL_waylandwindow.h
+++ b/src/video/wayland/SDL_waylandwindow.h
@@ -95,6 +95,7 @@ struct SDL_WindowData
     struct xdg_activation_token_v1 *activation_token;
     struct wp_viewport *viewport;
     struct wp_fractional_scale_v1 *fractional_scale;
+    struct zxdg_exported_v2 *exported;
 
     SDL_AtomicInt swap_interval_ready;
 
@@ -104,6 +105,7 @@ struct SDL_WindowData
     SDL_Window *keyboard_focus;
 
     char *app_id;
+    char *export_handle;
     float windowed_scale_factor;
 
     struct
diff --git a/wayland-protocols/xdg-foreign-unstable-v2.xml b/wayland-protocols/xdg-foreign-unstable-v2.xml
new file mode 100644
index 0000000000000..cc3271dca4d62
--- /dev/null
+++ b/wayland-protocols/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>