Merge pull request #1314 from derezzedex/dev/system-information
feat: fetch system information
This commit is contained in:
commit
2e7757a428
26 changed files with 482 additions and 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]
|
||||
|
|
|
|||
10
examples/system_information/Cargo.toml
Normal file
10
examples/system_information/Cargo.toml
Normal file
|
|
@ -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" }
|
||||
165
examples/system_information/src/main.rs
Normal file
165
examples/system_information/src/main.rs
Normal file
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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::{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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`].
|
||||
///
|
||||
|
|
|
|||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
6
native/src/system.rs
Normal file
6
native/src/system.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
//! Access the native system.
|
||||
mod action;
|
||||
mod information;
|
||||
|
||||
pub use action::Action;
|
||||
pub use information::Information;
|
||||
39
native/src/system/action.rs
Normal file
39
native/src/system/action.rs
Normal file
|
|
@ -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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
22
native/src/system/information.rs
Normal file
22
native/src/system/information.rs
Normal file
|
|
@ -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,
|
||||
}
|
||||
10
src/error.rs
10
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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
},
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
41
winit/src/system.rs
Normal file
41
winit/src/system.rs
Normal file
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue