Merge pull request #4795 from dignow/refact/win_cliprd_wait_timeout

Refact/win cliprd wait timeout
This commit is contained in:
RustDesk 2023-06-29 22:50:45 +08:00 committed by GitHub
commit c01dfc9af3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 223 additions and 37 deletions

View File

@ -998,6 +998,26 @@ Widget msgboxIcon(String type) {
// title should be null // title should be null
Widget msgboxContent(String type, String title, String text) { Widget msgboxContent(String type, String title, String text) {
String translateText(String text) {
if (text.indexOf('Failed') == 0 && text.indexOf(': ') > 0) {
List<String> words = text.split(': ');
for (var i = 0; i < words.length; ++i) {
words[i] = translate(words[i]);
}
text = words.join(': ');
} else {
List<String> words = text.split(' ');
if (words.length > 1 && words[0].endsWith('_tip')) {
words[0] = translate(words[0]);
final rest = text.substring(words[0].length + 1);
text = '${words[0]} ${translate(rest)}';
} else {
text = translate(text);
}
}
return text;
}
return Row( return Row(
children: [ children: [
msgboxIcon(type), msgboxIcon(type),
@ -1009,7 +1029,7 @@ Widget msgboxContent(String type, String title, String text) {
translate(title), translate(title),
style: TextStyle(fontSize: 21), style: TextStyle(fontSize: 21),
).marginOnly(bottom: 10), ).marginOnly(bottom: 10),
Text(translate(text), style: const TextStyle(fontSize: 15)), Text(translateText(text), style: const TextStyle(fontSize: 15)),
], ],
), ),
), ),

View File

