diff --git a/gdk/wayland/gdkwaylandwindow.h b/gdk/wayland/gdkwaylandwindow.h
index f0fb552..3121c9e 100644
--- a/gdk/wayland/gdkwaylandwindow.h
+++ b/gdk/wayland/gdkwaylandwindow.h
@@ -47,6 +47,8 @@ GType                    gdk_wayland_window_get_type             (void);
 struct wl_surface       *gdk_wayland_window_get_wl_surface       (GdkWindow *window);
 struct wl_shell_surface *gdk_wayland_window_get_wl_shell_surface (GdkWindow *window);
 
+void                     gdk_wayland_window_set_custom           (GdkWindow *window);
+
 G_END_DECLS
 
 #endif /* __GDK_WAYLAND_WINDOW_H__ */
diff --git a/gdk/wayland/gdkwindow-wayland.c b/gdk/wayland/gdkwindow-wayland.c
index 407f930..3ed9da9 100644
--- a/gdk/wayland/gdkwindow-wayland.c
+++ b/gdk/wayland/gdkwindow-wayland.c
@@ -135,6 +135,8 @@ struct _GdkWindowImplWayland
 
   gboolean fullscreen;
   int saved_width, saved_height; /* before going fullscreen */
+
+  gboolean custom;
 };
 
 struct _GdkWindowImplWaylandClass
@@ -263,11 +265,16 @@ _gdk_wayland_display_create_window_impl (GdkDisplay    *display,
 {
   GdkWindowImplWayland *impl;
   const char *title;
+  GdkWaylandDisplay *display_wayland =
+    GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
 
   impl = g_object_new (GDK_TYPE_WINDOW_IMPL_WAYLAND, NULL);
   window->impl = GDK_WINDOW_IMPL (impl);
   impl->wrapper = GDK_WINDOW (window);
 
+  impl->surface = wl_compositor_create_surface(display_wayland->compositor);
+  wl_surface_set_user_data(impl->surface, window);
+
   if (window->width > 65535 ||
       window->height > 65535)
     {
@@ -568,7 +575,7 @@ gdk_wayland_window_map (GdkWindow *window)
   GdkWaylandDisplay *wayland_display =
     GDK_WAYLAND_DISPLAY (gdk_window_get_display (window));
 
-  if (!impl->mapped)
+  if (!impl->mapped && impl->shell_surface)
     {
       if (impl->transient_for)
         {
@@ -680,13 +687,20 @@ gdk_wayland_window_show (GdkWindow *window, gboolean already_mapped)
       XSERVER_TIME_IS_LATER (display_wayland->user_time, impl->user_time))
     gdk_wayland_window_set_user_time (window, impl->user_time);
 
-  impl->surface = wl_compositor_create_surface(display_wayland->compositor);
-  wl_surface_set_user_data(impl->surface, window);
+  if (!impl->surface)
+    {
+      impl->surface =
+        wl_compositor_create_surface(display_wayland->compositor);
+      wl_surface_set_user_data(impl->surface, window);
+    }
 
-  impl->shell_surface = wl_shell_get_shell_surface (display_wayland->shell,
-                                                    impl->surface);
-  wl_shell_surface_add_listener(impl->shell_surface,
-                                &shell_surface_listener, window);
+  if (!impl->custom)
+    {
+      impl->shell_surface = wl_shell_get_shell_surface (display_wayland->shell,
+                                                        impl->surface);
+      wl_shell_surface_add_listener(impl->shell_surface,
+                                    &shell_surface_listener, window);
+    }
 
   gdk_window_set_type_hint (window, impl->hint);  
 
@@ -1279,6 +1293,9 @@ gdk_wayland_window_fullscreen (GdkWindow *window)
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
+  if (!impl->shell_surface)
+    return;
+
   if (impl->fullscreen)
     return;
 
@@ -1302,6 +1319,9 @@ gdk_wayland_window_unfullscreen (GdkWindow *window)
   if (GDK_WINDOW_DESTROYED (window))
     return;
 
+  if (!impl->shell_surface) /* Warn? */
+    return;
+
   if (!impl->fullscreen)
     return;
 
@@ -1432,6 +1452,9 @@ gdk_wayland_window_begin_resize_drag (GdkWindow     *window,
 
   impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
 
+  if (!impl->shell_surface) /* Warn? */
+    return;
+
   wl_shell_surface_resize (impl->shell_surface,
                            gdk_wayland_device_get_wl_seat (device),
                            _gdk_wayland_display_get_serial (wayland_display),
@@ -1461,6 +1484,9 @@ gdk_wayland_window_begin_move_drag (GdkWindow *window,
 
   impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
 
+  if (!impl->shell_surface) /* Warn? */
+    return;
+
   wl_shell_surface_move (impl->shell_surface,
                          gdk_wayland_device_get_wl_seat (device),
                          _gdk_wayland_display_get_serial (wayland_display));
@@ -1745,3 +1771,33 @@ gdk_wayland_window_get_wl_shell_surface (GdkWindow *window)
 
   return impl->shell_surface;
 }
+
+/**
+ * gdk_wayland_window_set_custom
+ * @window: (type GdkWaylandWindow): a #GdkWindow
+ *
+ * Marks a GdkWindow as a custom Wayland surface.  The application is
+ * expected to register the surface as another type of surface using
+ * some other Wayland interface.
+ *
+ * Must be called before the initial showing of the window.
+ *
+ * Since: 3.8
+ */
+void
+gdk_wayland_window_set_custom (GdkWindow *window)
+{
+  GdkWindowImplWayland *impl;
+
+  g_return_if_fail (GDK_IS_WAYLAND_WINDOW (window));
+
+  impl = GDK_WINDOW_IMPL_WAYLAND (window->impl);
+
+  if (impl->shell_surface)
+    {
+      g_warning ("Window is already a shell surface\n");
+      return;
+    }
+
+  impl->custom = TRUE;
+}
