feat: take screenshot (#11591)

* feat: take screenshot

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

* screenshot, vram temp switch capturer

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

* fix: misspelling

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

* screenshot, taking

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

* screenshot, rgba stride

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

* Bumps 1.4.0

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

---------

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou 2025-04-30 17:23:35 +08:00 committed by GitHub
parent 2864e1984a
commit c626c2414d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
82 changed files with 948 additions and 96 deletions

View file

@ -38,7 +38,7 @@ env:
# https://github.com/rustdesk/rustdesk/actions/runs/14414119794/job/40427970174
# 2. Update the `VCPKG_COMMIT_ID` in `ci.yml` and `playground.yml`.
VCPKG_COMMIT_ID: "6f29f12e82a8293156836ad81cc9bf5af41fe836"
VERSION: "1.3.9"
VERSION: "1.4.0"
NDK_VERSION: "r27c"
#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: "6f29f12e82a8293156836ad81cc9bf5af41fe836"
VERSION: "1.3.9"
VERSION: "1.4.0"
NDK_VERSION: "r26d"
#signing keys env variable checks
ANDROID_SIGNING_KEY: "${{ secrets.ANDROID_SIGNING_KEY }}"

4
Cargo.lock generated
View file

@ -5857,7 +5857,7 @@ dependencies = [
[[package]]
name = "rustdesk"
version = "1.3.9"
version = "1.4.0"
dependencies = [
"android-wakelock",
"android_logger",
@ -5960,7 +5960,7 @@ dependencies = [
[[package]]
name = "rustdesk-portable-packer"
version = "1.3.9"
version = "1.4.0"
dependencies = [
"brotli",
"dirs 5.0.1",

View file

@ -1,6 +1,6 @@
[package]
name = "rustdesk"
version = "1.3.9"
version = "1.4.0"
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.3.9
version: 1.4.0
exec: usr/share/rustdesk/rustdesk
exec_args: $@
apt:

View file

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

View file

@ -1,3 +1,4 @@
import 'dart:async';
import 'dart:convert';
import 'package:flutter/material.dart';
@ -15,7 +16,7 @@ bool isEditOsPassword = false;
class TTextMenu {
final Widget child;
final VoidCallback onPressed;
final VoidCallback? onPressed;
Widget? trailingIcon;
bool divider;
TTextMenu(
@ -294,6 +295,41 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
),
onPressed: () => ffi.recordingModel.toggle()));
}
// to-do:
// 1. Web desktop
// 2. Mobile, copy the image to the clipboard
if (isDesktop) {
final isScreenshotSupported = bind.sessionGetCommonSync(
sessionId: sessionId, key: 'is_screenshot_supported', param: '');
if ('true' == isScreenshotSupported) {
v.add(TTextMenu(
child: Text(ffi.ffiModel.timerScreenshot != null
? '${translate('Taking screenshot')} ...'
: translate('Take screenshot')),
onPressed: ffi.ffiModel.timerScreenshot != null
? null
: () {
if (pi.currentDisplay == kAllDisplayValue) {
msgBox(
sessionId,
'custom-nook-nocancel-hasclose-info',
'Take screenshot',
'screenshot-merged-screen-not-supported-tip',
'',
ffi.dialogManager);
} else {
bind.sessionTakeScreenshot(
sessionId: sessionId, display: pi.currentDisplay);
ffi.ffiModel.timerScreenshot =
Timer(Duration(seconds: 30), () {
ffi.ffiModel.timerScreenshot = null;
});
}
},
));
}
}
// fingerprint
if (!(isDesktop || isWebDesktop)) {
v.add(TTextMenu(

View file

@ -220,7 +220,8 @@ const double kDefaultQuality = 50;
const double kMaxQuality = 100;
const double kMaxMoreQuality = 2000;
const String kKeyPrinterIncommingJobAction = 'printer-incomming-job-action';
// incomming (should be incoming) is kept, because change it will break the previous setting.
const String kKeyPrinterIncomingJobAction = 'printer-incomming-job-action';
const String kValuePrinterIncomingJobDismiss = 'dismiss';
const String kValuePrinterIncomingJobDefault = '';
const String kValuePrinterIncomingJobSelected = 'selected';

View file

@ -1908,7 +1908,7 @@ class __PrinterState extends State<_Printer> {
final scrollController = ScrollController();
return ListView(controller: scrollController, children: [
outgoing(context),
incomming(context),
incoming(context),
]).marginOnly(bottom: _kListViewBottomMargin);
}
@ -1995,15 +1995,15 @@ class __PrinterState extends State<_Printer> {
return _Card(title: 'Outgoing Print Jobs', children: children);
}
Widget incomming(BuildContext context) {
Widget incoming(BuildContext context) {
onRadioChanged(String value) async {
await bind.mainSetLocalOption(
key: kKeyPrinterIncommingJobAction, value: value);
key: kKeyPrinterIncomingJobAction, value: value);
setState(() {});
}
PrinterOptions printerOptions = PrinterOptions.load();
return _Card(title: 'Incomming Print Jobs', children: [
return _Card(title: 'Incoming Print Jobs', children: [
_Radio(context,
value: kValuePrinterIncomingJobDismiss,
groupValue: printerOptions.action,

View file

@ -695,9 +695,9 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
);
if (index != null) {
if (index < mobileActionMenus.length) {
mobileActionMenus[index].onPressed.call();
mobileActionMenus[index].onPressed?.call();
} else if (index < mobileActionMenus.length + more.length) {
menus[index - mobileActionMenus.length].onPressed.call();
menus[index - mobileActionMenus.length].onPressed?.call();
}
}
}();
@ -770,7 +770,7 @@ class _RemotePageState extends State<RemotePage> with WidgetsBindingObserver {
elevation: 8,
);
if (index != null && index < menus.length) {
menus[index].onPressed.call();
menus[index].onPressed?.call();
}
});
}
@ -1267,7 +1267,7 @@ void showOptions(
title: resolution.child,
onTap: () {
close();
resolution.onPressed();
resolution.onPressed?.call();
},
));
}
@ -1279,7 +1279,7 @@ void showOptions(
title: virtualDisplayMenu.child,
onTap: () {
close();
virtualDisplayMenu.onPressed();
virtualDisplayMenu.onPressed?.call();
},
));
}

View file

@ -243,7 +243,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
Widget build(BuildContext context) {
Provider.of<FfiModel>(context);
final outgoingOnly = bind.isOutgoingOnly();
final incommingOnly = bind.isIncomingOnly();
final incomingOnly = bind.isIncomingOnly();
final customClientSection = CustomSettingsSection(
child: Column(
children: [
@ -728,7 +728,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
});
},
),
if (!incommingOnly)
if (!incomingOnly)
SettingsTile.switchTile(
title:
Text(translate('Automatically record outgoing sessions')),

View file

@ -478,9 +478,9 @@ class _ViewCameraPageState extends State<ViewCameraPage>
);
if (index != null) {
if (index < mobileActionMenus.length) {
mobileActionMenus[index].onPressed.call();
mobileActionMenus[index].onPressed?.call();
} else if (index < mobileActionMenus.length + more.length) {
menus[index - mobileActionMenus.length].onPressed.call();
menus[index - mobileActionMenus.length].onPressed?.call();
}
}
}();
@ -553,7 +553,7 @@ class _ViewCameraPageState extends State<ViewCameraPage>
elevation: 8,
);
if (index != null && index < menus.length) {
menus[index].onPressed.call();
menus[index].onPressed?.call();
}
});
}

View file

@ -34,6 +34,7 @@ import 'package:flutter_svg/flutter_svg.dart';
import 'package:get/get.dart';
import 'package:uuid/uuid.dart';
import 'package:window_manager/window_manager.dart';
import 'package:file_picker/file_picker.dart';
import '../common.dart';
import '../utils/image.dart' as img;
@ -119,6 +120,8 @@ class FfiModel with ChangeNotifier {
RxBool waitForFirstImage = true.obs;
bool isRefreshing = false;
Timer? timerScreenshot;
Rect? get rect => _rect;
bool get isOriginalResolutionSet =>
_pi.tryGetDisplayIfNotAllDisplay()?.isOriginalResolutionSet ?? false;
@ -216,6 +219,7 @@ class FfiModel with ChangeNotifier {
_timer = null;
clearPermissions();
waitForImageTimer?.cancel();
timerScreenshot?.cancel();
}
setConnectionType(String peerId, bool secure, bool direct) {
@ -414,12 +418,82 @@ class FfiModel with ChangeNotifier {
}
} else if (name == "printer_request") {
_handlePrinterRequest(evt, sessionId, peerId);
} else if (name == 'screenshot') {
_handleScreenshot(evt, sessionId, peerId);
} else {
debugPrint('Event is not handled in the fixed branch: $name');
}
};
}
_handleScreenshot(
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
timerScreenshot?.cancel();
timerScreenshot = null;
final msg = evt['msg'] ?? '';
final msgBoxType = 'custom-nook-nocancel-hasclose';
final msgBoxTitle = 'Take screenshot';
final dialogManager = parent.target!.dialogManager;
if (msg.isNotEmpty) {
msgBox(sessionId, msgBoxType, msgBoxTitle, msg, '', dialogManager);
} else {
final msgBoxText = 'screenshot-action-tip';
close() {
dialogManager.dismissAll();
}
saveAs() {
close();
Future.delayed(Duration.zero, () async {
final ts = DateTime.now().millisecondsSinceEpoch ~/ 1000;
String? outputFile = await FilePicker.platform.saveFile(
dialogTitle: '${translate('Save as')}...',
fileName: 'screenshot_$ts.png',
allowedExtensions: ['png'],
type: FileType.custom,
);
if (outputFile == null) {
bind.sessionHandleScreenshot(sessionId: sessionId, action: '2');
} else {
final res = await bind.sessionHandleScreenshot(
sessionId: sessionId, action: '0:$outputFile');
if (res.isNotEmpty) {
msgBox(sessionId, 'custom-nook-nocancel-hasclose-error',
'Take screenshot', res, '', dialogManager);
}
}
});
}
copyToClipboard() {
bind.sessionHandleScreenshot(sessionId: sessionId, action: '1');
close();
}
cancel() {
bind.sessionHandleScreenshot(sessionId: sessionId, action: '2');
close();
}
final List<Widget> buttons = [
dialogButton('${translate('Save as')}...', onPressed: saveAs),
dialogButton('Copy to clipboard', onPressed: copyToClipboard),
dialogButton('Cancel', onPressed: cancel),
];
dialogManager.dismissAll();
dialogManager.show(
(setState, close, context) => CustomAlertDialog(
title: null,
content: SelectionArea(
child: msgboxContent(msgBoxType, msgBoxTitle, msgBoxText)),
actions: buttons,
),
tag: '$msgBoxType-$msgBoxTitle-$msgBoxTitle',
);
}
}
_handlePrinterRequest(
Map<String, dynamic> evt, SessionID sessionId, String peerId) {
final id = evt['id'];
@ -451,7 +525,7 @@ class FfiModel with ChangeNotifier {
if (saveSettings.value || dontShowAgain.value) {
bind.mainSetLocalOption(key: kKeyPrinterSelected, value: printerName);
bind.mainSetLocalOption(
key: kKeyPrinterIncommingJobAction,
key: kKeyPrinterIncomingJobAction,
value: defaultOrSelectedGroupValue.value);
}
if (dontShowAgain.value) {
@ -463,7 +537,7 @@ class FfiModel with ChangeNotifier {
onCancel() {
if (dontShowAgain.value) {
bind.mainSetLocalOption(
key: kKeyPrinterIncommingJobAction,
key: kKeyPrinterIncomingJobAction,
value: kValuePrinterIncomingJobDismiss);
}
close();

View file

@ -13,7 +13,7 @@ class PrinterOptions {
required this.printerName});
static PrinterOptions load() {
var action = bind.mainGetLocalOption(key: kKeyPrinterIncommingJobAction);
var action = bind.mainGetLocalOption(key: kKeyPrinterIncomingJobAction);
if (![
kValuePrinterIncomingJobDismiss,
kValuePrinterIncomingJobDefault,
@ -28,7 +28,7 @@ class PrinterOptions {
if (action == kValuePrinterIncomingJobSelected) {
action = kValuePrinterIncomingJobDefault;
bind.mainSetLocalOption(
key: kKeyPrinterIncommingJobAction,
key: kKeyPrinterIncomingJobAction,
value: kValuePrinterIncomingJobDefault);
if (printerNames.isEmpty) {
selectedPrinterName = '';

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.3.9+57
version: 1.4.0+58
environment:
sdk: '^3.1.0'

@ -1 +1 @@
Subproject commit 3afaf6494475ef58dcaaae6b4e6d2303cc3d632b
Subproject commit 42aad01a517d4de7420ddcb7e99c29bd9f6d2b5a

View file

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

View file

@ -197,3 +197,40 @@ pub fn convert_to_yuv(
}
Ok(())
}
#[cfg(not(target_os = "ios"))]
pub fn convert(captured: &PixelBuffer, pixfmt: crate::Pixfmt, dst: &mut Vec<u8>) -> ResultType<()> {
if captured.pixfmt() == pixfmt {
dst.extend_from_slice(captured.data());
return Ok(());
}
let src = captured.data();
let src_stride = captured.stride();
let src_pixfmt = captured.pixfmt();
let src_width = captured.width();
let src_height = captured.height();
let unsupported = format!(
"unsupported pixfmt conversion: {src_pixfmt:?} -> {:?}",
pixfmt
);
match (src_pixfmt, pixfmt) {
(crate::Pixfmt::BGRA, crate::Pixfmt::RGBA) | (crate::Pixfmt::RGBA, crate::Pixfmt::BGRA) => {
dst.resize(src.len(), 0);
call_yuv!(ABGRToARGB(
src.as_ptr(),
src_stride[0] as _,
dst.as_mut_ptr(),
src_stride[0] as _,
src_width as _,
src_height as _,
));
}
_ => {
bail!(unsupported);
}
}
Ok(())
}

View file

@ -63,6 +63,7 @@ pub enum ImageFormat {
}
#[repr(C)]
#[derive(Clone)]
pub struct ImageRgb {
pub raw: Vec<u8>,
pub w: usize,

View file

@ -1,5 +1,5 @@
pkgname=rustdesk
pkgver=1.3.9
pkgver=1.4.0
pkgrel=0
epoch=
pkgdesc=""

View file

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

View file

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

View file

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

View file

@ -85,6 +85,7 @@ pub use super::lang::*;
pub mod file_trait;
pub mod helper;
pub mod io_loop;
pub mod screenshot;
pub const MILLI1: Duration = Duration::from_millis(1);
pub const SEC30: Duration = Duration::from_secs(30);
@ -3336,6 +3337,7 @@ pub enum Data {
CloseVoiceCall,
ResetDecoder(Option<usize>),
RenameFile((i32, String, String, bool)),
TakeScreenshot((i32, String)),
}
/// Keycode for key events.

View file

@ -962,6 +962,15 @@ impl<T: InvokeUiSession> Remote<T> {
}
}
},
Data::TakeScreenshot((display, sid)) => {
let mut msg = Message::new();
msg.set_screenshot_request(ScreenshotRequest {
display,
sid,
..Default::default()
});
allow_err!(peer.send(&msg).await);
}
_ => {}
}
true
@ -1909,6 +1918,11 @@ impl<T: InvokeUiSession> Remote<T> {
self.handler.set_displays(&pi.displays);
self.handler.set_platform_additions(&pi.platform_additions);
}
Some(message::Union::ScreenshotResponse(response)) => {
crate::client::screenshot::set_screenshot(response.data);
self.handler
.handle_screenshot_resp(response.sid, response.msg);
}
_ => {}
}
}

99
src/client/screenshot.rs Normal file
View file

@ -0,0 +1,99 @@
#[cfg(not(any(target_os = "android", target_os = "ios")))]
use crate::clipboard::{update_clipboard, ClipboardSide};
use hbb_common::{message_proto::*, ResultType};
use std::sync::Mutex;
lazy_static::lazy_static! {
static ref SCREENSHOT: Mutex<Screenshot> = Default::default();
}
pub enum ScreenshotAction {
SaveAs(String),
CopyToClipboard,
Discard,
}
impl Default for ScreenshotAction {
fn default() -> Self {
Self::Discard
}
}
impl From<&str> for ScreenshotAction {
fn from(value: &str) -> Self {
match value.chars().next() {
Some('0') => {
if let Some((pos, _)) = value.char_indices().nth(2) {
let substring = &value[pos..];
Self::SaveAs(substring.to_string())
} else {
Self::default()
}
}
Some('1') => Self::CopyToClipboard,
Some('2') => Self::default(),
_ => Self::default(),
}
}
}
impl Into<String> for ScreenshotAction {
fn into(self) -> String {
match self {
Self::SaveAs(p) => format!("0:{p}"),
Self::CopyToClipboard => "1".to_owned(),
Self::Discard => "2".to_owned(),
}
}
}
#[derive(Default)]
pub struct Screenshot {
data: Option<bytes::Bytes>,
}
impl Screenshot {
fn set_screenshot(&mut self, data: bytes::Bytes) {
self.data.replace(data);
}
fn handle_screenshot(&mut self, action: String) -> String {
let Some(data) = self.data.take() else {
return "No cached screenshot".to_owned();
};
match Self::handle_screenshot_(data, action) {
Ok(()) => "".to_owned(),
Err(e) => e.to_string(),
}
}
fn handle_screenshot_(data: bytes::Bytes, action: String) -> ResultType<()> {
match ScreenshotAction::from(&action as &str) {
ScreenshotAction::SaveAs(p) => {
std::fs::write(p, data)?;
}
ScreenshotAction::CopyToClipboard => {
#[cfg(not(any(target_os = "android", target_os = "ios")))]
{
let clips = vec![Clipboard {
compress: false,
content: data,
format: ClipboardFormat::ImagePng.into(),
..Default::default()
}];
update_clipboard(clips, ClipboardSide::Client);
}
}
ScreenshotAction::Discard => {}
}
Ok(())
}
}
pub fn set_screenshot(data: bytes::Bytes) {
SCREENSHOT.lock().unwrap().set_screenshot(data);
}
pub fn handle_screenshot(action: String) -> String {
SCREENSHOT.lock().unwrap().handle_screenshot(action)
}

View file

@ -147,6 +147,16 @@ pub fn is_support_file_paste_if_macos(ver: &str) -> bool {
hbb_common::get_version_number(ver) >= hbb_common::get_version_number("1.3.9")
}
#[inline]
pub fn is_support_screenshot(ver: &str) -> bool {
is_support_multi_ui_session_num(hbb_common::get_version_number(ver))
}
#[inline]
pub fn is_support_screenshot_num(ver: i64) -> bool {
ver >= hbb_common::get_version_number("1.4.0")
}
// is server process, with "--server" args
#[inline]
pub fn is_server() -> bool {

View file

@ -543,6 +543,25 @@ impl FlutterHandler {
pub fn push_event<V>(&self, name: &str, event: &[(&str, V)], excludes: &[&SessionID])
where
V: Sized + Serialize + Clone,
{
self.push_event_(name, event, &[], excludes);
}
pub fn push_event_to<V>(&self, name: &str, event: &[(&str, V)], include: &[&SessionID])
where
V: Sized + Serialize + Clone,
{
self.push_event_(name, event, include, &[]);
}
pub fn push_event_<V>(
&self,
name: &str,
event: &[(&str, V)],
includes: &[&SessionID],
excludes: &[&SessionID],
) where
V: Sized + Serialize + Clone,
{
let mut h: HashMap<&str, serde_json::Value> =
event.iter().map(|(k, v)| (*k, json!(*v))).collect();
@ -550,11 +569,20 @@ impl FlutterHandler {
h.insert("name", json!(name));
let out = serde_json::ser::to_string(&h).unwrap_or("".to_owned());
for (sid, session) in self.session_handlers.read().unwrap().iter() {
if excludes.contains(&sid) {
continue;
let mut push = false;
if includes.is_empty() {
if !excludes.contains(&sid) {
push = true;
}
} else {
if includes.contains(&sid) {
push = true;
}
}
if let Some(stream) = &session.event_stream {
stream.add(EventToUI::Event(out.clone()));
if push {
if let Some(stream) = &session.event_stream {
stream.add(EventToUI::Event(out.clone()));
}
}
}
}
@ -1067,6 +1095,16 @@ impl InvokeUiSession for FlutterHandler {
&[],
);
}
fn handle_screenshot_resp(&self, sid: String, msg: String) {
match SessionID::from_str(&sid) {
Ok(sid) => self.push_event_to("screenshot", &[("msg", json!(msg))], &[&sid]),
Err(e) => {
// Unreachable!
log::error!("Failed to parse sid \"{}\", {}", sid, e);
}
}
}
}
impl FlutterHandler {

View file

@ -250,6 +250,16 @@ pub fn session_refresh(session_id: SessionID, display: usize) {
}
}
pub fn session_take_screenshot(session_id: SessionID, display: usize) {
if let Some(s) = sessions::get_session_by_session_id(&session_id) {
s.take_screenshot(display as _, session_id.to_string());
}
}
pub fn session_handle_screenshot(session_id: SessionID, action: String) -> String {
crate::client::screenshot::handle_screenshot(action)
}
pub fn session_is_multi_ui_session(session_id: SessionID) -> SyncReturn<bool> {
if let Some(session) = sessions::get_session_by_session_id(&session_id) {
SyncReturn(session.is_multi_ui_session())
@ -2461,6 +2471,27 @@ pub fn main_set_common(_key: String, _value: String) {
}
}
pub fn session_get_common_sync(
session_id: SessionID,
key: String,
param: String,
) -> SyncReturn<Option<String>> {
SyncReturn(session_get_common(session_id, key, param))
}
pub fn session_get_common(session_id: SessionID, key: String, param: String) -> Option<String> {
if let Some(s) = sessions::get_session_by_session_id(&session_id) {
let v = if key == "is_screenshot_supported" {
s.is_screenshot_supported().to_string()
} else {
"".to_owned()
};
Some(v)
} else {
None
}
}
#[cfg(target_os = "android")]
pub mod server_side {
use hbb_common::{config, log};

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "الطابعة {} جاهزة"),
("Install {} Printer", "تثبيت طابعة {}"),
("Outgoing Print Jobs", "وظائف الطباعة الصادرة"),
("Incomming Print Jobs", "وظائف الطباعة الواردة"),
("Incoming Print Jobs", "وظائف الطباعة الواردة"),
("Incoming Print Job", "وظيفة طباعة واردة"),
("use-the-default-printer-tip", "استخدم الطابعة الافتراضية"),
("use-the-selected-printer-tip", "استخدم الطابعة المحددة"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "الطباعة عن بُعد غير مسموح بها على هذا الجهاز"),
("save-settings-tip", "حفظ الإعدادات"),
("dont-show-again-tip", "لا تظهر هذا مرة أخرى"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -653,7 +653,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Upload folder", "上传文件夹"),
("Upload files", "上传文件"),
("Clipboard is synchronized", "剪贴板已同步"),
("Update client clipboard", "更新客户端的贴板"),
("Update client clipboard", "更新客户端的贴板"),
("Untagged", "无标签"),
("new-version-of-{}-tip", "{} 版本更新"),
("Accessible devices", "可访问的设备"),
@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "{} 打印机已安装,您可以使用打印功能了。"),
("Install {} Printer", "安装 {} 打印机"),
("Outgoing Print Jobs", "传出的打印任务"),
("Incomming Print Jobs", "传入的打印任务"),
("Incoming Print Jobs", "传入的打印任务"),
("Incoming Print Job", "传入的打印任务"),
("use-the-default-printer-tip", "使用默认的打印机执行"),
("use-the-selected-printer-tip", "使用选择的打印机执行"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "被控端的权限设置拒绝了远程打印。"),
("save-settings-tip", "保存设置"),
("dont-show-again-tip", "不再显示此信息"),
("Take screenshot", "截屏"),
("Taking screenshot", "正在截屏"),
("screenshot-merged-screen-not-supported-tip", "当前不支持多个屏幕的合并截屏,请切换到单个屏幕重试。"),
("screenshot-action-tip", "请选择如何继续截屏。"),
("Save as", "另存为"),
("Copy to clipboard", "复制到剪贴板"),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "Der Drucker {} ist installiert und einsatzbereit."),
("Install {} Printer", "Drucker {} installieren"),
("Outgoing Print Jobs", "Ausgehende Druckaufträge"),
("Incomming Print Jobs", "Eingehende Druckaufträge"),
("Incoming Print Jobs", "Eingehende Druckaufträge"),
("Incoming Print Job", "Eingehender Druckauftrag"),
("use-the-default-printer-tip", "Standarddrucker verwenden"),
("use-the-selected-printer-tip", "Ausgewählten Drucker verwenden"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Die Berechtigungseinstellungen der kontrollierten Seite verweigern den entfernten Druck."),
("save-settings-tip", "Einstellungen speichern"),
("dont-show-again-tip", "Nicht mehr anzeigen"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -253,5 +253,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "The permission settings of the controlled side deny Remote Printing."),
("save-settings-tip", "Save settings"),
("dont-show-again-tip", "Don't show this again"),
("screenshot-merged-screen-not-supported-tip", "Merging screenshots of multiple displays is currently not supported. Please switch to a single display and try again."),
("screenshot-action-tip", "Please select how to continue with the screenshot."),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "La impresora {} está instalada y lista para usar."),
("Install {} Printer", "Instalar la impresora {}"),
("Outgoing Print Jobs", "Tareas salientes de impresión"),
("Incomming Print Jobs", "Tareas entrantes de impresión"),
("Incoming Print Jobs", "Tareas entrantes de impresión"),
("Incoming Print Job", "Trabajo entrante de impresión"),
("use-the-default-printer-tip", "Usar la impresora predeterminada"),
("use-the-selected-printer-tip", "Usar la impresora seleccionada"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Los ajustes de permisos del lado controlado no permiten la impresión remota."),
("save-settings-tip", "Guardar ajustes"),
("dont-show-again-tip", "No volver a mostrar"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "چاپگر {} آماده است"),
("Install {} Printer", "نصب چاپگر {}"),
("Outgoing Print Jobs", "وظایف چاپ خروجی"),
("Incomming Print Jobs", "وظایف چاپ ورودی"),
("Incoming Print Jobs", "وظایف چاپ ورودی"),
("Incoming Print Job", "وظیفه چاپ ورودی"),
("use-the-default-printer-tip", "از چاپگر پیش‌فرض استفاده کنید"),
("use-the-selected-printer-tip", "از چاپگر انتخاب‌شده استفاده کنید"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "شما مجوز لازم برای چاپ از راه دور را ندارید"),
("save-settings-tip", "تنظیمات را ذخیره کنید"),
("dont-show-again-tip", "دیگر نمایش داده نشود"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "Limprimante {} est installée et opérationnelle."),
("Install {} Printer", "Installer limprimante {}"),
("Outgoing Print Jobs", "Impressions sortantes"),
("Incomming Print Jobs", "Impressions entrantes"),
("Incoming Print Jobs", "Impressions entrantes"),
("Incoming Print Job", "Impression entrante"),
("use-the-default-printer-tip", "Utiliser limprimante par défaut"),
("use-the-selected-printer-tip", "Utiliser limprimante sélectionnée"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Les paramètres de lappareil contrôlé nautorisent pas limpression à distance."),
("save-settings-tip", "Enregistrer les paramètres"),
("dont-show-again-tip", "Ne plus afficher"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -239,7 +239,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Empty", "ცარიელი"),
("Invalid folder name", "არასწორი საქაღალდის სახელი"),
("Socks5 Proxy", "SOCKS5-პროქსი"),
("Proxy", "პროქსი"),
("Socks5/Http(s) Proxy", ""),
("Discovered", "ნაპოვნია"),
("install_daemon_tip", "ჩატვირთვისას გასაშვებად საჭიროა სისტემური სერვისის დაყენება"),
("Remote ID", "დაშორებული ID"),
@ -567,7 +567,6 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("id_input_tip", "შეგიძლიათ შეიყვანოთ იდენტიფიკატორი, პირდაპირი IP მისამართი ან დომენი პორტით (<დომენი>:<პორტი>).\nთუ გჭირდებათ წვდომა მოწყობილობაზე სხვა სერვერზე, დაამატეთ სერვერის მისამართი (<id>@<სერვერის_მისამართი>?key=<გასაღების_მნიშვნელობა>), მაგალითად:\n9123456234@192.168.16.1:21117?key=5Qbwsde3unUcJBtrx9ZkvUmwFNoExHzpryHuPUdqlWM=.\nთუ გჭირდებათ წვდომა მოწყობილობაზე საჯარო სერვერზე, შეიყვანეთ \"<id>@public\", გასაღები საჯარო სერვერისთვის არ არის საჭირო."),
("privacy_mode_impl_mag_tip", "რეჟიმი 1"),
("privacy_mode_impl_virtual_display_tip", "რეჟიმი 2"),
("privacy_mode_impl_virtual_display_tip", "რეჟიმი 2"),
("Enter privacy mode", "კონფიდენციალურობის რეჟიმის ჩართვა"),
("Exit privacy mode", "კონფიდენციალურობის რეჟიმის გამორთვა"),
("idd_not_support_under_win10_2004_tip", "არაპირდაპირი ჩვენების დრაივერი არ არის მხარდაჭერილი. საჭიროა Windows 10 ვერსია 2004 ან უფრო ახალი."),
@ -659,7 +658,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("new-version-of-{}-tip", "ხელმისაწვდომია ახალი ვერსია {}"),
("Accessible devices", "ხელმისაწვდომი მოწყობილობები"),
("View camera", "კამერის ნახვა"),
("upgrade_remote_rustdesk_client_to{}_tip", "განაახლეთ RustDesk კლიენტი ვერსიამდე {} ან უფრო ახალი დისტანციურ მხარეზე!"),
("upgrade_remote_rustdesk_client_to_{}_tip", ""),
("view_camera_unsupported_tip", "დისტანციური მოწყობილობა არ უჭერს მხარს კამერის ნახვას."),
("Enable camera", "კამერის ჩართვა"),
("No cameras", "კამერა არ არის"),
@ -672,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "პრინტერი {} დაინსტალირებულია და მზად არის გამოსაყენებლად."),
("Install {} Printer", "დააინსტალირეთ პრინტერი {}"),
("Outgoing Print Jobs", "გამავალი ბეჭდვის დავალება"),
("Incomming Print Jobs", "შემომავალი ბეჭდვის დავალება"),
("Incoming Print Jobs", "შემომავალი ბეჭდვის დავალება"),
("Incoming Print Job", "შემომავალი ბეჭდვის დავალება"),
("use-the-default-printer-tip", "ნაგულისხმევი პრინტერის გამოყენება"),
("use-the-selected-printer-tip", "არჩეული პრინტერის გამოყენება"),
@ -682,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "მართულ მხარეზე უფლებების პარამეტრები კრძალავს დისტანციურ ბეჭდვას."),
("save-settings-tip", "პარამეტრების შენახვა"),
("dont-show-again-tip", "აღარ აჩვენოთ"),
].iter().cloned().collect();
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "A(z) {} nyomtató készen áll"),
("Install {} Printer", "A(z) {} nyomtató nyomtató telepítése"),
("Outgoing Print Jobs", "Kimenő nyomtatási feladatok"),
("Incomming Print Jobs", "Bejövő nyomtatási feladatok"),
("Incoming Print Jobs", "Bejövő nyomtatási feladatok"),
("Incoming Print Job", "Bejövő nyomtatási feladat"),
("use-the-default-printer-tip", "Alapértelmezett nyomtató használata"),
("use-the-selected-printer-tip", "Kiválasztott nyomtató használata"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "A távoli nyomtatás nincs engedélyezve"),
("save-settings-tip", "Beállítások mentése"),
("dont-show-again-tip", "Ne jelenítse meg újra"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "La stampante {} è installata e pronta all'uso."),
("Install {} Printer", "Installa la stampante {}"),
("Outgoing Print Jobs", "Lavori di stampa in uscita"),
("Incomming Print Jobs", "Lavori di stampa in entrata"),
("Incoming Print Jobs", "Lavori di stampa in entrata"),
("Incoming Print Job", "Lavoro di stampa in entrata"),
("use-the-default-printer-tip", "Usa la stampante predefinita"),
("use-the-selected-printer-tip", "Usa la stampante selezionata"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Le impostazioni di autorizzazione del lato controllato negano la stampa remota."),
("save-settings-tip", "Salva impostazioni"),
("dont-show-again-tip", "Non visualizzare più questo messaggio"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "Printeris {} ir instalēts un gatavs lietošanai."),
("Install {} Printer", "Instalēt {} printeri"),
("Outgoing Print Jobs", "Izejošie drukas darbi"),
("Incomming Print Jobs", "Ienākošie drukas darbi"),
("Incoming Print Jobs", "Ienākošie drukas darbi"),
("Incoming Print Job", "Ienākošais drukas darbs"),
("use-the-default-printer-tip", "Izmantot noklusējuma printeri"),
("use-the-selected-printer-tip", "Izmantot atlasīto printeri"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Kontrolētās puses atļauju iestatījumi liedz attālo drukāšanu."),
("save-settings-tip", "Saglabāt iestatījumus"),
("dont-show-again-tip", "Nerādīt šo vēlreiz"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "De printer {} is geïnstalleerd en klaar voor gebruik."),
("Install {} Printer", "Installeer {} Printer"),
("Outgoing Print Jobs", "Uitgaande Afdruktaken"),
("Incomming Print Jobs", "Inkomende Afdruktaken"),
("Incoming Print Jobs", "Inkomende Afdruktaken"),
("Incoming Print Job", "Inkomende Afdruktaak"),
("use-the-default-printer-tip", "Gebruik de standaard printer"),
("use-the-selected-printer-tip", "Gebruik de geselecteerde printer"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Machtigingsinstellingen aan beheerde zijde verhinderen afdrukken op afstand."),
("save-settings-tip", "Instellingen opslaan"),
("dont-show-again-tip", "Dit bericht wordt niet meer weergegeven"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "Drukarka {} jest zainstalowana i gotowa do użycia."),
("Install {} Printer", "Zainstaluj drukarkę {}"),
("Outgoing Print Jobs", "Wychodzące zadania drukowania"),
("Incomming Print Jobs", "Przychodzące zadania drukowania"),
("Incoming Print Jobs", "Przychodzące zadania drukowania"),
("Incoming Print Job", "Przychodzące zadanie drukowania"),
("use-the-default-printer-tip", "Użyj domyślnej drukarki"),
("use-the-selected-printer-tip", "Użyj wybranej drukarki"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Ustawienia uprawnień po zdalnej stronie uniemożliwiają zdalne drukowanie."),
("save-settings-tip", "Zapisz ustawienia"),
("dont-show-again-tip", "Nie pokazuj więcej"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "A impressora {} está instalada e operacional."),
("Install {} Printer", "Instalar impressora {}"),
("Outgoing Print Jobs", "Trabalhos de impressão enviados"),
("Incomming Print Jobs", "Trabalhos de impressão recebidos"),
("Incoming Print Jobs", "Trabalhos de impressão recebidos"),
("Incoming Print Job", "Impressão recebida"),
("use-the-default-printer-tip", "Usar impressora padrão"),
("use-the-selected-printer-tip", "Usar impressora selecionada"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "As configurações do dispositivo controlado não permitem impressão remota."),
("save-settings-tip", "Salvar configurações"),
("dont-show-again-tip", "Não mostrar novamente"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "Принтер {} установлен и готов к использованию."),
("Install {} Printer", "Установить принтер {}"),
("Outgoing Print Jobs", "Исходящее задание печати"),
("Incomming Print Jobs", "Входящее задание печати"),
("Incoming Print Jobs", "Входящее задание печати"),
("Incoming Print Job", "Входящее задание печати"),
("use-the-default-printer-tip", "Использовать принтер по умолчанию"),
("use-the-selected-printer-tip", "Использовать выбранный принтер"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Настройки разрешений на управляемой стороне запрещают удалённую печать."),
("save-settings-tip", "Сохранить настройки"),
("dont-show-again-tip", "Больше не показывать"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "S'imprentadora {} est installada e pronta pro s'impreu."),
("Install {} Printer", "Installa s'imprentadora {}"),
("Outgoing Print Jobs", "Traballos de imprenta in essida"),
("Incomming Print Jobs", "Traballos de imprenta in intrada"),
("Incoming Print Jobs", "Traballos de imprenta in intrada"),
("Incoming Print Job", "Traballu de imprenta in intrada"),
("use-the-default-printer-tip", "Imprea s'imprentadora predefinida"),
("use-the-selected-printer-tip", "Imprea s'imprentadora seletzionada"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "Sas impostatziones de sos permissos de s'ala controllada negant s'imprenta remota."),
("save-settings-tip", "Sarva sas impostatziones"),
("dont-show-again-tip", "Non mustres prus custu messàgiu"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", "{} 印表機已安裝,您可以使用列印功能了。"),
("Install {} Printer", "安裝 {} 印表機"),
("Outgoing Print Jobs", "傳出的列印任務"),
("Incomming Print Jobs", "傳入的列印任務"),
("Incoming Print Jobs", "傳入的列印任務"),
("Incoming Print Job", "傳入的列印任務"),
("use-the-default-printer-tip", "使用預設的印表機"),
("use-the-selected-printer-tip", "使用選取的印表機"),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", "被控端的權限設置拒絕了遠端列印。"),
("save-settings-tip", "儲存設定"),
("dont-show-again-tip", "不再顯示此訊息"),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -671,7 +671,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("printer-{}-ready-tip", ""),
("Install {} Printer", ""),
("Outgoing Print Jobs", ""),
("Incomming Print Jobs", ""),
("Incoming Print Jobs", ""),
("Incoming Print Job", ""),
("use-the-default-printer-tip", ""),
("use-the-selected-printer-tip", ""),
@ -681,5 +681,11 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("remote-printing-disallowed-text-tip", ""),
("save-settings-tip", ""),
("dont-show-again-tip", ""),
("Take screenshot", ""),
("Taking screenshot", ""),
("screenshot-merged-screen-not-supported-tip", ""),
("screenshot-action-tip", ""),
("Save as", ""),
("Copy to clipboard", ""),
].iter().cloned().collect();
}

View file

@ -2819,6 +2819,16 @@ impl Connection {
Some(message::Union::VoiceCallResponse(_response)) => {
// TODO: Maybe we can do a voice call from cm directly.
}
Some(message::Union::ScreenshotRequest(request)) => {
if let Some(tx) = self.inner.tx.clone() {
crate::video_service::set_take_screenshot(
request.display as _,
request.sid.clone(),
tx,
);
self.refresh_video_display(Some(request.display as usize));
}
}
_ => {}
}
}

View file

@ -49,7 +49,7 @@ use scrap::{
codec::{Encoder, EncoderCfg},
record::{Recorder, RecorderContext},
vpxcodec::{VpxEncoderConfig, VpxVideoCodecId},
CodecFormat, Display, EncodeInput, TraitCapturer,
CodecFormat, Display, EncodeInput, TraitCapturer, TraitPixelBuffer,
};
#[cfg(windows)]
use std::sync::Once;
@ -70,6 +70,13 @@ lazy_static::lazy_static! {
pub static ref VIDEO_QOS: Arc<Mutex<VideoQoS>> = Default::default();
pub static ref IS_UAC_RUNNING: Arc<Mutex<bool>> = Default::default();
pub static ref IS_FOREGROUND_WINDOW_ELEVATED: Arc<Mutex<bool>> = Default::default();
static ref SCREENSHOTS: Mutex<HashMap<usize, Screenshot>> = Default::default();
}
struct Screenshot {
sid: String,
tx: Sender,
restore_vram: bool,
}
#[inline]
@ -457,7 +464,7 @@ fn get_capturer(
}
fn run(vs: VideoService) -> ResultType<()> {
let _raii = Raii::new(vs.sp.name());
let mut _raii = Raii::new(vs.sp.name());
// Wayland only support one video capturer for now. It is ok to call ensure_inited() here.
//
// ensure_inited() is needed because clear() may be called.
@ -639,6 +646,49 @@ fn run(vs: VideoService) -> ResultType<()> {
Ok(frame) => {
repeat_encode_counter = 0;
if frame.valid() {
let screenshot = SCREENSHOTS.lock().unwrap().remove(&display_idx);
if let Some(mut screenshot) = screenshot {
let restore_vram = screenshot.restore_vram;
let (msg, w, h, data) = match &frame {
scrap::Frame::PixelBuffer(f) => match get_rgba_from_pixelbuf(f) {
Ok(rgba) => ("".to_owned(), f.width(), f.height(), rgba),
Err(e) => {
let serr = e.to_string();
log::error!(
"Failed to convert the pix format into rgba, {}",
&serr
);
(format!("Convert pixfmt: {}", serr), 0, 0, vec![])
}
},
scrap::Frame::Texture(_) => {
if restore_vram {
// Already set one time, just ignore to break infinite loop.
// Though it's unreachable, this branch is kept to avoid infinite loop.
(
"Please change codec and try again.".to_owned(),
0,
0,
vec![],
)
} else {
#[cfg(all(windows, feature = "vram"))]
VRamEncoder::set_not_use(sp.name(), true);
screenshot.restore_vram = true;
SCREENSHOTS.lock().unwrap().insert(display_idx, screenshot);
_raii.try_vram = false;
bail!("SWITCH");
}
}
};
std::thread::spawn(move || {
handle_screenshot(screenshot, msg, w, h, data);
});
if restore_vram {
bail!("SWITCH");
}
}
let frame = frame.to(encoder.yuvfmt(), &mut yuv, &mut mid_data)?;
let send_conn_ids = handle_one_frame(
display_idx,
@ -764,24 +814,32 @@ fn run(vs: VideoService) -> ResultType<()> {
Ok(())
}
struct Raii(String);
struct Raii {
name: String,
try_vram: bool,
}
impl Raii {
fn new(name: String) -> Self {
log::info!("new video service: {}", name);
VIDEO_QOS.lock().unwrap().new_display(name.clone());
Raii(name)
Raii {
name,
try_vram: true,
}
}
}
impl Drop for Raii {
fn drop(&mut self) {
log::info!("stop video service: {}", self.0);
log::info!("stop video service: {}", self.name);
#[cfg(feature = "vram")]
VRamEncoder::set_not_use(self.0.clone(), false);
if self.try_vram {
VRamEncoder::set_not_use(self.name.clone(), false);
}
#[cfg(feature = "vram")]
Encoder::update(scrap::codec::EncodingUpdate::Check);
VIDEO_QOS.lock().unwrap().remove_display(&self.0);
VIDEO_QOS.lock().unwrap().remove_display(&self.name);
}
}
@ -1206,3 +1264,77 @@ fn check_qos(
drop(video_qos);
Ok(())
}
pub fn set_take_screenshot(display_idx: usize, sid: String, tx: Sender) {
SCREENSHOTS.lock().unwrap().insert(
display_idx,
Screenshot {
sid,
tx,
restore_vram: false,
},
);
}
// We need to this function, because the `stride` may be larger than `width * 4`.
fn get_rgba_from_pixelbuf<'a>(pixbuf: &scrap::PixelBuffer<'a>) -> ResultType<Vec<u8>> {
let w = pixbuf.width();
let h = pixbuf.height();
let stride = pixbuf.stride();
let Some(s) = stride.get(0) else {
bail!("Invalid pixel buf stride.")
};
if *s == w * 4 {
let mut rgba = vec![];
scrap::convert(pixbuf, scrap::Pixfmt::RGBA, &mut rgba)?;
Ok(rgba)
} else {
let bgra = pixbuf.data();
let mut bit_flipped = Vec::with_capacity(w * h * 4);
for y in 0..h {
for x in 0..w {
let i = s * y + 4 * x;
bit_flipped.extend_from_slice(&[bgra[i + 2], bgra[i + 1], bgra[i], bgra[i + 3]]);
}
}
Ok(bit_flipped)
}
}
fn handle_screenshot(screenshot: Screenshot, msg: String, w: usize, h: usize, data: Vec<u8>) {
let mut response = ScreenshotResponse::new();
response.sid = screenshot.sid;
if msg.is_empty() {
if data.is_empty() {
response.msg = "Failed to take screenshot, please try again later.".to_owned();
} else {
fn encode_png(width: usize, height: usize, rgba: Vec<u8>) -> ResultType<Vec<u8>> {
let mut png = Vec::new();
let mut encoder =
repng::Options::smallest(width as _, height as _).build(&mut png)?;
encoder.write(&rgba)?;
encoder.finish()?;
Ok(png)
}
match encode_png(w as _, h as _, data) {
Ok(png) => {
response.data = png.into();
}
Err(e) => {
response.msg = format!("Error encoding png: {}", e);
}
}
}
} else {
response.msg = msg;
}
let mut msg_out = Message::new();
msg_out.set_screenshot_response(response);
if let Err(e) = screenshot
.tx
.send((hbb_common::tokio::time::Instant::now(), Arc::new(msg_out)))
{
log::error!("Failed to send screenshot, {}", e);
}
}

View file

@ -230,6 +230,7 @@ class Header: Reactor.Component {
{restart_enabled && (pi.platform == "Linux" || pi.platform == "Windows" || pi.platform == "Mac OS") ? <li #restart_remote_device>{translate('Restart remote device')}</li> : ""}
{keyboard_enabled ? <li #lock-screen>{translate('Insert Lock')}</li> : ""}
{keyboard_enabled && pi.platform == "Windows" && pi.sas_enabled ? <li #block-input>{translate("Block user input")}</li> : ""}
{handler.is_screenshot_supported() ? <li #take-screenshot>{translate('Take screenshot')}</li> : "" }
<li #refresh>{translate('Refresh')}</li>
</menu>
</popup>;
@ -377,6 +378,10 @@ class Header: Reactor.Component {
handler.lock_screen();
}
event click $(#take-screenshot) {
handler.take_screenshot(pi.current_display, "");
}
event click $(#refresh) {
// 0 is just a dummy value. It will be ignored by the handler.
handler.refresh_video(0);
@ -546,6 +551,26 @@ handler.setCurrentDisplay = function(v) {
}
}
handler.screenshot = function(msg) {
if (msg) {
msgbox(
"custom-nocancel-nook-hasclose-error",
translate("Take screenshot"),
msg,
"",
function() {}
);
} else {
msgbox(
"custom-take-screenshot-nocancel-nook",
translate("Take screenshot"),
translate("screenshot-action-tip"),
"",
function() {}
);
}
}
function updatePrivacyMode() {
var el = $(li#privacy-mode);
if (el) {

View file

@ -132,6 +132,17 @@ class MsgboxComponent: Reactor.Component {
return this.type.indexOf("skip") >= 0;
}
function getScreenshotButtons() {
var isScreenshot = this.type.indexOf("take-screenshot") >= 0;
return isScreenshot
? <div>
<button .button #screenshotSaveAs .outline>{translate('Save as')}...</button>
<button .button #screenshotCopyToClip .outline>{translate('Copy to clipboard')}</button>
<button .button #screenshotCancel .outline>{translate('Cancel')}</button>
</div>
: "";
}
function render() {
this.set_outline_focus();
var color = this.getColor();
@ -170,6 +181,7 @@ class MsgboxComponent: Reactor.Component {
{hasOk || this.hasRetry ? <button .button #submit>{translate(this.hasRetry ? "Retry" : "OK")}</button> : ""}
{hasLink ? <button .button #jumplink .outline>{translate('JumpLink')}</button> : ""}
{hasClose ? <button .button #cancel .outline>{translate('Close')}</button> : ""}
{this.getScreenshotButtons()}
</div>
</div>
</div>
@ -246,6 +258,39 @@ class MsgboxComponent: Reactor.Component {
}
}
event click $(button#screenshotSaveAs) {
this.close();
handler.leave(handler.get_keyboard_mode());
const filter = "Png file (*.png)";
const defaultExt = "png";
const initialPath = System.path(#USER_DOCUMENTS, "screenshot");
const caption = "Save as";
var url = view.selectFile(#save, filter, defaultExt, initialPath, caption);
handler.enter(handler.get_keyboard_mode());
if(url) {
var res = handler.handle_screenshot("0:" + URL.toPath(url));
if (res) {
msgbox("custom-error-nocancel-nook-hasclose", "Take screenshot", res, "", function() {});
}
} else {
handler.handle_screenshot("2");
}
}
event click $(button#screenshotCopyToClip) {
this.close();
var res = handler.handle_screenshot("1");
if (res) {
msgbox("custom-error-nocancel-nook-hasclose", "Take screenshot", res, "", function() {});
}
}
event click $(button#screenshotCancel) {
this.close();
handler.handle_screenshot("2");
}
event keydown (evt) {
if (!evt.shortcutKey) {
if (isEnterKey(evt)) {

View file

@ -383,6 +383,10 @@ impl InvokeUiSession for SciterHandler {
fn printer_request(&self, id: i32, path: String) {
self.call("printerRequest", &make_args!(id, path));
}
fn handle_screenshot_resp(&self, _sid: String, msg: String) {
self.call("screenshot", &make_args!(msg));
}
}
pub struct SciterSession(Session<SciterHandler>);
@ -529,6 +533,9 @@ impl sciter::EventHandler for SciterSession {
fn save_custom_image_quality(i32);
fn refresh_video(i32);
fn record_screen(bool);
fn is_screenshot_supported();
fn take_screenshot(i32, String);
fn handle_screenshot(String);
fn get_toggle_option(String);
fn is_privacy_mode_supported();
fn toggle_option(String);
@ -866,6 +873,10 @@ impl SciterSession {
fn on_printer_selected(&self, id: i32, path: String, printer_name: String) {
self.printer_response(id, path, printer_name);
}
fn handle_screenshot(&self, action: String) -> String {
crate::client::screenshot::handle_screenshot(action)
}
}
pub fn make_fd(id: i32, entries: &Vec<FileEntry>, only_count: bool) -> Value {

View file

@ -412,6 +412,14 @@ impl<T: InvokeUiSession> Session<T> {
self.send(Data::RecordScreen(start));
}
pub fn is_screenshot_supported(&self) -> bool {
crate::common::is_support_screenshot_num(self.lc.read().unwrap().version)
}
pub fn take_screenshot(&self, display: i32, sid: String) {
self.send(Data::TakeScreenshot((display, sid)));
}
pub fn is_recording(&self) -> bool {
self.lc.read().unwrap().record_state
}
@ -1586,6 +1594,7 @@ pub trait InvokeUiSession: Send + Sync + Clone + 'static + Sized + Default {
fn update_record_status(&self, start: bool);
fn update_empty_dirs(&self, _res: ReadEmptyDirsResponse) {}
fn printer_request(&self, id: i32, path: String);
fn handle_screenshot_resp(&self, sid: String, msg: String);
}
impl<T: InvokeUiSession> Deref for Session<T> {