@ -150,6 +150,15 @@ extern "C"
typedef struct _cliprdr_client_context CliprdrClientContext; typedef struct _cliprdr_client_context CliprdrClientContext;
struct _NOTIFICATION_MESSAGE
{
// 0 - info, 1 - warning, 2 - error
UINT32 type;
char *msg;
char *details;
};
typedef struct _NOTIFICATION_MESSAGE NOTIFICATION_MESSAGE;
typedef UINT (*pcCliprdrServerCapabilities)(CliprdrClientContext *context, typedef UINT (*pcCliprdrServerCapabilities)(CliprdrClientContext *context,
const CLIPRDR_CAPABILITIES *capabilities); const CLIPRDR_CAPABILITIES *capabilities);
typedef UINT (*pcCliprdrClientCapabilities)(CliprdrClientContext *context, typedef UINT (*pcCliprdrClientCapabilities)(CliprdrClientContext *context,
@ -158,6 +167,9 @@ extern "C"
const CLIPRDR_MONITOR_READY *monitorReady); const CLIPRDR_MONITOR_READY *monitorReady);
typedef UINT (*pcCliprdrTempDirectory)(CliprdrClientContext *context, typedef UINT (*pcCliprdrTempDirectory)(CliprdrClientContext *context,
const CLIPRDR_TEMP_DIRECTORY *tempDirectory); const CLIPRDR_TEMP_DIRECTORY *tempDirectory);
typedef UINT (*pcNotifyClipboardMsg)(UINT32 connID, const NOTIFICATION_MESSAGE *msg);
typedef UINT (*pcCliprdrClientFormatList)(CliprdrClientContext *context, typedef UINT (*pcCliprdrClientFormatList)(CliprdrClientContext *context,
const CLIPRDR_FORMAT_LIST *formatList); const CLIPRDR_FORMAT_LIST *formatList);
typedef UINT (*pcCliprdrServerFormatList)(CliprdrClientContext *context, typedef UINT (*pcCliprdrServerFormatList)(CliprdrClientContext *context,
@ -199,10 +211,12 @@ extern "C"
BOOL EnableOthers; BOOL EnableOthers;
BOOL IsStopped; BOOL IsStopped;
UINT32 ResponseWaitTimeoutSecs;
pcCliprdrServerCapabilities ServerCapabilities; pcCliprdrServerCapabilities ServerCapabilities;
pcCliprdrClientCapabilities ClientCapabilities; pcCliprdrClientCapabilities ClientCapabilities;
pcCliprdrMonitorReady MonitorReady; pcCliprdrMonitorReady MonitorReady;
pcCliprdrTempDirectory TempDirectory; pcCliprdrTempDirectory TempDirectory;
pcNotifyClipboardMsg NotifyClipboardMsg;
pcCliprdrClientFormatList ClientFormatList; pcCliprdrClientFormatList ClientFormatList;
pcCliprdrServerFormatList ServerFormatList; pcCliprdrServerFormatList ServerFormatList;
pcCliprdrClientFormatListResponse ClientFormatListResponse; pcCliprdrClientFormatListResponse ClientFormatListResponse;
@ -228,4 +242,3 @@ extern "C"
#endif #endif
#endif // WF_CLIPRDR_H__ #endif // WF_CLIPRDR_H__

View File

@ -324,6 +324,14 @@ pub struct _CLIPRDR_FILE_CONTENTS_RESPONSE {
} }
pub type CLIPRDR_FILE_CONTENTS_RESPONSE = _CLIPRDR_FILE_CONTENTS_RESPONSE; pub type CLIPRDR_FILE_CONTENTS_RESPONSE = _CLIPRDR_FILE_CONTENTS_RESPONSE;
pub type CliprdrClientContext = _cliprdr_client_context; pub type CliprdrClientContext = _cliprdr_client_context;
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct _NOTIFICATION_MESSAGE {
pub r#type: UINT32, // 0 - info, 1 - warning, 2 - error
pub msg: *const BYTE,
pub details: *const BYTE,
}
pub type NOTIFICATION_MESSAGE = _NOTIFICATION_MESSAGE;
pub type pcCliprdrServerCapabilities = ::std::option::Option< pub type pcCliprdrServerCapabilities = ::std::option::Option<
unsafe extern "C" fn( unsafe extern "C" fn(
context: *mut CliprdrClientContext, context: *mut CliprdrClientContext,
@ -348,6 +356,8 @@ pub type pcCliprdrTempDirectory = ::std::option::Option<
tempDirectory: *const CLIPRDR_TEMP_DIRECTORY, tempDirectory: *const CLIPRDR_TEMP_DIRECTORY,
) -> UINT, ) -> UINT,
>; >;
pub type pcNotifyClipboardMsg =
::std::option::Option<unsafe extern "C" fn(connID: UINT32, msg: *const NOTIFICATION_MESSAGE) -> UINT>;
pub type pcCliprdrClientFormatList = ::std::option::Option< pub type pcCliprdrClientFormatList = ::std::option::Option<
unsafe extern "C" fn( unsafe extern "C" fn(
context: *mut CliprdrClientContext, context: *mut CliprdrClientContext,
@ -453,10 +463,12 @@ pub struct _cliprdr_client_context {
pub EnableFiles: BOOL, pub EnableFiles: BOOL,
pub EnableOthers: BOOL, pub EnableOthers: BOOL,
pub IsStopped: BOOL, pub IsStopped: BOOL,
pub ResponseWaitTimeoutSecs: UINT32,
pub ServerCapabilities: pcCliprdrServerCapabilities, pub ServerCapabilities: pcCliprdrServerCapabilities,
pub ClientCapabilities: pcCliprdrClientCapabilities, pub ClientCapabilities: pcCliprdrClientCapabilities,
pub MonitorReady: pcCliprdrMonitorReady, pub MonitorReady: pcCliprdrMonitorReady,
pub TempDirectory: pcCliprdrTempDirectory, pub TempDirectory: pcCliprdrTempDirectory,
pub NotifyClipboardMsg: pcNotifyClipboardMsg,
pub ClientFormatList: pcCliprdrClientFormatList, pub ClientFormatList: pcCliprdrClientFormatList,
pub ServerFormatList: pcCliprdrServerFormatList, pub ServerFormatList: pcCliprdrServerFormatList,
pub ClientFormatListResponse: pcCliprdrClientFormatListResponse, pub ClientFormatListResponse: pcCliprdrClientFormatListResponse,
@ -498,6 +510,8 @@ impl CliprdrClientContext {
pub fn create( pub fn create(
enable_files: bool, enable_files: bool,
enable_others: bool, enable_others: bool,
response_wait_timeout_secs: u32,
notify_callback: pcNotifyClipboardMsg,
client_format_list: pcCliprdrClientFormatList, client_format_list: pcCliprdrClientFormatList,
client_format_list_response: pcCliprdrClientFormatListResponse, client_format_list_response: pcCliprdrClientFormatListResponse,
client_format_data_request: pcCliprdrClientFormatDataRequest, client_format_data_request: pcCliprdrClientFormatDataRequest,
@ -510,10 +524,12 @@ impl CliprdrClientContext {
EnableFiles: if enable_files { TRUE } else { FALSE }, EnableFiles: if enable_files { TRUE } else { FALSE },
EnableOthers: if enable_others { TRUE } else { FALSE }, EnableOthers: if enable_others { TRUE } else { FALSE },
IsStopped: FALSE, IsStopped: FALSE,
ResponseWaitTimeoutSecs: response_wait_timeout_secs,
ServerCapabilities: None, ServerCapabilities: None,
ClientCapabilities: None, ClientCapabilities: None,
MonitorReady: None, MonitorReady: None,
TempDirectory: None, TempDirectory: None,
NotifyClipboardMsg: notify_callback,
ClientFormatList: client_format_list, ClientFormatList: client_format_list,
ServerFormatList: None, ServerFormatList: None,
ClientFormatListResponse: client_format_list_response, ClientFormatListResponse: client_format_list_response,

View File

@ -2,6 +2,8 @@ use crate::cliprdr::*;
use hbb_common::log; use hbb_common::log;
use std::sync::Mutex; use std::sync::Mutex;
const CLIPBOARD_RESPONSE_WAIT_TIMEOUT_SECS: u32 = 30;
lazy_static::lazy_static! { lazy_static::lazy_static! {
static ref CONTEXT_SEND: ContextSend = ContextSend{addr: Mutex::new(0)}; static ref CONTEXT_SEND: ContextSend = ContextSend{addr: Mutex::new(0)};
} }
@ -27,7 +29,11 @@ impl ContextSend {
let mut lock = CONTEXT_SEND.addr.lock().unwrap(); let mut lock = CONTEXT_SEND.addr.lock().unwrap();
if enabled { if enabled {
if *lock == 0 { if *lock == 0 {
match crate::create_cliprdr_context(true, false) { match crate::create_cliprdr_context(
true,
false,
CLIPBOARD_RESPONSE_WAIT_TIMEOUT_SECS,
) {
Ok(context) => { Ok(context) => {
log::info!("clipboard context for file transfer created."); log::info!("clipboard context for file transfer created.");
*lock = Box::into_raw(context) as _; *lock = Box::into_raw(context) as _;

View File

@ -1,6 +1,6 @@
use cliprdr::*; use cliprdr::*;
use hbb_common::{ use hbb_common::{
allow_err, log, allow_err, lazy_static, log,
tokio::sync::{ tokio::sync::{
mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender}, mpsc::{unbounded_channel, UnboundedReceiver, UnboundedSender},
Mutex as TokioMutex, Mutex as TokioMutex,
@ -19,10 +19,16 @@ pub mod context_send;
pub use context_send::*; pub use context_send::*;
const ERR_CODE_SERVER_FUNCTION_NONE: u32 = 0x00000001; const ERR_CODE_SERVER_FUNCTION_NONE: u32 = 0x00000001;
const ERR_CODE_INVALID_PARAMETER: u32 = 0x00000002;
#[derive(Debug, Serialize, Deserialize, Clone)] #[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(tag = "t", content = "c")] #[serde(tag = "t", content = "c")]
pub enum ClipboardFile { pub enum ClipboardFile {
NotifyCallback {
r#type: String,
title: String,
text: String,
},
MonitorReady, MonitorReady,
FormatList { FormatList {
format_list: Vec<(i32, String)>, format_list: Vec<(i32, String)>,
@ -167,41 +173,40 @@ pub fn server_clip_file(
conn_id: i32, conn_id: i32,
msg: ClipboardFile, msg: ClipboardFile,
) -> u32 { ) -> u32 {
let mut ret = 0;
match msg { match msg {
ClipboardFile::NotifyCallback { .. } => {
// unreachable
}
ClipboardFile::MonitorReady => { ClipboardFile::MonitorReady => {
log::debug!("server_monitor_ready called"); log::debug!("server_monitor_ready called");
let ret = server_monitor_ready(context, conn_id); ret = server_monitor_ready(context, conn_id);
log::debug!("server_monitor_ready called, return {}", ret); log::debug!("server_monitor_ready called, return {}", ret);
ret
} }
ClipboardFile::FormatList { format_list } => { ClipboardFile::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); 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
} }
ClipboardFile::FormatListResponse { msg_flags } => { ClipboardFile::FormatListResponse { msg_flags } => {
log::debug!("format_list_response called"); log::debug!("format_list_response called");
let ret = server_format_list_response(context, conn_id, msg_flags); 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
} }
ClipboardFile::FormatDataRequest { ClipboardFile::FormatDataRequest {
requested_format_id, requested_format_id,
} => { } => {
log::debug!("format_data_request called"); log::debug!("format_data_request called");
let ret = server_format_data_request(context, conn_id, requested_format_id); 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
} }
ClipboardFile::FormatDataResponse { ClipboardFile::FormatDataResponse {
msg_flags, msg_flags,
format_data, format_data,
} => { } => {
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); 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
} }
ClipboardFile::FileContentsRequest { ClipboardFile::FileContentsRequest {
stream_id, stream_id,
@ -214,7 +219,7 @@ pub fn server_clip_file(
clip_data_id, clip_data_id,
} => { } => {
log::debug!("file_contents_request called"); log::debug!("file_contents_request called");
let ret = server_file_contents_request( ret = server_file_contents_request(
context, context,
conn_id, conn_id,
stream_id, stream_id,
@ -227,7 +232,6 @@ pub fn server_clip_file(
clip_data_id, clip_data_id,
); );
log::debug!("server_file_contents_request called, return {}", ret); log::debug!("server_file_contents_request called, return {}", ret);
ret
} }
ClipboardFile::FileContentsResponse { ClipboardFile::FileContentsResponse {
msg_flags, msg_flags,
@ -235,7 +239,7 @@ pub fn server_clip_file(
requested_data, requested_data,
} => { } => {
log::debug!("file_contents_response called"); log::debug!("file_contents_response called");
let ret = server_file_contents_response( ret = server_file_contents_response(
context, context,
conn_id, conn_id,
msg_flags, msg_flags,
@ -243,9 +247,9 @@ pub fn server_clip_file(
requested_data, requested_data,
); );
log::debug!("server_file_contents_response called, return {}", ret); log::debug!("server_file_contents_response called, return {}", ret);
ret
} }
} }
ret
} }
pub fn server_monitor_ready(context: &mut Box<CliprdrClientContext>, conn_id: i32) -> u32 { pub fn server_monitor_ready(context: &mut Box<CliprdrClientContext>, conn_id: i32) -> u32 {
@ -446,10 +450,13 @@ 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,
response_wait_timeout_secs: u32,
) -> ResultType<Box<CliprdrClientContext>> { ) -> ResultType<Box<CliprdrClientContext>> {
Ok(CliprdrClientContext::create( Ok(CliprdrClientContext::create(
enable_files, enable_files,
enable_others, enable_others,
response_wait_timeout_secs,
Some(notify_callback),
Some(client_format_list), Some(client_format_list),
Some(client_format_list_response), Some(client_format_list_response),
Some(client_format_data_request), Some(client_format_data_request),
@ -459,6 +466,51 @@ pub fn create_cliprdr_context(
)?) )?)
} }
extern "C" fn notify_callback(conn_id: UINT32, msg: *const NOTIFICATION_MESSAGE) -> UINT {
log::debug!("notify_callback called");
let data = unsafe {
let msg = &*msg;
let details = if msg.details.is_null() {
Ok("")
} else {
CStr::from_ptr(msg.details as _).to_str()
};
match (CStr::from_ptr(msg.msg as _).to_str(), details) {
(Ok(m), Ok(d)) => {
let msgtype = format!(
"custom-{}-nocancel-nook-hasclose",
if msg.r#type == 0 {
"info"
} else if msg.r#type == 1 {
"warn"
} else {
"error"
}
);
let title = "Clipboard";
let text = if d.is_empty() {
m.to_string()
} else {
format!("{} {}", m, d)
};
ClipboardFile::NotifyCallback {
r#type: msgtype,
title: title.to_string(),
text,
}
}
_ => {
log::error!("notify_callback: failed to convert msg");
return ERR_CODE_INVALID_PARAMETER;
}
}
};
// no need to handle result here
send_data(conn_id as _, data);
0
}
extern "C" fn client_format_list( extern "C" fn client_format_list(
_context: *mut CliprdrClientContext, _context: *mut CliprdrClientContext,
clip_format_list: *const CLIPRDR_FORMAT_LIST, clip_format_list: *const CLIPRDR_FORMAT_LIST,

View File

@ -1449,14 +1449,16 @@ static UINT cliprdr_send_format_list(wfClipboard *clipboard, UINT32 connID)
return rc; return rc;
} }
UINT wait_response_event(wfClipboard *clipboard, HANDLE event, void **data) UINT wait_response_event(UINT32 connID, wfClipboard *clipboard, HANDLE event, void **data)
{ {
UINT rc = ERROR_SUCCESS; UINT rc = ERROR_SUCCESS;
clipboard->context->IsStopped = FALSE; clipboard->context->IsStopped = FALSE;
// with default 3min timeout DWORD waitOnceTimeoutMillis = 50;
for (int i = 0; i < 20 * 60 * 3; i++) int waitCount = 1000 * clipboard->context->ResponseWaitTimeoutSecs / waitOnceTimeoutMillis;
int i = 0;
for (; i < waitCount; i++)
{ {
DWORD waitRes = WaitForSingleObject(event, 50); DWORD waitRes = WaitForSingleObject(event, waitOnceTimeoutMillis);
if (waitRes == WAIT_TIMEOUT && clipboard->context->IsStopped == FALSE) if (waitRes == WAIT_TIMEOUT && clipboard->context->IsStopped == FALSE)
{ {
continue; continue;
@ -1487,7 +1489,21 @@ UINT wait_response_event(wfClipboard *clipboard, HANDLE event, void **data)
return rc; return rc;
} }
if ((*data) != NULL) if (i == waitCount)
{
NOTIFICATION_MESSAGE msg;
msg.type = 2;
msg.msg = "clipboard_wait_response_timeout_tip";
msg.details = NULL;
clipboard->context->NotifyClipboardMsg(connID, &msg);
rc = ERROR_INTERNAL_ERROR;
if (!ResetEvent(event))
{
// NOTE: critical error here, crash may be better
}
}
else if ((*data) != NULL)
{ {
if (!ResetEvent(event)) if (!ResetEvent(event))
{ {
@ -1519,7 +1535,7 @@ static UINT cliprdr_send_data_request(UINT32 connID, wfClipboard *clipboard, UIN
return rc; return rc;
} }
wait_response_event(clipboard, clipboard->response_data_event, &clipboard->hmem); wait_response_event(connID, clipboard, clipboard->response_data_event, &clipboard->hmem);
} }
UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, const void *streamid, ULONG index, UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, const void *streamid, ULONG index,
@ -1547,7 +1563,7 @@ UINT cliprdr_send_request_filecontents(wfClipboard *clipboard, UINT32 connID, co
return rc; return rc;
} }
return wait_response_event(clipboard, clipboard->req_fevent, (void **)&clipboard->req_fdata); return wait_response_event(connID, clipboard, clipboard->req_fevent, (void **)&clipboard->req_fdata);
} }
static UINT cliprdr_send_response_filecontents( static UINT cliprdr_send_response_filecontents(

View File

@ -206,16 +206,21 @@ 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) => match clip {
let is_stopping_allowed = clip.is_stopping_allowed(); clipboard::ClipboardFile::NotifyCallback{r#type, title, text} => {
let server_file_transfer_enabled = *self.handler.server_file_transfer_enabled.read().unwrap(); self.handler.msgbox(&r#type, &title, &text, "");
let file_transfer_enabled = self.handler.lc.read().unwrap().enable_file_transfer.v; }
let stop = is_stopping_allowed && !(server_file_transfer_enabled && file_transfer_enabled); _ => {
log::debug!("Process clipboard message from system, stop: {}, is_stopping_allowed: {}, server_file_transfer_enabled: {}, file_transfer_enabled: {}", stop, is_stopping_allowed, server_file_transfer_enabled, file_transfer_enabled); let is_stopping_allowed = clip.is_stopping_allowed();
if stop { let server_file_transfer_enabled = *self.handler.server_file_transfer_enabled.read().unwrap();
ContextSend::set_is_stopped(); let file_transfer_enabled = self.handler.lc.read().unwrap().enable_file_transfer.v;
} else { let stop = is_stopping_allowed && !(server_file_transfer_enabled && file_transfer_enabled);
allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await); log::debug!("Process clipboard message from system, stop: {}, is_stopping_allowed: {}, server_file_transfer_enabled: {}, file_transfer_enabled: {}", stop, is_stopping_allowed, server_file_transfer_enabled, file_transfer_enabled);
if stop {
ContextSend::set_is_stopped();
} else {
allow_err!(peer.send(&crate::clipboard_file::clip_2_msg(clip)).await);
}
} }
} }
None => { None => {

View File

@ -3,6 +3,20 @@ use hbb_common::message_proto::*;
pub fn clip_2_msg(clip: ClipboardFile) -> Message { pub fn clip_2_msg(clip: ClipboardFile) -> Message {
match clip { match clip {
ClipboardFile::NotifyCallback {
r#type,
title,
text,
} => Message {
union: Some(message::Union::MessageBox(MessageBox {
msgtype: r#type,
title,
text,
link: "".to_string(),
..Default::default()
})),
..Default::default()
},
ClipboardFile::MonitorReady => Message { ClipboardFile::MonitorReady => Message {
union: Some(message::Union::Cliprdr(Cliprdr { union: Some(message::Union::Cliprdr(Cliprdr {
union: Some(cliprdr::Union::Ready(CliprdrMonitorReady { union: Some(cliprdr::Union::Ready(CliprdrMonitorReady {

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "折叠工具栏"), ("Collapse toolbar", "折叠工具栏"),
("Accept and Elevate", "接受并提权"), ("Accept and Elevate", "接受并提权"),
("accept_and_elevate_btn_tooltip", "接受连接并提升 UAC 权限"), ("accept_and_elevate_btn_tooltip", "接受连接并提升 UAC 权限"),
("clipboard_wait_response_timeout_tip", "等待拷贝响应超时"),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "Symbolleiste einklappen"), ("Collapse toolbar", "Symbolleiste einklappen"),
("Accept and Elevate", "Akzeptieren und Rechte erhöhen"), ("Accept and Elevate", "Akzeptieren und Rechte erhöhen"),
("accept_and_elevate_btn_tooltip", "Akzeptieren Sie die Verbindung und erhöhen Sie die UAC-Berechtigungen."), ("accept_and_elevate_btn_tooltip", "Akzeptieren Sie die Verbindung und erhöhen Sie die UAC-Berechtigungen."),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -70,5 +70,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("resolution_fit_local_tip", "Fit local resolution"), ("resolution_fit_local_tip", "Fit local resolution"),
("resolution_custom_tip", "Custom resolution"), ("resolution_custom_tip", "Custom resolution"),
("accept_and_elevate_btn_tooltip", "Accept the connection and elevate UAC permissions."), ("accept_and_elevate_btn_tooltip", "Accept the connection and elevate UAC permissions."),
("clipboard_wait_response_timeout_tip", "Timed out waiting for copy response."),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "Contraer barra de herramientas"), ("Collapse toolbar", "Contraer barra de herramientas"),
("Accept and Elevate", "Aceptar y Elevar"), ("Accept and Elevate", "Aceptar y Elevar"),
("accept_and_elevate_btn_tooltip", "Aceptar la conexión y elevar permisos UAC."), ("accept_and_elevate_btn_tooltip", "Aceptar la conexión y elevar permisos UAC."),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "جمع کردن نوار ابزار"), ("Collapse toolbar", "جمع کردن نوار ابزار"),
("Accept and Elevate", "بپذیرید و افزایش دهید"), ("Accept and Elevate", "بپذیرید و افزایش دهید"),
("accept_and_elevate_btn_tooltip", "را افزایش دهید UAC اتصال را بپذیرید و مجوزهای."), ("accept_and_elevate_btn_tooltip", "را افزایش دهید UAC اتصال را بپذیرید و مجوزهای."),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "Comprimi barra strumenti"), ("Collapse toolbar", "Comprimi barra strumenti"),
("Accept and Elevate", "Accetta ed eleva"), ("Accept and Elevate", "Accetta ed eleva"),
("accept_and_elevate_btn_tooltip", "Accetta la connessione ed eleva le autorizzazioni UAC."), ("accept_and_elevate_btn_tooltip", "Accetta la connessione ed eleva le autorizzazioni UAC."),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "Werkbalk samenvouwen"), ("Collapse toolbar", "Werkbalk samenvouwen"),
("Accept and Elevate", "Accepteren en Verheffen"), ("Accept and Elevate", "Accepteren en Verheffen"),
("accept_and_elevate_btn_tooltip", "Accepteer de verbinding en verhoog de UAC-machtigingen."), ("accept_and_elevate_btn_tooltip", "Accepteer de verbinding en verhoog de UAC-machtigingen."),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "Zwiń pasek narzędzi"), ("Collapse toolbar", "Zwiń pasek narzędzi"),
("Accept and Elevate", "Akceptuj i Podnieś uprawnienia"), ("Accept and Elevate", "Akceptuj i Podnieś uprawnienia"),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "Свернуть панель инструментов"), ("Collapse toolbar", "Свернуть панель инструментов"),
("Accept and Elevate", "Принять и повысить"), ("Accept and Elevate", "Принять и повысить"),
("accept_and_elevate_btn_tooltip", "Разрешить подключение и повысить права UAC."), ("accept_and_elevate_btn_tooltip", "Разрешить подключение и повысить права UAC."),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", ""), ("Collapse toolbar", ""),
("Accept and Elevate", ""), ("Accept and Elevate", ""),
("accept_and_elevate_btn_tooltip", ""), ("accept_and_elevate_btn_tooltip", ""),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -511,5 +511,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Collapse toolbar", "Thu nhỏ thanh công cụ"), ("Collapse toolbar", "Thu nhỏ thanh công cụ"),
("Accept and Elevate", "Chấp nhận và Cấp Quyền"), ("Accept and Elevate", "Chấp nhận và Cấp Quyền"),
("accept_and_elevate_btn_tooltip", "Chấp nhận kết nối và cấp các quyền UAC."), ("accept_and_elevate_btn_tooltip", "Chấp nhận kết nối và cấp các quyền UAC."),
("clipboard_wait_response_timeout_tip", ""),
].iter().cloned().collect(); ].iter().cloned().collect();
} }

View File

@ -987,7 +987,7 @@ fn try_get_displays() -> ResultType<Vec<Display>> {
} }
#[inline] #[inline]
#[cfg(windows)] #[cfg(all(windows, feature = "virtual_display_driver"))]
fn no_displays(displays: &Vec<Display>) -> bool { fn no_displays(displays: &Vec<Display>) -> bool {
let display_len = displays.len(); let display_len = displays.len();
if display_len == 0 { if display_len == 0 {

View File

@ -5,6 +5,15 @@ function translate_text(text) {
fds[i] = translate(fds[i]); fds[i] = translate(fds[i]);
} }
text = fds.join(': '); text = fds.join(': ');
} else {
var fds = text.split(' ');
if (fds.length > 1 && fds[0].slice(-4) === '_tip') {
fds[0] = translate(fds[0]);
var rest = text.substring(fds[0].length + 1);
text = fds[0] + ' ' + translate(rest);
} else {
text = translate(text);
}
} }
return text; return text;
} }

View File

@ -423,7 +423,7 @@ impl<T: InvokeUiCM> IpcTaskRunner<T> {
Data::ClipboardFileEnabled(_enabled) => { Data::ClipboardFileEnabled(_enabled) => {
#[cfg(windows)] #[cfg(windows)]
{ {
self.file_transfer_enabled_peer =_enabled; self.file_transfer_enabled_peer = _enabled;
} }
} }
Data::Theme(dark) => { Data::Theme(dark) => {