diff --git a/src/chat/config.rs b/src/chat/config.rs index 9f0e3f6..83a58ea 100644 --- a/src/chat/config.rs +++ b/src/chat/config.rs @@ -8,7 +8,8 @@ const MESSAGE_FORMAT: &str = "\u{B9AC}\u{3E70}<{name}> {text}"; fn default_true() -> bool { true } pub fn default_max_messages() -> usize { 200 } -pub fn default_update_time() -> usize { 50 } +pub fn default_update_time() -> usize { 100 } +pub fn default_oof_update_time() -> usize { 10000 } pub fn default_host() -> String { "meex.lol:11234".to_string() } pub fn default_message_format() -> String { MESSAGE_FORMAT.to_string() } @@ -18,6 +19,7 @@ pub struct Config { #[serde(default)] pub name: Option, #[serde(default = "default_message_format")] pub message_format: String, #[serde(default = "default_update_time")] pub update_time: usize, + #[serde(default = "default_oof_update_time")] pub oof_update_time: usize, #[serde(default = "default_max_messages")] pub max_messages: usize, #[serde(default = "default_true")] pub hide_my_ip: bool, #[serde(default)] pub show_other_ip: bool, @@ -110,6 +112,7 @@ pub struct Args { #[arg(short='n', long)] pub name: Option, #[arg(long)] pub message_format: Option, #[arg(long)] pub update_time: Option, + #[arg(long)] pub oof_update_time: Option, #[arg(long)] pub max_messages: Option, #[arg(long)] pub hide_my_ip: Option, #[arg(long)] pub show_other_ip: Option, @@ -131,6 +134,7 @@ impl Args { if let Some(v) = self.proxy.clone() { config.proxy = Some(v) } if let Some(v) = self.message_format.clone() { config.message_format = v } if let Some(v) = self.update_time { config.update_time = v } + if let Some(v) = self.oof_update_time { config.oof_update_time = v } if let Some(v) = self.max_messages { config.max_messages = v } if let Some(v) = self.hide_my_ip { config.hide_my_ip = v } if let Some(v) = self.show_other_ip { config.show_other_ip = v } diff --git a/src/chat/ctx.rs b/src/chat/ctx.rs index 0b33d6c..bf949ee 100644 --- a/src/chat/ctx.rs +++ b/src/chat/ctx.rs @@ -1,4 +1,4 @@ -use std::sync::{atomic::{AtomicUsize, Ordering}, mpsc::Sender, Arc, RwLock}; +use std::sync::{atomic::{AtomicBool, AtomicUsize, Ordering}, mpsc::Sender, Arc, RwLock}; use rand::random; @@ -10,7 +10,8 @@ pub struct Context { pub sender: RwLock>>>, pub messages: RwLock>, pub packet_size: AtomicUsize, - pub name: RwLock + pub name: RwLock, + pub is_focused: AtomicBool } impl Context { @@ -22,6 +23,7 @@ impl Context { messages: RwLock::new(Vec::new()), packet_size: AtomicUsize::default(), name: RwLock::new(config.name.clone().unwrap_or_else(|| format!("Anon#{:X}", random::()))), + is_focused: AtomicBool::new(true) } } diff --git a/src/chat/gui.rs b/src/chat/gui.rs index 10e04a5..e45ffb2 100644 --- a/src/chat/gui.rs +++ b/src/chat/gui.rs @@ -1,4 +1,4 @@ -use std::sync::{mpsc::{channel, Receiver}, Arc, RwLock}; +use std::sync::{atomic::Ordering, mpsc::{channel, Receiver}, Arc, RwLock}; use std::cell::RefCell; use std::time::{Duration, SystemTime}; use std::thread; @@ -27,7 +27,7 @@ use gtk::{ Justification, Label, ListBox, Orientation, Overlay, Picture, ScrolledWindow, Settings, Window }; -use crate::proto::parse_rac_url; +use crate::{chat::config::default_oof_update_time, proto::parse_rac_url}; use super::{config::{default_max_messages, default_update_time, get_config_path, save_config, Config}, ctx::Context, on_send_message, parse_message, print_message, recv_tick, sanitize_message, SERVER_LIST}; @@ -164,6 +164,7 @@ fn open_settings(ctx: Arc, app: &Application) { let message_format_entry = gui_entry_setting!("Message Format", message_format, ctx, vbox); let proxy_entry = gui_option_entry_setting!("Socks5 proxy", proxy, ctx, vbox); let update_time_entry = gui_usize_entry_setting!("Update Time", update_time, ctx, vbox); + let oof_update_time_entry = gui_usize_entry_setting!("Out-of-focus Update Time", oof_update_time, ctx, vbox); let max_messages_entry = gui_usize_entry_setting!("Max Messages", max_messages, ctx, vbox); let hide_my_ip_entry = gui_checkbox_setting!("Hide My IP", hide_my_ip, ctx, vbox); let show_other_ip_entry = gui_checkbox_setting!("Show Other IP", show_other_ip, ctx, vbox); @@ -200,6 +201,7 @@ fn open_settings(ctx: Arc, app: &Application) { #[weak] wrac_enabled_entry, #[weak] proxy_entry, #[weak] debug_logs_entry, + #[weak] oof_update_time_entry, move |_| { let config = Config { host: host_entry.text().to_string(), @@ -224,6 +226,17 @@ fn open_settings(ctx: Arc, app: &Application) { update_time } }, + oof_update_time: { + let oof_update_time = oof_update_time_entry.text(); + + if let Ok(oof_update_time) = oof_update_time.parse::() { + oof_update_time + } else { + let oof_update_time = default_oof_update_time(); + oof_update_time_entry.set_text(&oof_update_time.to_string()); + oof_update_time + } + }, max_messages: { let max_messages = max_messages_entry.text(); @@ -481,11 +494,13 @@ fn build_ui(ctx: Arc, app: &Application) -> UiModel { timeout_add_local(Duration::from_millis(30), { let logo = logo.clone(); let logo_anim = logo_anim.clone(); + let ctx = ctx.clone(); move || { - logo.set_pixbuf(Some(&logo_anim.pixbuf())); - logo_anim.advance(SystemTime::now()); - + if ctx.is_focused.load(Ordering::SeqCst) { + logo.set_pixbuf(Some(&logo_anim.pixbuf())); + logo_anim.advance(SystemTime::now()); + } ControlFlow::Continue } }); @@ -658,30 +673,31 @@ fn setup(_: &Application, ctx: Arc, ui: UiModel) { run_recv_loop(ctx.clone()); let (tx, rx) = channel(); + + ui.window.connect_notify(Some("is-active"), { + let ctx = ctx.clone(); - #[cfg(feature = "libnotify")] - ui.window.connect_notify(Some("is-active"), move |a, _| { - if a.is_active() { - GLOBAL.with(|global| { - if let Some((ui, _)) = &*global.borrow() { - for i in ui.notifications.read().unwrap().clone() { - i.close().expect("libnotify close error"); - } - } - }); - } - }); + move |a, _| { + let is_focused = a.is_active(); - #[cfg(not(feature = "libnotify"))] - ui.window.connect_notify(Some("is-active"), move |a, _| { - if a.is_active() { - GLOBAL.with(|global| { - if let Some((ui, _)) = &*global.borrow() { - for i in ui.notifications.read().unwrap().clone() { - ui.app.withdraw_notification(&i); + ctx.is_focused.store(is_focused, Ordering::SeqCst); + + if is_focused { + make_recv_tick(ctx.clone()); + + GLOBAL.with(|global| { + if let Some((ui, _)) = &*global.borrow() { + #[cfg(feature = "libnotify")] + for i in ui.notifications.read().unwrap().clone() { + i.close().expect("libnotify close error"); + } + #[cfg(not(feature = "libnotify"))] + for i in ui.notifications.read().unwrap().clone() { + ui.app.withdraw_notification(&i); + } } - } - }); + }); + } } }); @@ -704,7 +720,7 @@ fn setup(_: &Application, ctx: Arc, ui: UiModel) { } } let message: String = rx.recv().unwrap(); - on_add_message(ctx.clone(), &ui, message); + on_add_message(ctx.clone(), &ui, message, !clear); } }); }); @@ -766,14 +782,14 @@ fn send_notification(_: Arc, ui: &UiModel, title: &str, message: &str) ui.notifications.write().unwrap().push(id); } -fn on_add_message(ctx: Arc, ui: &UiModel, message: String) { +fn on_add_message(ctx: Arc, ui: &UiModel, message: String, notify: bool) { let Some(message) = sanitize_message(message) else { return; }; if message.is_empty() { return; } - // TODO: caching these colors maybe?? + // TODO: cache these colors maybe?? let (ip_color, date_color, text_color) = if ui.is_dark_theme { ( @@ -803,13 +819,13 @@ fn on_add_message(ctx: Arc, ui: &UiModel, message: String) { if let Some((name, color)) = nick { label.push_str(&format!("<{}> ", color.to_uppercase(), glib::markup_escape_text(&name))); - if !ui.window.is_active() { + if notify && !ui.window.is_active() { if ctx.config(|o| o.chunked_enabled) { send_notification(ctx.clone(), ui, &format!("{}'s Message", &name), &glib::markup_escape_text(&content)); } } } else { - if !ui.window.is_active() { + if notify && !ui.window.is_active() { if ctx.config(|o| o.chunked_enabled) { send_notification(ctx.clone(), ui, "System Message", &content); } @@ -820,7 +836,7 @@ fn on_add_message(ctx: Arc, ui: &UiModel, message: String) { } else { label.push_str(&format!("{}", glib::markup_escape_text(&message))); - if !ui.window.is_active() { + if notify && !ui.window.is_active() { if ctx.config(|o| o.chunked_enabled) { send_notification(ctx.clone(), ui, "Chat Message", &message); } @@ -853,15 +869,27 @@ fn on_add_message(ctx: Arc, ui: &UiModel, message: String) { }); } +fn make_recv_tick(ctx: Arc) { + if let Err(e) = recv_tick(ctx.clone()) { + if ctx.config(|o| o.debug_logs) { + let _ = print_message(ctx.clone(), format!("Print messages error: {}", e.to_string()).to_string()); + } + thread::sleep(Duration::from_secs(1)); + } +} + fn run_recv_loop(ctx: Arc) { thread::spawn(move || { loop { - if let Err(e) = recv_tick(ctx.clone()) { - if ctx.config(|o| o.debug_logs) { - let _ = print_message(ctx.clone(), format!("Print messages error: {}", e.to_string()).to_string()); + make_recv_tick(ctx.clone()); + + thread::sleep(Duration::from_millis( + if ctx.is_focused.load(Ordering::SeqCst) { + ctx.config(|o| o.update_time) as u64 + } else { + ctx.config(|o| o.oof_update_time) as u64 } - thread::sleep(Duration::from_secs(1)); - } + )); } }); } diff --git a/src/chat/mod.rs b/src/chat/mod.rs index 92c7fd4..a97399c 100644 --- a/src/chat/mod.rs +++ b/src/chat/mod.rs @@ -221,7 +221,7 @@ pub fn recv_tick(ctx: Arc) -> Result<(), Box> { } _ => {} } - thread::sleep(Duration::from_millis(ctx.config(|o| o.update_time) as u64)); + Ok(()) }