diff --git a/local/recipes/wayland/redbear-compositor/source/src/main.rs b/local/recipes/wayland/redbear-compositor/source/src/main.rs index 5a34965def..857a92defd 100644 --- a/local/recipes/wayland/redbear-compositor/source/src/main.rs +++ b/local/recipes/wayland/redbear-compositor/source/src/main.rs @@ -934,6 +934,14 @@ const OBJECT_TYPE_ZWP_LINUX_DMABUF_V1: u32 = 31; const OBJECT_TYPE_ZWP_LINUX_BUFFER_PARAMS_V1: u32 = 32; const OBJECT_TYPE_WP_PRESENTATION: u32 = 33; const OBJECT_TYPE_WP_PRESENTATION_FEEDBACK: u32 = 34; +const OBJECT_TYPE_ZWLR_LAYER_SHELL_V1: u32 = 35; +const OBJECT_TYPE_ZWLR_LAYER_SURFACE_V1: u32 = 36; +const OBJECT_TYPE_ZWLR_OUTPUT_MANAGER_V1: u32 = 37; +const OBJECT_TYPE_ZWLR_OUTPUT_CONFIG_V1: u32 = 38; + +const ZWLR_LAYER_SURFACE_V1_CONFIGURE_EVENT: u16 = 0; +const ZWLR_OUTPUT_CONFIG_HEAD_V1_EVENT: u16 = 0; +const ZWLR_OUTPUT_CONFIG_V1_SUCCEEDED_EVENT: u16 = 0; // wl_subcompositor opcodes const WL_SUBCOMPOSITOR_GET_SUBSURFACE: u16 = 1; @@ -1382,6 +1390,16 @@ impl Compositor { interface: "wp_presentation".into(), version: 1, }, + Global { + name: 14, + interface: "zwlr_layer_shell_v1".into(), + version: 4, + }, + Global { + name: 15, + interface: "zwlr_output_manager_v1".into(), + version: 4, + }, ]; Ok(Self { @@ -1425,6 +1443,70 @@ impl Compositor { } } + fn stack_surface_relative( + client: &mut ClientState, + surface_id: u32, + sibling_surface_id: u32, + place_above: bool, + ) { + let sibling_z = client + .subsurfaces + .values() + .find(|ss| ss.surface_id == sibling_surface_id) + .map(|ss| ss.z_index) + .unwrap_or(0); + + if let Some(subsurface) = client + .subsurfaces + .values_mut() + .find(|ss| ss.surface_id == surface_id) + { + subsurface.z_index = if place_above { sibling_z + 1 } else { sibling_z - 1 }; + } + } + + fn disconnect_client(&self, client_id: u32, stream: &mut UnixStream, reason: &str) { + eprintln!("redbear-compositor: disconnecting client {}: {}", client_id, reason); + let _ = stream.shutdown(Shutdown::Both); + self.clients.lock().unwrap().remove(&client_id); + } + + fn write_event( + &self, + client_id: u32, + stream: &mut UnixStream, + msg: &[u8], + context: &str, + ) -> Result<(), String> { + match stream.write_all(msg) { + Ok(()) => Ok(()), + Err(err) => { + self.disconnect_client( + client_id, + stream, + &format!("{} write failed: {}", context, err), + ); + Err(format!("{} write failed: {}", context, err)) + } + } + } + + fn protocol_error( + &self, + client_id: u32, + stream: &mut UnixStream, + interface: &str, + object_id: u32, + opcode: u16, + ) -> Result { + let reason = format!( + "unexpected opcode {} on {} object {}", + opcode, interface, object_id + ); + self.disconnect_client(client_id, stream, &reason); + Err(reason) + } + pub fn run(&mut self) -> std::io::Result<()> { eprintln!("redbear-compositor: listening on Wayland socket"); let _ = std::fs::write( @@ -1469,8 +1551,12 @@ impl Compositor { Ok(()) } - fn send_globals(&self, stream: &mut UnixStream, registry_id: u32) { - // Advertise each global interface on the wl_registry object after get_registry. + fn send_globals( + &self, + client_id: u32, + stream: &mut UnixStream, + registry_id: u32, + ) -> Result<(), String> { for global in &self.globals { let mut payload = Vec::new(); push_u32(&mut payload, global.name); @@ -1480,30 +1566,48 @@ impl Compositor { let mut msg = Vec::with_capacity(8 + payload.len()); push_header(&mut msg, registry_id, WL_REGISTRY_GLOBAL, payload.len()); msg.extend_from_slice(&payload); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_registry.global")?; } + Ok(()) } - fn send_callback_done(&self, stream: &mut UnixStream, callback_id: u32, callback_data: u32) { + fn send_callback_done( + &self, + client_id: u32, + stream: &mut UnixStream, + callback_id: u32, + callback_data: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, callback_id, WL_CALLBACK_DONE, 4); push_u32(&mut msg, callback_data); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_callback.done") } - fn send_delete_id(&self, stream: &mut UnixStream, deleted_id: u32) { + fn send_delete_id( + &self, + client_id: u32, + stream: &mut UnixStream, + deleted_id: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, 1, WL_DISPLAY_DELETE_ID, 4); push_u32(&mut msg, deleted_id); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_display.delete_id") } #[allow(dead_code)] - fn send_global_remove(&self, stream: &mut UnixStream, registry_id: u32, name: u32) { + fn send_global_remove( + &self, + client_id: u32, + stream: &mut UnixStream, + registry_id: u32, + name: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, registry_id, WL_REGISTRY_GLOBAL_REMOVE, 4); push_u32(&mut msg, name); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_registry.global_remove") } fn handle_client(&self, client_id: u32, mut stream: UnixStream) { @@ -1584,7 +1688,7 @@ impl Compositor { } else { self.alloc_id() }; - self.send_callback_done(stream, callback_id, 0); + self.send_callback_done(client_id, stream, callback_id, 0)?; } WL_DISPLAY_DELETE_ID => { if payload.len() >= 4 { @@ -1614,7 +1718,7 @@ impl Compositor { } drop(clients); if send_globals { - self.send_globals(stream, registry_id); + self.send_globals(client_id, stream, registry_id)?; } } } @@ -1661,6 +1765,8 @@ impl Compositor { "zwp_linux_dmabuf_v1" => OBJECT_TYPE_ZWP_LINUX_DMABUF_V1, "wp_viewporter" => OBJECT_TYPE_WP_VIEWPORTER, "wp_presentation" => OBJECT_TYPE_WP_PRESENTATION, + "zwlr_layer_shell_v1" => OBJECT_TYPE_ZWLR_LAYER_SHELL_V1, + "zwlr_output_manager_v1" => OBJECT_TYPE_ZWLR_OUTPUT_MANAGER_V1, _ => { eprintln!( "redbear-compositor: unknown global interface '{}' bound to object {}", @@ -1672,17 +1778,17 @@ impl Compositor { client.objects.insert(new_id, type_id); client.object_versions.insert(new_id, object_version); if iface == "wl_shm" { - self.send_shm_format(stream, new_id, WL_SHM_FORMAT_ARGB8888); - self.send_shm_format(stream, new_id, WL_SHM_FORMAT_XRGB8888); + self.send_shm_format(client_id, stream, new_id, WL_SHM_FORMAT_ARGB8888)?; + self.send_shm_format(client_id, stream, new_id, WL_SHM_FORMAT_XRGB8888)?; } if iface == "wl_output" { - self.send_output_info(stream, new_id, object_version); + self.send_output_info(client_id, stream, new_id, object_version)?; } if iface == "wl_seat" { - self.send_seat_capabilities(stream, new_id, object_version); + self.send_seat_capabilities(client_id, stream, new_id, object_version)?; } if iface == "xdg_wm_base" { - self.send_xdg_wm_base_ping(stream, new_id); + self.send_xdg_wm_base_ping(client_id, stream, new_id)?; } } } @@ -1775,7 +1881,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } _ => { eprintln!( @@ -1849,7 +1955,7 @@ impl Compositor { client.shm_pools.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_SHM_POOL_RESIZE => { if payload.len() >= 4 { @@ -1881,7 +1987,7 @@ impl Compositor { client.surfaces.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_SURFACE_ATTACH => { if payload.len() >= 12 { @@ -1944,7 +2050,7 @@ impl Compositor { if let Some(buf_id) = release_id { if buf_id != 0 { - self.send_buffer_release(stream, buf_id); + self.send_buffer_release(client_id, stream, buf_id)?; } } } @@ -1956,7 +2062,12 @@ impl Compositor { let callback_id = u32::from_le_bytes([ payload[0], payload[1], payload[2], payload[3], ]); - self.send_callback_done(stream, callback_id, self.next_serial()); + self.send_callback_done( + client_id, + stream, + callback_id, + self.next_serial(), + )?; } } WL_SURFACE_SET_OPAQUE_REGION | WL_SURFACE_SET_INPUT_REGION => { @@ -2042,7 +2153,7 @@ impl Compositor { } drop(clients); if opcode == WL_SEAT_GET_KEYBOARD { - self.send_keyboard_setup(stream, new_id); + self.send_keyboard_setup(client_id, stream, new_id)?; } } } @@ -2053,7 +2164,7 @@ impl Compositor { client.object_versions.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } _ => { eprintln!( @@ -2095,7 +2206,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } XDG_WM_BASE_PONG => { // The compositor does not currently send xdg_wm_base.ping, but accepting @@ -2115,7 +2226,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } XDG_SURFACE_GET_TOPLEVEL => { if payload.len() >= 4 { @@ -2137,8 +2248,8 @@ impl Compositor { } drop(clients); let serial = self.next_serial(); - self.send_xdg_toplevel_configure(stream, toplevel_id); - self.send_xdg_surface_configure(stream, object_id, serial); + self.send_xdg_toplevel_configure(client_id, stream, toplevel_id)?; + self.send_xdg_surface_configure(client_id, stream, object_id, serial)?; } } XDG_SURFACE_GET_POPUP => { @@ -2152,8 +2263,8 @@ impl Compositor { } drop(clients); let serial = self.next_serial(); - self.send_xdg_popup_configure(stream, popup_id); - self.send_xdg_surface_configure(stream, object_id, serial); + self.send_xdg_popup_configure(client_id, stream, popup_id)?; + self.send_xdg_surface_configure(client_id, stream, object_id, serial)?; } } XDG_SURFACE_SET_WINDOW_GEOMETRY => { @@ -2198,7 +2309,7 @@ impl Compositor { client.object_versions.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } _ => { eprintln!( @@ -2225,7 +2336,7 @@ impl Compositor { } } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } _ => { eprintln!( @@ -2251,7 +2362,7 @@ impl Compositor { } } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } XDG_TOPLEVEL_SET_TITLE => { if let Some(title) = read_payload_string(payload) { @@ -2323,13 +2434,13 @@ impl Compositor { self.with_toplevel_state_mut(client_id, object_id, |ts| { ts.last_move_serial = read_payload_u32(payload, 0); }); - self.send_xdg_toplevel_configure(stream, object_id); + self.send_xdg_toplevel_configure(client_id, stream, object_id)?; } XDG_TOPLEVEL_RESIZE => { self.with_toplevel_state_mut(client_id, object_id, |ts| { ts.last_resize_serial = read_payload_u32(payload, 0); }); - self.send_xdg_toplevel_configure(stream, object_id); + self.send_xdg_toplevel_configure(client_id, stream, object_id)?; } _ => { eprintln!( @@ -2347,7 +2458,7 @@ impl Compositor { client.positioners.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } XDG_POSITIONER_SET_SIZE => { if let (Some(w), Some(h)) = (read_payload_i32(payload, 0), read_payload_i32(payload, 1)) { @@ -2465,7 +2576,7 @@ impl Compositor { } } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } XDG_POPUP_GRAB => { if payload.len() >= 8 { @@ -2501,13 +2612,18 @@ impl Compositor { ps.positioner_id = Some(positioner_id); if let Some(ref pos) = pos_state { if let Some((w, h)) = pos.size { - self.send_xdg_surface_configure(stream, object_id, self.next_serial()); + self.send_xdg_surface_configure( + client_id, + stream, + object_id, + self.next_serial(), + )?; } } } } drop(clients); - self.send_xdg_popup_repositioned(stream, object_id, token); + self.send_xdg_popup_repositioned(client_id, stream, object_id, token)?; } } _ => { @@ -2525,7 +2641,7 @@ impl Compositor { client.object_versions.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_POINTER_SET_CURSOR => { if let (Some(serial), Some(surface), Some(hotspot_x), Some(hotspot_y)) = ( @@ -2562,7 +2678,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_KEYBOARD_KEY | WL_KEYBOARD_ENTER | WL_KEYBOARD_LEAVE | WL_KEYBOARD_MODIFIERS | WL_KEYBOARD_REPEAT_INFO => { // Keyboard events dispatched to focused client surface when input daemon is wired. @@ -2582,14 +2698,15 @@ impl Compositor { let focused_surface = keyboard_state.focused_surface; drop(keyboard_state); if let Some(surface_id) = focused_surface { - let _ = self.send_keyboard_key_event( + self.send_keyboard_key_event( + client_id, stream, object_id, surface_id, event.time, event.keycode, event.state, - ); + )?; } } } @@ -2604,7 +2721,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } _ => { eprintln!( @@ -2650,7 +2767,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } ZXDG_DECORATION_MANAGER_V1_GET_TOPLEVEL_DECORATION => { if payload.len() >= 8 { @@ -2667,10 +2784,11 @@ impl Compositor { } drop(clients); self.send_zxdg_toplevel_decoration_configure( + client_id, stream, new_id, ZXDG_TOPLEVEL_DECORATION_MODE_SERVER_SIDE, - ); + )?; } } _ => { @@ -2688,14 +2806,15 @@ impl Compositor { client.decorations.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } ZXDG_TOPLEVEL_DECORATION_V1_SET_MODE | ZXDG_TOPLEVEL_DECORATION_V1_UNSET_MODE => { self.send_zxdg_toplevel_decoration_configure( + client_id, stream, object_id, ZXDG_TOPLEVEL_DECORATION_MODE_SERVER_SIDE, - ); + )?; } _ => { eprintln!( @@ -2711,7 +2830,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WP_VIEWPORTER_GET_VIEWPORT => { if payload.len() >= 8 { @@ -2745,7 +2864,7 @@ impl Compositor { client.xdg_to_surface.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WP_VIEWPORT_SET_SOURCE => { if let (Some(x), Some(y), Some(w), Some(h)) = ( @@ -2782,7 +2901,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } ZWP_LINUX_DMABUF_V1_CREATE_PARAMS => { if payload.len() >= 4 { @@ -2795,8 +2914,18 @@ impl Compositor { client.dmabuf_params.insert(new_id, DmabufParamsState::default()); } drop(clients); - self.send_linux_dmabuf_format(stream, object_id, DRM_FORMAT_XRGB8888); - self.send_linux_dmabuf_format(stream, object_id, DRM_FORMAT_ARGB8888); + self.send_linux_dmabuf_format( + client_id, + stream, + object_id, + DRM_FORMAT_XRGB8888, + )?; + self.send_linux_dmabuf_format( + client_id, + stream, + object_id, + DRM_FORMAT_ARGB8888, + )?; } } _ => { @@ -2814,7 +2943,7 @@ impl Compositor { client.dmabuf_params.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } ZWP_LINUX_BUFFER_PARAMS_V1_ADD => { if payload.len() >= 24 { @@ -2864,7 +2993,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WP_PRESENTATION_FEEDBACK => { if payload.len() >= 8 { @@ -2886,8 +3015,8 @@ impl Compositor { ); } drop(clients); - self.send_presentation_feedback_discarded(stream, new_id); - self.send_presentation_feedback_presented(stream, new_id); + self.send_presentation_feedback_discarded(client_id, stream, new_id)?; + self.send_presentation_feedback_presented(client_id, stream, new_id)?; } } _ => { @@ -2897,7 +3026,7 @@ impl Compositor { ); } }, - OBJECT_TYPE_WP_PRESENTATION_FEEDBACK => match opcode { +OBJECT_TYPE_WP_PRESENTATION_FEEDBACK => match opcode { WP_PRESENTATION_FEEDBACK_DESTROY => { let mut clients = self.clients.lock().unwrap(); if let Some(client) = clients.get_mut(&client_id) { @@ -2914,6 +3043,114 @@ impl Compositor { ); } }, + OBJECT_TYPE_ZWLR_LAYER_SHELL_V1 => match opcode { + ZWLR_LAYER_SHELL_V1_DESTROY => { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.objects.remove(&object_id); + } + drop(clients); + self.send_delete_id(stream, object_id); + } + ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE => { + if payload.len() >= 24 { + let new_id = u32::from_le_bytes([ + payload[0], payload[1], payload[2], payload[3], + ]); + let _surface_id = u32::from_le_bytes([ + payload[4], payload[5], payload[6], payload[7], + ]); + let _layer = u32::from_le_bytes([ + payload[8], payload[9], payload[10], payload[11], + ]); + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.objects.insert(new_id, OBJECT_TYPE_ZWLR_LAYER_SURFACE_V1); + } + drop(clients); + self.send_layer_surface_configure(stream, new_id); + } + } + _ => { + eprintln!( + "redbear-compositor: unhandled zwlr_layer_shell_v1 opcode {} on object {}", + opcode, object_id + ); + } + }, + OBJECT_TYPE_ZWLR_LAYER_SURFACE_V1 => match opcode { + ZWLR_LAYER_SURFACE_V1_DESTROY => { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.objects.remove(&object_id); + } + drop(clients); + self.send_delete_id(stream, object_id); + } + ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE => { + let _ = u32::from_le_bytes([ + payload[0], payload[1], payload[2], payload[3], + ]); + } + _ => { + eprintln!( + "redbear-compositor: unhandled zwlr_layer_surface_v1 opcode {} on object {}", + opcode, object_id + ); + } + }, + OBJECT_TYPE_ZWLR_OUTPUT_MANAGER_V1 => match opcode { + ZWLR_OUTPUT_MANAGER_V1_DESTROY => { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.objects.remove(&object_id); + } + drop(clients); + self.send_delete_id(stream, object_id); + } + ZWLR_OUTPUT_MANAGER_V1_CREATE_CONFIGURATION => { + if payload.len() >= 8 { + let new_id = u32::from_le_bytes([ + payload[0], payload[1], payload[2], payload[3], + ]); + let serial = self.next_serial(); + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.objects.insert(new_id, OBJECT_TYPE_ZWLR_OUTPUT_CONFIG_V1); + } + drop(clients); + self.send_output_config_serial(stream, new_id, serial); + } + } + _ => { + eprintln!( + "redbear-compositor: unhandled zwlr_output_manager_v1 opcode {} on object {}", + opcode, object_id + ); + } + }, + OBJECT_TYPE_ZWLR_OUTPUT_CONFIG_V1 => match opcode { + ZWLR_OUTPUT_CONFIG_V1_DESTROY => { + let mut clients = self.clients.lock().unwrap(); + if let Some(client) = clients.get_mut(&client_id) { + client.objects.remove(&object_id); + } + drop(clients); + self.send_delete_id(stream, object_id); + } + ZWLR_OUTPUT_CONFIG_V1_APPLY => { + self.send_output_config_succeeded(stream, object_id); + } + ZWLR_OUTPUT_CONFIG_V1_TEST => { + self.send_output_config_succeeded(stream, object_id); + } + _ => { + eprintln!( + "redbear-compositor: unhandled zwlr_output_config_v1 opcode {} on object {}", + opcode, object_id + ); + } + }, OBJECT_TYPE_WL_DATA_SOURCE => match opcode { WL_DATA_SOURCE_DESTROY => { let mut clients = self.clients.lock().unwrap(); @@ -2922,7 +3159,7 @@ impl Compositor { client.data_sources.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_DATA_SOURCE_OFFER => { if let Some(mime_type) = read_payload_string(payload) { @@ -2958,7 +3195,7 @@ impl Compositor { client.data_devices.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_DATA_DEVICE_START_DRAG => { // Accepted — drag-and-drop requires pointer-grab tracking, not yet wired. @@ -3011,7 +3248,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } _ => { eprintln!( @@ -3028,7 +3265,7 @@ impl Compositor { client.subsurfaces.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_SUBSURFACE_SET_POSITION => { if let (Some(x), Some(y)) = (read_payload_i32(payload, 0), read_payload_i32(payload, 1)) { @@ -3100,7 +3337,7 @@ impl Compositor { client.regions.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_REGION_ADD | WL_REGION_SUBTRACT => { if payload.len() >= 16 { @@ -3145,7 +3382,7 @@ impl Compositor { client.objects.remove(&object_id); } drop(clients); - self.send_delete_id(stream, object_id); + self.send_delete_id(client_id, stream, object_id)?; } WL_FIXES_DESTROY_REGISTRY => { if payload.len() >= 4 { @@ -3161,7 +3398,7 @@ impl Compositor { } } drop(clients); - self.send_delete_id(stream, registry_id); + self.send_delete_id(client_id, stream, registry_id)?; } } WL_FIXES_ACK_GLOBAL_REMOVE => { @@ -3269,20 +3506,36 @@ impl Compositor { } } - fn send_buffer_release(&self, stream: &mut UnixStream, buffer_id: u32) { + fn send_buffer_release( + &self, + client_id: u32, + stream: &mut UnixStream, + buffer_id: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(8); push_header(&mut msg, buffer_id, WL_BUFFER_RELEASE, 0); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_buffer.release") } - fn send_xdg_surface_configure(&self, stream: &mut UnixStream, surface_id: u32, serial: u32) { + fn send_xdg_surface_configure( + &self, + client_id: u32, + stream: &mut UnixStream, + surface_id: u32, + serial: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, surface_id, XDG_SURFACE_CONFIGURE, 4); push_u32(&mut msg, serial); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "xdg_surface.configure") } - fn send_xdg_toplevel_configure(&self, stream: &mut UnixStream, toplevel_id: u32) { + fn send_xdg_toplevel_configure( + &self, + client_id: u32, + stream: &mut UnixStream, + toplevel_id: u32, + ) -> Result<(), String> { let fb_w = self.fb_width as i32; let fb_h = self.fb_height as i32; let mut msg = Vec::with_capacity(20); @@ -3290,42 +3543,69 @@ impl Compositor { push_i32(&mut msg, fb_w); push_i32(&mut msg, fb_h); push_u32(&mut msg, 0); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "xdg_toplevel.configure") } - fn send_xdg_popup_configure(&self, stream: &mut UnixStream, popup_id: u32) { + fn send_xdg_popup_configure( + &self, + client_id: u32, + stream: &mut UnixStream, + popup_id: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(24); push_header(&mut msg, popup_id, XDG_POPUP_CONFIGURE, 16); push_i32(&mut msg, 0); push_i32(&mut msg, 0); push_i32(&mut msg, self.fb_width as i32); push_i32(&mut msg, self.fb_height as i32); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "xdg_popup.configure") } - fn send_xdg_popup_repositioned(&self, stream: &mut UnixStream, popup_id: u32, token: u32) { + fn send_xdg_popup_repositioned( + &self, + client_id: u32, + stream: &mut UnixStream, + popup_id: u32, + token: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, popup_id, XDG_POPUP_REPOSITIONED, 4); push_u32(&mut msg, token); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "xdg_popup.repositioned") } - fn send_xdg_wm_base_ping(&self, stream: &mut UnixStream, xdg_wm_base_id: u32) { + fn send_xdg_wm_base_ping( + &self, + client_id: u32, + stream: &mut UnixStream, + xdg_wm_base_id: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, xdg_wm_base_id, XDG_WM_BASE_PING, 4); push_u32(&mut msg, self.next_serial()); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "xdg_wm_base.ping") } - fn send_shm_format(&self, stream: &mut UnixStream, shm_id: u32, format: u32) { + fn send_shm_format( + &self, + client_id: u32, + stream: &mut UnixStream, + shm_id: u32, + format: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, shm_id, WL_SHM_FORMAT, 4); push_u32(&mut msg, format); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_shm.format") } - fn send_output_info(&self, stream: &mut UnixStream, output_id: u32, version: u32) { - // wl_output.geometry + fn send_output_info( + &self, + client_id: u32, + stream: &mut UnixStream, + output_id: u32, + version: u32, + ) -> Result<(), String> { { let mut payload = Vec::new(); push_i32(&mut payload, 0); @@ -3340,9 +3620,8 @@ impl Compositor { let mut msg = Vec::with_capacity(8 + payload.len()); push_header(&mut msg, output_id, WL_OUTPUT_GEOMETRY, payload.len()); msg.extend_from_slice(&payload); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_output.geometry")?; } - // wl_output.mode { let mut msg = Vec::with_capacity(24); push_header(&mut msg, output_id, WL_OUTPUT_MODE, 16); @@ -3350,15 +3629,13 @@ impl Compositor { push_i32(&mut msg, self.fb_width as i32); push_i32(&mut msg, self.fb_height as i32); push_i32(&mut msg, 60_000); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_output.mode")?; } - // wl_output.scale is v2+; wl_output.name/description are v4+. Only send events the - // client version made legal, because Qt binds older versions in some fallback paths. if version >= 2 { let mut msg = Vec::with_capacity(12); push_header(&mut msg, output_id, WL_OUTPUT_SCALE, 4); push_i32(&mut msg, 1); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_output.scale")?; } if version >= 4 { let mut payload = Vec::new(); @@ -3366,7 +3643,7 @@ impl Compositor { let mut msg = Vec::with_capacity(8 + payload.len()); push_header(&mut msg, output_id, WL_OUTPUT_NAME, payload.len()); msg.extend_from_slice(&payload); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_output.name")?; } if version >= 4 { let mut payload = Vec::new(); @@ -3374,35 +3651,46 @@ impl Compositor { let mut msg = Vec::with_capacity(8 + payload.len()); push_header(&mut msg, output_id, WL_OUTPUT_DESCRIPTION, payload.len()); msg.extend_from_slice(&payload); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_output.description")?; } if version >= 2 { let mut msg = Vec::with_capacity(8); push_header(&mut msg, output_id, WL_OUTPUT_DONE, 0); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_output.done")?; } + Ok(()) } - fn send_seat_capabilities(&self, stream: &mut UnixStream, seat_id: u32, version: u32) { - // wl_seat.capabilities — advertise pointer + keyboard for login UI. + fn send_seat_capabilities( + &self, + client_id: u32, + stream: &mut UnixStream, + seat_id: u32, + version: u32, + ) -> Result<(), String> { { let mut msg = Vec::with_capacity(12); push_header(&mut msg, seat_id, WL_SEAT_CAPABILITIES, 4); - push_u32(&mut msg, 0x3); // WL_SEAT_CAPABILITY_POINTER | WL_SEAT_CAPABILITY_KEYBOARD - let _ = stream.write_all(&msg); + push_u32(&mut msg, 0x3); + self.write_event(client_id, stream, &msg, "wl_seat.capabilities")?; } - // wl_seat.name is v2+ and is required by Qt6 to fully initialize the seat. if version >= 2 { let mut payload = Vec::new(); push_wayland_string(&mut payload, "seat0"); let mut msg = Vec::with_capacity(8 + payload.len()); push_header(&mut msg, seat_id, WL_SEAT_NAME, payload.len()); msg.extend_from_slice(&payload); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_seat.name")?; } + Ok(()) } - fn send_keyboard_setup(&self, stream: &mut UnixStream, keyboard_id: u32) { + fn send_keyboard_setup( + &self, + client_id: u32, + stream: &mut UnixStream, + keyboard_id: u32, + ) -> Result<(), String> { let fd = std::fs::File::open("/dev/null").ok().map(|file| file.into_raw_fd()); { @@ -3411,7 +3699,10 @@ impl Compositor { push_u32(&mut payload, 0); push_u32(&mut payload, 0); let fds = fd.iter().copied().collect::>(); - let _ = send_with_rights(stream, keyboard_id, WL_KEYBOARD_KEYMAP, &payload, &fds); + if let Err(err) = send_with_rights(stream, keyboard_id, WL_KEYBOARD_KEYMAP, &payload, &fds) { + self.disconnect_client(client_id, stream, &format!("wl_keyboard.keymap send failed: {}", err)); + return Err(format!("wl_keyboard.keymap send failed: {}", err)); + } } if let Some(fd) = fd { @@ -3423,7 +3714,7 @@ impl Compositor { push_header(&mut msg, keyboard_id, WL_KEYBOARD_REPEAT_INFO, 8); push_i32(&mut msg, 0); push_i32(&mut msg, 0); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_keyboard.repeat_info")?; } { @@ -3434,54 +3725,111 @@ impl Compositor { push_u32(&mut msg, 0); push_u32(&mut msg, 0); push_u32(&mut msg, 0); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wl_keyboard.modifiers")?; } + Ok(()) } fn send_keyboard_key_event( &self, + client_id: u32, stream: &mut UnixStream, keyboard_id: u32, _surface_id: u32, time: u32, keycode: u32, state: u32, - ) -> std::io::Result<()> { + ) -> Result<(), String> { let mut msg = Vec::with_capacity(24); push_header(&mut msg, keyboard_id, WL_KEYBOARD_KEY, 16); push_u32(&mut msg, self.next_serial()); push_u32(&mut msg, time); push_u32(&mut msg, keycode); push_u32(&mut msg, state); - stream.write_all(&msg) + self.write_event(client_id, stream, &msg, "wl_keyboard.key") } fn send_zxdg_toplevel_decoration_configure( &self, + client_id: u32, stream: &mut UnixStream, decoration_id: u32, mode: u32, - ) { + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, decoration_id, ZXDG_TOPLEVEL_DECORATION_V1_CONFIGURE, 4); push_u32(&mut msg, mode); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "zxdg_toplevel_decoration_v1.configure") } - fn send_linux_dmabuf_format(&self, stream: &mut UnixStream, dmabuf_id: u32, format: u32) { + fn send_linux_dmabuf_format( + &self, + client_id: u32, + stream: &mut UnixStream, + dmabuf_id: u32, + format: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(12); push_header(&mut msg, dmabuf_id, ZWP_LINUX_DMABUF_V1_FORMAT, 4); push_u32(&mut msg, format); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "zwp_linux_dmabuf_v1.format") } - fn send_presentation_feedback_discarded(&self, stream: &mut UnixStream, feedback_id: u32) { + fn send_presentation_feedback_discarded( + &self, + client_id: u32, + stream: &mut UnixStream, + feedback_id: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(8); push_header(&mut msg, feedback_id, WP_PRESENTATION_FEEDBACK_DISCARDED, 0); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wp_presentation_feedback.discarded") } - fn send_presentation_feedback_presented(&self, stream: &mut UnixStream, feedback_id: u32) { + fn send_layer_surface_configure( + &self, + client_id: u32, + stream: &mut UnixStream, + surface_id: u32, + _layer: u32, + ) -> Result<(), String> { + let mut msg = Vec::with_capacity(16); + push_header(&mut msg, surface_id, ZWLR_LAYER_SURFACE_V1_CONFIGURE_EVENT, 8); + push_u32(&mut msg, self.next_serial()); + push_u32(&mut msg, 0); + self.write_event(client_id, stream, &msg, "zwlr_layer_surface_v1.configure") + } + + fn send_output_config_serial( + &self, + client_id: u32, + stream: &mut UnixStream, + config_id: u32, + serial: u32, + ) -> Result<(), String> { + let mut msg = Vec::with_capacity(8); + push_header(&mut msg, config_id, ZWLR_OUTPUT_CONFIG_HEAD_V1_EVENT, 0); + let _ = serial; + self.write_event(client_id, stream, &msg, "zwlr_output_config_head_v1.serial") + } + + fn send_output_config_succeeded( + &self, + client_id: u32, + stream: &mut UnixStream, + config_id: u32, + ) -> Result<(), String> { + let mut msg = Vec::with_capacity(8); + push_header(&mut msg, config_id, ZWLR_OUTPUT_CONFIG_V1_SUCCEEDED_EVENT, 0); + self.write_event(client_id, stream, &msg, "zwlr_output_config_v1.succeeded") + } + + fn send_presentation_feedback_presented( + &self, + client_id: u32, + stream: &mut UnixStream, + feedback_id: u32, + ) -> Result<(), String> { let mut msg = Vec::with_capacity(40); push_header(&mut msg, feedback_id, WP_PRESENTATION_FEEDBACK_PRESENTED, 32); push_u32(&mut msg, 0); @@ -3492,7 +3840,7 @@ impl Compositor { push_u32(&mut msg, 0); push_u32(&mut msg, 0); push_u32(&mut msg, 0); - let _ = stream.write_all(&msg); + self.write_event(client_id, stream, &msg, "wp_presentation_feedback.presented") } } diff --git a/local/recipes/wayland/redbear-compositor/source/src/protocol.rs b/local/recipes/wayland/redbear-compositor/source/src/protocol.rs index 14c99020d4..8a5cc9433b 100644 --- a/local/recipes/wayland/redbear-compositor/source/src/protocol.rs +++ b/local/recipes/wayland/redbear-compositor/source/src/protocol.rs @@ -308,6 +308,46 @@ pub const WP_PRESENTATION_HINT_ZERO_COPY: u32 = 1 << 3; pub const OBJECT_TYPE_WP_PRESENTATION: u32 = 37; pub const OBJECT_TYPE_WP_PRESENTATION_FEEDBACK: u32 = 38; +pub const ZWLR_LAYER_SHELL_V1_DESTROY: u16 = 0; +pub const ZWLR_LAYER_SHELL_V1_GET_LAYER_SURFACE: u16 = 1; +pub const ZWLR_LAYER_SURFACE_V1_DESTROY: u16 = 0; +pub const ZWLR_LAYER_SURFACE_V1_SET_SIZE: u16 = 1; +pub const ZWLR_LAYER_SURFACE_V1_SET_ANCHOR: u16 = 2; +pub const ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_ZONE: u16 = 3; +pub const ZWLR_LAYER_SURFACE_V1_SET_MARGIN: u16 = 4; +pub const ZWLR_LAYER_SURFACE_V1_SET_KEYBOARD_INTERACTIVITY: u16 = 5; +pub const ZWLR_LAYER_SURFACE_V1_GET_POPUP: u16 = 6; +pub const ZWLR_LAYER_SURFACE_V1_ACK_CONFIGURE: u16 = 7; +pub const ZWLR_LAYER_SURFACE_V1_SET_LAYER: u16 = 8; +pub const ZWLR_LAYER_SURFACE_V1_SET_EXCLUSIVE_EDGE: u16 = 9; +pub const ZWLR_LAYER_SURFACE_V1_CONFIGURE_EVENT: u16 = 0; +pub const ZWLR_LAYER_SURFACE_V1_CLOSED_EVENT: u16 = 1; +pub const ZWLR_LAYER_SHELL_V1_LAYER_BACKGROUND: u32 = 0; +pub const ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM: u32 = 1; +pub const ZWLR_LAYER_SHELL_V1_LAYER_TOP: u32 = 2; +pub const ZWLR_LAYER_SHELL_V1_LAYER_OVERLAY: u32 = 3; +pub const OBJECT_TYPE_ZWLR_LAYER_SHELL_V1: u32 = 39; +pub const OBJECT_TYPE_ZWLR_LAYER_SURFACE_V1: u32 = 40; + +pub const ZWLR_OUTPUT_MANAGER_V1_DESTROY: u16 = 0; +pub const ZWLR_OUTPUT_MANAGER_V1_CREATE_CONFIGURATION: u16 = 1; +pub const ZWLR_OUTPUT_CONFIG_V1_DESTROY: u16 = 0; +pub const ZWLR_OUTPUT_CONFIG_V1_ENABLE_HEAD: u16 = 1; +pub const ZWLR_OUTPUT_CONFIG_V1_DISABLE_HEAD: u16 = 2; +pub const ZWLR_OUTPUT_CONFIG_V1_APPLY: u16 = 3; +pub const ZWLR_OUTPUT_CONFIG_V1_TEST: u16 = 4; +pub const ZWLR_OUTPUT_HEAD_V1_DESTROY: u16 = 0; +pub const ZWLR_OUTPUT_HEAD_V1_RELEASE: u16 = 1; +pub const ZWLR_OUTPUT_MODE_V1_DESTROY: u16 = 0; +pub const ZWLR_OUTPUT_MODE_V1_RELEASE: u16 = 1; +pub const ZWLR_OUTPUT_CONFIG_V1_APPLIED_EVENT: u16 = 0; +pub const ZWLR_OUTPUT_CONFIG_V1_SUCCEEDED_EVENT: u16 = 1; +pub const ZWLR_OUTPUT_CONFIG_HEAD_V1_EVENT: u16 = 0; +pub const OBJECT_TYPE_ZWLR_OUTPUT_MANAGER_V1: u32 = 41; +pub const OBJECT_TYPE_ZWLR_OUTPUT_CONFIG_V1: u32 = 42; +pub const OBJECT_TYPE_ZWLR_OUTPUT_HEAD_V1: u32 = 43; +pub const OBJECT_TYPE_ZWLR_OUTPUT_MODE_V1: u32 = 44; + pub const WL_SUBCOMPOSITOR_GET_SUBSURFACE: u16 = 1; pub const WL_SUBCOMPOSITOR_DESTROY: u16 = 0; pub const WL_SUBSURFACE_DESTROY: u16 = 0;