fixes: various fixes and cleanup
This commit is contained in:
parent
b4346ff3ca
commit
c1edb81084
27 changed files with 676 additions and 1455 deletions
19
Cargo.lock
generated
19
Cargo.lock
generated
|
|
@ -21,6 +21,7 @@ checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit"
|
name = "accesskit"
|
||||||
version = "0.22.0"
|
version = "0.22.0"
|
||||||
|
source = "git+https://github.com/wash2/accesskit?branch=iced-0.14#1f893441ec3dc5923f5430c02bba762f5444bbea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"uuid",
|
"uuid",
|
||||||
]
|
]
|
||||||
|
|
@ -28,6 +29,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit_atspi_common"
|
name = "accesskit_atspi_common"
|
||||||
version = "0.15.0"
|
version = "0.15.0"
|
||||||
|
source = "git+https://github.com/wash2/accesskit?branch=iced-0.14#1f893441ec3dc5923f5430c02bba762f5444bbea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
|
|
@ -39,6 +41,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit_consumer"
|
name = "accesskit_consumer"
|
||||||
version = "0.32.0"
|
version = "0.32.0"
|
||||||
|
source = "git+https://github.com/wash2/accesskit?branch=iced-0.14#1f893441ec3dc5923f5430c02bba762f5444bbea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"hashbrown 0.16.1",
|
"hashbrown 0.16.1",
|
||||||
|
|
@ -47,6 +50,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit_macos"
|
name = "accesskit_macos"
|
||||||
version = "0.23.0"
|
version = "0.23.0"
|
||||||
|
source = "git+https://github.com/wash2/accesskit?branch=iced-0.14#1f893441ec3dc5923f5430c02bba762f5444bbea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
|
|
@ -59,6 +63,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit_unix"
|
name = "accesskit_unix"
|
||||||
version = "0.18.0"
|
version = "0.18.0"
|
||||||
|
source = "git+https://github.com/wash2/accesskit?branch=iced-0.14#1f893441ec3dc5923f5430c02bba762f5444bbea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_atspi_common",
|
"accesskit_atspi_common",
|
||||||
|
|
@ -77,6 +82,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit_windows"
|
name = "accesskit_windows"
|
||||||
version = "0.30.0"
|
version = "0.30.0"
|
||||||
|
source = "git+https://github.com/wash2/accesskit?branch=iced-0.14#1f893441ec3dc5923f5430c02bba762f5444bbea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_consumer",
|
"accesskit_consumer",
|
||||||
|
|
@ -89,6 +95,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "accesskit_winit"
|
name = "accesskit_winit"
|
||||||
version = "0.30.0"
|
version = "0.30.0"
|
||||||
|
source = "git+https://github.com/wash2/accesskit?branch=iced-0.14#1f893441ec3dc5923f5430c02bba762f5444bbea"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"accesskit",
|
"accesskit",
|
||||||
"accesskit_macos",
|
"accesskit_macos",
|
||||||
|
|
@ -1637,6 +1644,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "dpi"
|
name = "dpi"
|
||||||
version = "0.1.2"
|
version = "0.1.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "drm"
|
name = "drm"
|
||||||
|
|
@ -8434,6 +8442,7 @@ checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650"
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit"
|
name = "winit"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"cfg_aliases",
|
"cfg_aliases",
|
||||||
|
|
@ -8459,6 +8468,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-android"
|
name = "winit-android"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"android-activity",
|
"android-activity",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
|
|
@ -8473,6 +8483,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-appkit"
|
name = "winit-appkit"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"block2 0.6.2",
|
"block2 0.6.2",
|
||||||
|
|
@ -8494,6 +8505,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-common"
|
name = "winit-common"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"memmap2 0.9.9",
|
"memmap2 0.9.9",
|
||||||
"objc2 0.6.3",
|
"objc2 0.6.3",
|
||||||
|
|
@ -8508,6 +8520,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-core"
|
name = "winit-core"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"cursor-icon",
|
"cursor-icon",
|
||||||
|
|
@ -8521,6 +8534,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-orbital"
|
name = "winit-orbital"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"dpi",
|
"dpi",
|
||||||
|
|
@ -8536,6 +8550,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-uikit"
|
name = "winit-uikit"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"block2 0.6.2",
|
"block2 0.6.2",
|
||||||
|
|
@ -8555,6 +8570,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-wayland"
|
name = "winit-wayland"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"ahash",
|
"ahash",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
|
|
@ -8580,6 +8596,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-web"
|
name = "winit-web"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"atomic-waker",
|
"atomic-waker",
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
|
|
@ -8601,6 +8618,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-win32"
|
name = "winit-win32"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"cursor-icon",
|
"cursor-icon",
|
||||||
|
|
@ -8616,6 +8634,7 @@ dependencies = [
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "winit-x11"
|
name = "winit-x11"
|
||||||
version = "0.31.0-beta.2"
|
version = "0.31.0-beta.2"
|
||||||
|
source = "git+https://github.com/pop-os/winit.git?branch=iced-0.14-rebase#a610ac9c7a72b39ff102ed4d946291618dc725b6"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bitflags 2.10.0",
|
"bitflags 2.10.0",
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,6 @@ advanced = [
|
||||||
"iced_core/advanced",
|
"iced_core/advanced",
|
||||||
"iced_widget/advanced",
|
"iced_widget/advanced",
|
||||||
] # Enables the advanced module
|
] # Enables the advanced module
|
||||||
multi-window = [
|
|
||||||
"iced_winit?/multi-window",
|
|
||||||
] # Enables experimental multi-window support.
|
|
||||||
basic-shaping = ["iced_core/basic-shaping"]
|
basic-shaping = ["iced_core/basic-shaping"]
|
||||||
# Enables advanced text shaping by default
|
# Enables advanced text shaping by default
|
||||||
advanced-shaping = ["iced_core/advanced-shaping"]
|
advanced-shaping = ["iced_core/advanced-shaping"]
|
||||||
|
|
@ -336,4 +333,3 @@ useless_conversion = "deny"
|
||||||
|
|
||||||
[workspace.lints.rustdoc]
|
[workspace.lints.rustdoc]
|
||||||
broken_intra_doc_links = "forbid"
|
broken_intra_doc_links = "forbid"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -78,6 +78,12 @@ impl From<f32> for Length {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl From<i32> for Length {
|
||||||
|
fn from(amount: i32) -> Self {
|
||||||
|
Length::Fixed(amount as f32)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl From<u16> for Length {
|
impl From<u16> for Length {
|
||||||
fn from(amount: u16) -> Self {
|
fn from(amount: u16) -> Self {
|
||||||
Length::Fixed(amount as f32)
|
Length::Fixed(amount as f32)
|
||||||
|
|
|
||||||
|
|
@ -46,7 +46,6 @@ impl Click {
|
||||||
previous: Option<Click>,
|
previous: Option<Click>,
|
||||||
) -> Click {
|
) -> Click {
|
||||||
let time = Instant::now();
|
let time = Instant::now();
|
||||||
|
|
||||||
let kind = if let Some(previous) = previous {
|
let kind = if let Some(previous) = previous {
|
||||||
if previous.is_consecutive(position, time)
|
if previous.is_consecutive(position, time)
|
||||||
&& button == previous.button
|
&& button == previous.button
|
||||||
|
|
|
||||||
|
|
@ -147,7 +147,6 @@ impl Tree {
|
||||||
|
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reconciliates the current tree with the provided [`Widget`].
|
/// Reconciliates the current tree with the provided [`Widget`].
|
||||||
///
|
///
|
||||||
/// If the tag of the [`Widget`] matches the tag of the [`Tree`], then the
|
/// If the tag of the [`Widget`] matches the tag of the [`Tree`], then the
|
||||||
|
|
@ -166,9 +165,10 @@ impl Tree {
|
||||||
new.borrow_mut();
|
new.borrow_mut();
|
||||||
|
|
||||||
let mut tag_match = self.tag == borrowed.tag();
|
let mut tag_match = self.tag == borrowed.tag();
|
||||||
|
|
||||||
if tag_match {
|
if tag_match {
|
||||||
if let Some(Id(Internal::Custom(_, n))) = borrowed.id() {
|
if let Some(Id(Internal::Custom(_, n))) = borrowed.id() {
|
||||||
let mut named = NAMED
|
if let Some((mut state, children)) = NAMED
|
||||||
.with(|named| named.borrow_mut().remove(&n))
|
.with(|named| named.borrow_mut().remove(&n))
|
||||||
.or_else(|| {
|
.or_else(|| {
|
||||||
//check self.id
|
//check self.id
|
||||||
|
|
@ -199,14 +199,14 @@ impl Tree {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
if let Some((mut state, children)) = named {
|
{
|
||||||
std::mem::swap(&mut self.state, &mut state);
|
std::mem::swap(&mut self.state, &mut state);
|
||||||
let widget_children = borrowed.children();
|
let widget_children = borrowed.children();
|
||||||
if !tag_match
|
if !tag_match
|
||||||
|| self.children.len() != widget_children.len()
|
|| self.children.len() != widget_children.len()
|
||||||
{
|
{
|
||||||
self.children = borrowed.children();
|
self.children = widget_children;
|
||||||
} else {
|
} else {
|
||||||
for (old_i, mut old) in children {
|
for (old_i, mut old) in children {
|
||||||
let Some(my_state) = self.children.get_mut(old_i)
|
let Some(my_state) = self.children.get_mut(old_i)
|
||||||
|
|
@ -244,8 +244,10 @@ impl Tree {
|
||||||
if let Some(id) = self.id.clone() {
|
if let Some(id) = self.id.clone() {
|
||||||
borrowed.set_id(id);
|
borrowed.set_id(id);
|
||||||
}
|
}
|
||||||
if self.children.len() != borrowed.children().len() {
|
let borrowed_children = borrowed.children();
|
||||||
self.children = borrowed.children();
|
|
||||||
|
if self.children.len() != borrowed_children.len() {
|
||||||
|
self.children = borrowed_children;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,6 +11,5 @@ iced = { path = "../..", default-features = false, features = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"debug",
|
"debug",
|
||||||
"winit",
|
"winit",
|
||||||
"multi-window",
|
|
||||||
"tiny-skia",
|
"tiny-skia",
|
||||||
] }
|
] }
|
||||||
|
|
|
||||||
|
|
@ -341,7 +341,7 @@ impl<'a, Message: 'static> Widget<Message, iced::Theme, iced::Renderer>
|
||||||
);
|
);
|
||||||
if matches!(s, event::Status::Captured) {
|
if matches!(s, event::Status::Captured) {
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let state = tree.state.downcast_mut::<State<()>>();
|
let state = tree.state.downcast_mut::<State<()>>();
|
||||||
|
|
@ -383,7 +383,7 @@ return;
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Event::Dnd(DndEvent::Offer(id, OfferEvent::Leave))
|
Event::Dnd(DndEvent::Offer(id, OfferEvent::Leave))
|
||||||
if id == Some(my_id) =>
|
if id == Some(my_id) =>
|
||||||
|
|
@ -407,7 +407,7 @@ return;
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Event::Dnd(DndEvent::Offer(id, OfferEvent::Motion { x, y }))
|
Event::Dnd(DndEvent::Offer(id, OfferEvent::Motion { x, y }))
|
||||||
if id == Some(my_id) =>
|
if id == Some(my_id) =>
|
||||||
|
|
@ -441,7 +441,7 @@ return;
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Event::Dnd(DndEvent::Offer(id, OfferEvent::LeaveDestination))
|
Event::Dnd(DndEvent::Offer(id, OfferEvent::LeaveDestination))
|
||||||
if id == Some(my_id) =>
|
if id == Some(my_id) =>
|
||||||
|
|
@ -452,7 +452,7 @@ return;
|
||||||
shell.publish(msg);
|
shell.publish(msg);
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Event::Dnd(DndEvent::Offer(id, OfferEvent::Drop))
|
Event::Dnd(DndEvent::Offer(id, OfferEvent::Drop))
|
||||||
if id == Some(my_id) =>
|
if id == Some(my_id) =>
|
||||||
|
|
@ -463,7 +463,7 @@ return;
|
||||||
shell.publish(msg);
|
shell.publish(msg);
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Event::Dnd(DndEvent::Offer(
|
Event::Dnd(DndEvent::Offer(
|
||||||
id,
|
id,
|
||||||
|
|
@ -478,13 +478,12 @@ return;
|
||||||
shell.publish(msg);
|
shell.publish(msg);
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Event::Dnd(DndEvent::Offer(
|
Event::Dnd(DndEvent::Offer(
|
||||||
id,
|
id,
|
||||||
OfferEvent::Data { data, mime_type },
|
OfferEvent::Data { data, mime_type },
|
||||||
)) if id == Some(my_id) => {
|
)) if id == Some(my_id) => {
|
||||||
dbg!("got data");
|
|
||||||
if let (Some(msg), ret) = state.on_data_received(
|
if let (Some(msg), ret) = state.on_data_received(
|
||||||
mime_type,
|
mime_type,
|
||||||
data,
|
data,
|
||||||
|
|
@ -497,7 +496,7 @@ return;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
@ -705,7 +704,6 @@ impl<T> State<T> {
|
||||||
impl Fn(String, Vec<u8>, DndAction, f64, f64) -> Message,
|
impl Fn(String, Vec<u8>, DndAction, f64, f64) -> Message,
|
||||||
>,
|
>,
|
||||||
) -> (Option<Message>, event::Status) {
|
) -> (Option<Message>, event::Status) {
|
||||||
dbg!("data received");
|
|
||||||
let Some(dnd) = self.drag_offer.as_ref() else {
|
let Some(dnd) = self.drag_offer.as_ref() else {
|
||||||
self.drag_offer = None;
|
self.drag_offer = None;
|
||||||
return (None, event::Status::Ignored);
|
return (None, event::Status::Ignored);
|
||||||
|
|
|
||||||
|
|
@ -217,9 +217,8 @@ impl<
|
||||||
}
|
}
|
||||||
|
|
||||||
state.left_pressed_position = Some(position);
|
state.left_pressed_position = Some(position);
|
||||||
// dbg!(&state, &self.id);
|
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mouse::Event::ButtonReleased(mouse::Button::Left)
|
mouse::Event::ButtonReleased(mouse::Button::Left)
|
||||||
|
|
@ -227,7 +226,7 @@ return;
|
||||||
{
|
{
|
||||||
state.left_pressed_position = None;
|
state.left_pressed_position = None;
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mouse::Event::CursorMoved { .. } => {
|
mouse::Event::CursorMoved { .. } => {
|
||||||
if let Some(position) = cursor.position() {
|
if let Some(position) = cursor.position() {
|
||||||
|
|
@ -240,7 +239,6 @@ return;
|
||||||
if let Some(left_pressed_position) =
|
if let Some(left_pressed_position) =
|
||||||
state.left_pressed_position
|
state.left_pressed_position
|
||||||
{
|
{
|
||||||
// dbg!(&state);
|
|
||||||
if position.distance(left_pressed_position)
|
if position.distance(left_pressed_position)
|
||||||
> self.drag_threshold
|
> self.drag_threshold
|
||||||
{
|
{
|
||||||
|
|
@ -261,7 +259,7 @@ return;
|
||||||
state.hovered = true;
|
state.hovered = true;
|
||||||
}
|
}
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => return ret,
|
_ => return ret,
|
||||||
|
|
@ -272,7 +270,7 @@ return;
|
||||||
if state.is_dragging {
|
if state.is_dragging {
|
||||||
state.is_dragging = false;
|
state.is_dragging = false;
|
||||||
shell.capture_event();
|
shell.capture_event();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use cctk::sctk::reexports::{
|
||||||
|
|
||||||
use iced::platform_specific::shell::commands::subsurface::get_subsurface;
|
use iced::platform_specific::shell::commands::subsurface::get_subsurface;
|
||||||
use iced::{
|
use iced::{
|
||||||
|
Element, Length, Subscription, Task,
|
||||||
event::wayland::Event as WaylandEvent,
|
event::wayland::Event as WaylandEvent,
|
||||||
platform_specific::{
|
platform_specific::{
|
||||||
runtime::wayland::subsurface::SctkSubsurfaceSettings,
|
runtime::wayland::subsurface::SctkSubsurfaceSettings,
|
||||||
|
|
@ -14,7 +15,6 @@ use iced::{
|
||||||
},
|
},
|
||||||
widget::{button, column, text, text_input},
|
widget::{button, column, text, text_input},
|
||||||
window::{self, Id, Settings},
|
window::{self, Id, Settings},
|
||||||
Element, Length, Subscription, Task,
|
|
||||||
};
|
};
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
|
@ -70,20 +70,17 @@ impl SubsurfaceApp {
|
||||||
|
|
||||||
fn update(&mut self, message: Message) -> Task<Message> {
|
fn update(&mut self, message: Message) -> Task<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::WaylandEvent(evt) => {
|
Message::WaylandEvent(evt) => match evt {
|
||||||
dbg!(&evt);
|
WaylandEvent::Output(_evt, output) => {
|
||||||
match evt {
|
if self.connection.is_none() {
|
||||||
WaylandEvent::Output(_evt, output) => {
|
if let Some(backend) = output.backend().upgrade() {
|
||||||
if self.connection.is_none() {
|
self.connection =
|
||||||
if let Some(backend) = output.backend().upgrade() {
|
Some(Connection::from_backend(backend));
|
||||||
self.connection =
|
|
||||||
Some(Connection::from_backend(backend));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
}
|
||||||
}
|
_ => {}
|
||||||
|
},
|
||||||
Message::Wayland(evt) => match evt {
|
Message::Wayland(evt) => match evt {
|
||||||
wayland::Event::RedBuffer(buffer) => {
|
wayland::Event::RedBuffer(buffer) => {
|
||||||
self.red_buffer = Some(buffer);
|
self.red_buffer = Some(buffer);
|
||||||
|
|
|
||||||
|
|
@ -116,139 +116,6 @@ pub trait Program: Sized {
|
||||||
fn presets(&self) -> &[Preset<Self::State, Self::Message>] {
|
fn presets(&self) -> &[Preset<Self::State, Self::Message>] {
|
||||||
&[]
|
&[]
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[cfg(feature = "winit")]
|
|
||||||
// /// Runs the [`Program`].
|
|
||||||
// ///
|
|
||||||
// /// The state of the [`Program`] must implement [`Default`].
|
|
||||||
// /// If your state does not implement [`Default`], use [`run_with`]
|
|
||||||
// /// instead.
|
|
||||||
// ///
|
|
||||||
// /// [`run_with`]: Self::run_with
|
|
||||||
// fn run(
|
|
||||||
// self,
|
|
||||||
// settings: crate::Settings,
|
|
||||||
// window_settings: Option<window::Settings>,
|
|
||||||
// ) -> crate::Result
|
|
||||||
// where
|
|
||||||
// Self: 'static,
|
|
||||||
// Self::State: Default,
|
|
||||||
// {
|
|
||||||
// self.run_with(settings, window_settings, || {
|
|
||||||
// (Self::State::default(), Task::none())
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[cfg(feature = "winit")]
|
|
||||||
// /// Runs the [`Program`] with the given [`Settings`] and a closure that creates the initial state.
|
|
||||||
// fn run_with<I>(
|
|
||||||
// self,
|
|
||||||
// settings: crate::Settings,
|
|
||||||
// window_settings: Option<window::Settings>,
|
|
||||||
// initialize: I,
|
|
||||||
// ) -> crate::Result
|
|
||||||
// where
|
|
||||||
// Self: 'static,
|
|
||||||
// I: FnOnce() -> (Self::State, Task<Self::Message>) + 'static,
|
|
||||||
// {
|
|
||||||
// use std::marker::PhantomData;
|
|
||||||
|
|
||||||
// struct Instance<P: Program, I> {
|
|
||||||
// program: P,
|
|
||||||
// state: P::State,
|
|
||||||
// _initialize: PhantomData<I>,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// impl<P: Program, I: FnOnce() -> (P::State, Task<P::Message>)>
|
|
||||||
// shell::Program for Instance<P, I>
|
|
||||||
// {
|
|
||||||
// type Message = P::Message;
|
|
||||||
// type Theme = P::Theme;
|
|
||||||
// type Renderer = P::Renderer;
|
|
||||||
// type Flags = (P, I);
|
|
||||||
// type Executor = P::Executor;
|
|
||||||
|
|
||||||
// fn new(
|
|
||||||
// (program, initialize): Self::Flags,
|
|
||||||
// ) -> (Self, Task<Self::Message>) {
|
|
||||||
// let (state, task) = initialize();
|
|
||||||
|
|
||||||
// (
|
|
||||||
// Self {
|
|
||||||
// program,
|
|
||||||
// state,
|
|
||||||
// _initialize: PhantomData,
|
|
||||||
// },
|
|
||||||
// task,
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn title(&self, window: window::Id) -> String {
|
|
||||||
// self.program.title(&self.state, window)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn update(
|
|
||||||
// &mut self,
|
|
||||||
// message: Self::Message,
|
|
||||||
// ) -> Task<Self::Message> {
|
|
||||||
// self.program.update(&mut self.state, message)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn view(
|
|
||||||
// &self,
|
|
||||||
// window: window::Id,
|
|
||||||
// ) -> crate::Element<'_, Self::Message, Self::Theme, Self::Renderer>
|
|
||||||
// {
|
|
||||||
// self.program.view(&self.state, window)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn subscription(&self) -> Subscription<Self::Message> {
|
|
||||||
// self.program.subscription(&self.state)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn theme(&self, window: window::Id) -> Self::Theme {
|
|
||||||
// self.program.theme(&self.state, window)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn style(&self, theme: &Self::Theme) -> Appearance {
|
|
||||||
// self.program.style(&self.state, theme)
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn scale_factor(&self, window: window::Id) -> f64 {
|
|
||||||
// self.program.scale_factor(&self.state, window)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// #[allow(clippy::needless_update)]
|
|
||||||
// let renderer_settings = crate::graphics::Settings {
|
|
||||||
// default_font: settings.default_font,
|
|
||||||
// default_text_size: settings.default_text_size,
|
|
||||||
// antialiasing: if settings.antialiasing {
|
|
||||||
// Some(crate::graphics::Antialiasing::MSAAx4)
|
|
||||||
// } else {
|
|
||||||
// None
|
|
||||||
// },
|
|
||||||
// ..crate::graphics::Settings::default()
|
|
||||||
// };
|
|
||||||
|
|
||||||
// Ok(shell::program::run::<
|
|
||||||
// Instance<Self, I>,
|
|
||||||
// <Self::Renderer as compositor::Default>::Compositor,
|
|
||||||
// >(
|
|
||||||
// crate::Settings {
|
|
||||||
// id: settings.id,
|
|
||||||
// fonts: settings.fonts,
|
|
||||||
// default_font: settings.default_font,
|
|
||||||
// default_text_size: settings.default_text_size,
|
|
||||||
// antialiasing: settings.antialiasing,
|
|
||||||
// exit_on_close_request: settings.exit_on_close_request,
|
|
||||||
// }
|
|
||||||
// .into(),
|
|
||||||
// renderer_settings,
|
|
||||||
// window_settings,
|
|
||||||
// (self, initialize),
|
|
||||||
// )?)
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Decorates a [`Program`] with the given title function.
|
/// Decorates a [`Program`] with the given title function.
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,6 @@ workspace = true
|
||||||
[features]
|
[features]
|
||||||
debug = []
|
debug = []
|
||||||
selector = ["dep:iced_selector"]
|
selector = ["dep:iced_selector"]
|
||||||
multi-window = []
|
|
||||||
a11y = ["iced_accessibility", "iced_core/a11y"]
|
a11y = ["iced_accessibility", "iced_core/a11y"]
|
||||||
wayland = ["iced_core/wayland", "cctk"]
|
wayland = ["iced_core/wayland", "cctk"]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,279 +0,0 @@
|
||||||
//! The internal state of a multi-window [`Program`].
|
|
||||||
use crate::core::event::{self, Event};
|
|
||||||
use crate::core::mouse;
|
|
||||||
use crate::core::renderer;
|
|
||||||
use crate::core::widget::operation::{self, Operation};
|
|
||||||
use crate::core::{Clipboard, Size};
|
|
||||||
use crate::user_interface::{self, UserInterface};
|
|
||||||
use crate::{Debug, Program, Task};
|
|
||||||
|
|
||||||
/// The execution state of a multi-window [`Program`]. It leverages caching, event
|
|
||||||
/// processing, and rendering primitive storage.
|
|
||||||
#[allow(missing_debug_implementations)]
|
|
||||||
pub struct State<P>
|
|
||||||
where
|
|
||||||
P: Program + 'static,
|
|
||||||
{
|
|
||||||
program: P,
|
|
||||||
caches: Option<Vec<user_interface::Cache>>,
|
|
||||||
queued_events: Vec<Event>,
|
|
||||||
queued_messages: Vec<P::Message>,
|
|
||||||
mouse_interaction: mouse::Interaction,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P> State<P>
|
|
||||||
where
|
|
||||||
P: Program + 'static,
|
|
||||||
{
|
|
||||||
/// Creates a new [`State`] with the provided [`Program`], initializing its
|
|
||||||
/// primitive with the given logical bounds and renderer.
|
|
||||||
pub fn new(
|
|
||||||
program: P,
|
|
||||||
bounds: Size,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) -> Self {
|
|
||||||
let user_interface = build_user_interface(
|
|
||||||
&program,
|
|
||||||
user_interface::Cache::default(),
|
|
||||||
renderer,
|
|
||||||
bounds,
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
|
|
||||||
let caches = Some(vec![user_interface.into_cache()]);
|
|
||||||
|
|
||||||
State {
|
|
||||||
program,
|
|
||||||
caches,
|
|
||||||
queued_events: Vec::new(),
|
|
||||||
queued_messages: Vec::new(),
|
|
||||||
mouse_interaction: mouse::Interaction::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to the [`Program`] of the [`State`].
|
|
||||||
pub fn program(&self) -> &P {
|
|
||||||
&self.program
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queues an event in the [`State`] for processing during an [`update`].
|
|
||||||
///
|
|
||||||
/// [`update`]: Self::update
|
|
||||||
pub fn queue_event(&mut self, event: Event) {
|
|
||||||
self.queued_events.push(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queues a message in the [`State`] for processing during an [`update`].
|
|
||||||
///
|
|
||||||
/// [`update`]: Self::update
|
|
||||||
pub fn queue_message(&mut self, message: P::Message) {
|
|
||||||
self.queued_messages.push(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the event queue of the [`State`] is empty or not.
|
|
||||||
pub fn is_queue_empty(&self) -> bool {
|
|
||||||
self.queued_events.is_empty() && self.queued_messages.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current [`mouse::Interaction`] of the [`State`].
|
|
||||||
pub fn mouse_interaction(&self) -> mouse::Interaction {
|
|
||||||
self.mouse_interaction
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Processes all the queued events and messages, rebuilding and redrawing
|
|
||||||
/// the widgets of the linked [`Program`] if necessary.
|
|
||||||
///
|
|
||||||
/// Returns a list containing the instances of [`Event`] that were not
|
|
||||||
/// captured by any widget, and the [`Task`] obtained from [`Program`]
|
|
||||||
/// after updating it, only if an update was necessary.
|
|
||||||
pub fn update(
|
|
||||||
&mut self,
|
|
||||||
bounds: Size,
|
|
||||||
cursor: mouse::Cursor,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
theme: &P::Theme,
|
|
||||||
style: &renderer::Style,
|
|
||||||
clipboard: &mut dyn Clipboard,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) -> (Vec<Event>, Option<Task<P::Message>>) {
|
|
||||||
let mut user_interfaces = build_user_interfaces(
|
|
||||||
&self.program,
|
|
||||||
self.caches.take().unwrap(),
|
|
||||||
renderer,
|
|
||||||
bounds,
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug.event_processing_started();
|
|
||||||
let mut messages = Vec::new();
|
|
||||||
|
|
||||||
let uncaptured_events = user_interfaces.iter_mut().fold(
|
|
||||||
vec![],
|
|
||||||
|mut uncaptured_events, ui| {
|
|
||||||
let (_, event_statuses) = ui.update(
|
|
||||||
&self.queued_events,
|
|
||||||
cursor,
|
|
||||||
renderer,
|
|
||||||
clipboard,
|
|
||||||
&mut messages,
|
|
||||||
);
|
|
||||||
|
|
||||||
uncaptured_events.extend(
|
|
||||||
self.queued_events
|
|
||||||
.iter()
|
|
||||||
.zip(event_statuses)
|
|
||||||
.filter_map(|(event, status)| {
|
|
||||||
matches!(status, event::Status::Ignored)
|
|
||||||
.then_some(event)
|
|
||||||
})
|
|
||||||
.cloned(),
|
|
||||||
);
|
|
||||||
uncaptured_events
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
self.queued_events.clear();
|
|
||||||
messages.append(&mut self.queued_messages);
|
|
||||||
debug.event_processing_finished();
|
|
||||||
|
|
||||||
let commands = if messages.is_empty() {
|
|
||||||
debug.draw_started();
|
|
||||||
|
|
||||||
for ui in &mut user_interfaces {
|
|
||||||
self.mouse_interaction =
|
|
||||||
ui.draw(renderer, theme, style, cursor);
|
|
||||||
}
|
|
||||||
|
|
||||||
debug.draw_finished();
|
|
||||||
|
|
||||||
self.caches = Some(
|
|
||||||
user_interfaces
|
|
||||||
.drain(..)
|
|
||||||
.map(UserInterface::into_cache)
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
let temp_caches = user_interfaces
|
|
||||||
.drain(..)
|
|
||||||
.map(UserInterface::into_cache)
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
drop(user_interfaces);
|
|
||||||
|
|
||||||
let commands = Task::batch(messages.into_iter().map(|msg| {
|
|
||||||
debug.log_message(&msg);
|
|
||||||
|
|
||||||
debug.update_started();
|
|
||||||
let task = self.program.update(msg);
|
|
||||||
debug.update_finished();
|
|
||||||
|
|
||||||
task
|
|
||||||
}));
|
|
||||||
|
|
||||||
let mut user_interfaces = build_user_interfaces(
|
|
||||||
&self.program,
|
|
||||||
temp_caches,
|
|
||||||
renderer,
|
|
||||||
bounds,
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug.draw_started();
|
|
||||||
for ui in &mut user_interfaces {
|
|
||||||
self.mouse_interaction =
|
|
||||||
ui.draw(renderer, theme, style, cursor);
|
|
||||||
}
|
|
||||||
debug.draw_finished();
|
|
||||||
|
|
||||||
self.caches = Some(
|
|
||||||
user_interfaces
|
|
||||||
.drain(..)
|
|
||||||
.map(UserInterface::into_cache)
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
|
|
||||||
Some(commands)
|
|
||||||
};
|
|
||||||
|
|
||||||
(uncaptured_events, commands)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Applies widget [`Operation`]s to the [`State`].
|
|
||||||
pub fn operate(
|
|
||||||
&mut self,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
operations: impl Iterator<Item = Box<dyn Operation>>,
|
|
||||||
bounds: Size,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) {
|
|
||||||
let mut user_interfaces = build_user_interfaces(
|
|
||||||
&self.program,
|
|
||||||
self.caches.take().unwrap(),
|
|
||||||
renderer,
|
|
||||||
bounds,
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
|
|
||||||
for operation in operations {
|
|
||||||
let mut current_operation = Some(operation);
|
|
||||||
|
|
||||||
while let Some(mut operation) = current_operation.take() {
|
|
||||||
for ui in &mut user_interfaces {
|
|
||||||
ui.operate(renderer, operation.as_mut());
|
|
||||||
}
|
|
||||||
|
|
||||||
match operation.finish() {
|
|
||||||
operation::Outcome::None => {}
|
|
||||||
operation::Outcome::Some(()) => {}
|
|
||||||
operation::Outcome::Chain(next) => {
|
|
||||||
current_operation = Some(next);
|
|
||||||
}
|
|
||||||
_ => {}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.caches = Some(
|
|
||||||
user_interfaces
|
|
||||||
.drain(..)
|
|
||||||
.map(UserInterface::into_cache)
|
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_user_interfaces<'a, P: Program>(
|
|
||||||
program: &'a P,
|
|
||||||
mut caches: Vec<user_interface::Cache>,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
size: Size,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) -> Vec<UserInterface<'a, P::Message, P::Theme, P::Renderer>> {
|
|
||||||
caches
|
|
||||||
.drain(..)
|
|
||||||
.map(|cache| {
|
|
||||||
build_user_interface(program, cache, renderer, size, debug)
|
|
||||||
})
|
|
||||||
.collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_user_interface<'a, P: Program>(
|
|
||||||
program: &'a P,
|
|
||||||
cache: user_interface::Cache,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
size: Size,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> {
|
|
||||||
debug.view_started();
|
|
||||||
let view = program.view();
|
|
||||||
debug.view_finished();
|
|
||||||
|
|
||||||
debug.layout_started();
|
|
||||||
let user_interface = UserInterface::build(view, size, cache, renderer);
|
|
||||||
debug.layout_finished();
|
|
||||||
|
|
||||||
user_interface
|
|
||||||
}
|
|
||||||
|
|
@ -1,237 +0,0 @@
|
||||||
use crate::core::event::{self, Event};
|
|
||||||
use crate::core::mouse;
|
|
||||||
use crate::core::renderer;
|
|
||||||
use crate::core::widget::operation::{self, Operation};
|
|
||||||
use crate::core::{Clipboard, Size};
|
|
||||||
use crate::user_interface::{self, UserInterface};
|
|
||||||
use crate::{Debug, Program, Task};
|
|
||||||
|
|
||||||
/// The execution state of a [`Program`]. It leverages caching, event
|
|
||||||
/// processing, and rendering primitive storage.
|
|
||||||
#[allow(missing_debug_implementations)]
|
|
||||||
pub struct State<P>
|
|
||||||
where
|
|
||||||
P: Program + 'static,
|
|
||||||
{
|
|
||||||
program: P,
|
|
||||||
cache: Option<user_interface::Cache>,
|
|
||||||
queued_events: Vec<Event>,
|
|
||||||
queued_messages: Vec<P::Message>,
|
|
||||||
mouse_interaction: mouse::Interaction,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<P> State<P>
|
|
||||||
where
|
|
||||||
P: Program + 'static,
|
|
||||||
{
|
|
||||||
/// Creates a new [`State`] with the provided [`Program`], initializing its
|
|
||||||
/// primitive with the given logical bounds and renderer.
|
|
||||||
pub fn new(
|
|
||||||
id: iced_core::id::Id,
|
|
||||||
mut program: P,
|
|
||||||
bounds: Size,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) -> Self {
|
|
||||||
let user_interface = build_user_interface(
|
|
||||||
id,
|
|
||||||
&mut program,
|
|
||||||
user_interface::Cache::default(),
|
|
||||||
renderer,
|
|
||||||
bounds,
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
|
|
||||||
let cache = Some(user_interface.into_cache());
|
|
||||||
|
|
||||||
State {
|
|
||||||
program,
|
|
||||||
cache,
|
|
||||||
queued_events: Vec::new(),
|
|
||||||
queued_messages: Vec::new(),
|
|
||||||
mouse_interaction: mouse::Interaction::None,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a reference to the [`Program`] of the [`State`].
|
|
||||||
pub fn program(&self) -> &P {
|
|
||||||
&self.program
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queues an event in the [`State`] for processing during an [`update`].
|
|
||||||
///
|
|
||||||
/// [`update`]: Self::update
|
|
||||||
pub fn queue_event(&mut self, event: Event) {
|
|
||||||
self.queued_events.push(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queues a message in the [`State`] for processing during an [`update`].
|
|
||||||
///
|
|
||||||
/// [`update`]: Self::update
|
|
||||||
pub fn queue_message(&mut self, message: P::Message) {
|
|
||||||
self.queued_messages.push(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether the event queue of the [`State`] is empty or not.
|
|
||||||
pub fn is_queue_empty(&self) -> bool {
|
|
||||||
self.queued_events.is_empty() && self.queued_messages.is_empty()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the current [`mouse::Interaction`] of the [`State`].
|
|
||||||
pub fn mouse_interaction(&self) -> mouse::Interaction {
|
|
||||||
self.mouse_interaction
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Processes all the queued events and messages, rebuilding and redrawing
|
|
||||||
/// the widgets of the linked [`Program`] if necessary.
|
|
||||||
///
|
|
||||||
/// Returns a list containing the instances of [`Event`] that were not
|
|
||||||
/// captured by any widget, and the [`Task`] obtained from [`Program`]
|
|
||||||
/// after updating it, only if an update was necessary.
|
|
||||||
pub fn update(
|
|
||||||
&mut self,
|
|
||||||
id: iced_core::id::Id,
|
|
||||||
bounds: Size,
|
|
||||||
cursor: mouse::Cursor,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
theme: &P::Theme,
|
|
||||||
style: &renderer::Style,
|
|
||||||
clipboard: &mut dyn Clipboard,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) -> (Vec<Event>, Option<Task<P::Message>>) {
|
|
||||||
let mut user_interface = build_user_interface(
|
|
||||||
id.clone(),
|
|
||||||
&mut self.program,
|
|
||||||
self.cache.take().unwrap(),
|
|
||||||
renderer,
|
|
||||||
bounds,
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug.event_processing_started();
|
|
||||||
let mut messages = Vec::new();
|
|
||||||
|
|
||||||
let (_, event_statuses) = user_interface.update(
|
|
||||||
&self.queued_events,
|
|
||||||
cursor,
|
|
||||||
renderer,
|
|
||||||
clipboard,
|
|
||||||
&mut messages,
|
|
||||||
);
|
|
||||||
|
|
||||||
let uncaptured_events = self
|
|
||||||
.queued_events
|
|
||||||
.iter()
|
|
||||||
.zip(event_statuses)
|
|
||||||
.filter_map(|(event, status)| {
|
|
||||||
matches!(status, event::Status::Ignored).then_some(event)
|
|
||||||
})
|
|
||||||
.cloned()
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
self.queued_events.clear();
|
|
||||||
messages.append(&mut self.queued_messages);
|
|
||||||
debug.event_processing_finished();
|
|
||||||
|
|
||||||
let task = if messages.is_empty() {
|
|
||||||
debug.draw_started();
|
|
||||||
self.mouse_interaction =
|
|
||||||
user_interface.draw(renderer, theme, style, cursor);
|
|
||||||
debug.draw_finished();
|
|
||||||
|
|
||||||
self.cache = Some(user_interface.into_cache());
|
|
||||||
|
|
||||||
None
|
|
||||||
} else {
|
|
||||||
// When there are messages, we are forced to rebuild twice
|
|
||||||
// for now :^)
|
|
||||||
let temp_cache = user_interface.into_cache();
|
|
||||||
|
|
||||||
let tasks = Task::batch(messages.into_iter().map(|message| {
|
|
||||||
debug.log_message(&message);
|
|
||||||
|
|
||||||
debug.update_started();
|
|
||||||
let task = self.program.update(message);
|
|
||||||
debug.update_finished();
|
|
||||||
|
|
||||||
task
|
|
||||||
}));
|
|
||||||
|
|
||||||
let mut user_interface = build_user_interface(
|
|
||||||
id,
|
|
||||||
&mut self.program,
|
|
||||||
temp_cache,
|
|
||||||
renderer,
|
|
||||||
bounds,
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
|
|
||||||
debug.draw_started();
|
|
||||||
self.mouse_interaction =
|
|
||||||
user_interface.draw(renderer, theme, style, cursor);
|
|
||||||
debug.draw_finished();
|
|
||||||
|
|
||||||
self.cache = Some(user_interface.into_cache());
|
|
||||||
|
|
||||||
Some(tasks)
|
|
||||||
};
|
|
||||||
|
|
||||||
(uncaptured_events, task)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Applies [`Operation`]s to the [`State`]
|
|
||||||
pub fn operate(
|
|
||||||
&mut self,
|
|
||||||
id: iced_core::id::Id,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
operations: impl Iterator<Item = Box<dyn Operation>>,
|
|
||||||
bounds: Size,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) {
|
|
||||||
let mut user_interface = build_user_interface(
|
|
||||||
id,
|
|
||||||
&mut self.program,
|
|
||||||
self.cache.take().unwrap(),
|
|
||||||
renderer,
|
|
||||||
bounds,
|
|
||||||
debug,
|
|
||||||
);
|
|
||||||
|
|
||||||
for operation in operations {
|
|
||||||
let mut current_operation = Some(operation);
|
|
||||||
|
|
||||||
while let Some(mut operation) = current_operation.take() {
|
|
||||||
user_interface.operate(renderer, operation.as_mut());
|
|
||||||
|
|
||||||
match operation.finish() {
|
|
||||||
operation::Outcome::None => {}
|
|
||||||
operation::Outcome::Some(()) => {}
|
|
||||||
operation::Outcome::Chain(next) => {
|
|
||||||
current_operation = Some(next);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
self.cache = Some(user_interface.into_cache());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn build_user_interface<'a, P: Program>(
|
|
||||||
_id: iced_core::id::Id,
|
|
||||||
program: &'a mut P,
|
|
||||||
cache: user_interface::Cache,
|
|
||||||
renderer: &mut P::Renderer,
|
|
||||||
size: Size,
|
|
||||||
debug: &mut Debug,
|
|
||||||
) -> UserInterface<'a, P::Message, P::Theme, P::Renderer> {
|
|
||||||
debug.view_started();
|
|
||||||
let view = program.view();
|
|
||||||
debug.view_finished();
|
|
||||||
|
|
||||||
debug.layout_started();
|
|
||||||
let user_interface = UserInterface::build(view, size, cache, renderer);
|
|
||||||
debug.layout_finished();
|
|
||||||
|
|
||||||
user_interface
|
|
||||||
}
|
|
||||||
23
src/lib.rs
23
src/lib.rs
|
|
@ -492,17 +492,17 @@ pub use iced_widget::core;
|
||||||
#[cfg(feature = "winit")]
|
#[cfg(feature = "winit")]
|
||||||
use iced_winit as shell;
|
use iced_winit as shell;
|
||||||
|
|
||||||
#[cfg(not(any(
|
// #[cfg(not(any(
|
||||||
target_arch = "wasm32",
|
// target_arch = "wasm32",
|
||||||
feature = "thread-pool",
|
// feature = "thread-pool",
|
||||||
feature = "tokio",
|
// feature = "tokio",
|
||||||
feature = "smol"
|
// feature = "smol"
|
||||||
)))]
|
// )))]
|
||||||
compile_error!(
|
// compile_error!(
|
||||||
"No futures executor has been enabled! You must enable an \
|
// "No futures executor has been enabled! You must enable an \
|
||||||
executor feature.\n\
|
// executor feature.\n\
|
||||||
Available options: thread-pool, tokio, or smol."
|
// Available options: thread-pool, tokio, or smol."
|
||||||
);
|
// );
|
||||||
|
|
||||||
// #[cfg(all(
|
// #[cfg(all(
|
||||||
// target_family = "unix",
|
// target_family = "unix",
|
||||||
|
|
@ -515,7 +515,6 @@ compile_error!(
|
||||||
// display server feature.\n\
|
// display server feature.\n\
|
||||||
// Available options: x11, wayland."
|
// Available options: x11, wayland."
|
||||||
// );
|
// );
|
||||||
|
|
||||||
#[cfg(feature = "highlighter")]
|
#[cfg(feature = "highlighter")]
|
||||||
pub use iced_highlighter as highlighter;
|
pub use iced_highlighter as highlighter;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -373,7 +373,6 @@ where
|
||||||
}
|
}
|
||||||
.build(),
|
.build(),
|
||||||
));
|
));
|
||||||
|
|
||||||
shell.invalidate_layout();
|
shell.invalidate_layout();
|
||||||
shell.request_redraw();
|
shell.request_redraw();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,522 +0,0 @@
|
||||||
use crate::core::event::{self, Event};
|
|
||||||
use crate::core::layout::{self, Layout};
|
|
||||||
use crate::core::mouse;
|
|
||||||
use crate::core::overlay;
|
|
||||||
use crate::core::renderer;
|
|
||||||
use crate::core::widget::tree::{self, Tree};
|
|
||||||
use crate::core::{
|
|
||||||
self, Clipboard, Element, Length, Point, Rectangle, Shell, Size, Vector,
|
|
||||||
Widget,
|
|
||||||
};
|
|
||||||
use crate::horizontal_space;
|
|
||||||
use crate::runtime::overlay::Nested;
|
|
||||||
|
|
||||||
use iced_renderer::core::widget::Operation;
|
|
||||||
use ouroboros::self_referencing;
|
|
||||||
use std::cell::{RefCell, RefMut};
|
|
||||||
use std::marker::PhantomData;
|
|
||||||
use std::ops::Deref;
|
|
||||||
|
|
||||||
/// A widget that is aware of its dimensions.
|
|
||||||
///
|
|
||||||
/// A [`Responsive`] widget will always try to fill all the available space of
|
|
||||||
/// its parent.
|
|
||||||
#[cfg(feature = "lazy")]
|
|
||||||
#[allow(missing_debug_implementations)]
|
|
||||||
pub struct Responsive<
|
|
||||||
'a,
|
|
||||||
Message,
|
|
||||||
Theme = crate::Theme,
|
|
||||||
Renderer = crate::Renderer,
|
|
||||||
> {
|
|
||||||
view: Box<dyn Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a>,
|
|
||||||
content: RefCell<Content<'a, Message, Theme, Renderer>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer> Responsive<'a, Message, Theme, Renderer>
|
|
||||||
where
|
|
||||||
Renderer: core::Renderer,
|
|
||||||
{
|
|
||||||
/// Creates a new [`Responsive`] widget with a closure that produces its
|
|
||||||
/// contents.
|
|
||||||
///
|
|
||||||
/// The `view` closure will be provided with the current [`Size`] of
|
|
||||||
/// the [`Responsive`] widget and, therefore, can be used to build the
|
|
||||||
/// contents of the widget in a responsive way.
|
|
||||||
pub fn new(
|
|
||||||
view: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
view: Box::new(view),
|
|
||||||
content: RefCell::new(Content {
|
|
||||||
size: Size::ZERO,
|
|
||||||
layout: None,
|
|
||||||
element: Element::new(horizontal_space().width(0)),
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct Content<'a, Message, Theme, Renderer> {
|
|
||||||
size: Size,
|
|
||||||
layout: Option<layout::Node>,
|
|
||||||
element: Element<'a, Message, Theme, Renderer>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer> Content<'a, Message, Theme, Renderer>
|
|
||||||
where
|
|
||||||
Renderer: core::Renderer,
|
|
||||||
{
|
|
||||||
fn layout(&mut self, tree: &mut Tree, renderer: &Renderer) {
|
|
||||||
if self.layout.is_none() {
|
|
||||||
self.layout = Some(self.element.as_widget().layout(
|
|
||||||
tree,
|
|
||||||
renderer,
|
|
||||||
&layout::Limits::new(Size::ZERO, self.size),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(
|
|
||||||
&mut self,
|
|
||||||
tree: &mut Tree,
|
|
||||||
new_size: Size,
|
|
||||||
view: &dyn Fn(Size) -> Element<'a, Message, Theme, Renderer>,
|
|
||||||
) {
|
|
||||||
if self.size == new_size {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
self.element = view(new_size);
|
|
||||||
self.size = new_size;
|
|
||||||
self.layout = None;
|
|
||||||
|
|
||||||
tree.diff(&mut self.element);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn resolve<R, T>(
|
|
||||||
&mut self,
|
|
||||||
tree: &mut Tree,
|
|
||||||
renderer: R,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
view: &dyn Fn(Size) -> Element<'a, Message, Theme, Renderer>,
|
|
||||||
f: impl FnOnce(
|
|
||||||
&mut Tree,
|
|
||||||
R,
|
|
||||||
Layout<'_>,
|
|
||||||
&mut Element<'a, Message, Theme, Renderer>,
|
|
||||||
) -> T,
|
|
||||||
) -> T
|
|
||||||
where
|
|
||||||
R: Deref<Target = Renderer>,
|
|
||||||
{
|
|
||||||
self.update(tree, layout.bounds().size(), view);
|
|
||||||
self.layout(tree, renderer.deref());
|
|
||||||
|
|
||||||
let content_layout = Layout::with_offset(
|
|
||||||
layout.position() - Point::ORIGIN,
|
|
||||||
self.layout.as_ref().unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
f(tree, renderer, content_layout, &mut self.element)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct State {
|
|
||||||
tree: RefCell<Tree>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
|
|
||||||
for Responsive<'a, Message, Theme, Renderer>
|
|
||||||
where
|
|
||||||
Renderer: core::Renderer,
|
|
||||||
{
|
|
||||||
fn tag(&self) -> tree::Tag {
|
|
||||||
tree::Tag::of::<State>()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn state(&self) -> tree::State {
|
|
||||||
tree::State::new(State {
|
|
||||||
tree: RefCell::new(Tree::empty()),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn size(&self) -> Size<Length> {
|
|
||||||
Size {
|
|
||||||
width: Length::Fill,
|
|
||||||
height: Length::Fill,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn layout(
|
|
||||||
&self,
|
|
||||||
_tree: &mut Tree,
|
|
||||||
_renderer: &Renderer,
|
|
||||||
limits: &layout::Limits,
|
|
||||||
) -> layout::Node {
|
|
||||||
layout::Node::new(limits.max())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn operate(
|
|
||||||
&self,
|
|
||||||
tree: &mut Tree,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
renderer: &Renderer,
|
|
||||||
operation: &mut dyn crate::core::widget::Operation,
|
|
||||||
) {
|
|
||||||
let state = tree.state.downcast_mut::<State>();
|
|
||||||
let mut content = self.content.borrow_mut();
|
|
||||||
|
|
||||||
content.resolve(
|
|
||||||
&mut state.tree.borrow_mut(),
|
|
||||||
renderer,
|
|
||||||
layout,
|
|
||||||
&self.view,
|
|
||||||
|tree, renderer, layout, element| {
|
|
||||||
element
|
|
||||||
.as_widget()
|
|
||||||
.operate(tree, layout, renderer, operation);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(
|
|
||||||
&mut self,
|
|
||||||
tree: &mut Tree,
|
|
||||||
event: Event,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
cursor: mouse::Cursor,
|
|
||||||
renderer: &Renderer,
|
|
||||||
clipboard: &mut dyn Clipboard,
|
|
||||||
shell: &mut Shell<'_, Message>,
|
|
||||||
viewport: &Rectangle,
|
|
||||||
) -> event::Status {
|
|
||||||
let state = tree.state.downcast_mut::<State>();
|
|
||||||
let mut content = self.content.borrow_mut();
|
|
||||||
|
|
||||||
let mut local_messages = vec![];
|
|
||||||
let mut local_shell = Shell::new(&mut local_messages);
|
|
||||||
|
|
||||||
let status = content.resolve(
|
|
||||||
&mut state.tree.borrow_mut(),
|
|
||||||
renderer,
|
|
||||||
layout,
|
|
||||||
&self.view,
|
|
||||||
|tree, renderer, layout, element| {
|
|
||||||
element.as_widget_mut().on_event(
|
|
||||||
tree,
|
|
||||||
event,
|
|
||||||
layout,
|
|
||||||
cursor,
|
|
||||||
renderer,
|
|
||||||
clipboard,
|
|
||||||
&mut local_shell,
|
|
||||||
viewport,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if local_shell.is_layout_invalid() {
|
|
||||||
content.layout = None;
|
|
||||||
}
|
|
||||||
|
|
||||||
shell.merge(local_shell, std::convert::identity);
|
|
||||||
|
|
||||||
status
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(
|
|
||||||
&self,
|
|
||||||
tree: &Tree,
|
|
||||||
renderer: &mut Renderer,
|
|
||||||
theme: &Theme,
|
|
||||||
style: &renderer::Style,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
cursor: mouse::Cursor,
|
|
||||||
viewport: &Rectangle,
|
|
||||||
) {
|
|
||||||
let state = tree.state.downcast_ref::<State>();
|
|
||||||
let mut content = self.content.borrow_mut();
|
|
||||||
|
|
||||||
content.resolve(
|
|
||||||
&mut state.tree.borrow_mut(),
|
|
||||||
renderer,
|
|
||||||
layout,
|
|
||||||
&self.view,
|
|
||||||
|tree, renderer, layout, element| {
|
|
||||||
element.as_widget().draw(
|
|
||||||
tree, renderer, theme, style, layout, cursor, viewport,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mouse_interaction(
|
|
||||||
&self,
|
|
||||||
tree: &Tree,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
cursor: mouse::Cursor,
|
|
||||||
viewport: &Rectangle,
|
|
||||||
renderer: &Renderer,
|
|
||||||
) -> mouse::Interaction {
|
|
||||||
let state = tree.state.downcast_ref::<State>();
|
|
||||||
let mut content = self.content.borrow_mut();
|
|
||||||
|
|
||||||
content.resolve(
|
|
||||||
&mut state.tree.borrow_mut(),
|
|
||||||
renderer,
|
|
||||||
layout,
|
|
||||||
&self.view,
|
|
||||||
|tree, renderer, layout, element| {
|
|
||||||
element
|
|
||||||
.as_widget()
|
|
||||||
.mouse_interaction(tree, layout, cursor, viewport, renderer)
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn overlay<'b>(
|
|
||||||
&'b mut self,
|
|
||||||
tree: &'b mut Tree,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
renderer: &Renderer,
|
|
||||||
translation: Vector,
|
|
||||||
) -> Option<overlay::Element<'b, Message, Theme, Renderer>> {
|
|
||||||
use std::ops::DerefMut;
|
|
||||||
|
|
||||||
let state = tree.state.downcast_ref::<State>();
|
|
||||||
|
|
||||||
let overlay = OverlayBuilder {
|
|
||||||
content: self.content.borrow_mut(),
|
|
||||||
tree: state.tree.borrow_mut(),
|
|
||||||
types: PhantomData,
|
|
||||||
overlay_builder: |content: &mut RefMut<
|
|
||||||
'_,
|
|
||||||
Content<'_, _, _, _>,
|
|
||||||
>,
|
|
||||||
tree| {
|
|
||||||
content.update(tree, layout.bounds().size(), &self.view);
|
|
||||||
content.layout(tree, renderer);
|
|
||||||
|
|
||||||
let Content {
|
|
||||||
element,
|
|
||||||
layout: content_layout_node,
|
|
||||||
..
|
|
||||||
} = content.deref_mut();
|
|
||||||
|
|
||||||
let content_layout = Layout::with_offset(
|
|
||||||
layout.bounds().position() - Point::ORIGIN,
|
|
||||||
content_layout_node.as_ref().unwrap(),
|
|
||||||
);
|
|
||||||
|
|
||||||
(
|
|
||||||
element
|
|
||||||
.as_widget_mut()
|
|
||||||
.overlay(tree, content_layout, renderer, translation)
|
|
||||||
.map(|overlay| RefCell::new(Nested::new(overlay))),
|
|
||||||
content_layout_node,
|
|
||||||
)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
.build();
|
|
||||||
|
|
||||||
if overlay.with_overlay(|(overlay, _layout)| overlay.is_some()) {
|
|
||||||
Some(overlay::Element::new(Box::new(overlay)))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "a11y")]
|
|
||||||
fn a11y_nodes(
|
|
||||||
&self,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
tree: &Tree,
|
|
||||||
cursor_position: mouse::Cursor,
|
|
||||||
) -> iced_accessibility::A11yTree {
|
|
||||||
let state = tree.state.downcast_ref::<State>().tree.borrow();
|
|
||||||
self.content.borrow().element.as_widget().a11y_nodes(
|
|
||||||
layout,
|
|
||||||
&*state,
|
|
||||||
cursor_position,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn id(&self) -> Option<core::widget::Id> {
|
|
||||||
self.content.borrow().element.as_widget().id()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_id(&mut self, _id: iced_runtime::core::id::Id) {
|
|
||||||
self.content
|
|
||||||
.borrow_mut()
|
|
||||||
.element
|
|
||||||
.as_widget_mut()
|
|
||||||
.set_id(_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn drag_destinations(
|
|
||||||
&self,
|
|
||||||
state: &Tree,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
renderer: &Renderer,
|
|
||||||
dnd_rectangles: &mut core::clipboard::DndDestinationRectangles,
|
|
||||||
) {
|
|
||||||
let ret = self.content.borrow_mut().resolve(
|
|
||||||
&mut state.state.downcast_ref::<State>().tree.borrow_mut(),
|
|
||||||
renderer,
|
|
||||||
layout,
|
|
||||||
&self.view,
|
|
||||||
|tree, r, layout, element| {
|
|
||||||
element.as_widget().drag_destinations(
|
|
||||||
tree,
|
|
||||||
layout,
|
|
||||||
r,
|
|
||||||
dnd_rectangles,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
ret
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, Message, Theme, Renderer>
|
|
||||||
From<Responsive<'a, Message, Theme, Renderer>>
|
|
||||||
for Element<'a, Message, Theme, Renderer>
|
|
||||||
where
|
|
||||||
Message: 'a,
|
|
||||||
Theme: 'a,
|
|
||||||
Renderer: core::Renderer + 'a,
|
|
||||||
{
|
|
||||||
fn from(responsive: Responsive<'a, Message, Theme, Renderer>) -> Self {
|
|
||||||
Self::new(responsive)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[self_referencing]
|
|
||||||
struct Overlay<'a, 'b, Message, Theme, Renderer> {
|
|
||||||
content: RefMut<'a, Content<'b, Message, Theme, Renderer>>,
|
|
||||||
tree: RefMut<'a, Tree>,
|
|
||||||
types: PhantomData<Message>,
|
|
||||||
|
|
||||||
#[borrows(mut content, mut tree)]
|
|
||||||
#[not_covariant]
|
|
||||||
overlay: (
|
|
||||||
Option<RefCell<Nested<'this, Message, Theme, Renderer>>>,
|
|
||||||
&'this mut Option<layout::Node>,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, Message, Theme, Renderer>
|
|
||||||
Overlay<'a, 'b, Message, Theme, Renderer>
|
|
||||||
{
|
|
||||||
fn with_overlay_maybe<T>(
|
|
||||||
&self,
|
|
||||||
f: impl FnOnce(&mut Nested<'_, Message, Theme, Renderer>) -> T,
|
|
||||||
) -> Option<T> {
|
|
||||||
self.with_overlay(|(overlay, _layout)| {
|
|
||||||
overlay.as_ref().map(|nested| (f)(&mut nested.borrow_mut()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn with_overlay_mut_maybe<T>(
|
|
||||||
&mut self,
|
|
||||||
f: impl FnOnce(&mut Nested<'_, Message, Theme, Renderer>) -> T,
|
|
||||||
) -> Option<T> {
|
|
||||||
self.with_overlay_mut(|(overlay, _layout)| {
|
|
||||||
overlay.as_mut().map(|nested| (f)(nested.get_mut()))
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, 'b, Message, Theme, Renderer>
|
|
||||||
overlay::Overlay<Message, Theme, Renderer>
|
|
||||||
for Overlay<'a, 'b, Message, Theme, Renderer>
|
|
||||||
where
|
|
||||||
Renderer: core::Renderer,
|
|
||||||
{
|
|
||||||
fn layout(&mut self, renderer: &Renderer, bounds: Size) -> layout::Node {
|
|
||||||
self.with_overlay_maybe(|overlay| overlay.layout(renderer, bounds))
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn draw(
|
|
||||||
&self,
|
|
||||||
renderer: &mut Renderer,
|
|
||||||
theme: &Theme,
|
|
||||||
style: &renderer::Style,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
cursor: mouse::Cursor,
|
|
||||||
) {
|
|
||||||
let _ = self.with_overlay_maybe(|overlay| {
|
|
||||||
overlay.draw(renderer, theme, style, layout, cursor);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn mouse_interaction(
|
|
||||||
&self,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
cursor: mouse::Cursor,
|
|
||||||
viewport: &Rectangle,
|
|
||||||
renderer: &Renderer,
|
|
||||||
) -> mouse::Interaction {
|
|
||||||
self.with_overlay_maybe(|overlay| {
|
|
||||||
overlay.mouse_interaction(layout, cursor, viewport, renderer)
|
|
||||||
})
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(
|
|
||||||
&mut self,
|
|
||||||
event: Event,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
cursor: mouse::Cursor,
|
|
||||||
renderer: &Renderer,
|
|
||||||
clipboard: &mut dyn Clipboard,
|
|
||||||
shell: &mut Shell<'_, Message>,
|
|
||||||
) -> event::Status {
|
|
||||||
let mut is_layout_invalid = false;
|
|
||||||
|
|
||||||
let event_status = self
|
|
||||||
.with_overlay_mut_maybe(|overlay| {
|
|
||||||
let event_status = overlay.on_event(
|
|
||||||
event, layout, cursor, renderer, clipboard, shell,
|
|
||||||
);
|
|
||||||
|
|
||||||
is_layout_invalid = shell.is_layout_invalid();
|
|
||||||
|
|
||||||
event_status
|
|
||||||
})
|
|
||||||
.unwrap_or(event::Status::Ignored);
|
|
||||||
|
|
||||||
if is_layout_invalid {
|
|
||||||
self.with_overlay_mut(|(_overlay, layout)| {
|
|
||||||
**layout = None;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
event_status
|
|
||||||
}
|
|
||||||
|
|
||||||
fn is_over(
|
|
||||||
&self,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
renderer: &Renderer,
|
|
||||||
cursor_position: Point,
|
|
||||||
) -> bool {
|
|
||||||
self.with_overlay_maybe(|overlay| {
|
|
||||||
overlay.is_over(layout, renderer, cursor_position)
|
|
||||||
})
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn operate(
|
|
||||||
&mut self,
|
|
||||||
layout: Layout<'_>,
|
|
||||||
renderer: &Renderer,
|
|
||||||
operation: &mut dyn Operation,
|
|
||||||
) {
|
|
||||||
let _ = self.with_overlay_mut_maybe(|overlay| {
|
|
||||||
overlay.operate(layout, renderer, operation);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -158,7 +158,7 @@ struct State {
|
||||||
// TODO: Support on_enter and on_exit
|
// TODO: Support on_enter and on_exit
|
||||||
drag_initiated: Option<Point>,
|
drag_initiated: Option<Point>,
|
||||||
is_out_of_bounds: bool,
|
is_out_of_bounds: bool,
|
||||||
last_click: Option<Click>,
|
last_press: Option<Click>,
|
||||||
}
|
}
|
||||||
impl Default for State {
|
impl Default for State {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
|
|
@ -166,7 +166,7 @@ impl Default for State {
|
||||||
is_hovered: Default::default(),
|
is_hovered: Default::default(),
|
||||||
drag_initiated: None,
|
drag_initiated: None,
|
||||||
is_out_of_bounds: true,
|
is_out_of_bounds: true,
|
||||||
last_click: None,
|
last_press: None,
|
||||||
cursor_position: None,
|
cursor_position: None,
|
||||||
bounds: Rectangle::default(),
|
bounds: Rectangle::default(),
|
||||||
previous_click: None,
|
previous_click: None,
|
||||||
|
|
@ -456,44 +456,46 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(message) = widget.on_double_press.as_ref() {
|
|
||||||
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) =
|
|
||||||
event
|
|
||||||
{
|
|
||||||
if let Some(cursor_position) = cursor.position() {
|
|
||||||
let click = mouse::Click::new(
|
|
||||||
cursor_position,
|
|
||||||
mouse::Button::Left,
|
|
||||||
state.last_click,
|
|
||||||
);
|
|
||||||
state.last_click = Some(click);
|
|
||||||
if let mouse::click::Kind::Double = click.kind() {
|
|
||||||
state.drag_initiated = None;
|
|
||||||
shell.publish(message.clone());
|
|
||||||
shell.capture_event();
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
|
if let Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left))
|
||||||
| Event::Touch(touch::Event::FingerPressed { .. }) = event
|
| Event::Touch(touch::Event::FingerPressed { .. }) = event
|
||||||
{
|
{
|
||||||
let mut captured = false;
|
if let Some(position) = cursor_position {
|
||||||
|
let new_click = mouse::Click::new(
|
||||||
|
position,
|
||||||
|
mouse::Button::Left,
|
||||||
|
state.last_press,
|
||||||
|
);
|
||||||
|
if new_click.kind() == mouse::click::Kind::Double
|
||||||
|
&& let Some(double_press) = widget.on_double_press.as_ref()
|
||||||
|
{
|
||||||
|
shell.publish(double_press.clone());
|
||||||
|
} else if let Some(on_press_message) = widget.on_press.as_ref() {
|
||||||
|
shell.publish(on_press_message.clone());
|
||||||
|
}
|
||||||
|
|
||||||
if let Some(position) = cursor_position
|
state.last_press = Some(new_click);
|
||||||
&& let Some(message) = widget.on_double_click.as_ref()
|
|
||||||
{
|
// Even if this is not a double click, but the press is nevertheless
|
||||||
|
// processed by us and should not be popup to parent widgets.
|
||||||
|
shell.capture_event();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
||||||
|
| Event::Touch(touch::Event::FingerLifted { .. }) = event
|
||||||
|
{
|
||||||
|
if let Some(position) = cursor_position {
|
||||||
let new_click = mouse::Click::new(
|
let new_click = mouse::Click::new(
|
||||||
position,
|
position,
|
||||||
mouse::Button::Left,
|
mouse::Button::Left,
|
||||||
state.previous_click,
|
state.previous_click,
|
||||||
);
|
);
|
||||||
|
if new_click.kind() == mouse::click::Kind::Double
|
||||||
if new_click.kind() == mouse::click::Kind::Double {
|
&& let Some(double_press) = widget.on_double_click.as_ref()
|
||||||
shell.publish(message.clone());
|
{
|
||||||
|
shell.publish(double_press.clone());
|
||||||
|
} else if let Some(on_press_message) = widget.on_release.as_ref() {
|
||||||
|
shell.publish(on_press_message.clone());
|
||||||
}
|
}
|
||||||
|
|
||||||
state.previous_click = Some(new_click);
|
state.previous_click = Some(new_click);
|
||||||
|
|
@ -505,15 +507,6 @@ fn update<Message: Clone, Theme, Renderer>(
|
||||||
}
|
}
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left))
|
|
||||||
| Event::Touch(touch::Event::FingerLifted { .. }) => {
|
|
||||||
state.drag_initiated = None;
|
|
||||||
if let Some(message) = widget.on_release.as_ref() {
|
|
||||||
shell.publish(message.clone());
|
|
||||||
}
|
|
||||||
shell.capture_event();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Right)) => {
|
Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Right)) => {
|
||||||
if let Some(message) = widget.on_right_release.as_ref() {
|
if let Some(message) = widget.on_right_release.as_ref() {
|
||||||
shell.publish(message.clone());
|
shell.publish(message.clone());
|
||||||
|
|
|
||||||
|
|
@ -400,13 +400,13 @@ where
|
||||||
retain
|
retain
|
||||||
});
|
});
|
||||||
|
|
||||||
// let ids = self.contents.iter().map(|_| None).collect(); // TODO
|
let ids = self.contents.iter().map(|_| None).collect(); // TODO
|
||||||
// tree.diff_children_custom(
|
tree.diff_children_custom(
|
||||||
// &mut self.contents,
|
&mut self.contents,
|
||||||
// ids,
|
ids,
|
||||||
// |state, (_, content): (_, _)| content.diff(state),
|
|state, content: _| content.diff(state),
|
||||||
// |(_, content): (_, _)| content.state(),
|
|content: _| content.state(),
|
||||||
// );
|
);
|
||||||
|
|
||||||
let Memory { order, .. } = tree.state.downcast_mut();
|
let Memory { order, .. } = tree.state.downcast_mut();
|
||||||
order.clone_from(&self.panes);
|
order.clone_from(&self.panes);
|
||||||
|
|
|
||||||
|
|
@ -1188,7 +1188,6 @@ where
|
||||||
if delta.y.abs() < AUTOSCROLL_DEADZONE {
|
if delta.y.abs() < AUTOSCROLL_DEADZONE {
|
||||||
delta.y = 0.0;
|
delta.y = 0.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if delta.x != 0.0 || delta.y != 0.0 {
|
if delta.x != 0.0 || delta.y != 0.0 {
|
||||||
let time_delta =
|
let time_delta =
|
||||||
if let Some(last_frame) = last_frame {
|
if let Some(last_frame) = last_frame {
|
||||||
|
|
@ -2007,7 +2006,6 @@ fn notify_viewport<Message>(
|
||||||
}
|
}
|
||||||
|
|
||||||
state.last_notified = Some(viewport);
|
state.last_notified = Some(viewport);
|
||||||
|
|
||||||
if let Some(on_scroll) = on_scroll {
|
if let Some(on_scroll) = on_scroll {
|
||||||
shell.publish(on_scroll(viewport));
|
shell.publish(on_scroll(viewport));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,6 @@ system = ["sysinfo"]
|
||||||
program = []
|
program = []
|
||||||
wayland-dlopen = ["winit/wayland-dlopen"]
|
wayland-dlopen = ["winit/wayland-dlopen"]
|
||||||
wayland-csd-adwaita = ["winit/wayland-csd-adwaita"]
|
wayland-csd-adwaita = ["winit/wayland-csd-adwaita"]
|
||||||
multi-window = ["iced_runtime/multi-window"]
|
|
||||||
a11y = ["iced_accessibility", "iced_runtime/a11y"]
|
a11y = ["iced_accessibility", "iced_runtime/a11y"]
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
339
winit/src/lib.rs
339
winit/src/lib.rs
|
|
@ -27,6 +27,7 @@ pub use program::runtime;
|
||||||
pub use runtime::futures;
|
pub use runtime::futures;
|
||||||
use window_clipboard::mime::ClipboardStoreData;
|
use window_clipboard::mime::ClipboardStoreData;
|
||||||
pub use winit;
|
pub use winit;
|
||||||
|
use winit::event::WindowEvent;
|
||||||
use winit::raw_window_handle::HasWindowHandle;
|
use winit::raw_window_handle::HasWindowHandle;
|
||||||
|
|
||||||
#[cfg(feature = "a11y")]
|
#[cfg(feature = "a11y")]
|
||||||
|
|
@ -76,6 +77,7 @@ use window::WindowManager;
|
||||||
use rustc_hash::FxHashMap;
|
use rustc_hash::FxHashMap;
|
||||||
use std::borrow::Cow;
|
use std::borrow::Cow;
|
||||||
use std::mem::ManuallyDrop;
|
use std::mem::ManuallyDrop;
|
||||||
|
use std::ops::ControlFlow;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
|
@ -130,7 +132,13 @@ where
|
||||||
let task = if let Some(window_settings) = window_settings {
|
let task = if let Some(window_settings) = window_settings {
|
||||||
let mut task = Some(task);
|
let mut task = Some(task);
|
||||||
|
|
||||||
let (_id, open) = runtime::window::open(window_settings);
|
let open = iced_runtime::task::oneshot(|channel| {
|
||||||
|
iced_runtime::Action::Window(iced_runtime::window::Action::Open(
|
||||||
|
window::Id::RESERVED,
|
||||||
|
window_settings,
|
||||||
|
channel,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
|
||||||
open.then(move |_| task.take().unwrap_or_else(Task::none))
|
open.then(move |_| task.take().unwrap_or_else(Task::none))
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -532,52 +540,49 @@ where
|
||||||
.start_send(Event::StartDnd)
|
.start_send(Event::StartDnd)
|
||||||
.expect("Send event");
|
.expect("Send event");
|
||||||
}
|
}
|
||||||
|
#[cfg(feature = "a11y")]
|
||||||
Control::InitAdapter(id, window) => {
|
Control::InitAdapter(id, window) => {
|
||||||
#[cfg(feature = "a11y")]
|
use crate::a11y::*;
|
||||||
{
|
use iced_accessibility::accesskit::{
|
||||||
use crate::a11y::*;
|
ActivationHandler, Node, NodeId, Role,
|
||||||
use iced_accessibility::accesskit::{
|
Tree, TreeUpdate,
|
||||||
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: self.control_sender.clone(),
|
||||||
|
title: String::new(),
|
||||||
};
|
};
|
||||||
use iced_accessibility::accesskit_winit::Adapter;
|
|
||||||
|
|
||||||
let node_id =
|
let action_handler = WinitActionHandler {
|
||||||
iced_runtime::core::id::window_node_id(
|
id,
|
||||||
);
|
proxy: self.control_sender.clone(),
|
||||||
|
};
|
||||||
|
|
||||||
let activation_handler =
|
let deactivation_handler =
|
||||||
WinitActivationHandler {
|
WinitDeactivationHandler {
|
||||||
proxy: self.control_sender.clone(),
|
|
||||||
title: String::new(),
|
|
||||||
};
|
|
||||||
|
|
||||||
let action_handler = WinitActionHandler {
|
|
||||||
id,
|
|
||||||
proxy: self.control_sender.clone(),
|
proxy: self.control_sender.clone(),
|
||||||
};
|
};
|
||||||
|
|
||||||
let deactivation_handler =
|
self.sender
|
||||||
WinitDeactivationHandler {
|
.start_send(Event::A11yAdapter(
|
||||||
proxy: self.control_sender.clone(),
|
id,
|
||||||
};
|
(
|
||||||
|
node_id,
|
||||||
self.sender
|
Adapter::with_direct_handlers(
|
||||||
.start_send(Event::A11yAdapter(
|
event_loop,
|
||||||
id,
|
window.as_ref(),
|
||||||
(
|
activation_handler,
|
||||||
node_id,
|
action_handler,
|
||||||
Adapter::with_direct_handlers(
|
deactivation_handler,
|
||||||
event_loop,
|
|
||||||
window.as_ref(),
|
|
||||||
activation_handler,
|
|
||||||
action_handler,
|
|
||||||
deactivation_handler,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
))
|
),
|
||||||
.expect("send event");
|
))
|
||||||
}
|
.expect("send event");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => {
|
_ => {
|
||||||
|
|
@ -776,69 +781,32 @@ async fn run_instance<P>(
|
||||||
control_sender
|
control_sender
|
||||||
.start_send(Control::InitAdapter(id, window.clone()))
|
.start_send(Control::InitAdapter(id, window.clone()))
|
||||||
.expect("Send control message");
|
.expect("Send control message");
|
||||||
if compositor.is_none() {
|
#[cfg(feature = "wayland")]
|
||||||
let (compositor_sender, compositor_receiver) =
|
platform_specific_handler.send_wayland(
|
||||||
oneshot::channel();
|
platform_specific::Action::TrackWindow(window.clone(), id),
|
||||||
|
);
|
||||||
let create_compositor = {
|
match create_compositor::<P>(
|
||||||
let window = window.clone();
|
window.clone(),
|
||||||
let display_handle = display_handle.clone();
|
CreateCompositor {
|
||||||
let proxy = proxy.clone();
|
proxy: &proxy,
|
||||||
let default_fonts = default_fonts.clone();
|
runtime: &mut runtime,
|
||||||
|
display_handle: &display_handle,
|
||||||
async move {
|
graphics_settings: &graphics_settings,
|
||||||
let shell = Shell::new(proxy.clone());
|
default_fonts: &default_fonts,
|
||||||
|
},
|
||||||
let mut compositor =
|
)
|
||||||
<P::Renderer as compositor::Default>::Compositor::new(
|
.await
|
||||||
graphics_settings,
|
{
|
||||||
display_handle,
|
Ok(comp) => {
|
||||||
window,
|
compositor = Some(comp);
|
||||||
shell,
|
}
|
||||||
).await;
|
Err(error) => {
|
||||||
|
control_sender
|
||||||
if let Ok(compositor) = &mut compositor {
|
.start_send(Control::Crash(
|
||||||
for font in default_fonts {
|
Error::GraphicsCreationFailed(error),
|
||||||
compositor.load_font(font.clone());
|
))
|
||||||
}
|
.expect("Send control message");
|
||||||
}
|
continue;
|
||||||
|
|
||||||
compositor_sender
|
|
||||||
.send(compositor)
|
|
||||||
.ok()
|
|
||||||
.expect("Send compositor");
|
|
||||||
|
|
||||||
// HACK! Send a proxy event on completion to trigger
|
|
||||||
// a runtime re-poll
|
|
||||||
// TODO: Send compositor through proxy (?)
|
|
||||||
{
|
|
||||||
let (sender, _receiver) = oneshot::channel();
|
|
||||||
|
|
||||||
proxy.send_action(Action::Window(
|
|
||||||
runtime::window::Action::GetLatest(sender),
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
#[cfg(target_arch = "wasm32")]
|
|
||||||
wasm_bindgen_futures::spawn_local(create_compositor);
|
|
||||||
|
|
||||||
#[cfg(not(target_arch = "wasm32"))]
|
|
||||||
runtime.block_on(create_compositor);
|
|
||||||
|
|
||||||
match compositor_receiver
|
|
||||||
.await
|
|
||||||
.expect("Wait for compositor")
|
|
||||||
{
|
|
||||||
Ok(new_compositor) => {
|
|
||||||
compositor = Some(new_compositor);
|
|
||||||
}
|
|
||||||
Err(error) => {
|
|
||||||
let _ = control_sender
|
|
||||||
.start_send(Control::Crash(error.into()));
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -982,6 +950,22 @@ async fn run_instance<P>(
|
||||||
else {
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
// XX must force update to corner radius before the surface is committed.
|
||||||
|
#[cfg(feature = "wayland")]
|
||||||
|
if window.surface_version != window.state.surface_version()
|
||||||
|
|| window.logical_size() != window.state.logical_size()
|
||||||
|
{
|
||||||
|
platform_specific_handler.send_wayland(
|
||||||
|
platform_specific::Action::ResizeWindow(id),
|
||||||
|
);
|
||||||
|
window.redraw_requested = true;
|
||||||
|
control_sender
|
||||||
|
.start_send(Control::Winit(
|
||||||
|
window.raw.id(),
|
||||||
|
WindowEvent::RedrawRequested,
|
||||||
|
))
|
||||||
|
.expect("Send redraw event");
|
||||||
|
}
|
||||||
window.redraw_requested = false;
|
window.redraw_requested = false;
|
||||||
|
|
||||||
let physical_size = window.state.physical_size();
|
let physical_size = window.state.physical_size();
|
||||||
|
|
@ -1330,7 +1314,6 @@ async fn run_instance<P>(
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let no_window_events = window_events.is_empty();
|
let no_window_events = window_events.is_empty();
|
||||||
#[cfg(feature = "wayland")]
|
#[cfg(feature = "wayland")]
|
||||||
window_events.push(core::Event::PlatformSpecific(
|
window_events.push(core::Event::PlatformSpecific(
|
||||||
|
|
@ -1376,6 +1359,14 @@ async fn run_instance<P>(
|
||||||
_ = window.raw.request_surface_size(s);
|
_ = window.raw.request_surface_size(s);
|
||||||
window.raw.set_min_surface_size(Some(s));
|
window.raw.set_min_surface_size(Some(s));
|
||||||
window.raw.set_max_surface_size(Some(s));
|
window.raw.set_max_surface_size(Some(s));
|
||||||
|
|
||||||
|
window.state.update(
|
||||||
|
&program,
|
||||||
|
window.raw.as_ref(),
|
||||||
|
&WindowEvent::SurfaceResized(
|
||||||
|
requested_physical_size,
|
||||||
|
),
|
||||||
|
);
|
||||||
window.state.synchronize(
|
window.state.synchronize(
|
||||||
&program,
|
&program,
|
||||||
id,
|
id,
|
||||||
|
|
@ -1499,7 +1490,9 @@ async fn run_instance<P>(
|
||||||
.start_send(Control::ChangeFlow(ControlFlow::Wait));
|
.start_send(Control::ChangeFlow(ControlFlow::Wait));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Event::Exit => break,
|
Event::Exit => {
|
||||||
|
break;
|
||||||
|
}
|
||||||
Event::Dnd(e) => {
|
Event::Dnd(e) => {
|
||||||
use winit::raw_window_handle::HasWindowHandle;
|
use winit::raw_window_handle::HasWindowHandle;
|
||||||
|
|
||||||
|
|
@ -1569,23 +1562,26 @@ async fn run_instance<P>(
|
||||||
a11y_enabled = enabled;
|
a11y_enabled = enabled;
|
||||||
}
|
}
|
||||||
Event::PlatformSpecific(e) => {
|
Event::PlatformSpecific(e) => {
|
||||||
if let Some(c) = compositor.as_mut() {
|
crate::platform_specific::handle_event(
|
||||||
crate::platform_specific::handle_event(
|
e,
|
||||||
e,
|
&mut events,
|
||||||
&mut events,
|
&mut platform_specific_handler,
|
||||||
&mut platform_specific_handler,
|
&program,
|
||||||
&program,
|
&mut compositor,
|
||||||
c,
|
&mut window_manager,
|
||||||
&mut window_manager,
|
&mut user_interfaces,
|
||||||
&mut user_interfaces,
|
&mut clipboard,
|
||||||
&mut clipboard,
|
#[cfg(feature = "a11y")]
|
||||||
#[cfg(feature = "a11y")]
|
&mut adapters,
|
||||||
&mut adapters,
|
CreateCompositor {
|
||||||
);
|
proxy: &proxy,
|
||||||
} else {
|
display_handle: &display_handle,
|
||||||
// TODO should we break?
|
graphics_settings: &graphics_settings,
|
||||||
break;
|
default_fonts: &default_fonts,
|
||||||
}
|
runtime: &mut runtime,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
Event::StartDnd => {
|
Event::StartDnd => {
|
||||||
let compositor = match compositor.as_mut() {
|
let compositor = match compositor.as_mut() {
|
||||||
|
|
@ -1614,12 +1610,15 @@ async fn run_instance<P>(
|
||||||
Some(s)
|
Some(s)
|
||||||
}
|
}
|
||||||
core::clipboard::DndSource::Widget(w) => {
|
core::clipboard::DndSource::Widget(w) => {
|
||||||
log::debug!(
|
log::trace!(
|
||||||
"start_dnd: searching for widget {:?}",
|
"start_dnd: searching for widget {:?}",
|
||||||
w
|
w
|
||||||
);
|
);
|
||||||
// search windows for widget with operation
|
// if user intefaces is just 1 len, use the single id instead of wasting time searching
|
||||||
let result = user_interfaces.iter_mut().find_map(
|
let result = if user_interfaces.len() ==1 {
|
||||||
|
user_interfaces.keys().next().cloned()
|
||||||
|
} else {
|
||||||
|
user_interfaces.iter_mut().find_map(
|
||||||
|(ui_id, ui)| {
|
|(ui_id, ui)| {
|
||||||
let Some(ui_renderer) = window_manager
|
let Some(ui_renderer) = window_manager
|
||||||
.get_mut(ui_id.clone())
|
.get_mut(ui_id.clone())
|
||||||
|
|
@ -1666,7 +1665,11 @@ async fn run_instance<P>(
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
},
|
},
|
||||||
);
|
)
|
||||||
|
};
|
||||||
|
|
||||||
|
// search windows for widget with operation
|
||||||
|
|
||||||
if result.is_none() {
|
if result.is_none() {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"start_dnd: widget {:?} not found; drag will fail",
|
"start_dnd: widget {:?} not found; drag will fail",
|
||||||
|
|
@ -1817,6 +1820,88 @@ async fn run_instance<P>(
|
||||||
let _ = ManuallyDrop::into_inner(user_interfaces);
|
let _ = ManuallyDrop::into_inner(user_interfaces);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct CreateCompositor<'a, P: Program> {
|
||||||
|
proxy: &'a Proxy<<P as Program>::Message>,
|
||||||
|
display_handle: &'a winit::event_loop::OwnedDisplayHandle,
|
||||||
|
graphics_settings: &'a iced_graphics::Settings,
|
||||||
|
default_fonts: &'a [Cow<'static, [u8]>],
|
||||||
|
runtime: &'a mut Runtime<
|
||||||
|
<P as Program>::Executor,
|
||||||
|
Proxy<<P as Program>::Message>,
|
||||||
|
Action<<P as Program>::Message>,
|
||||||
|
>,
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn create_compositor<'a, P>(
|
||||||
|
window: Arc<dyn winit::window::Window + 'static>,
|
||||||
|
CreateCompositor {
|
||||||
|
proxy,
|
||||||
|
display_handle,
|
||||||
|
graphics_settings,
|
||||||
|
default_fonts,
|
||||||
|
runtime,
|
||||||
|
}: CreateCompositor<'a, P>,
|
||||||
|
) -> Result<
|
||||||
|
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
||||||
|
iced_graphics::Error,
|
||||||
|
>
|
||||||
|
where
|
||||||
|
P: Program,
|
||||||
|
{
|
||||||
|
let (compositor_sender, compositor_receiver) = oneshot::channel();
|
||||||
|
|
||||||
|
let create_compositor = {
|
||||||
|
let display_handle = display_handle.clone();
|
||||||
|
let proxy = proxy.clone();
|
||||||
|
let graphics_settings = (*graphics_settings).clone();
|
||||||
|
let window = window.clone();
|
||||||
|
let default_fonts = default_fonts.to_vec();
|
||||||
|
|
||||||
|
async move {
|
||||||
|
let shell = Shell::new(proxy.clone());
|
||||||
|
|
||||||
|
let mut compositor =
|
||||||
|
<P::Renderer as compositor::Default>::Compositor::new(
|
||||||
|
graphics_settings,
|
||||||
|
display_handle,
|
||||||
|
window,
|
||||||
|
shell,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
if let Ok(compositor) = &mut compositor {
|
||||||
|
for font in default_fonts {
|
||||||
|
compositor.load_font(font.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
compositor_sender
|
||||||
|
.send(compositor)
|
||||||
|
.ok()
|
||||||
|
.expect("Send compositor");
|
||||||
|
|
||||||
|
// HACK! Send a proxy event on completion to trigger
|
||||||
|
// a runtime re-poll
|
||||||
|
// TODO: Send compositor through proxy (?)
|
||||||
|
{
|
||||||
|
let (sender, _receiver) = oneshot::channel();
|
||||||
|
|
||||||
|
proxy.send_action(Action::Window(
|
||||||
|
runtime::window::Action::GetLatest(sender),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#[cfg(target_arch = "wasm32")]
|
||||||
|
wasm_bindgen_futures::spawn_local(create_compositor);
|
||||||
|
|
||||||
|
#[cfg(not(target_arch = "wasm32"))]
|
||||||
|
runtime.block_on(create_compositor);
|
||||||
|
|
||||||
|
compositor_receiver.await.expect("Wait for compositor")
|
||||||
|
}
|
||||||
|
|
||||||
/// Builds a window's [`UserInterface`] for the [`Program`].
|
/// Builds a window's [`UserInterface`] for the [`Program`].
|
||||||
fn build_user_interface<'a, P: Program>(
|
fn build_user_interface<'a, P: Program>(
|
||||||
program: &'a program::Instance<P>,
|
program: &'a program::Instance<P>,
|
||||||
|
|
@ -1965,7 +2050,9 @@ where
|
||||||
let _ = ui_caches.remove(&id);
|
let _ = ui_caches.remove(&id);
|
||||||
let _ = interfaces.remove(&id);
|
let _ = interfaces.remove(&id);
|
||||||
let proxy = clipboard.proxy();
|
let proxy = clipboard.proxy();
|
||||||
|
#[cfg(feature = "wayland")]
|
||||||
|
platform_specific
|
||||||
|
.send_wayland(platform_specific::Action::RemoveWindow(id));
|
||||||
if let Some(window) = window_manager.remove(id) {
|
if let Some(window) = window_manager.remove(id) {
|
||||||
if clipboard.window_id() == Some(window.raw.id()) {
|
if clipboard.window_id() == Some(window.raw.id()) {
|
||||||
*clipboard = window_manager
|
*clipboard = window_manager
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
//! Wayland specific shell
|
//! Wayland specific shell
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::{borrow::Cow, collections::HashMap, sync::Arc};
|
||||||
|
|
||||||
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
||||||
use cctk::sctk::reexports::client::Connection;
|
use cctk::sctk::reexports::client::Connection;
|
||||||
|
|
@ -20,7 +20,7 @@ pub use wayland::*;
|
||||||
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
||||||
use wayland_backend::client::Backend;
|
use wayland_backend::client::Backend;
|
||||||
|
|
||||||
use crate::{Program, WindowManager};
|
use crate::{CreateCompositor, Program, WindowManager};
|
||||||
|
|
||||||
pub type UserInterfaces<'a, P> = HashMap<
|
pub type UserInterfaces<'a, P> = HashMap<
|
||||||
window::Id,
|
window::Id,
|
||||||
|
|
@ -176,12 +176,14 @@ impl PlatformSpecific {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_event<'a, P>(
|
pub(crate) async fn handle_event<'a, 'b, P>(
|
||||||
e: Event,
|
e: Event,
|
||||||
events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
|
events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
|
||||||
platform_specific: &mut PlatformSpecific,
|
platform_specific: &mut PlatformSpecific,
|
||||||
program: &'a crate::program::Instance<P>,
|
program: &'a crate::program::Instance<P>,
|
||||||
compositor: &mut <<P as Program>::Renderer as compositor::Default>::Compositor,
|
compositor: &mut Option<
|
||||||
|
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
||||||
|
>,
|
||||||
window_manager: &mut WindowManager<
|
window_manager: &mut WindowManager<
|
||||||
P,
|
P,
|
||||||
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
||||||
|
|
@ -192,23 +194,28 @@ pub(crate) fn handle_event<'a, P>(
|
||||||
window::Id,
|
window::Id,
|
||||||
(u64, iced_accessibility::accesskit_winit::Adapter),
|
(u64, iced_accessibility::accesskit_winit::Adapter),
|
||||||
>,
|
>,
|
||||||
|
create_compositor: CreateCompositor<'b, P>,
|
||||||
) where
|
) where
|
||||||
P: Program,
|
P: Program,
|
||||||
{
|
{
|
||||||
match e {
|
match e {
|
||||||
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
#[cfg(all(feature = "wayland", target_os = "linux"))]
|
||||||
Event::Wayland(e) => {
|
Event::Wayland(e) => {
|
||||||
platform_specific.wayland.handle_event(
|
platform_specific
|
||||||
e,
|
.wayland
|
||||||
events,
|
.handle_event(
|
||||||
program,
|
e,
|
||||||
compositor,
|
events,
|
||||||
window_manager,
|
program,
|
||||||
user_interfaces,
|
compositor,
|
||||||
clipboard,
|
window_manager,
|
||||||
#[cfg(feature = "a11y")]
|
user_interfaces,
|
||||||
adapters,
|
clipboard,
|
||||||
);
|
#[cfg(feature = "a11y")]
|
||||||
|
adapters,
|
||||||
|
create_compositor,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1232,7 +1232,6 @@ impl SctkState {
|
||||||
found |= p.data.id == settings.parent;
|
found |= p.data.id == settings.parent;
|
||||||
parent_mismatch |= found && p.data.id != settings.parent;
|
parent_mismatch |= found && p.data.id != settings.parent;
|
||||||
}
|
}
|
||||||
parent_mismatch |= !found;
|
|
||||||
if !self.destroyed.is_empty() || parent_mismatch {
|
if !self.destroyed.is_empty() || parent_mismatch {
|
||||||
if parent_mismatch {
|
if parent_mismatch {
|
||||||
let mut found = false;
|
let mut found = false;
|
||||||
|
|
|
||||||
|
|
@ -893,3 +893,195 @@ pub fn keysym_location(keysym: u32) -> Location {
|
||||||
_ => Location::Standard,
|
_ => Location::Standard,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn key_to_keysym(
|
||||||
|
unmodified_key: Key,
|
||||||
|
location: Location,
|
||||||
|
) -> Option<xkeysym::Keysym> {
|
||||||
|
use xkbcommon_dl::keysyms;
|
||||||
|
|
||||||
|
let raw = match unmodified_key {
|
||||||
|
Key::Named(named) => Some(match (named, location) {
|
||||||
|
(Named::Escape, _) => keysyms::Escape,
|
||||||
|
(Named::Backspace, _) => keysyms::BackSpace,
|
||||||
|
(Named::Tab, _) => keysyms::Tab,
|
||||||
|
(Named::Enter, _) => keysyms::Return,
|
||||||
|
|
||||||
|
(Named::Compose, _) => keysyms::Multi_key,
|
||||||
|
|
||||||
|
(Named::KanjiMode, _) => keysyms::Kanji,
|
||||||
|
(Named::Eisu, _) => keysyms::Eisu_toggle,
|
||||||
|
(Named::NonConvert, _) => keysyms::Muhenkan,
|
||||||
|
(Named::Convert, _) => keysyms::Henkan_Mode,
|
||||||
|
(Named::Romaji, _) => keysyms::Romaji,
|
||||||
|
(Named::Hiragana, _) => keysyms::Hiragana,
|
||||||
|
(Named::Katakana, _) => keysyms::Katakana,
|
||||||
|
(Named::HiraganaKatakana, _) => keysyms::Hiragana_Katakana,
|
||||||
|
(Named::Zenkaku, _) => keysyms::Zenkaku,
|
||||||
|
(Named::Hankaku, _) => keysyms::Hankaku,
|
||||||
|
(Named::ZenkakuHankaku, _) => keysyms::Zenkaku_Hankaku,
|
||||||
|
(Named::KanaMode, _) => keysyms::Kana_Lock,
|
||||||
|
(Named::Alphanumeric, _) => keysyms::Eisu_toggle,
|
||||||
|
(Named::CodeInput, _) => keysyms::Codeinput,
|
||||||
|
(Named::AllCandidates, _) => keysyms::MultipleCandidate,
|
||||||
|
(Named::PreviousCandidate, _) => keysyms::PreviousCandidate,
|
||||||
|
(Named::SingleCandidate, _) => keysyms::SingleCandidate,
|
||||||
|
|
||||||
|
(Named::ArrowUp, _) => keysyms::Up,
|
||||||
|
(Named::ArrowDown, _) => keysyms::Down,
|
||||||
|
(Named::ArrowLeft, _) => keysyms::Left,
|
||||||
|
(Named::ArrowRight, _) => keysyms::Right,
|
||||||
|
(Named::PageUp, _) => keysyms::Page_Up,
|
||||||
|
(Named::PageDown, _) => keysyms::Page_Down,
|
||||||
|
(Named::Home, _) => keysyms::Home,
|
||||||
|
(Named::End, _) => keysyms::End,
|
||||||
|
(Named::Insert, _) => keysyms::Insert,
|
||||||
|
(Named::Delete, _) => keysyms::Delete,
|
||||||
|
|
||||||
|
(Named::Undo, _) => keysyms::Undo,
|
||||||
|
(Named::Redo, _) => keysyms::Redo,
|
||||||
|
(Named::ContextMenu, _) => keysyms::Menu,
|
||||||
|
(Named::Find, _) => keysyms::Find,
|
||||||
|
(Named::Cancel, _) => keysyms::Cancel,
|
||||||
|
(Named::Help, _) => keysyms::Help,
|
||||||
|
(Named::Pause, _) => keysyms::Break,
|
||||||
|
(Named::ModeChange, _) => keysyms::Mode_switch,
|
||||||
|
(Named::NumLock, _) => keysyms::Num_Lock,
|
||||||
|
(Named::CapsLock, _) => keysyms::Caps_Lock,
|
||||||
|
(Named::ScrollLock, _) => keysyms::Scroll_Lock,
|
||||||
|
(Named::PrintScreen, _) => keysyms::Print,
|
||||||
|
|
||||||
|
(Named::F1, _) => keysyms::F1,
|
||||||
|
(Named::F2, _) => keysyms::F2,
|
||||||
|
(Named::F3, _) => keysyms::F3,
|
||||||
|
(Named::F4, _) => keysyms::F4,
|
||||||
|
(Named::F5, _) => keysyms::F5,
|
||||||
|
(Named::F6, _) => keysyms::F6,
|
||||||
|
(Named::F7, _) => keysyms::F7,
|
||||||
|
(Named::F8, _) => keysyms::F8,
|
||||||
|
(Named::F9, _) => keysyms::F9,
|
||||||
|
(Named::F10, _) => keysyms::F10,
|
||||||
|
(Named::F11, _) => keysyms::F11,
|
||||||
|
(Named::F12, _) => keysyms::F12,
|
||||||
|
(Named::F13, _) => keysyms::F13,
|
||||||
|
(Named::F14, _) => keysyms::F14,
|
||||||
|
(Named::F15, _) => keysyms::F15,
|
||||||
|
(Named::F16, _) => keysyms::F16,
|
||||||
|
(Named::F17, _) => keysyms::F17,
|
||||||
|
(Named::F18, _) => keysyms::F18,
|
||||||
|
(Named::F19, _) => keysyms::F19,
|
||||||
|
(Named::F20, _) => keysyms::F20,
|
||||||
|
|
||||||
|
(Named::Shift, _) => keysyms::Shift_L,
|
||||||
|
(Named::Control, _) => keysyms::Control_L,
|
||||||
|
(Named::Alt, _) => keysyms::Alt_L,
|
||||||
|
(Named::Super, _) => keysyms::Super_L,
|
||||||
|
(Named::Hyper, _) => keysyms::Hyper_L,
|
||||||
|
(Named::Meta, _) => keysyms::Meta_L,
|
||||||
|
|
||||||
|
(Named::AltGraph, _) => keysyms::ISO_Level3_Shift,
|
||||||
|
(Named::GroupNext, _) => keysyms::ISO_Next_Group,
|
||||||
|
(Named::GroupPrevious, _) => keysyms::ISO_Prev_Group,
|
||||||
|
(Named::GroupFirst, _) => keysyms::ISO_First_Group,
|
||||||
|
(Named::GroupLast, _) => keysyms::ISO_Last_Group,
|
||||||
|
|
||||||
|
(Named::EraseEof, _) => keysyms::_3270_EraseEOF,
|
||||||
|
(Named::Attn, _) => keysyms::_3270_Attn,
|
||||||
|
(Named::Play, _) => keysyms::_3270_Play,
|
||||||
|
(Named::ExSel, _) => keysyms::_3270_ExSelect,
|
||||||
|
(Named::CrSel, _) => keysyms::_3270_CursorSelect,
|
||||||
|
|
||||||
|
(Named::Space, _) => keysyms::space,
|
||||||
|
|
||||||
|
// XF86 multimedia / internet / power keys (subset shown)
|
||||||
|
(Named::BrightnessUp, _) => keysyms::XF86_MonBrightnessUp,
|
||||||
|
(Named::BrightnessDown, _) => keysyms::XF86_MonBrightnessDown,
|
||||||
|
(Named::Standby, _) => keysyms::XF86_Standby,
|
||||||
|
(Named::AudioVolumeDown, _) => keysyms::XF86_AudioLowerVolume,
|
||||||
|
(Named::AudioVolumeUp, _) => keysyms::XF86_AudioRaiseVolume,
|
||||||
|
(Named::MediaPlay, _) => keysyms::XF86_AudioPlay,
|
||||||
|
(Named::MediaStop, _) => keysyms::XF86_AudioStop,
|
||||||
|
(Named::MediaTrackPrevious, _) => keysyms::XF86_AudioPrev,
|
||||||
|
(Named::MediaTrackNext, _) => keysyms::XF86_AudioNext,
|
||||||
|
(Named::BrowserHome, _) => keysyms::XF86_HomePage,
|
||||||
|
(Named::LaunchMail, _) => keysyms::XF86_Mail,
|
||||||
|
(Named::BrowserSearch, _) => keysyms::XF86_Search,
|
||||||
|
(Named::MediaRecord, _) => keysyms::XF86_AudioRecord,
|
||||||
|
(Named::LaunchApplication2, _) => keysyms::XF86_Calculator,
|
||||||
|
(Named::LaunchCalendar, _) => keysyms::XF86_Calendar,
|
||||||
|
(Named::Power, _) => keysyms::XF86_PowerDown,
|
||||||
|
(Named::BrowserBack, _) => keysyms::XF86_Back,
|
||||||
|
(Named::BrowserForward, _) => keysyms::XF86_Forward,
|
||||||
|
(Named::BrowserRefresh, _) => keysyms::XF86_Refresh,
|
||||||
|
(Named::WakeUp, _) => keysyms::XF86_WakeUp,
|
||||||
|
(Named::Eject, _) => keysyms::XF86_Eject,
|
||||||
|
(Named::LaunchScreenSaver, _) => keysyms::XF86_ScreenSaver,
|
||||||
|
(Named::LaunchWebBrowser, _) => keysyms::XF86_WWW,
|
||||||
|
(Named::BrowserFavorites, _) => keysyms::XF86_Favorites,
|
||||||
|
(Named::MediaPause, _) => keysyms::XF86_AudioPause,
|
||||||
|
(Named::LaunchApplication1, _) => keysyms::XF86_MyComputer,
|
||||||
|
(Named::Close, _) => keysyms::XF86_Close,
|
||||||
|
(Named::Copy, _) => keysyms::XF86_Copy,
|
||||||
|
(Named::Cut, _) => keysyms::XF86_Cut,
|
||||||
|
(Named::LaunchSpreadsheet, _) => keysyms::XF86_Excel,
|
||||||
|
(Named::LogOff, _) => keysyms::XF86_LogOff,
|
||||||
|
(Named::New, _) => keysyms::XF86_New,
|
||||||
|
(Named::Open, _) => keysyms::XF86_Open,
|
||||||
|
(Named::Paste, _) => keysyms::XF86_Paste,
|
||||||
|
(Named::LaunchPhone, _) => keysyms::XF86_Phone,
|
||||||
|
(Named::MailReply, _) => keysyms::XF86_Reply,
|
||||||
|
(Named::Save, _) => keysyms::XF86_Save,
|
||||||
|
(Named::MailSend, _) => keysyms::XF86_Send,
|
||||||
|
(Named::SpellCheck, _) => keysyms::XF86_Spell,
|
||||||
|
(Named::SplitScreenToggle, _) => keysyms::XF86_SplitScreen,
|
||||||
|
(Named::LaunchMediaPlayer, _) => keysyms::XF86_Video,
|
||||||
|
(Named::LaunchWordProcessor, _) => keysyms::XF86_Word,
|
||||||
|
(Named::ZoomIn, _) => keysyms::XF86_ZoomIn,
|
||||||
|
(Named::ZoomOut, _) => keysyms::XF86_ZoomOut,
|
||||||
|
(Named::LaunchWebCam, _) => keysyms::XF86_WebCam,
|
||||||
|
(Named::MailForward, _) => keysyms::XF86_MailForward,
|
||||||
|
(Named::LaunchMusicPlayer, _) => keysyms::XF86_Music,
|
||||||
|
(Named::MediaFastForward, _) => keysyms::XF86_AudioForward,
|
||||||
|
(Named::RandomToggle, _) => keysyms::XF86_AudioRandomPlay,
|
||||||
|
(Named::Subtitle, _) => keysyms::XF86_Subtitle,
|
||||||
|
(Named::MediaAudioTrack, _) => keysyms::XF86_AudioCycleTrack,
|
||||||
|
(Named::Hibernate, _) => keysyms::XF86_Hibernate,
|
||||||
|
(Named::AudioVolumeMute, _) => keysyms::XF86_AudioMute,
|
||||||
|
(Named::VideoModeNext, _) => keysyms::XF86_Next_VMode,
|
||||||
|
|
||||||
|
_ => return None,
|
||||||
|
}),
|
||||||
|
Key::Character(c) if c.chars().count() == 1 => {
|
||||||
|
Some(match (c.chars().next(), location) {
|
||||||
|
(Some('0'), Location::Numpad) => keysyms::KP_0,
|
||||||
|
(Some('1'), Location::Numpad) => keysyms::KP_1,
|
||||||
|
(Some('2'), Location::Numpad) => keysyms::KP_2,
|
||||||
|
(Some('3'), Location::Numpad) => keysyms::KP_3,
|
||||||
|
(Some('4'), Location::Numpad) => keysyms::KP_4,
|
||||||
|
(Some('5'), Location::Numpad) => keysyms::KP_5,
|
||||||
|
(Some('6'), Location::Numpad) => keysyms::KP_6,
|
||||||
|
(Some('7'), Location::Numpad) => keysyms::KP_7,
|
||||||
|
(Some('8'), Location::Numpad) => keysyms::KP_8,
|
||||||
|
(Some('9'), Location::Numpad) => keysyms::KP_9,
|
||||||
|
(Some('.'), Location::Numpad) => keysyms::KP_Decimal,
|
||||||
|
(Some('+'), Location::Numpad) => keysyms::KP_Add,
|
||||||
|
(Some('-'), Location::Numpad) => keysyms::KP_Subtract,
|
||||||
|
(Some('*'), Location::Numpad) => keysyms::KP_Multiply,
|
||||||
|
(Some('/'), Location::Numpad) => keysyms::KP_Divide,
|
||||||
|
(Some('='), Location::Numpad) => keysyms::KP_Equal,
|
||||||
|
|
||||||
|
(Some(c), _) => unsafe {
|
||||||
|
let keysym =
|
||||||
|
xkbcommon::xkb::ffi::xkb_utf32_to_keysym(c as u32);
|
||||||
|
if keysym == keysyms::NoSymbol {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
keysym
|
||||||
|
},
|
||||||
|
_ => return None,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
raw.map(|k| xkeysym::Keysym::new(k))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ pub mod subsurface_widget;
|
||||||
pub mod winit_window;
|
pub mod winit_window;
|
||||||
|
|
||||||
use super::{PlatformSpecific, SurfaceIdWrapper};
|
use super::{PlatformSpecific, SurfaceIdWrapper};
|
||||||
use crate::{Control, Program, WindowManager};
|
use crate::{Control, CreateCompositor, Program, WindowManager};
|
||||||
|
|
||||||
use crate::platform_specific::UserInterfaces;
|
use crate::platform_specific::UserInterfaces;
|
||||||
use cctk::sctk::reexports::calloop;
|
use cctk::sctk::reexports::calloop;
|
||||||
|
|
@ -150,12 +150,14 @@ impl WaylandSpecific {
|
||||||
self.conn.as_ref()
|
self.conn.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn handle_event<'a, P>(
|
pub(crate) async fn handle_event<'a, 'b, P>(
|
||||||
&mut self,
|
&mut self,
|
||||||
e: SctkEvent,
|
e: SctkEvent,
|
||||||
events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
|
events: &mut Vec<(Option<window::Id>, iced_runtime::core::Event)>,
|
||||||
program: &'a crate::program::Instance<P>,
|
program: &'a crate::program::Instance<P>,
|
||||||
compositor: &mut <<P as Program>::Renderer as compositor::Default>::Compositor,
|
compositor: &mut Option<
|
||||||
|
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
||||||
|
>,
|
||||||
window_manager: &mut WindowManager<
|
window_manager: &mut WindowManager<
|
||||||
P,
|
P,
|
||||||
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
||||||
|
|
@ -166,6 +168,7 @@ impl WaylandSpecific {
|
||||||
window::Id,
|
window::Id,
|
||||||
(u64, iced_accessibility::accesskit_winit::Adapter),
|
(u64, iced_accessibility::accesskit_winit::Adapter),
|
||||||
>,
|
>,
|
||||||
|
create_compositor: CreateCompositor<'b, P>,
|
||||||
) where
|
) where
|
||||||
P: Program,
|
P: Program,
|
||||||
{
|
{
|
||||||
|
|
@ -196,22 +199,25 @@ impl WaylandSpecific {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
};
|
};
|
||||||
|
|
||||||
sctk_event.process(
|
sctk_event
|
||||||
modifiers,
|
.process(
|
||||||
program,
|
modifiers,
|
||||||
compositor,
|
program,
|
||||||
window_manager,
|
compositor,
|
||||||
surface_ids,
|
window_manager,
|
||||||
sender,
|
surface_ids,
|
||||||
event_sender,
|
sender,
|
||||||
proxy,
|
event_sender,
|
||||||
user_interfaces,
|
proxy,
|
||||||
events,
|
user_interfaces,
|
||||||
clipboard,
|
events,
|
||||||
subsurface_state,
|
clipboard,
|
||||||
#[cfg(feature = "a11y")]
|
subsurface_state,
|
||||||
adapters,
|
#[cfg(feature = "a11y")]
|
||||||
);
|
adapters,
|
||||||
|
create_compositor,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
Clipboard, Control, Program,
|
Clipboard, Control, CreateCompositor, Error, Program, create_compositor,
|
||||||
platform_specific::{
|
platform_specific::{
|
||||||
SurfaceIdWrapper, UserInterfaces,
|
SurfaceIdWrapper, UserInterfaces,
|
||||||
wayland::{
|
wayland::{
|
||||||
|
|
@ -342,11 +342,13 @@ pub struct SurfaceCompositorUpdate {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SctkEvent {
|
impl SctkEvent {
|
||||||
pub(crate) fn process<'a, P>(
|
pub(crate) async fn process<'a, 'b, P>(
|
||||||
self,
|
self,
|
||||||
modifiers: &mut Modifiers,
|
modifiers: &mut Modifiers,
|
||||||
program: &'a crate::program::Instance<P>,
|
program: &'a crate::program::Instance<P>,
|
||||||
compositor: &mut <<P as Program>::Renderer as compositor::Default>::Compositor,
|
compositor: &mut Option<
|
||||||
|
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
||||||
|
>,
|
||||||
window_manager: &mut crate::WindowManager<
|
window_manager: &mut crate::WindowManager<
|
||||||
P,
|
P,
|
||||||
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
<<P as Program>::Renderer as compositor::Default>::Compositor,
|
||||||
|
|
@ -363,6 +365,7 @@ impl SctkEvent {
|
||||||
window::Id,
|
window::Id,
|
||||||
(u64, iced_accessibility::accesskit_winit::Adapter),
|
(u64, iced_accessibility::accesskit_winit::Adapter),
|
||||||
>,
|
>,
|
||||||
|
create_compositor_data: CreateCompositor<'b, P>,
|
||||||
) where
|
) where
|
||||||
P: Program,
|
P: Program,
|
||||||
{
|
{
|
||||||
|
|
@ -766,7 +769,25 @@ impl SctkEvent {
|
||||||
sctk_winit.clone(),
|
sctk_winit.clone(),
|
||||||
))
|
))
|
||||||
.expect("Send control message");
|
.expect("Send control message");
|
||||||
|
if compositor.is_none() {
|
||||||
|
match create_compositor(
|
||||||
|
sctk_winit.clone(),
|
||||||
|
create_compositor_data,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(c) => *compositor = Some(c),
|
||||||
|
Err(error) => {
|
||||||
|
control_sender
|
||||||
|
.start_send(Control::Crash(
|
||||||
|
Error::GraphicsCreationFailed(error),
|
||||||
|
))
|
||||||
|
.expect("Send control message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let compositor = compositor.as_mut().unwrap();
|
||||||
let window = window_manager.insert(
|
let window = window_manager.insert(
|
||||||
surface_id,
|
surface_id,
|
||||||
sctk_winit,
|
sctk_winit,
|
||||||
|
|
@ -976,6 +997,10 @@ impl SctkEvent {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let Some(compositor) = compositor.as_mut() else {
|
||||||
|
log::error!("compositor missing");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let window = window_manager.insert(
|
let window = window_manager.insert(
|
||||||
surface_id,
|
surface_id,
|
||||||
|
|
@ -1190,6 +1215,25 @@ impl SctkEvent {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
if compositor.is_none() {
|
||||||
|
match create_compositor(
|
||||||
|
sctk_winit.clone(),
|
||||||
|
create_compositor_data,
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(c) => *compositor = Some(c),
|
||||||
|
Err(error) => {
|
||||||
|
control_sender
|
||||||
|
.start_send(Control::Crash(
|
||||||
|
Error::GraphicsCreationFailed(error),
|
||||||
|
))
|
||||||
|
.expect("Send control message");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let compositor = compositor.as_mut().unwrap();
|
||||||
|
|
||||||
let window = window_manager.insert(
|
let window = window_manager.insert(
|
||||||
surface_id,
|
surface_id,
|
||||||
|
|
@ -1201,20 +1245,70 @@ impl SctkEvent {
|
||||||
);
|
);
|
||||||
_ = surface_ids.insert(object_id, wrapper.clone());
|
_ = surface_ids.insert(object_id, wrapper.clone());
|
||||||
let logical_size = window.logical_size();
|
let logical_size = window.logical_size();
|
||||||
todo!()
|
let mut ui = crate::build_user_interface(
|
||||||
// let _ = user_interfaces.insert(
|
program,
|
||||||
// surface_id,
|
user_interface::Cache::default(),
|
||||||
// crate::build_user_interface(
|
&mut window.renderer,
|
||||||
// program,
|
logical_size,
|
||||||
// user_interface::Cache::default(),
|
surface_id,
|
||||||
// &mut window.renderer,
|
window.raw.clone(),
|
||||||
// logical_size,
|
window.prev_dnd_destination_rectangles_count,
|
||||||
// surface_id,
|
clipboard,
|
||||||
// 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,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
_ = user_interfaces.insert(surface_id, ui);
|
||||||
}
|
}
|
||||||
SctkEvent::SessionLockSurfaceConfigure {
|
SctkEvent::SessionLockSurfaceConfigure {
|
||||||
surface,
|
surface,
|
||||||
|
|
@ -1434,6 +1528,10 @@ impl SctkEvent {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
let Some(compositor) = compositor.as_mut() else {
|
||||||
|
log::error!("compositor missing");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
let window = window_manager.insert(
|
let window = window_manager.insert(
|
||||||
surface_id,
|
surface_id,
|
||||||
|
|
|
||||||
|
|
@ -72,8 +72,10 @@ where
|
||||||
);
|
);
|
||||||
let renderer = compositor.create_renderer();
|
let renderer = compositor.create_renderer();
|
||||||
|
|
||||||
|
self.aliases.retain(|w, i| *w != window.id() && *i != id);
|
||||||
let _ = self.aliases.insert(window.id(), id);
|
let _ = self.aliases.insert(window.id(), id);
|
||||||
|
|
||||||
|
self.entries.retain(|old, _| id != *old);
|
||||||
let _ = self.entries.insert(
|
let _ = self.entries.insert(
|
||||||
id,
|
id,
|
||||||
Window {
|
Window {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue