use std::sync::Arc;
use smithay_client_toolkit::compositor::CompositorState;
use smithay_client_toolkit::reexports::client::protocol::wl_surface::WlSurface;
use crate::egl_context::EglContext;
use crate::event_loop::SurfaceState;
use crate::render::Canvas;
use crate::types::{ Color, Rect };
use crate::widget::Element;
use super::{ DrawCtx, layout_and_draw };
use super::chrome::{ apply_input_region, draw_fallback_banner, draw_titlebar };
pub( crate ) fn draw_surface_full_gpu<Msg: Clone>(
ss: &mut SurfaceState<Msg>,
compositor: &CompositorState,
egl_ctx: &Arc<EglContext>,
view: &Element<Msg>,
bg: Color,
input_region: Option<&[Rect]>,
debug_layout: bool,
pw: u32,
ph: u32,
scale: u32,
request_frame: &dyn Fn( &WlSurface ),
)
{
let Some( es ) = ss.egl_surface.as_ref() else { return };
if egl_ctx.make_current( es ).is_err() { return; }
let canvas = ss.canvas.get_or_insert_with( ||
{
let mut c = Canvas::new_gles(
Arc::clone( egl_ctx.gl() ), egl_ctx.version, pw, ph,
);
c.set_dpi_scale( scale as f32 );
if let Some( reg ) = crate::theme::build_font_registry()
{
c.set_font_registry( Arc::new( reg ) );
}
c
} );
if canvas.size() != ( pw, ph )
{
canvas.resize( pw, ph );
canvas.set_dpi_scale( scale as f32 );
}
canvas.clear_clip();
let sf = scale as f32;
let tb_h = ss.titlebar_height * sf;
let screen_rect = Rect { x: 0.0, y: tb_h, width: pw as f32, height: ( ph as f32 - tb_h ).max( 0.0 ) };
if bg.a > 0.0 { canvas.fill( bg ); } else { canvas.clear(); }
ss.titlebar_close_rect = draw_titlebar( canvas, &ss.titlebar_title, pw, tb_h, sf );
let mut ctx: DrawCtx<Msg> = DrawCtx
{
focused_idx: ss.focused_idx,
hovered_idx: ss.hovered_idx,
pressed_idx: ss.gesture.pressed_idx,
cursor_state: std::mem::take( &mut ss.cursor_state ),
selection_anchor: std::mem::take( &mut ss.selection_anchor ),
widget_rects: Vec::new(),
debug_layout,
scroll_offsets: std::mem::take( &mut ss.scroll_offsets ),
scroll_rects: Vec::new(),
scroll_canvases: std::mem::take( &mut ss.scroll_canvases ),
scroll_navigable_items: std::mem::take( &mut ss.scroll_navigable_items ),
previous_widget_rects: ss.widget_rects.clone(),
accessible_extras: Vec::new(),
live_depth: 0,
};
layout_and_draw::<Msg>( view, canvas, screen_rect, &mut ctx, 0 );
if ctx.debug_layout
{
for w in &ctx.widget_rects
{
canvas.stroke_rect( w.rect, Color::rgb( 1.0, 0.0, 0.0 ), 1.5, 0.0 );
}
}
if let Some( ref menu ) = ss.context_menu
{
super::draw_context_menu( canvas, menu );
}
draw_fallback_banner( canvas, pw, sf );
canvas.present();
ss.prev_focused = ss.focused_idx;
ss.prev_hovered = ss.hovered_idx;
ss.prev_pressed = ss.gesture.pressed_idx;
ss.widget_rects = ctx.widget_rects;
ss.scroll_rects = ctx.scroll_rects;
ss.scroll_canvases = std::mem::take( &mut ctx.scroll_canvases );
ss.cursor_state = ctx.cursor_state;
ss.selection_anchor = ctx.selection_anchor;
ss.scroll_offsets = ctx.scroll_offsets;
ss.accessible_extras = ctx.accessible_extras;
ss.scroll_navigable_items = ctx.scroll_navigable_items;
ss.content_dirty = false;
let wl_surface = ss.surface.wl_surface();
apply_input_region( wl_surface, compositor, input_region, scale );
request_frame( wl_surface );
let _ = egl_ctx.swap_buffers_with_damage( es, &[ ( 0, 0, pw as i32, ph as i32 ) ] );
ss.frame_pending = true;
}
pub( crate ) fn draw_surface_partial_gpu<Msg: Clone>(
ss: &mut SurfaceState<Msg>,
compositor: &CompositorState,
egl_ctx: &Arc<EglContext>,
view: &Element<Msg>,
bg: Color,
input_region: Option<&[Rect]>,
dirty_rects: Vec<Rect>,
pw: u32,
ph: u32,
scale: u32,
request_frame: &dyn Fn( &WlSurface ),
)
{
let Some( es ) = ss.egl_surface.as_ref() else { return };
if egl_ctx.make_current( es ).is_err() { return; }
let canvas = ss.canvas.as_mut().expect( "partial path requires existing canvas" );
if canvas.size() != ( pw, ph )
{
canvas.resize( pw, ph );
canvas.set_dpi_scale( scale as f32 );
}
canvas.set_clip_rects( &dirty_rects );
let sf = scale as f32;
let tb_h = ss.titlebar_height * sf;
let screen_rect = Rect { x: 0.0, y: tb_h, width: pw as f32, height: ( ph as f32 - tb_h ).max( 0.0 ) };
if bg.a > 0.0 { canvas.fill( bg ); }
else
{
canvas.clear_rects_transparent( &dirty_rects );
}
ss.titlebar_close_rect = draw_titlebar( canvas, &ss.titlebar_title, pw, tb_h, sf );
let mut ctx: DrawCtx<Msg> = DrawCtx
{
focused_idx: ss.focused_idx,
hovered_idx: ss.hovered_idx,
pressed_idx: ss.gesture.pressed_idx,
cursor_state: std::mem::take( &mut ss.cursor_state ),
selection_anchor: std::mem::take( &mut ss.selection_anchor ),
widget_rects: Vec::new(),
debug_layout: false,
scroll_offsets: std::mem::take( &mut ss.scroll_offsets ),
scroll_rects: Vec::new(),
scroll_canvases: std::mem::take( &mut ss.scroll_canvases ),
scroll_navigable_items: std::mem::take( &mut ss.scroll_navigable_items ),
previous_widget_rects: ss.widget_rects.clone(),
accessible_extras: Vec::new(),
live_depth: 0,
};
layout_and_draw::<Msg>( view, canvas, screen_rect, &mut ctx, 0 );
if let Some( ref menu ) = ss.context_menu
{
super::draw_context_menu( canvas, menu );
}
draw_fallback_banner( canvas, pw, sf );
canvas.clear_clip();
canvas.present();
ss.prev_focused = ss.focused_idx;
ss.prev_hovered = ss.hovered_idx;
ss.prev_pressed = ss.gesture.pressed_idx;
ss.widget_rects = ctx.widget_rects;
ss.scroll_rects = ctx.scroll_rects;
ss.scroll_canvases = std::mem::take( &mut ctx.scroll_canvases );
ss.cursor_state = ctx.cursor_state;
ss.selection_anchor = ctx.selection_anchor;
ss.scroll_offsets = ctx.scroll_offsets;
ss.accessible_extras = ctx.accessible_extras;
ss.scroll_navigable_items = ctx.scroll_navigable_items;
ss.content_dirty = false;
let wl_surface = ss.surface.wl_surface();
apply_input_region( wl_surface, compositor, input_region, scale );
request_frame( wl_surface );
let damage: Vec<( i32, i32, i32, i32 )> = dirty_rects.iter().map( |r|
{
let x = r.x.floor() as i32;
let w = r.width.ceil() as i32;
let h = r.height.ceil() as i32;
let y_top = r.y.floor() as i32;
let y_bottom = ph as i32 - y_top - h;
( x, y_bottom.max( 0 ), w.max( 0 ), h.max( 0 ) )
} ).collect();
let _ = egl_ctx.swap_buffers_with_damage( es, &damage );
ss.frame_pending = true;
}