Repository: gtk-rs/gtk3-rs (language: rust)

Issue:
gdk wayland interaction
Is it possible to use the functions from `gdkwayland.h`?
Specifically i would like to use `gdk_wayland_window_get_wl_surface()` and `gdk_wayland_window_set_use_custom_surface()`.



Discussion / hints:
I also need access to ``gdkwayland.h`` functions and I don't know if I overlooked something or they just don't exist.
I looked for functions from ''gdkwayland.h'' in [gtk-sys](https://github.com/gtk-rs/sys) and [gir-files](https://github.com/gtk-rs/gir-files) and it looks like they are not there.

I also looked for ''.gir'' files for ``gdkwayland`` in Debian and Arch repos, but I can only find ''Gdk-3.0.gir'' and ''GdkX11-3.0.gir''.
I'm confused...
For GTK4 this exists now: https://github.com/gtk-rs/gtk4-rs/tree/master/gdk4-wayland
I wrote a very small part of gdk3-wayland manually for a crate I'm working on and I was wondering what would be the best way to upstream it here.

I'm thinking of adding the ffi types to gdk-sys's manual.rs & have a feature flag for enabling the gdk-wayland bindings without an extra separate crate. I only have the `gdk_wayland_window_unexport_handle` & `gdk_wayland_window_export_handle` parts, more could be added manually in the future by interested people.

Sounds like a good idea to bind them manually.
This can be closed then? @GuillaumeGomez @bilelmoussaoui 
No, a lot of items are still missing. I'll add them later.

Fix patch:
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index acc3ca0cdb4b..488df4c8aa53 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -20,8 +20,9 @@ jobs:
           - "1.56.0"
         conf:
           - { name: "atk", features: "v2_34", test_sys: true }
-          - { name: "gdk", features: "v3_24,wayland", test_sys: true }
+          - { name: "gdk", features: "v3_24", test_sys: true }
           - { name: "gdkx11", features: "v3_24", test_sys: true }
+          - { name: "gdkwayland", features: "v3_24", test_sys: false }
           - { name: "gtk", features: "v3_24_9", test_sys: false }
     steps:
       - uses: actions/checkout@v2
@@ -42,13 +43,13 @@ jobs:
         if: matrix.rust == 'nightly'
       - run: cargo run --release -- ../${{matrix.conf.name}}
         working-directory: checker
-        if: matrix.rust == 'nightly'
+        if: matrix.rust == 'nightly' && matrix.conf.name != 'gdkwayland'
       - run: cargo run --release -- --no-license ../${{matrix.conf.name}}/sys
         working-directory: checker
-        if: matrix.rust == 'nightly'
+        if: matrix.rust == 'nightly' && matrix.conf.name != 'gdkwayland'
       - run: ./check_init_asserts ../${{matrix.conf.name}}
         working-directory: checker
-        if: matrix.rust == 'nightly'
+        if: matrix.rust == 'nightly' && matrix.conf.name != 'gdkwayland'
       - name: Check doc aliases
         run: |
           python3 doc_aliases.py ../${{matrix.conf.name}}
diff --git a/Cargo.toml b/Cargo.toml
index 61ec1c3f4a0d..75b2d58e0ca2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,9 +1,22 @@
 [workspace]
+default-members = [
+  "atk",
+  "atk/sys",
+  "gdk",
+  "gdk/sys",
+  "gtk",
+  "gtk/sys",
+  "gtk3-macros",
+  "examples",
+]
+
 members = [
   "atk",
   "atk/sys",
   "gdk",
   "gdk/sys",
+  "gdkwayland",
+  "gdkwayland/sys",
   "gdkx11",
   "gdkx11/sys",
   "gtk",
diff --git a/gdk/Cargo.toml b/gdk/Cargo.toml
index 8ee06ed9440d..5859cf77fe11 100644
--- a/gdk/Cargo.toml
+++ b/gdk/Cargo.toml
@@ -23,8 +23,7 @@ name = "gdk"
 v3_20 = ["ffi/v3_20"]
 v3_22 = ["v3_20", "ffi/v3_22"]
 v3_24 = ["v3_22", "ffi/v3_24"]
-dox = ["ffi/dox", "glib/dox", "gio/dox", "gdk-pixbuf/dox", "cairo-rs/dox", "pango/dox", "wayland"]
-wayland = ["ffi/wayland"]
+dox = ["ffi/dox", "glib/dox", "gio/dox", "gdk-pixbuf/dox", "cairo-rs/dox", "pango/dox"]
 
 [package.metadata.docs.rs]
 features = ["dox"]
diff --git a/gdk/src/lib.rs b/gdk/src/lib.rs
index 30c9751c85bd..f25eac2bad82 100644
--- a/gdk/src/lib.rs
+++ b/gdk/src/lib.rs
@@ -24,9 +24,6 @@ mod auto;
 
 pub mod prelude;
 
-#[cfg(feature = "wayland")]
-pub mod wayland;
-
 pub use self::auto::functions::*;
 pub use crate::auto::*;
 
diff --git a/gdk/src/wayland/mod.rs b/gdk/src/wayland/mod.rs
deleted file mode 100644
index b98333f79160..000000000000
--- a/gdk/src/wayland/mod.rs
+++ /dev/null
@@ -1,4 +0,0 @@
-// Take a look at the license at the top of the repository in the LICENSE file.
-
-mod wayland_window;
-pub use wayland_window::WaylandWindow;
diff --git a/gdk/sys/Cargo.toml b/gdk/sys/Cargo.toml
index d0287a85c4e5..197a5dc5b34f 100644
--- a/gdk/sys/Cargo.toml
+++ b/gdk/sys/Cargo.toml
@@ -32,7 +32,6 @@ v3_20 = []
 v3_22 = ["v3_20"]
 v3_24 = ["v3_22"]
 dox = []
-wayland = []
 
 [lib]
 name = "gdk_sys"
diff --git a/gdk/sys/src/lib.rs b/gdk/sys/src/lib.rs
index 42e9387dc166..14e91d78e358 100644
--- a/gdk/sys/src/lib.rs
+++ b/gdk/sys/src/lib.rs
@@ -18,10 +18,6 @@ use glib_sys as glib;
 use gobject_sys as gobject;
 use pango_sys as pango;
 
-mod manual;
-
-pub use manual::*;
-
 #[allow(unused_imports)]
 use libc::{
     c_char, c_double, c_float, c_int, c_long, c_short, c_uchar, c_uint, c_ulong, c_ushort, c_void,
diff --git a/gdk/sys/src/manual.rs b/gdk/sys/src/manual.rs
deleted file mode 100644
index b2aba6b232c0..000000000000
--- a/gdk/sys/src/manual.rs
+++ /dev/null
@@ -1,80 +0,0 @@
-#[cfg(any(feature = "wayland", feature = "dox"))]
-use glib_sys::{gconstpointer, GType};
-#[cfg(any(feature = "wayland", feature = "dox"))]
-use libc::{c_char, c_void};
-
-#[repr(C)]
-#[cfg(any(feature = "wayland", feature = "dox"))]
-pub struct GdkWaylandWindow(c_void);
-
-#[cfg(any(feature = "wayland", feature = "dox"))]
-extern "C" {
-
-    //=========================================================================
-    // GdkWaylandWindow
-    //=========================================================================
-    pub fn gdk_wayland_window_get_type() -> GType;
-
-    pub fn gdk_wayland_window_set_use_custom_surface(window: *mut GdkWaylandWindow);
-
-    pub fn gdk_wayland_window_get_wl_surface(window: *mut GdkWaylandWindow) -> gconstpointer;
-
-    pub fn gdk_wayland_window_set_dbus_properties_libgtk_only(
-        window: *mut GdkWaylandWindow,
-        application_id: *const c_char,
-        app_menu_path: *const c_char,
-        menubar_path: *const c_char,
-        window_object_path: *const c_char,
-        application_object_path: *const c_char,
-        unique_bus_name: *const c_char,
-    );
-
-    #[cfg(any(feature = "v3_22", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
-    pub fn gdk_wayland_window_unexport_handle(window: *mut GdkWaylandWindow);
-
-    #[cfg(any(feature = "v3_22", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
-    pub fn gdk_wayland_window_export_handle(
-        window: *mut GdkWaylandWindow,
-        cb: Option<unsafe extern "C" fn(*mut GdkWaylandWindow, *const c_char, *mut c_void)>,
-        user_data: *mut c_void,
-        destroy_notify: Option<unsafe extern "C" fn(*mut c_void)>,
-    ) -> glib_sys::gboolean;
-
-    #[cfg(any(feature = "v3_22", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
-    pub fn gdk_wayland_window_set_transient_for_exported(
-        window: *mut GdkWaylandWindow,
-        parent_handle: *const c_char,
-    ) -> glib_sys::gboolean;
-
-    #[cfg(any(feature = "v3_24", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_24")))]
-    pub fn gdk_wayland_window_set_application_id(
-        window: *mut GdkWaylandWindow,
-        application_id: *const c_char,
-    ) -> glib_sys::gboolean;
-
-    #[cfg(any(feature = "v3_22", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
-    pub fn gdk_wayland_window_announce_csd(window: *mut GdkWaylandWindow);
-
-    #[cfg(any(feature = "v3_24", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_24")))]
-    pub fn gdk_wayland_window_announce_ssd(window: *mut GdkWaylandWindow);
-
-    #[cfg(any(feature = "v3_24", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_24")))]
-    pub fn gdk_wayland_window_add_frame_callback_surface(
-        window: *mut GdkWaylandWindow,
-        surface: gconstpointer,
-    );
-
-    #[cfg(any(feature = "v3_24", feature = "dox"))]
-    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_24")))]
-    pub fn gdk_wayland_window_remove_frame_callback_surface(
-        window: *mut GdkWaylandWindow,
-        surface: gconstpointer,
-    );
-}
diff --git a/gdkwayland/Cargo.toml b/gdkwayland/Cargo.toml
new file mode 100644
index 000000000000..d12df7d00929
--- /dev/null
+++ b/gdkwayland/Cargo.toml
@@ -0,0 +1,33 @@
+[package]
+authors = ["The gtk-rs Project Developers"]
+description = "Rust bindings of the GDK-Wayland 3 library"
+documentation = "https://gtk-rs.org/gtk3-rs/stable/latest/docs/gdk_wayland/"
+edition = "2021"
+homepage = "https://gtk-rs.org/"
+keywords = ["gdk", "gdk-wayland", "gtk-rs", "gnome", "GUI"]
+license = "MIT"
+name = "gdkwayland"
+readme = "README.md"
+repository = "https://github.com/gtk-rs/gtk3-rs"
+include = ["../LICENSE"]
+version = "0.15.0"
+rust-version = "1.56"
+
+[features]
+v3_20 = ["ffi/v3_20", "gdk/v3_20"]
+v3_22 = ["v3_20", "ffi/v3_22", "gdk/v3_22"]
+v3_24 = ["v3_22", "ffi/v3_24", "gdk/v3_24"]
+dox = ["ffi/dox"]
+
+[package.metadata.docs.rs]
+features = ["dox"]
+
+[dependencies]
+ffi = { path = "./sys", package = "gdkwayland-sys" }
+gdk = { path = "../gdk" }
+glib = { git = "https://github.com/gtk-rs/gtk-rs-core" }
+libc = "0.2"
+wayland-client = {version = "0.29", features = ["use_system_lib"]}
+
+[dev-dependencies]
+gir-format-check = "^0.1"
diff --git a/gdkwayland/README.md b/gdkwayland/README.md
new file mode 100644
index 000000000000..b8dc6eab69fa
--- /dev/null
+++ b/gdkwayland/README.md
@@ -0,0 +1,52 @@
+# Rust GDK3-Wayland bindings
+
+Project site is [here](https://gtk-rs.org/).
+
+__Rust__ bindings and wrappers for [GDK3-Wayland](https://developer.gnome.org/gdk3/),
+part of [gtk3-rs](https://github.com/gtk-rs/gtk3-rs).
+
+GDK3-Wayland __3.18__ is the lowest supported version for the underlying library.
+
+## Minimum supported Rust version
+
+Currently, the minimum supported Rust version is `1.56.0`.
+
+## Documentation
+
+ * [Rust API - Stable](https://gtk-rs.org/gtk3-rs/stable/latest/docs/gdk-wayland/)
+ * [Rust API - Development](https://gtk-rs.org/gtk3-rs/git/docs/gdk-wayland)
+ * [C API](https://developer.gnome.org/gdk3/stable/)
+ * [GTK Installation instructions](https://www.gtk.org/docs/installations/)
+
+## Using
+
+We recommend using [crates from crates.io](https://crates.io/keywords/gtk-rs),
+as [demonstrated here](https://gtk-rs.org/#using).
+
+If you want to track the bleeding edge, use the git dependency instead:
+
+```toml
+[dependencies]
+gdk-wayland = { git = "https://github.com/gtk-rs/gtk3-rs.git", package = "gdk-wayland" }
+```
+
+Avoid mixing versioned and git crates like this:
+
+```toml
+# This will not compile
+[dependencies]
+gdk-wayland = "0.15"
+gdk-wayland = { git = "https://github.com/gtk-rs/gtk3-rs.git", package = "gdk-wayland" }
+```
+
+### See Also
+
+ * [glib](https://crates.io/crates/glib)
+ * [cairo-rs](https://crates.io/crates/cairo-rs)
+ * [gdk-pixbuf](https://crates.io/crates/gdk-pixbuf)
+ * [gio](https://crates.io/crates/gio)
+ * [pango](https://crates.io/crates/pango)
+
+## License
+
+__gdk_waylang__ is available under the MIT License, please refer to it.
diff --git a/gdkwayland/src/lib.rs b/gdkwayland/src/lib.rs
new file mode 100644
index 000000000000..9157a8d7b247
--- /dev/null
+++ b/gdkwayland/src/lib.rs
@@ -0,0 +1,29 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+#![doc = include_str!("../README.md")]
+
+pub use gdk;
+
+mod wayland_device;
+pub use wayland_device::WaylandDevice;
+
+mod wayland_display;
+pub use wayland_display::WaylandDisplay;
+
+mod wayland_gl_context;
+pub use wayland_gl_context::WaylandGLContext;
+
+#[cfg(any(feature = "v3_22", feature = "dox"))]
+mod wayland_monitor;
+#[cfg(any(feature = "v3_22", feature = "dox"))]
+#[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+pub use wayland_monitor::WaylandMonitor;
+
+#[cfg(any(feature = "v3_20", feature = "dox"))]
+mod wayland_seat;
+#[cfg(any(feature = "v3_20", feature = "dox"))]
+#[cfg_attr(feature = "dox", doc(cfg(feature = "v3_20")))]
+pub use wayland_seat::WaylandSeat;
+
+mod wayland_window;
+pub use wayland_window::WaylandWindow;
diff --git a/gdkwayland/src/wayland_device.rs b/gdkwayland/src/wayland_device.rs
new file mode 100644
index 000000000000..e2b80f802b14
--- /dev/null
+++ b/gdkwayland/src/wayland_device.rs
@@ -0,0 +1,61 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+#[cfg(any(feature = "v3_22", feature = "dox"))]
+use gdk::DevicePadFeature;
+use glib::translate::*;
+
+use wayland_client::protocol::{wl_keyboard::WlKeyboard, wl_pointer::WlPointer, wl_seat::WlSeat};
+use wayland_client::sys::client::wl_proxy;
+use wayland_client::Proxy;
+
+glib::wrapper! {
+    #[doc(alias = "GdkWaylandDevice")]
+    pub struct WaylandDevice(Object<ffi::GdkWaylandDevice>) @extends gdk::Device;
+
+    match fn {
+        type_ => || ffi::gdk_wayland_device_get_type(),
+    }
+}
+
+impl WaylandDevice {
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    #[doc(alias = "gdk_wayland_device_pad_set_feedback")]
+    pub fn pad_set_feedback(&self, element: DevicePadFeature, idx: usize, label: &str) {
+        unsafe {
+            ffi::gdk_wayland_device_pad_set_feedback(
+                self.to_glib_none().0,
+                element.into_glib(),
+                idx as _,
+                label.to_glib_none().0,
+            )
+        }
+    }
+
+    #[doc(alias = "gdk_wayland_device_get_wl_seat")]
+    #[doc(alias = "get_wl_seat")]
+    pub fn wl_seat(&self) -> WlSeat {
+        unsafe {
+            let ptr = ffi::gdk_wayland_device_get_wl_seat(self.to_glib_none().0);
+            Proxy::from_c_ptr(ptr as *mut wl_proxy).into()
+        }
+    }
+
+    #[doc(alias = "gdk_wayland_device_get_wl_keyboard")]
+    #[doc(alias = "get_wl_keyboard")]
+    pub fn wl_keyboard(&self) -> WlKeyboard {
+        unsafe {
+            let ptr = ffi::gdk_wayland_device_get_wl_keyboard(self.to_glib_none().0);
+            Proxy::from_c_ptr(ptr as *mut wl_proxy).into()
+        }
+    }
+
+    #[doc(alias = "gdk_wayland_device_get_wl_pointer")]
+    #[doc(alias = "get_wl_pointer")]
+    pub fn wl_pointer(&self) -> WlPointer {
+        unsafe {
+            let ptr = ffi::gdk_wayland_device_get_wl_pointer(self.to_glib_none().0);
+            Proxy::from_c_ptr(ptr as *mut wl_proxy).into()
+        }
+    }
+}
diff --git a/gdkwayland/src/wayland_display.rs b/gdkwayland/src/wayland_display.rs
new file mode 100644
index 000000000000..a8cb890625ba
--- /dev/null
+++ b/gdkwayland/src/wayland_display.rs
@@ -0,0 +1,78 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use glib::translate::*;
+
+use wayland_client::protocol::{wl_compositor::WlCompositor, wl_display::WlDisplay};
+use wayland_client::sys::client::wl_proxy;
+use wayland_client::Proxy;
+
+glib::wrapper! {
+    #[doc(alias = "GdkWaylandDisplay")]
+    pub struct WaylandDisplay(Object<ffi::GdkWaylandDisplay>) @extends gdk::Display;
+
+    match fn {
+        type_ => || ffi::gdk_wayland_display_get_type(),
+    }
+}
+
+impl WaylandDisplay {
+    #[doc(alias = "gdk_wayland_display_get_wl_compositor")]
+    #[doc(alias = "get_wl_compositor")]
+    pub fn wl_compositor(&self) -> WlCompositor {
+        unsafe {
+            let ptr = ffi::gdk_wayland_display_get_wl_compositor(self.to_glib_none().0);
+            Proxy::from_c_ptr(ptr as *mut wl_proxy).into()
+        }
+    }
+
+    #[doc(alias = "gdk_wayland_display_get_wl_display")]
+    #[doc(alias = "get_wl_display")]
+    pub fn wl_display(&self) -> WlDisplay {
+        unsafe {
+            let ptr = ffi::gdk_wayland_display_get_wl_display(self.to_glib_none().0);
+            Proxy::from_c_ptr(ptr as *mut wl_proxy).into()
+        }
+    }
+
+    #[doc(alias = "gdk_wayland_display_set_cursor_theme")]
+    pub fn set_cursor_theme(&self, theme: &str, size: isize) {
+        unsafe {
+            ffi::gdk_wayland_display_set_cursor_theme(
+                self.to_glib_none().0,
+                theme.to_glib_none().0,
+                size as _,
+            )
+        }
+    }
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    #[doc(alias = "gdk_wayland_display_set_startup_notification_id")]
+    pub fn set_startup_notification_id(&self, startup_id: &str) {
+        unsafe {
+            ffi::gdk_wayland_display_set_startup_notification_id(
+                self.to_glib_none().0,
+                startup_id.to_glib_none().0,
+            )
+        }
+    }
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    #[doc(alias = "gdk_wayland_display_prefers_ssd")]
+    pub fn prefers_ssd(&self) -> bool {
+        unsafe { from_glib(ffi::gdk_wayland_display_prefers_ssd(self.to_glib_none().0)) }
+    }
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    #[doc(alias = "gdk_wayland_display_query_registry")]
+    pub fn query_registry(&self, global: &str) -> bool {
+        unsafe {
+            from_glib(ffi::gdk_wayland_display_query_registry(
+                self.to_glib_none().0,
+                global.to_glib_none().0,
+            ))
+        }
+    }
+}
diff --git a/gdkwayland/src/wayland_gl_context.rs b/gdkwayland/src/wayland_gl_context.rs
new file mode 100644
index 000000000000..19f05ffac918
--- /dev/null
+++ b/gdkwayland/src/wayland_gl_context.rs
@@ -0,0 +1,10 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+glib::wrapper! {
+    #[doc(alias = "GdkWaylandGLContext")]
+    pub struct WaylandGLContext(Object<ffi::GdkWaylandGLContext>) @extends gdk::GLContext;
+
+    match fn {
+        type_ => || ffi::gdk_wayland_gl_context_get_type(),
+    }
+}
diff --git a/gdkwayland/src/wayland_monitor.rs b/gdkwayland/src/wayland_monitor.rs
new file mode 100644
index 000000000000..57a3f5131e8a
--- /dev/null
+++ b/gdkwayland/src/wayland_monitor.rs
@@ -0,0 +1,26 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use glib::translate::ToGlibPtr;
+use wayland_client::protocol::wl_output::WlOutput;
+use wayland_client::sys::client::wl_proxy;
+use wayland_client::Proxy;
+
+glib::wrapper! {
+    #[doc(alias = "GdkWaylandMonitor")]
+    pub struct WaylandMonitor(Object<ffi::GdkWaylandMonitor>) @extends gdk::Monitor;
+
+    match fn {
+        type_ => || ffi::gdk_wayland_monitor_get_type(),
+    }
+}
+
+impl WaylandMonitor {
+    #[doc(alias = "gdk_wayland_monitor_get_wl_output")]
+    #[doc(alias = "get_wl_output")]
+    pub fn wl_output(&self) -> WlOutput {
+        unsafe {
+            let ptr = ffi::gdk_wayland_monitor_get_wl_output(self.to_glib_none().0);
+            Proxy::from_c_ptr(ptr as *mut wl_proxy).into()
+        }
+    }
+}
diff --git a/gdkwayland/src/wayland_seat.rs b/gdkwayland/src/wayland_seat.rs
new file mode 100644
index 000000000000..713e632fd919
--- /dev/null
+++ b/gdkwayland/src/wayland_seat.rs
@@ -0,0 +1,26 @@
+// Take a look at the license at the top of the repository in the LICENSE file.
+
+use glib::translate::ToGlibPtr;
+use wayland_client::protocol::wl_seat::WlSeat;
+use wayland_client::sys::client::wl_proxy;
+use wayland_client::Proxy;
+
+glib::wrapper! {
+    #[doc(alias = "GdkWaylandSeat")]
+    pub struct WaylandSeat(Object<ffi::GdkWaylandSeat>) @extends gdk::Seat;
+
+    match fn {
+        type_ => || ffi::gdk_wayland_seat_get_type(),
+    }
+}
+
+impl WaylandSeat {
+    #[doc(alias = "gdk_wayland_seat_get_wl_seat")]
+    #[doc(alias = "get_wl_seat")]
+    pub fn wl_seat(&self) -> WlSeat {
+        unsafe {
+            let ptr = ffi::gdk_wayland_seat_get_wl_seat(self.to_glib_none().0);
+            Proxy::from_c_ptr(ptr as *mut wl_proxy).into()
+        }
+    }
+}
diff --git a/gdk/src/wayland/wayland_window.rs b/gdkwayland/src/wayland_window.rs
similarity index 91%
rename from gdk/src/wayland/wayland_window.rs
rename to gdkwayland/src/wayland_window.rs
index 3f514c0f24b6..8af4e6d2eb08 100644
--- a/gdk/src/wayland/wayland_window.rs
+++ b/gdkwayland/src/wayland_window.rs
@@ -1,10 +1,11 @@
 // Take a look at the license at the top of the repository in the LICENSE file.
 
+use gdk::Atom;
 use glib::translate::*;
 
 glib::wrapper! {
     #[doc(alias = "GdkWaylandWindow")]
-    pub struct WaylandWindow(Object<ffi::GdkWaylandWindow>) @extends crate::Window;
+    pub struct WaylandWindow(Object<ffi::GdkWaylandWindow>) @extends gdk::Window;
 
     match fn {
         type_ => || ffi::gdk_wayland_window_get_type(),
@@ -12,6 +13,18 @@ glib::wrapper! {
 }
 
 impl WaylandWindow {
+    #[doc(alias = "gdk_wayland_selection_add_targets")]
+    pub fn selection_add_targets(&self, selection: &Atom, targets: &[&Atom]) {
+        unsafe {
+            ffi::gdk_wayland_selection_add_targets(
+                self.to_glib_none().0,
+                selection.to_glib_none().0,
+                targets.len() as _,
+                targets.to_glib_none().0,
+            )
+        }
+    }
+
     #[doc(alias = "gdk_wayland_window_set_use_custom_surface")]
     pub fn set_use_custom_surface(&self) {
         unsafe { ffi::gdk_wayland_window_set_use_custom_surface(self.to_glib_none().0) }
diff --git a/gdkwayland/sys/Cargo.toml b/gdkwayland/sys/Cargo.toml
new file mode 100644
index 000000000000..bd57306335ba
--- /dev/null
+++ b/gdkwayland/sys/Cargo.toml
@@ -0,0 +1,40 @@
+[package]
+authors = ["The gtk-rs Project Developers"]
+description = "FFI bindings to libgdk-3-wayland"
+homepage = "http://gtk-rs.org/"
+keywords = ["gdk", "ffi", "gtk-rs", "gnome"]
+license = "MIT"
+name = "gdkwayland-sys"
+repository = "https://github.com/gtk-rs/gtk3-rs"
+version = "0.15.0"
+include = ["../../LICENSE"]
+edition = "2021"
+rust-version = "1.56"
+
+[lib]
+name = "gdk_wayland_sys"
+
+[features]
+v3_20 = ["gdk-sys/v3_20"]
+v3_22 = ["v3_20", "gdk-sys/v3_22"]
+v3_24 = ["v3_22", "gdk-sys/v3_24"]
+dox = ["gdk-sys/dox"]
+
+[dependencies]
+libc = "0.2"
+
+[dependencies.glib-sys]
+git = "https://github.com/gtk-rs/gtk-rs-core"
+
+[dependencies.gobject-sys]
+git = "https://github.com/gtk-rs/gtk-rs-core"
+
+[dependencies.gdk-sys]
+path = "../../gdk/sys"
+
+[build-dependencies]
+pkg-config = "0.3.7"
+system-deps = "5"
+
+[package.metadata.docs.rs]
+features = ["dox"]
diff --git a/gdkwayland/sys/src/lib.rs b/gdkwayland/sys/src/lib.rs
new file mode 100644
index 000000000000..4bda2cd6ff58
--- /dev/null
+++ b/gdkwayland/sys/src/lib.rs
@@ -0,0 +1,190 @@
+use gdk_sys::{GdkAtom, GdkDevicePadFeature};
+use glib_sys::{gpointer, GType};
+use libc::{c_char, c_int, c_uint};
+
+macro_rules! opaque {
+    ($(#[$attr:meta])*
+     $name:ident) => {
+        // https://doc.rust-lang.org/nomicon/ffi.html#representing-opaque-structs
+        $(#[$attr])*
+        #[repr(C)]
+        pub struct $name {
+            _data: [u8; 0],
+            _marker: core::marker::PhantomData<(*mut u8, core::marker::PhantomPinned)>,
+        }
+        $(#[$attr])*
+        impl ::std::fmt::Debug for $name {
+            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
+                write!(f, "{} @ {:?}", stringify!($name), self as *const _)
+            }
+        }
+    };
+}
+
+opaque!(GdkWaylandDevice);
+opaque!(GdkWaylandDisplay);
+opaque!(GdkWaylandGLContext);
+opaque!(
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    GdkWaylandMonitor
+);
+opaque!(GdkWaylandWindow);
+opaque!(GdkWaylandSeat);
+
+extern "C" {
+    //=========================================================================
+    // GdkWaylandWindow
+    //=========================================================================
+    pub fn gdk_wayland_window_get_type() -> GType;
+
+    pub fn gdk_wayland_window_get_wl_surface(window: *mut GdkWaylandWindow) -> gpointer;
+
+    pub fn gdk_wayland_window_set_use_custom_surface(window: *mut GdkWaylandWindow);
+
+    pub fn gdk_wayland_window_set_dbus_properties_libgtk_only(
+        window: *mut GdkWaylandWindow,
+        application_id: *const c_char,
+        app_menu_path: *const c_char,
+        menubar_path: *const c_char,
+        window_object_path: *const c_char,
+        application_object_path: *const c_char,
+        unique_bus_name: *const c_char,
+    );
+
+    pub fn gdk_wayland_selection_add_targets(
+        window: *mut GdkWaylandWindow,
+        selection: GdkAtom,
+        ntargets: c_uint,
+        targets: *mut GdkAtom,
+    );
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_window_unexport_handle(window: *mut GdkWaylandWindow);
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_window_export_handle(
+        window: *mut GdkWaylandWindow,
+        cb: Option<unsafe extern "C" fn(*mut GdkWaylandWindow, *const c_char, *mut libc::c_void)>,
+        user_data: *mut libc::c_void,
+        destroy_notify: Option<unsafe extern "C" fn(*mut libc::c_void)>,
+    ) -> glib_sys::gboolean;
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_window_set_transient_for_exported(
+        window: *mut GdkWaylandWindow,
+        parent_handle: *const c_char,
+    ) -> glib_sys::gboolean;
+
+    #[cfg(any(feature = "v3_24", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_24")))]
+    pub fn gdk_wayland_window_set_application_id(
+        window: *mut GdkWaylandWindow,
+        application_id: *const c_char,
+    ) -> glib_sys::gboolean;
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_window_announce_csd(window: *mut GdkWaylandWindow);
+
+    #[cfg(any(feature = "v3_24", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_24")))]
+    pub fn gdk_wayland_window_announce_ssd(window: *mut GdkWaylandWindow);
+
+    #[cfg(any(feature = "v3_24", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_24")))]
+    pub fn gdk_wayland_window_add_frame_callback_surface(
+        window: *mut GdkWaylandWindow,
+        surface: glib_sys::gconstpointer,
+    );
+
+    #[cfg(any(feature = "v3_24", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_24")))]
+    pub fn gdk_wayland_window_remove_frame_callback_surface(
+        window: *mut GdkWaylandWindow,
+        surface: glib_sys::gconstpointer,
+    );
+
+    //=========================================================================
+    // GdkWaylandDevice
+    //=========================================================================
+    pub fn gdk_wayland_device_get_type() -> GType;
+
+    pub fn gdk_wayland_device_get_wl_seat(device: *mut GdkWaylandDevice) -> gpointer;
+
+    pub fn gdk_wayland_device_get_wl_pointer(device: *mut GdkWaylandDevice) -> gpointer;
+
+    pub fn gdk_wayland_device_get_wl_keyboard(device: *mut GdkWaylandDevice) -> gpointer;
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_device_get_node_path(device: *mut GdkWaylandDevice) -> *const c_char;
+
+    pub fn gdk_wayland_device_pad_set_feedback(
+        device: *mut GdkWaylandDevice,
+        element: GdkDevicePadFeature,
+        idx: c_uint,
+        label: *const c_char,
+    );
+
+    //=========================================================================
+    // GdkWaylandDisplay
+    //=========================================================================
+    pub fn gdk_wayland_display_get_type() -> GType;
+
+    pub fn gdk_wayland_display_set_cursor_theme(
+        display: *mut GdkWaylandDisplay,
+        theme: *const c_char,
+        size: c_int,
+    );
+
+    pub fn gdk_wayland_display_get_wl_display(display: *mut GdkWaylandDisplay) -> gpointer;
+
+    pub fn gdk_wayland_display_get_wl_compositor(display: *mut GdkWaylandDisplay) -> gpointer;
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_display_set_startup_notification_id(
+        display: *mut GdkWaylandDisplay,
+        startup_id: *const c_char,
+    );
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_display_prefers_ssd(display: *mut GdkWaylandDisplay) -> glib_sys::gboolean;
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_display_query_registry(
+        display: *mut GdkWaylandDisplay,
+        global: *const c_char,
+    ) -> glib_sys::gboolean;
+
+    //=========================================================================
+    // GdkWaylandGLContext
+    //=========================================================================
+    pub fn gdk_wayland_gl_context_get_type() -> GType;
+
+    //=========================================================================
+    // GdkWaylandSeat
+    //=========================================================================
+    pub fn gdk_wayland_seat_get_type() -> GType;
+
+    #[cfg(any(feature = "v3_20", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_20")))]
+    pub fn gdk_wayland_seat_get_wl_seat(seat: *mut GdkWaylandSeat) -> gpointer;
+
+    //=========================================================================
+    // GdkWaylandMonitor
+    //=========================================================================
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_monitor_get_type() -> GType;
+
+    #[cfg(any(feature = "v3_22", feature = "dox"))]
+    #[cfg_attr(feature = "dox", doc(cfg(feature = "v3_22")))]
+    pub fn gdk_wayland_monitor_get_wl_output(monitor: *mut GdkWaylandMonitor) -> gpointer;
+}


Test patch: