mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-12-02 20:15:54 +00:00
feat: dynamic lifecycle output management
This commit is contained in:
parent
5a1c551efb
commit
3e7bc76bb4
5 changed files with 401 additions and 10 deletions
|
|
@ -1,7 +1,8 @@
|
||||||
use crate::wayland::surfaces::app_state::AppState;
|
use crate::wayland::surfaces::app_state::AppState;
|
||||||
use crate::wayland::surfaces::display_metrics::DisplayMetrics;
|
use crate::wayland::surfaces::display_metrics::DisplayMetrics;
|
||||||
|
use crate::wayland::surfaces::surface_state::WindowState;
|
||||||
use layer_shika_domain::value_objects::output_info::OutputGeometry;
|
use layer_shika_domain::value_objects::output_info::OutputGeometry;
|
||||||
use log::info;
|
use log::{debug, info};
|
||||||
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::{
|
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::{
|
||||||
zwlr_layer_shell_v1::ZwlrLayerShellV1,
|
zwlr_layer_shell_v1::ZwlrLayerShellV1,
|
||||||
zwlr_layer_surface_v1::{self, ZwlrLayerSurfaceV1},
|
zwlr_layer_surface_v1::{self, ZwlrLayerSurfaceV1},
|
||||||
|
|
@ -13,6 +14,7 @@ use wayland_client::{
|
||||||
wl_compositor::WlCompositor,
|
wl_compositor::WlCompositor,
|
||||||
wl_output::{self, WlOutput},
|
wl_output::{self, WlOutput},
|
||||||
wl_pointer::{self, WlPointer},
|
wl_pointer::{self, WlPointer},
|
||||||
|
wl_registry::Event,
|
||||||
wl_registry::WlRegistry,
|
wl_registry::WlRegistry,
|
||||||
wl_seat::WlSeat,
|
wl_seat::WlSeat,
|
||||||
wl_surface::WlSurface,
|
wl_surface::WlSurface,
|
||||||
|
|
@ -76,7 +78,7 @@ impl Dispatch<WlOutput, ()> for AppState {
|
||||||
event: <WlOutput as Proxy>::Event,
|
event: <WlOutput as Proxy>::Event,
|
||||||
_data: &(),
|
_data: &(),
|
||||||
_conn: &Connection,
|
_conn: &Connection,
|
||||||
_qhandle: &QueueHandle<Self>,
|
qhandle: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
let output_id = proxy.id();
|
let output_id = proxy.id();
|
||||||
let handle = state.get_handle_by_output_id(&output_id);
|
let handle = state.get_handle_by_output_id(&output_id);
|
||||||
|
|
@ -139,7 +141,24 @@ impl Dispatch<WlOutput, ()> for AppState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
wl_output::Event::Done => {
|
wl_output::Event::Done => {
|
||||||
info!("WlOutput done");
|
info!("WlOutput done for output {:?}", output_id);
|
||||||
|
|
||||||
|
if let Some(manager) = state.output_manager() {
|
||||||
|
let manager_ref = manager.borrow();
|
||||||
|
if manager_ref.has_pending_output(&output_id) {
|
||||||
|
drop(manager_ref);
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Output {:?} configuration complete, finalizing...",
|
||||||
|
output_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let manager_ref = manager.borrow();
|
||||||
|
if let Err(e) = manager_ref.finalize_output(&output_id, state, qhandle) {
|
||||||
|
info!("Failed to finalize output {:?}: {e}", output_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -251,7 +270,6 @@ impl Dispatch<XdgWmBase, ()> for AppState {
|
||||||
_qhandle: &QueueHandle<Self>,
|
_qhandle: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
if let xdg_wm_base::Event::Ping { serial } = event {
|
if let xdg_wm_base::Event::Ping { serial } = event {
|
||||||
use crate::wayland::surfaces::surface_state::WindowState;
|
|
||||||
WindowState::handle_xdg_wm_base_ping(xdg_wm_base, serial);
|
WindowState::handle_xdg_wm_base_ping(xdg_wm_base, serial);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -330,6 +348,57 @@ impl Dispatch<XdgSurface, ()> for AppState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Dispatch<WlRegistry, GlobalListContents> for AppState {
|
||||||
|
fn event(
|
||||||
|
state: &mut Self,
|
||||||
|
registry: &WlRegistry,
|
||||||
|
event: <WlRegistry as Proxy>::Event,
|
||||||
|
_data: &GlobalListContents,
|
||||||
|
_conn: &Connection,
|
||||||
|
qhandle: &QueueHandle<Self>,
|
||||||
|
) {
|
||||||
|
match event {
|
||||||
|
Event::Global {
|
||||||
|
name,
|
||||||
|
interface,
|
||||||
|
version,
|
||||||
|
} => {
|
||||||
|
if interface == "wl_output" {
|
||||||
|
info!(
|
||||||
|
"Hot-plugged output detected! Binding wl_output with name {name}, version {version}"
|
||||||
|
);
|
||||||
|
|
||||||
|
let output = registry.bind::<WlOutput, _, _>(name, 4.min(version), qhandle, ());
|
||||||
|
let output_id = output.id();
|
||||||
|
|
||||||
|
if let Some(manager) = state.output_manager() {
|
||||||
|
let mut manager_ref = manager.borrow_mut();
|
||||||
|
let handle = manager_ref.register_output(output, qhandle);
|
||||||
|
info!("Registered hot-plugged output with handle {handle:?}");
|
||||||
|
|
||||||
|
state.register_registry_name(name, output_id);
|
||||||
|
} else {
|
||||||
|
info!("No output manager available yet (startup initialization)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Event::GlobalRemove { name } => {
|
||||||
|
info!("Registry global removed: name {name}");
|
||||||
|
|
||||||
|
if let Some(output_id) = state.unregister_registry_name(name) {
|
||||||
|
info!("Output with registry name {name} removed, cleaning up...");
|
||||||
|
|
||||||
|
if let Some(manager) = state.output_manager() {
|
||||||
|
let mut manager_ref = manager.borrow_mut();
|
||||||
|
manager_ref.remove_output(&output_id, state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
macro_rules! impl_empty_dispatch_app {
|
macro_rules! impl_empty_dispatch_app {
|
||||||
($(($t:ty, $u:ty)),+) => {
|
($(($t:ty, $u:ty)),+) => {
|
||||||
$(
|
$(
|
||||||
|
|
@ -342,7 +411,7 @@ macro_rules! impl_empty_dispatch_app {
|
||||||
_conn: &Connection,
|
_conn: &Connection,
|
||||||
_qhandle: &QueueHandle<Self>,
|
_qhandle: &QueueHandle<Self>,
|
||||||
) {
|
) {
|
||||||
info!("Implement empty dispatch event for {:?}", stringify!($t));
|
debug!("Implement empty dispatch event for {:?}", stringify!($t));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)+
|
)+
|
||||||
|
|
@ -350,7 +419,6 @@ macro_rules! impl_empty_dispatch_app {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl_empty_dispatch_app!(
|
impl_empty_dispatch_app!(
|
||||||
(WlRegistry, GlobalListContents),
|
|
||||||
(WlCompositor, ()),
|
(WlCompositor, ()),
|
||||||
(WlSurface, ()),
|
(WlSurface, ()),
|
||||||
(ZwlrLayerShellV1, ()),
|
(ZwlrLayerShellV1, ()),
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,10 @@ use layer_shika_domain::value_objects::output_handle::OutputHandle;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use wayland_client::backend::ObjectId;
|
use wayland_client::backend::ObjectId;
|
||||||
|
|
||||||
pub struct OutputMapping {
|
pub(crate) use output_manager::{OutputManager, OutputManagerContext};
|
||||||
|
pub(crate) mod output_manager;
|
||||||
|
|
||||||
|
pub(crate) struct OutputMapping {
|
||||||
object_to_handle: HashMap<ObjectId, OutputHandle>,
|
object_to_handle: HashMap<ObjectId, OutputHandle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -23,7 +26,6 @@ impl OutputMapping {
|
||||||
self.object_to_handle.get(object_id).copied()
|
self.object_to_handle.get(object_id).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
|
||||||
pub fn remove(&mut self, object_id: &ObjectId) -> Option<OutputHandle> {
|
pub fn remove(&mut self, object_id: &ObjectId) -> Option<OutputHandle> {
|
||||||
self.object_to_handle.remove(object_id)
|
self.object_to_handle.remove(object_id)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
240
crates/adapters/src/wayland/outputs/output_manager.rs
Normal file
240
crates/adapters/src/wayland/outputs/output_manager.rs
Normal file
|
|
@ -0,0 +1,240 @@
|
||||||
|
use crate::{
|
||||||
|
errors::{LayerShikaError, Result},
|
||||||
|
rendering::egl::context_factory::RenderContextFactory,
|
||||||
|
wayland::{
|
||||||
|
config::{LayerSurfaceConfig, WaylandWindowConfig},
|
||||||
|
shell_adapter::WaylandWindowingSystem,
|
||||||
|
surfaces::{
|
||||||
|
app_state::AppState,
|
||||||
|
event_context::SharedPointerSerial,
|
||||||
|
layer_surface::{SurfaceCtx, SurfaceSetupParams},
|
||||||
|
popup_manager::{PopupContext, PopupManager},
|
||||||
|
surface_builder::WindowStateBuilder,
|
||||||
|
surface_state::WindowState,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use layer_shika_domain::value_objects::{
|
||||||
|
output_handle::OutputHandle,
|
||||||
|
output_info::OutputInfo,
|
||||||
|
};
|
||||||
|
use log::{info, warn};
|
||||||
|
use smithay_client_toolkit::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::ZwlrLayerShellV1;
|
||||||
|
use std::{cell::RefCell, collections::HashMap, rc::Rc};
|
||||||
|
use wayland_client::{
|
||||||
|
backend::ObjectId,
|
||||||
|
protocol::{wl_compositor::WlCompositor, wl_output::WlOutput, wl_pointer::WlPointer},
|
||||||
|
Connection, Proxy, QueueHandle,
|
||||||
|
};
|
||||||
|
use wayland_protocols::{
|
||||||
|
wp::fractional_scale::v1::client::wp_fractional_scale_manager_v1::WpFractionalScaleManagerV1,
|
||||||
|
wp::viewporter::client::wp_viewporter::WpViewporter,
|
||||||
|
};
|
||||||
|
|
||||||
|
use super::OutputMapping;
|
||||||
|
|
||||||
|
pub struct OutputManagerContext {
|
||||||
|
pub compositor: WlCompositor,
|
||||||
|
pub layer_shell: ZwlrLayerShellV1,
|
||||||
|
pub fractional_scale_manager: Option<WpFractionalScaleManagerV1>,
|
||||||
|
pub viewporter: Option<WpViewporter>,
|
||||||
|
pub render_factory: Rc<RenderContextFactory>,
|
||||||
|
pub popup_context: PopupContext,
|
||||||
|
pub pointer: Rc<WlPointer>,
|
||||||
|
pub shared_serial: Rc<SharedPointerSerial>,
|
||||||
|
pub connection: Rc<Connection>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputManagerContext {
|
||||||
|
pub const fn connection(&self) -> &Rc<Connection> {
|
||||||
|
&self.connection
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PendingOutput {
|
||||||
|
proxy: WlOutput,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
output_id: ObjectId,
|
||||||
|
info: OutputInfo,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OutputManager {
|
||||||
|
context: OutputManagerContext,
|
||||||
|
config: WaylandWindowConfig,
|
||||||
|
pub(crate) layer_surface_config: LayerSurfaceConfig,
|
||||||
|
output_mapping: OutputMapping,
|
||||||
|
pending_outputs: RefCell<HashMap<ObjectId, PendingOutput>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OutputManager {
|
||||||
|
pub(crate) fn new(
|
||||||
|
context: OutputManagerContext,
|
||||||
|
config: WaylandWindowConfig,
|
||||||
|
layer_surface_config: LayerSurfaceConfig,
|
||||||
|
) -> Self {
|
||||||
|
Self {
|
||||||
|
context,
|
||||||
|
config,
|
||||||
|
layer_surface_config,
|
||||||
|
output_mapping: OutputMapping::new(),
|
||||||
|
pending_outputs: RefCell::new(HashMap::new()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_output(
|
||||||
|
&mut self,
|
||||||
|
output: WlOutput,
|
||||||
|
_queue_handle: &QueueHandle<AppState>,
|
||||||
|
) -> OutputHandle {
|
||||||
|
let output_id = output.id();
|
||||||
|
let handle = self.output_mapping.insert(output_id.clone());
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Registered new output with handle {handle:?}, id {:?}",
|
||||||
|
output_id
|
||||||
|
);
|
||||||
|
|
||||||
|
let info = OutputInfo::new(handle);
|
||||||
|
|
||||||
|
self.pending_outputs.borrow_mut().insert(
|
||||||
|
output_id.clone(),
|
||||||
|
PendingOutput {
|
||||||
|
proxy: output,
|
||||||
|
output_id,
|
||||||
|
info,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
handle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finalize_output(
|
||||||
|
&self,
|
||||||
|
output_id: &ObjectId,
|
||||||
|
app_state: &mut AppState,
|
||||||
|
queue_handle: &QueueHandle<AppState>,
|
||||||
|
) -> Result<()> {
|
||||||
|
let mut pending = self.pending_outputs.borrow_mut();
|
||||||
|
|
||||||
|
let Some(pending_output) = pending.remove(output_id) else {
|
||||||
|
return Err(LayerShikaError::InvalidInput {
|
||||||
|
message: format!("No pending output found for id {output_id:?}"),
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
let handle = pending_output.info.handle();
|
||||||
|
let mut info = pending_output.info;
|
||||||
|
|
||||||
|
let is_primary = app_state.output_registry().is_empty();
|
||||||
|
info.set_primary(is_primary);
|
||||||
|
|
||||||
|
if !self.config.output_policy.should_render(&info) {
|
||||||
|
info!(
|
||||||
|
"Skipping output {:?} due to output policy (primary: {})",
|
||||||
|
output_id, is_primary
|
||||||
|
);
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
info!(
|
||||||
|
"Finalizing output {:?} (handle: {handle:?}, primary: {})",
|
||||||
|
output_id, is_primary
|
||||||
|
);
|
||||||
|
|
||||||
|
let (window, main_surface_id) =
|
||||||
|
self.create_window_for_output(&pending_output.proxy, output_id, queue_handle)?;
|
||||||
|
|
||||||
|
app_state.add_output(output_id.clone(), main_surface_id, window);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn create_window_for_output(
|
||||||
|
&self,
|
||||||
|
output: &WlOutput,
|
||||||
|
_output_id: &ObjectId,
|
||||||
|
queue_handle: &QueueHandle<AppState>,
|
||||||
|
) -> Result<(WindowState, ObjectId)> {
|
||||||
|
let setup_params = SurfaceSetupParams {
|
||||||
|
compositor: &self.context.compositor,
|
||||||
|
output,
|
||||||
|
layer_shell: &self.context.layer_shell,
|
||||||
|
fractional_scale_manager: self.context.fractional_scale_manager.as_ref(),
|
||||||
|
viewporter: self.context.viewporter.as_ref(),
|
||||||
|
queue_handle,
|
||||||
|
layer: self.config.layer,
|
||||||
|
namespace: self.config.namespace.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let surface_ctx = SurfaceCtx::setup(&setup_params, &self.layer_surface_config);
|
||||||
|
let main_surface_id = surface_ctx.surface.id();
|
||||||
|
|
||||||
|
let window = WaylandWindowingSystem::initialize_renderer(
|
||||||
|
&surface_ctx.surface,
|
||||||
|
&self.config,
|
||||||
|
&self.context.render_factory,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let mut builder = WindowStateBuilder::new()
|
||||||
|
.with_component_definition(self.config.component_definition.clone())
|
||||||
|
.with_compilation_result(self.config.compilation_result.clone())
|
||||||
|
.with_surface(Rc::clone(&surface_ctx.surface))
|
||||||
|
.with_layer_surface(Rc::clone(&surface_ctx.layer_surface))
|
||||||
|
.with_scale_factor(self.config.scale_factor)
|
||||||
|
.with_height(self.config.height)
|
||||||
|
.with_exclusive_zone(self.config.exclusive_zone)
|
||||||
|
.with_connection(Rc::clone(self.context.connection()))
|
||||||
|
.with_pointer(Rc::clone(&self.context.pointer))
|
||||||
|
.with_window(Rc::clone(&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 mut window_state =
|
||||||
|
WindowState::new(builder).map_err(|e| LayerShikaError::WindowConfiguration {
|
||||||
|
message: e.to_string(),
|
||||||
|
})?;
|
||||||
|
|
||||||
|
let popup_manager = Rc::new(PopupManager::new(
|
||||||
|
self.context.popup_context.clone(),
|
||||||
|
Rc::clone(window_state.display_metrics()),
|
||||||
|
));
|
||||||
|
|
||||||
|
window_state.set_popup_manager(Rc::clone(&popup_manager));
|
||||||
|
window_state.set_shared_pointer_serial(Rc::clone(&self.context.shared_serial));
|
||||||
|
|
||||||
|
Ok((window_state, main_surface_id))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn remove_output(&mut self, output_id: &ObjectId, app_state: &mut AppState) {
|
||||||
|
if let Some(handle) = self.output_mapping.remove(output_id) {
|
||||||
|
info!("Removing output {handle:?} (id: {output_id:?})");
|
||||||
|
|
||||||
|
if let Some(_window) = app_state.remove_output(handle) {
|
||||||
|
info!("Cleaned up window for output {handle:?}");
|
||||||
|
} else {
|
||||||
|
warn!("No window found for output handle {handle:?}");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
self.pending_outputs.borrow_mut().remove(output_id);
|
||||||
|
info!("Removed pending output {output_id:?}");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_handle_by_output_id(&self, output_id: &ObjectId) -> Option<OutputHandle> {
|
||||||
|
self.output_mapping.get(output_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn has_pending_output(&self, output_id: &ObjectId) -> bool {
|
||||||
|
self.pending_outputs.borrow().contains_key(output_id)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pending_output_count(&self) -> usize {
|
||||||
|
self.pending_outputs.borrow().len()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,6 +2,7 @@ use crate::wayland::{
|
||||||
config::{LayerSurfaceConfig, WaylandWindowConfig},
|
config::{LayerSurfaceConfig, WaylandWindowConfig},
|
||||||
globals::context::GlobalContext,
|
globals::context::GlobalContext,
|
||||||
managed_proxies::ManagedWlPointer,
|
managed_proxies::ManagedWlPointer,
|
||||||
|
outputs::{OutputManager, OutputManagerContext},
|
||||||
surfaces::layer_surface::{SurfaceCtx, SurfaceSetupParams},
|
surfaces::layer_surface::{SurfaceCtx, SurfaceSetupParams},
|
||||||
surfaces::popup_manager::{PopupContext, PopupManager},
|
surfaces::popup_manager::{PopupContext, PopupManager},
|
||||||
surfaces::{
|
surfaces::{
|
||||||
|
|
@ -34,6 +35,7 @@ use slint_interpreter::ComponentInstance;
|
||||||
use smithay_client_toolkit::reexports::calloop::{
|
use smithay_client_toolkit::reexports::calloop::{
|
||||||
EventLoop, Interest, LoopHandle, Mode, PostAction, generic::Generic,
|
EventLoop, Interest, LoopHandle, Mode, PostAction, generic::Generic,
|
||||||
};
|
};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
Connection, EventQueue, Proxy, QueueHandle,
|
Connection, EventQueue, Proxy, QueueHandle,
|
||||||
|
|
@ -50,6 +52,17 @@ struct OutputSetup {
|
||||||
builder: WindowStateBuilder,
|
builder: WindowStateBuilder,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct OutputManagerParams<'a> {
|
||||||
|
config: &'a WaylandWindowConfig,
|
||||||
|
global_ctx: &'a GlobalContext,
|
||||||
|
connection: &'a Connection,
|
||||||
|
layer_surface_config: LayerSurfaceConfig,
|
||||||
|
render_factory: &'a Rc<RenderContextFactory>,
|
||||||
|
popup_context: &'a PopupContext,
|
||||||
|
pointer: &'a Rc<WlPointer>,
|
||||||
|
shared_serial: &'a Rc<SharedPointerSerial>,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct WaylandWindowingSystem {
|
pub struct WaylandWindowingSystem {
|
||||||
state: AppState,
|
state: AppState,
|
||||||
connection: Rc<Connection>,
|
connection: Rc<Connection>,
|
||||||
|
|
@ -266,9 +279,42 @@ impl WaylandWindowingSystem {
|
||||||
&shared_serial,
|
&shared_serial,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let output_manager = Self::create_output_manager(&OutputManagerParams {
|
||||||
|
config,
|
||||||
|
global_ctx: &global_ctx,
|
||||||
|
connection,
|
||||||
|
layer_surface_config,
|
||||||
|
render_factory: &render_factory,
|
||||||
|
popup_context: &popup_context,
|
||||||
|
pointer: &pointer,
|
||||||
|
shared_serial: &shared_serial,
|
||||||
|
});
|
||||||
|
|
||||||
|
app_state.set_output_manager(Rc::new(RefCell::new(output_manager)));
|
||||||
|
|
||||||
Ok(app_state)
|
Ok(app_state)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_output_manager(params: &OutputManagerParams<'_>) -> OutputManager {
|
||||||
|
let manager_context = OutputManagerContext {
|
||||||
|
compositor: params.global_ctx.compositor.clone(),
|
||||||
|
layer_shell: params.global_ctx.layer_shell.clone(),
|
||||||
|
fractional_scale_manager: params.global_ctx.fractional_scale_manager.clone(),
|
||||||
|
viewporter: params.global_ctx.viewporter.clone(),
|
||||||
|
render_factory: Rc::clone(params.render_factory),
|
||||||
|
popup_context: params.popup_context.clone(),
|
||||||
|
pointer: Rc::clone(params.pointer),
|
||||||
|
shared_serial: Rc::clone(params.shared_serial),
|
||||||
|
connection: Rc::new(params.connection.clone()),
|
||||||
|
};
|
||||||
|
|
||||||
|
OutputManager::new(
|
||||||
|
manager_context,
|
||||||
|
params.config.clone(),
|
||||||
|
params.layer_surface_config,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fn setup_shared_popup_creator(
|
fn setup_shared_popup_creator(
|
||||||
popup_managers: Vec<Rc<PopupManager>>,
|
popup_managers: Vec<Rc<PopupManager>>,
|
||||||
layer_surfaces: Vec<Rc<ZwlrLayerSurfaceV1>>,
|
layer_surfaces: Vec<Rc<ZwlrLayerSurfaceV1>>,
|
||||||
|
|
@ -322,7 +368,7 @@ impl WaylandWindowingSystem {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_renderer(
|
pub(crate) fn initialize_renderer(
|
||||||
surface: &Rc<WlSurface>,
|
surface: &Rc<WlSurface>,
|
||||||
config: &WaylandWindowConfig,
|
config: &WaylandWindowConfig,
|
||||||
render_factory: &Rc<RenderContextFactory>,
|
render_factory: &Rc<RenderContextFactory>,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
use super::event_context::SharedPointerSerial;
|
use super::event_context::SharedPointerSerial;
|
||||||
use super::surface_state::WindowState;
|
use super::surface_state::WindowState;
|
||||||
use crate::wayland::managed_proxies::ManagedWlPointer;
|
use crate::wayland::managed_proxies::ManagedWlPointer;
|
||||||
use crate::wayland::outputs::OutputMapping;
|
use crate::wayland::outputs::{OutputManager, OutputMapping};
|
||||||
use layer_shika_domain::entities::output_registry::OutputRegistry;
|
use layer_shika_domain::entities::output_registry::OutputRegistry;
|
||||||
use layer_shika_domain::value_objects::output_handle::OutputHandle;
|
use layer_shika_domain::value_objects::output_handle::OutputHandle;
|
||||||
use layer_shika_domain::value_objects::output_info::OutputInfo;
|
use layer_shika_domain::value_objects::output_info::OutputInfo;
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use wayland_client::Proxy;
|
use wayland_client::Proxy;
|
||||||
|
|
@ -19,6 +20,8 @@ pub struct AppState {
|
||||||
surface_to_output: HashMap<ObjectId, OutputHandle>,
|
surface_to_output: HashMap<ObjectId, OutputHandle>,
|
||||||
_pointer: ManagedWlPointer,
|
_pointer: ManagedWlPointer,
|
||||||
shared_pointer_serial: Rc<SharedPointerSerial>,
|
shared_pointer_serial: Rc<SharedPointerSerial>,
|
||||||
|
output_manager: Option<Rc<RefCell<OutputManager>>>,
|
||||||
|
registry_name_to_output_id: HashMap<u32, ObjectId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl AppState {
|
impl AppState {
|
||||||
|
|
@ -30,9 +33,31 @@ impl AppState {
|
||||||
surface_to_output: HashMap::new(),
|
surface_to_output: HashMap::new(),
|
||||||
_pointer: pointer,
|
_pointer: pointer,
|
||||||
shared_pointer_serial: shared_serial,
|
shared_pointer_serial: shared_serial,
|
||||||
|
output_manager: None,
|
||||||
|
registry_name_to_output_id: HashMap::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn set_output_manager(&mut self, manager: Rc<RefCell<OutputManager>>) {
|
||||||
|
self.output_manager = Some(manager);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn output_manager(&self) -> Option<Rc<RefCell<OutputManager>>> {
|
||||||
|
self.output_manager.as_ref().map(Rc::clone)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn register_registry_name(&mut self, name: u32, output_id: ObjectId) {
|
||||||
|
self.registry_name_to_output_id.insert(name, output_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn find_output_id_by_registry_name(&self, name: u32) -> Option<ObjectId> {
|
||||||
|
self.registry_name_to_output_id.get(&name).cloned()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn unregister_registry_name(&mut self, name: u32) -> Option<ObjectId> {
|
||||||
|
self.registry_name_to_output_id.remove(&name)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn add_output(
|
pub fn add_output(
|
||||||
&mut self,
|
&mut self,
|
||||||
output_id: ObjectId,
|
output_id: ObjectId,
|
||||||
|
|
@ -51,6 +76,16 @@ impl AppState {
|
||||||
self.windows.insert(handle, window);
|
self.windows.insert(handle, window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn remove_output(&mut self, handle: OutputHandle) -> Option<PerOutputWindow> {
|
||||||
|
self.output_registry.remove(handle);
|
||||||
|
|
||||||
|
let window = self.windows.remove(&handle);
|
||||||
|
|
||||||
|
self.surface_to_output.retain(|_, h| *h != handle);
|
||||||
|
|
||||||
|
window
|
||||||
|
}
|
||||||
|
|
||||||
pub fn get_output_by_handle(&self, handle: OutputHandle) -> Option<&PerOutputWindow> {
|
pub fn get_output_by_handle(&self, handle: OutputHandle) -> Option<&PerOutputWindow> {
|
||||||
self.windows.get(&handle)
|
self.windows.get(&handle)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue