mirror of
https://github.com/marcoallegretti/WEFT_OS.git
synced 2026-03-26 17:03:09 +00:00
Merge pull request #1 from marcoallegretti/hardening/os-integration-and-rendering
Hardening/os integration and rendering
This commit is contained in:
commit
b99cc73a47
9 changed files with 166 additions and 80 deletions
|
|
@ -130,12 +130,17 @@ impl App {
|
||||||
let Some(pixels) = rendering_context.read_pixels() else {
|
let Some(pixels) = rendering_context.read_pixels() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let ctx = softbuffer::Context::new(Arc::clone(window)).expect("softbuffer context");
|
let Ok(ctx) = softbuffer::Context::new(Arc::clone(window)) else {
|
||||||
let mut surface =
|
tracing::warn!("softbuffer context creation failed; skipping frame");
|
||||||
softbuffer::Surface::new(&ctx, Arc::clone(window)).expect("softbuffer surface");
|
return;
|
||||||
|
};
|
||||||
|
let Ok(mut surface) = softbuffer::Surface::new(&ctx, Arc::clone(window)) else {
|
||||||
|
tracing::warn!("softbuffer surface creation failed; skipping frame");
|
||||||
|
return;
|
||||||
|
};
|
||||||
let _ = surface.resize(
|
let _ = surface.resize(
|
||||||
std::num::NonZeroU32::new(size.width).unwrap_or(std::num::NonZeroU32::new(1).unwrap()),
|
std::num::NonZeroU32::new(size.width).unwrap_or(std::num::NonZeroU32::MIN),
|
||||||
std::num::NonZeroU32::new(size.height).unwrap_or(std::num::NonZeroU32::new(1).unwrap()),
|
std::num::NonZeroU32::new(size.height).unwrap_or(std::num::NonZeroU32::MIN),
|
||||||
);
|
);
|
||||||
let Ok(mut buf) = surface.buffer_mut() else {
|
let Ok(mut buf) = surface.buffer_mut() else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -155,11 +160,14 @@ impl ApplicationHandler<ServoWake> for App {
|
||||||
|
|
||||||
let title = format!("WEFT App — {}", self.url.host_str().unwrap_or("app"));
|
let title = format!("WEFT App — {}", self.url.host_str().unwrap_or("app"));
|
||||||
let attrs = WindowAttributes::default().with_title(title);
|
let attrs = WindowAttributes::default().with_title(title);
|
||||||
let window = Arc::new(
|
let window = match event_loop.create_window(attrs) {
|
||||||
event_loop
|
Ok(w) => Arc::new(w),
|
||||||
.create_window(attrs)
|
Err(e) => {
|
||||||
.expect("failed to create app window"),
|
tracing::error!(error = %e, "failed to create app window; exiting");
|
||||||
);
|
event_loop.exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
self.window = Some(Arc::clone(&window));
|
self.window = Some(Arc::clone(&window));
|
||||||
|
|
||||||
|
|
@ -185,7 +193,11 @@ impl ApplicationHandler<ServoWake> for App {
|
||||||
|
|
||||||
servo.set_delegate(Rc::new(WeftServoDelegate));
|
servo.set_delegate(Rc::new(WeftServoDelegate));
|
||||||
|
|
||||||
let rendering_context = build_rendering_ctx(event_loop, &window, size);
|
let Some(rendering_context) = build_rendering_ctx(event_loop, &window, size) else {
|
||||||
|
tracing::error!("no rendering context available; exiting without READY signal");
|
||||||
|
event_loop.exit();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let ucm = Rc::new(UserContentManager::new(&servo));
|
let ucm = Rc::new(UserContentManager::new(&servo));
|
||||||
if let Some(kit_js) = load_ui_kit_script() {
|
if let Some(kit_js) = load_ui_kit_script() {
|
||||||
|
|
@ -326,7 +338,7 @@ fn build_rendering_ctx(
|
||||||
event_loop: &ActiveEventLoop,
|
event_loop: &ActiveEventLoop,
|
||||||
window: &Arc<Window>,
|
window: &Arc<Window>,
|
||||||
size: winit::dpi::PhysicalSize<u32>,
|
size: winit::dpi::PhysicalSize<u32>,
|
||||||
) -> RenderingCtx {
|
) -> Option<RenderingCtx> {
|
||||||
if std::env::var_os("WEFT_EGL_RENDERING").is_some() {
|
if std::env::var_os("WEFT_EGL_RENDERING").is_some() {
|
||||||
let display_handle = event_loop.display_handle();
|
let display_handle = event_loop.display_handle();
|
||||||
let window_handle = window.window_handle();
|
let window_handle = window.window_handle();
|
||||||
|
|
@ -334,7 +346,7 @@ fn build_rendering_ctx(
|
||||||
match servo::WindowRenderingContext::new(dh, wh, size) {
|
match servo::WindowRenderingContext::new(dh, wh, size) {
|
||||||
Ok(rc) => {
|
Ok(rc) => {
|
||||||
tracing::info!("using EGL rendering context");
|
tracing::info!("using EGL rendering context");
|
||||||
return RenderingCtx::Egl(Rc::new(rc));
|
return Some(RenderingCtx::Egl(Rc::new(rc)));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!("EGL rendering context failed ({e}), falling back to software");
|
tracing::warn!("EGL rendering context failed ({e}), falling back to software");
|
||||||
|
|
@ -342,10 +354,14 @@ fn build_rendering_ctx(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RenderingCtx::Software(Rc::new(
|
match servo::SoftwareRenderingContext::new(servo::euclid::Size2D::new(size.width, size.height))
|
||||||
servo::SoftwareRenderingContext::new(servo::euclid::Size2D::new(size.width, size.height))
|
{
|
||||||
.expect("SoftwareRenderingContext"),
|
Ok(rc) => Some(RenderingCtx::Software(Rc::new(rc))),
|
||||||
))
|
Err(e) => {
|
||||||
|
tracing::error!("SoftwareRenderingContext failed: {e}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn ui_kit_path() -> std::path::PathBuf {
|
fn ui_kit_path() -> std::path::PathBuf {
|
||||||
|
|
|
||||||
|
|
@ -172,7 +172,10 @@ impl ShellClient {
|
||||||
WlSurface::from_id(&conn, id).context("wl_surface from_id")?
|
WlSurface::from_id(&conn, id).context("wl_surface from_id")?
|
||||||
};
|
};
|
||||||
|
|
||||||
let manager = data.manager.as_ref().unwrap();
|
let manager = data
|
||||||
|
.manager
|
||||||
|
.as_ref()
|
||||||
|
.expect("manager is Some; guaranteed by ensure! above");
|
||||||
let title = format!("{app_id}/{session_id}");
|
let title = format!("{app_id}/{session_id}");
|
||||||
let window = manager.create_window(
|
let window = manager.create_window(
|
||||||
app_id.to_string(),
|
app_id.to_string(),
|
||||||
|
|
|
||||||
|
|
@ -313,23 +313,32 @@ pub(crate) async fn supervise(
|
||||||
_ = &mut abort_rx => None,
|
_ = &mut abort_rx => None,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut app_shell: Option<tokio::process::Child> = None;
|
let app_shell = match ready_result {
|
||||||
match ready_result {
|
|
||||||
Some(Ok(Ok(remaining_stdout))) => {
|
Some(Ok(Ok(remaining_stdout))) => {
|
||||||
registry
|
{
|
||||||
.lock()
|
let mut reg = registry.lock().await;
|
||||||
.await
|
reg.set_state(session_id, AppStateKind::Running);
|
||||||
.set_state(session_id, AppStateKind::Running);
|
let _ = reg.broadcast().send(Response::AppReady {
|
||||||
let _ = registry.lock().await.broadcast().send(Response::AppReady {
|
session_id,
|
||||||
session_id,
|
app_id: app_id.to_owned(),
|
||||||
app_id: app_id.to_owned(),
|
});
|
||||||
});
|
}
|
||||||
tracing::info!(session_id, %app_id, "app ready");
|
tracing::info!(session_id, %app_id, "app ready");
|
||||||
tokio::spawn(drain_stdout(remaining_stdout, session_id));
|
tokio::spawn(drain_stdout(remaining_stdout, session_id));
|
||||||
app_shell = spawn_app_shell(session_id, app_id).await;
|
spawn_app_shell(session_id, app_id).await
|
||||||
}
|
}
|
||||||
Some(Ok(Err(e))) => {
|
Some(Ok(Err(e))) => {
|
||||||
tracing::warn!(session_id, %app_id, error = %e, "stdout read error before READY");
|
tracing::warn!(session_id, %app_id, error = %e, "stdout read error before READY; killing process");
|
||||||
|
let _ = child.kill().await;
|
||||||
|
kill_portal(portal).await;
|
||||||
|
let mut reg = registry.lock().await;
|
||||||
|
reg.set_state(session_id, AppStateKind::Stopped);
|
||||||
|
reg.remove_abort_sender(session_id);
|
||||||
|
let _ = reg.broadcast().send(Response::AppState {
|
||||||
|
session_id,
|
||||||
|
state: AppStateKind::Stopped,
|
||||||
|
});
|
||||||
|
return Ok(());
|
||||||
}
|
}
|
||||||
Some(Err(_elapsed)) => {
|
Some(Err(_elapsed)) => {
|
||||||
tracing::warn!(session_id, %app_id, "READY timeout after 30s; killing process");
|
tracing::warn!(session_id, %app_id, "READY timeout after 30s; killing process");
|
||||||
|
|
@ -356,7 +365,7 @@ pub(crate) async fn supervise(
|
||||||
});
|
});
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
|
||||||
tokio::spawn(drain_stderr(stderr, session_id));
|
tokio::spawn(drain_stderr(stderr, session_id));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -137,10 +137,12 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
|
|
||||||
loop_handle
|
loop_handle
|
||||||
.insert_source(listening_socket, |stream, _, state| {
|
.insert_source(listening_socket, |stream, _, state| {
|
||||||
state
|
if let Err(e) = state
|
||||||
.display_handle
|
.display_handle
|
||||||
.insert_client(stream, Arc::new(WeftClientState::default()))
|
.insert_client(stream, Arc::new(WeftClientState::default()))
|
||||||
.unwrap();
|
{
|
||||||
|
tracing::warn!(?e, "failed to insert Wayland client");
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.map_err(|e| anyhow::anyhow!("socket source: {e}"))?;
|
.map_err(|e| anyhow::anyhow!("socket source: {e}"))?;
|
||||||
|
|
||||||
|
|
@ -150,7 +152,9 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
|_, display, state| {
|
|_, display, state| {
|
||||||
// Safety: Display is owned by this Generic source and outlives the event loop.
|
// Safety: Display is owned by this Generic source and outlives the event loop.
|
||||||
unsafe {
|
unsafe {
|
||||||
display.get_mut().dispatch_clients(state).unwrap();
|
if let Err(e) = display.get_mut().dispatch_clients(state) {
|
||||||
|
tracing::warn!(?e, "Wayland dispatch error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(PostAction::Continue)
|
Ok(PostAction::Continue)
|
||||||
},
|
},
|
||||||
|
|
@ -375,16 +379,21 @@ fn device_added(state: &mut WeftCompositorState, node: DrmNode, path: &Path) ->
|
||||||
)
|
)
|
||||||
.map_err(|e| anyhow::anyhow!("DRM notifier: {e}"))?;
|
.map_err(|e| anyhow::anyhow!("DRM notifier: {e}"))?;
|
||||||
|
|
||||||
state.drm.as_mut().unwrap().devices.insert(
|
state
|
||||||
node,
|
.drm
|
||||||
WeftDrmDevice {
|
.as_mut()
|
||||||
drm_output_manager,
|
.context("DRM data missing after initialization")?
|
||||||
drm_scanner: DrmScanner::new(),
|
.devices
|
||||||
surfaces: HashMap::new(),
|
.insert(
|
||||||
render_node,
|
node,
|
||||||
registration_token,
|
WeftDrmDevice {
|
||||||
},
|
drm_output_manager,
|
||||||
);
|
drm_scanner: DrmScanner::new(),
|
||||||
|
surfaces: HashMap::new(),
|
||||||
|
render_node,
|
||||||
|
registration_token,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
device_changed(state, node);
|
device_changed(state, node);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -604,7 +613,7 @@ fn render_output(state: &mut WeftCompositorState, node: DrmNode, crtc: crtc::Han
|
||||||
};
|
};
|
||||||
|
|
||||||
let render_node = {
|
let render_node = {
|
||||||
let d = state.drm.as_ref().unwrap();
|
let Some(d) = state.drm.as_ref() else { return };
|
||||||
d.devices
|
d.devices
|
||||||
.get(&node)
|
.get(&node)
|
||||||
.and_then(|d| d.render_node)
|
.and_then(|d| d.render_node)
|
||||||
|
|
|
||||||
|
|
@ -63,10 +63,12 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
|
|
||||||
loop_handle
|
loop_handle
|
||||||
.insert_source(listening_socket, |client_stream, _, state| {
|
.insert_source(listening_socket, |client_stream, _, state| {
|
||||||
state
|
if let Err(e) = state
|
||||||
.display_handle
|
.display_handle
|
||||||
.insert_client(client_stream, Arc::new(WeftClientState::default()))
|
.insert_client(client_stream, Arc::new(WeftClientState::default()))
|
||||||
.unwrap();
|
{
|
||||||
|
tracing::warn!(?e, "failed to insert Wayland client");
|
||||||
|
}
|
||||||
})
|
})
|
||||||
.map_err(|e| anyhow::anyhow!("socket source insertion failed: {e}"))?;
|
.map_err(|e| anyhow::anyhow!("socket source insertion failed: {e}"))?;
|
||||||
|
|
||||||
|
|
@ -78,7 +80,9 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
// Safety: the display is owned by this Generic source and is never dropped
|
// Safety: the display is owned by this Generic source and is never dropped
|
||||||
// while the event loop runs.
|
// while the event loop runs.
|
||||||
unsafe {
|
unsafe {
|
||||||
display.get_mut().dispatch_clients(state).unwrap();
|
if let Err(e) = display.get_mut().dispatch_clients(state) {
|
||||||
|
tracing::warn!(?e, "Wayland dispatch error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Ok(PostAction::Continue)
|
Ok(PostAction::Continue)
|
||||||
},
|
},
|
||||||
|
|
@ -129,9 +133,8 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
let size = backend.window_size();
|
let size = backend.window_size();
|
||||||
let full_damage = Rectangle::from_size(size);
|
let full_damage = Rectangle::from_size(size);
|
||||||
|
|
||||||
{
|
let render_ok = match backend.bind() {
|
||||||
let (renderer, mut framebuffer) = backend.bind().unwrap();
|
Ok((renderer, mut framebuffer)) => smithay::desktop::space::render_output::<
|
||||||
smithay::desktop::space::render_output::<
|
|
||||||
_,
|
_,
|
||||||
WaylandSurfaceRenderElement<GlesRenderer>,
|
WaylandSurfaceRenderElement<GlesRenderer>,
|
||||||
_,
|
_,
|
||||||
|
|
@ -147,9 +150,18 @@ pub fn run() -> anyhow::Result<()> {
|
||||||
&mut damage_tracker,
|
&mut damage_tracker,
|
||||||
[0.1_f32, 0.1, 0.1, 1.0],
|
[0.1_f32, 0.1, 0.1, 1.0],
|
||||||
)
|
)
|
||||||
.unwrap();
|
.map_err(|e| tracing::warn!(?e, "render_output failed"))
|
||||||
|
.is_ok(),
|
||||||
|
Err(e) => {
|
||||||
|
tracing::warn!(?e, "backend bind failed");
|
||||||
|
false
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if render_ok {
|
||||||
|
if let Err(e) = backend.submit(Some(&[full_damage])) {
|
||||||
|
tracing::warn!(?e, "backend submit failed");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
backend.submit(Some(&[full_damage])).unwrap();
|
|
||||||
|
|
||||||
state.space.elements().for_each(|window| {
|
state.space.elements().for_each(|window| {
|
||||||
window.send_frame(
|
window.send_frame(
|
||||||
|
|
|
||||||
|
|
@ -294,9 +294,13 @@ impl WlrLayerShellHandler for WeftCompositorState {
|
||||||
) {
|
) {
|
||||||
let desktop_surface = DesktopLayerSurface::new(surface, namespace);
|
let desktop_surface = DesktopLayerSurface::new(surface, namespace);
|
||||||
if let Some(output) = self.space.outputs().next().cloned() {
|
if let Some(output) = self.space.outputs().next().cloned() {
|
||||||
layer_map_for_output(&output)
|
if layer_map_for_output(&output)
|
||||||
.map_layer(&desktop_surface)
|
.map_layer(&desktop_surface)
|
||||||
.expect("layer surface must not already be mapped");
|
.is_err()
|
||||||
|
{
|
||||||
|
tracing::warn!("received duplicate layer surface mapping; ignoring");
|
||||||
|
return;
|
||||||
|
}
|
||||||
layer_map_for_output(&output).arrange();
|
layer_map_for_output(&output).arrange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -212,7 +212,7 @@ fn run_module(
|
||||||
move |_: wasmtime::StoreContextMut<'_, State>,
|
move |_: wasmtime::StoreContextMut<'_, State>,
|
||||||
(payload,): (String,)|
|
(payload,): (String,)|
|
||||||
-> wasmtime::Result<(Result<(), String>,)> {
|
-> wasmtime::Result<(Result<(), String>,)> {
|
||||||
let mut guard = ipc_send.lock().unwrap();
|
let mut guard = ipc_send.lock().unwrap_or_else(|p| p.into_inner());
|
||||||
match guard.as_mut() {
|
match guard.as_mut() {
|
||||||
Some(ipc) => Ok((ipc.send(&payload),)),
|
Some(ipc) => Ok((ipc.send(&payload),)),
|
||||||
None => Ok((Err("IPC not connected".to_owned()),)),
|
None => Ok((Err("IPC not connected".to_owned()),)),
|
||||||
|
|
@ -227,7 +227,7 @@ fn run_module(
|
||||||
move |_: wasmtime::StoreContextMut<'_, State>,
|
move |_: wasmtime::StoreContextMut<'_, State>,
|
||||||
()|
|
()|
|
||||||
-> wasmtime::Result<(Option<String>,)> {
|
-> wasmtime::Result<(Option<String>,)> {
|
||||||
let mut guard = ipc_recv.lock().unwrap();
|
let mut guard = ipc_recv.lock().unwrap_or_else(|p| p.into_inner());
|
||||||
Ok((guard.as_mut().and_then(|ipc| ipc.recv()),))
|
Ok((guard.as_mut().and_then(|ipc| ipc.recv()),))
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
@ -299,7 +299,7 @@ fn run_module(
|
||||||
if let Some(socket_path) = ipc_socket {
|
if let Some(socket_path) = ipc_socket {
|
||||||
ctx_builder.env("WEFT_IPC_SOCKET", socket_path);
|
ctx_builder.env("WEFT_IPC_SOCKET", socket_path);
|
||||||
if let Some(ipc) = IpcState::connect(socket_path) {
|
if let Some(ipc) = IpcState::connect(socket_path) {
|
||||||
*ipc_state.lock().unwrap() = Some(ipc);
|
*ipc_state.lock().unwrap_or_else(|p| p.into_inner()) = Some(ipc);
|
||||||
} else {
|
} else {
|
||||||
tracing::warn!("weft:app/ipc: could not connect to IPC socket {socket_path}");
|
tracing::warn!("weft:app/ipc: could not connect to IPC socket {socket_path}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -96,6 +96,7 @@ struct App {
|
||||||
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>,
|
shell_client: Option<crate::shell_client::ShellClient>,
|
||||||
|
gesture_thread: Option<std::thread::JoinHandle<()>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
|
@ -113,6 +114,7 @@ impl App {
|
||||||
modifiers: ModifiersState::default(),
|
modifiers: ModifiersState::default(),
|
||||||
cursor_pos: servo::euclid::default::Point2D::zero(),
|
cursor_pos: servo::euclid::default::Point2D::zero(),
|
||||||
shell_client: None,
|
shell_client: None,
|
||||||
|
gesture_thread: None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -128,12 +130,17 @@ impl App {
|
||||||
let Some(pixels) = rendering_context.read_pixels() else {
|
let Some(pixels) = rendering_context.read_pixels() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
let ctx = softbuffer::Context::new(Arc::clone(window)).expect("softbuffer context");
|
let Ok(ctx) = softbuffer::Context::new(Arc::clone(window)) else {
|
||||||
let mut surface =
|
tracing::warn!("softbuffer context creation failed; skipping frame");
|
||||||
softbuffer::Surface::new(&ctx, Arc::clone(window)).expect("softbuffer surface");
|
return;
|
||||||
|
};
|
||||||
|
let Ok(mut surface) = softbuffer::Surface::new(&ctx, Arc::clone(window)) else {
|
||||||
|
tracing::warn!("softbuffer surface creation failed; skipping frame");
|
||||||
|
return;
|
||||||
|
};
|
||||||
let _ = surface.resize(
|
let _ = surface.resize(
|
||||||
std::num::NonZeroU32::new(size.width).unwrap_or(std::num::NonZeroU32::new(1).unwrap()),
|
std::num::NonZeroU32::new(size.width).unwrap_or(std::num::NonZeroU32::MIN),
|
||||||
std::num::NonZeroU32::new(size.height).unwrap_or(std::num::NonZeroU32::new(1).unwrap()),
|
std::num::NonZeroU32::new(size.height).unwrap_or(std::num::NonZeroU32::MIN),
|
||||||
);
|
);
|
||||||
let Ok(mut buf) = surface.buffer_mut() else {
|
let Ok(mut buf) = surface.buffer_mut() else {
|
||||||
return;
|
return;
|
||||||
|
|
@ -152,11 +159,14 @@ impl ApplicationHandler<ServoWake> for App {
|
||||||
}
|
}
|
||||||
|
|
||||||
let attrs = WindowAttributes::default().with_title("WEFT Shell");
|
let attrs = WindowAttributes::default().with_title("WEFT Shell");
|
||||||
let window = Arc::new(
|
let window = match event_loop.create_window(attrs) {
|
||||||
event_loop
|
Ok(w) => Arc::new(w),
|
||||||
.create_window(attrs)
|
Err(e) => {
|
||||||
.expect("failed to create shell window"),
|
tracing::error!(error = %e, "failed to create shell window; exiting");
|
||||||
);
|
event_loop.exit();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
let size = window.inner_size();
|
let size = window.inner_size();
|
||||||
self.window = Some(Arc::clone(&window));
|
self.window = Some(Arc::clone(&window));
|
||||||
|
|
||||||
|
|
@ -177,7 +187,11 @@ impl ApplicationHandler<ServoWake> for App {
|
||||||
|
|
||||||
servo.set_delegate(Rc::new(WeftServoDelegate));
|
servo.set_delegate(Rc::new(WeftServoDelegate));
|
||||||
|
|
||||||
let rendering_context = build_rendering_ctx(event_loop, &window, size);
|
let Some(rendering_context) = build_rendering_ctx(event_loop, &window, size) else {
|
||||||
|
tracing::error!("no rendering context available; shell cannot start");
|
||||||
|
event_loop.exit();
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let user_content_manager = Rc::new(UserContentManager::new(&servo));
|
let user_content_manager = Rc::new(UserContentManager::new(&servo));
|
||||||
if let Some(kit_js) = load_ui_kit_script() {
|
if let Some(kit_js) = load_ui_kit_script() {
|
||||||
|
|
@ -226,10 +240,22 @@ impl ApplicationHandler<ServoWake> for App {
|
||||||
}
|
}
|
||||||
let gestures = sc.take_pending_gestures();
|
let gestures = sc.take_pending_gestures();
|
||||||
if !gestures.is_empty() {
|
if !gestures.is_empty() {
|
||||||
let ws_port = self.ws_port;
|
let prev_done = self
|
||||||
std::thread::spawn(move || {
|
.gesture_thread
|
||||||
forward_gestures_to_appd(ws_port, &gestures);
|
.as_ref()
|
||||||
});
|
.map(|h| h.is_finished())
|
||||||
|
.unwrap_or(true);
|
||||||
|
if prev_done {
|
||||||
|
let ws_port = self.ws_port;
|
||||||
|
self.gesture_thread = Some(std::thread::spawn(move || {
|
||||||
|
forward_gestures_to_appd(ws_port, &gestures);
|
||||||
|
}));
|
||||||
|
} else {
|
||||||
|
tracing::debug!(
|
||||||
|
count = gestures.len(),
|
||||||
|
"gesture forwarding in progress; dropping batch"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(servo) = &self.servo {
|
if let Some(servo) = &self.servo {
|
||||||
|
|
@ -319,7 +345,7 @@ fn build_rendering_ctx(
|
||||||
event_loop: &ActiveEventLoop,
|
event_loop: &ActiveEventLoop,
|
||||||
window: &Arc<Window>,
|
window: &Arc<Window>,
|
||||||
size: winit::dpi::PhysicalSize<u32>,
|
size: winit::dpi::PhysicalSize<u32>,
|
||||||
) -> RenderingCtx {
|
) -> Option<RenderingCtx> {
|
||||||
if std::env::var_os("WEFT_EGL_RENDERING").is_some() {
|
if std::env::var_os("WEFT_EGL_RENDERING").is_some() {
|
||||||
let display_handle = event_loop.display_handle();
|
let display_handle = event_loop.display_handle();
|
||||||
let window_handle = window.window_handle();
|
let window_handle = window.window_handle();
|
||||||
|
|
@ -327,7 +353,7 @@ fn build_rendering_ctx(
|
||||||
match servo::WindowRenderingContext::new(dh, wh, size) {
|
match servo::WindowRenderingContext::new(dh, wh, size) {
|
||||||
Ok(rc) => {
|
Ok(rc) => {
|
||||||
tracing::info!("using EGL rendering context");
|
tracing::info!("using EGL rendering context");
|
||||||
return RenderingCtx::Egl(Rc::new(rc));
|
return Some(RenderingCtx::Egl(Rc::new(rc)));
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::warn!("EGL rendering context failed ({e}), falling back to software");
|
tracing::warn!("EGL rendering context failed ({e}), falling back to software");
|
||||||
|
|
@ -335,10 +361,14 @@ fn build_rendering_ctx(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RenderingCtx::Software(Rc::new(
|
match servo::SoftwareRenderingContext::new(servo::euclid::Size2D::new(size.width, size.height))
|
||||||
servo::SoftwareRenderingContext::new(servo::euclid::Size2D::new(size.width, size.height))
|
{
|
||||||
.expect("SoftwareRenderingContext"),
|
Ok(rc) => Some(RenderingCtx::Software(Rc::new(rc))),
|
||||||
))
|
Err(e) => {
|
||||||
|
tracing::error!("SoftwareRenderingContext failed: {e}");
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Public entry point ────────────────────────────────────────────────────────
|
// ── Public entry point ────────────────────────────────────────────────────────
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,10 @@ impl ShellClient {
|
||||||
WlSurface::from_id(&conn, id).context("wl_surface from_id")?
|
WlSurface::from_id(&conn, id).context("wl_surface from_id")?
|
||||||
};
|
};
|
||||||
|
|
||||||
let manager = data.manager.as_ref().unwrap();
|
let manager = data
|
||||||
|
.manager
|
||||||
|
.as_ref()
|
||||||
|
.expect("manager is Some; guaranteed by ensure! above");
|
||||||
let window = manager.create_window(
|
let window = manager.create_window(
|
||||||
"org.weft.system.shell".to_string(),
|
"org.weft.system.shell".to_string(),
|
||||||
"WEFT Shell".to_string(),
|
"WEFT Shell".to_string(),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue