win_fix_multi_tab: send monitor ready on clipboard is ready

Signed-off-by: fufesou <shuanglongchen@yeah.net>
This commit is contained in:
fufesou 2022-10-26 22:37:45 +08:00
parent a9602f95ed
commit c87e7f1e28
6 changed files with 117 additions and 129 deletions

View File

@ -0,0 +1,60 @@
use crate::cliprdr::*;
use hbb_common::log;
use std::sync::Mutex;
#[cfg(windows)]
lazy_static::lazy_static! {
static ref CONTEXT_SEND: ContextSend = ContextSend{addr: Mutex::new(0)};
}
pub struct ContextSend {
addr: Mutex<u64>,
}
impl ContextSend {
pub fn is_enabled() -> bool {
*CONTEXT_SEND.addr.lock().unwrap() != 0
}
pub fn enable(enabled: bool) {
let mut lock = CONTEXT_SEND.addr.lock().unwrap();
if enabled {
if *lock == 0 {
match crate::create_cliprdr_context(true, false, crate::ProcessSide::ClientSide) {
Ok(context) => {
log::info!("clipboard context for file transfer created.");
*lock = Box::into_raw(context) as _;
}
Err(err) => {
log::error!(
"Create clipboard context for file transfer: {}",
err.to_string()
);
}
}
}
} else {
if *lock != 0 {
unsafe {
let _ = Box::from_raw(*lock as *mut CliprdrClientContext);
}
log::info!("clipboard context for file transfer destroyed.");
*lock = 0;
}
}
}
pub fn proc<F: FnOnce(&mut Box<CliprdrClientContext>) -> u32>(f: F) -> u32 {
let mut lock = CONTEXT_SEND.addr.lock().unwrap();
if *lock != 0 {
unsafe {
let mut context = Box::from_raw(*lock as *mut CliprdrClientContext);
let res = f(&mut context);
*lock = Box::into_raw(context) as _;
res
}
} else {
0
}
}
}

View File

@ -16,6 +16,8 @@ use std::{
};
pub mod cliprdr;
pub mod context_send;
pub use context_send::*;
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(tag = "t", content = "c")]

View File

@ -6,6 +6,9 @@ use crate::common;
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::common::{check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL};
#[cfg(windows)]
use clipboard::{cliprdr::CliprdrClientContext, ContextSend};
use crate::ui_session_interface::{InvokeUiSession, Session};
use crate::{client::Data, client::Interface};
@ -33,11 +36,6 @@ use std::collections::HashMap;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};
#[cfg(windows)]
lazy_static::lazy_static! {
static ref CLIPBOARD_FILE_CONTEXT: Mutex<u64> = Mutex::new(0);
}
pub struct Remote<T: InvokeUiSession> {
handler: Session<T>,
video_sender: MediaSender,
@ -58,37 +56,6 @@ pub struct Remote<T: InvokeUiSession> {
video_format: CodecFormat,
}
#[cfg(windows)]
fn check_clipboard_file_context(enable_file_transfer: bool) {
let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst) && enable_file_transfer;
let mut lock = CLIPBOARD_FILE_CONTEXT.lock().unwrap();
if enabled {
if *lock == 0 {
match clipboard::create_cliprdr_context(true, false, clipboard::ProcessSide::ClientSide)
{
Ok(context) => {
log::info!("clipboard context for file transfer created.");
*lock = Box::into_raw(context) as _;
}
Err(err) => {
log::error!(
"Create clipboard context for file transfer: {}",
err.to_string()
);
}
}
}
} else {
if *lock != 0 {
unsafe {
let _ = Box::from_raw(*lock as *mut clipboard::cliprdr::CliprdrClientContext);
}
log::info!("clipboard context for file transfer destroyed.");
*lock = 0;
}
}
}
impl<T: InvokeUiSession> Remote<T> {
pub fn new(
handler: Session<T>,
@ -1202,23 +1169,19 @@ impl<T: InvokeUiSession> Remote<T> {
fn check_clipboard_file_context(&self) {
#[cfg(windows)]
{
check_clipboard_file_context(self.handler.lc.read().unwrap().enable_file_transfer);
let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst)
&& self.handler.lc.read().unwrap().enable_file_transfer;
ContextSend::enable(enabled);
}
}
#[cfg(windows)]
fn handle_cliprdr_msg(&self, clip: message_proto::Cliprdr) {
if !self.handler.lc.read().unwrap().disable_clipboard {
let mut lock = CLIPBOARD_FILE_CONTEXT.lock().unwrap();
if *lock != 0 {
unsafe {
let mut context =
Box::from_raw(*lock as *mut clipboard::cliprdr::CliprdrClientContext);
if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) {
clipboard::server_clip_file(&mut context, self.client_conn_id, clip);
}
*lock = Box::into_raw(context) as _;
}
if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) {
ContextSend::proc(|context: &mut Box<CliprdrClientContext>| -> u32 {
clipboard::server_clip_file(context, self.client_conn_id, clip)
});
}
}
}

View File

@ -53,11 +53,8 @@ fn check_connect_status(
) {
let status = Arc::new(Mutex::new((0, false, 0, "".to_owned())));
let options = Arc::new(Mutex::new(Config::get_options()));
let cloned = status.clone();
let cloned_options = options.clone();
let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>();
let password = Arc::new(Mutex::new(String::default()));
let cloned_password = password.clone();
std::thread::spawn(move || crate::ui_interface::check_connect_status_(reconnect, rx));
(status, options, tx, password)
}

View File

@ -11,9 +11,7 @@ use std::{
};
#[cfg(windows)]
use clipboard::empty_clipboard;
#[cfg(windows)]
use hbb_common::chrono::Duration;
use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, ContextSend};
use serde_derive::Serialize;
use crate::ipc::{self, new_listener, Connection, Data};
@ -56,7 +54,6 @@ pub struct Client {
struct IpcTaskRunner<T: InvokeUiCM> {
stream: Connection,
cm: ConnectionManager<T>,
tx_file: mpsc::UnboundedSender<ClipboardFileData>,
tx: mpsc::UnboundedSender<Data>,
rx: mpsc::UnboundedReceiver<Data>,
conn_id: i32,
@ -233,14 +230,31 @@ pub fn get_clients_length() -> usize {
clients.len()
}
#[derive(Debug)]
pub enum ClipboardFileData {
#[cfg(windows)]
Clip((i32, ipc::ClipbaordFile)),
Enable((i32, bool)),
}
impl<T: InvokeUiCM> IpcTaskRunner<T> {
#[cfg(windows)]
async fn enable_cliprdr_file_context(&mut self, conn_id: i32, enabled: bool) {
if conn_id == 0 {
return;
}
let pre_enabled = ContextSend::is_enabled();
ContextSend::enable(enabled);
if !pre_enabled && ContextSend::is_enabled() {
allow_err!(
self.stream
.send(&Data::ClipbaordFile(clipboard::ClipbaordFile::MonitorReady))
.await
);
}
clipboard::set_conn_enabled(conn_id, enabled);
if !enabled {
ContextSend::proc(|context: &mut Box<CliprdrClientContext>| -> u32 {
clipboard::empty_clipboard(context, conn_id);
0
});
}
}
async fn run(&mut self) {
use hbb_common::config::LocalConfig;
@ -251,10 +265,8 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
#[cfg(windows)]
if self.conn_id > 0 {
allow_err!(self.tx_file.send(ClipboardFileData::Enable((
self.conn_id,
self.file_transfer_enabled
))));
self.enable_cliprdr_file_context(self.conn_id, self.file_transfer_enabled)
.await;
}
#[cfg(windows)]
@ -297,13 +309,15 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
break;
}
Data::Close => {
allow_err!(self.tx_file.send(ClipboardFileData::Enable((self.conn_id, false))));
#[cfg(windows)]
self.enable_cliprdr_file_context(self.conn_id, false).await;
log::info!("cm ipc connection closed from connection request");
break;
}
Data::Disconnected => {
close = false;
allow_err!(self.tx_file.send(ClipboardFileData::Enable((self.conn_id, false))));
#[cfg(windows)]
self.enable_cliprdr_file_context(self.conn_id, false).await;
log::info!("cm ipc connection disconnect");
break;
}
@ -320,13 +334,20 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
Data::FS(fs) => {
handle_fs(fs, &mut write_jobs, &self.tx).await;
}
#[cfg(windows)]
Data::ClipbaordFile(_clip) => {
allow_err!(self.tx_file.send(ClipboardFileData::Clip((self.conn_id, _clip))));
#[cfg(windows)]
{
let conn_id = self.conn_id;
ContextSend::proc(|context: &mut Box<CliprdrClientContext>| -> u32 {
clipboard::server_clip_file(context, conn_id, _clip)
});
}
}
#[cfg(windows)]
Data::ClipboardFileEnabled(enabled) => {
allow_err!(self.tx_file.send(ClipboardFileData::Enable((self.conn_id, enabled))));
Data::ClipboardFileEnabled(_enabled) => {
#[cfg(windows)]
self.enable_cliprdr_file_context(self.conn_id, _enabled).await;
}
Data::Theme(dark) => {
self.cm.change_theme(dark);
@ -364,16 +385,11 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
}
}
async fn ipc_task(
stream: Connection,
cm: ConnectionManager<T>,
tx_file: mpsc::UnboundedSender<ClipboardFileData>,
) {
async fn ipc_task(stream: Connection, cm: ConnectionManager<T>) {
let (tx, rx) = mpsc::unbounded_channel::<Data>();
let mut task_runner = Self {
stream,
cm,
tx_file,
tx,
rx,
conn_id: 0,
@ -391,13 +407,6 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
#[tokio::main(flavor = "current_thread")]
pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
#[cfg(windows)]
let cm_clip = cm.clone();
let (tx_file, _rx_file) = mpsc::unbounded_channel::<ClipboardFileData>();
#[cfg(windows)]
std::thread::spawn(move || start_clipboard_file(_rx_file));
#[cfg(windows)]
std::thread::spawn(move || {
log::info!("try create privacy mode window");
@ -422,7 +431,6 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
tokio::spawn(IpcTaskRunner::<T>::ipc_task(
Connection::new(stream),
cm.clone(),
tx_file.clone(),
));
}
Err(err) => {
@ -723,47 +731,3 @@ fn send_raw(msg: Message, tx: &UnboundedSender<Data>) {
err => allow_err!(err),
}
}
#[cfg(windows)]
#[tokio::main(flavor = "current_thread")]
pub async fn start_clipboard_file(mut rx: mpsc::UnboundedReceiver<ClipboardFileData>) {
let mut cliprdr_context = None;
loop {
tokio::select! {
server_msg = rx.recv() => match server_msg {
Some(ClipboardFileData::Clip((conn_id, clip))) => {
if let Some(ctx) = cliprdr_context.as_mut() {
clipboard::server_clip_file(ctx, conn_id, clip);
}
}
Some(ClipboardFileData::Enable((id, enabled))) => {
if enabled && cliprdr_context.is_none() {
cliprdr_context = Some(match clipboard::create_cliprdr_context(true, false, clipboard::ProcessSide::ServerSide) {
Ok(context) => {
log::info!("clipboard context for file transfer created.");
context
}
Err(err) => {
log::error!(
"Create clipboard context for file transfer: {}",
err.to_string()
);
return;
}
});
}
clipboard::set_conn_enabled(id, enabled);
if !enabled {
if let Some(ctx) = cliprdr_context.as_mut() {
clipboard::empty_clipboard(ctx, id);
}
}
}
None => {
break
}
}
}
}
}

View File

@ -6,6 +6,7 @@ use crate::client::{
load_config, send_mouse, start_video_audio_threads, FileManager, Key, LoginConfigHandler,
QualityStatus, KEY_MAP, SERVER_KEYBOARD_ENABLED,
};
#[cfg(target_os = "linux")]
use crate::common::IS_X11;
use crate::{client::Data, client::Interface};
use async_trait::async_trait;
@ -812,6 +813,7 @@ impl<T: InvokeUiSession> Session<T> {
let keycode: u32 = keycode as u32;
let scancode: u32 = scancode as u32;
#[cfg(not(target_os = "windows"))]
let key = rdev::key_from_scancode(scancode) as RdevKey;
// Windows requires special handling
#[cfg(target_os = "windows")]