fix bug that freezes window when server hands

This commit is contained in:
MeexReay 2025-06-16 07:55:08 +03:00
parent 9c29d4e742
commit 0260206500
3 changed files with 32 additions and 43 deletions

View File

@ -7,7 +7,7 @@ use super::config::Config;
pub struct Context { pub struct Context {
pub registered: RwLock<Option<String>>, pub registered: RwLock<Option<String>>,
pub config: RwLock<Config>, pub config: RwLock<Config>,
pub sender: RwLock<Option<Arc<Sender<(String, bool)>>>>, pub sender: RwLock<Option<Arc<Sender<(Vec<String>, bool)>>>>,
pub messages: RwLock<Vec<String>>, pub messages: RwLock<Vec<String>>,
pub packet_size: AtomicUsize, pub packet_size: AtomicUsize,
pub name: RwLock<String>, pub name: RwLock<String>,

View File

@ -1,4 +1,4 @@
use std::sync::{atomic::Ordering, mpsc::{channel, Receiver}, Arc, RwLock}; use std::sync::{atomic::Ordering, mpsc::channel, Arc, RwLock};
use std::cell::RefCell; use std::cell::RefCell;
use std::time::{Duration, SystemTime}; use std::time::{Duration, SystemTime};
use std::thread; use std::thread;
@ -6,7 +6,7 @@ use std::error::Error;
use chrono::Local; use chrono::Local;
use gtk4 as gtk; use gtk4::{self as gtk};
use gtk::gdk_pixbuf::{Pixbuf, PixbufAnimation, PixbufLoader}; use gtk::gdk_pixbuf::{Pixbuf, PixbufAnimation, PixbufLoader};
use gtk::prelude::*; use gtk::prelude::*;
@ -45,15 +45,15 @@ struct UiModel {
} }
thread_local!( thread_local!(
static GLOBAL: RefCell<Option<(UiModel, Receiver<String>)>> = RefCell::new(None); static GLOBAL: RefCell<Option<UiModel>> = RefCell::new(None);
); );
pub fn clear_chat_messages(ctx: Arc<Context>, message: String) { pub fn clear_chat_messages(ctx: Arc<Context>, messages: Vec<String>) {
let _ = ctx.sender.read().unwrap().clone().unwrap().send((message, true)); let _ = ctx.sender.read().unwrap().clone().unwrap().send((messages, true));
} }
pub fn add_chat_message(ctx: Arc<Context>, message: String) { pub fn add_chat_messages(ctx: Arc<Context>, messages: Vec<String>) {
let _ = ctx.sender.read().unwrap().clone().unwrap().send((message, false)); let _ = ctx.sender.read().unwrap().clone().unwrap().send((messages, false));
} }
fn load_pixbuf(data: &[u8]) -> Result<Pixbuf, Box<dyn Error>> { fn load_pixbuf(data: &[u8]) -> Result<Pixbuf, Box<dyn Error>> {
@ -407,7 +407,7 @@ fn build_menu(ctx: Arc<Context>, app: &Application) {
move |_, _, _| { move |_, _, _| {
AboutDialog::builder() AboutDialog::builder()
.application(&app) .application(&app)
.authors(["TheMixRay", "MeexReay"]) .authors(["MeexReay"])
.license(" DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE .license(" DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
Version 2, December 2004 Version 2, December 2004
@ -619,7 +619,7 @@ fn build_ui(ctx: Arc<Context>, app: &Application) -> UiModel {
if let Err(e) = on_send_message(ctx.clone(), &text_entry.text()) { if let Err(e) = on_send_message(ctx.clone(), &text_entry.text()) {
if ctx.config(|o| o.debug_logs) { if ctx.config(|o| o.debug_logs) {
let msg = format!("Send message error: {}", e.to_string()).to_string(); let msg = format!("Send message error: {}", e.to_string()).to_string();
add_chat_message(ctx.clone(), msg); add_chat_messages(ctx.clone(), vec![msg]);
} }
} }
} }
@ -640,7 +640,7 @@ fn build_ui(ctx: Arc<Context>, app: &Application) -> UiModel {
if let Err(e) = on_send_message(ctx.clone(), &text_entry.text()) { if let Err(e) = on_send_message(ctx.clone(), &text_entry.text()) {
if ctx.config(|o| o.debug_logs) { if ctx.config(|o| o.debug_logs) {
let msg = format!("Send message error: {}", e.to_string()).to_string(); let msg = format!("Send message error: {}", e.to_string()).to_string();
add_chat_message(ctx.clone(), msg); add_chat_messages(ctx.clone(), vec![msg]);
} }
} }
} }
@ -708,8 +708,6 @@ fn setup(_: &Application, ctx: Arc<Context>, ui: UiModel) {
run_recv_loop(ctx.clone()); run_recv_loop(ctx.clone());
let (tx, rx) = channel();
ui.window.connect_notify(Some("is-active"), { ui.window.connect_notify(Some("is-active"), {
let ctx = ctx.clone(); let ctx = ctx.clone();
@ -719,10 +717,15 @@ fn setup(_: &Application, ctx: Arc<Context>, ui: UiModel) {
ctx.is_focused.store(is_focused, Ordering::SeqCst); ctx.is_focused.store(is_focused, Ordering::SeqCst);
if is_focused { if is_focused {
make_recv_tick(ctx.clone()); thread::spawn({
let ctx = ctx.clone();
move || {
make_recv_tick(ctx.clone());
}
});
GLOBAL.with(|global| { GLOBAL.with(|global| {
if let Some((ui, _)) = &*global.borrow() { if let Some(ui) = &*global.borrow() {
#[cfg(feature = "libnotify")] #[cfg(feature = "libnotify")]
for i in ui.notifications.read().unwrap().clone() { for i in ui.notifications.read().unwrap().clone() {
i.close().expect("libnotify close error"); i.close().expect("libnotify close error");
@ -738,25 +741,25 @@ fn setup(_: &Application, ctx: Arc<Context>, ui: UiModel) {
}); });
GLOBAL.with(|global| { GLOBAL.with(|global| {
*global.borrow_mut() = Some((ui, rx)); *global.borrow_mut() = Some(ui);
}); });
thread::spawn({ thread::spawn({
let ctx = ctx.clone(); let ctx = ctx.clone();
move || { move || {
while let Ok((message, clear)) = receiver.recv() { while let Ok((messages, clear)) = receiver.recv() {
let _ = tx.send(message.clone());
let ctx = ctx.clone(); let ctx = ctx.clone();
timeout_add_once(Duration::ZERO, move || { timeout_add_once(Duration::ZERO, move || {
GLOBAL.with(|global| { GLOBAL.with(|global| {
if let Some((ui, rx)) = &*global.borrow() { if let Some(ui) = &*global.borrow() {
if clear { if clear {
while let Some(row) = ui.chat_box.last_child() { while let Some(row) = ui.chat_box.last_child() {
ui.chat_box.remove(&row); ui.chat_box.remove(&row);
} }
} }
let message: String = rx.recv().unwrap(); for message in messages.iter() {
on_add_message(ctx.clone(), &ui, message, !clear); on_add_message(ctx.clone(), &ui, message.to_string(), !clear);
}
} }
}); });
}); });
@ -825,7 +828,7 @@ fn on_add_message(ctx: Arc<Context>, ui: &UiModel, message: String, notify: bool
return; return;
} }
// TODO: cache these colors maybe?? // TODO: softcode these colors
let (ip_color, date_color, text_color) = if ui.is_dark_theme { let (ip_color, date_color, text_color) = if ui.is_dark_theme {
( (
@ -897,7 +900,7 @@ fn on_add_message(ctx: Arc<Context>, ui: &UiModel, message: String, notify: bool
timeout_add_local_once(Duration::from_millis(1000), move || { timeout_add_local_once(Duration::from_millis(1000), move || {
GLOBAL.with(|global| { GLOBAL.with(|global| {
if let Some((ui, _)) = &*global.borrow() { if let Some(ui) = &*global.borrow() {
let o = &ui.chat_scrolled; let o = &ui.chat_scrolled;
o.vadjustment().set_value(o.vadjustment().upper() - o.vadjustment().page_size()); o.vadjustment().set_value(o.vadjustment().upper() - o.vadjustment().page_size());
} }

View File

@ -6,7 +6,7 @@ use crate::connect_rac;
use super::proto::{connect, read_messages, send_message, send_message_spoof_auth, register_user, send_message_auth}; use super::proto::{connect, read_messages, send_message, send_message_spoof_auth, register_user, send_message_auth};
use gui::{add_chat_message, clear_chat_messages}; use gui::{add_chat_messages, clear_chat_messages};
use lazy_static::lazy_static; use lazy_static::lazy_static;
use regex::Regex; use regex::Regex;
@ -171,7 +171,7 @@ pub fn prepare_message(ctx: Arc<Context>, message: &str) -> String {
pub fn print_message(ctx: Arc<Context>, message: String) -> Result<(), Box<dyn Error>> { pub fn print_message(ctx: Arc<Context>, message: String) -> Result<(), Box<dyn Error>> {
ctx.add_message(ctx.config(|o| o.max_messages), vec![message.clone()]); ctx.add_message(ctx.config(|o| o.max_messages), vec![message.clone()]);
add_chat_message(ctx.clone(), message); add_chat_messages(ctx.clone(), vec![message]);
Ok(()) Ok(())
} }
@ -190,33 +190,19 @@ pub fn recv_tick(ctx: Arc<Context>) -> Result<(), Box<dyn Error>> {
ctx.add_messages_packet(ctx.config(|o| o.max_messages), messages.clone(), size); ctx.add_messages_packet(ctx.config(|o| o.max_messages), messages.clone(), size);
if last_size == 0 { if last_size == 0 {
if messages.len() >= 1 { if messages.len() >= 1 {
clear_chat_messages(ctx.clone(), messages[0].clone()); clear_chat_messages(ctx.clone(), messages);
if messages.len() >= 2 {
for msg in &messages[1..] {
add_chat_message(ctx.clone(), msg.clone());
}
}
} }
} else { } else {
for msg in messages { add_chat_messages(ctx.clone(), messages);
add_chat_message(ctx.clone(), msg.clone());
}
} }
} else { } else {
ctx.put_messages_packet(ctx.config(|o| o.max_messages), messages.clone(), size); ctx.put_messages_packet(ctx.config(|o| o.max_messages), messages.clone(), size);
if messages.len() >= 1 { clear_chat_messages(ctx.clone(), messages);
clear_chat_messages(ctx.clone(), messages[0].clone());
if messages.len() >= 2 {
for msg in &messages[1..] {
add_chat_message(ctx.clone(), msg.clone());
}
}
}
} }
}, },
Err(e) => { Err(e) => {
if ctx.config(|o| o.debug_logs) { if ctx.config(|o| o.debug_logs) {
add_chat_message(ctx.clone(), format!("Read messages error: {}", e.to_string())); add_chat_messages(ctx.clone(), vec![format!("Read messages error: {}", e.to_string())]);
} }
} }
_ => {} _ => {}