Merge branch 'master' into feature/test-recorder
This commit is contained in:
commit
a052ce58b0
69 changed files with 1555 additions and 833 deletions
|
|
@ -5,6 +5,7 @@
|
|||
use crate::core::input_method;
|
||||
use crate::core::keyboard;
|
||||
use crate::core::mouse;
|
||||
use crate::core::theme;
|
||||
use crate::core::touch;
|
||||
use crate::core::window;
|
||||
use crate::core::{Event, Point, Size};
|
||||
|
|
@ -13,6 +14,7 @@ use crate::core::{Event, Point, Size};
|
|||
pub fn window_attributes(
|
||||
settings: window::Settings,
|
||||
title: &str,
|
||||
scale_factor: f32,
|
||||
primary_monitor: Option<winit::monitor::MonitorHandle>,
|
||||
_id: Option<String>,
|
||||
) -> winit::window::WindowAttributes {
|
||||
|
|
@ -21,8 +23,8 @@ pub fn window_attributes(
|
|||
attributes = attributes
|
||||
.with_title(title)
|
||||
.with_inner_size(winit::dpi::LogicalSize {
|
||||
width: settings.size.width,
|
||||
height: settings.size.height,
|
||||
width: settings.size.width * scale_factor,
|
||||
height: settings.size.height * scale_factor,
|
||||
})
|
||||
.with_maximized(settings.maximized)
|
||||
.with_fullscreen(
|
||||
|
|
@ -138,7 +140,7 @@ pub fn window_attributes(
|
|||
/// Converts a winit window event into an iced event.
|
||||
pub fn window_event(
|
||||
event: winit::event::WindowEvent,
|
||||
scale_factor: f64,
|
||||
scale_factor: f32,
|
||||
modifiers: winit::keyboard::ModifiersState,
|
||||
) -> Option<Event> {
|
||||
use winit::event::Ime;
|
||||
|
|
@ -146,7 +148,7 @@ pub fn window_event(
|
|||
|
||||
match event {
|
||||
WindowEvent::Resized(new_size) => {
|
||||
let logical_size = new_size.to_logical(scale_factor);
|
||||
let logical_size = new_size.to_logical(f64::from(scale_factor));
|
||||
|
||||
Some(Event::Window(window::Event::Resized(Size {
|
||||
width: logical_size.width,
|
||||
|
|
@ -157,7 +159,7 @@ pub fn window_event(
|
|||
Some(Event::Window(window::Event::CloseRequested))
|
||||
}
|
||||
WindowEvent::CursorMoved { position, .. } => {
|
||||
let position = position.to_logical::<f64>(scale_factor);
|
||||
let position = position.to_logical::<f64>(f64::from(scale_factor));
|
||||
|
||||
Some(Event::Mouse(mouse::Event::CursorMoved {
|
||||
position: Point::new(position.x as f32, position.y as f32),
|
||||
|
|
@ -313,7 +315,7 @@ pub fn window_event(
|
|||
}
|
||||
WindowEvent::Moved(position) => {
|
||||
let winit::dpi::LogicalPosition { x, y } =
|
||||
position.to_logical(scale_factor);
|
||||
position.to_logical(f64::from(scale_factor));
|
||||
|
||||
Some(Event::Window(window::Event::Moved(Point::new(x, y))))
|
||||
}
|
||||
|
|
@ -321,7 +323,7 @@ pub fn window_event(
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a [`window::Level`] to a [`winit`] window level.
|
||||
/// Converts a [`window::Level`] into a [`winit`] window level.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
pub fn window_level(level: window::Level) -> winit::window::WindowLevel {
|
||||
|
|
@ -334,7 +336,7 @@ pub fn window_level(level: window::Level) -> winit::window::WindowLevel {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a [`window::Position`] to a [`winit`] logical position for a given monitor.
|
||||
/// Converts a [`window::Position`] into a [`winit`] logical position for a given monitor.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
pub fn position(
|
||||
|
|
@ -406,7 +408,7 @@ pub fn position(
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a [`window::Mode`] to a [`winit`] fullscreen mode.
|
||||
/// Converts a [`window::Mode`] into a [`winit`] fullscreen mode.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
pub fn fullscreen(
|
||||
|
|
@ -421,7 +423,7 @@ pub fn fullscreen(
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a [`window::Mode`] to a visibility flag.
|
||||
/// Converts a [`window::Mode`] into a visibility flag.
|
||||
pub fn visible(mode: window::Mode) -> bool {
|
||||
match mode {
|
||||
window::Mode::Windowed | window::Mode::Fullscreen => true,
|
||||
|
|
@ -429,7 +431,7 @@ pub fn visible(mode: window::Mode) -> bool {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a [`winit`] fullscreen mode to a [`window::Mode`].
|
||||
/// Converts a [`winit`] fullscreen mode into a [`window::Mode`].
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
pub fn mode(mode: Option<winit::window::Fullscreen>) -> window::Mode {
|
||||
|
|
@ -439,7 +441,28 @@ pub fn mode(mode: Option<winit::window::Fullscreen>) -> window::Mode {
|
|||
}
|
||||
}
|
||||
|
||||
/// Converts a [`mouse::Interaction`] to a [`winit`] cursor icon.
|
||||
/// Converts a [`winit`] window theme into a [`theme::Mode`].
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
pub fn theme_mode(theme: winit::window::Theme) -> theme::Mode {
|
||||
match theme {
|
||||
winit::window::Theme::Light => theme::Mode::Light,
|
||||
winit::window::Theme::Dark => theme::Mode::Dark,
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a [`theme::Mode`] into a window theme.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
pub fn window_theme(mode: theme::Mode) -> Option<winit::window::Theme> {
|
||||
match mode {
|
||||
theme::Mode::None => None,
|
||||
theme::Mode::Light => Some(winit::window::Theme::Light),
|
||||
theme::Mode::Dark => Some(winit::window::Theme::Dark),
|
||||
}
|
||||
}
|
||||
|
||||
/// Converts a [`mouse::Interaction`] into a [`winit`] cursor icon.
|
||||
///
|
||||
/// [`winit`]: https://github.com/rust-windowing/winit
|
||||
pub fn mouse_interaction(
|
||||
|
|
@ -510,12 +533,12 @@ pub fn modifiers(
|
|||
result
|
||||
}
|
||||
|
||||
/// Converts a physical cursor position to a logical `Point`.
|
||||
/// Converts a physical cursor position into a logical `Point`.
|
||||
pub fn cursor_position(
|
||||
position: winit::dpi::PhysicalPosition<f64>,
|
||||
scale_factor: f64,
|
||||
scale_factor: f32,
|
||||
) -> Point {
|
||||
let logical_position = position.to_logical(scale_factor);
|
||||
let logical_position = position.to_logical(f64::from(scale_factor));
|
||||
|
||||
Point::new(logical_position.x, logical_position.y)
|
||||
}
|
||||
|
|
@ -526,11 +549,12 @@ pub fn cursor_position(
|
|||
/// [`iced`]: https://github.com/iced-rs/iced/tree/0.12
|
||||
pub fn touch_event(
|
||||
touch: winit::event::Touch,
|
||||
scale_factor: f64,
|
||||
scale_factor: f32,
|
||||
) -> touch::Event {
|
||||
let id = touch::Finger(touch.id);
|
||||
let position = {
|
||||
let location = touch.location.to_logical::<f64>(scale_factor);
|
||||
let location =
|
||||
touch.location.to_logical::<f64>(f64::from(scale_factor));
|
||||
|
||||
Point::new(location.x as f32, location.y as f32)
|
||||
};
|
||||
|
|
@ -1180,7 +1204,7 @@ pub fn icon(icon: window::Icon) -> Option<winit::window::Icon> {
|
|||
winit::window::Icon::from_rgba(pixels, size.width, size.height).ok()
|
||||
}
|
||||
|
||||
/// Convertions some [`input_method::Purpose`] to its `winit` counterpart.
|
||||
/// Converts some [`input_method::Purpose`] into its `winit` counterpart.
|
||||
pub fn ime_purpose(
|
||||
purpose: input_method::Purpose,
|
||||
) -> winit::window::ImePurpose {
|
||||
|
|
|
|||
216
winit/src/lib.rs
216
winit/src/lib.rs
|
|
@ -29,9 +29,6 @@ pub use winit;
|
|||
pub mod clipboard;
|
||||
pub mod conversion;
|
||||
|
||||
#[cfg(feature = "system")]
|
||||
pub mod system;
|
||||
|
||||
mod error;
|
||||
mod proxy;
|
||||
mod window;
|
||||
|
|
@ -53,6 +50,7 @@ use crate::futures::futures::{Future, StreamExt};
|
|||
use crate::futures::subscription;
|
||||
use crate::futures::{Executor, Runtime};
|
||||
use crate::graphics::{Compositor, compositor};
|
||||
use crate::runtime::system;
|
||||
use crate::runtime::user_interface::{self, UserInterface};
|
||||
use crate::runtime::{Action, Task};
|
||||
|
||||
|
|
@ -109,7 +107,7 @@ where
|
|||
|
||||
let (_id, open) = runtime::window::open(window_settings);
|
||||
|
||||
open.then(move |_| task.take().unwrap_or(Task::none()))
|
||||
open.then(move |_| task.take().unwrap_or_else(Task::none))
|
||||
} else {
|
||||
task
|
||||
};
|
||||
|
|
@ -124,6 +122,7 @@ where
|
|||
|
||||
let (event_sender, event_receiver) = mpsc::unbounded();
|
||||
let (control_sender, control_receiver) = mpsc::unbounded();
|
||||
let (system_theme_sender, system_theme_receiver) = oneshot::channel();
|
||||
|
||||
let instance = Box::pin(run_instance::<P>(
|
||||
program,
|
||||
|
|
@ -134,6 +133,7 @@ where
|
|||
is_daemon,
|
||||
graphics_settings,
|
||||
settings.fonts,
|
||||
system_theme_receiver,
|
||||
));
|
||||
|
||||
let context = task::Context::from_waker(task::noop_waker_ref());
|
||||
|
|
@ -145,6 +145,7 @@ where
|
|||
sender: mpsc::UnboundedSender<Event<Action<Message>>>,
|
||||
receiver: mpsc::UnboundedReceiver<Control>,
|
||||
error: Option<Error>,
|
||||
system_theme: Option<oneshot::Sender<theme::Mode>>,
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
canvas: Option<web_sys::HtmlCanvasElement>,
|
||||
|
|
@ -157,6 +158,7 @@ where
|
|||
sender: event_sender,
|
||||
receiver: control_receiver,
|
||||
error: None,
|
||||
system_theme: Some(system_theme_sender),
|
||||
|
||||
#[cfg(target_arch = "wasm32")]
|
||||
canvas: None,
|
||||
|
|
@ -169,10 +171,15 @@ where
|
|||
where
|
||||
F: Future<Output = ()>,
|
||||
{
|
||||
fn resumed(
|
||||
&mut self,
|
||||
_event_loop: &winit::event_loop::ActiveEventLoop,
|
||||
) {
|
||||
fn resumed(&mut self, event_loop: &winit::event_loop::ActiveEventLoop) {
|
||||
if let Some(sender) = self.system_theme.take() {
|
||||
let _ = sender.send(
|
||||
event_loop
|
||||
.system_theme()
|
||||
.map(conversion::theme_mode)
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn new_events(
|
||||
|
|
@ -307,6 +314,7 @@ where
|
|||
id,
|
||||
settings,
|
||||
title,
|
||||
scale_factor,
|
||||
monitor,
|
||||
on_open,
|
||||
} => {
|
||||
|
|
@ -323,6 +331,7 @@ where
|
|||
conversion::window_attributes(
|
||||
settings,
|
||||
&title,
|
||||
scale_factor,
|
||||
monitor
|
||||
.or(event_loop.primary_monitor()),
|
||||
self.id.clone(),
|
||||
|
|
@ -417,7 +426,9 @@ where
|
|||
);
|
||||
}
|
||||
Control::Exit => {
|
||||
self.process_event(event_loop, Event::Exit);
|
||||
event_loop.exit();
|
||||
break;
|
||||
}
|
||||
Control::Crash(error) => {
|
||||
self.error = Some(error);
|
||||
|
|
@ -464,6 +475,7 @@ enum Event<Message: 'static> {
|
|||
on_open: oneshot::Sender<window::Id>,
|
||||
},
|
||||
EventLoopAwakened(winit::event::Event<Message>),
|
||||
Exit,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
|
|
@ -477,6 +489,7 @@ enum Control {
|
|||
title: String,
|
||||
monitor: Option<winit::monitor::MonitorHandle>,
|
||||
on_open: oneshot::Sender<window::Id>,
|
||||
scale_factor: f32,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -489,6 +502,7 @@ async fn run_instance<P>(
|
|||
is_daemon: bool,
|
||||
graphics_settings: graphics::Settings,
|
||||
default_fonts: Vec<Cow<'static, [u8]>>,
|
||||
mut _system_theme: oneshot::Receiver<theme::Mode>,
|
||||
) where
|
||||
P: Program + 'static,
|
||||
P::Theme: theme::Base,
|
||||
|
|
@ -508,6 +522,38 @@ async fn run_instance<P>(
|
|||
let mut user_interfaces = ManuallyDrop::new(FxHashMap::default());
|
||||
let mut clipboard = Clipboard::unconnected();
|
||||
|
||||
#[cfg(all(feature = "linux-theme-detection", target_os = "linux"))]
|
||||
let mut system_theme = {
|
||||
let to_mode = |color_scheme| match color_scheme {
|
||||
mundy::ColorScheme::NoPreference => theme::Mode::None,
|
||||
mundy::ColorScheme::Light => theme::Mode::Light,
|
||||
mundy::ColorScheme::Dark => theme::Mode::Dark,
|
||||
};
|
||||
|
||||
runtime.run(
|
||||
mundy::Preferences::stream(mundy::Interest::ColorScheme)
|
||||
.map(move |preferences| {
|
||||
Action::System(system::Action::NotifyTheme(to_mode(
|
||||
preferences.color_scheme,
|
||||
)))
|
||||
})
|
||||
.boxed(),
|
||||
);
|
||||
|
||||
mundy::Preferences::once_blocking(
|
||||
mundy::Interest::ColorScheme,
|
||||
core::time::Duration::from_millis(200),
|
||||
)
|
||||
.map(|preferences| to_mode(preferences.color_scheme))
|
||||
.unwrap_or_default()
|
||||
};
|
||||
|
||||
#[cfg(not(all(feature = "linux-theme-detection", target_os = "linux")))]
|
||||
let mut system_theme =
|
||||
_system_theme.try_recv().ok().flatten().unwrap_or_default();
|
||||
|
||||
log::info!("System theme: {system_theme:?}");
|
||||
|
||||
loop {
|
||||
// Empty the queue if possible
|
||||
let event = if let Ok(event) = event_receiver.try_next() {
|
||||
|
|
@ -586,14 +632,20 @@ async fn run_instance<P>(
|
|||
}
|
||||
}
|
||||
|
||||
debug::theme_changed(|| {
|
||||
if window_manager.is_empty() {
|
||||
theme::Base::palette(&program.theme(id))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
let window_theme = window
|
||||
.theme()
|
||||
.map(conversion::theme_mode)
|
||||
.unwrap_or_default();
|
||||
|
||||
if system_theme != window_theme {
|
||||
system_theme = window_theme;
|
||||
|
||||
runtime.broadcast(subscription::Event::SystemThemeChanged(
|
||||
window_theme,
|
||||
));
|
||||
}
|
||||
|
||||
let is_first = window_manager.is_empty();
|
||||
let window = window_manager.insert(
|
||||
id,
|
||||
window,
|
||||
|
|
@ -602,8 +654,21 @@ async fn run_instance<P>(
|
|||
.as_mut()
|
||||
.expect("Compositor must be initialized"),
|
||||
exit_on_close_request,
|
||||
system_theme,
|
||||
);
|
||||
|
||||
window.raw.set_theme(conversion::window_theme(
|
||||
window.state.theme_mode(),
|
||||
));
|
||||
|
||||
debug::theme_changed(|| {
|
||||
if is_first {
|
||||
theme::Base::palette(window.state.theme())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
});
|
||||
|
||||
let logical_size = window.state.logical_size();
|
||||
|
||||
let _ = user_interfaces.insert(
|
||||
|
|
@ -686,6 +751,7 @@ async fn run_instance<P>(
|
|||
run_action(
|
||||
action,
|
||||
&program,
|
||||
&mut runtime,
|
||||
&mut compositor,
|
||||
&mut events,
|
||||
&mut messages,
|
||||
|
|
@ -695,6 +761,7 @@ async fn run_instance<P>(
|
|||
&mut window_manager,
|
||||
&mut ui_caches,
|
||||
&mut is_window_opening,
|
||||
&mut system_theme,
|
||||
);
|
||||
actions += 1;
|
||||
}
|
||||
|
|
@ -853,11 +920,24 @@ async fn run_instance<P>(
|
|||
continue;
|
||||
};
|
||||
|
||||
if matches!(
|
||||
window_event,
|
||||
winit::event::WindowEvent::Resized(_)
|
||||
) {
|
||||
window.raw.request_redraw();
|
||||
match window_event {
|
||||
winit::event::WindowEvent::Resized(_) => {
|
||||
window.raw.request_redraw();
|
||||
}
|
||||
winit::event::WindowEvent::ThemeChanged(theme) => {
|
||||
let mode = conversion::theme_mode(theme);
|
||||
|
||||
if mode != system_theme {
|
||||
system_theme = mode;
|
||||
|
||||
runtime.broadcast(
|
||||
subscription::Event::SystemThemeChanged(
|
||||
mode,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
|
||||
if matches!(
|
||||
|
|
@ -870,6 +950,7 @@ async fn run_instance<P>(
|
|||
id,
|
||||
)),
|
||||
&program,
|
||||
&mut runtime,
|
||||
&mut compositor,
|
||||
&mut events,
|
||||
&mut messages,
|
||||
|
|
@ -879,9 +960,14 @@ async fn run_instance<P>(
|
|||
&mut window_manager,
|
||||
&mut ui_caches,
|
||||
&mut is_window_opening,
|
||||
&mut system_theme,
|
||||
);
|
||||
} else {
|
||||
window.state.update(&window.raw, &window_event);
|
||||
window.state.update(
|
||||
&program,
|
||||
&window.raw,
|
||||
&window_event,
|
||||
);
|
||||
|
||||
if let Some(event) = conversion::window_event(
|
||||
window_event,
|
||||
|
|
@ -1033,6 +1119,7 @@ async fn run_instance<P>(
|
|||
_ => {}
|
||||
}
|
||||
}
|
||||
Event::Exit => break,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1085,6 +1172,7 @@ fn update<P: Program, E: Executor>(
|
|||
fn run_action<'a, P, C>(
|
||||
action: Action<P::Message>,
|
||||
program: &'a program::Instance<P>,
|
||||
runtime: &mut Runtime<P::Executor, Proxy<P::Message>, Action<P::Message>>,
|
||||
compositor: &mut Option<C>,
|
||||
events: &mut Vec<(window::Id, core::Event)>,
|
||||
messages: &mut Vec<P::Message>,
|
||||
|
|
@ -1097,13 +1185,13 @@ fn run_action<'a, P, C>(
|
|||
window_manager: &mut WindowManager<P, C>,
|
||||
ui_caches: &mut FxHashMap<window::Id, user_interface::Cache>,
|
||||
is_window_opening: &mut bool,
|
||||
system_theme: &mut theme::Mode,
|
||||
) where
|
||||
P: Program,
|
||||
C: Compositor<Renderer = P::Renderer> + 'static,
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
use crate::runtime::clipboard;
|
||||
use crate::runtime::system;
|
||||
use crate::runtime::window;
|
||||
|
||||
match action {
|
||||
|
|
@ -1127,6 +1215,7 @@ fn run_action<'a, P, C>(
|
|||
id,
|
||||
settings,
|
||||
title: program.title(id),
|
||||
scale_factor: program.scale_factor(id),
|
||||
monitor,
|
||||
on_open: channel,
|
||||
})
|
||||
|
|
@ -1187,7 +1276,10 @@ fn run_action<'a, P, C>(
|
|||
winit::dpi::LogicalSize {
|
||||
width: size.width,
|
||||
height: size.height,
|
||||
},
|
||||
}
|
||||
.to_physical::<f32>(f64::from(
|
||||
window.state.scale_factor(),
|
||||
)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -1198,6 +1290,9 @@ fn run_action<'a, P, C>(
|
|||
width: size.width,
|
||||
height: size.height,
|
||||
}
|
||||
.to_physical::<f32>(f64::from(
|
||||
window.state.scale_factor(),
|
||||
))
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -1208,6 +1303,9 @@ fn run_action<'a, P, C>(
|
|||
width: size.width,
|
||||
height: size.height,
|
||||
}
|
||||
.to_physical::<f32>(f64::from(
|
||||
window.state.scale_factor(),
|
||||
))
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -1218,6 +1316,9 @@ fn run_action<'a, P, C>(
|
|||
width: size.width,
|
||||
height: size.height,
|
||||
}
|
||||
.to_physical::<f32>(f64::from(
|
||||
window.state.scale_factor(),
|
||||
))
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
|
@ -1231,7 +1332,7 @@ fn run_action<'a, P, C>(
|
|||
let size = window
|
||||
.raw
|
||||
.inner_size()
|
||||
.to_logical(window.raw.scale_factor());
|
||||
.to_logical(f64::from(window.state.scale_factor()));
|
||||
|
||||
let _ = channel.send(Size::new(size.width, size.height));
|
||||
}
|
||||
|
|
@ -1398,21 +1499,44 @@ fn run_action<'a, P, C>(
|
|||
}
|
||||
},
|
||||
Action::System(action) => match action {
|
||||
system::Action::QueryInformation(_channel) => {
|
||||
#[cfg(feature = "system")]
|
||||
system::Action::GetInformation(_channel) => {
|
||||
#[cfg(feature = "sysinfo")]
|
||||
{
|
||||
if let Some(compositor) = compositor {
|
||||
let graphics_info = compositor.fetch_information();
|
||||
let graphics_info = compositor.information();
|
||||
|
||||
let _ = std::thread::spawn(move || {
|
||||
let information =
|
||||
crate::system::information(graphics_info);
|
||||
let information = system_information(graphics_info);
|
||||
|
||||
let _ = _channel.send(information);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
system::Action::GetTheme(channel) => {
|
||||
let _ = channel.send(*system_theme);
|
||||
}
|
||||
system::Action::NotifyTheme(mode) => {
|
||||
if mode != *system_theme {
|
||||
*system_theme = mode;
|
||||
|
||||
runtime.broadcast(subscription::Event::SystemThemeChanged(
|
||||
mode,
|
||||
));
|
||||
}
|
||||
|
||||
let Some(theme) = conversion::window_theme(mode) else {
|
||||
return;
|
||||
};
|
||||
|
||||
for (_id, window) in window_manager.iter_mut() {
|
||||
window.state.update(
|
||||
program,
|
||||
&window.raw,
|
||||
&winit::event::WindowEvent::ThemeChanged(theme),
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
Action::Widget(operation) => {
|
||||
let mut current_operation = Some(operation);
|
||||
|
|
@ -1521,3 +1645,37 @@ pub fn user_force_quit(
|
|||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "sysinfo")]
|
||||
fn system_information(
|
||||
graphics: compositor::Information,
|
||||
) -> system::Information {
|
||||
use sysinfo::{Process, System};
|
||||
|
||||
let mut system = System::new_all();
|
||||
system.refresh_all();
|
||||
|
||||
let cpu_brand = system
|
||||
.cpus()
|
||||
.first()
|
||||
.map(|cpu| cpu.brand().to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
let memory_used = sysinfo::get_current_pid()
|
||||
.and_then(|pid| system.process(pid).ok_or("Process not found"))
|
||||
.map(Process::memory)
|
||||
.ok();
|
||||
|
||||
system::Information {
|
||||
system_name: System::name(),
|
||||
system_kernel: System::kernel_version(),
|
||||
system_version: System::long_os_version(),
|
||||
system_short_version: System::os_version(),
|
||||
cpu_brand,
|
||||
cpu_cores: system.physical_core_count(),
|
||||
memory_total: system.total_memory(),
|
||||
memory_used,
|
||||
graphics_adapter: graphics.adapter,
|
||||
graphics_backend: graphics.backend,
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,43 +0,0 @@
|
|||
//! Access the native system.
|
||||
use crate::graphics::compositor;
|
||||
use crate::runtime::system::{Action, Information};
|
||||
use crate::runtime::{self, Task};
|
||||
|
||||
/// Query for available system information.
|
||||
pub fn fetch_information() -> Task<Information> {
|
||||
runtime::task::oneshot(|channel| {
|
||||
runtime::Action::System(Action::QueryInformation(channel))
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn information(
|
||||
graphics_info: compositor::Information,
|
||||
) -> Information {
|
||||
use sysinfo::{Process, System};
|
||||
let mut system = System::new_all();
|
||||
system.refresh_all();
|
||||
|
||||
let cpu_brand = system
|
||||
.cpus()
|
||||
.first()
|
||||
.map(|cpu| cpu.brand().to_string())
|
||||
.unwrap_or_default();
|
||||
|
||||
let memory_used = sysinfo::get_current_pid()
|
||||
.and_then(|pid| system.process(pid).ok_or("Process not found"))
|
||||
.map(Process::memory)
|
||||
.ok();
|
||||
|
||||
Information {
|
||||
system_name: System::name(),
|
||||
system_kernel: System::kernel_version(),
|
||||
system_version: System::long_os_version(),
|
||||
system_short_version: System::os_version(),
|
||||
cpu_brand,
|
||||
cpu_cores: system.physical_core_count(),
|
||||
memory_total: system.total_memory(),
|
||||
memory_used,
|
||||
graphics_adapter: graphics_info.adapter,
|
||||
graphics_backend: graphics_info.backend,
|
||||
}
|
||||
}
|
||||
|
|
@ -55,8 +55,9 @@ where
|
|||
program: &program::Instance<P>,
|
||||
compositor: &mut C,
|
||||
exit_on_close_request: bool,
|
||||
system_theme: theme::Mode,
|
||||
) -> &mut Window<P, C> {
|
||||
let state = State::new(program, id, &window);
|
||||
let state = State::new(program, id, &window, system_theme);
|
||||
let viewport_version = state.viewport_version();
|
||||
let physical_size = state.physical_size();
|
||||
let surface = compositor.create_surface(
|
||||
|
|
|
|||
|
|
@ -9,18 +9,20 @@ use winit::window::Window;
|
|||
|
||||
use std::fmt::{Debug, Formatter};
|
||||
|
||||
/// The state of a multi-windowed [`Program`].
|
||||
/// The state of the window of a [`Program`].
|
||||
pub struct State<P: Program>
|
||||
where
|
||||
P::Theme: theme::Base,
|
||||
{
|
||||
title: String,
|
||||
scale_factor: f64,
|
||||
scale_factor: f32,
|
||||
viewport: Viewport,
|
||||
viewport_version: u64,
|
||||
cursor_position: Option<winit::dpi::PhysicalPosition<f64>>,
|
||||
modifiers: winit::keyboard::ModifiersState,
|
||||
theme: P::Theme,
|
||||
theme: Option<P::Theme>,
|
||||
theme_mode: theme::Mode,
|
||||
default_theme: P::Theme,
|
||||
style: theme::Style,
|
||||
}
|
||||
|
||||
|
|
@ -29,7 +31,7 @@ where
|
|||
P::Theme: theme::Base,
|
||||
{
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
f.debug_struct("multi_window::State")
|
||||
f.debug_struct("window::State")
|
||||
.field("title", &self.title)
|
||||
.field("scale_factor", &self.scale_factor)
|
||||
.field("viewport", &self.viewport)
|
||||
|
|
@ -49,18 +51,22 @@ where
|
|||
program: &program::Instance<P>,
|
||||
window_id: window::Id,
|
||||
window: &Window,
|
||||
system_theme: theme::Mode,
|
||||
) -> Self {
|
||||
let title = program.title(window_id);
|
||||
let scale_factor = program.scale_factor(window_id);
|
||||
let theme = program.theme(window_id);
|
||||
let style = program.style(&theme);
|
||||
let theme_mode =
|
||||
theme.as_ref().map(theme::Base::mode).unwrap_or_default();
|
||||
let default_theme = <P::Theme as theme::Base>::default(system_theme);
|
||||
let style = program.style(theme.as_ref().unwrap_or(&default_theme));
|
||||
|
||||
let viewport = {
|
||||
let physical_size = window.inner_size();
|
||||
|
||||
Viewport::with_physical_size(
|
||||
Size::new(physical_size.width, physical_size.height),
|
||||
window.scale_factor() * scale_factor,
|
||||
window.scale_factor() as f32 * scale_factor,
|
||||
)
|
||||
};
|
||||
|
||||
|
|
@ -72,6 +78,8 @@ where
|
|||
cursor_position: None,
|
||||
modifiers: winit::keyboard::ModifiersState::default(),
|
||||
theme,
|
||||
theme_mode,
|
||||
default_theme,
|
||||
style,
|
||||
}
|
||||
}
|
||||
|
|
@ -99,7 +107,7 @@ where
|
|||
}
|
||||
|
||||
/// Returns the current scale factor of the [`Viewport`] of the [`State`].
|
||||
pub fn scale_factor(&self) -> f64 {
|
||||
pub fn scale_factor(&self) -> f32 {
|
||||
self.viewport.scale_factor()
|
||||
}
|
||||
|
||||
|
|
@ -123,7 +131,12 @@ where
|
|||
|
||||
/// Returns the current theme of the [`State`].
|
||||
pub fn theme(&self) -> &P::Theme {
|
||||
&self.theme
|
||||
self.theme.as_ref().unwrap_or(&self.default_theme)
|
||||
}
|
||||
|
||||
/// Returns the current [`theme::Mode`] of the [`State`].
|
||||
pub fn theme_mode(&self) -> theme::Mode {
|
||||
self.theme_mode
|
||||
}
|
||||
|
||||
/// Returns the current background [`Color`] of the [`State`].
|
||||
|
|
@ -137,14 +150,19 @@ where
|
|||
}
|
||||
|
||||
/// Processes the provided window event and updates the [`State`] accordingly.
|
||||
pub fn update(&mut self, window: &Window, event: &WindowEvent) {
|
||||
pub fn update(
|
||||
&mut self,
|
||||
program: &program::Instance<P>,
|
||||
window: &Window,
|
||||
event: &WindowEvent,
|
||||
) {
|
||||
match event {
|
||||
WindowEvent::Resized(new_size) => {
|
||||
let size = Size::new(new_size.width, new_size.height);
|
||||
|
||||
self.viewport = Viewport::with_physical_size(
|
||||
size,
|
||||
window.scale_factor() * self.scale_factor,
|
||||
window.scale_factor() as f32 * self.scale_factor,
|
||||
);
|
||||
|
||||
self.viewport_version = self.viewport_version.wrapping_add(1);
|
||||
|
|
@ -157,7 +175,7 @@ where
|
|||
|
||||
self.viewport = Viewport::with_physical_size(
|
||||
size,
|
||||
new_scale_factor * self.scale_factor,
|
||||
*new_scale_factor as f32 * self.scale_factor,
|
||||
);
|
||||
|
||||
self.viewport_version = self.viewport_version.wrapping_add(1);
|
||||
|
|
@ -174,6 +192,16 @@ where
|
|||
WindowEvent::ModifiersChanged(new_modifiers) => {
|
||||
self.modifiers = new_modifiers.state();
|
||||
}
|
||||
WindowEvent::ThemeChanged(theme) => {
|
||||
self.default_theme = <P::Theme as theme::Base>::default(
|
||||
conversion::theme_mode(*theme),
|
||||
);
|
||||
|
||||
if self.theme.is_none() {
|
||||
self.style = program.style(&self.default_theme);
|
||||
window.request_redraw();
|
||||
}
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
|
@ -182,7 +210,7 @@ where
|
|||
/// window.
|
||||
///
|
||||
/// Normally, a [`Program`] should be synchronized with its [`State`]
|
||||
/// and window after calling [`State::update`].
|
||||
/// and window after calling [`Program::update`].
|
||||
pub fn synchronize(
|
||||
&mut self,
|
||||
program: &program::Instance<P>,
|
||||
|
|
@ -208,7 +236,7 @@ where
|
|||
{
|
||||
self.viewport = Viewport::with_physical_size(
|
||||
Size::new(new_size.width, new_size.height),
|
||||
window.scale_factor() * new_scale_factor,
|
||||
window.scale_factor() as f32 * new_scale_factor,
|
||||
);
|
||||
self.viewport_version = self.viewport_version.wrapping_add(1);
|
||||
|
||||
|
|
@ -217,6 +245,45 @@ where
|
|||
|
||||
// Update theme and appearance
|
||||
self.theme = program.theme(window_id);
|
||||
self.style = program.style(&self.theme);
|
||||
self.style = program.style(self.theme());
|
||||
|
||||
let new_mode = self
|
||||
.theme
|
||||
.as_ref()
|
||||
.map(theme::Base::mode)
|
||||
.unwrap_or_default();
|
||||
|
||||
if self.theme_mode != new_mode {
|
||||
#[cfg(not(target_os = "linux"))]
|
||||
{
|
||||
window.set_theme(conversion::window_theme(new_mode));
|
||||
|
||||
// Assume the old mode matches the system one
|
||||
// We will be notified otherwise
|
||||
if new_mode == theme::Mode::None {
|
||||
self.default_theme =
|
||||
<P::Theme as theme::Base>::default(self.theme_mode);
|
||||
|
||||
if self.theme.is_none() {
|
||||
self.style = program.style(&self.default_theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
{
|
||||
// mundy always notifies system theme changes, so we
|
||||
// just restore the default theme mode.
|
||||
let new_mode = if new_mode == theme::Mode::None {
|
||||
theme::Base::mode(&self.default_theme)
|
||||
} else {
|
||||
new_mode
|
||||
};
|
||||
|
||||
window.set_theme(conversion::window_theme(new_mode));
|
||||
}
|
||||
|
||||
self.theme_mode = new_mode;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue