summaryrefslogtreecommitdiffstats
path: root/winit
diff options
context:
space:
mode:
Diffstat (limited to 'winit')
-rw-r--r--winit/Cargo.toml2
-rw-r--r--winit/src/conversion.rs2
-rw-r--r--winit/src/program.rs257
-rw-r--r--winit/src/program/state.rs32
-rw-r--r--winit/src/program/window_manager.rs31
-rw-r--r--winit/src/settings.rs11
6 files changed, 182 insertions, 153 deletions
diff --git a/winit/Cargo.toml b/winit/Cargo.toml
index bd6feb00..10a6369b 100644
--- a/winit/Cargo.toml
+++ b/winit/Cargo.toml
@@ -22,7 +22,7 @@ x11 = ["winit/x11"]
wayland = ["winit/wayland"]
wayland-dlopen = ["winit/wayland-dlopen"]
wayland-csd-adwaita = ["winit/wayland-csd-adwaita"]
-multi-window = ["iced_runtime/multi-window"]
+unconditional-rendering = []
[dependencies]
iced_futures.workspace = true
diff --git a/winit/src/conversion.rs b/winit/src/conversion.rs
index e454c208..01c6abc8 100644
--- a/winit/src/conversion.rs
+++ b/winit/src/conversion.rs
@@ -197,6 +197,8 @@ pub fn window_event(
}))
}
},
+ // Ignore keyboard presses/releases during window focus/unfocus
+ WindowEvent::KeyboardInput { is_synthetic, .. } if is_synthetic => None,
WindowEvent::KeyboardInput { event, .. } => Some(Event::Keyboard({
let key = {
#[cfg(not(target_arch = "wasm32"))]
diff --git a/winit/src/program.rs b/winit/src/program.rs
index 8d1eec3a..cc19a4e0 100644
--- a/winit/src/program.rs
+++ b/winit/src/program.rs
@@ -8,10 +8,11 @@ use crate::conversion;
use crate::core;
use crate::core::mouse;
use crate::core::renderer;
+use crate::core::theme;
use crate::core::time::Instant;
use crate::core::widget::operation;
use crate::core::window;
-use crate::core::{Color, Element, Point, Size, Theme};
+use crate::core::{Element, Point, Size};
use crate::futures::futures::channel::mpsc;
use crate::futures::futures::channel::oneshot;
use crate::futures::futures::task;
@@ -46,7 +47,7 @@ use std::sync::Arc;
pub trait Program
where
Self: Sized,
- Self::Theme: DefaultStyle,
+ Self::Theme: theme::Base,
{
/// The type of __messages__ your [`Program`] will produce.
type Message: std::fmt::Debug + Send;
@@ -106,8 +107,8 @@ where
fn theme(&self, window: window::Id) -> Self::Theme;
/// Returns the `Style` variation of the `Theme`.
- fn style(&self, theme: &Self::Theme) -> Appearance {
- theme.default_style()
+ fn style(&self, theme: &Self::Theme) -> theme::Style {
+ theme::Base::base(theme)
}
/// Returns the event `Subscription` for the current state of the
@@ -138,37 +139,6 @@ where
}
}
-/// The appearance of a program.
-#[derive(Debug, Clone, Copy, PartialEq)]
-pub struct Appearance {
- /// The background [`Color`] of the application.
- pub background_color: Color,
-
- /// The default text [`Color`] of the application.
- pub text_color: Color,
-}
-
-/// The default style of a [`Program`].
-pub trait DefaultStyle {
- /// Returns the default style of a [`Program`].
- fn default_style(&self) -> Appearance;
-}
-
-impl DefaultStyle for Theme {
- fn default_style(&self) -> Appearance {
- default(self)
- }
-}
-
-/// The default [`Appearance`] of a [`Program`] with the built-in [`Theme`].
-pub fn default(theme: &Theme) -> Appearance {
- let palette = theme.extended_palette();
-
- Appearance {
- background_color: palette.background.base.color,
- text_color: palette.background.base.text,
- }
-}
/// Runs a [`Program`] with an executor, compositor, and the provided
/// settings.
pub fn run<P, C>(
@@ -180,7 +150,7 @@ pub fn run<P, C>(
where
P: Program + 'static,
C: Compositor<Renderer = P::Renderer> + 'static,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
use winit::event_loop::EventLoop;
@@ -538,10 +508,25 @@ where
log::info!("Window attributes for id `{id:#?}`: {window_attributes:#?}");
+ // On macOS, the `position` in `WindowAttributes` represents the "inner"
+ // position of the window; while on other platforms it's the "outer" position.
+ // We fix the inconsistency on macOS by positioning the window after creation.
+ #[cfg(target_os = "macos")]
+ let mut window_attributes = window_attributes;
+
+ #[cfg(target_os = "macos")]
+ let position =
+ window_attributes.position.take();
+
let window = event_loop
.create_window(window_attributes)
.expect("Create window");
+ #[cfg(target_os = "macos")]
+ if let Some(position) = position {
+ window.set_outer_position(position);
+ }
+
#[cfg(target_arch = "wasm32")]
{
use winit::platform::web::WindowExtWebSys;
@@ -674,7 +659,7 @@ async fn run_instance<P, C>(
) where
P: Program + 'static,
C: Compositor<Renderer = P::Renderer> + 'static,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
use winit::event;
use winit::event_loop::ControlFlow;
@@ -758,12 +743,23 @@ async fn run_instance<P, C>(
}
Event::EventLoopAwakened(event) => {
match event {
+ event::Event::NewEvents(event::StartCause::Init) => {
+ for (_id, window) in window_manager.iter_mut() {
+ window.raw.request_redraw();
+ }
+ }
event::Event::NewEvents(
- event::StartCause::Init
- | event::StartCause::ResumeTimeReached { .. },
+ event::StartCause::ResumeTimeReached { .. },
) => {
+ let now = Instant::now();
+
for (_id, window) in window_manager.iter_mut() {
- window.raw.request_redraw();
+ if let Some(redraw_at) = window.redraw_at {
+ if redraw_at <= now {
+ window.raw.request_redraw();
+ window.redraw_at = None;
+ }
+ }
}
}
event::Event::PlatformSpecific(
@@ -807,11 +803,39 @@ async fn run_instance<P, C>(
continue;
};
- // TODO: Avoid redrawing all the time by forcing widgets to
- // request redraws on state changes
- //
- // Then, we can use the `interface_state` here to decide if a redraw
- // is needed right away, or simply wait until a specific time.
+ let physical_size = window.state.physical_size();
+
+ if physical_size.width == 0 || physical_size.height == 0
+ {
+ continue;
+ }
+
+ if window.viewport_version
+ != window.state.viewport_version()
+ {
+ let logical_size = window.state.logical_size();
+
+ debug.layout_started();
+ let ui = user_interfaces
+ .remove(&id)
+ .expect("Remove user interface");
+
+ let _ = user_interfaces.insert(
+ id,
+ ui.relayout(logical_size, &mut window.renderer),
+ );
+ debug.layout_finished();
+
+ compositor.configure_surface(
+ &mut window.surface,
+ physical_size.width,
+ physical_size.height,
+ );
+
+ window.viewport_version =
+ window.state.viewport_version();
+ }
+
let redraw_event = core::Event::Window(
window::Event::RedrawRequested(Instant::now()),
);
@@ -857,81 +881,18 @@ async fn run_instance<P, C>(
status: core::event::Status::Ignored,
});
- let _ = control_sender.start_send(Control::ChangeFlow(
- match ui_state {
- user_interface::State::Updated {
- redraw_request: Some(redraw_request),
- } => match redraw_request {
- window::RedrawRequest::NextFrame => {
- window.raw.request_redraw();
-
- ControlFlow::Wait
- }
- window::RedrawRequest::At(at) => {
- ControlFlow::WaitUntil(at)
- }
- },
- _ => ControlFlow::Wait,
- },
- ));
-
- let physical_size = window.state.physical_size();
-
- if physical_size.width == 0 || physical_size.height == 0
+ if let user_interface::State::Updated {
+ redraw_request: Some(redraw_request),
+ } = ui_state
{
- continue;
- }
-
- if window.viewport_version
- != window.state.viewport_version()
- {
- let logical_size = window.state.logical_size();
-
- debug.layout_started();
- let ui = user_interfaces
- .remove(&id)
- .expect("Remove user interface");
-
- let _ = user_interfaces.insert(
- id,
- ui.relayout(logical_size, &mut window.renderer),
- );
- debug.layout_finished();
-
- debug.draw_started();
- let new_mouse_interaction = user_interfaces
- .get_mut(&id)
- .expect("Get user interface")
- .draw(
- &mut window.renderer,
- window.state.theme(),
- &renderer::Style {
- text_color: window.state.text_color(),
- },
- window.state.cursor(),
- );
- debug.draw_finished();
-
- if new_mouse_interaction != window.mouse_interaction
- {
- window.raw.set_cursor(
- conversion::mouse_interaction(
- new_mouse_interaction,
- ),
- );
-
- window.mouse_interaction =
- new_mouse_interaction;
+ match redraw_request {
+ window::RedrawRequest::NextFrame => {
+ window.raw.request_redraw();
+ }
+ window::RedrawRequest::At(at) => {
+ window.redraw_at = Some(at);
+ }
}
-
- compositor.configure_surface(
- &mut window.surface,
- physical_size.width,
- physical_size.height,
- );
-
- window.viewport_version =
- window.state.viewport_version();
}
debug.render_started();
@@ -995,6 +956,13 @@ async fn run_instance<P, C>(
if matches!(
window_event,
+ winit::event::WindowEvent::Resized(_)
+ ) {
+ window.raw.request_redraw();
+ }
+
+ if matches!(
+ window_event,
winit::event::WindowEvent::CloseRequested
) && window.exit_on_close_request
{
@@ -1031,7 +999,10 @@ async fn run_instance<P, C>(
}
}
event::Event::AboutToWait => {
- if events.is_empty() && messages.is_empty() {
+ if events.is_empty()
+ && messages.is_empty()
+ && window_manager.is_idle()
+ {
continue;
}
@@ -1065,13 +1036,27 @@ async fn run_instance<P, C>(
&mut messages,
);
+ #[cfg(feature = "unconditional-rendering")]
window.raw.request_redraw();
- if !uis_stale {
- uis_stale = matches!(
- ui_state,
- user_interface::State::Outdated
- );
+ match ui_state {
+ #[cfg(not(
+ feature = "unconditional-rendering"
+ ))]
+ user_interface::State::Updated {
+ redraw_request: Some(redraw_request),
+ } => match redraw_request {
+ window::RedrawRequest::NextFrame => {
+ window.raw.request_redraw();
+ }
+ window::RedrawRequest::At(at) => {
+ window.redraw_at = Some(at);
+ }
+ },
+ user_interface::State::Outdated => {
+ uis_stale = true;
+ }
+ user_interface::State::Updated { .. } => {}
}
for (event, status) in window_events
@@ -1139,6 +1124,17 @@ async fn run_instance<P, C>(
actions = 0;
}
}
+
+ if let Some(redraw_at) = window_manager.redraw_at() {
+ let _ =
+ control_sender.start_send(Control::ChangeFlow(
+ ControlFlow::WaitUntil(redraw_at),
+ ));
+ } else {
+ let _ = control_sender.start_send(
+ Control::ChangeFlow(ControlFlow::Wait),
+ );
+ }
}
_ => {}
}
@@ -1159,7 +1155,7 @@ fn build_user_interface<'a, P: Program>(
id: window::Id,
) -> UserInterface<'a, P::Message, P::Theme, P::Renderer>
where
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
debug.view_started();
let view = program.view(id);
@@ -1178,7 +1174,7 @@ fn update<P: Program, E: Executor>(
debug: &mut Debug,
messages: &mut Vec<P::Message>,
) where
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
for message in messages.drain(..) {
debug.log_message(&message);
@@ -1215,7 +1211,7 @@ fn run_action<P, C>(
) where
P: Program,
C: Compositor<Renderer = P::Renderer> + 'static,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
use crate::runtime::clipboard;
use crate::runtime::system;
@@ -1329,7 +1325,7 @@ fn run_action<P, C>(
if let Some(window) = window_manager.get(id) {
let position = window
.raw
- .inner_position()
+ .outer_position()
.map(|position| {
let position = position
.to_logical::<f32>(window.raw.scale_factor());
@@ -1445,13 +1441,12 @@ fn run_action<P, C>(
if let Some(window) = window_manager.get_mut(id) {
let bytes = compositor.screenshot(
&mut window.renderer,
- &mut window.surface,
window.state.viewport(),
window.state.background_color(),
&debug.overlay(),
);
- let _ = channel.send(window::Screenshot::new(
+ let _ = channel.send(core::window::Screenshot::new(
bytes,
window.state.physical_size(),
window.state.viewport().scale_factor(),
@@ -1526,7 +1521,7 @@ pub fn build_user_interfaces<'a, P: Program, C>(
) -> FxHashMap<window::Id, UserInterface<'a, P::Message, P::Theme, P::Renderer>>
where
C: Compositor<Renderer = P::Renderer>,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
cached_user_interfaces
.drain()
diff --git a/winit/src/program/state.rs b/winit/src/program/state.rs
index a7fa2788..e883d04a 100644
--- a/winit/src/program/state.rs
+++ b/winit/src/program/state.rs
@@ -1,17 +1,18 @@
use crate::conversion;
-use crate::core::{mouse, window};
+use crate::core::{mouse, theme, window};
use crate::core::{Color, Size};
use crate::graphics::Viewport;
-use crate::program::{self, Program};
-use std::fmt::{Debug, Formatter};
+use crate::program::Program;
use winit::event::{Touch, WindowEvent};
use winit::window::Window;
+use std::fmt::{Debug, Formatter};
+
/// The state of a multi-windowed [`Program`].
pub struct State<P: Program>
where
- P::Theme: program::DefaultStyle,
+ P::Theme: theme::Base,
{
title: String,
scale_factor: f64,
@@ -20,12 +21,12 @@ where
cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
modifiers: winit::keyboard::ModifiersState,
theme: P::Theme,
- appearance: program::Appearance,
+ style: theme::Style,
}
impl<P: Program> Debug for State<P>
where
- P::Theme: program::DefaultStyle,
+ P::Theme: theme::Base,
{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.debug_struct("multi_window::State")
@@ -34,14 +35,14 @@ where
.field("viewport", &self.viewport)
.field("viewport_version", &self.viewport_version)
.field("cursor_position", &self.cursor_position)
- .field("appearance", &self.appearance)
+ .field("style", &self.style)
.finish()
}
}
impl<P: Program> State<P>
where
- P::Theme: program::DefaultStyle,
+ P::Theme: theme::Base,
{
/// Creates a new [`State`] for the provided [`Program`]'s `window`.
pub fn new(
@@ -52,7 +53,7 @@ where
let title = application.title(window_id);
let scale_factor = application.scale_factor(window_id);
let theme = application.theme(window_id);
- let appearance = application.style(&theme);
+ let style = application.style(&theme);
let viewport = {
let physical_size = window.inner_size();
@@ -71,7 +72,7 @@ where
cursor_position: None,
modifiers: winit::keyboard::ModifiersState::default(),
theme,
- appearance,
+ style,
}
}
@@ -127,12 +128,12 @@ where
/// Returns the current background [`Color`] of the [`State`].
pub fn background_color(&self) -> Color {
- self.appearance.background_color
+ self.style.background_color
}
/// Returns the current text [`Color`] of the [`State`].
pub fn text_color(&self) -> Color {
- self.appearance.text_color
+ self.style.text_color
}
/// Processes the provided window event and updates the [`State`] accordingly.
@@ -190,7 +191,10 @@ where
..
},
..
- } => _debug.toggle(),
+ } => {
+ _debug.toggle();
+ window.request_redraw();
+ }
_ => {}
}
}
@@ -234,6 +238,6 @@ where
// Update theme and appearance
self.theme = application.theme(window_id);
- self.appearance = application.style(&self.theme);
+ self.style = application.style(&self.theme);
}
}
diff --git a/winit/src/program/window_manager.rs b/winit/src/program/window_manager.rs
index 3d22e155..a3c991df 100644
--- a/winit/src/program/window_manager.rs
+++ b/winit/src/program/window_manager.rs
@@ -1,8 +1,10 @@
use crate::core::mouse;
+use crate::core::theme;
+use crate::core::time::Instant;
use crate::core::window::Id;
use crate::core::{Point, Size};
use crate::graphics::Compositor;
-use crate::program::{DefaultStyle, Program, State};
+use crate::program::{Program, State};
use std::collections::BTreeMap;
use std::sync::Arc;
@@ -13,7 +15,7 @@ pub struct WindowManager<P, C>
where
P: Program,
C: Compositor<Renderer = P::Renderer>,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
aliases: BTreeMap<winit::window::WindowId, Id>,
entries: BTreeMap<Id, Window<P, C>>,
@@ -23,7 +25,7 @@ impl<P, C> WindowManager<P, C>
where
P: Program,
C: Compositor<Renderer = P::Renderer>,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
pub fn new() -> Self {
Self {
@@ -62,6 +64,7 @@ where
surface,
renderer,
mouse_interaction: mouse::Interaction::None,
+ redraw_at: None,
},
);
@@ -74,6 +77,19 @@ where
self.entries.is_empty()
}
+ pub fn is_idle(&self) -> bool {
+ self.entries
+ .values()
+ .all(|window| window.redraw_at.is_none())
+ }
+
+ pub fn redraw_at(&self) -> Option<Instant> {
+ self.entries
+ .values()
+ .filter_map(|window| window.redraw_at)
+ .min()
+ }
+
pub fn first(&self) -> Option<&Window<P, C>> {
self.entries.first_key_value().map(|(_id, window)| window)
}
@@ -117,7 +133,7 @@ impl<P, C> Default for WindowManager<P, C>
where
P: Program,
C: Compositor<Renderer = P::Renderer>,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
fn default() -> Self {
Self::new()
@@ -129,7 +145,7 @@ pub struct Window<P, C>
where
P: Program,
C: Compositor<Renderer = P::Renderer>,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
pub raw: Arc<winit::window::Window>,
pub state: State<P>,
@@ -138,17 +154,18 @@ where
pub mouse_interaction: mouse::Interaction,
pub surface: C::Surface,
pub renderer: P::Renderer,
+ pub redraw_at: Option<Instant>,
}
impl<P, C> Window<P, C>
where
P: Program,
C: Compositor<Renderer = P::Renderer>,
- P::Theme: DefaultStyle,
+ P::Theme: theme::Base,
{
pub fn position(&self) -> Option<Point> {
self.raw
- .inner_position()
+ .outer_position()
.ok()
.map(|position| position.to_logical(self.raw.scale_factor()))
.map(|position| Point {
diff --git a/winit/src/settings.rs b/winit/src/settings.rs
index 78368a04..e2bf8abf 100644
--- a/winit/src/settings.rs
+++ b/winit/src/settings.rs
@@ -1,4 +1,6 @@
//! Configure your application.
+use crate::core;
+
use std::borrow::Cow;
/// The settings of an application.
@@ -13,3 +15,12 @@ pub struct Settings {
/// The fonts to load on boot.
pub fonts: Vec<Cow<'static, [u8]>>,
}
+
+impl From<core::Settings> for Settings {
+ fn from(settings: core::Settings) -> Self {
+ Self {
+ id: settings.id,
+ fonts: settings.fonts,
+ }
+ }
+}