mirror of
https://gitlab.com/asus-linux/asusctl.git
synced 2026-02-06 00:15:04 +01:00
Refactor ROGCC to use dbus to communicate with self instead of pipe file
This commit is contained in:
@@ -1,6 +1,5 @@
|
||||
use std::borrow::BorrowMut;
|
||||
use std::env::args;
|
||||
use std::io::{Read, Write};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::process::exit;
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -10,7 +9,7 @@ use std::time::Duration;
|
||||
use config_traits::{StdConfig, StdConfigLoad1};
|
||||
use dmi_id::DMIID;
|
||||
use gumdrop::Options;
|
||||
use log::{info, LevelFilter};
|
||||
use log::{info, warn, LevelFilter};
|
||||
use rog_control_center::cli_options::CliStart;
|
||||
use rog_control_center::config::Config;
|
||||
use rog_control_center::error::Result;
|
||||
@@ -18,41 +17,71 @@ use rog_control_center::notify::start_notifications;
|
||||
use rog_control_center::slint::ComponentHandle;
|
||||
use rog_control_center::tray::init_tray;
|
||||
use rog_control_center::ui::setup_window;
|
||||
use rog_control_center::{
|
||||
get_ipc_file, on_tmp_dir_exists, print_versions, MainWindow, QUIT_APP, SHOWING_GUI, SHOW_GUI,
|
||||
use rog_control_center::zbus::{
|
||||
AppState, ROGCCZbus, ROGCCZbusProxyBlocking, ZBUS_IFACE, ZBUS_PATH,
|
||||
};
|
||||
use rog_control_center::{print_versions, MainWindow};
|
||||
use tokio::runtime::Runtime;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
#[cfg(feature = "tokio-debug")]
|
||||
console_subscriber::init();
|
||||
let mut logger = env_logger::Builder::new();
|
||||
logger
|
||||
.filter_level(LevelFilter::Warn)
|
||||
.parse_default_env()
|
||||
.target(env_logger::Target::Stdout)
|
||||
.format_timestamp(None)
|
||||
.init();
|
||||
|
||||
// Try to open a proxy and check for app state first
|
||||
{
|
||||
let user_con = zbus::blocking::Connection::session()?;
|
||||
if let Ok(proxy) = ROGCCZbusProxyBlocking::new(&user_con) {
|
||||
if let Ok(state) = proxy.state() {
|
||||
info!("App is already running: {state:?}, opening the window");
|
||||
// if there is a proxy connection assume the app is already running
|
||||
proxy.set_state(AppState::MainWindowShouldOpen)?;
|
||||
std::process::exit(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// version checks
|
||||
let self_version = env!("CARGO_PKG_VERSION");
|
||||
let conn = zbus::blocking::Connection::system()?;
|
||||
let proxy = rog_dbus::zbus_platform::PlatformProxyBlocking::new(&conn)?;
|
||||
let asusd_version = proxy.version().unwrap();
|
||||
let zbus_con = zbus::blocking::Connection::system()?;
|
||||
let platform_proxy = rog_dbus::zbus_platform::PlatformProxyBlocking::new(&zbus_con)?;
|
||||
let asusd_version = platform_proxy.version().unwrap();
|
||||
if asusd_version != self_version {
|
||||
println!("Version mismatch: asusctl = {self_version}, asusd = {asusd_version}");
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
// start tokio
|
||||
let rt = Runtime::new().expect("Unable to create Runtime");
|
||||
// Enter the runtime so that `tokio::spawn` is available immediately.
|
||||
let _enter = rt.enter();
|
||||
|
||||
#[cfg(feature = "tokio-debug")]
|
||||
console_subscriber::init();
|
||||
|
||||
let state_zbus = ROGCCZbus::new();
|
||||
let app_state = state_zbus.clone_state();
|
||||
let _conn = zbus::connection::Builder::session()?
|
||||
.name(ZBUS_IFACE)?
|
||||
.serve_at(ZBUS_PATH, state_zbus)?
|
||||
.build()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
warn!("{}: add_to_server {}", ZBUS_PATH, err);
|
||||
err
|
||||
})?;
|
||||
|
||||
let dmi = DMIID::new().unwrap_or_default();
|
||||
let board_name = dmi.board_name;
|
||||
let prod_family = dmi.product_family;
|
||||
info!("Running on {board_name}, product: {prod_family}");
|
||||
let is_rog_ally = prod_family == "RC71L";
|
||||
|
||||
// tmp-dir must live to the end of program life
|
||||
let _tmp_dir = match tempfile::Builder::new()
|
||||
.prefix("rog-gui")
|
||||
.rand_bytes(0)
|
||||
.tempdir()
|
||||
{
|
||||
Ok(tmp) => tmp,
|
||||
Err(_) => on_tmp_dir_exists().unwrap(),
|
||||
};
|
||||
|
||||
let args: Vec<String> = args().skip(1).collect();
|
||||
|
||||
let cli_parsed = match CliStart::parse_args_default(&args) {
|
||||
@@ -66,15 +95,7 @@ async fn main() -> Result<()> {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let mut logger = env_logger::Builder::new();
|
||||
logger
|
||||
.filter_level(LevelFilter::Warn)
|
||||
.parse_default_env()
|
||||
.target(env_logger::Target::Stdout)
|
||||
.format_timestamp(None)
|
||||
.init();
|
||||
|
||||
let supported_properties = proxy.supported_properties().unwrap_or_default();
|
||||
let supported_properties = platform_proxy.supported_properties().unwrap_or_default();
|
||||
|
||||
// Startup
|
||||
let mut config = Config::new().load();
|
||||
@@ -99,8 +120,6 @@ async fn main() -> Result<()> {
|
||||
|
||||
if config.startup_in_background {
|
||||
config.run_in_background = true;
|
||||
} else {
|
||||
get_ipc_file().unwrap().write_all(&[SHOW_GUI, 0]).unwrap();
|
||||
}
|
||||
config.write();
|
||||
|
||||
@@ -108,10 +127,6 @@ async fn main() -> Result<()> {
|
||||
let startup_in_background = config.startup_in_background;
|
||||
let config = Arc::new(Mutex::new(config));
|
||||
|
||||
// start tokio
|
||||
let rt = Runtime::new().expect("Unable to create Runtime");
|
||||
// Enter the runtime so that `tokio::spawn` is available immediately.
|
||||
let _enter = rt.enter();
|
||||
start_notifications(config.clone(), &rt)?;
|
||||
|
||||
if enable_tray_icon {
|
||||
@@ -121,7 +136,11 @@ async fn main() -> Result<()> {
|
||||
thread_local! { pub static UI: std::cell::RefCell<Option<MainWindow>> = Default::default()};
|
||||
// i_slint_backend_selector::with_platform(|_| Ok(())).unwrap();
|
||||
|
||||
let mut do_once = !startup_in_background;
|
||||
if !startup_in_background {
|
||||
if let Ok(mut lock) = app_state.lock() {
|
||||
*lock = AppState::MainWindowShouldOpen;
|
||||
}
|
||||
}
|
||||
|
||||
if std::env::var("RUST_TRANSLATIONS").is_ok() {
|
||||
// don't care about content
|
||||
@@ -133,42 +152,40 @@ async fn main() -> Result<()> {
|
||||
}
|
||||
|
||||
thread::spawn(move || {
|
||||
let mut buf = [0u8; 2];
|
||||
// blocks until it is read, typically the read will happen after a second
|
||||
// process writes to the IPC (so there is data to actually read)
|
||||
let mut state = AppState::StartingUp;
|
||||
loop {
|
||||
if do_once {
|
||||
buf[0] = SHOW_GUI;
|
||||
do_once = false;
|
||||
} else {
|
||||
get_ipc_file().unwrap().read_exact(&mut buf).unwrap();
|
||||
// save as a var, don't hold the lock the entire time or deadlocks happen
|
||||
if let Ok(lock) = app_state.lock() {
|
||||
state = *lock;
|
||||
}
|
||||
|
||||
if buf[0] == SHOW_GUI {
|
||||
// There's a balancing act with read/write timing of IPC, there needs to be a
|
||||
// small sleep after this to give any other process a chance to
|
||||
// read the IPC before looping
|
||||
get_ipc_file()
|
||||
.unwrap()
|
||||
.write_all(&[SHOWING_GUI, 0])
|
||||
.unwrap();
|
||||
if state == AppState::MainWindowShouldOpen {
|
||||
if let Ok(mut lock) = app_state.lock() {
|
||||
*lock = AppState::MainWindowOpen;
|
||||
}
|
||||
sleep(Duration::from_millis(50));
|
||||
|
||||
let config_copy = config.clone();
|
||||
let app_state_copy = app_state.clone();
|
||||
slint::invoke_from_event_loop(move || {
|
||||
UI.with(|ui| {
|
||||
let app_state_copy = app_state_copy.clone();
|
||||
let mut ui = ui.borrow_mut();
|
||||
if let Some(ui) = ui.as_mut() {
|
||||
ui.window().show().unwrap();
|
||||
ui.window().on_close_requested(|| {
|
||||
get_ipc_file().unwrap().write_all(&[0, 0]).unwrap();
|
||||
ui.window().on_close_requested(move || {
|
||||
if let Ok(mut lock) = app_state_copy.lock() {
|
||||
*lock = AppState::MainWindowClosed;
|
||||
}
|
||||
slint::CloseRequestResponse::HideWindow
|
||||
});
|
||||
} else {
|
||||
let newui = setup_window(config_copy);
|
||||
newui.window().show().unwrap();
|
||||
newui.window().on_close_requested(|| {
|
||||
get_ipc_file().unwrap().write_all(&[0, 0]).unwrap();
|
||||
newui.window().on_close_requested(move || {
|
||||
if let Ok(mut lock) = app_state_copy.lock() {
|
||||
*lock = AppState::MainWindowClosed;
|
||||
}
|
||||
slint::CloseRequestResponse::HideWindow
|
||||
});
|
||||
ui.replace(newui);
|
||||
@@ -176,29 +193,26 @@ async fn main() -> Result<()> {
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
} else {
|
||||
if buf[1] == QUIT_APP {
|
||||
slint::quit_event_loop().unwrap();
|
||||
exit(0);
|
||||
}
|
||||
if buf[0] != SHOWING_GUI {
|
||||
if let Ok(lock) = config.lock() {
|
||||
if !lock.run_in_background {
|
||||
slint::quit_event_loop().unwrap();
|
||||
exit(0);
|
||||
}
|
||||
} else if state == AppState::QuitApp {
|
||||
slint::quit_event_loop().unwrap();
|
||||
exit(0);
|
||||
} else if state != AppState::MainWindowOpen {
|
||||
if let Ok(lock) = config.lock() {
|
||||
if !lock.run_in_background {
|
||||
slint::quit_event_loop().unwrap();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
slint::invoke_from_event_loop(move || {
|
||||
UI.with(|ui| {
|
||||
let mut ui = ui.take();
|
||||
if let Some(ui) = ui.borrow_mut() {
|
||||
ui.window().hide().unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
slint::invoke_from_event_loop(move || {
|
||||
UI.with(|ui| {
|
||||
let mut ui = ui.take();
|
||||
if let Some(ui) = ui.borrow_mut() {
|
||||
ui.window().hide().unwrap();
|
||||
}
|
||||
});
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user