use std::time::Instant;
use smithay::wayland::compositor::{SurfaceAttributes, with_states};
use smithay::{
backend::renderer::{
element::Kind, element::surface::render_elements_from_surface_tree, gles::GlesRenderer,
},
utils::{Physical, Rectangle},
};
use super::super::bearings::{BearingChipLayout, collect_bearing_layouts};
use super::super::cursor_surface_hotspot;
use super::super::layer_shell::collect_layer_surfaces;
use super::super::node::{NodeSnapshot, collect_hover_preview};
use super::super::pin_icon::PinBadgeLayout;
use super::super::state::ClosingWindowAnimationSnapshot;
use crate::compositor::interaction::ResizeCtx;
use crate::compositor::root::Halley;
use crate::window::{
ActiveBorderRect, CroppedClippedSurfaceElement, OffscreenNodeTexture, StackWindowDrawUnit,
WindowShadowRect, collect_active_surfaces,
};
pub(super) type SurfaceElement =
smithay::backend::renderer::element::surface::WaylandSurfaceRenderElement<GlesRenderer>;
pub(super) struct PreparedFrameState {
pub(super) damage: Rectangle<i32, Physical>,
pub(super) now: Instant,
}
pub(super) struct SceneCollections {
pub(super) session_lock_elements: Vec<SurfaceElement>,
pub(super) layer_background_elements: Vec<SurfaceElement>,
pub(super) layer_bottom_elements: Vec<SurfaceElement>,
pub(super) layer_top_elements: Vec<SurfaceElement>,
pub(super) layer_overlay_elements: Vec<SurfaceElement>,
pub(super) active_elements: Vec<CroppedClippedSurfaceElement>,
pub(super) resized_active_elements: Vec<CroppedClippedSurfaceElement>,
pub(super) fullscreen_active_elements: Vec<CroppedClippedSurfaceElement>,
pub(super) above_fullscreen_active_elements: Vec<CroppedClippedSurfaceElement>,
pub(super) offscreen_textures: Vec<OffscreenNodeTexture>,
pub(super) resized_offscreen_textures: Vec<OffscreenNodeTexture>,
pub(super) fullscreen_offscreen_textures: Vec<OffscreenNodeTexture>,
pub(super) above_fullscreen_offscreen_textures: Vec<OffscreenNodeTexture>,
pub(super) popup_offscreen_textures: Vec<OffscreenNodeTexture>,
pub(super) popup_elements:
Vec<smithay::backend::renderer::element::utils::CropRenderElement<SurfaceElement>>,
pub(super) fullscreen_popup_offscreen_textures: Vec<OffscreenNodeTexture>,
pub(super) fullscreen_popup_elements:
Vec<smithay::backend::renderer::element::utils::CropRenderElement<SurfaceElement>>,
pub(super) above_fullscreen_popup_offscreen_textures: Vec<OffscreenNodeTexture>,
pub(super) above_fullscreen_popup_elements:
Vec<smithay::backend::renderer::element::utils::CropRenderElement<SurfaceElement>>,
pub(super) stack_window_units: Vec<StackWindowDrawUnit>,
pub(super) above_fullscreen_stack_window_units: Vec<StackWindowDrawUnit>,
pub(super) shadow_rects: Vec<WindowShadowRect>,
pub(super) resized_shadow_rects: Vec<WindowShadowRect>,
pub(super) above_fullscreen_shadow_rects: Vec<WindowShadowRect>,
pub(super) border_rects: Vec<ActiveBorderRect>,
pub(super) resized_border_rects: Vec<ActiveBorderRect>,
pub(super) above_fullscreen_border_rects: Vec<ActiveBorderRect>,
pub(super) closing_window_animations: Vec<ClosingWindowAnimationSnapshot>,
pub(super) pin_badges: Vec<PinBadgeLayout>,
pub(super) hover_preview_rect: Option<(i32, i32, i32, i32)>,
pub(super) hover_preview_elements: Vec<SurfaceElement>,
pub(super) render_nodes: Vec<NodeSnapshot>,
pub(super) bearing_layouts: Vec<BearingChipLayout>,
}
pub(super) struct CursorScene {
pub(super) cursor_status: smithay::input::pointer::CursorImageStatus,
pub(super) cursor_surface_elements: Vec<SurfaceElement>,
}
pub(super) fn prepare_debug_frame_state(
st: &mut Halley,
size: smithay::utils::Size<i32, Physical>,
) -> PreparedFrameState {
let now = Instant::now();
if crate::protocol::wayland::session_lock::session_lock_active(st) {
crate::protocol::wayland::session_lock::configure_surfaces(st);
}
if !st.input.interaction_state.suppress_layer_shell_configure {
crate::compositor::monitor::layer_shell::configure_layer_shell_surfaces(
st,
(size.w, size.h).into(),
);
}
PreparedFrameState {
damage: Rectangle::<i32, Physical>::from_size(size),
now,
}
}
pub(super) fn collect_debug_frame_scene(
renderer: &mut GlesRenderer,
st: &mut Halley,
size: smithay::utils::Size<i32, Physical>,
resize_preview: Option<ResizeCtx>,
hover_node: Option<halley_core::field::NodeId>,
preview_hover_node: Option<halley_core::field::NodeId>,
now: Instant,
) -> SceneCollections {
if crate::protocol::wayland::session_lock::session_lock_active(st) {
let session_lock_elements =
crate::protocol::wayland::session_lock::current_monitor_surfaces(st)
.into_iter()
.flat_map(|surface| {
render_elements_from_surface_tree(
renderer,
&surface,
(0, 0),
1.0,
1.0,
Kind::Unspecified,
)
})
.collect();
return SceneCollections {
session_lock_elements,
layer_background_elements: Vec::new(),
layer_bottom_elements: Vec::new(),
layer_top_elements: Vec::new(),
layer_overlay_elements: Vec::new(),
active_elements: Vec::new(),
resized_active_elements: Vec::new(),
fullscreen_active_elements: Vec::new(),
above_fullscreen_active_elements: Vec::new(),
offscreen_textures: Vec::new(),
resized_offscreen_textures: Vec::new(),
fullscreen_offscreen_textures: Vec::new(),
above_fullscreen_offscreen_textures: Vec::new(),
popup_offscreen_textures: Vec::new(),
popup_elements: Vec::new(),
fullscreen_popup_offscreen_textures: Vec::new(),
fullscreen_popup_elements: Vec::new(),
above_fullscreen_popup_offscreen_textures: Vec::new(),
above_fullscreen_popup_elements: Vec::new(),
stack_window_units: Vec::new(),
above_fullscreen_stack_window_units: Vec::new(),
shadow_rects: Vec::new(),
resized_shadow_rects: Vec::new(),
above_fullscreen_shadow_rects: Vec::new(),
border_rects: Vec::new(),
resized_border_rects: Vec::new(),
above_fullscreen_border_rects: Vec::new(),
closing_window_animations: Vec::new(),
pin_badges: Vec::new(),
hover_preview_rect: None,
hover_preview_elements: Vec::new(),
render_nodes: Vec::new(),
bearing_layouts: Vec::new(),
};
}
let render_monitor = st.model.monitor_state.current_monitor.clone();
let bearings_mix = st
.ui
.render_state
.bearings_mix_for_monitor(render_monitor.as_str());
let (
layer_background_elements,
layer_bottom_elements,
layer_top_elements,
layer_overlay_elements,
) = collect_layer_surfaces(renderer, st, size, now);
let window_plan = collect_active_surfaces(renderer, st, size, resize_preview, now);
let closing_window_animations = if st.runtime.tuning.window_close_animation_enabled() {
st.ui
.render_state
.closing_window_animation_snapshots(render_monitor.as_str(), now)
} else {
Vec::new()
};
let hovered_preview_id = preview_hover_node.and_then(|id| {
st.model.field.node(id).and_then(|n| {
matches!(
n.state,
halley_core::field::NodeState::Node | halley_core::field::NodeState::Core
)
.then_some(id)
})
});
let overlay_hover_preview = st
.input
.interaction_state
.overlay_hover_target
.as_ref()
.filter(|target| {
target.monitor == render_monitor
&& preview_hover_node == Some(target.node_id)
&& st
.input
.interaction_state
.cluster_overflow_drag_preview
.is_none()
})
.map(|target| (target.node_id, target.screen_anchor, target.prefer_left));
let (hover_preview_rect, hover_preview_elements) = collect_hover_preview(
renderer,
st,
size,
render_monitor.as_str(),
&window_plan.node_surface_map,
hovered_preview_id,
overlay_hover_preview,
hover_node,
now,
);
let render_nodes = st
.model
.field
.nodes()
.keys()
.copied()
.into_iter()
.filter_map(|id| {
let node = st.model.field.node(id)?;
if !st.model.field.participates_in_field_view(id)
|| !st.model.field.is_visible(id)
|| !st.node_assigned_to_current_monitor(id)
{
return None;
}
Some(NodeSnapshot {
id,
state: node.state.clone(),
pos: node.pos,
intrinsic_size: node.intrinsic_size,
label: node.label.clone(),
})
})
.collect();
let bearing_layouts =
collect_bearing_layouts(st, size.w, size.h, render_monitor.as_str(), bearings_mix);
SceneCollections {
session_lock_elements: Vec::new(),
layer_background_elements,
layer_bottom_elements,
layer_top_elements,
layer_overlay_elements,
active_elements: window_plan.active_elements,
resized_active_elements: window_plan.resized_active_elements,
fullscreen_active_elements: window_plan.fullscreen_active_elements,
above_fullscreen_active_elements: window_plan.above_fullscreen_active_elements,
offscreen_textures: window_plan.offscreen_textures,
resized_offscreen_textures: window_plan.resized_offscreen_textures,
fullscreen_offscreen_textures: window_plan.fullscreen_offscreen_textures,
above_fullscreen_offscreen_textures: window_plan.above_fullscreen_offscreen_textures,
popup_offscreen_textures: window_plan.popup_offscreen_textures,
popup_elements: window_plan.popup_elements,
fullscreen_popup_offscreen_textures: window_plan.fullscreen_popup_offscreen_textures,
fullscreen_popup_elements: window_plan.fullscreen_popup_elements,
above_fullscreen_popup_offscreen_textures: window_plan
.above_fullscreen_popup_offscreen_textures,
above_fullscreen_popup_elements: window_plan.above_fullscreen_popup_elements,
stack_window_units: window_plan.stack_window_units,
above_fullscreen_stack_window_units: window_plan.above_fullscreen_stack_window_units,
shadow_rects: window_plan.shadow_rects,
resized_shadow_rects: window_plan.resized_shadow_rects,
above_fullscreen_shadow_rects: window_plan.above_fullscreen_shadow_rects,
border_rects: window_plan.border_rects,
resized_border_rects: window_plan.resized_border_rects,
above_fullscreen_border_rects: window_plan.above_fullscreen_border_rects,
closing_window_animations,
pin_badges: window_plan.pin_badges,
hover_preview_rect,
hover_preview_elements,
render_nodes,
bearing_layouts,
}
}
pub(super) fn collect_cursor_scene(
renderer: &mut GlesRenderer,
cursor_screen: Option<(f32, f32)>,
cursor_image: Option<&smithay::input::pointer::CursorImageStatus>,
) -> CursorScene {
let cursor_status = cursor_image
.cloned()
.unwrap_or_else(smithay::input::pointer::CursorImageStatus::default_named);
let mut cursor_surface_elements = Vec::new();
if let (Some((sx, sy)), smithay::input::pointer::CursorImageStatus::Surface(surface)) =
(cursor_screen, cursor_status.clone())
{
let scale = with_states(&surface, |states| {
states
.cached_state
.get::<SurfaceAttributes>()
.current()
.buffer_scale as f64
});
let (hotspot_x, hotspot_y) = cursor_surface_hotspot(&surface);
let loc = (sx.round() as i32 - hotspot_x, sy.round() as i32 - hotspot_y);
cursor_surface_elements = render_elements_from_surface_tree(
renderer,
&surface,
loc,
scale,
1.0,
Kind::Unspecified,
);
}
CursorScene {
cursor_status,
cursor_surface_elements,
}
}