Compare commits

..

10 Commits

Author SHA1 Message Date
rustdesk
0a0625126e fix https://github.com/rustdesk/rustdesk/issues/15326 2026-06-18 12:09:51 +08:00
Maison da Silva
8a955888bf Fix Portuguese translations for consistency (#15325)
Fix Portuguese translations for consistency
2026-06-18 10:28:34 +08:00
21pages
36e812e550 update hwcodec (#15323)
Signed-off-by: 21pages <sunboeasy@gmail.com>
2026-06-17 22:58:46 +08:00
rustdesk
8baa995c7a bump version 2026-06-17 22:18:45 +08:00
RustDesk
f4a0535289 autocomplete online (#15313)
* autocomplete online

* review fix

* review fix

* remove literalInput
2026-06-17 22:04:34 +08:00
RustDesk
6665242edf Revert "refact: privacy mdoe 1, multi-monitors (#15318)" (#15320)
This reverts commit 3cdf1cce54.
2026-06-17 21:46:40 +08:00
fufesou
3cdf1cce54 refact: privacy mdoe 1, multi-monitors (#15318)
* refact: privacy mdoe 1, multi-monitors

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix: harden privacy mode overlay & capture cleanup

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-17 21:43:57 +08:00
fufesou
88ae00ba73 refact: restart remote device, autoconnect (#15290)
* refact: restart remote device, autoconnect

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix: guard restart reconnect timer after session close

Signed-off-by: fufesou <linlong1266@gmail.com>

* Simple refactor

Signed-off-by: fufesou <linlong1266@gmail.com>

* fix(restart): auto connect, comments

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-17 17:50:18 +08:00
Maison da Silva
7c26575dbd Update translation for remote toolbar docking message (#15297)
* Update translation for remote toolbar docking message

Update translation for remote toolbar docking message

* Translate 'Display' to 'Tela' in Portuguese locale

* Change translation of 'Display' to 'Exibição'
2026-06-17 17:36:27 +08:00
fufesou
93d064a9b0 refact(oidc): icon azure to microsoft (#15278)
* refact(oidc): icon azure to microsoft

Signed-off-by: fufesou <linlong1266@gmail.com>

* Simple refactor

Signed-off-by: fufesou <linlong1266@gmail.com>

* refact: oidc, remove unused auth-azure.svg

Signed-off-by: fufesou <linlong1266@gmail.com>

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
2026-06-17 14:36:53 +08:00
21 changed files with 266 additions and 60 deletions

View File

@@ -39,7 +39,7 @@ env:
# 2. Update the `VCPKG_COMMIT_ID` in `ci.yml` and `playground.yml`.
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
ARMV7_VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836" # 2025.01.13, got "/opt/artifacts/vcpkg/vcpkg: No such file or directory" with latest version
VERSION: "1.4.7"
VERSION: "1.4.8"
NDK_VERSION: "r28c"
#signing keys env variable checks
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"

View File

@@ -17,7 +17,7 @@ env:
TAG_NAME: "nightly"
VCPKG_BINARY_SOURCES: "clear;x-gha,readwrite"
VCPKG_COMMIT_ID: "120deac3062162151622ca4860575a33844ba10b"
VERSION: "1.4.7"
VERSION: "1.4.8"
NDK_VERSION: "r26d"
#signing keys env variable checks
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"

6
Cargo.lock generated
View File

@@ -3952,7 +3952,7 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
[[package]]
name = "hwcodec"
version = "0.7.1"
source = "git+https://github.com/rustdesk-org/hwcodec#398e5a8938dd8768ade0fcdc27ea80e8b4b38738"
source = "git+https://github.com/rustdesk-org/hwcodec#778df1f99597722473b29443bac22ae6c23946fe"
dependencies = [
"bindgen 0.59.2",
"cc",
@@ -7270,7 +7270,7 @@ dependencies = [
[[package]]
name = "rustdesk"
version = "1.4.7"
version = "1.4.8"
dependencies = [
"android-wakelock",
"android_logger",
@@ -7385,7 +7385,7 @@ dependencies = [
[[package]]
name = "rustdesk-portable-packer"
version = "1.4.7"
version = "1.4.8"
dependencies = [
"brotli",
"dirs 5.0.1",

View File

@@ -1,6 +1,6 @@
[package]
name = "rustdesk"
version = "1.4.7"
version = "1.4.8"
authors = ["rustdesk <info@rustdesk.com>"]
edition = "2021"
build= "build.rs"

View File

@@ -18,7 +18,7 @@ AppDir:
id: rustdesk
name: rustdesk
icon: rustdesk
version: 1.4.7
version: 1.4.8
exec: usr/share/rustdesk/rustdesk
exec_args: $@
apt:

View File

@@ -18,7 +18,7 @@ AppDir:
id: rustdesk
name: rustdesk
icon: rustdesk
version: 1.4.7
version: 1.4.8
exec: usr/share/rustdesk/rustdesk
exec_args: $@
apt:

View File

@@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="256" height="199"><path fill="#0089d6" d="M118.432 187.698c32.89-5.81 60.055-10.618 60.367-10.684l.568-.12-31.052-36.935c-17.078-20.314-31.051-37.014-31.051-37.11 0-.182 32.063-88.477 32.243-88.792.06-.105 21.88 37.567 52.893 91.32 29.035 50.323 52.973 91.815 53.195 92.203l.405.707-98.684-.012-98.684-.013 59.8-10.564zM0 176.435c0-.052 14.631-25.451 32.514-56.442l32.514-56.347 37.891-31.799C123.76 14.358 140.867.027 140.935.001c.069-.026-.205.664-.609 1.534s-18.919 40.582-41.145 88.25l-40.41 86.67-29.386.037c-16.162.02-29.385-.005-29.385-.057z"/></svg>

Before

Width:  |  Height:  |  Size: 604 B

View File

@@ -24,6 +24,35 @@ const kOpSvgList = [
'microsoft'
];
class _OidcProviderBranding {
final String label;
final String iconKey;
const _OidcProviderBranding({
required this.label,
required this.iconKey,
});
}
_OidcProviderBranding _oidcProviderBranding(String op) {
switch (op.toLowerCase()) {
case 'azure':
return _OidcProviderBranding(
label: 'Microsoft',
iconKey: 'microsoft',
);
default:
return _OidcProviderBranding(
label: {
'github': 'GitHub',
'gitlab': 'GitLab',
}[op.toLowerCase()] ??
toCapitalized(op),
iconKey: op.toLowerCase(),
);
}
}
class _IconOP extends StatelessWidget {
final String op;
final String? icon;
@@ -74,11 +103,8 @@ class ButtonOP extends StatelessWidget {
@override
Widget build(BuildContext context) {
final opLabel = {
'github': 'GitHub',
'gitlab': 'GitLab'
}[op.toLowerCase()] ??
toCapitalized(op);
final branding = _oidcProviderBranding(op);
final buttonLabel = translate("Continue with {${branding.label}}");
return Row(children: [
Container(
height: height,
@@ -95,7 +121,7 @@ class ButtonOP extends StatelessWidget {
SizedBox(
width: 30,
child: _IconOP(
op: op,
op: branding.iconKey,
icon: icon,
margin: EdgeInsets.only(right: 5),
),
@@ -103,8 +129,7 @@ class ButtonOP extends StatelessWidget {
Expanded(
child: FittedBox(
fit: BoxFit.scaleDown,
child: Center(
child: Text(translate("Continue with {$opLabel}"))),
child: Center(child: Text(buttonLabel)),
),
),
],

View File

@@ -55,6 +55,8 @@ import 'package:flutter_hbb/native/custom_cursor.dart'
typedef HandleMsgBox = Function(Map<String, dynamic> evt, String id);
typedef ReconnectHandle = Function(OverlayDialogManager, SessionID, bool);
final _constSessionId = Uuid().v4obj();
// Empirical restart reconnect cadence: keep the last frame briefly and retry quickly.
const _restartReconnectSilentDelaySecs = 5;
class CachedPeerData {
Map<String, dynamic> updatePrivacyMode = {};
@@ -119,6 +121,7 @@ class FfiModel with ChangeNotifier {
bool _touchMode = false;
late VirtualMouseMode virtualMouseMode;
Timer? _timer;
Timer? _restartReconnectDelayTimer;
var _reconnects = 1;
DateTime? _offlineReconnectStartTime;
bool _viewOnly = false;
@@ -250,6 +253,7 @@ class FfiModel with ChangeNotifier {
_inputBlocked = false;
_timer?.cancel();
_timer = null;
resetRestartReconnectState();
clearPermissions();
waitForImageTimer?.cancel();
timerScreenshot?.cancel();
@@ -341,6 +345,7 @@ class FfiModel with ChangeNotifier {
} else if (name == 'connection_ready') {
setConnectionType(peerId, evt['secure'] == 'true',
evt['direct'] == 'true', evt['stream_type'] ?? '');
resetRestartReconnectState();
} else if (name == 'switch_display') {
// switch display is kept for backward compatibility
handleSwitchDisplay(evt, sessionId, peerId);
@@ -922,8 +927,28 @@ class FfiModel with ChangeNotifier {
enterUserLoginAndPasswordDialog(
sessionId, dialogManager, 'terminal-admin-login-tip', false);
} else if (type == 'restarting') {
showMsgBox(sessionId, type, title, text, link, false, dialogManager,
hasCancel: false);
// Treat restart messages as reconnect control events. Rust still sends
// title/text for legacy UI and translation reuse; Flutter keeps the last
// frame briefly, then shows the Connecting overlay.
if (_restartReconnectDelayTimer == null) {
parent.target?.inputModel.setRelativeMouseMode(false);
bind.sessionReconnect(sessionId: sessionId, forceRelay: false);
clearPermissions();
// Retry once more after the silent window so restart reconnect attempts
// are spaced by the empirical short cadence instead of only updating UI.
_restartReconnectDelayTimer =
Timer(Duration(seconds: _restartReconnectSilentDelaySecs), () {
_restartReconnectDelayTimer = null;
if (parent.target?.closed == true) {
return;
}
reconnect(dialogManager, sessionId, false);
});
}
} else if (type == 'restarting-show') {
_restartReconnectDelayTimer?.cancel();
_restartReconnectDelayTimer = null;
reconnect(dialogManager, sessionId, false);
} else if (type == 'wait-remote-accept-nook') {
showWaitAcceptDialog(sessionId, type, title, text, dialogManager);
} else if (type == 'on-uac' || type == 'on-foreground-elevated') {
@@ -949,6 +974,11 @@ class FfiModel with ChangeNotifier {
}
}
void resetRestartReconnectState() {
_restartReconnectDelayTimer?.cancel();
_restartReconnectDelayTimer = null;
}
/// Auto-retry check for "Remote desktop is offline" error.
/// returns true to auto-retry, false otherwise.
bool shouldAutoRetryOnOffline(
@@ -1374,6 +1404,7 @@ class FfiModel with ChangeNotifier {
if (displays.isNotEmpty) {
_reconnects = 1;
_offlineReconnectStartTime = null;
resetRestartReconnectState();
waitForFirstImage.value = true;
isRefreshing = false;
}
@@ -3666,6 +3697,7 @@ class FFI {
/// Mobile reuse FFI
void mobileReset() {
ffiModel.resetRestartReconnectState();
ffiModel.waitForFirstImage.value = true;
ffiModel.isRefreshing = false;
ffiModel.waitForImageDialogShow.value = true;
@@ -3879,6 +3911,7 @@ class FFI {
}
if (ffiModel.waitForFirstImage.value == true) {
ffiModel.waitForFirstImage.value = false;
ffiModel.resetRestartReconnectState();
dialogManager.dismissAll();
await canvasModel.updateViewStyle();
await canvasModel.updateScrollStyle();

View File

@@ -16,7 +16,7 @@ publish_to: "none" # Remove this line if you wish to publish to pub.dev
# Read more about iOS versioning at
# https://developer.apple.com/library/archive/documentation/General/Reference/InfoPlistKeyReference/Articles/CoreFoundationKeys.html
# 1.1.9-1 works for android, but for ios it becomes 1.1.91, need to set it to 1.1.9-a.1 for iOS, will get 1.1.9.1, but iOS store not allow 4 numbers
version: 1.4.7+65
version: 1.4.8+66
environment:
sdk: '^3.1.0'

View File

@@ -7,7 +7,8 @@ use fuser::MountOption;
use hbb_common::{config::APP_NAME, log};
use parking_lot::Mutex;
use std::{
path::PathBuf,
io,
path::{Path, PathBuf},
sync::{mpsc::Sender, Arc},
time::Duration,
};
@@ -53,8 +54,16 @@ pub fn init_fuse_context(is_client: bool) -> Result<(), CliprdrError> {
} else {
FUSE_CONTEXT_SERVER.lock()
};
if fuse_context_lock.is_some() {
return Ok(());
if let Some(ctx) = fuse_context_lock.as_ref() {
if is_mount_point_healthy(&ctx.mount_point) {
return Ok(());
}
log::warn!(
"clipboard FUSE mount {} is disconnected, remounting",
ctx.mount_point.display()
);
let stale_context = fuse_context_lock.take();
drop(stale_context);
}
let mount_point = if is_client {
FUSE_MOUNT_POINT_CLIENT.clone()
@@ -159,35 +168,100 @@ struct FuseContext {
}
// this function must be called after the main IPC is up
fn prepare_fuse_mount_point(mount_point: &PathBuf) {
fn prepare_fuse_mount_point(mount_point: &Path) {
use std::{
fs::{self, Permissions},
os::unix::prelude::PermissionsExt,
};
fs::create_dir(mount_point).ok();
fs::set_permissions(mount_point, Permissions::from_mode(0o777)).ok();
if let Some(parent) = mount_point.parent() {
if let Err(e) = fs::create_dir_all(parent) {
log::warn!("failed to create FUSE mount parent {:?}: {:?}", parent, e);
}
}
if let Err(e) = std::process::Command::new("umount")
.arg(mount_point)
.status()
{
log::warn!("umount {:?} may fail: {:?}", mount_point, e);
unmount_fuse_mount_point(mount_point);
if let Err(e) = fs::create_dir_all(mount_point) {
log::warn!(
"failed to create FUSE mount point {:?}: {:?}",
mount_point,
e
);
}
if let Err(e) = fs::set_permissions(mount_point, Permissions::from_mode(0o777)) {
log::warn!(
"failed to set FUSE mount point permissions {:?}: {:?}",
mount_point,
e
);
}
}
fn uninit_fuse_context_(is_client: bool) {
if is_client {
let _ = FUSE_CONTEXT_CLIENT.lock().take();
} else {
let _ = FUSE_CONTEXT_SERVER.lock().take();
fn is_mount_point_healthy(mount_point: &Path) -> bool {
is_mount_point_healthy_result(std::fs::metadata(mount_point))
}
fn is_mount_point_healthy_result<T>(result: io::Result<T>) -> bool {
match result {
Ok(_) => true,
Err(e) => {
e.raw_os_error() != Some(libc::ENOTCONN) && e.kind() != io::ErrorKind::NotFound
}
}
}
fn unmount_fuse_mount_point(mount_point: &Path) {
if run_unmount_command("umount", &["-l"], mount_point) {
return;
}
if run_unmount_command("fusermount3", &["-uz"], mount_point) {
return;
}
run_unmount_command("fusermount", &["-uz"], mount_point);
}
fn run_unmount_command(program: &str, args: &[&str], mount_point: &Path) -> bool {
match std::process::Command::new(program)
.args(args)
.arg(mount_point)
.status()
{
Ok(status) if status.success() => {}
Ok(status) => {
log::debug!(
"{} {:?} exited with status {:?}",
program,
mount_point,
status.code()
);
return false;
}
Err(e) => {
log::debug!("failed to run {} for {:?}: {:?}", program, mount_point, e);
return false;
}
}
true
}
fn uninit_fuse_context_(is_client: bool) {
let mut fuse_context_lock = if is_client {
FUSE_CONTEXT_CLIENT.lock()
} else {
FUSE_CONTEXT_SERVER.lock()
};
let ctx = fuse_context_lock.take();
drop(ctx);
}
impl Drop for FuseContext {
fn drop(&mut self) {
self.session.lock().take().map(|s| s.join());
log::info!("unmounting clipboard FUSE from {}", self.mount_point.display());
unmount_fuse_mount_point(&self.mount_point);
if let Some(session) = self.session.lock().take() {
session.join();
}
}
}
@@ -223,3 +297,30 @@ impl FuseContext {
.collect())
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::{fs, io};
#[test]
fn reports_disconnected_fuse_mount_as_unhealthy() {
let err = io::Error::from_raw_os_error(libc::ENOTCONN);
assert!(!is_mount_point_healthy_result::<()>(Err(err)));
}
#[test]
fn reports_existing_directory_mount_point_as_healthy() {
let mount_point = std::env::temp_dir().join(format!(
"rustdesk-fuse-mount-health-test-{}",
std::process::id()
));
let _ = fs::remove_dir_all(&mount_point);
fs::create_dir(&mount_point).unwrap();
assert!(is_mount_point_healthy(&mount_point));
let _ = fs::remove_dir_all(&mount_point);
}
}

View File

@@ -1,6 +1,6 @@
[package]
name = "rustdesk-portable-packer"
version = "1.4.7"
version = "1.4.8"
edition = "2021"
description = "RustDesk Remote Desktop"

View File

@@ -1,5 +1,5 @@
pkgname=rustdesk
pkgver=1.4.7
pkgver=1.4.8
pkgrel=0
epoch=
pkgdesc=""

View File

@@ -1,3 +1,3 @@
#! /usr/bin/env bash
sed -i "s/$1/$2/g" res/*spec res/PKGBUILD flutter/pubspec.yaml Cargo.toml .github/workflows/*yml flatpak/*json appimage/*yml libs/portable/Cargo.toml
sed -i "s/\b$1\b/$2/g" res/*spec res/PKGBUILD flutter/pubspec.yaml Cargo.toml .github/workflows/*yml flatpak/*json appimage/*yml libs/portable/Cargo.toml
cargo run # to bump version in cargo lock

View File

@@ -1,5 +1,5 @@
Name: rustdesk
Version: 1.4.7
Version: 1.4.8
Release: 0
Summary: RPM package
License: GPL-3.0

View File

@@ -1,5 +1,5 @@
Name: rustdesk
Version: 1.4.7
Version: 1.4.8
Release: 0
Summary: RPM package
License: GPL-3.0

View File

@@ -1,5 +1,5 @@
Name: rustdesk
Version: 1.4.7
Version: 1.4.8
Release: 0
Summary: RPM package
License: GPL-3.0

View File

@@ -96,6 +96,8 @@ pub mod screenshot;
pub const MILLI1: Duration = Duration::from_millis(1);
pub const SEC30: Duration = Duration::from_secs(30);
// Empirical restart reconnect grace window.
const RESTART_REMOTE_DEVICE_GRACE: Duration = Duration::from_secs(5 * 60);
pub const VIDEO_QUEUE_SIZE: usize = 120;
const MAX_DECODE_FAIL_COUNTER: usize = 3;
@@ -1740,7 +1742,10 @@ pub struct LoginConfigHandler {
features: Option<Features>,
pub session_id: u64, // used for local <-> server communication
pub supported_encoding: SupportedEncoding,
pub restarting_remote_device: bool,
restarting_remote_device: bool,
// Start time of the restart grace window. On Windows the peer may briefly
// reconnect before the real reboot disconnect.
restart_remote_device_at: Option<Instant>,
pub force_relay: bool,
pub direct: Option<bool>,
pub received: bool,
@@ -1849,7 +1854,7 @@ impl LoginConfigHandler {
}
self.session_id = sid;
self.supported_encoding = Default::default();
self.restarting_remote_device = false;
self.clear_restarting_remote_device();
self.force_relay =
config::option2bool("force-always-relay", &self.get_option("force-always-relay"))
|| force_relay
@@ -2779,6 +2784,30 @@ impl LoginConfigHandler {
msg_out
}
pub fn mark_restarting_remote_device(&mut self) {
self.restarting_remote_device = true;
self.restart_remote_device_at = Some(Instant::now());
}
pub fn clear_restarting_remote_device(&mut self) {
self.restarting_remote_device = false;
self.restart_remote_device_at = None;
}
pub fn is_restarting_remote_device(&self) -> bool {
if !self.restarting_remote_device {
return false;
}
// Keep this flag alive for a short grace window instead of clearing it on
// connection_ready or the first peer bytes. During OS restart the peer can
// briefly reconnect before the real reboot disconnect, and clearing it too
// early would let the next disconnect escape the restart flow and fall back
// to the normal error dialog / manual reconnect path.
self.restart_remote_device_at
.map(|started_at| started_at.elapsed() < RESTART_REMOTE_DEVICE_GRACE)
.unwrap_or(false)
}
pub fn get_conn_token(&self) -> Option<String> {
if self.password.is_empty() {
return None;
@@ -3718,9 +3747,18 @@ pub trait Interface: Send + Clone + 'static + Sized {
fn on_establish_connection_error(&self, err: String) {
let title = "Connection Error";
let text = err.to_string();
let lc = self.get_lch();
let direct = lc.read().unwrap().direct;
let received = lc.read().unwrap().received;
let lch = self.get_lch();
let (is_restarting, direct, received) = {
let lc = lch.read().unwrap();
(lc.is_restarting_remote_device(), lc.direct, lc.received)
};
if is_restarting {
log::info!("Restart remote device, suppress connection error: {err}");
// Flutter treats this as a reconnect control event. The text is kept
// for legacy UI and existing translation reuse.
self.msgbox("restarting", "Restarting remote device", "Connection in progress. Please wait.", "");
return;
}
let mut relay_hint = false;
let mut relay_hint_type = "relay-hint";

View File

@@ -10,6 +10,10 @@ use crate::{
common::get_default_sound_input,
ui_session_interface::{InvokeUiSession, Session},
};
// Empirical no-data window before exposing the restart reconnect state to the UI.
// Restart msgbox text is kept as a legacy UI fallback; Flutter handles the type as a control event.
const RESTART_REMOTE_DEVICE_NO_DATA_TIMEOUT: Duration = Duration::from_secs(5);
#[cfg(feature = "unix-file-copy-paste")]
use crate::{clipboard::try_empty_clipboard_files, clipboard_file::unix_file_clip};
#[cfg(any(
@@ -153,7 +157,6 @@ impl<T: InvokeUiSession> Remote<T> {
}
};
let mut last_recv_time = Instant::now();
let mut received = false;
let conn_type = if self.handler.is_file_transfer() {
ConnType::FILE_TRANSFER
@@ -219,6 +222,7 @@ impl<T: InvokeUiSession> Remote<T> {
let mut fps_instant = Instant::now();
let _keep_it = client::hc_connection(feedback, rendezvous_server, token).await;
let mut last_recv_time = Instant::now();
loop {
tokio::select! {
@@ -244,7 +248,7 @@ impl<T: InvokeUiSession> Remote<T> {
} else {
if self.handler.is_restarting_remote_device() {
log::info!("Restart remote device");
self.handler.msgbox("restarting", "Restarting remote device", "remote_restarting_tip", "");
self.handler.msgbox("restarting", "Restarting remote device", "Connection in progress. Please wait.", "");
} else {
log::info!("Reset by the peer");
self.handler.msgbox("error", "Connection Error", "Reset by the peer", "");
@@ -279,6 +283,12 @@ impl<T: InvokeUiSession> Remote<T> {
}
}
_ = status_timer.tick() => {
if self.handler.is_restarting_remote_device()
&& last_recv_time.elapsed() >= RESTART_REMOTE_DEVICE_NO_DATA_TIMEOUT
{
self.handler.msgbox("restarting-show", "Restarting remote device", "Connection in progress. Please wait.", "");
break;
}
let elapsed = fps_instant.elapsed().as_millis();
if elapsed < 1000 {
continue;

View File

@@ -24,9 +24,9 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Refresh random password", "Atualizar senha aleatória"),
("Set your own password", "Configure sua própria senha"),
("Enable keyboard/mouse", "Habilitar teclado/mouse"),
("Enable clipboard", "Habilitar Área de Transferência"),
("Enable file transfer", "Habilitar Transferência de Arquivos"),
("Enable TCP tunneling", "Habilitar Tunelamento TCP"),
("Enable clipboard", "Habilitar área de transferência"),
("Enable file transfer", "Habilitar transferência de arquivos"),
("Enable TCP tunneling", "Habilitar tunelamento TCP"),
("IP Whitelisting", "Lista de IPs Confiáveis"),
("ID/Relay Server", "Servidor ID/Relay"),
("Import server config", "Importar Configuração do Servidor"),
@@ -430,7 +430,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Strong", "Forte"),
("Switch Sides", "Trocar de lado"),
("Please confirm if you want to share your desktop?", "Por favor, confirme se você deseja compartilhar sua área de trabalho?"),
("Display", "Display"),
("Display", "Exibição"),
("Default View Style", "Estilo de Visualização Padrão"),
("Default Scroll Style", "Estilo de Rolagem Padrão"),
("Default Image Quality", "Qualidade de Imagem Padrão"),
@@ -693,11 +693,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Enable IPv6 P2P connection", "Habilitar conexão IPv6 P2P"),
("Enable UDP hole punching", "Habilitar UDP hole punching"),
("View camera", "Visualizar câmera"),
("Enable camera", "Ativar câmera"),
("No cameras", "Sem câmeras"),
("Enable camera", "Habilitar câmera"),
("No cameras", "Nenhuma câmeras"),
("view_camera_unsupported_tip", "O dispositivo remoto não suporta visualização da câmera."),
("Terminal", "Terminal"),
("Enable terminal", "Habilitar Terminal"),
("Enable terminal", "Habilitar terminal"),
("New tab", "Nova aba"),
("Keep terminal sessions on disconnect", "Manter sessões de terminal ao desconectar"),
("Terminal (Run as administrator)", "Terminal (Executar como administrador)"),
@@ -744,7 +744,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("password-hidden-tip", "A senha permanente está definida como (oculta)."),
("preset-password-in-use-tip", "A senha predefinida está sendo usada."),
("Enable privacy mode", "Habilitar modo de privacidade"),
("allow-remote-toolbar-docking-any-edge", "Permitir fixar a barra de ferramentas remota em qualquer borda da janela"),
("allow-remote-toolbar-docking-any-edge", "Fixar a barra de ferramentas remota em qualquer borda da janela"),
("API Token", "Token de API"),
("Deploy", "Implantar"),
("Custom ID (optional)", "ID personalizado (opcional)"),

View File

@@ -560,7 +560,7 @@ impl<T: InvokeUiSession> Session<T> {
pub fn restart_remote_device(&self) {
let mut lc = self.lc.write().unwrap();
lc.restarting_remote_device = true;
lc.mark_restarting_remote_device();
let msg = lc.restart_remote_device();
self.send(Data::Message(msg));
}
@@ -656,7 +656,7 @@ impl<T: InvokeUiSession> Session<T> {
}
pub fn is_restarting_remote_device(&self) -> bool {
self.lc.read().unwrap().restarting_remote_device
self.lc.read().unwrap().is_restarting_remote_device()
}
#[inline]