fixed hang when dragging some apps *cough* chromium

This commit is contained in:
galister 2026-07-05 23:36:13 +09:00
parent df1cf668a0
commit 3f071a530c
2 changed files with 144 additions and 120 deletions

View File

@ -16,6 +16,8 @@ pub struct Window {
pub visible: bool,
pub toplevel: Rc<ToplevelSurface>,
pub process: process::ProcessHandle,
pub pending_configure_size: Option<Size<i32, Logical>>,
}
impl Window {
@ -35,6 +37,7 @@ impl Window {
visible: true,
toplevel,
process,
pending_configure_size: None,
}
}
@ -42,33 +45,48 @@ impl Window {
self.min_size != self.max_size
}
pub fn checked_configure_size(&mut self, size: Size<i32, Logical>) {
let clamped_size = size.clamp(self.min_size, self.max_size);
pub fn clamp_configure_size(
&self,
size: Size<i32, Logical>,
bounds: Size<i32, Logical>,
) -> Size<i32, Logical> {
let min_size = Size::new(
self.min_size.w.max(1).min(bounds.w),
self.min_size.h.max(1).min(bounds.h),
);
self.toplevel.with_pending_state(|state| {
state.bounds = Some(self.bounds);
state.size = Some(clamped_size);
});
self.toplevel.send_configure();
self.remember_committed_size(size);
let max_size = Size::new(
self.max_size.w.max(min_size.w).min(bounds.w),
self.max_size.h.max(min_size.h).min(bounds.h),
);
Size::new(size.w.max(1), size.h.max(1)).clamp(min_size, max_size)
}
pub fn configure_size(&mut self, size: Option<Size<i32, Logical>>, bounds: Size<i32, Logical>) {
fn send_size_configure(&mut self, size: Size<i32, Logical>, bounds: Size<i32, Logical>) {
let clamped_size = self.clamp_configure_size(size, bounds);
if self.pending_configure_size == Some(clamped_size) {
return;
}
self.toplevel.with_pending_state(|state| {
state.bounds = Some(bounds);
state.size = size;
state.size = Some(clamped_size);
});
self.toplevel.send_configure();
self.bounds = bounds;
if let Some(size) = size {
self.remember_committed_size(size);
}
self.pending_configure_size = Some(clamped_size);
}
pub fn checked_configure_size(&mut self, size: Size<i32, Logical>) {
self.send_size_configure(size, self.bounds);
}
pub fn request_size(&mut self, size: Size<i32, Logical>, bounds: Size<i32, Logical>) {
let size = size.clamp(Size::new(1, 1), bounds);
self.configure_size(Some(size), bounds);
self.send_size_configure(size, bounds);
}
pub fn remember_committed_size(&mut self, size: Size<i32, Logical>) -> bool {
@ -80,6 +98,8 @@ impl Window {
self.size_x = size_x;
self.size_y = size_y;
self.pending_configure_size = None;
changed
}
}

View File

@ -511,22 +511,27 @@ impl WvrWindowBackend {
let Some(wvr_server) = app.wvr_server.as_mut() else {
return Ok(());
};
let bounds = wvr_server.manager.state.output_logical_size();
let requested = Size::new(inner_extent[0].max(1) as i32, inner_extent[1].max(1) as i32);
let clamped = requested.clamp(Size::new(1, 1), bounds);
let committed = Size::new(inner_extent[0].max(1) as i32, inner_extent[1].max(1) as i32);
let Some(window) = wvr_server.wm.windows.get_mut(&self.window) else {
return Ok(());
};
if requested == clamped {
// client picked a new size that fits
window.remember_committed_size(requested);
let clamped = window.clamp_configure_size(committed, bounds);
if committed == clamped {
window.remember_committed_size(committed);
} else if window.pending_configure_size.is_none() {
log::warn!("Client committed invalid size {committed:?}; requesting {clamped:?}");
window.request_size(clamped, bounds);
} else {
// client committed something outside the output bounds
if window.size_x != clamped.w as u32 || window.size_y != clamped.h as u32 {
window.request_size(clamped, bounds);
}
log::trace!(
"Client committed invalid size {committed:?}, but configure {:?} is already pending",
window.pending_configure_size,
);
}
Ok(())
@ -620,107 +625,106 @@ impl OverlayBackend for WvrWindowBackend {
let force_render = tree_dirty || mem::take(&mut self.just_resumed);
with_states(toplevel.wl_surface(), |states| {
if let Some(surf) = SurfaceBufWithImage::get_from_surface(states) {
let mut meta = FrameMeta {
extent: surf.image.extent_u32arr(),
format: surf.image.format(),
clear: WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]),
stereo: self.stereo.unwrap_or(StereoMode::None),
..Default::default()
};
let Some(surf) = with_states(toplevel.wl_surface(), SurfaceBufWithImage::get_from_surface)
else {
log::trace!("{}: no buffer for wl_surface", self.name);
return Ok(ShouldRender::Unable);
};
if let Some(stereo) = self.stereo {
// Apply stereo full frame logic
if self.stereo_full_frame {
match stereo {
StereoMode::LeftRight | StereoMode::RightLeft => {
meta.extent[0] /= 2;
}
StereoMode::TopBottom | StereoMode::BottomTop => {
meta.extent[1] /= 2;
}
_ => {}
}
let mut meta = FrameMeta {
extent: surf.image.extent_u32arr(),
format: surf.image.format(),
clear: WGfxClearMode::Clear([0.0, 0.0, 0.0, 0.0]),
stereo: self.stereo.unwrap_or(StereoMode::None),
..Default::default()
};
if let Some(stereo) = self.stereo {
// Apply stereo full frame logic
if self.stereo_full_frame {
match stereo {
StereoMode::LeftRight | StereoMode::RightLeft => {
meta.extent[0] /= 2;
}
}
let inner_extent = meta.extent;
self.sync_committed_toplevel_size(app, inner_extent)?;
meta.extent[0] += BORDER_SIZE * 2;
meta.extent[1] += BORDER_SIZE * 2 + BAR_SIZE;
if let Some(pipeline) = self.pipeline.as_mut() {
if self.inner_extent != inner_extent {
pipeline.set_layout(
app,
[inner_extent[0] as _, inner_extent[1] as _],
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
Transform::Normal,
)?;
self.apply_extent(app, &meta)?;
self.inner_extent = inner_extent;
StereoMode::TopBottom | StereoMode::BottomTop => {
meta.extent[1] /= 2;
}
} else {
let pipeline = ScreenPipeline::new(
&meta,
app,
self.stereo.unwrap_or(StereoMode::None),
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
Transform::Normal,
)?;
self.apply_extent(app, &meta)?;
self.pipeline = Some(pipeline);
_ => {}
}
let mouse = app
.wvr_server
.as_ref()
.unwrap()
.wm
.mouse
.as_ref()
.filter(|m| m.hover_window == self.window)
.map(|m| MouseMeta {
x: (m.x as f32) / (inner_extent[0] as f32),
y: (m.y as f32) / (inner_extent[1] as f32),
});
let dirty = self.mouse != mouse || rendered_surfaces_dirty(&self.popups, &popups);
if !self.scrolling {
self.mouse = mouse;
}
self.popups = popups;
self.meta = Some(meta);
if force_render {
self.cur_image = Some(surf.image);
return Ok(ShouldRender::Should);
}
if self
.cur_image
.as_ref()
.is_none_or(|i| *i.image() != *surf.image.image())
{
log::trace!(
"{}: new {} image",
self.name,
if surf.dmabuf { "DMA-buf" } else { "SHM" }
);
self.cur_image = Some(surf.image);
Ok(ShouldRender::Should)
} else if dirty {
Ok(ShouldRender::Should)
} else {
Ok(should_render_panel)
}
} else {
log::trace!("{}: no buffer for wl_surface", self.name);
Ok(ShouldRender::Unable)
}
})
}
let inner_extent = meta.extent;
self.sync_committed_toplevel_size(app, inner_extent)?;
meta.extent[0] += BORDER_SIZE * 2;
meta.extent[1] += BORDER_SIZE * 2 + BAR_SIZE;
if let Some(pipeline) = self.pipeline.as_mut() {
if self.inner_extent != inner_extent {
pipeline.set_layout(
app,
[inner_extent[0] as _, inner_extent[1] as _],
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
Transform::Normal,
)?;
self.apply_extent(app, &meta)?;
self.inner_extent = inner_extent;
}
} else {
let pipeline = ScreenPipeline::new(
&meta,
app,
self.stereo.unwrap_or(StereoMode::None),
[BORDER_SIZE as _, (BAR_SIZE + BORDER_SIZE) as _],
Transform::Normal,
)?;
self.apply_extent(app, &meta)?;
self.pipeline = Some(pipeline);
}
let mouse = app
.wvr_server
.as_ref()
.unwrap()
.wm
.mouse
.as_ref()
.filter(|m| m.hover_window == self.window)
.map(|m| MouseMeta {
x: (m.x as f32) / (inner_extent[0] as f32),
y: (m.y as f32) / (inner_extent[1] as f32),
});
let dirty = self.mouse != mouse || rendered_surfaces_dirty(&self.popups, &popups);
if !self.scrolling {
self.mouse = mouse;
}
self.popups = popups;
self.meta = Some(meta);
if force_render {
self.cur_image = Some(surf.image);
return Ok(ShouldRender::Should);
}
if self
.cur_image
.as_ref()
.is_none_or(|i| *i.image() != *surf.image.image())
{
log::trace!(
"{}: new {} image",
self.name,
if surf.dmabuf { "DMA-buf" } else { "SHM" }
);
self.cur_image = Some(surf.image);
Ok(ShouldRender::Should)
} else if dirty {
Ok(ShouldRender::Should)
} else {
Ok(should_render_panel)
}
}
fn render(