Stop rendering instead of unmapping windows (regression)

Layer shell surfaces currently don't render anymore. I may need to manually render them instead of getting them through Space::space_render_elements.
This commit is contained in:
Ottatop 2023-09-02 02:46:26 -05:00
parent 5744654cb1
commit 15e03b6c17
9 changed files with 141 additions and 46 deletions

View file

@ -1344,18 +1344,19 @@ impl State {
};
let result = render_surface(
&mut self.cursor_status,
&self.space,
&self.windows,
self.dnd_icon.as_ref(),
&self.focus_state.focus_stack,
surface,
&mut renderer,
&self.space,
&output,
self.seat.input_method(),
self.pointer_location,
&pointer_image,
&mut backend.pointer_element,
&mut self.cursor_status,
self.dnd_icon.as_ref(),
self.pointer_location,
&self.clock,
&self.focus_state.focus_stack,
);
let reschedule = match &result {
Ok(has_rendered) => !has_rendered,
@ -1448,30 +1449,32 @@ impl State {
#[allow(clippy::too_many_arguments)]
fn render_surface<'a>(
cursor_status: &mut CursorImageStatus,
space: &Space<WindowElement>,
windows: &[WindowElement],
dnd_icon: Option<&WlSurface>,
focus_stack: &[WindowElement],
surface: &'a mut SurfaceData,
renderer: &mut UdevRenderer<'a, '_>,
space: &Space<WindowElement>,
output: &Output,
input_method: &InputMethodHandle,
pointer_location: Point<f64, Logical>,
pointer_image: &TextureBuffer<MultiTexture>,
pointer_element: &mut PointerElement<MultiTexture>,
cursor_status: &mut CursorImageStatus,
dnd_icon: Option<&WlSurface>,
pointer_location: Point<f64, Logical>,
clock: &Clock<Monotonic>,
focus_stack: &[WindowElement],
) -> Result<bool, SwapBuffersError> {
let output_render_elements = crate::render::generate_render_elements(
renderer,
space,
output,
input_method,
windows,
pointer_location,
pointer_element,
Some(pointer_image),
cursor_status,
dnd_icon,
focus_stack,
renderer,
output,
input_method,
pointer_element,
Some(pointer_image),
);
let res = surface.compositor.render_frame::<_, _, GlesTexture>(

View file

@ -237,16 +237,17 @@ pub fn run_winit() -> anyhow::Result<()> {
*full_redraw = full_redraw.saturating_sub(1);
let output_render_elements = crate::render::generate_render_elements(
backend.backend.renderer(),
&state.space,
&output,
state.seat.input_method(),
&state.windows,
state.pointer_location,
&mut pointer_element,
None,
&mut state.cursor_status,
state.dnd_icon.as_ref(),
&state.focus_state.focus_stack,
backend.backend.renderer(),
&output,
state.seat.input_method(),
&mut pointer_element,
None,
);
let render_res = backend.backend.bind().and_then(|_| {
@ -271,6 +272,7 @@ pub fn run_winit() -> anyhow::Result<()> {
Ok(render_output_result) => {
let has_rendered = render_output_result.damage.is_some();
if let Some(damage) = render_output_result.damage {
// tracing::debug!("damage rects are {damage:?}");
if let Err(err) = backend.backend.submit(Some(&damage)) {
tracing::warn!("{}", err);
}

View file

@ -121,6 +121,7 @@ impl CompositorHandler for State {
if let Some(window) = self.window_for_surface(surface) {
window.with_state(|state| {
if let LocationRequestState::Acknowledged(new_pos) = state.loc_request_state {
tracing::debug!("Mapping Acknowledged window");
state.loc_request_state = LocationRequestState::Idle;
self.space.map_element(window.clone(), new_pos, false);
}
@ -128,6 +129,7 @@ impl CompositorHandler for State {
}
// correct focus layering
// TODO: maybe do this at the end of every event loop cycle instead?
self.focus_state.fix_up_focus(&mut self.space);
}

View file

@ -93,6 +93,8 @@ impl XdgShellHandler for State {
self.windows.push(window.clone());
let win_clone = window.clone();
// Let the initial configure happen before updating the windows
self.schedule(
move |_data| {
if let WindowElement::Wayland(window) = &win_clone {
@ -170,10 +172,8 @@ impl XdgShellHandler for State {
self.update_windows(&focused_output);
}
// let mut windows: Vec<Window> = self.space.elements().cloned().collect();
// windows.retain(|window| window.toplevel() != &surface);
// Layouts::master_stack(self, windows, crate::layout::Direction::Left);
let focus = self.focus_state.current_focus().map(FocusTarget::Window);
self.seat
.get_keyboard()
.expect("Seat had no keyboard")
@ -192,7 +192,7 @@ impl XdgShellHandler for State {
crate::grab::move_grab::move_request_client(
self,
surface.wl_surface(),
&Seat::from_resource(&seat).expect("Couldn't get seat from WlSeat"),
&Seat::from_resource(&seat).expect("couldn't get seat from WlSeat"),
serial,
BUTTON_LEFT,
);
@ -209,7 +209,7 @@ impl XdgShellHandler for State {
crate::grab::resize_grab::resize_request_client(
self,
surface.wl_surface(),
&Seat::from_resource(&seat).expect("Couldn't get seat from WlSeat"),
&Seat::from_resource(&seat).expect("couldn't get seat from WlSeat"),
serial,
edges.into(),
BUTTON_LEFT,
@ -230,7 +230,7 @@ impl XdgShellHandler for State {
}
fn grab(&mut self, surface: PopupSurface, seat: WlSeat, serial: Serial) {
let seat: Seat<Self> = Seat::from_resource(&seat).expect("Couldn't get seat from WlSeat");
let seat: Seat<Self> = Seat::from_resource(&seat).expect("couldn't get seat from WlSeat");
let popup_kind = PopupKind::Xdg(surface);
if let Some(root) = find_popup_root_surface(&popup_kind).ok().and_then(|root| {
self.window_for_surface(&root)
@ -282,18 +282,43 @@ impl XdgShellHandler for State {
match &configure {
Configure::Toplevel(configure) => {
if configure.serial >= serial {
// tracing::debug!("acked configure, new loc is {:?}", new_loc);
tracing::debug!("acked configure, new loc is {:?}", new_loc);
state.loc_request_state =
LocationRequestState::Acknowledged(new_loc);
// Send a frame here because it causes (most) unmapped windows to
// commit. I haven't done enough doc diving to know if there's a
// better way.
if let Some(focused_output) =
self.focus_state.focused_output.clone()
{
tracing::debug!("Sending ack frame to window");
window.send_frame(
&focused_output,
self.clock.now(),
Some(Duration::ZERO),
surface_primary_scanout_output,
);
// Forcibly map the window after 16ms if it hasn't committed
let current_time = self.clock.now();
let win_clone = window.clone();
self.schedule(
move |data| {
smithay::utils::Time::elapsed(
&current_time,
data.state.clock.now(),
) > Duration::from_millis(100)
},
move |data| {
win_clone.send_frame(
&focused_output,
data.state.clock.now(),
Some(Duration::ZERO),
surface_primary_scanout_output,
);
},
);
}
}
}

View file

@ -53,6 +53,8 @@ impl State {
}
}
/// Compute tiled window locations and sizes, size maximized and fullscreen windows correctly,
/// and send configures and that cool stuff.
pub fn update_windows(&mut self, output: &Output) {
let Some(layout) = output.with_state(|state| {
state.focused_tags().next().cloned().map(|tag| tag.layout())
@ -66,6 +68,9 @@ impl State {
})
});
tracing::debug!("{} on", windows_on_foc_tags.len());
// Don't unmap windows that aren't on `output` (that would clear all other monitors)
windows_not_on_foc_tags.retain(|win| win.output(self) == Some(output.clone()));
let tiled_windows = windows_on_foc_tags
@ -132,13 +137,14 @@ impl State {
});
}
self.loop_handle.insert_idle(|data| {
crate::state::schedule_on_commit(data, windows_on_foc_tags, |dt| {
for win in windows_not_on_foc_tags {
dt.state.space.unmap_elem(&win);
}
})
});
// self.loop_handle.insert_idle(|data| {
// crate::state::schedule_on_commit(data, windows_on_foc_tags, |dt| {
// for win in windows_not_on_foc_tags {
// // dt.state.space.map_element(win, (500, 0), false);
// dt.state.space.unmap_elem(&win);
// }
// })
// });
}
}

View file

@ -8,7 +8,6 @@
//! While Pinnacle is not a library, this documentation serves to guide those who want to
//! contribute or learn how building something like this works.
#![deny(unused_imports)] // gonna force myself to keep stuff clean
#![warn(clippy::unwrap_used)]
mod api;

View file

@ -11,7 +11,7 @@ use smithay::{
ImportAll, ImportMem, Renderer, Texture,
},
desktop::{
space::{self, SpaceRenderElements, SurfaceTree},
space::{SpaceRenderElements, SurfaceTree},
Space,
},
input::pointer::{CursorImageAttributes, CursorImageStatus},
@ -25,7 +25,7 @@ use smithay::{
wayland::{compositor, input_method::InputMethodHandle},
};
use crate::{state::WithState, window::WindowElement};
use crate::{state::WithState, tag::Tag, window::WindowElement};
use self::pointer::{PointerElement, PointerRenderElement};
@ -78,16 +78,17 @@ where
#[allow(clippy::too_many_arguments)]
pub fn generate_render_elements<R, T>(
renderer: &mut R,
space: &Space<WindowElement>,
output: &Output,
input_method: &InputMethodHandle,
windows: &[WindowElement],
pointer_location: Point<f64, Logical>,
pointer_element: &mut PointerElement<T>,
pointer_image: Option<&TextureBuffer<T>>,
cursor_status: &mut CursorImageStatus,
dnd_icon: Option<&WlSurface>,
focus_stack: &[WindowElement],
renderer: &mut R,
output: &Output,
input_method: &InputMethodHandle,
pointer_element: &mut PointerElement<T>,
pointer_image: Option<&TextureBuffer<T>>,
) -> Vec<OutputRenderElements<R, WaylandSurfaceRenderElement<R>>>
where
R: Renderer<TextureId = T> + ImportAll + ImportMem,
@ -211,9 +212,18 @@ where
output_render_elements
} else {
// render everything
let space_render_elements =
space::space_render_elements(renderer, [space], output, 1.0)
.expect("Failed to get render elements");
// let space_render_elements =
// space::space_render_elements(renderer, [space], output, 1.0)
// .expect("Failed to get render elements");
let tags = space
.outputs()
.flat_map(|op| {
op.with_state(|state| state.focused_tags().cloned().collect::<Vec<_>>())
})
.collect::<Vec<_>>();
let space_render_elements: Vec<WaylandSurfaceRenderElement<R>> =
Tag::tag_render_elements(&tags, windows, space, renderer);
let mut output_render_elements =
Vec::<OutputRenderElements<_, WaylandSurfaceRenderElement<_>>>::new();
@ -226,6 +236,7 @@ where
output_render_elements.extend(
space_render_elements
.into_iter()
.map(CustomRenderElements::from)
.map(OutputRenderElements::from),
);
output_render_elements

View file

@ -589,6 +589,10 @@ impl ApiState {
pub trait WithState {
type State: Default;
/// Access data map state.
///
/// RefCell Safety: This function will panic if called within itself.
fn with_state<F, T>(&self, func: F) -> T
where
F: FnMut(&mut Self::State) -> T;

View file

@ -7,11 +7,20 @@ use std::{
sync::atomic::{AtomicU32, Ordering},
};
use smithay::output::Output;
use smithay::{
backend::renderer::{
element::{surface::WaylandSurfaceRenderElement, AsRenderElements},
ImportAll, ImportMem, Renderer,
},
desktop::{space::SpaceElement, Space},
output::Output,
utils::Scale,
};
use crate::{
layout::Layout,
state::{State, WithState},
window::WindowElement,
};
static TAG_ID_COUNTER: AtomicU32 = AtomicU32::new(0);
@ -64,6 +73,7 @@ impl Eq for TagInner {}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Tag(Rc<RefCell<TagInner>>);
// RefCell Safety: These methods should never panic because they are all self-contained or Copy.
impl Tag {
pub fn id(&self) -> TagId {
self.0.borrow().id
@ -107,4 +117,37 @@ impl Tag {
.find(|output| output.with_state(|state| state.tags.iter().any(|tg| tg == self)))
.cloned()
}
/// Get the render_elements for the provided tags.
pub fn tag_render_elements<R, C>(
tags: &[Tag],
windows: &[WindowElement],
space: &Space<WindowElement>,
renderer: &mut R,
) -> Vec<C>
where
R: Renderer + ImportAll + ImportMem,
<R as Renderer>::TextureId: 'static,
C: From<WaylandSurfaceRenderElement<R>>,
{
let elements = windows
.iter()
.filter(|win| {
win.with_state(|state| {
state
.tags
.iter()
.any(|tag| tags.iter().any(|tag2| tag == tag2))
})
})
.flat_map(|win| {
let loc = (space.element_location(win).unwrap_or((0, 0).into())
- win.geometry().loc)
.to_physical(1);
win.render_elements::<C>(renderer, loc, Scale::from(1.0), 1.0)
})
.collect::<Vec<_>>();
elements
}
}