mirror of
https://codeberg.org/waydeer/layer-shika.git
synced 2025-12-23 11:25:54 +00:00
refactor: make outputs a first-class concept
This commit is contained in:
parent
8cd94cd13e
commit
e194682785
9 changed files with 187 additions and 53 deletions
|
|
@ -138,7 +138,7 @@ impl Dispatch<WlPointer, ()> for AppState {
|
|||
if let Some(window) = state.get_output_by_surface_mut(&surface_id) {
|
||||
window.handle_pointer_enter(serial, &surface, surface_x, surface_y);
|
||||
|
||||
if let Some(key) = state.get_key_by_surface(&surface_id).cloned() {
|
||||
if let Some(key) = state.get_key_by_surface(&surface_id) {
|
||||
state.set_active_output(Some(key));
|
||||
}
|
||||
} else {
|
||||
|
|
@ -158,7 +158,7 @@ impl Dispatch<WlPointer, ()> for AppState {
|
|||
surface_y,
|
||||
..
|
||||
} => {
|
||||
if let Some(output_key) = state.active_output().cloned() {
|
||||
if let Some(output_key) = state.active_output() {
|
||||
if let Some(window) = state.get_output_by_key_mut(&output_key) {
|
||||
window.handle_pointer_motion(surface_x, surface_y);
|
||||
}
|
||||
|
|
@ -166,7 +166,7 @@ impl Dispatch<WlPointer, ()> for AppState {
|
|||
}
|
||||
|
||||
wl_pointer::Event::Leave { .. } => {
|
||||
if let Some(output_key) = state.active_output().cloned() {
|
||||
if let Some(output_key) = state.active_output() {
|
||||
if let Some(window) = state.get_output_by_key_mut(&output_key) {
|
||||
window.handle_pointer_leave();
|
||||
}
|
||||
|
|
@ -179,7 +179,7 @@ impl Dispatch<WlPointer, ()> for AppState {
|
|||
state: button_state,
|
||||
..
|
||||
} => {
|
||||
if let Some(output_key) = state.active_output().cloned() {
|
||||
if let Some(output_key) = state.active_output() {
|
||||
if let Some(window) = state.get_output_by_key_mut(&output_key) {
|
||||
window.handle_pointer_button(serial, button_state);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,42 @@
|
|||
use layer_shika_domain::value_objects::output_handle::OutputHandle;
|
||||
use std::collections::hash_map::DefaultHasher;
|
||||
use std::hash::{Hash, Hasher};
|
||||
use wayland_client::backend::ObjectId;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct OutputKey(ObjectId);
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct OutputKey {
|
||||
handle: OutputHandle,
|
||||
_object_id_hash: u64,
|
||||
}
|
||||
|
||||
impl OutputKey {
|
||||
pub const fn new(id: ObjectId) -> Self {
|
||||
Self(id)
|
||||
pub fn new(object_id: &ObjectId) -> Self {
|
||||
let mut hasher = DefaultHasher::new();
|
||||
object_id.hash(&mut hasher);
|
||||
let object_id_hash = hasher.finish();
|
||||
|
||||
Self {
|
||||
handle: OutputHandle::new(),
|
||||
_object_id_hash: object_id_hash,
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn id(&self) -> &ObjectId {
|
||||
&self.0
|
||||
pub const fn handle(&self) -> OutputHandle {
|
||||
self.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ObjectId> for OutputKey {
|
||||
fn from(id: ObjectId) -> Self {
|
||||
Self::new(id)
|
||||
Self::new(&id)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<OutputHandle> for OutputKey {
|
||||
fn from(handle: OutputHandle) -> Self {
|
||||
Self {
|
||||
handle,
|
||||
_object_id_hash: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,21 +1,23 @@
|
|||
use super::surface_state::WindowState;
|
||||
use super::event_context::SharedPointerSerial;
|
||||
use super::surface_state::WindowState;
|
||||
use crate::wayland::managed_proxies::ManagedWlPointer;
|
||||
use crate::wayland::outputs::OutputKey;
|
||||
use layer_shika_domain::value_objects::output_handle::OutputHandle;
|
||||
use std::collections::HashMap;
|
||||
use std::rc::Rc;
|
||||
use wayland_client::backend::ObjectId;
|
||||
use wayland_client::Proxy;
|
||||
use wayland_client::backend::ObjectId;
|
||||
|
||||
pub type PerOutputWindow = WindowState;
|
||||
|
||||
pub struct AppState {
|
||||
outputs: HashMap<OutputKey, PerOutputWindow>,
|
||||
surface_to_output: HashMap<ObjectId, OutputKey>,
|
||||
output_to_key: HashMap<ObjectId, OutputKey>,
|
||||
outputs: HashMap<OutputHandle, PerOutputWindow>,
|
||||
surface_to_output: HashMap<ObjectId, OutputHandle>,
|
||||
output_to_handle: HashMap<ObjectId, OutputHandle>,
|
||||
_pointer: ManagedWlPointer,
|
||||
shared_pointer_serial: Rc<SharedPointerSerial>,
|
||||
active_output: Option<OutputKey>,
|
||||
active_output: Option<OutputHandle>,
|
||||
primary_output: Option<OutputHandle>,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
|
|
@ -23,10 +25,11 @@ impl AppState {
|
|||
Self {
|
||||
outputs: HashMap::new(),
|
||||
surface_to_output: HashMap::new(),
|
||||
output_to_key: HashMap::new(),
|
||||
output_to_handle: HashMap::new(),
|
||||
_pointer: pointer,
|
||||
shared_pointer_serial: shared_serial,
|
||||
active_output: None,
|
||||
primary_output: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -36,40 +39,56 @@ impl AppState {
|
|||
main_surface_id: ObjectId,
|
||||
window: PerOutputWindow,
|
||||
) {
|
||||
let key = OutputKey::new(output_id.clone());
|
||||
self.output_to_key.insert(output_id, key.clone());
|
||||
self.surface_to_output
|
||||
.insert(main_surface_id, key.clone());
|
||||
self.outputs.insert(key, window);
|
||||
let key = OutputKey::new(&output_id);
|
||||
let handle = key.handle();
|
||||
self.output_to_handle.insert(output_id, handle);
|
||||
self.surface_to_output.insert(main_surface_id, handle);
|
||||
|
||||
if self.primary_output.is_none() {
|
||||
self.primary_output = Some(handle);
|
||||
}
|
||||
|
||||
self.outputs.insert(handle, window);
|
||||
}
|
||||
|
||||
pub fn get_output_by_key(&self, key: &OutputKey) -> Option<&PerOutputWindow> {
|
||||
self.outputs.get(key)
|
||||
self.outputs.get(&key.handle())
|
||||
}
|
||||
|
||||
pub fn get_output_by_key_mut(&mut self, key: &OutputKey) -> Option<&mut PerOutputWindow> {
|
||||
self.outputs.get_mut(key)
|
||||
self.outputs.get_mut(&key.handle())
|
||||
}
|
||||
|
||||
pub fn get_output_by_handle(&self, handle: OutputHandle) -> Option<&PerOutputWindow> {
|
||||
self.outputs.get(&handle)
|
||||
}
|
||||
|
||||
pub fn get_output_by_handle_mut(
|
||||
&mut self,
|
||||
handle: OutputHandle,
|
||||
) -> Option<&mut PerOutputWindow> {
|
||||
self.outputs.get_mut(&handle)
|
||||
}
|
||||
|
||||
pub fn get_output_by_output_id(&self, output_id: &ObjectId) -> Option<&PerOutputWindow> {
|
||||
self.output_to_key
|
||||
self.output_to_handle
|
||||
.get(output_id)
|
||||
.and_then(|key| self.outputs.get(key))
|
||||
.and_then(|handle| self.outputs.get(handle))
|
||||
}
|
||||
|
||||
pub fn get_output_by_output_id_mut(
|
||||
&mut self,
|
||||
output_id: &ObjectId,
|
||||
) -> Option<&mut PerOutputWindow> {
|
||||
self.output_to_key
|
||||
self.output_to_handle
|
||||
.get(output_id)
|
||||
.and_then(|key| self.outputs.get_mut(key))
|
||||
.and_then(|handle| self.outputs.get_mut(handle))
|
||||
}
|
||||
|
||||
pub fn get_output_by_surface(&self, surface_id: &ObjectId) -> Option<&PerOutputWindow> {
|
||||
self.surface_to_output
|
||||
.get(surface_id)
|
||||
.and_then(|key| self.outputs.get(key))
|
||||
.and_then(|handle| self.outputs.get(handle))
|
||||
}
|
||||
|
||||
pub fn get_output_by_surface_mut(
|
||||
|
|
@ -78,40 +97,66 @@ impl AppState {
|
|||
) -> Option<&mut PerOutputWindow> {
|
||||
self.surface_to_output
|
||||
.get(surface_id)
|
||||
.and_then(|key| self.outputs.get_mut(key))
|
||||
.and_then(|handle| self.outputs.get_mut(handle))
|
||||
}
|
||||
|
||||
pub fn get_output_by_layer_surface_mut(
|
||||
&mut self,
|
||||
layer_surface_id: &ObjectId,
|
||||
) -> Option<&mut PerOutputWindow> {
|
||||
self.outputs.values_mut().find(|window| {
|
||||
window.layer_surface().as_ref().id() == *layer_surface_id
|
||||
})
|
||||
self.outputs
|
||||
.values_mut()
|
||||
.find(|window| window.layer_surface().as_ref().id() == *layer_surface_id)
|
||||
}
|
||||
|
||||
pub fn get_key_by_surface(&self, surface_id: &ObjectId) -> Option<&OutputKey> {
|
||||
self.surface_to_output.get(surface_id)
|
||||
pub fn get_key_by_surface(&self, surface_id: &ObjectId) -> Option<OutputKey> {
|
||||
self.surface_to_output
|
||||
.get(surface_id)
|
||||
.map(|&handle| OutputKey::from(handle))
|
||||
}
|
||||
|
||||
pub fn get_key_by_output_id(&self, output_id: &ObjectId) -> Option<&OutputKey> {
|
||||
self.output_to_key.get(output_id)
|
||||
pub fn get_key_by_output_id(&self, output_id: &ObjectId) -> Option<OutputKey> {
|
||||
self.output_to_handle
|
||||
.get(output_id)
|
||||
.map(|&handle| OutputKey::from(handle))
|
||||
}
|
||||
|
||||
pub fn get_handle_by_surface(&self, surface_id: &ObjectId) -> Option<OutputHandle> {
|
||||
self.surface_to_output.get(surface_id).copied()
|
||||
}
|
||||
|
||||
pub fn get_handle_by_output_id(&self, output_id: &ObjectId) -> Option<OutputHandle> {
|
||||
self.output_to_handle.get(output_id).copied()
|
||||
}
|
||||
|
||||
pub fn register_popup_surface(&mut self, popup_surface_id: ObjectId, output_key: OutputKey) {
|
||||
self.surface_to_output.insert(popup_surface_id, output_key);
|
||||
self.surface_to_output
|
||||
.insert(popup_surface_id, output_key.handle());
|
||||
}
|
||||
|
||||
pub fn set_active_output(&mut self, key: Option<OutputKey>) {
|
||||
self.active_output = key;
|
||||
self.active_output = key.map(|k| k.handle());
|
||||
}
|
||||
|
||||
pub const fn active_output(&self) -> Option<&OutputKey> {
|
||||
self.active_output.as_ref()
|
||||
pub fn set_active_output_handle(&mut self, handle: Option<OutputHandle>) {
|
||||
self.active_output = handle;
|
||||
}
|
||||
|
||||
pub fn active_output(&self) -> Option<OutputKey> {
|
||||
self.active_output.map(OutputKey::from)
|
||||
}
|
||||
|
||||
pub fn active_output_handle(&self) -> Option<OutputHandle> {
|
||||
self.active_output
|
||||
}
|
||||
|
||||
pub fn primary_output(&self) -> Option<&PerOutputWindow> {
|
||||
self.outputs.values().next()
|
||||
self.primary_output
|
||||
.and_then(|handle| self.outputs.get(&handle))
|
||||
}
|
||||
|
||||
pub fn primary_output_handle(&self) -> Option<OutputHandle> {
|
||||
self.primary_output
|
||||
}
|
||||
|
||||
pub fn all_outputs(&self) -> impl Iterator<Item = &PerOutputWindow> {
|
||||
|
|
@ -122,6 +167,12 @@ impl AppState {
|
|||
self.outputs.values_mut()
|
||||
}
|
||||
|
||||
pub fn outputs_with_handles(&self) -> impl Iterator<Item = (OutputHandle, &PerOutputWindow)> {
|
||||
self.outputs
|
||||
.iter()
|
||||
.map(|(&handle, window)| (handle, window))
|
||||
}
|
||||
|
||||
pub const fn shared_pointer_serial(&self) -> &Rc<SharedPointerSerial> {
|
||||
&self.shared_pointer_serial
|
||||
}
|
||||
|
|
@ -150,12 +201,22 @@ impl AppState {
|
|||
}
|
||||
|
||||
pub fn get_key_by_popup(&self, popup_surface_id: &ObjectId) -> Option<OutputKey> {
|
||||
self.outputs.iter().find_map(|(key, window)| {
|
||||
self.outputs.iter().find_map(|(&handle, window)| {
|
||||
window
|
||||
.popup_manager()
|
||||
.as_ref()
|
||||
.and_then(|pm| pm.find_by_surface(popup_surface_id))
|
||||
.map(|_| key.clone())
|
||||
.map(|_| OutputKey::from(handle))
|
||||
})
|
||||
}
|
||||
|
||||
pub fn get_handle_by_popup(&self, popup_surface_id: &ObjectId) -> Option<OutputHandle> {
|
||||
self.outputs.iter().find_map(|(&handle, window)| {
|
||||
window
|
||||
.popup_manager()
|
||||
.as_ref()
|
||||
.and_then(|pm| pm.find_by_surface(popup_surface_id))
|
||||
.map(|_| handle)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ pub use layer_shika_adapters::platform::{slint, slint_interpreter};
|
|||
pub use layer_shika_domain::value_objects::anchor::AnchorEdges;
|
||||
pub use layer_shika_domain::value_objects::keyboard_interactivity::KeyboardInteractivity;
|
||||
pub use layer_shika_domain::value_objects::layer::Layer;
|
||||
pub use layer_shika_domain::value_objects::output_handle::OutputHandle;
|
||||
pub use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||
pub use layer_shika_domain::value_objects::popup_request::{
|
||||
PopupAt, PopupHandle, PopupRequest, PopupSize,
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ use layer_shika_adapters::{
|
|||
};
|
||||
use layer_shika_domain::config::WindowConfig;
|
||||
use layer_shika_domain::errors::DomainError;
|
||||
use layer_shika_domain::value_objects::output_handle::OutputHandle;
|
||||
use layer_shika_domain::value_objects::popup_positioning_mode::PopupPositioningMode;
|
||||
use layer_shika_domain::value_objects::popup_request::{PopupHandle, PopupRequest, PopupSize};
|
||||
use std::cell::Cell;
|
||||
|
|
@ -139,10 +140,32 @@ impl RuntimeState<'_> {
|
|||
.map(WindowState::component_instance)
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn primary_output_handle(&self) -> Option<OutputHandle> {
|
||||
self.app_state.primary_output_handle()
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub fn active_output_handle(&self) -> Option<OutputHandle> {
|
||||
self.app_state.active_output_handle()
|
||||
}
|
||||
|
||||
pub fn outputs(&self) -> impl Iterator<Item = (OutputHandle, &ComponentInstance)> {
|
||||
self.app_state
|
||||
.outputs_with_handles()
|
||||
.map(|(handle, window)| (handle, window.component_instance()))
|
||||
}
|
||||
|
||||
pub fn get_output_component(&self, handle: OutputHandle) -> Option<&ComponentInstance> {
|
||||
self.app_state
|
||||
.get_output_by_handle(handle)
|
||||
.map(WindowState::component_instance)
|
||||
}
|
||||
|
||||
fn active_or_primary_output(&self) -> Option<&WindowState> {
|
||||
self.app_state
|
||||
.active_output()
|
||||
.and_then(|key| self.app_state.get_output_by_key(key))
|
||||
.and_then(|key| self.app_state.get_output_by_key(&key))
|
||||
.or_else(|| self.app_state.primary_output())
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ pub mod dimensions;
|
|||
pub mod keyboard_interactivity;
|
||||
pub mod layer;
|
||||
pub mod margins;
|
||||
pub mod output_handle;
|
||||
pub mod popup_config;
|
||||
pub mod popup_positioning_mode;
|
||||
pub mod popup_request;
|
||||
|
|
|
|||
26
crates/domain/src/value_objects/output_handle.rs
Normal file
26
crates/domain/src/value_objects/output_handle.rs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
|
||||
static NEXT_OUTPUT_ID: AtomicUsize = AtomicUsize::new(1);
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct OutputHandle {
|
||||
id: usize,
|
||||
}
|
||||
|
||||
impl OutputHandle {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
id: NEXT_OUTPUT_ID.fetch_add(1, Ordering::Relaxed),
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn id(&self) -> usize {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for OutputHandle {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
|
@ -44,9 +44,9 @@
|
|||
pub mod prelude;
|
||||
|
||||
pub use layer_shika_composition::{
|
||||
AnchorEdges, Error, EventLoopHandle, KeyboardInteractivity, Layer, LayerShika, PopupAt,
|
||||
PopupHandle, PopupPositioningMode, PopupRequest, PopupSize, PopupWindow, Result, RuntimeState,
|
||||
SlintCallbackContract, SlintCallbackNames, WindowingSystem,
|
||||
AnchorEdges, Error, EventLoopHandle, KeyboardInteractivity, Layer, LayerShika, OutputHandle,
|
||||
PopupAt, PopupHandle, PopupPositioningMode, PopupRequest, PopupSize, PopupWindow, Result,
|
||||
RuntimeState, SlintCallbackContract, SlintCallbackNames, WindowingSystem,
|
||||
};
|
||||
|
||||
pub use layer_shika_composition::{slint, slint_interpreter};
|
||||
|
|
|
|||
|
|
@ -10,14 +10,14 @@
|
|||
|
||||
// Core API types
|
||||
pub use crate::{
|
||||
Error, EventLoopHandle, LayerShika, PopupWindow, Result, RuntimeState,
|
||||
SlintCallbackContract, SlintCallbackNames, WindowingSystem,
|
||||
Error, EventLoopHandle, LayerShika, PopupWindow, Result, RuntimeState, SlintCallbackContract,
|
||||
SlintCallbackNames, WindowingSystem,
|
||||
};
|
||||
|
||||
// Domain value objects
|
||||
pub use crate::{
|
||||
AnchorEdges, KeyboardInteractivity, Layer, PopupAt, PopupHandle, PopupPositioningMode,
|
||||
PopupRequest, PopupSize,
|
||||
AnchorEdges, KeyboardInteractivity, Layer, OutputHandle, PopupAt, PopupHandle,
|
||||
PopupPositioningMode, PopupRequest, PopupSize,
|
||||
};
|
||||
|
||||
// Event loop types
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue