Merge branch 'master' into keyboard

This commit is contained in:
fufesou 2022-12-14 11:12:55 +08:00
commit 47658667d6
19 changed files with 424 additions and 233 deletions

View File

@ -47,8 +47,8 @@ jobs:
run: |
flutter doctor -v
flutter precache --windows
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk/windows-x64-release-flutter.zip -OutFile windows-x64-release-flutter.zip
Expand-Archive windows-x64-release-flutter.zip -DestinationPath engine
Invoke-WebRequest -Uri https://github.com/Kingtous/engine/releases/download/v3.0.5-rustdesk.2/windows-x64-flutter-release.zip -OutFile windows-x64-flutter-release.zip
Expand-Archive windows-x64-flutter-release.zip -DestinationPath engine
mv -Force engine/* C:/hostedtoolcache/windows/flutter/stable-3.0.5-x64/bin/cache/artifacts/engine/windows-x64-release/
- name: Install Rust toolchain

408
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -47,7 +47,7 @@ libc = "0.2"
parity-tokio-ipc = { git = "https://github.com/open-trade/parity-tokio-ipc" }
flexi_logger = { version = "0.22", features = ["async", "use_chrono_for_offset"] }
runas = "0.2"
magnum-opus = { git = "https://github.com/SoLongAndThanksForAllThePizza/magnum-opus" }
magnum-opus = { git = "https://github.com/rustdesk/magnum-opus" }
dasp = { version = "0.11", features = ["signal", "interpolate-linear", "interpolate"], optional = true }
rubato = { version = "0.12", optional = true }
samplerate = { version = "0.2", optional = true }
@ -118,6 +118,7 @@ dbus = "0.9"
dbus-crossroads = "0.5"
gtk = "0.15"
libappindicator = "0.7"
glib = "0.16.5"
[target.'cfg(target_os = "android")'.dependencies]
android_logger = "0.11"

View File

@ -5,6 +5,8 @@ import 'dart:ui' as ui;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_custom_cursor/cursor_manager.dart'
as custom_cursor_manager;
import 'package:get/get.dart';
import 'package:provider/provider.dart';
import 'package:wakelock/wakelock.dart';
@ -109,17 +111,17 @@ class _RemotePageState extends State<RemotePage>
id: widget.id, arg: 'show-remote-cursor');
_zoomCursor.value =
bind.sessionGetToggleOptionSync(id: widget.id, arg: 'zoom-cursor');
if (!_isCustomCursorInited) {
customCursorController.registerNeedUpdateCursorCallback(
(String? lastKey, String? currentKey) async {
if (_firstEnterImage.value) {
_firstEnterImage.value = false;
return true;
}
return lastKey == null || lastKey != currentKey;
});
_isCustomCursorInited = true;
}
// if (!_isCustomCursorInited) {
// customCursorController.registerNeedUpdateCursorCallback(
// (String? lastKey, String? currentKey) async {
// if (_firstEnterImage.value) {
// _firstEnterImage.value = false;
// return true;
// }
// return lastKey == null || lastKey != currentKey;
// });
// _isCustomCursorInited = true;
// }
}
@override
@ -366,15 +368,23 @@ class _ImagePaintState extends State<ImagePaint> {
return MouseCursor.defer;
} else {
final key = cache.updateGetKey(scale, zoomCursor.value);
cursor.addKey(key);
return FlutterCustomMemoryImageCursor(
pixbuf: cache.data,
key: key,
hotx: cache.hotx,
hoty: cache.hoty,
imageWidth: (cache.width * cache.scale).toInt(),
imageHeight: (cache.height * cache.scale).toInt(),
);
if (!cursor.cachedKeys.contains(key)) {
debugPrint("Register custom cursor with key $key");
// [Safety]
// It's ok to call async registerCursor in current synchronous context,
// because activating the cursor is also an async call and will always
// be executed after this.
custom_cursor_manager.CursorManager.instance
.registerCursor(custom_cursor_manager.CursorData()
..buffer = cache.data!
..height = (cache.height * cache.scale).toInt()
..width = (cache.width * cache.scale).toInt()
..hotX = cache.hotx
..hotY = cache.hoty
..name = key);
cursor.addKey(key);
}
return FlutterCustomMemoryImageCursor(key: key);
}
}

View File

@ -19,7 +19,7 @@ import 'package:flutter_hbb/common/shared_state.dart';
import 'package:flutter_hbb/utils/multi_window_manager.dart';
import 'package:tuple/tuple.dart';
import 'package:image/image.dart' as img2;
import 'package:flutter_custom_cursor/flutter_custom_cursor.dart';
import 'package:flutter_custom_cursor/cursor_manager.dart';
import 'package:flutter_svg/flutter_svg.dart';
import '../common.dart';
@ -1113,7 +1113,8 @@ class CursorModel with ChangeNotifier {
_clearCache() {
final keys = {...cachedKeys};
for (var k in keys) {
customCursorController.freeCache(k);
debugPrint("deleting cursor with key $k");
CursorManager.instance.deleteCursor(k);
}
}
}

View File

@ -7,7 +7,7 @@ packages:
name: _fe_analyzer_shared
url: "https://pub.dartlang.org"
source: hosted
version: "49.0.0"
version: "50.0.0"
after_layout:
dependency: transitive
description:
@ -21,7 +21,7 @@ packages:
name: analyzer
url: "https://pub.dartlang.org"
source: hosted
version: "5.1.0"
version: "5.2.0"
animations:
dependency: transitive
description:
@ -352,7 +352,7 @@ packages:
name: file_picker
url: "https://pub.dartlang.org"
source: hosted
version: "5.2.1"
version: "5.2.3"
fixnum:
dependency: transitive
description:
@ -389,12 +389,10 @@ packages:
flutter_custom_cursor:
dependency: "direct main"
description:
path: "."
ref: "74b1b314142b6775c1243067a3503ac568ebc74b"
resolved-ref: "74b1b314142b6775c1243067a3503ac568ebc74b"
url: "https://github.com/Kingtous/rustdesk_flutter_custom_cursor"
source: git
version: "0.0.1"
name: flutter_custom_cursor
url: "https://pub.dartlang.org"
source: hosted
version: "0.0.2"
flutter_improved_scrolling:
dependency: "direct main"
description:
@ -455,14 +453,14 @@ packages:
name: freezed
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.1"
version: "2.3.2"
freezed_annotation:
dependency: "direct main"
description:
name: freezed_annotation
url: "https://pub.dartlang.org"
source: hosted
version: "2.1.0"
version: "2.2.0"
frontend_server_client:
dependency: transitive
description:
@ -637,7 +635,7 @@ packages:
name: mime
url: "https://pub.dartlang.org"
source: hosted
version: "1.0.2"
version: "1.0.3"
nested:
dependency: transitive
description:
@ -1106,7 +1104,7 @@ packages:
name: video_player
url: "https://pub.dartlang.org"
source: hosted
version: "2.4.7"
version: "2.4.9"
video_player_android:
dependency: transitive
description:

View File

@ -65,10 +65,7 @@ dependencies:
url: https://github.com/Kingtous/rustdesk_desktop_multi_window
ref: 82f9eab81cb2c7bfb938def7a1b399a6279bbc75
freezed_annotation: ^2.0.3
flutter_custom_cursor:
git:
url: https://github.com/Kingtous/rustdesk_flutter_custom_cursor
ref: 74b1b314142b6775c1243067a3503ac568ebc74b
flutter_custom_cursor: ^0.0.2
window_size:
git:
url: https://github.com/google/flutter-desktop-embedding.git

View File

@ -66,6 +66,21 @@ macro_rules! allow_err {
} else {
}
};
($e:expr, $($arg:tt)*) => {
if let Err(err) = $e {
log::debug!(
"{:?}, {}, {}:{}:{}:{}",
err,
format_args!($($arg)*),
module_path!(),
file!(),
line!(),
column!()
);
} else {
}
};
}
#[inline]
@ -250,4 +265,10 @@ mod tests {
let addr = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(192, 168, 16, 32), 21116));
assert_eq!(addr, AddrMangle::decode(&AddrMangle::encode(addr)));
}
#[test]
fn test_allow_err() {
allow_err!(Err("test err") as Result<(), &str>);
allow_err!(Err("test err with msg") as Result<(), &str>, "prompt {}", "failed");
}
}

View File

@ -218,7 +218,7 @@ impl Encoder {
#[inline]
pub fn current_hw_encoder_name() -> Option<String> {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
if enable_hwcodec_option() {
return HwEncoder::current_name().lock().unwrap().clone();
} else {
return None;
@ -229,7 +229,7 @@ impl Encoder {
pub fn supported_encoding() -> (bool, bool) {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
if enable_hwcodec_option() {
let best = HwEncoder::best();
(
best.h264.as_ref().map_or(false, |c| c.score > 0),
@ -246,7 +246,7 @@ impl Encoder {
impl Decoder {
pub fn video_codec_state(_id: &str) -> VideoCodecState {
#[cfg(feature = "hwcodec")]
if check_hwcodec_config() {
if enable_hwcodec_option() {
let best = HwDecoder::best();
return VideoCodecState {
score_vpx: SCORE_VPX,
@ -257,7 +257,7 @@ impl Decoder {
};
}
#[cfg(feature = "mediacodec")]
if check_hwcodec_config() {
if enable_hwcodec_option() {
let score_h264 = if H264_DECODER_SUPPORT.load(std::sync::atomic::Ordering::SeqCst) {
92
} else {
@ -287,11 +287,19 @@ impl Decoder {
Decoder {
vpx,
#[cfg(feature = "hwcodec")]
hw: HwDecoder::new_decoders(),
hw: if enable_hwcodec_option() {
HwDecoder::new_decoders()
} else {
HwDecoders::default()
},
#[cfg(feature = "hwcodec")]
i420: vec![],
#[cfg(feature = "mediacodec")]
media_codec: MediaCodecDecoder::new_decoders(),
media_codec: if enable_hwcodec_option() {
MediaCodecDecoder::new_decoders()
} else {
MediaCodecDecoders::default()
},
}
}
@ -415,7 +423,7 @@ impl Decoder {
}
#[cfg(any(feature = "hwcodec", feature = "mediacodec"))]
fn check_hwcodec_config() -> bool {
fn enable_hwcodec_option() -> bool {
if let Some(v) = Config2::get().options.get("enable-hwcodec") {
return v != "N";
}

View File

@ -94,7 +94,7 @@ impl EncoderApi for HwEncoder {
frames.push(EncodedVideoFrame {
data: Bytes::from(frame.data),
pts: frame.pts as _,
key:frame.key == 1,
key: frame.key == 1,
..Default::default()
});
}
@ -175,6 +175,7 @@ pub struct HwDecoder {
pub info: CodecInfo,
}
#[derive(Default)]
pub struct HwDecoders {
pub h264: Option<HwDecoder>,
pub h265: Option<HwDecoder>,

View File

@ -37,6 +37,7 @@ impl Deref for MediaCodecDecoder {
}
}
#[derive(Default)]
pub struct MediaCodecDecoders {
pub h264: Option<MediaCodecDecoder>,
pub h265: Option<MediaCodecDecoder>,

View File

@ -173,7 +173,7 @@ pub fn core_main() -> Option<Vec<String>> {
crate::start_os_service();
return None;
} else if args[0] == "--server" {
log::info!("start --server");
log::info!("start --server with user {}", crate::username());
#[cfg(target_os = "windows")]
{
crate::start_server(true);

View File

@ -56,7 +56,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Too frequent", "Zu häufig"),
("Cancel", "Abbrechen"),
("Skip", "Überspringen"),
("Close", "Sitzung beenden"),
("Close", "Schließen"),
("Retry", "Erneut versuchen"),
("OK", "OK"),
("Password Required", "Passwort erforderlich"),
@ -358,7 +358,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Unpin menubar", "Menüleiste lösen"),
("Recording", "Aufnahme"),
("Directory", "Verzeichnis"),
("Automatically record incoming sessions", "Automatische Aufzeichnung eingehender Sitzungen"),
("Automatically record incoming sessions", "Eingehende Sitzungen automatisch aufzeichnen"),
("Change", "Ändern"),
("Start session recording", "Sitzungsaufzeichnung starten"),
("Stop session recording", "Sitzungsaufzeichnung beenden"),
@ -398,7 +398,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Hide connection management window", "Fenster zur Verwaltung der Verbindung verstecken"),
("hide_cm_tip", "Dies ist nur möglich, wenn der Zugriff nur über ein permanentes Passwort erfolgt."), // Sehr unklar. Muss noch angepasst werden. Original: Allow hiding only if accepting sessions via password and using pernament passw"),
("wayland_experiment_tip", ""),
("Right click to select tabs", ""),
("Add to Address Book", ""),
("Right click to select tabs", "Register mit rechtem Mausklick auswählen"),
("Add to Address Book", "Zum Adressbuch hinzufügen"),
].iter().cloned().collect();
}

View File

@ -17,7 +17,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Transfer File", "Transferir archivo"),
("Connect", "Conectar"),
("Recent Sessions", "Sesiones recientes"),
("Address Book", "Directorio"),
("Address Book", "Libreta de direcciones"),
("Confirmation", "Confirmación"),
("TCP Tunneling", "Túnel TCP"),
("Remove", "Quitar"),

View File

@ -179,7 +179,8 @@ fn set_x11_env(uid: &str) {
log::info!("uid of seat0: {}", uid);
let gdm = format!("/run/user/{}/gdm/Xauthority", uid);
let mut auth = get_env_tries("XAUTHORITY", uid, 10);
if auth.is_empty() {
// auth is another user's when uid = 0, https://github.com/rustdesk/rustdesk/issues/2468
if auth.is_empty() || uid == "0" {
auth = if std::path::Path::new(&gdm).exists() {
gdm
} else {

View File

@ -439,6 +439,7 @@ extern "C" {
fn win32_disable_lowlevel_keyboard(hwnd: HWND);
fn win_stop_system_key_propagate(v: BOOL);
fn is_win_down() -> BOOL;
fn is_local_system() -> BOOL;
}
extern "system" {
@ -718,10 +719,10 @@ pub fn set_share_rdp(enable: bool) {
}
pub fn get_active_username() -> String {
let name = crate::username();
if name != "SYSTEM" {
return name;
if !is_root() {
return crate::username();
}
extern "C" {
fn get_active_user(path: *mut u16, n: u32, rdp: BOOL) -> u32;
}
@ -757,7 +758,8 @@ pub fn is_prelogin() -> bool {
}
pub fn is_root() -> bool {
crate::username() == "SYSTEM"
// https://stackoverflow.com/questions/4023586/correct-way-to-find-out-if-a-service-is-running-as-the-system-user
unsafe { is_local_system() == TRUE }
}
pub fn lock_screen() {

View File

@ -379,7 +379,9 @@ impl RendezvousMediator {
)
.await?;
let local_addr = socket.local_addr();
allow_err!(socket_client::connect_tcp(peer_addr, local_addr, 300).await);
// key important here for punch hole to tell my gateway incoming peer is safe.
// it can not be async here, because local_addr can not be reused, we must close the connection before use it again.
allow_err!(socket_client::connect_tcp(peer_addr, local_addr, 30).await);
socket
};
let mut msg_out = Message::new();

View File

@ -88,6 +88,9 @@ pub fn start_tray() {
/// This function will block current execution, show the tray icon and handle events.
#[cfg(target_os = "linux")]
pub fn start_tray() {
use std::time::Duration;
use glib::{clone, Continue};
use gtk::traits::{GtkMenuItemExt, MenuShellExt, WidgetExt};
info!("configuring tray");
@ -106,9 +109,9 @@ pub fn start_tray() {
crate::client::translate("Stop service".to_owned())
};
let menu_item_service = gtk::MenuItem::with_label(label.as_str());
menu_item_service.connect_activate(move |item| {
menu_item_service.connect_activate(move |_| {
let _lock = crate::ui_interface::SENDER.lock().unwrap();
update_tray_service_item(item);
change_service_state();
});
menu.append(&menu_item_service);
// show tray item
@ -116,6 +119,16 @@ pub fn start_tray() {
appindicator.set_menu(&mut menu);
// start event loop
info!("Setting tray event loop");
// check the connection status for every second
glib::timeout_add_local(
Duration::from_secs(1),
clone!(@strong menu_item_service as item => move || {
let _lock = crate::ui_interface::SENDER.lock().unwrap();
update_tray_service_item(&item);
// continue to trigger the next status check
Continue(true)
}),
);
gtk::main();
} else {
error!("Tray process exit now");
@ -123,17 +136,25 @@ pub fn start_tray() {
}
#[cfg(target_os = "linux")]
fn change_service_state() {
if is_service_stoped() {
debug!("Now try to start service");
crate::ipc::set_option("stop-service", "");
} else {
debug!("Now try to stop service");
crate::ipc::set_option("stop-service", "Y");
}
}
#[cfg(target_os = "linux")]
#[inline]
fn update_tray_service_item(item: &gtk::MenuItem) {
use gtk::traits::GtkMenuItemExt;
if is_service_stoped() {
debug!("Now try to start service");
item.set_label(&crate::client::translate("Stop service".to_owned()));
crate::ipc::set_option("stop-service", "");
} else {
debug!("Now try to stop service");
item.set_label(&crate::client::translate("Start Service".to_owned()));
crate::ipc::set_option("stop-service", "Y");
} else {
item.set_label(&crate::client::translate("Stop service".to_owned()));
}
}
@ -189,10 +210,10 @@ pub fn make_tray() {
match mode {
dark_light::Mode::Dark => {
icon_path = "mac-tray-light.png";
},
}
dark_light::Mode::Light => {
icon_path = "mac-tray-dark.png";
},
}
}
if let Ok(mut tray) = TrayItem::new(&crate::get_app_name(), icon_path) {
tray.add_label(&format!(
@ -211,4 +232,3 @@ pub fn make_tray() {
}
}
}

View File

@ -588,4 +588,44 @@ extern "C"
stop_system_key_propagate = v;
}
// https://stackoverflow.com/questions/4023586/correct-way-to-find-out-if-a-service-is-running-as-the-system-user
BOOL is_local_system()
{
HANDLE hToken;
UCHAR bTokenUser[sizeof(TOKEN_USER) + 8 + 4 * SID_MAX_SUB_AUTHORITIES];
PTOKEN_USER pTokenUser = (PTOKEN_USER)bTokenUser;
ULONG cbTokenUser;
SID_IDENTIFIER_AUTHORITY siaNT = SECURITY_NT_AUTHORITY;
PSID pSystemSid;
BOOL bSystem;
// open process token
if (!OpenProcessToken(GetCurrentProcess(),
TOKEN_QUERY,
&hToken))
return FALSE;
// retrieve user SID
if (!GetTokenInformation(hToken, TokenUser, pTokenUser,
sizeof(bTokenUser), &cbTokenUser))
{
CloseHandle(hToken);
return FALSE;
}
CloseHandle(hToken);
// allocate LocalSystem well-known SID
if (!AllocateAndInitializeSid(&siaNT, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &pSystemSid))
return FALSE;
// compare the user SID from the token with the LocalSystem SID
bSystem = EqualSid(pTokenUser->User.Sid, pSystemSid);
FreeSid(pSystemSid);
return bSystem;
}
} // end of extern "C"