From 2faa5cfd18fb6a7e0f12fa83b06f36dc69c0c1b1 Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 25 Oct 2022 18:46:38 +0800 Subject: [PATCH 01/11] win_fix_multi_tab: refactor clipboard on windows, mid commit Signed-off-by: fufesou --- libs/clipboard/src/cliprdr.rs | 2 - libs/clipboard/src/lib.rs | 176 +++++++++++++----------- libs/clipboard/src/windows/wf_cliprdr.c | 15 +- libs/hbb_common/protos/message.proto | 8 -- 4 files changed, 110 insertions(+), 91 deletions(-) diff --git a/libs/clipboard/src/cliprdr.rs b/libs/clipboard/src/cliprdr.rs index 08d4021e8..f8d5d84b0 100644 --- a/libs/clipboard/src/cliprdr.rs +++ b/libs/clipboard/src/cliprdr.rs @@ -239,8 +239,6 @@ pub type CLIPRDR_FORMAT = _CLIPRDR_FORMAT; pub struct _CLIPRDR_FORMAT_LIST { pub connID: UINT32, pub msgType: UINT16, - pub msgFlags: UINT16, - pub dataLen: UINT32, pub numFormats: UINT32, pub formats: *mut CLIPRDR_FORMAT, } diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 7c6ccae0d..4d1632292 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -1,6 +1,6 @@ use cliprdr::*; use hbb_common::{ - log, + allow_err, log, tokio::sync::{ mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, Mutex as TokioMutex, @@ -12,7 +12,7 @@ use std::{ boxed::Box, collections::HashMap, ffi::{CStr, CString}, - sync::Mutex, + sync::{Arc, Mutex, RwLock}, }; pub mod cliprdr; @@ -20,25 +20,20 @@ pub mod cliprdr; #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "t", content = "c")] pub enum ClipbaordFile { - ServerFormatList { - conn_id: i32, + FormatList { format_list: Vec<(i32, String)>, }, - ServerFormatListResponse { - conn_id: i32, + FormatListResponse { msg_flags: i32, }, - ServerFormatDataRequest { - conn_id: i32, + FormatDataRequest { requested_format_id: i32, }, - ServerFormatDataResponse { - conn_id: i32, + FormatDataResponse { msg_flags: i32, format_data: Vec, }, FileContentsRequest { - conn_id: i32, stream_id: i32, list_index: i32, dw_flags: i32, @@ -49,7 +44,6 @@ pub enum ClipbaordFile { clip_data_id: i32, }, FileContentsResponse { - conn_id: i32, msg_flags: i32, stream_id: i32, requested_data: Vec, @@ -61,18 +55,76 @@ struct ConnEnabled { conn_enabled: HashMap, } -lazy_static::lazy_static! { - static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(i32, ClipbaordFile)>, TokioMutex>) = { - let (tx, rx) = unbounded_channel(); - (tx, TokioMutex::new(rx)) - }; +struct MsgChannel { + peer_id: String, + conn_id: i32, + sender: UnboundedSender, + receiver: Arc>>, +} +lazy_static::lazy_static! { + static ref VEC_MSG_CHANNEL: RwLock> = Default::default(); static ref CLIP_CONN_ENABLED: Mutex = Mutex::new(ConnEnabled::default()); } -#[inline(always)] -pub fn get_rx_clip_client<'a>() -> &'a TokioMutex> { - &MSG_CHANNEL_CLIENT.1 +#[inline] +pub async fn get_rx_cliprdr_client<'a>( + peer_id: &str, +) -> (i32, Arc>>) { + let mut lock = VEC_MSG_CHANNEL.write().unwrap(); + match lock.iter().find(|x| x.peer_id == peer_id.to_owned()) { + Some(msg_channel) => (msg_channel.conn_id, msg_channel.receiver.clone()), + None => { + let (sender, receiver) = unbounded_channel(); + let receiver = Arc::new(TokioMutex::new(receiver)); + let receiver2 = receiver.clone(); + let conn_id = lock.len() as i32 + 1; + let msg_channel = MsgChannel { + peer_id: peer_id.to_owned(), + conn_id, + sender, + receiver, + }; + lock.push(msg_channel); + (conn_id, receiver2) + } + } +} + +#[inline] +pub async fn get_rx_cliprdr_server<'a>( + conn_id: i32, +) -> Arc>> { + let mut lock = VEC_MSG_CHANNEL.write().unwrap(); + match lock.iter().find(|x| x.conn_id == conn_id) { + Some(msg_channel) => msg_channel.receiver.clone(), + None => { + let (sender, receiver) = unbounded_channel(); + let receiver = Arc::new(TokioMutex::new(receiver)); + let receiver2 = receiver.clone(); + let msg_channel = MsgChannel { + peer_id: "".to_owned(), + conn_id, + sender, + receiver, + }; + lock.push(msg_channel); + receiver2 + } + } +} + +#[inline] +fn send_data(conn_id: i32, data: ClipbaordFile) { + // no need to handle result here + if let Some(msg_channel) = VEC_MSG_CHANNEL + .read() + .unwrap() + .iter() + .find(|x| x.conn_id == conn_id) + { + allow_err!(msg_channel.sender.send(data)); + } } pub fn set_conn_enabled(conn_id: i32, enabled: bool) { @@ -88,61 +140,40 @@ pub fn empty_clipboard(context: &mut Box, conn_id: i32) -> pub fn server_clip_file( context: &mut Box, - s_conn_id: i32, + conn_id: i32, msg: ClipbaordFile, ) -> u32 { match msg { - ClipbaordFile::ServerFormatList { - mut conn_id, - format_list, - } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } + ClipbaordFile::FormatList { format_list } => { log::debug!("server_format_list called"); let ret = server_format_list(context, conn_id, format_list); log::debug!("server_format_list called, return {}", ret); ret } - ClipbaordFile::ServerFormatListResponse { - mut conn_id, - msg_flags, - } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } + ClipbaordFile::FormatListResponse { msg_flags } => { log::debug!("format_list_response called"); let ret = server_format_list_response(context, conn_id, msg_flags); log::debug!("server_format_list_response called, return {}", ret); ret } - ClipbaordFile::ServerFormatDataRequest { - mut conn_id, + ClipbaordFile::FormatDataRequest { requested_format_id, } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } log::debug!("format_data_request called"); let ret = server_format_data_request(context, conn_id, requested_format_id); log::debug!("server_format_data_request called, return {}", ret); ret } - ClipbaordFile::ServerFormatDataResponse { - mut conn_id, + ClipbaordFile::FormatDataResponse { msg_flags, format_data, } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } log::debug!("format_data_response called"); let ret = server_format_data_response(context, conn_id, msg_flags, format_data); log::debug!("server_format_data_response called, return {}", ret); ret } ClipbaordFile::FileContentsRequest { - mut conn_id, stream_id, list_index, dw_flags, @@ -152,9 +183,6 @@ pub fn server_clip_file( have_clip_data_id, clip_data_id, } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } log::debug!("file_contents_request called"); let ret = server_file_contents_request( context, @@ -172,14 +200,10 @@ pub fn server_clip_file( ret } ClipbaordFile::FileContentsResponse { - mut conn_id, msg_flags, stream_id, requested_data, } => { - if s_conn_id != 0 { - conn_id = s_conn_id as i32; - } log::debug!("file_contents_response called"); let ret = server_file_contents_response( context, @@ -225,8 +249,6 @@ pub fn server_format_list( let format_list = CLIPRDR_FORMAT_LIST { connID: conn_id as UINT32, msgType: 0 as UINT16, - msgFlags: 0 as UINT16, - dataLen: 0 as UINT32, numFormats: num_formats, formats: formats.as_mut_ptr(), }; @@ -243,6 +265,7 @@ pub fn server_format_list( ret as u32 } } + pub fn server_format_list_response( context: &mut Box, conn_id: i32, @@ -262,6 +285,7 @@ pub fn server_format_list_response( ret as u32 } } + pub fn server_format_data_request( context: &mut Box, conn_id: i32, @@ -280,6 +304,7 @@ pub fn server_format_data_request( ret as u32 } } + pub fn server_format_data_response( context: &mut Box, conn_id: i32, @@ -301,6 +326,7 @@ pub fn server_format_data_response( ret as u32 } } + pub fn server_file_contents_request( context: &mut Box, conn_id: i32, @@ -335,6 +361,7 @@ pub fn server_file_contents_request( ret as u32 } } + pub fn server_file_contents_response( context: &mut Box, conn_id: i32, @@ -398,7 +425,7 @@ extern "C" fn client_format_list( ) -> UINT { log::debug!("client_format_list called"); - let conn_id; + // let conn_id; let mut format_list: Vec<(i32, String)> = Vec::new(); unsafe { let mut i = 0u32; @@ -420,14 +447,15 @@ extern "C" fn client_format_list( // log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name); i += 1; } - conn_id = (*clip_format_list).connID as i32; + // conn_id = (*clip_format_list).connID as i32; } - let data = ClipbaordFile::ServerFormatList { - conn_id, - format_list, - }; + let data = ClipbaordFile::FormatList { format_list }; // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + VEC_MSG_CHANNEL + .read() + .unwrap() + .iter() + .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone()))); 0 } @@ -444,9 +472,8 @@ extern "C" fn client_format_list_response( conn_id = (*format_list_response).connID as i32; msg_flags = (*format_list_response).msgFlags as i32; } - let data = ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags }; - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + let data = ClipbaordFile::FormatListResponse { msg_flags }; + send_data(conn_id, data); 0 } @@ -463,12 +490,11 @@ extern "C" fn client_format_data_request( conn_id = (*format_data_request).connID as i32; requested_format_id = (*format_data_request).requestedFormatId as i32; } - let data = ClipbaordFile::ServerFormatDataRequest { - conn_id, + let data = ClipbaordFile::FormatDataRequest { requested_format_id, }; // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + send_data(conn_id, data); 0 } @@ -495,13 +521,11 @@ extern "C" fn client_format_data_response( .to_vec(); } } - let data = ClipbaordFile::ServerFormatDataResponse { - conn_id, + let data = ClipbaordFile::FormatDataResponse { msg_flags, format_data, }; - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + send_data(conn_id, data); 0 } @@ -544,7 +568,6 @@ extern "C" fn client_file_contents_request( } let data = ClipbaordFile::FileContentsRequest { - conn_id, stream_id, list_index, dw_flags, @@ -554,8 +577,7 @@ extern "C" fn client_file_contents_request( have_clip_data_id, clip_data_id, }; - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + send_data(conn_id, data); 0 } @@ -585,13 +607,11 @@ extern "C" fn client_file_contents_response( } } let data = ClipbaordFile::FileContentsResponse { - conn_id, msg_flags, stream_id, requested_data, }; - // no need to handle result here - MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); + send_data(conn_id, data); 0 } diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index f55eeb718..58c7a301e 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -193,6 +193,7 @@ struct _CliprdrDataObject ULONG m_nStreams; IStream **m_pStream; void *m_pData; + DWORD m_processID; UINT32 m_connID; }; typedef struct _CliprdrDataObject CliprdrDataObject; @@ -246,7 +247,7 @@ BOOL wf_cliprdr_init(wfClipboard *clipboard, CliprdrClientContext *cliprdr); BOOL wf_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr); BOOL wf_do_empty_cliprdr(wfClipboard *clipboard); -static BOOL wf_create_file_obj(UINT32 connID, wfClipboard *cliprdrrdr, IDataObject **ppDataObject); +static BOOL wf_create_file_obj(UINT32 *connID, wfClipboard *clipboard, IDataObject **ppDataObject); static void wf_destroy_file_obj(IDataObject *instance); static UINT32 get_remote_format_id(wfClipboard *clipboard, UINT32 local_format); static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UINT32 format); @@ -673,6 +674,12 @@ static HRESULT STDMETHODCALLTYPE CliprdrDataObject_GetData(IDataObject *This, FO if (!pFormatEtc || !pMedium || !instance) return E_INVALIDARG; + // Not the same process id + if (instance->m_processID != GetCurrentProcessId()) + { + return E_INVALIDARG; + } + clipboard = (wfClipboard *)instance->m_pData; if (!clipboard->context->CheckEnabled(instance->m_connID)) { @@ -892,6 +899,7 @@ static CliprdrDataObject *CliprdrDataObject_New(UINT32 connID, FORMATETC *fmtetc instance->m_pData = data; instance->m_nStreams = 0; instance->m_pStream = NULL; + instance->m_processID = GetCurrentProcessId(); instance->m_connID = connID; if (count > 0) @@ -966,7 +974,7 @@ static BOOL wf_create_file_obj(UINT32 *connID, wfClipboard *clipboard, IDataObje stgmeds[1].tymed = TYMED_ISTREAM; stgmeds[1].pstm = NULL; stgmeds[1].pUnkForRelease = NULL; - *ppDataObject = (IDataObject *)CliprdrDataObject_New(*connID, fmtetc, stgmeds, 2, clipboard); + *ppDataObject = (IDataObject *)CliprdrDataObject_New(*connID, *(connID + 1), fmtetc, stgmeds, 2, clipboard); return (*ppDataObject) ? TRUE : FALSE; } @@ -1669,7 +1677,8 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM DEBUG_CLIPRDR("info: WM_RENDERFORMAT"); // https://docs.microsoft.com/en-us/windows/win32/dataxchg/wm-renderformat?redirectedfrom=MSDN - if (cliprdr_send_data_request(0, 0, clipboard, (UINT32)wParam) != 0) + // to-do: ensure usage of 0 + if (cliprdr_send_data_request(0, clipboard, (UINT32)wParam) != 0) { DEBUG_CLIPRDR("error: cliprdr_send_data_request failed."); break; diff --git a/libs/hbb_common/protos/message.proto b/libs/hbb_common/protos/message.proto index 4bb015866..aaa02c327 100644 --- a/libs/hbb_common/protos/message.proto +++ b/libs/hbb_common/protos/message.proto @@ -360,38 +360,31 @@ message FileDirCreate { // main logic from freeRDP message CliprdrMonitorReady { - int32 conn_id = 1; } message CliprdrFormat { - int32 conn_id = 1; int32 id = 2; string format = 3; } message CliprdrServerFormatList { - int32 conn_id = 1; repeated CliprdrFormat formats = 2; } message CliprdrServerFormatListResponse { - int32 conn_id = 1; int32 msg_flags = 2; } message CliprdrServerFormatDataRequest { - int32 conn_id = 1; int32 requested_format_id = 2; } message CliprdrServerFormatDataResponse { - int32 conn_id = 1; int32 msg_flags = 2; bytes format_data = 3; } message CliprdrFileContentsRequest { - int32 conn_id = 1; int32 stream_id = 2; int32 list_index = 3; int32 dw_flags = 4; @@ -403,7 +396,6 @@ message CliprdrFileContentsRequest { } message CliprdrFileContentsResponse { - int32 conn_id = 1; int32 msg_flags = 3; int32 stream_id = 4; bytes requested_data = 5; From a49552d28bce0a5ee6a8abaa225450e4a11ef23f Mon Sep 17 00:00:00 2001 From: fufesou Date: Tue, 25 Oct 2022 22:07:29 +0800 Subject: [PATCH 02/11] win_fix_multi_tab: refactor clipboard on windows, mid commit2 Signed-off-by: fufesou --- libs/clipboard/src/lib.rs | 4 +- src/client/io_loop.rs | 17 ++- src/clipboard_file.rs | 58 +++----- src/flutter.rs | 2 +- src/ui/cm.rs | 5 - src/ui/remote.rs | 6 - src/ui_cm_interface.rs | 276 ++++++++++++++++++++++++-------------- 7 files changed, 208 insertions(+), 160 deletions(-) diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 4d1632292..9f9e7cda9 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -68,7 +68,7 @@ lazy_static::lazy_static! { } #[inline] -pub async fn get_rx_cliprdr_client<'a>( +pub fn get_rx_cliprdr_client<'a>( peer_id: &str, ) -> (i32, Arc>>) { let mut lock = VEC_MSG_CHANNEL.write().unwrap(); @@ -92,7 +92,7 @@ pub async fn get_rx_cliprdr_client<'a>( } #[inline] -pub async fn get_rx_cliprdr_server<'a>( +pub fn get_rx_cliprdr_server<'a>( conn_id: i32, ) -> Arc>> { let mut lock = VEC_MSG_CHANNEL.write().unwrap(); diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index a415576c8..d7a0995c8 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -44,6 +44,8 @@ pub struct Remote { first_frame: bool, #[cfg(windows)] clipboard_file_context: Option>, + #[cfg(windows)] + client_conn_id: i32, // used for clipboard data_count: Arc, frame_count: Arc, video_format: CodecFormat, @@ -73,6 +75,8 @@ impl Remote { first_frame: false, #[cfg(windows)] clipboard_file_context: None, + #[cfg(windows)] + client_conn_id: 0, data_count: Arc::new(AtomicUsize::new(0)), frame_count, video_format: CodecFormat::Unknown, @@ -107,7 +111,14 @@ impl Remote { #[cfg(not(windows))] let (_tx_holder, mut rx_clip_client) = mpsc::unbounded_channel::(); #[cfg(windows)] - let mut rx_clip_client = clipboard::get_rx_clip_client().lock().await; + let (client_conn_id, rx_clip_client1) = + clipboard::get_rx_cliprdr_client(&self.handler.id); + #[cfg(windows)] + let mut rx_clip_client = rx_clip_client1.lock().await; + #[cfg(windows)] + { + self.client_conn_id = client_conn_id; + } let mut status_timer = time::interval(Duration::new(1, 0)); @@ -152,7 +163,7 @@ impl Remote { _msg = rx_clip_client.recv() => { #[cfg(windows)] match _msg { - Some((_, clip)) => { + Some(clip) => { allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await); } None => { @@ -781,7 +792,7 @@ impl Remote { if !self.handler.lc.read().unwrap().disable_clipboard { if let Some(context) = &mut self.clipboard_file_context { if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) { - clipboard::server_clip_file(context, 0, clip); + clipboard::server_clip_file(context, self.client_conn_id, clip); } } } diff --git a/src/clipboard_file.rs b/src/clipboard_file.rs index b6c0513e8..6ae211eeb 100644 --- a/src/clipboard_file.rs +++ b/src/clipboard_file.rs @@ -3,14 +3,10 @@ use hbb_common::message_proto::*; pub fn clip_2_msg(clip: ClipbaordFile) -> Message { match clip { - ClipbaordFile::ServerFormatList { - conn_id, - format_list, - } => { + ClipbaordFile::FormatList { format_list } => { let mut formats: Vec = Vec::new(); for v in format_list.iter() { formats.push(CliprdrFormat { - conn_id: 0, id: v.0, format: v.1.clone(), ..Default::default() @@ -19,7 +15,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FormatList(CliprdrServerFormatList { - conn_id, formats, ..Default::default() })), @@ -28,11 +23,10 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { ..Default::default() } } - ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags } => Message { + ClipbaordFile::FormatListResponse { msg_flags } => Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FormatListResponse( CliprdrServerFormatListResponse { - conn_id, msg_flags, ..Default::default() }, @@ -41,14 +35,12 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { })), ..Default::default() }, - ClipbaordFile::ServerFormatDataRequest { - conn_id, + ClipbaordFile::FormatDataRequest { requested_format_id, } => Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FormatDataRequest( CliprdrServerFormatDataRequest { - conn_id, requested_format_id, ..Default::default() }, @@ -57,15 +49,13 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { })), ..Default::default() }, - ClipbaordFile::ServerFormatDataResponse { - conn_id, + ClipbaordFile::FormatDataResponse { msg_flags, format_data, } => Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FormatDataResponse( CliprdrServerFormatDataResponse { - conn_id, msg_flags, format_data: format_data.into(), ..Default::default() @@ -76,7 +66,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { ..Default::default() }, ClipbaordFile::FileContentsRequest { - conn_id, stream_id, list_index, dw_flags, @@ -89,7 +78,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FileContentsRequest( CliprdrFileContentsRequest { - conn_id, stream_id, list_index, dw_flags, @@ -106,7 +94,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { ..Default::default() }, ClipbaordFile::FileContentsResponse { - conn_id, msg_flags, stream_id, requested_data, @@ -114,7 +101,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { union: Some(message::Union::Cliprdr(Cliprdr { union: Some(cliprdr::Union::FileContentsResponse( CliprdrFileContentsResponse { - conn_id, msg_flags, stream_id, requested_data: requested_data.into(), @@ -135,33 +121,20 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option { for v in data.formats.iter() { format_list.push((v.id, v.format.clone())); } - Some(ClipbaordFile::ServerFormatList { - conn_id: data.conn_id, - format_list, - }) - } - Some(cliprdr::Union::FormatListResponse(data)) => { - Some(ClipbaordFile::ServerFormatListResponse { - conn_id: data.conn_id, - msg_flags: data.msg_flags, - }) - } - Some(cliprdr::Union::FormatDataRequest(data)) => { - Some(ClipbaordFile::ServerFormatDataRequest { - conn_id: data.conn_id, - requested_format_id: data.requested_format_id, - }) - } - Some(cliprdr::Union::FormatDataResponse(data)) => { - Some(ClipbaordFile::ServerFormatDataResponse { - conn_id: data.conn_id, - msg_flags: data.msg_flags, - format_data: data.format_data.into(), - }) + Some(ClipbaordFile::FormatList { format_list }) } + Some(cliprdr::Union::FormatListResponse(data)) => Some(ClipbaordFile::FormatListResponse { + msg_flags: data.msg_flags, + }), + Some(cliprdr::Union::FormatDataRequest(data)) => Some(ClipbaordFile::FormatDataRequest { + requested_format_id: data.requested_format_id, + }), + Some(cliprdr::Union::FormatDataResponse(data)) => Some(ClipbaordFile::FormatDataResponse { + msg_flags: data.msg_flags, + format_data: data.format_data.into(), + }), Some(cliprdr::Union::FileContentsRequest(data)) => { Some(ClipbaordFile::FileContentsRequest { - conn_id: data.conn_id, stream_id: data.stream_id, list_index: data.list_index, dw_flags: data.dw_flags, @@ -174,7 +147,6 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option { } Some(cliprdr::Union::FileContentsResponse(data)) => { Some(ClipbaordFile::FileContentsResponse { - conn_id: data.conn_id, msg_flags: data.msg_flags, stream_id: data.stream_id, requested_data: data.requested_data.into(), diff --git a/src/flutter.rs b/src/flutter.rs index 2b95f9cfb..c651c9fbe 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -22,7 +22,7 @@ pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer"; pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward"; lazy_static::lazy_static! { - pub static ref SESSIONS: RwLock>> = Default::default(); + pub static ref SESSIONS: RwLock>> = Default::default(); pub static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel } diff --git a/src/ui/cm.rs b/src/ui/cm.rs index e5a46817a..3472a184e 100644 --- a/src/ui/cm.rs +++ b/src/ui/cm.rs @@ -2,11 +2,6 @@ use crate::ipc::start_pa; use crate::ui_cm_interface::{start_ipc, ConnectionManager, InvokeUiCM}; -#[cfg(windows)] -use clipboard::{ - create_cliprdr_context, empty_clipboard, get_rx_clip_client, server_clip_file, set_conn_enabled, -}; - use hbb_common::{allow_err, log}; use sciter::{make_args, Element, Value, HELEMENT}; use std::sync::Mutex; diff --git a/src/ui/remote.rs b/src/ui/remote.rs index dfd6394a5..ce10827c4 100644 --- a/src/ui/remote.rs +++ b/src/ui/remote.rs @@ -14,12 +14,6 @@ use sciter::{ Value, }; -#[cfg(windows)] -use clipboard::{ - cliprdr::CliprdrClientContext, create_cliprdr_context as create_clipboard_file_context, - get_rx_clip_client, server_clip_file, -}; - use hbb_common::{ allow_err, fs::TransferJobMeta, log, message_proto::*, rendezvous_proto::ConnType, }; diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 96fb84b6d..886babe0f 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -8,6 +8,8 @@ use std::{ }, }; +use clipboard::empty_clipboard; +use hbb_common::chrono::Duration; use serde_derive::Serialize; use crate::ipc::Data; @@ -47,7 +49,7 @@ pub struct Client { } lazy_static::lazy_static! { - static ref CLIENTS: RwLock> = Default::default(); + static ref CLIENTS: RwLock> = Default::default(); static ref CLICK_TIME: AtomicI64 = AtomicI64::new(0); } @@ -215,22 +217,182 @@ pub fn get_clients_length() -> usize { clients.len() } +#[derive(Debug)] pub enum ClipboardFileData { #[cfg(windows)] - Clip((i32, ipc::ClipbaordFile)), + Clip(ipc::ClipbaordFile), Enable((i32, bool)), } +async fn cm_ipc_task_wait_login( + mut stream: Connection, + cm: ConnectionManager, + tx: mpsc::UnboundedSender, +) -> (Connection, ConnectionManager, Option<(i32, bool)>) { + let mut ret = None; + loop { + tokio::select! { + res = stream.next() => { + match res { + Err(err) => { + log::info!("cm ipc connection closed: {}", err); + break; + } + Ok(Some(data)) => { + match data { + Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled, restart, recording} => { + log::debug!("conn_id: {}", id); + cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, tx); + ret = Some((id, file_transfer_enabled)); + break; + } + Data::Close => { + log::info!("cm ipc connection closed from connection request"); + break; + } + Data::Disconnected => { + log::info!("cm ipc connection disconnect"); + break; + } + _ => { + + } + } + } + _ => {} + } + } + } + } + (stream, cm, ret) +} + +#[cfg(windows)] +fn create_cliprdr_context_(enabled: bool) -> Option> { + if enabled { + match clipboard::create_cliprdr_context(true, false) { + Ok(context) => { + log::info!("clipboard context for file transfer created."); + Some(context) + } + Err(err) => { + log::error!( + "Create clipboard context for file transfer: {}", + err.to_string() + ); + None + } + } + } else { + None + } +} + +async fn cm_ipc_task_loop( + mut stream: Connection, + cm: ConnectionManager, + tx: mpsc::UnboundedSender, + mut rx: mpsc::UnboundedReceiver, + mut conn_id: i32, + #[cfg(windows)] file_transfer_enabled: bool, +) { + use hbb_common::config::LocalConfig; + + // for tmp use, without real conn id + let conn_id_tmp = -1; + let mut write_jobs: Vec = Vec::new(); + let mut close = true; + + let (tx_file, _rx_file) = mpsc::unbounded_channel::(); + #[cfg(windows)] + std::thread::spawn(move || { + start_clipboard_file(conn_id, _rx_file); + }); + #[cfg(windows)] + allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, file_transfer_enabled)))); + + loop { + tokio::select! { + res = stream.next() => { + match res { + Err(err) => { + log::info!("cm ipc connection closed: {}", err); + break; + } + Ok(Some(data)) => { + match data { + Data::Close => { + allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, false)))); + log::info!("cm ipc connection closed from connection request"); + break; + } + Data::Disconnected => { + close = false; + allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, false)))); + log::info!("cm ipc connection disconnect"); + break; + } + Data::PrivacyModeState((id, _)) => { + conn_id = conn_id_tmp; + allow_err!(tx.send(data)); + } + Data::ClickTime(ms) => { + CLICK_TIME.store(ms, Ordering::SeqCst); + } + Data::ChatMessage { text } => { + cm.new_message(conn_id, text); + } + Data::FS(fs) => { + handle_fs(fs, &mut write_jobs, &tx).await; + } + #[cfg(windows)] + Data::ClipbaordFile(_clip) => { + allow_err!(tx_file.send(ClipboardFileData::Clip(_clip))); + } + #[cfg(windows)] + Data::ClipboardFileEnabled(enabled) => { + allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, enabled)))); + } + Data::Theme(dark) => { + cm.change_theme(dark); + } + Data::Language(lang) => { + LocalConfig::set_option("lang".to_owned(), lang); + cm.change_language(); + } + _ => { + + } + } + } + _ => {} + } + } + Some(data) = rx.recv() => { + if stream.send(&data).await.is_err() { + break; + } + } + } + } + if conn_id != conn_id_tmp { + cm.remove_connection(conn_id, close); + } +} + +async fn cm_ipc_task(stream: Connection, cm: ConnectionManager) { + let (tx, rx) = mpsc::unbounded_channel::(); + let (stream, cm, wait_res) = cm_ipc_task_wait_login(stream, cm, tx.clone()).await; + if let Some((conn_id, file_transfer_enabled)) = wait_res { + cm_ipc_task_loop(stream, cm, tx, rx, conn_id, file_transfer_enabled).await; + } +} + #[cfg(not(any(target_os = "android", target_os = "ios")))] #[tokio::main(flavor = "current_thread")] pub async fn start_ipc(cm: ConnectionManager) { - use hbb_common::config::LocalConfig; - - let (tx_file, _rx_file) = mpsc::unbounded_channel::(); #[cfg(windows)] let cm_clip = cm.clone(); - #[cfg(windows)] - std::thread::spawn(move || start_clipboard_file(cm_clip, _rx_file)); #[cfg(windows)] std::thread::spawn(move || { @@ -253,94 +415,7 @@ pub async fn start_ipc(cm: ConnectionManager) { match result { Ok(stream) => { log::debug!("Got new connection"); - let mut stream = Connection::new(stream); - let cm = cm.clone(); - let tx_file = tx_file.clone(); - tokio::spawn(async move { - // for tmp use, without real conn id - let conn_id_tmp = -1; - let mut conn_id: i32 = 0; - let (tx, mut rx) = mpsc::unbounded_channel::(); - let mut write_jobs: Vec = Vec::new(); - let mut close = true; - loop { - tokio::select! { - res = stream.next() => { - match res { - Err(err) => { - log::info!("cm ipc connection closed: {}", err); - break; - } - Ok(Some(data)) => { - match data { - Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled, restart, recording} => { - log::debug!("conn_id: {}", id); - conn_id = id; - tx_file.send(ClipboardFileData::Enable((id, file_transfer_enabled))).ok(); - cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, tx.clone()); - } - Data::Close => { - tx_file.send(ClipboardFileData::Enable((conn_id, false))).ok(); - log::info!("cm ipc connection closed from connection request"); - break; - } - Data::Disconnected => { - close = false; - tx_file.send(ClipboardFileData::Enable((conn_id, false))).ok(); - log::info!("cm ipc connection disconnect"); - break; - } - Data::PrivacyModeState((id, _)) => { - conn_id = conn_id_tmp; - allow_err!(tx.send(data)); - } - Data::ClickTime(ms) => { - CLICK_TIME.store(ms, Ordering::SeqCst); - } - Data::ChatMessage { text } => { - cm.new_message(conn_id, text); - } - Data::FS(fs) => { - handle_fs(fs, &mut write_jobs, &tx).await; - } - #[cfg(windows)] - Data::ClipbaordFile(_clip) => { - tx_file - .send(ClipboardFileData::Clip((conn_id, _clip))) - .ok(); - } - #[cfg(windows)] - Data::ClipboardFileEnabled(enabled) => { - tx_file - .send(ClipboardFileData::Enable((conn_id, enabled))) - .ok(); - } - Data::Theme(dark) => { - cm.change_theme(dark); - } - Data::Language(lang) => { - LocalConfig::set_option("lang".to_owned(), lang); - cm.change_language(); - } - _ => { - - } - } - } - _ => {} - } - } - Some(data) = rx.recv() => { - if stream.send(&data).await.is_err() { - break; - } - } - } - } - if conn_id != conn_id_tmp { - cm.remove_connection(conn_id, close); - } - }); + tokio::spawn(cm_ipc_task(Connection::new(stream), cm.clone())); } Err(err) => { log::error!("Couldn't get cm client: {:?}", err); @@ -643,17 +718,18 @@ fn send_raw(msg: Message, tx: &UnboundedSender) { #[cfg(windows)] #[tokio::main(flavor = "current_thread")] -pub async fn start_clipboard_file( - cm: ConnectionManager, +pub async fn start_clipboard_file( + conn_id: i32, mut rx: mpsc::UnboundedReceiver, ) { let mut cliprdr_context = None; - let mut rx_clip_client = clipboard::get_rx_clip_client().lock().await; + let rx_clip_client1 = clipboard::get_rx_cliprdr_server(conn_id); + let mut rx_clip_client = rx_clip_client1.lock().await; loop { tokio::select! { clip_file = rx_clip_client.recv() => match clip_file { - Some((conn_id, clip)) => { + Some(clip) => { cmd_inner_send( conn_id, Data::ClipbaordFile(clip) @@ -664,7 +740,7 @@ pub async fn start_clipboard_file( } }, server_msg = rx.recv() => match server_msg { - Some(ClipboardFileData::Clip((conn_id, clip))) => { + Some(ClipboardFileData::Clip(clip)) => { if let Some(ctx) = cliprdr_context.as_mut() { clipboard::server_clip_file(ctx, conn_id, clip); } From 007cdb1020ae3800cc368541faac12ab09ee3457 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 26 Oct 2022 10:28:06 +0800 Subject: [PATCH 03/11] win_fix_multi_tab: refactor clipboard on windows, mid commit3 Signed-off-by: fufesou --- src/client/io_loop.rs | 90 ++++++++++++++++++++++++--------------- src/ui_cm_interface.rs | 95 ++++++++++++++---------------------------- 2 files changed, 89 insertions(+), 96 deletions(-) diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index d7a0995c8..6f85f6076 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -22,13 +22,22 @@ use hbb_common::tokio::{ sync::mpsc, time::{self, Duration, Instant, Interval}, }; -use hbb_common::{allow_err, message_proto::*, sleep}; +use hbb_common::{ + allow_err, + message_proto::{self, *}, + sleep, +}; use hbb_common::{fs, log, Stream}; use std::collections::HashMap; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; +lazy_static::lazy_static! { + #[cfg(windows)] + static ref CLIPBOARD_FILE_CONTEXT: Mutex = Mutex::new(0); +} + pub struct Remote { handler: Session, video_sender: MediaSender, @@ -43,14 +52,42 @@ pub struct Remote { last_update_jobs_status: (Instant, HashMap), first_frame: bool, #[cfg(windows)] - clipboard_file_context: Option>, - #[cfg(windows)] client_conn_id: i32, // used for clipboard data_count: Arc, frame_count: Arc, 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) { + 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 Remote { pub fn new( handler: Session, @@ -74,8 +111,6 @@ impl Remote { last_update_jobs_status: (Instant::now(), Default::default()), first_frame: false, #[cfg(windows)] - clipboard_file_context: None, - #[cfg(windows)] client_conn_id: 0, data_count: Arc::new(AtomicUsize::new(0)), frame_count, @@ -789,13 +824,7 @@ impl Remote { } #[cfg(windows)] Some(message::Union::Cliprdr(clip)) => { - if !self.handler.lc.read().unwrap().disable_clipboard { - if let Some(context) = &mut self.clipboard_file_context { - if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) { - clipboard::server_clip_file(context, self.client_conn_id, clip); - } - } - } + self.handle_cliprdr_msg(clip); } Some(message::Union::FileResponse(fr)) => { match fr.union { @@ -1169,30 +1198,25 @@ impl Remote { true } - fn check_clipboard_file_context(&mut self) { + fn check_clipboard_file_context(&self) { #[cfg(windows)] { - let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst) - && self.handler.lc.read().unwrap().enable_file_transfer; - if enabled == self.clipboard_file_context.is_none() { - self.clipboard_file_context = if enabled { - match clipboard::create_cliprdr_context(true, false) { - Ok(context) => { - log::info!("clipboard context for file transfer created."); - Some(context) - } - Err(err) => { - log::error!( - "Create clipboard context for file transfer: {}", - err.to_string() - ); - None - } + check_clipboard_file_context(self.handler.lc.read().unwrap().enable_file_transfer); + } + } + + 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); } - } else { - log::info!("clipboard context for file transfer destroyed."); - None - }; + *lock = Box::into_raw(context) as _; + } } } } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 886babe0f..188398bb2 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -220,7 +220,7 @@ pub fn get_clients_length() -> usize { #[derive(Debug)] pub enum ClipboardFileData { #[cfg(windows)] - Clip(ipc::ClipbaordFile), + Clip((i32, ipc::ClipbaordFile)), Enable((i32, bool)), } @@ -267,30 +267,10 @@ async fn cm_ipc_task_wait_login( (stream, cm, ret) } -#[cfg(windows)] -fn create_cliprdr_context_(enabled: bool) -> Option> { - if enabled { - match clipboard::create_cliprdr_context(true, false) { - Ok(context) => { - log::info!("clipboard context for file transfer created."); - Some(context) - } - Err(err) => { - log::error!( - "Create clipboard context for file transfer: {}", - err.to_string() - ); - None - } - } - } else { - None - } -} - async fn cm_ipc_task_loop( mut stream: Connection, cm: ConnectionManager, + tx_file: mpsc::UnboundedSender, tx: mpsc::UnboundedSender, mut rx: mpsc::UnboundedReceiver, mut conn_id: i32, @@ -303,14 +283,14 @@ async fn cm_ipc_task_loop( let mut write_jobs: Vec = Vec::new(); let mut close = true; - let (tx_file, _rx_file) = mpsc::unbounded_channel::(); - #[cfg(windows)] - std::thread::spawn(move || { - start_clipboard_file(conn_id, _rx_file); - }); #[cfg(windows)] allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, file_transfer_enabled)))); + #[cfg(windows)] + let rx_clip_client1 = clipboard::get_rx_cliprdr_server(conn_id); + #[cfg(windows)] + let mut rx_clip_client = rx_clip_client1.lock().await; + loop { tokio::select! { res = stream.next() => { @@ -347,7 +327,7 @@ async fn cm_ipc_task_loop( } #[cfg(windows)] Data::ClipbaordFile(_clip) => { - allow_err!(tx_file.send(ClipboardFileData::Clip(_clip))); + allow_err!(tx_file.send(ClipboardFileData::Clip((conn_id, _clip)))); } #[cfg(windows)] Data::ClipboardFileEnabled(enabled) => { @@ -373,6 +353,14 @@ async fn cm_ipc_task_loop( break; } } + clip_file = rx_clip_client.recv() => match clip_file { + Some(clip) => { + allow_err!(tx.send(Data::ClipbaordFile(clip))); + } + None => { + // + } + }, } } if conn_id != conn_id_tmp { @@ -380,11 +368,15 @@ async fn cm_ipc_task_loop( } } -async fn cm_ipc_task(stream: Connection, cm: ConnectionManager) { +async fn cm_ipc_task( + stream: Connection, + cm: ConnectionManager, + tx_file: mpsc::UnboundedSender, +) { let (tx, rx) = mpsc::unbounded_channel::(); let (stream, cm, wait_res) = cm_ipc_task_wait_login(stream, cm, tx.clone()).await; if let Some((conn_id, file_transfer_enabled)) = wait_res { - cm_ipc_task_loop(stream, cm, tx, rx, conn_id, file_transfer_enabled).await; + cm_ipc_task_loop(stream, cm, tx_file, tx, rx, conn_id, file_transfer_enabled).await; } } @@ -394,6 +386,9 @@ pub async fn start_ipc(cm: ConnectionManager) { #[cfg(windows)] let cm_clip = cm.clone(); + let (tx_file, _rx_file) = mpsc::unbounded_channel::(); + std::thread::spawn(move || start_clipboard_file(_rx_file)); + #[cfg(windows)] std::thread::spawn(move || { log::info!("try create privacy mode window"); @@ -415,7 +410,11 @@ pub async fn start_ipc(cm: ConnectionManager) { match result { Ok(stream) => { log::debug!("Got new connection"); - tokio::spawn(cm_ipc_task(Connection::new(stream), cm.clone())); + tokio::spawn(cm_ipc_task( + Connection::new(stream), + cm.clone(), + tx_file.clone(), + )); } Err(err) => { log::error!("Couldn't get cm client: {:?}", err); @@ -718,29 +717,13 @@ fn send_raw(msg: Message, tx: &UnboundedSender) { #[cfg(windows)] #[tokio::main(flavor = "current_thread")] -pub async fn start_clipboard_file( - conn_id: i32, - mut rx: mpsc::UnboundedReceiver, -) { +pub async fn start_clipboard_file(mut rx: mpsc::UnboundedReceiver) { let mut cliprdr_context = None; - let rx_clip_client1 = clipboard::get_rx_cliprdr_server(conn_id); - let mut rx_clip_client = rx_clip_client1.lock().await; loop { tokio::select! { - clip_file = rx_clip_client.recv() => match clip_file { - Some(clip) => { - cmd_inner_send( - conn_id, - Data::ClipbaordFile(clip) - ); - } - None => { - // - } - }, server_msg = rx.recv() => match server_msg { - Some(ClipboardFileData::Clip(clip)) => { + Some(ClipboardFileData::Clip((conn_id, clip))) => { if let Some(ctx) = cliprdr_context.as_mut() { clipboard::server_clip_file(ctx, conn_id, clip); } @@ -775,17 +758,3 @@ pub async fn start_clipboard_file( } } } - -#[cfg(windows)] -fn cmd_inner_send(id: i32, data: Data) { - let lock = CLIENTS.read().unwrap(); - if id != 0 { - if let Some(s) = lock.get(&id) { - allow_err!(s.tx.send(data)); - } - } else { - for s in lock.values() { - allow_err!(s.tx.send(data.clone())); - } - } -} From c5c77808a5138212b83e42a56e21ec2195076e4e Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 26 Oct 2022 14:15:24 +0800 Subject: [PATCH 04/11] win_fix_multi_tab: refactor clipboard on windows, init debug done Signed-off-by: fufesou --- libs/clipboard/src/cliprdr.rs | 2 ++ libs/clipboard/src/lib.rs | 18 +++++++++++++++++- libs/clipboard/src/windows/wf_cliprdr.c | 18 +++++++++--------- src/client/io_loop.rs | 3 ++- src/ui_cm_interface.rs | 2 +- 5 files changed, 31 insertions(+), 12 deletions(-) diff --git a/libs/clipboard/src/cliprdr.rs b/libs/clipboard/src/cliprdr.rs index f8d5d84b0..08d4021e8 100644 --- a/libs/clipboard/src/cliprdr.rs +++ b/libs/clipboard/src/cliprdr.rs @@ -239,6 +239,8 @@ pub type CLIPRDR_FORMAT = _CLIPRDR_FORMAT; pub struct _CLIPRDR_FORMAT_LIST { pub connID: UINT32, pub msgType: UINT16, + pub msgFlags: UINT16, + pub dataLen: UINT32, pub numFormats: UINT32, pub formats: *mut CLIPRDR_FORMAT, } diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 9f9e7cda9..f4d3c9de1 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -62,9 +62,17 @@ struct MsgChannel { receiver: Arc>>, } +#[derive(PartialEq)] +pub enum ProcessSide { + UnknownSide, + ClientSide, + ServerSide, +} + lazy_static::lazy_static! { static ref VEC_MSG_CHANNEL: RwLock> = Default::default(); static ref CLIP_CONN_ENABLED: Mutex = Mutex::new(ConnEnabled::default()); + static ref PROCESS_SIDE: RwLock = RwLock::new(ProcessSide::UnknownSide); } #[inline] @@ -249,6 +257,8 @@ pub fn server_format_list( let format_list = CLIPRDR_FORMAT_LIST { connID: conn_id as UINT32, msgType: 0 as UINT16, + msgFlags: 0 as UINT16, + dataLen: 0 as UINT32, numFormats: num_formats, formats: formats.as_mut_ptr(), }; @@ -390,7 +400,10 @@ pub fn server_file_contents_response( pub fn create_cliprdr_context( enable_files: bool, enable_others: bool, + process_side: ProcessSide, ) -> ResultType> { + *PROCESS_SIDE.write().unwrap() = process_side; + Ok(CliprdrClientContext::create( enable_files, enable_others, @@ -405,8 +418,11 @@ pub fn create_cliprdr_context( } extern "C" fn check_enabled(conn_id: UINT32) -> BOOL { - let lock = CLIP_CONN_ENABLED.lock().unwrap(); + if *PROCESS_SIDE.read().unwrap() == ProcessSide::ClientSide { + return TRUE; + } + let lock = CLIP_CONN_ENABLED.lock().unwrap(); let mut connd_enabled = false; if conn_id != 0 { if let Some(true) = lock.conn_enabled.get(&(conn_id as i32)) { diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index 58c7a301e..9dcec737d 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -135,14 +135,14 @@ typedef struct _FORMAT_IDS FORMAT_IDS; #define TAG "windows" -#ifdef WITH_DEBUG_CLIPRDR -#define DEBUG_CLIPRDR(...) printf(TAG, __VA_ARGS__) -#else -#define DEBUG_CLIPRDR(...) \ - do \ - { \ - } while (0) -#endif +// #ifdef WITH_DEBUG_CLIPRDR +#define DEBUG_CLIPRDR(fmt, ...) fprintf(stderr, "DEBUG %s[%d] %s() " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__);fflush(stderr) +// #else +// #define DEBUG_CLIPRDR(fmt, ...) \ +// do \ +// { \ +// } while (0) +// #endif typedef BOOL(WINAPI *fnAddClipboardFormatListener)(HWND hwnd); typedef BOOL(WINAPI *fnRemoveClipboardFormatListener)(HWND hwnd); @@ -974,7 +974,7 @@ static BOOL wf_create_file_obj(UINT32 *connID, wfClipboard *clipboard, IDataObje stgmeds[1].tymed = TYMED_ISTREAM; stgmeds[1].pstm = NULL; stgmeds[1].pUnkForRelease = NULL; - *ppDataObject = (IDataObject *)CliprdrDataObject_New(*connID, *(connID + 1), fmtetc, stgmeds, 2, clipboard); + *ppDataObject = (IDataObject *)CliprdrDataObject_New(*connID, fmtetc, stgmeds, 2, clipboard); return (*ppDataObject) ? TRUE : FALSE; } diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 6f85f6076..bf30cfae1 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -64,7 +64,8 @@ fn check_clipboard_file_context(enable_file_transfer: bool) { let mut lock = CLIPBOARD_FILE_CONTEXT.lock().unwrap(); if enabled { if *lock == 0 { - match clipboard::create_cliprdr_context(true, false) { + 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 _; diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 188398bb2..26f3d636c 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -730,7 +730,7 @@ pub async fn start_clipboard_file(mut rx: mpsc::UnboundedReceiver { if enabled && cliprdr_context.is_none() { - cliprdr_context = Some(match clipboard::create_cliprdr_context(true, false) { + cliprdr_context = Some(match clipboard::create_cliprdr_context(true, false, clipboard::ProcessSide::ServerSide) { Ok(context) => { log::info!("clipboard context for file transfer created."); context From adf4f3eea484ade1773c5dbc1a2e99c61fd1c901 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 26 Oct 2022 19:42:14 +0800 Subject: [PATCH 05/11] win_fix_multi_tab: refactor clipboard on windows, monitor ready mid commit Signed-off-by: fufesou --- libs/clipboard/src/lib.rs | 38 +++- libs/clipboard/src/windows/wf_cliprdr.c | 17 +- src/clipboard_file.rs | 10 + src/flutter.rs | 11 + src/ui_cm_interface.rs | 290 ++++++++++++------------ 5 files changed, 209 insertions(+), 157 deletions(-) diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index f4d3c9de1..33547a6f2 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -20,6 +20,7 @@ pub mod cliprdr; #[derive(Debug, Serialize, Deserialize, Clone)] #[serde(tag = "t", content = "c")] pub enum ClipbaordFile { + MonitorReady, FormatList { format_list: Vec<(i32, String)>, }, @@ -152,6 +153,12 @@ pub fn server_clip_file( msg: ClipbaordFile, ) -> u32 { match msg { + ClipbaordFile::MonitorReady => { + log::debug!("server_monitor_ready called"); + let ret = server_monitor_ready(context, conn_id); + log::debug!("server_monitor_ready called, return {}", ret); + ret + } ClipbaordFile::FormatList { format_list } => { log::debug!("server_format_list called"); let ret = server_format_list(context, conn_id, format_list); @@ -226,6 +233,19 @@ pub fn server_clip_file( } } +pub fn server_monitor_ready(context: &mut Box, conn_id: i32) -> u32 { + unsafe { + let monitor_ready = CLIPRDR_MONITOR_READY { + connID: conn_id as UINT32, + msgType: 0 as UINT16, + msgFlags: 0 as UINT16, + dataLen: 0 as UINT32, + }; + let ret = ((**context).MonitorReady.unwrap())(&mut (**context), &monitor_ready); + ret as u32 + } +} + pub fn server_format_list( context: &mut Box, conn_id: i32, @@ -441,7 +461,7 @@ extern "C" fn client_format_list( ) -> UINT { log::debug!("client_format_list called"); - // let conn_id; + let conn_id; let mut format_list: Vec<(i32, String)> = Vec::new(); unsafe { let mut i = 0u32; @@ -463,15 +483,19 @@ extern "C" fn client_format_list( // log::debug!("format list item {}: format id: {}, format name: {}", i, format_data.formatId, &format_name); i += 1; } - // conn_id = (*clip_format_list).connID as i32; + conn_id = (*clip_format_list).connID as i32; } let data = ClipbaordFile::FormatList { format_list }; // no need to handle result here - VEC_MSG_CHANNEL - .read() - .unwrap() - .iter() - .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone()))); + if conn_id == 0 { + VEC_MSG_CHANNEL + .read() + .unwrap() + .iter() + .for_each(|msg_channel| allow_err!(msg_channel.sender.send(data.clone()))); + } else { + send_data(conn_id, data); + } 0 } diff --git a/libs/clipboard/src/windows/wf_cliprdr.c b/libs/clipboard/src/windows/wf_cliprdr.c index 9dcec737d..7374b27c1 100644 --- a/libs/clipboard/src/windows/wf_cliprdr.c +++ b/libs/clipboard/src/windows/wf_cliprdr.c @@ -1348,7 +1348,7 @@ static BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard *clipboard, PUINT lpu return TRUE; } -static UINT cliprdr_send_format_list(wfClipboard *clipboard) +static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID) { UINT rc; int count = 0; @@ -1423,7 +1423,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard) } } - formatList.connID = 0; + formatList.connID = connID; formatList.numFormats = numFormats; formatList.formats = formats; formatList.msgType = CB_FORMAT_LIST; @@ -1653,7 +1653,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM clipboard->hmem = NULL; } - cliprdr_send_format_list(clipboard); + cliprdr_send_format_list(clipboard, 0); } } @@ -1704,7 +1704,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM if ((GetClipboardOwner() != clipboard->hwnd) && (S_FALSE == OleIsCurrentClipboard(clipboard->data_obj))) { - cliprdr_send_format_list(clipboard); + cliprdr_send_format_list(clipboard, 0); } SendMessage(clipboard->hWndNextViewer, Msg, wParam, lParam); @@ -2137,9 +2137,14 @@ static UINT wf_cliprdr_send_client_capabilities(wfClipboard *clipboard) CLIPRDR_CAPABILITIES capabilities; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; - if (!clipboard || !clipboard->context || !clipboard->context->ClientCapabilities) + if (!clipboard || !clipboard->context) return ERROR_INTERNAL_ERROR; + // Ignore ClientCapabilities for now + if (!clipboard->context->ClientCapabilities) { + return CHANNEL_RC_OK; + } + capabilities.connID = 0; capabilities.cCapabilitiesSets = 1; capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET *)&(generalCapabilitySet); @@ -2171,7 +2176,7 @@ static UINT wf_cliprdr_monitor_ready(CliprdrClientContext *context, if (rc != CHANNEL_RC_OK) return rc; - return cliprdr_send_format_list(clipboard); + return cliprdr_send_format_list(clipboard, monitorReady->connID); } /** diff --git a/src/clipboard_file.rs b/src/clipboard_file.rs index 6ae211eeb..e6f40e215 100644 --- a/src/clipboard_file.rs +++ b/src/clipboard_file.rs @@ -3,6 +3,15 @@ use hbb_common::message_proto::*; pub fn clip_2_msg(clip: ClipbaordFile) -> Message { match clip { + ClipbaordFile::MonitorReady => Message { + union: Some(message::Union::Cliprdr(Cliprdr { + union: Some(cliprdr::Union::Ready(CliprdrMonitorReady { + ..Default::default() + })), + ..Default::default() + })), + ..Default::default() + }, ClipbaordFile::FormatList { format_list } => { let mut formats: Vec = Vec::new(); for v in format_list.iter() { @@ -116,6 +125,7 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message { pub fn msg_2_clip(msg: Cliprdr) -> Option { match msg.union { + Some(cliprdr::Union::Ready(_)) => Some(ClipbaordFile::MonitorReady), Some(cliprdr::Union::FormatList(data)) => { let mut format_list: Vec<(i32, String)> = Vec::new(); for v in data.formats.iter() { diff --git a/src/flutter.rs b/src/flutter.rs index c651c9fbe..d477b62d5 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -22,6 +22,7 @@ pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer"; pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward"; lazy_static::lazy_static! { + static ref CUR_SESSION_ID: RwLock = Default::default(); pub static ref SESSIONS: RwLock>> = Default::default(); pub static ref GLOBAL_EVENT_STREAM: RwLock>> = Default::default(); // rust to dart event channel } @@ -564,3 +565,13 @@ pub fn make_fd_flutter(id: i32, entries: &Vec, only_count: bool) -> S m.insert("total_size".into(), json!(n as f64)); serde_json::to_string(&m).unwrap_or("".into()) } + +pub fn get_cur_session_id() -> String { + *CUR_SESSION_ID.read().unwrap() +} + +pub fn set_cur_session_id(id: String) { + if get_cur_session_id() != id { + *CUR_SESSION_ID.write().unwrap() = id; + } +} diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 26f3d636c..0356a46a9 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -4,7 +4,7 @@ use std::{ iter::FromIterator, sync::{ atomic::{AtomicI64, Ordering}, - RwLock, + Arc, RwLock, }, }; @@ -24,7 +24,10 @@ use hbb_common::{ protobuf::Message as _, tokio::{ self, - sync::mpsc::{self, UnboundedSender}, + sync::{ + mpsc::{self, unbounded_channel, UnboundedSender}, + Mutex as TokioMutex, + }, task::spawn_blocking, }, }; @@ -48,6 +51,17 @@ pub struct Client { tx: UnboundedSender, } +struct IpcTaskRunner { + stream: Connection, + cm: ConnectionManager, + tx_file: mpsc::UnboundedSender, + tx: mpsc::UnboundedSender, + rx: mpsc::UnboundedReceiver, + conn_id: i32, + #[cfg(windows)] + file_transfer_enabled: bool, +} + lazy_static::lazy_static! { static ref CLIENTS: RwLock> = Default::default(); static ref CLICK_TIME: AtomicI64 = AtomicI64::new(0); @@ -224,159 +238,147 @@ pub enum ClipboardFileData { Enable((i32, bool)), } -async fn cm_ipc_task_wait_login( - mut stream: Connection, - cm: ConnectionManager, - tx: mpsc::UnboundedSender, -) -> (Connection, ConnectionManager, Option<(i32, bool)>) { - let mut ret = None; - loop { - tokio::select! { - res = stream.next() => { - match res { - Err(err) => { - log::info!("cm ipc connection closed: {}", err); - break; - } - Ok(Some(data)) => { - match data { - Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled, restart, recording} => { - log::debug!("conn_id: {}", id); - cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, tx); - ret = Some((id, file_transfer_enabled)); - break; - } - Data::Close => { - log::info!("cm ipc connection closed from connection request"); - break; - } - Data::Disconnected => { - log::info!("cm ipc connection disconnect"); - break; - } - _ => { +impl IpcTaskRunner { + async fn run(&mut self) { + use hbb_common::config::LocalConfig; + // for tmp use, without real conn id + let conn_id_tmp = -1; + let mut write_jobs: Vec = Vec::new(); + let mut close = true; + + #[cfg(windows)] + if self.conn_id > 0 { + allow_err!(self.tx_file.send(ClipboardFileData::Enable(( + self.conn_id, + self.file_transfer_enabled + )))); + } + + #[cfg(windows)] + let rx_clip1; + let mut rx_clip; + let _tx_clip; + #[cfg(windows)] + if self.conn_id > 0 { + rx_clip1 = clipboard::get_rx_cliprdr_server(self.conn_id); + rx_clip = rx_clip1.lock().await; + } else { + let rx_clip2; + (_tx_clip, rx_clip2) = unbounded_channel::(); + rx_clip1 = Arc::new(TokioMutex::new(rx_clip2)); + rx_clip = rx_clip1.lock().await; + } + + loop { + tokio::select! { + res = self.stream.next() => { + match res { + Err(err) => { + log::info!("cm ipc connection closed: {}", err); + break; + } + Ok(Some(data)) => { + match data { + Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled, restart, recording} => { + log::debug!("conn_id: {}", id); + self.cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, self.tx.clone()); + self.conn_id = id; + #[cfg(windows)] + { + self.file_transfer_enabled = file_transfer_enabled; + } + break; + } + Data::Close => { + allow_err!(self.tx_file.send(ClipboardFileData::Enable((self.conn_id, false)))); + 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)))); + log::info!("cm ipc connection disconnect"); + break; + } + Data::PrivacyModeState((id, _)) => { + self.conn_id = conn_id_tmp; + allow_err!(self.tx.send(data)); + } + Data::ClickTime(ms) => { + CLICK_TIME.store(ms, Ordering::SeqCst); + } + Data::ChatMessage { text } => { + self.cm.new_message(self.conn_id, text); + } + 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)] + Data::ClipboardFileEnabled(enabled) => { + allow_err!(self.tx_file.send(ClipboardFileData::Enable((self.conn_id, enabled)))); + } + Data::Theme(dark) => { + self.cm.change_theme(dark); + } + Data::Language(lang) => { + LocalConfig::set_option("lang".to_owned(), lang); + self.cm.change_language(); + } + _ => { + + } } } + _ => {} } - _ => {} } - } - } - } - (stream, cm, ret) -} - -async fn cm_ipc_task_loop( - mut stream: Connection, - cm: ConnectionManager, - tx_file: mpsc::UnboundedSender, - tx: mpsc::UnboundedSender, - mut rx: mpsc::UnboundedReceiver, - mut conn_id: i32, - #[cfg(windows)] file_transfer_enabled: bool, -) { - use hbb_common::config::LocalConfig; - - // for tmp use, without real conn id - let conn_id_tmp = -1; - let mut write_jobs: Vec = Vec::new(); - let mut close = true; - - #[cfg(windows)] - allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, file_transfer_enabled)))); - - #[cfg(windows)] - let rx_clip_client1 = clipboard::get_rx_cliprdr_server(conn_id); - #[cfg(windows)] - let mut rx_clip_client = rx_clip_client1.lock().await; - - loop { - tokio::select! { - res = stream.next() => { - match res { - Err(err) => { - log::info!("cm ipc connection closed: {}", err); + Some(data) = self.rx.recv() => { + if self.stream.send(&data).await.is_err() { break; } - Ok(Some(data)) => { - match data { - Data::Close => { - allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, false)))); - log::info!("cm ipc connection closed from connection request"); - break; - } - Data::Disconnected => { - close = false; - allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, false)))); - log::info!("cm ipc connection disconnect"); - break; - } - Data::PrivacyModeState((id, _)) => { - conn_id = conn_id_tmp; - allow_err!(tx.send(data)); - } - Data::ClickTime(ms) => { - CLICK_TIME.store(ms, Ordering::SeqCst); - } - Data::ChatMessage { text } => { - cm.new_message(conn_id, text); - } - Data::FS(fs) => { - handle_fs(fs, &mut write_jobs, &tx).await; - } - #[cfg(windows)] - Data::ClipbaordFile(_clip) => { - allow_err!(tx_file.send(ClipboardFileData::Clip((conn_id, _clip)))); - } - #[cfg(windows)] - Data::ClipboardFileEnabled(enabled) => { - allow_err!(tx_file.send(ClipboardFileData::Enable((conn_id, enabled)))); - } - Data::Theme(dark) => { - cm.change_theme(dark); - } - Data::Language(lang) => { - LocalConfig::set_option("lang".to_owned(), lang); - cm.change_language(); - } - _ => { - - } - } + } + clip_file = rx_clip.recv() => match clip_file { + Some(clip) => { + #[cfg(windows)] + allow_err!(self.tx.send(Data::ClipbaordFile(clip))); } - _ => {} - } + None => { + // + } + }, } - Some(data) = rx.recv() => { - if stream.send(&data).await.is_err() { - break; - } - } - clip_file = rx_clip_client.recv() => match clip_file { - Some(clip) => { - allow_err!(tx.send(Data::ClipbaordFile(clip))); - } - None => { - // - } - }, + } + if self.conn_id != 0 && self.conn_id != conn_id_tmp { + self.cm.remove_connection(self.conn_id, close); } } - if conn_id != conn_id_tmp { - cm.remove_connection(conn_id, close); - } -} -async fn cm_ipc_task( - stream: Connection, - cm: ConnectionManager, - tx_file: mpsc::UnboundedSender, -) { - let (tx, rx) = mpsc::unbounded_channel::(); - let (stream, cm, wait_res) = cm_ipc_task_wait_login(stream, cm, tx.clone()).await; - if let Some((conn_id, file_transfer_enabled)) = wait_res { - cm_ipc_task_loop(stream, cm, tx_file, tx, rx, conn_id, file_transfer_enabled).await; + async fn ipc_task( + stream: Connection, + cm: ConnectionManager, + tx_file: mpsc::UnboundedSender, + ) { + let (tx, rx) = mpsc::unbounded_channel::(); + let mut task_runner = Self { + stream, + cm, + tx_file, + tx, + rx, + conn_id: 0, + #[cfg(windows)] + file_transfer_enabled: false, + }; + + task_runner.run().await; + if task_runner.conn_id > 0 { + task_runner.run().await; + } } } @@ -410,7 +412,7 @@ pub async fn start_ipc(cm: ConnectionManager) { match result { Ok(stream) => { log::debug!("Got new connection"); - tokio::spawn(cm_ipc_task( + tokio::spawn(IpcTaskRunner::::ipc_task( Connection::new(stream), cm.clone(), tx_file.clone(), From a9602f95edbc3d5733bba139fdc2657a0c3c616b Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 26 Oct 2022 06:40:22 -0700 Subject: [PATCH 06/11] win_fix_multi_tab: build linux Signed-off-by: fufesou --- src/client/io_loop.rs | 3 ++- src/ui.rs | 22 +++++++++++----------- src/ui_cm_interface.rs | 33 ++++++++++++++++++++------------- src/ui_interface.rs | 4 ++-- 4 files changed, 35 insertions(+), 27 deletions(-) diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index bf30cfae1..5ab6e3d85 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -33,8 +33,8 @@ use std::collections::HashMap; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Mutex}; +#[cfg(windows)] lazy_static::lazy_static! { - #[cfg(windows)] static ref CLIPBOARD_FILE_CONTEXT: Mutex = Mutex::new(0); } @@ -1206,6 +1206,7 @@ impl Remote { } } + #[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(); diff --git a/src/ui.rs b/src/ui.rs index 63dc4704a..6a9837a59 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -514,17 +514,17 @@ impl UI { } fn get_lan_peers(&self) -> String { - let peers = get_lan_peers() - .into_iter() - .map(|mut peer| { - ( - peer.remove("id").unwrap_or_default(), - peer.remove("username").unwrap_or_default(), - peer.remove("hostname").unwrap_or_default(), - peer.remove("platform").unwrap_or_default(), - ) - }) - .collect::>(); + // let peers = get_lan_peers() + // .into_iter() + // .map(|mut peer| { + // ( + // peer.remove("id").unwrap_or_default(), + // peer.remove("username").unwrap_or_default(), + // peer.remove("hostname").unwrap_or_default(), + // peer.remove("platform").unwrap_or_default(), + // ) + // }) + // .collect::>(); serde_json::to_string(&get_lan_peers()).unwrap_or_default() } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 0356a46a9..79152abe6 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -1,19 +1,24 @@ -use std::ops::{Deref, DerefMut}; +#[cfg(windows)] +use std::sync::Arc; use std::{ collections::HashMap, iter::FromIterator, + ops::{Deref, DerefMut}, sync::{ atomic::{AtomicI64, Ordering}, - Arc, RwLock, + RwLock, }, }; +#[cfg(windows)] use clipboard::empty_clipboard; +#[cfg(windows)] use hbb_common::chrono::Duration; use serde_derive::Serialize; -use crate::ipc::Data; -use crate::ipc::{self, new_listener, Connection}; +use crate::ipc::{self, new_listener, Connection, Data}; +#[cfg(windows)] +use hbb_common::tokio::sync::Mutex as TokioMutex; use hbb_common::{ allow_err, config::Config, @@ -24,10 +29,7 @@ use hbb_common::{ protobuf::Message as _, tokio::{ self, - sync::{ - mpsc::{self, unbounded_channel, UnboundedSender}, - Mutex as TokioMutex, - }, + sync::mpsc::{self, unbounded_channel, UnboundedSender}, task::spawn_blocking, }, }; @@ -269,6 +271,10 @@ impl IpcTaskRunner { rx_clip1 = Arc::new(TokioMutex::new(rx_clip2)); rx_clip = rx_clip1.lock().await; } + #[cfg(not(windows))] + { + (_tx_clip, rx_clip) = unbounded_channel::(); + } loop { tokio::select! { @@ -280,13 +286,13 @@ impl IpcTaskRunner { } Ok(Some(data)) => { match data { - Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled, restart, recording} => { + Data::Login{id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, file_transfer_enabled: _file_transfer_enabled, restart, recording} => { log::debug!("conn_id: {}", id); self.cm.add_connection(id, is_file_transfer, port_forward, peer_id, name, authorized, keyboard, clipboard, audio, file, restart, recording, self.tx.clone()); self.conn_id = id; #[cfg(windows)] { - self.file_transfer_enabled = file_transfer_enabled; + self.file_transfer_enabled = _file_transfer_enabled; } break; } @@ -301,7 +307,7 @@ impl IpcTaskRunner { log::info!("cm ipc connection disconnect"); break; } - Data::PrivacyModeState((id, _)) => { + Data::PrivacyModeState(_) => { self.conn_id = conn_id_tmp; allow_err!(self.tx.send(data)); } @@ -343,9 +349,9 @@ impl IpcTaskRunner { } } clip_file = rx_clip.recv() => match clip_file { - Some(clip) => { + Some(_clip) => { #[cfg(windows)] - allow_err!(self.tx.send(Data::ClipbaordFile(clip))); + allow_err!(self.tx.send(Data::ClipbaordFile(_clip))); } None => { // @@ -389,6 +395,7 @@ pub async fn start_ipc(cm: ConnectionManager) { let cm_clip = cm.clone(); let (tx_file, _rx_file) = mpsc::unbounded_channel::(); + #[cfg(windows)] std::thread::spawn(move || start_clipboard_file(_rx_file)); #[cfg(windows)] diff --git a/src/ui_interface.rs b/src/ui_interface.rs index 142c9cb43..0f7db9a1d 100644 --- a/src/ui_interface.rs +++ b/src/ui_interface.rs @@ -76,11 +76,11 @@ pub fn goto_install() { } #[inline] -pub fn install_me(_options: String, _path: String, silent: bool, debug: bool) { +pub fn install_me(_options: String, _path: String, _silent: bool, _debug: bool) { #[cfg(windows)] std::thread::spawn(move || { allow_err!(crate::platform::windows::install_me( - &_options, _path, silent, debug + &_options, _path, _silent, _debug )); std::process::exit(0); }); From c87e7f1e287021ccddf2208e6c229ceb9de8be5d Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 26 Oct 2022 22:37:45 +0800 Subject: [PATCH 07/11] win_fix_multi_tab: send monitor ready on clipboard is ready Signed-off-by: fufesou --- libs/clipboard/src/context_send.rs | 60 ++++++++++++++ libs/clipboard/src/lib.rs | 2 + src/client/io_loop.rs | 57 +++----------- src/ui.rs | 3 - src/ui_cm_interface.rs | 122 ++++++++++------------------- src/ui_session_interface.rs | 2 + 6 files changed, 117 insertions(+), 129 deletions(-) create mode 100644 libs/clipboard/src/context_send.rs diff --git a/libs/clipboard/src/context_send.rs b/libs/clipboard/src/context_send.rs new file mode 100644 index 000000000..869e8a11b --- /dev/null +++ b/libs/clipboard/src/context_send.rs @@ -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, +} + +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) -> 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 + } + } +} diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index 33547a6f2..fa65adc37 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -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")] diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 5ab6e3d85..662addea5 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -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 = Mutex::new(0); -} - pub struct Remote { handler: Session, video_sender: MediaSender, @@ -58,37 +56,6 @@ pub struct Remote { 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 Remote { pub fn new( handler: Session, @@ -1202,23 +1169,19 @@ impl Remote { 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| -> u32 { + clipboard::server_clip_file(context, self.client_conn_id, clip) + }); } } } diff --git a/src/ui.rs b/src/ui.rs index 6a9837a59..548bfad43 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -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::(); 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) } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 79152abe6..9c45ad269 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -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 { stream: Connection, cm: ConnectionManager, - tx_file: mpsc::UnboundedSender, tx: mpsc::UnboundedSender, rx: mpsc::UnboundedReceiver, 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 IpcTaskRunner { + #[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| -> u32 { + clipboard::empty_clipboard(context, conn_id); + 0 + }); + } + } + async fn run(&mut self) { use hbb_common::config::LocalConfig; @@ -251,10 +265,8 @@ impl IpcTaskRunner { #[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 IpcTaskRunner { 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 IpcTaskRunner { 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| -> 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 IpcTaskRunner { } } - async fn ipc_task( - stream: Connection, - cm: ConnectionManager, - tx_file: mpsc::UnboundedSender, - ) { + async fn ipc_task(stream: Connection, cm: ConnectionManager) { let (tx, rx) = mpsc::unbounded_channel::(); let mut task_runner = Self { stream, cm, - tx_file, tx, rx, conn_id: 0, @@ -391,13 +407,6 @@ impl IpcTaskRunner { #[cfg(not(any(target_os = "android", target_os = "ios")))] #[tokio::main(flavor = "current_thread")] pub async fn start_ipc(cm: ConnectionManager) { - #[cfg(windows)] - let cm_clip = cm.clone(); - - let (tx_file, _rx_file) = mpsc::unbounded_channel::(); - #[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(cm: ConnectionManager) { tokio::spawn(IpcTaskRunner::::ipc_task( Connection::new(stream), cm.clone(), - tx_file.clone(), )); } Err(err) => { @@ -723,47 +731,3 @@ fn send_raw(msg: Message, tx: &UnboundedSender) { err => allow_err!(err), } } - -#[cfg(windows)] -#[tokio::main(flavor = "current_thread")] -pub async fn start_clipboard_file(mut rx: mpsc::UnboundedReceiver) { - 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 - } - } - } - } -} diff --git a/src/ui_session_interface.rs b/src/ui_session_interface.rs index f95a743c2..a085e9822 100644 --- a/src/ui_session_interface.rs +++ b/src/ui_session_interface.rs @@ -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 Session { 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")] From 702c81cafe6cb0518b4320860d0c2b738a94a327 Mon Sep 17 00:00:00 2001 From: fufesou Date: Wed, 26 Oct 2022 07:43:54 -0700 Subject: [PATCH 08/11] win_fix_multi_tab: linux build Signed-off-by: fufesou --- libs/clipboard/src/context_send.rs | 1 - src/server/wayland.rs | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/libs/clipboard/src/context_send.rs b/libs/clipboard/src/context_send.rs index 869e8a11b..b19270a37 100644 --- a/libs/clipboard/src/context_send.rs +++ b/libs/clipboard/src/context_send.rs @@ -2,7 +2,6 @@ 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)}; } diff --git a/src/server/wayland.rs b/src/server/wayland.rs index 8cf1623c5..de304c459 100644 --- a/src/server/wayland.rs +++ b/src/server/wayland.rs @@ -249,8 +249,8 @@ pub(super) fn release_resouce() { if *write_lock != 0 { let cap_display_info: *mut CapDisplayInfo = *write_lock as _; unsafe { - let box_capturer = Box::from_raw((*cap_display_info).capturer.0); - let box_cap_display_info = Box::from_raw(cap_display_info); + let _box_capturer = Box::from_raw((*cap_display_info).capturer.0); + let _box_cap_display_info = Box::from_raw(cap_display_info); *write_lock = 0; } } From db99eccbe0268fa8045f92be10c14e2cdc29a1b2 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 27 Oct 2022 10:56:14 +0800 Subject: [PATCH 09/11] win_fix_multi_tab: win clipboard refactor Signed-off-by: fufesou --- .../desktop/pages/file_manager_tab_page.dart | 2 +- .../desktop/pages/port_forward_tab_page.dart | 2 +- .../lib/desktop/pages/remote_tab_page.dart | 9 ++++-- flutter/lib/desktop/pages/server_page.dart | 4 +-- .../lib/desktop/widgets/tabbar_widget.dart | 14 +++++---- libs/clipboard/src/lib.rs | 17 +++++++---- src/client/io_loop.rs | 10 +++++++ src/flutter.rs | 2 +- src/flutter_ffi.rs | 4 +++ src/ui_cm_interface.rs | 29 ++++++++++++++----- 10 files changed, 66 insertions(+), 27 deletions(-) diff --git a/flutter/lib/desktop/pages/file_manager_tab_page.dart b/flutter/lib/desktop/pages/file_manager_tab_page.dart index 68ad2529c..5dd0629fb 100644 --- a/flutter/lib/desktop/pages/file_manager_tab_page.dart +++ b/flutter/lib/desktop/pages/file_manager_tab_page.dart @@ -43,7 +43,7 @@ class _FileManagerTabPageState extends State { void initState() { super.initState(); - tabController.onRemove = (_, id) => onRemoveId(id); + tabController.onRemoved = (_, id) => onRemoveId(id); rustDeskWinManager.setMethodHandler((call, fromWindowId) async { print( diff --git a/flutter/lib/desktop/pages/port_forward_tab_page.dart b/flutter/lib/desktop/pages/port_forward_tab_page.dart index 6d7390493..de3ba0d92 100644 --- a/flutter/lib/desktop/pages/port_forward_tab_page.dart +++ b/flutter/lib/desktop/pages/port_forward_tab_page.dart @@ -46,7 +46,7 @@ class _PortForwardTabPageState extends State { void initState() { super.initState(); - tabController.onRemove = (_, id) => onRemoveId(id); + tabController.onRemoved = (_, id) => onRemoveId(id); rustDeskWinManager.setMethodHandler((call, fromWindowId) async { debugPrint( diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index b73dacec2..b3ebb5497 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -59,11 +59,12 @@ class _ConnectionTabPageState extends State { void initState() { super.initState(); - tabController.onRemove = (_, id) => onRemoveId(id); + tabController.onRemoved = (_, id) => onRemoveId(id); + tabController.onSelected = (_, id) => onSelectId(id); rustDeskWinManager.setMethodHandler((call, fromWindowId) async { print( - "call ${call.method} with args ${call.arguments} from window ${fromWindowId}"); + "call ${call.method} with args ${call.arguments} from window $fromWindowId"); final RxBool fullscreen = Get.find(tag: 'fullscreen'); // for simplify, just replace connectionId @@ -174,6 +175,10 @@ class _ConnectionTabPageState extends State { _update_remote_count(); } + void onSelectId(String id) { + bind.setCurSessionId(id: id); + } + int windowId() { return widget.params["windowId"]; } diff --git a/flutter/lib/desktop/pages/server_page.dart b/flutter/lib/desktop/pages/server_page.dart index 2211a0b0d..d04f7871f 100644 --- a/flutter/lib/desktop/pages/server_page.dart +++ b/flutter/lib/desktop/pages/server_page.dart @@ -30,7 +30,7 @@ class _DesktopServerPageState extends State void initState() { gFFI.ffiModel.updateEventListener(""); windowManager.addListener(this); - tabController.onRemove = (_, id) => onRemoveId(id); + tabController.onRemoved = (_, id) => onRemoveId(id); super.initState(); } @@ -99,7 +99,7 @@ class ConnectionManagerState extends State { @override void initState() { gFFI.serverModel.updateClientState(); - gFFI.serverModel.tabController.onSelected = (index) => + gFFI.serverModel.tabController.onSelected = (index, _) => gFFI.chatModel.changeCurrentID(gFFI.serverModel.clients[index].id); super.initState(); } diff --git a/flutter/lib/desktop/widgets/tabbar_widget.dart b/flutter/lib/desktop/widgets/tabbar_widget.dart index 92c868c34..7fae47e69 100644 --- a/flutter/lib/desktop/widgets/tabbar_widget.dart +++ b/flutter/lib/desktop/widgets/tabbar_widget.dart @@ -70,10 +70,11 @@ class DesktopTabController { final DesktopTabType tabType; /// index, key - Function(int, String)? onRemove; - Function(int)? onSelected; + Function(int, String)? onRemoved; + Function(int, String)? onSelected; - DesktopTabController({required this.tabType}); + DesktopTabController( + {required this.tabType, this.onRemoved, this.onSelected}); int get length => state.value.tabs.length; @@ -114,7 +115,7 @@ class DesktopTabController { state.value.tabs.removeAt(index); state.value.scrollController.itemCount = state.value.tabs.length; jumpTo(toIndex); - onRemove?.call(index, key); + onRemoved?.call(index, key); } void jumpTo(int index) { @@ -134,7 +135,8 @@ class DesktopTabController { })); }); if (state.value.tabs.length > index) { - onSelected?.call(index); + final key = state.value.tabs[index].key; + onSelected?.call(index, key); } } @@ -146,7 +148,7 @@ class DesktopTabController { void closeBy(String? key) { if (!isDesktop) return; - assert(onRemove != null); + assert(onRemoved != null); if (key == null) { if (state.value.selected < state.value.tabs.length) { remove(state.value.selected); diff --git a/libs/clipboard/src/lib.rs b/libs/clipboard/src/lib.rs index fa65adc37..b992e39e3 100644 --- a/libs/clipboard/src/lib.rs +++ b/libs/clipboard/src/lib.rs @@ -78,8 +78,16 @@ lazy_static::lazy_static! { static ref PROCESS_SIDE: RwLock = RwLock::new(ProcessSide::UnknownSide); } -#[inline] -pub fn get_rx_cliprdr_client<'a>( +pub fn get_client_conn_id(peer_id: &str) -> Option { + VEC_MSG_CHANNEL + .read() + .unwrap() + .iter() + .find(|x| x.peer_id == peer_id.to_owned()) + .map(|x| x.conn_id) +} + +pub fn get_rx_cliprdr_client( peer_id: &str, ) -> (i32, Arc>>) { let mut lock = VEC_MSG_CHANNEL.write().unwrap(); @@ -102,10 +110,7 @@ pub fn get_rx_cliprdr_client<'a>( } } -#[inline] -pub fn get_rx_cliprdr_server<'a>( - conn_id: i32, -) -> Arc>> { +pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc>> { let mut lock = VEC_MSG_CHANNEL.write().unwrap(); match lock.iter().find(|x| x.conn_id == conn_id) { Some(msg_channel) => msg_channel.receiver.clone(), diff --git a/src/client/io_loop.rs b/src/client/io_loop.rs index 662addea5..b108c1ad0 100644 --- a/src/client/io_loop.rs +++ b/src/client/io_loop.rs @@ -1178,6 +1178,16 @@ impl Remote { #[cfg(windows)] fn handle_cliprdr_msg(&self, clip: message_proto::Cliprdr) { if !self.handler.lc.read().unwrap().disable_clipboard { + #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))] + if let Some(message_proto::cliprdr::Union::FormatList(_)) = &clip.union { + if self.client_conn_id + != clipboard::get_client_conn_id(&crate::flutter::get_cur_session_id()) + .unwrap_or(0) + { + return; + } + } + if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) { ContextSend::proc(|context: &mut Box| -> u32 { clipboard::server_clip_file(context, self.client_conn_id, clip) diff --git a/src/flutter.rs b/src/flutter.rs index d477b62d5..5e844f910 100644 --- a/src/flutter.rs +++ b/src/flutter.rs @@ -567,7 +567,7 @@ pub fn make_fd_flutter(id: i32, entries: &Vec, only_count: bool) -> S } pub fn get_cur_session_id() -> String { - *CUR_SESSION_ID.read().unwrap() + CUR_SESSION_ID.read().unwrap().clone() } pub fn set_cur_session_id(id: String) { diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs index 5fdb3122c..cddaf4d79 100644 --- a/src/flutter_ffi.rs +++ b/src/flutter_ffi.rs @@ -1052,6 +1052,10 @@ pub fn main_update_me() -> SyncReturn { SyncReturn(true) } +pub fn set_cur_session_id(id: String) { + super::flutter::set_cur_session_id(id) +} + pub fn install_show_run_without_install() -> SyncReturn { SyncReturn(show_run_without_install()) } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 9c45ad269..70ea1a15c 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -259,7 +259,6 @@ impl IpcTaskRunner { use hbb_common::config::LocalConfig; // for tmp use, without real conn id - let conn_id_tmp = -1; let mut write_jobs: Vec = Vec::new(); let mut close = true; @@ -321,9 +320,8 @@ impl IpcTaskRunner { log::info!("cm ipc connection disconnect"); break; } - Data::PrivacyModeState(_) => { - self.conn_id = conn_id_tmp; - allow_err!(self.tx.send(data)); + Data::PrivacyModeState((id, _)) => { + cm_inner_send(id, data); } Data::ClickTime(ms) => { CLICK_TIME.store(ms, Ordering::SeqCst); @@ -338,7 +336,6 @@ impl IpcTaskRunner { #[cfg(windows)] { let conn_id = self.conn_id; - ContextSend::proc(|context: &mut Box| -> u32 { clipboard::server_clip_file(context, conn_id, _clip) }); @@ -380,12 +377,10 @@ impl IpcTaskRunner { }, } } - if self.conn_id != 0 && self.conn_id != conn_id_tmp { - self.cm.remove_connection(self.conn_id, close); - } } async fn ipc_task(stream: Connection, cm: ConnectionManager) { + log::debug!("ipc task begin"); let (tx, rx) = mpsc::unbounded_channel::(); let mut task_runner = Self { stream, @@ -401,6 +396,10 @@ impl IpcTaskRunner { if task_runner.conn_id > 0 { task_runner.run().await; } + if task_runner.conn_id > 0 { + task_runner.cm.remove_connection(task_runner.conn_id, close); + } + log::debug!("ipc task end"); } } @@ -731,3 +730,17 @@ fn send_raw(msg: Message, tx: &UnboundedSender) { err => allow_err!(err), } } + +#[cfg(windows)] +fn cm_inner_send(id: i32, data: Data) { + let lock = CLIENTS.read().unwrap(); + if id != 0 { + if let Some(s) = lock.get(&id) { + allow_err!(s.tx.send(data)); + } + } else { + for s in lock.values() { + allow_err!(s.tx.send(data.clone())); + } + } +} From 38803f0de54b19e89cadf50681675a46f79e5f11 Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 27 Oct 2022 12:07:48 +0800 Subject: [PATCH 10/11] win_fix_multi_tab: debug done Signed-off-by: fufesou --- flutter/lib/models/model.dart | 9 ++++----- src/ui_cm_interface.rs | 9 ++++++--- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/flutter/lib/models/model.dart b/flutter/lib/models/model.dart index 8e5723588..aa9dfd8e2 100644 --- a/flutter/lib/models/model.dart +++ b/flutter/lib/models/model.dart @@ -28,7 +28,7 @@ import 'input_model.dart'; import 'platform_model.dart'; typedef HandleMsgBox = Function(Map evt, String id); -bool _waitForImage = false; +final _waitForImage = {}; class FfiModel with ChangeNotifier { PeerInfo _pi = PeerInfo(); @@ -92,7 +92,6 @@ class FfiModel with ChangeNotifier { clear() { _pi = PeerInfo(); _display = Display(); - _waitForImage = false; _secure = null; _direct = null; _inputBlocked = false; @@ -314,7 +313,7 @@ class FfiModel with ChangeNotifier { parent.target?.dialogManager.showLoading( translate('Connected, waiting for image...'), onCancel: closeConnection); - _waitForImage = true; + _waitForImage[peerId] = true; _reconnects = 1; } } @@ -354,8 +353,8 @@ class ImageModel with ChangeNotifier { ImageModel(this.parent); onRgba(Uint8List rgba) { - if (_waitForImage) { - _waitForImage = false; + if (_waitForImage[id]!) { + _waitForImage[id] = false; parent.target?.dialogManager.dismissAll(); } final pid = parent.target?.id; diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index 70ea1a15c..c14a4f0c7 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -56,6 +56,7 @@ struct IpcTaskRunner { cm: ConnectionManager, tx: mpsc::UnboundedSender, rx: mpsc::UnboundedReceiver, + close: bool, conn_id: i32, #[cfg(windows)] file_transfer_enabled: bool, @@ -260,7 +261,6 @@ impl IpcTaskRunner { // for tmp use, without real conn id let mut write_jobs: Vec = Vec::new(); - let mut close = true; #[cfg(windows)] if self.conn_id > 0 { @@ -314,7 +314,7 @@ impl IpcTaskRunner { break; } Data::Disconnected => { - close = false; + self.close = false; #[cfg(windows)] self.enable_cliprdr_file_context(self.conn_id, false).await; log::info!("cm ipc connection disconnect"); @@ -387,6 +387,7 @@ impl IpcTaskRunner { cm, tx, rx, + close: true, conn_id: 0, #[cfg(windows)] file_transfer_enabled: false, @@ -397,7 +398,9 @@ impl IpcTaskRunner { task_runner.run().await; } if task_runner.conn_id > 0 { - task_runner.cm.remove_connection(task_runner.conn_id, close); + task_runner + .cm + .remove_connection(task_runner.conn_id, task_runner.close); } log::debug!("ipc task end"); } From 45513834749b5e800936244dcf2f766a7f2c223b Mon Sep 17 00:00:00 2001 From: fufesou Date: Thu, 27 Oct 2022 15:52:40 +0800 Subject: [PATCH 11/11] win_fix_multi_tab: debug flutter done Signed-off-by: fufesou --- flutter/lib/desktop/pages/remote_tab_page.dart | 10 +++------- src/ui_cm_interface.rs | 5 +++-- 2 files changed, 6 insertions(+), 9 deletions(-) diff --git a/flutter/lib/desktop/pages/remote_tab_page.dart b/flutter/lib/desktop/pages/remote_tab_page.dart index b3ebb5497..93008de07 100644 --- a/flutter/lib/desktop/pages/remote_tab_page.dart +++ b/flutter/lib/desktop/pages/remote_tab_page.dart @@ -24,8 +24,9 @@ class ConnectionTabPage extends StatefulWidget { } class _ConnectionTabPageState extends State { - final tabController = - Get.put(DesktopTabController(tabType: DesktopTabType.remoteScreen)); + final tabController = Get.put(DesktopTabController( + tabType: DesktopTabType.remoteScreen, + onSelected: (_, id) => bind.setCurSessionId(id: id))); static const IconData selectedIcon = Icons.desktop_windows_sharp; static const IconData unselectedIcon = Icons.desktop_windows_outlined; @@ -60,7 +61,6 @@ class _ConnectionTabPageState extends State { super.initState(); tabController.onRemoved = (_, id) => onRemoveId(id); - tabController.onSelected = (_, id) => onSelectId(id); rustDeskWinManager.setMethodHandler((call, fromWindowId) async { print( @@ -175,10 +175,6 @@ class _ConnectionTabPageState extends State { _update_remote_count(); } - void onSelectId(String id) { - bind.setCurSessionId(id: id); - } - int windowId() { return widget.params["windowId"]; } diff --git a/src/ui_cm_interface.rs b/src/ui_cm_interface.rs index c14a4f0c7..7296f8738 100644 --- a/src/ui_cm_interface.rs +++ b/src/ui_cm_interface.rs @@ -320,8 +320,9 @@ impl IpcTaskRunner { log::info!("cm ipc connection disconnect"); break; } - Data::PrivacyModeState((id, _)) => { - cm_inner_send(id, data); + Data::PrivacyModeState((_id, _)) => { + #[cfg(windows)] + cm_inner_send(_id, data); } Data::ClickTime(ms) => { CLICK_TIME.store(ms, Ordering::SeqCst);