Fix multi-monitor fullscreen rendering and pointer input

This commit is contained in:
Ottatop 2023-12-23 22:03:20 -06:00
parent f8d1e59c06
commit 31172c5a4e
6 changed files with 73 additions and 70 deletions

View file

@ -121,7 +121,8 @@ impl State {
FloatingOrTiled::Tiled(_) => FloatingOrTiled::Tiled(Some(rect)),
}
});
if let Some(output) = window.output(self) {
for output in self.space.outputs_for_element(&window) {
self.update_windows(&output);
self.schedule_render(&output);
}
@ -158,11 +159,6 @@ impl State {
let Some(output) = window.output(self) else { return };
self.update_windows(&output);
// Sometimes toggling won't change the window size,
// causing no commit.
//
// Schedule a render in case the window moves.
self.schedule_render(&output);
}
Msg::ToggleFullscreen { window_id } => {
@ -185,9 +181,8 @@ impl State {
self.config.window_rules.push((cond, rule));
}
Msg::WindowMoveGrab { button } => {
// TODO: in the future, there may be movable layer surfaces
let Some((FocusTarget::Window(window), _)) =
self.surface_under(self.pointer_location)
self.focus_target_under(self.pointer_location)
else {
return;
};
@ -208,7 +203,7 @@ impl State {
// TODO: in the future, there may be movable layer surfaces
let pointer_loc = self.pointer_location;
let Some((FocusTarget::Window(window), window_loc)) =
self.surface_under(pointer_loc)
self.focus_target_under(pointer_loc)
else {
return;
};
@ -749,7 +744,6 @@ impl State {
}
};
// This is not important enough to crash on error, so just print the error instead
if let Err(err) = self.async_scheduler.schedule(future) {
tracing::error!("Failed to schedule future: {err}");
}

View file

@ -402,9 +402,9 @@ pub fn run_udev() -> anyhow::Result<()> {
data.state.connector_connected(node, connector, crtc);
}
}
// for output in data.state.space.outputs().cloned().collect::<Vec<_>>() {
// data.state.schedule_render(&output);
// }
for output in data.state.space.outputs().cloned().collect::<Vec<_>>() {
data.state.schedule_render(&output);
}
}
}
})

View file

@ -146,6 +146,11 @@ impl PointerGrab<State> for MoveSurfaceGrab {
.configure(new_geo)
.expect("failed to configure x11 win");
}
let outputs = state.space.outputs_for_element(&self.window);
for output in outputs {
state.schedule_render(&output);
}
}
}

View file

