diff options
-rw-r--r-- | Cargo.toml | 7 | ||||
-rw-r--r-- | examples/system_information/Cargo.toml | 10 | ||||
-rw-r--r-- | examples/system_information/src/main.rs | 165 | ||||
-rw-r--r-- | glow/src/settings.rs | 14 | ||||
-rw-r--r-- | glow/src/window/compositor.rs | 13 | ||||
-rw-r--r-- | glutin/Cargo.toml | 4 | ||||
-rw-r--r-- | glutin/src/application.rs | 26 | ||||
-rw-r--r-- | glutin/src/lib.rs | 13 | ||||
-rw-r--r-- | graphics/src/error.rs | 18 | ||||
-rw-r--r-- | graphics/src/lib.rs | 1 | ||||
-rw-r--r-- | graphics/src/window.rs | 6 | ||||
-rw-r--r-- | graphics/src/window/compositor.rs | 14 | ||||
-rw-r--r-- | graphics/src/window/gl_compositor.rs | 6 | ||||
-rw-r--r-- | native/src/command/action.rs | 6 | ||||
-rw-r--r-- | native/src/lib.rs | 1 | ||||
-rw-r--r-- | native/src/system.rs | 6 | ||||
-rw-r--r-- | native/src/system/action.rs | 39 | ||||
-rw-r--r-- | native/src/system/information.rs | 22 | ||||
-rw-r--r-- | src/error.rs | 10 | ||||
-rw-r--r-- | src/lib.rs | 3 | ||||
-rw-r--r-- | wgpu/src/window/compositor.rs | 41 | ||||
-rw-r--r-- | winit/Cargo.toml | 5 | ||||
-rw-r--r-- | winit/src/application.rs | 52 | ||||
-rw-r--r-- | winit/src/error.rs | 12 | ||||
-rw-r--r-- | winit/src/lib.rs | 3 | ||||
-rw-r--r-- | winit/src/system.rs | 41 |
26 files changed, 482 insertions, 56 deletions
@@ -42,6 +42,8 @@ smol = ["iced_futures/smol"] palette = ["iced_core/palette"] # Enables pure, virtual widgets in the `pure` module pure = ["iced_pure", "iced_graphics/pure"] +# Enables querying system information +system = ["iced_winit/system"] [badges] maintenance = { status = "actively-developed" } @@ -82,19 +84,20 @@ members = [ "examples/stopwatch", "examples/styling", "examples/svg", + "examples/system_information", "examples/todos", "examples/tooltip", "examples/tour", "examples/url_handler", + "examples/websocket", "examples/pure/component", "examples/pure/counter", "examples/pure/game_of_life", "examples/pure/pane_grid", "examples/pure/pick_list", "examples/pure/todos", - "examples/pure/tour", "examples/pure/tooltip", - "examples/websocket", + "examples/pure/tour", ] [dependencies] diff --git a/examples/system_information/Cargo.toml b/examples/system_information/Cargo.toml new file mode 100644 index 00000000..7d1e4b94 --- /dev/null +++ b/examples/system_information/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "system_information" +version = "0.1.0" +authors = ["Richard <richardsoncusto@gmail.com>"] +edition = "2021" +publish = false + +[dependencies] +iced = { path = "../..", features = ["system"] } +bytesize = { version = "1.1.0" } diff --git a/examples/system_information/src/main.rs b/examples/system_information/src/main.rs new file mode 100644 index 00000000..560220b8 --- /dev/null +++ b/examples/system_information/src/main.rs @@ -0,0 +1,165 @@ +use iced::{ + button, executor, system, Application, Button, Column, Command, Container, + Element, Length, Settings, Text, +}; + +use bytesize::ByteSize; + +pub fn main() -> iced::Result { + Example::run(Settings::default()) +} + +enum Example { + Loading, + Loaded { + information: system::Information, + refresh_button: button::State, + }, +} + +#[derive(Clone, Debug)] +enum Message { + InformationReceived(system::Information), + Refresh, +} + +impl Application for Example { + type Message = Message; + type Executor = executor::Default; + type Flags = (); + + fn new(_flags: ()) -> (Self, Command<Message>) { + ( + Self::Loading, + system::fetch_information(Message::InformationReceived), + ) + } + + fn title(&self) -> String { + String::from("System Information - Iced") + } + + fn update(&mut self, message: Message) -> Command<Message> { + match message { + Message::Refresh => { + *self = Self::Loading; + + return system::fetch_information(Message::InformationReceived); + } + Message::InformationReceived(information) => { + let refresh_button = button::State::new(); + *self = Self::Loaded { + information, + refresh_button, + }; + } + } + + Command::none() + } + + fn view(&mut self) -> Element<Message> { + let content: Element<Message> = match self { + Example::Loading => Text::new("Loading...").size(40).into(), + Example::Loaded { + information, + refresh_button, + } => { + let system_name = Text::new(format!( + "System name: {}", + information + .system_name + .as_ref() + .unwrap_or(&"unknown".to_string()) + )); + + let system_kernel = Text::new(format!( + "System kernel: {}", + information + .system_kernel + .as_ref() + .unwrap_or(&"unknown".to_string()) + )); + + let system_version = Text::new(format!( + "System version: {}", + information + .system_version + .as_ref() + .unwrap_or(&"unknown".to_string()) + )); + + let cpu_brand = Text::new(format!( + "Processor brand: {}", + information.cpu_brand + )); + + let cpu_cores = Text::new(format!( + "Processor cores: {}", + information + .cpu_cores + .map_or("unknown".to_string(), |cores| cores + .to_string()) + )); + + let memory_readable = + ByteSize::kb(information.memory_total).to_string(); + + let memory_total = Text::new(format!( + "Memory (total): {}", + format!( + "{} kb ({})", + information.memory_total, memory_readable + ) + )); + + let memory_text = if let Some(memory_used) = + information.memory_used + { + let memory_readable = ByteSize::kb(memory_used).to_string(); + + format!("{} kb ({})", memory_used, memory_readable) + } else { + String::from("None") + }; + + let memory_used = + Text::new(format!("Memory (used): {}", memory_text)); + + let graphics_adapter = Text::new(format!( + "Graphics adapter: {}", + information.graphics_adapter + )); + + let graphics_backend = Text::new(format!( + "Graphics backend: {}", + information.graphics_backend + )); + + Column::with_children(vec![ + system_name.size(30).into(), + system_kernel.size(30).into(), + system_version.size(30).into(), + cpu_brand.size(30).into(), + cpu_cores.size(30).into(), + memory_total.size(30).into(), + memory_used.size(30).into(), + graphics_adapter.size(30).into(), + graphics_backend.size(30).into(), + Button::new(refresh_button, Text::new("Refresh")) + .on_press(Message::Refresh) + .into(), + ]) + .spacing(10) + .into() + } + }; + + Container::new(content) + .center_x() + .center_y() + .width(Length::Fill) + .height(Length::Fill) + .into() + } +} diff --git a/glow/src/settings.rs b/glow/src/settings.rs index f3dddfaf..3691747b 100644 --- a/glow/src/settings.rs +++ b/glow/src/settings.rs @@ -4,7 +4,7 @@ pub use iced_graphics::Antialiasing; /// The settings of a [`Backend`]. /// /// [`Backend`]: crate::Backend -#[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[derive(Clone, Copy, PartialEq, Eq)] pub struct Settings { /// The bytes of the font that will be used by default. /// @@ -39,6 +39,18 @@ impl Default for Settings { } } +impl std::fmt::Debug for Settings { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("Settings") + // Instead of printing the font bytes, we simply show a `bool` indicating if using a default font or not. + .field("default_font", &self.default_font.is_none()) + .field("default_text_size", &self.default_text_size) + .field("text_multithreading", &self.text_multithreading) + .field("antialiasing", &self.antialiasing) + .finish() + } +} + impl Settings { /// Creates new [`Settings`] using environment configuration. /// diff --git a/glow/src/window/compositor.rs b/glow/src/window/compositor.rs index 44019fb2..622d7fc0 100644 --- a/glow/src/window/compositor.rs +++ b/glow/src/window/compositor.rs @@ -2,7 +2,7 @@ use crate::{Backend, Color, Error, Renderer, Settings, Viewport}; use core::ffi::c_void; use glow::HasContext; -use iced_graphics::{Antialiasing, Size}; +use iced_graphics::{compositor, Antialiasing, Size}; /// A window graphics backend for iced powered by `glow`. #[allow(missing_debug_implementations)] @@ -20,6 +20,8 @@ impl iced_graphics::window::GLCompositor for Compositor { ) -> Result<(Self, Self::Renderer), Error> { let gl = glow::Context::from_loader_function(loader_function); + log::info!("{:#?}", settings); + let version = gl.version(); log::info!("Version: {:?}", version); log::info!("Embedded: {}", version.is_embedded); @@ -65,6 +67,15 @@ impl iced_graphics::window::GLCompositor for Compositor { } } + fn fetch_information(&self) -> compositor::Information { + let adapter = unsafe { self.gl.get_parameter_string(glow::RENDERER) }; + + compositor::Information { + backend: format!("{:?}", self.gl.version()), + adapter, + } + } + fn present<T: AsRef<str>>( &mut self, renderer: &mut Self::Renderer, diff --git a/glutin/Cargo.toml b/glutin/Cargo.toml index fca0cd9f..5ad038c0 100644 --- a/glutin/Cargo.toml +++ b/glutin/Cargo.toml @@ -12,6 +12,10 @@ categories = ["gui"] [features] debug = ["iced_winit/debug"] +system = ["iced_winit/system"] + +[dependencies.log] +version = "0.4" [dependencies.glutin] version = "0.28" diff --git a/glutin/src/application.rs b/glutin/src/application.rs index 27a932fc..dbc9b580 100644 --- a/glutin/src/application.rs +++ b/glutin/src/application.rs @@ -61,6 +61,8 @@ where settings.id, ); + log::info!("Window builder: {:#?}", builder); + let opengl_builder = ContextBuilder::new() .with_vsync(true) .with_multisampling(C::sample_count(&compositor_settings) as u16); @@ -75,17 +77,35 @@ where (opengl_builder, opengles_builder) }; + log::info!("Trying first builder: {:#?}", first_builder); + let context = first_builder .build_windowed(builder.clone(), &event_loop) - .or_else(|_| second_builder.build_windowed(builder, &event_loop)) + .or_else(|_| { + log::info!("Trying second builder: {:#?}", second_builder); + second_builder.build_windowed(builder, &event_loop) + }) .map_err(|error| { use glutin::CreationError; + use iced_graphics::Error as ContextError; match error { CreationError::Window(error) => { Error::WindowCreationFailed(error) } - _ => Error::GraphicsAdapterNotFound, + CreationError::OpenGlVersionNotSupported => { + Error::GraphicsCreationFailed( + ContextError::VersionNotSupported, + ) + } + CreationError::NoAvailablePixelFormat => { + Error::GraphicsCreationFailed( + ContextError::NoAvailablePixelFormat, + ) + } + error => Error::GraphicsCreationFailed( + ContextError::BackendError(error.to_string()), + ), } })?; @@ -110,6 +130,7 @@ where &mut clipboard, &mut proxy, context.window(), + || compositor.fetch_information(), ); runtime.track(subscription); @@ -244,6 +265,7 @@ async fn run_instance<A, E, C>( &mut debug, &mut messages, context.window(), + || compositor.fetch_information(), ); // Update window diff --git a/glutin/src/lib.rs b/glutin/src/lib.rs index 72397791..146dfc4d 100644 --- a/glutin/src/lib.rs +++ b/glutin/src/lib.rs @@ -14,20 +14,11 @@ #![forbid(rust_2018_idioms)] pub use glutin; + #[doc(no_inline)] -pub use iced_native::*; +pub use iced_winit::*; pub mod application; -pub use iced_winit::clipboard; -pub use iced_winit::conversion; -pub use iced_winit::settings; -pub use iced_winit::window; -pub use iced_winit::{Error, Mode}; - #[doc(no_inline)] pub use application::Application; -#[doc(no_inline)] -pub use clipboard::Clipboard; -#[doc(no_inline)] -pub use settings::Settings; diff --git a/graphics/src/error.rs b/graphics/src/error.rs index c86e326a..77758f54 100644 --- a/graphics/src/error.rs +++ b/graphics/src/error.rs @@ -1,7 +1,19 @@ -/// A graphical error that occurred while running an application. +/// An error that occurred while creating an application's graphical context. #[derive(Debug, thiserror::Error)] pub enum Error { - /// A suitable graphics adapter or device could not be found + /// The requested backend version is not supported. + #[error("the requested backend version is not supported")] + VersionNotSupported, + + /// Failed to find any pixel format that matches the criteria. + #[error("failed to find any pixel format that matches the criteria")] + NoAvailablePixelFormat, + + /// A suitable graphics adapter or device could not be found. #[error("a suitable graphics adapter or device could not be found")] - AdapterNotFound, + GraphicsAdapterNotFound, + + /// An error occured in the context's internal backend + #[error("an error occured in the context's internal backend")] + BackendError(String), } diff --git a/graphics/src/lib.rs b/graphics/src/lib.rs index 9661f6ef..370f70d6 100644 --- a/graphics/src/lib.rs +++ b/graphics/src/lib.rs @@ -39,6 +39,7 @@ pub use primitive::Primitive; pub use renderer::Renderer; pub use transformation::Transformation; pub use viewport::Viewport; +pub use window::compositor; pub use iced_native::alignment; pub use iced_native::{ diff --git a/graphics/src/window.rs b/graphics/src/window.rs index 67ec3322..a38b81f3 100644 --- a/graphics/src/window.rs +++ b/graphics/src/window.rs @@ -1,10 +1,10 @@ //! Draw graphics to window surfaces. -mod compositor; +pub mod compositor; #[cfg(feature = "opengl")] -mod gl_compositor; +pub mod gl_compositor; -pub use compositor::{Compositor, SurfaceError}; +pub use compositor::Compositor; #[cfg(feature = "opengl")] pub use gl_compositor::GLCompositor; diff --git a/graphics/src/window/compositor.rs b/graphics/src/window/compositor.rs index 04a87bc6..0c4cadcd 100644 --- a/graphics/src/window/compositor.rs +++ b/graphics/src/window/compositor.rs @@ -1,3 +1,5 @@ +//! A compositor is responsible for initializing a renderer and managing window +//! surfaces. use crate::{Color, Error, Viewport}; use raw_window_handle::HasRawWindowHandle; @@ -38,6 +40,9 @@ pub trait Compositor: Sized { height: u32, ); + /// Returns [`GraphicsInformation`] used by this [`Compositor`]. + fn fetch_information(&self) -> Information; + /// Presents the [`Renderer`] primitives to the next frame of the given [`Surface`]. /// /// [`Renderer`]: Self::Renderer @@ -72,3 +77,12 @@ pub enum SurfaceError { #[error("There is no more memory left to allocate a new frame")] OutOfMemory, } + +/// Contains informations about the graphics (e.g. graphics adapter, graphics backend). +#[derive(Debug)] +pub struct Information { + /// Contains the graphics adapter. + pub adapter: String, + /// Contains the graphics backend. + pub backend: String, +} diff --git a/graphics/src/window/gl_compositor.rs b/graphics/src/window/gl_compositor.rs index b1b995f1..4ff17366 100644 --- a/graphics/src/window/gl_compositor.rs +++ b/graphics/src/window/gl_compositor.rs @@ -1,3 +1,6 @@ +//! A compositor is responsible for initializing a renderer and managing window +//! surfaces. +use crate::compositor::Information; use crate::{Color, Error, Size, Viewport}; use core::ffi::c_void; @@ -48,6 +51,9 @@ pub trait GLCompositor: Sized { /// Resizes the viewport of the [`GLCompositor`]. fn resize_viewport(&mut self, physical_size: Size<u32>); + /// Returns [`GraphicsInformation`] used by this [`Compositor`]. + fn fetch_information(&self) -> Information; + /// Presents the primitives of the [`Renderer`] to the next frame of the /// [`GLCompositor`]. /// diff --git a/native/src/command/action.rs b/native/src/command/action.rs index cd4309ed..1bb03cef 100644 --- a/native/src/command/action.rs +++ b/native/src/command/action.rs @@ -1,4 +1,5 @@ use crate::clipboard; +use crate::system; use crate::window; use iced_futures::MaybeSend; @@ -19,6 +20,9 @@ pub enum Action<T> { /// Run a window action. Window(window::Action), + + /// Run a system action. + System(system::Action<T>), } impl<T> Action<T> { @@ -38,6 +42,7 @@ impl<T> Action<T> { Self::Future(future) => Action::Future(Box::pin(future.map(f))), Self::Clipboard(action) => Action::Clipboard(action.map(f)), Self::Window(window) => Action::Window(window), + Self::System(system) => Action::System(system.map(f)), } } } @@ -50,6 +55,7 @@ impl<T> fmt::Debug for Action<T> { write!(f, "Action::Clipboard({:?})", action) } Self::Window(action) => write!(f, "Action::Window({:?})", action), + Self::System(action) => write!(f, "Action::System({:?})", action), } } } diff --git a/native/src/lib.rs b/native/src/lib.rs index a37535a7..db60976f 100644 --- a/native/src/lib.rs +++ b/native/src/lib.rs @@ -48,6 +48,7 @@ pub mod program; pub mod renderer; pub mod subscription; pub mod svg; +pub mod system; pub mod text; pub mod touch; pub mod user_interface; diff --git a/native/src/system.rs b/native/src/system.rs new file mode 100644 index 00000000..61c8ff29 --- /dev/null +++ b/native/src/system.rs @@ -0,0 +1,6 @@ +//! Access the native system. +mod action; +mod information; + +pub use action::Action; +pub use information::Information; diff --git a/native/src/system/action.rs b/native/src/system/action.rs new file mode 100644 index 00000000..dea9536f --- /dev/null +++ b/native/src/system/action.rs @@ -0,0 +1,39 @@ +use crate::system; + +use iced_futures::MaybeSend; +use std::fmt; + +/// An operation to be performed on the system. +pub enum Action<T> { + /// Query system information and produce `T` with the result. + QueryInformation(Box<dyn Closure<T>>), +} + +pub trait Closure<T>: Fn(system::Information) -> T + MaybeSend {} + +impl<T, O> Closure<O> for T where T: Fn(system::Information) -> O + MaybeSend {} + +impl<T> Action<T> { + /// Maps the output of a system [`Action`] using the provided closure. + pub fn map<A>( + self, + f: impl Fn(T) -> A + 'static + MaybeSend + Sync, + ) -> Action<A> + where + T: 'static, + { + match self { + Self::QueryInformation(o) => { + Action::QueryInformation(Box::new(move |s| f(o(s)))) + } + } + } +} + +impl<T> fmt::Debug for Action<T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::QueryInformation(_) => write!(f, "Action::QueryInformation"), + } + } +} diff --git a/native/src/system/information.rs b/native/src/system/information.rs new file mode 100644 index 00000000..fa4a835b --- /dev/null +++ b/native/src/system/information.rs @@ -0,0 +1,22 @@ +/// Contains informations about the system (e.g. system name, processor, memory, graphics adapter). +#[derive(Clone, Debug)] +pub struct Information { + /// Contains the system name. + pub system_name: Option<String>, + /// Contains the kernel version. + pub system_kernel: Option<String>, + /// Contains the systme version. + pub system_version: Option<String>, + /// Contains the processor brand. + pub cpu_brand: String, + /// Contains the number of physical cores on the processor. + pub cpu_cores: Option<usize>, + /// Contains the total RAM size in KB. + pub memory_total: u64, + /// Contains the system used RAM size in KB. + pub memory_used: Option<u64>, + /// Contains the graphics backend. + pub graphics_backend: String, + /// Contains the graphics adapter. + pub graphics_adapter: String, +} diff --git a/src/error.rs b/src/error.rs index 17479c60..0bfa3ff1 100644 --- a/src/error.rs +++ b/src/error.rs @@ -11,9 +11,9 @@ pub enum Error { #[error("the application window could not be created")] WindowCreationFailed(Box<dyn std::error::Error + Send + Sync>), - /// A suitable graphics adapter or device could not be found. - #[error("a suitable graphics adapter or device could not be found")] - GraphicsAdapterNotFound, + /// The application graphics context could not be created. + #[error("the application graphics context could not be created")] + GraphicsCreationFailed(iced_graphics::Error), } impl From<iced_winit::Error> for Error { @@ -25,8 +25,8 @@ impl From<iced_winit::Error> for Error { iced_winit::Error::WindowCreationFailed(error) => { Error::WindowCreationFailed(Box::new(error)) } - iced_winit::Error::GraphicsAdapterNotFound => { - Error::GraphicsAdapterNotFound + iced_winit::Error::GraphicsCreationFailed(error) => { + Error::GraphicsCreationFailed(error) } } } @@ -229,3 +229,6 @@ pub use runtime::{ Alignment, Background, Color, Command, ContentFit, Font, Length, Padding, Point, Rectangle, Size, Subscription, Vector, }; + +#[cfg(feature = "system")] +pub use runtime::system; diff --git a/wgpu/src/window/compositor.rs b/wgpu/src/window/compositor.rs index 64c53607..54ea8247 100644 --- a/wgpu/src/window/compositor.rs +++ b/wgpu/src/window/compositor.rs @@ -1,6 +1,7 @@ use crate::{Backend, Color, Error, Renderer, Settings, Viewport}; use futures::task::SpawnExt; +use iced_graphics::compositor; use iced_native::futures; use raw_window_handle::HasRawWindowHandle; @@ -9,6 +10,7 @@ use raw_window_handle::HasRawWindowHandle; pub struct Compositor { settings: Settings, instance: wgpu::Instance, + adapter: wgpu::Adapter, device: wgpu::Device, queue: wgpu::Queue, staging_belt: wgpu::util::StagingBelt, @@ -28,6 +30,17 @@ impl Compositor { ) -> Option<Self> { let instance = wgpu::Instance::new(settings.internal_backend); + log::info!("{:#?}", settings); + + #[cfg(not(target_arch = "wasm32"))] + if log::max_level() >= log::LevelFilter::Info { + let available_adapters: Vec<_> = instance + .enumerate_adapters(settings.internal_backend) + .map(|adapter| adapter.get_info()) + .collect(); + log::info!("Available adapters: {:#?}", available_adapters); + } + #[allow(unsafe_code)] let compatible_surface = compatible_window .map(|window| unsafe { instance.create_surface(window) }); @@ -44,10 +57,14 @@ impl Compositor { }) .await?; + log::info!("Selected: {:#?}", adapter.get_info()); + let format = compatible_surface .as_ref() .and_then(|surface| surface.get_preferred_format(&adapter))?; + log::info!("Selected format: {:?}", format); + #[cfg(target_arch = "wasm32")] let limits = wgpu::Limits::downlevel_webgl2_defaults() .using_resolution(adapter.limits()); @@ -78,6 +95,7 @@ impl Compositor { Some(Compositor { instance, settings, + adapter, device, queue, staging_belt, @@ -105,7 +123,7 @@ impl iced_graphics::window::Compositor for Compositor { settings, compatible_window, )) - .ok_or(Error::AdapterNotFound)?; + .ok_or(Error::GraphicsAdapterNotFound)?; let backend = compositor.create_backend(); @@ -140,6 +158,15 @@ impl iced_graphics::window::Compositor for Compositor { ); } + fn fetch_information(&self) -> compositor::Information { + let information = self.adapter.get_info(); + + compositor::Information { + adapter: information.name, + backend: format!("{:?}", information.backend), + } + } + fn present<T: AsRef<str>>( &mut self, renderer: &mut Self::Renderer, @@ -147,7 +174,7 @@ impl iced_graphics::window::Compositor for Compositor { viewport: &Viewport, background_color: Color, overlay: &[T], - ) -> Result<(), iced_graphics::window::SurfaceError> { + ) -> Result<(), compositor::SurfaceError> { match surface.get_current_texture() { Ok(frame) => { let mut encoder = self.device.create_command_encoder( @@ -215,16 +242,14 @@ impl iced_graphics::window::Compositor for Compositor { } Err(error) => match error { wgpu::SurfaceError::Timeout => { - Err(iced_graphics::window::SurfaceError::Timeout) + Err(compositor::SurfaceError::Timeout) } wgpu::SurfaceError::Outdated => { - Err(iced_graphics::window::SurfaceError::Outdated) - } - wgpu::SurfaceError::Lost => { - Err(iced_graphics::window::SurfaceError::Lost) + Err(compositor::SurfaceError::Outdated) } + wgpu::SurfaceError::Lost => Err(compositor::SurfaceError::Lost), wgpu::SurfaceError::OutOfMemory => { - Err(iced_graphics::window::SurfaceError::OutOfMemory) + Err(compositor::SurfaceError::OutOfMemory) } }, } diff --git a/winit/Cargo.toml b/winit/Cargo.toml index 2beebdfb..3b9ae859 100644 --- a/winit/Cargo.toml +++ b/winit/Cargo.toml @@ -12,6 +12,7 @@ categories = ["gui"] [features] debug = ["iced_native/debug"] +system = ["sysinfo"] [dependencies] window_clipboard = "0.2" @@ -41,3 +42,7 @@ version = "0.3.6" [target.'cfg(target_arch = "wasm32")'.dependencies.web-sys] version = "0.3" features = ["Document", "Window"] + +[dependencies.sysinfo] +version = "0.23" +optional = true diff --git a/winit/src/application.rs b/winit/src/application.rs index ed077507..90b03d56 100644 --- a/winit/src/application.rs +++ b/winit/src/application.rs @@ -13,6 +13,7 @@ use crate::{ use iced_futures::futures; use iced_futures::futures::channel::mpsc; +use iced_graphics::compositor; use iced_graphics::window; use iced_native::program::Program; use iced_native::user_interface::{self, UserInterface}; @@ -137,14 +138,16 @@ where let subscription = application.subscription(); - let window = settings - .window - .into_builder( - &application.title(), - application.mode(), - event_loop.primary_monitor(), - settings.id, - ) + let builder = settings.window.into_builder( + &application.title(), + application.mode(), + event_loop.primary_monitor(), + settings.id, + ); + + log::info!("Window builder: {:#?}", builder); + + let window = builder .build(&event_loop) .map_err(Error::WindowCreationFailed)?; @@ -165,17 +168,18 @@ where let mut clipboard = Clipboard::connect(&window); + let (compositor, renderer) = C::new(compositor_settings, Some(&window))?; + run_command( init_command, &mut runtime, &mut clipboard, &mut proxy, &window, + || compositor.fetch_information(), ); runtime.track(subscription); - let (compositor, renderer) = C::new(compositor_settings, Some(&window))?; - let (mut sender, receiver) = mpsc::unbounded(); let mut instance = Box::pin(run_instance::<A, E, C>( @@ -315,6 +319,7 @@ async fn run_instance<A, E, C>( &mut debug, &mut messages, &window, + || compositor.fetch_information(), ); // Update window @@ -420,7 +425,7 @@ async fn run_instance<A, E, C>( } Err(error) => match error { // This is an unrecoverable error. - window::SurfaceError::OutOfMemory => { + compositor::SurfaceError::OutOfMemory => { panic!("{:?}", error); } _ => { @@ -514,6 +519,7 @@ pub fn update<A: Application, E: Executor>( debug: &mut Debug, messages: &mut Vec<A::Message>, window: &winit::window::Window, + graphics_info: impl FnOnce() -> compositor::Information + Copy, ) { for message in messages.drain(..) { debug.log_message(&message); @@ -522,7 +528,7 @@ pub fn update<A: Application, E: Executor>( let command = runtime.enter(|| application.update(message)); debug.update_finished(); - run_command(command, runtime, clipboard, proxy, window); + run_command(command, runtime, clipboard, proxy, window, graphics_info); } let subscription = application.subscription(); @@ -536,8 +542,10 @@ pub fn run_command<Message: 'static + std::fmt::Debug + Send, E: Executor>( clipboard: &mut Clipboard, proxy: &mut winit::event_loop::EventLoopProxy<Message>, window: &winit::window::Window, + _graphics_info: impl FnOnce() -> compositor::Information + Copy, ) { use iced_native::command; + use iced_native::system; use iced_native::window; for action in command.actions() { @@ -571,6 +579,26 @@ pub fn run_command<Message: 'static + std::fmt::Debug + Send, E: Executor>( }); } }, + command::Action::System(action) => match action { + system::Action::QueryInformation(_tag) => { + #[cfg(feature = "system")] + { + let graphics_info = _graphics_info(); + let proxy = proxy.clone(); + + let _ = std::thread::spawn(move || { + let information = + crate::system::information(graphics_info); + + let message = _tag(information); + + proxy + .send_event(message) + .expect("Send message to event loop") + }); + } + } + }, } } } diff --git a/winit/src/error.rs b/winit/src/error.rs index 8e1d20e8..eaeafd51 100644 --- a/winit/src/error.rs +++ b/winit/src/error.rs @@ -11,17 +11,13 @@ pub enum Error { #[error("the application window could not be created")] WindowCreationFailed(winit::error::OsError), - /// A suitable graphics adapter or device could not be found. - #[error("a suitable graphics adapter or device could not be found")] - GraphicsAdapterNotFound, + /// The application graphics context could not be created. + #[error("the application graphics context could not be created")] + GraphicsCreationFailed(iced_graphics::Error), } impl From<iced_graphics::Error> for Error { fn from(error: iced_graphics::Error) -> Error { - match error { - iced_graphics::Error::AdapterNotFound => { - Error::GraphicsAdapterNotFound - } - } + Error::GraphicsCreationFailed(error) } } diff --git a/winit/src/lib.rs b/winit/src/lib.rs index 2bb30caa..22e7efdf 100644 --- a/winit/src/lib.rs +++ b/winit/src/lib.rs @@ -33,6 +33,9 @@ pub mod conversion; pub mod settings; pub mod window; +#[cfg(feature = "system")] +pub mod system; + mod error; mod mode; mod position; diff --git a/winit/src/system.rs b/winit/src/system.rs new file mode 100644 index 00000000..0ed61dc9 --- /dev/null +++ b/winit/src/system.rs @@ -0,0 +1,41 @@ +//! Access the native system. +use crate::command::{self, Command}; +pub use iced_native::system::*; + +use iced_graphics::compositor; + +/// Query for available system information. +pub fn fetch_information<Message>( + f: impl Fn(Information) -> Message + Send + 'static, +) -> Command<Message> { + Command::single(command::Action::System(Action::QueryInformation( + Box::new(f), + ))) +} + +pub(crate) fn information( + graphics_info: compositor::Information, +) -> Information { + use sysinfo::{ProcessExt, ProcessorExt, System, SystemExt}; + let mut system = System::new_all(); + system.refresh_all(); + + let cpu = system.global_processor_info(); + + let memory_used = sysinfo::get_current_pid() + .and_then(|pid| system.process(pid).ok_or("Process not found")) + .and_then(|process| Ok(process.memory())) + .ok(); + + Information { + system_name: system.name(), + system_kernel: system.kernel_version(), + system_version: system.long_os_version(), + cpu_brand: cpu.brand().into(), + cpu_cores: system.physical_core_count(), + memory_total: system.total_memory(), + memory_used, + graphics_adapter: graphics_info.adapter, + graphics_backend: graphics_info.backend, + } +} |