mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
refactor: Address review feedback
- Remove deprecated supergfx integration - Ensure DBus is used instead of direct calls (verified) - Clean up unused imports and modules
This commit is contained in:
@@ -1,200 +0,0 @@
|
||||
//! Software-based keyboard animation for keyboards that only support Static mode.
|
||||
//! Provides Rainbow and Color Cycle animations via timer-based color updates.
|
||||
|
||||
use log::{info, warn};
|
||||
use slint::Weak;
|
||||
use std::process::Command;
|
||||
use std::sync::atomic::{AtomicBool, AtomicU32, Ordering};
|
||||
use std::sync::Arc;
|
||||
use std::time::Duration;
|
||||
|
||||
use crate::MainWindow;
|
||||
|
||||
/// Animation mode enum matching the UI
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||
pub enum AnimationMode {
|
||||
#[default]
|
||||
None,
|
||||
Rainbow,
|
||||
ColorCycle,
|
||||
}
|
||||
|
||||
impl From<i32> for AnimationMode {
|
||||
fn from(v: i32) -> Self {
|
||||
match v {
|
||||
1 => AnimationMode::Rainbow,
|
||||
2 => AnimationMode::ColorCycle,
|
||||
_ => AnimationMode::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Shared state for the animator
|
||||
pub struct AnimatorState {
|
||||
/// Current animation mode
|
||||
pub mode: AtomicU32,
|
||||
/// Animation speed in milliseconds (update interval)
|
||||
pub speed_ms: AtomicU32,
|
||||
/// Stop signal
|
||||
pub stop: AtomicBool,
|
||||
/// Current hue for rainbow mode (0-360)
|
||||
hue: AtomicU32,
|
||||
}
|
||||
|
||||
impl Default for AnimatorState {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mode: AtomicU32::new(0),
|
||||
speed_ms: AtomicU32::new(200),
|
||||
stop: AtomicBool::new(false),
|
||||
hue: AtomicU32::new(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert HSV to RGB (H: 0-360, S: 0-100, V: 0-100)
|
||||
fn hsv_to_rgb(h: u32, s: u32, v: u32) -> (u8, u8, u8) {
|
||||
let s = s as f32 / 100.0;
|
||||
let v = v as f32 / 100.0;
|
||||
let c = v * s;
|
||||
let h_prime = (h as f32 / 60.0) % 6.0;
|
||||
let x = c * (1.0 - ((h_prime % 2.0) - 1.0).abs());
|
||||
let m = v - c;
|
||||
|
||||
let (r, g, b) = match h_prime as u32 {
|
||||
0 => (c, x, 0.0),
|
||||
1 => (x, c, 0.0),
|
||||
2 => (0.0, c, x),
|
||||
3 => (0.0, x, c),
|
||||
4 => (x, 0.0, c),
|
||||
_ => (c, 0.0, x),
|
||||
};
|
||||
|
||||
(
|
||||
((r + m) * 255.0) as u8,
|
||||
((g + m) * 255.0) as u8,
|
||||
((b + m) * 255.0) as u8,
|
||||
)
|
||||
}
|
||||
|
||||
/// Format RGB as hex color string for asusctl
|
||||
fn rgb_to_hex(r: u8, g: u8, b: u8) -> String {
|
||||
format!("{:02x}{:02x}{:02x}", r, g, b)
|
||||
}
|
||||
|
||||
// Simple LCG for random numbers to avoid pulling in rand crate
|
||||
fn next_random(seed: &mut u64) -> u32 {
|
||||
*seed = seed.wrapping_mul(6364136223846793005).wrapping_add(1);
|
||||
(*seed >> 32) as u32
|
||||
}
|
||||
|
||||
/// Start the animation loop (runs in tokio task)
|
||||
pub fn start_animator(state: Arc<AnimatorState>, _ui_weak: Weak<MainWindow>) {
|
||||
info!("Starting keyboard animator");
|
||||
|
||||
tokio::spawn(async move {
|
||||
// Local state for Color Cycle (RGB)
|
||||
let mut current_r: f32 = 255.0;
|
||||
let mut current_g: f32 = 0.0;
|
||||
let mut current_b: f32 = 0.0;
|
||||
let mut target_r: f32 = 0.0;
|
||||
let mut target_g: f32 = 255.0;
|
||||
let mut target_b: f32 = 0.0;
|
||||
let mut seed = std::time::SystemTime::now()
|
||||
.duration_since(std::time::UNIX_EPOCH)
|
||||
.map(|d| d.as_nanos() as u64)
|
||||
.unwrap_or(12345);
|
||||
|
||||
loop {
|
||||
// Check for stop signal
|
||||
if state.stop.load(Ordering::Relaxed) {
|
||||
info!("Animator stopping");
|
||||
break;
|
||||
}
|
||||
|
||||
let mode = AnimationMode::from(state.mode.load(Ordering::Relaxed) as i32);
|
||||
// Cap speed at 150ms for stability
|
||||
let raw_speed = state.speed_ms.load(Ordering::Relaxed);
|
||||
let effective_speed = raw_speed.max(150) as u64;
|
||||
|
||||
if mode == AnimationMode::None {
|
||||
// No animation, sleep longer
|
||||
tokio::time::sleep(Duration::from_millis(500)).await;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Calculate next color
|
||||
let hex_color = match mode {
|
||||
AnimationMode::Rainbow => {
|
||||
// Hue step 1 for smooth, granular transitions
|
||||
let hue = state.hue.fetch_add(1, Ordering::Relaxed) % 360;
|
||||
let (r, g, b) = hsv_to_rgb(hue, 100, 100);
|
||||
rgb_to_hex(r, g, b)
|
||||
}
|
||||
AnimationMode::ColorCycle => {
|
||||
// RGB Linear Interpolation (Fading) - NOT Rainbow
|
||||
|
||||
// 1. Check distance to target
|
||||
let dist_sq = (target_r - current_r).powi(2)
|
||||
+ (target_g - current_g).powi(2)
|
||||
+ (target_b - current_b).powi(2);
|
||||
|
||||
// If close, pick new random target color
|
||||
if dist_sq < 100.0 {
|
||||
let next_h = next_random(&mut seed) % 360;
|
||||
let (r, g, b) = hsv_to_rgb(next_h, 100, 100);
|
||||
target_r = r as f32;
|
||||
target_g = g as f32;
|
||||
target_b = b as f32;
|
||||
}
|
||||
|
||||
// 2. Lerp towards target (5% per frame for smooth ease-out)
|
||||
let factor = 0.05;
|
||||
current_r += (target_r - current_r) * factor;
|
||||
current_g += (target_g - current_g) * factor;
|
||||
current_b += (target_b - current_b) * factor;
|
||||
|
||||
rgb_to_hex(current_r as u8, current_g as u8, current_b as u8)
|
||||
}
|
||||
AnimationMode::None => continue,
|
||||
};
|
||||
|
||||
// Send color update via asusctl command (blocking, AWAITED to prevent races)
|
||||
let hex = hex_color.clone();
|
||||
let _ = tokio::task::spawn_blocking(move || {
|
||||
let result = Command::new("asusctl")
|
||||
.args([
|
||||
"aura", "static", "-c", &hex,
|
||||
])
|
||||
.output();
|
||||
|
||||
if let Err(e) = result {
|
||||
warn!("Failed to set aura color: {}", e);
|
||||
}
|
||||
})
|
||||
.await;
|
||||
|
||||
// Sleep for the animation speed interval
|
||||
tokio::time::sleep(Duration::from_millis(effective_speed)).await;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/// Stop the animator
|
||||
pub fn stop_animator(state: &Arc<AnimatorState>) {
|
||||
state.stop.store(true, Ordering::Relaxed);
|
||||
state.mode.store(0, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Set animation mode
|
||||
pub fn set_animation_mode(state: &Arc<AnimatorState>, mode: AnimationMode) {
|
||||
state.mode.store(mode as u32, Ordering::Relaxed);
|
||||
// Reset stop flag in case we're restarting
|
||||
state.stop.store(false, Ordering::Relaxed);
|
||||
}
|
||||
|
||||
/// Set animation speed
|
||||
pub fn set_animation_speed(state: &Arc<AnimatorState>, speed_ms: u32) {
|
||||
let clamped = speed_ms.clamp(50, 2000);
|
||||
state.speed_ms.store(clamped, Ordering::Relaxed);
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
pub mod aura_animator;
|
||||
pub mod setup_anime;
|
||||
pub mod setup_aura;
|
||||
pub mod setup_fan_curve_custom;
|
||||
@@ -6,7 +5,6 @@ pub mod setup_fans;
|
||||
pub mod setup_screenpad;
|
||||
pub mod setup_slash;
|
||||
pub mod setup_status;
|
||||
pub mod setup_supergfx;
|
||||
pub mod setup_system;
|
||||
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -24,7 +22,6 @@ use crate::ui::setup_fans::setup_fan_curve_page;
|
||||
use crate::ui::setup_screenpad::setup_screenpad;
|
||||
use crate::ui::setup_slash::setup_slash;
|
||||
use crate::ui::setup_status::setup_status;
|
||||
use crate::ui::setup_supergfx::setup_supergfx;
|
||||
use crate::ui::setup_system::{setup_system_page, setup_system_page_callbacks};
|
||||
use crate::{AppSettingsPageData, MainWindow};
|
||||
|
||||
@@ -116,20 +113,7 @@ pub fn setup_window(
|
||||
available.contains(&"xyz.ljones.Aura".to_string()),
|
||||
available.contains(&"xyz.ljones.Anime".to_string()),
|
||||
available.contains(&"xyz.ljones.Slash".to_string()),
|
||||
// Supergfx check
|
||||
{
|
||||
if let Ok(conn) = zbus::blocking::Connection::system() {
|
||||
zbus::blocking::fdo::DBusProxy::new(&conn)
|
||||
.ok()
|
||||
.and_then(|p| {
|
||||
p.name_has_owner("org.supergfxctl.Daemon".try_into().ok()?)
|
||||
.ok()
|
||||
})
|
||||
.unwrap_or(false)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
},
|
||||
false,
|
||||
// Screenpad check (Backlight interface)
|
||||
available.contains(&"xyz.ljones.Backlight".to_string()),
|
||||
available.contains(&"xyz.ljones.FanCurves".to_string()),
|
||||
@@ -186,9 +170,7 @@ pub fn setup_window(
|
||||
setup_slash(&ui, config.clone());
|
||||
}
|
||||
|
||||
// Always try to setup supergfx if detected above, but for simplicity here we assume if sidebar has it (re-check or just run)
|
||||
// We didn't capture the boolean above. Let's just run it, it handles its own availability check internally via async proxy creation.
|
||||
setup_supergfx(&ui, config.clone());
|
||||
|
||||
if available.contains(&"xyz.ljones.Backlight".to_string()) {
|
||||
setup_screenpad(&ui, config.clone());
|
||||
@@ -237,22 +219,6 @@ pub fn setup_app_settings_page(ui: &MainWindow, config: Arc<Mutex<Config>>) {
|
||||
});
|
||||
|
||||
// Granular notification toggles
|
||||
let config_copy = config.clone();
|
||||
global.on_set_notify_gfx_switch(move |enable| {
|
||||
if let Ok(mut lock) = config_copy.try_lock() {
|
||||
lock.notifications.receive_notify_gfx = enable;
|
||||
lock.write();
|
||||
}
|
||||
});
|
||||
|
||||
let config_copy = config.clone();
|
||||
global.on_set_notify_gfx_status(move |enable| {
|
||||
if let Ok(mut lock) = config_copy.try_lock() {
|
||||
lock.notifications.receive_notify_gfx_status = enable;
|
||||
lock.write();
|
||||
}
|
||||
});
|
||||
|
||||
let config_copy = config.clone();
|
||||
global.on_set_notify_platform_profile(move |enable| {
|
||||
if let Ok(mut lock) = config_copy.try_lock() {
|
||||
@@ -267,8 +233,6 @@ pub fn setup_app_settings_page(ui: &MainWindow, config: Arc<Mutex<Config>>) {
|
||||
global.set_startup_in_background(lock.startup_in_background);
|
||||
global.set_enable_tray_icon(lock.enable_tray_icon);
|
||||
global.set_notifications_enabled(lock.notifications.enabled);
|
||||
global.set_notify_gfx_switch(lock.notifications.receive_notify_gfx);
|
||||
global.set_notify_gfx_status(lock.notifications.receive_notify_gfx_status);
|
||||
global.set_notify_platform_profile(lock.notifications.receive_notify_platform_profile);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,13 @@
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use log::{debug, error, info};
|
||||
use rog_aura::animation::AnimationMode;
|
||||
use rog_aura::keyboard::LaptopAuraPower;
|
||||
use rog_aura::{AuraDeviceType, PowerZones};
|
||||
use rog_aura::{AuraDeviceType, Colour, PowerZones};
|
||||
use rog_dbus::zbus_aura::AuraProxy;
|
||||
use slint::{ComponentHandle, Model, RgbaColor, SharedString};
|
||||
|
||||
use crate::config::Config;
|
||||
use crate::ui::aura_animator::{
|
||||
set_animation_mode, set_animation_speed, start_animator, AnimationMode, AnimatorState,
|
||||
};
|
||||
use crate::ui::show_toast;
|
||||
use crate::{
|
||||
set_ui_callbacks, set_ui_props_async, AuraPageData, MainWindow, PowerZones as SlintPowerZones,
|
||||
@@ -126,17 +124,15 @@ pub fn setup_aura_page(ui: &MainWindow, _states: Arc<Mutex<Config>>) {
|
||||
.ok();
|
||||
}
|
||||
|
||||
// Create animator state (shared across callbacks)
|
||||
let animator_state = Arc::new(AnimatorState::default());
|
||||
|
||||
if let Ok(modes) = aura.supported_basic_modes().await {
|
||||
log::debug!("Available LED modes {modes:?}");
|
||||
|
||||
// Check if only Static mode is available (enable software animation)
|
||||
let static_only = modes.len() == 1 && modes.iter().any(|m| *m == 0.into());
|
||||
|
||||
let handle_for_anim = handle.clone();
|
||||
let animator_state_clone = animator_state.clone();
|
||||
// Clone proxy for callbacks
|
||||
let aura_for_animation = aura.clone();
|
||||
|
||||
handle
|
||||
.upgrade_in_event_loop(move |handle| {
|
||||
let m: Vec<i32> = modes.iter().map(|n| (*n).into()).collect();
|
||||
@@ -163,23 +159,69 @@ pub fn setup_aura_page(ui: &MainWindow, _states: Arc<Mutex<Config>>) {
|
||||
.global::<AuraPageData>()
|
||||
.set_soft_animation_available(true);
|
||||
|
||||
// Start the animator thread
|
||||
start_animator(animator_state_clone.clone(), handle_for_anim.clone());
|
||||
|
||||
// Connect mode callback
|
||||
let state_for_mode = animator_state_clone.clone();
|
||||
// Connect mode callback - uses DBus to start animation in daemon
|
||||
let aura_mode = aura_for_animation.clone();
|
||||
let handle_weak = handle.as_weak();
|
||||
handle
|
||||
.global::<AuraPageData>()
|
||||
.on_cb_soft_animation_mode(move |mode| {
|
||||
set_animation_mode(&state_for_mode, AnimationMode::from(mode));
|
||||
});
|
||||
let aura_inner = aura_mode.clone();
|
||||
let handle = match handle_weak.upgrade() {
|
||||
Some(h) => h,
|
||||
None => return,
|
||||
};
|
||||
|
||||
// Connect speed callback
|
||||
let state_for_speed = animator_state_clone.clone();
|
||||
handle
|
||||
.global::<AuraPageData>()
|
||||
.on_cb_soft_animation_speed(move |speed| {
|
||||
set_animation_speed(&state_for_speed, speed as u32);
|
||||
let data = handle.global::<AuraPageData>().get_led_mode_data();
|
||||
let c1 = data.colour1;
|
||||
let c2 = data.colour2;
|
||||
|
||||
let c1_rog = Colour {
|
||||
r: c1.red(),
|
||||
g: c1.green(),
|
||||
b: c1.blue(),
|
||||
};
|
||||
let c2_rog = Colour {
|
||||
r: c2.red(),
|
||||
g: c2.green(),
|
||||
b: c2.blue(),
|
||||
};
|
||||
|
||||
let anim_mode = match mode {
|
||||
1 => AnimationMode::Rainbow { speed_ms: 100 },
|
||||
2 => AnimationMode::ColorCycle {
|
||||
speed_ms: 200,
|
||||
colors: vec![
|
||||
Colour { r: 255, g: 0, b: 0 },
|
||||
Colour { r: 0, g: 255, b: 0 },
|
||||
Colour { r: 0, g: 0, b: 255 },
|
||||
],
|
||||
},
|
||||
3 => AnimationMode::Breathe {
|
||||
speed_ms: 100,
|
||||
color1: c1_rog,
|
||||
color2: c2_rog,
|
||||
},
|
||||
4 => AnimationMode::Pulse {
|
||||
speed_ms: 50,
|
||||
color: c1_rog,
|
||||
min_brightness: 0.2,
|
||||
max_brightness: 1.0,
|
||||
},
|
||||
_ => AnimationMode::None,
|
||||
};
|
||||
tokio::spawn(async move {
|
||||
let json =
|
||||
serde_json::to_string(&anim_mode).unwrap_or_default();
|
||||
if anim_mode == AnimationMode::None {
|
||||
if let Err(e) = aura_inner.stop_animation().await {
|
||||
error!("Failed to stop animation: {e}");
|
||||
}
|
||||
} else {
|
||||
if let Err(e) = aura_inner.start_animation(json).await {
|
||||
error!("Failed to start animation: {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
})
|
||||
@@ -204,12 +246,79 @@ pub fn setup_aura_page(ui: &MainWindow, _states: Arc<Mutex<Config>>) {
|
||||
"Setting keyboard LEDmode failed"
|
||||
);
|
||||
|
||||
set_ui_callbacks!(handle,
|
||||
AuraPageData(.into()),
|
||||
proxy_copy.led_mode_data(.into()),
|
||||
"Keyboard LED mode set to {:?}",
|
||||
"Setting keyboard LED mode failed"
|
||||
);
|
||||
let proxy_data = proxy_copy.clone();
|
||||
let aura_soft = proxy_copy.clone();
|
||||
let handle_weak = handle.as_weak();
|
||||
|
||||
handle
|
||||
.global::<AuraPageData>()
|
||||
.on_cb_led_mode_data(move |data| {
|
||||
// 1. Update hardware mode
|
||||
let p = proxy_data.clone();
|
||||
let d = data.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Err(e) = p.set_led_mode_data(d.into()).await {
|
||||
error!("Setting keyboard LED mode failed: {e}");
|
||||
} else {
|
||||
debug!("Keyboard LED mode set");
|
||||
}
|
||||
});
|
||||
|
||||
// 2. Update software animation if active
|
||||
let handle = match handle_weak.upgrade() {
|
||||
Some(h) => h,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let soft_mode = handle.global::<AuraPageData>().get_soft_animation_mode();
|
||||
if soft_mode != 0 {
|
||||
let c1 = data.colour1;
|
||||
let c2 = data.colour2;
|
||||
let c1_rog = Colour {
|
||||
r: c1.red(),
|
||||
g: c1.green(),
|
||||
b: c1.blue(),
|
||||
};
|
||||
let c2_rog = Colour {
|
||||
r: c2.red(),
|
||||
g: c2.green(),
|
||||
b: c2.blue(),
|
||||
};
|
||||
|
||||
let anim_mode = match soft_mode {
|
||||
1 => AnimationMode::Rainbow { speed_ms: 100 },
|
||||
2 => AnimationMode::ColorCycle {
|
||||
speed_ms: 200,
|
||||
colors: vec![
|
||||
Colour { r: 255, g: 0, b: 0 },
|
||||
Colour { r: 0, g: 255, b: 0 },
|
||||
Colour { r: 0, g: 0, b: 255 },
|
||||
],
|
||||
},
|
||||
3 => AnimationMode::Breathe {
|
||||
speed_ms: 100,
|
||||
color1: c1_rog,
|
||||
color2: c2_rog,
|
||||
},
|
||||
4 => AnimationMode::Pulse {
|
||||
speed_ms: 50,
|
||||
color: c1_rog,
|
||||
min_brightness: 0.2,
|
||||
max_brightness: 1.0,
|
||||
},
|
||||
_ => AnimationMode::None,
|
||||
};
|
||||
|
||||
let aura_s = aura_soft.clone();
|
||||
tokio::spawn(async move {
|
||||
if let Ok(json) = serde_json::to_string(&anim_mode) {
|
||||
if let Err(e) = aura_s.start_animation(json).await {
|
||||
error!("Failed to update software animation: {e}");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// set_ui_callbacks!(handle,
|
||||
// AuraPageData(.clone().into()),
|
||||
|
||||
@@ -1,102 +0,0 @@
|
||||
use crate::config::Config;
|
||||
use crate::ui::show_toast;
|
||||
use crate::{MainWindow, SupergfxPageData};
|
||||
use slint::{ComponentHandle, Model, SharedString, VecModel};
|
||||
use std::rc::Rc;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use zbus::proxy;
|
||||
|
||||
#[proxy(
|
||||
interface = "org.supergfxctl.Daemon",
|
||||
default_service = "org.supergfxctl.Daemon",
|
||||
default_path = "/org/supergfxctl/Gfx"
|
||||
)]
|
||||
trait Supergfx {
|
||||
fn supported(&self) -> zbus::Result<Vec<String>>;
|
||||
fn mode(&self) -> zbus::Result<String>;
|
||||
fn set_mode(&self, mode: &str) -> zbus::Result<()>;
|
||||
fn vendor(&self) -> zbus::Result<String>;
|
||||
}
|
||||
|
||||
pub fn setup_supergfx(ui: &MainWindow, _config: Arc<Mutex<Config>>) {
|
||||
let ui_weak = ui.as_weak();
|
||||
|
||||
tokio::spawn(async move {
|
||||
let conn = match zbus::Connection::system().await {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
log::warn!("Failed to connect to system bus: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
let proxy = match SupergfxProxy::new(&conn).await {
|
||||
Ok(p) => p,
|
||||
Err(e) => {
|
||||
log::warn!("Failed to create Supergfx proxy: {}", e);
|
||||
return;
|
||||
}
|
||||
};
|
||||
|
||||
// Register Callbacks on UI Thread
|
||||
{
|
||||
let proxy_copy = proxy.clone();
|
||||
let ui_weak_copy = ui_weak.clone();
|
||||
let _ = ui_weak.upgrade_in_event_loop(move |ui| {
|
||||
let handle_copy = ui_weak_copy.clone();
|
||||
ui.global::<SupergfxPageData>()
|
||||
.on_set_mode(move |mode_str| {
|
||||
let proxy = proxy_copy.clone();
|
||||
let handle = handle_copy.clone();
|
||||
tokio::spawn(async move {
|
||||
show_toast(
|
||||
format!("Switching to {}. Logout required.", mode_str).into(),
|
||||
"Failed to set mode".into(),
|
||||
handle,
|
||||
proxy.set_mode(&mode_str).await,
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
// Fetch Initial State
|
||||
// Vendor
|
||||
if let Ok(vendor) = proxy.vendor().await {
|
||||
let _ = ui_weak.upgrade_in_event_loop(move |ui| {
|
||||
ui.global::<SupergfxPageData>().set_vendor(vendor.into())
|
||||
});
|
||||
}
|
||||
|
||||
// Supported Modes
|
||||
if let Ok(supported) = proxy.supported().await {
|
||||
let modes: Vec<SharedString> = supported
|
||||
.iter()
|
||||
.map(|s| SharedString::from(s.as_str()))
|
||||
.collect();
|
||||
let _ = ui_weak.upgrade_in_event_loop(move |ui| {
|
||||
let mode_model = Rc::new(VecModel::from(modes));
|
||||
ui.global::<SupergfxPageData>()
|
||||
.set_supported_modes(mode_model.into())
|
||||
});
|
||||
}
|
||||
|
||||
// Current Mode
|
||||
if let Ok(mode) = proxy.mode().await {
|
||||
let _ = ui_weak.upgrade_in_event_loop(move |ui| {
|
||||
let g = ui.global::<SupergfxPageData>();
|
||||
g.set_current_mode(mode.clone().into());
|
||||
// Update selection index
|
||||
let model = g.get_supported_modes();
|
||||
for (i, m) in model.iter().enumerate() {
|
||||
if m == mode.as_str() {
|
||||
g.set_selected_index(i as i32);
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// No signal monitoring implemented as supergfxctl state changes usually require user action/logout
|
||||
});
|
||||
}
|
||||
Reference in New Issue
Block a user