diff --git a/src/main.rs b/src/main.rs index 7964ea6..466ed6c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -192,13 +192,13 @@ fn main() { let mut wayland = wayland::Wayland::new().unwrap(); info!("Stardust ready!"); - if let Some(project_dirs) = project_dirs.as_ref() { + let startup_child = if let Some(project_dirs) = project_dirs.as_ref() { let startup_script_path = cli_args .startup_script .clone() .and_then(|p| p.canonicalize().ok()) .unwrap_or_else(|| project_dirs.config_dir().join("startup")); - let _startup = Command::new(startup_script_path) + Command::new(startup_script_path) .stdin(Stdio::null()) .env( "FLAT_WAYLAND_DISPLAY", @@ -218,8 +218,11 @@ fn main() { .env("MOZ_ENABLE_WAYLAND", "1") .env("CLUTTER_BACKEND", "wayland") .env("SDL_VIDEODRIVER", "wayland") - .spawn(); - } + .spawn() + .ok() + } else { + None + }; let mut last_frame_delta = Duration::ZERO; let mut sleep_duration = Duration::ZERO; @@ -273,14 +276,18 @@ fn main() { ) }); - #[cfg(feature = "wayland")] - let _wayland = ManuallyDrop::new(wayland); + if let Some(mut startup_child) = startup_child { + let _ = startup_child.kill(); + } let _ = event_stop_tx.send(()); event_thread .join() .expect("Failed to cleanly shut down event loop") .unwrap(); + #[cfg(feature = "wayland")] + let _wayland = ManuallyDrop::new(wayland); + info!("Cleanly shut down Stardust"); } diff --git a/src/nodes/items/environment.rs b/src/nodes/items/environment.rs index c2e17a0..c81c890 100644 --- a/src/nodes/items/environment.rs +++ b/src/nodes/items/environment.rs @@ -54,8 +54,8 @@ impl EnvironmentItem { } } impl ItemSpecialization for EnvironmentItem { - fn serialize_start_data(&self, id: &str) -> Vec { - serialize((id, self.path.as_str())).unwrap() + fn serialize_start_data(&self, id: &str) -> Option> { + serialize((id, self.path.as_str())).ok() } } diff --git a/src/nodes/items/mod.rs b/src/nodes/items/mod.rs index 8b5a86e..9887467 100644 --- a/src/nodes/items/mod.rs +++ b/src/nodes/items/mod.rs @@ -172,7 +172,7 @@ impl Drop for Item { } pub trait ItemSpecialization { - fn serialize_start_data(&self, id: &str) -> Vec; + fn serialize_start_data(&self, id: &str) -> Option>; } pub enum ItemType { @@ -240,10 +240,8 @@ impl ItemUI { self.item_aliases.add(item.uid.clone(), &alias_node); } - let _ = node.send_remote_signal( - "create_item", - &item.specialization.serialize_start_data(&item.uid), - ); + let Some(serialized_data) = item.specialization.serialize_start_data(&item.uid) else {return}; + let _ = node.send_remote_signal("create_item", &serialized_data); } fn handle_destroy_item(&self, item: &Item) { self.item_aliases.remove(&item.uid); @@ -360,10 +358,9 @@ impl ItemAcceptor { if let Ok(alias_node) = item.make_alias(&client, &node.path) { self.accepted_aliases.add(item.uid.clone(), &alias_node); } - let _ = node.send_remote_signal( - "capture", - &item.specialization.serialize_start_data(&item.uid), - ); + + let Some(serialized_data) = item.specialization.serialize_start_data(&item.uid) else {return}; + let _ = node.send_remote_signal("capture", &serialized_data); } fn handle_release(&self, item: &Item) { let Some(node) = self.node.upgrade() else { return }; diff --git a/src/wayland/panel_item.rs b/src/wayland/panel_item.rs index 12bfdad..6ca0123 100644 --- a/src/wayland/panel_item.rs +++ b/src/wayland/panel_item.rs @@ -156,50 +156,58 @@ pub enum RecommendedState { #[derive(Debug)] pub struct WaylandBackend { toplevel: WlWeak, + toplevel_wl_surface: WlWeak, popups: Mutex>>, cursor: Mutex>>, } impl WaylandBackend { - pub fn create(toplevel: XdgToplevel) -> Self { - WaylandBackend { + pub fn create(toplevel: XdgToplevel) -> Option { + let toplevel_wl_surface = + XdgSurfaceData::get(&ToplevelData::get(&toplevel).lock().xdg_surface()?)? + .lock() + .wl_surface()? + .downgrade(); + Some(WaylandBackend { toplevel: toplevel.downgrade(), + toplevel_wl_surface, popups: Mutex::new(FxHashMap::default()), cursor: Mutex::new(None), - } + }) } - fn toplevel(&self) -> XdgToplevel { - self.toplevel.upgrade().unwrap() + fn toplevel(&self) -> Option { + self.toplevel.upgrade().ok() } - fn toplevel_xdg_surface(&self) -> XdgSurface { - let toplevel = self.toplevel(); + fn toplevel_xdg_surface(&self) -> Option { + let toplevel = self.toplevel()?; let data = ToplevelData::get(&toplevel).lock(); data.xdg_surface() } - fn toplevel_wl_surface(&self) -> WlSurface { - XdgSurfaceData::get(&self.toplevel_xdg_surface()) - .lock() - .wl_surface() + fn toplevel_wl_surface(&self) -> Option { + self.toplevel_wl_surface.upgrade().ok() } fn wl_surface_from_id(&self, id: &SurfaceID) -> Option { match id { SurfaceID::Cursor => self.cursor.lock().clone()?.upgrade().ok(), - SurfaceID::Toplevel => Some(self.toplevel_wl_surface()), + SurfaceID::Toplevel => self.toplevel_wl_surface(), SurfaceID::Popup(popup) => { let popups = self.popups.lock(); let popup = popups.get(popup)?.upgrade().ok()?; - let surf = PopupData::get(&popup).lock().wl_surface(); - Some(surf) + let wl_surface = PopupData::get(&popup)?.lock().wl_surface(); + wl_surface } } } fn input_surfaces(&self) -> Vec { - let mut surfaces = vec![self.toplevel_wl_surface()]; + let mut surfaces = self + .toplevel_wl_surface() + .map(|s| vec![s]) + .unwrap_or_default(); surfaces.extend(self.popups.lock().values().filter_map(|p| { let popup = p.upgrade().ok()?; - let popup_data = PopupData::get(&popup).lock(); - let xdg_surface = popup_data.xdg_surface(); - let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock(); - Some(xdg_surface_data.wl_surface()) + let popup_data = PopupData::get(&popup)?.lock(); + let xdg_surface = popup_data.xdg_surface()?; + let xdg_surface_data = XdgSurfaceData::get(&xdg_surface)?.lock(); + xdg_surface_data.wl_surface() })); surfaces } @@ -211,7 +219,7 @@ impl WaylandBackend { bounds: Option>, ) { let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return}; - let xdg_surface = self.toplevel_xdg_surface(); + let Some(xdg_surface) = self.toplevel_xdg_surface() else {return}; debug!(?size, ?states, ?bounds, "Configure toplevel info"); if let Some(bounds) = bounds { if xdg_toplevel.version() > EVT_CONFIGURE_BOUNDS_SINCE { @@ -231,15 +239,19 @@ impl WaylandBackend { } fn serialize_toplevel(&self) -> Result> { - let toplevel = self.toplevel(); + let toplevel = self + .toplevel() + .ok_or_else(|| eyre!("Toplevel does not exist"))?; let state = ToplevelData::get(&toplevel); let data = serialize(&state.lock().clone())?; Ok(data) } fn set_toplevel_capabilities(&self, capabilities: Vec) { - self.toplevel().wm_capabilities(capabilities); - self.toplevel_xdg_surface().configure(SERIAL_COUNTER.inc()); + let Ok(xdg_toplevel) = self.toplevel.upgrade() else {return}; + xdg_toplevel.wm_capabilities(capabilities); + let Some(xdg_surface) = self.toplevel_xdg_surface() else {return}; + xdg_surface.configure(SERIAL_COUNTER.inc()); } pub fn new_popup(&self, panel_item: &PanelItem, popup: &XdgPopup, data: &PopupData) { @@ -259,13 +271,15 @@ impl WaylandBackend { ); } pub fn drop_popup(&self, panel_item: &PanelItem, uid: &str) { - if let Some(popup) = self - .popups - .lock() - .remove(uid) - .and_then(|popup| popup.upgrade().ok()?.data::>().cloned()) - { - panel_item.seat_data.drop_surface(&popup.wl_surface()); + 'seat_drop: { + let Some(popup) = self + .popups + .lock() + .remove(uid) else {break 'seat_drop}; + let Some(popup) = popup.upgrade().ok() else {break 'seat_drop}; + let Some(popup) = popup.data::>().cloned() else {break 'seat_drop}; + let Some(wl_surface) = popup.wl_surface() else {break 'seat_drop}; + panel_item.seat_data.drop_surface(&wl_surface); } let Some(node) = panel_item.node.upgrade() else { return }; @@ -457,14 +471,14 @@ impl PanelItem { Some(panel_item.clone()) } - fn toplevel_wl_surface(&self) -> WlSurface { + fn toplevel_wl_surface(&self) -> Option { match &self.backend { Backend::Wayland(w) => w.toplevel_wl_surface(), - Backend::X11(x) => x.toplevel.wl_surface().unwrap(), + Backend::X11(x) => x.toplevel.wl_surface(), } } fn core_surface(&self) -> Option> { - compositor::with_states(&self.toplevel_wl_surface(), |data| { + compositor::with_states(&self.toplevel_wl_surface()?, |data| { data.data_map.get::>().cloned() }) } @@ -616,7 +630,10 @@ impl PanelItem { keymap, match &panel_item.backend { Backend::Wayland(w) => w.input_surfaces(), - Backend::X11(_) => vec![panel_item.toplevel_wl_surface()], + Backend::X11(_) => panel_item + .toplevel_wl_surface() + .map(|s| vec![s]) + .unwrap_or_default(), }, ); @@ -666,7 +683,8 @@ impl PanelItem { let Some(panel_item) = PanelItem::from_node(node) else { return Ok(()) }; let Some(core_surface) = panel_item.core_surface() else { return Ok(()) }; if let Backend::Wayland(w) = &panel_item.backend { - if w.toplevel().version() < EVT_WM_CAPABILITIES_SINCE { + let Some(toplevel) = w.toplevel() else {return Ok(())}; + if toplevel.version() < EVT_WM_CAPABILITIES_SINCE { return Ok(()); } } @@ -707,17 +725,17 @@ impl PanelItem { } pub fn on_drop(&self) { - let toplevel = self.toplevel_wl_surface(); + let Some(toplevel) = self.toplevel_wl_surface() else {return}; self.seat_data.drop_surface(&toplevel); - debug!("Drop panel item"); + debug!("Dropped panel item gracefully"); } } impl ItemSpecialization for PanelItem { - fn serialize_start_data(&self, id: &str) -> Vec { + fn serialize_start_data(&self, id: &str) -> Option> { match &self.backend { Backend::Wayland(w) => { - let toplevel = w.toplevel(); + let toplevel = w.toplevel()?; let toplevel_state = ToplevelData::get(&toplevel); let toplevel_state = toplevel_state.lock().clone(); @@ -734,7 +752,7 @@ impl ItemSpecialization for PanelItem { keyboard_grab, ), )) - .unwrap() + .ok() } Backend::X11(x) => { let size = ( @@ -761,7 +779,7 @@ impl ItemSpecialization for PanelItem { None::, None::, ); - serialize((id, info)).unwrap() + serialize((id, info)).ok() } } } diff --git a/src/wayland/state.rs b/src/wayland/state.rs index 75ba131..fa0c996 100644 --- a/src/wayland/state.rs +++ b/src/wayland/state.rs @@ -130,7 +130,7 @@ impl WaylandState { ); let _output_global = output.create_global::(&display_handle); let mode = Mode { - size: (4096, 4096).into(), + size: (2048, 2048).into(), refresh: 60000, }; output.change_current_state( diff --git a/src/wayland/xdg_shell.rs b/src/wayland/xdg_shell.rs index 67956bc..a9a20de 100644 --- a/src/wayland/xdg_shell.rs +++ b/src/wayland/xdg_shell.rs @@ -220,11 +220,11 @@ impl XdgSurfaceData { geometry: None, } } - pub fn get(xdg_surface: &XdgSurface) -> &Mutex { - xdg_surface.data::>().unwrap() + pub fn get(xdg_surface: &XdgSurface) -> Option<&Mutex> { + xdg_surface.data::>() } - pub fn wl_surface(&self) -> WlSurface { - self.wl_surface.upgrade().unwrap() + pub fn wl_surface(&self) -> Option { + self.wl_surface.upgrade().ok() } pub fn panel_item(&self) -> Option> { self.panel_item.upgrade() @@ -274,23 +274,25 @@ impl Dispatch, WaylandState> for WaylandState let client_credentials = client.get_credentials(&state.display_handle).ok(); let seat_data = state.seats.get(&client.id()).unwrap().clone(); + let Some(wl_surface) = xdg_surface_data.lock().wl_surface() else {return}; CoreSurface::add_to( &state.display, state.display_handle.clone(), - &xdg_surface_data.lock().wl_surface(), + &wl_surface, { let toplevel = toplevel.downgrade(); move || { let toplevel = toplevel.upgrade().unwrap(); let toplevel_data = ToplevelData::get(&toplevel); - let xdg_surface = toplevel_data.lock().xdg_surface(); - let xdg_surface_data = XdgSurfaceData::get(&xdg_surface); - let wl_surface = xdg_surface_data.lock().wl_surface(); + let Some(xdg_surface) = toplevel_data.lock().xdg_surface() else {return}; + let Some(xdg_surface_data) = XdgSurfaceData::get(&xdg_surface) else {return}; + let Some(wl_surface) = xdg_surface_data.lock().wl_surface() else {return}; xdg_surface_data.lock().surface_id = SurfaceID::Toplevel; + let Some(backend) = WaylandBackend::create(toplevel.clone()) else {return}; let (node, panel_item) = PanelItem::create( wl_surface.clone(), - Backend::Wayland(WaylandBackend::create(toplevel.clone())), + Backend::Wayland(backend), client_credentials, seat_data.clone(), ); @@ -304,6 +306,7 @@ impl Dispatch, WaylandState> for WaylandState let toplevel = toplevel.upgrade().unwrap(); let toplevel_data = ToplevelData::get(&toplevel); let Some(panel_item) = toplevel_data.lock().panel_item() else { + let Some(xdg_surface) = toplevel_data.lock().xdg_surface() else {return}; // if the wayland toplevel isn't mapped, hammer it again with a configure until it cooperates toplevel.configure( 0, @@ -314,7 +317,6 @@ impl Dispatch, WaylandState> for WaylandState vec![] }, ); - let xdg_surface = toplevel_data.lock().xdg_surface(); xdg_surface.configure(SERIAL_COUNTER.inc()); return }; @@ -353,11 +355,10 @@ impl Dispatch, WaylandState> for WaylandState xdg_surface_data.lock().surface_id = SurfaceID::Popup(uid); let panel_item = parent_data.panel_item().unwrap(); xdg_surface_data.lock().panel_item = Arc::downgrade(&panel_item); - - panel_item.seat_data.new_surface( - &xdg_surface_data.lock().wl_surface(), - Arc::downgrade(&panel_item), - ); + let Some(wl_surface) = xdg_surface_data.lock().wl_surface() else {return}; + panel_item + .seat_data + .new_surface(&wl_surface, Arc::downgrade(&panel_item)); debug!(?xdg_popup, ?xdg_surface, "Create XDG popup"); let xdg_surface = xdg_surface.downgrade(); @@ -368,7 +369,7 @@ impl Dispatch, WaylandState> for WaylandState &xdg_surface_data.lock().wl_surface.upgrade().unwrap(), move || { let xdg_popup = xdg_popup.upgrade().unwrap(); - let popup_data = PopupData::get(&xdg_popup); + let Some(popup_data) = PopupData::get(&xdg_popup) else {return}; let popup_data = popup_data.lock(); // panel_item.commit_popup(popup_data); let Backend::Wayland(wayland_backend) = &panel_item.backend else {return}; @@ -444,21 +445,22 @@ impl ToplevelData { toplevel.data::>().unwrap() } - pub fn xdg_surface(&self) -> XdgSurface { - self.xdg_surface.upgrade().unwrap() + pub fn xdg_surface(&self) -> Option { + self.xdg_surface.upgrade().ok() } fn panel_item(&self) -> Option> { - let xdg_surface = self.xdg_surface(); - let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock(); + let xdg_surface = self.xdg_surface()?; + let xdg_surface_data = XdgSurfaceData::get(&xdg_surface)?.lock(); xdg_surface_data.panel_item() } } impl Serialize for ToplevelData { fn serialize(&self, serializer: S) -> Result { - let xdg_surface = self.xdg_surface(); - let xdg_surface_data = XdgSurfaceData::get(&xdg_surface).lock(); + let Some(xdg_surface) = self.xdg_surface() else {return serializer.serialize_none()}; + let Some(xdg_surface_data) = XdgSurfaceData::get(&xdg_surface) else {return serializer.serialize_none()}; + let xdg_surface_data = xdg_surface_data.lock(); let geometry = xdg_surface_data.geometry.clone(); - let wl_surface = xdg_surface_data.wl_surface(); + let Some(wl_surface) = xdg_surface_data.wl_surface() else {return serde_error::("Wayland surface not found")}; let Some(core_surface) = CoreSurface::from_wl_surface(&wl_surface) else {return serde_error::("Core surface not found")}; let Some(size) = core_surface.size() else {return serializer.serialize_none()}; let geometry = geometry.unwrap_or_else(|| Geometry { @@ -604,21 +606,25 @@ impl PopupData { xdg_surface: xdg_surface.downgrade(), } } - pub fn get(popup: &XdgPopup) -> &Mutex { - popup.data::>().unwrap() + pub fn get(popup: &XdgPopup) -> Option<&Mutex> { + popup.data::>() } - pub fn xdg_surface(&self) -> XdgSurface { - self.xdg_surface.upgrade().unwrap() + pub fn xdg_surface(&self) -> Option { + self.xdg_surface.upgrade().ok() } fn panel_item(&self) -> Option> { - XdgSurfaceData::get(&self.xdg_surface()).lock().panel_item() + XdgSurfaceData::get(&self.xdg_surface()?)? + .lock() + .panel_item() } // fn get_parent(&self) -> Option { // self.parent.as_ref()?.upgrade().ok() // } - pub fn wl_surface(&self) -> WlSurface { - XdgSurfaceData::get(&self.xdg_surface()).lock().wl_surface() + pub fn wl_surface(&self) -> Option { + XdgSurfaceData::get(&self.xdg_surface()?)? + .lock() + .wl_surface() } pub fn positioner_data(&self) -> Option { diff --git a/src/wayland/xwayland.rs b/src/wayland/xwayland.rs index 5a758dc..10fdda5 100644 --- a/src/wayland/xwayland.rs +++ b/src/wayland/xwayland.rs @@ -28,8 +28,8 @@ pub static DISPLAY: OnceCell = OnceCell::new(); pub struct XWaylandState { pub display: u32, - xwayland: XWayland, - event_loop_signal: LoopSignal, + _xwayland: XWayland, + _event_loop_signal: LoopSignal, event_loop_join: Option>>, } impl XWaylandState { @@ -71,8 +71,8 @@ impl XWaylandState { )?; let _ = tx.send(XWaylandState { display, - xwayland, - event_loop_signal: event_loop.get_signal(), + _xwayland: xwayland, + _event_loop_signal: event_loop.get_signal(), event_loop_join: None, }); let wayland_display_handle = wayland_display.lock().handle(); @@ -82,7 +82,7 @@ impl XWaylandState { wm: None, seat: None, }; - event_loop.run(Duration::from_secs(60 * 60), &mut handler, |_| ()) + event_loop.run(Duration::from_millis(100), &mut handler, |_| ()) }); let mut state = rx.blocking_recv()?; @@ -92,12 +92,12 @@ impl XWaylandState { Ok(state) } } -impl Drop for XWaylandState { - fn drop(&mut self) { - self.xwayland.shutdown(); - self.event_loop_signal.stop(); - } -} +// impl Drop for XWaylandState { +// fn drop(&mut self) { +// self.xwayland.shutdown(); +// self.event_loop_signal.stop(); +// } +// } struct XWaylandHandler { wayland_display: Arc>>,