Skip to content

Commit

Permalink
feat: overlap notify events
Browse files Browse the repository at this point in the history
  • Loading branch information
wash2 committed Nov 24, 2024
1 parent 4802059 commit 4102aec
Show file tree
Hide file tree
Showing 11 changed files with 427 additions and 46 deletions.
4 changes: 4 additions & 0 deletions core/src/event/wayland/mod.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
mod layer;
mod output;
mod overlap_notify;
mod popup;
mod seat;
mod session_lock;
Expand All @@ -12,6 +13,7 @@ use cctk::sctk::reexports::client::protocol::{

pub use layer::*;
pub use output::*;
pub use overlap_notify::*;
pub use popup::*;
pub use seat::*;
pub use session_lock::*;
Expand All @@ -26,6 +28,8 @@ pub enum Event {
Popup(PopupEvent, WlSurface, Id),
/// output event
Output(OutputEvent, WlOutput),
/// Overlap notify event
OverlapNotify(overlap_notify::OverlapNotifyEvent),
/// window event
Window(WindowEvent),
/// Seat Event
Expand Down
21 changes: 21 additions & 0 deletions core/src/event/wayland/overlap_notify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
use cctk::{sctk::shell::wlr_layer::Layer, wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1};

#[derive(Debug, Clone, PartialEq)]
pub enum OverlapNotifyEvent {
OverlapToplevelAdd {
toplevel: ExtForeignToplevelHandleV1,
logical_rect: crate::Rectangle,
},
OverlapToplevelRemove {
toplevel: ExtForeignToplevelHandleV1,
},
OverlapLayerAdd {
identifier: String,
exclusive: u32,
layer: Option<Layer>,
logical_rect: crate::Rectangle,
},
OverlapLayerRemove {
identifier: String,
},
}
15 changes: 11 additions & 4 deletions runtime/src/platform_specific/wayland/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
use std::fmt::Debug;

use iced_core::window::Id;

/// activation Actions
pub mod activation;

Expand All @@ -22,21 +24,26 @@ pub enum Action {
Activation(activation::Action),
/// session lock
SessionLock(session_lock::Action),
/// Overlap Notify
OverlapNotify(Id, bool),
}

impl Debug for Action {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Self::LayerSurface(arg0) => {
Action::LayerSurface(arg0) => {
f.debug_tuple("LayerSurface").field(arg0).finish()
}
Self::Popup(arg0) => f.debug_tuple("Popup").field(arg0).finish(),
Self::Activation(arg0) => {
Action::Popup(arg0) => f.debug_tuple("Popup").field(arg0).finish(),
Action::Activation(arg0) => {
f.debug_tuple("Activation").field(arg0).finish()
}
Self::SessionLock(arg0) => {
Action::SessionLock(arg0) => {
f.debug_tuple("SessionLock").field(arg0).finish()
}
Action::OverlapNotify(id, _) => {
f.debug_tuple("OverlapNotify").field(id).finish()
}
}
}
}
1 change: 1 addition & 0 deletions winit/src/platform_specific/wayland/commands/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
pub mod activation;
pub mod layer_surface;
pub mod overlap_notify;
pub mod popup;
pub mod session_lock;
14 changes: 14 additions & 0 deletions winit/src/platform_specific/wayland/commands/overlap_notify.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
use iced_futures::core::window::Id;
use iced_runtime::{
platform_specific::{self, wayland},
task, Action, Task,
};

/// Request subscription for overlap notification events on the surface
pub fn overlap_notify<Message>(id: Id, enable: bool) -> Task<Message> {
task::effect(Action::PlatformSpecific(
platform_specific::Action::Wayland(wayland::Action::OverlapNotify(
id, enable,
)),
))
}
5 changes: 4 additions & 1 deletion winit/src/platform_specific/wayland/event_loop/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub mod state;
use crate::platform_specific::SurfaceIdWrapper;
use crate::{
futures::futures::channel::mpsc,
handlers::overlap::OverlapNotifyV1,
platform_specific::wayland::{
handlers::{
wp_fractional_scaling::FractionalScalingManager,
Expand All @@ -17,7 +18,6 @@ use crate::{
subsurface_widget::SubsurfaceState,
};

use raw_window_handle::HasDisplayHandle;
use cctk::sctk::reexports::calloop_wayland_source::WaylandSource;
use cctk::sctk::{
activation::ActivationState,
Expand All @@ -36,6 +36,7 @@ use cctk::sctk::{
shell::{wlr_layer::LayerShell, xdg::XdgShell, WaylandSurface},
shm::Shm,
};
use raw_window_handle::HasDisplayHandle;
use state::{FrameStatus, SctkWindow};
#[cfg(feature = "a11y")]
use std::sync::{Arc, Mutex};
Expand Down Expand Up @@ -201,6 +202,7 @@ impl SctkEventLoop {
activation_state: ActivationState::bind(&globals, &qh).ok(),
session_lock_state: SessionLockState::new(&globals, &qh),
session_lock: None,
overlap_notify: OverlapNotifyV1::bind(&globals, &qh).ok(),

queue_handle: qh,
loop_handle,
Expand Down Expand Up @@ -228,6 +230,7 @@ impl SctkEventLoop {
pending_popup: Default::default(),
activation_token_ctr: 0,
token_senders: HashMap::new(),
overlap_notifications: HashMap::new(),
},
_features: Default::default(),
};
Expand Down
63 changes: 47 additions & 16 deletions winit/src/platform_specific/wayland/event_loop/state.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::{
handlers::activation::IcedRequestData,
handlers::{
activation::IcedRequestData,
overlap::{OverlapNotificationV1, OverlapNotifyV1},
},
platform_specific::{
wayland::{
handlers::{
Expand Down Expand Up @@ -27,22 +30,11 @@ use winit::{
platform::wayland::WindowExtWayland,
};

use iced_runtime::{
core::{self, touch, Point},
keyboard::Modifiers,
platform_specific::{
self,
wayland::{
layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings},
popup::SctkPopupSettings,
Action,
},
},
};
use cctk::sctk::{
use cctk::{cosmic_protocols::overlap_notify::v1::client::zcosmic_overlap_notification_v1::ZcosmicOverlapNotificationV1, sctk::{
activation::{ActivationState, RequestData},
compositor::CompositorState,
error::GlobalError,
globals::GlobalData,
output::OutputState,
reexports::{
calloop::{timer::TimeoutAction, LoopHandle},
Expand Down Expand Up @@ -74,7 +66,7 @@ use cctk::sctk::{
shell::{
wlr_layer::{
Anchor, KeyboardInteractivity, Layer, LayerShell, LayerSurface,
LayerSurfaceConfigure,
LayerSurfaceConfigure, SurfaceKind,
},
xdg::{
popup::{Popup, PopupConfigure},
Expand All @@ -83,6 +75,18 @@ use cctk::sctk::{
WaylandSurface,
},
shm::{multi::MultiPool, Shm},
}};
use iced_runtime::{
core::{self, touch, Point},
keyboard::Modifiers,
platform_specific::{
self,
wayland::{
layer_surface::{IcedMargin, IcedOutput, SctkLayerSurfaceSettings},
popup::SctkPopupSettings,
Action,
},
},
};
use wayland_protocols::{
wp::{
Expand Down Expand Up @@ -326,7 +330,11 @@ pub struct SctkState {
/// a memory pool
pub(crate) _multipool: Option<MultiPool<WlSurface>>,

// all present outputs
/// all notification objects
pub(crate) overlap_notifications:
HashMap<ObjectId, ZcosmicOverlapNotificationV1>,

/// all present outputs
pub(crate) outputs: Vec<WlOutput>,
// though (for now) only one seat will be active in an iced application at a time, all ought to be tracked
// Active seat is the first seat in the list
Expand Down Expand Up @@ -379,6 +387,7 @@ pub struct SctkState {
pub(crate) to_commit: HashMap<core::window::Id, WlSurface>,
pub(crate) destroyed: HashSet<core::window::Id>,
pub(crate) pending_popup: Option<(SctkPopupSettings, usize)>,
pub(crate) overlap_notify: Option<OverlapNotifyV1>,

pub(crate) activation_token_ctr: u32,
pub(crate) token_senders: HashMap<u32, oneshot::Sender<Option<String>>>,
Expand Down Expand Up @@ -1176,6 +1185,28 @@ impl SctkState {
}
}
}
Action::OverlapNotify(id, enabled) => {
if let Some(layer_surface) = self.layer_surfaces.iter_mut().find(|l| l.id == id) {
let Some(overlap_notify_state) = self.overlap_notify.as_ref() else {
tracing::error!("Overlap notify is not supported.");
return Ok(());
};
let my_id = layer_surface.surface.wl_surface().id();

if enabled && !self.overlap_notifications.contains_key(&my_id) {
let SurfaceKind::Wlr(wlr) = &layer_surface.surface.kind() else {
tracing::error!("Overlap notify is not supported for non wlr surface.");
return Ok(());
};
let notification = overlap_notify_state.notify.notify_on_overlap(wlr, &self.queue_handle, GlobalData);
_ = self.overlap_notifications.insert(my_id, notification);
} else {
_ = self.overlap_notifications.remove(&my_id);
}
} else {
tracing::error!("Overlap notify subscription cannot be created for surface. No matching layer surface found.");
}
},
};
Ok(())
}
Expand Down
3 changes: 2 additions & 1 deletion winit/src/platform_specific/wayland/handlers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@
pub mod activation;
pub mod compositor;
pub mod output;
// pub mod overlap;
pub mod overlap;
pub mod seat;
pub mod session_lock;
pub mod shell;
pub mod subcompositor;
pub mod toplevel;
pub mod wp_fractional_scaling;
pub mod wp_viewporter;

Expand Down
122 changes: 122 additions & 0 deletions winit/src/platform_specific/wayland/handlers/overlap.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
use cctk::{
cosmic_protocols::overlap_notify::v1::client::{
zcosmic_overlap_notification_v1::{self, ZcosmicOverlapNotificationV1},
zcosmic_overlap_notify_v1::ZcosmicOverlapNotifyV1,
}, sctk::shell::wlr_layer::Layer, wayland_client::{
self, event_created_child,
globals::{BindError, GlobalList},
protocol::wl_surface::WlSurface,
Connection, Dispatch, Proxy, QueueHandle,
}, wayland_protocols::ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1
};
use cctk::sctk::globals::GlobalData;
use iced_futures::core::Rectangle;

use crate::{event_loop::state::SctkState, sctk_event::SctkEvent};

#[derive(Debug, Clone)]
pub struct OverlapNotifyV1 {
pub(crate) notify: ZcosmicOverlapNotifyV1,
}

impl OverlapNotifyV1 {
pub fn bind(
globals: &GlobalList,
qh: &QueueHandle<SctkState>,
) -> Result<OverlapNotifyV1, BindError> {
let notify = globals.bind(qh, 1..=1, GlobalData)?;
Ok(OverlapNotifyV1 { notify })
}
}

impl Dispatch<ZcosmicOverlapNotifyV1, GlobalData, SctkState>
for OverlapNotifyV1
{
fn event(
_: &mut SctkState,
_: &ZcosmicOverlapNotifyV1,
_: <ZcosmicOverlapNotifyV1 as Proxy>::Event,
_: &GlobalData,
_: &Connection,
_: &QueueHandle<SctkState>,
) {
}
}

pub struct OverlapNotificationV1 {
surface: WlSurface,
}

impl Dispatch<ZcosmicOverlapNotificationV1, GlobalData, SctkState>
for OverlapNotificationV1
{
fn event(
state: &mut SctkState,
n: &ZcosmicOverlapNotificationV1,
event: <ZcosmicOverlapNotificationV1 as Proxy>::Event,
_: &GlobalData,
_: &Connection,
_: &QueueHandle<SctkState>,
) {
let data: Option<&OverlapNotificationV1> = n.data();
let Some(data) = data else {
return;
};

let surface = data.surface.clone();

state.sctk_events.push(match event {
zcosmic_overlap_notification_v1::Event::ToplevelEnter {
toplevel,
x,
y,
width,
height,
} => SctkEvent::OverlapToplevelAdd {
surface,
toplevel,
logical_rect: Rectangle::new(
(x as f32, y as f32).into(),
(width as f32, height as f32).into(),
),
},
zcosmic_overlap_notification_v1::Event::ToplevelLeave {
toplevel,
} => {
SctkEvent::OverlapToplevelRemove { surface, toplevel }
}
zcosmic_overlap_notification_v1::Event::LayerEnter {
identifier,
exclusive,
layer,
x,
y,
width,
height,
} => SctkEvent::OverlapLayerAdd { surface, identifier, exclusive, layer: match layer {
wayland_client::WEnum::Value(v) => match v {
cctk::sctk::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::Layer::Background => Some(Layer::Background),
cctk::sctk::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::Layer::Bottom => Some(Layer::Bottom),
cctk::sctk::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::Layer::Top => Some(Layer::Top),
cctk::sctk::reexports::protocols_wlr::layer_shell::v1::client::zwlr_layer_shell_v1::Layer::Overlay => Some(Layer::Overlay),
_ => Default::default(),
},
wayland_client::WEnum::Unknown(_) => Default::default(),
}, logical_rect: Rectangle::new(
(x as f32, y as f32).into(),
(width as f32, height as f32).into(),
), },
zcosmic_overlap_notification_v1::Event::LayerLeave {
identifier,
} => SctkEvent::OverlapLayerRemove { identifier, surface },
_ => unimplemented!(),
});
}

event_created_child!(SctkState, ZcosmicOverlapNotifyV1, [
0 => (ExtForeignToplevelHandleV1, Default::default())
]);
}

wayland_client::delegate_dispatch!(SctkState: [ZcosmicOverlapNotifyV1: GlobalData] => OverlapNotifyV1);
wayland_client::delegate_dispatch!(SctkState: [ZcosmicOverlapNotificationV1: GlobalData] => OverlapNotificationV1);
Loading

0 comments on commit 4102aec

Please sign in to comment.