mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-10-28 06:34:24 +00:00
refactor: split surface, globals, system
This commit is contained in:
parent
18d1827415
commit
6a72d83d0f
4 changed files with 378 additions and 347 deletions
66
src/windowing/globals.rs
Normal file
66
src/windowing/globals.rs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
use crate::{bind_globals, errors::LayerShikaError};
|
||||
use log::info;
|
||||
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::ZwlrLayerShellV1;
|
||||
use wayland_client::{
|
||||
globals::registry_queue_init,
|
||||
protocol::{wl_compositor::WlCompositor, wl_output::WlOutput, wl_seat::WlSeat},
|
||||
Connection, QueueHandle,
|
||||
};
|
||||
use wayland_protocols::wp::fractional_scale::v1::client::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1;
|
||||
use wayland_protocols::wp::viewporter::client::wp_viewporter::WpViewporter;
|
||||
|
||||
use super::state::WindowState;
|
||||
|
||||
pub struct GlobalCtx {
|
||||
pub compositor: WlCompositor,
|
||||
pub output: WlOutput,
|
||||
pub layer_shell: ZwlrLayerShellV1,
|
||||
pub seat: WlSeat,
|
||||
pub fractional_scale_manager: Option<WpFractionalScaleManagerV1>,
|
||||
pub viewporter: Option<WpViewporter>,
|
||||
}
|
||||
|
||||
impl GlobalCtx {
|
||||
pub fn initialize(
|
||||
connection: &Connection,
|
||||
queue_handle: &QueueHandle<WindowState>,
|
||||
) -> Result<Self, LayerShikaError> {
|
||||
let global_list = registry_queue_init::<WindowState>(connection)
|
||||
.map(|(global_list, _)| global_list)
|
||||
.map_err(|e| LayerShikaError::GlobalInitialization(e.to_string()))?;
|
||||
|
||||
let (compositor, output, layer_shell, seat) = bind_globals!(
|
||||
&global_list,
|
||||
queue_handle,
|
||||
(WlCompositor, compositor, 3..=6),
|
||||
(WlOutput, output, 1..=4),
|
||||
(ZwlrLayerShellV1, layer_shell, 1..=5),
|
||||
(WlSeat, seat, 1..=9)
|
||||
)?;
|
||||
|
||||
let fractional_scale_manager = global_list
|
||||
.bind::<WpFractionalScaleManagerV1, _, _>(queue_handle, 1..=1, ())
|
||||
.ok();
|
||||
|
||||
let viewporter = global_list
|
||||
.bind::<WpViewporter, _, _>(queue_handle, 1..=1, ())
|
||||
.ok();
|
||||
|
||||
if fractional_scale_manager.is_none() {
|
||||
info!("Fractional scale protocol not available, using integer scaling");
|
||||
}
|
||||
|
||||
if viewporter.is_none() {
|
||||
info!("Viewporter protocol not available");
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
compositor,
|
||||
output,
|
||||
layer_shell,
|
||||
seat,
|
||||
fractional_scale_manager,
|
||||
viewporter,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -1,352 +1,9 @@
|
|||
use self::state::WindowState;
|
||||
use crate::{
|
||||
bind_globals,
|
||||
errors::{LayerShikaError, Result},
|
||||
rendering::{egl_context::EGLContext, femtovg_window::FemtoVGWindow},
|
||||
};
|
||||
use config::{LayerSurfaceParams, WindowConfig};
|
||||
use log::{debug, error, info};
|
||||
use slint::{
|
||||
platform::{femtovg_renderer::FemtoVGRenderer, update_timers_and_animations},
|
||||
LogicalPosition, PhysicalSize,
|
||||
};
|
||||
use slint_interpreter::ComponentInstance;
|
||||
use smithay_client_toolkit::reexports::{
|
||||
calloop::{generic::Generic, EventLoop, Interest, LoopHandle, Mode, PostAction},
|
||||
protocols_wlr::layer_shell::v1::client::{
|
||||
zwlr_layer_shell_v1::ZwlrLayerShellV1, zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||
},
|
||||
};
|
||||
use state::builder::WindowStateBuilder;
|
||||
use std::rc::Rc;
|
||||
use wayland_client::{
|
||||
globals::registry_queue_init,
|
||||
protocol::{
|
||||
wl_compositor::WlCompositor, wl_display::WlDisplay, wl_output::WlOutput, wl_seat::WlSeat,
|
||||
wl_surface::WlSurface,
|
||||
},
|
||||
Connection, EventQueue, Proxy, QueueHandle,
|
||||
};
|
||||
use wayland_protocols::wp::fractional_scale::v1::client::{
|
||||
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
|
||||
wp_fractional_scale_v1::WpFractionalScaleV1,
|
||||
};
|
||||
use wayland_protocols::wp::viewporter::client::{
|
||||
wp_viewport::WpViewport, wp_viewporter::WpViewporter,
|
||||
};
|
||||
|
||||
pub mod builder;
|
||||
mod config;
|
||||
mod globals;
|
||||
mod macros;
|
||||
mod state;
|
||||
mod surface;
|
||||
mod system;
|
||||
|
||||
pub struct GlobalCtx {
|
||||
pub compositor: WlCompositor,
|
||||
pub output: WlOutput,
|
||||
pub layer_shell: ZwlrLayerShellV1,
|
||||
pub seat: WlSeat,
|
||||
pub fractional_scale_manager: Option<WpFractionalScaleManagerV1>,
|
||||
pub viewporter: Option<WpViewporter>,
|
||||
}
|
||||
|
||||
pub struct SurfaceCtx {
|
||||
pub surface: Rc<WlSurface>,
|
||||
pub layer_surface: Rc<ZwlrLayerSurfaceV1>,
|
||||
pub fractional_scale: Option<Rc<WpFractionalScaleV1>>,
|
||||
pub viewport: Option<Rc<WpViewport>>,
|
||||
}
|
||||
|
||||
pub struct WindowingSystem {
|
||||
state: WindowState,
|
||||
connection: Rc<Connection>,
|
||||
event_queue: EventQueue<WindowState>,
|
||||
event_loop: EventLoop<'static, WindowState>,
|
||||
}
|
||||
|
||||
impl WindowingSystem {
|
||||
fn new(config: WindowConfig) -> Result<Self> {
|
||||
info!("Initializing WindowingSystem");
|
||||
let connection =
|
||||
Rc::new(Connection::connect_to_env().map_err(LayerShikaError::WaylandConnection)?);
|
||||
let event_queue = connection.new_event_queue();
|
||||
|
||||
let global_ctx = Self::initialize_globals(&connection, &event_queue.handle())
|
||||
.map_err(|e| LayerShikaError::GlobalInitialization(e.to_string()))?;
|
||||
|
||||
let output_ref = &global_ctx.output;
|
||||
let surface_ctx = Self::setup_surface(
|
||||
&global_ctx.compositor,
|
||||
output_ref,
|
||||
&global_ctx.layer_shell,
|
||||
global_ctx.fractional_scale_manager.as_ref(),
|
||||
global_ctx.viewporter.as_ref(),
|
||||
&event_queue.handle(),
|
||||
&config,
|
||||
);
|
||||
|
||||
let pointer = Rc::new(global_ctx.seat.get_pointer(&event_queue.handle(), ()));
|
||||
let output = Rc::new(global_ctx.output);
|
||||
let window =
|
||||
Self::initialize_renderer(&surface_ctx.surface, &connection.display(), &config)
|
||||
.map_err(|e| LayerShikaError::EGLContextCreation(e.to_string()))?;
|
||||
|
||||
let mut builder = WindowStateBuilder::new()
|
||||
.with_component_definition(config.component_definition)
|
||||
.with_surface(Rc::clone(&surface_ctx.surface))
|
||||
.with_layer_surface(Rc::clone(&surface_ctx.layer_surface))
|
||||
.with_pointer(Rc::clone(&pointer))
|
||||
.with_output(Rc::clone(&output))
|
||||
.with_scale_factor(config.scale_factor)
|
||||
.with_height(config.height)
|
||||
.with_exclusive_zone(config.exclusive_zone)
|
||||
.with_window(window);
|
||||
|
||||
if let Some(fs) = surface_ctx.fractional_scale {
|
||||
builder = builder.with_fractional_scale(fs);
|
||||
}
|
||||
|
||||
if let Some(vp) = surface_ctx.viewport {
|
||||
builder = builder.with_viewport(vp);
|
||||
}
|
||||
|
||||
let state = builder
|
||||
.build()
|
||||
.map_err(|e| LayerShikaError::WindowConfiguration(e.to_string()))?;
|
||||
|
||||
let event_loop =
|
||||
EventLoop::try_new().map_err(|e| LayerShikaError::EventLoop(e.to_string()))?;
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
connection,
|
||||
event_queue,
|
||||
event_loop,
|
||||
})
|
||||
}
|
||||
|
||||
fn initialize_globals(
|
||||
connection: &Connection,
|
||||
queue_handle: &QueueHandle<WindowState>,
|
||||
) -> Result<GlobalCtx> {
|
||||
let global_list = registry_queue_init::<WindowState>(connection)
|
||||
.map(|(global_list, _)| global_list)
|
||||
.map_err(|e| LayerShikaError::GlobalInitialization(e.to_string()))?;
|
||||
|
||||
let (compositor, output, layer_shell, seat) = bind_globals!(
|
||||
&global_list,
|
||||
queue_handle,
|
||||
(WlCompositor, compositor, 3..=6),
|
||||
(WlOutput, output, 1..=4),
|
||||
(ZwlrLayerShellV1, layer_shell, 1..=5),
|
||||
(WlSeat, seat, 1..=9)
|
||||
)?;
|
||||
|
||||
let fractional_scale_manager = global_list
|
||||
.bind::<WpFractionalScaleManagerV1, _, _>(queue_handle, 1..=1, ())
|
||||
.ok();
|
||||
|
||||
let viewporter = global_list
|
||||
.bind::<WpViewporter, _, _>(queue_handle, 1..=1, ())
|
||||
.ok();
|
||||
|
||||
if fractional_scale_manager.is_none() {
|
||||
info!("Fractional scale protocol not available, using integer scaling");
|
||||
}
|
||||
|
||||
if viewporter.is_none() {
|
||||
info!("Viewporter protocol not available");
|
||||
}
|
||||
|
||||
Ok(GlobalCtx {
|
||||
compositor,
|
||||
output,
|
||||
layer_shell,
|
||||
seat,
|
||||
fractional_scale_manager,
|
||||
viewporter,
|
||||
})
|
||||
}
|
||||
|
||||
fn setup_surface(
|
||||
compositor: &WlCompositor,
|
||||
output: &WlOutput,
|
||||
layer_shell: &ZwlrLayerShellV1,
|
||||
fractional_scale_manager: Option<&WpFractionalScaleManagerV1>,
|
||||
viewporter: Option<&WpViewporter>,
|
||||
queue_handle: &QueueHandle<WindowState>,
|
||||
config: &WindowConfig,
|
||||
) -> SurfaceCtx {
|
||||
let surface = Rc::new(compositor.create_surface(queue_handle, ()));
|
||||
let layer_surface = Rc::new(layer_shell.get_layer_surface(
|
||||
&surface,
|
||||
Some(output),
|
||||
config.layer,
|
||||
config.namespace.clone(),
|
||||
queue_handle,
|
||||
(),
|
||||
));
|
||||
|
||||
let fractional_scale = fractional_scale_manager.map(|manager| {
|
||||
info!("Creating fractional scale object for surface");
|
||||
Rc::new(manager.get_fractional_scale(&surface, queue_handle, ()))
|
||||
});
|
||||
|
||||
let viewport = viewporter.map(|vp| {
|
||||
info!("Creating viewport for surface");
|
||||
Rc::new(vp.get_viewport(&surface, queue_handle, ()))
|
||||
});
|
||||
|
||||
let params = LayerSurfaceParams {
|
||||
anchor: config.anchor,
|
||||
margin: config.margin,
|
||||
exclusive_zone: config.exclusive_zone,
|
||||
keyboard_interactivity: config.keyboard_interactivity,
|
||||
height: config.height,
|
||||
};
|
||||
|
||||
Self::configure_layer_surface(&layer_surface, &surface, ¶ms);
|
||||
|
||||
surface.set_buffer_scale(1);
|
||||
|
||||
SurfaceCtx {
|
||||
surface,
|
||||
layer_surface,
|
||||
fractional_scale,
|
||||
viewport,
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_layer_surface(
|
||||
layer_surface: &Rc<ZwlrLayerSurfaceV1>,
|
||||
surface: &WlSurface,
|
||||
params: &LayerSurfaceParams,
|
||||
) {
|
||||
layer_surface.set_anchor(params.anchor);
|
||||
layer_surface.set_margin(
|
||||
params.margin.top,
|
||||
params.margin.right,
|
||||
params.margin.bottom,
|
||||
params.margin.left,
|
||||
);
|
||||
|
||||
layer_surface.set_exclusive_zone(params.exclusive_zone);
|
||||
layer_surface.set_keyboard_interactivity(params.keyboard_interactivity);
|
||||
layer_surface.set_size(1, params.height);
|
||||
surface.commit();
|
||||
}
|
||||
|
||||
fn initialize_renderer(
|
||||
surface: &Rc<WlSurface>,
|
||||
display: &WlDisplay,
|
||||
config: &WindowConfig,
|
||||
) -> Result<Rc<FemtoVGWindow>> {
|
||||
let init_size = PhysicalSize::new(1, 1);
|
||||
|
||||
let context = EGLContext::builder()
|
||||
.with_display_id(display.id())
|
||||
.with_surface_id(surface.id())
|
||||
.with_size(init_size)
|
||||
.build()
|
||||
.map_err(|e| LayerShikaError::EGLContextCreation(e.to_string()))?;
|
||||
|
||||
let renderer = FemtoVGRenderer::new(context)
|
||||
.map_err(|e| LayerShikaError::FemtoVGRendererCreation(e.to_string()))?;
|
||||
|
||||
let femtovg_window = FemtoVGWindow::new(renderer);
|
||||
femtovg_window.set_size(slint::WindowSize::Physical(init_size));
|
||||
femtovg_window.set_scale_factor(config.scale_factor);
|
||||
femtovg_window.set_position(LogicalPosition::new(0., 0.));
|
||||
|
||||
Ok(femtovg_window)
|
||||
}
|
||||
|
||||
pub fn event_loop_handle(&self) -> LoopHandle<'static, WindowState> {
|
||||
self.event_loop.handle()
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<()> {
|
||||
info!("Starting WindowingSystem main loop");
|
||||
|
||||
while self
|
||||
.event_queue
|
||||
.blocking_dispatch(&mut self.state)
|
||||
.map_err(|e| LayerShikaError::WaylandProtocol(e.to_string()))?
|
||||
> 0
|
||||
{
|
||||
self.connection
|
||||
.flush()
|
||||
.map_err(|e| LayerShikaError::WaylandProtocol(e.to_string()))?;
|
||||
self.state
|
||||
.window()
|
||||
.render_frame_if_dirty()
|
||||
.map_err(|e| LayerShikaError::Rendering(e.to_string()))?;
|
||||
}
|
||||
|
||||
self.setup_wayland_event_source()?;
|
||||
|
||||
let event_queue = &mut self.event_queue;
|
||||
let connection = &self.connection;
|
||||
|
||||
self.event_loop
|
||||
.run(None, &mut self.state, move |shared_data| {
|
||||
if let Err(e) = Self::process_events(connection, event_queue, shared_data) {
|
||||
error!("Error processing events: {e}");
|
||||
}
|
||||
})
|
||||
.map_err(|e| LayerShikaError::EventLoop(e.to_string()))
|
||||
}
|
||||
|
||||
fn setup_wayland_event_source(&self) -> Result<()> {
|
||||
debug!("Setting up Wayland event source");
|
||||
|
||||
let connection = Rc::clone(&self.connection);
|
||||
|
||||
self.event_loop
|
||||
.handle()
|
||||
.insert_source(
|
||||
Generic::new(connection, Interest::READ, Mode::Level),
|
||||
move |_, _connection, _shared_data| Ok(PostAction::Continue),
|
||||
)
|
||||
.map_err(|e| LayerShikaError::EventLoop(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_events(
|
||||
connection: &Connection,
|
||||
event_queue: &mut EventQueue<WindowState>,
|
||||
shared_data: &mut WindowState,
|
||||
) -> Result<()> {
|
||||
if let Some(guard) = event_queue.prepare_read() {
|
||||
guard
|
||||
.read()
|
||||
.map_err(|e| LayerShikaError::WaylandProtocol(e.to_string()))?;
|
||||
}
|
||||
connection.flush()?;
|
||||
|
||||
event_queue
|
||||
.dispatch_pending(shared_data)
|
||||
.map_err(|e| LayerShikaError::WaylandProtocol(e.to_string()))?;
|
||||
|
||||
update_timers_and_animations();
|
||||
|
||||
shared_data
|
||||
.window()
|
||||
.render_frame_if_dirty()
|
||||
.map_err(|e| LayerShikaError::Rendering(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub const fn component_instance(&self) -> &ComponentInstance {
|
||||
self.state.component_instance()
|
||||
}
|
||||
|
||||
pub fn window(&self) -> Rc<FemtoVGWindow> {
|
||||
self.state.window()
|
||||
}
|
||||
|
||||
pub const fn state(&self) -> &WindowState {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
pub use system::WindowingSystem;
|
||||
|
|
|
|||
93
src/windowing/surface.rs
Normal file
93
src/windowing/surface.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use super::{config::LayerSurfaceParams, state::WindowState};
|
||||
use log::info;
|
||||
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::{
|
||||
zwlr_layer_shell_v1::{Layer, ZwlrLayerShellV1},
|
||||
zwlr_layer_surface_v1::ZwlrLayerSurfaceV1,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
use wayland_client::{
|
||||
protocol::{wl_compositor::WlCompositor, wl_output::WlOutput, wl_surface::WlSurface},
|
||||
QueueHandle,
|
||||
};
|
||||
use wayland_protocols::wp::fractional_scale::v1::client::{
|
||||
wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
|
||||
wp_fractional_scale_v1::WpFractionalScaleV1,
|
||||
};
|
||||
use wayland_protocols::wp::viewporter::client::{
|
||||
wp_viewport::WpViewport, wp_viewporter::WpViewporter,
|
||||
};
|
||||
|
||||
pub struct SurfaceSetupParams<'a> {
|
||||
pub compositor: &'a WlCompositor,
|
||||
pub output: &'a WlOutput,
|
||||
pub layer_shell: &'a ZwlrLayerShellV1,
|
||||
pub fractional_scale_manager: Option<&'a WpFractionalScaleManagerV1>,
|
||||
pub viewporter: Option<&'a WpViewporter>,
|
||||
pub queue_handle: &'a QueueHandle<WindowState>,
|
||||
pub layer: Layer,
|
||||
pub namespace: String,
|
||||
}
|
||||
|
||||
pub struct SurfaceCtx {
|
||||
pub surface: Rc<WlSurface>,
|
||||
pub layer_surface: Rc<ZwlrLayerSurfaceV1>,
|
||||
pub fractional_scale: Option<Rc<WpFractionalScaleV1>>,
|
||||
pub viewport: Option<Rc<WpViewport>>,
|
||||
}
|
||||
|
||||
impl SurfaceCtx {
|
||||
pub fn setup(setup_params: &SurfaceSetupParams<'_>, params: &LayerSurfaceParams) -> Self {
|
||||
let surface = Rc::new(
|
||||
setup_params
|
||||
.compositor
|
||||
.create_surface(setup_params.queue_handle, ()),
|
||||
);
|
||||
let layer_surface = Rc::new(setup_params.layer_shell.get_layer_surface(
|
||||
&surface,
|
||||
Some(setup_params.output),
|
||||
setup_params.layer,
|
||||
setup_params.namespace.clone(),
|
||||
setup_params.queue_handle,
|
||||
(),
|
||||
));
|
||||
|
||||
let fractional_scale = setup_params.fractional_scale_manager.map(|manager| {
|
||||
info!("Creating fractional scale object for surface");
|
||||
Rc::new(manager.get_fractional_scale(&surface, setup_params.queue_handle, ()))
|
||||
});
|
||||
|
||||
let viewport = setup_params.viewporter.map(|vp| {
|
||||
info!("Creating viewport for surface");
|
||||
Rc::new(vp.get_viewport(&surface, setup_params.queue_handle, ()))
|
||||
});
|
||||
|
||||
Self::configure_layer_surface(&layer_surface, &surface, params);
|
||||
surface.set_buffer_scale(1);
|
||||
|
||||
Self {
|
||||
surface,
|
||||
layer_surface,
|
||||
fractional_scale,
|
||||
viewport,
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_layer_surface(
|
||||
layer_surface: &Rc<ZwlrLayerSurfaceV1>,
|
||||
surface: &WlSurface,
|
||||
params: &LayerSurfaceParams,
|
||||
) {
|
||||
layer_surface.set_anchor(params.anchor);
|
||||
layer_surface.set_margin(
|
||||
params.margin.top,
|
||||
params.margin.right,
|
||||
params.margin.bottom,
|
||||
params.margin.left,
|
||||
);
|
||||
|
||||
layer_surface.set_exclusive_zone(params.exclusive_zone);
|
||||
layer_surface.set_keyboard_interactivity(params.keyboard_interactivity);
|
||||
layer_surface.set_size(1, params.height);
|
||||
surface.commit();
|
||||
}
|
||||
}
|
||||
215
src/windowing/system.rs
Normal file
215
src/windowing/system.rs
Normal file
|
|
@ -0,0 +1,215 @@
|
|||
use super::{
|
||||
config::{LayerSurfaceParams, WindowConfig},
|
||||
globals::GlobalCtx,
|
||||
state::{builder::WindowStateBuilder, WindowState},
|
||||
surface::{SurfaceCtx, SurfaceSetupParams},
|
||||
};
|
||||
use crate::{
|
||||
errors::{LayerShikaError, Result},
|
||||
rendering::{egl_context::EGLContext, femtovg_window::FemtoVGWindow},
|
||||
};
|
||||
use log::{error, info};
|
||||
use slint::{
|
||||
platform::{femtovg_renderer::FemtoVGRenderer, update_timers_and_animations},
|
||||
LogicalPosition, PhysicalSize,
|
||||
};
|
||||
use slint_interpreter::ComponentInstance;
|
||||
use smithay_client_toolkit::reexports::calloop::{
|
||||
generic::Generic, EventLoop, Interest, LoopHandle, Mode, PostAction,
|
||||
};
|
||||
use std::rc::Rc;
|
||||
use wayland_client::{
|
||||
protocol::{wl_display::WlDisplay, wl_surface::WlSurface},
|
||||
Connection, EventQueue, Proxy,
|
||||
};
|
||||
|
||||
pub struct WindowingSystem {
|
||||
state: WindowState,
|
||||
connection: Rc<Connection>,
|
||||
event_queue: EventQueue<WindowState>,
|
||||
event_loop: EventLoop<'static, WindowState>,
|
||||
}
|
||||
|
||||
impl WindowingSystem {
|
||||
pub(super) fn new(config: WindowConfig) -> Result<Self> {
|
||||
info!("Initializing WindowingSystem");
|
||||
let connection =
|
||||
Rc::new(Connection::connect_to_env().map_err(LayerShikaError::WaylandConnection)?);
|
||||
let event_queue = connection.new_event_queue();
|
||||
|
||||
let global_ctx = GlobalCtx::initialize(&connection, &event_queue.handle())
|
||||
.map_err(|e| LayerShikaError::GlobalInitialization(e.to_string()))?;
|
||||
|
||||
let layer_surface_params = LayerSurfaceParams {
|
||||
anchor: config.anchor,
|
||||
margin: config.margin,
|
||||
exclusive_zone: config.exclusive_zone,
|
||||
keyboard_interactivity: config.keyboard_interactivity,
|
||||
height: config.height,
|
||||
};
|
||||
|
||||
let setup_params = SurfaceSetupParams {
|
||||
compositor: &global_ctx.compositor,
|
||||
output: &global_ctx.output,
|
||||
layer_shell: &global_ctx.layer_shell,
|
||||
fractional_scale_manager: global_ctx.fractional_scale_manager.as_ref(),
|
||||
viewporter: global_ctx.viewporter.as_ref(),
|
||||
queue_handle: &event_queue.handle(),
|
||||
layer: config.layer,
|
||||
namespace: config.namespace.clone(),
|
||||
};
|
||||
|
||||
let surface_ctx = SurfaceCtx::setup(&setup_params, &layer_surface_params);
|
||||
|
||||
let pointer = Rc::new(global_ctx.seat.get_pointer(&event_queue.handle(), ()));
|
||||
let output = Rc::new(global_ctx.output);
|
||||
let window = Self::initialize_renderer(&surface_ctx.surface, &connection.display(), &config)
|
||||
.map_err(|e| LayerShikaError::EGLContextCreation(e.to_string()))?;
|
||||
|
||||
let mut builder = WindowStateBuilder::new()
|
||||
.with_component_definition(config.component_definition)
|
||||
.with_surface(Rc::clone(&surface_ctx.surface))
|
||||
.with_layer_surface(Rc::clone(&surface_ctx.layer_surface))
|
||||
.with_pointer(Rc::clone(&pointer))
|
||||
.with_output(Rc::clone(&output))
|
||||
.with_scale_factor(config.scale_factor)
|
||||
.with_height(config.height)
|
||||
.with_exclusive_zone(config.exclusive_zone)
|
||||
.with_window(window);
|
||||
|
||||
if let Some(fs) = &surface_ctx.fractional_scale {
|
||||
builder = builder.with_fractional_scale(Rc::clone(fs));
|
||||
}
|
||||
|
||||
if let Some(vp) = &surface_ctx.viewport {
|
||||
builder = builder.with_viewport(Rc::clone(vp));
|
||||
}
|
||||
|
||||
let state = builder
|
||||
.build()
|
||||
.map_err(|e| LayerShikaError::WindowConfiguration(e.to_string()))?;
|
||||
|
||||
let event_loop =
|
||||
EventLoop::try_new().map_err(|e| LayerShikaError::EventLoop(e.to_string()))?;
|
||||
|
||||
Ok(Self {
|
||||
state,
|
||||
connection,
|
||||
event_queue,
|
||||
event_loop,
|
||||
})
|
||||
}
|
||||
|
||||
fn initialize_renderer(
|
||||
surface: &Rc<WlSurface>,
|
||||
display: &WlDisplay,
|
||||
config: &WindowConfig,
|
||||
) -> Result<Rc<FemtoVGWindow>> {
|
||||
let init_size = PhysicalSize::new(1, 1);
|
||||
|
||||
let context = EGLContext::builder()
|
||||
.with_display_id(display.id())
|
||||
.with_surface_id(surface.id())
|
||||
.with_size(init_size)
|
||||
.build()
|
||||
.map_err(|e| LayerShikaError::EGLContextCreation(e.to_string()))?;
|
||||
|
||||
let renderer = FemtoVGRenderer::new(context)
|
||||
.map_err(|e| LayerShikaError::FemtoVGRendererCreation(e.to_string()))?;
|
||||
|
||||
let femtovg_window = FemtoVGWindow::new(renderer);
|
||||
femtovg_window.set_size(slint::WindowSize::Physical(init_size));
|
||||
femtovg_window.set_scale_factor(config.scale_factor);
|
||||
femtovg_window.set_position(LogicalPosition::new(0., 0.));
|
||||
|
||||
Ok(femtovg_window)
|
||||
}
|
||||
|
||||
pub fn event_loop_handle(&self) -> LoopHandle<'static, WindowState> {
|
||||
self.event_loop.handle()
|
||||
}
|
||||
|
||||
pub fn run(&mut self) -> Result<()> {
|
||||
info!("Starting WindowingSystem main loop");
|
||||
|
||||
while self
|
||||
.event_queue
|
||||
.blocking_dispatch(&mut self.state)
|
||||
.map_err(|e| LayerShikaError::WaylandProtocol(e.to_string()))?
|
||||
> 0
|
||||
{
|
||||
self.connection
|
||||
.flush()
|
||||
.map_err(|e| LayerShikaError::WaylandProtocol(e.to_string()))?;
|
||||
self.state
|
||||
.window()
|
||||
.render_frame_if_dirty()
|
||||
.map_err(|e| LayerShikaError::Rendering(e.to_string()))?;
|
||||
}
|
||||
|
||||
self.setup_wayland_event_source()?;
|
||||
|
||||
let event_queue = &mut self.event_queue;
|
||||
let connection = &self.connection;
|
||||
|
||||
self.event_loop
|
||||
.run(None, &mut self.state, move |shared_data| {
|
||||
if let Err(e) = Self::process_events(connection, event_queue, shared_data) {
|
||||
error!("Error processing events: {e}");
|
||||
}
|
||||
})
|
||||
.map_err(|e| LayerShikaError::EventLoop(e.to_string()))
|
||||
}
|
||||
|
||||
fn setup_wayland_event_source(&self) -> Result<()> {
|
||||
let connection = Rc::clone(&self.connection);
|
||||
|
||||
self.event_loop
|
||||
.handle()
|
||||
.insert_source(
|
||||
Generic::new(connection, Interest::READ, Mode::Level),
|
||||
move |_, _connection, _shared_data| Ok(PostAction::Continue),
|
||||
)
|
||||
.map_err(|e| LayerShikaError::EventLoop(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_events(
|
||||
connection: &Connection,
|
||||
event_queue: &mut EventQueue<WindowState>,
|
||||
shared_data: &mut WindowState,
|
||||
) -> Result<()> {
|
||||
if let Some(guard) = event_queue.prepare_read() {
|
||||
guard
|
||||
.read()
|
||||
.map_err(|e| LayerShikaError::WaylandProtocol(e.to_string()))?;
|
||||
}
|
||||
connection.flush()?;
|
||||
|
||||
event_queue
|
||||
.dispatch_pending(shared_data)
|
||||
.map_err(|e| LayerShikaError::WaylandProtocol(e.to_string()))?;
|
||||
|
||||
update_timers_and_animations();
|
||||
|
||||
shared_data
|
||||
.window()
|
||||
.render_frame_if_dirty()
|
||||
.map_err(|e| LayerShikaError::Rendering(e.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub const fn component_instance(&self) -> &ComponentInstance {
|
||||
self.state.component_instance()
|
||||
}
|
||||
|
||||
pub fn window(&self) -> Rc<FemtoVGWindow> {
|
||||
self.state.window()
|
||||
}
|
||||
|
||||
pub const fn state(&self) -> &WindowState {
|
||||
&self.state
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue