mirror of
https://github.com/CloudNebulaProject/wayray.git
synced 2026-04-10 13:10:41 +00:00
Wire up Winit backend and calloop event loop for wrsrvd
Initialize WinitGraphicsBackend with GlesRenderer, create a virtual Output matching the window size, set up a Wayland listening socket via ListeningSocketSource, and run the main event loop through calloop with WinitEventLoop as an event source. The compositor now opens a window and accepts Wayland client connections.
This commit is contained in:
parent
383e91addf
commit
50c8f68906
2 changed files with 150 additions and 4 deletions
|
|
@ -2,11 +2,31 @@ mod errors;
|
|||
mod handlers;
|
||||
mod state;
|
||||
|
||||
use std::sync::Arc;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::handlers::ClientState;
|
||||
use crate::state::WayRay;
|
||||
use miette::Result;
|
||||
use smithay::reexports::wayland_server::Display;
|
||||
use smithay::{
|
||||
backend::{
|
||||
renderer::gles::GlesRenderer,
|
||||
winit::{self, WinitEvent},
|
||||
},
|
||||
output::{Mode, Output, PhysicalProperties, Subpixel},
|
||||
reexports::wayland_server::Display,
|
||||
utils::Transform,
|
||||
wayland::{compositor::CompositorClientState, socket::ListeningSocketSource},
|
||||
};
|
||||
use tracing::info;
|
||||
|
||||
/// Data accessible from calloop event callbacks.
|
||||
struct CalloopData {
|
||||
state: WayRay,
|
||||
display: Display<WayRay>,
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
tracing_subscriber::fmt()
|
||||
.with_env_filter(
|
||||
|
|
@ -17,10 +37,133 @@ fn main() -> Result<()> {
|
|||
|
||||
info!("wrsrvd starting");
|
||||
|
||||
// Create the Wayland display.
|
||||
let mut display = Display::<WayRay>::new()
|
||||
.map_err(|e| errors::WayRayError::DisplayInit(Box::new(e)))?;
|
||||
let _state = WayRay::new(&mut display);
|
||||
info!("compositor state initialized");
|
||||
|
||||
// Initialize the Winit backend (opens a window, creates a GlesRenderer).
|
||||
let (backend, winit_event_loop) = winit::init::<GlesRenderer>().map_err(|e| {
|
||||
errors::WayRayError::BackendInit(Box::<dyn std::error::Error + Send + Sync>::from(
|
||||
e.to_string(),
|
||||
))
|
||||
})?;
|
||||
info!("winit backend initialized");
|
||||
|
||||
// Create a virtual output matching the window size.
|
||||
let window_size = backend.window_size();
|
||||
let output = Output::new(
|
||||
"wayray-0".to_string(),
|
||||
PhysicalProperties {
|
||||
size: (0, 0).into(),
|
||||
subpixel: Subpixel::Unknown,
|
||||
make: "WayRay".to_string(),
|
||||
model: "Virtual".to_string(),
|
||||
},
|
||||
);
|
||||
|
||||
let mode = Mode {
|
||||
size: window_size,
|
||||
refresh: 60_000, // 60 Hz in millihertz
|
||||
};
|
||||
output.change_current_state(Some(mode), Some(Transform::Flipped180), None, None);
|
||||
output.set_preferred(mode);
|
||||
|
||||
// Create the global output for Wayland clients to bind to.
|
||||
output.create_global::<WayRay>(&display.handle());
|
||||
|
||||
// Create compositor state.
|
||||
let mut state = WayRay::new(&mut display, output.clone());
|
||||
|
||||
// Map the output into the compositor space.
|
||||
state.space.map_output(&output, (0, 0));
|
||||
info!("output mapped: {:?} @ {:?}", mode.size, mode.refresh);
|
||||
|
||||
// Create a Wayland listening socket for clients.
|
||||
let listening_socket = ListeningSocketSource::new_auto()
|
||||
.map_err(|e| errors::WayRayError::DisplayInit(Box::new(e)))?;
|
||||
let socket_name = listening_socket.socket_name().to_os_string();
|
||||
info!(?socket_name, "wayland socket created");
|
||||
|
||||
// Set WAYLAND_DISPLAY so child processes can find us.
|
||||
// SAFETY: This is called early in main before any other threads are spawned,
|
||||
// so there are no concurrent readers of the environment.
|
||||
unsafe { std::env::set_var("WAYLAND_DISPLAY", &socket_name) };
|
||||
|
||||
// Create the calloop event loop.
|
||||
let mut event_loop: smithay::reexports::calloop::EventLoop<CalloopData> =
|
||||
smithay::reexports::calloop::EventLoop::try_new()
|
||||
.map_err(|e| errors::WayRayError::EventLoop(Box::new(e)))?;
|
||||
|
||||
let loop_handle = event_loop.handle();
|
||||
|
||||
// Insert the Wayland listening socket as a calloop source.
|
||||
// When a new client connects, insert it into the display.
|
||||
loop_handle
|
||||
.insert_source(listening_socket, |client_stream, _, data| {
|
||||
data.display
|
||||
.handle()
|
||||
.insert_client(
|
||||
client_stream,
|
||||
Arc::new(ClientState {
|
||||
compositor_state: CompositorClientState::default(),
|
||||
}),
|
||||
)
|
||||
.ok();
|
||||
})
|
||||
.map_err(|e| errors::WayRayError::EventLoop(Box::new(e.error)))?;
|
||||
|
||||
// Shared flag to signal the main loop to exit.
|
||||
let running = Arc::new(AtomicBool::new(true));
|
||||
let running_clone = running.clone();
|
||||
|
||||
// Insert the Winit event loop as a calloop source.
|
||||
loop_handle
|
||||
.insert_source(winit_event_loop, move |event, _, _data| match event {
|
||||
WinitEvent::Resized { size, scale_factor } => {
|
||||
info!(?size, scale_factor, "window resized");
|
||||
}
|
||||
WinitEvent::Focus(focused) => {
|
||||
info!(focused, "window focus changed");
|
||||
}
|
||||
WinitEvent::Input(_event) => {
|
||||
// Input handling is Task 7 -- ignore for now.
|
||||
}
|
||||
WinitEvent::Redraw => {
|
||||
// Rendering is Task 6 -- ignore for now.
|
||||
}
|
||||
WinitEvent::CloseRequested => {
|
||||
info!("close requested, shutting down");
|
||||
running_clone.store(false, Ordering::SeqCst);
|
||||
}
|
||||
})
|
||||
.map_err(|e| errors::WayRayError::EventLoop(Box::new(e.error)))?;
|
||||
|
||||
// Keep a handle to the backend (needed for rendering in Task 6).
|
||||
let _backend = backend;
|
||||
|
||||
let mut calloop_data = CalloopData { state, display };
|
||||
|
||||
info!("entering main event loop");
|
||||
|
||||
// Main event loop.
|
||||
while running.load(Ordering::SeqCst) {
|
||||
// Dispatch Wayland clients.
|
||||
calloop_data
|
||||
.display
|
||||
.dispatch_clients(&mut calloop_data.state)
|
||||
.map_err(|e| errors::WayRayError::EventLoop(Box::new(e)))?;
|
||||
|
||||
calloop_data
|
||||
.display
|
||||
.flush_clients()
|
||||
.map_err(|e| errors::WayRayError::EventLoop(Box::new(e)))?;
|
||||
|
||||
// Dispatch calloop sources (Winit events + Wayland socket) with ~16ms timeout.
|
||||
event_loop
|
||||
.dispatch(Duration::from_millis(16), &mut calloop_data)
|
||||
.map_err(|e| errors::WayRayError::EventLoop(Box::new(e)))?;
|
||||
}
|
||||
|
||||
info!("wrsrvd shutting down");
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
use smithay::{
|
||||
desktop::Space,
|
||||
input::{Seat, SeatState},
|
||||
output::Output,
|
||||
reexports::wayland_server::{Display, DisplayHandle},
|
||||
utils::{Clock, Monotonic},
|
||||
wayland::{
|
||||
|
|
@ -28,11 +29,12 @@ pub struct WayRay {
|
|||
pub space: Space<smithay::desktop::Window>,
|
||||
pub seat: Seat<Self>,
|
||||
pub clock: Clock<Monotonic>,
|
||||
pub output: Output,
|
||||
}
|
||||
|
||||
impl WayRay {
|
||||
/// Create a new WayRay compositor state, initializing all Smithay subsystems.
|
||||
pub fn new(display: &mut Display<Self>) -> Self {
|
||||
pub fn new(display: &mut Display<Self>, output: Output) -> Self {
|
||||
let dh = display.handle();
|
||||
|
||||
let compositor_state = CompositorState::new::<Self>(&dh);
|
||||
|
|
@ -58,6 +60,7 @@ impl WayRay {
|
|||
space: Space::default(),
|
||||
seat,
|
||||
clock: Clock::new(),
|
||||
output,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue