From d75e0dad22a6f0e82d6f969061e2abe568262c5e Mon Sep 17 00:00:00 2001 From: Ottatop Date: Sat, 12 Aug 2023 12:01:55 -0500 Subject: [PATCH] Rework fullscreen tracking, fix fullscreen on udev --- src/backend/udev.rs | 75 ++++++++++++++++++++++++++++++--------- src/backend/winit.rs | 25 +++++++------ src/handlers/xdg_shell.rs | 4 +-- src/input.rs | 16 ++++----- src/render.rs | 14 +++++++- src/tag.rs | 12 ------- 6 files changed, 93 insertions(+), 53 deletions(-) diff --git a/src/backend/udev.rs b/src/backend/udev.rs index a30d1a8..752d911 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -32,7 +32,8 @@ use smithay::{ renderer::{ damage::{self, OutputDamageTracker}, element::{ - texture::TextureBuffer, AsRenderElements, RenderElement, RenderElementStates, + self, surface::WaylandSurfaceRenderElement, texture::TextureBuffer, + AsRenderElements, RenderElement, RenderElementStates, }, gles::{GlesRenderer, GlesTexture}, multigpu::{gbm::GbmGlesBackend, GpuManager, MultiRenderer, MultiTexture}, @@ -98,7 +99,7 @@ use smithay_drm_extras::{ use crate::{ api::msg::{Args, OutgoingMsg}, render::{pointer::PointerElement, CustomRenderElements, OutputRenderElements}, - state::{take_presentation_feedback, CalloopData, State, SurfaceDmabufFeedback}, + state::{take_presentation_feedback, CalloopData, State, SurfaceDmabufFeedback, WithState}, window::WindowElement, }; @@ -1377,6 +1378,7 @@ impl State { &mut self.cursor_status, self.dnd_icon.as_ref(), &self.clock, + &self.focus_state.focus_stack, ); let reschedule = match &result { Ok(has_rendered) => !has_rendered, @@ -1482,11 +1484,12 @@ fn render_surface<'a>( cursor_status: &mut CursorImageStatus, dnd_icon: Option<&WlSurface>, clock: &Clock, + focus_stack: &[WindowElement], ) -> Result { let output_geometry = space.output_geometry(output).unwrap(); let scale = Scale::from(output.current_scale().fractional_scale()); - let mut custom_elements: Vec> = Vec::new(); + let mut custom_render_elements: Vec> = Vec::new(); // draw input method surface if any let rectangle = input_method.coordinates(); let position = Point::from(( @@ -1494,7 +1497,7 @@ fn render_surface<'a>( rectangle.loc.y + rectangle.size.h, )); input_method.with_surface(|surface| { - custom_elements.extend(AsRenderElements::>::render_elements( + custom_render_elements.extend(AsRenderElements::>::render_elements( &SurfaceTree::from_surface(surface), renderer, position.to_physical_precise_round(scale), @@ -1537,7 +1540,7 @@ fn render_surface<'a>( pointer_element.set_status(cursor_status.clone()); } - custom_elements.extend(pointer_element.render_elements( + custom_render_elements.extend(pointer_element.render_elements( renderer, cursor_pos_scaled, scale, @@ -1545,7 +1548,7 @@ fn render_surface<'a>( )); if let Some(dnd_icon) = dnd_icon { - custom_elements.extend(AsRenderElements::render_elements( + custom_render_elements.extend(AsRenderElements::render_elements( &smithay::desktop::space::SurfaceTree::from_surface(dnd_icon), renderer, cursor_pos_scaled, @@ -1555,19 +1558,57 @@ fn render_surface<'a>( } } - let mut output_render_elements = custom_elements - .into_iter() - .map(OutputRenderElements::from) - .collect::>(); + let output_render_elements = { + let top_fullscreen_window = focus_stack.iter().rev().find(|win| { + win.with_state(|state| { + state.status.is_fullscreen() && state.tags.iter().any(|tag| tag.active()) + }) + }); - let space_render_elements = - space::space_render_elements(renderer, [space], output, 1.0).unwrap(); + // If fullscreen windows exist, render only the topmost one + // TODO: wait until the fullscreen window has committed, this will stop flickering + if let Some(window) = top_fullscreen_window { + let mut output_render_elements = + Vec::>>::new(); - output_render_elements.extend( - space_render_elements - .into_iter() - .map(OutputRenderElements::Space), - ); + let window_render_elements: Vec> = + window.render_elements(renderer, (0, 0).into(), scale, 1.0); + + output_render_elements.extend( + custom_render_elements + .into_iter() + .map(OutputRenderElements::from), + ); + + output_render_elements.extend( + window_render_elements + .into_iter() + .map(|elem| OutputRenderElements::Window(element::Wrap::from(elem))), + ); + + 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 mut output_render_elements = + Vec::>>::new(); + + output_render_elements.extend( + custom_render_elements + .into_iter() + .map(OutputRenderElements::from), + ); + output_render_elements.extend( + space_render_elements + .into_iter() + .map(OutputRenderElements::from), + ); + output_render_elements + } + }; let res = surface.compositor.render_frame::<_, _, GlesTexture>( renderer, diff --git a/src/backend/winit.rs b/src/backend/winit.rs index 23f0b75..43b2a42 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -295,21 +295,20 @@ pub fn run_winit() -> Result<(), Box> { )); } - let active_tag_with_fullscreen = { - output.with_state(|state| { - state - .tags - .iter() - .filter(|tag| tag.active()) - .find(|tag| tag.fullscreen_window().is_some()) - .cloned() - }) - }; - let output_render_elements = { let renderer = state.backend_data.backend.renderer(); - if let Some(tag) = active_tag_with_fullscreen { + let top_fullscreen_window = + state.focus_state.focus_stack.iter().rev().find(|win| { + win.with_state(|state| { + state.status.is_fullscreen() + && state.tags.iter().any(|tag| tag.active()) + }) + }); + + // If fullscreen windows exist, render only the topmost one + // TODO: wait until the fullscreen window has committed, this will stop flickering + if let Some(window) = top_fullscreen_window { let mut output_render_elements = Vec::< OutputRenderElements< GlesRenderer, @@ -317,7 +316,6 @@ pub fn run_winit() -> Result<(), Box> { >, >::new(); - let Some(window) = tag.fullscreen_window() else { unreachable!() }; let window_render_elements: Vec> = window.render_elements(renderer, (0, 0).into(), scale, 1.0); @@ -335,6 +333,7 @@ pub fn run_winit() -> Result<(), Box> { output_render_elements } else { + // render everything let space_render_elements = space::space_render_elements(renderer, [&state.space], &output, 1.0) .expect("Failed to get render elements"); diff --git a/src/handlers/xdg_shell.rs b/src/handlers/xdg_shell.rs index f916013..e74f225 100644 --- a/src/handlers/xdg_shell.rs +++ b/src/handlers/xdg_shell.rs @@ -326,7 +326,7 @@ impl XdgShellHandler for State { window.with_state(|state| { let tags = state.tags.iter(); for tag in tags { - tag.set_fullscreen_window(window.clone()); + // tag.set_fullscreen_window(window.clone()); } }); } @@ -352,7 +352,7 @@ impl XdgShellHandler for State { if let Some(window) = self.window_for_surface(surface.wl_surface()) { window.with_state(|state| { for tag in state.tags.iter() { - tag.set_fullscreen_window(None); + // tag.set_fullscreen_window(None); } }); } diff --git a/src/input.rs b/src/input.rs index 9efc3e3..85067f3 100644 --- a/src/input.rs +++ b/src/input.rs @@ -57,7 +57,6 @@ impl State { where P: Into>, { - // TODO: fullscreen let point: Point = point.into(); let output = self.space.outputs().find(|op| { @@ -74,14 +73,15 @@ impl State { let layers = layer_map_for_output(output); + let top_fullscreen_window = self.focus_state.focus_stack.iter().rev().find(|win| { + win.with_state(|state| { + state.status.is_fullscreen() && state.tags.iter().any(|tag| tag.active()) + }) + }); + // I think I'm going a bit too far with the functional stuff - [output] - .into_iter() - .flat_map(|op| op.with_state(|state| state.tags.clone())) - .filter(|tag| tag.active()) - .find(|tag| tag.fullscreen_window().is_some()) - .and_then(|tag| tag.fullscreen_window()) - .map(|window| (FocusTarget::from(window), output_geo.loc)) + top_fullscreen_window + .map(|window| (FocusTarget::from(window.clone()), output_geo.loc)) .or_else(|| { layers .layer_under(wlr_layer::Layer::Overlay, point) diff --git a/src/render.rs b/src/render.rs index 3152138..525a54f 100644 --- a/src/render.rs +++ b/src/render.rs @@ -12,7 +12,7 @@ use smithay::{ use crate::window::WindowElement; -use self::pointer::PointerRenderElement; +use self::pointer::{PointerElement, PointerRenderElement}; pub mod pointer; @@ -60,3 +60,15 @@ where .collect() } } + +pub fn render_elements( + renderer: &mut R, + pointer_element: &mut PointerElement, +) -> Vec>> +where + R: Renderer + ImportAll, + ::TextureId: 'static, + T: Texture, +{ + vec![] +} diff --git a/src/tag.rs b/src/tag.rs index e6f1184..08893d0 100644 --- a/src/tag.rs +++ b/src/tag.rs @@ -13,7 +13,6 @@ use crate::{ backend::Backend, layout::Layout, state::{State, WithState}, - window::WindowElement, }; static TAG_ID_COUNTER: AtomicU32 = AtomicU32::new(0); @@ -45,8 +44,6 @@ struct TagInner { active: bool, /// What layout this tag has. layout: Layout, - /// The fullscreen window, if any. - fullscreen_window: Option, } impl PartialEq for TagInner { @@ -84,14 +81,6 @@ impl Tag { pub fn set_layout(&self, layout: Layout) { self.0.borrow_mut().layout = layout; } - - pub fn fullscreen_window(&self) -> Option { - self.0.borrow().fullscreen_window.clone() - } - - pub fn set_fullscreen_window(&self, window: impl Into>) { - self.0.borrow_mut().fullscreen_window = window.into(); - } } impl Tag { @@ -101,7 +90,6 @@ impl Tag { name, active: false, layout: Layout::MasterStack, // TODO: get from config - fullscreen_window: None, }))) }