mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-12-02 18:59:24 +08:00
Merge pull request #1840 from fufesou/win_fix_multi_tab
Win fix multi tab
This commit is contained in:
commit
cf1ba283b4
@ -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(
|
||||||
|
@ -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(
|
||||||
|
@ -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
|
||||||
|
@ -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();
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
|
59
libs/clipboard/src/context_send.rs
Normal file
59
libs/clipboard/src/context_send.rs
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -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;
|
||||||
|
@ -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)
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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(),
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -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())
|
||||||
}
|
}
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
25
src/ui.rs
25
src/ui.rs
@ -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()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
};
|
};
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
});
|
});
|
||||||
|
@ -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")]
|
||||||
|
Loading…
Reference in New Issue
Block a user