Merge pull request #1314 from derezzedex/dev/system-information

feat: fetch system information
This commit is contained in:
Héctor Ramón 2022-05-11 18:08:36 +02:00 committed by GitHub
commit 2e7757a428
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
26 changed files with 482 additions and 56 deletions

View file

@ -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]

View 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" }

View 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()
}
}

View file

@ -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.
///

View file

@ -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,

View file

@ -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"

View file

@ -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

View file

@ -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;

View file

@ -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),
}

View file

@ -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::{

View file

@ -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;

View file

@ -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,
}

View file

@ -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`].
///

View file

@ -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),
}
}
}

View file

@ -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
View file

@ -0,0 +1,6 @@
//! Access the native system.
mod action;
mod information;
pub use action::Action;
pub use information::Information;

View 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"),
}
}
}

View 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,
}

View file

@ -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)
}
}
}

View file

@ -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;

View file

@ -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)
}
},
}

View file

@ -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

View file

@ -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")
});
}
}
},
}
}
}

View file

@ -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)
}
}

View file

@ -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
View 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,
}
}