@ -10,7 +10,7 @@ use smithay::{
delegate_compositor, delegate_data_device, delegate_fractional_scale, delegate_layer_shell,
delegate_output, delegate_presentation, delegate_primary_selection, delegate_relative_pointer,
delegate_seat, delegate_shm, delegate_viewporter,
desktop::{self, find_popup_root_surface, layer_map_for_output, PopupKind, WindowSurfaceType},
desktop::{self, layer_map_for_output, PopupKind, WindowSurfaceType},
input::{pointer::CursorImageStatus, Seat, SeatHandler, SeatState},
output::Output,
reexports::{
@ -130,24 +130,33 @@ impl CompositorHandler for State {
crate::grab::resize_grab::handle_commit(self, surface);
let output = if let Some(output) = self
.window_for_surface(surface)
.and_then(|win| win.output(self))
{
output // surface is a window
} else if let Some(output) = self
.window_for_surface(&root)
.and_then(|win| win.output(self))
{
output // root is a window
} else if let Some(output) = self
.popup_manager
.find_popup(surface)
.and_then(|popup| find_popup_root_surface(&popup).ok())
.and_then(|surf| self.window_for_surface(&surf))
.and_then(|win| win.output(self))
{
output // surface is a popup
let outputs = if let Some(window) = self.window_for_surface(surface) {
let mut outputs = self.space.outputs_for_element(&window);
// When the window hasn't been mapped `outputs` is empty,
// so also trigger a render using the window's tags' output
if let Some(output) = window.output(self) {
outputs.push(output);
}
outputs // surface is a window
} else if let Some(window) = self.window_for_surface(&root) {
let mut outputs = self.space.outputs_for_element(&window);
if let Some(output) = window.output(self) {
outputs.push(output);
}
outputs // surface is a root window
} else if let Some(PopupKind::Xdg(surf)) = self.popup_manager.find_popup(surface) {
let geo = surf.with_pending_state(|state| state.geometry);
let outputs = self
.space
.outputs()
.filter_map(|output| {
let op_geo = self.space.output_geometry(output);
op_geo.and_then(|op_geo| op_geo.overlaps_or_touches(geo).then_some(output))
})
.cloned()
.collect::<Vec<_>>();
outputs
} else if let Some(output) = self
.space
.outputs()
@ -159,12 +168,14 @@ impl CompositorHandler for State {
})
.cloned()
{
output // surface is a layer surface
vec![output] // surface is a layer surface
} else {
return;
};
self.schedule_render(&output);
for output in outputs {
self.schedule_render(&output);
}
}
fn client_compositor_state<'a>(&self, client: &'a Client) -> &'a CompositorClientState {

View file

@ -77,7 +77,7 @@ impl State {
}
/// Get the [`FocusTarget`] under `point`.
pub fn surface_under<P>(&self, point: P) -> Option<(FocusTarget, Point<i32, Logical>)>
pub fn focus_target_under<P>(&self, point: P) -> Option<(FocusTarget, Point<i32, Logical>)>
where
P: Into<Point<f64, Logical>>,
{
@ -100,7 +100,11 @@ impl State {
let top_fullscreen_window = self.focus_state.focus_stack.iter().rev().find(|win| {
win.with_state(|state| {
state.fullscreen_or_maximized.is_fullscreen()
&& state.tags.iter().any(|tag| tag.active())
&& output.with_state(|op_state| {
op_state
.focused_tags()
.any(|op_tag| state.tags.contains(op_tag))
})
})
});
@ -290,7 +294,7 @@ impl State {
// If the button was clicked, focus on the window below if exists, else
// unfocus on windows.
if button_state == ButtonState::Pressed {
if let Some((focus, _)) = self.surface_under(pointer_loc) {
if let Some((focus, _)) = self.focus_target_under(pointer_loc) {
// Move window to top of stack.
if let FocusTarget::Window(window) = &focus {
self.space.raise_element(window, true);
@ -465,7 +469,7 @@ impl State {
pointer.motion(
self,
self.surface_under(pointer_loc),
self.focus_target_under(pointer_loc),
&MotionEvent {
location: pointer_loc,
serial,
@ -499,7 +503,7 @@ impl State {
}
}
let surface_under = self.surface_under(self.pointer_location);
let surface_under = self.focus_target_under(self.pointer_location);
if let Some(pointer) = self.seat.get_pointer() {
pointer.motion(

View file

@ -157,12 +157,7 @@ where
.iter()
.rev() // rev because I treat the focus stack backwards vs how the renderer orders it
.filter(|win| {
let output_tags = output.with_state(|state| state.focused_tags().cloned().collect::<Vec<_>>());
let win_tags = win.with_state(|state| state.tags.clone());
output_tags.into_iter().any(|tag| win_tags.iter().any(|tg| &tag == tg))
// win.is_on_active_tag(space.outputs())
win.is_on_active_tag(space.outputs())
})
.map(|win| {
// subtract win.geometry().loc to align decorations correctly
@ -176,6 +171,7 @@ where
(win.render_elements::<WaylandSurfaceRenderElement<R>>(renderer, loc, scale, 1.0), elem_geo)
}).flat_map(|(elems, rect)| {
// elems.into_iter().map(OutputRenderElements::from).collect::<Vec<_>>()
match rect {
Some(rect) => {
elems.into_iter().filter_map(|elem| {
@ -187,8 +183,6 @@ where
})
.collect::<Vec<_>>();
tracing::debug!(elem_count = elements.len());
elements
}
@ -223,15 +217,6 @@ where
let (windows, override_redirect_windows) = windows
.iter()
// TODO: copy pasted from tag_render_elements
.filter(|win| {
let output_tags = output.with_state(|state| state.focused_tags().cloned().collect::<Vec<_>>());
let win_tags = win.with_state(|state| state.tags.clone());
output_tags.into_iter().any(|tag| win_tags.iter().any(|tg| &tag == tg))
// win.is_on_active_tag(space.outputs())
})
.cloned()
.partition::<Vec<_>, _>(|win| !win.is_x11_override_redirect());
@ -320,22 +305,26 @@ where
output_render_elements.extend(o_r_elements.map(OutputRenderElements::from));
let top_fullscreen_window = windows.iter().rev().find(|win| {
let is_wayland_actually_fullscreen = {
if let WindowElement::Wayland(window) = win {
window
.toplevel()
.current_state()
.states
.contains(xdg_toplevel::State::Fullscreen)
} else {
true
}
};
win.with_state(|state| {
let is_wayland_actually_fullscreen = {
if let WindowElement::Wayland(window) = win {
window
.toplevel()
.current_state()
.states
.contains(xdg_toplevel::State::Fullscreen)
} else {
true
}
};
state.fullscreen_or_maximized.is_fullscreen()
&& state.tags.iter().any(|tag| tag.active())
&& is_wayland_actually_fullscreen
})
&& output.with_state(|op_state| {
op_state
.focused_tags()
.any(|op_tag| state.tags.contains(op_tag))
})
}) && is_wayland_actually_fullscreen
});
// If fullscreen windows exist, render only the topmost one