2022-02-04 21:04:17 +01:00
|
|
|
// SPDX-License-Identifier: GPL-3.0-only
|
|
|
|
|
|
2023-02-25 00:17:54 +01:00
|
|
|
use std::{
|
|
|
|
|
borrow::{Borrow, BorrowMut},
|
|
|
|
|
cell::RefCell,
|
2023-05-17 19:46:21 +02:00
|
|
|
collections::HashMap,
|
|
|
|
|
sync::Weak,
|
2023-05-22 20:19:11 +02:00
|
|
|
time::Instant,
|
2023-02-25 00:17:54 +01:00
|
|
|
};
|
|
|
|
|
|
2023-08-01 14:26:51 -07:00
|
|
|
#[cfg(feature = "debug")]
|
2024-03-21 17:49:06 +01:00
|
|
|
use crate::debug::fps_ui;
|
2022-02-04 21:04:17 +01:00
|
|
|
use crate::{
|
2024-03-12 19:42:48 +01:00
|
|
|
backend::render::element::DamageElement,
|
2023-03-07 16:37:11 +01:00
|
|
|
shell::{
|
2023-12-07 19:53:41 +00:00
|
|
|
focus::target::WindowGroup,
|
|
|
|
|
grabs::{SeatMenuGrabState, SeatMoveGrabState},
|
|
|
|
|
layout::tiling::ANIMATION_DURATION,
|
2023-11-14 13:13:42 -08:00
|
|
|
CosmicMapped, CosmicMappedRenderElement, OverviewMode, SessionLock, Trigger,
|
2024-03-07 13:14:53 -06:00
|
|
|
WorkspaceDelta, WorkspaceRenderElement,
|
2023-03-07 16:37:11 +01:00
|
|
|
},
|
2023-11-14 13:13:42 -08:00
|
|
|
state::{Common, Fps},
|
2023-10-25 19:24:51 +02:00
|
|
|
utils::prelude::*,
|
2022-11-03 18:51:27 +01:00
|
|
|
wayland::{
|
2023-05-22 20:19:11 +02:00
|
|
|
handlers::{
|
|
|
|
|
data_device::get_dnd_icon,
|
2024-03-12 19:42:48 +01:00
|
|
|
screencopy::{render_session, FrameHolder, SessionData, WORKSPACE_OVERVIEW_NAMESPACE},
|
2022-11-03 18:51:27 +01:00
|
|
|
},
|
2024-03-12 19:42:48 +01:00
|
|
|
protocols::workspace::WorkspaceHandle,
|
2022-11-03 18:51:27 +01:00
|
|
|
},
|
2022-08-30 13:28:36 +02:00
|
|
|
};
|
2022-02-04 21:04:17 +01:00
|
|
|
|
2023-09-07 13:28:08 -07:00
|
|
|
use cosmic_comp_config::workspace::WorkspaceLayout;
|
2023-07-11 17:12:56 +02:00
|
|
|
use keyframe::{ease, functions::EaseInOutCubic};
|
2022-02-04 21:04:17 +01:00
|
|
|
use smithay::{
|
2022-03-22 12:36:03 +01:00
|
|
|
backend::{
|
2022-11-03 18:51:27 +01:00
|
|
|
allocator::dmabuf::Dmabuf,
|
2024-02-07 12:33:32 +01:00
|
|
|
drm::{DrmDeviceFd, DrmNode},
|
2022-03-22 12:36:03 +01:00
|
|
|
renderer::{
|
2022-11-17 20:32:54 +01:00
|
|
|
buffer_dimensions,
|
2023-07-31 19:12:33 +02:00
|
|
|
damage::{Error as RenderError, OutputDamageTracker, RenderOutputResult},
|
2023-05-22 20:19:11 +02:00
|
|
|
element::{
|
2023-10-16 12:28:19 -07:00
|
|
|
surface::{render_elements_from_surface_tree, WaylandSurfaceRenderElement},
|
2023-05-22 20:19:11 +02:00
|
|
|
utils::{Relocate, RelocateRenderElement},
|
2023-12-20 21:15:53 +00:00
|
|
|
AsRenderElements, Element, Id, Kind, RenderElement,
|
2023-05-22 20:19:11 +02:00
|
|
|
},
|
2023-04-18 17:10:21 +02:00
|
|
|
gles::{
|
|
|
|
|
element::PixelShaderElement, GlesError, GlesPixelProgram, GlesRenderer, Uniform,
|
2023-02-25 00:17:54 +01:00
|
|
|
UniformName, UniformType,
|
|
|
|
|
},
|
2022-11-17 20:32:54 +01:00
|
|
|
glow::GlowRenderer,
|
2023-05-19 19:44:57 +02:00
|
|
|
multigpu::{gbm::GbmGlesBackend, Error as MultiError, MultiFrame, MultiRenderer},
|
2023-06-28 22:20:06 +02:00
|
|
|
sync::SyncPoint,
|
2022-11-03 18:51:27 +01:00
|
|
|
Bind, Blit, ExportMem, ImportAll, ImportMem, Offscreen, Renderer, TextureFilter,
|
2022-03-22 12:36:03 +01:00
|
|
|
},
|
2022-03-16 20:05:24 +01:00
|
|
|
},
|
2023-07-13 17:19:29 +02:00
|
|
|
desktop::{layer_map_for_output, PopupManager},
|
2023-07-31 19:12:33 +02:00
|
|
|
output::{Output, OutputNoMode},
|
2024-03-12 19:42:48 +01:00
|
|
|
utils::{IsAlive, Logical, Point, Rectangle, Scale, Transform},
|
2023-04-18 17:10:21 +02:00
|
|
|
wayland::{
|
|
|
|
|
dmabuf::get_dmabuf,
|
2023-05-22 20:19:11 +02:00
|
|
|
shell::wlr_layer::Layer,
|
2023-04-18 17:10:21 +02:00
|
|
|
shm::{shm_format_to_fourcc, with_buffer_contents},
|
|
|
|
|
},
|
2022-02-04 21:04:17 +01:00
|
|
|
};
|
|
|
|
|
|
2024-03-07 13:14:53 -06:00
|
|
|
pub mod animations;
|
|
|
|
|
|
2022-08-05 14:28:37 +02:00
|
|
|
pub mod cursor;
|
2022-11-17 20:32:54 +01:00
|
|
|
pub mod element;
|
2022-11-28 17:48:50 +01:00
|
|
|
use self::element::{AsGlowRenderer, CosmicElement};
|
2022-02-04 21:04:17 +01:00
|
|
|
|
2024-02-07 12:33:32 +01:00
|
|
|
pub type GlMultiRenderer<'a> = MultiRenderer<
|
|
|
|
|
'a,
|
|
|
|
|
'a,
|
|
|
|
|
GbmGlesBackend<GlowRenderer, DrmDeviceFd>,
|
|
|
|
|
GbmGlesBackend<GlowRenderer, DrmDeviceFd>,
|
|
|
|
|
>;
|
|
|
|
|
pub type GlMultiFrame<'a, 'frame> = MultiFrame<
|
|
|
|
|
'a,
|
|
|
|
|
'a,
|
|
|
|
|
'frame,
|
|
|
|
|
GbmGlesBackend<GlowRenderer, DrmDeviceFd>,
|
|
|
|
|
GbmGlesBackend<GlowRenderer, DrmDeviceFd>,
|
|
|
|
|
>;
|
|
|
|
|
pub type GlMultiError = MultiError<
|
|
|
|
|
GbmGlesBackend<GlowRenderer, DrmDeviceFd>,
|
|
|
|
|
GbmGlesBackend<GlowRenderer, DrmDeviceFd>,
|
|
|
|
|
>;
|
2022-03-16 20:06:31 +01:00
|
|
|
|
2023-10-17 17:50:15 -04:00
|
|
|
pub static CLEAR_COLOR: [f32; 4] = [0.153, 0.161, 0.165, 1.0];
|
2023-05-26 20:51:10 +02:00
|
|
|
pub static OUTLINE_SHADER: &str = include_str!("./shaders/rounded_outline.frag");
|
|
|
|
|
pub static RECTANGLE_SHADER: &str = include_str!("./shaders/rounded_rectangle.frag");
|
2024-03-11 17:07:39 +01:00
|
|
|
pub static GROUP_COLOR: [f32; 3] = [0.788, 0.788, 0.788];
|
|
|
|
|
pub static ACTIVE_GROUP_COLOR: [f32; 3] = [0.58, 0.922, 0.922];
|
2023-02-25 00:17:54 +01:00
|
|
|
|
2023-04-18 17:10:21 +02:00
|
|
|
pub struct IndicatorShader(pub GlesPixelProgram);
|
2023-05-17 19:46:21 +02:00
|
|
|
|
2023-08-11 18:15:22 +02:00
|
|
|
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
|
|
|
|
pub enum Usage {
|
|
|
|
|
OverviewBackdrop,
|
|
|
|
|
Overlay,
|
|
|
|
|
MoveGrabIndicator,
|
|
|
|
|
FocusIndicator,
|
|
|
|
|
PotentialGroupIndicator,
|
2024-03-18 00:12:58 -05:00
|
|
|
SnappingIndicator,
|
2023-08-11 18:15:22 +02:00
|
|
|
}
|
|
|
|
|
|
2023-05-17 19:46:21 +02:00
|
|
|
#[derive(Clone)]
|
2023-05-31 13:27:52 +02:00
|
|
|
pub enum Key {
|
|
|
|
|
Static(Id),
|
2023-05-17 19:46:21 +02:00
|
|
|
Group(Weak<()>),
|
2023-08-11 18:15:22 +02:00
|
|
|
Window(Usage, CosmicMapped),
|
2023-05-17 19:46:21 +02:00
|
|
|
}
|
2023-05-31 13:27:52 +02:00
|
|
|
impl std::hash::Hash for Key {
|
2023-05-17 19:46:21 +02:00
|
|
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
|
|
|
|
match self {
|
2023-05-31 13:27:52 +02:00
|
|
|
Key::Static(id) => id.hash(state),
|
|
|
|
|
Key::Group(arc) => (arc.as_ptr() as usize).hash(state),
|
2023-08-11 18:15:22 +02:00
|
|
|
Key::Window(usage, window) => {
|
|
|
|
|
usage.hash(state);
|
|
|
|
|
window.hash(state);
|
|
|
|
|
}
|
2023-05-17 19:46:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-31 13:27:52 +02:00
|
|
|
impl PartialEq for Key {
|
2023-05-17 19:46:21 +02:00
|
|
|
fn eq(&self, other: &Self) -> bool {
|
|
|
|
|
match (self, other) {
|
2023-05-31 13:27:52 +02:00
|
|
|
(Key::Static(s1), Key::Static(s2)) => s1 == s2,
|
|
|
|
|
(Key::Group(g1), Key::Group(g2)) => Weak::ptr_eq(g1, g2),
|
2023-08-11 18:15:22 +02:00
|
|
|
(Key::Window(u1, w1), Key::Window(u2, w2)) => u1 == u2 && w1 == w2,
|
2023-05-17 19:46:21 +02:00
|
|
|
_ => false,
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-05-31 13:27:52 +02:00
|
|
|
impl Eq for Key {}
|
|
|
|
|
impl From<WindowGroup> for Key {
|
2023-05-17 19:46:21 +02:00
|
|
|
fn from(group: WindowGroup) -> Self {
|
2023-05-31 13:27:52 +02:00
|
|
|
Key::Group(group.alive.clone())
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
impl From<Id> for Key {
|
|
|
|
|
fn from(id: Id) -> Self {
|
|
|
|
|
Key::Static(id)
|
2023-05-17 19:46:21 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
|
struct IndicatorSettings {
|
|
|
|
|
thickness: u8,
|
2023-05-30 13:20:46 +02:00
|
|
|
radius: u8,
|
2023-05-17 19:46:21 +02:00
|
|
|
alpha: f32,
|
|
|
|
|
color: [f32; 3],
|
|
|
|
|
}
|
2023-05-31 13:27:52 +02:00
|
|
|
type IndicatorCache = RefCell<HashMap<Key, (IndicatorSettings, PixelShaderElement)>>;
|
2023-02-25 00:17:54 +01:00
|
|
|
|
|
|
|
|
impl IndicatorShader {
|
2023-04-18 17:10:21 +02:00
|
|
|
pub fn get<R: AsGlowRenderer>(renderer: &R) -> GlesPixelProgram {
|
|
|
|
|
Borrow::<GlesRenderer>::borrow(renderer.glow_renderer())
|
2023-02-25 00:17:54 +01:00
|
|
|
.egl_context()
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<IndicatorShader>()
|
|
|
|
|
.expect("Custom Shaders not initialized")
|
|
|
|
|
.0
|
|
|
|
|
.clone()
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-25 21:36:44 +02:00
|
|
|
pub fn focus_element<R: AsGlowRenderer>(
|
|
|
|
|
renderer: &R,
|
2023-05-31 13:27:52 +02:00
|
|
|
key: impl Into<Key>,
|
2023-10-25 19:24:51 +02:00
|
|
|
mut element_geo: Rectangle<i32, Local>,
|
2023-05-25 21:36:44 +02:00
|
|
|
thickness: u8,
|
2023-08-31 18:17:37 +02:00
|
|
|
scale: f64,
|
2023-05-25 21:36:44 +02:00
|
|
|
alpha: f32,
|
2023-10-10 13:55:34 -04:00
|
|
|
active_window_hint: [f32; 3],
|
2023-05-25 21:36:44 +02:00
|
|
|
) -> PixelShaderElement {
|
|
|
|
|
let t = thickness as i32;
|
|
|
|
|
element_geo.loc -= (t, t).into();
|
|
|
|
|
element_geo.size += (t * 2, t * 2).into();
|
|
|
|
|
|
2023-05-30 13:20:46 +02:00
|
|
|
IndicatorShader::element(
|
|
|
|
|
renderer,
|
|
|
|
|
key,
|
|
|
|
|
element_geo,
|
|
|
|
|
thickness,
|
|
|
|
|
thickness * 2,
|
|
|
|
|
alpha,
|
2023-08-31 18:17:37 +02:00
|
|
|
scale,
|
2023-10-10 13:55:34 -04:00
|
|
|
active_window_hint,
|
2023-05-30 13:20:46 +02:00
|
|
|
)
|
2023-05-25 21:36:44 +02:00
|
|
|
}
|
|
|
|
|
|
2023-02-25 00:17:54 +01:00
|
|
|
pub fn element<R: AsGlowRenderer>(
|
|
|
|
|
renderer: &R,
|
2023-05-31 13:27:52 +02:00
|
|
|
key: impl Into<Key>,
|
2023-10-25 19:24:51 +02:00
|
|
|
geo: Rectangle<i32, Local>,
|
2023-03-09 18:27:11 +01:00
|
|
|
thickness: u8,
|
2023-05-30 13:20:46 +02:00
|
|
|
radius: u8,
|
2023-05-12 20:01:37 +02:00
|
|
|
alpha: f32,
|
2023-08-31 18:17:37 +02:00
|
|
|
scale: f64,
|
2023-05-17 19:46:21 +02:00
|
|
|
color: [f32; 3],
|
2023-02-25 00:17:54 +01:00
|
|
|
) -> PixelShaderElement {
|
2023-08-31 18:17:37 +02:00
|
|
|
let thickness = (thickness as f64 * scale).round() as u8;
|
|
|
|
|
|
2023-05-17 19:46:21 +02:00
|
|
|
let settings = IndicatorSettings {
|
|
|
|
|
thickness,
|
2023-05-30 13:20:46 +02:00
|
|
|
radius,
|
2023-05-17 19:46:21 +02:00
|
|
|
alpha,
|
|
|
|
|
color,
|
|
|
|
|
};
|
2023-02-25 00:17:54 +01:00
|
|
|
|
2023-04-18 17:10:21 +02:00
|
|
|
let user_data = Borrow::<GlesRenderer>::borrow(renderer.glow_renderer())
|
2023-02-25 00:17:54 +01:00
|
|
|
.egl_context()
|
|
|
|
|
.user_data();
|
|
|
|
|
|
2023-05-17 19:46:21 +02:00
|
|
|
user_data.insert_if_missing(|| IndicatorCache::new(HashMap::new()));
|
|
|
|
|
let mut cache = user_data.get::<IndicatorCache>().unwrap().borrow_mut();
|
|
|
|
|
cache.retain(|k, _| match k {
|
2023-05-31 13:27:52 +02:00
|
|
|
Key::Static(_) => true,
|
|
|
|
|
Key::Group(w) => w.upgrade().is_some(),
|
2023-08-11 18:15:22 +02:00
|
|
|
Key::Window(_, w) => w.alive(),
|
2023-05-17 19:46:21 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let key = key.into();
|
|
|
|
|
if cache
|
|
|
|
|
.get(&key)
|
|
|
|
|
.filter(|(old_settings, _)| &settings == old_settings)
|
|
|
|
|
.is_none()
|
|
|
|
|
{
|
|
|
|
|
let thickness: f32 = thickness as f32;
|
|
|
|
|
let shader = Self::get(renderer);
|
|
|
|
|
|
|
|
|
|
let elem = PixelShaderElement::new(
|
|
|
|
|
shader,
|
2023-10-25 19:24:51 +02:00
|
|
|
geo.as_logical(),
|
2023-05-17 19:46:21 +02:00
|
|
|
None, //TODO
|
|
|
|
|
alpha,
|
|
|
|
|
vec![
|
2023-06-01 17:03:55 +02:00
|
|
|
Uniform::new(
|
|
|
|
|
"color",
|
|
|
|
|
[color[0] * alpha, color[1] * alpha, color[2] * alpha],
|
|
|
|
|
),
|
2023-05-17 19:46:21 +02:00
|
|
|
Uniform::new("thickness", thickness),
|
2023-05-30 13:20:46 +02:00
|
|
|
Uniform::new("radius", radius as f32),
|
2023-05-17 19:46:21 +02:00
|
|
|
],
|
2023-09-13 20:24:11 -07:00
|
|
|
Kind::Unspecified,
|
2023-05-17 19:46:21 +02:00
|
|
|
);
|
|
|
|
|
cache.insert(key.clone(), (settings, elem));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let elem = &mut cache.get_mut(&key).unwrap().1;
|
2023-10-25 19:24:51 +02:00
|
|
|
if elem.geometry(1.0.into()).to_logical(1) != geo.as_logical() {
|
|
|
|
|
elem.resize(geo.as_logical(), None);
|
2023-02-25 00:17:54 +01:00
|
|
|
}
|
2023-05-17 19:46:21 +02:00
|
|
|
elem.clone()
|
2023-02-25 00:17:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 20:51:10 +02:00
|
|
|
pub struct BackdropShader(pub GlesPixelProgram);
|
|
|
|
|
|
|
|
|
|
#[derive(PartialEq)]
|
|
|
|
|
struct BackdropSettings {
|
|
|
|
|
radius: f32,
|
|
|
|
|
alpha: f32,
|
|
|
|
|
color: [f32; 3],
|
|
|
|
|
}
|
2023-05-31 13:27:52 +02:00
|
|
|
type BackdropCache = RefCell<HashMap<Key, (BackdropSettings, PixelShaderElement)>>;
|
2023-05-26 20:51:10 +02:00
|
|
|
|
|
|
|
|
impl BackdropShader {
|
|
|
|
|
pub fn get<R: AsGlowRenderer>(renderer: &R) -> GlesPixelProgram {
|
|
|
|
|
Borrow::<GlesRenderer>::borrow(renderer.glow_renderer())
|
|
|
|
|
.egl_context()
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<BackdropShader>()
|
|
|
|
|
.expect("Custom Shaders not initialized")
|
|
|
|
|
.0
|
|
|
|
|
.clone()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pub fn element<R: AsGlowRenderer>(
|
|
|
|
|
renderer: &R,
|
2023-05-31 13:27:52 +02:00
|
|
|
key: impl Into<Key>,
|
2023-10-25 19:24:51 +02:00
|
|
|
geo: Rectangle<i32, Local>,
|
2023-05-26 20:51:10 +02:00
|
|
|
radius: f32,
|
|
|
|
|
alpha: f32,
|
|
|
|
|
color: [f32; 3],
|
|
|
|
|
) -> PixelShaderElement {
|
|
|
|
|
let settings = BackdropSettings {
|
|
|
|
|
radius,
|
|
|
|
|
alpha,
|
|
|
|
|
color,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let user_data = Borrow::<GlesRenderer>::borrow(renderer.glow_renderer())
|
|
|
|
|
.egl_context()
|
|
|
|
|
.user_data();
|
|
|
|
|
|
|
|
|
|
user_data.insert_if_missing(|| BackdropCache::new(HashMap::new()));
|
|
|
|
|
let mut cache = user_data.get::<BackdropCache>().unwrap().borrow_mut();
|
|
|
|
|
cache.retain(|k, _| match k {
|
2023-05-31 13:27:52 +02:00
|
|
|
Key::Static(_) => true,
|
|
|
|
|
Key::Group(a) => a.upgrade().is_some(),
|
2023-08-11 18:15:22 +02:00
|
|
|
Key::Window(_, w) => w.alive(),
|
2023-05-26 20:51:10 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let key = key.into();
|
|
|
|
|
if cache
|
|
|
|
|
.get(&key)
|
|
|
|
|
.filter(|(old_settings, _)| &settings == old_settings)
|
|
|
|
|
.is_none()
|
|
|
|
|
{
|
|
|
|
|
let shader = Self::get(renderer);
|
|
|
|
|
|
|
|
|
|
let elem = PixelShaderElement::new(
|
|
|
|
|
shader,
|
2023-10-25 19:24:51 +02:00
|
|
|
geo.as_logical(),
|
2023-05-26 20:51:10 +02:00
|
|
|
None, // TODO
|
|
|
|
|
alpha,
|
2023-06-01 17:03:55 +02:00
|
|
|
vec![
|
|
|
|
|
Uniform::new(
|
|
|
|
|
"color",
|
|
|
|
|
[color[0] * alpha, color[1] * alpha, color[2] * alpha],
|
|
|
|
|
),
|
|
|
|
|
Uniform::new("radius", radius),
|
|
|
|
|
],
|
2023-09-13 20:24:11 -07:00
|
|
|
Kind::Unspecified,
|
2023-05-26 20:51:10 +02:00
|
|
|
);
|
|
|
|
|
cache.insert(key.clone(), (settings, elem));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let elem = &mut cache.get_mut(&key).unwrap().1;
|
2023-10-25 19:24:51 +02:00
|
|
|
if elem.geometry(1.0.into()).to_logical(1) != geo.as_logical() {
|
|
|
|
|
elem.resize(geo.as_logical(), None);
|
2023-05-26 20:51:10 +02:00
|
|
|
}
|
|
|
|
|
elem.clone()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-04-18 17:10:21 +02:00
|
|
|
pub fn init_shaders<R: AsGlowRenderer>(renderer: &mut R) -> Result<(), GlesError> {
|
2023-02-25 00:17:54 +01:00
|
|
|
let glow_renderer = renderer.glow_renderer_mut();
|
2023-04-18 17:10:21 +02:00
|
|
|
let gles_renderer: &mut GlesRenderer = glow_renderer.borrow_mut();
|
2023-02-25 00:17:54 +01:00
|
|
|
|
2024-01-17 11:34:19 +00:00
|
|
|
{
|
|
|
|
|
let egl_context = gles_renderer.egl_context();
|
|
|
|
|
if egl_context.user_data().get::<IndicatorShader>().is_some()
|
|
|
|
|
&& egl_context.user_data().get::<BackdropShader>().is_some()
|
|
|
|
|
{
|
|
|
|
|
return Ok(());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 20:51:10 +02:00
|
|
|
let outline_shader = gles_renderer.compile_custom_pixel_shader(
|
|
|
|
|
OUTLINE_SHADER,
|
2023-02-25 00:17:54 +01:00
|
|
|
&[
|
|
|
|
|
UniformName::new("color", UniformType::_3f),
|
|
|
|
|
UniformName::new("thickness", UniformType::_1f),
|
|
|
|
|
UniformName::new("radius", UniformType::_1f),
|
|
|
|
|
],
|
|
|
|
|
)?;
|
2023-05-26 20:51:10 +02:00
|
|
|
let rectangle_shader = gles_renderer.compile_custom_pixel_shader(
|
|
|
|
|
RECTANGLE_SHADER,
|
|
|
|
|
&[
|
|
|
|
|
UniformName::new("color", UniformType::_3f),
|
|
|
|
|
UniformName::new("radius", UniformType::_1f),
|
|
|
|
|
],
|
|
|
|
|
)?;
|
2023-02-25 00:17:54 +01:00
|
|
|
|
|
|
|
|
let egl_context = gles_renderer.egl_context();
|
|
|
|
|
egl_context
|
|
|
|
|
.user_data()
|
2023-05-26 20:51:10 +02:00
|
|
|
.insert_if_missing(|| IndicatorShader(outline_shader));
|
|
|
|
|
egl_context
|
|
|
|
|
.user_data()
|
|
|
|
|
.insert_if_missing(|| BackdropShader(rectangle_shader));
|
2023-02-25 00:17:54 +01:00
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
|
}
|
2022-04-22 15:18:28 +02:00
|
|
|
|
2022-11-03 18:51:27 +01:00
|
|
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
|
|
|
pub enum CursorMode {
|
|
|
|
|
None,
|
|
|
|
|
NotDefault,
|
|
|
|
|
All,
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-07 19:15:44 -07:00
|
|
|
#[profiling::function]
|
2024-03-12 19:42:48 +01:00
|
|
|
pub fn cursor_elements<'frame, R>(
|
2022-08-05 16:28:05 +02:00
|
|
|
renderer: &mut R,
|
|
|
|
|
state: &Common,
|
|
|
|
|
output: &Output,
|
2022-11-03 18:51:27 +01:00
|
|
|
mode: CursorMode,
|
2024-04-10 13:33:26 -07:00
|
|
|
exclude_dnd_icon: bool,
|
2024-03-12 19:42:48 +01:00
|
|
|
) -> Vec<CosmicElement<R>>
|
2022-08-05 16:28:05 +02:00
|
|
|
where
|
2022-11-22 10:28:30 +01:00
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
2022-09-28 12:01:29 +02:00
|
|
|
<R as Renderer>::TextureId: Clone + 'static,
|
2022-11-22 10:28:30 +01:00
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
2022-08-05 16:28:05 +02:00
|
|
|
{
|
2022-09-28 12:01:29 +02:00
|
|
|
let scale = output.current_scale().fractional_scale();
|
|
|
|
|
let mut elements = Vec::new();
|
2022-08-05 16:28:05 +02:00
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
for seat in state.seats() {
|
2022-08-05 16:28:05 +02:00
|
|
|
let pointer = match seat.get_pointer() {
|
|
|
|
|
Some(ptr) => ptr,
|
|
|
|
|
None => continue,
|
|
|
|
|
};
|
2022-11-22 19:52:13 +01:00
|
|
|
let location = pointer.current_location() - output.current_location().to_f64();
|
2022-08-05 16:28:05 +02:00
|
|
|
|
2022-11-03 18:51:27 +01:00
|
|
|
if mode != CursorMode::None {
|
|
|
|
|
elements.extend(
|
|
|
|
|
cursor::draw_cursor(
|
|
|
|
|
renderer,
|
|
|
|
|
seat,
|
|
|
|
|
location,
|
|
|
|
|
scale.into(),
|
2022-11-17 20:32:54 +01:00
|
|
|
state.clock.now(),
|
2022-11-03 18:51:27 +01:00
|
|
|
mode != CursorMode::NotDefault,
|
|
|
|
|
)
|
|
|
|
|
.into_iter()
|
2024-03-12 19:42:48 +01:00
|
|
|
.map(|(elem, hotspot)| {
|
|
|
|
|
CosmicElement::Cursor(RelocateRenderElement::from_element(
|
|
|
|
|
elem,
|
|
|
|
|
Point::from((-hotspot.x, -hotspot.y)),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}),
|
2022-11-03 18:51:27 +01:00
|
|
|
);
|
|
|
|
|
}
|
2022-10-26 15:26:07 +02:00
|
|
|
|
2024-04-10 13:33:26 -07:00
|
|
|
if !exclude_dnd_icon {
|
|
|
|
|
if let Some(wl_surface) = get_dnd_icon(seat) {
|
|
|
|
|
elements.extend(
|
|
|
|
|
cursor::draw_dnd_icon(renderer, &wl_surface, location.to_i32_round(), scale)
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(CosmicElement::Dnd),
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-10-26 15:26:07 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-10 13:55:34 -04:00
|
|
|
let theme = state.theme.cosmic();
|
2022-10-26 15:26:07 +02:00
|
|
|
if let Some(grab_elements) = seat
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<SeatMoveGrabState>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.borrow()
|
|
|
|
|
.as_ref()
|
2024-03-12 19:42:48 +01:00
|
|
|
.map(|state| state.render::<CosmicElement<R>, R>(renderer, seat, output, theme))
|
2022-10-26 15:26:07 +02:00
|
|
|
{
|
|
|
|
|
elements.extend(grab_elements);
|
|
|
|
|
}
|
2023-12-07 19:53:41 +00:00
|
|
|
|
|
|
|
|
if let Some(grab_elements) = seat
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<SeatMenuGrabState>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.borrow()
|
|
|
|
|
.as_ref()
|
|
|
|
|
.map(|state| state.render::<CosmicMappedRenderElement<R>, R>(renderer, output))
|
|
|
|
|
{
|
|
|
|
|
elements.extend(grab_elements.into_iter().map(Into::into));
|
|
|
|
|
}
|
2022-08-05 16:28:05 +02:00
|
|
|
}
|
|
|
|
|
|
2022-09-28 12:01:29 +02:00
|
|
|
elements
|
2022-08-05 16:28:05 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-07 19:15:44 -07:00
|
|
|
#[profiling::function]
|
2023-03-07 22:20:44 +01:00
|
|
|
pub fn workspace_elements<R>(
|
2023-03-07 16:37:11 +01:00
|
|
|
_gpu: Option<&DrmNode>,
|
|
|
|
|
renderer: &mut R,
|
|
|
|
|
state: &mut Common,
|
|
|
|
|
output: &Output,
|
2024-03-07 13:14:53 -06:00
|
|
|
previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>,
|
2023-05-22 20:19:11 +02:00
|
|
|
current: (WorkspaceHandle, usize),
|
2023-03-07 16:37:11 +01:00
|
|
|
cursor_mode: CursorMode,
|
|
|
|
|
_fps: &mut Option<&mut Fps>,
|
|
|
|
|
exclude_workspace_overview: bool,
|
2023-03-07 22:20:44 +01:00
|
|
|
) -> Result<Vec<CosmicElement<R>>, RenderError<R>>
|
2023-03-07 16:37:11 +01:00
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
|
|
|
|
<R as Renderer>::TextureId: Clone + 'static,
|
2023-04-18 17:10:21 +02:00
|
|
|
<R as Renderer>::Error: From<GlesError>,
|
2023-03-07 16:37:11 +01:00
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
2023-03-07 16:37:11 +01:00
|
|
|
{
|
2024-04-10 13:33:26 -07:00
|
|
|
let mut elements = cursor_elements(
|
|
|
|
|
renderer,
|
|
|
|
|
state,
|
|
|
|
|
output,
|
|
|
|
|
cursor_mode,
|
|
|
|
|
exclude_workspace_overview,
|
|
|
|
|
);
|
2023-03-07 16:37:11 +01:00
|
|
|
|
|
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
{
|
|
|
|
|
let output_geo = output.geometry();
|
|
|
|
|
let scale = output.current_scale().fractional_scale();
|
|
|
|
|
|
|
|
|
|
if let Some(fps) = _fps.as_mut() {
|
|
|
|
|
let fps_overlay = fps_ui(
|
|
|
|
|
_gpu,
|
|
|
|
|
state,
|
|
|
|
|
renderer.glow_renderer_mut(),
|
|
|
|
|
*fps,
|
|
|
|
|
Rectangle::from_loc_and_size(
|
|
|
|
|
(0, 0),
|
|
|
|
|
(output_geo.size.w.min(400), output_geo.size.h.min(800)),
|
|
|
|
|
),
|
|
|
|
|
scale,
|
|
|
|
|
)
|
|
|
|
|
.map_err(<R as Renderer>::Error::from)
|
|
|
|
|
.map_err(RenderError::Rendering)?;
|
|
|
|
|
elements.push(fps_overlay.into());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-16 12:28:19 -07:00
|
|
|
// If session locked, only show session lock surfaces
|
2023-11-14 13:13:42 -08:00
|
|
|
if let Some(session_lock) = &state.shell.session_lock {
|
2023-10-16 12:28:19 -07:00
|
|
|
elements.extend(
|
|
|
|
|
session_lock_elements(renderer, output, session_lock)
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|x| WorkspaceRenderElement::from(x).into()),
|
|
|
|
|
);
|
|
|
|
|
return Ok(elements);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-20 15:22:03 -07:00
|
|
|
let theme = state.theme.cosmic();
|
|
|
|
|
|
2023-05-19 19:44:57 +02:00
|
|
|
let overview = state.shell.overview_mode();
|
2023-07-06 00:03:26 +02:00
|
|
|
let (resize_mode, resize_indicator) = state.shell.resize_mode();
|
|
|
|
|
let resize_indicator = resize_indicator.map(|indicator| (resize_mode, indicator));
|
2023-09-08 22:16:39 +02:00
|
|
|
let swap_tree = if let OverviewMode::Started(Trigger::KeyboardSwap(_, desc), _) = &overview.0 {
|
2023-10-25 19:41:30 +02:00
|
|
|
if current.0 != desc.handle {
|
|
|
|
|
state
|
|
|
|
|
.shell
|
2023-11-22 12:45:29 +01:00
|
|
|
.workspaces
|
2023-10-25 19:41:30 +02:00
|
|
|
.space_for_handle(&desc.handle)
|
|
|
|
|
.map(|w| w.tiling_layer.tree())
|
2023-09-08 22:16:39 +02:00
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
let overview = (
|
|
|
|
|
overview.0,
|
|
|
|
|
overview.1.map(|indicator| (indicator, swap_tree)),
|
|
|
|
|
);
|
2023-07-06 00:03:26 +02:00
|
|
|
|
2023-03-07 16:37:11 +01:00
|
|
|
let last_active_seat = state.last_active_seat().clone();
|
|
|
|
|
let move_active = last_active_seat
|
|
|
|
|
.user_data()
|
|
|
|
|
.get::<SeatMoveGrabState>()
|
|
|
|
|
.unwrap()
|
|
|
|
|
.borrow()
|
|
|
|
|
.is_some();
|
2023-03-10 16:20:17 -08:00
|
|
|
let active_output = last_active_seat.active_output();
|
2023-05-22 20:19:11 +02:00
|
|
|
let output_size = output.geometry().size;
|
|
|
|
|
let output_scale = output.current_scale().fractional_scale();
|
|
|
|
|
|
2023-12-20 19:54:04 +00:00
|
|
|
let set = state
|
2023-05-22 20:19:11 +02:00
|
|
|
.shell
|
2023-11-22 12:45:29 +01:00
|
|
|
.workspaces
|
2023-12-20 19:54:04 +00:00
|
|
|
.sets
|
|
|
|
|
.get(output)
|
2023-05-22 20:19:11 +02:00
|
|
|
.ok_or(OutputNoMode)?;
|
2023-12-20 19:54:04 +00:00
|
|
|
let workspace = set
|
|
|
|
|
.workspaces
|
|
|
|
|
.iter()
|
|
|
|
|
.find(|w| w.handle == current.0)
|
|
|
|
|
.ok_or(OutputNoMode)?;
|
|
|
|
|
let is_active_space = workspace.outputs().any(|o| o == &active_output);
|
2023-05-22 20:19:11 +02:00
|
|
|
|
2023-09-15 18:37:34 +02:00
|
|
|
let has_fullscreen = workspace
|
|
|
|
|
.fullscreen
|
2023-10-25 19:41:30 +02:00
|
|
|
.as_ref()
|
2023-09-15 18:37:34 +02:00
|
|
|
.filter(|f| !f.is_animating())
|
2023-10-25 19:41:30 +02:00
|
|
|
.is_some();
|
2023-07-13 17:19:29 +02:00
|
|
|
let (overlay_elements, overlay_popups) =
|
|
|
|
|
split_layer_elements(renderer, output, Layer::Overlay, exclude_workspace_overview);
|
|
|
|
|
|
|
|
|
|
// overlay is above everything
|
|
|
|
|
elements.extend(overlay_popups.into_iter().map(Into::into));
|
|
|
|
|
elements.extend(overlay_elements.into_iter().map(Into::into));
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
let mut window_elements = if !has_fullscreen {
|
2023-07-13 17:19:29 +02:00
|
|
|
let (top_elements, top_popups) =
|
|
|
|
|
split_layer_elements(renderer, output, Layer::Top, exclude_workspace_overview);
|
|
|
|
|
elements.extend(top_popups.into_iter().map(Into::into));
|
|
|
|
|
top_elements.into_iter().map(Into::into).collect()
|
|
|
|
|
} else {
|
|
|
|
|
Vec::new()
|
|
|
|
|
};
|
2023-12-20 19:54:04 +00:00
|
|
|
|
2024-02-08 14:25:18 -05:00
|
|
|
let active_hint = if state.config.cosmic_conf.active_hint {
|
|
|
|
|
theme.active_hint as u8
|
|
|
|
|
} else {
|
|
|
|
|
0
|
|
|
|
|
};
|
2023-05-22 20:19:11 +02:00
|
|
|
|
2023-12-20 21:15:53 +00:00
|
|
|
// overlay redirect windows
|
|
|
|
|
// they need to be over sticky windows, because they could be popups of sticky windows,
|
|
|
|
|
// and we can't differenciate that.
|
|
|
|
|
elements.extend(
|
|
|
|
|
state
|
|
|
|
|
.shell
|
|
|
|
|
.override_redirect_windows
|
|
|
|
|
.iter()
|
|
|
|
|
.filter(|or| {
|
|
|
|
|
(*or)
|
|
|
|
|
.geometry()
|
|
|
|
|
.as_global()
|
|
|
|
|
.intersection(workspace.output.geometry())
|
|
|
|
|
.is_some()
|
|
|
|
|
})
|
|
|
|
|
.flat_map(|or| {
|
|
|
|
|
AsRenderElements::<R>::render_elements::<WorkspaceRenderElement<R>>(
|
|
|
|
|
or,
|
|
|
|
|
renderer,
|
|
|
|
|
(or.geometry().loc - workspace.output.geometry().loc.as_logical())
|
|
|
|
|
.to_physical_precise_round(output_scale),
|
|
|
|
|
Scale::from(output_scale),
|
|
|
|
|
1.0,
|
|
|
|
|
)
|
|
|
|
|
})
|
|
|
|
|
.map(|p_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
p_element,
|
|
|
|
|
(0, 0),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}),
|
|
|
|
|
);
|
|
|
|
|
|
2023-12-20 19:54:04 +00:00
|
|
|
// sticky windows
|
|
|
|
|
if !has_fullscreen {
|
|
|
|
|
let alpha = match &overview.0 {
|
|
|
|
|
OverviewMode::Started(_, started) => {
|
|
|
|
|
(1.0 - (Instant::now().duration_since(*started).as_millis()
|
|
|
|
|
/ ANIMATION_DURATION.as_millis()) as f32)
|
|
|
|
|
.max(0.0)
|
|
|
|
|
* 0.4
|
|
|
|
|
+ 0.6
|
|
|
|
|
}
|
|
|
|
|
OverviewMode::Ended(_, ended) => {
|
|
|
|
|
((Instant::now().duration_since(*ended).as_millis()
|
|
|
|
|
/ ANIMATION_DURATION.as_millis()) as f32)
|
|
|
|
|
* 0.4
|
|
|
|
|
+ 0.6
|
|
|
|
|
}
|
|
|
|
|
OverviewMode::None => 1.0,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let current_focus = (!move_active && is_active_space)
|
|
|
|
|
.then_some(&last_active_seat)
|
|
|
|
|
.map(|seat| workspace.focus_stack.get(seat));
|
|
|
|
|
|
|
|
|
|
let (w_elements, p_elements) = set.sticky_layer.render(
|
|
|
|
|
renderer,
|
|
|
|
|
current_focus.as_ref().and_then(|stack| stack.last()),
|
|
|
|
|
resize_indicator.clone(),
|
|
|
|
|
active_hint,
|
|
|
|
|
alpha,
|
|
|
|
|
theme,
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
elements.extend(p_elements.into_iter().map(|p_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
WorkspaceRenderElement::Window(p_element),
|
|
|
|
|
(0, 0),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
window_elements.extend(w_elements.into_iter().map(|w_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
WorkspaceRenderElement::Window(w_element),
|
|
|
|
|
(0, 0),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-22 20:19:11 +02:00
|
|
|
let offset = match previous.as_ref() {
|
|
|
|
|
Some((previous, previous_idx, start)) => {
|
2024-02-08 14:25:18 -05:00
|
|
|
let layout = state.config.cosmic_conf.workspaces.workspace_layout;
|
2023-05-22 20:19:11 +02:00
|
|
|
|
|
|
|
|
let workspace = state
|
|
|
|
|
.shell
|
2023-11-22 12:45:29 +01:00
|
|
|
.workspaces
|
2023-05-22 20:19:11 +02:00
|
|
|
.space_for_handle(&previous)
|
|
|
|
|
.ok_or(OutputNoMode)?;
|
2023-10-25 19:41:30 +02:00
|
|
|
let has_fullscreen = workspace.fullscreen.is_some();
|
2023-05-22 20:19:11 +02:00
|
|
|
let is_active_space = workspace.outputs().any(|o| o == &active_output);
|
|
|
|
|
|
2024-03-07 13:14:53 -06:00
|
|
|
let percentage = match start {
|
|
|
|
|
WorkspaceDelta::Shortcut(st) => ease(
|
|
|
|
|
EaseInOutCubic,
|
|
|
|
|
0.0,
|
|
|
|
|
1.0,
|
|
|
|
|
Instant::now().duration_since(*st).as_millis() as f32
|
|
|
|
|
/ ANIMATION_DURATION.as_millis() as f32,
|
|
|
|
|
),
|
|
|
|
|
WorkspaceDelta::Gesture(prog) => *prog as f32,
|
|
|
|
|
WorkspaceDelta::GestureEnd(st, spring) => {
|
|
|
|
|
(spring.value_at(Instant::now().duration_since(*st)) as f32).clamp(0.0, 1.0)
|
|
|
|
|
}
|
2023-05-22 20:19:11 +02:00
|
|
|
};
|
|
|
|
|
let offset = Point::<i32, Logical>::from(match (layout, *previous_idx < current.1) {
|
|
|
|
|
(WorkspaceLayout::Vertical, true) => {
|
|
|
|
|
(0, (-output_size.h as f32 * percentage).round() as i32)
|
|
|
|
|
}
|
|
|
|
|
(WorkspaceLayout::Vertical, false) => {
|
|
|
|
|
(0, (output_size.h as f32 * percentage).round() as i32)
|
|
|
|
|
}
|
|
|
|
|
(WorkspaceLayout::Horizontal, true) => {
|
|
|
|
|
((-output_size.w as f32 * percentage).round() as i32, 0)
|
|
|
|
|
}
|
|
|
|
|
(WorkspaceLayout::Horizontal, false) => {
|
|
|
|
|
((output_size.w as f32 * percentage).round() as i32, 0)
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2023-07-13 17:19:29 +02:00
|
|
|
let (w_elements, p_elements) = workspace
|
2023-10-25 19:41:30 +02:00
|
|
|
.render::<R>(
|
2023-07-13 17:19:29 +02:00
|
|
|
renderer,
|
|
|
|
|
(!move_active && is_active_space).then_some(&last_active_seat),
|
|
|
|
|
overview.clone(),
|
|
|
|
|
resize_indicator.clone(),
|
2023-10-10 13:55:34 -04:00
|
|
|
active_hint,
|
|
|
|
|
theme,
|
2023-07-13 17:19:29 +02:00
|
|
|
)
|
|
|
|
|
.map_err(|_| OutputNoMode)?;
|
|
|
|
|
elements.extend(p_elements.into_iter().map(|p_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
p_element,
|
|
|
|
|
offset.to_physical_precise_round(output_scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
window_elements.extend(w_elements.into_iter().map(|w_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
w_element,
|
|
|
|
|
offset.to_physical_precise_round(output_scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
2023-05-22 20:19:11 +02:00
|
|
|
|
2023-09-13 20:14:54 +02:00
|
|
|
if !has_fullscreen {
|
|
|
|
|
let (w_elements, p_elements) =
|
|
|
|
|
background_layer_elements(renderer, output, exclude_workspace_overview);
|
|
|
|
|
elements.extend(p_elements.into_iter().map(|p_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
p_element,
|
|
|
|
|
offset.to_physical_precise_round(output_scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
window_elements.extend(w_elements.into_iter().map(|w_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
w_element,
|
|
|
|
|
offset.to_physical_precise_round(output_scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
}
|
2023-05-22 20:19:11 +02:00
|
|
|
|
|
|
|
|
Point::<i32, Logical>::from(match (layout, *previous_idx < current.1) {
|
|
|
|
|
(WorkspaceLayout::Vertical, true) => (0, output_size.h + offset.y),
|
|
|
|
|
(WorkspaceLayout::Vertical, false) => (0, -(output_size.h - offset.y)),
|
|
|
|
|
(WorkspaceLayout::Horizontal, true) => (output_size.w + offset.x, 0),
|
|
|
|
|
(WorkspaceLayout::Horizontal, false) => (-(output_size.w - offset.y), 0),
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
None => (0, 0).into(),
|
|
|
|
|
};
|
|
|
|
|
|
2023-07-13 17:19:29 +02:00
|
|
|
let (w_elements, p_elements) = workspace
|
2023-10-25 19:41:30 +02:00
|
|
|
.render::<R>(
|
2023-07-13 17:19:29 +02:00
|
|
|
renderer,
|
|
|
|
|
(!move_active && is_active_space).then_some(&last_active_seat),
|
|
|
|
|
overview,
|
|
|
|
|
resize_indicator,
|
2023-10-10 13:55:34 -04:00
|
|
|
active_hint,
|
|
|
|
|
theme,
|
2023-07-13 17:19:29 +02:00
|
|
|
)
|
|
|
|
|
.map_err(|_| OutputNoMode)?;
|
|
|
|
|
elements.extend(p_elements.into_iter().map(|p_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
p_element,
|
|
|
|
|
offset.to_physical_precise_round(output_scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
window_elements.extend(w_elements.into_iter().map(|w_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
w_element,
|
|
|
|
|
offset.to_physical_precise_round(output_scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
|
2023-10-25 19:41:30 +02:00
|
|
|
if !has_fullscreen {
|
2023-09-13 20:14:54 +02:00
|
|
|
let (w_elements, p_elements) =
|
|
|
|
|
background_layer_elements(renderer, output, exclude_workspace_overview);
|
|
|
|
|
|
|
|
|
|
elements.extend(p_elements.into_iter().map(|p_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
p_element,
|
|
|
|
|
offset.to_physical_precise_round(output_scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
window_elements.extend(w_elements.into_iter().map(|w_element| {
|
|
|
|
|
CosmicElement::Workspace(RelocateRenderElement::from_element(
|
|
|
|
|
w_element,
|
|
|
|
|
offset.to_physical_precise_round(output_scale),
|
|
|
|
|
Relocate::Relative,
|
|
|
|
|
))
|
|
|
|
|
}));
|
|
|
|
|
}
|
2023-07-13 17:19:29 +02:00
|
|
|
|
|
|
|
|
elements.extend(window_elements);
|
2023-03-07 16:37:11 +01:00
|
|
|
|
|
|
|
|
Ok(elements)
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-13 17:19:29 +02:00
|
|
|
pub fn split_layer_elements<R>(
|
2023-05-22 20:19:11 +02:00
|
|
|
renderer: &mut R,
|
|
|
|
|
output: &Output,
|
2023-07-13 17:19:29 +02:00
|
|
|
layer: Layer,
|
2023-05-22 20:19:11 +02:00
|
|
|
exclude_workspace_overview: bool,
|
2023-07-13 17:19:29 +02:00
|
|
|
) -> (
|
|
|
|
|
Vec<WorkspaceRenderElement<R>>,
|
|
|
|
|
Vec<WorkspaceRenderElement<R>>,
|
|
|
|
|
)
|
2023-05-22 20:19:11 +02:00
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
|
|
|
|
<R as Renderer>::TextureId: Clone + 'static,
|
|
|
|
|
<R as Renderer>::Error: From<GlesError>,
|
|
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
|
|
|
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
|
|
|
|
{
|
|
|
|
|
let layer_map = layer_map_for_output(output);
|
|
|
|
|
let output_scale = output.current_scale().fractional_scale();
|
|
|
|
|
|
2023-07-13 17:19:29 +02:00
|
|
|
let mut popup_elements = Vec::new();
|
|
|
|
|
let mut layer_elements = Vec::new();
|
|
|
|
|
|
2023-05-22 20:19:11 +02:00
|
|
|
layer_map
|
2023-07-13 17:19:29 +02:00
|
|
|
.layers_on(layer)
|
2023-05-22 20:19:11 +02:00
|
|
|
.rev()
|
|
|
|
|
.filter(|s| !(exclude_workspace_overview && s.namespace() == WORKSPACE_OVERVIEW_NAMESPACE))
|
|
|
|
|
.filter_map(|surface| {
|
|
|
|
|
layer_map
|
|
|
|
|
.layer_geometry(surface)
|
|
|
|
|
.map(|geo| (geo.loc, surface))
|
|
|
|
|
})
|
2023-07-13 17:19:29 +02:00
|
|
|
.for_each(|(location, surface)| {
|
|
|
|
|
let location = location.to_physical_precise_round(output_scale);
|
|
|
|
|
let surface = surface.wl_surface();
|
|
|
|
|
let scale = Scale::from(output_scale);
|
|
|
|
|
|
|
|
|
|
popup_elements.extend(PopupManager::popups_for_surface(surface).flat_map(
|
|
|
|
|
|(popup, popup_offset)| {
|
|
|
|
|
let offset = (popup_offset - popup.geometry().loc)
|
|
|
|
|
.to_f64()
|
|
|
|
|
.to_physical(scale)
|
|
|
|
|
.to_i32_round();
|
|
|
|
|
|
|
|
|
|
render_elements_from_surface_tree(
|
|
|
|
|
renderer,
|
|
|
|
|
popup.wl_surface(),
|
|
|
|
|
location + offset,
|
|
|
|
|
scale,
|
|
|
|
|
1.0,
|
2023-09-13 20:24:11 -07:00
|
|
|
Kind::Unspecified,
|
2023-07-13 17:19:29 +02:00
|
|
|
)
|
|
|
|
|
},
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
layer_elements.extend(render_elements_from_surface_tree(
|
2023-09-13 20:24:11 -07:00
|
|
|
renderer,
|
|
|
|
|
surface,
|
|
|
|
|
location,
|
|
|
|
|
scale,
|
|
|
|
|
1.0,
|
|
|
|
|
Kind::Unspecified,
|
2023-07-13 17:19:29 +02:00
|
|
|
));
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
(layer_elements, popup_elements)
|
2023-05-22 20:19:11 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// bottom and background layer surfaces
|
|
|
|
|
pub fn background_layer_elements<R>(
|
|
|
|
|
renderer: &mut R,
|
|
|
|
|
output: &Output,
|
|
|
|
|
exclude_workspace_overview: bool,
|
2023-07-13 17:19:29 +02:00
|
|
|
) -> (
|
|
|
|
|
Vec<WorkspaceRenderElement<R>>,
|
|
|
|
|
Vec<WorkspaceRenderElement<R>>,
|
|
|
|
|
)
|
2023-05-22 20:19:11 +02:00
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll + ImportMem + AsGlowRenderer,
|
|
|
|
|
<R as Renderer>::TextureId: Clone + 'static,
|
|
|
|
|
<R as Renderer>::Error: From<GlesError>,
|
|
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
|
|
|
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
|
|
|
|
{
|
2023-07-13 17:19:29 +02:00
|
|
|
let (mut layer_elements, mut popup_elements) =
|
|
|
|
|
split_layer_elements(renderer, output, Layer::Bottom, exclude_workspace_overview);
|
|
|
|
|
let more = split_layer_elements(
|
|
|
|
|
renderer,
|
|
|
|
|
output,
|
|
|
|
|
Layer::Background,
|
|
|
|
|
exclude_workspace_overview,
|
|
|
|
|
);
|
|
|
|
|
layer_elements.extend(more.0);
|
|
|
|
|
popup_elements.extend(more.1);
|
|
|
|
|
(layer_elements, popup_elements)
|
2023-05-22 20:19:11 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-16 12:28:19 -07:00
|
|
|
fn session_lock_elements<R>(
|
|
|
|
|
renderer: &mut R,
|
|
|
|
|
output: &Output,
|
|
|
|
|
session_lock: &SessionLock,
|
|
|
|
|
) -> Vec<WaylandSurfaceRenderElement<R>>
|
|
|
|
|
where
|
|
|
|
|
R: Renderer + ImportAll,
|
|
|
|
|
<R as Renderer>::TextureId: Clone + 'static,
|
|
|
|
|
{
|
|
|
|
|
if let Some(surface) = session_lock.surfaces.get(output) {
|
|
|
|
|
let scale = Scale::from(output.current_scale().fractional_scale());
|
|
|
|
|
render_elements_from_surface_tree(
|
|
|
|
|
renderer,
|
|
|
|
|
surface.wl_surface(),
|
|
|
|
|
(0, 0),
|
|
|
|
|
scale,
|
|
|
|
|
1.0,
|
|
|
|
|
Kind::Unspecified,
|
|
|
|
|
)
|
|
|
|
|
} else {
|
|
|
|
|
Vec::new()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-07 19:15:44 -07:00
|
|
|
#[profiling::function]
|
2024-04-08 16:55:41 -07:00
|
|
|
pub fn render_output<'d, R, Target, OffTarget>(
|
2022-04-22 15:18:28 +02:00
|
|
|
gpu: Option<&DrmNode>,
|
2022-03-16 20:05:24 +01:00
|
|
|
renderer: &mut R,
|
2022-11-17 20:32:54 +01:00
|
|
|
target: Target,
|
2024-04-08 16:55:41 -07:00
|
|
|
damage_tracker: &'d mut OutputDamageTracker,
|
2022-09-28 12:01:29 +02:00
|
|
|
age: usize,
|
2022-02-04 21:04:17 +01:00
|
|
|
state: &mut Common,
|
|
|
|
|
output: &Output,
|
2022-11-03 18:51:27 +01:00
|
|
|
cursor_mode: CursorMode,
|
2022-11-22 18:20:20 +01:00
|
|
|
fps: Option<&mut Fps>,
|
2024-04-08 16:55:41 -07:00
|
|
|
) -> Result<RenderOutputResult<'d>, RenderError<R>>
|
2022-08-05 14:28:37 +02:00
|
|
|
where
|
2022-11-03 18:51:27 +01:00
|
|
|
R: Renderer
|
|
|
|
|
+ ImportAll
|
|
|
|
|
+ ImportMem
|
|
|
|
|
+ ExportMem
|
|
|
|
|
+ Bind<Dmabuf>
|
2022-11-17 20:32:54 +01:00
|
|
|
+ Bind<Target>
|
|
|
|
|
+ Offscreen<OffTarget>
|
2024-03-12 19:42:48 +01:00
|
|
|
+ Blit<Target>
|
2022-11-17 20:32:54 +01:00
|
|
|
+ AsGlowRenderer,
|
2022-08-05 14:28:37 +02:00
|
|
|
<R as Renderer>::TextureId: Clone + 'static,
|
2023-04-18 17:10:21 +02:00
|
|
|
<R as Renderer>::Error: From<GlesError>,
|
2022-11-17 20:32:54 +01:00
|
|
|
CosmicElement<R>: RenderElement<R>,
|
2022-11-22 10:28:30 +01:00
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
2024-03-12 19:42:48 +01:00
|
|
|
Target: Clone,
|
2022-08-05 14:28:37 +02:00
|
|
|
{
|
2023-05-22 20:19:11 +02:00
|
|
|
let (previous_workspace, workspace) = state.shell.workspaces.active(output);
|
|
|
|
|
let (previous_idx, idx) = state.shell.workspaces.active_num(output);
|
|
|
|
|
let previous_workspace = previous_workspace
|
|
|
|
|
.zip(previous_idx)
|
|
|
|
|
.map(|((w, start), idx)| (w.handle, idx, start));
|
|
|
|
|
let workspace = (workspace.handle, idx);
|
|
|
|
|
|
2023-01-23 18:25:01 +01:00
|
|
|
let result = render_workspace(
|
2022-08-05 14:28:37 +02:00
|
|
|
gpu,
|
|
|
|
|
renderer,
|
2024-03-12 19:42:48 +01:00
|
|
|
target.clone(),
|
2022-09-28 12:01:29 +02:00
|
|
|
damage_tracker,
|
2022-08-05 14:28:37 +02:00
|
|
|
age,
|
2024-03-12 19:42:48 +01:00
|
|
|
None,
|
2022-08-05 14:28:37 +02:00
|
|
|
state,
|
|
|
|
|
output,
|
2023-05-22 20:19:11 +02:00
|
|
|
previous_workspace,
|
|
|
|
|
workspace,
|
2022-11-03 18:51:27 +01:00
|
|
|
cursor_mode,
|
2022-11-17 20:32:54 +01:00
|
|
|
fps,
|
2023-02-10 14:32:56 -08:00
|
|
|
false,
|
2023-01-23 18:25:01 +01:00
|
|
|
);
|
|
|
|
|
|
2024-03-12 19:42:48 +01:00
|
|
|
match result {
|
|
|
|
|
Ok((res, mut elements)) => {
|
|
|
|
|
for (session, frame) in output.take_pending_frames() {
|
|
|
|
|
if let Some((frame, damage)) = render_session(
|
|
|
|
|
renderer,
|
|
|
|
|
&session.user_data().get::<SessionData>().unwrap(),
|
|
|
|
|
frame,
|
|
|
|
|
output.current_transform(),
|
|
|
|
|
|buffer, renderer, dt, age, additional_damage| {
|
|
|
|
|
let old_len = if !additional_damage.is_empty() {
|
|
|
|
|
let area = output
|
|
|
|
|
.current_mode()
|
|
|
|
|
.ok_or(RenderError::OutputNoMode(OutputNoMode))
|
|
|
|
|
.map(
|
|
|
|
|
|mode| {
|
|
|
|
|
mode.size
|
|
|
|
|
.to_logical(1)
|
|
|
|
|
.to_buffer(1, Transform::Normal)
|
|
|
|
|
.to_f64()
|
|
|
|
|
}, /* TODO: Mode is Buffer..., why is this Physical in the first place */
|
|
|
|
|
)?;
|
|
|
|
|
|
|
|
|
|
let old_len = elements.len();
|
|
|
|
|
elements.extend(
|
|
|
|
|
additional_damage
|
|
|
|
|
.into_iter()
|
|
|
|
|
.map(|rect| {
|
|
|
|
|
rect.to_f64()
|
|
|
|
|
.to_logical(
|
|
|
|
|
output.current_scale().fractional_scale(),
|
|
|
|
|
output.current_transform(),
|
|
|
|
|
&area,
|
|
|
|
|
)
|
|
|
|
|
.to_i32_round()
|
|
|
|
|
})
|
|
|
|
|
.map(DamageElement::new)
|
|
|
|
|
.map(Into::into),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
Some(old_len)
|
|
|
|
|
} else {
|
|
|
|
|
None
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
let res = dt.damage_output(age, &elements)?;
|
|
|
|
|
|
|
|
|
|
if let Some(old_len) = old_len {
|
|
|
|
|
elements.truncate(old_len);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let (Some(ref damage), _) = &res {
|
|
|
|
|
if let Ok(dmabuf) = get_dmabuf(buffer) {
|
|
|
|
|
renderer.bind(dmabuf).map_err(RenderError::Rendering)?;
|
|
|
|
|
} else {
|
|
|
|
|
let size = buffer_dimensions(buffer).unwrap();
|
|
|
|
|
let format = with_buffer_contents(buffer, |_, _, data| {
|
|
|
|
|
shm_format_to_fourcc(data.format)
|
|
|
|
|
})
|
|
|
|
|
.map_err(|_| OutputNoMode)? // eh, we have to do some error
|
|
|
|
|
.expect(
|
|
|
|
|
"We should be able to convert all hardcoded shm screencopy formats",
|
|
|
|
|
);
|
|
|
|
|
let render_buffer = renderer
|
|
|
|
|
.create_buffer(format, size)
|
|
|
|
|
.map_err(RenderError::Rendering)?;
|
|
|
|
|
renderer
|
|
|
|
|
.bind(render_buffer)
|
|
|
|
|
.map_err(RenderError::Rendering)?;
|
|
|
|
|
}
|
2024-04-08 16:55:41 -07:00
|
|
|
for rect in damage.iter() {
|
2024-03-12 19:42:48 +01:00
|
|
|
renderer
|
|
|
|
|
.blit_from(target.clone(), *rect, *rect, TextureFilter::Nearest)
|
|
|
|
|
.map_err(RenderError::Rendering)?;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(RenderOutputResult {
|
|
|
|
|
damage: res.0,
|
|
|
|
|
sync: SyncPoint::default(),
|
|
|
|
|
states: res.1,
|
|
|
|
|
})
|
|
|
|
|
},
|
|
|
|
|
)? {
|
|
|
|
|
frame.success(output.current_transform(), damage, state.clock.now());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Ok(res)
|
|
|
|
|
}
|
|
|
|
|
Err(err) => Err(err),
|
|
|
|
|
}
|
2022-08-05 14:28:37 +02:00
|
|
|
}
|
|
|
|
|
|
2023-10-07 19:15:44 -07:00
|
|
|
#[profiling::function]
|
2024-04-08 16:55:41 -07:00
|
|
|
pub fn render_workspace<'d, R, Target, OffTarget>(
|
2022-11-03 18:51:27 +01:00
|
|
|
gpu: Option<&DrmNode>,
|
2022-08-05 14:28:37 +02:00
|
|
|
renderer: &mut R,
|
2022-11-17 20:32:54 +01:00
|
|
|
target: Target,
|
2024-04-08 16:55:41 -07:00
|
|
|
damage_tracker: &'d mut OutputDamageTracker,
|
2022-09-28 12:01:29 +02:00
|
|
|
age: usize,
|
2024-03-12 19:42:48 +01:00
|
|
|
additional_damage: Option<Vec<Rectangle<i32, Logical>>>,
|
2022-08-05 14:28:37 +02:00
|
|
|
state: &mut Common,
|
|
|
|
|
output: &Output,
|
2024-03-07 13:14:53 -06:00
|
|
|
previous: Option<(WorkspaceHandle, usize, WorkspaceDelta)>,
|
2023-05-22 20:19:11 +02:00
|
|
|
current: (WorkspaceHandle, usize),
|
2024-03-12 19:42:48 +01:00
|
|
|
cursor_mode: CursorMode,
|
2022-11-22 18:20:20 +01:00
|
|
|
mut fps: Option<&mut Fps>,
|
2023-02-10 14:32:56 -08:00
|
|
|
exclude_workspace_overview: bool,
|
2024-04-08 16:55:41 -07:00
|
|
|
) -> Result<(RenderOutputResult<'d>, Vec<CosmicElement<R>>), RenderError<R>>
|
2022-03-16 20:05:24 +01:00
|
|
|
where
|
2022-11-03 18:51:27 +01:00
|
|
|
R: Renderer
|
|
|
|
|
+ ImportAll
|
|
|
|
|
+ ImportMem
|
|
|
|
|
+ ExportMem
|
|
|
|
|
+ Bind<Dmabuf>
|
2022-11-17 20:32:54 +01:00
|
|
|
+ Bind<Target>
|
|
|
|
|
+ Offscreen<OffTarget>
|
|
|
|
|
+ AsGlowRenderer,
|
2022-03-16 20:05:24 +01:00
|
|
|
<R as Renderer>::TextureId: Clone + 'static,
|
2023-04-18 17:10:21 +02:00
|
|
|
<R as Renderer>::Error: From<GlesError>,
|
2022-11-17 20:32:54 +01:00
|
|
|
CosmicElement<R>: RenderElement<R>,
|
2022-11-22 10:28:30 +01:00
|
|
|
CosmicMappedRenderElement<R>: RenderElement<R>,
|
2023-05-19 19:44:57 +02:00
|
|
|
WorkspaceRenderElement<R>: RenderElement<R>,
|
2022-03-16 20:05:24 +01:00
|
|
|
{
|
2022-08-03 16:34:04 +02:00
|
|
|
if let Some(ref mut fps) = fps {
|
2022-02-04 21:04:17 +01:00
|
|
|
fps.start();
|
2022-11-28 17:48:50 +01:00
|
|
|
#[cfg(feature = "debug")]
|
2023-02-27 23:54:28 +01:00
|
|
|
if let Some(rd) = fps.rd.as_mut() {
|
|
|
|
|
rd.start_frame_capture(
|
|
|
|
|
renderer.glow_renderer().egl_context().get_context_handle(),
|
|
|
|
|
std::ptr::null(),
|
|
|
|
|
);
|
2022-11-28 17:48:50 +01:00
|
|
|
}
|
2022-02-04 21:04:17 +01:00
|
|
|
}
|
2022-08-05 14:28:37 +02:00
|
|
|
|
2024-03-12 19:42:48 +01:00
|
|
|
let mut elements: Vec<CosmicElement<R>> = workspace_elements(
|
2023-03-07 16:37:11 +01:00
|
|
|
gpu,
|
|
|
|
|
renderer,
|
|
|
|
|
state,
|
|
|
|
|
output,
|
2023-05-22 20:19:11 +02:00
|
|
|
previous,
|
|
|
|
|
current,
|
2023-03-07 16:37:11 +01:00
|
|
|
cursor_mode,
|
|
|
|
|
&mut fps,
|
|
|
|
|
exclude_workspace_overview,
|
|
|
|
|
)?;
|
2024-03-12 19:42:48 +01:00
|
|
|
|
|
|
|
|
if let Some(additional_damage) = additional_damage {
|
|
|
|
|
let output_geo = output.geometry().to_local(&output).as_logical();
|
|
|
|
|
elements.extend(
|
|
|
|
|
additional_damage
|
|
|
|
|
.into_iter()
|
|
|
|
|
.filter_map(|rect| rect.intersection(output_geo))
|
|
|
|
|
.map(DamageElement::new)
|
|
|
|
|
.map(Into::<CosmicElement<R>>::into),
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-18 17:20:52 +01:00
|
|
|
if let Some(fps) = fps.as_mut() {
|
|
|
|
|
fps.elements();
|
|
|
|
|
}
|
|
|
|
|
|
2022-11-17 20:32:54 +01:00
|
|
|
renderer.bind(target).map_err(RenderError::Rendering)?;
|
2023-10-10 13:55:34 -04:00
|
|
|
let res = damage_tracker.render_output(
|
|
|
|
|
renderer,
|
|
|
|
|
age,
|
|
|
|
|
&elements,
|
2023-10-17 17:50:15 -04:00
|
|
|
CLEAR_COLOR, // TODO use a theme neutral color
|
2023-10-10 13:55:34 -04:00
|
|
|
);
|
2022-02-04 21:04:17 +01:00
|
|
|
|
2022-11-17 20:32:54 +01:00
|
|
|
if let Some(fps) = fps.as_mut() {
|
2022-11-18 17:20:52 +01:00
|
|
|
fps.render();
|
2022-04-22 15:18:28 +02:00
|
|
|
}
|
2022-05-03 13:37:51 +02:00
|
|
|
|
2023-02-27 23:54:28 +01:00
|
|
|
#[cfg(feature = "debug")]
|
|
|
|
|
if let Some(ref mut fps) = fps {
|
|
|
|
|
if let Some(rd) = fps.rd.as_mut() {
|
|
|
|
|
rd.end_frame_capture(
|
|
|
|
|
renderer.glow_renderer().egl_context().get_context_handle(),
|
|
|
|
|
std::ptr::null(),
|
|
|
|
|
);
|
2022-11-18 17:20:52 +01:00
|
|
|
}
|
2022-11-03 18:51:27 +01:00
|
|
|
}
|
|
|
|
|
|
2024-03-12 19:42:48 +01:00
|
|
|
res.map(|res| (res, elements))
|
2022-02-04 21:04:17 +01:00
|
|
|
}
|