nativeshell 0.1.16

NativeShell Rust package
Documentation
use std::{cell::RefCell, rc::Weak};

use windows::Win32::{
    Foundation::HWND,
    Graphics::Gdi::{MonitorFromWindow, MONITOR_DEFAULTTONEAREST},
    UI::WindowsAndMessaging::GetForegroundWindow,
};

use crate::shell::{api_model::Screen, screen_manager::ScreenManagerDelegate, IPoint, Point};

use super::{
    display::Displays,
    error::{PlatformError, PlatformResult},
};

pub struct PlatformScreenManager {}

impl PlatformScreenManager {
    pub fn new(delegate: Weak<RefCell<dyn ScreenManagerDelegate>>) -> Self {
        Displays::on_displays_changed(move || {
            if let Some(delegate) = delegate.upgrade() {
                delegate.borrow().screen_configuration_changed();
            }
        });
        Self {}
    }

    pub fn get_screens(&self) -> PlatformResult<Vec<Screen>> {
        let displays = Displays::get_displays();
        Ok(displays
            .displays
            .iter()
            .map(|d| Screen {
                id: d.id,
                frame: d.logical.clone(),
                work_area: d.work.clone(),
                scaling_factor: d.scale,
            })
            .collect())
    }

    pub fn get_main_screen(&self) -> PlatformResult<i64> {
        let window = unsafe { GetForegroundWindow() };
        if window.0 == 0 {
            return Ok(0);
        }
        Self::screen_id_from_hwnd(window)
    }

    pub fn screen_id_from_hwnd(window: HWND) -> PlatformResult<i64> {
        let monitor = unsafe { MonitorFromWindow(window, MONITOR_DEFAULTTONEAREST) };
        let displays = Displays::get_displays();
        let res = displays
            .displays
            .iter()
            .find(|d| d.handle == monitor)
            .map(|d| d.id);
        Ok(res.unwrap_or(0))
    }

    pub fn logical_to_system(&self, offset: Point) -> PlatformResult<Point> {
        let displays = Displays::get_displays();
        let res = displays.convert_logical_to_physical(&offset);
        res.map_or_else(
            || Err(PlatformError::OffsetOutOfScreenBounds),
            |f| Ok(f.into()),
        )
    }

    pub fn system_to_logical(&self, offset: Point) -> PlatformResult<Point> {
        let displays = Displays::get_displays();
        let res = displays.convert_physical_to_logical(&IPoint::from(offset));
        res.map_or_else(|| Err(PlatformError::OffsetOutOfScreenBounds), Ok)
    }
}