brewery
notashelf /
c68d3445e72da17183b1401e92b924c463babf9f

beer

public

A terminal worth pouring time into

Star0tarball
clone
ssh://git@git.notashelf.dev:33/notashelf/beer.git

Commit c68d3445e72d

tarball

NotAShelf <raf@notashelf.dev> · 2026-06-24 05:25 UTC

unverified4 files changed+649-1
wayland: we have a (blank) window ladies and gentlemen

Signed-off-by: NotAShelf <raf@notashelf.dev>
Change-Id: Id2b91339a2d43cc95041dafe835c6a526a6a6964
diff --git a/Cargo.lock b/Cargo.lockindex 3c80efc..bc71799 100644--- a/Cargo.lock+++ b/Cargo.lock@@ -22,9 +22,74 @@ name = "beer" version = "0.0.0" dependencies = [  "anyhow",+ "calloop",+ "calloop-wayland-source",  "pound",+ "smithay-client-toolkit",  "tracing",  "tracing-subscriber",+ "wayland-client",+]++[[package]]+name = "bitflags"+version = "2.13.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"++[[package]]+name = "bytemuck"+version = "1.25.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec"+dependencies = [+ "bytemuck_derive",+]++[[package]]+name = "bytemuck_derive"+version = "1.10.2"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff"+dependencies = [+ "proc-macro2",+ "quote",+ "syn",+]++[[package]]+name = "calloop"+version = "0.14.4"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7"+dependencies = [+ "bitflags",+ "polling",+ "rustix",+ "slab",+ "tracing",+]++[[package]]+name = "calloop-wayland-source"+version = "0.4.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa"+dependencies = [+ "calloop",+ "rustix",+ "wayland-backend",+ "wayland-client",+]++[[package]]+name = "cc"+version = "1.2.65"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96"+dependencies = [+ "find-msvc-tools",+ "shlex", ]  [[package]]@@ -34,12 +99,73 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"  [[package]]+name = "concurrent-queue"+version = "2.5.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973"+dependencies = [+ "crossbeam-utils",+]++[[package]]+name = "crossbeam-utils"+version = "0.8.21"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"++[[package]]+name = "cursor-icon"+version = "1.2.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f"++[[package]]+name = "downcast-rs"+version = "1.2.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2"++[[package]]+name = "errno"+version = "0.3.14"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"+dependencies = [+ "libc",+ "windows-sys",+]++[[package]]+name = "find-msvc-tools"+version = "0.1.9"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582"++[[package]]+name = "hermit-abi"+version = "0.5.2"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"++[[package]] name = "lazy_static" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"  [[package]]+name = "libc"+version = "0.2.186"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"++[[package]]+name = "linux-raw-sys"+version = "0.12.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"++[[package]] name = "log" version = "0.4.32" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -61,6 +187,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"  [[package]]+name = "memmap2"+version = "0.9.11"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "d1219ed1b7f229ee7104d281dd01d6802fe28bb6e95d292942c4daacdeb798c0"+dependencies = [+ "libc",+]++[[package]] name = "nu-ansi-term" version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -82,6 +217,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd"  [[package]]+name = "pkg-config"+version = "0.3.33"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e"++[[package]]+name = "polling"+version = "3.11.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218"+dependencies = [+ "cfg-if",+ "concurrent-queue",+ "hermit-abi",+ "pin-project-lite",+ "rustix",+ "windows-sys",+]++[[package]] name = "pound" version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -111,6 +266,15 @@ dependencies = [ ]  [[package]]+name = "quick-xml"+version = "0.39.4"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "cdcc8dd4e2f670d309a5f0e83fe36dfdc05af317008fea29144da1a2ac858e5e"+dependencies = [+ "memchr",+]++[[package]] name = "quote" version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -137,6 +301,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"  [[package]]+name = "rustix"+version = "1.1.4"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"+dependencies = [+ "bitflags",+ "errno",+ "libc",+ "linux-raw-sys",+ "windows-sys",+]++[[package]] name = "sharded-slab" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -146,12 +323,54 @@ dependencies = [ ]  [[package]]+name = "shlex"+version = "2.0.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"++[[package]]+name = "slab"+version = "0.4.12"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5"++[[package]] name = "smallvec" version = "1.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90"  [[package]]+name = "smithay-client-toolkit"+version = "0.20.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0"+dependencies = [+ "bitflags",+ "bytemuck",+ "calloop",+ "calloop-wayland-source",+ "cursor-icon",+ "libc",+ "log",+ "memmap2",+ "pkg-config",+ "rustix",+ "thiserror",+ "wayland-backend",+ "wayland-client",+ "wayland-csd-frame",+ "wayland-cursor",+ "wayland-protocols",+ "wayland-protocols-experimental",+ "wayland-protocols-misc",+ "wayland-protocols-wlr",+ "wayland-scanner",+ "xkbcommon",+ "xkeysym",+]++[[package]] name = "syn" version = "2.0.118" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -163,6 +382,26 @@ dependencies = [ ]  [[package]]+name = "thiserror"+version = "2.0.18"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4"+dependencies = [+ "thiserror-impl",+]++[[package]]+name = "thiserror-impl"+version = "2.0.18"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"+dependencies = [+ "proc-macro2",+ "quote",+ "syn",+]++[[package]] name = "thread_local" version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -177,6 +416,7 @@ version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [+ "log",  "pin-project-lite",  "tracing-attributes",  "tracing-core",@@ -255,6 +495,124 @@ dependencies = [ ]  [[package]]+name = "wayland-backend"+version = "0.3.15"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "2857dd20b54e916ec7253b3d6b4d5c4d7d4ca2c33c2e11c6c76a99bd8744755d"+dependencies = [+ "cc",+ "downcast-rs",+ "rustix",+ "smallvec",+ "wayland-sys",+]++[[package]]+name = "wayland-client"+version = "0.31.14"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "645c7c96bb74690c3189b5c9cb4ca1627062bb23693a4fad9d8c3de958260144"+dependencies = [+ "bitflags",+ "rustix",+ "wayland-backend",+ "wayland-scanner",+]++[[package]]+name = "wayland-csd-frame"+version = "0.3.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e"+dependencies = [+ "bitflags",+ "cursor-icon",+ "wayland-backend",+]++[[package]]+name = "wayland-cursor"+version = "0.31.14"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "4a52d18780be9b1314328a3de5f930b73d2200112e3849ca6cb11822793fb34d"+dependencies = [+ "rustix",+ "wayland-client",+ "xcursor",+]++[[package]]+name = "wayland-protocols"+version = "0.32.13"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "23d0c813de3daa2ed6520af85a3bd49b0e722a3078506899aa9686fea58dc4b6"+dependencies = [+ "bitflags",+ "wayland-backend",+ "wayland-client",+ "wayland-scanner",+]++[[package]]+name = "wayland-protocols-experimental"+version = "20250721.0.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1"+dependencies = [+ "bitflags",+ "wayland-backend",+ "wayland-client",+ "wayland-protocols",+ "wayland-scanner",+]++[[package]]+name = "wayland-protocols-misc"+version = "0.3.12"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "6e9567599ef23e09b8dad6e429e5738d4509dfc46b3b21f32841a304d16b29c8"+dependencies = [+ "bitflags",+ "wayland-backend",+ "wayland-client",+ "wayland-protocols",+ "wayland-scanner",+]++[[package]]+name = "wayland-protocols-wlr"+version = "0.3.12"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "eb04e52f7836d7c7976c78ca0250d61e33873c34156a2a1fc9474828ec268234"+dependencies = [+ "bitflags",+ "wayland-backend",+ "wayland-client",+ "wayland-protocols",+ "wayland-scanner",+]++[[package]]+name = "wayland-scanner"+version = "0.31.10"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "9c324a910fd86ebdc364a3e61ec1f11737d3b1d6c273c0239ee8ff4bc0d24b4a"+dependencies = [+ "proc-macro2",+ "quick-xml",+ "quote",+]++[[package]]+name = "wayland-sys"+version = "0.31.11"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "d8eab23fefc9e41f8e841df4a9c707e8a8c4ed26e944ef69297184de2785e3be"+dependencies = [+ "pkg-config",+]++[[package]] name = "windows-link" version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index"@@ -268,3 +626,29 @@ checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [  "windows-link", ]++[[package]]+name = "xcursor"+version = "0.3.10"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b"++[[package]]+name = "xkbcommon"+version = "0.8.0"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "8d66ca9352cbd4eecbbc40871d8a11b4ac8107cfc528a6e14d7c19c69d0e1ac9"+dependencies = [+ "libc",+ "memmap2",+ "xkeysym",+]++[[package]]+name = "xkeysym"+version = "0.2.1"+source = "registry+https://github.com/rust-lang/crates.io-index"+checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56"+dependencies = [+ "bytemuck",+]diff --git a/Cargo.toml b/Cargo.tomlindex f0a465f..7a88bfc 100644--- a/Cargo.toml+++ b/Cargo.toml@@ -9,9 +9,13 @@ readme = true  [dependencies] anyhow = "1.0.102"+calloop = "0.14.4"+calloop-wayland-source = "0.4.1" pound = "0.1.6"+smithay-client-toolkit = "0.20.0" tracing = "0.1.44" tracing-subscriber = { version = "0.3.23", features = ["env-filter"] }+wayland-client = "0.31.14"  [lints.rust] unsafe_op_in_unsafe_fn = "deny"diff --git a/src/main.rs b/src/main.rsindex 6ead51e..a0be920 100644--- a/src/main.rs+++ b/src/main.rs@@ -1,5 +1,7 @@ //! beer, a fast, software-rendered, Wayland-native terminal emulator. +mod wayland;+ use std::process::ExitCode;  use pound::Parse;@@ -45,5 +47,5 @@ fn run(cli: Cli) -> anyhow::Result<()> {     }      tracing::info!("starting beer");-    todo!("window mode")+    wayland::run() }diff --git a/src/wayland.rs b/src/wayland.rsnew file mode 100644index 0000000..29f681e--- /dev/null+++ b/src/wayland.rs@@ -0,0 +1,258 @@+//! Wayland front-end: connection, surface, and software-drawn window.+//!+//! Uses smithay-client-toolkit for protocol boilerplate and calloop for the+//! event loop, so the PTY master fd and timers share one loop.++use std::time::Duration;++use anyhow::Context;+use calloop::EventLoop;+use calloop_wayland_source::WaylandSource;+use smithay_client_toolkit::{+    compositor::{CompositorHandler, CompositorState},+    delegate_compositor, delegate_output, delegate_registry, delegate_seat, delegate_shm,+    delegate_xdg_shell, delegate_xdg_window,+    output::{OutputHandler, OutputState},+    registry::{ProvidesRegistryState, RegistryState},+    registry_handlers,+    seat::{Capability, SeatHandler, SeatState},+    shell::{+        WaylandSurface,+        xdg::{+            XdgShell,+            window::{Window, WindowConfigure, WindowDecorations, WindowHandler},+        },+    },+    shm::{Shm, ShmHandler, slot::SlotPool},+};+use wayland_client::{+    Connection, QueueHandle,+    globals::registry_queue_init,+    protocol::{wl_output, wl_seat, wl_shm, wl_surface},+};++/// Default window size in pixels before the compositor suggests one.+const DEFAULT_W: u32 = 800;+const DEFAULT_H: u32 = 600;+/// Background fill, 0xAARRGGBB. Foot-ish dark grey.+const BG: u32 = 0xFF18_1818;++/// Run a single window until it is closed.+pub fn run() -> anyhow::Result<()> {+    let conn = Connection::connect_to_env().context("connect to Wayland compositor")?;+    let (globals, event_queue) =+        registry_queue_init(&conn).context("initialize Wayland registry")?;+    let qh = event_queue.handle();++    let mut event_loop: EventLoop<App> =+        EventLoop::try_new().context("create calloop event loop")?;+    WaylandSource::new(conn, event_queue)+        .insert(event_loop.handle())+        .map_err(|e| anyhow::anyhow!("insert Wayland source into event loop: {e}"))?;++    let compositor = CompositorState::bind(&globals, &qh).context("compositor not available")?;+    let xdg_shell = XdgShell::bind(&globals, &qh).context("xdg_wm_base not available")?;+    let shm = Shm::bind(&globals, &qh).context("wl_shm not available")?;++    let surface = compositor.create_surface(&qh);+    let window = xdg_shell.create_window(surface, WindowDecorations::RequestServer, &qh);+    window.set_title("beer");+    window.set_app_id("dev.notashelf.beer");+    window.set_min_size(Some((1, 1)));+    // First commit with no buffer kicks off the initial configure.+    window.commit();++    let pool = SlotPool::new(DEFAULT_W as usize * DEFAULT_H as usize * 4, &shm)+        .context("create shm slot pool")?;++    let mut app = App {+        registry_state: RegistryState::new(&globals),+        output_state: OutputState::new(&globals, &qh),+        seat_state: SeatState::new(&globals, &qh),+        shm,+        pool,+        window,+        width: DEFAULT_W,+        height: DEFAULT_H,+        configured: false,+        exit: false,+    };++    while !app.exit {+        event_loop+            .dispatch(Duration::from_millis(16), &mut app)+            .context("dispatch event loop")?;+    }+    Ok(())+}++/// Window + Wayland client state shared across all protocol handlers.+#[derive(Debug)]+struct App {+    registry_state: RegistryState,+    output_state: OutputState,+    seat_state: SeatState,+    shm: Shm,+    pool: SlotPool,+    window: Window,+    width: u32,+    height: u32,+    configured: bool,+    exit: bool,+}++impl App {+    /// Fill the surface with the background colour and present it.+    fn draw(&mut self) {+        let (w, h) = (self.width, self.height);+        let stride = w as i32 * 4;++        let (buffer, canvas) =+            match self+                .pool+                .create_buffer(w as i32, h as i32, stride, wl_shm::Format::Argb8888)+            {+                Ok(buf) => buf,+                Err(err) => {+                    tracing::error!("allocate shm buffer: {err}");+                    return;+                }+            };++        let bytes = BG.to_le_bytes();+        for px in canvas.chunks_exact_mut(4) {+            px.copy_from_slice(&bytes);+        }++        let surface = self.window.wl_surface();+        if let Err(err) = buffer.attach_to(surface) {+            tracing::error!("attach buffer: {err}");+            return;+        }+        surface.damage_buffer(0, 0, w as i32, h as i32);+        self.window.commit();+    }+}++impl CompositorHandler for App {+    fn scale_factor_changed(+        &mut self,+        _: &Connection,+        _: &QueueHandle<Self>,+        _: &wl_surface::WlSurface,+        _: i32,+    ) {+    }++    fn transform_changed(+        &mut self,+        _: &Connection,+        _: &QueueHandle<Self>,+        _: &wl_surface::WlSurface,+        _: wl_output::Transform,+    ) {+    }++    fn frame(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &wl_surface::WlSurface, _: u32) {}++    fn surface_enter(+        &mut self,+        _: &Connection,+        _: &QueueHandle<Self>,+        _: &wl_surface::WlSurface,+        _: &wl_output::WlOutput,+    ) {+    }++    fn surface_leave(+        &mut self,+        _: &Connection,+        _: &QueueHandle<Self>,+        _: &wl_surface::WlSurface,+        _: &wl_output::WlOutput,+    ) {+    }+}++impl WindowHandler for App {+    fn request_close(&mut self, _: &Connection, _: &QueueHandle<Self>, _: &Window) {+        self.exit = true;+    }++    fn configure(+        &mut self,+        _: &Connection,+        _: &QueueHandle<Self>,+        _: &Window,+        configure: WindowConfigure,+        _serial: u32,+    ) {+        if let (Some(w), Some(h)) = configure.new_size {+            self.width = w.get();+            self.height = h.get();+        }+        self.configured = true;+        self.draw();+    }+}++impl ShmHandler for App {+    fn shm_state(&mut self) -> &mut Shm {+        &mut self.shm+    }+}++impl SeatHandler for App {+    fn seat_state(&mut self) -> &mut SeatState {+        &mut self.seat_state+    }++    fn new_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}++    fn new_capability(+        &mut self,+        _: &Connection,+        _: &QueueHandle<Self>,+        _: wl_seat::WlSeat,+        _: Capability,+    ) {+    }++    fn remove_capability(+        &mut self,+        _: &Connection,+        _: &QueueHandle<Self>,+        _: wl_seat::WlSeat,+        _: Capability,+    ) {+    }++    fn remove_seat(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_seat::WlSeat) {}+}++impl OutputHandler for App {+    fn output_state(&mut self) -> &mut OutputState {+        &mut self.output_state+    }++    fn new_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) {}++    fn update_output(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) {}++    fn output_destroyed(&mut self, _: &Connection, _: &QueueHandle<Self>, _: wl_output::WlOutput) {}+}++impl ProvidesRegistryState for App {+    fn registry(&mut self) -> &mut RegistryState {+        &mut self.registry_state+    }+    registry_handlers![OutputState, SeatState];+}++delegate_compositor!(App);+delegate_output!(App);+delegate_shm!(App);+delegate_seat!(App);+delegate_xdg_shell!(App);+delegate_xdg_window!(App);+delegate_registry!(App);