Merge pull request #1840 from fufesou/win_fix_multi_tab

Win fix multi tab
This commit is contained in:
RustDesk 2022-10-27 16:21:11 +08:00 committed by GitHub
commit cf1ba283b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 553 additions and 389 deletions

View File

@ -43,7 +43,7 @@ class _FileManagerTabPageState extends State<FileManagerTabPage> {
void initState() { void initState() {
super.initState(); super.initState();
tabController.onRemove = (_, id) => onRemoveId(id); tabController.onRemoved = (_, id) => onRemoveId(id);
rustDeskWinManager.setMethodHandler((call, fromWindowId) async { rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
print( print(

View File

@ -46,7 +46,7 @@ class _PortForwardTabPageState extends State<PortForwardTabPage> {
void initState() { void initState() {
super.initState(); super.initState();
tabController.onRemove = (_, id) => onRemoveId(id); tabController.onRemoved = (_, id) => onRemoveId(id);
rustDeskWinManager.setMethodHandler((call, fromWindowId) async { rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
debugPrint( debugPrint(

View File

@ -24,8 +24,9 @@ class ConnectionTabPage extends StatefulWidget {
} }
class _ConnectionTabPageState extends State<ConnectionTabPage> { class _ConnectionTabPageState extends State<ConnectionTabPage> {
final tabController = final tabController = Get.put(DesktopTabController(
Get.put(DesktopTabController(tabType: DesktopTabType.remoteScreen)); tabType: DesktopTabType.remoteScreen,
onSelected: (_, id) => bind.setCurSessionId(id: id)));
static const IconData selectedIcon = Icons.desktop_windows_sharp; static const IconData selectedIcon = Icons.desktop_windows_sharp;
static const IconData unselectedIcon = Icons.desktop_windows_outlined; static const IconData unselectedIcon = Icons.desktop_windows_outlined;
@ -59,11 +60,11 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
void initState() { void initState() {
super.initState(); super.initState();
tabController.onRemove = (_, id) => onRemoveId(id); tabController.onRemoved = (_, id) => onRemoveId(id);
rustDeskWinManager.setMethodHandler((call, fromWindowId) async { rustDeskWinManager.setMethodHandler((call, fromWindowId) async {
print( 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'); final RxBool fullscreen = Get.find(tag: 'fullscreen');
// for simplify, just replace connectionId // for simplify, just replace connectionId

View File

@ -30,7 +30,7 @@ class _DesktopServerPageState extends State<DesktopServerPage>
void initState() { void initState() {
gFFI.ffiModel.updateEventListener(""); gFFI.ffiModel.updateEventListener("");
windowManager.addListener(this); windowManager.addListener(this);
tabController.onRemove = (_, id) => onRemoveId(id); tabController.onRemoved = (_, id) => onRemoveId(id);
super.initState(); super.initState();
} }
@ -99,7 +99,7 @@ class ConnectionManagerState extends State<ConnectionManager> {
@override @override
void initState() { void initState() {
gFFI.serverModel.updateClientState(); gFFI.serverModel.updateClientState();
gFFI.serverModel.tabController.onSelected = (index) => gFFI.serverModel.tabController.onSelected = (index, _) =>
gFFI.chatModel.changeCurrentID(gFFI.serverModel.clients[index].id); gFFI.chatModel.changeCurrentID(gFFI.serverModel.clients[index].id);
super.initState(); super.initState();
} }

View File

@ -70,10 +70,11 @@ class DesktopTabController {
final DesktopTabType tabType; final DesktopTabType tabType;
/// index, key /// index, key
Function(int, String)? onRemove; Function(int, String)? onRemoved;
Function(int)? onSelected; Function(int, String)? onSelected;
DesktopTabController({required this.tabType}); DesktopTabController(
{required this.tabType, this.onRemoved, this.onSelected});
int get length => state.value.tabs.length; int get length => state.value.tabs.length;
@ -114,7 +115,7 @@ class DesktopTabController {
state.value.tabs.removeAt(index); state.value.tabs.removeAt(index);
state.value.scrollController.itemCount = state.value.tabs.length; state.value.scrollController.itemCount = state.value.tabs.length;
jumpTo(toIndex); jumpTo(toIndex);
onRemove?.call(index, key); onRemoved?.call(index, key);
} }
void jumpTo(int index) { void jumpTo(int index) {
@ -134,7 +135,8 @@ class DesktopTabController {
})); }));
}); });
if (state.value.tabs.length > index) { 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) { void closeBy(String? key) {
if (!isDesktop) return; if (!isDesktop) return;
assert(onRemove != null); assert(onRemoved != null);
if (key == null) { if (key == null) {
if (state.value.selected < state.value.tabs.length) { if (state.value.selected < state.value.tabs.length) {
remove(state.value.selected); remove(state.value.selected);

View File

@ -28,7 +28,7 @@ import 'input_model.dart';
import 'platform_model.dart'; import 'platform_model.dart';
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id); typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
bool _waitForImage = false; final _waitForImage = <String, bool>{};
class FfiModel with ChangeNotifier { class FfiModel with ChangeNotifier {
PeerInfo _pi = PeerInfo(); PeerInfo _pi = PeerInfo();
@ -92,7 +92,6 @@ class FfiModel with ChangeNotifier {
clear() { clear() {
_pi = PeerInfo(); _pi = PeerInfo();
_display = Display(); _display = Display();
_waitForImage = false;
_secure = null; _secure = null;
_direct = null; _direct = null;
_inputBlocked = false; _inputBlocked = false;
@ -314,7 +313,7 @@ class FfiModel with ChangeNotifier {
parent.target?.dialogManager.showLoading( parent.target?.dialogManager.showLoading(
translate('Connected, waiting for image...'), translate('Connected, waiting for image...'),
onCancel: closeConnection); onCancel: closeConnection);
_waitForImage = true; _waitForImage[peerId] = true;
_reconnects = 1; _reconnects = 1;
} }
} }
@ -354,8 +353,8 @@ class ImageModel with ChangeNotifier {
ImageModel(this.parent); ImageModel(this.parent);
onRgba(Uint8List rgba) { onRgba(Uint8List rgba) {
if (_waitForImage) { if (_waitForImage[id]!) {
_waitForImage = false; _waitForImage[id] = false;
parent.target?.dialogManager.dismissAll(); parent.target?.dialogManager.dismissAll();
} }
final pid = parent.target?.id; final pid = parent.target?.id;

View File

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

View File

@ -1,6 +1,6 @@
use cliprdr::*; use cliprdr::*;
use hbb_common::{ use hbb_common::{
log, allow_err, log,
tokio::sync::{ tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex, Mutex as TokioMutex,
@ -12,33 +12,31 @@ use std::{
boxed::Box, boxed::Box,
collections::HashMap, collections::HashMap,
ffi::{CStr, CString}, ffi::{CStr, CString},
sync::Mutex, sync::{Arc, Mutex, RwLock},
}; };
pub mod cliprdr; pub mod cliprdr;
pub mod context_send;
pub use context_send::*;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(tag = "t", content = "c")] #[serde(tag = "t", content = "c")]
pub enum ClipbaordFile { pub enum ClipbaordFile {
ServerFormatList { MonitorReady,
conn_id: i32, FormatList {
format_list: Vec<(i32, String)>, format_list: Vec<(i32, String)>,
}, },
ServerFormatListResponse { FormatListResponse {
conn_id: i32,
msg_flags: i32, msg_flags: i32,
}, },
ServerFormatDataRequest { FormatDataRequest {
conn_id: i32,
requested_format_id: i32, requested_format_id: i32,
}, },
ServerFormatDataResponse { FormatDataResponse {
conn_id: i32,
msg_flags: i32, msg_flags: i32,
format_data: Vec<u8>, format_data: Vec<u8>,
}, },
FileContentsRequest { FileContentsRequest {
conn_id: i32,
stream_id: i32, stream_id: i32,
list_index: i32, list_index: i32,
dw_flags: i32, dw_flags: i32,
@ -49,7 +47,6 @@ pub enum ClipbaordFile {
clip_data_id: i32, clip_data_id: i32,
}, },
FileContentsResponse { FileContentsResponse {
conn_id: i32,
msg_flags: i32, msg_flags: i32,
stream_id: i32, stream_id: i32,
requested_data: Vec<u8>, requested_data: Vec<u8>,
@ -61,18 +58,89 @@ struct ConnEnabled {
conn_enabled: HashMap<i32, bool>, conn_enabled: HashMap<i32, bool>,
} }
lazy_static::lazy_static! { struct MsgChannel {
static ref MSG_CHANNEL_CLIENT: (UnboundedSender<(i32, ClipbaordFile)>, TokioMutex<UnboundedReceiver<(i32, ClipbaordFile)>>) = { peer_id: String,
let (tx, rx) = unbounded_channel(); conn_id: i32,
(tx, TokioMutex::new(rx)) sender: UnboundedSender<ClipbaordFile>,
}; receiver: Arc<TokioMutex<UnboundedReceiver<ClipbaordFile>>>,
static ref CLIP_CONN_ENABLED: Mutex<ConnEnabled> = Mutex::new(ConnEnabled::default());
} }
#[inline(always)] #[derive(PartialEq)]
pub fn get_rx_clip_client<'a>() -> &'a TokioMutex<UnboundedReceiver<(i32, ClipbaordFile)>> { pub enum ProcessSide {
&MSG_CHANNEL_CLIENT.1 UnknownSide,
ClientSide,
ServerSide,
}
lazy_static::lazy_static! {
static ref VEC_MSG_CHANNEL: RwLock<Vec<MsgChannel>> = Default::default();
static ref CLIP_CONN_ENABLED: Mutex<ConnEnabled> = Mutex::new(ConnEnabled::default());
static ref PROCESS_SIDE: RwLock<ProcessSide> = RwLock::new(ProcessSide::UnknownSide);
}
pub fn get_client_conn_id(peer_id: &str) -> Option<i32> {
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<TokioMutex<UnboundedReceiver<ClipbaordFile>>>) {
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)
}
}
}
pub fn get_rx_cliprdr_server(conn_id: i32) -> Arc<TokioMutex<UnboundedReceiver<ClipbaordFile>>> {
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) { pub fn set_conn_enabled(conn_id: i32, enabled: bool) {
@ -88,61 +156,46 @@ pub fn empty_clipboard(context: &mut Box<CliprdrClientContext>, conn_id: i32) ->
pub fn server_clip_file( pub fn server_clip_file(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
s_conn_id: i32, conn_id: i32,
msg: ClipbaordFile, msg: ClipbaordFile,
) -> u32 { ) -> u32 {
match msg { match msg {
ClipbaordFile::ServerFormatList { ClipbaordFile::MonitorReady => {
mut conn_id, log::debug!("server_monitor_ready called");
format_list, let ret = server_monitor_ready(context, conn_id);
} => { log::debug!("server_monitor_ready called, return {}", ret);
if s_conn_id != 0 { ret
conn_id = s_conn_id as i32; }
} ClipbaordFile::FormatList { format_list } => {
log::debug!("server_format_list called"); log::debug!("server_format_list called");
let ret = server_format_list(context, conn_id, format_list); let ret = server_format_list(context, conn_id, format_list);
log::debug!("server_format_list called, return {}", ret); log::debug!("server_format_list called, return {}", ret);
ret ret
} }
ClipbaordFile::ServerFormatListResponse { ClipbaordFile::FormatListResponse { msg_flags } => {
mut conn_id,
msg_flags,
} => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("format_list_response called"); log::debug!("format_list_response called");
let ret = server_format_list_response(context, conn_id, msg_flags); let ret = server_format_list_response(context, conn_id, msg_flags);
log::debug!("server_format_list_response called, return {}", ret); log::debug!("server_format_list_response called, return {}", ret);
ret ret
} }
ClipbaordFile::ServerFormatDataRequest { ClipbaordFile::FormatDataRequest {
mut conn_id,
requested_format_id, requested_format_id,
} => { } => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("format_data_request called"); log::debug!("format_data_request called");
let ret = server_format_data_request(context, conn_id, requested_format_id); let ret = server_format_data_request(context, conn_id, requested_format_id);
log::debug!("server_format_data_request called, return {}", ret); log::debug!("server_format_data_request called, return {}", ret);
ret ret
} }
ClipbaordFile::ServerFormatDataResponse { ClipbaordFile::FormatDataResponse {
mut conn_id,
msg_flags, msg_flags,
format_data, format_data,
} => { } => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("format_data_response called"); log::debug!("format_data_response called");
let ret = server_format_data_response(context, conn_id, msg_flags, format_data); let ret = server_format_data_response(context, conn_id, msg_flags, format_data);
log::debug!("server_format_data_response called, return {}", ret); log::debug!("server_format_data_response called, return {}", ret);
ret ret
} }
ClipbaordFile::FileContentsRequest { ClipbaordFile::FileContentsRequest {
mut conn_id,
stream_id, stream_id,
list_index, list_index,
dw_flags, dw_flags,
@ -152,9 +205,6 @@ pub fn server_clip_file(
have_clip_data_id, have_clip_data_id,
clip_data_id, clip_data_id,
} => { } => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("file_contents_request called"); log::debug!("file_contents_request called");
let ret = server_file_contents_request( let ret = server_file_contents_request(
context, context,
@ -172,14 +222,10 @@ pub fn server_clip_file(
ret ret
} }
ClipbaordFile::FileContentsResponse { ClipbaordFile::FileContentsResponse {
mut conn_id,
msg_flags, msg_flags,
stream_id, stream_id,
requested_data, requested_data,
} => { } => {
if s_conn_id != 0 {
conn_id = s_conn_id as i32;
}
log::debug!("file_contents_response called"); log::debug!("file_contents_response called");
let ret = server_file_contents_response( let ret = server_file_contents_response(
context, context,
@ -194,6 +240,19 @@ pub fn server_clip_file(
} }
} }
pub fn server_monitor_ready(context: &mut Box<CliprdrClientContext>, 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( pub fn server_format_list(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: i32, conn_id: i32,
@ -243,6 +302,7 @@ pub fn server_format_list(
ret as u32 ret as u32
} }
} }
pub fn server_format_list_response( pub fn server_format_list_response(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: i32, conn_id: i32,
@ -262,6 +322,7 @@ pub fn server_format_list_response(
ret as u32 ret as u32
} }
} }
pub fn server_format_data_request( pub fn server_format_data_request(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: i32, conn_id: i32,
@ -280,6 +341,7 @@ pub fn server_format_data_request(
ret as u32 ret as u32
} }
} }
pub fn server_format_data_response( pub fn server_format_data_response(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: i32, conn_id: i32,
@ -301,6 +363,7 @@ pub fn server_format_data_response(
ret as u32 ret as u32
} }
} }
pub fn server_file_contents_request( pub fn server_file_contents_request(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: i32, conn_id: i32,
@ -335,6 +398,7 @@ pub fn server_file_contents_request(
ret as u32 ret as u32
} }
} }
pub fn server_file_contents_response( pub fn server_file_contents_response(
context: &mut Box<CliprdrClientContext>, context: &mut Box<CliprdrClientContext>,
conn_id: i32, conn_id: i32,
@ -363,7 +427,10 @@ pub fn server_file_contents_response(
pub fn create_cliprdr_context( pub fn create_cliprdr_context(
enable_files: bool, enable_files: bool,
enable_others: bool, enable_others: bool,
process_side: ProcessSide,
) -> ResultType<Box<CliprdrClientContext>> { ) -> ResultType<Box<CliprdrClientContext>> {
*PROCESS_SIDE.write().unwrap() = process_side;
Ok(CliprdrClientContext::create( Ok(CliprdrClientContext::create(
enable_files, enable_files,
enable_others, enable_others,
@ -378,8 +445,11 @@ pub fn create_cliprdr_context(
} }
extern "C" fn check_enabled(conn_id: UINT32) -> BOOL { 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; let mut connd_enabled = false;
if conn_id != 0 { if conn_id != 0 {
if let Some(true) = lock.conn_enabled.get(&(conn_id as i32)) { if let Some(true) = lock.conn_enabled.get(&(conn_id as i32)) {
@ -422,12 +492,17 @@ extern "C" fn client_format_list(
} }
conn_id = (*clip_format_list).connID as i32; conn_id = (*clip_format_list).connID as i32;
} }
let data = ClipbaordFile::ServerFormatList { let data = ClipbaordFile::FormatList { format_list };
conn_id,
format_list,
};
// no need to handle result here // no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); 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 0
} }
@ -444,9 +519,8 @@ extern "C" fn client_format_list_response(
conn_id = (*format_list_response).connID as i32; conn_id = (*format_list_response).connID as i32;
msg_flags = (*format_list_response).msgFlags as i32; msg_flags = (*format_list_response).msgFlags as i32;
} }
let data = ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags }; let data = ClipbaordFile::FormatListResponse { msg_flags };
// no need to handle result here send_data(conn_id, data);
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0 0
} }
@ -463,12 +537,11 @@ extern "C" fn client_format_data_request(
conn_id = (*format_data_request).connID as i32; conn_id = (*format_data_request).connID as i32;
requested_format_id = (*format_data_request).requestedFormatId as i32; requested_format_id = (*format_data_request).requestedFormatId as i32;
} }
let data = ClipbaordFile::ServerFormatDataRequest { let data = ClipbaordFile::FormatDataRequest {
conn_id,
requested_format_id, requested_format_id,
}; };
// no need to handle result here // no need to handle result here
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap(); send_data(conn_id, data);
0 0
} }
@ -495,13 +568,11 @@ extern "C" fn client_format_data_response(
.to_vec(); .to_vec();
} }
} }
let data = ClipbaordFile::ServerFormatDataResponse { let data = ClipbaordFile::FormatDataResponse {
conn_id,
msg_flags, msg_flags,
format_data, format_data,
}; };
// no need to handle result here send_data(conn_id, data);
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0 0
} }
@ -544,7 +615,6 @@ extern "C" fn client_file_contents_request(
} }
let data = ClipbaordFile::FileContentsRequest { let data = ClipbaordFile::FileContentsRequest {
conn_id,
stream_id, stream_id,
list_index, list_index,
dw_flags, dw_flags,
@ -554,8 +624,7 @@ extern "C" fn client_file_contents_request(
have_clip_data_id, have_clip_data_id,
clip_data_id, clip_data_id,
}; };
// no need to handle result here send_data(conn_id, data);
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0 0
} }
@ -585,13 +654,11 @@ extern "C" fn client_file_contents_response(
} }
} }
let data = ClipbaordFile::FileContentsResponse { let data = ClipbaordFile::FileContentsResponse {
conn_id,
msg_flags, msg_flags,
stream_id, stream_id,
requested_data, requested_data,
}; };
// no need to handle result here send_data(conn_id, data);
MSG_CHANNEL_CLIENT.0.send((conn_id, data)).unwrap();
0 0
} }

View File

@ -135,14 +135,14 @@ typedef struct _FORMAT_IDS FORMAT_IDS;
#define TAG "windows" #define TAG "windows"
#ifdef WITH_DEBUG_CLIPRDR // #ifdef WITH_DEBUG_CLIPRDR
#define DEBUG_CLIPRDR(...) printf(TAG, __VA_ARGS__) #define DEBUG_CLIPRDR(fmt, ...) fprintf(stderr, "DEBUG %s[%d] %s() " fmt "\n", __FILE__, __LINE__, __func__, ##__VA_ARGS__);fflush(stderr)
#else // #else
#define DEBUG_CLIPRDR(...) \ // #define DEBUG_CLIPRDR(fmt, ...) \
do \ // do \
{ \ // { \
} while (0) // } while (0)
#endif // #endif
typedef BOOL(WINAPI *fnAddClipboardFormatListener)(HWND hwnd); typedef BOOL(WINAPI *fnAddClipboardFormatListener)(HWND hwnd);
typedef BOOL(WINAPI *fnRemoveClipboardFormatListener)(HWND hwnd); typedef BOOL(WINAPI *fnRemoveClipboardFormatListener)(HWND hwnd);
@ -193,6 +193,7 @@ struct _CliprdrDataObject
ULONG m_nStreams; ULONG m_nStreams;
IStream **m_pStream; IStream **m_pStream;
void *m_pData; void *m_pData;
DWORD m_processID;
UINT32 m_connID; UINT32 m_connID;
}; };
typedef struct _CliprdrDataObject CliprdrDataObject; 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_cliprdr_uninit(wfClipboard *clipboard, CliprdrClientContext *cliprdr);
BOOL wf_do_empty_cliprdr(wfClipboard *clipboard); 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 void wf_destroy_file_obj(IDataObject *instance);
static UINT32 get_remote_format_id(wfClipboard *clipboard, UINT32 local_format); static UINT32 get_remote_format_id(wfClipboard *clipboard, UINT32 local_format);
static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UINT32 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) if (!pFormatEtc || !pMedium || !instance)
return E_INVALIDARG; return E_INVALIDARG;
// Not the same process id
if (instance->m_processID != GetCurrentProcessId())
{
return E_INVALIDARG;
}
clipboard = (wfClipboard *)instance->m_pData; clipboard = (wfClipboard *)instance->m_pData;
if (!clipboard->context->CheckEnabled(instance->m_connID)) 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_pData = data;
instance->m_nStreams = 0; instance->m_nStreams = 0;
instance->m_pStream = NULL; instance->m_pStream = NULL;
instance->m_processID = GetCurrentProcessId();
instance->m_connID = connID; instance->m_connID = connID;
if (count > 0) if (count > 0)
@ -1340,7 +1348,7 @@ static BOOL cliprdr_GetUpdatedClipboardFormats(wfClipboard *clipboard, PUINT lpu
return TRUE; return TRUE;
} }
static UINT cliprdr_send_format_list(wfClipboard *clipboard) static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID)
{ {
UINT rc; UINT rc;
int count = 0; int count = 0;
@ -1415,7 +1423,7 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard)
} }
} }
formatList.connID = 0; formatList.connID = connID;
formatList.numFormats = numFormats; formatList.numFormats = numFormats;
formatList.formats = formats; formatList.formats = formats;
formatList.msgType = CB_FORMAT_LIST; formatList.msgType = CB_FORMAT_LIST;
@ -1645,7 +1653,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
clipboard->hmem = NULL; clipboard->hmem = NULL;
} }
cliprdr_send_format_list(clipboard); cliprdr_send_format_list(clipboard, 0);
} }
} }
@ -1669,7 +1677,8 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
DEBUG_CLIPRDR("info: WM_RENDERFORMAT"); DEBUG_CLIPRDR("info: WM_RENDERFORMAT");
// https://docs.microsoft.com/en-us/windows/win32/dataxchg/wm-renderformat?redirectedfrom=MSDN // 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."); DEBUG_CLIPRDR("error: cliprdr_send_data_request failed.");
break; break;
@ -1695,7 +1704,7 @@ static LRESULT CALLBACK cliprdr_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM
if ((GetClipboardOwner() != clipboard->hwnd) && if ((GetClipboardOwner() != clipboard->hwnd) &&
(S_FALSE == OleIsCurrentClipboard(clipboard->data_obj))) (S_FALSE == OleIsCurrentClipboard(clipboard->data_obj)))
{ {
cliprdr_send_format_list(clipboard); cliprdr_send_format_list(clipboard, 0);
} }
SendMessage(clipboard->hWndNextViewer, Msg, wParam, lParam); SendMessage(clipboard->hWndNextViewer, Msg, wParam, lParam);
@ -2128,9 +2137,14 @@ static UINT wf_cliprdr_send_client_capabilities(wfClipboard *clipboard)
CLIPRDR_CAPABILITIES capabilities; CLIPRDR_CAPABILITIES capabilities;
CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet; CLIPRDR_GENERAL_CAPABILITY_SET generalCapabilitySet;
if (!clipboard || !clipboard->context || !clipboard->context->ClientCapabilities) if (!clipboard || !clipboard->context)
return ERROR_INTERNAL_ERROR; return ERROR_INTERNAL_ERROR;
// Ignore ClientCapabilities for now
if (!clipboard->context->ClientCapabilities) {
return CHANNEL_RC_OK;
}
capabilities.connID = 0; capabilities.connID = 0;
capabilities.cCapabilitiesSets = 1; capabilities.cCapabilitiesSets = 1;
capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET *)&(generalCapabilitySet); capabilities.capabilitySets = (CLIPRDR_CAPABILITY_SET *)&(generalCapabilitySet);
@ -2162,7 +2176,7 @@ static UINT wf_cliprdr_monitor_ready(CliprdrClientContext *context,
if (rc != CHANNEL_RC_OK) if (rc != CHANNEL_RC_OK)
return rc; return rc;
return cliprdr_send_format_list(clipboard); return cliprdr_send_format_list(clipboard, monitorReady->connID);
} }
/** /**

View File

@ -360,38 +360,31 @@ message FileDirCreate {
// main logic from freeRDP // main logic from freeRDP
message CliprdrMonitorReady { message CliprdrMonitorReady {
int32 conn_id = 1;
} }
message CliprdrFormat { message CliprdrFormat {
int32 conn_id = 1;
int32 id = 2; int32 id = 2;
string format = 3; string format = 3;
} }
message CliprdrServerFormatList { message CliprdrServerFormatList {
int32 conn_id = 1;
repeated CliprdrFormat formats = 2; repeated CliprdrFormat formats = 2;
} }
message CliprdrServerFormatListResponse { message CliprdrServerFormatListResponse {
int32 conn_id = 1;
int32 msg_flags = 2; int32 msg_flags = 2;
} }
message CliprdrServerFormatDataRequest { message CliprdrServerFormatDataRequest {
int32 conn_id = 1;
int32 requested_format_id = 2; int32 requested_format_id = 2;
} }
message CliprdrServerFormatDataResponse { message CliprdrServerFormatDataResponse {
int32 conn_id = 1;
int32 msg_flags = 2; int32 msg_flags = 2;
bytes format_data = 3; bytes format_data = 3;
} }
message CliprdrFileContentsRequest { message CliprdrFileContentsRequest {
int32 conn_id = 1;
int32 stream_id = 2; int32 stream_id = 2;
int32 list_index = 3; int32 list_index = 3;
int32 dw_flags = 4; int32 dw_flags = 4;
@ -403,7 +396,6 @@ message CliprdrFileContentsRequest {
} }
message CliprdrFileContentsResponse { message CliprdrFileContentsResponse {
int32 conn_id = 1;
int32 msg_flags = 3; int32 msg_flags = 3;
int32 stream_id = 4; int32 stream_id = 4;
bytes requested_data = 5; bytes requested_data = 5;

View File

@ -6,6 +6,9 @@ use crate::common;
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::common::{check_clipboard, update_clipboard, ClipboardContext, CLIPBOARD_INTERVAL}; 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::ui_session_interface::{InvokeUiSession, Session};
use crate::{client::Data, client::Interface}; use crate::{client::Data, client::Interface};
@ -22,7 +25,11 @@ use hbb_common::tokio::{
sync::mpsc, sync::mpsc,
time::{self, Duration, Instant, Interval}, 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 hbb_common::{fs, log, Stream};
use std::collections::HashMap; use std::collections::HashMap;
@ -43,7 +50,7 @@ pub struct Remote<T: InvokeUiSession> {
last_update_jobs_status: (Instant, HashMap<i32, u64>), last_update_jobs_status: (Instant, HashMap<i32, u64>),
first_frame: bool, first_frame: bool,
#[cfg(windows)] #[cfg(windows)]
clipboard_file_context: Option<Box<clipboard::cliprdr::CliprdrClientContext>>, client_conn_id: i32, // used for clipboard
data_count: Arc<AtomicUsize>, data_count: Arc<AtomicUsize>,
frame_count: Arc<AtomicUsize>, frame_count: Arc<AtomicUsize>,
video_format: CodecFormat, video_format: CodecFormat,
@ -72,7 +79,7 @@ impl<T: InvokeUiSession> Remote<T> {
last_update_jobs_status: (Instant::now(), Default::default()), last_update_jobs_status: (Instant::now(), Default::default()),
first_frame: false, first_frame: false,
#[cfg(windows)] #[cfg(windows)]
clipboard_file_context: None, client_conn_id: 0,
data_count: Arc::new(AtomicUsize::new(0)), data_count: Arc::new(AtomicUsize::new(0)),
frame_count, frame_count,
video_format: CodecFormat::Unknown, video_format: CodecFormat::Unknown,
@ -107,7 +114,14 @@ impl<T: InvokeUiSession> Remote<T> {
#[cfg(not(windows))] #[cfg(not(windows))]
let (_tx_holder, mut rx_clip_client) = mpsc::unbounded_channel::<i32>(); let (_tx_holder, mut rx_clip_client) = mpsc::unbounded_channel::<i32>();
#[cfg(windows)] #[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)); let mut status_timer = time::interval(Duration::new(1, 0));
@ -152,7 +166,7 @@ impl<T: InvokeUiSession> Remote<T> {
_msg = rx_clip_client.recv() => { _msg = rx_clip_client.recv() => {
#[cfg(windows)] #[cfg(windows)]
match _msg { match _msg {
Some((_, clip)) => { Some(clip) => {
allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await); allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await);
} }
None => { None => {
@ -778,13 +792,7 @@ impl<T: InvokeUiSession> Remote<T> {
} }
#[cfg(windows)] #[cfg(windows)]
Some(message::Union::Cliprdr(clip)) => { Some(message::Union::Cliprdr(clip)) => {
if !self.handler.lc.read().unwrap().disable_clipboard { self.handle_cliprdr_msg(clip);
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);
}
}
}
} }
Some(message::Union::FileResponse(fr)) => { Some(message::Union::FileResponse(fr)) => {
match fr.union { match fr.union {
@ -1158,30 +1166,32 @@ impl<T: InvokeUiSession> Remote<T> {
true true
} }
fn check_clipboard_file_context(&mut self) { fn check_clipboard_file_context(&self) {
#[cfg(windows)] #[cfg(windows)]
{ {
let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst) let enabled = SERVER_FILE_TRANSFER_ENABLED.load(Ordering::SeqCst)
&& self.handler.lc.read().unwrap().enable_file_transfer; && self.handler.lc.read().unwrap().enable_file_transfer;
if enabled == self.clipboard_file_context.is_none() { ContextSend::enable(enabled);
self.clipboard_file_context = if enabled { }
match clipboard::create_cliprdr_context(true, false) { }
Ok(context) => {
log::info!("clipboard context for file transfer created."); #[cfg(windows)]
Some(context) fn handle_cliprdr_msg(&self, clip: message_proto::Cliprdr) {
} if !self.handler.lc.read().unwrap().disable_clipboard {
Err(err) => { #[cfg(any(target_os = "android", target_os = "ios", feature = "flutter"))]
log::error!( if let Some(message_proto::cliprdr::Union::FormatList(_)) = &clip.union {
"Create clipboard context for file transfer: {}", if self.client_conn_id
err.to_string() != clipboard::get_client_conn_id(&crate::flutter::get_cur_session_id())
); .unwrap_or(0)
None {
} return;
} }
} else { }
log::info!("clipboard context for file transfer destroyed.");
None if let Some(clip) = crate::clipboard_file::msg_2_clip(clip) {
}; ContextSend::proc(|context: &mut Box<CliprdrClientContext>| -> u32 {
clipboard::server_clip_file(context, self.client_conn_id, clip)
});
} }
} }
} }

View File

@ -3,14 +3,19 @@ use hbb_common::message_proto::*;
pub fn clip_2_msg(clip: ClipbaordFile) -> Message { pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
match clip { match clip {
ClipbaordFile::ServerFormatList { ClipbaordFile::MonitorReady => Message {
conn_id, union: Some(message::Union::Cliprdr(Cliprdr {
format_list, union: Some(cliprdr::Union::Ready(CliprdrMonitorReady {
} => { ..Default::default()
})),
..Default::default()
})),
..Default::default()
},
ClipbaordFile::FormatList { format_list } => {
let mut formats: Vec<CliprdrFormat> = Vec::new(); let mut formats: Vec<CliprdrFormat> = Vec::new();
for v in format_list.iter() { for v in format_list.iter() {
formats.push(CliprdrFormat { formats.push(CliprdrFormat {
conn_id: 0,
id: v.0, id: v.0,
format: v.1.clone(), format: v.1.clone(),
..Default::default() ..Default::default()
@ -19,7 +24,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
Message { Message {
union: Some(message::Union::Cliprdr(Cliprdr { union: Some(message::Union::Cliprdr(Cliprdr {
union: Some(cliprdr::Union::FormatList(CliprdrServerFormatList { union: Some(cliprdr::Union::FormatList(CliprdrServerFormatList {
conn_id,
formats, formats,
..Default::default() ..Default::default()
})), })),
@ -28,11 +32,10 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
..Default::default() ..Default::default()
} }
} }
ClipbaordFile::ServerFormatListResponse { conn_id, msg_flags } => Message { ClipbaordFile::FormatListResponse { msg_flags } => Message {
union: Some(message::Union::Cliprdr(Cliprdr { union: Some(message::Union::Cliprdr(Cliprdr {
union: Some(cliprdr::Union::FormatListResponse( union: Some(cliprdr::Union::FormatListResponse(
CliprdrServerFormatListResponse { CliprdrServerFormatListResponse {
conn_id,
msg_flags, msg_flags,
..Default::default() ..Default::default()
}, },
@ -41,14 +44,12 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
})), })),
..Default::default() ..Default::default()
}, },
ClipbaordFile::ServerFormatDataRequest { ClipbaordFile::FormatDataRequest {
conn_id,
requested_format_id, requested_format_id,
} => Message { } => Message {
union: Some(message::Union::Cliprdr(Cliprdr { union: Some(message::Union::Cliprdr(Cliprdr {
union: Some(cliprdr::Union::FormatDataRequest( union: Some(cliprdr::Union::FormatDataRequest(
CliprdrServerFormatDataRequest { CliprdrServerFormatDataRequest {
conn_id,
requested_format_id, requested_format_id,
..Default::default() ..Default::default()
}, },
@ -57,15 +58,13 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
})), })),
..Default::default() ..Default::default()
}, },
ClipbaordFile::ServerFormatDataResponse { ClipbaordFile::FormatDataResponse {
conn_id,
msg_flags, msg_flags,
format_data, format_data,
} => Message { } => Message {
union: Some(message::Union::Cliprdr(Cliprdr { union: Some(message::Union::Cliprdr(Cliprdr {
union: Some(cliprdr::Union::FormatDataResponse( union: Some(cliprdr::Union::FormatDataResponse(
CliprdrServerFormatDataResponse { CliprdrServerFormatDataResponse {
conn_id,
msg_flags, msg_flags,
format_data: format_data.into(), format_data: format_data.into(),
..Default::default() ..Default::default()
@ -76,7 +75,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
..Default::default() ..Default::default()
}, },
ClipbaordFile::FileContentsRequest { ClipbaordFile::FileContentsRequest {
conn_id,
stream_id, stream_id,
list_index, list_index,
dw_flags, dw_flags,
@ -89,7 +87,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
union: Some(message::Union::Cliprdr(Cliprdr { union: Some(message::Union::Cliprdr(Cliprdr {
union: Some(cliprdr::Union::FileContentsRequest( union: Some(cliprdr::Union::FileContentsRequest(
CliprdrFileContentsRequest { CliprdrFileContentsRequest {
conn_id,
stream_id, stream_id,
list_index, list_index,
dw_flags, dw_flags,
@ -106,7 +103,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
..Default::default() ..Default::default()
}, },
ClipbaordFile::FileContentsResponse { ClipbaordFile::FileContentsResponse {
conn_id,
msg_flags, msg_flags,
stream_id, stream_id,
requested_data, requested_data,
@ -114,7 +110,6 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
union: Some(message::Union::Cliprdr(Cliprdr { union: Some(message::Union::Cliprdr(Cliprdr {
union: Some(cliprdr::Union::FileContentsResponse( union: Some(cliprdr::Union::FileContentsResponse(
CliprdrFileContentsResponse { CliprdrFileContentsResponse {
conn_id,
msg_flags, msg_flags,
stream_id, stream_id,
requested_data: requested_data.into(), requested_data: requested_data.into(),
@ -130,38 +125,26 @@ pub fn clip_2_msg(clip: ClipbaordFile) -> Message {
pub fn msg_2_clip(msg: Cliprdr) -> Option<ClipbaordFile> { pub fn msg_2_clip(msg: Cliprdr) -> Option<ClipbaordFile> {
match msg.union { match msg.union {
Some(cliprdr::Union::Ready(_)) => Some(ClipbaordFile::MonitorReady),
Some(cliprdr::Union::FormatList(data)) => { Some(cliprdr::Union::FormatList(data)) => {
let mut format_list: Vec<(i32, String)> = Vec::new(); let mut format_list: Vec<(i32, String)> = Vec::new();
for v in data.formats.iter() { for v in data.formats.iter() {
format_list.push((v.id, v.format.clone())); format_list.push((v.id, v.format.clone()));
} }
Some(ClipbaordFile::ServerFormatList { Some(ClipbaordFile::FormatList { format_list })
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(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(cliprdr::Union::FileContentsRequest(data)) => {
Some(ClipbaordFile::FileContentsRequest { Some(ClipbaordFile::FileContentsRequest {
conn_id: data.conn_id,
stream_id: data.stream_id, stream_id: data.stream_id,
list_index: data.list_index, list_index: data.list_index,
dw_flags: data.dw_flags, dw_flags: data.dw_flags,
@ -174,7 +157,6 @@ pub fn msg_2_clip(msg: Cliprdr) -> Option<ClipbaordFile> {
} }
Some(cliprdr::Union::FileContentsResponse(data)) => { Some(cliprdr::Union::FileContentsResponse(data)) => {
Some(ClipbaordFile::FileContentsResponse { Some(ClipbaordFile::FileContentsResponse {
conn_id: data.conn_id,
msg_flags: data.msg_flags, msg_flags: data.msg_flags,
stream_id: data.stream_id, stream_id: data.stream_id,
requested_data: data.requested_data.into(), requested_data: data.requested_data.into(),

View File

@ -22,7 +22,8 @@ pub(super) const APP_TYPE_DESKTOP_FILE_TRANSFER: &str = "file transfer";
pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward"; pub(super) const APP_TYPE_DESKTOP_PORT_FORWARD: &str = "port forward";
lazy_static::lazy_static! { lazy_static::lazy_static! {
pub static ref SESSIONS: RwLock<HashMap<String,Session<FlutterHandler>>> = Default::default(); static ref CUR_SESSION_ID: RwLock<String> = Default::default();
pub static ref SESSIONS: RwLock<HashMap<String, Session<FlutterHandler>>> = Default::default();
pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel pub static ref GLOBAL_EVENT_STREAM: RwLock<HashMap<String, StreamSink<String>>> = Default::default(); // rust to dart event channel
} }
@ -564,3 +565,13 @@ pub fn make_fd_flutter(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> S
m.insert("total_size".into(), json!(n as f64)); m.insert("total_size".into(), json!(n as f64));
serde_json::to_string(&m).unwrap_or("".into()) serde_json::to_string(&m).unwrap_or("".into())
} }
pub fn get_cur_session_id() -> String {
CUR_SESSION_ID.read().unwrap().clone()
}
pub fn set_cur_session_id(id: String) {
if get_cur_session_id() != id {
*CUR_SESSION_ID.write().unwrap() = id;
}
}

View File

@ -1052,6 +1052,10 @@ pub fn main_update_me() -> SyncReturn<bool> {
SyncReturn(true) 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<bool> { pub fn install_show_run_without_install() -> SyncReturn<bool> {
SyncReturn(show_run_without_install()) SyncReturn(show_run_without_install())
} }

View File

@ -249,8 +249,8 @@ pub(super) fn release_resouce() {
if *write_lock != 0 { if *write_lock != 0 {
let cap_display_info: *mut CapDisplayInfo = *write_lock as _; let cap_display_info: *mut CapDisplayInfo = *write_lock as _;
unsafe { unsafe {
let box_capturer = Box::from_raw((*cap_display_info).capturer.0); let _box_capturer = Box::from_raw((*cap_display_info).capturer.0);
let box_cap_display_info = Box::from_raw(cap_display_info); let _box_cap_display_info = Box::from_raw(cap_display_info);
*write_lock = 0; *write_lock = 0;
} }
} }

View File

@ -53,11 +53,8 @@ fn check_connect_status(
) { ) {
let status = Arc::new(Mutex::new((0, false, 0, "".to_owned()))); let status = Arc::new(Mutex::new((0, false, 0, "".to_owned())));
let options = Arc::new(Mutex::new(Config::get_options())); let options = Arc::new(Mutex::new(Config::get_options()));
let cloned = status.clone();
let cloned_options = options.clone();
let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>(); let (tx, rx) = mpsc::unbounded_channel::<ipc::Data>();
let password = Arc::new(Mutex::new(String::default())); 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)); std::thread::spawn(move || crate::ui_interface::check_connect_status_(reconnect, rx));
(status, options, tx, password) (status, options, tx, password)
} }
@ -514,17 +511,17 @@ impl UI {
} }
fn get_lan_peers(&self) -> String { fn get_lan_peers(&self) -> String {
let peers = get_lan_peers() // let peers = get_lan_peers()
.into_iter() // .into_iter()
.map(|mut peer| { // .map(|mut peer| {
( // (
peer.remove("id").unwrap_or_default(), // peer.remove("id").unwrap_or_default(),
peer.remove("username").unwrap_or_default(), // peer.remove("username").unwrap_or_default(),
peer.remove("hostname").unwrap_or_default(), // peer.remove("hostname").unwrap_or_default(),
peer.remove("platform").unwrap_or_default(), // peer.remove("platform").unwrap_or_default(),
) // )
}) // })
.collect::<Vec<(String, String, String, String)>>(); // .collect::<Vec<(String, String, String, String)>>();
serde_json::to_string(&get_lan_peers()).unwrap_or_default() serde_json::to_string(&get_lan_peers()).unwrap_or_default()
} }

View File

@ -2,11 +2,6 @@
use crate::ipc::start_pa; use crate::ipc::start_pa;
use crate::ui_cm_interface::{start_ipc, ConnectionManager, InvokeUiCM}; 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 hbb_common::{allow_err, log};
use sciter::{make_args, Element, Value, HELEMENT}; use sciter::{make_args, Element, Value, HELEMENT};
use std::sync::Mutex; use std::sync::Mutex;

View File

@ -14,12 +14,6 @@ use sciter::{
Value, 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::{ use hbb_common::{
allow_err, fs::TransferJobMeta, log, message_proto::*, rendezvous_proto::ConnType, allow_err, fs::TransferJobMeta, log, message_proto::*, rendezvous_proto::ConnType,
}; };

View File

@ -1,17 +1,22 @@
use std::ops::{Deref, DerefMut}; #[cfg(windows)]
use std::sync::Arc;
use std::{ use std::{
collections::HashMap, collections::HashMap,
iter::FromIterator, iter::FromIterator,
ops::{Deref, DerefMut},
sync::{ sync::{
atomic::{AtomicI64, Ordering}, atomic::{AtomicI64, Ordering},
RwLock, RwLock,
}, },
}; };
#[cfg(windows)]
use clipboard::{cliprdr::CliprdrClientContext, empty_clipboard, ContextSend};
use serde_derive::Serialize; use serde_derive::Serialize;
use crate::ipc::Data; use crate::ipc::{self, new_listener, Connection, Data};
use crate::ipc::{self, new_listener, Connection}; #[cfg(windows)]
use hbb_common::tokio::sync::Mutex as TokioMutex;
use hbb_common::{ use hbb_common::{
allow_err, allow_err,
config::Config, config::Config,
@ -22,7 +27,7 @@ use hbb_common::{
protobuf::Message as _, protobuf::Message as _,
tokio::{ tokio::{
self, self,
sync::mpsc::{self, UnboundedSender}, sync::mpsc::{self, unbounded_channel, UnboundedSender},
task::spawn_blocking, task::spawn_blocking,
}, },
}; };
@ -46,8 +51,19 @@ pub struct Client {
tx: UnboundedSender<Data>, tx: UnboundedSender<Data>,
} }
struct IpcTaskRunner<T: InvokeUiCM> {
stream: Connection,
cm: ConnectionManager<T>,
tx: mpsc::UnboundedSender<Data>,
rx: mpsc::UnboundedReceiver<Data>,
close: bool,
conn_id: i32,
#[cfg(windows)]
file_transfer_enabled: bool,
}
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref CLIENTS: RwLock<HashMap<i32,Client>> = Default::default(); static ref CLIENTS: RwLock<HashMap<i32, Client>> = Default::default();
static ref CLICK_TIME: AtomicI64 = AtomicI64::new(0); static ref CLICK_TIME: AtomicI64 = AtomicI64::new(0);
} }
@ -215,23 +231,185 @@ pub fn get_clients_length() -> usize {
clients.len() clients.len()
} }
pub enum ClipboardFileData { impl<T: InvokeUiCM> IpcTaskRunner<T> {
#[cfg(windows)] #[cfg(windows)]
Clip((i32, ipc::ClipbaordFile)), async fn enable_cliprdr_file_context(&mut self, conn_id: i32, enabled: bool) {
Enable((i32, bool)), if conn_id == 0 {
return;
}
let pre_enabled = ContextSend::is_enabled();
ContextSend::enable(enabled);
if !pre_enabled && ContextSend::is_enabled() {
allow_err!(
self.stream
.send(&Data::ClipbaordFile(clipboard::ClipbaordFile::MonitorReady))
.await
);
}
clipboard::set_conn_enabled(conn_id, enabled);
if !enabled {
ContextSend::proc(|context: &mut Box<CliprdrClientContext>| -> u32 {
clipboard::empty_clipboard(context, conn_id);
0
});
}
}
async fn run(&mut self) {
use hbb_common::config::LocalConfig;
// for tmp use, without real conn id
let mut write_jobs: Vec<fs::TransferJob> = Vec::new();
#[cfg(windows)]
if self.conn_id > 0 {
self.enable_cliprdr_file_context(self.conn_id, self.file_transfer_enabled)
.await;
}
#[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::<clipboard::ClipbaordFile>();
rx_clip1 = Arc::new(TokioMutex::new(rx_clip2));
rx_clip = rx_clip1.lock().await;
}
#[cfg(not(windows))]
{
(_tx_clip, rx_clip) = unbounded_channel::<i32>();
}
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: _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 => {
#[cfg(windows)]
self.enable_cliprdr_file_context(self.conn_id, false).await;
log::info!("cm ipc connection closed from connection request");
break;
}
Data::Disconnected => {
self.close = false;
#[cfg(windows)]
self.enable_cliprdr_file_context(self.conn_id, false).await;
log::info!("cm ipc connection disconnect");
break;
}
Data::PrivacyModeState((_id, _)) => {
#[cfg(windows)]
cm_inner_send(_id, 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;
}
Data::ClipbaordFile(_clip) => {
#[cfg(windows)]
{
let conn_id = self.conn_id;
ContextSend::proc(|context: &mut Box<CliprdrClientContext>| -> u32 {
clipboard::server_clip_file(context, conn_id, _clip)
});
}
}
#[cfg(windows)]
Data::ClipboardFileEnabled(_enabled) => {
#[cfg(windows)]
self.enable_cliprdr_file_context(self.conn_id, _enabled).await;
}
Data::Theme(dark) => {
self.cm.change_theme(dark);
}
Data::Language(lang) => {
LocalConfig::set_option("lang".to_owned(), lang);
self.cm.change_language();
}
_ => {
}
}
}
_ => {}
}
}
Some(data) = self.rx.recv() => {
if self.stream.send(&data).await.is_err() {
break;
}
}
clip_file = rx_clip.recv() => match clip_file {
Some(_clip) => {
#[cfg(windows)]
allow_err!(self.tx.send(Data::ClipbaordFile(_clip)));
}
None => {
//
}
},
}
}
}
async fn ipc_task(stream: Connection, cm: ConnectionManager<T>) {
log::debug!("ipc task begin");
let (tx, rx) = mpsc::unbounded_channel::<Data>();
let mut task_runner = Self {
stream,
cm,
tx,
rx,
close: true,
conn_id: 0,
#[cfg(windows)]
file_transfer_enabled: false,
};
task_runner.run().await;
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, task_runner.close);
}
log::debug!("ipc task end");
}
} }
#[cfg(not(any(target_os = "android", target_os = "ios")))] #[cfg(not(any(target_os = "android", target_os = "ios")))]
#[tokio::main(flavor = "current_thread")] #[tokio::main(flavor = "current_thread")]
pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) { pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
use hbb_common::config::LocalConfig;
let (tx_file, _rx_file) = mpsc::unbounded_channel::<ClipboardFileData>();
#[cfg(windows)]
let cm_clip = cm.clone();
#[cfg(windows)]
std::thread::spawn(move || start_clipboard_file(cm_clip, _rx_file));
#[cfg(windows)] #[cfg(windows)]
std::thread::spawn(move || { std::thread::spawn(move || {
log::info!("try create privacy mode window"); log::info!("try create privacy mode window");
@ -253,94 +431,10 @@ pub async fn start_ipc<T: InvokeUiCM>(cm: ConnectionManager<T>) {
match result { match result {
Ok(stream) => { Ok(stream) => {
log::debug!("Got new connection"); log::debug!("Got new connection");
let mut stream = Connection::new(stream); tokio::spawn(IpcTaskRunner::<T>::ipc_task(
let cm = cm.clone(); Connection::new(stream),
let tx_file = tx_file.clone(); cm.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::<Data>();
let mut write_jobs: Vec<fs::TransferJob> = 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);
}
});
} }
Err(err) => { Err(err) => {
log::error!("Couldn't get cm client: {:?}", err); log::error!("Couldn't get cm client: {:?}", err);
@ -642,66 +736,7 @@ fn send_raw(msg: Message, tx: &UnboundedSender<Data>) {
} }
#[cfg(windows)] #[cfg(windows)]
#[tokio::main(flavor = "current_thread")] fn cm_inner_send(id: i32, data: Data) {
pub async fn start_clipboard_file<T: InvokeUiCM>(
cm: ConnectionManager<T>,
mut rx: mpsc::UnboundedReceiver<ClipboardFileData>,
) {
let mut cliprdr_context = None;
let mut rx_clip_client = clipboard::get_rx_clip_client().lock().await;
loop {
tokio::select! {
clip_file = rx_clip_client.recv() => match clip_file {
Some((conn_id, clip)) => {
cmd_inner_send(
conn_id,
Data::ClipbaordFile(clip)
);
}
None => {
//
}
},
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) {
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
}
}
}
}
}
#[cfg(windows)]
fn cmd_inner_send(id: i32, data: Data) {
let lock = CLIENTS.read().unwrap(); let lock = CLIENTS.read().unwrap();
if id != 0 { if id != 0 {
if let Some(s) = lock.get(&id) { if let Some(s) = lock.get(&id) {

View File

@ -76,11 +76,11 @@ pub fn goto_install() {
} }
#[inline] #[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)] #[cfg(windows)]
std::thread::spawn(move || { std::thread::spawn(move || {
allow_err!(crate::platform::windows::install_me( allow_err!(crate::platform::windows::install_me(
&_options, _path, silent, debug &_options, _path, _silent, _debug
)); ));
std::process::exit(0); std::process::exit(0);
}); });

View File

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