kael 0.2.0

GPU-accelerated native UI framework for Rust — build desktop apps with Metal, DirectX, and Vulkan rendering
Documentation
use core_foundation::base::TCFType;
use core_foundation::base::{CFRelease, CFTypeRef};
use core_foundation::string::CFString;
use core_foundation::string::CFStringRef;
use objc2_foundation::NSProcessInfo;
use std::ffi::c_void;

#[link(name = "IOKit", kind = "framework")]
unsafe extern "C" {
    fn IOPMAssertionCreateWithName(
        assertion_type: *const c_void,
        assertion_level: u32,
        reason_for_activity: *const c_void,
        assertion_id: *mut u32,
    ) -> i32;
    fn IOPMAssertionRelease(assertion_id: u32) -> i32;
    fn IOPSCopyPowerSourcesInfo() -> CFTypeRef;
    fn IOPSGetProvidingPowerSourceType(blob: CFTypeRef) -> CFStringRef;
}

const IOPM_ASSERTION_LEVEL_ON: u32 = 255;

pub(crate) fn power_mode() -> crate::PowerMode {
    if low_power_mode_enabled() {
        crate::PowerMode::LowPower
    } else if on_battery_power() {
        crate::PowerMode::Balanced
    } else {
        crate::PowerMode::Performance
    }
}

pub fn start_power_save_blocker(kind: crate::PowerSaveBlockerKind) -> Option<u32> {
    unsafe {
        let assertion_type = match kind {
            crate::PowerSaveBlockerKind::PreventAppSuspension => {
                CFString::new("PreventUserIdleSystemSleep")
            }
            crate::PowerSaveBlockerKind::PreventDisplaySleep => {
                CFString::new("PreventUserIdleDisplaySleep")
            }
        };
        let reason = CFString::new("Application requested power save blocker");
        let mut assertion_id: u32 = 0;

        let result = IOPMAssertionCreateWithName(
            assertion_type.as_concrete_TypeRef() as *const c_void,
            IOPM_ASSERTION_LEVEL_ON,
            reason.as_concrete_TypeRef() as *const c_void,
            &mut assertion_id,
        );

        if result == 0 {
            Some(assertion_id)
        } else {
            None
        }
    }
}

pub fn stop_power_save_blocker(id: u32) {
    unsafe {
        IOPMAssertionRelease(id);
    }
}

fn low_power_mode_enabled() -> bool {
    NSProcessInfo::processInfo().isLowPowerModeEnabled()
}

fn on_battery_power() -> bool {
    unsafe {
        let power_sources = IOPSCopyPowerSourcesInfo();
        if power_sources.is_null() {
            return false;
        }

        let source_type = IOPSGetProvidingPowerSourceType(power_sources);
        let is_battery = if source_type.is_null() {
            false
        } else {
            let source_type: CFString = TCFType::wrap_under_get_rule(source_type);
            source_type == CFString::new("Battery Power")
        };

        CFRelease(power_sources);
        is_battery
    }
}

pub fn system_idle_time() -> Option<std::time::Duration> {
    unsafe {
        let seconds = CGEventSourceSecondsSinceLastEventType(0, u32::MAX);
        if seconds >= 0.0 {
            Some(std::time::Duration::from_secs_f64(seconds))
        } else {
            None
        }
    }
}

#[link(name = "ApplicationServices", kind = "framework")]
unsafe extern "C" {
    fn CGEventSourceSecondsSinceLastEventType(source_state: u32, event_type: u32) -> f64;
}