Switch tray to knsi crate. Many things to do

This commit is contained in:
Luke D. Jones
2024-12-17 22:05:40 +13:00
parent 39b16ffc91
commit ccdc576319
5 changed files with 733 additions and 449 deletions

View File

@@ -4,16 +4,15 @@
use std::fs::OpenOptions;
use std::io::{Read, Write};
use std::path::{Path, PathBuf};
use std::process::exit;
use std::sync::{Arc, Mutex, OnceLock};
use std::thread::sleep;
use std::time::Duration;
use betrayer::{Icon, Menu, MenuItem, TrayEvent, TrayIcon, TrayIconBuilder};
use log::{debug, error, info, warn};
use ksni::{Handle, Icon, TrayMethods};
// use betrayer::{Icon, Menu, MenuItem, TrayEvent, TrayIcon, TrayIconBuilder};
use log::{error, info, warn};
use rog_platform::platform::Properties;
use supergfxctl::pci_device::{Device, GfxMode, GfxPower};
use supergfxctl::zbus_proxy::DaemonProxyBlocking as GfxProxy;
use supergfxctl::zbus_proxy::DaemonProxy as GfxProxy;
use versions::Versioning;
use crate::config::Config;
@@ -32,27 +31,12 @@ struct Icons {
static ICONS: OnceLock<Icons> = OnceLock::new();
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
enum TrayAction {
Open,
Quit,
}
fn open_app() {
fn toggle_app(open: bool) {
if let Ok(mut ipc) = get_ipc_file().map_err(|e| {
error!("ROGTray: get_ipc_file: {}", e);
}) {
debug!("Tray told app to show self");
ipc.write_all(&[SHOW_GUI, 0]).ok();
}
}
fn quit_app() {
if let Ok(mut ipc) = get_ipc_file().map_err(|e| {
error!("ROGTray: get_ipc_file: {}", e);
}) {
debug!("Tray told app to show self");
ipc.write_all(&[QUIT_APP, 0]).ok();
let action = if open { SHOW_GUI } else { QUIT_APP };
ipc.write_all(&[action, 0]).ok();
}
}
@@ -63,34 +47,70 @@ fn read_icon(file: &Path) -> Icon {
let mut bytes = Vec::new();
file.read_to_end(&mut bytes).unwrap();
Icon::from_png_bytes(&bytes)
.unwrap_or(Icon::from_rgba(vec![255u8; 32 * 32 * 4], 32, 32).unwrap())
}
let mut img = image::load_from_memory_with_format(&bytes, image::ImageFormat::Png)
.expect("icon not found")
.to_rgba8();
for image::Rgba(pixel) in img.pixels_mut() {
// (╯°□°)╯︵ ┻━┻
*pixel = u32::from_be_bytes(*pixel).rotate_right(8).to_be_bytes();
}
fn build_menu() -> Menu<TrayAction> {
Menu::new([
MenuItem::separator(),
MenuItem::button("Open", TrayAction::Open),
MenuItem::button("Quit App", TrayAction::Quit),
])
}
fn do_action(event: TrayEvent<TrayAction>) {
if let TrayEvent::Menu(action) = event {
match action {
TrayAction::Open => open_app(),
TrayAction::Quit => {
quit_app();
exit(0);
}
}
let (width, height) = img.dimensions();
Icon {
width: width as i32,
height: height as i32,
data: img.into_raw(),
}
}
fn set_tray_icon_and_tip(
struct AsusTray {
current_title: String,
current_icon: Icon,
}
impl ksni::Tray for AsusTray {
fn id(&self) -> String {
TRAY_LABEL.into()
}
fn icon_pixmap(&self) -> Vec<ksni::Icon> {
vec![self.current_icon.clone()]
}
fn title(&self) -> String {
self.current_title.clone()
}
fn status(&self) -> ksni::Status {
ksni::Status::Active
}
fn menu(&self) -> Vec<ksni::MenuItem<Self>> {
use ksni::menu::*;
vec![
StandardItem {
label: "Open ROGCC".into(),
icon_name: "rog-control-center".into(),
activate: Box::new(|_| toggle_app(true)),
..Default::default()
}
.into(),
MenuItem::Separator,
StandardItem {
label: "Quit ROGCC".into(),
icon_name: "application-exit".into(),
activate: Box::new(|_| std::process::exit(0)),
..Default::default()
}
.into(),
]
}
}
async fn set_tray_icon_and_tip(
mode: GfxMode,
power: GfxPower,
tray: &mut TrayIcon<TrayAction>,
tray: &mut Handle<AsusTray>,
supergfx_active: bool,
) {
if let Some(icons) = ICONS.get() {
@@ -113,16 +133,16 @@ fn set_tray_icon_and_tip(
}
}
};
// *tray = TrayIconBuilder::<TrayAction>::new()
// .with_icon(icon)
// .with_tooltip(format!("ROG: gpu mode = {mode:?}, gpu power = {power:?}"))
// .with_menu(build_menu())
// .build(do_action)
// .map_err(|e| log::error!("Tray unable to be initialised: {e:?}"))
// .unwrap();
tray.set_icon(Some(icon));
tray.set_tooltip(format!("ROG: gpu mode = {mode:?}, gpu power = {power:?}"));
tray.update(|tray: &mut AsusTray| {
dbg!(power);
tray.current_icon = icon;
tray.current_title = format!(
"ROG: gpu mode = {mode:?}, gpu power =
{power:?}"
);
})
.await;
}
}
@@ -142,86 +162,85 @@ fn find_dgpu() -> Option<Device> {
/// The tray is controlled somewhat by `Arc<Mutex<SystemState>>`
pub fn init_tray(_supported_properties: Vec<Properties>, config: Arc<Mutex<Config>>) {
std::thread::spawn(move || {
tokio::spawn(async move {
let rog_red = read_icon(&PathBuf::from("asus_notif_red.png"));
if let Ok(mut tray) = TrayIconBuilder::<TrayAction>::new()
.with_icon(rog_red.clone())
.with_tooltip(TRAY_LABEL)
.with_menu(build_menu())
.build(do_action)
let tray = AsusTray {
current_title: TRAY_LABEL.to_string(),
current_icon: rog_red.clone(),
};
let mut tray = tray
.spawn_without_dbus_name()
.await
.map_err(|e| {
log::error!(
"Tray unable to be initialised: {e:?}. Do you have a system tray enabled?"
)
})
{
info!("Tray started");
let rog_blue = read_icon(&PathBuf::from("asus_notif_blue.png"));
let rog_green = read_icon(&PathBuf::from("asus_notif_green.png"));
let rog_white = read_icon(&PathBuf::from("asus_notif_white.png"));
let gpu_integrated = read_icon(&PathBuf::from("rog-control-center.png"));
ICONS.get_or_init(|| Icons {
rog_blue,
rog_red: rog_red.clone(),
rog_green,
rog_white,
gpu_integrated,
});
.unwrap();
let mut has_supergfx = false;
let conn = zbus::blocking::Connection::system().unwrap();
if let Ok(gfx_proxy) = GfxProxy::new(&conn) {
match gfx_proxy.mode() {
Ok(_) => {
has_supergfx = true;
if let Ok(version) = gfx_proxy.version() {
if let Some(version) = Versioning::new(&version) {
let curr_gfx = Versioning::new("5.2.0").unwrap();
warn!("supergfxd version = {version}");
if version < curr_gfx {
// Don't allow mode changing if too old a version
warn!("supergfxd found but is too old to use");
has_supergfx = false;
}
info!("Tray started");
let rog_blue = read_icon(&PathBuf::from("asus_notif_blue.png"));
let rog_green = read_icon(&PathBuf::from("asus_notif_green.png"));
let rog_white = read_icon(&PathBuf::from("asus_notif_white.png"));
let gpu_integrated = read_icon(&PathBuf::from("rog-control-center.png"));
ICONS.get_or_init(|| Icons {
rog_blue,
rog_red: rog_red.clone(),
rog_green,
rog_white,
gpu_integrated,
});
let mut has_supergfx = false;
let conn = zbus::Connection::system().await.unwrap();
if let Ok(gfx_proxy) = GfxProxy::new(&conn).await {
match gfx_proxy.mode().await {
Ok(_) => {
has_supergfx = true;
if let Ok(version) = gfx_proxy.version().await {
if let Some(version) = Versioning::new(&version) {
let curr_gfx = Versioning::new("5.2.0").unwrap();
warn!("supergfxd version = {version}");
if version < curr_gfx {
// Don't allow mode changing if too old a version
warn!("supergfxd found but is too old to use");
has_supergfx = false;
}
}
}
Err(e) => warn!("Couldn't get mode form supergfxd: {e:?}"),
}
Err(e) => warn!("Couldn't get mode form supergfxd: {e:?}"),
}
info!("Started ROGTray");
let mut last_power = GfxPower::Unknown;
let dev = find_dgpu();
loop {
sleep(Duration::from_millis(1000));
if let Ok(lock) = config.try_lock() {
if !lock.enable_tray_icon {
return;
}
info!("Started ROGTray");
let mut last_power = GfxPower::Unknown;
let dev = find_dgpu();
loop {
tokio::time::sleep(Duration::from_millis(1000)).await;
if let Ok(lock) = config.try_lock() {
if !lock.enable_tray_icon {
return;
}
if has_supergfx {
if let Ok(mode) = gfx_proxy.mode() {
if let Ok(power) = gfx_proxy.power() {
if last_power != power {
set_tray_icon_and_tip(mode, power, &mut tray, has_supergfx);
last_power = power;
}
}
}
} else if let Some(dev) = dev.as_ref() {
if let Ok(power) = dev.get_runtime_status() {
}
if has_supergfx {
if let Ok(mode) = gfx_proxy.mode().await {
if let Ok(power) = gfx_proxy.power().await {
if last_power != power {
set_tray_icon_and_tip(
GfxMode::Hybrid,
power,
&mut tray,
has_supergfx,
);
set_tray_icon_and_tip(mode, power, &mut tray, has_supergfx).await;
last_power = power;
}
}
}
} else if let Some(dev) = dev.as_ref() {
if let Ok(power) = dev.get_runtime_status() {
if last_power != power {
set_tray_icon_and_tip(GfxMode::Hybrid, power, &mut tray, has_supergfx)
.await;
last_power = power;
}
}
}
}
}