Ideally pointer should be seperate from touch, but this should match how
Iced handles input in normal winit windows.
d475ae5b45/winit/src/window/state.rs (L165-L170)
With this, touch input for applets seems to work as expected in general.
1721 lines
69 KiB
Rust
Executable file
1721 lines
69 KiB
Rust
Executable file
use crate::{
|
|
Clipboard, Control, Program,
|
|
platform_specific::{
|
|
SurfaceIdWrapper, UserInterfaces,
|
|
wayland::{
|
|
conversion::{
|
|
modifiers_to_native, pointer_axis_to_native,
|
|
pointer_button_to_native,
|
|
},
|
|
keymap::{self, keysym_to_key},
|
|
subsurface_widget::SubsurfaceState,
|
|
},
|
|
},
|
|
};
|
|
|
|
use dnd::DndSurface;
|
|
use iced_debug::core::theme;
|
|
use iced_futures::{
|
|
core::{
|
|
Clipboard as _, Clipboard as _, Size,
|
|
event::{
|
|
PlatformSpecific,
|
|
wayland::{
|
|
LayerEvent, OverlapNotifyEvent, PopupEvent, SessionLockEvent,
|
|
},
|
|
},
|
|
},
|
|
event,
|
|
futures::channel::mpsc,
|
|
};
|
|
use iced_graphics::{Compositor, compositor};
|
|
use iced_runtime::{
|
|
core::{
|
|
Point,
|
|
event::wayland,
|
|
keyboard, mouse, touch,
|
|
window::{self, Id as SurfaceId},
|
|
},
|
|
keyboard::{Key, Location, key},
|
|
user_interface,
|
|
};
|
|
|
|
use cctk::{
|
|
cosmic_protocols::overlap_notify::v1::client::zcosmic_overlap_notification_v1,
|
|
sctk::{
|
|
output::OutputInfo,
|
|
reexports::{
|
|
calloop::channel,
|
|
client::{
|
|
Proxy, QueueHandle,
|
|
backend::ObjectId,
|
|
protocol::{
|
|
wl_display::WlDisplay, wl_keyboard::WlKeyboard,
|
|
wl_output::WlOutput, wl_pointer::WlPointer,
|
|
wl_seat::WlSeat, wl_surface::WlSurface, wl_touch::WlTouch,
|
|
},
|
|
},
|
|
csd_frame::WindowManagerCapabilities,
|
|
},
|
|
seat::{
|
|
Capability,
|
|
keyboard::{KeyEvent, Modifiers},
|
|
pointer::{PointerEvent, PointerEventKind},
|
|
},
|
|
session_lock::SessionLockSurfaceConfigure,
|
|
shell::{
|
|
wlr_layer::{Layer, LayerSurfaceConfigure},
|
|
xdg::{popup::PopupConfigure, window::WindowConfigure},
|
|
},
|
|
},
|
|
wayland_client::protocol::wl_subsurface::WlSubsurface,
|
|
};
|
|
use std::{
|
|
any::Any,
|
|
collections::HashMap,
|
|
num::NonZeroU32,
|
|
sync::{Arc, Mutex},
|
|
};
|
|
use wayland_protocols::{
|
|
ext::foreign_toplevel_list::v1::client::ext_foreign_toplevel_handle_v1::ExtForeignToplevelHandleV1,
|
|
wp::viewporter::client::wp_viewport::WpViewport,
|
|
};
|
|
use winit::{
|
|
dpi::{self, PhysicalSize},
|
|
event::WindowEvent,
|
|
event_loop::EventLoopProxy,
|
|
window::WindowId,
|
|
};
|
|
use xkeysym::Keysym;
|
|
|
|
use super::{
|
|
SubsurfaceInstance,
|
|
event_loop::state::{Common, CommonSurface, SctkState},
|
|
keymap::raw_keycode_to_physicalkey,
|
|
subsurface_widget::remove_iced_subsurface,
|
|
winit_window::SctkWinitWindow,
|
|
};
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum SctkEvent {
|
|
//
|
|
// Input events
|
|
//
|
|
SeatEvent {
|
|
variant: SeatEventVariant,
|
|
id: WlSeat,
|
|
},
|
|
PointerEvent {
|
|
variant: PointerEvent,
|
|
ptr_id: WlPointer,
|
|
seat_id: WlSeat,
|
|
},
|
|
KeyboardEvent {
|
|
variant: KeyboardEventVariant,
|
|
kbd_id: WlKeyboard,
|
|
seat_id: WlSeat,
|
|
surface: WlSurface,
|
|
},
|
|
TouchEvent {
|
|
variant: touch::Event,
|
|
touch_id: WlTouch,
|
|
seat_id: WlSeat,
|
|
surface: WlSurface,
|
|
},
|
|
// TODO data device & touch
|
|
|
|
//
|
|
// Surface Events
|
|
//
|
|
WindowEvent {
|
|
variant: WindowEventVariant,
|
|
id: WlSurface,
|
|
},
|
|
LayerSurfaceEvent {
|
|
variant: LayerSurfaceEventVariant,
|
|
id: WlSurface,
|
|
},
|
|
OverlapToplevelAdd {
|
|
surface: WlSurface,
|
|
toplevel: ExtForeignToplevelHandleV1,
|
|
logical_rect: iced_runtime::core::Rectangle,
|
|
},
|
|
OverlapToplevelRemove {
|
|
surface: WlSurface,
|
|
toplevel: ExtForeignToplevelHandleV1,
|
|
},
|
|
OverlapLayerAdd {
|
|
surface: WlSurface,
|
|
namespace: String,
|
|
identifier: String,
|
|
exclusive: u32,
|
|
layer: Option<Layer>,
|
|
logical_rect: iced_runtime::core::Rectangle,
|
|
},
|
|
OverlapLayerRemove {
|
|
surface: WlSurface,
|
|
identifier: String,
|
|
},
|
|
PopupEvent {
|
|
variant: PopupEventVariant,
|
|
/// this may be the Id of a window or layer surface
|
|
toplevel_id: WlSurface,
|
|
/// this may be any SurfaceId
|
|
parent_id: WlSurface,
|
|
/// the id of this popup
|
|
id: WlSurface,
|
|
},
|
|
|
|
SubsurfaceEvent(SubsurfaceEventVariant),
|
|
|
|
//
|
|
// output events
|
|
//
|
|
NewOutput {
|
|
id: WlOutput,
|
|
info: Option<OutputInfo>,
|
|
},
|
|
UpdateOutput {
|
|
id: WlOutput,
|
|
info: OutputInfo,
|
|
},
|
|
RemovedOutput(WlOutput),
|
|
//
|
|
// compositor events
|
|
//
|
|
ScaleFactorChanged {
|
|
factor: f64,
|
|
id: WlOutput,
|
|
inner_size: winit::dpi::PhysicalSize<u32>,
|
|
},
|
|
|
|
/// session lock events
|
|
SessionLocked,
|
|
SessionLockFinished,
|
|
SessionLockSurfaceCreated {
|
|
queue_handle: QueueHandle<SctkState>,
|
|
surface: CommonSurface,
|
|
native_id: SurfaceId,
|
|
common: Arc<Mutex<Common>>,
|
|
display: WlDisplay,
|
|
},
|
|
SessionLockSurfaceConfigure {
|
|
surface: WlSurface,
|
|
configure: SessionLockSurfaceConfigure,
|
|
first: bool,
|
|
},
|
|
SessionLockSurfaceDone {
|
|
surface: WlSurface,
|
|
},
|
|
SessionUnlocked,
|
|
SurfaceScaleFactorChanged(f64, WlSurface, window::Id),
|
|
Winit(WindowId, WindowEvent),
|
|
Subcompositor(SubsurfaceState),
|
|
}
|
|
|
|
#[cfg(feature = "a11y")]
|
|
#[derive(Debug, Clone)]
|
|
pub struct ActionRequestEvent {
|
|
pub surface_id: ObjectId,
|
|
pub request: iced_accessibility::accesskit::ActionRequest,
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum SeatEventVariant {
|
|
New,
|
|
Remove,
|
|
NewCapability(Capability, ObjectId),
|
|
RemoveCapability(Capability, ObjectId),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum KeyboardEventVariant {
|
|
Leave(WlSurface),
|
|
Enter(WlSurface),
|
|
Press(KeyEvent),
|
|
Repeat(KeyEvent),
|
|
Release(KeyEvent),
|
|
Modifiers(Modifiers),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum WindowEventVariant {
|
|
Created(WlSurface, SurfaceId),
|
|
/// <https://wayland.app/protocols/xdg-shell#xdg_toplevel:event:close>
|
|
Close,
|
|
/// <https://wayland.app/protocols/xdg-shell#xdg_toplevel:event:wm_capabilities>
|
|
WmCapabilities(WindowManagerCapabilities),
|
|
/// <https://wayland.app/protocols/xdg-shell#xdg_toplevel:event:configure_bounds>
|
|
ConfigureBounds {
|
|
width: u32,
|
|
height: u32,
|
|
},
|
|
/// <https://wayland.app/protocols/xdg-shell#xdg_toplevel:event:configure>
|
|
Configure((NonZeroU32, NonZeroU32), WindowConfigure, WlSurface, bool),
|
|
Size((NonZeroU32, NonZeroU32), WlSurface, bool),
|
|
/// window state changed
|
|
StateChanged(cctk::sctk::reexports::csd_frame::WindowState),
|
|
/// Scale Factor
|
|
ScaleFactorChanged(f64, Option<WpViewport>),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum PopupEventVariant {
|
|
/// Popup Created
|
|
Created(
|
|
QueueHandle<SctkState>,
|
|
CommonSurface,
|
|
SurfaceId,
|
|
Arc<Mutex<Common>>,
|
|
WlDisplay,
|
|
),
|
|
/// <https://wayland.app/protocols/xdg-shell#xdg_popup:event:popup_done>
|
|
Done,
|
|
/// <https://wayland.app/protocols/xdg-shell#xdg_popup:event:configure>
|
|
Configure(PopupConfigure, WlSurface, bool),
|
|
/// <https://wayland.app/protocols/xdg-shell#xdg_popup:event:repositioned>
|
|
RepositionionedPopup { token: u32 },
|
|
/// size
|
|
Size(u32, u32),
|
|
/// Scale Factor
|
|
ScaleFactorChanged(f64, Option<WpViewport>),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum SubsurfaceEventVariant {
|
|
/// Popup Created
|
|
Created {
|
|
parent_id: window::Id,
|
|
parent: WlSurface,
|
|
surface: WlSurface,
|
|
qh: QueueHandle<SctkState>,
|
|
common_surface: CommonSurface,
|
|
surface_id: SurfaceId,
|
|
common: Arc<Mutex<Common>>,
|
|
display: WlDisplay,
|
|
z: i32,
|
|
},
|
|
/// Destroyed
|
|
Destroyed(SubsurfaceInstance),
|
|
/// Resized
|
|
Resized(SurfaceId, dpi::Size),
|
|
}
|
|
|
|
#[derive(Debug, Clone)]
|
|
pub enum LayerSurfaceEventVariant {
|
|
/// sent after creation of the layer surface
|
|
Created(
|
|
QueueHandle<SctkState>,
|
|
CommonSurface,
|
|
SurfaceId,
|
|
Arc<Mutex<Common>>,
|
|
WlDisplay,
|
|
String,
|
|
),
|
|
/// <https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1:event:closed>
|
|
Done,
|
|
/// <https://wayland.app/protocols/wlr-layer-shell-unstable-v1#zwlr_layer_surface_v1:event:configure>
|
|
Configure(LayerSurfaceConfigure, WlSurface, bool),
|
|
/// Scale Factor
|
|
ScaleFactorChanged(f64, Option<WpViewport>),
|
|
}
|
|
|
|
/// Pending update to a window requested by the user.
|
|
#[derive(Default, Debug, Clone, Copy)]
|
|
pub struct SurfaceUserRequest {
|
|
/// Whether `redraw` was requested.
|
|
pub redraw_requested: bool,
|
|
|
|
/// Wether the frame should be refreshed.
|
|
pub refresh_frame: bool,
|
|
}
|
|
|
|
// The window update coming from the compositor.
|
|
#[derive(Default, Debug, Clone)]
|
|
pub struct SurfaceCompositorUpdate {
|
|
/// New window configure.
|
|
pub configure: Option<WindowConfigure>,
|
|
|
|
/// New scale factor.
|
|
pub scale_factor: Option<i32>,
|
|
}
|
|
|
|
impl SctkEvent {
|
|
pub(crate) fn process<'a, P>(
|
|
self,
|
|
modifiers: &mut Modifiers,
|
|
program: &'a crate::program::Instance<P>,
|
|
compositor: &mut <<P as Program>::Renderer as compositor::Default>::Compositor,
|
|
window_manager: &mut crate::WindowManager<
|
|
P,
|
|
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
|
>,
|
|
surface_ids: &mut HashMap<ObjectId, SurfaceIdWrapper>,
|
|
sctk_tx: &channel::Sender<super::Action>,
|
|
control_sender: &mpsc::UnboundedSender<Control>,
|
|
proxy: &EventLoopProxy,
|
|
user_interfaces: &mut UserInterfaces<'a, P>,
|
|
events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
|
|
clipboard: &mut Clipboard,
|
|
subsurface_state: &mut Option<SubsurfaceState>,
|
|
#[cfg(feature = "a11y")] adapters: &mut HashMap<
|
|
window::Id,
|
|
(u64, iced_accessibility::accesskit_winit::Adapter),
|
|
>,
|
|
) where
|
|
P: Program,
|
|
{
|
|
match self {
|
|
// TODO Ashley: Platform specific multi-seat events?
|
|
SctkEvent::SeatEvent { .. } => Default::default(),
|
|
SctkEvent::PointerEvent { variant, .. } => match variant.kind {
|
|
PointerEventKind::Enter { .. } => {
|
|
let id = surface_ids
|
|
.get(&variant.surface.id())
|
|
.map(|id| id.inner());
|
|
if let Some(w) =
|
|
id.clone().and_then(|id| window_manager.get_mut(id))
|
|
{
|
|
w.state.set_logical_cursor_pos(
|
|
(variant.position.0, variant.position.1).into(),
|
|
)
|
|
}
|
|
events.push((
|
|
id,
|
|
iced_runtime::core::Event::Mouse(
|
|
mouse::Event::CursorMoved {
|
|
position: Point::new(
|
|
variant.position.0 as f32,
|
|
variant.position.1 as f32,
|
|
),
|
|
},
|
|
),
|
|
));
|
|
}
|
|
PointerEventKind::Leave { .. } => events.push((
|
|
surface_ids.get(&variant.surface.id()).map(|id| id.inner()),
|
|
iced_runtime::core::Event::Mouse(mouse::Event::CursorLeft),
|
|
)),
|
|
PointerEventKind::Motion { .. } => {
|
|
let id = surface_ids
|
|
.get(&variant.surface.id())
|
|
.map(|id| id.inner());
|
|
if let Some(w) =
|
|
id.clone().and_then(|id| window_manager.get_mut(id))
|
|
{
|
|
w.state.set_logical_cursor_pos(
|
|
(variant.position.0, variant.position.1).into(),
|
|
)
|
|
}
|
|
events.push((
|
|
id,
|
|
iced_runtime::core::Event::Mouse(
|
|
mouse::Event::CursorMoved {
|
|
position: Point::new(
|
|
variant.position.0 as f32,
|
|
variant.position.1 as f32,
|
|
),
|
|
},
|
|
),
|
|
));
|
|
}
|
|
PointerEventKind::Press {
|
|
time: _,
|
|
button,
|
|
serial: _,
|
|
} => {
|
|
if let Some(e) = pointer_button_to_native(button).map(|b| {
|
|
iced_runtime::core::Event::Mouse(
|
|
mouse::Event::ButtonPressed(b),
|
|
)
|
|
}) {
|
|
events.push((
|
|
surface_ids
|
|
.get(&variant.surface.id())
|
|
.map(|id| id.inner()),
|
|
e,
|
|
));
|
|
}
|
|
} // TODO Ashley: conversion
|
|
PointerEventKind::Release {
|
|
time: _,
|
|
button,
|
|
serial: _,
|
|
} => {
|
|
if let Some(e) = pointer_button_to_native(button).map(|b| {
|
|
iced_runtime::core::Event::Mouse(
|
|
mouse::Event::ButtonReleased(b),
|
|
)
|
|
}) {
|
|
events.push((
|
|
surface_ids
|
|
.get(&variant.surface.id())
|
|
.map(|id| id.inner()),
|
|
e,
|
|
));
|
|
}
|
|
} // TODO Ashley: conversion
|
|
PointerEventKind::Axis {
|
|
time: _,
|
|
horizontal,
|
|
vertical,
|
|
source,
|
|
} => {
|
|
if let Some(e) =
|
|
pointer_axis_to_native(source, horizontal, vertical)
|
|
.map(|a| {
|
|
iced_runtime::core::Event::Mouse(
|
|
mouse::Event::WheelScrolled { delta: a },
|
|
)
|
|
})
|
|
{
|
|
events.push((
|
|
surface_ids
|
|
.get(&variant.surface.id())
|
|
.map(|id| id.inner()),
|
|
e,
|
|
));
|
|
}
|
|
} // TODO Ashley: conversion
|
|
},
|
|
SctkEvent::KeyboardEvent {
|
|
variant,
|
|
kbd_id: _,
|
|
seat_id,
|
|
surface,
|
|
} => match variant {
|
|
KeyboardEventVariant::Leave(surface) => {
|
|
if let Some(e) =
|
|
surface_ids.get(&surface.id()).and_then(|id| match id {
|
|
SurfaceIdWrapper::LayerSurface(_id) => Some(
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::Layer(
|
|
LayerEvent::Unfocused,
|
|
surface.clone(),
|
|
id.inner(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SurfaceIdWrapper::Window(id) => {
|
|
Some(iced_runtime::core::Event::Window(
|
|
window::Event::Unfocused,
|
|
))
|
|
}
|
|
SurfaceIdWrapper::Popup(_id) => Some(
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::Popup(
|
|
PopupEvent::Unfocused,
|
|
surface.clone(),
|
|
id.inner(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SurfaceIdWrapper::SessionLock(_) => Some(
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::SessionLock(
|
|
SessionLockEvent::Unfocused(
|
|
surface.clone(),
|
|
id.inner(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SurfaceIdWrapper::Subsurface(id) => None,
|
|
})
|
|
{
|
|
events.push((
|
|
surface_ids.get(&surface.id()).map(|id| id.inner()),
|
|
e,
|
|
));
|
|
}
|
|
|
|
events.push((
|
|
surface_ids.get(&surface.id()).map(|id| id.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(wayland::Event::Seat(
|
|
wayland::SeatEvent::Leave,
|
|
seat_id,
|
|
)),
|
|
),
|
|
))
|
|
}
|
|
KeyboardEventVariant::Enter(surface) => {
|
|
if let Some(e) =
|
|
surface_ids.get(&surface.id()).and_then(|id| {
|
|
match id {
|
|
SurfaceIdWrapper::LayerSurface(_id) => Some(
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::Layer(
|
|
LayerEvent::Focused,
|
|
surface.clone(),
|
|
id.inner(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SurfaceIdWrapper::Window(id) => {
|
|
Some(iced_runtime::core::Event::Window(
|
|
window::Event::Focused,
|
|
))
|
|
}
|
|
SurfaceIdWrapper::Popup(_id) => Some(
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::Popup(
|
|
PopupEvent::Focused,
|
|
surface.clone(),
|
|
id.inner(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SurfaceIdWrapper::SessionLock(_) => Some(
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::SessionLock(
|
|
SessionLockEvent::Focused(
|
|
surface.clone(),
|
|
id.inner(),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
),
|
|
SurfaceIdWrapper::Subsurface(_) => None,
|
|
}
|
|
.map(|e| (Some(id.inner()), e))
|
|
})
|
|
{
|
|
events.push(e);
|
|
}
|
|
|
|
events.push((
|
|
surface_ids.get(&surface.id()).map(|id| id.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(wayland::Event::Seat(
|
|
wayland::SeatEvent::Enter,
|
|
seat_id,
|
|
)),
|
|
),
|
|
));
|
|
}
|
|
KeyboardEventVariant::Press(ke) => {
|
|
let (key, location) = keysym_to_vkey_location(ke.keysym);
|
|
let physical_key = raw_keycode_to_physicalkey(ke.raw_code);
|
|
let physical_key =
|
|
crate::conversion::physical_key(physical_key);
|
|
events.push((
|
|
surface_ids.get(&surface.id()).map(|id| id.inner()),
|
|
iced_runtime::core::Event::Keyboard(
|
|
keyboard::Event::KeyPressed {
|
|
key: key.clone(),
|
|
location: location,
|
|
text: ke.utf8.map(|s| s.into()),
|
|
modifiers: modifiers_to_native(*modifiers),
|
|
physical_key,
|
|
repeat: false,
|
|
modified_key: key, // TODO calculate without Ctrl?
|
|
},
|
|
),
|
|
))
|
|
}
|
|
KeyboardEventVariant::Repeat(KeyEvent {
|
|
keysym,
|
|
utf8,
|
|
raw_code,
|
|
..
|
|
}) => {
|
|
let (key, location) = keysym_to_vkey_location(keysym);
|
|
let physical_key = raw_keycode_to_physicalkey(raw_code);
|
|
let physical_key =
|
|
crate::conversion::physical_key(physical_key);
|
|
|
|
events.push((
|
|
surface_ids.get(&surface.id()).map(|id| id.inner()),
|
|
iced_runtime::core::Event::Keyboard(
|
|
keyboard::Event::KeyPressed {
|
|
key: key.clone(),
|
|
location: location,
|
|
text: utf8.map(|s| s.into()),
|
|
modifiers: modifiers_to_native(*modifiers),
|
|
physical_key,
|
|
repeat: true,
|
|
modified_key: key, // TODO calculate without Ctrl?
|
|
},
|
|
),
|
|
))
|
|
}
|
|
KeyboardEventVariant::Release(ke) => {
|
|
let (k, location) = keysym_to_vkey_location(ke.keysym);
|
|
let physical_key = raw_keycode_to_physicalkey(ke.raw_code);
|
|
let physical_key =
|
|
crate::conversion::physical_key(physical_key);
|
|
events.push((
|
|
surface_ids.get(&surface.id()).map(|id| id.inner()),
|
|
iced_runtime::core::Event::Keyboard(
|
|
keyboard::Event::KeyReleased {
|
|
key: k.clone(),
|
|
location,
|
|
modifiers: modifiers_to_native(*modifiers),
|
|
modified_key: k,
|
|
physical_key: physical_key,
|
|
},
|
|
),
|
|
))
|
|
}
|
|
KeyboardEventVariant::Modifiers(new_mods) => {
|
|
*modifiers = new_mods;
|
|
events.push((
|
|
surface_ids.get(&surface.id()).map(|id| id.inner()),
|
|
iced_runtime::core::Event::Keyboard(
|
|
keyboard::Event::ModifiersChanged(
|
|
modifiers_to_native(new_mods),
|
|
),
|
|
),
|
|
))
|
|
}
|
|
},
|
|
SctkEvent::TouchEvent {
|
|
variant,
|
|
touch_id: _,
|
|
seat_id: _,
|
|
surface,
|
|
} => {
|
|
let position = match variant {
|
|
touch::Event::FingerPressed { position, .. } => position,
|
|
touch::Event::FingerMoved { position, .. } => position,
|
|
touch::Event::FingerLifted { position, .. } => position,
|
|
touch::Event::FingerLost { position, .. } => position,
|
|
};
|
|
let id = surface_ids.get(&surface.id()).map(|id| id.inner());
|
|
if let Some(w) =
|
|
id.clone().and_then(|id| window_manager.get_mut(id))
|
|
{
|
|
w.state.set_logical_cursor_pos(
|
|
(position.x, position.y).into(),
|
|
);
|
|
}
|
|
events.push((id, iced_runtime::core::Event::Touch(variant)))
|
|
}
|
|
SctkEvent::WindowEvent { .. } => {}
|
|
SctkEvent::LayerSurfaceEvent {
|
|
variant,
|
|
id: surface,
|
|
} => match variant {
|
|
LayerSurfaceEventVariant::Done => {
|
|
if let Some(id) = surface_ids.remove(&surface.id()) {
|
|
if let Some(w) = window_manager.remove(id.inner()) {
|
|
clipboard.register_dnd_destination(
|
|
DndSurface(Arc::new(Box::new(w.raw.clone()))),
|
|
Vec::new(),
|
|
);
|
|
if clipboard
|
|
.window_id()
|
|
.is_some_and(|id| w.raw.id() == id)
|
|
{
|
|
*clipboard = Clipboard::unconnected();
|
|
}
|
|
}
|
|
events.push((
|
|
Some(id.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::Layer(
|
|
LayerEvent::Done,
|
|
surface,
|
|
id.inner(),
|
|
),
|
|
),
|
|
),
|
|
));
|
|
}
|
|
}
|
|
LayerSurfaceEventVariant::Created(
|
|
queue_handle,
|
|
surface,
|
|
surface_id,
|
|
common,
|
|
display,
|
|
..,
|
|
) => {
|
|
let wl_surface = surface.wl_surface();
|
|
let object_id = wl_surface.id();
|
|
let wrapper =
|
|
SurfaceIdWrapper::LayerSurface(surface_id.clone());
|
|
_ = surface_ids.insert(object_id.clone(), wrapper.clone());
|
|
let sctk_winit = SctkWinitWindow::new(
|
|
sctk_tx.clone(),
|
|
common,
|
|
wrapper,
|
|
surface,
|
|
display,
|
|
queue_handle,
|
|
);
|
|
// TODO must move this to the winit handler, where we have access to the event loop
|
|
// #[cfg(feature = "a11y")]
|
|
// {
|
|
// use crate::a11y::*;
|
|
// use iced_accessibility::accesskit::{
|
|
// ActivationHandler, Node, NodeId, Role, Tree,
|
|
// TreeUpdate,
|
|
// };
|
|
// use iced_accessibility::accesskit_winit::Adapter;
|
|
|
|
// let node_id = iced_runtime::core::id::window_node_id();
|
|
|
|
// let activation_handler = WinitActivationHandler {
|
|
// proxy: control_sender.clone(),
|
|
// title: String::new(),
|
|
// };
|
|
|
|
// let action_handler = WinitActionHandler {
|
|
// id: surface_id,
|
|
// proxy: control_sender.clone(),
|
|
// };
|
|
|
|
// let deactivation_handler = WinitDeactivationHandler {
|
|
// proxy: control_sender.clone(),
|
|
// };
|
|
// _ = adapters.insert(
|
|
// surface_id,
|
|
// (
|
|
// node_id,
|
|
// Adapter::with_direct_handlers(
|
|
// event_loop,
|
|
// sctk_winit.as_ref(),
|
|
// activation_handler,
|
|
// action_handler,
|
|
// deactivation_handler,
|
|
// ),
|
|
// ),
|
|
// );
|
|
// }
|
|
|
|
let window = window_manager.insert(
|
|
surface_id,
|
|
sctk_winit,
|
|
program,
|
|
compositor,
|
|
false, // TODO do we want to get this value here?
|
|
theme::Mode::None, // TODO do we really need to track the system theme here?
|
|
);
|
|
_ = surface_ids.insert(object_id, wrapper.clone());
|
|
let logical_size = window.logical_size();
|
|
|
|
if clipboard.window_id().is_none() {
|
|
*clipboard = Clipboard::connect(
|
|
window.raw.clone(),
|
|
crate::clipboard::ControlSender {
|
|
sender: control_sender.clone(),
|
|
proxy: proxy.clone(),
|
|
},
|
|
);
|
|
}
|
|
|
|
let mut ui = crate::build_user_interface(
|
|
program,
|
|
user_interface::Cache::default(),
|
|
&mut window.renderer,
|
|
logical_size,
|
|
surface_id,
|
|
window.raw.clone(),
|
|
window.prev_dnd_destination_rectangles_count,
|
|
clipboard,
|
|
);
|
|
|
|
_ = ui.update(
|
|
&vec![iced_runtime::core::Event::PlatformSpecific(
|
|
iced_runtime::core::event::PlatformSpecific::Wayland(
|
|
iced_runtime::core::event::wayland::Event::RequestResize,
|
|
),
|
|
)],
|
|
window.state.cursor(),
|
|
&mut window.renderer,
|
|
clipboard,
|
|
&mut Vec::new(),
|
|
);
|
|
|
|
if let Some(requested_size) =
|
|
clipboard.requested_logical_size.lock().unwrap().take()
|
|
{
|
|
let requested_physical_size =
|
|
winit::dpi::PhysicalSize::new(
|
|
(requested_size.width as f64
|
|
* window.state.scale_factor())
|
|
.ceil() as u32,
|
|
(requested_size.height as f64
|
|
* window.state.scale_factor())
|
|
.ceil() as u32,
|
|
);
|
|
let physical_size = window.state.physical_size();
|
|
if requested_physical_size.width != physical_size.width
|
|
|| requested_physical_size.height
|
|
!= physical_size.height
|
|
{
|
|
// FIXME what to do when we are stuck in a configure event/resize request loop
|
|
// We don't have control over how winit handles this.
|
|
window.resize_enabled = true;
|
|
|
|
let s = winit::dpi::Size::Physical(
|
|
requested_physical_size,
|
|
);
|
|
_ = window.raw.request_surface_size(s);
|
|
window.raw.set_min_surface_size(Some(s));
|
|
window.raw.set_max_surface_size(Some(s));
|
|
window.state.synchronize(
|
|
&program,
|
|
surface_id,
|
|
window.raw.as_ref(),
|
|
);
|
|
}
|
|
}
|
|
|
|
let _ = user_interfaces.insert(surface_id, ui);
|
|
}
|
|
LayerSurfaceEventVariant::ScaleFactorChanged(..) => {}
|
|
LayerSurfaceEventVariant::Configure(
|
|
configure,
|
|
surface,
|
|
first,
|
|
) => {
|
|
if let Some((id, w)) =
|
|
surface_ids.get(&surface.id()).and_then(|id| {
|
|
window_manager
|
|
.get_mut(id.inner())
|
|
.map(|v| (id.inner(), v))
|
|
})
|
|
{
|
|
let scale = w.state.scale_factor();
|
|
let p_w = (configure.new_size.0.max(1) as f64 * scale)
|
|
.ceil() as u32;
|
|
let p_h = (configure.new_size.1.max(1) as f64 * scale)
|
|
.ceil() as u32;
|
|
w.state.update(
|
|
program,
|
|
w.raw.as_ref(),
|
|
&WindowEvent::SurfaceResized(PhysicalSize::new(
|
|
p_w, p_h,
|
|
)),
|
|
);
|
|
if first {
|
|
events.push((
|
|
Some(id),
|
|
iced_runtime::core::Event::Window(
|
|
window::Event::Opened {
|
|
size: w.state.logical_size(),
|
|
position: Default::default(),
|
|
},
|
|
),
|
|
))
|
|
} else {
|
|
events.push((
|
|
Some(id),
|
|
iced_runtime::core::Event::Window(
|
|
window::Event::Resized(
|
|
w.state.logical_size(),
|
|
),
|
|
),
|
|
))
|
|
}
|
|
}
|
|
}
|
|
},
|
|
SctkEvent::PopupEvent {
|
|
variant,
|
|
id: surface,
|
|
..
|
|
} => {
|
|
match variant {
|
|
PopupEventVariant::Done => {
|
|
if let Some(e) =
|
|
surface_ids.remove(&surface.id()).map(|id| {
|
|
if let Some(w) =
|
|
window_manager.remove(id.inner())
|
|
{
|
|
clipboard.register_dnd_destination(
|
|
DndSurface(Arc::new(Box::new(
|
|
w.raw.clone(),
|
|
))),
|
|
Vec::new(),
|
|
);
|
|
if clipboard
|
|
.window_id()
|
|
.is_some_and(|id| w.raw.id() == id)
|
|
{
|
|
*clipboard = Clipboard::unconnected();
|
|
}
|
|
}
|
|
_ = user_interfaces.remove(&id.inner());
|
|
|
|
(
|
|
Some(id.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::Popup(
|
|
PopupEvent::Done,
|
|
surface,
|
|
id.inner(),
|
|
),
|
|
),
|
|
),
|
|
)
|
|
})
|
|
{
|
|
events.push(e)
|
|
}
|
|
}
|
|
PopupEventVariant::Created(
|
|
queue_handle,
|
|
surface,
|
|
surface_id,
|
|
common,
|
|
display,
|
|
) => {
|
|
let wl_surface = surface.wl_surface();
|
|
let wrapper = SurfaceIdWrapper::Popup(surface_id);
|
|
_ = surface_ids
|
|
.insert(wl_surface.id(), wrapper.clone());
|
|
let sctk_winit = SctkWinitWindow::new(
|
|
sctk_tx.clone(),
|
|
common,
|
|
wrapper,
|
|
surface,
|
|
display,
|
|
queue_handle,
|
|
);
|
|
// TODO must move this to the winit handler, where we have access to the event loop
|
|
// #[cfg(feature = "a11y")]
|
|
// {
|
|
// use crate::a11y::*;
|
|
// use iced_accessibility::accesskit::{
|
|
// ActivationHandler, Node, NodeId, Role, Tree,
|
|
// TreeUpdate,
|
|
// };
|
|
// use iced_accessibility::accesskit_winit::Adapter;
|
|
|
|
// let node_id =
|
|
// iced_runtime::core::id::window_node_id();
|
|
|
|
// let activation_handler = WinitActivationHandler {
|
|
// proxy: control_sender.clone(),
|
|
// title: String::new(),
|
|
// };
|
|
|
|
// let action_handler = WinitActionHandler {
|
|
// id: surface_id,
|
|
// proxy: control_sender.clone(),
|
|
// };
|
|
|
|
// let deactivation_handler =
|
|
// WinitDeactivationHandler {
|
|
// proxy: control_sender.clone(),
|
|
// };
|
|
// _ = adapters.insert(
|
|
// surface_id,
|
|
// (
|
|
// node_id,
|
|
// Adapter::with_direct_handlers(
|
|
// event_loop,
|
|
// sctk_winit.as_ref(),
|
|
// activation_handler,
|
|
// action_handler,
|
|
// deactivation_handler,
|
|
// ),
|
|
// ),
|
|
// );
|
|
// }
|
|
|
|
if clipboard.window_id().is_none() {
|
|
*clipboard = Clipboard::connect(
|
|
sctk_winit.clone(),
|
|
crate::clipboard::ControlSender {
|
|
sender: control_sender.clone(),
|
|
proxy: proxy.clone(),
|
|
},
|
|
);
|
|
}
|
|
|
|
let window = window_manager.insert(
|
|
surface_id,
|
|
sctk_winit,
|
|
program,
|
|
compositor,
|
|
false, // TODO do we want to get this value here?
|
|
theme::Mode::None, // TODO do we really need to track the system theme here?
|
|
);
|
|
let logical_size = window.logical_size();
|
|
|
|
let mut ui = crate::build_user_interface(
|
|
program,
|
|
user_interface::Cache::default(),
|
|
&mut window.renderer,
|
|
logical_size,
|
|
surface_id,
|
|
window.raw.clone(),
|
|
window.prev_dnd_destination_rectangles_count,
|
|
clipboard,
|
|
);
|
|
|
|
_ = ui.update(
|
|
&vec![iced_runtime::core::Event::PlatformSpecific(
|
|
iced_runtime::core::event::PlatformSpecific::Wayland(
|
|
iced_runtime::core::event::wayland::Event::RequestResize,
|
|
),
|
|
)],
|
|
window.state.cursor(),
|
|
&mut window.renderer,
|
|
clipboard,
|
|
&mut Vec::new(),
|
|
);
|
|
|
|
if let Some(requested_size) = clipboard
|
|
.requested_logical_size
|
|
.lock()
|
|
.unwrap()
|
|
.take()
|
|
{
|
|
let requested_physical_size =
|
|
winit::dpi::PhysicalSize::new(
|
|
(requested_size.width as f64
|
|
* window.state.scale_factor())
|
|
.ceil()
|
|
as u32,
|
|
(requested_size.height as f64
|
|
* window.state.scale_factor())
|
|
.ceil()
|
|
as u32,
|
|
);
|
|
let physical_size = window.state.physical_size();
|
|
if requested_physical_size.width
|
|
!= physical_size.width
|
|
|| requested_physical_size.height
|
|
!= physical_size.height
|
|
{
|
|
// FIXME what to do when we are stuck in a configure event/resize request loop
|
|
// We don't have control over how winit handles this.
|
|
window.resize_enabled = true;
|
|
|
|
let s = winit::dpi::Size::Physical(
|
|
requested_physical_size,
|
|
);
|
|
_ = window.raw.request_surface_size(s);
|
|
window.raw.set_min_surface_size(Some(s));
|
|
window.raw.set_max_surface_size(Some(s));
|
|
window.state.synchronize(
|
|
&program,
|
|
surface_id,
|
|
window.raw.as_ref(),
|
|
);
|
|
}
|
|
}
|
|
|
|
let _ = user_interfaces.insert(surface_id, ui);
|
|
}
|
|
PopupEventVariant::Configure(configure, surface, first) => {
|
|
let size = Size::new(
|
|
configure.width as f32,
|
|
configure.height as f32,
|
|
);
|
|
|
|
if let Some((id, w)) =
|
|
surface_ids.get(&surface.id()).and_then(|id| {
|
|
window_manager
|
|
.get_mut(id.inner())
|
|
.map(|v| (id.inner(), v))
|
|
})
|
|
{
|
|
let scale = w.state.scale_factor();
|
|
let p_w = (configure.width.max(1) as f64 * scale)
|
|
.ceil()
|
|
as u32;
|
|
let p_h = (configure.height.max(1) as f64 * scale)
|
|
.ceil()
|
|
as u32;
|
|
|
|
w.state.update(
|
|
program,
|
|
w.raw.as_ref(),
|
|
&WindowEvent::SurfaceResized(
|
|
PhysicalSize::new(p_w, p_h),
|
|
),
|
|
);
|
|
if first {
|
|
events.push((
|
|
Some(id),
|
|
iced_runtime::core::Event::Window(
|
|
window::Event::Opened {
|
|
size: size,
|
|
position: Default::default(),
|
|
},
|
|
),
|
|
))
|
|
} else {
|
|
events.push((
|
|
Some(id),
|
|
iced_runtime::core::Event::Window(
|
|
window::Event::Resized(size),
|
|
),
|
|
))
|
|
}
|
|
}
|
|
} // TODO
|
|
PopupEventVariant::RepositionionedPopup { token: _ } => {}
|
|
PopupEventVariant::Size(_, _) => {}
|
|
PopupEventVariant::ScaleFactorChanged(..) => {}
|
|
}
|
|
}
|
|
SctkEvent::NewOutput { id, info } => events.push((
|
|
None,
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(wayland::Event::Output(
|
|
wayland::OutputEvent::Created(info),
|
|
id,
|
|
)),
|
|
),
|
|
)),
|
|
SctkEvent::UpdateOutput { id, info } => events.push((
|
|
None,
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(wayland::Event::Output(
|
|
wayland::OutputEvent::InfoUpdate(info),
|
|
id,
|
|
)),
|
|
),
|
|
)),
|
|
SctkEvent::RemovedOutput(id) => events.push((
|
|
None,
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(wayland::Event::Output(
|
|
wayland::OutputEvent::Removed,
|
|
id,
|
|
)),
|
|
),
|
|
)),
|
|
SctkEvent::ScaleFactorChanged {
|
|
factor: _,
|
|
id: _,
|
|
inner_size: _,
|
|
} => Default::default(),
|
|
SctkEvent::SessionLocked => events.push((
|
|
None,
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(wayland::Event::SessionLock(
|
|
wayland::SessionLockEvent::Locked,
|
|
)),
|
|
),
|
|
)),
|
|
SctkEvent::SessionLockFinished => events.push((
|
|
None,
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(wayland::Event::SessionLock(
|
|
wayland::SessionLockEvent::Finished,
|
|
)),
|
|
),
|
|
)),
|
|
SctkEvent::SessionLockSurfaceCreated {
|
|
queue_handle,
|
|
surface,
|
|
native_id: surface_id,
|
|
common,
|
|
display,
|
|
} => {
|
|
let wl_surface = surface.wl_surface();
|
|
let object_id = wl_surface.id().clone();
|
|
let wrapper = SurfaceIdWrapper::SessionLock(surface_id.clone());
|
|
_ = surface_ids.insert(object_id.clone(), wrapper.clone());
|
|
let sctk_winit = SctkWinitWindow::new(
|
|
sctk_tx.clone(),
|
|
common,
|
|
wrapper,
|
|
surface,
|
|
display,
|
|
queue_handle,
|
|
);
|
|
// TODO must move this to the winit handler, where we have access to the event loop
|
|
// #[cfg(feature = "a11y")]
|
|
// {
|
|
// use crate::a11y::*;
|
|
// use iced_accessibility::accesskit::{
|
|
// ActivationHandler, Node, NodeId, Role, Tree, TreeUpdate,
|
|
// };
|
|
// use iced_accessibility::accesskit_winit::Adapter;
|
|
|
|
// let node_id = iced_runtime::core::id::window_node_id();
|
|
|
|
// let activation_handler = WinitActivationHandler {
|
|
// proxy: control_sender.clone(),
|
|
// // TODO lock screen title
|
|
// title: String::new(),
|
|
// };
|
|
|
|
// let action_handler = WinitActionHandler {
|
|
// id: surface_id,
|
|
// proxy: control_sender.clone(),
|
|
// };
|
|
|
|
// let deactivation_handler = WinitDeactivationHandler {
|
|
// proxy: control_sender.clone(),
|
|
// };
|
|
// _ = adapters.insert(
|
|
// surface_id,
|
|
// (
|
|
// node_id,
|
|
// Adapter::with_direct_handlers(
|
|
// event_loop,
|
|
// sctk_winit.as_ref(),
|
|
// activation_handler,
|
|
// action_handler,
|
|
// deactivation_handler,
|
|
// ),
|
|
// ),
|
|
// );
|
|
// }
|
|
|
|
if clipboard.window_id().is_none() {
|
|
*clipboard = Clipboard::connect(
|
|
sctk_winit.clone(),
|
|
crate::clipboard::ControlSender {
|
|
sender: control_sender.clone(),
|
|
proxy: proxy.clone(),
|
|
},
|
|
);
|
|
}
|
|
|
|
let window = window_manager.insert(
|
|
surface_id,
|
|
sctk_winit,
|
|
program,
|
|
compositor,
|
|
false, // TODO do we want to get this value here?
|
|
theme::Mode::None, // TODO do we really need to track the system theme here?
|
|
);
|
|
_ = surface_ids.insert(object_id, wrapper.clone());
|
|
let logical_size = window.logical_size();
|
|
todo!()
|
|
// let _ = user_interfaces.insert(
|
|
// surface_id,
|
|
// crate::build_user_interface(
|
|
// program,
|
|
// user_interface::Cache::default(),
|
|
// &mut window.renderer,
|
|
// logical_size,
|
|
// surface_id,
|
|
// window.raw.clone(),
|
|
// window.prev_dnd_destination_rectangles_count,
|
|
// clipboard,
|
|
// ),
|
|
// );
|
|
}
|
|
SctkEvent::SessionLockSurfaceConfigure {
|
|
surface,
|
|
configure,
|
|
first,
|
|
} => {
|
|
let size = Size::new(
|
|
configure.new_size.0 as f32,
|
|
configure.new_size.1 as f32,
|
|
);
|
|
if let Some((id, w)) =
|
|
surface_ids.get(&surface.id()).and_then(|id| {
|
|
window_manager
|
|
.get_mut(id.inner())
|
|
.map(|v| (id.inner(), v))
|
|
})
|
|
{
|
|
let scale = w.state.scale_factor();
|
|
let p_w = (configure.new_size.0.max(1) as f64 * scale)
|
|
.round() as u32;
|
|
let p_h = (configure.new_size.1.max(1) as f64 * scale)
|
|
.round() as u32;
|
|
w.state.update(
|
|
program,
|
|
w.raw.as_ref(),
|
|
&WindowEvent::SurfaceResized(PhysicalSize::new(
|
|
p_w, p_h,
|
|
)),
|
|
);
|
|
if first {
|
|
events.push((
|
|
Some(id),
|
|
iced_runtime::core::Event::Window(
|
|
window::Event::Opened {
|
|
size: size,
|
|
position: Default::default(),
|
|
},
|
|
),
|
|
))
|
|
} else {
|
|
events.push((
|
|
Some(id),
|
|
iced_runtime::core::Event::Window(
|
|
window::Event::Resized(size),
|
|
),
|
|
))
|
|
}
|
|
}
|
|
}
|
|
SctkEvent::SessionLockSurfaceDone { surface } => {
|
|
if let Some(id) = surface_ids.remove(&surface.id()) {
|
|
_ = window_manager.remove(id.inner());
|
|
}
|
|
}
|
|
SctkEvent::SessionUnlocked => events.push((
|
|
None,
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(wayland::Event::SessionLock(
|
|
wayland::SessionLockEvent::Unlocked,
|
|
)),
|
|
),
|
|
)),
|
|
SctkEvent::Winit(_, _) => {}
|
|
SctkEvent::SurfaceScaleFactorChanged(scale, _, id) => {
|
|
if let Some(w) = window_manager.get_mut(id) {
|
|
w.state.update_scale_factor(scale);
|
|
}
|
|
}
|
|
SctkEvent::Subcompositor(s) => {
|
|
*subsurface_state = Some(s);
|
|
}
|
|
SctkEvent::OverlapToplevelAdd {
|
|
surface,
|
|
toplevel,
|
|
logical_rect,
|
|
} => {
|
|
if let Some(id) = surface_ids.get(&surface.id()) {
|
|
events.push((
|
|
Some(id.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::OverlapNotify(
|
|
OverlapNotifyEvent::OverlapToplevelAdd {
|
|
toplevel,
|
|
logical_rect,
|
|
},
|
|
),
|
|
),
|
|
),
|
|
))
|
|
}
|
|
}
|
|
SctkEvent::OverlapToplevelRemove { surface, toplevel } => {
|
|
if let Some(id) = surface_ids.get(&surface.id()) {
|
|
events.push((
|
|
Some(id.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::OverlapNotify(
|
|
OverlapNotifyEvent::OverlapToplevelRemove {
|
|
toplevel,
|
|
},
|
|
),
|
|
),
|
|
),
|
|
))
|
|
}
|
|
}
|
|
SctkEvent::OverlapLayerAdd {
|
|
surface,
|
|
namespace,
|
|
identifier,
|
|
exclusive,
|
|
layer,
|
|
logical_rect,
|
|
} => {
|
|
if let Some(id) = surface_ids.get(&surface.id()) {
|
|
events.push((
|
|
Some(id.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::OverlapNotify(
|
|
OverlapNotifyEvent::OverlapLayerAdd {
|
|
identifier,
|
|
namespace,
|
|
exclusive,
|
|
layer,
|
|
logical_rect,
|
|
},
|
|
),
|
|
),
|
|
),
|
|
))
|
|
}
|
|
}
|
|
SctkEvent::OverlapLayerRemove {
|
|
surface,
|
|
identifier,
|
|
} => {
|
|
if let Some(id) = surface_ids.get(&surface.id()) {
|
|
events.push((
|
|
Some(id.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::OverlapNotify(
|
|
OverlapNotifyEvent::OverlapLayerRemove {
|
|
identifier,
|
|
},
|
|
),
|
|
),
|
|
),
|
|
))
|
|
}
|
|
}
|
|
SctkEvent::SubsurfaceEvent(variant) => match variant {
|
|
SubsurfaceEventVariant::Created {
|
|
parent_id,
|
|
common_surface,
|
|
common,
|
|
z,
|
|
parent,
|
|
surface: _,
|
|
qh,
|
|
surface_id,
|
|
display,
|
|
} => {
|
|
let CommonSurface::Subsurface {
|
|
wl_surface,
|
|
wl_subsurface,
|
|
} = &common_surface
|
|
else {
|
|
return;
|
|
};
|
|
if let Some(subsurface_state) = subsurface_state.as_mut() {
|
|
subsurface_state.new_iced_subsurfaces.push((
|
|
parent_id,
|
|
parent,
|
|
surface_id,
|
|
wl_subsurface.clone(),
|
|
wl_surface.clone(),
|
|
z,
|
|
));
|
|
}
|
|
|
|
let wrapper = SurfaceIdWrapper::Popup(surface_id);
|
|
_ = surface_ids.insert(wl_surface.id(), wrapper.clone());
|
|
let sctk_winit = SctkWinitWindow::new(
|
|
sctk_tx.clone(),
|
|
common,
|
|
wrapper,
|
|
common_surface,
|
|
display,
|
|
qh,
|
|
);
|
|
// #[cfg(feature = "a11y")]
|
|
// {
|
|
// use crate::a11y::*;
|
|
// use iced_accessibility::accesskit::{
|
|
// ActivationHandler, NodeBuilder, NodeId, Role, Tree,
|
|
// TreeUpdate,
|
|
// };
|
|
// use iced_accessibility::accesskit_winit::Adapter;
|
|
|
|
// let node_id = iced_runtime::core::id::window_node_id();
|
|
|
|
// let activation_handler = WinitActivationHandler {
|
|
// proxy: control_sender.clone(),
|
|
// title: String::new(),
|
|
// };
|
|
|
|
// let action_handler = WinitActionHandler {
|
|
// id: surface_id,
|
|
// proxy: control_sender.clone(),
|
|
// };
|
|
|
|
// let deactivation_handler = WinitDeactivationHandler {
|
|
// proxy: control_sender.clone(),
|
|
// };
|
|
// _ = adapters.insert(
|
|
// surface_id,
|
|
// (
|
|
// node_id,
|
|
// Adapter::with_direct_handlers(
|
|
// sctk_winit.as_ref(),
|
|
// activation_handler,
|
|
// action_handler,
|
|
// deactivation_handler,
|
|
// ),
|
|
// ),
|
|
// );
|
|
// }
|
|
|
|
if clipboard.window_id().is_none() {
|
|
*clipboard = Clipboard::connect(
|
|
sctk_winit.clone(),
|
|
crate::clipboard::ControlSender {
|
|
sender: control_sender.clone(),
|
|
proxy: proxy.clone(),
|
|
},
|
|
);
|
|
}
|
|
|
|
let window = window_manager.insert(
|
|
surface_id,
|
|
sctk_winit,
|
|
program,
|
|
compositor,
|
|
false, // TODO do we want to get this value here?
|
|
theme::Mode::None,
|
|
);
|
|
let logical_size = window.logical_size();
|
|
|
|
let mut ui = crate::build_user_interface(
|
|
program,
|
|
user_interface::Cache::default(),
|
|
&mut window.renderer,
|
|
logical_size,
|
|
surface_id,
|
|
window.raw.clone(),
|
|
window.prev_dnd_destination_rectangles_count,
|
|
clipboard,
|
|
);
|
|
|
|
_ = ui.update(
|
|
&vec![iced_runtime::core::Event::PlatformSpecific(
|
|
iced_runtime::core::event::PlatformSpecific::Wayland(
|
|
iced_runtime::core::event::wayland::Event::RequestResize,
|
|
),
|
|
)],
|
|
window.state.cursor(),
|
|
&mut window.renderer,
|
|
clipboard,
|
|
&mut Vec::new(),
|
|
);
|
|
|
|
if let Some(requested_size) =
|
|
clipboard.requested_logical_size.lock().unwrap().take()
|
|
{
|
|
let requested_physical_size =
|
|
winit::dpi::PhysicalSize::new(
|
|
(requested_size.width as f64
|
|
* window.state.scale_factor())
|
|
.ceil() as u32,
|
|
(requested_size.height as f64
|
|
* window.state.scale_factor())
|
|
.ceil() as u32,
|
|
);
|
|
let physical_size = window.state.physical_size();
|
|
if requested_physical_size.width != physical_size.width
|
|
|| requested_physical_size.height
|
|
!= physical_size.height
|
|
{
|
|
// FIXME what to do when we are stuck in a configure event/resize request loop
|
|
// We don't have control over how winit handles this.
|
|
window.resize_enabled = true;
|
|
|
|
let s = winit::dpi::Size::Physical(
|
|
requested_physical_size,
|
|
);
|
|
_ = window.raw.request_surface_size(s);
|
|
window.raw.set_min_surface_size(Some(s));
|
|
window.raw.set_max_surface_size(Some(s));
|
|
window.state.synchronize(
|
|
&program,
|
|
surface_id,
|
|
window.raw.as_ref(),
|
|
);
|
|
}
|
|
}
|
|
events.push((
|
|
Some(surface_id),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::Subsurface(
|
|
wayland::SubsurfaceEvent::Created,
|
|
),
|
|
),
|
|
),
|
|
));
|
|
let _ = user_interfaces.insert(surface_id, ui);
|
|
}
|
|
SubsurfaceEventVariant::Destroyed(instance) => {
|
|
remove_iced_subsurface(&instance.wl_surface);
|
|
|
|
if let Some(id_wrapper) =
|
|
surface_ids.remove(&instance.wl_surface.id())
|
|
{
|
|
_ = user_interfaces.remove(&id_wrapper.inner());
|
|
|
|
if let Some(w) =
|
|
window_manager.remove(id_wrapper.inner())
|
|
{
|
|
clipboard.register_dnd_destination(
|
|
DndSurface(Arc::new(Box::new(w.raw.clone()))),
|
|
Vec::new(),
|
|
);
|
|
if clipboard
|
|
.window_id()
|
|
.is_some_and(|id| w.raw.id() == id)
|
|
{
|
|
*clipboard = Clipboard::unconnected();
|
|
}
|
|
}
|
|
events.push((
|
|
Some(id_wrapper.inner()),
|
|
iced_runtime::core::Event::PlatformSpecific(
|
|
PlatformSpecific::Wayland(
|
|
wayland::Event::Subsurface(
|
|
wayland::SubsurfaceEvent::Destroyed,
|
|
),
|
|
),
|
|
),
|
|
));
|
|
}
|
|
if let Some(subsurface_state) = subsurface_state.as_mut() {
|
|
subsurface_state.unmapped_subsurfaces.push(instance);
|
|
}
|
|
}
|
|
SubsurfaceEventVariant::Resized(id, size) => {
|
|
if let Some((id, w)) =
|
|
window_manager.get_mut(id).map(|v| (id, v))
|
|
{
|
|
let scale = w.state.scale_factor();
|
|
let physical_size = size.to_physical(scale);
|
|
w.state.update(
|
|
program,
|
|
w.raw.as_ref(),
|
|
&WindowEvent::SurfaceResized(PhysicalSize::new(
|
|
physical_size.width,
|
|
physical_size.height,
|
|
)),
|
|
);
|
|
|
|
events.push((
|
|
Some(id),
|
|
iced_runtime::core::Event::Window(
|
|
window::Event::Opened {
|
|
size: w.state.logical_size(),
|
|
position: Default::default(),
|
|
},
|
|
),
|
|
))
|
|
}
|
|
}
|
|
},
|
|
}
|
|
}
|
|
}
|
|
|
|
fn keysym_to_vkey_location(keysym: Keysym) -> (Key, Location) {
|
|
let raw = keysym.raw();
|
|
let mut key = keysym_to_key(raw);
|
|
if matches!(key, key::Key::Unidentified) {
|
|
// XXX is there a better way to do this?
|
|
// we need to be able to determine the actual character for the key
|
|
// not the combination, so this seems to be correct
|
|
let mut utf8 = xkbcommon::xkb::keysym_to_utf8(keysym);
|
|
// remove null terminator
|
|
_ = utf8.pop();
|
|
if utf8.len() > 0 {
|
|
key = Key::Character(utf8.into());
|
|
}
|
|
}
|
|
|
|
let location = keymap::keysym_location(raw);
|
|
(key, location)
|
|
}
|