mirror of
https://github.com/marcoallegretti/WEFT_OS.git
synced 2026-03-27 01:13:09 +00:00
feat(servo-shell): dispatch shell client event queue in servo event loop
Wire ShellClient into App so its Wayland event queue is dispatched each frame via about_to_wait. This ensures configure, focus_changed, and window_closed events from the compositor are processed. window_closed now triggers a clean Servo shutdown. The EGL rendering path (WindowRenderingContext + surfman eglSwapBuffers) produces frames transparently via Mesa DMA-BUF buffer sharing; no explicit zwp_linux_dmabuf_v1 code is required in the shell. Remaining: ZweftShellWindowV1 is created with surface=null; sharing the winit wl_surface with the shell client connection is not currently feasible without refactoring to a single shared Wayland connection.
This commit is contained in:
parent
c244a58844
commit
3ee2f283d8
3 changed files with 43 additions and 13 deletions
|
|
@ -64,19 +64,28 @@ On Fedora/RHEL: `mesa-libGL-devel openssl-devel dbus-devel systemd-devel libxkbc
|
||||||
Default: `SoftwareRenderingContext` (CPU rasterisation) blitted to a
|
Default: `SoftwareRenderingContext` (CPU rasterisation) blitted to a
|
||||||
`softbuffer`-backed winit window.
|
`softbuffer`-backed winit window.
|
||||||
|
|
||||||
EGL path (scaffolded): set `WEFT_EGL_RENDERING=1` at runtime. The embedder
|
EGL path: set `WEFT_EGL_RENDERING=1` at runtime. The embedder attempts
|
||||||
attempts `WindowRenderingContext::new` using the winit display and window
|
`WindowRenderingContext::new` using the winit display and window handles.
|
||||||
handles. If construction fails it falls back to software automatically.
|
If construction fails it falls back to software automatically.
|
||||||
When the EGL path is active Servo presents directly to the EGL surface;
|
When the EGL path is active Servo presents directly to the EGL surface via
|
||||||
the softbuffer blit is skipped. Full DMA-BUF export to the Wayland
|
surfman's `eglSwapBuffers`; the softbuffer blit is skipped. Mesa handles
|
||||||
compositor is not yet wired (`RenderingCtx::Egl` blit body is a no-op).
|
DMA-BUF buffer sharing with the compositor transparently.
|
||||||
|
|
||||||
## Known gaps at this pin
|
## Known gaps at this pin
|
||||||
|
|
||||||
- **GAP-1**: ~~Wayland input events not forwarded to Servo~~ **Resolved** — keyboard and
|
- **GAP-1**: ~~Wayland input events not forwarded to Servo~~ **Resolved** — keyboard and
|
||||||
mouse events forwarded via `webview.notify_input_event`; key mapping in `keyutils.rs`.
|
mouse events forwarded via `webview.notify_input_event`; key mapping in `keyutils.rs`.
|
||||||
- **GAP-2**: EGL `WindowRenderingContext` path scaffolded (`WEFT_EGL_RENDERING=1`);
|
- **GAP-2**: EGL `WindowRenderingContext` path scaffolded (`WEFT_EGL_RENDERING=1`).
|
||||||
DMA-BUF export to the Wayland compositor (linux-dmabuf-unstable-v1) not yet wired.
|
When EGL is active, Servo presents frames via surfman's `eglSwapBuffers`; Mesa handles
|
||||||
|
DMA-BUF buffer sharing with the compositor transparently — no explicit
|
||||||
|
`zwp_linux_dmabuf_v1` code is needed in the shell for basic rendering.
|
||||||
|
The `zweft_shell_manager_v1` event queue is now dispatched each frame so `configure`,
|
||||||
|
`focus_changed`, and `window_closed` events are processed; `window_closed` triggers a
|
||||||
|
clean Servo shutdown.
|
||||||
|
Remaining gap: the `ZweftShellWindowV1` is created with `surface = null`; the winit
|
||||||
|
`wl_surface` is not yet associated with the shell window slot (requires sharing a single
|
||||||
|
Wayland connection between winit and the shell client, which is not currently feasible
|
||||||
|
without significant refactoring).
|
||||||
- **GAP-3**: WebGPU adapter on Mesa may fail CTS — validation task, requires Mesa GPU hardware.
|
- **GAP-3**: WebGPU adapter on Mesa may fail CTS — validation task, requires Mesa GPU hardware.
|
||||||
- **GAP-4**: ~~CSS Grid~~ **Grid resolved** (Taffy-backed, fully wired).
|
- **GAP-4**: ~~CSS Grid~~ **Grid resolved** (Taffy-backed, fully wired).
|
||||||
~~CSS `backdrop-filter` unimplemented~~ **`backdrop-filter` resolved** (servo/servo issue
|
~~CSS `backdrop-filter` unimplemented~~ **`backdrop-filter` resolved** (servo/servo issue
|
||||||
|
|
|
||||||
|
|
@ -99,6 +99,7 @@ struct App {
|
||||||
shutting_down: bool,
|
shutting_down: bool,
|
||||||
modifiers: ModifiersState,
|
modifiers: ModifiersState,
|
||||||
cursor_pos: servo::euclid::default::Point2D<f32>,
|
cursor_pos: servo::euclid::default::Point2D<f32>,
|
||||||
|
shell_client: Option<crate::shell_client::ShellClient>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
|
@ -107,6 +108,7 @@ impl App {
|
||||||
waker: WeftEventLoopWaker,
|
waker: WeftEventLoopWaker,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
app_rx: mpsc::Receiver<crate::appd_ws::AppdCmd>,
|
app_rx: mpsc::Receiver<crate::appd_ws::AppdCmd>,
|
||||||
|
shell_client: Option<crate::shell_client::ShellClient>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
url,
|
url,
|
||||||
|
|
@ -123,6 +125,7 @@ impl App {
|
||||||
shutting_down: false,
|
shutting_down: false,
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
cursor_pos: servo::euclid::default::Point2D::zero(),
|
cursor_pos: servo::euclid::default::Point2D::zero(),
|
||||||
|
shell_client,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -246,6 +249,18 @@ impl ApplicationHandler<ServoWake> for App {
|
||||||
event_loop.exit();
|
event_loop.exit();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if let Some(sc) = &mut self.shell_client {
|
||||||
|
match sc.dispatch_pending() {
|
||||||
|
Ok(false) => {
|
||||||
|
self.shutting_down = true;
|
||||||
|
if let Some(servo) = &self.servo {
|
||||||
|
servo.start_shutting_down();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => tracing::warn!("shell client dispatch error: {e}"),
|
||||||
|
Ok(true) => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
while let Ok(cmd) = self.app_rx.try_recv() {
|
while let Ok(cmd) = self.app_rx.try_recv() {
|
||||||
match cmd {
|
match cmd {
|
||||||
crate::appd_ws::AppdCmd::Launch { session_id, app_id } => {
|
crate::appd_ws::AppdCmd::Launch { session_id, app_id } => {
|
||||||
|
|
@ -418,7 +433,11 @@ fn app_store_roots() -> Vec<PathBuf> {
|
||||||
roots
|
roots
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run(html_path: &Path, ws_port: u16) -> anyhow::Result<()> {
|
pub fn run(
|
||||||
|
html_path: &Path,
|
||||||
|
ws_port: u16,
|
||||||
|
shell_client: Option<crate::shell_client::ShellClient>,
|
||||||
|
) -> anyhow::Result<()> {
|
||||||
let url_str = format!("file://{}", html_path.display());
|
let url_str = format!("file://{}", html_path.display());
|
||||||
let raw_url =
|
let raw_url =
|
||||||
ServoUrl::parse(&url_str).map_err(|e| anyhow::anyhow!("invalid URL {url_str}: {e}"))?;
|
ServoUrl::parse(&url_str).map_err(|e| anyhow::anyhow!("invalid URL {url_str}: {e}"))?;
|
||||||
|
|
@ -436,7 +455,7 @@ pub fn run(html_path: &Path, ws_port: u16) -> anyhow::Result<()> {
|
||||||
let waker_for_thread = waker.clone();
|
let waker_for_thread = waker.clone();
|
||||||
crate::appd_ws::spawn_appd_listener(ws_port, app_tx, Box::new(move || waker_for_thread.wake()));
|
crate::appd_ws::spawn_appd_listener(ws_port, app_tx, Box::new(move || waker_for_thread.wake()));
|
||||||
|
|
||||||
let mut app = App::new(url, waker, ws_port, app_rx);
|
let mut app = App::new(url, waker, ws_port, app_rx, shell_client);
|
||||||
event_loop
|
event_loop
|
||||||
.run_app(&mut app)
|
.run_app(&mut app)
|
||||||
.map_err(|e| anyhow::anyhow!("event loop run: {e}"))
|
.map_err(|e| anyhow::anyhow!("event loop run: {e}"))
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ fn run() -> anyhow::Result<()> {
|
||||||
let ws_port = appd_ws_port();
|
let ws_port = appd_ws_port();
|
||||||
tracing::info!(ws_port, "appd WebSocket port");
|
tracing::info!(ws_port, "appd WebSocket port");
|
||||||
|
|
||||||
let _shell = match shell_client::ShellClient::connect() {
|
let shell = match shell_client::ShellClient::connect() {
|
||||||
Ok(c) => {
|
Ok(c) => {
|
||||||
tracing::info!("shell window registered with compositor");
|
tracing::info!("shell window registered with compositor");
|
||||||
Some(c)
|
Some(c)
|
||||||
|
|
@ -45,7 +45,7 @@ fn run() -> anyhow::Result<()> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
embed_servo(&wayland_display, &html_path, ws_port)
|
embed_servo(&wayland_display, &html_path, ws_port, shell)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn system_ui_html_path() -> anyhow::Result<PathBuf> {
|
fn system_ui_html_path() -> anyhow::Result<PathBuf> {
|
||||||
|
|
@ -86,12 +86,14 @@ fn embed_servo(
|
||||||
_wayland_display: &str,
|
_wayland_display: &str,
|
||||||
html_path: &std::path::Path,
|
html_path: &std::path::Path,
|
||||||
ws_port: u16,
|
ws_port: u16,
|
||||||
|
shell_client: Option<shell_client::ShellClient>,
|
||||||
) -> anyhow::Result<()> {
|
) -> anyhow::Result<()> {
|
||||||
#[cfg(feature = "servo-embed")]
|
#[cfg(feature = "servo-embed")]
|
||||||
return embedder::run(html_path, ws_port);
|
return embedder::run(html_path, ws_port, shell_client);
|
||||||
|
|
||||||
#[cfg(not(feature = "servo-embed"))]
|
#[cfg(not(feature = "servo-embed"))]
|
||||||
{
|
{
|
||||||
|
let _ = shell_client;
|
||||||
tracing::warn!(
|
tracing::warn!(
|
||||||
path = %html_path.display(),
|
path = %html_path.display(),
|
||||||
ws_port,
|
ws_port,
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue