diff --git a/Cargo.lock b/Cargo.lock index 8376ea4e..6f11eda0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -455,7 +455,7 @@ dependencies = [ "fontdb 0.10.0", "libm", "log", - "ouroboros 0.15.5", + "ouroboros 0.15.6", "rangemap", "rustybuzz 0.6.0", "swash", @@ -1097,7 +1097,7 @@ checksum = "d52186a39c335aa6f79fc0bf1c3cf854870b6ad4e50a7bb8a59b4ba1331f478a" dependencies = [ "fontconfig-parser", "log", - "memmap2 0.5.8", + "memmap2 0.5.10", "ttf-parser 0.17.1", ] @@ -1108,7 +1108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8131752b3f3b876a20f42b3d08233ad177d6e7ec6d18aaa6954489a201071be5" dependencies = [ "log", - "memmap2 0.5.8", + "memmap2 0.5.10", "ttf-parser 0.17.1", ] @@ -1355,9 +1355,9 @@ dependencies = [ [[package]] name = "glyph_brush" -version = "0.7.6" +version = "0.7.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b773a724cb29f6119043a46bd2fc6bfedce59ab9898a3c07df66082acbea0ca" +checksum = "4edefd123f28a0b1d41ec4a489c2b43020b369180800977801611084f342978d" dependencies = [ "glyph_brush_draw_cache", "glyph_brush_layout", @@ -1975,9 +1975,9 @@ dependencies = [ [[package]] name = "memmap2" -version = "0.5.8" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b182332558b18d807c4ce1ca8ca983b34c3ee32765e47b3f0f69b90355cc1dc" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] @@ -2263,18 +2263,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d829733185c1ca374f17e52b762f24f535ec625d2cc1f070e34c8a9068f341b" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.9" +version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2be1598bf1c313dcdd12092e3f1920f463462525a21b7b4e11b4168353d0123e" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -2348,12 +2348,12 @@ dependencies = [ [[package]] name = "ouroboros" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbb50b356159620db6ac971c6d5c9ab788c9cc38a6f49619fca2a27acb062ca" +checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" dependencies = [ "aliasable", - "ouroboros_macro 0.15.5", + "ouroboros_macro 0.15.6", ] [[package]] @@ -2371,9 +2371,9 @@ dependencies = [ [[package]] name = "ouroboros_macro" -version = "0.15.5" +version = "0.15.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0d9d1a6191c4f391f87219d1ea42b23f09ee84d64763cd05ee6ea88d9f384d" +checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" dependencies = [ "Inflector", "proc-macro-error", @@ -2874,9 +2874,9 @@ dependencies = [ [[package]] name = "rgb" -version = "0.8.35" +version = "0.8.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7495acf66551cdb696b7711408144bcd3194fc78e32f3a09e809bfe7dd4a7ce3" +checksum = "20ec2d3e3fc7a92ced357df9cebd5a10b6fb2aa1ee797bf7e9ce2f17dffc8f59" dependencies = [ "bytemuck", ] @@ -3114,9 +3114,9 @@ checksum = "7bd3e3206899af3f8b12af284fafc038cc1dc2b41d1b89dd17297221c5d225de" [[package]] name = "slab" -version = "0.4.7" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4614a76b2a8be0058caa9dbbaf66d988527d86d003c11a94fbd335d7661edcef" +checksum = "6528351c9bc8ab22353f9d776db39a20288e8d6c37ef8cfe3317cf875eecfc2d" dependencies = [ "autocfg", ] @@ -3200,7 +3200,7 @@ dependencies = [ "dlib", "lazy_static", "log", - "memmap2 0.5.8", + "memmap2 0.5.10", "nix 0.24.3", "pkg-config", "wayland-client 0.29.5", @@ -3350,9 +3350,9 @@ dependencies = [ [[package]] name = "syn" -version = "1.0.107" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f4064b5b16e03ae50984a5a8ed5d4f8803e6bc1fd170a3cda91a1be4b18e3f5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ "proc-macro2", "quote", @@ -3862,9 +3862,9 @@ dependencies = [ [[package]] name = "wayland-backend" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb23bfea266c92bb051ea36cce0eb1a52b743dc1c5f168021947eda79764656d" +checksum = "79ebd48bfc1178c9190c7ff80cc822b3335ffc83141e9aa723168f377257623e" dependencies = [ "cc", "downcast-rs", @@ -4450,7 +4450,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbee136714379ab22da0280207fdb7f47e0bb940adea97731b65598b8c7a92e" dependencies = [ "libc", - "memmap2 0.5.8", + "memmap2 0.5.10", ] [[package]] diff --git a/src/backend/kms/mod.rs b/src/backend/kms/mod.rs index 652f8d5a..62c0b665 100644 --- a/src/backend/kms/mod.rs +++ b/src/backend/kms/mod.rs @@ -72,7 +72,7 @@ mod drm_helpers; mod socket; use socket::*; -use super::render::{CursorMode, GlMultiRenderer}; +use super::render::{init_shaders, CursorMode, GlMultiRenderer}; // for now we assume we need at least 3ms const MIN_RENDER_TIME: Duration = Duration::from_millis(3); @@ -542,14 +542,18 @@ impl State { render_node ) })?; + + let mut renderer = match backend.api.single_renderer(&render_node) { + Ok(renderer) => renderer, + Err(err) => { + warn!(?err, "Failed to initialize output."); + backend.api.as_mut().remove_node(&render_node); + return Ok(()); + } + }; + init_shaders(&mut renderer).expect("Failed to initialize renderer"); + for (crtc, conn) in outputs { - let mut renderer = match backend.api.single_renderer(&render_node) { - Ok(renderer) => renderer, - Err(err) => { - warn!(?err, "Failed to initialize output."); - continue; - } - }; match device.setup_surface(crtc, conn, (w, 0), &mut renderer) { Ok(output) => { w += output diff --git a/src/backend/render/mod.rs b/src/backend/render/mod.rs index 409eaa6d..52c7b5a5 100644 --- a/src/backend/render/mod.rs +++ b/src/backend/render/mod.rs @@ -1,5 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-only +use std::{ + borrow::{Borrow, BorrowMut}, + cell::RefCell, +}; + #[cfg(feature = "debug")] use crate::{debug::fps_ui, utils::prelude::*}; use crate::{ @@ -26,15 +31,18 @@ use smithay::{ damage::{ DamageTrackedRenderer, DamageTrackedRendererError as RenderError, OutputNoMode, }, - element::{RenderElement, RenderElementStates}, - gles2::Gles2Error, + element::{Element, RenderElement, RenderElementStates}, + gles2::{ + element::PixelShaderElement, Gles2Error, Gles2PixelProgram, Gles2Renderer, Uniform, + UniformName, UniformType, + }, glow::GlowRenderer, multigpu::{gbm::GbmGlesBackend, MultiFrame, MultiRenderer}, Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter, }, }, output::Output, - utils::{Physical, Rectangle}, + utils::{Logical, Physical, Point, Rectangle, Size}, wayland::dmabuf::get_dmabuf, }; use tracing::warn; @@ -50,6 +58,93 @@ pub type GlMultiFrame<'a, 'b, 'frame> = MultiFrame<'a, 'a, 'b, 'frame, GbmGlesBackend, GbmGlesBackend>; pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0]; +pub static FOCUS_INDICATOR_COLOR: [f32; 4] = [0.580, 0.921, 0.921, 1.0]; +pub static FOCUS_INDICATOR_THICKNESS: f32 = 4.0; +pub static FOCUS_INDICATOR_RADIUS: f32 = 8.0; +pub static FOCUS_INDICATOR_SHADER: &str = include_str!("./shaders/focus_indicator.frag"); + +pub struct IndicatorShader(pub Gles2PixelProgram); +struct IndicatorElement(pub RefCell); + +impl IndicatorShader { + pub fn get(renderer: &R) -> Gles2PixelProgram { + Borrow::::borrow(renderer.glow_renderer()) + .egl_context() + .user_data() + .get::() + .expect("Custom Shaders not initialized") + .0 + .clone() + } + + pub fn element( + renderer: &R, + geo: Rectangle, + ) -> PixelShaderElement { + let thickness = FOCUS_INDICATOR_THICKNESS; + let thickness_loc = (thickness as i32, thickness as i32); + let thickness_size = ((thickness * 2.0) as i32, (thickness * 2.0) as i32); + let geo = Rectangle::from_loc_and_size( + geo.loc - Point::from(thickness_loc), + geo.size + Size::from(thickness_size), + ); + + let user_data = Borrow::::borrow(renderer.glow_renderer()) + .egl_context() + .user_data(); + + match user_data.get::() { + Some(elem) => { + let mut elem = elem.0.borrow_mut(); + if elem.geometry(1.0.into()).to_logical(1) != geo { + elem.resize(geo, None); + } + elem.clone() + } + None => { + let shader = Self::get(renderer); + let color = FOCUS_INDICATOR_COLOR; + + let elem = PixelShaderElement::new( + shader, + dbg!(geo), + None, //TODO + color[3], + vec![ + Uniform::new("color", [color[0], color[1], color[2]]), + Uniform::new("thickness", thickness), + Uniform::new("radius", FOCUS_INDICATOR_RADIUS), + ], + ); + if !user_data.insert_if_missing(|| IndicatorElement(RefCell::new(elem.clone()))) { + *user_data.get::().unwrap().0.borrow_mut() = elem.clone(); + } + elem + } + } + } +} + +pub fn init_shaders(renderer: &mut R) -> Result<(), Gles2Error> { + let glow_renderer = renderer.glow_renderer_mut(); + let gles_renderer: &mut Gles2Renderer = glow_renderer.borrow_mut(); + + let indicator_shader = gles_renderer.compile_custom_pixel_shader( + FOCUS_INDICATOR_SHADER, + &[ + UniformName::new("color", UniformType::_3f), + UniformName::new("thickness", UniformType::_1f), + UniformName::new("radius", UniformType::_1f), + ], + )?; + + let egl_context = gles_renderer.egl_context(); + egl_context + .user_data() + .insert_if_missing(|| IndicatorShader(indicator_shader)); + + Ok(()) +} #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum CursorMode { @@ -248,6 +343,13 @@ where } } + let last_active_seat = state.last_active_seat().clone(); + let move_active = last_active_seat + .user_data() + .get::() + .unwrap() + .borrow() + .is_some(); elements.extend( workspace .render_output::( @@ -255,6 +357,7 @@ where output, &state.shell.override_redirect_windows, state.xwayland_state.values_mut(), + (!move_active).then_some(&last_active_seat), exclude_workspace_overview, ) .map_err(|_| OutputNoMode)? diff --git a/src/backend/render/shaders/focus_indicator.frag b/src/backend/render/shaders/focus_indicator.frag new file mode 100644 index 00000000..cebaf8db --- /dev/null +++ b/src/backend/render/shaders/focus_indicator.frag @@ -0,0 +1,33 @@ +precision mediump float; +uniform float alpha; +#if defined(DEBUG_FLAGS) +uniform float tint; +#endif +uniform vec2 size; +varying vec2 v_coords; + +uniform vec3 color; +uniform float thickness; +uniform float radius; + +float rounded_box(vec2 center, vec2 size, float radius) { + return length(max(abs(center) - size + radius, 0.0)) - radius; +} + +void main() { + vec2 center = size / 2.0 - vec2(0.5); + vec2 location = v_coords * size; + vec4 mix_color; + + float distance = rounded_box(location - center, size / 2.0 - vec2(thickness / 2.0), radius); + float smoothedAlpha = 1.0 - smoothstep(0.0, 2.0, abs(distance) - (thickness / 2.0)); + + mix_color = mix(vec4(0.0, 0.0, 0.0, 0.0), vec4(color, alpha), smoothedAlpha); + +#if defined(DEBUG_FLAGS) + if (tint == 1.0) + mix_color = vec4(0.0, 0.3, 0.0, 0.2) + mix_color * 0.8; +#endif + + gl_FragColor = mix_color; +} \ No newline at end of file diff --git a/src/backend/winit.rs b/src/backend/winit.rs index d3281fdc..a75384ee 100644 --- a/src/backend/winit.rs +++ b/src/backend/winit.rs @@ -32,7 +32,7 @@ use tracing::{error, info, warn}; #[cfg(feature = "debug")] use crate::state::Fps; -use super::render::CursorMode; +use super::render::{init_shaders, CursorMode}; pub struct WinitState { // The winit backend currently has no notion of multiple windows @@ -147,6 +147,7 @@ pub fn init_backend( ) -> Result<()> { let (mut backend, mut input) = winit::init().map_err(|_| anyhow!("Failed to initilize winit backend"))?; + init_shaders(backend.renderer()).expect("Failed to initialize renderer"); init_egl_client_side(dh, state, &mut backend)?; diff --git a/src/backend/x11.rs b/src/backend/x11.rs index 8154e591..66cd06fc 100644 --- a/src/backend/x11.rs +++ b/src/backend/x11.rs @@ -42,6 +42,8 @@ use tracing::{debug, error, info, warn}; #[cfg(feature = "debug")] use crate::state::Fps; +use super::render::init_shaders; + enum Allocator { Gbm(GbmAllocator), Vulkan(PhysicalDevice), @@ -348,6 +350,7 @@ pub fn init_backend( let mut renderer = unsafe { GlowRenderer::new(context) }.with_context(|| "Failed to initialize renderer")?; + init_shaders(&mut renderer).expect("Failed to initialize renderer"); init_egl_client_side(dh, state, &mut renderer)?; state.backend = BackendData::X11(X11State { diff --git a/src/shell/element/mod.rs b/src/shell/element/mod.rs index 06709daf..9d28f9d9 100644 --- a/src/shell/element/mod.rs +++ b/src/shell/element/mod.rs @@ -1,5 +1,8 @@ use crate::{ - backend::render::{element::AsGlowRenderer, GlMultiFrame, GlMultiRenderer}, + backend::render::{ + element::{AsGlowFrame, AsGlowRenderer}, + GlMultiFrame, GlMultiRenderer, + }, state::State, utils::prelude::SeatExt, }; @@ -9,7 +12,9 @@ use smithay::{ input::KeyState, renderer::{ element::{AsRenderElements, Element, RenderElement, UnderlyingStorage}, + gles2::element::PixelShaderElement, glow::GlowRenderer, + multigpu::Error as MultiError, ImportAll, ImportMem, Renderer, }, }, @@ -46,14 +51,10 @@ pub use self::stack::CosmicStack; pub mod window; pub use self::window::CosmicWindow; -#[cfg(feature = "debug")] -use crate::backend::render::element::AsGlowFrame; #[cfg(feature = "debug")] use egui::plot::{Corner, Legend, Plot, PlotPoints, Polygon}; #[cfg(feature = "debug")] -use smithay::backend::renderer::{ - element::texture::TextureRenderElement, gles2::Gles2Texture, multigpu::Error as MultiError, -}; +use smithay::backend::renderer::{element::texture::TextureRenderElement, gles2::Gles2Texture}; #[cfg(feature = "debug")] use tracing::debug; @@ -659,6 +660,7 @@ where { Stack(self::stack::CosmicStackRenderElement), Window(self::window::CosmicWindowRenderElement), + Indicator(PixelShaderElement), #[cfg(feature = "debug")] Egui(TextureRenderElement), } @@ -672,6 +674,7 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.id(), CosmicMappedRenderElement::Window(elem) => elem.id(), + CosmicMappedRenderElement::Indicator(elem) => elem.id(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.id(), } @@ -681,6 +684,7 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.current_commit(), CosmicMappedRenderElement::Window(elem) => elem.current_commit(), + CosmicMappedRenderElement::Indicator(elem) => elem.current_commit(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.current_commit(), } @@ -690,6 +694,7 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.src(), CosmicMappedRenderElement::Window(elem) => elem.src(), + CosmicMappedRenderElement::Indicator(elem) => elem.src(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.src(), } @@ -699,6 +704,7 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.geometry(scale), CosmicMappedRenderElement::Window(elem) => elem.geometry(scale), + CosmicMappedRenderElement::Indicator(elem) => elem.geometry(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.geometry(scale), } @@ -708,6 +714,7 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.location(scale), CosmicMappedRenderElement::Window(elem) => elem.location(scale), + CosmicMappedRenderElement::Indicator(elem) => elem.location(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.location(scale), } @@ -717,6 +724,7 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.transform(), CosmicMappedRenderElement::Window(elem) => elem.transform(), + CosmicMappedRenderElement::Indicator(elem) => elem.transform(), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.transform(), } @@ -730,6 +738,7 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.damage_since(scale, commit), CosmicMappedRenderElement::Window(elem) => elem.damage_since(scale, commit), + CosmicMappedRenderElement::Indicator(elem) => elem.damage_since(scale, commit), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.damage_since(scale, commit), } @@ -739,6 +748,7 @@ where match self { CosmicMappedRenderElement::Stack(elem) => elem.opaque_regions(scale), CosmicMappedRenderElement::Window(elem) => elem.opaque_regions(scale), + CosmicMappedRenderElement::Indicator(elem) => elem.opaque_regions(scale), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.opaque_regions(scale), } @@ -756,6 +766,9 @@ impl RenderElement for CosmicMappedRenderElement { match self { CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::Indicator(elem) => { + RenderElement::::draw(elem, frame, src, dst, damage) + } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { RenderElement::::draw(elem, frame, src, dst, damage) @@ -767,6 +780,7 @@ impl RenderElement for CosmicMappedRenderElement { match self { CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::Indicator(elem) => elem.underlying_storage(renderer), #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => elem.underlying_storage(renderer), } @@ -786,6 +800,10 @@ impl<'a, 'b> RenderElement> match self { CosmicMappedRenderElement::Stack(elem) => elem.draw(frame, src, dst, damage), CosmicMappedRenderElement::Window(elem) => elem.draw(frame, src, dst, damage), + CosmicMappedRenderElement::Indicator(elem) => { + RenderElement::::draw(elem, frame.glow_frame_mut(), src, dst, damage) + .map_err(|err| MultiError::Render(err)) + } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { let glow_frame = frame.glow_frame_mut(); @@ -802,6 +820,9 @@ impl<'a, 'b> RenderElement> match self { CosmicMappedRenderElement::Stack(elem) => elem.underlying_storage(renderer), CosmicMappedRenderElement::Window(elem) => elem.underlying_storage(renderer), + CosmicMappedRenderElement::Indicator(elem) => { + elem.underlying_storage(renderer.glow_renderer_mut()) + } #[cfg(feature = "debug")] CosmicMappedRenderElement::Egui(elem) => { let glow_renderer = renderer.glow_renderer_mut(); @@ -836,6 +857,18 @@ where CosmicMappedRenderElement::Window(elem) } } + +impl From for CosmicMappedRenderElement +where + R: Renderer + ImportAll + ImportMem + AsGlowRenderer, + ::TextureId: 'static, + CosmicMappedRenderElement: RenderElement, +{ + fn from(elem: PixelShaderElement) -> Self { + CosmicMappedRenderElement::Indicator(elem) + } +} + #[cfg(feature = "debug")] impl From> for CosmicMappedRenderElement where diff --git a/src/shell/layout/floating/grabs/moving.rs b/src/shell/layout/floating/grabs/moving.rs index 6fd9bcc8..c4617ac0 100644 --- a/src/shell/layout/floating/grabs/moving.rs +++ b/src/shell/layout/floating/grabs/moving.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - backend::render::element::AsGlowRenderer, + backend::render::{element::AsGlowRenderer, IndicatorShader}, shell::{ element::{CosmicMapped, CosmicMappedRenderElement}, focus::target::{KeyboardFocusTarget, PointerFocusTarget}, @@ -56,13 +56,22 @@ impl MoveGrabState { } let scale = output.current_scale().fractional_scale().into(); - AsRenderElements::::render_elements::( + let mut elements: Vec = vec![CosmicMappedRenderElement::from(IndicatorShader::element( + renderer, + Rectangle::from_loc_and_size( + location.to_i32_round() - output.geometry().loc, + self.window.geometry().size, + ), + )) + .into()]; + elements.extend(AsRenderElements::::render_elements::( &self.window, renderer, (location.to_i32_round() - output.geometry().loc - self.window.geometry().loc) .to_physical_precise_round(scale), scale, - ) + )); + elements } pub fn send_frames( diff --git a/src/shell/layout/floating/mod.rs b/src/shell/layout/floating/mod.rs index 4417478a..c4f8c8fb 100644 --- a/src/shell/layout/floating/mod.rs +++ b/src/shell/layout/floating/mod.rs @@ -1,7 +1,10 @@ // SPDX-License-Identifier: GPL-3.0-only use smithay::{ - backend::renderer::{element::RenderElement, ImportAll, ImportMem, Renderer}, + backend::renderer::{ + element::{AsRenderElements, RenderElement}, + ImportAll, ImportMem, Renderer, + }, desktop::{layer_map_for_output, space::SpaceElement, Space}, input::{pointer::GrabStartData as PointerGrabStartData, Seat}, output::Output, @@ -10,11 +13,11 @@ use smithay::{ use std::collections::HashMap; use crate::{ - backend::render::element::AsGlowRenderer, + backend::render::{element::AsGlowRenderer, IndicatorShader}, shell::{ element::{CosmicMapped, CosmicMappedRenderElement}, grabs::ResizeEdge, - CosmicSurface, OutputNotMapped, + CosmicSurface, }, state::State, utils::prelude::*, @@ -342,16 +345,37 @@ impl FloatingLayout { &self, renderer: &mut R, output: &Output, - ) -> Result>, OutputNotMapped> + focused: Option<&CosmicMapped>, + ) -> Vec> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, ::TextureId: 'static, CosmicMappedRenderElement: RenderElement, { let output_scale = output.current_scale().fractional_scale(); - let output_geo = self.space.output_geometry(output).ok_or(OutputNotMapped)?; - Ok(self - .space - .render_elements_for_region(renderer, &output_geo, output_scale)) + self.space + .elements_for_output(output) + .rev() + .flat_map(|elem| { + let render_location = + self.space.element_location(elem).unwrap() - elem.geometry().loc; + let mut elements = elem.render_elements( + renderer, + render_location.to_physical_precise_round(output_scale), + output_scale.into(), + ); + if focused == Some(elem) { + let element = IndicatorShader::element( + renderer, + Rectangle::from_loc_and_size( + self.space.element_location(elem).unwrap(), + elem.geometry().size, + ), + ); + elements.insert(0, element.into()); + } + elements + }) + .collect() } } diff --git a/src/shell/layout/tiling/mod.rs b/src/shell/layout/tiling/mod.rs index ceb4f58e..187c33a7 100644 --- a/src/shell/layout/tiling/mod.rs +++ b/src/shell/layout/tiling/mod.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only use crate::{ - backend::render::element::AsGlowRenderer, + backend::render::{element::AsGlowRenderer, IndicatorShader}, shell::{ element::{CosmicMapped, CosmicMappedRenderElement}, focus::{ @@ -1299,6 +1299,7 @@ impl TilingLayout { &self, renderer: &mut R, output: &Output, + focused: Option<&CosmicMapped>, ) -> Result>, OutputNotMapped> where R: Renderer + ImportAll + ImportMem + AsGlowRenderer, @@ -1360,16 +1361,25 @@ impl TilingLayout { }) .flatten() .flat_map(|(mapped, loc)| { - AsRenderElements::::render_elements::>( - mapped, - renderer, - loc.to_physical_precise_round(output_scale) - - mapped - .geometry() - .loc - .to_physical_precise_round(output_scale), - Scale::from(output_scale), - ) + let mut elements = + AsRenderElements::::render_elements::>( + mapped, + renderer, + loc.to_physical_precise_round(output_scale) + - mapped + .geometry() + .loc + .to_physical_precise_round(output_scale), + Scale::from(output_scale), + ); + if focused == Some(mapped) { + let element = IndicatorShader::element( + renderer, + Rectangle::from_loc_and_size(loc, mapped.geometry().size), + ); + elements.insert(0, element.into()); + } + elements }) .collect::>()) } diff --git a/src/shell/workspace.rs b/src/shell/workspace.rs index fa807019..b6830828 100644 --- a/src/shell/workspace.rs +++ b/src/shell/workspace.rs @@ -435,6 +435,7 @@ impl Workspace { output: &Output, override_redirect_windows: &[X11Surface], xwm_state: impl Iterator, + draw_focus_indicator: Option<&Seat>, exclude_workspace_overview: bool, ) -> Result>, OutputNotMapped> where @@ -559,10 +560,12 @@ impl Workspace { }), ); + let focused = + draw_focus_indicator.and_then(|seat| self.focus_stack.get(seat).last().cloned()); // floating surfaces render_elements.extend( self.floating_layer - .render_output::(renderer, output)? + .render_output::(renderer, output, focused.as_ref()) .into_iter() .map(WorkspaceRenderElement::from), ); @@ -570,7 +573,7 @@ impl Workspace { //tiling surfaces render_elements.extend( self.tiling_layer - .render_output::(renderer, output)? + .render_output::(renderer, output, focused.as_ref())? .into_iter() .map(WorkspaceRenderElement::from), );