feat: startup script
This commit is contained in:
@@ -1,8 +1,6 @@
|
||||
use super::client::Client;
|
||||
use super::task;
|
||||
use color_eyre::eyre::Result;
|
||||
use once_cell::sync::OnceCell;
|
||||
use stardust_xr::server;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::AtomicU64;
|
||||
use std::sync::Arc;
|
||||
@@ -12,20 +10,12 @@ use tokio::task::JoinHandle;
|
||||
pub static FRAME: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
pub struct EventLoop {
|
||||
pub socket_path: PathBuf,
|
||||
join_handle: OnceCell<JoinHandle<()>>,
|
||||
join_handle: JoinHandle<()>,
|
||||
}
|
||||
|
||||
impl EventLoop {
|
||||
pub fn new() -> Result<Arc<Self>> {
|
||||
let socket_path = server::get_free_socket_path()
|
||||
.ok_or_else(|| std::io::Error::from(std::io::ErrorKind::Other))?;
|
||||
let socket = UnixListener::bind(socket_path.clone())?;
|
||||
|
||||
let event_loop = Arc::new(EventLoop {
|
||||
socket_path,
|
||||
join_handle: OnceCell::new(),
|
||||
});
|
||||
pub fn new(socket_path: PathBuf) -> Result<Arc<Self>> {
|
||||
let socket = UnixListener::bind(socket_path)?;
|
||||
|
||||
let join_handle = task::new(|| "event loop", async move {
|
||||
loop {
|
||||
@@ -33,7 +23,7 @@ impl EventLoop {
|
||||
Client::from_connection(socket);
|
||||
}
|
||||
})?;
|
||||
let _ = event_loop.join_handle.set(join_handle);
|
||||
let event_loop = Arc::new(EventLoop { join_handle });
|
||||
|
||||
Ok(event_loop)
|
||||
}
|
||||
@@ -41,8 +31,6 @@ impl EventLoop {
|
||||
|
||||
impl Drop for EventLoop {
|
||||
fn drop(&mut self) {
|
||||
if let Some(join_handle) = self.join_handle.take() {
|
||||
join_handle.abort();
|
||||
}
|
||||
self.join_handle.abort();
|
||||
}
|
||||
}
|
||||
|
||||
39
src/main.rs
39
src/main.rs
@@ -14,6 +14,9 @@ use self::core::eventloop::EventLoop;
|
||||
use clap::Parser;
|
||||
use color_eyre::eyre::Result;
|
||||
use directories::ProjectDirs;
|
||||
use stardust_xr::server;
|
||||
use std::path::PathBuf;
|
||||
use std::process::Command;
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
use stereokit::input::Handed;
|
||||
@@ -43,6 +46,11 @@ struct CliArgs {
|
||||
disable_controller: bool,
|
||||
}
|
||||
|
||||
struct EventLoopInfo {
|
||||
tokio_handle: Handle,
|
||||
socket_path: PathBuf,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
let registry = tracing_subscriber::registry();
|
||||
#[cfg(feature = "profile_app")]
|
||||
@@ -121,16 +129,25 @@ fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
let (event_stop_tx, event_stop_rx) = oneshot::channel::<()>();
|
||||
let (handle_sender, handle_receiver) = oneshot::channel::<Handle>();
|
||||
let (info_sender, info_receiver) = oneshot::channel::<EventLoopInfo>();
|
||||
let event_thread = std::thread::Builder::new()
|
||||
.name("event_loop".to_owned())
|
||||
.spawn(move || event_loop(handle_sender, event_stop_rx))?;
|
||||
let _tokio_handle = handle_receiver.blocking_recv()?.enter();
|
||||
.spawn(move || event_loop(info_sender, event_stop_rx))?;
|
||||
let event_loop_info = info_receiver.blocking_recv()?;
|
||||
let _tokio_handle = event_loop_info.tokio_handle.enter();
|
||||
|
||||
#[cfg(feature = "wayland")]
|
||||
let mut wayland = wayland::Wayland::new()?;
|
||||
info!("Stardust ready!");
|
||||
|
||||
let _startup = Command::new(project_dirs.config_dir().join("startup"))
|
||||
.env("WAYLAND_DISPLAY", &wayland.socket_name)
|
||||
.env(
|
||||
"STARDUST_INSTANCE",
|
||||
event_loop_info.socket_path.file_name().unwrap(),
|
||||
)
|
||||
.spawn();
|
||||
|
||||
let mut last_frame_delta = Duration::ZERO;
|
||||
let mut sleep_duration = Duration::ZERO;
|
||||
debug_span!("StereoKit").in_scope(|| {
|
||||
@@ -202,18 +219,20 @@ fn main() -> Result<()> {
|
||||
// #[tokio::main]
|
||||
#[tokio::main(flavor = "current_thread")]
|
||||
async fn event_loop(
|
||||
handle_sender: oneshot::Sender<Handle>,
|
||||
info_sender: oneshot::Sender<EventLoopInfo>,
|
||||
stop_rx: oneshot::Receiver<()>,
|
||||
) -> color_eyre::eyre::Result<()> {
|
||||
let _ = handle_sender.send(Handle::current());
|
||||
// console_subscriber::init();
|
||||
|
||||
let event_loop = EventLoop::new().expect("Couldn't create server socket");
|
||||
let socket_path = server::get_free_socket_path().unwrap();
|
||||
let _event_loop = EventLoop::new(socket_path.clone()).expect("Couldn't create server socket");
|
||||
info!("Init event loop");
|
||||
info!(
|
||||
"Stardust socket created at {}",
|
||||
event_loop.socket_path.display()
|
||||
socket_path = ?socket_path.display(),
|
||||
"Stardust socket created"
|
||||
);
|
||||
let _ = info_sender.send(EventLoopInfo {
|
||||
tokio_handle: Handle::current(),
|
||||
socket_path,
|
||||
});
|
||||
|
||||
let result = tokio::select! {
|
||||
biased;
|
||||
|
||||
@@ -5,6 +5,7 @@ use smithay::{
|
||||
wayland::compositor::{self, CompositorHandler, CompositorState},
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tracing::debug;
|
||||
|
||||
impl CompositorHandler for WaylandState {
|
||||
fn compositor_state(&mut self) -> &mut CompositorState {
|
||||
@@ -12,6 +13,7 @@ impl CompositorHandler for WaylandState {
|
||||
}
|
||||
|
||||
fn commit(&mut self, surface: &WlSurface) {
|
||||
debug!(?surface, "Surface commit");
|
||||
CoreSurface::add_to(&self.display, self.display_handle.clone(), surface);
|
||||
if let Some(panel_item) = compositor::with_states(surface, |data| {
|
||||
data.data_map.get::<Arc<PanelItem>>().cloned()
|
||||
|
||||
@@ -31,7 +31,7 @@ use stereokit as sk;
|
||||
use tokio::{
|
||||
io::unix::AsyncFd, net::UnixListener as AsyncUnixListener, sync::mpsc, task::JoinHandle,
|
||||
};
|
||||
use tracing::{info, instrument};
|
||||
use tracing::{debug, debug_span, info, instrument};
|
||||
|
||||
pub static SERIAL_COUNTER: CounterU32 = CounterU32::new(0);
|
||||
|
||||
@@ -62,6 +62,7 @@ pub struct Wayland {
|
||||
log: slog::Logger,
|
||||
|
||||
display: Arc<Mutex<Display<WaylandState>>>,
|
||||
pub socket_name: String,
|
||||
join_handle: JoinHandle<Result<()>>,
|
||||
renderer: Gles2Renderer,
|
||||
state: Arc<Mutex<WaylandState>>,
|
||||
@@ -92,12 +93,17 @@ impl Wayland {
|
||||
let (global_destroy_queue_in, global_destroy_queue) = mpsc::channel(8);
|
||||
GLOBAL_DESTROY_QUEUE.set(global_destroy_queue_in).unwrap();
|
||||
|
||||
let socket = ListeningSocket::bind_auto("wayland", 0..33)?;
|
||||
let socket_name = socket.socket_name().unwrap().to_str().unwrap().to_string();
|
||||
info!(socket_name, "Wayland active");
|
||||
|
||||
let join_handle =
|
||||
Wayland::start_loop(display.clone(), state.clone(), global_destroy_queue)?;
|
||||
Wayland::start_loop(display.clone(), socket, state.clone(), global_destroy_queue)?;
|
||||
|
||||
Ok(Wayland {
|
||||
log,
|
||||
display,
|
||||
socket_name,
|
||||
join_handle,
|
||||
renderer,
|
||||
state,
|
||||
@@ -106,14 +112,10 @@ impl Wayland {
|
||||
|
||||
fn start_loop(
|
||||
display: Arc<Mutex<Display<WaylandState>>>,
|
||||
socket: ListeningSocket,
|
||||
state: Arc<Mutex<WaylandState>>,
|
||||
mut global_destroy_queue: mpsc::Receiver<GlobalId>,
|
||||
) -> Result<JoinHandle<Result<()>>> {
|
||||
let socket = ListeningSocket::bind_auto("wayland", 0..33)?;
|
||||
if let Some(socket_name) = socket.socket_name() {
|
||||
info!("Wayland compositor {:?} active", socket_name);
|
||||
}
|
||||
|
||||
let listen_async =
|
||||
AsyncUnixListener::from_std(unsafe { UnixListener::from_raw_fd(socket.as_raw_fd()) })?;
|
||||
|
||||
@@ -128,6 +130,7 @@ impl Wayland {
|
||||
loop {
|
||||
tokio::select! {
|
||||
e = global_destroy_queue.recv() => { // New global to destroy
|
||||
debug!(?e, "destroy global");
|
||||
dh1.remove_global::<WaylandState>(e.unwrap());
|
||||
}
|
||||
acc = listen_async.accept() => { // New client connected
|
||||
@@ -138,9 +141,12 @@ impl Wayland {
|
||||
}
|
||||
e = dispatch_poll_listener.readable() => { // Dispatch
|
||||
let mut guard = e?;
|
||||
let mut display = display.lock();
|
||||
display.dispatch_clients(&mut *state.lock())?;
|
||||
display.flush_clients()?;
|
||||
debug_span!("Dispatch wayland event").in_scope(|| -> Result<(), color_eyre::Report> {
|
||||
let mut display = display.lock();
|
||||
display.dispatch_clients(&mut *state.lock())?;
|
||||
display.flush_clients()?;
|
||||
Ok(())
|
||||
})?;
|
||||
guard.clear_ready();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -40,6 +40,7 @@ use smithay::{
|
||||
};
|
||||
use stardust_xr::schemas::flex::{deserialize, serialize};
|
||||
use std::sync::{Arc, Weak};
|
||||
use tracing::debug;
|
||||
use xkbcommon::xkb::{self, ffi::XKB_KEYMAP_FORMAT_TEXT_V1, Keymap};
|
||||
|
||||
lazy_static! {
|
||||
@@ -98,7 +99,7 @@ impl Default for ToplevelState {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[derive(Debug, Clone, Copy, Serialize)]
|
||||
#[serde(tag = "type", content = "content")]
|
||||
pub enum RecommendedState {
|
||||
Maximize(bool),
|
||||
@@ -122,6 +123,7 @@ impl PanelItem {
|
||||
client_credentials: Option<Credentials>,
|
||||
seat_data: SeatData,
|
||||
) -> (Arc<Node>, Arc<PanelItem>) {
|
||||
debug!(?toplevel, ?client_credentials, "Create panel item");
|
||||
let node = Arc::new(Node::create(
|
||||
&INTERNAL_CLIENT,
|
||||
"/item/panel/item",
|
||||
@@ -241,7 +243,7 @@ impl PanelItem {
|
||||
calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct SurfaceMaterialInfo<'a> {
|
||||
model_path: &'a str,
|
||||
idx: u32,
|
||||
@@ -255,6 +257,7 @@ impl PanelItem {
|
||||
.model
|
||||
.get()
|
||||
.ok_or_else(|| eyre!("Node is not a model"))?;
|
||||
debug!(?info, "Apply toplevel material");
|
||||
|
||||
if let ItemType::Panel(panel_item) = &node.item.get().unwrap().specialization {
|
||||
if let Some(core_surface) = panel_item.core_surface() {
|
||||
@@ -274,12 +277,13 @@ impl PanelItem {
|
||||
let Some(cursor) = panel_item.seat_data.cursor() else { return Ok(())};
|
||||
let Some(core_surface) = CoreSurface::from_wl_surface(&cursor) else { return Ok(()) };
|
||||
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct SurfaceMaterialInfo<'a> {
|
||||
model_path: &'a str,
|
||||
idx: u32,
|
||||
}
|
||||
let info: SurfaceMaterialInfo = deserialize(data)?;
|
||||
debug!(?cursor, ?info, "Apply cursor material");
|
||||
let model_node = calling_client
|
||||
.scenegraph
|
||||
.get_node(info.model_path)
|
||||
@@ -307,6 +311,7 @@ impl PanelItem {
|
||||
let Some(wl_surface) = core_surface.wl_surface() else { return Ok(()) };
|
||||
let Some(pointer) = panel_item.seat_data.pointer() else { return Ok(()) };
|
||||
|
||||
debug!(?wl_surface, ?pointer, "Pointer deactivate");
|
||||
pointer.leave(SERIAL_COUNTER.inc(), &wl_surface);
|
||||
*panel_item.seat_data.pointer_focus.lock() = None;
|
||||
pointer.frame();
|
||||
@@ -327,6 +332,7 @@ impl PanelItem {
|
||||
let mut position: Vector2<f64> = deserialize(data)?;
|
||||
position.x = position.x.clamp(0.0, pointer_surface_size.x as f64);
|
||||
position.y = position.y.clamp(0.0, pointer_surface_size.y as f64);
|
||||
debug!(?wl_surface, ?pointer, ?position, "Pointer motion");
|
||||
|
||||
let mut pointer_focus = panel_item.seat_data.pointer_focus.lock();
|
||||
if let Some(old_surface) = pointer_focus
|
||||
@@ -358,6 +364,7 @@ impl PanelItem {
|
||||
let Some(pointer) = panel_item.seat_data.pointer() else { return Ok(()) };
|
||||
|
||||
let (button, state): (u32, u32) = deserialize(data)?;
|
||||
debug!(?pointer, button, state, "Pointer button");
|
||||
pointer.button(
|
||||
SERIAL_COUNTER.inc(),
|
||||
0,
|
||||
@@ -391,6 +398,8 @@ impl PanelItem {
|
||||
}
|
||||
let args: Option<PointerScrollArgs> = deserialize(data)?;
|
||||
|
||||
debug!(?pointer, "Pointer scroll");
|
||||
|
||||
match args {
|
||||
Some(args) => {
|
||||
pointer.axis(0, Axis::HorizontalScroll, args.axis_continuous.x as f64);
|
||||
@@ -430,7 +439,7 @@ impl PanelItem {
|
||||
_calling_client: Arc<Client>,
|
||||
data: &[u8],
|
||||
) -> Result<()> {
|
||||
#[derive(Deserialize)]
|
||||
#[derive(Debug, Deserialize)]
|
||||
struct Names<'a> {
|
||||
rules: &'a str,
|
||||
model: &'a str,
|
||||
@@ -462,12 +471,13 @@ impl PanelItem {
|
||||
|
||||
let mut keyboard_info = panel_item.seat_data.keyboard_info.lock();
|
||||
if keyboard_info.is_none() {
|
||||
debug!(?keyboard, ?wl_surface, "Activate keyboard");
|
||||
keyboard.enter(SERIAL_COUNTER.inc(), &wl_surface, vec![]);
|
||||
keyboard.repeat_info(0, 0);
|
||||
keyboard_info.replace(KeyboardInfo::new(keymap));
|
||||
keyboard_info.as_ref().unwrap().keymap.send(keyboard)?;
|
||||
core_surface.flush_clients();
|
||||
}
|
||||
keyboard_info.replace(KeyboardInfo::new(keymap));
|
||||
keyboard_info.as_ref().unwrap().keymap.send(keyboard)?;
|
||||
core_surface.flush_clients();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -482,6 +492,8 @@ impl PanelItem {
|
||||
let Some(wl_surface) = panel_item.toplevel_wl_surface() else { return Ok(()) };
|
||||
let Some(keyboard) = panel_item.seat_data.keyboard() else { return Ok(()) };
|
||||
|
||||
debug!(?keyboard, ?wl_surface, "Deactivate keyboard");
|
||||
|
||||
let mut keyboard_info = panel_item.seat_data.keyboard_info.lock();
|
||||
if keyboard_info.is_some() {
|
||||
keyboard.leave(SERIAL_COUNTER.inc(), &wl_surface);
|
||||
@@ -504,6 +516,7 @@ impl PanelItem {
|
||||
let mut keyboard_info = panel_item.seat_data.keyboard_info.lock();
|
||||
if let Some(keyboard_info) = &mut *keyboard_info {
|
||||
let (key, state): (u32, u32) = deserialize(data)?;
|
||||
debug!(?keyboard, key, state, "Set keyboard key state");
|
||||
keyboard_info.process(key, state, keyboard)?;
|
||||
core_surface.flush_clients();
|
||||
}
|
||||
@@ -529,6 +542,7 @@ impl PanelItem {
|
||||
}
|
||||
|
||||
let info: ConfigureToplevelInfo = deserialize(data)?;
|
||||
debug!(info = ?&info, "Configure toplevel info");
|
||||
if let Some(xdg_state) = panel_item.toplevel_state() {
|
||||
xdg_state.lock().queued_state.as_mut().unwrap().states = info.states.clone();
|
||||
}
|
||||
@@ -562,7 +576,9 @@ impl PanelItem {
|
||||
let Ok(xdg_toplevel) = panel_item.toplevel.upgrade() else { return Ok(()) };
|
||||
let Some(xdg_surface) = panel_item.toplevel_surface_data().and_then(|d| d.xdg_surface.upgrade().ok()) else { return Ok(()) };
|
||||
|
||||
xdg_toplevel.wm_capabilities(deserialize(data)?);
|
||||
let capabilities: Vec<u8> = deserialize(data)?;
|
||||
debug!("Set toplevel capabilities");
|
||||
xdg_toplevel.wm_capabilities(capabilities);
|
||||
xdg_surface.configure(SERIAL_COUNTER.inc());
|
||||
core_surface.flush_clients();
|
||||
|
||||
@@ -592,6 +608,8 @@ impl PanelItem {
|
||||
}
|
||||
}
|
||||
|
||||
debug!(state = ?&*state, "Commit toplevel");
|
||||
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
let queued_state = state.queued_state.take().unwrap();
|
||||
*state = (*queued_state).clone();
|
||||
@@ -602,14 +620,15 @@ impl PanelItem {
|
||||
|
||||
pub fn recommend_toplevel_state(&self, state: RecommendedState) {
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
dbg!(&state);
|
||||
let data = serialize(state).unwrap();
|
||||
debug!(?state, "Recommend toplevel state");
|
||||
|
||||
let _ = node.send_remote_signal("recommend_toplevel_state", &data);
|
||||
}
|
||||
|
||||
pub fn set_cursor(&self, surface: Option<&WlSurface>, hotspot_x: i32, hotspot_y: i32) {
|
||||
let Some(node) = self.node.upgrade() else { return };
|
||||
debug!(?surface, hotspot_x, hotspot_y, "Set cursor size");
|
||||
let mut data = serialize(()).unwrap();
|
||||
|
||||
let cursor_size = surface
|
||||
@@ -627,6 +646,8 @@ impl PanelItem {
|
||||
let Ok(toplevel_surface) = self.toplevel_surface.upgrade() else { return; };
|
||||
let Some(focused_surface) = self.seat_data.pointer_focused_surface() else { return; };
|
||||
|
||||
debug!("Drop panel item");
|
||||
|
||||
if focused_surface.id() == toplevel_surface.id() {
|
||||
let Some(pointer) = self.seat_data.pointer() else { return };
|
||||
pointer.leave(SERIAL_COUNTER.inc(), &toplevel_surface);
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use std::sync::Arc;
|
||||
use super::{
|
||||
panel_item::{PanelItem, RecommendedState, ToplevelState},
|
||||
state::WaylandState,
|
||||
@@ -24,6 +23,8 @@ use smithay::{
|
||||
},
|
||||
wayland::compositor,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
use tracing::{debug, warn};
|
||||
|
||||
impl GlobalDispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
fn bind(
|
||||
@@ -55,19 +56,26 @@ impl Dispatch<XdgWmBase, (), WaylandState> for WaylandState {
|
||||
) {
|
||||
match request {
|
||||
xdg_wm_base::Request::CreatePositioner { id } => {
|
||||
data_init.init(id, Arc::new(Mutex::new(PositionerData::default())));
|
||||
let positioner =
|
||||
data_init.init(id, Arc::new(Mutex::new(PositionerData::default())));
|
||||
debug!(?positioner, "Create XDG positioner");
|
||||
}
|
||||
xdg_wm_base::Request::GetXdgSurface { id, surface } => {
|
||||
data_init.init(
|
||||
let xdg_surface = data_init.init(
|
||||
id,
|
||||
WaylandSurface {
|
||||
wl_surface: surface.downgrade(),
|
||||
geometry: Arc::new(Mutex::new(None)),
|
||||
},
|
||||
);
|
||||
debug!(?xdg_surface, "Create XDG surface");
|
||||
}
|
||||
xdg_wm_base::Request::Pong { serial } => {
|
||||
debug!(serial, "Client pong");
|
||||
}
|
||||
xdg_wm_base::Request::Destroy => {
|
||||
debug!("Destroy XDG WM base");
|
||||
}
|
||||
xdg_wm_base::Request::Pong { serial: _ } => (),
|
||||
xdg_wm_base::Request::Destroy => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -103,7 +111,7 @@ impl Dispatch<XdgPositioner, Arc<Mutex<PositionerData>>, WaylandState> for Wayla
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
resource: &XdgPositioner,
|
||||
positioner: &XdgPositioner,
|
||||
request: xdg_positioner::Request,
|
||||
data: &Arc<Mutex<PositionerData>>,
|
||||
_dhandle: &DisplayHandle,
|
||||
@@ -111,6 +119,7 @@ impl Dispatch<XdgPositioner, Arc<Mutex<PositionerData>>, WaylandState> for Wayla
|
||||
) {
|
||||
match request {
|
||||
xdg_positioner::Request::SetSize { width, height } => {
|
||||
debug!(?positioner, width, height, "Set positioner size");
|
||||
data.lock().size = Vector2::from([width as u32, height as u32]);
|
||||
}
|
||||
xdg_positioner::Request::SetAnchorRect {
|
||||
@@ -120,43 +129,66 @@ impl Dispatch<XdgPositioner, Arc<Mutex<PositionerData>>, WaylandState> for Wayla
|
||||
height,
|
||||
} => {
|
||||
if width < 1 || height < 1 {
|
||||
resource.post_error(
|
||||
positioner.post_error(
|
||||
xdg_positioner::Error::InvalidInput,
|
||||
"Invalid size for positioner's anchor rectangle.",
|
||||
);
|
||||
warn!(
|
||||
?positioner,
|
||||
width, height, "Invalid size for positioner's anchor rectangle"
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
debug!(
|
||||
?positioner,
|
||||
x, y, width, height, "Set positioner anchor rectangle"
|
||||
);
|
||||
let mut data = data.lock();
|
||||
data.anchor_rect_pos = [x, y].into();
|
||||
data.anchor_rect_size = [width as u32, height as u32].into();
|
||||
}
|
||||
xdg_positioner::Request::SetAnchor { anchor } => {
|
||||
if let WEnum::Value(anchor) = anchor {
|
||||
debug!(?positioner, ?anchor, "Set positioner anchor");
|
||||
data.lock().anchor = anchor as u32;
|
||||
}
|
||||
}
|
||||
xdg_positioner::Request::SetGravity { gravity } => {
|
||||
if let WEnum::Value(gravity) = gravity {
|
||||
debug!(?positioner, ?gravity, "Set positioner gravity");
|
||||
data.lock().gravity = gravity as u32;
|
||||
}
|
||||
}
|
||||
xdg_positioner::Request::SetConstraintAdjustment {
|
||||
constraint_adjustment,
|
||||
} => {
|
||||
debug!(
|
||||
?positioner,
|
||||
constraint_adjustment, "Set positioner constraint adjustment"
|
||||
);
|
||||
data.lock().constraint_adjustment = constraint_adjustment;
|
||||
}
|
||||
xdg_positioner::Request::SetOffset { x, y } => {
|
||||
debug!(?positioner, x, y, "Set positioner offset");
|
||||
data.lock().offset = [x, y].into();
|
||||
}
|
||||
xdg_positioner::Request::SetReactive => {
|
||||
debug!(?positioner, "Set positioner reactive");
|
||||
data.lock().reactive = true;
|
||||
}
|
||||
xdg_positioner::Request::SetParentSize {
|
||||
parent_width: _,
|
||||
parent_height: _,
|
||||
} => (),
|
||||
xdg_positioner::Request::SetParentConfigure { serial: _ } => (),
|
||||
parent_width,
|
||||
parent_height,
|
||||
} => {
|
||||
debug!(
|
||||
?positioner,
|
||||
parent_width, parent_height, "Set positioner parent size"
|
||||
);
|
||||
}
|
||||
xdg_positioner::Request::SetParentConfigure { serial } => {
|
||||
debug!(?positioner, serial, "Set positioner parent size");
|
||||
}
|
||||
xdg_positioner::Request::Destroy => (),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
@@ -196,6 +228,7 @@ impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
},
|
||||
},
|
||||
);
|
||||
debug!(?toplevel, ?xdg_surface, "Create XDG toplevel");
|
||||
|
||||
if toplevel.version() >= EVT_WM_CAPABILITIES_SINCE {
|
||||
toplevel.wm_capabilities(vec![]);
|
||||
@@ -218,7 +251,9 @@ impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
parent: _,
|
||||
positioner: _,
|
||||
} => {
|
||||
data_init.init(id, ());
|
||||
let popup = data_init.init(id, ());
|
||||
debug!(?popup, ?xdg_surface, "Create XDG popup");
|
||||
popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
||||
}
|
||||
xdg_surface::Request::SetWindowGeometry {
|
||||
x,
|
||||
@@ -226,6 +261,10 @@ impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
width,
|
||||
height,
|
||||
} => {
|
||||
debug!(
|
||||
?xdg_surface,
|
||||
x, y, width, height, "Set XDG surface geometry"
|
||||
);
|
||||
let geometry = SurfaceGeometry {
|
||||
origin: [x as u32, y as u32].into(),
|
||||
size: [width as u32, height as u32].into(),
|
||||
@@ -239,8 +278,12 @@ impl Dispatch<XdgSurface, WaylandSurface, WaylandState> for WaylandState {
|
||||
data.data_map.insert_if_missing_threadsafe(|| geometry);
|
||||
});
|
||||
}
|
||||
xdg_surface::Request::AckConfigure { serial: _ } => (),
|
||||
xdg_surface::Request::Destroy => (),
|
||||
xdg_surface::Request::AckConfigure { serial } => {
|
||||
debug!(?xdg_surface, serial, "Acknowledge XDG surface configure");
|
||||
}
|
||||
xdg_surface::Request::Destroy => {
|
||||
debug!(?xdg_surface, "Destroy XDG surface");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
@@ -263,7 +306,7 @@ impl Dispatch<XdgToplevel, XdgToplevelData, WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
_resource: &XdgToplevel,
|
||||
xdg_toplevel: &XdgToplevel,
|
||||
request: xdg_toplevel::Request,
|
||||
data: &XdgToplevelData,
|
||||
_dhandle: &DisplayHandle,
|
||||
@@ -271,46 +314,63 @@ impl Dispatch<XdgToplevel, XdgToplevelData, WaylandState> for WaylandState {
|
||||
) {
|
||||
match request {
|
||||
xdg_toplevel::Request::SetParent { parent } => {
|
||||
debug!(?xdg_toplevel, ?parent, "Set XDG Toplevel parent");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.parent = parent.map(|toplevel| toplevel.downgrade());
|
||||
}
|
||||
xdg_toplevel::Request::SetTitle { title } => {
|
||||
debug!(?xdg_toplevel, ?title, "Set XDG Toplevel title");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.title = (!title.is_empty()).then_some(title);
|
||||
}
|
||||
xdg_toplevel::Request::SetAppId { app_id } => {
|
||||
debug!(?xdg_toplevel, ?app_id, "Set XDG Toplevel app ID");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.app_id = (!app_id.is_empty()).then_some(app_id);
|
||||
}
|
||||
xdg_toplevel::Request::ShowWindowMenu {
|
||||
seat: _,
|
||||
serial: _,
|
||||
x: _,
|
||||
y: _,
|
||||
} => (),
|
||||
xdg_toplevel::Request::Move { seat: _, serial: _ } => {
|
||||
xdg_toplevel::Request::ShowWindowMenu { seat, serial, x, y } => {
|
||||
debug!(
|
||||
?xdg_toplevel,
|
||||
?seat,
|
||||
serial,
|
||||
x,
|
||||
y,
|
||||
"Show XDG Toplevel window menu"
|
||||
);
|
||||
}
|
||||
xdg_toplevel::Request::Move { seat, serial } => {
|
||||
debug!(?xdg_toplevel, ?seat, serial, "XDG Toplevel move request");
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Move);
|
||||
}
|
||||
xdg_toplevel::Request::Resize {
|
||||
seat: _,
|
||||
serial: _,
|
||||
seat,
|
||||
serial,
|
||||
edges,
|
||||
} => {
|
||||
let WEnum::Value(edges) = edges else { return };
|
||||
debug!(
|
||||
?xdg_toplevel,
|
||||
?seat,
|
||||
serial,
|
||||
?edges,
|
||||
"XDG Toplevel resize request"
|
||||
);
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Resize(edges as u32));
|
||||
}
|
||||
xdg_toplevel::Request::SetMaxSize { width, height } => {
|
||||
debug!(?xdg_toplevel, width, height, "Set XDG Toplevel max size");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.max_size = (width > 1 || height > 1)
|
||||
.then_some(Vector2::from([width as u32, height as u32]));
|
||||
}
|
||||
xdg_toplevel::Request::SetMinSize { width, height } => {
|
||||
debug!(?xdg_toplevel, width, height, "Set XDG Toplevel min size");
|
||||
let mut state = data.state.lock();
|
||||
let queued_state = state.queued_state.as_mut().unwrap();
|
||||
queued_state.min_size = (width > 1 || height > 1)
|
||||
@@ -337,6 +397,7 @@ impl Dispatch<XdgToplevel, XdgToplevelData, WaylandState> for WaylandState {
|
||||
panel_item.recommend_toplevel_state(RecommendedState::Minimize);
|
||||
}
|
||||
xdg_toplevel::Request::Destroy => {
|
||||
debug!(?xdg_toplevel, "Destroy XDG Toplevel");
|
||||
let Some(panel_item) = data.panel_item() else { return };
|
||||
panel_item.on_drop();
|
||||
}
|
||||
@@ -349,19 +410,24 @@ impl Dispatch<XdgPopup, (), WaylandState> for WaylandState {
|
||||
fn request(
|
||||
_state: &mut WaylandState,
|
||||
_client: &Client,
|
||||
_resource: &XdgPopup,
|
||||
xdg_popup: &XdgPopup,
|
||||
request: xdg_popup::Request,
|
||||
_data: &(),
|
||||
_dhandle: &DisplayHandle,
|
||||
_data_init: &mut DataInit<'_, WaylandState>,
|
||||
) {
|
||||
match request {
|
||||
xdg_popup::Request::Grab { seat: _, serial: _ } => (),
|
||||
xdg_popup::Request::Reposition {
|
||||
positioner: _,
|
||||
token: _,
|
||||
} => (),
|
||||
xdg_popup::Request::Destroy => (),
|
||||
xdg_popup::Request::Grab { seat, serial } => {
|
||||
debug!(?xdg_popup, ?seat, serial, "XDG popup grab");
|
||||
xdg_popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
||||
}
|
||||
xdg_popup::Request::Reposition { positioner, token } => {
|
||||
debug!(?xdg_popup, ?positioner, token, "XDG popup reposition");
|
||||
xdg_popup.popup_done(); // temporary hack to avoid apps locking up before popups are implemented
|
||||
}
|
||||
xdg_popup::Request::Destroy => {
|
||||
debug!(?xdg_popup, "Destroy XDG popup");
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user