git.lucas.co / cce-compositor
Wayland compositor (wlroots)
git clone https://git.lucas.co/cce-compositor.git

commitcdfe80232aaa5cda3de8344d5e8f6be9d32e9f7b
parent1b8e9a53c7
authorLucas Galante <[email protected]>
date2026-05-29 17:36
Update system configuration and interface modules

 build.rs                  |  28 ++++++-------
 src/cursor.rs             |   5 ++-
 src/input_manager.rs      |   4 +-
 src/layer_shell.rs        |  10 +++--
 src/seat.rs               |  41 ++++++++++---------
 src/server.rs             | 100 ++++++++++++++++------------------------------
 src/shell_surface.rs      |  25 +++++++++++-
 src/window.rs             |  35 ++++++++++++----
 src/wlroots_log_wrapper.c |   4 ++
 src/xwayland_window.rs    |   2 +-
 wrapper.h                 |   5 ++-
 11 files changed, 142 insertions(+), 117 deletions(-)

diff --git a/build.rs b/build.rs
index 077c025..da159a9 100644
--- a/build.rs
+++ b/build.rs
@@ -6,16 +6,16 @@ fn main() {
     println!("cargo:rerun-if-changed=wrapper.h");
 
     // Probe system libraries
-    let wlroots = pkg_config::Config::new()
-        .atleast_version("0.20.0")
-        .probe("wlroots-0.20")
-        .expect("wlroots-0.20 is required");
-
     let scenefx = pkg_config::Config::new()
         .atleast_version("0.4.0")
         .probe("scenefx-0.4")
         .expect("scenefx-0.4 is required");
 
+    let wlroots = pkg_config::Config::new()
+        .atleast_version("0.19.0")
+        .probe("wlroots-0.19")
+        .expect("wlroots-0.19 is required");
+
     let wl_server = pkg_config::probe_library("wayland-server")
         .expect("wayland-server is required");
 
@@ -49,6 +49,14 @@ fn main() {
         ("wlr-layer-shell-unstable-v1.xml", "protocol/upstream/wlr-layer-shell-unstable-v1.xml"),
         ("wlr-output-power-management-unstable-v1.xml", "protocol/upstream/wlr-output-power-management-unstable-v1.xml"),
         ("virtual-keyboard-unstable-v1.xml", "protocol/upstream/virtual-keyboard-unstable-v1.xml"),
+        ("tablet-v2.xml", "/usr/share/wayland-protocols/stable/tablet/tablet-v2.xml"),
+        ("xdg-shell.xml", "/usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml"),
+        ("color-management-v1.xml", "/usr/share/wayland-protocols/staging/color-management/color-management-v1.xml"),
+        ("content-type-v1.xml", "/usr/share/wayland-protocols/staging/content-type/content-type-v1.xml"),
+        ("cursor-shape-v1.xml", "/usr/share/wayland-protocols/staging/cursor-shape/cursor-shape-v1.xml"),
+        ("ext-image-copy-capture-v1.xml", "/usr/share/wayland-protocols/staging/ext-image-copy-capture/ext-image-copy-capture-v1.xml"),
+        ("pointer-constraints-unstable-v1.xml", "/usr/share/wayland-protocols/unstable/pointer-constraints/pointer-constraints-unstable-v1.xml"),
+        ("tearing-control-v1.xml", "/usr/share/wayland-protocols/staging/tearing-control/tearing-control-v1.xml"),
     ];
 
     for (name, path) in upstream_protocols {
@@ -122,9 +130,6 @@ fn main() {
 
     // Add include paths for scenefx, wlroots, and wayland-server
     for path in &scenefx.include_paths {
-        if path.to_string_lossy().contains("wlroots-0.19") {
-            continue;
-        }
         build.include(path);
     }
     for path in &wlroots.include_paths {
@@ -145,12 +150,7 @@ fn main() {
 
     // Pass include paths to bindgen clang argument parser
     let mut include_paths = vec![out_dir.clone()];
-    for path in scenefx.include_paths.clone() {
-        if path.to_string_lossy().contains("wlroots-0.19") {
-            continue;
-        }
-        include_paths.push(path);
-    }
+    include_paths.extend(scenefx.include_paths.clone());
     include_paths.extend(wlroots.include_paths.clone());
     include_paths.extend(wl_server.include_paths.clone());
     include_paths.extend(xkb.include_paths.clone());
diff --git a/src/cursor.rs b/src/cursor.rs
index 32c8680..d0db355 100644
--- a/src/cursor.rs
+++ b/src/cursor.rs
@@ -392,7 +392,10 @@ impl Cursor {
                     if !image.is_null() {
                         ffi::wlr_xwayland_set_cursor(
                             (*(*self.seat).server).xwayland,
-                            ffi::wlr_xcursor_image_get_buffer(image),
+                            (*image).buffer,
+                            (*image).width * 4,
+                            (*image).width,
+                            (*image).height,
                             (*image).hotspot_x as i32,
                             (*image).hotspot_y as i32,
                         );
diff --git a/src/input_manager.rs b/src/input_manager.rs
index 8841715..6209664 100644
--- a/src/input_manager.rs
+++ b/src/input_manager.rs
@@ -82,12 +82,12 @@ impl InputManager {
         // Connect new_text_input listener
         let new_text_input_ptr = &mut self.new_text_input as *mut ffi::wl_listener as *mut WlListener;
         (*new_text_input_ptr).notify = Some(handle_new_text_input);
-        wl_signal_add(&mut (*self.text_input_manager).events.new_text_input, &mut self.new_text_input);
+        wl_signal_add(&mut (*self.text_input_manager).events.text_input, &mut self.new_text_input);
 
         // Connect new_input_method listener
         let new_input_method_ptr = &mut self.new_input_method as *mut ffi::wl_listener as *mut WlListener;
         (*new_input_method_ptr).notify = Some(handle_new_input_method);
-        wl_signal_add(&mut (*self.input_method_manager).events.new_input_method, &mut self.new_input_method);
+        wl_signal_add(&mut (*self.input_method_manager).events.input_method, &mut self.new_input_method);
 
         Ok(())
     }
diff --git a/src/layer_shell.rs b/src/layer_shell.rs
index 5264cf6..ff981ae 100644
--- a/src/layer_shell.rs
+++ b/src/layer_shell.rs
@@ -462,10 +462,12 @@ unsafe extern "C" fn handle_layer_surface_commit(listener: *mut ffi::wl_listener
     let layer_surface = crate::container_of!(listener, LayerSurface, commit);
     let wlr_layer_surface = (*layer_surface).wlr_layer_surface;
 
-    ffi::river_scene_node_enable_blur(
-        (*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node,
-        true,
-    );
+    if (*wlr_layer_surface).current.layer != ffi::zwlr_layer_shell_v1_layer_ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND {
+        ffi::river_scene_node_enable_blur(
+            (*(*layer_surface).scene_layer_surface).tree as *mut ffi::wlr_scene_node,
+            true,
+        );
+    }
 
     assert!(!(*wlr_layer_surface).output.is_null());
 
diff --git a/src/seat.rs b/src/seat.rs
index b35791e..81b7dd6 100644
--- a/src/seat.rs
+++ b/src/seat.rs
@@ -306,24 +306,26 @@ impl Seat {
         match new_focus {
             Focus::None => {}
             Focus::LayerSurface(surface) => {
-                let kbd = ffi::river_wlr_seat_get_keyboard(self.wlr_seat);
-                if !kbd.is_null() {
-                    let modifiers = ffi::river_wlr_keyboard_get_modifiers(kbd);
-                    ffi::wlr_seat_keyboard_notify_enter(
-                        self.wlr_seat,
-                        surface,
-                        std::ptr::null_mut(),
-                        0,
-                        modifiers,
-                    );
-                } else {
-                    ffi::wlr_seat_keyboard_notify_enter(
-                        self.wlr_seat,
-                        surface,
-                        std::ptr::null_mut(),
-                        0,
-                        std::ptr::null_mut(),
-                    );
+                if !surface.is_null() {
+                    let kbd = ffi::river_wlr_seat_get_keyboard(self.wlr_seat);
+                    if !kbd.is_null() {
+                        let modifiers = ffi::river_wlr_keyboard_get_modifiers(kbd);
+                        ffi::wlr_seat_keyboard_notify_enter(
+                            self.wlr_seat,
+                            surface,
+                            std::ptr::null_mut(),
+                            0,
+                            modifiers,
+                        );
+                    } else {
+                        ffi::wlr_seat_keyboard_notify_enter(
+                            self.wlr_seat,
+                            surface,
+                            std::ptr::null_mut(),
+                            0,
+                            std::ptr::null_mut(),
+                        );
+                    }
                 }
 
                 let lx = self.cursor.x();
@@ -456,6 +458,9 @@ impl Seat {
     }
 
     pub unsafe fn keyboard_notify_enter(&mut self, wlr_surface: *mut ffi::wlr_surface) {
+        if wlr_surface.is_null() {
+            return;
+        }
         let kbd = ffi::river_wlr_seat_get_keyboard(self.wlr_seat);
         if !kbd.is_null() {
             let group_ptr = ffi::river_wlr_keyboard_get_data(kbd) as *mut crate::keyboard_group::KeyboardGroup;
diff --git a/src/server.rs b/src/server.rs
index e0e34b0..0a967f7 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -50,7 +50,6 @@ pub struct WlrRendererEvents {
 
 #[repr(C)]
 pub struct WlrRendererFeatures {
-    pub input_color_transform: bool,
     pub output_color_transform: bool,
     pub timeline: bool,
 }
@@ -58,7 +57,6 @@ pub struct WlrRendererFeatures {
 #[repr(C)]
 pub struct WlrRenderer {
     pub render_buffer_caps: u32,
-    pub color_encodings: u32,
     pub events: WlrRendererEvents,
     pub features: WlrRendererFeatures,
 }
@@ -167,6 +165,7 @@ pub struct WlrXwayland {
     pub own_server: bool,
     pub xwm: *mut std::ffi::c_void,
     pub shell_v1: *mut std::ffi::c_void,
+    pub cursor: *mut std::ffi::c_void,
     pub display_name: *const std::os::raw::c_char,
     pub wl_display: *mut ffi::wl_display,
     pub compositor: *mut ffi::wlr_compositor,
@@ -221,7 +220,7 @@ pub struct Server {
     pub wl_server: *mut ffi::wl_display,
     pub sigint_source: *mut ffi::wl_event_source,
     pub sigterm_source: *mut ffi::wl_event_source,
-    pub fixes: *mut ffi::wlr_fixes,
+    // pub fixes: *mut ffi::wlr_fixes,
     pub backend: *mut ffi::wlr_backend,
     pub session: *mut ffi::wlr_session,
     pub renderer: *mut ffi::wlr_renderer,
@@ -234,7 +233,7 @@ pub struct Server {
     pub single_pixel_buffer_manager: *mut ffi::wlr_single_pixel_buffer_manager_v1,
     pub alpha_modifier: *mut ffi::wlr_alpha_modifier_v1,
     pub color_manager: *mut ffi::wlr_color_manager_v1,
-    pub color_representation_manager: *mut ffi::wlr_color_representation_manager_v1,
+    // pub color_representation_manager: *mut ffi::wlr_color_representation_manager_v1,
     pub viewporter: *mut ffi::wlr_viewporter,
     pub fractional_scale_manager: *mut ffi::wlr_fractional_scale_manager_v1,
     pub compositor: *mut ffi::wlr_compositor,
@@ -255,7 +254,7 @@ pub struct Server {
     pub output_image_capture_source_manager: *mut ffi::wlr_ext_output_image_capture_source_manager_v1,
     pub wlr_foreign_toplevel_manager: *mut ffi::wlr_foreign_toplevel_manager_v1,
     pub foreign_toplevel_list: *mut ffi::wlr_ext_foreign_toplevel_list_v1,
-    pub toplevel_capture_source_manager: *mut ffi::wlr_ext_foreign_toplevel_image_capture_source_manager_v1,
+    // pub toplevel_capture_source_manager: *mut ffi::wlr_ext_foreign_toplevel_image_capture_source_manager_v1,
     pub tearing_control_manager: *mut ffi::wlr_tearing_control_manager_v1,
 
     pub xwayland: *mut ffi::wlr_xwayland,
@@ -278,7 +277,7 @@ pub struct Server {
     pub new_toplevel_decoration: ffi::wl_listener,
     pub request_activate: ffi::wl_listener,
     pub request_set_cursor_shape: ffi::wl_listener,
-    pub toplevel_capture_request: ffi::wl_listener,
+    // pub toplevel_capture_request: ffi::wl_listener,
     pub new_xsurface: ffi::wl_listener,
 }
 
@@ -331,10 +330,10 @@ unsafe extern "C" fn handle_request_set_cursor_shape(listener: *mut ffi::wl_list
     }
 }
 
-unsafe extern "C" fn handle_toplevel_capture_request(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
-    let _server = container_of!(listener, Server, toplevel_capture_request);
-    log::info!("toplevel capture request");
-}
+// unsafe extern "C" fn handle_toplevel_capture_request(listener: *mut ffi::wl_listener, _data: *mut std::ffi::c_void) {
+//     let _server = container_of!(listener, Server, toplevel_capture_request);
+//     log::info!("toplevel capture request");
+// }
 
 unsafe extern "C" fn handle_new_xwayland_surface(listener: *mut ffi::wl_listener, data: *mut std::ffi::c_void) {
     let server = container_of!(listener, Server, new_xsurface);
@@ -377,9 +376,9 @@ impl Server {
             self.backend = backend;
             self.session = session;
 
-            let renderer = ffi::wlr_renderer_autocreate(backend);
+            let renderer = ffi::fx_renderer_create(backend);
             if renderer.is_null() {
-                return Err("Failed to autocreate wlr_renderer");
+                return Err("Failed to create fx_renderer");
             }
             self.renderer = renderer;
 
@@ -395,11 +394,11 @@ impl Server {
             }
             self.xdg_foreign_registry = xdg_foreign_registry;
 
-            let fixes = ffi::wlr_fixes_create(wl_server, 1);
-            if fixes.is_null() {
-                return Err("Failed to create wlr_fixes");
-            }
-            self.fixes = fixes;
+            // let fixes = ffi::wlr_fixes_create(wl_server, 1);
+            // if fixes.is_null() {
+            //     return Err("Failed to create wlr_fixes");
+            // }
+            // self.fixes = fixes;
 
             let allocator = ffi::wlr_allocator_autocreate(backend, renderer);
             if allocator.is_null() {
@@ -431,11 +430,11 @@ impl Server {
             }
             self.alpha_modifier = alpha_modifier;
 
-            let color_representation_manager = ffi::wlr_color_representation_manager_v1_create_with_renderer(wl_server, 1, renderer);
-            if color_representation_manager.is_null() {
-                return Err("Failed to create color representation manager");
-            }
-            self.color_representation_manager = color_representation_manager;
+            // let color_representation_manager = ffi::wlr_color_representation_manager_v1_create_with_renderer(wl_server, 1, renderer);
+            // if color_representation_manager.is_null() {
+            //     return Err("Failed to create color representation manager");
+            // }
+            // self.color_representation_manager = color_representation_manager;
 
             let viewporter = ffi::wlr_viewporter_create(wl_server);
             if viewporter.is_null() {
@@ -455,7 +454,7 @@ impl Server {
             }
             self.subcompositor = subcompositor;
 
-            let cursor_shape_manager = ffi::wlr_cursor_shape_manager_v1_create(wl_server, 2);
+            let cursor_shape_manager = ffi::wlr_cursor_shape_manager_v1_create(wl_server, 1);
             if cursor_shape_manager.is_null() {
                 return Err("Failed to create cursor shape manager");
             }
@@ -545,11 +544,11 @@ impl Server {
             }
             self.foreign_toplevel_list = foreign_toplevel_list;
 
-            let toplevel_capture_source_manager = ffi::wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(wl_server, 1);
-            if toplevel_capture_source_manager.is_null() {
-                return Err("Failed to create toplevel capture source manager");
-            }
-            self.toplevel_capture_source_manager = toplevel_capture_source_manager;
+            // let toplevel_capture_source_manager = ffi::wlr_ext_foreign_toplevel_image_capture_source_manager_v1_create(wl_server, 1);
+            // if toplevel_capture_source_manager.is_null() {
+            //     return Err("Failed to create toplevel capture source manager");
+            // }
+            // self.toplevel_capture_source_manager = toplevel_capture_source_manager;
 
             let tearing_control_manager = ffi::wlr_tearing_control_manager_v1_create(wl_server, 1);
             if tearing_control_manager.is_null() {
@@ -582,39 +581,8 @@ impl Server {
             }
 
             // Setup color manager if supported
-            if (*renderer_cast).features.input_color_transform {
-                let mut len: usize = 0;
-                let primaries = ffi::wlr_color_manager_v1_primaries_list_from_renderer(renderer, &mut len);
-                let transfer_functions = ffi::wlr_color_manager_v1_transfer_function_list_from_renderer(renderer, &mut len);
-
-                let render_intents = [ffi::wp_color_manager_v1_render_intent_WP_COLOR_MANAGER_V1_RENDER_INTENT_PERCEPTUAL];
-                
-                self.color_manager = ffi::wlr_color_manager_v1_create(
-                    wl_server,
-                    2,
-                    &ffi::wlr_color_manager_v1_options {
-                        features: ffi::wlr_color_manager_v1_features {
-                            icc_v2_v4: false,
-                            parametric: true,
-                            set_primaries: false,
-                            set_tf_power: false,
-                            set_luminances: false,
-                            set_mastering_display_primaries: true,
-                            extended_target_volume: false,
-                            windows_scrgb: false,
-                        },
-                        render_intents: render_intents.as_ptr(),
-                        render_intents_len: render_intents.len(),
-                        primaries,
-                        primaries_len: len,
-                        transfer_functions,
-                        transfer_functions_len: len,
-                    }
-                );
-
-                libc::free(primaries as *mut _);
-                libc::free(transfer_functions as *mut _);
-            }
+            // (Commented out for wlroots 0.19 compatibility)
+            self.color_manager = std::ptr::null_mut();
 
             // Setup subcomponents stubs
             let server_ptr = self as *mut Server;
@@ -645,21 +613,21 @@ impl Server {
             let req_cursor = &mut self.request_set_cursor_shape as *mut ffi::wl_listener as *mut WlListener;
             (*req_cursor).notify = Some(handle_request_set_cursor_shape);
 
-            let cap_req = &mut self.toplevel_capture_request as *mut ffi::wl_listener as *mut WlListener;
-            (*cap_req).notify = Some(handle_toplevel_capture_request);
+            // let cap_req = &mut self.toplevel_capture_request as *mut ffi::wl_listener as *mut WlListener;
+            // (*cap_req).notify = Some(handle_toplevel_capture_request);
 
             let xdg_shell_cast = self.xdg_shell as *mut WlrXdgShell;
             let xdg_decoration_manager_cast = self.xdg_decoration_manager as *mut WlrXdgDecorationManagerV1;
             let xdg_activation_cast = self.xdg_activation as *mut WlrXdgActivationV1;
             let cursor_shape_manager_cast = self.cursor_shape_manager as *mut WlrCursorShapeManagerV1;
-            let toplevel_capture_source_manager_cast = self.toplevel_capture_source_manager as *mut WlrExtForeignToplevelImageCaptureSourceManagerV1;
+            // let toplevel_capture_source_manager_cast = self.toplevel_capture_source_manager as *mut WlrExtForeignToplevelImageCaptureSourceManagerV1;
 
             wl_signal_add(&mut (*renderer_cast).events.lost, &mut self.renderer_lost);
             wl_signal_add(&mut (*xdg_shell_cast).events.new_toplevel, &mut self.new_xdg_toplevel);
             wl_signal_add(&mut (*xdg_decoration_manager_cast).events.new_toplevel_decoration, &mut self.new_toplevel_decoration);
             wl_signal_add(&mut (*xdg_activation_cast).events.request_activate, &mut self.request_activate);
             wl_signal_add(&mut (*cursor_shape_manager_cast).events.request_set_shape, &mut self.request_set_cursor_shape);
-            wl_signal_add(&mut (*toplevel_capture_source_manager_cast).events.new_request, &mut self.toplevel_capture_request);
+            // wl_signal_add(&mut (*toplevel_capture_source_manager_cast).events.new_request, &mut self.toplevel_capture_request);
 
             // Register Xwayland surface listener if active
             if !self.xwayland.is_null() {
@@ -684,7 +652,7 @@ impl Server {
             wl_listener_remove(&mut self.new_toplevel_decoration);
             wl_listener_remove(&mut self.request_activate);
             wl_listener_remove(&mut self.request_set_cursor_shape);
-            wl_listener_remove(&mut self.toplevel_capture_request);
+            // wl_listener_remove(&mut self.toplevel_capture_request);
 
             if !self.xwayland.is_null() {
                 wl_listener_remove(&mut self.new_xsurface);
diff --git a/src/shell_surface.rs b/src/shell_surface.rs
index d397625..1041dbf 100644
--- a/src/shell_surface.rs
+++ b/src/shell_surface.rs
@@ -68,7 +68,7 @@ impl ShellSurface {
             shell_surface_v1,
             &SHELL_SURFACE_INTERFACE as *const _ as *const _,
             raw as *mut _,
-            None,
+            Some(handle_shell_surface_destroy_resource),
         );
 
         let hidden_tree = (*server).scene.hidden_tree;
@@ -181,12 +181,35 @@ unsafe extern "C" fn commit(surface: *mut ffi::wlr_surface) {
     }
 }
 
+unsafe extern "C" fn handle_shell_surface_destroy_resource(resource: *mut ffi::wl_resource) {
+    let shell_surface = ffi::wl_resource_get_user_data(resource) as *mut ShellSurface;
+    if !shell_surface.is_null() {
+        ffi::river_wlr_surface_set_role_object((*shell_surface).surface, std::ptr::null_mut());
+        (*shell_surface).object = std::ptr::null_mut();
+        
+        ffi::wlr_surface_unmap((*shell_surface).surface);
+        (*shell_surface).node.make_inert();
+        (*shell_surface).node.deinit();
+        ffi::wlr_scene_node_destroy((*shell_surface).tree as *mut ffi::wlr_scene_node);
+        ffi::wlr_scene_node_destroy((*shell_surface).popup_tree as *mut ffi::wlr_scene_node);
+
+        let _ = Box::from_raw(shell_surface);
+    }
+}
+
 unsafe extern "C" fn role_destroy(surface: *mut ffi::wlr_surface) {
     let shell_surface = from_wlr_surface(surface);
     if shell_surface.is_null() {
         return;
     }
 
+    ffi::river_wlr_surface_set_role_object(surface, std::ptr::null_mut());
+    if !(*shell_surface).object.is_null() {
+        ffi::wl_resource_set_user_data((*shell_surface).object, std::ptr::null_mut());
+        ffi::wl_resource_destroy((*shell_surface).object);
+        (*shell_surface).object = std::ptr::null_mut();
+    }
+
     ffi::wlr_surface_unmap((*shell_surface).surface);
 
     (*shell_surface).node.make_inert();
diff --git a/src/window.rs b/src/window.rs
index b73340f..b53d49e 100644
--- a/src/window.rs
+++ b/src/window.rs
@@ -248,14 +248,7 @@ impl Window {
             return Err("Failed to create fullscreen rect");
         }
 
-        let clear_color = [0.0f32, 0.0f32, 0.0f32, 0.0f32];
-        let border_left = ffi::wlr_scene_rect_create(tree, 0, 0, clear_color.as_ptr());
-        let border_right = ffi::wlr_scene_rect_create(tree, 0, 0, clear_color.as_ptr());
-        let border_top = ffi::wlr_scene_rect_create(tree, 0, 0, clear_color.as_ptr());
-        let border_bottom = ffi::wlr_scene_rect_create(tree, 0, 0, clear_color.as_ptr());
-
         let decorations_below_tree = ffi::wlr_scene_tree_create(tree);
-        let decorations_above_tree = ffi::wlr_scene_tree_create(tree);
 
         let surfaces = match crate::scene::SaveableSurfaces::init(tree) {
             Ok(s) => s,
@@ -267,6 +260,14 @@ impl Window {
             }
         };
 
+        let clear_color = [0.0f32, 0.0f32, 0.0f32, 0.0f32];
+        let border_left = ffi::wlr_scene_rect_create(tree, 0, 0, clear_color.as_ptr());
+        let border_right = ffi::wlr_scene_rect_create(tree, 0, 0, clear_color.as_ptr());
+        let border_top = ffi::wlr_scene_rect_create(tree, 0, 0, clear_color.as_ptr());
+        let border_bottom = ffi::wlr_scene_rect_create(tree, 0, 0, clear_color.as_ptr());
+
+        let decorations_above_tree = ffi::wlr_scene_tree_create(tree);
+
         let mut window = Box::new(Window {
             ref_key: crate::slotmap::Key { generation: 0, index: 0 },
             server,
@@ -1930,6 +1931,9 @@ impl Decoration {
             );
             self.object = std::ptr::null_mut();
         }
+        if !self.surface.is_null() {
+            ffi::river_wlr_surface_set_role_object(self.surface, std::ptr::null_mut());
+        }
         self.surfaces.save();
     }
 
@@ -2045,11 +2049,26 @@ static INERT_DECORATION_INTERFACE: ffi::river_decoration_v1_interface = ffi::riv
 unsafe extern "C" fn handle_dec_destroy_resource(resource: *mut ffi::wl_resource) {
     let dec = ffi::wl_resource_get_user_data(resource) as *mut Decoration;
     if !dec.is_null() {
+        ffi::river_wlr_surface_set_role_object((*dec).surface, std::ptr::null_mut());
         (*dec).object = std::ptr::null_mut();
         (*dec).destroy();
     }
 }
 
+unsafe extern "C" fn dec_role_destroy(surface: *mut ffi::wlr_surface) {
+    let dec = decoration_from_wlr_surface(surface);
+    if dec.is_null() {
+        return;
+    }
+    ffi::river_wlr_surface_set_role_object(surface, std::ptr::null_mut());
+    if !(*dec).object.is_null() {
+        ffi::wl_resource_set_user_data((*dec).object, std::ptr::null_mut());
+        ffi::wl_resource_destroy((*dec).object);
+        (*dec).object = std::ptr::null_mut();
+    }
+    (*dec).destroy();
+}
+
 #[no_mangle]
 pub static mut DECORATION_ROLE: ffi::wlr_surface_role = ffi::wlr_surface_role {
     name: b"river_decoration_v1\0".as_ptr() as *const _,
@@ -2058,5 +2077,5 @@ pub static mut DECORATION_ROLE: ffi::wlr_surface_role = ffi::wlr_surface_role {
     commit: Some(dec_commit),
     map: None,
     unmap: None,
-    destroy: None,
+    destroy: Some(dec_role_destroy),
 };
diff --git a/src/wlroots_log_wrapper.c b/src/wlroots_log_wrapper.c
index 0e9c1fd..bc4927f 100644
--- a/src/wlroots_log_wrapper.c
+++ b/src/wlroots_log_wrapper.c
@@ -647,6 +647,10 @@ void river_wlr_keyboard_init(struct wlr_keyboard *keyboard,
 }
 
 static void enable_blur_iterator(struct wlr_scene_buffer *buffer, int sx, int sy, void *user_data) {
+	struct wlr_scene_surface *scene_surface = wlr_scene_surface_try_from_buffer(buffer);
+	if (!scene_surface) {
+		return;
+	}
 	bool enabled = *(bool *)user_data;
 	wlr_scene_buffer_set_backdrop_blur(buffer, enabled);
 	wlr_scene_buffer_set_backdrop_blur_optimized(buffer, enabled);
diff --git a/src/xwayland_window.rs b/src/xwayland_window.rs
index 587e888..c1ed65d 100644
--- a/src/xwayland_window.rs
+++ b/src/xwayland_window.rs
@@ -96,7 +96,7 @@ impl XwaylandWindow {
         connect_listener(&mut (*xsurface).events.dissociate, &mut (*raw).dissociate, handle_dissociate);
         connect_listener(&mut (*xsurface).events.request_configure, &mut (*raw).request_configure, handle_request_configure);
         connect_listener(&mut (*xsurface).events.set_override_redirect, &mut (*raw).set_override_redirect, handle_set_override_redirect);
-        connect_listener(&mut (*xsurface).events.set_size_hints, &mut (*raw).set_size_hints, handle_set_size_hints);
+        // connect_listener(&mut (*xsurface).events.set_size_hints, &mut (*raw).set_size_hints, handle_set_size_hints);
         connect_listener(&mut (*xsurface).events.set_title, &mut (*raw).set_title, handle_set_title);
         connect_listener(&mut (*xsurface).events.set_class, &mut (*raw).set_class, handle_set_class);
         connect_listener(&mut (*xsurface).events.set_parent, &mut (*raw).set_parent, handle_set_parent);
diff --git a/wrapper.h b/wrapper.h
index 41cf574..efe0ca5 100644
--- a/wrapper.h
+++ b/wrapper.h
@@ -16,7 +16,7 @@
 #include <wlr/render/pixman.h>
 
 // Wlroots types
-#include <wlr/types/wlr_fixes.h>
+// #include <wlr/types/wlr_fixes.h>
 #include <wlr/types/wlr_compositor.h>
 #include <wlr/types/wlr_subcompositor.h>
 #include <wlr/types/wlr_data_device.h>
@@ -69,10 +69,11 @@
 #include <wlr/types/wlr_single_pixel_buffer_v1.h>
 #include <wlr/types/wlr_alpha_modifier_v1.h>
 #include <wlr/types/wlr_color_management_v1.h>
-#include <wlr/types/wlr_color_representation_v1.h>
+// #include <wlr/types/wlr_color_representation_v1.h>
 #include <wlr/types/wlr_linux_dmabuf_v1.h>
 #include <wlr/types/wlr_linux_drm_syncobj_v1.h>
 #include <scenefx/types/wlr_scene.h>
+#include <scenefx/render/fx_renderer/fx_renderer.h>
 
 #include <wlr/util/addon.h>
 #include <wlr/xwayland.h>